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\n");
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_CONFIGURE:
397 			dp->data.conf = 0;
398 			ret = dp_altmode_configured(dp);
399 			break;
400 		default:
401 			break;
402 		}
403 		break;
404 	default:
405 		break;
406 	}
407 
408 	if (dp->state != DP_STATE_IDLE)
409 		schedule_work(&dp->work);
410 
411 err_unlock:
412 	mutex_unlock(&dp->lock);
413 	return ret;
414 }
415 
dp_cable_altmode_vdm(struct typec_altmode * alt,enum typec_plug_index sop,const u32 hdr,const u32 * vdo,int count)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)
418 {
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);
422 	int ret = 0;
423 
424 	mutex_lock(&dp->lock);
425 
426 	if (dp->state != DP_STATE_IDLE) {
427 		ret = -EBUSY;
428 		goto err_unlock;
429 	}
430 
431 	switch (cmd_type) {
432 	case CMDT_RSP_ACK:
433 		switch (cmd) {
434 		case CMD_ENTER_MODE:
435 			typec_altmode_update_active(dp->plug_prime, true);
436 			dp->state = DP_STATE_ENTER;
437 			break;
438 		case CMD_EXIT_MODE:
439 			dp->data_prime.status = 0;
440 			dp->data_prime.conf = 0;
441 			typec_altmode_update_active(dp->plug_prime, false);
442 			break;
443 		case DP_CMD_CONFIGURE:
444 			dp->state = DP_STATE_CONFIGURE;
445 			break;
446 		default:
447 			break;
448 		}
449 		break;
450 	case CMDT_RSP_NAK:
451 		switch (cmd) {
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;
458 			break;
459 		default:
460 			break;
461 		}
462 		break;
463 	default:
464 		break;
465 	}
466 
467 	if (dp->state != DP_STATE_IDLE)
468 		schedule_work(&dp->work);
469 
470 err_unlock:
471 	mutex_unlock(&dp->lock);
472 	return ret;
473 }
474 
dp_altmode_activate(struct typec_altmode * alt,int activate)475 static int dp_altmode_activate(struct typec_altmode *alt, int activate)
476 {
477 	struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
478 	int ret;
479 
480 	if (activate) {
481 		if (dp->plug_prime) {
482 			ret = typec_cable_altmode_enter(alt, TYPEC_PLUG_SOP_P, NULL);
483 			if (ret < 0) {
484 				typec_altmode_put_plug(dp->plug_prime);
485 				dp->plug_prime = NULL;
486 			} else {
487 				return ret;
488 			}
489 		}
490 		return typec_altmode_enter(alt, NULL);
491 	} else {
492 		return typec_altmode_exit(alt);
493 	}
494 }
495 
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,
500 };
501 
502 static const struct typec_cable_ops dp_cable_ops = {
503 	.vdm = dp_cable_altmode_vdm,
504 };
505 
506 static const char * const configurations[] = {
507 	[DP_CONF_USB]	= "USB",
508 	[DP_CONF_DFP_D]	= "source",
509 	[DP_CONF_UFP_D]	= "sink",
510 };
511 
512 static ssize_t
configuration_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)513 configuration_store(struct device *dev, struct device_attribute *attr,
514 		    const char *buf, size_t size)
515 {
516 	struct dp_altmode *dp = dev_get_drvdata(dev);
517 	u32 conf;
518 	u32 cap;
519 	int con;
520 	int ret = 0;
521 
522 	con = sysfs_match_string(configurations, buf);
523 	if (con < 0)
524 		return con;
525 
526 	mutex_lock(&dp->lock);
527 
528 	if (dp->state != DP_STATE_IDLE) {
529 		ret = -EBUSY;
530 		goto err_unlock;
531 	}
532 
533 	cap = DP_CAP_CAPABILITY(dp->alt->vdo);
534 
535 	if ((con == DP_CONF_DFP_D && !(cap & DP_CAP_DFP_D)) ||
536 	    (con == DP_CONF_UFP_D && !(cap & DP_CAP_UFP_D))) {
537 		ret = -EINVAL;
538 		goto err_unlock;
539 	}
540 
541 	conf = dp->data.conf & ~DP_CONF_DUAL_D;
542 	conf |= con;
543 
544 	if (dp->alt->active) {
545 		ret = dp_altmode_configure_vdm(dp, conf);
546 		if (ret)
547 			goto err_unlock;
548 	}
549 
550 	dp->data.conf = conf;
551 
552 err_unlock:
553 	mutex_unlock(&dp->lock);
554 
555 	return ret ? ret : size;
556 }
557 
configuration_show(struct device * dev,struct device_attribute * attr,char * buf)558 static ssize_t configuration_show(struct device *dev,
559 				  struct device_attribute *attr, char *buf)
560 {
561 	struct dp_altmode *dp = dev_get_drvdata(dev);
562 	int len;
563 	u8 cap;
564 	u8 cur;
565 	int i;
566 
567 	mutex_lock(&dp->lock);
568 
569 	cap = DP_CAP_CAPABILITY(dp->alt->vdo);
570 	cur = DP_CONF_CURRENTLY(dp->data.conf);
571 
572 	len = sprintf(buf, "%s ", cur ? "USB" : "[USB]");
573 
574 	for (i = 1; i < ARRAY_SIZE(configurations); i++) {
575 		if (i == cur)
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]);
580 	}
581 
582 	mutex_unlock(&dp->lock);
583 
584 	buf[len - 1] = '\n';
585 	return len;
586 }
587 static DEVICE_ATTR_RW(configuration);
588 
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",
596 };
597 
598 /*
599  * Helper function to extract a peripheral's currently supported
600  * Pin Assignments from its DisplayPort alternate mode state.
601  */
get_current_pin_assignments(struct dp_altmode * dp)602 static u8 get_current_pin_assignments(struct dp_altmode *dp)
603 {
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);
606 	else
607 		return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
608 }
609 
610 static ssize_t
pin_assignment_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)611 pin_assignment_store(struct device *dev, struct device_attribute *attr,
612 		     const char *buf, size_t size)
613 {
614 	struct dp_altmode *dp = dev_get_drvdata(dev);
615 	u8 assignments;
616 	u32 conf;
617 	int ret;
618 
619 	ret = sysfs_match_string(pin_assignments, buf);
620 	if (ret < 0)
621 		return ret;
622 
623 	conf = DP_CONF_SET_PIN_ASSIGN(BIT(ret));
624 	ret = 0;
625 
626 	mutex_lock(&dp->lock);
627 
628 	if (conf & dp->data.conf)
629 		goto out_unlock;
630 
631 	if (dp->state != DP_STATE_IDLE) {
632 		ret = -EBUSY;
633 		goto out_unlock;
634 	}
635 
636 	assignments = get_current_pin_assignments(dp);
637 
638 	if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
639 		ret = -EINVAL;
640 		goto out_unlock;
641 	}
642 
643 	conf |= dp->data.conf & ~DP_CONF_PIN_ASSIGNEMENT_MASK;
644 
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);
649 		if (ret)
650 			goto out_unlock;
651 	}
652 
653 	dp->data.conf = conf;
654 
655 out_unlock:
656 	mutex_unlock(&dp->lock);
657 
658 	return ret ? ret : size;
659 }
660 
pin_assignment_show(struct device * dev,struct device_attribute * attr,char * buf)661 static ssize_t pin_assignment_show(struct device *dev,
662 				   struct device_attribute *attr, char *buf)
663 {
664 	struct dp_altmode *dp = dev_get_drvdata(dev);
665 	u8 assignments;
666 	int len = 0;
667 	u8 cur;
668 	int i;
669 
670 	mutex_lock(&dp->lock);
671 
672 	cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
673 
674 	assignments = get_current_pin_assignments(dp);
675 
676 	for (i = 0; assignments; assignments >>= 1, i++) {
677 		if (assignments & 1) {
678 			if (i == cur)
679 				len += sprintf(buf + len, "[%s] ",
680 					       pin_assignments[i]);
681 			else
682 				len += sprintf(buf + len, "%s ",
683 					       pin_assignments[i]);
684 		}
685 	}
686 
687 	mutex_unlock(&dp->lock);
688 
689 	/* get_current_pin_assignments can return 0 when no matching pin assignments are found */
690 	if (len == 0)
691 		len++;
692 
693 	buf[len - 1] = '\n';
694 	return len;
695 }
696 static DEVICE_ATTR_RW(pin_assignment);
697 
hpd_show(struct device * dev,struct device_attribute * attr,char * buf)698 static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf)
699 {
700 	struct dp_altmode *dp = dev_get_drvdata(dev);
701 
702 	return sysfs_emit(buf, "%d\n", dp->hpd);
703 }
704 static DEVICE_ATTR_RO(hpd);
705 
706 static struct attribute *displayport_attrs[] = {
707 	&dev_attr_configuration.attr,
708 	&dev_attr_pin_assignment.attr,
709 	&dev_attr_hpd.attr,
710 	NULL
711 };
712 
713 static const struct attribute_group displayport_group = {
714 	.name = "displayport",
715 	.attrs = displayport_attrs,
716 };
717 
718 static const struct attribute_group *displayport_groups[] = {
719 	&displayport_group,
720 	NULL,
721 };
722 
dp_altmode_probe(struct typec_altmode * alt)723 int dp_altmode_probe(struct typec_altmode *alt)
724 {
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;
729 
730 	/* FIXME: Port can only be DFP_U. */
731 
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)))
737 		return -ENODEV;
738 
739 	dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
740 	if (!dp)
741 		return -ENOMEM;
742 
743 	INIT_WORK(&dp->work, dp_altmode_work);
744 	mutex_init(&dp->lock);
745 	dp->port = port;
746 	dp->alt = alt;
747 
748 	alt->desc = "DisplayPort";
749 	typec_altmode_set_ops(alt, &dp_altmode_ops);
750 
751 	if (plug) {
752 		plug->desc = "Displayport";
753 		plug->cable_ops = &dp_cable_ops;
754 	}
755 
756 	dp->plug_prime = plug;
757 
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);
761 	else
762 		dp->connector_fwnode = fwnode_handle_get(fwnode); /* embedded DP */
763 	if (IS_ERR(dp->connector_fwnode))
764 		dp->connector_fwnode = NULL;
765 
766 	typec_altmode_set_drvdata(alt, dp);
767 	if (plug)
768 		typec_altmode_set_drvdata(plug, dp);
769 
770 	dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
771 	schedule_work(&dp->work);
772 
773 	return 0;
774 }
775 EXPORT_SYMBOL_GPL(dp_altmode_probe);
776 
dp_altmode_remove(struct typec_altmode * alt)777 void dp_altmode_remove(struct typec_altmode *alt)
778 {
779 	struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
780 
781 	cancel_work_sync(&dp->work);
782 	typec_altmode_put_plug(dp->plug_prime);
783 
784 	if (dp->connector_fwnode) {
785 		drm_connector_oob_hotplug_event(dp->connector_fwnode,
786 						connector_status_disconnected);
787 
788 		fwnode_handle_put(dp->connector_fwnode);
789 	}
790 }
791 EXPORT_SYMBOL_GPL(dp_altmode_remove);
792 
793 static const struct typec_device_id dp_typec_id[] = {
794 	{ USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE },
795 	{ },
796 };
797 MODULE_DEVICE_TABLE(typec, dp_typec_id);
798 
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,
803 	.driver = {
804 		.name = "typec_displayport",
805 		.dev_groups = displayport_groups,
806 	},
807 };
808 module_typec_altmode_driver(dp_altmode_driver);
809 
810 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
811 MODULE_LICENSE("GPL v2");
812 MODULE_DESCRIPTION("DisplayPort Alternate Mode");
813