File Index
Files and directories
Sign in
FILE

intel_pmc_mux.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/mux/intel_pmc_mux.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for Intel PMC USB mux control
  4 *
  5 * Copyright (C) 2020 Intel Corporation
  6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
  7 */
  8
  9#include <linux/acpi.h>
 10#include <linux/module.h>
 11#include <linux/platform_data/x86/intel_scu_ipc.h>
 12#include <linux/platform_device.h>
 13#include <linux/property.h>
 14#include <linux/usb/pd.h>
 15#include <linux/usb/role.h>
 16#include <linux/usb/typec_mux.h>
 17#include <linux/usb/typec_dp.h>
 18#include <linux/usb/typec_tbt.h>
 19#include <linux/debugfs.h>
 20#include <linux/usb.h>
 21
 22#define PMC_USBC_CMD		0xa7
 23
 24/* Response status bits */
 25#define PMC_USB_RESP_STATUS_FAILURE	BIT(0)
 26#define PMC_USB_RESP_STATUS_FATAL	BIT(1)
 27
 28/* "Usage" OOB Message field values */
 29enum {
 30	PMC_USB_CONNECT,
 31	PMC_USB_DISCONNECT,
 32	PMC_USB_SAFE_MODE,
 33	PMC_USB_ALT_MODE,
 34	PMC_USB_DP_HPD,
 35};
 36
 37#define PMC_USB_MSG_USB2_PORT_SHIFT	0
 38#define PMC_USB_MSG_USB3_PORT_SHIFT	4
 39#define PMC_USB_MSG_UFP_SHIFT		4
 40#define PMC_USB_MSG_ORI_HSL_SHIFT	5
 41#define PMC_USB_MSG_ORI_AUX_SHIFT	6
 42
 43/* Alt Mode Request */
 44struct altmode_req {
 45	u8 usage;
 46	u8 mode_type;
 47	u8 mode_id;
 48	u8 reserved;
 49	u32 mode_data;
 50} __packed;
 51
 52#define PMC_USB_MODE_TYPE_SHIFT		4
 53
 54enum {
 55	PMC_USB_MODE_TYPE_USB,
 56	PMC_USB_MODE_TYPE_DP,
 57	PMC_USB_MODE_TYPE_TBT,
 58};
 59
 60/* Common Mode Data bits */
 61#define PMC_USB_ALTMODE_RETIMER_CABLE	BIT(2)
 62
 63#define PMC_USB_ALTMODE_ORI_SHIFT	1
 64#define PMC_USB_ALTMODE_UFP_SHIFT	3
 65
 66/* DP specific Mode Data bits */
 67#define PMC_USB_ALTMODE_DP_MODE_SHIFT	8
 68
 69/* TBT specific Mode Data bits */
 70#define PMC_USB_ALTMODE_TBT_TYPE	BIT(17)
 71#define PMC_USB_ALTMODE_CABLE_TYPE	BIT(18)
 72#define PMC_USB_ALTMODE_ACTIVE_LINK	BIT(20)
 73#define PMC_USB_ALTMODE_ACTIVE_CABLE	BIT(22)
 74#define PMC_USB_ALTMODE_FORCE_LSR	BIT(23)
 75#define PMC_USB_ALTMODE_CABLE_SPD(_s_)	(((_s_) & GENMASK(2, 0)) << 25)
 76#define   PMC_USB_ALTMODE_CABLE_USB31	1
 77#define   PMC_USB_ALTMODE_CABLE_10GPS	2
 78#define   PMC_USB_ALTMODE_CABLE_20GPS	3
 79#define PMC_USB_ALTMODE_TBT_GEN(_g_)	(((_g_) & GENMASK(1, 0)) << 28)
 80
 81/* Display HPD Request bits */
 82#define PMC_USB_DP_HPD_LVL		BIT(4)
 83#define PMC_USB_DP_HPD_IRQ		BIT(5)
 84
 85/*
 86 * Input Output Manager (IOM) PORT STATUS
 87 */
 88#define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK		GENMASK(9, 6)
 89#define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT		6
 90#define IOM_PORT_STATUS_ACTIVITY_TYPE_USB		0x03
 91/* activity type: Safe Mode */
 92#define IOM_PORT_STATUS_ACTIVITY_TYPE_SAFE_MODE		0x04
 93/* activity type: Display Port */
 94#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP		0x05
 95/* activity type: Display Port Multi Function Device */
 96#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP_MFD		0x06
 97/* activity type: Thunderbolt */
 98#define IOM_PORT_STATUS_ACTIVITY_TYPE_TBT		0x07
 99#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_USB	0x0c
