diff mbox series

[5/5] usb: mtu3: support function remote wakeup

Message ID 20220708071903.25752-5-chunfeng.yun@mediatek.com
State New
Headers show
Series [1/5] usb: mtu3: fix coverity of string buffer | expand

Commit Message

Chunfeng Yun (云春峰) July 8, 2022, 7:19 a.m. UTC
Add function wake notification to support function remote wakeup,
currently assume the composite device only enable function wake
for the first interface.

Forward request to function driver when the recipient is an interface,
including:
GetStatus() request to the first interface in a function returns the
information about 'function remote wakeup' and 'function remote wakeup
capalbe';
SetFeature request of FUNCTION_SUSPEND to an interface recipient, the
controller driver saves the suspend option;

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
 drivers/usb/mtu3/mtu3_gadget.c     | 18 ++++++++++++++++++
 drivers/usb/mtu3/mtu3_gadget_ep0.c |  8 ++++----
 drivers/usb/mtu3/mtu3_hw_regs.h    | 16 ++++++++++++++++
 3 files changed, 38 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index a751e0533c2d..291ec53c6c75 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -433,6 +433,13 @@  static int mtu3_gadget_get_frame(struct usb_gadget *gadget)
 	return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM);
 }
 
+static void function_wake_notif(struct mtu3 *mtu, u8 intf)
+{
+	mtu3_writel(mtu->mac_base, U3D_DEV_NOTIF_0,
+		    TYPE_FUNCTION_WAKE | DEV_NOTIF_VAL_FW(intf));
+	mtu3_setbits(mtu->mac_base, U3D_DEV_NOTIF_0, SEND_DEV_NOTIF);
+}
+
 static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
 {
 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
@@ -446,7 +453,18 @@  static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
 
 	spin_lock_irqsave(&mtu->lock, flags);
 	if (mtu->g.speed >= USB_SPEED_SUPER) {
+		/*
+		 * class driver may do function wakeup even UFP is in U0,
+		 * and UX_EXIT only takes effect in U1/U2/U3;
+		 */
 		mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
+		/*
+		 * Assume there's only one function on the composite device
+		 * and enable remote wake for the first interface.
+		 * FIXME if the IAD (interface association descriptor) shows
+		 * there is more than one function.
+		 */
+		function_wake_notif(mtu, 0);
 	} else {
 		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
 		spin_unlock_irqrestore(&mtu->lock, flags);
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
index 7e7013508af6..e4fd1bb14a55 100644
--- a/drivers/usb/mtu3/mtu3_gadget_ep0.c
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -226,6 +226,8 @@  ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
 
 		break;
 	case USB_RECIP_INTERFACE:
+		/* status of function remote wakeup, forward request */
+		handled = 0;
 		break;
 	case USB_RECIP_ENDPOINT:
 		epnum = (u8) le16_to_cpu(setup->wIndex);
@@ -397,10 +399,8 @@  static int ep0_handle_feature(struct mtu3 *mtu,
 		/* superspeed only */
 		if (value == USB_INTRF_FUNC_SUSPEND &&
 		    mtu->g.speed >= USB_SPEED_SUPER) {
-			/*
-			 * forward the request because function drivers
-			 * should handle it
-			 */
+			/* forward the request for function suspend */
+			mtu->may_wakeup = !!(index & USB_INTRF_FUNC_SUSPEND_RW);
 			handled = 0;
 		}
 		break;
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 072db1f6470e..519a58301f45 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -341,6 +341,8 @@ 
 #define U3D_LINK_UX_INACT_TIMER	(SSUSB_USB3_SYS_CSR_BASE + 0x020C)
 #define U3D_LINK_POWER_CONTROL	(SSUSB_USB3_SYS_CSR_BASE + 0x0210)
 #define U3D_LINK_ERR_COUNT	(SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+#define U3D_DEV_NOTIF_0		(SSUSB_USB3_SYS_CSR_BASE + 0x0290)
+#define U3D_DEV_NOTIF_1		(SSUSB_USB3_SYS_CSR_BASE + 0x0294)
 
 /*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/
 
@@ -365,6 +367,20 @@ 
 #define CLR_LINK_ERR_CNT	BIT(16)
 #define LINK_ERROR_COUNT	GENMASK(15, 0)
 
+/* U3D_DEV_NOTIF_0 */
+#define DEV_NOTIF_TYPE_SPECIFIC_LOW_MSK		GENMASK(31, 8)
+#define DEV_NOTIF_VAL_FW(x)		(((x) & 0xff) << 8)
+#define DEV_NOTIF_VAL_LTM(x)	(((x) & 0xfff) << 8)
+#define DEV_NOTIF_VAL_IAM(x)	(((x) & 0xffff) << 8)
+#define DEV_NOTIF_TYPE_MSK		GENMASK(7, 4)
+/* Notification Type */
+#define TYPE_FUNCTION_WAKE			(0x1 << 4)
+#define TYPE_LATENCY_TOLERANCE_MESSAGE		(0x2 << 4)
+#define TYPE_BUS_INTERVAL_ADJUST_MESSAGE	(0x3 << 4)
+#define TYPE_HOST_ROLE_REQUEST			(0x4 << 4)
+#define TYPE_SUBLINK_SPEED			(0x5 << 4)
+#define SEND_DEV_NOTIF			BIT(0)
+
 /*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/
 
 #define U3D_POWER_MANAGEMENT		(SSUSB_USB2_CSR_BASE + 0x0004)