xref: /linux/drivers/gpu/drm/i915/display/intel_de.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2026 Intel Corporation
4  */
5 
6 #include <linux/delay.h>
7 
8 #include <drm/drm_print.h>
9 
10 #include "intel_de.h"
11 
12 static int intel_de_wait_for_register(struct intel_display *display,
13 				      intel_reg_t reg, u32 mask, u32 value,
14 				      unsigned int timeout_us,
15 				      u32 (*read)(struct intel_display *display, intel_reg_t reg),
16 				      u32 *out_val, bool is_atomic)
17 {
18 	const ktime_t end = ktime_add_us(ktime_get_raw(), timeout_us);
19 	int wait_max = 1000;
20 	int wait = 10;
21 	u32 reg_value;
22 	int ret;
23 
24 	might_sleep_if(!is_atomic);
25 
26 	if (timeout_us <= 10) {
27 		is_atomic = true;
28 		wait = 1;
29 	}
30 
31 	for (;;) {
32 		bool expired = ktime_after(ktime_get_raw(), end);
33 
34 		/* guarantee the condition is evaluated after timeout expired */
35 		barrier();
36 
37 		reg_value = read(display, reg);
38 		if ((reg_value & mask) == value) {
39 			ret = 0;
40 			break;
41 		}
42 
43 		if (expired) {
44 			ret = -ETIMEDOUT;
45 			break;
46 		}
47 
48 		if (is_atomic)
49 			udelay(wait);
50 		else
51 			usleep_range(wait, wait << 1);
52 
53 		if (wait < wait_max)
54 			wait <<= 1;
55 	}
56 
57 	if (out_val)
58 		*out_val = reg_value;
59 
60 	return ret;
61 }
62 
63 int intel_de_wait_us(struct intel_display *display, intel_reg_t reg,
64 		     u32 mask, u32 value, unsigned int timeout_us,
65 		     u32 *out_value)
66 {
67 	int ret;
68 
69 	intel_dmc_wl_get(display, reg);
70 
71 	ret = intel_de_wait_for_register(display, reg, mask, value,
72 					 timeout_us,
73 					 intel_de_read,
74 					 out_value, false);
75 
76 	intel_dmc_wl_put(display, reg);
77 
78 	return ret;
79 }
80 
81 int intel_de_wait_ms(struct intel_display *display, intel_reg_t reg,
82 		     u32 mask, u32 value, unsigned int timeout_ms,
83 		     u32 *out_value)
84 {
85 	int ret;
86 
87 	intel_dmc_wl_get(display, reg);
88 
89 	ret = intel_de_wait_for_register(display, reg, mask, value,
90 					 timeout_ms * 1000,
91 					 intel_de_read,
92 					 out_value, false);
93 
94 	intel_dmc_wl_put(display, reg);
95 
96 	return ret;
97 }
98 
99 int intel_de_wait_fw_ms(struct intel_display *display, intel_reg_t reg,
100 			u32 mask, u32 value, unsigned int timeout_ms,
101 			u32 *out_value)
102 {
103 	return intel_de_wait_for_register(display, reg, mask, value,
104 					  timeout_ms * 1000,
105 					  intel_de_read_fw,
106 					  out_value, false);
107 }
108 
109 int intel_de_wait_fw_us_atomic(struct intel_display *display, intel_reg_t reg,
110 			       u32 mask, u32 value, unsigned int timeout_us,
111 			       u32 *out_value)
112 {
113 	return intel_de_wait_for_register(display, reg, mask, value,
114 					  timeout_us,
115 					  intel_de_read_fw,
116 					  out_value, true);
117 }
118 
119 int intel_de_wait_for_set_us(struct intel_display *display, intel_reg_t reg,
120 			     u32 mask, unsigned int timeout_us)
121 {
122 	return intel_de_wait_us(display, reg, mask, mask, timeout_us, NULL);
123 }
124 
125 int intel_de_wait_for_clear_us(struct intel_display *display, intel_reg_t reg,
126 			       u32 mask, unsigned int timeout_us)
127 {
128 	return intel_de_wait_us(display, reg, mask, 0, timeout_us, NULL);
129 }
130 
131 int intel_de_wait_for_set_ms(struct intel_display *display, intel_reg_t reg,
132 			     u32 mask, unsigned int timeout_ms)
133 {
134 	return intel_de_wait_ms(display, reg, mask, mask, timeout_ms, NULL);
135 }
136 
137 int intel_de_wait_for_clear_ms(struct intel_display *display, intel_reg_t reg,
138 			       u32 mask, unsigned int timeout_ms)
139 {
140 	return intel_de_wait_ms(display, reg, mask, 0, timeout_ms, NULL);
141 }
142 
143 u8 intel_de_read8(struct intel_display *display, intel_reg_t reg)
144 {
145 	/* this is only used on VGA registers (possible on pre-g4x) */
146 	drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x);
147 
148 	return intel_uncore_read8(__to_uncore(display), reg);
149 }
150 
151 void intel_de_write8(struct intel_display *display, intel_reg_t reg, u8 val)
152 {
153 	drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 5 || display->platform.g4x);
154 
155 	intel_uncore_write8(__to_uncore(display), reg, val);
156 }
157 
158 u16 intel_de_read16(struct intel_display *display, intel_reg_t reg)
159 {
160 	/* this is only used on MCHBAR registers on pre-SNB */
161 	drm_WARN_ON(display->drm, DISPLAY_VER(display) >= 6);
162 
163 	return intel_uncore_read16(__to_uncore(display), reg);
164 }
165