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_ENTER_PRIME,
54 DP_STATE_UPDATE,
55 DP_STATE_CONFIGURE,
56 DP_STATE_CONFIGURE_PRIME,
57 DP_STATE_EXIT,
58 DP_STATE_EXIT_PRIME,
59 };
60
61 struct dp_altmode {
62 struct typec_displayport_data data;
63 struct typec_displayport_data data_prime;
64
65 enum dp_state state;
66 bool hpd;
67 bool pending_hpd;
68
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;
75 };
76
dp_altmode_notify(struct dp_altmode * dp)77 static int dp_altmode_notify(struct dp_altmode *dp)
78 {
79 unsigned long conf;
80 u8 state;
81
82 if (dp->data.conf) {
83 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
84 conf = TYPEC_MODAL_STATE(state);
85 } else {
86 conf = TYPEC_STATE_USB;
87 }
88
89 return typec_altmode_notify(dp->alt, conf, &dp->data);
90 }
91
dp_altmode_configure(struct dp_altmode * dp,u8 con)92 static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
93 {
94 u8 pin_assign = 0;
95 u32 conf;
96
97 /* DP Signalling */
98 conf = (dp->data.conf & DP_CONF_SIGNALLING_MASK) >> DP_CONF_SIGNALLING_SHIFT;
99
100 switch (con) {
101 case DP_STATUS_CON_DISABLED:
102 return 0;
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 */
108 if (dp->plug_prime)
109 pin_assign &= DP_CAP_DFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
110 break;
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 */
117 if (dp->plug_prime)
118 pin_assign &= DP_CAP_UFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
119 break;
120 default:
121 break;
122 }
123
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);
135 }
136
137 if (!pin_assign)
138 return -EINVAL;
139
140 conf |= DP_CONF_SET_PIN_ASSIGN(pin_assign);
141 }
142
143 dp->data.conf = conf;
144 if (dp->plug_prime)
145 dp->data_prime.conf = conf;
146
147 return 0;
148 }
149
dp_altmode_status_update(struct dp_altmode * dp)150 static int dp_altmode_status_update(struct dp_altmode *dp)
151 {
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);
155 int ret = 0;
156
157 if (configured && (dp->data.status & DP_STATUS_SWITCH_TO_USB)) {
158 dp->data.conf = 0;
159 dp->data_prime.conf = 0;
160 dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
161 DP_STATE_CONFIGURE;
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);
166 if (!ret) {
167 dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
168 DP_STATE_CONFIGURE;
169 if (dp->hpd != hpd) {
170 dp->hpd = hpd;
171 dp->pending_hpd = true;
172 }
173 }
174 } else {
175 drm_connector_oob_hotplug_event(dp->connector_fwnode,
176 hpd ? connector_status_connected :
177 connector_status_disconnected);
178 dp->hpd = hpd;
179 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
180 }
181
182 return ret;
183 }
184
dp_altmode_configured(struct dp_altmode * dp)185 static int dp_altmode_configured(struct dp_altmode *dp)
186 {
187 sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
188 sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
189 /*
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.
193 */
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;
199 }
200
201 return dp_altmode_notify(dp);
202 }
203
dp_altmode_configure_vdm(struct dp_altmode * dp,u32 conf)204 static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
205 {
206 int svdm_version = typec_altmode_get_svdm_version(dp->alt);
207 u32 header;
208 int ret;
209
210 if (svdm_version < 0)
211 return svdm_version;
212
213 header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE);
214 ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
215 if (ret) {
216 dev_err(&dp->alt->dev,
217 "unable to put to connector to safe mode\n");
218 return ret;
219 }
220
221 ret = typec_altmode_vdm(dp->alt, header, &conf, 2);
222 if (ret)
223 dp_altmode_notify(dp);
224
225 return ret;
226 }
227
dp_altmode_configure_vdm_cable(struct dp_altmode * dp,u32 conf)228 static int dp_altmode_configure_vdm_cable(struct dp_altmode *dp, u32 conf)
229 {
230 int svdm_version = typec_altmode_get_cable_svdm_version(dp->plug_prime);
231 u32 header;
232
233 if (svdm_version < 0)
234 return svdm_version;
235
236 header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE);
237
238 return typec_cable_altmode_vdm(dp->plug_prime, TYPEC_PLUG_SOP_P, header, &conf, 2);
239 }
240
dp_altmode_work(struct work_struct * work)241 static void dp_altmode_work(struct work_struct *work)
242 {
243 struct dp_altmode *dp = container_of(work, struct dp_altmode, work);
244 int svdm_version;
245 u32 header;
246 u32 vdo;
247 int ret;
248
249 mutex_lock(&dp->lock);
250
251 switch (dp->state) {
252 case DP_STATE_ENTER:
253 ret = typec_altmode_enter(dp->alt, NULL);
254 if (ret && ret != -EBUSY)
255 dev_err(&dp->alt->dev, "failed to enter mode: %d\n", ret);
256 break;
257 case DP_STATE_ENTER_PRIME:
258 ret = typec_cable_altmode_enter(dp->alt, TYPEC_PLUG_SOP_P, NULL);
259 /*
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
262 * it.
263 */
264 if (ret && ret != -EBUSY) {
265 dev_err(&dp->alt->dev, "plug failed to enter mode\n");
266 dp->state = DP_STATE_ENTER;
267 goto disable_prime;
268 }
269 break;
270 case DP_STATE_UPDATE:
271 svdm_version = typec_altmode_get_svdm_version(dp->alt);
272 if (svdm_version < 0)
273 break;
274 header = DP_HEADER(dp, svdm_version, DP_CMD_STATUS_UPDATE);
275 vdo = 1;
276 ret = typec_altmode_vdm(dp->alt, header, &vdo, 2);
277 if (ret)
278 dev_err(&dp->alt->dev,
279 "unable to send Status Update command (%d)\n",
280 ret);
281 break;
282 case DP_STATE_CONFIGURE:
283 ret = dp_altmode_configure_vdm(dp, dp->data.conf);
284 if (ret)
285 dev_err(&dp->alt->dev,
286 "unable to send Configure command (%d)\n", ret);
287 break;
288 case DP_STATE_CONFIGURE_PRIME:
289 ret = dp_altmode_configure_vdm_cable(dp, dp->data_prime.conf);
290 if (ret) {
291 dev_err(&dp->plug_prime->dev,
292 "unable to send Configure command (%d)\n",
293 ret);
294 dp->state = DP_STATE_CONFIGURE;
295 goto disable_prime;
296 }
297 break;
298 case DP_STATE_EXIT:
299 if (typec_altmode_exit(dp->alt))
300 dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
301 break;
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");
305 break;
306 default:
307 break;
308 }
309
310 dp->state = DP_STATE_IDLE;
311
312 mutex_unlock(&dp->lock);
313 return;
314
315 disable_prime:
316 typec_altmode_put_plug(dp->plug_prime);
317 dp->plug_prime = NULL;
318 schedule_work(&dp->work);
319 mutex_unlock(&dp->lock);
320 }
321
dp_altmode_attention(struct typec_altmode * alt,const u32 vdo)322 static void dp_altmode_attention(struct typec_altmode *alt, const u32 vdo)
323 {
324 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
325 u8 old_state;
326
327 mutex_lock(&dp->lock);
328
329 old_state = dp->state;
330 dp->data.status = vdo;
331
332 if (old_state != DP_STATE_IDLE)
333 dev_warn(&alt->dev, "ATTENTION while processing state %d\n",
334 old_state);
335
336 if (dp_altmode_status_update(dp))
337 dev_warn(&alt->dev, "%s: status update failed\n", __func__);
338
339 if (dp_altmode_notify(dp))
340 dev_err(&alt->dev, "%s: notification failed\n", __func__);
341
342 if (old_state == DP_STATE_IDLE && dp->state != DP_STATE_IDLE)
343 schedule_work(&dp->work);
344
345 mutex_unlock(&dp->lock);
346 }
347
dp_altmode_vdm(struct typec_altmode * alt,const u32 hdr,const u32 * vdo,int count)348 static int dp_altmode_vdm(struct typec_altmode *alt,
349 const u32 hdr, const u32 *vdo, int count)
350 {
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);
354 int ret = 0;
355
356 mutex_lock(&dp->lock);
357
358 if (dp->state != DP_STATE_IDLE) {
359 ret = -EBUSY;
360 goto err_unlock;
361 }
362
363 switch (cmd_type) {
364 case CMDT_RSP_ACK:
365 switch (cmd) {
366 case CMD_ENTER_MODE:
367 typec_altmode_update_active(alt, true);
368 dp->state = DP_STATE_UPDATE;
369 break;
370 case CMD_EXIT_MODE:
371 typec_altmode_update_active(alt, false);
372 dp->data.status = 0;
373 dp->data.conf = 0;
374 if (dp->hpd) {
375 drm_connector_oob_hotplug_event(dp->connector_fwnode,
376 connector_status_disconnected);
377 dp->hpd = false;
378 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
379 }
380 if (dp->plug_prime)
381 dp->state = DP_STATE_EXIT_PRIME;
382 break;
383 case DP_CMD_STATUS_UPDATE:
384 dp->data.status = *vdo;
385 ret = dp_altmode_status_update(dp);
386 break;
387 case DP_CMD_CONFIGURE:
388 ret = dp_altmode_configured(dp);
389 break;
390 default:
391 break;
392 }
393 break;
394 case CMDT_RSP_NAK:
395 switch (cmd) {
396 case DP_CMD_STATUS_UPDATE:
397 if (typec_altmode_exit(alt))
398 dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
399 break;
400 case DP_CMD_CONFIGURE:
401 dp->data.conf = 0;
402 ret = dp_altmode_configured(dp);
403 break;
404 default:
405 break;
406 }
407 break;
408 default:
409 break;
410 }
411
412 if (dp->state != DP_STATE_IDLE)
413 schedule_work(&dp->work);
414
415 err_unlock:
416 mutex_unlock(&dp->lock);
417 return ret;
418 }
419
dp_cable_altmode_vdm(struct typec_altmode * alt,enum typec_plug_index sop,const u32 hdr,const u32 * vdo,int count)420 static int dp_cable_altmode_vdm(struct typec_altmode *alt, enum typec_plug_index sop,
421 const u32 hdr, const u32 *vdo, int count)
422 {
423 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
424 int cmd_type = PD_VDO_CMDT(hdr);
425 int cmd = PD_VDO_CMD(hdr);
426 int ret = 0;
427
428 mutex_lock(&dp->lock);
429
430 if (dp->state != DP_STATE_IDLE) {
431 ret = -EBUSY;
432 goto err_unlock;
433 }
434
435 switch (cmd_type) {
436 case CMDT_RSP_ACK:
437 switch (cmd) {
438 case CMD_ENTER_MODE:
439 typec_altmode_update_active(dp->plug_prime, true);
440 dp->state = DP_STATE_ENTER;
441 break;
442 case CMD_EXIT_MODE:
443 dp->data_prime.status = 0;
444 dp->data_prime.conf = 0;
445 typec_altmode_update_active(dp->plug_prime, false);
446 break;
447 case DP_CMD_CONFIGURE:
448 dp->state = DP_STATE_CONFIGURE;
449 break;
450 default:
451 break;
452 }
453 break;
454 case CMDT_RSP_NAK:
455 switch (cmd) {
456 case DP_CMD_CONFIGURE:
457 dp->data_prime.conf = 0;
458 /* Attempt to configure on SOP, drop plug */
459 typec_altmode_put_plug(dp->plug_prime);
460 dp->plug_prime = NULL;
461 dp->state = DP_STATE_CONFIGURE;
462 break;
463 default:
464 break;
465 }
466 break;
467 default:
468 break;
469 }
470
471 if (dp->state != DP_STATE_IDLE)
472 schedule_work(&dp->work);
473
474 err_unlock:
475 mutex_unlock(&dp->lock);
476 return ret;
477 }
478
dp_altmode_activate(struct typec_altmode * alt,int activate)479 static int dp_altmode_activate(struct typec_altmode *alt, int activate)
480 {
481 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
482 int ret;
483
484 if (activate) {
485 if (dp->plug_prime) {
486 ret = typec_cable_altmode_enter(alt, TYPEC_PLUG_SOP_P, NULL);
487 if (ret < 0) {
488 typec_altmode_put_plug(dp->plug_prime);
489 dp->plug_prime = NULL;
490 } else {
491 return ret;
492 }
493 }
494 return typec_altmode_enter(alt, NULL);
495 } else {
496 return typec_altmode_exit(alt);
497 }
498 }
499
500 static const struct typec_altmode_ops dp_altmode_ops = {
501 .attention = dp_altmode_attention,
502 .vdm = dp_altmode_vdm,
503 .activate = dp_altmode_activate,
504 };
505
506 static const struct typec_cable_ops dp_cable_ops = {
507 .vdm = dp_cable_altmode_vdm,
508 };
509
510 static const char * const configurations[] = {
511 [DP_CONF_USB] = "USB",
512 [DP_CONF_DFP_D] = "source",
513 [DP_CONF_UFP_D] = "sink",
514 };
515
516 static ssize_t
configuration_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)517 configuration_store(struct device *dev, struct device_attribute *attr,
518 const char *buf, size_t size)
519 {
520 struct dp_altmode *dp = dev_get_drvdata(dev);
521 u32 conf;
522 u32 cap;
523 int con;
524 int ret = 0;
525
526 con = sysfs_match_string(configurations, buf);
527 if (con < 0)
528 return con;
529
530 mutex_lock(&dp->lock);
531
532 if (dp->state != DP_STATE_IDLE) {
533 ret = -EBUSY;
534 goto err_unlock;
535 }
536
537 cap = DP_CAP_CAPABILITY(dp->alt->vdo);
538
539 if ((con == DP_CONF_DFP_D && !(cap & DP_CAP_DFP_D)) ||
540 (con == DP_CONF_UFP_D && !(cap & DP_CAP_UFP_D))) {
541 ret = -EINVAL;
542 goto err_unlock;
543 }
544
545 conf = dp->data.conf & ~DP_CONF_DUAL_D;
546 conf |= con;
547
548 if (dp->alt->active) {
549 ret = dp_altmode_configure_vdm(dp, conf);
550 if (ret)
551 goto err_unlock;
552 }
553
554 dp->data.conf = conf;
555
556 err_unlock:
557 mutex_unlock(&dp->lock);
558
559 return ret ? ret : size;
560 }
561
configuration_show(struct device * dev,struct device_attribute * attr,char * buf)562 static ssize_t configuration_show(struct device *dev,
563 struct device_attribute *attr, char *buf)
564 {
565 struct dp_altmode *dp = dev_get_drvdata(dev);
566 int len;
567 u8 cap;
568 u8 cur;
569 int i;
570
571 mutex_lock(&dp->lock);
572
573 cap = DP_CAP_CAPABILITY(dp->alt->vdo);
574 cur = DP_CONF_CURRENTLY(dp->data.conf);
575
576 len = sprintf(buf, "%s ", cur ? "USB" : "[USB]");
577
578 for (i = 1; i < ARRAY_SIZE(configurations); i++) {
579 if (i == cur)
580 len += sprintf(buf + len, "[%s] ", configurations[i]);
581 else if ((i == DP_CONF_DFP_D && cap & DP_CAP_DFP_D) ||
582 (i == DP_CONF_UFP_D && cap & DP_CAP_UFP_D))
583 len += sprintf(buf + len, "%s ", configurations[i]);
584 }
585
586 mutex_unlock(&dp->lock);
587
588 buf[len - 1] = '\n';
589 return len;
590 }
591 static DEVICE_ATTR_RW(configuration);
592
593 static const char * const pin_assignments[] = {
594 [DP_PIN_ASSIGN_A] = "A",
595 [DP_PIN_ASSIGN_B] = "B",
596 [DP_PIN_ASSIGN_C] = "C",
597 [DP_PIN_ASSIGN_D] = "D",
598 [DP_PIN_ASSIGN_E] = "E",
599 [DP_PIN_ASSIGN_F] = "F",
600 };
601
602 /*
603 * Helper function to extract a peripheral's currently supported
604 * Pin Assignments from its DisplayPort alternate mode state.
605 */
get_current_pin_assignments(struct dp_altmode * dp)606 static u8 get_current_pin_assignments(struct dp_altmode *dp)
607 {
608 if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D)
609 return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo);
610 else
611 return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
612 }
613
614 static ssize_t
pin_assignment_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)615 pin_assignment_store(struct device *dev, struct device_attribute *attr,
616 const char *buf, size_t size)
617 {
618 struct dp_altmode *dp = dev_get_drvdata(dev);
619 u8 assignments;
620 u32 conf;
621 int ret;
622
623 ret = sysfs_match_string(pin_assignments, buf);
624 if (ret < 0)
625 return ret;
626
627 conf = DP_CONF_SET_PIN_ASSIGN(BIT(ret));
628 ret = 0;
629
630 mutex_lock(&dp->lock);
631
632 if (conf & dp->data.conf)
633 goto out_unlock;
634
635 if (dp->state != DP_STATE_IDLE) {
636 ret = -EBUSY;
637 goto out_unlock;
638 }
639
640 assignments = get_current_pin_assignments(dp);
641
642 if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
643 ret = -EINVAL;
644 goto out_unlock;
645 }
646
647 conf |= dp->data.conf & ~DP_CONF_PIN_ASSIGNEMENT_MASK;
648
649 /* Only send Configure command if a configuration has been set */
650 if (dp->alt->active && DP_CONF_CURRENTLY(dp->data.conf)) {
651 /* todo: send manual configure over SOP'*/
652 ret = dp_altmode_configure_vdm(dp, conf);
653 if (ret)
654 goto out_unlock;
655 }
656
657 dp->data.conf = conf;
658
659 out_unlock:
660 mutex_unlock(&dp->lock);
661
662 return ret ? ret : size;
663 }
664
pin_assignment_show(struct device * dev,struct device_attribute * attr,char * buf)665 static ssize_t pin_assignment_show(struct device *dev,
666 struct device_attribute *attr, char *buf)
667 {
668 struct dp_altmode *dp = dev_get_drvdata(dev);
669 u8 assignments;
670 int len = 0;
671 u8 cur;
672 int i;
673
674 mutex_lock(&dp->lock);
675
676 cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
677
678 assignments = get_current_pin_assignments(dp);
679
680 for (i = 0; assignments; assignments >>= 1, i++) {
681 if (assignments & 1) {
682 if (i == cur)
683 len += sprintf(buf + len, "[%s] ",
684 pin_assignments[i]);
685 else
686 len += sprintf(buf + len, "%s ",
687 pin_assignments[i]);
688 }
689 }
690
691 mutex_unlock(&dp->lock);
692
693 /* get_current_pin_assignments can return 0 when no matching pin assignments are found */
694 if (len == 0)
695 len++;
696
697 buf[len - 1] = '\n';
698 return len;
699 }
700 static DEVICE_ATTR_RW(pin_assignment);
701
hpd_show(struct device * dev,struct device_attribute * attr,char * buf)702 static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf)
703 {
704 struct dp_altmode *dp = dev_get_drvdata(dev);
705
706 return sysfs_emit(buf, "%d\n", dp->hpd);
707 }
708 static DEVICE_ATTR_RO(hpd);
709
710 static struct attribute *displayport_attrs[] = {
711 &dev_attr_configuration.attr,
712 &dev_attr_pin_assignment.attr,
713 &dev_attr_hpd.attr,
714 NULL
715 };
716
717 static const struct attribute_group displayport_group = {
718 .name = "displayport",
719 .attrs = displayport_attrs,
720 };
721
722 static const struct attribute_group *displayport_groups[] = {
723 &displayport_group,
724 NULL,
725 };
726
dp_altmode_probe(struct typec_altmode * alt)727 int dp_altmode_probe(struct typec_altmode *alt)
728 {
729 const struct typec_altmode *port = typec_altmode_get_partner(alt);
730 struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
731 struct fwnode_handle *fwnode;
732 struct dp_altmode *dp;
733
734 /* FIXME: Port can only be DFP_U. */
735
736 /* Make sure we have compatible pin configurations */
737 if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) &
738 DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) &&
739 !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) &
740 DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)))
741 return -ENODEV;
742
743 dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
744 if (!dp)
745 return -ENOMEM;
746
747 INIT_WORK(&dp->work, dp_altmode_work);
748 mutex_init(&dp->lock);
749 dp->port = port;
750 dp->alt = alt;
751
752 alt->desc = "DisplayPort";
753 typec_altmode_set_ops(alt, &dp_altmode_ops);
754
755 if (plug) {
756 plug->desc = "Displayport";
757 plug->cable_ops = &dp_cable_ops;
758 }
759
760 dp->plug_prime = plug;
761
762 fwnode = dev_fwnode(alt->dev.parent->parent); /* typec_port fwnode */
763 if (fwnode_property_present(fwnode, "displayport"))
764 dp->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
765 else
766 dp->connector_fwnode = fwnode_handle_get(fwnode); /* embedded DP */
767 if (IS_ERR(dp->connector_fwnode))
768 dp->connector_fwnode = NULL;
769
770 typec_altmode_set_drvdata(alt, dp);
771 if (plug)
772 typec_altmode_set_drvdata(plug, dp);
773
774 dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
775 schedule_work(&dp->work);
776
777 return 0;
778 }
779 EXPORT_SYMBOL_GPL(dp_altmode_probe);
780
dp_altmode_remove(struct typec_altmode * alt)781 void dp_altmode_remove(struct typec_altmode *alt)
782 {
783 struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
784
785 cancel_work_sync(&dp->work);
786 typec_altmode_put_plug(dp->plug_prime);
787
788 if (dp->connector_fwnode) {
789 drm_connector_oob_hotplug_event(dp->connector_fwnode,
790 connector_status_disconnected);
791
792 fwnode_handle_put(dp->connector_fwnode);
793 }
794 }
795 EXPORT_SYMBOL_GPL(dp_altmode_remove);
796
797 static const struct typec_device_id dp_typec_id[] = {
798 { USB_TYPEC_DP_SID },
799 { },
800 };
801 MODULE_DEVICE_TABLE(typec, dp_typec_id);
802
803 static struct typec_altmode_driver dp_altmode_driver = {
804 .id_table = dp_typec_id,
805 .probe = dp_altmode_probe,
806 .remove = dp_altmode_remove,
807 .driver = {
808 .name = "typec_displayport",
809 .dev_groups = displayport_groups,
810 },
811 };
812 module_typec_altmode_driver(dp_altmode_driver);
813
814 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
815 MODULE_LICENSE("GPL v2");
816 MODULE_DESCRIPTION("DisplayPort Alternate Mode");
817