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_display_types.h" 26 #include "intel_dp_aux_backlight.h" 27 28 static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) 29 { 30 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 31 u8 reg_val = 0; 32 33 /* Early return when display use other mechanism to enable backlight. */ 34 if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP)) 35 return; 36 37 if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER, 38 ®_val) < 0) { 39 drm_dbg_kms(&i915->drm, "Failed to read DPCD register 0x%x\n", 40 DP_EDP_DISPLAY_CONTROL_REGISTER); 41 return; 42 } 43 if (enable) 44 reg_val |= DP_EDP_BACKLIGHT_ENABLE; 45 else 46 reg_val &= ~(DP_EDP_BACKLIGHT_ENABLE); 47 48 if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_DISPLAY_CONTROL_REGISTER, 49 reg_val) != 1) { 50 drm_dbg_kms(&i915->drm, "Failed to %s aux backlight\n", 51 enable ? "enable" : "disable"); 52 } 53 } 54 55 static bool intel_dp_aux_backlight_dpcd_mode(struct intel_connector *connector) 56 { 57 struct intel_dp *intel_dp = intel_attached_dp(connector); 58 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 59 u8 mode_reg; 60 61 if (drm_dp_dpcd_readb(&intel_dp->aux, 62 DP_EDP_BACKLIGHT_MODE_SET_REGISTER, 63 &mode_reg) != 1) { 64 drm_dbg_kms(&i915->drm, 65 "Failed to read the DPCD register 0x%x\n", 66 DP_EDP_BACKLIGHT_MODE_SET_REGISTER); 67 return false; 68 } 69 70 return (mode_reg & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK) == 71 DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; 72 } 73 74 /* 75 * Read the current backlight value from DPCD register(s) based 76 * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported 77 */ 78 static u32 intel_dp_aux_get_backlight(struct intel_connector *connector) 79 { 80 struct intel_dp *intel_dp = intel_attached_dp(connector); 81 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 82 u8 read_val[2] = { 0x0 }; 83 u16 level = 0; 84 85 /* 86 * If we're not in DPCD control mode yet, the programmed brightness 87 * value is meaningless and we should assume max brightness 88 */ 89 if (!intel_dp_aux_backlight_dpcd_mode(connector)) 90 return connector->panel.backlight.max; 91 92 if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, 93 &read_val, sizeof(read_val)) < 0) { 94 drm_dbg_kms(&i915->drm, "Failed to read DPCD register 0x%x\n", 95 DP_EDP_BACKLIGHT_BRIGHTNESS_MSB); 96 return 0; 97 } 98 level = read_val[0]; 99 if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) 100 level = (read_val[0] << 8 | read_val[1]); 101 102 return level; 103 } 104 105 /* 106 * Sends the current backlight level over the aux channel, checking if its using 107 * 8-bit or 16 bit value (MSB and LSB) 108 */ 109 static void 110 intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 level) 111 { 112 struct intel_connector *connector = to_intel_connector(conn_state->connector); 113 struct intel_dp *intel_dp = intel_attached_dp(connector); 114 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 115 u8 vals[2] = { 0x0 }; 116 117 vals[0] = level; 118 119 /* Write the MSB and/or LSB */ 120 if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) { 121 vals[0] = (level & 0xFF00) >> 8; 122 vals[1] = (level & 0xFF); 123 } 124 if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, 125 vals, sizeof(vals)) < 0) { 126 drm_dbg_kms(&i915->drm, 127 "Failed to write aux backlight level\n"); 128 return; 129 } 130 } 131 132 /* 133 * Set PWM Frequency divider to match desired frequency in vbt. 134 * The PWM Frequency is calculated as 27Mhz / (F x P). 135 * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the 136 * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h) 137 * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the 138 * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h) 139 */ 140 static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector) 141 { 142 struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 143 struct intel_dp *intel_dp = intel_attached_dp(connector); 144 const u8 pn = connector->panel.backlight.pwmgen_bit_count; 145 int freq, fxp, f, fxp_actual, fxp_min, fxp_max; 146 147 freq = dev_priv->vbt.backlight.pwm_freq_hz; 148 if (!freq) { 149 drm_dbg_kms(&dev_priv->drm, 150 "Use panel default backlight frequency\n"); 151 return false; 152 } 153 154 fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq); 155 f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255); 156 fxp_actual = f << pn; 157 158 /* Ensure frequency is within 25% of desired value */ 159 fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4); 160 fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4); 161 162 if (fxp_min > fxp_actual || fxp_actual > fxp_max) { 163 drm_dbg_kms(&dev_priv->drm, "Actual frequency out of range\n"); 164 return false; 165 } 166 167 if (drm_dp_dpcd_writeb(&intel_dp->aux, 168 DP_EDP_BACKLIGHT_FREQ_SET, (u8) f) < 0) { 169 drm_dbg_kms(&dev_priv->drm, 170 "Failed to write aux backlight freq\n"); 171 return false; 172 } 173 return true; 174 } 175 176 static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_state, 177 const struct drm_connector_state *conn_state) 178 { 179 struct intel_connector *connector = to_intel_connector(conn_state->connector); 180 struct intel_dp *intel_dp = intel_attached_dp(connector); 181 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 182 struct intel_panel *panel = &connector->panel; 183 u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode; 184 185 if (drm_dp_dpcd_readb(&intel_dp->aux, 186 DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) { 187 drm_dbg_kms(&i915->drm, "Failed to read DPCD register 0x%x\n", 188 DP_EDP_BACKLIGHT_MODE_SET_REGISTER); 189 return; 190 } 191 192 new_dpcd_buf = dpcd_buf; 193 edp_backlight_mode = dpcd_buf & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK; 194 195 switch (edp_backlight_mode) { 196 case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM: 197 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET: 198 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT: 199 new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK; 200 new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; 201 202 if (drm_dp_dpcd_writeb(&intel_dp->aux, 203 DP_EDP_PWMGEN_BIT_COUNT, 204 panel->backlight.pwmgen_bit_count) < 0) 205 drm_dbg_kms(&i915->drm, 206 "Failed to write aux pwmgen bit count\n"); 207 208 break; 209 210 /* Do nothing when it is already DPCD mode */ 211 case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD: 212 default: 213 break; 214 } 215 216 if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP) 217 if (intel_dp_aux_set_pwm_freq(connector)) 218 new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; 219 220 if (new_dpcd_buf != dpcd_buf) { 221 if (drm_dp_dpcd_writeb(&intel_dp->aux, 222 DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf) < 0) { 223 drm_dbg_kms(&i915->drm, 224 "Failed to write aux backlight mode\n"); 225 } 226 } 227 228 intel_dp_aux_set_backlight(conn_state, 229 connector->panel.backlight.level); 230 set_aux_backlight_enable(intel_dp, true); 231 } 232 233 static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state) 234 { 235 set_aux_backlight_enable(enc_to_intel_dp(to_intel_encoder(old_conn_state->best_encoder)), 236 false); 237 } 238 239 static u32 intel_dp_aux_calc_max_backlight(struct intel_connector *connector) 240 { 241 struct drm_i915_private *i915 = to_i915(connector->base.dev); 242 struct intel_dp *intel_dp = intel_attached_dp(connector); 243 struct intel_panel *panel = &connector->panel; 244 u32 max_backlight = 0; 245 int freq, fxp, fxp_min, fxp_max, fxp_actual, f = 1; 246 u8 pn, pn_min, pn_max; 247 248 if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT, &pn) == 1) { 249 pn &= DP_EDP_PWMGEN_BIT_COUNT_MASK; 250 max_backlight = (1 << pn) - 1; 251 } 252 253 /* Find desired value of (F x P) 254 * Note that, if F x P is out of supported range, the maximum value or 255 * minimum value will applied automatically. So no need to check that. 256 */ 257 freq = i915->vbt.backlight.pwm_freq_hz; 258 drm_dbg_kms(&i915->drm, "VBT defined backlight frequency %u Hz\n", 259 freq); 260 if (!freq) { 261 drm_dbg_kms(&i915->drm, 262 "Use panel default backlight frequency\n"); 263 return max_backlight; 264 } 265 266 fxp = DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ), freq); 267 268 /* Use highest possible value of Pn for more granularity of brightness 269 * adjustment while satifying the conditions below. 270 * - Pn is in the range of Pn_min and Pn_max 271 * - F is in the range of 1 and 255 272 * - FxP is within 25% of desired value. 273 * Note: 25% is arbitrary value and may need some tweak. 274 */ 275 if (drm_dp_dpcd_readb(&intel_dp->aux, 276 DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &pn_min) != 1) { 277 drm_dbg_kms(&i915->drm, 278 "Failed to read pwmgen bit count cap min\n"); 279 return max_backlight; 280 } 281 if (drm_dp_dpcd_readb(&intel_dp->aux, 282 DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX, &pn_max) != 1) { 283 drm_dbg_kms(&i915->drm, 284 "Failed to read pwmgen bit count cap max\n"); 285 return max_backlight; 286 } 287 pn_min &= DP_EDP_PWMGEN_BIT_COUNT_MASK; 288 pn_max &= DP_EDP_PWMGEN_BIT_COUNT_MASK; 289 290 fxp_min = DIV_ROUND_CLOSEST(fxp * 3, 4); 291 fxp_max = DIV_ROUND_CLOSEST(fxp * 5, 4); 292 if (fxp_min < (1 << pn_min) || (255 << pn_max) < fxp_max) { 293 drm_dbg_kms(&i915->drm, 294 "VBT defined backlight frequency out of range\n"); 295 return max_backlight; 296 } 297 298 for (pn = pn_max; pn >= pn_min; pn--) { 299 f = clamp(DIV_ROUND_CLOSEST(fxp, 1 << pn), 1, 255); 300 fxp_actual = f << pn; 301 if (fxp_min <= fxp_actual && fxp_actual <= fxp_max) 302 break; 303 } 304 305 drm_dbg_kms(&i915->drm, "Using eDP pwmgen bit count of %d\n", pn); 306 if (drm_dp_dpcd_writeb(&intel_dp->aux, 307 DP_EDP_PWMGEN_BIT_COUNT, pn) < 0) { 308 drm_dbg_kms(&i915->drm, 309 "Failed to write aux pwmgen bit count\n"); 310 return max_backlight; 311 } 312 panel->backlight.pwmgen_bit_count = pn; 313 314 max_backlight = (1 << pn) - 1; 315 316 return max_backlight; 317 } 318 319 static int intel_dp_aux_setup_backlight(struct intel_connector *connector, 320 enum pipe pipe) 321 { 322 struct intel_panel *panel = &connector->panel; 323 324 panel->backlight.max = intel_dp_aux_calc_max_backlight(connector); 325 if (!panel->backlight.max) 326 return -ENODEV; 327 328 panel->backlight.min = 0; 329 panel->backlight.level = intel_dp_aux_get_backlight(connector); 330 panel->backlight.enabled = intel_dp_aux_backlight_dpcd_mode(connector) && 331 panel->backlight.level != 0; 332 333 return 0; 334 } 335 336 static bool 337 intel_dp_aux_display_control_capable(struct intel_connector *connector) 338 { 339 struct intel_dp *intel_dp = intel_attached_dp(connector); 340 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 341 342 /* Check the eDP Display control capabilities registers to determine if 343 * the panel can support backlight control over the aux channel 344 */ 345 if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP && 346 (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) { 347 drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n"); 348 return true; 349 } 350 return false; 351 } 352 353 int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector) 354 { 355 struct intel_panel *panel = &intel_connector->panel; 356 struct intel_dp *intel_dp = enc_to_intel_dp(intel_connector->encoder); 357 struct drm_i915_private *i915 = dp_to_i915(intel_dp); 358 359 if (i915->params.enable_dpcd_backlight == 0 || 360 !intel_dp_aux_display_control_capable(intel_connector)) 361 return -ENODEV; 362 363 /* 364 * There are a lot of machines that don't advertise the backlight 365 * control interface to use properly in their VBIOS, :\ 366 */ 367 if (i915->vbt.backlight.type != 368 INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE && 369 i915->params.enable_dpcd_backlight != 1 && 370 !drm_dp_has_quirk(&intel_dp->desc, intel_dp->edid_quirks, 371 DP_QUIRK_FORCE_DPCD_BACKLIGHT)) { 372 drm_info(&i915->drm, 373 "Panel advertises DPCD backlight support, but " 374 "VBT disagrees. If your backlight controls " 375 "don't work try booting with " 376 "i915.enable_dpcd_backlight=1. If your machine " 377 "needs this, please file a _new_ bug report on " 378 "drm/i915, see " FDO_BUG_URL " for details.\n"); 379 return -ENODEV; 380 } 381 382 panel->backlight.setup = intel_dp_aux_setup_backlight; 383 panel->backlight.enable = intel_dp_aux_enable_backlight; 384 panel->backlight.disable = intel_dp_aux_disable_backlight; 385 panel->backlight.set = intel_dp_aux_set_backlight; 386 panel->backlight.get = intel_dp_aux_get_backlight; 387 388 return 0; 389 } 390