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");