Commit 1742b765 authored by Chunfeng Yun's avatar Chunfeng Yun Committed by Greg Kroah-Hartman

usb: mtu3: support function remote wakeup

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: default avatarChunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/20220708071903.25752-5-chunfeng.yun@mediatek.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 683ff6e4
...@@ -433,6 +433,13 @@ static int mtu3_gadget_get_frame(struct usb_gadget *gadget) ...@@ -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); 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) static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
{ {
struct mtu3 *mtu = gadget_to_mtu3(gadget); struct mtu3 *mtu = gadget_to_mtu3(gadget);
...@@ -446,7 +453,18 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget) ...@@ -446,7 +453,18 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
spin_lock_irqsave(&mtu->lock, flags); spin_lock_irqsave(&mtu->lock, flags);
if (mtu->g.speed >= USB_SPEED_SUPER) { 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); 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 { } else {
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME); mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
spin_unlock_irqrestore(&mtu->lock, flags); spin_unlock_irqrestore(&mtu->lock, flags);
......
...@@ -226,6 +226,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) ...@@ -226,6 +226,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
break; break;
case USB_RECIP_INTERFACE: case USB_RECIP_INTERFACE:
/* status of function remote wakeup, forward request */
handled = 0;
break; break;
case USB_RECIP_ENDPOINT: case USB_RECIP_ENDPOINT:
epnum = (u8) le16_to_cpu(setup->wIndex); epnum = (u8) le16_to_cpu(setup->wIndex);
...@@ -397,10 +399,8 @@ static int ep0_handle_feature(struct mtu3 *mtu, ...@@ -397,10 +399,8 @@ static int ep0_handle_feature(struct mtu3 *mtu,
/* superspeed only */ /* superspeed only */
if (value == USB_INTRF_FUNC_SUSPEND && if (value == USB_INTRF_FUNC_SUSPEND &&
mtu->g.speed >= USB_SPEED_SUPER) { mtu->g.speed >= USB_SPEED_SUPER) {
/* /* forward the request for function suspend */
* forward the request because function drivers mtu->may_wakeup = !!(index & USB_INTRF_FUNC_SUSPEND_RW);
* should handle it
*/
handled = 0; handled = 0;
} }
break; break;
......
...@@ -341,6 +341,8 @@ ...@@ -341,6 +341,8 @@
#define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C) #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_POWER_CONTROL (SSUSB_USB3_SYS_CSR_BASE + 0x0210)
#define U3D_LINK_ERR_COUNT (SSUSB_USB3_SYS_CSR_BASE + 0x0214) #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 ----------------*/ /*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/
...@@ -365,6 +367,20 @@ ...@@ -365,6 +367,20 @@
#define CLR_LINK_ERR_CNT BIT(16) #define CLR_LINK_ERR_CNT BIT(16)
#define LINK_ERROR_COUNT GENMASK(15, 0) #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 ----------------*/ /*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/
#define U3D_POWER_MANAGEMENT (SSUSB_USB2_CSR_BASE + 0x0004) #define U3D_POWER_MANAGEMENT (SSUSB_USB2_CSR_BASE + 0x0004)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment