1 /* 2 * Copyright © 2016 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <linux/delay.h> 24 #include <linux/errno.h> 25 #include <linux/export.h> 26 #include <linux/i2c.h> 27 #include <linux/slab.h> 28 #include <linux/string.h> 29 30 #include <drm/display/drm_dp_dual_mode_helper.h> 31 #include <drm/drm_device.h> 32 #include <drm/drm_print.h> 33 34 /** 35 * DOC: dp dual mode helpers 36 * 37 * Helper functions to deal with DP dual mode (aka. DP++) adaptors. 38 * 39 * Type 1: 40 * Adaptor registers (if any) and the sink DDC bus may be accessed via I2C. 41 * 42 * Type 2: 43 * Adaptor registers and sink DDC bus can be accessed either via I2C or 44 * I2C-over-AUX. Source devices may choose to implement either of these 45 * access methods. 46 */ 47 48 #define DP_DUAL_MODE_SLAVE_ADDRESS 0x40 49 50 /** 51 * drm_dp_dual_mode_read - Read from the DP dual mode adaptor register(s) 52 * @adapter: I2C adapter for the DDC bus 53 * @offset: register offset 54 * @buffer: buffer for return data 55 * @size: sizo of the buffer 56 * 57 * Reads @size bytes from the DP dual mode adaptor registers 58 * starting at @offset. 59 * 60 * Returns: 61 * 0 on success, negative error code on failure 62 */ 63 ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter, 64 u8 offset, void *buffer, size_t size) 65 { 66 struct i2c_msg msgs[] = { 67 { 68 .addr = DP_DUAL_MODE_SLAVE_ADDRESS, 69 .flags = 0, 70 .len = 1, 71 .buf = &offset, 72 }, 73 { 74 .addr = DP_DUAL_MODE_SLAVE_ADDRESS, 75 .flags = I2C_M_RD, 76 .len = size, 77 .buf = buffer, 78 }, 79 }; 80 int ret; 81 82 ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); 83 if (ret < 0) 84 return ret; 85 if (ret != ARRAY_SIZE(msgs)) 86 return -EPROTO; 87 88 return 0; 89 } 90 EXPORT_SYMBOL(drm_dp_dual_mode_read); 91 92 /** 93 * drm_dp_dual_mode_write - Write to the DP dual mode adaptor register(s) 94 * @adapter: I2C adapter for the DDC bus 95 * @offset: register offset 96 * @buffer: buffer for write data 97 * @size: sizo of the buffer 98 * 99 * Writes @size bytes to the DP dual mode adaptor registers 100 * starting at @offset. 101 * 102 * Returns: 103 * 0 on success, negative error code on failure 104 */ 105 ssize_t drm_dp_dual_mode_write(struct i2c_adapter *adapter, 106 u8 offset, const void *buffer, size_t size) 107 { 108 struct i2c_msg msg = { 109 .addr = DP_DUAL_MODE_SLAVE_ADDRESS, 110 .flags = 0, 111 .len = 1 + size, 112 .buf = NULL, 113 }; 114 void *data; 115 int ret; 116 117 data = kmalloc(msg.len, GFP_KERNEL); 118 if (!data) 119 return -ENOMEM; 120 121 msg.buf = data; 122 123 memcpy(data, &offset, 1); 124 memcpy(data + 1, buffer, size); 125 126 ret = i2c_transfer(adapter, &msg, 1); 127 128 kfree(data); 129 130 if (ret < 0) 131 return ret; 132 if (ret != 1) 133 return -EPROTO; 134 135 return 0; 136 } 137 EXPORT_SYMBOL(drm_dp_dual_mode_write); 138 139 static bool is_hdmi_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN]) 140 { 141 static const char dp_dual_mode_hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] = 142 "DP-HDMI ADAPTOR\x04"; 143 144 return memcmp(hdmi_id, dp_dual_mode_hdmi_id, 145 sizeof(dp_dual_mode_hdmi_id)) == 0; 146 } 147 148 static bool is_type1_adaptor(uint8_t adaptor_id) 149 { 150 return adaptor_id == 0 || adaptor_id == 0xff; 151 } 152 153 static bool is_type2_adaptor(uint8_t adaptor_id) 154 { 155 return adaptor_id == (DP_DUAL_MODE_TYPE_TYPE2 | 156 DP_DUAL_MODE_REV_TYPE2); 157 } 158 159 static bool is_lspcon_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN], 160 const uint8_t adaptor_id) 161 { 162 return is_hdmi_adaptor(hdmi_id) && 163 (adaptor_id == (DP_DUAL_MODE_TYPE_TYPE2 | 164 DP_DUAL_MODE_TYPE_HAS_DPCD)); 165 } 166 167 /** 168 * drm_dp_dual_mode_detect - Identify the DP dual mode adaptor 169 * @dev: &drm_device to use 170 * @adapter: I2C adapter for the DDC bus 171 * 172 * Attempt to identify the type of the DP dual mode adaptor used. 173 * 174 * Note that when the answer is @DRM_DP_DUAL_MODE_UNKNOWN it's not 175 * certain whether we're dealing with a native HDMI port or 176 * a type 1 DVI dual mode adaptor. The driver will have to use 177 * some other hardware/driver specific mechanism to make that 178 * distinction. 179 * 180 * Returns: 181 * The type of the DP dual mode adaptor used 182 */ 183 enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev, 184 struct i2c_adapter *adapter) 185 { 186 char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN] = {}; 187 uint8_t adaptor_id = 0x00; 188 ssize_t ret; 189 190 /* 191 * Let's see if the adaptor is there the by reading the 192 * HDMI ID registers. 193 * 194 * Note that type 1 DVI adaptors are not required to implemnt 195 * any registers, and that presents a problem for detection. 196 * If the i2c transfer is nacked, we may or may not be dealing 197 * with a type 1 DVI adaptor. Some other mechanism of detecting 198 * the presence of the adaptor is required. One way would be 199 * to check the state of the CONFIG1 pin, Another method would 200 * simply require the driver to know whether the port is a DP++ 201 * port or a native HDMI port. Both of these methods are entirely 202 * hardware/driver specific so we can't deal with them here. 203 */ 204 ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_HDMI_ID, 205 hdmi_id, sizeof(hdmi_id)); 206 drm_dbg_kms(dev, "DP dual mode HDMI ID: %*pE (err %zd)\n", 207 ret ? 0 : (int)sizeof(hdmi_id), hdmi_id, ret); 208 if (ret) 209 return DRM_DP_DUAL_MODE_UNKNOWN; 210 211 /* 212 * Sigh. Some (maybe all?) type 1 adaptors are broken and ack 213 * the offset but ignore it, and instead they just always return 214 * data from the start of the HDMI ID buffer. So for a broken 215 * type 1 HDMI adaptor a single byte read will always give us 216 * 0x44, and for a type 1 DVI adaptor it should give 0x00 217 * (assuming it implements any registers). Fortunately neither 218 * of those values will match the type 2 signature of the 219 * DP_DUAL_MODE_ADAPTOR_ID register so we can proceed with 220 * the type 2 adaptor detection safely even in the presence 221 * of broken type 1 adaptors. 222 */ 223 ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID, 224 &adaptor_id, sizeof(adaptor_id)); 225 drm_dbg_kms(dev, "DP dual mode adaptor ID: %02x (err %zd)\n", adaptor_id, ret); 226 if (ret == 0) { 227 if (is_lspcon_adaptor(hdmi_id, adaptor_id)) 228 return DRM_DP_DUAL_MODE_LSPCON; 229 if (is_type2_adaptor(adaptor_id)) { 230 if (is_hdmi_adaptor(hdmi_id)) 231 return DRM_DP_DUAL_MODE_TYPE2_HDMI; 232 else 233 return DRM_DP_DUAL_MODE_TYPE2_DVI; 234 } 235 /* 236 * If neither a proper type 1 ID nor a broken type 1 adaptor 237 * as described above, assume type 1, but let the user know 238 * that we may have misdetected the type. 239 */ 240 if (!is_type1_adaptor(adaptor_id) && adaptor_id != hdmi_id[0]) 241 drm_err(dev, "Unexpected DP dual mode adaptor ID %02x\n", adaptor_id); 242 243 } 244 245 if (is_hdmi_adaptor(hdmi_id)) 246 return DRM_DP_DUAL_MODE_TYPE1_HDMI; 247 else 248 return DRM_DP_DUAL_MODE_TYPE1_DVI; 249 } 250 EXPORT_SYMBOL(drm_dp_dual_mode_detect); 251 252 /** 253 * drm_dp_dual_mode_max_tmds_clock - Max TMDS clock for DP dual mode adaptor 254 * @dev: &drm_device to use 255 * @type: DP dual mode adaptor type 256 * @adapter: I2C adapter for the DDC bus 257 * 258 * Determine the max TMDS clock the adaptor supports based on the 259 * type of the dual mode adaptor and the DP_DUAL_MODE_MAX_TMDS_CLOCK 260 * register (on type2 adaptors). As some type 1 adaptors have 261 * problems with registers (see comments in drm_dp_dual_mode_detect()) 262 * we don't read the register on those, instead we simply assume 263 * a 165 MHz limit based on the specification. 264 * 265 * Returns: 266 * Maximum supported TMDS clock rate for the DP dual mode adaptor in kHz. 267 */ 268 int drm_dp_dual_mode_max_tmds_clock(const struct drm_device *dev, enum drm_dp_dual_mode_type type, 269 struct i2c_adapter *adapter) 270 { 271 uint8_t max_tmds_clock; 272 ssize_t ret; 273 274 /* native HDMI so no limit */ 275 if (type == DRM_DP_DUAL_MODE_NONE) 276 return 0; 277 278 /* 279 * Type 1 adaptors are limited to 165MHz 280 * Type 2 adaptors can tells us their limit 281 */ 282 if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) 283 return 165000; 284 285 ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_MAX_TMDS_CLOCK, 286 &max_tmds_clock, sizeof(max_tmds_clock)); 287 if (ret || max_tmds_clock == 0x00 || max_tmds_clock == 0xff) { 288 drm_dbg_kms(dev, "Failed to query max TMDS clock\n"); 289 return 165000; 290 } 291 292 return max_tmds_clock * 5000 / 2; 293 } 294 EXPORT_SYMBOL(drm_dp_dual_mode_max_tmds_clock); 295 296 /** 297 * drm_dp_dual_mode_get_tmds_output - Get the state of the TMDS output buffers in the DP dual mode adaptor 298 * @dev: &drm_device to use 299 * @type: DP dual mode adaptor type 300 * @adapter: I2C adapter for the DDC bus 301 * @enabled: current state of the TMDS output buffers 302 * 303 * Get the state of the TMDS output buffers in the adaptor. For 304 * type2 adaptors this is queried from the DP_DUAL_MODE_TMDS_OEN 305 * register. As some type 1 adaptors have problems with registers 306 * (see comments in drm_dp_dual_mode_detect()) we don't read the 307 * register on those, instead we simply assume that the buffers 308 * are always enabled. 309 * 310 * Returns: 311 * 0 on success, negative error code on failure 312 */ 313 int drm_dp_dual_mode_get_tmds_output(const struct drm_device *dev, 314 enum drm_dp_dual_mode_type type, struct i2c_adapter *adapter, 315 bool *enabled) 316 { 317 uint8_t tmds_oen; 318 ssize_t ret; 319 320 if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) { 321 *enabled = true; 322 return 0; 323 } 324 325 ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, 326 &tmds_oen, sizeof(tmds_oen)); 327 if (ret) { 328 drm_dbg_kms(dev, "Failed to query state of TMDS output buffers\n"); 329 return ret; 330 } 331 332 *enabled = !(tmds_oen & DP_DUAL_MODE_TMDS_DISABLE); 333 334 return 0; 335 } 336 EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output); 337 338 /** 339 * drm_dp_dual_mode_set_tmds_output - Enable/disable TMDS output buffers in the DP dual mode adaptor 340 * @dev: &drm_device to use 341 * @type: DP dual mode adaptor type 342 * @adapter: I2C adapter for the DDC bus 343 * @enable: enable (as opposed to disable) the TMDS output buffers 344 * 345 * Set the state of the TMDS output buffers in the adaptor. For 346 * type2 this is set via the DP_DUAL_MODE_TMDS_OEN register. As 347 * some type 1 adaptors have problems with registers (see comments 348 * in drm_dp_dual_mode_detect()) we avoid touching the register, 349 * making this function a no-op on type 1 adaptors. 350 * 351 * Returns: 352 * 0 on success, negative error code on failure 353 */ 354 int drm_dp_dual_mode_set_tmds_output(const struct drm_device *dev, enum drm_dp_dual_mode_type type, 355 struct i2c_adapter *adapter, bool enable) 356 { 357 uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE; 358 ssize_t ret; 359 int retry; 360 361 if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) 362 return 0; 363 364 /* 365 * LSPCON adapters in low-power state may ignore the first write, so 366 * read back and verify the written value a few times. 367 */ 368 for (retry = 0; retry < 3; retry++) { 369 uint8_t tmp; 370 371 ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, 372 &tmds_oen, sizeof(tmds_oen)); 373 if (ret) { 374 drm_dbg_kms(dev, "Failed to %s TMDS output buffers (%d attempts)\n", 375 enable ? "enable" : "disable", retry + 1); 376 return ret; 377 } 378 379 ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, 380 &tmp, sizeof(tmp)); 381 if (ret) { 382 drm_dbg_kms(dev, 383 "I2C read failed during TMDS output buffer %s (%d attempts)\n", 384 enable ? "enabling" : "disabling", retry + 1); 385 return ret; 386 } 387 388 if (tmp == tmds_oen) 389 return 0; 390 } 391 392 drm_dbg_kms(dev, "I2C write value mismatch during TMDS output buffer %s\n", 393 enable ? "enabling" : "disabling"); 394 395 return -EIO; 396 } 397 EXPORT_SYMBOL(drm_dp_dual_mode_set_tmds_output); 398 399 /** 400 * drm_dp_get_dual_mode_type_name - Get the name of the DP dual mode adaptor type as a string 401 * @type: DP dual mode adaptor type 402 * 403 * Returns: 404 * String representation of the DP dual mode adaptor type 405 */ 406 const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type) 407 { 408 switch (type) { 409 case DRM_DP_DUAL_MODE_NONE: 410 return "none"; 411 case DRM_DP_DUAL_MODE_TYPE1_DVI: 412 return "type 1 DVI"; 413 case DRM_DP_DUAL_MODE_TYPE1_HDMI: 414 return "type 1 HDMI"; 415 case DRM_DP_DUAL_MODE_TYPE2_DVI: 416 return "type 2 DVI"; 417 case DRM_DP_DUAL_MODE_TYPE2_HDMI: 418 return "type 2 HDMI"; 419 case DRM_DP_DUAL_MODE_LSPCON: 420 return "lspcon"; 421 default: 422 WARN_ON(type != DRM_DP_DUAL_MODE_UNKNOWN); 423 return "unknown"; 424 } 425 } 426 EXPORT_SYMBOL(drm_dp_get_dual_mode_type_name); 427 428 /** 429 * drm_lspcon_get_mode: Get LSPCON's current mode of operation by 430 * reading offset (0x80, 0x41) 431 * @dev: &drm_device to use 432 * @adapter: I2C-over-aux adapter 433 * @mode: current lspcon mode of operation output variable 434 * 435 * Returns: 436 * 0 on success, sets the current_mode value to appropriate mode 437 * -error on failure 438 */ 439 int drm_lspcon_get_mode(const struct drm_device *dev, struct i2c_adapter *adapter, 440 enum drm_lspcon_mode *mode) 441 { 442 u8 data; 443 int ret = 0; 444 int retry; 445 446 if (!mode) { 447 drm_err(dev, "NULL input\n"); 448 return -EINVAL; 449 } 450 451 /* Read Status: i2c over aux */ 452 for (retry = 0; retry < 6; retry++) { 453 if (retry) 454 usleep_range(500, 1000); 455 456 ret = drm_dp_dual_mode_read(adapter, 457 DP_DUAL_MODE_LSPCON_CURRENT_MODE, 458 &data, sizeof(data)); 459 if (!ret) 460 break; 461 } 462 463 if (ret < 0) { 464 drm_dbg_kms(dev, "LSPCON read(0x80, 0x41) failed\n"); 465 return -EFAULT; 466 } 467 468 if (data & DP_DUAL_MODE_LSPCON_MODE_PCON) 469 *mode = DRM_LSPCON_MODE_PCON; 470 else 471 *mode = DRM_LSPCON_MODE_LS; 472 return 0; 473 } 474 EXPORT_SYMBOL(drm_lspcon_get_mode); 475 476 /** 477 * drm_lspcon_set_mode: Change LSPCON's mode of operation by 478 * writing offset (0x80, 0x40) 479 * @dev: &drm_device to use 480 * @adapter: I2C-over-aux adapter 481 * @mode: required mode of operation 482 * 483 * Returns: 484 * 0 on success, -error on failure/timeout 485 */ 486 int drm_lspcon_set_mode(const struct drm_device *dev, struct i2c_adapter *adapter, 487 enum drm_lspcon_mode mode) 488 { 489 u8 data = 0; 490 int ret; 491 int time_out = 200; 492 enum drm_lspcon_mode current_mode; 493 494 if (mode == DRM_LSPCON_MODE_PCON) 495 data = DP_DUAL_MODE_LSPCON_MODE_PCON; 496 497 /* Change mode */ 498 ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_LSPCON_MODE_CHANGE, 499 &data, sizeof(data)); 500 if (ret < 0) { 501 drm_err(dev, "LSPCON mode change failed\n"); 502 return ret; 503 } 504 505 /* 506 * Confirm mode change by reading the status bit. 507 * Sometimes, it takes a while to change the mode, 508 * so wait and retry until time out or done. 509 */ 510 do { 511 ret = drm_lspcon_get_mode(dev, adapter, ¤t_mode); 512 if (ret) { 513 drm_err(dev, "can't confirm LSPCON mode change\n"); 514 return ret; 515 } else { 516 if (current_mode != mode) { 517 msleep(10); 518 time_out -= 10; 519 } else { 520 drm_dbg_kms(dev, "LSPCON mode changed to %s\n", 521 mode == DRM_LSPCON_MODE_LS ? "LS" : "PCON"); 522 return 0; 523 } 524 } 525 } while (time_out); 526 527 drm_err(dev, "LSPCON mode change timed out\n"); 528 return -ETIMEDOUT; 529 } 530 EXPORT_SYMBOL(drm_lspcon_set_mode); 531