summaryrefslogtreecommitdiff
path: root/drivers/usb/mtu3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/mtu3')
-rw-r--r--drivers/usb/mtu3/Makefile11
-rw-r--r--drivers/usb/mtu3/mtu3.h57
-rw-r--r--drivers/usb/mtu3/mtu3_core.c27
-rw-r--r--drivers/usb/mtu3/mtu3_debug.h50
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c539
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c156
-rw-r--r--drivers/usb/mtu3/mtu3_dr.h4
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c20
-rw-r--r--drivers/usb/mtu3/mtu3_gadget_ep0.c4
-rw-r--r--drivers/usb/mtu3/mtu3_hw_regs.h48
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c47
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.c118
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.h1
-rw-r--r--drivers/usb/mtu3/mtu3_trace.c23
-rw-r--r--drivers/usb/mtu3/mtu3_trace.h279
15 files changed, 1149 insertions, 235 deletions
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
index 4a9715812bf9..3bf8cbcc1add 100644
--- a/drivers/usb/mtu3/Makefile
+++ b/drivers/usb/mtu3/Makefile
@@ -2,10 +2,17 @@
ccflags-$(CONFIG_USB_MTU3_DEBUG) += -DDEBUG
+# define_trace.h needs to know how to find our header
+CFLAGS_mtu3_trace.o := -I$(src)
+
obj-$(CONFIG_USB_MTU3) += mtu3.o
mtu3-y := mtu3_plat.o
+ifneq ($(CONFIG_TRACING),)
+ mtu3-y += mtu3_trace.o
+endif
+
ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
mtu3-y += mtu3_host.o
endif
@@ -17,3 +24,7 @@ endif
ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),)
mtu3-y += mtu3_dr.o
endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+ mtu3-y += mtu3_debugfs.o
+endif
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 87823ac0d120..76ecf12fdf62 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -63,6 +63,15 @@ struct mtu3_request;
#define MTU3_U2_IP_SLOT_DEFAULT 1
/**
+ * IP TRUNK version
+ * from 0x1003 version, USB3 Gen2 is supported, two changes affect driver:
+ * 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted,
+ * but not backward compatible
+ * 2. QMU extend buffer length supported
+ */
+#define MTU3_TRUNK_VERS_1003 0x1003
+
+/**
* Normally the device works on HS or SS, to simplify fifo management,
* devide fifo into some 512B parts, use bitmap to manage it; And
* 128 bits size of bitmap is large enough, that means it can manage
@@ -135,45 +144,33 @@ struct mtu3_fifo_info {
* The format of TX GPD is a little different from RX one.
* And the size of GPD is 16 bytes.
*
- * @flag:
+ * @dw0_info:
* bit0: Hardware Own (HWO)
* bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported
* bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1
+ * bit6: [EL] Zero Length Packet (ZLP), moved from @dw3_info[29]
* bit7: Interrupt On Completion (IOC)
- * @chksum: This is used to validate the contents of this GPD;
- * If TXQ_CS_EN / RXQ_CS_EN bit is set, an interrupt is issued
- * when checksum validation fails;
- * 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
+ * bit[31:16]: ([EL] bit[31:12]) allow data buffer length (RX ONLY),
+ * the buffer length of the data to receive
+ * bit[23:16]: ([EL] bit[31:24]) extension address (TX ONLY),
+ * lower 4 bits are extension bits of @buffer,
+ * upper 4 bits are 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),
+ * @dw3_info:
+ * bit[15:0]: ([EL] bit[19:0]) data buffer length,
+ * (TX): the buffer length of the data to transmit
+ * (RX): The total length of data received
+ * bit[23:16]: ([EL] bit[31:24]) extension address (RX ONLY),
+ * lower 4 bits are extension bits of @buffer,
+ * upper 4 bits are extension bits of @next_gpd
+ * bit29: ([EL] abandoned) Zero Length Packet (ZLP) (TX ONLY)
*/
struct qmu_gpd {
- __u8 flag;
- __u8 chksum;
- union {
- __le16 data_buf_len;
- __le16 tx_ext_addr;
- };
+ __le32 dw0_info;
__le32 next_gpd;
__le32 buffer;
- __le16 buf_len;
- union {
- __u8 ext_len;
- __u8 rx_ext_addr;
- };
- __u8 ext_flag;
+ __le32 dw3_info;
} __packed;
/**
@@ -316,6 +313,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev)
* @may_wakeup: means device's remote wakeup is enabled
* @is_self_powered: is reported in device status and the config descriptor
* @delayed_status: true when function drivers ask for delayed status
+ * @gen2cp: compatible with USB3 Gen2 IP
* @ep0_req: dummy request used while handling standard USB requests
* for GET_STATUS and SET_SEL
* @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests
@@ -356,6 +354,7 @@ struct mtu3 {
unsigned u2_enable:1;
unsigned is_u3_ip:1;
unsigned delayed_status:1;
+ unsigned gen2cp:1;
u8 address;
u8 test_mode_nr;
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 4fee200795a5..f8bd1d57e795 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include "mtu3.h"
+#include "mtu3_debug.h"
+#include "mtu3_trace.h"
static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size)
{
@@ -299,6 +301,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
int interval, int burst, int mult)
{
void __iomem *mbase = mtu->mac_base;
+ bool gen2cp = mtu->gen2cp;
int epnum = mep->epnum;
u32 csr0, csr1, csr2;
int fifo_sgsz, fifo_addr;
@@ -319,7 +322,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
num_pkts = (burst + 1) * (mult + 1) - 1;
csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot);
- csr1 |= TX_MAX_PKT(num_pkts) | TX_MULT(mult);
+ csr1 |= TX_MAX_PKT(gen2cp, num_pkts) | TX_MULT(gen2cp, mult);
csr2 = TX_FIFOADDR(fifo_addr >> 4);
csr2 |= TX_FIFOSEGSIZE(fifo_sgsz);
@@ -355,7 +358,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
num_pkts = (burst + 1) * (mult + 1) - 1;
csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot);
- csr1 |= RX_MAX_PKT(num_pkts) | RX_MULT(mult);
+ csr1 |= RX_MAX_PKT(gen2cp, num_pkts) | RX_MULT(gen2cp, mult);
csr2 = RX_FIFOADDR(fifo_addr >> 4);
csr2 |= RX_FIFOSEGSIZE(fifo_sgsz);
@@ -600,6 +603,10 @@ static void mtu3_regs_init(struct mtu3 *mtu)
mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
/* enable automatical HWRW from L1 */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
+
+ /* use new QMU format when HW version >= 0x1003 */
+ if (mtu->gen2cp)
+ mtu3_writel(mbase, U3D_QFCR, ~0x0);
}
static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
@@ -650,6 +657,8 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
break;
}
dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed));
+ mtu3_dbg_trace(mtu->dev, "link speed %s",
+ usb_speed_string(udev_speed));
mtu->g.speed = udev_speed;
mtu->g.ep0->maxpacket = maxpkt;
@@ -672,6 +681,7 @@ static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE);
mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */
dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm);
+ trace_mtu3_u3_ltssm_isr(ltssm);
if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
mtu3_gadget_reset(mtu);
@@ -702,6 +712,7 @@ static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE);
mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */
dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm);
+ trace_mtu3_u2_common_isr(u2comm);
if (u2comm & SUSPEND_INTR)
mtu3_gadget_suspend(mtu);
@@ -749,13 +760,15 @@ static irqreturn_t mtu3_irq(int irq, void *data)
static int mtu3_hw_init(struct mtu3 *mtu)
{
- u32 cap_dev;
+ u32 value;
int ret;
- mtu->hw_version = mtu3_readl(mtu->ippc_base, U3D_SSUSB_HW_ID);
+ value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_TRUNK_VERS);
+ mtu->hw_version = IP_TRUNK_VERS(value);
+ mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003);
- cap_dev = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
- mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev);
+ value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
+ mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value);
dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version,
mtu->is_u3_ip ? "U3" : "U2");
@@ -893,6 +906,8 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
mtu3_stop(mtu);
+ ssusb_dev_debugfs_init(ssusb);
+
dev_dbg(dev, " %s() done...\n", __func__);
return 0;
diff --git a/drivers/usb/mtu3/mtu3_debug.h b/drivers/usb/mtu3/mtu3_debug.h
new file mode 100644
index 000000000000..e96a69234d05
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_debug.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_debug.h - debug header
+ *
+ * Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __MTU3_DEBUG_H__
+#define __MTU3_DEBUG_H__
+
+#include <linux/debugfs.h>
+
+#define MTU3_DEBUGFS_NAME_LEN 32
+
+struct mtu3_regset {
+ char name[MTU3_DEBUGFS_NAME_LEN];
+ struct debugfs_regset32 regset;
+ size_t nregs;
+};
+
+struct mtu3_file_map {
+ const char *name;
+ int (*show)(struct seq_file *s, void *unused);
+};
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb);
+void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb);
+void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb);
+void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb);
+
+#else
+static inline void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb) {}
+static inline void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb) {}
+static inline void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb) {}
+static inline void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb) {}
+
+#endif /* CONFIG_DEBUG_FS */
+
+#if IS_ENABLED(CONFIG_TRACING)
+void mtu3_dbg_trace(struct device *dev, const char *fmt, ...);
+
+#else
+static inline void mtu3_dbg_trace(struct device *dev, const char *fmt, ...) {}
+
+#endif /* CONFIG_TRACING */
+
+#endif /* __MTU3_DEBUG_H__ */
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
new file mode 100644
index 000000000000..62c57ddc554e
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtu3_debugfs.c - debugfs interface
+ *
+ * Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/uaccess.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+#include "mtu3_debug.h"
+
+#define dump_register(nm) \
+{ \
+ .name = __stringify(nm), \
+ .offset = U3D_ ##nm, \
+}
+
+#define dump_prb_reg(nm, os) \
+{ \
+ .name = nm, \
+ .offset = os, \
+}
+
+static const struct debugfs_reg32 mtu3_ippc_regs[] = {
+ dump_register(SSUSB_IP_PW_CTRL0),
+ dump_register(SSUSB_IP_PW_CTRL1),
+ dump_register(SSUSB_IP_PW_CTRL2),
+ dump_register(SSUSB_IP_PW_CTRL3),
+ dump_register(SSUSB_OTG_STS),
+ dump_register(SSUSB_IP_XHCI_CAP),
+ dump_register(SSUSB_IP_DEV_CAP),
+ dump_register(SSUSB_U3_CTRL_0P),
+ dump_register(SSUSB_U2_CTRL_0P),
+ dump_register(SSUSB_HW_ID),
+ dump_register(SSUSB_HW_SUB_ID),
+ dump_register(SSUSB_IP_SPARE0),
+};
+
+static const struct debugfs_reg32 mtu3_dev_regs[] = {
+ dump_register(LV1ISR),
+ dump_register(LV1IER),
+ dump_register(EPISR),
+ dump_register(EPIER),
+ dump_register(EP0CSR),
+ dump_register(RXCOUNT0),
+ dump_register(QISAR0),
+ dump_register(QIER0),
+ dump_register(QISAR1),
+ dump_register(QIER1),
+ dump_register(CAP_EPNTXFFSZ),
+ dump_register(CAP_EPNRXFFSZ),
+ dump_register(CAP_EPINFO),
+ dump_register(MISC_CTRL),
+};
+
+static const struct debugfs_reg32 mtu3_csr_regs[] = {
+ dump_register(DEVICE_CONF),
+ dump_register(DEV_LINK_INTR_ENABLE),
+ dump_register(DEV_LINK_INTR),
+ dump_register(LTSSM_CTRL),
+ dump_register(USB3_CONFIG),
+ dump_register(LINK_STATE_MACHINE),
+ dump_register(LTSSM_INTR_ENABLE),
+ dump_register(LTSSM_INTR),
+ dump_register(U3U2_SWITCH_CTRL),
+ dump_register(POWER_MANAGEMENT),
+ dump_register(DEVICE_CONTROL),
+ dump_register(COMMON_USB_INTR_ENABLE),
+ dump_register(COMMON_USB_INTR),
+ dump_register(USB20_MISC_CONTROL),
+ dump_register(USB20_OPSTATE),
+};
+
+static int mtu3_link_state_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3 *mtu = sf->private;
+ void __iomem *mbase = mtu->mac_base;
+
+ seq_printf(sf, "opstate: %#x, ltssm: %#x\n",
+ mtu3_readl(mbase, U3D_USB20_OPSTATE),
+ LTSSM_STATE(mtu3_readl(mbase, U3D_LINK_STATE_MACHINE)));
+
+ return 0;
+}
+
+static int mtu3_ep_used_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3 *mtu = sf->private;
+ struct mtu3_ep *mep;
+ unsigned long flags;
+ int used = 0;
+ int i;
+
+ spin_lock_irqsave(&mtu->lock, flags);
+
+ for (i = 0; i < mtu->num_eps; i++) {
+ mep = mtu->in_eps + i;
+ if (mep->flags & MTU3_EP_ENABLED) {
+ seq_printf(sf, "%s - type: %d\n", mep->name, mep->type);
+ used++;
+ }
+
+ mep = mtu->out_eps + i;
+ if (mep->flags & MTU3_EP_ENABLED) {
+ seq_printf(sf, "%s - type: %d\n", mep->name, mep->type);
+ used++;
+ }
+ }
+ seq_printf(sf, "total used: %d eps\n", used);
+
+ spin_unlock_irqrestore(&mtu->lock, flags);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(mtu3_link_state);
+DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used);
+
+static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base,
+ const struct debugfs_reg32 *regs, size_t nregs,
+ const char *name, struct dentry *parent)
+{
+ struct debugfs_regset32 *regset;
+ struct mtu3_regset *mregs;
+
+ mregs = devm_kzalloc(mtu->dev, sizeof(*regset), GFP_KERNEL);
+ if (!mregs)
+ return;
+
+ sprintf(mregs->name, "%s", name);
+ regset = &mregs->regset;
+ regset->regs = regs;
+ regset->nregs = nregs;
+ regset->base = base;
+
+ debugfs_create_regset32(mregs->name, 0444, parent, regset);
+}
+
+static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep,
+ struct dentry *parent)
+{
+ struct debugfs_reg32 *regs;
+ int epnum = mep->epnum;
+ int in = mep->is_in;
+
+ regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL);
+ if (!regs)
+ return;
+
+ regs[0].name = in ? "TCR0" : "RCR0";
+ regs[0].offset = in ? MU3D_EP_TXCR0(epnum) : MU3D_EP_RXCR0(epnum);
+ regs[1].name = in ? "TCR1" : "RCR1";
+ regs[1].offset = in ? MU3D_EP_TXCR1(epnum) : MU3D_EP_RXCR1(epnum);
+ regs[2].name = in ? "TCR2" : "RCR2";
+ regs[2].offset = in ? MU3D_EP_TXCR2(epnum) : MU3D_EP_RXCR2(epnum);
+ regs[3].name = in ? "TQHIAR" : "RQHIAR";
+ regs[3].offset = in ? USB_QMU_TQHIAR(epnum) : USB_QMU_RQHIAR(epnum);
+ regs[4].name = in ? "TQCSR" : "RQCSR";
+ regs[4].offset = in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+ regs[5].name = in ? "TQSAR" : "RQSAR";
+ regs[5].offset = in ? USB_QMU_TQSAR(epnum) : USB_QMU_RQSAR(epnum);
+ regs[6].name = in ? "TQCPR" : "RQCPR";
+ regs[6].offset = in ? USB_QMU_TQCPR(epnum) : USB_QMU_RQCPR(epnum);
+
+ mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent);
+}
+
+static int mtu3_ep_info_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3_ep *mep = sf->private;
+ struct mtu3 *mtu = mep->mtu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mtu->lock, flags);
+ seq_printf(sf, "ep - type:%d, maxp:%d, slot:%d, flags:%x\n",
+ mep->type, mep->maxp, mep->slot, mep->flags);
+ spin_unlock_irqrestore(&mtu->lock, flags);
+
+ return 0;
+}
+
+static int mtu3_fifo_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3_ep *mep = sf->private;
+ struct mtu3 *mtu = mep->mtu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mtu->lock, flags);
+ seq_printf(sf, "fifo - seg_size:%d, addr:%d, size:%d\n",
+ mep->fifo_seg_size, mep->fifo_addr, mep->fifo_size);
+ spin_unlock_irqrestore(&mtu->lock, flags);
+
+ return 0;
+}
+
+static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3_ep *mep = sf->private;
+ struct mtu3 *mtu = mep->mtu;
+ struct mtu3_gpd_ring *ring;
+ unsigned long flags;
+
+ ring = &mep->gpd_ring;
+ spin_lock_irqsave(&mtu->lock, flags);
+ seq_printf(sf,
+ "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n",
+ &ring->dma, ring->start, ring->end,
+ ring->enqueue, ring->dequeue);
+ spin_unlock_irqrestore(&mtu->lock, flags);
+
+ return 0;
+}
+
+static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused)
+{
+ struct mtu3_ep *mep = sf->private;
+ struct mtu3 *mtu = mep->mtu;
+ struct mtu3_gpd_ring *ring;
+ struct qmu_gpd *gpd;
+ dma_addr_t dma;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&mtu->lock, flags);
+ ring = &mep->gpd_ring;
+ gpd = ring->start;
+ if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) {
+ seq_puts(sf, "empty!\n");
+ goto out;
+ }
+
+ for (i = 0; i < MAX_GPD_NUM; i++, gpd++) {
+ dma = ring->dma + i * sizeof(*gpd);
+ seq_printf(sf, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n",
+ i, &dma, gpd, gpd->dw0_info, gpd->next_gpd,
+ gpd->buffer, gpd->dw3_info);
+ }
+
+out:
+ spin_unlock_irqrestore(&mtu->lock, flags);
+
+ return 0;
+}
+
+static const struct mtu3_file_map mtu3_ep_files[] = {
+ {"ep-info", mtu3_ep_info_show, },
+ {"fifo", mtu3_fifo_show, },
+ {"qmu-ring", mtu3_qmu_ring_show, },
+ {"qmu-gpd", mtu3_qmu_gpd_show, },
+};
+
+static int mtu3_ep_open(struct inode *inode, struct file *file)
+{
+ const char *file_name = file_dentry(file)->d_iname;
+ const struct mtu3_file_map *f_map;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
+ f_map = &mtu3_ep_files[i];
+
+ if (strcmp(f_map->name, file_name) == 0)
+ break;
+ }
+
+ return single_open(file, f_map->show, inode->i_private);
+}
+
+static const struct file_operations mtu3_ep_fops = {
+ .open = mtu3_ep_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct debugfs_reg32 mtu3_prb_regs[] = {
+ dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0),
+ dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1),
+ dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2),
+ dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3),
+ dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4),
+ dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5),
+};
+
+static int mtu3_probe_show(struct seq_file *sf, void *unused)
+{
+ const char *file_name = file_dentry(sf->file)->d_iname;
+ struct mtu3 *mtu = sf->private;
+ const struct debugfs_reg32 *regs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
+ regs = &mtu3_prb_regs[i];
+
+ if (strcmp(regs->name, file_name) == 0)
+ break;
+ }
+
+ seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset,
+ mtu3_readl(mtu->ippc_base, (u32)regs->offset));
+
+ return 0;
+}
+
+static int mtu3_probe_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtu3_probe_show, inode->i_private);
+}
+
+static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ const char *file_name = file_dentry(file)->d_iname;
+ struct seq_file *sf = file->private_data;
+ struct mtu3 *mtu = sf->private;
+ const struct debugfs_reg32 *regs;
+ char buf[32];
+ u32 val;
+ int i;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (kstrtou32(buf, 0, &val))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
+ regs = &mtu3_prb_regs[i];
+
+ if (strcmp(regs->name, file_name) == 0)
+ break;
+ }
+ mtu3_writel(mtu->ippc_base, (u32)regs->offset, val);
+
+ return count;
+}
+
+static const struct file_operations mtu3_probe_fops = {
+ .open = mtu3_probe_open,
+ .write = mtu3_probe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu)
+{
+ struct ssusb_mtk *ssusb = mtu->ssusb;
+ struct debugfs_reg32 *regs;
+ struct dentry *dir_prb;
+ int i;
+
+ dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root);
+
+ for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
+ regs = &mtu3_prb_regs[i];
+ debugfs_create_file(regs->name, 0644, dir_prb,
+ mtu, &mtu3_probe_fops);
+ }
+
+ mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs,
+ ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb);
+}
+
+static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep,
+ struct dentry *parent)
+{
+ const struct mtu3_file_map *files;
+ struct dentry *dir_ep;
+ int i;
+
+ dir_ep = debugfs_create_dir(mep->name, parent);
+ mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep);
+
+ for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
+ files = &mtu3_ep_files[i];
+
+ debugfs_create_file(files->name, 0444, dir_ep,
+ mep, &mtu3_ep_fops);
+ }
+}
+
+static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu)
+{
+ struct ssusb_mtk *ssusb = mtu->ssusb;
+ struct dentry *dir_eps;
+ int i;
+
+ dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root);
+
+ for (i = 1; i < mtu->num_eps; i++) {
+ mtu3_debugfs_create_ep_dir(mtu->in_eps + i, dir_eps);
+ mtu3_debugfs_create_ep_dir(mtu->out_eps + i, dir_eps);
+ }
+}
+
+void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb)
+{
+ struct mtu3 *mtu = ssusb->u3d;
+ struct dentry *dir_regs;
+
+ dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root);
+
+ mtu3_debugfs_regset(mtu, mtu->ippc_base,
+ mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs),
+ "reg-ippc", dir_regs);
+
+ mtu3_debugfs_regset(mtu, mtu->mac_base,
+ mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs),
+ "reg-dev", dir_regs);
+
+ mtu3_debugfs_regset(mtu, mtu->mac_base,
+ mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs),
+ "reg-csr", dir_regs);
+
+ mtu3_debugfs_create_ep_dirs(mtu);
+
+ mtu3_debugfs_create_prb_files(mtu);
+
+ debugfs_create_file("link-state", 0444, ssusb->dbgfs_root,
+ mtu, &mtu3_link_state_fops);
+ debugfs_create_file("ep-used", 0444, ssusb->dbgfs_root,
+ mtu, &mtu3_ep_used_fops);
+}
+
+static int ssusb_mode_show(struct seq_file *sf, void *unused)
+{
+ struct ssusb_mtk *ssusb = sf->private;
+
+ seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
+ ssusb->is_host ? "host" : "device",
+ ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
+
+ return 0;
+}
+
+static int ssusb_mode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ssusb_mode_show, inode->i_private);
+}
+
+static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *sf = file->private_data;
+ struct ssusb_mtk *ssusb = sf->private;
+ char buf[16];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
+ ssusb_mode_manual_switch(ssusb, 1);
+ } else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
+ ssusb_mode_manual_switch(ssusb, 0);
+ } else {
+ dev_err(ssusb->dev, "wrong or duplicated setting\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ssusb_mode_fops = {
+ .open = ssusb_mode_open,
+ .write = ssusb_mode_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int ssusb_vbus_show(struct seq_file *sf, void *unused)
+{
+ struct ssusb_mtk *ssusb = sf->private;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
+ regulator_is_enabled(otg_sx->vbus) ? "on" : "off");
+
+ return 0;
+}
+
+static int ssusb_vbus_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ssusb_vbus_show, inode->i_private);
+}
+
+static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *sf = file->private_data;
+ struct ssusb_mtk *ssusb = sf->private;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ char buf[16];
+ bool enable;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (kstrtobool(buf, &enable)) {
+ dev_err(ssusb->dev, "wrong setting\n");
+ return -EINVAL;
+ }
+
+ ssusb_set_vbus(otg_sx, enable);
+
+ return count;
+}
+
+static const struct file_operations ssusb_vbus_fops = {
+ .open = ssusb_vbus_open,
+ .write = ssusb_vbus_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb)
+{
+ struct dentry *root = ssusb->dbgfs_root;
+
+ debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops);
+ debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);
+}
+
+void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb)
+{
+ ssusb->dbgfs_root =
+ debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
+}
+
+void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb)
+{
+ debugfs_remove_recursive(ssusb->dbgfs_root);
+ ssusb->dbgfs_root = NULL;
+}
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index ac60e9c8564e..5fcb71af875a 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -7,16 +7,9 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
-#include <linux/debugfs.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-
#include "mtu3.h"
#include "mtu3_dr.h"
+#include "mtu3_debug.h"
#define USB2_PORT 2
#define USB3_PORT 3
@@ -28,6 +21,22 @@ enum mtu3_vbus_id_state {
MTU3_VBUS_VALID,
};
+static char *mailbox_state_string(enum mtu3_vbus_id_state state)
+{
+ switch (state) {
+ case MTU3_ID_FLOAT:
+ return "ID_FLOAT";
+ case MTU3_ID_GROUND:
+ return "ID_GROUND";
+ case MTU3_VBUS_OFF:
+ return "VBUS_OFF";
+ case MTU3_VBUS_VALID:
+ return "VBUS_VALID";
+ default:
+ return "UNKNOWN";
+ }
+}
+
static void toggle_opstate(struct ssusb_mtk *ssusb)
{
if (!ssusb->otg_switch.is_u3_drd) {
@@ -147,7 +156,8 @@ static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
container_of(otg_sx, struct ssusb_mtk, otg_switch);
struct mtu3 *mtu = ssusb->u3d;
- dev_dbg(ssusb->dev, "mailbox state(%d)\n", status);
+ dev_dbg(ssusb->dev, "mailbox %s\n", mailbox_state_string(status));
+ mtu3_dbg_trace(ssusb->dev, "mailbox %s", mailbox_state_string(status));
switch (status) {
case MTU3_ID_GROUND:
@@ -238,14 +248,18 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
&otg_sx->vbus_nb);
- if (ret < 0)
+ if (ret < 0) {
dev_err(ssusb->dev, "failed to register notifier for USB\n");
+ return ret;
+ }
otg_sx->id_nb.notifier_call = ssusb_id_notifier;
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
&otg_sx->id_nb);
- if (ret < 0)
+ if (ret < 0) {
dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
+ return ret;
+ }
dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
extcon_get_state(edev, EXTCON_USB),
@@ -266,7 +280,7 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
* This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode.
*/
-static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
+void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
@@ -281,114 +295,6 @@ static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
}
}
-static int ssusb_mode_show(struct seq_file *sf, void *unused)
-{
- struct ssusb_mtk *ssusb = sf->private;
-
- seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
- ssusb->is_host ? "host" : "device",
- ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
-
- return 0;
-}
-
-static int ssusb_mode_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ssusb_mode_show, inode->i_private);
-}
-
-static ssize_t ssusb_mode_write(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
-{
- struct seq_file *sf = file->private_data;
- struct ssusb_mtk *ssusb = sf->private;
- char buf[16];
-
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
- ssusb_mode_manual_switch(ssusb, 1);
- } else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
- ssusb_mode_manual_switch(ssusb, 0);
- } else {
- dev_err(ssusb->dev, "wrong or duplicated setting\n");
- return -EINVAL;
- }
-
- return count;
-}
-
-static const struct file_operations ssusb_mode_fops = {
- .open = ssusb_mode_open,
- .write = ssusb_mode_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int ssusb_vbus_show(struct seq_file *sf, void *unused)
-{
- struct ssusb_mtk *ssusb = sf->private;
- struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
-
- seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
- regulator_is_enabled(otg_sx->vbus) ? "on" : "off");
-
- return 0;
-}
-
-static int ssusb_vbus_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ssusb_vbus_show, inode->i_private);
-}
-
-static ssize_t ssusb_vbus_write(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
-{
- struct seq_file *sf = file->private_data;
- struct ssusb_mtk *ssusb = sf->private;
- struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- char buf[16];
- bool enable;
-
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- if (kstrtobool(buf, &enable)) {
- dev_err(ssusb->dev, "wrong setting\n");
- return -EINVAL;
- }
-
- ssusb_set_vbus(otg_sx, enable);
-
- return count;
-}
-
-static const struct file_operations ssusb_vbus_fops = {
- .open = ssusb_vbus_open,
- .write = ssusb_vbus_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)
-{
- struct dentry *root;
-
- root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
- ssusb->dbgfs_root = root;
-
- debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops);
- debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);
-}
-
-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)
{
@@ -415,25 +321,23 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ int ret = 0;
INIT_WORK(&otg_sx->id_work, ssusb_id_work);
INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work);
if (otg_sx->manual_drd_enabled)
- ssusb_debugfs_init(ssusb);
+ ssusb_dr_debugfs_init(ssusb);
else
- ssusb_extcon_register(otg_sx);
+ ret = ssusb_extcon_register(otg_sx);
- return 0;
+ return ret;
}
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (otg_sx->manual_drd_enabled)
- ssusb_debugfs_exit(ssusb);
-
cancel_work_sync(&otg_sx->id_work);
cancel_work_sync(&otg_sx->vbus_work);
}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index 50702fdcde28..ba6fe357ce29 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -71,6 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
#if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
+void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host);
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);
@@ -85,6 +86,9 @@ static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{}
+static inline void
+ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) {}
+
static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
{
return 0;
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index bbcd3332471d..f93732e53fd8 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -8,6 +8,7 @@
*/
#include "mtu3.h"
+#include "mtu3_trace.h"
void mtu3_req_complete(struct mtu3_ep *mep,
struct usb_request *req, int status)
@@ -25,6 +26,8 @@ __acquires(mep->mtu->lock)
mtu = mreq->mtu;
mep->busy = 1;
+
+ trace_mtu3_req_complete(mreq);
spin_unlock(&mtu->lock);
/* ep0 makes use of PIO, needn't unmap it */
@@ -201,6 +204,7 @@ error:
spin_unlock_irqrestore(&mtu->lock, flags);
dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep);
+ trace_mtu3_gadget_ep_enable(mep);
return ret;
}
@@ -212,6 +216,7 @@ static int mtu3_gadget_ep_disable(struct usb_ep *ep)
unsigned long flags;
dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name);
+ trace_mtu3_gadget_ep_disable(mep);
if (!(mep->flags & MTU3_EP_ENABLED)) {
dev_warn(mtu->dev, "%s is already disabled\n", mep->name);
@@ -242,13 +247,17 @@ struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
mreq->request.dma = DMA_ADDR_INVALID;
mreq->epnum = mep->epnum;
mreq->mep = mep;
+ trace_mtu3_alloc_request(mreq);
return &mreq->request;
}
void mtu3_free_request(struct usb_ep *ep, struct usb_request *req)
{
- kfree(to_mtu3_request(req));
+ struct mtu3_request *mreq = to_mtu3_request(req);
+
+ trace_mtu3_free_request(mreq);
+ kfree(mreq);
}
static int mtu3_gadget_queue(struct usb_ep *ep,
@@ -278,10 +287,12 @@ static int mtu3_gadget_queue(struct usb_ep *ep,
__func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name,
mreq, ep->maxpacket, mreq->request.length);
- if (req->length > GPD_BUF_SIZE) {
+ if (req->length > GPD_BUF_SIZE ||
+ (mtu->gen2cp && req->length > GPD_BUF_SIZE_EL)) {
dev_warn(mtu->dev,
"req length > supported MAX:%d requested:%d\n",
- GPD_BUF_SIZE, req->length);
+ mtu->gen2cp ? GPD_BUF_SIZE_EL : GPD_BUF_SIZE,
+ req->length);
return -EOPNOTSUPP;
}
@@ -314,6 +325,7 @@ static int mtu3_gadget_queue(struct usb_ep *ep,
error:
spin_unlock_irqrestore(&mtu->lock, flags);
+ trace_mtu3_gadget_queue(mreq);
return ret;
}
@@ -331,6 +343,7 @@ static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req)
return -EINVAL;
dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req);
+ trace_mtu3_gadget_dequeue(mreq);
spin_lock_irqsave(&mtu->lock, flags);
@@ -401,6 +414,7 @@ static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value)
done:
spin_unlock_irqrestore(&mtu->lock, flags);
+ trace_mtu3_gadget_ep_set_halt(mep);
return ret;
}
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
index 7cb7ac980446..4da216c99726 100644
--- a/drivers/usb/mtu3/mtu3_gadget_ep0.c
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -11,6 +11,8 @@
#include <linux/usb/composite.h>
#include "mtu3.h"
+#include "mtu3_debug.h"
+#include "mtu3_trace.h"
/* ep0 is always mtu3->in_eps[0] */
#define next_ep0_request(mtu) next_request((mtu)->ep0)
@@ -634,6 +636,7 @@ __acquires(mtu->lock)
int handled = 0;
ep0_read_setup(mtu, &setup);
+ trace_mtu3_handle_setup(&setup);
if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
handled = handle_standard_request(mtu, &setup);
@@ -710,6 +713,7 @@ irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
ret = IRQ_HANDLED;
}
dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
+ mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu));
switch (mtu->ep0_state) {
case MU3D_EP0_STATE_TX:
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 1d65b7476f23..8382d066749e 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -49,6 +49,7 @@
#define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404)
#define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408)
#define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C)
+#define U3D_QFCR (SSUSB_DEV_BASE + 0x0428)
#define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484)
#define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4)
@@ -133,11 +134,23 @@
#define TX_W1C_BITS (~(TX_SENTSTALL))
/* U3D_TX1CSR1 */
-#define TX_MULT(x) (((x) & 0x3) << 22)
-#define TX_MAX_PKT(x) (((x) & 0x3f) << 16)
+#define TX_MAX_PKT_G2(x) (((x) & 0x7f) << 24)
+#define TX_MULT_G2(x) (((x) & 0x7) << 21)
+#define TX_MULT_OG(x) (((x) & 0x3) << 22)
+#define TX_MAX_PKT_OG(x) (((x) & 0x3f) << 16)
#define TX_SLOT(x) (((x) & 0x3f) << 8)
#define TX_TYPE(x) (((x) & 0x3) << 4)
#define TX_SS_BURST(x) (((x) & 0xf) << 0)
+#define TX_MULT(g2c, x) \
+({ \
+ typeof(x) x_ = (x); \
+ (g2c) ? TX_MULT_G2(x_) : TX_MULT_OG(x_); \
+})
+#define TX_MAX_PKT(g2c, x) \
+({ \
+ typeof(x) x_ = (x); \
+ (g2c) ? TX_MAX_PKT_G2(x_) : TX_MAX_PKT_OG(x_); \
+})
/* for TX_TYPE & RX_TYPE */
#define TYPE_BULK (0x0)
@@ -160,11 +173,23 @@
#define RX_W1C_BITS (~(RX_SENTSTALL | RX_RXPKTRDY))
/* U3D_RX1CSR1 */
-#define RX_MULT(x) (((x) & 0x3) << 22)
-#define RX_MAX_PKT(x) (((x) & 0x3f) << 16)
+#define RX_MAX_PKT_G2(x) (((x) & 0x7f) << 24)
+#define RX_MULT_G2(x) (((x) & 0x7) << 21)
+#define RX_MULT_OG(x) (((x) & 0x3) << 22)
+#define RX_MAX_PKT_OG(x) (((x) & 0x3f) << 16)
#define RX_SLOT(x) (((x) & 0x3f) << 8)
#define RX_TYPE(x) (((x) & 0x3) << 4)
#define RX_SS_BURST(x) (((x) & 0xf) << 0)
+#define RX_MULT(g2c, x) \
+({ \
+ typeof(x) x_ = (x); \
+ (g2c) ? RX_MULT_G2(x_) : RX_MULT_OG(x_); \
+})
+#define RX_MAX_PKT(g2c, x) \
+({ \
+ typeof(x) x_ = (x); \
+ (g2c) ? RX_MAX_PKT_G2(x_) : RX_MAX_PKT_OG(x_); \
+})
/* U3D_RX1CSR2 */
#define RX_BINTERVAL(x) (((x) & 0xff) << 24)
@@ -265,6 +290,7 @@
#define U3D_LTSSM_CTRL (SSUSB_USB3_MAC_CSR_BASE + 0x0010)
#define U3D_USB3_CONFIG (SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+#define U3D_LINK_STATE_MACHINE (SSUSB_USB3_MAC_CSR_BASE + 0x0134)
#define U3D_LTSSM_INTR_ENABLE (SSUSB_USB3_MAC_CSR_BASE + 0x013C)
#define U3D_LTSSM_INTR (SSUSB_USB3_MAC_CSR_BASE + 0x0140)
@@ -282,6 +308,9 @@
/* U3D_USB3_CONFIG */
#define USB3_EN BIT(0)
+/* U3D_LINK_STATE_MACHINE */
+#define LTSSM_STATE(x) ((x) & 0x1f)
+
/* U3D_LTSSM_INTR_ENABLE */
/* U3D_LTSSM_INTR */
#define U3_RESUME_INTR BIT(18)
@@ -347,6 +376,7 @@
#define U3D_USB20_FRAME_NUM (SSUSB_USB2_CSR_BASE + 0x003C)
#define U3D_USB20_LPM_PARAMETER (SSUSB_USB2_CSR_BASE + 0x0044)
#define U3D_USB20_MISC_CONTROL (SSUSB_USB2_CSR_BASE + 0x004C)
+#define U3D_USB20_OPSTATE (SSUSB_USB2_CSR_BASE + 0x0060)
/*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/
@@ -419,6 +449,13 @@
#define U3D_SSUSB_DEV_RST_CTRL (SSUSB_SIFSLV_IPPC_BASE + 0x0098)
#define U3D_SSUSB_HW_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
#define U3D_SSUSB_HW_SUB_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_TRUNK_VERS (U3D_SSUSB_HW_SUB_ID)
+#define U3D_SSUSB_PRB_CTRL0 (SSUSB_SIFSLV_IPPC_BASE + 0x00B0)
+#define U3D_SSUSB_PRB_CTRL1 (SSUSB_SIFSLV_IPPC_BASE + 0x00B4)
+#define U3D_SSUSB_PRB_CTRL2 (SSUSB_SIFSLV_IPPC_BASE + 0x00B8)
+#define U3D_SSUSB_PRB_CTRL3 (SSUSB_SIFSLV_IPPC_BASE + 0x00BC)
+#define U3D_SSUSB_PRB_CTRL4 (SSUSB_SIFSLV_IPPC_BASE + 0x00C0)
+#define U3D_SSUSB_PRB_CTRL5 (SSUSB_SIFSLV_IPPC_BASE + 0x00C4)
#define U3D_SSUSB_IP_SPARE0 (SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
/*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/
@@ -483,4 +520,7 @@
/* U3D_SSUSB_DEV_RST_CTRL */
#define SSUSB_DEV_SW_RST BIT(0)
+/* U3D_SSUSB_IP_TRUNK_VERS */
+#define IP_TRUNK_VERS(x) (((x) >> 16) & 0xffff)
+
#endif /* _SSUSB_HW_REGS_H_ */
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index e086630e41a9..fd0f6c5dfbc1 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -16,6 +16,7 @@
#include "mtu3.h"
#include "mtu3_dr.h"
+#include "mtu3_debug.h"
/* u2-port0 should be powered on and enabled; */
int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
@@ -210,30 +211,16 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
}
-/* ignore the error if the clock does not exist */
-static struct clk *get_optional_clk(struct device *dev, const char *id)
-{
- struct clk *opt_clk;
-
- opt_clk = devm_clk_get(dev, id);
- /* ignore error number except EPROBE_DEFER */
- if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER))
- opt_clk = NULL;
-
- return opt_clk;
-}
-
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
struct device *dev = &pdev->dev;
- struct regulator *vbus;
struct resource *res;
int i;
int ret;
- ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33");
+ ssusb->vusb33 = devm_regulator_get(dev, "vusb33");
if (IS_ERR(ssusb->vusb33)) {
dev_err(dev, "failed to get vusb33\n");
return PTR_ERR(ssusb->vusb33);
@@ -245,15 +232,15 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->sys_clk);
}
- ssusb->ref_clk = get_optional_clk(dev, "ref_ck");
+ ssusb->ref_clk = devm_clk_get_optional(dev, "ref_ck");
if (IS_ERR(ssusb->ref_clk))
return PTR_ERR(ssusb->ref_clk);
- ssusb->mcu_clk = get_optional_clk(dev, "mcu_ck");
+ ssusb->mcu_clk = devm_clk_get_optional(dev, "mcu_ck");
if (IS_ERR(ssusb->mcu_clk))
return PTR_ERR(ssusb->mcu_clk);
- ssusb->dma_clk = get_optional_clk(dev, "dma_ck");
+ ssusb->dma_clk = devm_clk_get_optional(dev, "dma_ck");
if (IS_ERR(ssusb->dma_clk))
return PTR_ERR(ssusb->dma_clk);
@@ -286,7 +273,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
ssusb->dr_mode = USB_DR_MODE_OTG;
if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
- return 0;
+ goto out;
/* if host role is supported */
ret = ssusb_wakeup_of_property_parse(ssusb, node);
@@ -299,15 +286,14 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
of_property_read_u32(node, "mediatek,u3p-dis-msk",
&ssusb->u3p_dis_msk);
- vbus = devm_regulator_get(&pdev->dev, "vbus");
- if (IS_ERR(vbus)) {
+ otg_sx->vbus = devm_regulator_get(dev, "vbus");
+ if (IS_ERR(otg_sx->vbus)) {
dev_err(dev, "failed to get vbus\n");
- return PTR_ERR(vbus);
+ return PTR_ERR(otg_sx->vbus);
}
- otg_sx->vbus = vbus;
if (ssusb->dr_mode == USB_DR_MODE_HOST)
- return 0;
+ goto out;
/* if dual-role mode is supported */
otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
@@ -322,6 +308,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
}
}
+out:
dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n",
ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
otg_sx->manual_drd_enabled ? "manual" : "auto");
@@ -354,6 +341,8 @@ static int mtu3_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ssusb_debugfs_create_root(ssusb);
+
/* enable power domain */
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -401,7 +390,11 @@ static int mtu3_probe(struct platform_device *pdev)
goto gadget_exit;
}
- ssusb_otg_switch_init(ssusb);
+ ret = ssusb_otg_switch_init(ssusb);
+ if (ret) {
+ dev_err(dev, "failed to initialize switch\n");
+ goto host_exit;
+ }
break;
default:
dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
@@ -411,6 +404,8 @@ static int mtu3_probe(struct platform_device *pdev)
return 0;
+host_exit:
+ ssusb_host_exit(ssusb);
gadget_exit:
ssusb_gadget_exit(ssusb);
comm_exit:
@@ -418,6 +413,7 @@ comm_exit:
comm_init_err:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
+ ssusb_debugfs_remove_root(ssusb);
return ret;
}
@@ -445,6 +441,7 @@ static int mtu3_remove(struct platform_device *pdev)
ssusb_rscs_exit(ssusb);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ ssusb_debugfs_remove_root(ssusb);
return 0;
}
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
index 09f19f70fe8f..3f414f91b589 100644
--- a/drivers/usb/mtu3/mtu3_qmu.c
+++ b/drivers/usb/mtu3/mtu3_qmu.c
@@ -22,17 +22,49 @@
#include <linux/iopoll.h>
#include "mtu3.h"
+#include "mtu3_trace.h"
#define QMU_CHECKSUM_LEN 16
#define GPD_FLAGS_HWO BIT(0)
#define GPD_FLAGS_BDP BIT(1)
#define GPD_FLAGS_BPS BIT(2)
+#define GPD_FLAGS_ZLP BIT(6)
#define GPD_FLAGS_IOC BIT(7)
-
-#define GPD_EXT_FLAG_ZLP BIT(5)
-#define GPD_EXT_NGP(x) (((x) & 0xf) << 4)
-#define GPD_EXT_BUF(x) (((x) & 0xf) << 0)
+#define GET_GPD_HWO(gpd) (le32_to_cpu((gpd)->dw0_info) & GPD_FLAGS_HWO)
+
+#define GPD_RX_BUF_LEN_OG(x) (((x) & 0xffff) << 16)
+#define GPD_RX_BUF_LEN_EL(x) (((x) & 0xfffff) << 12)
+#define GPD_RX_BUF_LEN(mtu, x) \
+({ \
+ typeof(x) x_ = (x); \
+ ((mtu)->gen2cp) ? GPD_RX_BUF_LEN_EL(x_) : GPD_RX_BUF_LEN_OG(x_); \
+})
+
+#define GPD_DATA_LEN_OG(x) ((x) & 0xffff)
+#define GPD_DATA_LEN_EL(x) ((x) & 0xfffff)
+#define GPD_DATA_LEN(mtu, x) \
+({ \
+ typeof(x) x_ = (x); \
+ ((mtu)->gen2cp) ? GPD_DATA_LEN_EL(x_) : GPD_DATA_LEN_OG(x_); \
+})
+
+#define GPD_EXT_FLAG_ZLP BIT(29)
+#define GPD_EXT_NGP_OG(x) (((x) & 0xf) << 20)
+#define GPD_EXT_BUF_OG(x) (((x) & 0xf) << 16)
+#define GPD_EXT_NGP_EL(x) (((x) & 0xf) << 28)
+#define GPD_EXT_BUF_EL(x) (((x) & 0xf) << 24)
+#define GPD_EXT_NGP(mtu, x) \
+({ \
+ typeof(x) x_ = (x); \
+ ((mtu)->gen2cp) ? GPD_EXT_NGP_EL(x_) : GPD_EXT_NGP_OG(x_); \
+})
+
+#define GPD_EXT_BUF(mtu, x) \
+({ \
+ typeof(x) x_ = (x); \
+ ((mtu)->gen2cp) ? GPD_EXT_BUF_EL(x_) : GPD_EXT_BUF_OG(x_); \
+})
#define HILO_GEN64(hi, lo) (((u64)(hi) << 32) + (lo))
#define HILO_DMA(hi, lo) \
@@ -125,7 +157,7 @@ static void reset_gpd_list(struct mtu3_ep *mep)
struct qmu_gpd *gpd = ring->start;
if (gpd) {
- gpd->flag &= ~GPD_FLAGS_HWO;
+ gpd->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO);
gpd_ring_init(ring, gpd);
}
}
@@ -214,16 +246,14 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request;
+ struct mtu3 *mtu = mep->mtu;
dma_addr_t enq_dma;
- u16 ext_addr;
-
- /* set all fields to zero as default value */
- memset(gpd, 0, sizeof(*gpd));
+ u32 ext_addr;
+ gpd->dw0_info = 0; /* SW own it */
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
- ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
- gpd->buf_len = cpu_to_le16(req->length);
- gpd->flag |= GPD_FLAGS_IOC;
+ ext_addr = GPD_EXT_BUF(mtu, upper_32_bits(req->dma));
+ gpd->dw3_info = cpu_to_le32(GPD_DATA_LEN(mtu, req->length));
/* get the next GPD */
enq = advance_enq_gpd(ring);
@@ -231,17 +261,22 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
mep->epnum, gpd, enq, &enq_dma);
- enq->flag &= ~GPD_FLAGS_HWO;
+ enq->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO);
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
- ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
- gpd->tx_ext_addr = cpu_to_le16(ext_addr);
-
- if (req->zero)
- gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+ ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma));
+ gpd->dw0_info = cpu_to_le32(ext_addr);
+
+ if (req->zero) {
+ if (mtu->gen2cp)
+ gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_ZLP);
+ else
+ gpd->dw3_info |= cpu_to_le32(GPD_EXT_FLAG_ZLP);
+ }
- gpd->flag |= GPD_FLAGS_HWO;
+ gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO);
mreq->gpd = gpd;
+ trace_mtu3_prepare_gpd(mep, gpd);
return 0;
}
@@ -252,16 +287,14 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request;
+ struct mtu3 *mtu = mep->mtu;
dma_addr_t enq_dma;
- u16 ext_addr;
-
- /* set all fields to zero as default value */
- memset(gpd, 0, sizeof(*gpd));
+ u32 ext_addr;
+ gpd->dw0_info = 0; /* SW own it */
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
- ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
- gpd->data_buf_len = cpu_to_le16(req->length);
- gpd->flag |= GPD_FLAGS_IOC;
+ ext_addr = GPD_EXT_BUF(mtu, upper_32_bits(req->dma));
+ gpd->dw0_info = cpu_to_le32(GPD_RX_BUF_LEN(mtu, req->length));
/* get the next GPD */
enq = advance_enq_gpd(ring);
@@ -269,13 +302,14 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
mep->epnum, gpd, enq, &enq_dma);
- enq->flag &= ~GPD_FLAGS_HWO;
+ enq->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO);
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
- ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
- gpd->rx_ext_addr = cpu_to_le16(ext_addr);
- gpd->flag |= GPD_FLAGS_HWO;
+ ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma));
+ gpd->dw3_info = cpu_to_le32(ext_addr);
+ gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO);
mreq->gpd = gpd;
+ trace_mtu3_prepare_gpd(mep, gpd);
return 0;
}
@@ -382,27 +416,25 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd_current = NULL;
- struct usb_request *req = NULL;
struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
u32 txcsr = 0;
int ret;
mreq = next_request(mep);
- if (mreq && mreq->request.length == 0)
- req = &mreq->request;
- else
+ if (mreq && mreq->request.length != 0)
return;
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
- if (le16_to_cpu(gpd_current->buf_len) != 0) {
+ if (GPD_DATA_LEN(mtu, le32_to_cpu(gpd_current->dw3_info)) != 0) {
dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum);
return;
}
- dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, req);
+ dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, mreq);
+ trace_mtu3_zlp_exp_gpd(mep, gpd_current);
mtu3_clrbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN);
@@ -415,8 +447,7 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_TXPKTRDY);
/* by pass the current GDP */
- gpd_current->flag |= GPD_FLAGS_BPS;
- gpd_current->flag |= GPD_FLAGS_HWO;
+ gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO);
/*enable DMAREQEN, switch back to QMU mode */
mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN);
@@ -448,7 +479,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+ while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -458,7 +489,8 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
}
request = &mreq->request;
- request->actual = le16_to_cpu(gpd->buf_len);
+ request->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info));
+ trace_mtu3_complete_gpd(mep, gpd);
mtu3_req_complete(mep, request, 0);
gpd = advance_deq_gpd(ring);
@@ -486,7 +518,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+ while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -496,7 +528,8 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
}
req = &mreq->request;
- req->actual = le16_to_cpu(gpd->buf_len);
+ req->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info));
+ trace_mtu3_complete_gpd(mep, gpd);
mtu3_req_complete(mep, req, 0);
gpd = advance_deq_gpd(ring);
@@ -574,6 +607,7 @@ irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu)
dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n",
(qmu_done_status & 0xFFFF), qmu_done_status >> 16,
qmu_status);
+ trace_mtu3_qmu_isr(qmu_done_status, qmu_status);
if (qmu_done_status)
qmu_done_isr(mtu, qmu_done_status);
diff --git a/drivers/usb/mtu3/mtu3_qmu.h b/drivers/usb/mtu3/mtu3_qmu.h
index 81f5151a55ed..9cfde201db63 100644
--- a/drivers/usb/mtu3/mtu3_qmu.h
+++ b/drivers/usb/mtu3/mtu3_qmu.h
@@ -15,6 +15,7 @@
#define QMU_GPD_RING_SIZE (MAX_GPD_NUM * QMU_GPD_SIZE)
#define GPD_BUF_SIZE 65532
+#define GPD_BUF_SIZE_EL 1048572
void mtu3_qmu_stop(struct mtu3_ep *mep);
int mtu3_qmu_start(struct mtu3_ep *mep);
diff --git a/drivers/usb/mtu3/mtu3_trace.c b/drivers/usb/mtu3/mtu3_trace.c
new file mode 100644
index 000000000000..4f5e7857ec31
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_trace.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * mtu3_trace.c - trace support
+ *
+ * Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "mtu3_trace.h"
+
+void mtu3_dbg_trace(struct device *dev, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ trace_mtu3_log(dev, &vaf);
+ va_end(args);
+}
diff --git a/drivers/usb/mtu3/mtu3_trace.h b/drivers/usb/mtu3/mtu3_trace.h
new file mode 100644
index 000000000000..050e30f0fbd4
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_trace.h
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * mtu3_trace.h - trace support
+ *
+ * Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mtu3
+
+#if !defined(__MTU3_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
+#define __MTU3_TRACE_H__
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include "mtu3.h"
+
+#define MTU3_MSG_MAX 256
+
+TRACE_EVENT(mtu3_log,
+ TP_PROTO(struct device *dev, struct va_format *vaf),
+ TP_ARGS(dev, vaf),
+ TP_STRUCT__entry(
+ __string(name, dev_name(dev))
+ __dynamic_array(char, msg, MTU3_MSG_MAX)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ vsnprintf(__get_str(msg), MTU3_MSG_MAX, vaf->fmt, *vaf->va);
+ ),
+ TP_printk("%s: %s", __get_str(name), __get_str(msg))
+);
+
+TRACE_EVENT(mtu3_u3_ltssm_isr,
+ TP_PROTO(u32 intr),
+ TP_ARGS(intr),
+ TP_STRUCT__entry(
+ __field(u32, intr)
+ ),
+ TP_fast_assign(
+ __entry->intr = intr;
+ ),
+ TP_printk("(%08x) %s %s %s %s %s %s", __entry->intr,
+ __entry->intr & HOT_RST_INTR ? "HOT_RST" : "",
+ __entry->intr & WARM_RST_INTR ? "WARM_RST" : "",
+ __entry->intr & ENTER_U3_INTR ? "ENT_U3" : "",
+ __entry->intr & EXIT_U3_INTR ? "EXIT_U3" : "",
+ __entry->intr & VBUS_RISE_INTR ? "VBUS_RISE" : "",
+ __entry->intr & VBUS_FALL_INTR ? "VBUS_FALL" : ""
+ )
+);
+
+TRACE_EVENT(mtu3_u2_common_isr,
+ TP_PROTO(u32 intr),
+ TP_ARGS(intr),
+ TP_STRUCT__entry(
+ __field(u32, intr)
+ ),
+ TP_fast_assign(
+ __entry->intr = intr;
+ ),
+ TP_printk("(%08x) %s %s %s", __entry->intr,
+ __entry->intr & SUSPEND_INTR ? "SUSPEND" : "",
+ __entry->intr & RESUME_INTR ? "RESUME" : "",
+ __entry->intr & RESET_INTR ? "RESET" : ""
+ )
+);
+
+TRACE_EVENT(mtu3_qmu_isr,
+ TP_PROTO(u32 done_intr, u32 exp_intr),
+ TP_ARGS(done_intr, exp_intr),
+ TP_STRUCT__entry(
+ __field(u32, done_intr)
+ __field(u32, exp_intr)
+ ),
+ TP_fast_assign(
+ __entry->done_intr = done_intr;
+ __entry->exp_intr = exp_intr;
+ ),
+ TP_printk("done (tx %04x, rx %04x), exp (%08x)",
+ __entry->done_intr & 0xffff,
+ __entry->done_intr >> 16,
+ __entry->exp_intr
+ )
+);
+
+DECLARE_EVENT_CLASS(mtu3_log_setup,
+ TP_PROTO(struct usb_ctrlrequest *setup),
+ TP_ARGS(setup),
+ TP_STRUCT__entry(
+ __field(__u8, bRequestType)
+ __field(__u8, bRequest)
+ __field(__u16, wValue)
+ __field(__u16, wIndex)
+ __field(__u16, wLength)
+ ),
+ TP_fast_assign(
+ __entry->bRequestType = setup->bRequestType;
+ __entry->bRequest = setup->bRequest;
+ __entry->wValue = le16_to_cpu(setup->wValue);
+ __entry->wIndex = le16_to_cpu(setup->wIndex);
+ __entry->wLength = le16_to_cpu(setup->wLength);
+ ),
+ TP_printk("setup - %02x %02x %04x %04x %04x",
+ __entry->bRequestType, __entry->bRequest,
+ __entry->wValue, __entry->wIndex, __entry->wLength
+ )
+);
+
+DEFINE_EVENT(mtu3_log_setup, mtu3_handle_setup,
+ TP_PROTO(struct usb_ctrlrequest *setup),
+ TP_ARGS(setup)
+);
+
+DECLARE_EVENT_CLASS(mtu3_log_request,
+ TP_PROTO(struct mtu3_request *mreq),
+ TP_ARGS(mreq),
+ TP_STRUCT__entry(
+ __string(name, mreq->mep->name)
+ __field(struct mtu3_request *, mreq)
+ __field(struct qmu_gpd *, gpd)
+ __field(unsigned int, actual)
+ __field(unsigned int, length)
+ __field(int, status)
+ __field(int, zero)
+ __field(int, no_interrupt)
+ ),
+ TP_fast_assign(
+ __assign_str(name, mreq->mep->name);
+ __entry->mreq = mreq;
+ __entry->gpd = mreq->gpd;
+ __entry->actual = mreq->request.actual;
+ __entry->length = mreq->request.length;
+ __entry->status = mreq->request.status;
+ __entry->zero = mreq->request.zero;
+ __entry->no_interrupt = mreq->request.no_interrupt;
+ ),
+ TP_printk("%s: req %p gpd %p len %u/%u %s%s --> %d",
+ __get_str(name), __entry->mreq, __entry->gpd,
+ __entry->actual, __entry->length,
+ __entry->zero ? "Z" : "z",
+ __entry->no_interrupt ? "i" : "I",
+ __entry->status
+ )
+);
+
+DEFINE_EVENT(mtu3_log_request, mtu3_alloc_request,
+ TP_PROTO(struct mtu3_request *req),
+ TP_ARGS(req)
+);
+
+DEFINE_EVENT(mtu3_log_request, mtu3_free_request,
+ TP_PROTO(struct mtu3_request *req),
+ TP_ARGS(req)
+);
+
+DEFINE_EVENT(mtu3_log_request, mtu3_gadget_queue,
+ TP_PROTO(struct mtu3_request *req),
+ TP_ARGS(req)
+);
+
+DEFINE_EVENT(mtu3_log_request, mtu3_gadget_dequeue,
+ TP_PROTO(struct mtu3_request *req),
+ TP_ARGS(req)
+);
+
+DEFINE_EVENT(mtu3_log_request, mtu3_req_complete,
+ TP_PROTO(struct mtu3_request *req),
+ TP_ARGS(req)
+);
+
+DECLARE_EVENT_CLASS(mtu3_log_gpd,
+ TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd),
+ TP_ARGS(mep, gpd),
+ TP_STRUCT__entry(
+ __string(name, mep->name)
+ __field(struct qmu_gpd *, gpd)
+ __field(u32, dw0)
+ __field(u32, dw1)
+ __field(u32, dw2)
+ __field(u32, dw3)
+ ),
+ TP_fast_assign(
+ __assign_str(name, mep->name);
+ __entry->gpd = gpd;
+ __entry->dw0 = le32_to_cpu(gpd->dw0_info);
+ __entry->dw1 = le32_to_cpu(gpd->next_gpd);
+ __entry->dw2 = le32_to_cpu(gpd->buffer);
+ __entry->dw3 = le32_to_cpu(gpd->dw3_info);
+ ),
+ TP_printk("%s: gpd %p - %08x %08x %08x %08x",
+ __get_str(name), __entry->gpd,
+ __entry->dw0, __entry->dw1,
+ __entry->dw2, __entry->dw3
+ )
+);
+
+DEFINE_EVENT(mtu3_log_gpd, mtu3_prepare_gpd,
+ TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd),
+ TP_ARGS(mep, gpd)
+);
+
+DEFINE_EVENT(mtu3_log_gpd, mtu3_complete_gpd,
+ TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd),
+ TP_ARGS(mep, gpd)
+);
+
+DEFINE_EVENT(mtu3_log_gpd, mtu3_zlp_exp_gpd,
+ TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd),
+ TP_ARGS(mep, gpd)
+);
+
+DECLARE_EVENT_CLASS(mtu3_log_ep,
+ TP_PROTO(struct mtu3_ep *mep),
+ TP_ARGS(mep),
+ TP_STRUCT__entry(
+ __string(name, mep->name)
+ __field(unsigned int, type)
+ __field(unsigned int, slot)
+ __field(unsigned int, maxp)
+ __field(unsigned int, mult)
+ __field(unsigned int, maxburst)
+ __field(unsigned int, flags)
+ __field(unsigned int, direction)
+ __field(struct mtu3_gpd_ring *, gpd_ring)
+ ),
+ TP_fast_assign(
+ __assign_str(name, mep->name);
+ __entry->type = mep->type;
+ __entry->slot = mep->slot;
+ __entry->maxp = mep->ep.maxpacket;
+ __entry->mult = mep->ep.mult;
+ __entry->maxburst = mep->ep.maxburst;
+ __entry->flags = mep->flags;
+ __entry->direction = mep->is_in;
+ __entry->gpd_ring = &mep->gpd_ring;
+ ),
+ TP_printk("%s: type %d maxp %d slot %d mult %d burst %d ring %p/%pad flags %c:%c%c%c:%c",
+ __get_str(name), __entry->type,
+ __entry->maxp, __entry->slot,
+ __entry->mult, __entry->maxburst,
+ __entry->gpd_ring, &__entry->gpd_ring->dma,
+ __entry->flags & MTU3_EP_ENABLED ? 'E' : 'e',
+ __entry->flags & MTU3_EP_STALL ? 'S' : 's',
+ __entry->flags & MTU3_EP_WEDGE ? 'W' : 'w',
+ __entry->flags & MTU3_EP_BUSY ? 'B' : 'b',
+ __entry->direction ? '<' : '>'
+ )
+);
+
+DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_enable,
+ TP_PROTO(struct mtu3_ep *mep),
+ TP_ARGS(mep)
+);
+
+DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_disable,
+ TP_PROTO(struct mtu3_ep *mep),
+ TP_ARGS(mep)
+);
+
+DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_set_halt,
+ TP_PROTO(struct mtu3_ep *mep),
+ TP_ARGS(mep)
+);
+
+#endif /* __MTU3_TRACE_H__ */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mtu3_trace
+
+#include <trace/define_trace.h>