1 // SPDX-License-Identifier: GPL-2.0
3 * USB Typec-C DisplayPort Alternate Mode driver
5 * Copyright (C) 2018 Intel Corporation
6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
8 * DisplayPort is trademark of VESA (www.vesa.org)
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"
20 #define DP_HEADER(_dp, ver, cmd) (VDO((_dp)->alt->svid, 1, ver, cmd) \
21 | VDO_OPOS(USB_TYPEC_DP_MODE))
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) | \
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) | \
40 /* DP only pin assignments */
41 #define DP_PIN_ASSIGN_DP_ONLY_MASK (BIT(DP_PIN_ASSIGN_A) | \
42 BIT(DP_PIN_ASSIGN_C) | \
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) | \
56 DP_STATE_CONFIGURE_PRIME,
62 struct typec_displayport_data data;
63 struct typec_displayport_data data_prime;
69 struct mutex lock; /* device lock */
70 struct work_struct work;
71 struct typec_altmode *alt;
72 const struct typec_altmode *port;
73 struct fwnode_handle *connector_fwnode;
74 struct typec_altmode *plug_prime;
77 static int dp_altmode_notify(struct dp_altmode *dp)
83 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
84 conf = TYPEC_MODAL_STATE(state);
86 conf = TYPEC_STATE_USB;
89 return typec_altmode_notify(dp->alt, conf, &dp->data);
92 static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
98 conf = (dp->data.conf & DP_CONF_SIGNALLING_MASK) >> DP_CONF_SIGNALLING_SHIFT;
101 case DP_STATUS_CON_DISABLED:
103 case DP_STATUS_CON_DFP_D:
104 conf |= DP_CONF_UFP_U_AS_DFP_D;
105 pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) &
106 DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo);
107 /* Account for active cable capabilities */
109 pin_assign &= DP_CAP_DFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
111 case DP_STATUS_CON_UFP_D:
112 case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */
113 conf |= DP_CONF_UFP_U_AS_UFP_D;
114 pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) &
115 DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo);
116 /* Account for active cable capabilities */
118 pin_assign &= DP_CAP_UFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
124 /* Determining the initial pin assignment. */
125 if (!DP_CONF_GET_PIN_ASSIGN(dp->data.conf)) {
126 /* Is USB together with DP preferred */
127 if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC &&
128 pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK)
129 pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK;
130 else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) {
131 pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK;
132 /* Default to pin assign C if available */
133 if (pin_assign & BIT(DP_PIN_ASSIGN_C))
134 pin_assign = BIT(DP_PIN_ASSIGN_C);
140 conf |= DP_CONF_SET_PIN_ASSIGN(pin_assign);
143 dp->data.conf = conf;
145 dp->data_prime.conf = conf;
150 static int dp_altmode_status_update(struct dp_altmode *dp)
152 bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
153 bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE);
154 u8 con = DP_STATUS_CONNECTION(dp->data.status);
157 if (configured && (dp->data.status & DP_STATUS_SWITCH_TO_USB)) {
159 dp->data_prime.conf = 0;
160 dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
162 } else if (dp->data.status & DP_STATUS_EXIT_DP_MODE) {
163 dp->state = DP_STATE_EXIT;
164 } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) {
165 ret = dp_altmode_configure(dp, con);
167 dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
169 if (dp->hpd != hpd) {
171 dp->pending_hpd = true;
175 drm_connector_oob_hotplug_event(dp->connector_fwnode,
176 hpd ? connector_status_connected :
177 connector_status_disconnected);
179 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
185 static int dp_altmode_configured(struct dp_altmode *dp)
187 sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
188 sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
190 * If the DFP_D/UFP_D sends a change in HPD when first notifying the
191 * DisplayPort driver that it is connected, then we wait until
192 * configuration is complete to signal HPD.
194 if (dp->pending_hpd) {
195 drm_connector_oob_hotplug_event(dp->connector_fwnode,
196 connector_status_connected);
197 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
198 dp->pending_hpd = false;
201 return dp_altmode_notify(dp);
204 static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
206 int svdm_version = typec_altmode_get_svdm_version(dp->alt);
210 if (svdm_version < 0)
213 header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE);
214 ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
216 dev_err(&dp->alt->dev,
217 "unable to put to connector to safe mode\n");
221 ret = typec_altmode_vdm(dp->alt, header, &conf, 2);
223 dp_altmode_notify(dp);
228 static int dp_altmode_configure_vdm_cable(struct dp_altmode *dp, u32 conf)
230 int svdm_version = typec_altmode_get_cable_svdm_version(dp->plug_prime);
233 if (svdm_version < 0)
236 header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE);
238 return typec_cable_altmode_vdm(dp->plug_prime, TYPEC_PLUG_SOP_P, header, &conf, 2);
241 static void dp_altmode_work(struct work_struct *work)
243 struct dp_altmode *dp = container_of(work, struct dp_altmode, work);
249 mutex_lock(&dp->lock);
253 ret = typec_altmode_enter(dp->alt, NULL);
254 if (ret && ret != -EBUSY)
255 dev_err(&dp->alt->dev, "failed to enter mode\n");
257 case DP_STATE_ENTER_PRIME:
258 ret = typec_cable_altmode_enter(dp->alt, TYPEC_PLUG_SOP_P, NULL);
260 * If we fail to enter Alt Mode on SOP', then we should drop the
261 * plug from the driver and attempt to run the driver without
264 if (ret && ret != -EBUSY) {
265 dev_err(&dp->alt->dev, "plug failed to enter mode\n");
266 dp->state = DP_STATE_ENTER;
270 case DP_STATE_UPDATE:
271 svdm_version = typec_altmode_get_svdm_version(dp->alt);
272 if (svdm_version < 0)
274 header = DP_HEADER(dp, svdm_version, DP_CMD_STATUS_UPDATE);
276 ret = typec_altmode_vdm(dp->alt, header, &vdo, 2);
278 dev_err(&dp->alt->dev,
279 "unable to send Status Update command (%d)\n",
282 case DP_STATE_CONFIGURE:
283 ret = dp_altmode_configure_vdm(dp, dp->data.conf);
285 dev_err(&dp->alt->dev,
286 "unable to send Configure command (%d)\n", ret);
288 case DP_STATE_CONFIGURE_PRIME:
289 ret = dp_altmode_configure_vdm_cable(dp, dp->data_prime.conf);
291 dev_err(&dp->plug_prime->dev,
292 "unable to send Configure command (%d)\n",
294 dp->state = DP_STATE_CONFIGURE;
299 if (typec_altmode_exit(dp->alt))
300 dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
302 case DP_STATE_EXIT_PRIME:
303 if (typec_cable_altmode_exit(dp->plug_prime, TYPEC_PLUG_SOP_P))
304 dev_err(&dp->plug_prime->dev, "Exit Mode Failed!\n");
310 dp->state = DP_STATE_IDLE;
312 mutex_unlock(&dp->lock);
316 typec_altmode_put_plug(dp->plug_prime);
317 dp->plug_prime = NULL;
318 schedule_work(&dp->work);
319 mutex_unlock(&dp->lock);
322 static void dp_altmode_attention(struct typec_altmode *alt, const u32 vdo)
324 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
327 mutex_lock(&dp->lock);
329 old_state = dp->state;
330 dp->data.status = vdo;
332 if (old_state != DP_STATE_IDLE)
333 dev_warn(&alt->dev, "ATTENTION while processing state %d\n",
336 if (dp_altmode_status_update(dp))
337 dev_warn(&alt->dev, "%s: status update failed\n", __func__);
339 if (dp_altmode_notify(dp))
340 dev_err(&alt->dev, "%s: notification failed\n", __func__);
342 if (old_state == DP_STATE_IDLE && dp->state != DP_STATE_IDLE)
343 schedule_work(&dp->work);
345 mutex_unlock(&dp->lock);
348 static int dp_altmode_vdm(struct typec_altmode *alt,
349 const u32 hdr, const u32 *vdo, int count)
351 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
352 int cmd_type = PD_VDO_CMDT(hdr);
353 int cmd = PD_VDO_CMD(hdr);
356 mutex_lock(&dp->lock);
358 if (dp->state != DP_STATE_IDLE) {
367 typec_altmode_update_active(alt, true);
368 dp->state = DP_STATE_UPDATE;
371 typec_altmode_update_active(alt, false);
375 drm_connector_oob_hotplug_event(dp->connector_fwnode,
376 connector_status_disconnected);
378 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
381 dp->state = DP_STATE_EXIT_PRIME;
383 case DP_CMD_STATUS_UPDATE:
384 dp->data.status = *vdo;
385 ret = dp_altmode_status_update(dp);
387 case DP_CMD_CONFIGURE:
388 ret = dp_altmode_configured(dp);
396 case DP_CMD_CONFIGURE:
398 ret = dp_altmode_configured(dp);
408 if (dp->state != DP_STATE_IDLE)
409 schedule_work(&dp->work);
412 mutex_unlock(&dp->lock);
416 static int dp_cable_altmode_vdm(struct typec_altmode *alt, enum typec_plug_index sop,
417 const u32 hdr, const u32 *vdo, int count)
419 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
420 int cmd_type = PD_VDO_CMDT(hdr);
421 int cmd = PD_VDO_CMD(hdr);
424 mutex_lock(&dp->lock);
426 if (dp->state != DP_STATE_IDLE) {
435 typec_altmode_update_active(dp->plug_prime, true);
436 dp->state = DP_STATE_ENTER;
439 dp->data_prime.status = 0;
440 dp->data_prime.conf = 0;
441 typec_altmode_update_active(dp->plug_prime, false);
443 case DP_CMD_CONFIGURE:
444 dp->state = DP_STATE_CONFIGURE;
452 case DP_CMD_CONFIGURE:
453 dp->data_prime.conf = 0;
454 /* Attempt to configure on SOP, drop plug */
455 typec_altmode_put_plug(dp->plug_prime);
456 dp->plug_prime = NULL;
457 dp->state = DP_STATE_CONFIGURE;
467 if (dp->state != DP_STATE_IDLE)
468 schedule_work(&dp->work);
471 mutex_unlock(&dp->lock);
475 static int dp_altmode_activate(struct typec_altmode *alt, int activate)
477 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
481 if (dp->plug_prime) {
482 ret = typec_cable_altmode_enter(alt, TYPEC_PLUG_SOP_P, NULL);
484 typec_altmode_put_plug(dp->plug_prime);
485 dp->plug_prime = NULL;
490 return typec_altmode_enter(alt, NULL);
492 return typec_altmode_exit(alt);
496 static const struct typec_altmode_ops dp_altmode_ops = {
497 .attention = dp_altmode_attention,
498 .vdm = dp_altmode_vdm,
499 .activate = dp_altmode_activate,
502 static const struct typec_cable_ops dp_cable_ops = {
503 .vdm = dp_cable_altmode_vdm,
506 static const char * const configurations[] = {
507 [DP_CONF_USB] = "USB",
508 [DP_CONF_DFP_D] = "source",
509 [DP_CONF_UFP_D] = "sink",
513 configuration_store(struct device *dev, struct device_attribute *attr,
514 const char *buf, size_t size)
516 struct dp_altmode *dp = dev_get_drvdata(dev);
522 con = sysfs_match_string(configurations, buf);
526 mutex_lock(&dp->lock);
528 if (dp->state != DP_STATE_IDLE) {
533 cap = DP_CAP_CAPABILITY(dp->alt->vdo);
535 if ((con == DP_CONF_DFP_D && !(cap & DP_CAP_DFP_D)) ||
536 (con == DP_CONF_UFP_D && !(cap & DP_CAP_UFP_D))) {
541 conf = dp->data.conf & ~DP_CONF_DUAL_D;
544 if (dp->alt->active) {
545 ret = dp_altmode_configure_vdm(dp, conf);
550 dp->data.conf = conf;
553 mutex_unlock(&dp->lock);
555 return ret ? ret : size;
558 static ssize_t configuration_show(struct device *dev,
559 struct device_attribute *attr, char *buf)
561 struct dp_altmode *dp = dev_get_drvdata(dev);
567 mutex_lock(&dp->lock);
569 cap = DP_CAP_CAPABILITY(dp->alt->vdo);
570 cur = DP_CONF_CURRENTLY(dp->data.conf);
572 len = sprintf(buf, "%s ", cur ? "USB" : "[USB]");
574 for (i = 1; i < ARRAY_SIZE(configurations); i++) {
576 len += sprintf(buf + len, "[%s] ", configurations[i]);
577 else if ((i == DP_CONF_DFP_D && cap & DP_CAP_DFP_D) ||
578 (i == DP_CONF_UFP_D && cap & DP_CAP_UFP_D))
579 len += sprintf(buf + len, "%s ", configurations[i]);
582 mutex_unlock(&dp->lock);
587 static DEVICE_ATTR_RW(configuration);
589 static const char * const pin_assignments[] = {
590 [DP_PIN_ASSIGN_A] = "A",
591 [DP_PIN_ASSIGN_B] = "B",
592 [DP_PIN_ASSIGN_C] = "C",
593 [DP_PIN_ASSIGN_D] = "D",
594 [DP_PIN_ASSIGN_E] = "E",
595 [DP_PIN_ASSIGN_F] = "F",
599 * Helper function to extract a peripheral's currently supported
600 * Pin Assignments from its DisplayPort alternate mode state.
602 static u8 get_current_pin_assignments(struct dp_altmode *dp)
604 if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D)
605 return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo);
607 return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
611 pin_assignment_store(struct device *dev, struct device_attribute *attr,
612 const char *buf, size_t size)
614 struct dp_altmode *dp = dev_get_drvdata(dev);
619 ret = sysfs_match_string(pin_assignments, buf);
623 conf = DP_CONF_SET_PIN_ASSIGN(BIT(ret));
626 mutex_lock(&dp->lock);
628 if (conf & dp->data.conf)
631 if (dp->state != DP_STATE_IDLE) {
636 assignments = get_current_pin_assignments(dp);
638 if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
643 conf |= dp->data.conf & ~DP_CONF_PIN_ASSIGNEMENT_MASK;
645 /* Only send Configure command if a configuration has been set */
646 if (dp->alt->active && DP_CONF_CURRENTLY(dp->data.conf)) {
647 /* todo: send manual configure over SOP'*/
648 ret = dp_altmode_configure_vdm(dp, conf);
653 dp->data.conf = conf;
656 mutex_unlock(&dp->lock);
658 return ret ? ret : size;
661 static ssize_t pin_assignment_show(struct device *dev,
662 struct device_attribute *attr, char *buf)
664 struct dp_altmode *dp = dev_get_drvdata(dev);
670 mutex_lock(&dp->lock);
672 cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
674 assignments = get_current_pin_assignments(dp);
676 for (i = 0; assignments; assignments >>= 1, i++) {
677 if (assignments & 1) {
679 len += sprintf(buf + len, "[%s] ",
682 len += sprintf(buf + len, "%s ",
687 mutex_unlock(&dp->lock);
689 /* get_current_pin_assignments can return 0 when no matching pin assignments are found */
696 static DEVICE_ATTR_RW(pin_assignment);
698 static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf)
700 struct dp_altmode *dp = dev_get_drvdata(dev);
702 return sysfs_emit(buf, "%d\n", dp->hpd);
704 static DEVICE_ATTR_RO(hpd);
706 static struct attribute *displayport_attrs[] = {
707 &dev_attr_configuration.attr,
708 &dev_attr_pin_assignment.attr,
713 static const struct attribute_group displayport_group = {
714 .name = "displayport",
715 .attrs = displayport_attrs,
718 static const struct attribute_group *displayport_groups[] = {
723 int dp_altmode_probe(struct typec_altmode *alt)
725 const struct typec_altmode *port = typec_altmode_get_partner(alt);
726 struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
727 struct fwnode_handle *fwnode;
728 struct dp_altmode *dp;
730 /* FIXME: Port can only be DFP_U. */
732 /* Make sure we have compatiple pin configurations */
733 if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) &
734 DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) &&
735 !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) &
736 DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)))
739 dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
743 INIT_WORK(&dp->work, dp_altmode_work);
744 mutex_init(&dp->lock);
748 alt->desc = "DisplayPort";
749 alt->ops = &dp_altmode_ops;
752 plug->desc = "Displayport";
753 plug->cable_ops = &dp_cable_ops;
756 dp->plug_prime = plug;
758 fwnode = dev_fwnode(alt->dev.parent->parent); /* typec_port fwnode */
759 if (fwnode_property_present(fwnode, "displayport"))
760 dp->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
762 dp->connector_fwnode = fwnode_handle_get(fwnode); /* embedded DP */
763 if (IS_ERR(dp->connector_fwnode))
764 dp->connector_fwnode = NULL;
766 typec_altmode_set_drvdata(alt, dp);
768 typec_altmode_set_drvdata(plug, dp);
770 dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
771 schedule_work(&dp->work);
775 EXPORT_SYMBOL_GPL(dp_altmode_probe);
777 void dp_altmode_remove(struct typec_altmode *alt)
779 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
781 cancel_work_sync(&dp->work);
782 typec_altmode_put_plug(dp->plug_prime);
784 if (dp->connector_fwnode) {
785 drm_connector_oob_hotplug_event(dp->connector_fwnode,
786 connector_status_disconnected);
788 fwnode_handle_put(dp->connector_fwnode);
791 EXPORT_SYMBOL_GPL(dp_altmode_remove);
793 static const struct typec_device_id dp_typec_id[] = {
794 { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE },
797 MODULE_DEVICE_TABLE(typec, dp_typec_id);
799 static struct typec_altmode_driver dp_altmode_driver = {
800 .id_table = dp_typec_id,
801 .probe = dp_altmode_probe,
802 .remove = dp_altmode_remove,
804 .name = "typec_displayport",
805 .owner = THIS_MODULE,
806 .dev_groups = displayport_groups,
809 module_typec_altmode_driver(dp_altmode_driver);
811 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
812 MODULE_LICENSE("GPL v2");
813 MODULE_DESCRIPTION("DisplayPort Alternate Mode");