100#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_TBT_USB	0x0d
101/* Upstream Facing Port Information */
102#define IOM_PORT_STATUS_UFP				BIT(10)
103/* Display Port Hot Plug Detect status */
104#define IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK		GENMASK(13, 12)
105#define IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT		12
106#define IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT		0x01
107#define IOM_PORT_STATUS_DHPD_HPD_SOURCE_TBT		BIT(14)
108#define IOM_PORT_STATUS_CONNECTED			BIT(31)
109
110#define IOM_PORT_ACTIVITY_IS(_status_, _type_)				\
111	((((_status_) & IOM_PORT_STATUS_ACTIVITY_TYPE_MASK) >>		\
112	  IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT) ==			\
113	 (IOM_PORT_STATUS_ACTIVITY_TYPE_##_type_))
114
115#define IOM_PORT_HPD_ASSERTED(_status_)					\
116	((((_status_) & IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK) >>	\
117	  IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT) &			\
118	 IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT)
119
120/* IOM port status register */
121#define IOM_PORT_STATUS_REGS(_offset_, _size_)	((_offset_) | (_size_))
122#define IOM_PORT_STATUS_REGS_SZ_MASK		BIT(0)
123#define IOM_PORT_STATUS_REGS_SZ_4		0
124#define IOM_PORT_STATUS_REGS_SZ_8		1
125#define IOM_PORT_STATUS_REGS_OFFSET(_d_)				\
126	((_d_) & ~IOM_PORT_STATUS_REGS_SZ_MASK)
127#define IOM_PORT_STATUS_REGS_SIZE(_d_)					\
128	(4 << ((_d_) & IOM_PORT_STATUS_REGS_SZ_MASK))
129
130struct pmc_usb;
131
132struct pmc_usb_port {
133	int num;
134	u32 iom_status;
135	struct pmc_usb *pmc;
136	struct typec_mux_dev *typec_mux;
137	struct typec_switch_dev *typec_sw;
138	struct usb_role_switch *usb_sw;
139
140	enum typec_orientation orientation;
141	enum usb_role role;
142
143	u8 usb2_port;
144	u8 usb3_port;
145
146	enum typec_orientation sbu_orientation;
147	enum typec_orientation hsl_orientation;
148};
149
150struct pmc_usb {
151	u8 num_ports;
152	struct device *dev;
153	struct intel_scu_ipc_dev *ipc;
154	struct pmc_usb_port *port;
155	struct acpi_device *iom_adev;
156	void __iomem *iom_base;
157	u32 iom_port_status_offset;
158	u8 iom_port_status_size;
159
160	struct dentry *dentry;
161};
162
163static struct dentry *pmc_mux_debugfs_root;
164
165static void update_port_status(struct pmc_usb_port *port)
166{
167	u8 port_num;
168
169	/* SoC expects the USB Type-C port numbers to start with 0 */
170	port_num = port->usb3_port - 1;
171
172	port->iom_status = readl(port->pmc->iom_base +
173				 port->pmc->iom_port_status_offset +
174				 port_num * port->pmc->iom_port_status_size);
175}
176
177static int sbu_orientation(struct pmc_usb_port *port)
178{
179	if (port->sbu_orientation)
180		return port->sbu_orientation - 1;
181
182	return port->orientation - 1;
183}
184
185static int hsl_orientation(struct pmc_usb_port *port)
186{
187	if (port->hsl_orientation)
188		return port->hsl_orientation - 1;
189
190	return port->orientation - 1;
191}
192
193static bool is_pmc_mux_tbt(struct acpi_device *adev)
194{
195	return acpi_dev_hid_uid_match(adev, "INTC1072", NULL) ||
196	       acpi_dev_hid_uid_match(adev, "INTC1079", NULL);
197}
198
199static int pmc_usb_send_command(struct intel_scu_ipc_dev *ipc, u8 *msg, u32 len)
200{
201	u8 response[4];
202	u8 status_res;
203	int ret;
204
205	/*
206	 * Error bit will always be 0 with the USBC command.
207	 * Status can be checked from the response message if the
208	 * function intel_scu_ipc_dev_command succeeds.
209	 */
210	ret = intel_scu_ipc_dev_command(ipc, PMC_USBC_CMD, 0, msg,
211					len, response, sizeof(response));
212
213	if (ret)
214		return ret;
215
216	status_res = (msg[0] & 0xf) < PMC_USB_SAFE_MODE ?
217		     response[2] : response[1];
218
219	if (status_res & PMC_USB_RESP_STATUS_FAILURE) {
220		if (status_res & PMC_USB_RESP_STATUS_FATAL)
221			return -EIO;
222
223		return -EBUSY;
224	}
225
226	return 0;
227}
228
229static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len)
230{
231	int retry_count = 3;
232	int ret;
233
234	/*
235	 * If PMC is busy then retry the command once again
236	 */
237	while (retry_count--) {
238		ret = pmc_usb_send_command(port->pmc->ipc, msg, len);
239		if (ret != -EBUSY)
240			break;
241	}
242
243	return ret;
244}
245
246static int
247pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp)
248{
249	u8 msg[2] = { };
250	int ret;
251
252	msg[0] = PMC_USB_DP_HPD;
253	msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
254
255	/* Configure HPD first if HPD,IRQ comes together */
256	if (!IOM_PORT_HPD_ASSERTED(port->iom_status) &&
257	    dp->status & DP_STATUS_IRQ_HPD &&
258	    dp->status & DP_STATUS_HPD_STATE) {
259		msg[1] = PMC_USB_DP_HPD_LVL;
260		ret = pmc_usb_command(port, msg, sizeof(msg));
261		if (ret)
262			return ret;
263	}
264
265	if (dp->status & DP_STATUS_IRQ_HPD)
266		msg[1] = PMC_USB_DP_HPD_IRQ;
267
268	if (dp->status & DP_STATUS_HPD_STATE)
269		msg[1] |= PMC_USB_DP_HPD_LVL;
270
271	return pmc_usb_command(port, msg, sizeof(msg));
272}
273
274static int
275pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
276{
277	struct typec_displayport_data *data = state->data;
278	struct altmode_req req = { };
279	int ret;
280
281	if (IOM_PORT_ACTIVITY_IS(port->iom_status, DP) ||
282	    IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) {
283		if (IOM_PORT_HPD_ASSERTED(port->iom_status) &&
284		    (!(data->status & DP_STATUS_IRQ_HPD) &&
285		     data->status & DP_STATUS_HPD_STATE))
286			return 0;
287
288		return pmc_usb_mux_dp_hpd(port, state->data);
289	}
290
291	req.usage = PMC_USB_ALT_MODE;
292	req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
293	req.mode_type = PMC_USB_MODE_TYPE_DP << PMC_USB_MODE_TYPE_SHIFT;
294
295	req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
296	req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
297
298	req.mode_data |= (state->mode - TYPEC_STATE_MODAL) <<
299			 PMC_USB_ALTMODE_DP_MODE_SHIFT;
300
301	if (!is_pmc_mux_tbt(port->pmc->iom_adev)) {
302		u8 cable_speed = (data->conf & DP_CONF_SIGNALLING_MASK) >>
303				  DP_CONF_SIGNALLING_SHIFT;
304
305		u8 cable_type = (data->conf & DP_CONF_CABLE_TYPE_MASK) >>
306				 DP_CONF_CABLE_TYPE_SHIFT;
307
308		req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
309
310		if (cable_type == DP_CONF_CABLE_TYPE_OPTICAL)
311			req.mode_data |= PMC_USB_ALTMODE_CABLE_TYPE;
312		else if (cable_type == DP_CONF_CABLE_TYPE_RE_TIMER)
313			req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE |
314					 PMC_USB_ALTMODE_RETIMER_CABLE;
315		else if (cable_type == DP_CONF_CABLE_TYPE_RE_DRIVER)
316			req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE;
317	}
318
319	ret = pmc_usb_command(port, (void *)&req, sizeof(req));
320	if (ret)
321		return ret;
322
323	if (data->status & (DP_STATUS_IRQ_HPD | DP_STATUS_HPD_STATE))
324		return pmc_usb_mux_dp_hpd(port, state->data);
325
326	return 0;
327}
328
329static int
330pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
331{
332	struct typec_thunderbolt_data *data = state->data;
333	u8 cable_rounded = TBT_CABLE_ROUNDED_SUPPORT(data->cable_mode);
334	u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode);
335	struct altmode_req req = { };
336
337	if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) ||
338	    IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB))
339		return 0;
340
341	req.usage = PMC_USB_ALT_MODE;
342	req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
343	req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT;
344
345	req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
346	req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
347
348	if (TBT_ADAPTER(data->device_mode) == TBT_ADAPTER_TBT3)
349		req.mode_data |= PMC_USB_ALTMODE_TBT_TYPE;
350
351	if (data->cable_mode & TBT_CABLE_OPTICAL)
352		req.mode_data |= PMC_USB_ALTMODE_CABLE_TYPE;
353
354	if (data->cable_mode & TBT_CABLE_LINK_TRAINING)
355		req.mode_data |= PMC_USB_ALTMODE_ACTIVE_LINK;
356
357	if (acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1072", NULL) ||
358	    acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1079", NULL)) {
359		if ((data->enter_vdo & TBT_ENTER_MODE_ACTIVE_CABLE) ||
360		    (data->cable_mode & TBT_CABLE_RETIMER))
361			req.mode_data |= PMC_USB_ALTMODE_RETIMER_CABLE;
362	} else {
363		if (data->enter_vdo & TBT_ENTER_MODE_ACTIVE_CABLE)
364			req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE;
365
366		if (data->cable_mode & TBT_CABLE_RETIMER)
367			req.mode_data |= PMC_USB_ALTMODE_RETIMER_CABLE;
368	}
369
370	req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
371
372	req.mode_data |= PMC_USB_ALTMODE_TBT_GEN(cable_rounded);
373
374	return pmc_usb_command(port, (void *)&req, sizeof(req));
375}
376
377static int
378pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state)
379{
380	struct enter_usb_data *data = state->data;
381	struct altmode_req req = { };
382	u8 cable_speed;
383
384	if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) ||
385	    IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB))
386		return 0;
387
388	req.usage = PMC_USB_ALT_MODE;
389	req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
390	req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT;
391
392	/* USB4 Mode */
393	req.mode_data = PMC_USB_ALTMODE_FORCE_LSR;
394
395	if (data->active_link_training)
396		req.mode_data |= PMC_USB_ALTMODE_ACTIVE_LINK;
397
398	req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
399	req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
400
401	switch ((data->eudo & EUDO_CABLE_TYPE_MASK) >> EUDO_CABLE_TYPE_SHIFT) {
402	case EUDO_CABLE_TYPE_PASSIVE:
403		break;
404	case EUDO_CABLE_TYPE_OPTICAL:
405		req.mode_data |= PMC_USB_ALTMODE_CABLE_TYPE;
406		fallthrough;
407	case EUDO_CABLE_TYPE_RE_TIMER:
408		if (!acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1072", NULL) ||
409		    !acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1079", NULL))
410			req.mode_data |= PMC_USB_ALTMODE_RETIMER_CABLE;
411		fallthrough;
412	default:
413		if (acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1072", NULL) ||
414		    acpi_dev_hid_uid_match(port->pmc->iom_adev, "INTC1079", NULL))
415			req.mode_data |= PMC_USB_ALTMODE_RETIMER_CABLE;
416		else
417			req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE;
418
419		/* Configure data rate to rounded in the case of Active TBT3
420		 * and USB4 cables.
421		 */
422		req.mode_data |= PMC_USB_ALTMODE_TBT_GEN(1);
423		break;
424	}
425
426	cable_speed = (data->eudo & EUDO_CABLE_SPEED_MASK) >> EUDO_CABLE_SPEED_SHIFT;
427	req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
428
429	return pmc_usb_command(port, (void *)&req, sizeof(req));
430}
431
432static int pmc_usb_mux_safe_state(struct pmc_usb_port *port,
433				  struct typec_mux_state *state)
434{
435	u8 msg;
436
437	if (IOM_PORT_ACTIVITY_IS(port->iom_status, SAFE_MODE))
438		return 0;
439
440	if ((IOM_PORT_ACTIVITY_IS(port->iom_status, DP) ||
441	     IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) &&
442	     state->alt && state->alt->svid == USB_TYPEC_DP_SID)
443		return 0;
444
445	if ((IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) ||
446	     IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) &&
447	     state->alt && state->alt->svid == USB_TYPEC_TBT_SID)
448		return 0;
449
450	msg = PMC_USB_SAFE_MODE;
451	msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
452
453	return pmc_usb_command(port, &msg, sizeof(msg));
454}
455
456static int pmc_usb_disconnect(struct pmc_usb_port *port)
457{
458	struct typec_displayport_data data = { };
459	u8 msg[2];
460
461	if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED))
462		return 0;
463
464	/* Clear DisplayPort HPD if it's still asserted. */
465	if (IOM_PORT_HPD_ASSERTED(port->iom_status))
466		pmc_usb_mux_dp_hpd(port, &data);
467
468	msg[0] = PMC_USB_DISCONNECT;
469	msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
470
471	msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
472
473	return pmc_usb_command(port, msg, sizeof(msg));
474}
475
476static int pmc_usb_connect(struct pmc_usb_port *port, enum usb_role role)
477{
478	u8 ufp = role == USB_ROLE_DEVICE ? 1 : 0;
479	u8 msg[2];
480	int ret;
481
482	if (port->orientation == TYPEC_ORIENTATION_NONE)
483		return -EINVAL;
484
485	if (port->iom_status & IOM_PORT_STATUS_CONNECTED) {
486		if (port->role == role || port->role == USB_ROLE_NONE)
487			return 0;
488
489		/* Role swap */
490		ret = pmc_usb_disconnect(port);
491		if (ret)
492			return ret;
493	}
494
495	msg[0] = PMC_USB_CONNECT;
496	msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
497
498	msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
499	msg[1] |= ufp << PMC_USB_MSG_UFP_SHIFT;
500	msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT;
501	msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT;
502
503	return pmc_usb_command(port, msg, sizeof(msg));
504}
505
506static int
507pmc_usb_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
508{
509	struct pmc_usb_port *port = typec_mux_get_drvdata(mux);
510
511	update_port_status(port);
512
513	if (port->orientation == TYPEC_ORIENTATION_NONE || port->role == USB_ROLE_NONE)
514		return 0;
515
516	if (state->mode == TYPEC_STATE_SAFE)
517		return pmc_usb_mux_safe_state(port, state);
518	if (state->mode == TYPEC_STATE_USB)
519		return pmc_usb_connect(port, port->role);
520
521	if (state->alt) {
522		switch (state->alt->svid) {
523		case USB_TYPEC_TBT_SID:
524			return pmc_usb_mux_tbt(port, state);
525		case USB_TYPEC_DP_SID:
526			return pmc_usb_mux_dp(port, state);
527		}
528	} else {
529		switch (state->mode) {
530		case TYPEC_MODE_USB2:
531			/* REVISIT: Try with usb3_port set to 0? */
532			break;
533		case TYPEC_MODE_USB3:
534			return pmc_usb_connect(port, port->role);
535		case TYPEC_MODE_USB4:
536			return pmc_usb_mux_usb4(port, state);
537		}
538	}
539
540	return -EOPNOTSUPP;
541}
542
543static int pmc_usb_set_orientation(struct typec_switch_dev *sw,
544				   enum typec_orientation orientation)
545{
546	struct pmc_usb_port *port = typec_switch_get_drvdata(sw);
547
548	update_port_status(port);
549
550	port->orientation = orientation;
551
552	return 0;
553}
554
555static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role)
556{
557	struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw);
558	int ret;
559
560	update_port_status(port);
561
562	if (role == USB_ROLE_NONE)
563		ret = pmc_usb_disconnect(port);
564	else
565		ret = pmc_usb_connect(port, role);
566
567	port->role = role;
568
569	return ret;
570}
571
572static int pmc_usb_register_port(struct pmc_usb *pmc, int index,
573				 struct fwnode_handle *fwnode)
574{
575	struct pmc_usb_port *port = &pmc->port[index];
576	struct usb_role_switch_desc desc = { };
577	struct typec_switch_desc sw_desc = { };
578	struct typec_mux_desc mux_desc = { };
579	const char *str;
580	int ret;
581
582	ret = fwnode_property_read_u8(fwnode, "usb2-port-number", &port->usb2_port);
583	if (ret)
584		return ret;
585
586	ret = fwnode_property_read_u8(fwnode, "usb3-port-number", &port->usb3_port);
587	if (ret)
588		return ret;
589
590	ret = fwnode_property_read_string(fwnode, "sbu-orientation", &str);
591	if (!ret)
592		port->sbu_orientation = typec_find_orientation(str);
593
594	ret = fwnode_property_read_string(fwnode, "hsl-orientation", &str);
595	if (!ret)
596		port->hsl_orientation = typec_find_orientation(str);
597
598	port->num = index;
599	port->pmc = pmc;
600
601	sw_desc.fwnode = fwnode;
602	sw_desc.drvdata = port;
603	sw_desc.name = fwnode_get_name(fwnode);
604	sw_desc.set = pmc_usb_set_orientation;
605
606	port->typec_sw = typec_switch_register(pmc->dev, &sw_desc);
607	if (IS_ERR(port->typec_sw))
608		return PTR_ERR(port->typec_sw);
609
610	mux_desc.fwnode = fwnode;
611	mux_desc.drvdata = port;
612	mux_desc.name = fwnode_get_name(fwnode);
613	mux_desc.set = pmc_usb_mux_set;
614
615	port->typec_mux = typec_mux_register(pmc->dev, &mux_desc);
616	if (IS_ERR(port->typec_mux)) {
617		ret = PTR_ERR(port->typec_mux);
618		goto err_unregister_switch;
619	}
620
621	desc.fwnode = fwnode;
622	desc.driver_data = port;
623	desc.name = fwnode_get_name(fwnode);
624	desc.set = pmc_usb_set_role;
625	desc.allow_userspace_control = true;
626
627	port->usb_sw = usb_role_switch_register(pmc->dev, &desc);
628	if (IS_ERR(port->usb_sw)) {
629		ret = PTR_ERR(port->usb_sw);
630		goto err_unregister_mux;
631	}
632
633	return 0;
634
635err_unregister_mux:
636	typec_mux_unregister(port->typec_mux);
637
638err_unregister_switch:
639	typec_switch_unregister(port->typec_sw);
640
641	return ret;
642}
643
644/* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */
645static const struct acpi_device_id iom_acpi_ids[] = {
646	/* TigerLake */
647	{ "INTC1072", IOM_PORT_STATUS_REGS(0x560, IOM_PORT_STATUS_REGS_SZ_4) },
648
649	/* AlderLake */
650	{ "INTC1079", IOM_PORT_STATUS_REGS(0x160, IOM_PORT_STATUS_REGS_SZ_4) },
651
652	/* Meteor Lake */
653	{ "INTC107A", IOM_PORT_STATUS_REGS(0x160, IOM_PORT_STATUS_REGS_SZ_4) },
654
655	/* Lunar Lake */
656	{ "INTC10EA", IOM_PORT_STATUS_REGS(0x150, IOM_PORT_STATUS_REGS_SZ_8) },
657	{}
658};
659
660static int pmc_usb_probe_iom(struct pmc_usb *pmc)
661{
662	struct list_head resource_list;
663	struct resource_entry *rentry;
664	static const struct acpi_device_id *dev_id;
665	struct acpi_device *adev = NULL;
666	int ret;
667
668	for (dev_id = &iom_acpi_ids[0]; dev_id->id[0]; dev_id++) {
669		adev = acpi_dev_get_first_match_dev(dev_id->id, NULL, -1);
670		if (adev)
671			break;
672	}
673	if (!adev)
674		return -ENODEV;
675
676	pmc->iom_port_status_offset = IOM_PORT_STATUS_REGS_OFFSET(dev_id->driver_data);
677	pmc->iom_port_status_size = IOM_PORT_STATUS_REGS_SIZE(dev_id->driver_data);
678
679	INIT_LIST_HEAD(&resource_list);
680	ret = acpi_dev_get_memory_resources(adev, &resource_list);
681	if (ret < 0) {
682		acpi_dev_put(adev);
683		return ret;
684	}
685
686	rentry = list_first_entry_or_null(&resource_list, struct resource_entry, node);
687	if (rentry)
688		pmc->iom_base = devm_ioremap_resource(pmc->dev, rentry->res);
689
690	acpi_dev_free_resource_list(&resource_list);
691
692	if (!pmc->iom_base) {
693		acpi_dev_put(adev);
694		return -ENOMEM;
695	}
696
697	if (IS_ERR(pmc->iom_base)) {
698		acpi_dev_put(adev);
699		return PTR_ERR(pmc->iom_base);
700	}
701
702	pmc->iom_adev = adev;
703
704	return 0;
705}
706
707static int port_iom_status_show(struct seq_file *s, void *unused)
708{
709	struct pmc_usb_port *port = s->private;
710
711	update_port_status(port);
712	seq_printf(s, "0x%08x\n", port->iom_status);
713
714	return 0;
715}
716DEFINE_SHOW_ATTRIBUTE(port_iom_status);
717
718static void pmc_mux_port_debugfs_init(struct pmc_usb_port *port)
719{
720	struct dentry *debugfs_dir;
721	char name[8];
722
723	snprintf(name, sizeof(name), "port%d", port->usb3_port - 1);
724
725	debugfs_dir = debugfs_create_dir(name, port->pmc->dentry);
726	debugfs_create_file("iom_status", 0400, debugfs_dir, port,
727			    &port_iom_status_fops);
728}
729
730static int pmc_usb_probe(struct platform_device *pdev)
731{
732	struct fwnode_handle *fwnode = NULL;
733	struct pmc_usb *pmc;
734	int i = 0;
735	int ret;
736
737	pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
738	if (!pmc)
739		return -ENOMEM;
740
741	device_for_each_child_node(&pdev->dev, fwnode)
742		pmc->num_ports++;
743
744	/* The IOM microcontroller has a limitation of max 4 ports. */
745	if (pmc->num_ports > 4) {
746		dev_err(&pdev->dev, "driver limited to 4 ports\n");
747		return -ERANGE;
748	}
749
750	pmc->port = devm_kcalloc(&pdev->dev, pmc->num_ports,
751				 sizeof(struct pmc_usb_port), GFP_KERNEL);
752	if (!pmc->port)
753		return -ENOMEM;
754
755	pmc->ipc = devm_intel_scu_ipc_dev_get(&pdev->dev);
756	if (!pmc->ipc)
757		return -EPROBE_DEFER;
758
759	pmc->dev = &pdev->dev;
760
761	ret = pmc_usb_probe_iom(pmc);
762	if (ret)
763		return ret;
764
765	pmc->dentry = debugfs_create_dir(dev_name(pmc->dev), pmc_mux_debugfs_root);
766
767	/*
768	 * For every physical USB connector (USB2 and USB3 combo) there is a
769	 * child ACPI device node under the PMC mux ACPI device object.
770	 */
771	for (i = 0; i < pmc->num_ports; i++) {
772		fwnode = device_get_next_child_node(pmc->dev, fwnode);
773		if (!fwnode)
774			break;
775
776		ret = pmc_usb_register_port(pmc, i, fwnode);
777		if (ret) {
778			fwnode_handle_put(fwnode);
779			goto err_remove_ports;
780		}
781
782		pmc_mux_port_debugfs_init(&pmc->port[i]);
783	}
784
785	platform_set_drvdata(pdev, pmc);
786
787	return 0;
788
789err_remove_ports:
790	for (i = 0; i < pmc->num_ports; i++) {
791		typec_switch_unregister(pmc->port[i].typec_sw);
792		typec_mux_unregister(pmc->port[i].typec_mux);
793		usb_role_switch_unregister(pmc->port[i].usb_sw);
794	}
795
796	acpi_dev_put(pmc->iom_adev);
797
798	debugfs_remove(pmc->dentry);
799
800	return ret;
801}
802
803static void pmc_usb_remove(struct platform_device *pdev)
804{
805	struct pmc_usb *pmc = platform_get_drvdata(pdev);
806	int i;
807
808	for (i = 0; i < pmc->num_ports; i++) {
809		typec_switch_unregister(pmc->port[i].typec_sw);
810		typec_mux_unregister(pmc->port[i].typec_mux);
811		usb_role_switch_unregister(pmc->port[i].usb_sw);
812	}
813
814	acpi_dev_put(pmc->iom_adev);
815
816	debugfs_remove(pmc->dentry);
817}
818
819static const struct acpi_device_id pmc_usb_acpi_ids[] = {
820	{ "INTC105C", },
821	{ }
822};
823MODULE_DEVICE_TABLE(acpi, pmc_usb_acpi_ids);
824
825static struct platform_driver pmc_usb_driver = {
826	.driver = {
827		.name = "intel_pmc_usb",
828		.acpi_match_table = ACPI_PTR(pmc_usb_acpi_ids),
829	},
830	.probe = pmc_usb_probe,
831	.remove = pmc_usb_remove,
832};
833
834static int __init pmc_usb_init(void)
835{
836	pmc_mux_debugfs_root = debugfs_create_dir("intel_pmc_mux", usb_debug_root);
837
838	return platform_driver_register(&pmc_usb_driver);
839}
840module_init(pmc_usb_init);
841
842static void __exit pmc_usb_exit(void)
843{
844	platform_driver_unregister(&pmc_usb_driver);
845	debugfs_remove(pmc_mux_debugfs_root);
846}
847module_exit(pmc_usb_exit);
848
849MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
850MODULE_LICENSE("GPL v2");
851MODULE_DESCRIPTION("Intel PMC USB mux control");
~/ Read-only file preview.