summaryrefslogtreecommitdiff
path: root/drivers/usb/mtu3
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 21:14:07 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 21:14:07 -0800
commit894025f24bd028942da3e602b87d9f7223109b14 (patch)
tree57f23d2bcdd59aaa6a3e7e26e175e678bfa9a5f4 /drivers/usb/mtu3
parentfb0255fb2941ef6f21742b2bc146d6b9aef4fedc (diff)
parentcdafb6d8b8da7fde266f79b3287ac221aa841879 (diff)
downloadlinux-894025f24bd028942da3e602b87d9f7223109b14.tar.gz
linux-894025f24bd028942da3e602b87d9f7223109b14.tar.bz2
linux-894025f24bd028942da3e602b87d9f7223109b14.zip
Merge tag 'usb-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH: "Here is the big set of USB and PHY driver updates for 4.15-rc1. There is the usual amount of gadget and xhci driver updates, along with phy and chipidea enhancements. There's also a lot of SPDX tags and license boilerplate cleanups as well, which provide some churn in the diffstat. Other major thing is the typec code that moved out of staging and into the "real" part of the drivers/usb/ tree, which was nice to see happen. All of these have been in linux-next with no reported issues for a while" * tag 'usb-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (263 commits) usb: gadget: f_fs: Fix use-after-free in ffs_free_inst USB: usbfs: compute urb->actual_length for isochronous usb: core: message: remember to reset 'ret' to 0 when necessary USB: typec: Remove remaining redundant license text USB: typec: add SPDX identifiers to some files USB: renesas_usbhs: rcar?.h: add SPDX tags USB: chipidea: ci_hdrc_tegra.c: add SPDX line USB: host: xhci-debugfs: add SPDX lines USB: add SPDX identifiers to all remaining Makefiles usb: host: isp1362-hcd: remove a couple of redundant assignments USB: adutux: remove redundant variable minor usb: core: add a new usb_get_ptm_status() helper usb: core: add a 'type' parameter to usb_get_status() usb: core: introduce a new usb_get_std_status() helper usb: core: rename usb_get_status() 'type' argument to 'recip' usb: core: add Status Type definitions USB: gadget: Remove redundant license text USB: gadget: function: Remove redundant license text USB: gadget: udc: Remove redundant license text USB: gadget: legacy: Remove redundant license text ...
Diffstat (limited to 'drivers/usb/mtu3')
-rw-r--r--drivers/usb/mtu3/mtu3.h59
-rw-r--r--drivers/usb/mtu3/mtu3_core.c72
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c72
-rw-r--r--drivers/usb/mtu3/mtu3_dr.h17
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c14
-rw-r--r--drivers/usb/mtu3/mtu3_gadget_ep0.c27
-rw-r--r--drivers/usb/mtu3/mtu3_host.c89
-rw-r--r--drivers/usb/mtu3/mtu3_hw_regs.h24
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c176
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.c113
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.h11
11 files changed, 369 insertions, 305 deletions
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index b26fffc58446..3c888d942a9f 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3.h - MediaTek USB3 DRD header
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __MTU3_H__
@@ -46,6 +37,9 @@ struct mtu3_request;
#define MU3D_EP_RXCR1(epnum) (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
#define MU3D_EP_RXCR2(epnum) (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQHIAR(epnum) (U3D_TXQHIAR1 + (((epnum) - 1) * 0x4))
+#define USB_QMU_RQHIAR(epnum) (U3D_RXQHIAR1 + (((epnum) - 1) * 0x4))
+
#define USB_QMU_RQCSR(epnum) (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQSAR(epnum) (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQCPR(epnum) (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
@@ -91,6 +85,7 @@ enum mtu3_speed {
MTU3_SPEED_FULL = 1,
MTU3_SPEED_HIGH = 3,
MTU3_SPEED_SUPER = 4,
+ MTU3_SPEED_SUPER_PLUS = 5,
};
/**
@@ -112,6 +107,19 @@ enum mtu3_g_ep0_state {
};
/**
+ * MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
+ * by IDPIN signal.
+ * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
+ * IDPIN signal.
+ * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
+ */
+enum mtu3_dr_force_mode {
+ MTU3_DR_FORCE_NONE = 0,
+ MTU3_DR_FORCE_HOST,
+ MTU3_DR_FORCE_DEVICE,
+};
+
+/**
* @base: the base address of fifo
* @limit: the bitmap size in bits
* @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
@@ -138,23 +146,33 @@ struct mtu3_fifo_info {
* Checksum value is calculated over the 16 bytes of the GPD by default;
* @data_buf_len (RX ONLY): This value indicates the length of
* the assigned data buffer
+ * @tx_ext_addr (TX ONLY): [3:0] are 4 extension bits of @buffer,
+ * [7:4] are 4 extension bits of @next_gpd
* @next_gpd: Physical address of the next GPD
* @buffer: Physical address of the data buffer
* @buf_len:
* (TX): This value indicates the length of the assigned data buffer
* (RX): The total length of data received
* @ext_len: reserved
+ * @rx_ext_addr(RX ONLY): [3:0] are 4 extension bits of @buffer,
+ * [7:4] are 4 extension bits of @next_gpd
* @ext_flag:
* bit5 (TX ONLY): Zero Length Packet (ZLP),
*/
struct qmu_gpd {
__u8 flag;
__u8 chksum;
- __le16 data_buf_len;
+ union {
+ __le16 data_buf_len;
+ __le16 tx_ext_addr;
+ };
__le32 next_gpd;
__le32 buffer;
__le16 buf_len;
- __u8 ext_len;
+ union {
+ __u8 ext_len;
+ __u8 rx_ext_addr;
+ };
__u8 ext_flag;
} __packed;
@@ -183,7 +201,6 @@ struct mtu3_gpd_ring {
* xHCI driver initialization, it's necessary for system bootup
* as device.
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
-* @id_*: used to maually switch between host and device modes by idpin
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input.
*/
@@ -194,10 +211,6 @@ struct otg_switch_mtk {
struct notifier_block id_nb;
struct delayed_work extcon_reg_dwork;
bool is_u3_drd;
- /* dual-role switch by debugfs */
- struct pinctrl *id_pinctrl;
- struct pinctrl_state *id_float;
- struct pinctrl_state *id_ground;
bool manual_drd_enabled;
};
@@ -206,14 +219,17 @@ struct otg_switch_mtk {
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
* @sys_clk: system clock of mtu3, shared by device/host IP
+ * @ref_clk: reference clock
+ * @mcu_clk: mcu_bus_ck clock for AHB bus etc
+ * @dma_clk: dma_bus_ck clock for AXI bus etc
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
* @u3_ports: number of usb3.0 host ports
+ * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
+ * disable u3port0, bit1==1 to disable u3port1,... etc
* @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode
- * @wk_deb_p0: port0's wakeup debounce clock
- * @wk_deb_p1: it's optional, and depends on port1 is supported or not
*/
struct ssusb_mtk {
struct device *dev;
@@ -226,17 +242,18 @@ struct ssusb_mtk {
struct regulator *vusb33;
struct clk *sys_clk;
struct clk *ref_clk;
+ struct clk *mcu_clk;
+ struct clk *dma_clk;
/* otg */
struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
bool is_host;
int u2_ports;
int u3_ports;
+ int u3p_dis_msk;
struct dentry *dbgfs_root;
/* usb wakeup for host mode */
bool wakeup_en;
- struct clk *wk_deb_p0;
- struct clk *wk_deb_p1;
struct regmap *pericfg;
};
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 99c65b0788ff..b1b99a8f6a7a 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_core.c - hardware access layer and gadget init/exit of
* MediaTek usb3 Dual-Role Controller Driver
@@ -5,18 +6,9 @@
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
@@ -114,7 +106,9 @@ static int mtu3_device_enable(struct mtu3 *mtu)
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
(SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
SSUSB_U2_PORT_HOST_SEL));
- mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
+
+ if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
+ mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
return ssusb_check_clocks(mtu->ssusb, check_clk);
}
@@ -129,7 +123,10 @@ static void mtu3_device_disable(struct mtu3 *mtu)
mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
- mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
+
+ if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
+ mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
+
mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
}
@@ -236,7 +233,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
{
- if (mtu->is_u3_ip && (mtu->max_speed == USB_SPEED_SUPER))
+ if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER)
mtu3_ss_func_set(mtu, is_on);
else
mtu3_hs_softconn_set(mtu, is_on);
@@ -546,6 +543,9 @@ static void mtu3_set_speed(struct mtu3 *mtu)
mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
/* HS/FS detected by HW */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+ } else if (mtu->max_speed == USB_SPEED_SUPER) {
+ mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
+ SSUSB_U3_PORT_SSP_SPEED);
}
dev_info(mtu->dev, "max_speed: %s\n",
@@ -623,6 +623,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
udev_speed = USB_SPEED_SUPER;
maxpkt = 512;
break;
+ case MTU3_SPEED_SUPER_PLUS:
+ udev_speed = USB_SPEED_SUPER_PLUS;
+ maxpkt = 512;
+ break;
default:
udev_speed = USB_SPEED_UNKNOWN;
break;
@@ -759,7 +763,31 @@ static void mtu3_hw_exit(struct mtu3 *mtu)
mtu3_mem_free(mtu);
}
-/*-------------------------------------------------------------------------*/
+/**
+ * we set 32-bit DMA mask by default, here check whether the controller
+ * supports 36-bit DMA or not, if it does, set 36-bit DMA mask.
+ */
+static int mtu3_set_dma_mask(struct mtu3 *mtu)
+{
+ struct device *dev = mtu->dev;
+ bool is_36bit = false;
+ int ret = 0;
+ u32 value;
+
+ value = mtu3_readl(mtu->mac_base, U3D_MISC_CTRL);
+ if (value & DMA_ADDR_36BIT) {
+ is_36bit = true;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+ /* If set 36-bit DMA mask fails, fall back to 32-bit DMA mask */
+ if (ret) {
+ is_36bit = false;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ }
+ }
+ dev_info(dev, "dma mask: %s bits\n", is_36bit ? "36" : "32");
+
+ return ret;
+}
int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{
@@ -774,9 +802,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return -ENOMEM;
mtu->irq = platform_get_irq(pdev, 0);
- if (mtu->irq <= 0) {
+ if (mtu->irq < 0) {
dev_err(dev, "fail to get irq number\n");
- return -ENODEV;
+ return mtu->irq;
}
dev_info(dev, "irq %d\n", mtu->irq);
@@ -800,14 +828,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
break;
default:
dev_err(dev, "invalid max_speed: %s\n",
usb_speed_string(mtu->max_speed));
/* fall through */
case USB_SPEED_UNKNOWN:
- /* default as SS */
- mtu->max_speed = USB_SPEED_SUPER;
+ /* default as SSP */
+ mtu->max_speed = USB_SPEED_SUPER_PLUS;
break;
}
@@ -820,6 +849,12 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return ret;
}
+ ret = mtu3_set_dma_mask(mtu);
+ if (ret) {
+ dev_err(dev, "mtu3 set dma_mask failed:%d\n", ret);
+ goto dma_mask_err;
+ }
+
ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu);
if (ret) {
dev_err(dev, "request irq %d failed!\n", mtu->irq);
@@ -845,6 +880,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
gadget_err:
device_init_wakeup(dev, false);
+dma_mask_err:
irq_err:
mtu3_hw_exit(mtu);
ssusb->u3d = NULL;
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 560256115b23..db7562d99b95 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_dr.c - dual role switch and host glue layer
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/debugfs.h>
@@ -261,21 +252,22 @@ static void extcon_register_dwork(struct work_struct *work)
* depending on user input.
* This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode.
- * It generates cable state changes by pulling up/down IDPIN and
- * notifies driver to switch mode by "extcon-usb-gpio".
- * NOTE: when use MICRO receptacle, should not enable this interface.
*/
static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host)
- pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
- else
- pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
+ if (to_host) {
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
+ } else {
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
+ ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ }
}
-
static int ssusb_mode_show(struct seq_file *sf, void *unused)
{
struct ssusb_mtk *ssusb = sf->private;
@@ -388,17 +380,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
debugfs_remove_recursive(ssusb->dbgfs_root);
}
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+ enum mtu3_dr_force_mode mode)
+{
+ u32 value;
+
+ value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
+ switch (mode) {
+ case MTU3_DR_FORCE_DEVICE:
+ value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
+ break;
+ case MTU3_DR_FORCE_HOST:
+ value |= SSUSB_U2_PORT_FORCE_IDDIG;
+ value &= ~SSUSB_U2_PORT_RG_IDDIG;
+ break;
+ case MTU3_DR_FORCE_NONE:
+ value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
+ break;
+ default:
+ return;
+ }
+ mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
+}
+
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
-
- if (otg_sx->manual_drd_enabled)
+ if (otg_sx->manual_drd_enabled) {
ssusb_debugfs_init(ssusb);
-
- /* It is enough to delay 1s for waiting for host initialization */
- schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+ } else {
+ INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
+ extcon_register_dwork);
+
+ /*
+ * It is enough to delay 1s for waiting for
+ * host initialization
+ */
+ schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+ }
return 0;
}
@@ -407,8 +427,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- cancel_delayed_work(&otg_sx->extcon_reg_dwork);
-
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
+ else
+ cancel_delayed_work(&otg_sx->extcon_reg_dwork);
}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index 9b228b5811b0..c179192408ba 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_dr.h - dual role switch and host glue layer header
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef _MTU3_DR_H_
@@ -87,6 +78,8 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
+void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
+ enum mtu3_dr_force_mode mode);
#else
@@ -103,6 +96,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
return 0;
}
+static inline void
+ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
+{}
+
#endif
#endif /* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 434fca58143c..f05f10f5c171 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_gadget.c - MediaTek usb3 DRD peripheral support
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "mtu3.h"
@@ -89,6 +80,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
switch (mtu->g.speed) {
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
if (usb_endpoint_xfer_int(desc) ||
usb_endpoint_xfer_isoc(desc)) {
interval = desc->bInterval;
@@ -456,7 +448,7 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
return -EOPNOTSUPP;
spin_lock_irqsave(&mtu->lock, flags);
- if (mtu->g.speed == USB_SPEED_SUPER) {
+ if (mtu->g.speed >= USB_SPEED_SUPER) {
mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
} else {
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
index 958d74dd2b78..ebdcf7a38c29 100644
--- a/drivers/usb/mtu3/mtu3_gadget_ep0.c
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
*
* Copyright (c) 2016 MediaTek Inc.
*
* Author: Chunfeng.Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/usb/composite.h>
@@ -212,8 +203,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
case USB_RECIP_DEVICE:
result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
- /* superspeed only */
- if (mtu->g.speed == USB_SPEED_SUPER) {
+
+ if (mtu->g.speed >= USB_SPEED_SUPER) {
result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
}
@@ -329,8 +320,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = handle_test_mode(mtu, setup);
break;
case USB_DEVICE_U1_ENABLE:
- if (mtu->g.speed != USB_SPEED_SUPER ||
- mtu->g.state != USB_STATE_CONFIGURED)
+ if (mtu->g.speed < USB_SPEED_SUPER ||
+ mtu->g.state != USB_STATE_CONFIGURED)
break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
@@ -344,8 +335,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = 1;
break;
case USB_DEVICE_U2_ENABLE:
- if (mtu->g.speed != USB_SPEED_SUPER ||
- mtu->g.state != USB_STATE_CONFIGURED)
+ if (mtu->g.speed < USB_SPEED_SUPER ||
+ mtu->g.state != USB_STATE_CONFIGURED)
break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
@@ -384,8 +375,8 @@ static int ep0_handle_feature(struct mtu3 *mtu,
break;
case USB_RECIP_INTERFACE:
/* superspeed only */
- if ((value == USB_INTRF_FUNC_SUSPEND)
- && (mtu->g.speed == USB_SPEED_SUPER)) {
+ if (value == USB_INTRF_FUNC_SUSPEND &&
+ mtu->g.speed >= USB_SPEED_SUPER) {
/*
* forward the request because function drivers
* should handle it
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index e42d308b8dc2..d237d7e65c44 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_dr.c - dual role switch and host glue layer
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/clk.h>
@@ -79,20 +70,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
if (!ssusb->wakeup_en)
return 0;
- ssusb->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
- if (IS_ERR(ssusb->wk_deb_p0)) {
- dev_err(dev, "fail to get wakeup_deb_p0\n");
- return PTR_ERR(ssusb->wk_deb_p0);
- }
-
- if (of_property_read_bool(dn, "wakeup_deb_p1")) {
- ssusb->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
- if (IS_ERR(ssusb->wk_deb_p1)) {
- dev_err(dev, "fail to get wakeup_deb_p1\n");
- return PTR_ERR(ssusb->wk_deb_p1);
- }
- }
-
ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
"mediatek,syscon-wakeup");
if (IS_ERR(ssusb->pericfg)) {
@@ -103,36 +80,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
return 0;
}
-static int ssusb_wakeup_clks_enable(struct ssusb_mtk *ssusb)
-{
- int ret;
-
- ret = clk_prepare_enable(ssusb->wk_deb_p0);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable wk_deb_p0\n");
- goto usb_p0_err;
- }
-
- ret = clk_prepare_enable(ssusb->wk_deb_p1);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable wk_deb_p1\n");
- goto usb_p1_err;
- }
-
- return 0;
-
-usb_p1_err:
- clk_disable_unprepare(ssusb->wk_deb_p0);
-usb_p0_err:
- return -EINVAL;
-}
-
-static void ssusb_wakeup_clks_disable(struct ssusb_mtk *ssusb)
-{
- clk_disable_unprepare(ssusb->wk_deb_p1);
- clk_disable_unprepare(ssusb->wk_deb_p0);
-}
-
static void host_ports_num_get(struct ssusb_mtk *ssusb)
{
u32 xhci_cap;
@@ -151,6 +98,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
void __iomem *ibase = ssusb->ippc_base;
int num_u3p = ssusb->u3_ports;
int num_u2p = ssusb->u2_ports;
+ int u3_ports_disabed;
u32 check_clk;
u32 value;
int i;
@@ -158,8 +106,14 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
/* power on host ip */
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
- /* power on and enable all u3 ports */
+ /* power on and enable u3 ports except skipped ones */
+ u3_ports_disabed = 0;
for (i = 0; i < num_u3p; i++) {
+ if ((0x1 << i) & ssusb->u3p_dis_msk) {
+ u3_ports_disabed++;
+ continue;
+ }
+
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
value |= SSUSB_U3_PORT_HOST_SEL;
@@ -175,7 +129,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
}
check_clk = SSUSB_XHCI_RST_B_STS;
- if (num_u3p)
+ if (num_u3p > u3_ports_disabed)
check_clk = SSUSB_U3_MAC_RST_B_STS;
return ssusb_check_clocks(ssusb, check_clk);
@@ -190,8 +144,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
int ret;
int i;
- /* power down and disable all u3 ports */
+ /* power down and disable u3 ports except skipped ones */
for (i = 0; i < num_u3p; i++) {
+ if ((0x1 << i) & ssusb->u3p_dis_msk)
+ continue;
+
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value |= SSUSB_U3_PORT_PDN;
value |= suspend ? 0 : SSUSB_U3_PORT_DIS;
@@ -223,6 +180,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
static void ssusb_host_setup(struct ssusb_mtk *ssusb)
{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
host_ports_num_get(ssusb);
/*
@@ -231,6 +190,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
*/
ssusb_host_enable(ssusb);
+ if (otg_sx->manual_drd_enabled)
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+
/* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1);
}
@@ -276,19 +238,14 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{
- int ret = 0;
-
- if (ssusb->wakeup_en) {
- ret = ssusb_wakeup_clks_enable(ssusb);
+ if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_en(ssusb);
- }
- return ret;
+
+ return 0;
}
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
{
- if (ssusb->wakeup_en) {
+ if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_dis(ssusb);
- ssusb_wakeup_clks_disable(ssusb);
- }
}
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 06b29664470f..6ee371478d89 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef _SSUSB_HW_REGS_H_
@@ -58,6 +49,8 @@
#define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404)
#define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408)
#define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C)
+#define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484)
+#define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4)
#define U3D_TXQCSR1 (SSUSB_DEV_BASE + 0x0510)
#define U3D_TXQSAR1 (SSUSB_DEV_BASE + 0x0514)
@@ -189,6 +182,13 @@
#define QMU_RX_COZ(x) (BIT(16) << (x))
#define QMU_RX_ZLP(x) (BIT(0) << (x))
+/* U3D_TXQHIAR1 */
+/* U3D_RXQHIAR1 */
+#define QMU_LAST_DONE_PTR_HI(x) (((x) >> 16) & 0xf)
+#define QMU_CUR_GPD_ADDR_HI(x) (((x) >> 8) & 0xf)
+#define QMU_START_ADDR_HI_MSK GENMASK(3, 0)
+#define QMU_START_ADDR_HI(x) (((x) & 0xf) << 0)
+
/* U3D_TXQCSR1 */
/* U3D_RXQCSR1 */
#define QMU_Q_ACTIVE BIT(15)
@@ -225,6 +225,7 @@
#define CAP_TX_EP_NUM(x) ((x) & 0x1f)
/* U3D_MISC_CTRL */
+#define DMA_ADDR_36BIT BIT(31)
#define VBUS_ON BIT(1)
#define VBUS_FRC_EN BIT(0)
@@ -457,11 +458,14 @@
#define SSUSB_VBUS_CHG_INT_B_EN BIT(6)
/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED BIT(9)
#define SSUSB_U3_PORT_HOST_SEL BIT(2)
#define SSUSB_U3_PORT_PDN BIT(1)
#define SSUSB_U3_PORT_DIS BIT(0)
/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_RG_IDDIG BIT(12)
+#define SSUSB_U2_PORT_FORCE_IDDIG BIT(11)
#define SSUSB_U2_PORT_VBUSVALID BIT(9)
#define SSUSB_U2_PORT_OTG_SEL BIT(7)
#define SSUSB_U2_PORT_HOST BIT(2)
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 088e3e685c4f..3650fd11fc49 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 MediaTek Inc.
*
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/clk.h>
@@ -21,7 +12,6 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include "mtu3.h"
@@ -110,15 +100,9 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
phy_power_off(ssusb->phys[i]);
}
-static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
+static int ssusb_clks_enable(struct ssusb_mtk *ssusb)
{
- int ret = 0;
-
- ret = regulator_enable(ssusb->vusb33);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable vusb33\n");
- goto vusb33_err;
- }
+ int ret;
ret = clk_prepare_enable(ssusb->sys_clk);
if (ret) {
@@ -132,6 +116,52 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
goto ref_clk_err;
}
+ ret = clk_prepare_enable(ssusb->mcu_clk);
+ if (ret) {
+ dev_err(ssusb->dev, "failed to enable mcu_clk\n");
+ goto mcu_clk_err;
+ }
+
+ ret = clk_prepare_enable(ssusb->dma_clk);
+ if (ret) {
+ dev_err(ssusb->dev, "failed to enable dma_clk\n");
+ goto dma_clk_err;
+ }
+
+ return 0;
+
+dma_clk_err:
+ clk_disable_unprepare(ssusb->mcu_clk);
+mcu_clk_err:
+ clk_disable_unprepare(ssusb->ref_clk);
+ref_