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