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