]>
Commit | Line | Data |
---|---|---|
e7156c83 YA |
1 | /* |
2 | * Copyright © 2015 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | */ | |
24 | ||
25 | #include "intel_drv.h" | |
26 | ||
27 | static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) | |
28 | { | |
29 | uint8_t reg_val = 0; | |
30 | ||
49d191dd PV |
31 | /* Early return when display use other mechanism to enable backlight. */ |
32 | if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP)) | |
33 | return; | |
34 | ||
e7156c83 YA |
35 | if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER, |
36 | ®_val) < 0) { | |
37 | DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n", | |
38 | DP_EDP_DISPLAY_CONTROL_REGISTER); | |
39 | return; | |
40 | } | |
41 | if (enable) | |
42 | reg_val |= DP_EDP_BACKLIGHT_ENABLE; | |
43 | else | |
44 | reg_val &= ~(DP_EDP_BACKLIGHT_ENABLE); | |
45 | ||
46 | if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER, | |
47 | reg_val) != 1) { | |
48 | DRM_DEBUG_KMS("Failed to %s aux backlight\n", | |
49 | enable ? "enable" : "disable"); | |
50 | } | |
51 | } | |
52 | ||
53 | /* | |
54 | * Read the current backlight value from DPCD register(s) based | |
55 | * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported | |
56 | */ | |
57 | static uint32_t intel_dp_aux_get_backlight(struct intel_connector *connector) | |
58 | { | |
59 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); | |
60 | uint8_t read_val[2] = { 0x0 }; | |
61 | uint16_t level = 0; | |
62 | ||
63 | if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, | |
64 | &read_val, sizeof(read_val)) < 0) { | |
65 | DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n", | |
66 | DP_EDP_BACKLIGHT_BRIGHTNESS_MSB); | |
67 | return 0; | |
68 | } | |
69 | level = read_val[0]; | |
70 | if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) | |
71 | level = (read_val[0] << 8 | read_val[1]); | |
72 | ||
73 | return level; | |
74 | } | |
75 | ||
76 | /* | |
77 | * Sends the current backlight level over the aux channel, checking if its using | |
78 | * 8-bit or 16 bit value (MSB and LSB) | |
79 | */ | |
80 | static void | |
7d025e08 | 81 | intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 level) |
e7156c83 | 82 | { |
7d025e08 | 83 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
e7156c83 YA |
84 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); |
85 | uint8_t vals[2] = { 0x0 }; | |
86 | ||
87 | vals[0] = level; | |
88 | ||
89 | /* Write the MSB and/or LSB */ | |
90 | if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) { | |
91 | vals[0] = (level & 0xFF00) >> 8; | |
92 | vals[1] = (level & 0xFF); | |
93 | } | |
94 | if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, | |
95 | vals, sizeof(vals)) < 0) { | |
96 | DRM_DEBUG_KMS("Failed to write aux backlight level\n"); | |
97 | return; | |
98 | } | |
99 | } | |
100 | ||
c03e53b0 PV |
101 | /* |
102 | * Set PWM Frequency divider to match desired frequency in vbt. | |
103 | * The PWM Frequency is calculated as 27Mhz / (F x P). | |
104 | * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the | |
105 | * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h) | |
106 | * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the | |
107 | * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h) | |
108 | */ | |
109 | static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector) | |
110 | { | |
111 | struct drm_i915_private *dev_priv = to_i915(connector->base.dev); | |
112 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); | |
113 | int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1; | |
114 | u8 pn, pn_min, pn_max; | |
115 | ||
116 | /* Find desired value of (F x P) | |
117 | * Note that, if F x P is out of supported range, the maximum value or | |
118 | * minimum value will applied automatically. So no need to check that. | |
119 | */ | |
120 | freq = dev_priv->vbt.backlight.pwm_freq_hz; | |
121 | DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq); | |
122 | if (!freq) { | |
123 | DRM_DEBUG_KMS("Use panel default backlight frequency\n"); | |
124 | return false; | |
125 | } | |
126 | ||
127 | fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq); | |
128 | ||
129 | /* Use highest possible value of Pn for more granularity of brightness | |
130 | * adjustment while satifying the conditions below. | |
131 | * - Pn is in the range of Pn_min and Pn_max | |
132 | * - F is in the range of 1 and 255 | |
133 | * - FxP is within 25% of desired value. | |
134 | * Note: 25% is arbitrary value and may need some tweak. | |
135 | */ | |
136 | if (drm_dp_dpcd_readb(&intel_dp->aux, | |
137 | DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) { | |
138 | DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n"); | |
139 | return false; | |
140 | } | |
141 | if (drm_dp_dpcd_readb(&intel_dp->aux, | |
142 | DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) { | |
143 | DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n"); | |
144 | return false; | |
145 | } | |
146 | pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK; | |
147 | pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK; | |
148 | ||
149 | fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4); | |
150 | fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4); | |
151 | if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) { | |
152 | DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n"); | |
153 | return false; | |
154 | } | |
155 | ||
156 | for (pn = pn_max; pn >= pn_min; pn--) { | |
157 | f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255); | |
158 | fxp_actual = f << pn; | |
159 | if (fxp_min <= fxp_actual && fxp_actual <= fxp_max) | |
160 | break; | |
161 | } | |
162 | ||
163 | if (drm_dp_dpcd_writeb(&intel_dp->aux, | |
164 | DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) { | |
165 | DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n"); | |
166 | return false; | |
167 | } | |
168 | if (drm_dp_dpcd_writeb(&intel_dp->aux, | |
169 | DP_EDP_BACKLIGHT_FREQ_SET, (u8) f) < 0) { | |
170 | DRM_DEBUG_KMS("Failed to write aux backlight freq\n"); | |
171 | return false; | |
172 | } | |
173 | return true; | |
174 | } | |
175 | ||
7d025e08 ML |
176 | static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_state, |
177 | const struct drm_connector_state *conn_state) | |
e7156c83 | 178 | { |
7d025e08 | 179 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
e7156c83 | 180 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); |
c03e53b0 | 181 | uint8_t dpcd_buf, new_dpcd_buf, edp_backlight_mode; |
e7156c83 | 182 | |
73ab484c PV |
183 | if (drm_dp_dpcd_readb(&intel_dp->aux, |
184 | DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) { | |
185 | DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n", | |
186 | DP_EDP_BACKLIGHT_MODE_SET_REGISTER); | |
187 | return; | |
188 | } | |
189 | ||
c03e53b0 | 190 | new_dpcd_buf = dpcd_buf; |
73ab484c PV |
191 | edp_backlight_mode = dpcd_buf & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK; |
192 | ||
193 | switch (edp_backlight_mode) { | |
194 | case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM: | |
195 | case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET: | |
196 | case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT: | |
c03e53b0 PV |
197 | new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK; |
198 | new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; | |
73ab484c PV |
199 | break; |
200 | ||
201 | /* Do nothing when it is already DPCD mode */ | |
202 | case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD: | |
203 | default: | |
204 | break; | |
205 | } | |
e9c9e5ae | 206 | |
c03e53b0 PV |
207 | if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP) |
208 | if (intel_dp_aux_set_pwm_freq(connector)) | |
209 | new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; | |
210 | ||
211 | if (new_dpcd_buf != dpcd_buf) { | |
212 | if (drm_dp_dpcd_writeb(&intel_dp->aux, | |
213 | DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf) < 0) { | |
214 | DRM_DEBUG_KMS("Failed to write aux backlight mode\n"); | |
215 | } | |
216 | } | |
217 | ||
e9c9e5ae | 218 | set_aux_backlight_enable(intel_dp, true); |
7d025e08 | 219 | intel_dp_aux_set_backlight(conn_state, connector->panel.backlight.level); |
e7156c83 YA |
220 | } |
221 | ||
7d025e08 | 222 | static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state) |
e7156c83 | 223 | { |
7d025e08 | 224 | set_aux_backlight_enable(enc_to_intel_dp(old_conn_state->best_encoder), false); |
e7156c83 YA |
225 | } |
226 | ||
227 | static int intel_dp_aux_setup_backlight(struct intel_connector *connector, | |
228 | enum pipe pipe) | |
229 | { | |
230 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); | |
231 | struct intel_panel *panel = &connector->panel; | |
232 | ||
e7156c83 YA |
233 | if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) |
234 | panel->backlight.max = 0xFFFF; | |
235 | else | |
236 | panel->backlight.max = 0xFF; | |
237 | ||
238 | panel->backlight.min = 0; | |
239 | panel->backlight.level = intel_dp_aux_get_backlight(connector); | |
240 | ||
241 | panel->backlight.enabled = panel->backlight.level != 0; | |
242 | ||
243 | return 0; | |
244 | } | |
245 | ||
246 | static bool | |
247 | intel_dp_aux_display_control_capable(struct intel_connector *connector) | |
248 | { | |
249 | struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); | |
250 | ||
7d025e08 | 251 | /* Check the eDP Display control capabilities registers to determine if |
e7156c83 YA |
252 | * the panel can support backlight control over the aux channel |
253 | */ | |
d2939424 JN |
254 | if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP && |
255 | (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) && | |
256 | !(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) { | |
e7156c83 YA |
257 | DRM_DEBUG_KMS("AUX Backlight Control Supported!\n"); |
258 | return true; | |
259 | } | |
260 | return false; | |
261 | } | |
262 | ||
263 | int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector) | |
264 | { | |
265 | struct intel_panel *panel = &intel_connector->panel; | |
266 | ||
267 | if (!i915.enable_dpcd_backlight) | |
268 | return -ENODEV; | |
269 | ||
270 | if (!intel_dp_aux_display_control_capable(intel_connector)) | |
271 | return -ENODEV; | |
272 | ||
273 | panel->backlight.setup = intel_dp_aux_setup_backlight; | |
274 | panel->backlight.enable = intel_dp_aux_enable_backlight; | |
275 | panel->backlight.disable = intel_dp_aux_disable_backlight; | |
276 | panel->backlight.set = intel_dp_aux_set_backlight; | |
277 | panel->backlight.get = intel_dp_aux_get_backlight; | |
278 | ||
279 | return 0; | |
280 | } |