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