1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * USB Typec-C DisplayPort Alternate Mode driver 4 * 5 * Copyright (C) 2018 Intel Corporation 6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> 7 * 8 * DisplayPort is trademark of VESA (www.vesa.org) 9 */ 10 11 #include <linux/delay.h> 12 #include <linux/mutex.h> 13 #include <linux/module.h> 14 #include <linux/property.h> 15 #include <linux/usb/pd_vdo.h> 16 #include <linux/usb/typec_dp.h> 17 #include <drm/drm_connector.h> 18 #include "displayport.h" 19 20 #define DP_HEADER(_dp, ver, cmd) (VDO((_dp)->alt->svid, 1, ver, cmd) \ 21 | VDO_OPOS(USB_TYPEC_DP_MODE)) 22 23 enum { 24 DP_CONF_USB, 25 DP_CONF_DFP_D, 26 DP_CONF_UFP_D, 27 DP_CONF_DUAL_D, 28 }; 29 30 /* Pin assignments that use USB3.1 Gen2 signaling to carry DP protocol */ 31 #define DP_PIN_ASSIGN_GEN2_BR_MASK (BIT(DP_PIN_ASSIGN_A) | \ 32 BIT(DP_PIN_ASSIGN_B)) 33 34 /* Pin assignments that use DP v1.3 signaling to carry DP protocol */ 35 #define DP_PIN_ASSIGN_DP_BR_MASK (BIT(DP_PIN_ASSIGN_C) | \ 36 BIT(DP_PIN_ASSIGN_D) | \ 37 BIT(DP_PIN_ASSIGN_E) | \ 38 BIT(DP_PIN_ASSIGN_F)) 39 40 /* DP only pin assignments */ 41 #define DP_PIN_ASSIGN_DP_ONLY_MASK (BIT(DP_PIN_ASSIGN_A) | \ 42 BIT(DP_PIN_ASSIGN_C) | \ 43 BIT(DP_PIN_ASSIGN_E)) 44 45 /* Pin assignments where one channel is for USB */ 46 #define DP_PIN_ASSIGN_MULTI_FUNC_MASK (BIT(DP_PIN_ASSIGN_B) | \ 47 BIT(DP_PIN_ASSIGN_D) | \ 48 BIT(DP_PIN_ASSIGN_F)) 49 50 enum dp_state { 51 DP_STATE_IDLE, 52 DP_STATE_ENTER, 53 DP_STATE_UPDATE, 54 DP_STATE_CONFIGURE, 55 DP_STATE_EXIT, 56 }; 57 58 struct dp_altmode { 59 struct typec_displayport_data data; 60 61 enum dp_state state; 62 bool hpd; 63 64 struct mutex lock; /* device lock */ 65 struct work_struct work; 66 struct typec_altmode *alt; 67 const struct typec_altmode *port; 68 struct fwnode_handle *connector_fwnode; 69 }; 70 71 static int dp_altmode_notify(struct dp_altmode *dp) 72 { 73 unsigned long conf; 74 u8 state; 75 76 if (dp->data.conf) { 77 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf)); 78 conf = TYPEC_MODAL_STATE(state); 79 } else { 80 conf = TYPEC_STATE_USB; 81 } 82 83 return typec_altmode_notify(dp->alt, conf, &dp->data); 84 } 85 86 static int dp_altmode_configure(struct dp_altmode *dp, u8 con) 87 { 88 u32 conf = DP_CONF_SIGNALING_DP; /* Only DP signaling supported */ 89 u8 pin_assign = 0; 90 91 switch (con) { 92 case DP_STATUS_CON_DISABLED: 93 return 0; 94 case DP_STATUS_CON_DFP_D: 95 conf |= DP_CONF_UFP_U_AS_DFP_D; 96 pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) & 97 DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo); 98 break; 99 case DP_STATUS_CON_UFP_D: 100 case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */ 101 conf |= DP_CONF_UFP_U_AS_UFP_D; 102 pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) & 103 DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo); 104 break; 105 default: 106 break; 107 } 108 109 /* Determining the initial pin assignment. */ 110 if (!DP_CONF_GET_PIN_ASSIGN(dp->data.conf)) { 111 /* Is USB together with DP preferred */ 112 if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC && 113 pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK) 114 pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK; 115 else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) { 116 pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK; 117 /* Default to pin assign C if available */ 118 if (pin_assign & BIT(DP_PIN_ASSIGN_C)) 119 pin_assign = BIT(DP_PIN_ASSIGN_C); 120 } 121 122 if (!pin_assign) 123 return -EINVAL; 124 125 conf |= DP_CONF_SET_PIN_ASSIGN(pin_assign); 126 } 127 128 dp->data.conf = conf; 129 130 return 0; 131 } 132 133 static int dp_altmode_status_update(struct dp_altmode *dp) 134 { 135 bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf); 136 bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE); 137 u8 con = DP_STATUS_CONNECTION(dp->data.status); 138 int ret = 0; 139 140 if (configured && (dp->data.status & DP_STATUS_SWITCH_TO_USB)) { 141 dp->data.conf = 0; 142 dp->state = DP_STATE_CONFIGURE; 143 } else if (dp->data.status & DP_STATUS_EXIT_DP_MODE) { 144 dp->state = DP_STATE_EXIT; 145 } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) { 146 ret = dp_altmode_configure(dp, con); 147 if (!ret) 148 dp->state = DP_STATE_CONFIGURE; 149 } else { 150 if (dp->hpd != hpd) { 151 drm_connector_oob_hotplug_event(dp->connector_fwnode); 152 dp->hpd = hpd; 153 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); 154 } 155 } 156 157 return ret; 158 } 159 160 static int dp_altmode_configured(struct dp_altmode *dp) 161 { 162 sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration"); 163 sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment"); 164 165 return dp_altmode_notify(dp); 166 } 167 168 static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf) 169 { 170 int svdm_version = typec_altmode_get_svdm_version(dp->alt); 171 u32 header; 172 int ret; 173 174 if (svdm_version < 0) 175 return svdm_version; 176 177 header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE); 178 ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data); 179 if (ret) { 180 dev_err(&dp->alt->dev, 181 "unable to put to connector to safe mode\n"); 182 return ret; 183 } 184 185 ret = typec_altmode_vdm(dp->alt, header, &conf, 2); 186 if (ret) 187 dp_altmode_notify(dp); 188 189 return ret; 190 } 191 192 static void dp_altmode_work(struct work_struct *work) 193 { 194 struct dp_altmode *dp = container_of(work, struct dp_altmode, work); 195 int svdm_version; 196 u32 header; 197 u32 vdo; 198 int ret; 199 200 mutex_lock(&dp->lock); 201 202 switch (dp->state) { 203 case DP_STATE_ENTER: 204 ret = typec_altmode_enter(dp->alt, NULL); 205 if (ret && ret != -EBUSY) 206 dev_err(&dp->alt->dev, "failed to enter mode\n"); 207 break; 208 case DP_STATE_UPDATE: 209 svdm_version = typec_altmode_get_svdm_version(dp->alt); 210 if (svdm_version < 0) 211 break; 212 header = DP_HEADER(dp, svdm_version, DP_CMD_STATUS_UPDATE); 213 vdo = 1; 214 ret = typec_altmode_vdm(dp->alt, header, &vdo, 2); 215 if (ret) 216 dev_err(&dp->alt->dev, 217 "unable to send Status Update command (%d)\n", 218 ret); 219 break; 220 case DP_STATE_CONFIGURE: 221 ret = dp_altmode_configure_vdm(dp, dp->data.conf); 222 if (ret) 223 dev_err(&dp->alt->dev, 224 "unable to send Configure command (%d)\n", ret); 225 break; 226 case DP_STATE_EXIT: 227 if (typec_altmode_exit(dp->alt)) 228 dev_err(&dp->alt->dev, "Exit Mode Failed!\n"); 229 break; 230 default: 231 break; 232 } 233 234 dp->state = DP_STATE_IDLE; 235 236 mutex_unlock(&dp->lock); 237 } 238 239 static void dp_altmode_attention(struct typec_altmode *alt, const u32 vdo) 240 { 241 struct dp_altmode *dp = typec_altmode_get_drvdata(alt); 242 u8 old_state; 243 244 mutex_lock(&dp->lock); 245 246 old_state = dp->state; 247 dp->data.status = vdo; 248 249 if (old_state != DP_STATE_IDLE) 250 dev_warn(&alt->dev, "ATTENTION while processing state %d\n", 251 old_state); 252 253 if (dp_altmode_status_update(dp)) 254 dev_warn(&alt->dev, "%s: status update failed\n", __func__); 255 256 if (dp_altmode_notify(dp)) 257 dev_err(&alt->dev, "%s: notification failed\n", __func__); 258 259 if (old_state == DP_STATE_IDLE && dp->state != DP_STATE_IDLE) 260 schedule_work(&dp->work); 261 262 mutex_unlock(&dp->lock); 263 } 264 265 static int dp_altmode_vdm(struct typec_altmode *alt, 266 const u32 hdr, const u32 *vdo, int count) 267 { 268 struct dp_altmode *dp = typec_altmode_get_drvdata(alt); 269 int cmd_type = PD_VDO_CMDT(hdr); 270 int cmd = PD_VDO_CMD(hdr); 271 int ret = 0; 272 273 mutex_lock(&dp->lock); 274 275 if (dp->state != DP_STATE_IDLE) { 276 ret = -EBUSY; 277 goto err_unlock; 278 } 279 280 switch (cmd_type) { 281 case CMDT_RSP_ACK: 282 switch (cmd) { 283 case CMD_ENTER_MODE: 284 typec_altmode_update_active(alt, true); 285 dp->state = DP_STATE_UPDATE; 286 break; 287 case CMD_EXIT_MODE: 288 typec_altmode_update_active(alt, false); 289 dp->data.status = 0; 290 dp->data.conf = 0; 291 break; 292 case DP_CMD_STATUS_UPDATE: 293 dp->data.status = *vdo; 294 ret = dp_altmode_status_update(dp); 295 break; 296 case DP_CMD_CONFIGURE: 297 ret = dp_altmode_configured(dp); 298 break; 299 default: 300 break; 301 } 302 break; 303 case CMDT_RSP_NAK: 304 switch (cmd) { 305 case DP_CMD_CONFIGURE: 306 dp->data.conf = 0; 307 ret = dp_altmode_configured(dp); 308 break; 309 default: 310 break; 311 } 312 break; 313 default: 314 break; 315 } 316 317 if (dp->state != DP_STATE_IDLE) 318 schedule_work(&dp->work); 319 320 err_unlock: 321 mutex_unlock(&dp->lock); 322 return ret; 323 } 324 325 static int dp_altmode_activate(struct typec_altmode *alt, int activate) 326 { 327 return activate ? typec_altmode_enter(alt, NULL) : 328 typec_altmode_exit(alt); 329 } 330 331 static const struct typec_altmode_ops dp_altmode_ops = { 332 .attention = dp_altmode_attention, 333 .vdm = dp_altmode_vdm, 334 .activate = dp_altmode_activate, 335 }; 336 337 static const char * const configurations[] = { 338 [DP_CONF_USB] = "USB", 339 [DP_CONF_DFP_D] = "source", 340 [DP_CONF_UFP_D] = "sink", 341 }; 342 343 static ssize_t 344 configuration_store(struct device *dev, struct device_attribute *attr, 345 const char *buf, size_t size) 346 { 347 struct dp_altmode *dp = dev_get_drvdata(dev); 348 u32 conf; 349 u32 cap; 350 int con; 351 int ret = 0; 352 353 con = sysfs_match_string(configurations, buf); 354 if (con < 0) 355 return con; 356 357 mutex_lock(&dp->lock); 358 359 if (dp->state != DP_STATE_IDLE) { 360 ret = -EBUSY; 361 goto err_unlock; 362 } 363 364 cap = DP_CAP_CAPABILITY(dp->alt->vdo); 365 366 if ((con == DP_CONF_DFP_D && !(cap & DP_CAP_DFP_D)) || 367 (con == DP_CONF_UFP_D && !(cap & DP_CAP_UFP_D))) { 368 ret = -EINVAL; 369 goto err_unlock; 370 } 371 372 conf = dp->data.conf & ~DP_CONF_DUAL_D; 373 conf |= con; 374 375 if (dp->alt->active) { 376 ret = dp_altmode_configure_vdm(dp, conf); 377 if (ret) 378 goto err_unlock; 379 } 380 381 dp->data.conf = conf; 382 383 err_unlock: 384 mutex_unlock(&dp->lock); 385 386 return ret ? ret : size; 387 } 388 389 static ssize_t configuration_show(struct device *dev, 390 struct device_attribute *attr, char *buf) 391 { 392 struct dp_altmode *dp = dev_get_drvdata(dev); 393 int len; 394 u8 cap; 395 u8 cur; 396 int i; 397 398 mutex_lock(&dp->lock); 399 400 cap = DP_CAP_CAPABILITY(dp->alt->vdo); 401 cur = DP_CONF_CURRENTLY(dp->data.conf); 402 403 len = sprintf(buf, "%s ", cur ? "USB" : "[USB]"); 404 405 for (i = 1; i < ARRAY_SIZE(configurations); i++) { 406 if (i == cur) 407 len += sprintf(buf + len, "[%s] ", configurations[i]); 408 else if ((i == DP_CONF_DFP_D && cap & DP_CAP_DFP_D) || 409 (i == DP_CONF_UFP_D && cap & DP_CAP_UFP_D)) 410 len += sprintf(buf + len, "%s ", configurations[i]); 411 } 412 413 mutex_unlock(&dp->lock); 414 415 buf[len - 1] = '\n'; 416 return len; 417 } 418 static DEVICE_ATTR_RW(configuration); 419 420 static const char * const pin_assignments[] = { 421 [DP_PIN_ASSIGN_A] = "A", 422 [DP_PIN_ASSIGN_B] = "B", 423 [DP_PIN_ASSIGN_C] = "C", 424 [DP_PIN_ASSIGN_D] = "D", 425 [DP_PIN_ASSIGN_E] = "E", 426 [DP_PIN_ASSIGN_F] = "F", 427 }; 428 429 /* 430 * Helper function to extract a peripheral's currently supported 431 * Pin Assignments from its DisplayPort alternate mode state. 432 */ 433 static u8 get_current_pin_assignments(struct dp_altmode *dp) 434 { 435 if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D) 436 return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo); 437 else 438 return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo); 439 } 440 441 static ssize_t 442 pin_assignment_store(struct device *dev, struct device_attribute *attr, 443 const char *buf, size_t size) 444 { 445 struct dp_altmode *dp = dev_get_drvdata(dev); 446 u8 assignments; 447 u32 conf; 448 int ret; 449 450 ret = sysfs_match_string(pin_assignments, buf); 451 if (ret < 0) 452 return ret; 453 454 conf = DP_CONF_SET_PIN_ASSIGN(BIT(ret)); 455 ret = 0; 456 457 mutex_lock(&dp->lock); 458 459 if (conf & dp->data.conf) 460 goto out_unlock; 461 462 if (dp->state != DP_STATE_IDLE) { 463 ret = -EBUSY; 464 goto out_unlock; 465 } 466 467 assignments = get_current_pin_assignments(dp); 468 469 if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) { 470 ret = -EINVAL; 471 goto out_unlock; 472 } 473 474 conf |= dp->data.conf & ~DP_CONF_PIN_ASSIGNEMENT_MASK; 475 476 /* Only send Configure command if a configuration has been set */ 477 if (dp->alt->active && DP_CONF_CURRENTLY(dp->data.conf)) { 478 ret = dp_altmode_configure_vdm(dp, conf); 479 if (ret) 480 goto out_unlock; 481 } 482 483 dp->data.conf = conf; 484 485 out_unlock: 486 mutex_unlock(&dp->lock); 487 488 return ret ? ret : size; 489 } 490 491 static ssize_t pin_assignment_show(struct device *dev, 492 struct device_attribute *attr, char *buf) 493 { 494 struct dp_altmode *dp = dev_get_drvdata(dev); 495 u8 assignments; 496 int len = 0; 497 u8 cur; 498 int i; 499 500 mutex_lock(&dp->lock); 501 502 cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf)); 503 504 assignments = get_current_pin_assignments(dp); 505 506 for (i = 0; assignments; assignments >>= 1, i++) { 507 if (assignments & 1) { 508 if (i == cur) 509 len += sprintf(buf + len, "[%s] ", 510 pin_assignments[i]); 511 else 512 len += sprintf(buf + len, "%s ", 513 pin_assignments[i]); 514 } 515 } 516 517 mutex_unlock(&dp->lock); 518 519 buf[len - 1] = '\n'; 520 return len; 521 } 522 static DEVICE_ATTR_RW(pin_assignment); 523 524 static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf) 525 { 526 struct dp_altmode *dp = dev_get_drvdata(dev); 527 528 return sysfs_emit(buf, "%d\n", dp->hpd); 529 } 530 static DEVICE_ATTR_RO(hpd); 531 532 static struct attribute *dp_altmode_attrs[] = { 533 &dev_attr_configuration.attr, 534 &dev_attr_pin_assignment.attr, 535 &dev_attr_hpd.attr, 536 NULL 537 }; 538 539 static const struct attribute_group dp_altmode_group = { 540 .name = "displayport", 541 .attrs = dp_altmode_attrs, 542 }; 543 544 int dp_altmode_probe(struct typec_altmode *alt) 545 { 546 const struct typec_altmode *port = typec_altmode_get_partner(alt); 547 struct fwnode_handle *fwnode; 548 struct dp_altmode *dp; 549 int ret; 550 551 /* FIXME: Port can only be DFP_U. */ 552 553 /* Make sure we have compatiple pin configurations */ 554 if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & 555 DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && 556 !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & 557 DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) 558 return -ENODEV; 559 560 ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group); 561 if (ret) 562 return ret; 563 564 dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); 565 if (!dp) 566 return -ENOMEM; 567 568 INIT_WORK(&dp->work, dp_altmode_work); 569 mutex_init(&dp->lock); 570 dp->port = port; 571 dp->alt = alt; 572 573 alt->desc = "DisplayPort"; 574 alt->ops = &dp_altmode_ops; 575 576 fwnode = dev_fwnode(alt->dev.parent->parent); /* typec_port fwnode */ 577 dp->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0); 578 if (IS_ERR(dp->connector_fwnode)) 579 dp->connector_fwnode = NULL; 580 581 typec_altmode_set_drvdata(alt, dp); 582 583 dp->state = DP_STATE_ENTER; 584 schedule_work(&dp->work); 585 586 return 0; 587 } 588 EXPORT_SYMBOL_GPL(dp_altmode_probe); 589 590 void dp_altmode_remove(struct typec_altmode *alt) 591 { 592 struct dp_altmode *dp = typec_altmode_get_drvdata(alt); 593 594 sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group); 595 cancel_work_sync(&dp->work); 596 597 if (dp->connector_fwnode) { 598 if (dp->hpd) 599 drm_connector_oob_hotplug_event(dp->connector_fwnode); 600 601 fwnode_handle_put(dp->connector_fwnode); 602 } 603 } 604 EXPORT_SYMBOL_GPL(dp_altmode_remove); 605 606 static const struct typec_device_id dp_typec_id[] = { 607 { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE }, 608 { }, 609 }; 610 MODULE_DEVICE_TABLE(typec, dp_typec_id); 611 612 static struct typec_altmode_driver dp_altmode_driver = { 613 .id_table = dp_typec_id, 614 .probe = dp_altmode_probe, 615 .remove = dp_altmode_remove, 616 .driver = { 617 .name = "typec_displayport", 618 .owner = THIS_MODULE, 619 }, 620 }; 621 module_typec_altmode_driver(dp_altmode_driver); 622 623 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); 624 MODULE_LICENSE("GPL v2"); 625 MODULE_DESCRIPTION("DisplayPort Alternate Mode"); 626