usb: mtu3: supports new QMU format
In order to support U3gen2 ISOC transfer upto 96DPs, extend the data buffer length. Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
09befc326e
commit
48e0d3735a
|
@ -148,22 +148,23 @@ struct mtu3_fifo_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)
|
||||
* bit[31:16]: allow data buffer length (RX ONLY),
|
||||
* bit[31:16]: ([EL] bit[31:12]) allow data buffer length (RX ONLY),
|
||||
* the buffer length of the data to receive
|
||||
* bit[23:16]: extension address (TX ONLY),
|
||||
* 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
|
||||
* @dw3_info:
|
||||
* bit[15:0]: data buffer length,
|
||||
* 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]: extension address (RX ONLY),
|
||||
* 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: Zero Length Packet (ZLP) (TX ONLY)
|
||||
* bit29: ([EL] abandoned) Zero Length Packet (ZLP) (TX ONLY)
|
||||
*/
|
||||
struct qmu_gpd {
|
||||
__le32 dw0_info;
|
||||
|
|
|
@ -601,6 +601,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)
|
||||
|
@ -755,6 +759,7 @@ static int mtu3_hw_init(struct mtu3 *mtu)
|
|||
|
||||
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);
|
||||
|
||||
value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
|
||||
mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value);
|
||||
|
|
|
@ -278,10 +278,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -28,14 +28,42 @@
|
|||
#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 GET_GPD_HWO(gpd) (le32_to_cpu((gpd)->dw0_info) & GPD_FLAGS_HWO)
|
||||
|
||||
#define GPD_RX_BUF_LEN(x) (((x) & 0xffff) << 16)
|
||||
#define GPD_DATA_LEN(x) ((x) & 0xffff)
|
||||
#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(x) (((x) & 0xf) << 20)
|
||||
#define GPD_EXT_BUF(x) (((x) & 0xf) << 16)
|
||||
#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) \
|
||||
|
@ -217,13 +245,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;
|
||||
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->dw3_info = cpu_to_le32(GPD_DATA_LEN(req->length));
|
||||
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);
|
||||
|
@ -233,11 +262,15 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
|
|||
|
||||
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));
|
||||
ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma));
|
||||
gpd->dw0_info = cpu_to_le32(ext_addr);
|
||||
|
||||
if (req->zero)
|
||||
gpd->dw3_info |= cpu_to_le32(GPD_EXT_FLAG_ZLP);
|
||||
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->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO);
|
||||
|
||||
|
@ -252,13 +285,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;
|
||||
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->dw0_info = cpu_to_le32(GPD_RX_BUF_LEN(req->length));
|
||||
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);
|
||||
|
@ -268,7 +302,7 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
|
|||
|
||||
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));
|
||||
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);
|
||||
|
||||
|
@ -391,7 +425,7 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
|
|||
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
|
||||
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
|
||||
|
||||
if (GPD_DATA_LEN(le32_to_cpu(gpd_current->dw3_info)) != 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;
|
||||
}
|
||||
|
@ -451,7 +485,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
|
|||
}
|
||||
|
||||
request = &mreq->request;
|
||||
request->actual = GPD_DATA_LEN(le32_to_cpu(gpd->dw3_info));
|
||||
request->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info));
|
||||
mtu3_req_complete(mep, request, 0);
|
||||
|
||||
gpd = advance_deq_gpd(ring);
|
||||
|
@ -489,7 +523,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
|
|||
}
|
||||
req = &mreq->request;
|
||||
|
||||
req->actual = GPD_DATA_LEN(le32_to_cpu(gpd->dw3_info));
|
||||
req->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info));
|
||||
mtu3_req_complete(mep, req, 0);
|
||||
|
||||
gpd = advance_deq_gpd(ring);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user