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