162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NVIDIA Tegra XUSB device mode controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2015, Google Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/completion.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1362306a36Sopenharmony_ci#include <linux/dmapool.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/iopoll.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/phy/phy.h> 2062306a36Sopenharmony_ci#include <linux/phy/tegra/xusb.h> 2162306a36Sopenharmony_ci#include <linux/pm_domain.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2562306a36Sopenharmony_ci#include <linux/reset.h> 2662306a36Sopenharmony_ci#include <linux/usb/ch9.h> 2762306a36Sopenharmony_ci#include <linux/usb/gadget.h> 2862306a36Sopenharmony_ci#include <linux/usb/otg.h> 2962306a36Sopenharmony_ci#include <linux/usb/role.h> 3062306a36Sopenharmony_ci#include <linux/usb/phy.h> 3162306a36Sopenharmony_ci#include <linux/workqueue.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* XUSB_DEV registers */ 3462306a36Sopenharmony_ci#define DB 0x004 3562306a36Sopenharmony_ci#define DB_TARGET_MASK GENMASK(15, 8) 3662306a36Sopenharmony_ci#define DB_TARGET(x) (((x) << 8) & DB_TARGET_MASK) 3762306a36Sopenharmony_ci#define DB_STREAMID_MASK GENMASK(31, 16) 3862306a36Sopenharmony_ci#define DB_STREAMID(x) (((x) << 16) & DB_STREAMID_MASK) 3962306a36Sopenharmony_ci#define ERSTSZ 0x008 4062306a36Sopenharmony_ci#define ERSTSZ_ERSTXSZ_SHIFT(x) ((x) * 16) 4162306a36Sopenharmony_ci#define ERSTSZ_ERSTXSZ_MASK GENMASK(15, 0) 4262306a36Sopenharmony_ci#define ERSTXBALO(x) (0x010 + 8 * (x)) 4362306a36Sopenharmony_ci#define ERSTXBAHI(x) (0x014 + 8 * (x)) 4462306a36Sopenharmony_ci#define ERDPLO 0x020 4562306a36Sopenharmony_ci#define ERDPLO_EHB BIT(3) 4662306a36Sopenharmony_ci#define ERDPHI 0x024 4762306a36Sopenharmony_ci#define EREPLO 0x028 4862306a36Sopenharmony_ci#define EREPLO_ECS BIT(0) 4962306a36Sopenharmony_ci#define EREPLO_SEGI BIT(1) 5062306a36Sopenharmony_ci#define EREPHI 0x02c 5162306a36Sopenharmony_ci#define CTRL 0x030 5262306a36Sopenharmony_ci#define CTRL_RUN BIT(0) 5362306a36Sopenharmony_ci#define CTRL_LSE BIT(1) 5462306a36Sopenharmony_ci#define CTRL_IE BIT(4) 5562306a36Sopenharmony_ci#define CTRL_SMI_EVT BIT(5) 5662306a36Sopenharmony_ci#define CTRL_SMI_DSE BIT(6) 5762306a36Sopenharmony_ci#define CTRL_EWE BIT(7) 5862306a36Sopenharmony_ci#define CTRL_DEVADDR_MASK GENMASK(30, 24) 5962306a36Sopenharmony_ci#define CTRL_DEVADDR(x) (((x) << 24) & CTRL_DEVADDR_MASK) 6062306a36Sopenharmony_ci#define CTRL_ENABLE BIT(31) 6162306a36Sopenharmony_ci#define ST 0x034 6262306a36Sopenharmony_ci#define ST_RC BIT(0) 6362306a36Sopenharmony_ci#define ST_IP BIT(4) 6462306a36Sopenharmony_ci#define RT_IMOD 0x038 6562306a36Sopenharmony_ci#define RT_IMOD_IMODI_MASK GENMASK(15, 0) 6662306a36Sopenharmony_ci#define RT_IMOD_IMODI(x) ((x) & RT_IMOD_IMODI_MASK) 6762306a36Sopenharmony_ci#define RT_IMOD_IMODC_MASK GENMASK(31, 16) 6862306a36Sopenharmony_ci#define RT_IMOD_IMODC(x) (((x) << 16) & RT_IMOD_IMODC_MASK) 6962306a36Sopenharmony_ci#define PORTSC 0x03c 7062306a36Sopenharmony_ci#define PORTSC_CCS BIT(0) 7162306a36Sopenharmony_ci#define PORTSC_PED BIT(1) 7262306a36Sopenharmony_ci#define PORTSC_PR BIT(4) 7362306a36Sopenharmony_ci#define PORTSC_PLS_SHIFT 5 7462306a36Sopenharmony_ci#define PORTSC_PLS_MASK GENMASK(8, 5) 7562306a36Sopenharmony_ci#define PORTSC_PLS_U0 0x0 7662306a36Sopenharmony_ci#define PORTSC_PLS_U2 0x2 7762306a36Sopenharmony_ci#define PORTSC_PLS_U3 0x3 7862306a36Sopenharmony_ci#define PORTSC_PLS_DISABLED 0x4 7962306a36Sopenharmony_ci#define PORTSC_PLS_RXDETECT 0x5 8062306a36Sopenharmony_ci#define PORTSC_PLS_INACTIVE 0x6 8162306a36Sopenharmony_ci#define PORTSC_PLS_RESUME 0xf 8262306a36Sopenharmony_ci#define PORTSC_PLS(x) (((x) << PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK) 8362306a36Sopenharmony_ci#define PORTSC_PS_SHIFT 10 8462306a36Sopenharmony_ci#define PORTSC_PS_MASK GENMASK(13, 10) 8562306a36Sopenharmony_ci#define PORTSC_PS_UNDEFINED 0x0 8662306a36Sopenharmony_ci#define PORTSC_PS_FS 0x1 8762306a36Sopenharmony_ci#define PORTSC_PS_LS 0x2 8862306a36Sopenharmony_ci#define PORTSC_PS_HS 0x3 8962306a36Sopenharmony_ci#define PORTSC_PS_SS 0x4 9062306a36Sopenharmony_ci#define PORTSC_LWS BIT(16) 9162306a36Sopenharmony_ci#define PORTSC_CSC BIT(17) 9262306a36Sopenharmony_ci#define PORTSC_WRC BIT(19) 9362306a36Sopenharmony_ci#define PORTSC_PRC BIT(21) 9462306a36Sopenharmony_ci#define PORTSC_PLC BIT(22) 9562306a36Sopenharmony_ci#define PORTSC_CEC BIT(23) 9662306a36Sopenharmony_ci#define PORTSC_WPR BIT(30) 9762306a36Sopenharmony_ci#define PORTSC_CHANGE_MASK (PORTSC_CSC | PORTSC_WRC | PORTSC_PRC | \ 9862306a36Sopenharmony_ci PORTSC_PLC | PORTSC_CEC) 9962306a36Sopenharmony_ci#define ECPLO 0x040 10062306a36Sopenharmony_ci#define ECPHI 0x044 10162306a36Sopenharmony_ci#define MFINDEX 0x048 10262306a36Sopenharmony_ci#define MFINDEX_FRAME_SHIFT 3 10362306a36Sopenharmony_ci#define MFINDEX_FRAME_MASK GENMASK(13, 3) 10462306a36Sopenharmony_ci#define PORTPM 0x04c 10562306a36Sopenharmony_ci#define PORTPM_L1S_MASK GENMASK(1, 0) 10662306a36Sopenharmony_ci#define PORTPM_L1S_DROP 0x0 10762306a36Sopenharmony_ci#define PORTPM_L1S_ACCEPT 0x1 10862306a36Sopenharmony_ci#define PORTPM_L1S_NYET 0x2 10962306a36Sopenharmony_ci#define PORTPM_L1S_STALL 0x3 11062306a36Sopenharmony_ci#define PORTPM_L1S(x) ((x) & PORTPM_L1S_MASK) 11162306a36Sopenharmony_ci#define PORTPM_RWE BIT(3) 11262306a36Sopenharmony_ci#define PORTPM_U2TIMEOUT_MASK GENMASK(15, 8) 11362306a36Sopenharmony_ci#define PORTPM_U1TIMEOUT_MASK GENMASK(23, 16) 11462306a36Sopenharmony_ci#define PORTPM_FLA BIT(24) 11562306a36Sopenharmony_ci#define PORTPM_VBA BIT(25) 11662306a36Sopenharmony_ci#define PORTPM_WOC BIT(26) 11762306a36Sopenharmony_ci#define PORTPM_WOD BIT(27) 11862306a36Sopenharmony_ci#define PORTPM_U1E BIT(28) 11962306a36Sopenharmony_ci#define PORTPM_U2E BIT(29) 12062306a36Sopenharmony_ci#define PORTPM_FRWE BIT(30) 12162306a36Sopenharmony_ci#define PORTPM_PNG_CYA BIT(31) 12262306a36Sopenharmony_ci#define EP_HALT 0x050 12362306a36Sopenharmony_ci#define EP_PAUSE 0x054 12462306a36Sopenharmony_ci#define EP_RELOAD 0x058 12562306a36Sopenharmony_ci#define EP_STCHG 0x05c 12662306a36Sopenharmony_ci#define DEVNOTIF_LO 0x064 12762306a36Sopenharmony_ci#define DEVNOTIF_LO_TRIG BIT(0) 12862306a36Sopenharmony_ci#define DEVNOTIF_LO_TYPE_MASK GENMASK(7, 4) 12962306a36Sopenharmony_ci#define DEVNOTIF_LO_TYPE(x) (((x) << 4) & DEVNOTIF_LO_TYPE_MASK) 13062306a36Sopenharmony_ci#define DEVNOTIF_LO_TYPE_FUNCTION_WAKE 0x1 13162306a36Sopenharmony_ci#define DEVNOTIF_HI 0x068 13262306a36Sopenharmony_ci#define PORTHALT 0x06c 13362306a36Sopenharmony_ci#define PORTHALT_HALT_LTSSM BIT(0) 13462306a36Sopenharmony_ci#define PORTHALT_HALT_REJECT BIT(1) 13562306a36Sopenharmony_ci#define PORTHALT_STCHG_REQ BIT(20) 13662306a36Sopenharmony_ci#define PORTHALT_STCHG_INTR_EN BIT(24) 13762306a36Sopenharmony_ci#define PORT_TM 0x070 13862306a36Sopenharmony_ci#define EP_THREAD_ACTIVE 0x074 13962306a36Sopenharmony_ci#define EP_STOPPED 0x078 14062306a36Sopenharmony_ci#define HSFSPI_COUNT0 0x100 14162306a36Sopenharmony_ci#define HSFSPI_COUNT13 0x134 14262306a36Sopenharmony_ci#define HSFSPI_COUNT13_U2_RESUME_K_DURATION_MASK GENMASK(29, 0) 14362306a36Sopenharmony_ci#define HSFSPI_COUNT13_U2_RESUME_K_DURATION(x) ((x) & \ 14462306a36Sopenharmony_ci HSFSPI_COUNT13_U2_RESUME_K_DURATION_MASK) 14562306a36Sopenharmony_ci#define BLCG 0x840 14662306a36Sopenharmony_ci#define SSPX_CORE_CNT0 0x610 14762306a36Sopenharmony_ci#define SSPX_CORE_CNT0_PING_TBURST_MASK GENMASK(7, 0) 14862306a36Sopenharmony_ci#define SSPX_CORE_CNT0_PING_TBURST(x) ((x) & SSPX_CORE_CNT0_PING_TBURST_MASK) 14962306a36Sopenharmony_ci#define SSPX_CORE_CNT30 0x688 15062306a36Sopenharmony_ci#define SSPX_CORE_CNT30_LMPITP_TIMER_MASK GENMASK(19, 0) 15162306a36Sopenharmony_ci#define SSPX_CORE_CNT30_LMPITP_TIMER(x) ((x) & \ 15262306a36Sopenharmony_ci SSPX_CORE_CNT30_LMPITP_TIMER_MASK) 15362306a36Sopenharmony_ci#define SSPX_CORE_CNT32 0x690 15462306a36Sopenharmony_ci#define SSPX_CORE_CNT32_POLL_TBURST_MAX_MASK GENMASK(7, 0) 15562306a36Sopenharmony_ci#define SSPX_CORE_CNT32_POLL_TBURST_MAX(x) ((x) & \ 15662306a36Sopenharmony_ci SSPX_CORE_CNT32_POLL_TBURST_MAX_MASK) 15762306a36Sopenharmony_ci#define SSPX_CORE_CNT56 0x6fc 15862306a36Sopenharmony_ci#define SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK GENMASK(19, 0) 15962306a36Sopenharmony_ci#define SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(x) ((x) & \ 16062306a36Sopenharmony_ci SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK) 16162306a36Sopenharmony_ci#define SSPX_CORE_CNT57 0x700 16262306a36Sopenharmony_ci#define SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK GENMASK(19, 0) 16362306a36Sopenharmony_ci#define SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(x) ((x) & \ 16462306a36Sopenharmony_ci SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK) 16562306a36Sopenharmony_ci#define SSPX_CORE_CNT65 0x720 16662306a36Sopenharmony_ci#define SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK GENMASK(19, 0) 16762306a36Sopenharmony_ci#define SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(x) ((x) & \ 16862306a36Sopenharmony_ci SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK) 16962306a36Sopenharmony_ci#define SSPX_CORE_CNT66 0x724 17062306a36Sopenharmony_ci#define SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK GENMASK(19, 0) 17162306a36Sopenharmony_ci#define SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(x) ((x) & \ 17262306a36Sopenharmony_ci SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK) 17362306a36Sopenharmony_ci#define SSPX_CORE_CNT67 0x728 17462306a36Sopenharmony_ci#define SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK GENMASK(19, 0) 17562306a36Sopenharmony_ci#define SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(x) ((x) & \ 17662306a36Sopenharmony_ci SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK) 17762306a36Sopenharmony_ci#define SSPX_CORE_CNT72 0x73c 17862306a36Sopenharmony_ci#define SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK GENMASK(19, 0) 17962306a36Sopenharmony_ci#define SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(x) ((x) & \ 18062306a36Sopenharmony_ci SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK) 18162306a36Sopenharmony_ci#define SSPX_CORE_PADCTL4 0x750 18262306a36Sopenharmony_ci#define SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3_MASK GENMASK(19, 0) 18362306a36Sopenharmony_ci#define SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3(x) ((x) & \ 18462306a36Sopenharmony_ci SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3_MASK) 18562306a36Sopenharmony_ci#define BLCG_DFPCI BIT(0) 18662306a36Sopenharmony_ci#define BLCG_UFPCI BIT(1) 18762306a36Sopenharmony_ci#define BLCG_FE BIT(2) 18862306a36Sopenharmony_ci#define BLCG_COREPLL_PWRDN BIT(8) 18962306a36Sopenharmony_ci#define BLCG_IOPLL_0_PWRDN BIT(9) 19062306a36Sopenharmony_ci#define BLCG_IOPLL_1_PWRDN BIT(10) 19162306a36Sopenharmony_ci#define BLCG_IOPLL_2_PWRDN BIT(11) 19262306a36Sopenharmony_ci#define BLCG_ALL 0x1ff 19362306a36Sopenharmony_ci#define CFG_DEV_SSPI_XFER 0x858 19462306a36Sopenharmony_ci#define CFG_DEV_SSPI_XFER_ACKTIMEOUT_MASK GENMASK(31, 0) 19562306a36Sopenharmony_ci#define CFG_DEV_SSPI_XFER_ACKTIMEOUT(x) ((x) & \ 19662306a36Sopenharmony_ci CFG_DEV_SSPI_XFER_ACKTIMEOUT_MASK) 19762306a36Sopenharmony_ci#define CFG_DEV_FE 0x85c 19862306a36Sopenharmony_ci#define CFG_DEV_FE_PORTREGSEL_MASK GENMASK(1, 0) 19962306a36Sopenharmony_ci#define CFG_DEV_FE_PORTREGSEL_SS_PI 1 20062306a36Sopenharmony_ci#define CFG_DEV_FE_PORTREGSEL_HSFS_PI 2 20162306a36Sopenharmony_ci#define CFG_DEV_FE_PORTREGSEL(x) ((x) & CFG_DEV_FE_PORTREGSEL_MASK) 20262306a36Sopenharmony_ci#define CFG_DEV_FE_INFINITE_SS_RETRY BIT(29) 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* FPCI registers */ 20562306a36Sopenharmony_ci#define XUSB_DEV_CFG_1 0x004 20662306a36Sopenharmony_ci#define XUSB_DEV_CFG_1_IO_SPACE_EN BIT(0) 20762306a36Sopenharmony_ci#define XUSB_DEV_CFG_1_MEMORY_SPACE_EN BIT(1) 20862306a36Sopenharmony_ci#define XUSB_DEV_CFG_1_BUS_MASTER_EN BIT(2) 20962306a36Sopenharmony_ci#define XUSB_DEV_CFG_4 0x010 21062306a36Sopenharmony_ci#define XUSB_DEV_CFG_4_BASE_ADDR_MASK GENMASK(31, 15) 21162306a36Sopenharmony_ci#define XUSB_DEV_CFG_5 0x014 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* IPFS registers */ 21462306a36Sopenharmony_ci#define XUSB_DEV_CONFIGURATION_0 0x180 21562306a36Sopenharmony_ci#define XUSB_DEV_CONFIGURATION_0_EN_FPCI BIT(0) 21662306a36Sopenharmony_ci#define XUSB_DEV_INTR_MASK_0 0x188 21762306a36Sopenharmony_ci#define XUSB_DEV_INTR_MASK_0_IP_INT_MASK BIT(16) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistruct tegra_xudc_ep_context { 22062306a36Sopenharmony_ci __le32 info0; 22162306a36Sopenharmony_ci __le32 info1; 22262306a36Sopenharmony_ci __le32 deq_lo; 22362306a36Sopenharmony_ci __le32 deq_hi; 22462306a36Sopenharmony_ci __le32 tx_info; 22562306a36Sopenharmony_ci __le32 rsvd[11]; 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define EP_STATE_DISABLED 0 22962306a36Sopenharmony_ci#define EP_STATE_RUNNING 1 23062306a36Sopenharmony_ci#define EP_STATE_HALTED 2 23162306a36Sopenharmony_ci#define EP_STATE_STOPPED 3 23262306a36Sopenharmony_ci#define EP_STATE_ERROR 4 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#define EP_TYPE_INVALID 0 23562306a36Sopenharmony_ci#define EP_TYPE_ISOCH_OUT 1 23662306a36Sopenharmony_ci#define EP_TYPE_BULK_OUT 2 23762306a36Sopenharmony_ci#define EP_TYPE_INTERRUPT_OUT 3 23862306a36Sopenharmony_ci#define EP_TYPE_CONTROL 4 23962306a36Sopenharmony_ci#define EP_TYPE_ISCOH_IN 5 24062306a36Sopenharmony_ci#define EP_TYPE_BULK_IN 6 24162306a36Sopenharmony_ci#define EP_TYPE_INTERRUPT_IN 7 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#define BUILD_EP_CONTEXT_RW(name, member, shift, mask) \ 24462306a36Sopenharmony_cistatic inline u32 ep_ctx_read_##name(struct tegra_xudc_ep_context *ctx) \ 24562306a36Sopenharmony_ci{ \ 24662306a36Sopenharmony_ci return (le32_to_cpu(ctx->member) >> (shift)) & (mask); \ 24762306a36Sopenharmony_ci} \ 24862306a36Sopenharmony_cistatic inline void \ 24962306a36Sopenharmony_ciep_ctx_write_##name(struct tegra_xudc_ep_context *ctx, u32 val) \ 25062306a36Sopenharmony_ci{ \ 25162306a36Sopenharmony_ci u32 tmp; \ 25262306a36Sopenharmony_ci \ 25362306a36Sopenharmony_ci tmp = le32_to_cpu(ctx->member) & ~((mask) << (shift)); \ 25462306a36Sopenharmony_ci tmp |= (val & (mask)) << (shift); \ 25562306a36Sopenharmony_ci ctx->member = cpu_to_le32(tmp); \ 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(state, info0, 0, 0x7) 25962306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(mult, info0, 8, 0x3) 26062306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(max_pstreams, info0, 10, 0x1f) 26162306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(lsa, info0, 15, 0x1) 26262306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(interval, info0, 16, 0xff) 26362306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(cerr, info1, 1, 0x3) 26462306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(type, info1, 3, 0x7) 26562306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(hid, info1, 7, 0x1) 26662306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(max_burst_size, info1, 8, 0xff) 26762306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(max_packet_size, info1, 16, 0xffff) 26862306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(dcs, deq_lo, 0, 0x1) 26962306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(deq_lo, deq_lo, 4, 0xfffffff) 27062306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(deq_hi, deq_hi, 0, 0xffffffff) 27162306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(avg_trb_len, tx_info, 0, 0xffff) 27262306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(max_esit_payload, tx_info, 16, 0xffff) 27362306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(edtla, rsvd[0], 0, 0xffffff) 27462306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(rsvd, rsvd[0], 24, 0x1) 27562306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(partial_td, rsvd[0], 25, 0x1) 27662306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(splitxstate, rsvd[0], 26, 0x1) 27762306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(seq_num, rsvd[0], 27, 0x1f) 27862306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(cerrcnt, rsvd[1], 18, 0x3) 27962306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(data_offset, rsvd[2], 0, 0x1ffff) 28062306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(numtrbs, rsvd[2], 22, 0x1f) 28162306a36Sopenharmony_ciBUILD_EP_CONTEXT_RW(devaddr, rsvd[6], 0, 0x7f) 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic inline u64 ep_ctx_read_deq_ptr(struct tegra_xudc_ep_context *ctx) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return ((u64)ep_ctx_read_deq_hi(ctx) << 32) | 28662306a36Sopenharmony_ci (ep_ctx_read_deq_lo(ctx) << 4); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic inline void 29062306a36Sopenharmony_ciep_ctx_write_deq_ptr(struct tegra_xudc_ep_context *ctx, u64 addr) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci ep_ctx_write_deq_lo(ctx, lower_32_bits(addr) >> 4); 29362306a36Sopenharmony_ci ep_ctx_write_deq_hi(ctx, upper_32_bits(addr)); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistruct tegra_xudc_trb { 29762306a36Sopenharmony_ci __le32 data_lo; 29862306a36Sopenharmony_ci __le32 data_hi; 29962306a36Sopenharmony_ci __le32 status; 30062306a36Sopenharmony_ci __le32 control; 30162306a36Sopenharmony_ci}; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci#define TRB_TYPE_RSVD 0 30462306a36Sopenharmony_ci#define TRB_TYPE_NORMAL 1 30562306a36Sopenharmony_ci#define TRB_TYPE_SETUP_STAGE 2 30662306a36Sopenharmony_ci#define TRB_TYPE_DATA_STAGE 3 30762306a36Sopenharmony_ci#define TRB_TYPE_STATUS_STAGE 4 30862306a36Sopenharmony_ci#define TRB_TYPE_ISOCH 5 30962306a36Sopenharmony_ci#define TRB_TYPE_LINK 6 31062306a36Sopenharmony_ci#define TRB_TYPE_TRANSFER_EVENT 32 31162306a36Sopenharmony_ci#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34 31262306a36Sopenharmony_ci#define TRB_TYPE_STREAM 48 31362306a36Sopenharmony_ci#define TRB_TYPE_SETUP_PACKET_EVENT 63 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#define TRB_CMPL_CODE_INVALID 0 31662306a36Sopenharmony_ci#define TRB_CMPL_CODE_SUCCESS 1 31762306a36Sopenharmony_ci#define TRB_CMPL_CODE_DATA_BUFFER_ERR 2 31862306a36Sopenharmony_ci#define TRB_CMPL_CODE_BABBLE_DETECTED_ERR 3 31962306a36Sopenharmony_ci#define TRB_CMPL_CODE_USB_TRANS_ERR 4 32062306a36Sopenharmony_ci#define TRB_CMPL_CODE_TRB_ERR 5 32162306a36Sopenharmony_ci#define TRB_CMPL_CODE_STALL 6 32262306a36Sopenharmony_ci#define TRB_CMPL_CODE_INVALID_STREAM_TYPE_ERR 10 32362306a36Sopenharmony_ci#define TRB_CMPL_CODE_SHORT_PACKET 13 32462306a36Sopenharmony_ci#define TRB_CMPL_CODE_RING_UNDERRUN 14 32562306a36Sopenharmony_ci#define TRB_CMPL_CODE_RING_OVERRUN 15 32662306a36Sopenharmony_ci#define TRB_CMPL_CODE_EVENT_RING_FULL_ERR 21 32762306a36Sopenharmony_ci#define TRB_CMPL_CODE_STOPPED 26 32862306a36Sopenharmony_ci#define TRB_CMPL_CODE_ISOCH_BUFFER_OVERRUN 31 32962306a36Sopenharmony_ci#define TRB_CMPL_CODE_STREAM_NUMP_ERROR 219 33062306a36Sopenharmony_ci#define TRB_CMPL_CODE_PRIME_PIPE_RECEIVED 220 33162306a36Sopenharmony_ci#define TRB_CMPL_CODE_HOST_REJECTED 221 33262306a36Sopenharmony_ci#define TRB_CMPL_CODE_CTRL_DIR_ERR 222 33362306a36Sopenharmony_ci#define TRB_CMPL_CODE_CTRL_SEQNUM_ERR 223 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci#define BUILD_TRB_RW(name, member, shift, mask) \ 33662306a36Sopenharmony_cistatic inline u32 trb_read_##name(struct tegra_xudc_trb *trb) \ 33762306a36Sopenharmony_ci{ \ 33862306a36Sopenharmony_ci return (le32_to_cpu(trb->member) >> (shift)) & (mask); \ 33962306a36Sopenharmony_ci} \ 34062306a36Sopenharmony_cistatic inline void \ 34162306a36Sopenharmony_citrb_write_##name(struct tegra_xudc_trb *trb, u32 val) \ 34262306a36Sopenharmony_ci{ \ 34362306a36Sopenharmony_ci u32 tmp; \ 34462306a36Sopenharmony_ci \ 34562306a36Sopenharmony_ci tmp = le32_to_cpu(trb->member) & ~((mask) << (shift)); \ 34662306a36Sopenharmony_ci tmp |= (val & (mask)) << (shift); \ 34762306a36Sopenharmony_ci trb->member = cpu_to_le32(tmp); \ 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ciBUILD_TRB_RW(data_lo, data_lo, 0, 0xffffffff) 35162306a36Sopenharmony_ciBUILD_TRB_RW(data_hi, data_hi, 0, 0xffffffff) 35262306a36Sopenharmony_ciBUILD_TRB_RW(seq_num, status, 0, 0xffff) 35362306a36Sopenharmony_ciBUILD_TRB_RW(transfer_len, status, 0, 0xffffff) 35462306a36Sopenharmony_ciBUILD_TRB_RW(td_size, status, 17, 0x1f) 35562306a36Sopenharmony_ciBUILD_TRB_RW(cmpl_code, status, 24, 0xff) 35662306a36Sopenharmony_ciBUILD_TRB_RW(cycle, control, 0, 0x1) 35762306a36Sopenharmony_ciBUILD_TRB_RW(toggle_cycle, control, 1, 0x1) 35862306a36Sopenharmony_ciBUILD_TRB_RW(isp, control, 2, 0x1) 35962306a36Sopenharmony_ciBUILD_TRB_RW(chain, control, 4, 0x1) 36062306a36Sopenharmony_ciBUILD_TRB_RW(ioc, control, 5, 0x1) 36162306a36Sopenharmony_ciBUILD_TRB_RW(type, control, 10, 0x3f) 36262306a36Sopenharmony_ciBUILD_TRB_RW(stream_id, control, 16, 0xffff) 36362306a36Sopenharmony_ciBUILD_TRB_RW(endpoint_id, control, 16, 0x1f) 36462306a36Sopenharmony_ciBUILD_TRB_RW(tlbpc, control, 16, 0xf) 36562306a36Sopenharmony_ciBUILD_TRB_RW(data_stage_dir, control, 16, 0x1) 36662306a36Sopenharmony_ciBUILD_TRB_RW(frame_id, control, 20, 0x7ff) 36762306a36Sopenharmony_ciBUILD_TRB_RW(sia, control, 31, 0x1) 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic inline u64 trb_read_data_ptr(struct tegra_xudc_trb *trb) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return ((u64)trb_read_data_hi(trb) << 32) | 37262306a36Sopenharmony_ci trb_read_data_lo(trb); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic inline void trb_write_data_ptr(struct tegra_xudc_trb *trb, u64 addr) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci trb_write_data_lo(trb, lower_32_bits(addr)); 37862306a36Sopenharmony_ci trb_write_data_hi(trb, upper_32_bits(addr)); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistruct tegra_xudc_request { 38262306a36Sopenharmony_ci struct usb_request usb_req; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci size_t buf_queued; 38562306a36Sopenharmony_ci unsigned int trbs_queued; 38662306a36Sopenharmony_ci unsigned int trbs_needed; 38762306a36Sopenharmony_ci bool need_zlp; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci struct tegra_xudc_trb *first_trb; 39062306a36Sopenharmony_ci struct tegra_xudc_trb *last_trb; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci struct list_head list; 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistruct tegra_xudc_ep { 39662306a36Sopenharmony_ci struct tegra_xudc *xudc; 39762306a36Sopenharmony_ci struct usb_ep usb_ep; 39862306a36Sopenharmony_ci unsigned int index; 39962306a36Sopenharmony_ci char name[8]; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci struct tegra_xudc_ep_context *context; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci#define XUDC_TRANSFER_RING_SIZE 64 40462306a36Sopenharmony_ci struct tegra_xudc_trb *transfer_ring; 40562306a36Sopenharmony_ci dma_addr_t transfer_ring_phys; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci unsigned int enq_ptr; 40862306a36Sopenharmony_ci unsigned int deq_ptr; 40962306a36Sopenharmony_ci bool pcs; 41062306a36Sopenharmony_ci bool ring_full; 41162306a36Sopenharmony_ci bool stream_rejected; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci struct list_head queue; 41462306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc; 41562306a36Sopenharmony_ci const struct usb_ss_ep_comp_descriptor *comp_desc; 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistruct tegra_xudc_sel_timing { 41962306a36Sopenharmony_ci __u8 u1sel; 42062306a36Sopenharmony_ci __u8 u1pel; 42162306a36Sopenharmony_ci __le16 u2sel; 42262306a36Sopenharmony_ci __le16 u2pel; 42362306a36Sopenharmony_ci}; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cienum tegra_xudc_setup_state { 42662306a36Sopenharmony_ci WAIT_FOR_SETUP, 42762306a36Sopenharmony_ci DATA_STAGE_XFER, 42862306a36Sopenharmony_ci DATA_STAGE_RECV, 42962306a36Sopenharmony_ci STATUS_STAGE_XFER, 43062306a36Sopenharmony_ci STATUS_STAGE_RECV, 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistruct tegra_xudc_setup_packet { 43462306a36Sopenharmony_ci struct usb_ctrlrequest ctrl_req; 43562306a36Sopenharmony_ci unsigned int seq_num; 43662306a36Sopenharmony_ci}; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistruct tegra_xudc_save_regs { 43962306a36Sopenharmony_ci u32 ctrl; 44062306a36Sopenharmony_ci u32 portpm; 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistruct tegra_xudc { 44462306a36Sopenharmony_ci struct device *dev; 44562306a36Sopenharmony_ci const struct tegra_xudc_soc *soc; 44662306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spinlock_t lock; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci struct usb_gadget gadget; 45162306a36Sopenharmony_ci struct usb_gadget_driver *driver; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci#define XUDC_NR_EVENT_RINGS 2 45462306a36Sopenharmony_ci#define XUDC_EVENT_RING_SIZE 4096 45562306a36Sopenharmony_ci struct tegra_xudc_trb *event_ring[XUDC_NR_EVENT_RINGS]; 45662306a36Sopenharmony_ci dma_addr_t event_ring_phys[XUDC_NR_EVENT_RINGS]; 45762306a36Sopenharmony_ci unsigned int event_ring_index; 45862306a36Sopenharmony_ci unsigned int event_ring_deq_ptr; 45962306a36Sopenharmony_ci bool ccs; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci#define XUDC_NR_EPS 32 46262306a36Sopenharmony_ci struct tegra_xudc_ep ep[XUDC_NR_EPS]; 46362306a36Sopenharmony_ci struct tegra_xudc_ep_context *ep_context; 46462306a36Sopenharmony_ci dma_addr_t ep_context_phys; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci struct device *genpd_dev_device; 46762306a36Sopenharmony_ci struct device *genpd_dev_ss; 46862306a36Sopenharmony_ci struct device_link *genpd_dl_device; 46962306a36Sopenharmony_ci struct device_link *genpd_dl_ss; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci struct dma_pool *transfer_ring_pool; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci bool queued_setup_packet; 47462306a36Sopenharmony_ci struct tegra_xudc_setup_packet setup_packet; 47562306a36Sopenharmony_ci enum tegra_xudc_setup_state setup_state; 47662306a36Sopenharmony_ci u16 setup_seq_num; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci u16 dev_addr; 47962306a36Sopenharmony_ci u16 isoch_delay; 48062306a36Sopenharmony_ci struct tegra_xudc_sel_timing sel_timing; 48162306a36Sopenharmony_ci u8 test_mode_pattern; 48262306a36Sopenharmony_ci u16 status_buf; 48362306a36Sopenharmony_ci struct tegra_xudc_request *ep0_req; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci bool pullup; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci unsigned int nr_enabled_eps; 48862306a36Sopenharmony_ci unsigned int nr_isoch_eps; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci unsigned int device_state; 49162306a36Sopenharmony_ci unsigned int resume_state; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci int irq; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci void __iomem *base; 49662306a36Sopenharmony_ci resource_size_t phys_base; 49762306a36Sopenharmony_ci void __iomem *ipfs; 49862306a36Sopenharmony_ci void __iomem *fpci; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci struct regulator_bulk_data *supplies; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci struct clk_bulk_data *clks; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci bool device_mode; 50562306a36Sopenharmony_ci struct work_struct usb_role_sw_work; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci struct phy **usb3_phy; 50862306a36Sopenharmony_ci struct phy *curr_usb3_phy; 50962306a36Sopenharmony_ci struct phy **utmi_phy; 51062306a36Sopenharmony_ci struct phy *curr_utmi_phy; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci struct tegra_xudc_save_regs saved_regs; 51362306a36Sopenharmony_ci bool suspended; 51462306a36Sopenharmony_ci bool powergated; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci struct usb_phy **usbphy; 51762306a36Sopenharmony_ci struct usb_phy *curr_usbphy; 51862306a36Sopenharmony_ci struct notifier_block vbus_nb; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci struct completion disconnect_complete; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci bool selfpowered; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci#define TOGGLE_VBUS_WAIT_MS 100 52562306a36Sopenharmony_ci struct delayed_work plc_reset_work; 52662306a36Sopenharmony_ci bool wait_csc; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci struct delayed_work port_reset_war_work; 52962306a36Sopenharmony_ci bool wait_for_sec_prc; 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci#define XUDC_TRB_MAX_BUFFER_SIZE 65536 53362306a36Sopenharmony_ci#define XUDC_MAX_ISOCH_EPS 4 53462306a36Sopenharmony_ci#define XUDC_INTERRUPT_MODERATION_US 0 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor tegra_xudc_ep0_desc = { 53762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 53862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 53962306a36Sopenharmony_ci .bEndpointAddress = 0, 54062306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 54162306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(64), 54262306a36Sopenharmony_ci}; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistruct tegra_xudc_soc { 54562306a36Sopenharmony_ci const char * const *supply_names; 54662306a36Sopenharmony_ci unsigned int num_supplies; 54762306a36Sopenharmony_ci const char * const *clock_names; 54862306a36Sopenharmony_ci unsigned int num_clks; 54962306a36Sopenharmony_ci unsigned int num_phys; 55062306a36Sopenharmony_ci bool u1_enable; 55162306a36Sopenharmony_ci bool u2_enable; 55262306a36Sopenharmony_ci bool lpm_enable; 55362306a36Sopenharmony_ci bool invalid_seq_num; 55462306a36Sopenharmony_ci bool pls_quirk; 55562306a36Sopenharmony_ci bool port_reset_quirk; 55662306a36Sopenharmony_ci bool port_speed_quirk; 55762306a36Sopenharmony_ci bool has_ipfs; 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic inline u32 fpci_readl(struct tegra_xudc *xudc, unsigned int offset) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci return readl(xudc->fpci + offset); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic inline void fpci_writel(struct tegra_xudc *xudc, u32 val, 56662306a36Sopenharmony_ci unsigned int offset) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci writel(val, xudc->fpci + offset); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic inline u32 ipfs_readl(struct tegra_xudc *xudc, unsigned int offset) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci return readl(xudc->ipfs + offset); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic inline void ipfs_writel(struct tegra_xudc *xudc, u32 val, 57762306a36Sopenharmony_ci unsigned int offset) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci writel(val, xudc->ipfs + offset); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic inline u32 xudc_readl(struct tegra_xudc *xudc, unsigned int offset) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci return readl(xudc->base + offset); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic inline void xudc_writel(struct tegra_xudc *xudc, u32 val, 58862306a36Sopenharmony_ci unsigned int offset) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci writel(val, xudc->base + offset); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic inline int xudc_readl_poll(struct tegra_xudc *xudc, 59462306a36Sopenharmony_ci unsigned int offset, u32 mask, u32 val) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci u32 regval; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return readl_poll_timeout_atomic(xudc->base + offset, regval, 59962306a36Sopenharmony_ci (regval & mask) == val, 1, 100); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic inline struct tegra_xudc *to_xudc(struct usb_gadget *gadget) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci return container_of(gadget, struct tegra_xudc, gadget); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic inline struct tegra_xudc_ep *to_xudc_ep(struct usb_ep *ep) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci return container_of(ep, struct tegra_xudc_ep, usb_ep); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic inline struct tegra_xudc_request *to_xudc_req(struct usb_request *req) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci return container_of(req, struct tegra_xudc_request, usb_req); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic inline void dump_trb(struct tegra_xudc *xudc, const char *type, 61862306a36Sopenharmony_ci struct tegra_xudc_trb *trb) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci dev_dbg(xudc->dev, 62162306a36Sopenharmony_ci "%s: %p, lo = %#x, hi = %#x, status = %#x, control = %#x\n", 62262306a36Sopenharmony_ci type, trb, trb->data_lo, trb->data_hi, trb->status, 62362306a36Sopenharmony_ci trb->control); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void tegra_xudc_limit_port_speed(struct tegra_xudc *xudc) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci u32 val; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* limit port speed to gen 1 */ 63162306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT56); 63262306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK); 63362306a36Sopenharmony_ci val |= SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(0x260); 63462306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT56); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT57); 63762306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK); 63862306a36Sopenharmony_ci val |= SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(0x6D6); 63962306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT57); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT65); 64262306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK); 64362306a36Sopenharmony_ci val |= SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(0x4B0); 64462306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT66); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT66); 64762306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK); 64862306a36Sopenharmony_ci val |= SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(0x4B0); 64962306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT66); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT67); 65262306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK); 65362306a36Sopenharmony_ci val |= SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(0x4B0); 65462306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT67); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT72); 65762306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK); 65862306a36Sopenharmony_ci val |= SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(0x10); 65962306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT72); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic void tegra_xudc_restore_port_speed(struct tegra_xudc *xudc) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci u32 val; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* restore port speed to gen2 */ 66762306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT56); 66862306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK); 66962306a36Sopenharmony_ci val |= SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(0x438); 67062306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT56); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT57); 67362306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK); 67462306a36Sopenharmony_ci val |= SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(0x528); 67562306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT57); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT65); 67862306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK); 67962306a36Sopenharmony_ci val |= SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(0xE10); 68062306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT66); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT66); 68362306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK); 68462306a36Sopenharmony_ci val |= SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(0x348); 68562306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT66); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT67); 68862306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK); 68962306a36Sopenharmony_ci val |= SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(0x5a0); 69062306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT67); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT72); 69362306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK); 69462306a36Sopenharmony_ci val |= SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(0x1c21); 69562306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT72); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic void tegra_xudc_device_mode_on(struct tegra_xudc *xudc) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci int err; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci pm_runtime_get_sync(xudc->dev); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci err = phy_power_on(xudc->curr_utmi_phy); 70762306a36Sopenharmony_ci if (err < 0) 70862306a36Sopenharmony_ci dev_err(xudc->dev, "UTMI power on failed: %d\n", err); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci err = phy_power_on(xudc->curr_usb3_phy); 71162306a36Sopenharmony_ci if (err < 0) 71262306a36Sopenharmony_ci dev_err(xudc->dev, "USB3 PHY power on failed: %d\n", err); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci dev_dbg(xudc->dev, "device mode on\n"); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, 71762306a36Sopenharmony_ci USB_ROLE_DEVICE); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci bool connected = false; 72362306a36Sopenharmony_ci u32 pls, val; 72462306a36Sopenharmony_ci int err; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci dev_dbg(xudc->dev, "device mode off\n"); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci connected = !!(xudc_readl(xudc, PORTSC) & PORTSC_CCS); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci reinit_completion(&xudc->disconnect_complete); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (xudc->soc->port_speed_quirk) 73362306a36Sopenharmony_ci tegra_xudc_restore_port_speed(xudc); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, USB_ROLE_NONE); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >> 73862306a36Sopenharmony_ci PORTSC_PLS_SHIFT; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Direct link to U0 if disconnected in RESUME or U2. */ 74162306a36Sopenharmony_ci if (xudc->soc->pls_quirk && xudc->gadget.speed == USB_SPEED_SUPER && 74262306a36Sopenharmony_ci (pls == PORTSC_PLS_RESUME || pls == PORTSC_PLS_U2)) { 74362306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 74462306a36Sopenharmony_ci val |= PORTPM_FRWE; 74562306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci val = xudc_readl(xudc, PORTSC); 74862306a36Sopenharmony_ci val &= ~(PORTSC_CHANGE_MASK | PORTSC_PLS_MASK); 74962306a36Sopenharmony_ci val |= PORTSC_LWS | PORTSC_PLS(PORTSC_PLS_U0); 75062306a36Sopenharmony_ci xudc_writel(xudc, val, PORTSC); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* Wait for disconnect event. */ 75462306a36Sopenharmony_ci if (connected) 75562306a36Sopenharmony_ci wait_for_completion(&xudc->disconnect_complete); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Make sure interrupt handler has completed before powergating. */ 75862306a36Sopenharmony_ci synchronize_irq(xudc->irq); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci tegra_phy_xusb_utmi_pad_power_down(xudc->curr_utmi_phy); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci err = phy_power_off(xudc->curr_utmi_phy); 76362306a36Sopenharmony_ci if (err < 0) 76462306a36Sopenharmony_ci dev_err(xudc->dev, "UTMI PHY power off failed: %d\n", err); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci err = phy_power_off(xudc->curr_usb3_phy); 76762306a36Sopenharmony_ci if (err < 0) 76862306a36Sopenharmony_ci dev_err(xudc->dev, "USB3 PHY power off failed: %d\n", err); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci pm_runtime_put(xudc->dev); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void tegra_xudc_usb_role_sw_work(struct work_struct *work) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct tegra_xudc *xudc = container_of(work, struct tegra_xudc, 77662306a36Sopenharmony_ci usb_role_sw_work); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (xudc->device_mode) 77962306a36Sopenharmony_ci tegra_xudc_device_mode_on(xudc); 78062306a36Sopenharmony_ci else 78162306a36Sopenharmony_ci tegra_xudc_device_mode_off(xudc); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int tegra_xudc_get_phy_index(struct tegra_xudc *xudc, 78562306a36Sopenharmony_ci struct usb_phy *usbphy) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci unsigned int i; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 79062306a36Sopenharmony_ci if (xudc->usbphy[i] && usbphy == xudc->usbphy[i]) 79162306a36Sopenharmony_ci return i; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci dev_info(xudc->dev, "phy index could not be found for shared USB PHY"); 79562306a36Sopenharmony_ci return -1; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void tegra_xudc_update_data_role(struct tegra_xudc *xudc, 79962306a36Sopenharmony_ci struct usb_phy *usbphy) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci int phy_index; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if ((xudc->device_mode && usbphy->last_event == USB_EVENT_VBUS) || 80462306a36Sopenharmony_ci (!xudc->device_mode && usbphy->last_event != USB_EVENT_VBUS)) { 80562306a36Sopenharmony_ci dev_dbg(xudc->dev, "Same role(%d) received. Ignore", 80662306a36Sopenharmony_ci xudc->device_mode); 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci xudc->device_mode = (usbphy->last_event == USB_EVENT_VBUS) ? true : 81162306a36Sopenharmony_ci false; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci phy_index = tegra_xudc_get_phy_index(xudc, usbphy); 81462306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s(): current phy index is %d\n", __func__, 81562306a36Sopenharmony_ci phy_index); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (!xudc->suspended && phy_index != -1) { 81862306a36Sopenharmony_ci xudc->curr_utmi_phy = xudc->utmi_phy[phy_index]; 81962306a36Sopenharmony_ci xudc->curr_usb3_phy = xudc->usb3_phy[phy_index]; 82062306a36Sopenharmony_ci xudc->curr_usbphy = usbphy; 82162306a36Sopenharmony_ci schedule_work(&xudc->usb_role_sw_work); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int tegra_xudc_vbus_notify(struct notifier_block *nb, 82662306a36Sopenharmony_ci unsigned long action, void *data) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc, 82962306a36Sopenharmony_ci vbus_nb); 83062306a36Sopenharmony_ci struct usb_phy *usbphy = (struct usb_phy *)data; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci tegra_xudc_update_data_role(xudc, usbphy); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return NOTIFY_OK; 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic void tegra_xudc_plc_reset_work(struct work_struct *work) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 84262306a36Sopenharmony_ci struct tegra_xudc *xudc = container_of(dwork, struct tegra_xudc, 84362306a36Sopenharmony_ci plc_reset_work); 84462306a36Sopenharmony_ci unsigned long flags; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (xudc->wait_csc) { 84962306a36Sopenharmony_ci u32 pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >> 85062306a36Sopenharmony_ci PORTSC_PLS_SHIFT; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (pls == PORTSC_PLS_INACTIVE) { 85362306a36Sopenharmony_ci dev_info(xudc->dev, "PLS = Inactive. Toggle VBUS\n"); 85462306a36Sopenharmony_ci phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, 85562306a36Sopenharmony_ci USB_ROLE_NONE); 85662306a36Sopenharmony_ci phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, 85762306a36Sopenharmony_ci USB_ROLE_DEVICE); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci xudc->wait_csc = false; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic void tegra_xudc_port_reset_war_work(struct work_struct *work) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 86962306a36Sopenharmony_ci struct tegra_xudc *xudc = 87062306a36Sopenharmony_ci container_of(dwork, struct tegra_xudc, port_reset_war_work); 87162306a36Sopenharmony_ci unsigned long flags; 87262306a36Sopenharmony_ci u32 pls; 87362306a36Sopenharmony_ci int ret; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (xudc->device_mode && xudc->wait_for_sec_prc) { 87862306a36Sopenharmony_ci pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >> 87962306a36Sopenharmony_ci PORTSC_PLS_SHIFT; 88062306a36Sopenharmony_ci dev_dbg(xudc->dev, "pls = %x\n", pls); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (pls == PORTSC_PLS_DISABLED) { 88362306a36Sopenharmony_ci dev_dbg(xudc->dev, "toggle vbus\n"); 88462306a36Sopenharmony_ci /* PRC doesn't complete in 100ms, toggle the vbus */ 88562306a36Sopenharmony_ci ret = tegra_phy_xusb_utmi_port_reset( 88662306a36Sopenharmony_ci xudc->curr_utmi_phy); 88762306a36Sopenharmony_ci if (ret == 1) 88862306a36Sopenharmony_ci xudc->wait_for_sec_prc = 0; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic dma_addr_t trb_virt_to_phys(struct tegra_xudc_ep *ep, 89662306a36Sopenharmony_ci struct tegra_xudc_trb *trb) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci unsigned int index; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci index = trb - ep->transfer_ring; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (WARN_ON(index >= XUDC_TRANSFER_RING_SIZE)) 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci return (ep->transfer_ring_phys + index * sizeof(*trb)); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic struct tegra_xudc_trb *trb_phys_to_virt(struct tegra_xudc_ep *ep, 90962306a36Sopenharmony_ci dma_addr_t addr) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct tegra_xudc_trb *trb; 91262306a36Sopenharmony_ci unsigned int index; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci index = (addr - ep->transfer_ring_phys) / sizeof(*trb); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (WARN_ON(index >= XUDC_TRANSFER_RING_SIZE)) 91762306a36Sopenharmony_ci return NULL; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci trb = &ep->transfer_ring[index]; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return trb; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic void ep_reload(struct tegra_xudc *xudc, unsigned int ep) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_RELOAD); 92762306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_RELOAD, BIT(ep), 0); 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void ep_pause(struct tegra_xudc *xudc, unsigned int ep) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci u32 val; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci val = xudc_readl(xudc, EP_PAUSE); 93562306a36Sopenharmony_ci if (val & BIT(ep)) 93662306a36Sopenharmony_ci return; 93762306a36Sopenharmony_ci val |= BIT(ep); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci xudc_writel(xudc, val, EP_PAUSE); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, BIT(ep), BIT(ep)); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_STCHG); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic void ep_unpause(struct tegra_xudc *xudc, unsigned int ep) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci u32 val; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci val = xudc_readl(xudc, EP_PAUSE); 95162306a36Sopenharmony_ci if (!(val & BIT(ep))) 95262306a36Sopenharmony_ci return; 95362306a36Sopenharmony_ci val &= ~BIT(ep); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci xudc_writel(xudc, val, EP_PAUSE); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, BIT(ep), BIT(ep)); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_STCHG); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic void ep_unpause_all(struct tegra_xudc *xudc) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci u32 val; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci val = xudc_readl(xudc, EP_PAUSE); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci xudc_writel(xudc, 0, EP_PAUSE); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, val, val); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci xudc_writel(xudc, val, EP_STCHG); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic void ep_halt(struct tegra_xudc *xudc, unsigned int ep) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci u32 val; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci val = xudc_readl(xudc, EP_HALT); 98062306a36Sopenharmony_ci if (val & BIT(ep)) 98162306a36Sopenharmony_ci return; 98262306a36Sopenharmony_ci val |= BIT(ep); 98362306a36Sopenharmony_ci xudc_writel(xudc, val, EP_HALT); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, BIT(ep), BIT(ep)); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_STCHG); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic void ep_unhalt(struct tegra_xudc *xudc, unsigned int ep) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci u32 val; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci val = xudc_readl(xudc, EP_HALT); 99562306a36Sopenharmony_ci if (!(val & BIT(ep))) 99662306a36Sopenharmony_ci return; 99762306a36Sopenharmony_ci val &= ~BIT(ep); 99862306a36Sopenharmony_ci xudc_writel(xudc, val, EP_HALT); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, BIT(ep), BIT(ep)); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_STCHG); 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic void ep_unhalt_all(struct tegra_xudc *xudc) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci u32 val; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci val = xudc_readl(xudc, EP_HALT); 101062306a36Sopenharmony_ci if (!val) 101162306a36Sopenharmony_ci return; 101262306a36Sopenharmony_ci xudc_writel(xudc, 0, EP_HALT); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STCHG, val, val); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci xudc_writel(xudc, val, EP_STCHG); 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void ep_wait_for_stopped(struct tegra_xudc *xudc, unsigned int ep) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_STOPPED, BIT(ep), BIT(ep)); 102262306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep), EP_STOPPED); 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic void ep_wait_for_inactive(struct tegra_xudc *xudc, unsigned int ep) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci xudc_readl_poll(xudc, EP_THREAD_ACTIVE, BIT(ep), 0); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic void tegra_xudc_req_done(struct tegra_xudc_ep *ep, 103162306a36Sopenharmony_ci struct tegra_xudc_request *req, int status) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci dev_dbg(xudc->dev, "completing request %p on EP %u with status %d\n", 103662306a36Sopenharmony_ci req, ep->index, status); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (likely(req->usb_req.status == -EINPROGRESS)) 103962306a36Sopenharmony_ci req->usb_req.status = status; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci list_del_init(&req->list); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (usb_endpoint_xfer_control(ep->desc)) { 104462306a36Sopenharmony_ci usb_gadget_unmap_request(&xudc->gadget, &req->usb_req, 104562306a36Sopenharmony_ci (xudc->setup_state == 104662306a36Sopenharmony_ci DATA_STAGE_XFER)); 104762306a36Sopenharmony_ci } else { 104862306a36Sopenharmony_ci usb_gadget_unmap_request(&xudc->gadget, &req->usb_req, 104962306a36Sopenharmony_ci usb_endpoint_dir_in(ep->desc)); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci spin_unlock(&xudc->lock); 105362306a36Sopenharmony_ci usb_gadget_giveback_request(&ep->usb_ep, &req->usb_req); 105462306a36Sopenharmony_ci spin_lock(&xudc->lock); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic void tegra_xudc_ep_nuke(struct tegra_xudc_ep *ep, int status) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct tegra_xudc_request *req; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 106262306a36Sopenharmony_ci req = list_first_entry(&ep->queue, struct tegra_xudc_request, 106362306a36Sopenharmony_ci list); 106462306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, status); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic unsigned int ep_available_trbs(struct tegra_xudc_ep *ep) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci if (ep->ring_full) 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (ep->deq_ptr > ep->enq_ptr) 107462306a36Sopenharmony_ci return ep->deq_ptr - ep->enq_ptr - 1; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return XUDC_TRANSFER_RING_SIZE - (ep->enq_ptr - ep->deq_ptr) - 2; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic void tegra_xudc_queue_one_trb(struct tegra_xudc_ep *ep, 108062306a36Sopenharmony_ci struct tegra_xudc_request *req, 108162306a36Sopenharmony_ci struct tegra_xudc_trb *trb, 108262306a36Sopenharmony_ci bool ioc) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 108562306a36Sopenharmony_ci dma_addr_t buf_addr; 108662306a36Sopenharmony_ci size_t len; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci len = min_t(size_t, XUDC_TRB_MAX_BUFFER_SIZE, req->usb_req.length - 108962306a36Sopenharmony_ci req->buf_queued); 109062306a36Sopenharmony_ci if (len > 0) 109162306a36Sopenharmony_ci buf_addr = req->usb_req.dma + req->buf_queued; 109262306a36Sopenharmony_ci else 109362306a36Sopenharmony_ci buf_addr = 0; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci trb_write_data_ptr(trb, buf_addr); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci trb_write_transfer_len(trb, len); 109862306a36Sopenharmony_ci trb_write_td_size(trb, req->trbs_needed - req->trbs_queued - 1); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (req->trbs_queued == req->trbs_needed - 1 || 110162306a36Sopenharmony_ci (req->need_zlp && req->trbs_queued == req->trbs_needed - 2)) 110262306a36Sopenharmony_ci trb_write_chain(trb, 0); 110362306a36Sopenharmony_ci else 110462306a36Sopenharmony_ci trb_write_chain(trb, 1); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci trb_write_ioc(trb, ioc); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (usb_endpoint_dir_out(ep->desc) || 110962306a36Sopenharmony_ci (usb_endpoint_xfer_control(ep->desc) && 111062306a36Sopenharmony_ci (xudc->setup_state == DATA_STAGE_RECV))) 111162306a36Sopenharmony_ci trb_write_isp(trb, 1); 111262306a36Sopenharmony_ci else 111362306a36Sopenharmony_ci trb_write_isp(trb, 0); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (usb_endpoint_xfer_control(ep->desc)) { 111662306a36Sopenharmony_ci if (xudc->setup_state == DATA_STAGE_XFER || 111762306a36Sopenharmony_ci xudc->setup_state == DATA_STAGE_RECV) 111862306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_DATA_STAGE); 111962306a36Sopenharmony_ci else 112062306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_STATUS_STAGE); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (xudc->setup_state == DATA_STAGE_XFER || 112362306a36Sopenharmony_ci xudc->setup_state == STATUS_STAGE_XFER) 112462306a36Sopenharmony_ci trb_write_data_stage_dir(trb, 1); 112562306a36Sopenharmony_ci else 112662306a36Sopenharmony_ci trb_write_data_stage_dir(trb, 0); 112762306a36Sopenharmony_ci } else if (usb_endpoint_xfer_isoc(ep->desc)) { 112862306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_ISOCH); 112962306a36Sopenharmony_ci trb_write_sia(trb, 1); 113062306a36Sopenharmony_ci trb_write_frame_id(trb, 0); 113162306a36Sopenharmony_ci trb_write_tlbpc(trb, 0); 113262306a36Sopenharmony_ci } else if (usb_ss_max_streams(ep->comp_desc)) { 113362306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_STREAM); 113462306a36Sopenharmony_ci trb_write_stream_id(trb, req->usb_req.stream_id); 113562306a36Sopenharmony_ci } else { 113662306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_NORMAL); 113762306a36Sopenharmony_ci trb_write_stream_id(trb, 0); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci trb_write_cycle(trb, ep->pcs); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci req->trbs_queued++; 114362306a36Sopenharmony_ci req->buf_queued += len; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci dump_trb(xudc, "TRANSFER", trb); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic unsigned int tegra_xudc_queue_trbs(struct tegra_xudc_ep *ep, 114962306a36Sopenharmony_ci struct tegra_xudc_request *req) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci unsigned int i, count, available; 115262306a36Sopenharmony_ci bool wait_td = false; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci available = ep_available_trbs(ep); 115562306a36Sopenharmony_ci count = req->trbs_needed - req->trbs_queued; 115662306a36Sopenharmony_ci if (available < count) { 115762306a36Sopenharmony_ci count = available; 115862306a36Sopenharmony_ci ep->ring_full = true; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* 116262306a36Sopenharmony_ci * To generate zero-length packet on USB bus, SW needs schedule a 116362306a36Sopenharmony_ci * standalone zero-length TD. According to HW's behavior, SW needs 116462306a36Sopenharmony_ci * to schedule TDs in different ways for different endpoint types. 116562306a36Sopenharmony_ci * 116662306a36Sopenharmony_ci * For control endpoint: 116762306a36Sopenharmony_ci * - Data stage TD (IOC = 1, CH = 0) 116862306a36Sopenharmony_ci * - Ring doorbell and wait transfer event 116962306a36Sopenharmony_ci * - Data stage TD for ZLP (IOC = 1, CH = 0) 117062306a36Sopenharmony_ci * - Ring doorbell 117162306a36Sopenharmony_ci * 117262306a36Sopenharmony_ci * For bulk and interrupt endpoints: 117362306a36Sopenharmony_ci * - Normal transfer TD (IOC = 0, CH = 0) 117462306a36Sopenharmony_ci * - Normal transfer TD for ZLP (IOC = 1, CH = 0) 117562306a36Sopenharmony_ci * - Ring doorbell 117662306a36Sopenharmony_ci */ 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (req->need_zlp && usb_endpoint_xfer_control(ep->desc) && count > 1) 117962306a36Sopenharmony_ci wait_td = true; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (!req->first_trb) 118262306a36Sopenharmony_ci req->first_trb = &ep->transfer_ring[ep->enq_ptr]; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 118562306a36Sopenharmony_ci struct tegra_xudc_trb *trb = &ep->transfer_ring[ep->enq_ptr]; 118662306a36Sopenharmony_ci bool ioc = false; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if ((i == count - 1) || (wait_td && i == count - 2)) 118962306a36Sopenharmony_ci ioc = true; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci tegra_xudc_queue_one_trb(ep, req, trb, ioc); 119262306a36Sopenharmony_ci req->last_trb = trb; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci ep->enq_ptr++; 119562306a36Sopenharmony_ci if (ep->enq_ptr == XUDC_TRANSFER_RING_SIZE - 1) { 119662306a36Sopenharmony_ci trb = &ep->transfer_ring[ep->enq_ptr]; 119762306a36Sopenharmony_ci trb_write_cycle(trb, ep->pcs); 119862306a36Sopenharmony_ci ep->pcs = !ep->pcs; 119962306a36Sopenharmony_ci ep->enq_ptr = 0; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (ioc) 120362306a36Sopenharmony_ci break; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return count; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic void tegra_xudc_ep_ring_doorbell(struct tegra_xudc_ep *ep) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 121262306a36Sopenharmony_ci u32 val; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (list_empty(&ep->queue)) 121562306a36Sopenharmony_ci return; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci val = DB_TARGET(ep->index); 121862306a36Sopenharmony_ci if (usb_endpoint_xfer_control(ep->desc)) { 121962306a36Sopenharmony_ci val |= DB_STREAMID(xudc->setup_seq_num); 122062306a36Sopenharmony_ci } else if (usb_ss_max_streams(ep->comp_desc) > 0) { 122162306a36Sopenharmony_ci struct tegra_xudc_request *req; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* Don't ring doorbell if the stream has been rejected. */ 122462306a36Sopenharmony_ci if (ep->stream_rejected) 122562306a36Sopenharmony_ci return; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci req = list_first_entry(&ep->queue, struct tegra_xudc_request, 122862306a36Sopenharmony_ci list); 122962306a36Sopenharmony_ci val |= DB_STREAMID(req->usb_req.stream_id); 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci dev_dbg(xudc->dev, "ring doorbell: %#x\n", val); 123362306a36Sopenharmony_ci xudc_writel(xudc, val, DB); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic void tegra_xudc_ep_kick_queue(struct tegra_xudc_ep *ep) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct tegra_xudc_request *req; 123962306a36Sopenharmony_ci bool trbs_queued = false; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci list_for_each_entry(req, &ep->queue, list) { 124262306a36Sopenharmony_ci if (ep->ring_full) 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (tegra_xudc_queue_trbs(ep, req) > 0) 124662306a36Sopenharmony_ci trbs_queued = true; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (trbs_queued) 125062306a36Sopenharmony_ci tegra_xudc_ep_ring_doorbell(ep); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic int 125462306a36Sopenharmony_ci__tegra_xudc_ep_queue(struct tegra_xudc_ep *ep, struct tegra_xudc_request *req) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 125762306a36Sopenharmony_ci int err; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (usb_endpoint_xfer_control(ep->desc) && !list_empty(&ep->queue)) { 126062306a36Sopenharmony_ci dev_err(xudc->dev, "control EP has pending transfers\n"); 126162306a36Sopenharmony_ci return -EINVAL; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (usb_endpoint_xfer_control(ep->desc)) { 126562306a36Sopenharmony_ci err = usb_gadget_map_request(&xudc->gadget, &req->usb_req, 126662306a36Sopenharmony_ci (xudc->setup_state == 126762306a36Sopenharmony_ci DATA_STAGE_XFER)); 126862306a36Sopenharmony_ci } else { 126962306a36Sopenharmony_ci err = usb_gadget_map_request(&xudc->gadget, &req->usb_req, 127062306a36Sopenharmony_ci usb_endpoint_dir_in(ep->desc)); 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (err < 0) { 127462306a36Sopenharmony_ci dev_err(xudc->dev, "failed to map request: %d\n", err); 127562306a36Sopenharmony_ci return err; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci req->first_trb = NULL; 127962306a36Sopenharmony_ci req->last_trb = NULL; 128062306a36Sopenharmony_ci req->buf_queued = 0; 128162306a36Sopenharmony_ci req->trbs_queued = 0; 128262306a36Sopenharmony_ci req->need_zlp = false; 128362306a36Sopenharmony_ci req->trbs_needed = DIV_ROUND_UP(req->usb_req.length, 128462306a36Sopenharmony_ci XUDC_TRB_MAX_BUFFER_SIZE); 128562306a36Sopenharmony_ci if (req->usb_req.length == 0) 128662306a36Sopenharmony_ci req->trbs_needed++; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (!usb_endpoint_xfer_isoc(ep->desc) && 128962306a36Sopenharmony_ci req->usb_req.zero && req->usb_req.length && 129062306a36Sopenharmony_ci ((req->usb_req.length % ep->usb_ep.maxpacket) == 0)) { 129162306a36Sopenharmony_ci req->trbs_needed++; 129262306a36Sopenharmony_ci req->need_zlp = true; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci req->usb_req.status = -EINPROGRESS; 129662306a36Sopenharmony_ci req->usb_req.actual = 0; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci list_add_tail(&req->list, &ep->queue); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci tegra_xudc_ep_kick_queue(ep); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic int 130662306a36Sopenharmony_citegra_xudc_ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req, 130762306a36Sopenharmony_ci gfp_t gfp) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct tegra_xudc_request *req; 131062306a36Sopenharmony_ci struct tegra_xudc_ep *ep; 131162306a36Sopenharmony_ci struct tegra_xudc *xudc; 131262306a36Sopenharmony_ci unsigned long flags; 131362306a36Sopenharmony_ci int ret; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (!usb_ep || !usb_req) 131662306a36Sopenharmony_ci return -EINVAL; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci ep = to_xudc_ep(usb_ep); 131962306a36Sopenharmony_ci req = to_xudc_req(usb_req); 132062306a36Sopenharmony_ci xudc = ep->xudc; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 132362306a36Sopenharmony_ci if (xudc->powergated || !ep->desc) { 132462306a36Sopenharmony_ci ret = -ESHUTDOWN; 132562306a36Sopenharmony_ci goto unlock; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci ret = __tegra_xudc_ep_queue(ep, req); 132962306a36Sopenharmony_ciunlock: 133062306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci return ret; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic void squeeze_transfer_ring(struct tegra_xudc_ep *ep, 133662306a36Sopenharmony_ci struct tegra_xudc_request *req) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci struct tegra_xudc_trb *trb = req->first_trb; 133962306a36Sopenharmony_ci bool pcs_enq = trb_read_cycle(trb); 134062306a36Sopenharmony_ci bool pcs; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* 134362306a36Sopenharmony_ci * Clear out all the TRBs part of or after the cancelled request, 134462306a36Sopenharmony_ci * and must correct trb cycle bit to the last un-enqueued state. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_ci while (trb != &ep->transfer_ring[ep->enq_ptr]) { 134762306a36Sopenharmony_ci pcs = trb_read_cycle(trb); 134862306a36Sopenharmony_ci memset(trb, 0, sizeof(*trb)); 134962306a36Sopenharmony_ci trb_write_cycle(trb, !pcs); 135062306a36Sopenharmony_ci trb++; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (trb_read_type(trb) == TRB_TYPE_LINK) 135362306a36Sopenharmony_ci trb = ep->transfer_ring; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci /* Requests will be re-queued at the start of the cancelled request. */ 135762306a36Sopenharmony_ci ep->enq_ptr = req->first_trb - ep->transfer_ring; 135862306a36Sopenharmony_ci /* 135962306a36Sopenharmony_ci * Retrieve the correct cycle bit state from the first trb of 136062306a36Sopenharmony_ci * the cancelled request. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci ep->pcs = pcs_enq; 136362306a36Sopenharmony_ci ep->ring_full = false; 136462306a36Sopenharmony_ci list_for_each_entry_continue(req, &ep->queue, list) { 136562306a36Sopenharmony_ci req->usb_req.status = -EINPROGRESS; 136662306a36Sopenharmony_ci req->usb_req.actual = 0; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci req->first_trb = NULL; 136962306a36Sopenharmony_ci req->last_trb = NULL; 137062306a36Sopenharmony_ci req->buf_queued = 0; 137162306a36Sopenharmony_ci req->trbs_queued = 0; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci/* 137662306a36Sopenharmony_ci * Determine if the given TRB is in the range [first trb, last trb] for the 137762306a36Sopenharmony_ci * given request. 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_cistatic bool trb_in_request(struct tegra_xudc_ep *ep, 138062306a36Sopenharmony_ci struct tegra_xudc_request *req, 138162306a36Sopenharmony_ci struct tegra_xudc_trb *trb) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci dev_dbg(ep->xudc->dev, "%s: request %p -> %p; trb %p\n", __func__, 138462306a36Sopenharmony_ci req->first_trb, req->last_trb, trb); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (trb >= req->first_trb && (trb <= req->last_trb || 138762306a36Sopenharmony_ci req->last_trb < req->first_trb)) 138862306a36Sopenharmony_ci return true; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (trb < req->first_trb && trb <= req->last_trb && 139162306a36Sopenharmony_ci req->last_trb < req->first_trb) 139262306a36Sopenharmony_ci return true; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci return false; 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci/* 139862306a36Sopenharmony_ci * Determine if the given TRB is in the range [EP enqueue pointer, first TRB) 139962306a36Sopenharmony_ci * for the given endpoint and request. 140062306a36Sopenharmony_ci */ 140162306a36Sopenharmony_cistatic bool trb_before_request(struct tegra_xudc_ep *ep, 140262306a36Sopenharmony_ci struct tegra_xudc_request *req, 140362306a36Sopenharmony_ci struct tegra_xudc_trb *trb) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci struct tegra_xudc_trb *enq_trb = &ep->transfer_ring[ep->enq_ptr]; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci dev_dbg(ep->xudc->dev, "%s: request %p -> %p; enq ptr: %p; trb %p\n", 140862306a36Sopenharmony_ci __func__, req->first_trb, req->last_trb, enq_trb, trb); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (trb < req->first_trb && (enq_trb <= trb || 141162306a36Sopenharmony_ci req->first_trb < enq_trb)) 141262306a36Sopenharmony_ci return true; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (trb > req->first_trb && req->first_trb < enq_trb && enq_trb <= trb) 141562306a36Sopenharmony_ci return true; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci return false; 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic int 142162306a36Sopenharmony_ci__tegra_xudc_ep_dequeue(struct tegra_xudc_ep *ep, 142262306a36Sopenharmony_ci struct tegra_xudc_request *req) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 142562306a36Sopenharmony_ci struct tegra_xudc_request *r = NULL, *iter; 142662306a36Sopenharmony_ci struct tegra_xudc_trb *deq_trb; 142762306a36Sopenharmony_ci bool busy, kick_queue = false; 142862306a36Sopenharmony_ci int ret = 0; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Make sure the request is actually queued to this endpoint. */ 143162306a36Sopenharmony_ci list_for_each_entry(iter, &ep->queue, list) { 143262306a36Sopenharmony_ci if (iter != req) 143362306a36Sopenharmony_ci continue; 143462306a36Sopenharmony_ci r = iter; 143562306a36Sopenharmony_ci break; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (!r) 143962306a36Sopenharmony_ci return -EINVAL; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* Request hasn't been queued in the transfer ring yet. */ 144262306a36Sopenharmony_ci if (!req->trbs_queued) { 144362306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, -ECONNRESET); 144462306a36Sopenharmony_ci return 0; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* Halt DMA for this endpoint. */ 144862306a36Sopenharmony_ci if (ep_ctx_read_state(ep->context) == EP_STATE_RUNNING) { 144962306a36Sopenharmony_ci ep_pause(xudc, ep->index); 145062306a36Sopenharmony_ci ep_wait_for_inactive(xudc, ep->index); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci deq_trb = trb_phys_to_virt(ep, ep_ctx_read_deq_ptr(ep->context)); 145462306a36Sopenharmony_ci /* Is the hardware processing the TRB at the dequeue pointer? */ 145562306a36Sopenharmony_ci busy = (trb_read_cycle(deq_trb) == ep_ctx_read_dcs(ep->context)); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (trb_in_request(ep, req, deq_trb) && busy) { 145862306a36Sopenharmony_ci /* 145962306a36Sopenharmony_ci * Request has been partially completed or it hasn't 146062306a36Sopenharmony_ci * started processing yet. 146162306a36Sopenharmony_ci */ 146262306a36Sopenharmony_ci dma_addr_t deq_ptr; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci squeeze_transfer_ring(ep, req); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci req->usb_req.actual = ep_ctx_read_edtla(ep->context); 146762306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, -ECONNRESET); 146862306a36Sopenharmony_ci kick_queue = true; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* EDTLA is > 0: request has been partially completed */ 147162306a36Sopenharmony_ci if (req->usb_req.actual > 0) { 147262306a36Sopenharmony_ci /* 147362306a36Sopenharmony_ci * Abort the pending transfer and update the dequeue 147462306a36Sopenharmony_ci * pointer 147562306a36Sopenharmony_ci */ 147662306a36Sopenharmony_ci ep_ctx_write_edtla(ep->context, 0); 147762306a36Sopenharmony_ci ep_ctx_write_partial_td(ep->context, 0); 147862306a36Sopenharmony_ci ep_ctx_write_data_offset(ep->context, 0); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci deq_ptr = trb_virt_to_phys(ep, 148162306a36Sopenharmony_ci &ep->transfer_ring[ep->enq_ptr]); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci if (dma_mapping_error(xudc->dev, deq_ptr)) { 148462306a36Sopenharmony_ci ret = -EINVAL; 148562306a36Sopenharmony_ci } else { 148662306a36Sopenharmony_ci ep_ctx_write_deq_ptr(ep->context, deq_ptr); 148762306a36Sopenharmony_ci ep_ctx_write_dcs(ep->context, ep->pcs); 148862306a36Sopenharmony_ci ep_reload(xudc, ep->index); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci } else if (trb_before_request(ep, req, deq_trb) && busy) { 149262306a36Sopenharmony_ci /* Request hasn't started processing yet. */ 149362306a36Sopenharmony_ci squeeze_transfer_ring(ep, req); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, -ECONNRESET); 149662306a36Sopenharmony_ci kick_queue = true; 149762306a36Sopenharmony_ci } else { 149862306a36Sopenharmony_ci /* 149962306a36Sopenharmony_ci * Request has completed, but we haven't processed the 150062306a36Sopenharmony_ci * completion event yet. 150162306a36Sopenharmony_ci */ 150262306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, -ECONNRESET); 150362306a36Sopenharmony_ci ret = -EINVAL; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* Resume the endpoint. */ 150762306a36Sopenharmony_ci ep_unpause(xudc, ep->index); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (kick_queue) 151062306a36Sopenharmony_ci tegra_xudc_ep_kick_queue(ep); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci return ret; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic int 151662306a36Sopenharmony_citegra_xudc_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci struct tegra_xudc_request *req; 151962306a36Sopenharmony_ci struct tegra_xudc_ep *ep; 152062306a36Sopenharmony_ci struct tegra_xudc *xudc; 152162306a36Sopenharmony_ci unsigned long flags; 152262306a36Sopenharmony_ci int ret; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (!usb_ep || !usb_req) 152562306a36Sopenharmony_ci return -EINVAL; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ep = to_xudc_ep(usb_ep); 152862306a36Sopenharmony_ci req = to_xudc_req(usb_req); 152962306a36Sopenharmony_ci xudc = ep->xudc; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (xudc->powergated || !ep->desc) { 153462306a36Sopenharmony_ci ret = -ESHUTDOWN; 153562306a36Sopenharmony_ci goto unlock; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci ret = __tegra_xudc_ep_dequeue(ep, req); 153962306a36Sopenharmony_ciunlock: 154062306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci return ret; 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic int __tegra_xudc_ep_set_halt(struct tegra_xudc_ep *ep, bool halt) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci if (!ep->desc) 155062306a36Sopenharmony_ci return -EINVAL; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(ep->desc)) { 155362306a36Sopenharmony_ci dev_err(xudc->dev, "can't halt isochronous EP\n"); 155462306a36Sopenharmony_ci return -ENOTSUPP; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (!!(xudc_readl(xudc, EP_HALT) & BIT(ep->index)) == halt) { 155862306a36Sopenharmony_ci dev_dbg(xudc->dev, "EP %u already %s\n", ep->index, 155962306a36Sopenharmony_ci halt ? "halted" : "not halted"); 156062306a36Sopenharmony_ci return 0; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (halt) { 156462306a36Sopenharmony_ci ep_halt(xudc, ep->index); 156562306a36Sopenharmony_ci } else { 156662306a36Sopenharmony_ci ep_ctx_write_state(ep->context, EP_STATE_DISABLED); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci ep_reload(xudc, ep->index); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci ep_ctx_write_state(ep->context, EP_STATE_RUNNING); 157162306a36Sopenharmony_ci ep_ctx_write_rsvd(ep->context, 0); 157262306a36Sopenharmony_ci ep_ctx_write_partial_td(ep->context, 0); 157362306a36Sopenharmony_ci ep_ctx_write_splitxstate(ep->context, 0); 157462306a36Sopenharmony_ci ep_ctx_write_seq_num(ep->context, 0); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci ep_reload(xudc, ep->index); 157762306a36Sopenharmony_ci ep_unpause(xudc, ep->index); 157862306a36Sopenharmony_ci ep_unhalt(xudc, ep->index); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci tegra_xudc_ep_ring_doorbell(ep); 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci return 0; 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cistatic int tegra_xudc_ep_set_halt(struct usb_ep *usb_ep, int value) 158762306a36Sopenharmony_ci{ 158862306a36Sopenharmony_ci struct tegra_xudc_ep *ep; 158962306a36Sopenharmony_ci struct tegra_xudc *xudc; 159062306a36Sopenharmony_ci unsigned long flags; 159162306a36Sopenharmony_ci int ret; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (!usb_ep) 159462306a36Sopenharmony_ci return -EINVAL; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci ep = to_xudc_ep(usb_ep); 159762306a36Sopenharmony_ci xudc = ep->xudc; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 160062306a36Sopenharmony_ci if (xudc->powergated) { 160162306a36Sopenharmony_ci ret = -ESHUTDOWN; 160262306a36Sopenharmony_ci goto unlock; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (value && usb_endpoint_dir_in(ep->desc) && 160662306a36Sopenharmony_ci !list_empty(&ep->queue)) { 160762306a36Sopenharmony_ci dev_err(xudc->dev, "can't halt EP with requests pending\n"); 160862306a36Sopenharmony_ci ret = -EAGAIN; 160962306a36Sopenharmony_ci goto unlock; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci ret = __tegra_xudc_ep_set_halt(ep, value); 161362306a36Sopenharmony_ciunlock: 161462306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci return ret; 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_cistatic void tegra_xudc_ep_context_setup(struct tegra_xudc_ep *ep) 162062306a36Sopenharmony_ci{ 162162306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc = ep->desc; 162262306a36Sopenharmony_ci const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc; 162362306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 162462306a36Sopenharmony_ci u16 maxpacket, maxburst = 0, esit = 0; 162562306a36Sopenharmony_ci u32 val; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci maxpacket = usb_endpoint_maxp(desc); 162862306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) { 162962306a36Sopenharmony_ci if (!usb_endpoint_xfer_control(desc)) 163062306a36Sopenharmony_ci maxburst = comp_desc->bMaxBurst; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) 163362306a36Sopenharmony_ci esit = le16_to_cpu(comp_desc->wBytesPerInterval); 163462306a36Sopenharmony_ci } else if ((xudc->gadget.speed < USB_SPEED_SUPER) && 163562306a36Sopenharmony_ci (usb_endpoint_xfer_int(desc) || 163662306a36Sopenharmony_ci usb_endpoint_xfer_isoc(desc))) { 163762306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_HIGH) { 163862306a36Sopenharmony_ci maxburst = usb_endpoint_maxp_mult(desc) - 1; 163962306a36Sopenharmony_ci if (maxburst == 0x3) { 164062306a36Sopenharmony_ci dev_warn(xudc->dev, 164162306a36Sopenharmony_ci "invalid endpoint maxburst\n"); 164262306a36Sopenharmony_ci maxburst = 0x2; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci esit = maxpacket * (maxburst + 1); 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci memset(ep->context, 0, sizeof(*ep->context)); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci ep_ctx_write_state(ep->context, EP_STATE_RUNNING); 165162306a36Sopenharmony_ci ep_ctx_write_interval(ep->context, desc->bInterval); 165262306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) { 165362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc)) { 165462306a36Sopenharmony_ci ep_ctx_write_mult(ep->context, 165562306a36Sopenharmony_ci comp_desc->bmAttributes & 0x3); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (usb_endpoint_xfer_bulk(desc)) { 165962306a36Sopenharmony_ci ep_ctx_write_max_pstreams(ep->context, 166062306a36Sopenharmony_ci comp_desc->bmAttributes & 166162306a36Sopenharmony_ci 0x1f); 166262306a36Sopenharmony_ci ep_ctx_write_lsa(ep->context, 1); 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (!usb_endpoint_xfer_control(desc) && usb_endpoint_dir_out(desc)) 166762306a36Sopenharmony_ci val = usb_endpoint_type(desc); 166862306a36Sopenharmony_ci else 166962306a36Sopenharmony_ci val = usb_endpoint_type(desc) + EP_TYPE_CONTROL; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci ep_ctx_write_type(ep->context, val); 167262306a36Sopenharmony_ci ep_ctx_write_cerr(ep->context, 0x3); 167362306a36Sopenharmony_ci ep_ctx_write_max_packet_size(ep->context, maxpacket); 167462306a36Sopenharmony_ci ep_ctx_write_max_burst_size(ep->context, maxburst); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci ep_ctx_write_deq_ptr(ep->context, ep->transfer_ring_phys); 167762306a36Sopenharmony_ci ep_ctx_write_dcs(ep->context, ep->pcs); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci /* Select a reasonable average TRB length based on endpoint type. */ 168062306a36Sopenharmony_ci switch (usb_endpoint_type(desc)) { 168162306a36Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 168262306a36Sopenharmony_ci val = 8; 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 168562306a36Sopenharmony_ci val = 1024; 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 168862306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 168962306a36Sopenharmony_ci default: 169062306a36Sopenharmony_ci val = 3072; 169162306a36Sopenharmony_ci break; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci ep_ctx_write_avg_trb_len(ep->context, val); 169562306a36Sopenharmony_ci ep_ctx_write_max_esit_payload(ep->context, esit); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci ep_ctx_write_cerrcnt(ep->context, 0x3); 169862306a36Sopenharmony_ci} 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic void setup_link_trb(struct tegra_xudc_ep *ep, 170162306a36Sopenharmony_ci struct tegra_xudc_trb *trb) 170262306a36Sopenharmony_ci{ 170362306a36Sopenharmony_ci trb_write_data_ptr(trb, ep->transfer_ring_phys); 170462306a36Sopenharmony_ci trb_write_type(trb, TRB_TYPE_LINK); 170562306a36Sopenharmony_ci trb_write_toggle_cycle(trb, 1); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic int __tegra_xudc_ep_disable(struct tegra_xudc_ep *ep) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (ep_ctx_read_state(ep->context) == EP_STATE_DISABLED) { 171362306a36Sopenharmony_ci dev_err(xudc->dev, "endpoint %u already disabled\n", 171462306a36Sopenharmony_ci ep->index); 171562306a36Sopenharmony_ci return -EINVAL; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci ep_ctx_write_state(ep->context, EP_STATE_DISABLED); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci ep_reload(xudc, ep->index); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci tegra_xudc_ep_nuke(ep, -ESHUTDOWN); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci xudc->nr_enabled_eps--; 172562306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(ep->desc)) 172662306a36Sopenharmony_ci xudc->nr_isoch_eps--; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci ep->desc = NULL; 172962306a36Sopenharmony_ci ep->comp_desc = NULL; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci memset(ep->context, 0, sizeof(*ep->context)); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci ep_unpause(xudc, ep->index); 173462306a36Sopenharmony_ci ep_unhalt(xudc, ep->index); 173562306a36Sopenharmony_ci if (xudc_readl(xudc, EP_STOPPED) & BIT(ep->index)) 173662306a36Sopenharmony_ci xudc_writel(xudc, BIT(ep->index), EP_STOPPED); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* 173962306a36Sopenharmony_ci * If this is the last endpoint disabled in a de-configure request, 174062306a36Sopenharmony_ci * switch back to address state. 174162306a36Sopenharmony_ci */ 174262306a36Sopenharmony_ci if ((xudc->device_state == USB_STATE_CONFIGURED) && 174362306a36Sopenharmony_ci (xudc->nr_enabled_eps == 1)) { 174462306a36Sopenharmony_ci u32 val; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci xudc->device_state = USB_STATE_ADDRESS; 174762306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 175062306a36Sopenharmony_ci val &= ~CTRL_RUN; 175162306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci dev_info(xudc->dev, "ep %u disabled\n", ep->index); 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci return 0; 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic int tegra_xudc_ep_disable(struct usb_ep *usb_ep) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci struct tegra_xudc_ep *ep; 176262306a36Sopenharmony_ci struct tegra_xudc *xudc; 176362306a36Sopenharmony_ci unsigned long flags; 176462306a36Sopenharmony_ci int ret; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci if (!usb_ep) 176762306a36Sopenharmony_ci return -EINVAL; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci ep = to_xudc_ep(usb_ep); 177062306a36Sopenharmony_ci xudc = ep->xudc; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 177362306a36Sopenharmony_ci if (xudc->powergated) { 177462306a36Sopenharmony_ci ret = -ESHUTDOWN; 177562306a36Sopenharmony_ci goto unlock; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci ret = __tegra_xudc_ep_disable(ep); 177962306a36Sopenharmony_ciunlock: 178062306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci return ret; 178362306a36Sopenharmony_ci} 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic int __tegra_xudc_ep_enable(struct tegra_xudc_ep *ep, 178662306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 178762306a36Sopenharmony_ci{ 178862306a36Sopenharmony_ci struct tegra_xudc *xudc = ep->xudc; 178962306a36Sopenharmony_ci unsigned int i; 179062306a36Sopenharmony_ci u32 val; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER && 179362306a36Sopenharmony_ci !usb_endpoint_xfer_control(desc) && !ep->usb_ep.comp_desc) 179462306a36Sopenharmony_ci return -EINVAL; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci /* Disable the EP if it is not disabled */ 179762306a36Sopenharmony_ci if (ep_ctx_read_state(ep->context) != EP_STATE_DISABLED) 179862306a36Sopenharmony_ci __tegra_xudc_ep_disable(ep); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci ep->desc = desc; 180162306a36Sopenharmony_ci ep->comp_desc = ep->usb_ep.comp_desc; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc)) { 180462306a36Sopenharmony_ci if (xudc->nr_isoch_eps > XUDC_MAX_ISOCH_EPS) { 180562306a36Sopenharmony_ci dev_err(xudc->dev, "too many isochronous endpoints\n"); 180662306a36Sopenharmony_ci return -EBUSY; 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci xudc->nr_isoch_eps++; 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci memset(ep->transfer_ring, 0, XUDC_TRANSFER_RING_SIZE * 181262306a36Sopenharmony_ci sizeof(*ep->transfer_ring)); 181362306a36Sopenharmony_ci setup_link_trb(ep, &ep->transfer_ring[XUDC_TRANSFER_RING_SIZE - 1]); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci ep->enq_ptr = 0; 181662306a36Sopenharmony_ci ep->deq_ptr = 0; 181762306a36Sopenharmony_ci ep->pcs = true; 181862306a36Sopenharmony_ci ep->ring_full = false; 181962306a36Sopenharmony_ci xudc->nr_enabled_eps++; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci tegra_xudc_ep_context_setup(ep); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* 182462306a36Sopenharmony_ci * No need to reload and un-halt EP0. This will be done automatically 182562306a36Sopenharmony_ci * once a valid SETUP packet is received. 182662306a36Sopenharmony_ci */ 182762306a36Sopenharmony_ci if (usb_endpoint_xfer_control(desc)) 182862306a36Sopenharmony_ci goto out; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* 183162306a36Sopenharmony_ci * Transition to configured state once the first non-control 183262306a36Sopenharmony_ci * endpoint is enabled. 183362306a36Sopenharmony_ci */ 183462306a36Sopenharmony_ci if (xudc->device_state == USB_STATE_ADDRESS) { 183562306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 183662306a36Sopenharmony_ci val |= CTRL_RUN; 183762306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci xudc->device_state = USB_STATE_CONFIGURED; 184062306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc)) { 184462306a36Sopenharmony_ci /* 184562306a36Sopenharmony_ci * Pause all bulk endpoints when enabling an isoch endpoint 184662306a36Sopenharmony_ci * to ensure the isoch endpoint is allocated enough bandwidth. 184762306a36Sopenharmony_ci */ 184862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) { 184962306a36Sopenharmony_ci if (xudc->ep[i].desc && 185062306a36Sopenharmony_ci usb_endpoint_xfer_bulk(xudc->ep[i].desc)) 185162306a36Sopenharmony_ci ep_pause(xudc, i); 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci ep_reload(xudc, ep->index); 185662306a36Sopenharmony_ci ep_unpause(xudc, ep->index); 185762306a36Sopenharmony_ci ep_unhalt(xudc, ep->index); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc)) { 186062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) { 186162306a36Sopenharmony_ci if (xudc->ep[i].desc && 186262306a36Sopenharmony_ci usb_endpoint_xfer_bulk(xudc->ep[i].desc)) 186362306a36Sopenharmony_ci ep_unpause(xudc, i); 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ciout: 186862306a36Sopenharmony_ci dev_info(xudc->dev, "EP %u (type: %s, dir: %s) enabled\n", ep->index, 186962306a36Sopenharmony_ci usb_ep_type_string(usb_endpoint_type(ep->desc)), 187062306a36Sopenharmony_ci usb_endpoint_dir_in(ep->desc) ? "in" : "out"); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci return 0; 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistatic int tegra_xudc_ep_enable(struct usb_ep *usb_ep, 187662306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 187762306a36Sopenharmony_ci{ 187862306a36Sopenharmony_ci struct tegra_xudc_ep *ep; 187962306a36Sopenharmony_ci struct tegra_xudc *xudc; 188062306a36Sopenharmony_ci unsigned long flags; 188162306a36Sopenharmony_ci int ret; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (!usb_ep || !desc || (desc->bDescriptorType != USB_DT_ENDPOINT)) 188462306a36Sopenharmony_ci return -EINVAL; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci ep = to_xudc_ep(usb_ep); 188762306a36Sopenharmony_ci xudc = ep->xudc; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 189062306a36Sopenharmony_ci if (xudc->powergated) { 189162306a36Sopenharmony_ci ret = -ESHUTDOWN; 189262306a36Sopenharmony_ci goto unlock; 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci ret = __tegra_xudc_ep_enable(ep, desc); 189662306a36Sopenharmony_ciunlock: 189762306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci return ret; 190062306a36Sopenharmony_ci} 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_cistatic struct usb_request * 190362306a36Sopenharmony_citegra_xudc_ep_alloc_request(struct usb_ep *usb_ep, gfp_t gfp) 190462306a36Sopenharmony_ci{ 190562306a36Sopenharmony_ci struct tegra_xudc_request *req; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci req = kzalloc(sizeof(*req), gfp); 190862306a36Sopenharmony_ci if (!req) 190962306a36Sopenharmony_ci return NULL; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci INIT_LIST_HEAD(&req->list); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci return &req->usb_req; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic void tegra_xudc_ep_free_request(struct usb_ep *usb_ep, 191762306a36Sopenharmony_ci struct usb_request *usb_req) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci struct tegra_xudc_request *req = to_xudc_req(usb_req); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci kfree(req); 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic const struct usb_ep_ops tegra_xudc_ep_ops = { 192562306a36Sopenharmony_ci .enable = tegra_xudc_ep_enable, 192662306a36Sopenharmony_ci .disable = tegra_xudc_ep_disable, 192762306a36Sopenharmony_ci .alloc_request = tegra_xudc_ep_alloc_request, 192862306a36Sopenharmony_ci .free_request = tegra_xudc_ep_free_request, 192962306a36Sopenharmony_ci .queue = tegra_xudc_ep_queue, 193062306a36Sopenharmony_ci .dequeue = tegra_xudc_ep_dequeue, 193162306a36Sopenharmony_ci .set_halt = tegra_xudc_ep_set_halt, 193262306a36Sopenharmony_ci}; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_cistatic int tegra_xudc_ep0_enable(struct usb_ep *usb_ep, 193562306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 193662306a36Sopenharmony_ci{ 193762306a36Sopenharmony_ci return -EBUSY; 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic int tegra_xudc_ep0_disable(struct usb_ep *usb_ep) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci return -EBUSY; 194362306a36Sopenharmony_ci} 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_cistatic const struct usb_ep_ops tegra_xudc_ep0_ops = { 194662306a36Sopenharmony_ci .enable = tegra_xudc_ep0_enable, 194762306a36Sopenharmony_ci .disable = tegra_xudc_ep0_disable, 194862306a36Sopenharmony_ci .alloc_request = tegra_xudc_ep_alloc_request, 194962306a36Sopenharmony_ci .free_request = tegra_xudc_ep_free_request, 195062306a36Sopenharmony_ci .queue = tegra_xudc_ep_queue, 195162306a36Sopenharmony_ci .dequeue = tegra_xudc_ep_dequeue, 195262306a36Sopenharmony_ci .set_halt = tegra_xudc_ep_set_halt, 195362306a36Sopenharmony_ci}; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_cistatic int tegra_xudc_gadget_get_frame(struct usb_gadget *gadget) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 195862306a36Sopenharmony_ci unsigned long flags; 195962306a36Sopenharmony_ci int ret; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 196262306a36Sopenharmony_ci if (xudc->powergated) { 196362306a36Sopenharmony_ci ret = -ESHUTDOWN; 196462306a36Sopenharmony_ci goto unlock; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci ret = (xudc_readl(xudc, MFINDEX) & MFINDEX_FRAME_MASK) >> 196862306a36Sopenharmony_ci MFINDEX_FRAME_SHIFT; 196962306a36Sopenharmony_ciunlock: 197062306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci return ret; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_cistatic void tegra_xudc_resume_device_state(struct tegra_xudc *xudc) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci unsigned int i; 197862306a36Sopenharmony_ci u32 val; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci ep_unpause_all(xudc); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci /* Direct link to U0. */ 198362306a36Sopenharmony_ci val = xudc_readl(xudc, PORTSC); 198462306a36Sopenharmony_ci if (((val & PORTSC_PLS_MASK) >> PORTSC_PLS_SHIFT) != PORTSC_PLS_U0) { 198562306a36Sopenharmony_ci val &= ~(PORTSC_CHANGE_MASK | PORTSC_PLS_MASK); 198662306a36Sopenharmony_ci val |= PORTSC_LWS | PORTSC_PLS(PORTSC_PLS_U0); 198762306a36Sopenharmony_ci xudc_writel(xudc, val, PORTSC); 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (xudc->device_state == USB_STATE_SUSPENDED) { 199162306a36Sopenharmony_ci xudc->device_state = xudc->resume_state; 199262306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 199362306a36Sopenharmony_ci xudc->resume_state = 0; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* 199762306a36Sopenharmony_ci * Doorbells may be dropped if they are sent too soon (< ~200ns) 199862306a36Sopenharmony_ci * after unpausing the endpoint. Wait for 500ns just to be safe. 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_ci ndelay(500); 200162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) 200262306a36Sopenharmony_ci tegra_xudc_ep_ring_doorbell(&xudc->ep[i]); 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic int tegra_xudc_gadget_wakeup(struct usb_gadget *gadget) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 200862306a36Sopenharmony_ci unsigned long flags; 200962306a36Sopenharmony_ci int ret = 0; 201062306a36Sopenharmony_ci u32 val; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (xudc->powergated) { 201562306a36Sopenharmony_ci ret = -ESHUTDOWN; 201662306a36Sopenharmony_ci goto unlock; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 201962306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: PORTPM=%#x, speed=%x\n", __func__, 202062306a36Sopenharmony_ci val, gadget->speed); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci if (((xudc->gadget.speed <= USB_SPEED_HIGH) && 202362306a36Sopenharmony_ci (val & PORTPM_RWE)) || 202462306a36Sopenharmony_ci ((xudc->gadget.speed == USB_SPEED_SUPER) && 202562306a36Sopenharmony_ci (val & PORTPM_FRWE))) { 202662306a36Sopenharmony_ci tegra_xudc_resume_device_state(xudc); 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci /* Send Device Notification packet. */ 202962306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) { 203062306a36Sopenharmony_ci val = DEVNOTIF_LO_TYPE(DEVNOTIF_LO_TYPE_FUNCTION_WAKE) 203162306a36Sopenharmony_ci | DEVNOTIF_LO_TRIG; 203262306a36Sopenharmony_ci xudc_writel(xudc, 0, DEVNOTIF_HI); 203362306a36Sopenharmony_ci xudc_writel(xudc, val, DEVNOTIF_LO); 203462306a36Sopenharmony_ci } 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ciunlock: 203862306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: ret value is %d", __func__, ret); 203962306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci return ret; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic int tegra_xudc_gadget_pullup(struct usb_gadget *gadget, int is_on) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 204762306a36Sopenharmony_ci unsigned long flags; 204862306a36Sopenharmony_ci u32 val; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci pm_runtime_get_sync(xudc->dev); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (is_on != xudc->pullup) { 205562306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 205662306a36Sopenharmony_ci if (is_on) 205762306a36Sopenharmony_ci val |= CTRL_ENABLE; 205862306a36Sopenharmony_ci else 205962306a36Sopenharmony_ci val &= ~CTRL_ENABLE; 206062306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci xudc->pullup = is_on; 206462306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: pullup:%d", __func__, is_on); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci pm_runtime_put(xudc->dev); 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci return 0; 207162306a36Sopenharmony_ci} 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_cistatic int tegra_xudc_gadget_start(struct usb_gadget *gadget, 207462306a36Sopenharmony_ci struct usb_gadget_driver *driver) 207562306a36Sopenharmony_ci{ 207662306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 207762306a36Sopenharmony_ci unsigned long flags; 207862306a36Sopenharmony_ci u32 val; 207962306a36Sopenharmony_ci int ret; 208062306a36Sopenharmony_ci unsigned int i; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if (!driver) 208362306a36Sopenharmony_ci return -EINVAL; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci pm_runtime_get_sync(xudc->dev); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (xudc->driver) { 209062306a36Sopenharmony_ci ret = -EBUSY; 209162306a36Sopenharmony_ci goto unlock; 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 209562306a36Sopenharmony_ci xudc->device_state = USB_STATE_DEFAULT; 209662306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci ret = __tegra_xudc_ep_enable(&xudc->ep[0], &tegra_xudc_ep0_desc); 209962306a36Sopenharmony_ci if (ret < 0) 210062306a36Sopenharmony_ci goto unlock; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 210362306a36Sopenharmony_ci val |= CTRL_IE | CTRL_LSE; 210462306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci val = xudc_readl(xudc, PORTHALT); 210762306a36Sopenharmony_ci val |= PORTHALT_STCHG_INTR_EN; 210862306a36Sopenharmony_ci xudc_writel(xudc, val, PORTHALT); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci if (xudc->pullup) { 211162306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 211262306a36Sopenharmony_ci val |= CTRL_ENABLE; 211362306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) 211762306a36Sopenharmony_ci if (xudc->usbphy[i]) 211862306a36Sopenharmony_ci otg_set_peripheral(xudc->usbphy[i]->otg, gadget); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci xudc->driver = driver; 212162306a36Sopenharmony_ciunlock: 212262306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: ret value is %d", __func__, ret); 212362306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci pm_runtime_put(xudc->dev); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci return ret; 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic int tegra_xudc_gadget_stop(struct usb_gadget *gadget) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 213362306a36Sopenharmony_ci unsigned long flags; 213462306a36Sopenharmony_ci u32 val; 213562306a36Sopenharmony_ci unsigned int i; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci pm_runtime_get_sync(xudc->dev); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) 214262306a36Sopenharmony_ci if (xudc->usbphy[i]) 214362306a36Sopenharmony_ci otg_set_peripheral(xudc->usbphy[i]->otg, NULL); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 214662306a36Sopenharmony_ci val &= ~(CTRL_IE | CTRL_ENABLE); 214762306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci __tegra_xudc_ep_disable(&xudc->ep[0]); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci xudc->driver = NULL; 215262306a36Sopenharmony_ci dev_dbg(xudc->dev, "Gadget stopped"); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci pm_runtime_put(xudc->dev); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return 0; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, 216262306a36Sopenharmony_ci unsigned int m_a) 216362306a36Sopenharmony_ci{ 216462306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE) 216962306a36Sopenharmony_ci return usb_phy_set_power(xudc->curr_usbphy, m_a); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci return 0; 217262306a36Sopenharmony_ci} 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_cistatic int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) 217562306a36Sopenharmony_ci{ 217662306a36Sopenharmony_ci struct tegra_xudc *xudc = to_xudc(gadget); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci dev_dbg(xudc->dev, "%s: %d\n", __func__, is_on); 217962306a36Sopenharmony_ci xudc->selfpowered = !!is_on; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci return 0; 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic const struct usb_gadget_ops tegra_xudc_gadget_ops = { 218562306a36Sopenharmony_ci .get_frame = tegra_xudc_gadget_get_frame, 218662306a36Sopenharmony_ci .wakeup = tegra_xudc_gadget_wakeup, 218762306a36Sopenharmony_ci .pullup = tegra_xudc_gadget_pullup, 218862306a36Sopenharmony_ci .udc_start = tegra_xudc_gadget_start, 218962306a36Sopenharmony_ci .udc_stop = tegra_xudc_gadget_stop, 219062306a36Sopenharmony_ci .vbus_draw = tegra_xudc_gadget_vbus_draw, 219162306a36Sopenharmony_ci .set_selfpowered = tegra_xudc_set_selfpowered, 219262306a36Sopenharmony_ci}; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic void no_op_complete(struct usb_ep *ep, struct usb_request *req) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_cistatic int 219962306a36Sopenharmony_citegra_xudc_ep0_queue_status(struct tegra_xudc *xudc, 220062306a36Sopenharmony_ci void (*cmpl)(struct usb_ep *, struct usb_request *)) 220162306a36Sopenharmony_ci{ 220262306a36Sopenharmony_ci xudc->ep0_req->usb_req.buf = NULL; 220362306a36Sopenharmony_ci xudc->ep0_req->usb_req.dma = 0; 220462306a36Sopenharmony_ci xudc->ep0_req->usb_req.length = 0; 220562306a36Sopenharmony_ci xudc->ep0_req->usb_req.complete = cmpl; 220662306a36Sopenharmony_ci xudc->ep0_req->usb_req.context = xudc; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci return __tegra_xudc_ep_queue(&xudc->ep[0], xudc->ep0_req); 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic int 221262306a36Sopenharmony_citegra_xudc_ep0_queue_data(struct tegra_xudc *xudc, void *buf, size_t len, 221362306a36Sopenharmony_ci void (*cmpl)(struct usb_ep *, struct usb_request *)) 221462306a36Sopenharmony_ci{ 221562306a36Sopenharmony_ci xudc->ep0_req->usb_req.buf = buf; 221662306a36Sopenharmony_ci xudc->ep0_req->usb_req.length = len; 221762306a36Sopenharmony_ci xudc->ep0_req->usb_req.complete = cmpl; 221862306a36Sopenharmony_ci xudc->ep0_req->usb_req.context = xudc; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci return __tegra_xudc_ep_queue(&xudc->ep[0], xudc->ep0_req); 222162306a36Sopenharmony_ci} 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_cistatic void tegra_xudc_ep0_req_done(struct tegra_xudc *xudc) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci switch (xudc->setup_state) { 222662306a36Sopenharmony_ci case DATA_STAGE_XFER: 222762306a36Sopenharmony_ci xudc->setup_state = STATUS_STAGE_RECV; 222862306a36Sopenharmony_ci tegra_xudc_ep0_queue_status(xudc, no_op_complete); 222962306a36Sopenharmony_ci break; 223062306a36Sopenharmony_ci case DATA_STAGE_RECV: 223162306a36Sopenharmony_ci xudc->setup_state = STATUS_STAGE_XFER; 223262306a36Sopenharmony_ci tegra_xudc_ep0_queue_status(xudc, no_op_complete); 223362306a36Sopenharmony_ci break; 223462306a36Sopenharmony_ci default: 223562306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 223662306a36Sopenharmony_ci break; 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci} 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic int tegra_xudc_ep0_delegate_req(struct tegra_xudc *xudc, 224162306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci int ret; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci spin_unlock(&xudc->lock); 224662306a36Sopenharmony_ci ret = xudc->driver->setup(&xudc->gadget, ctrl); 224762306a36Sopenharmony_ci spin_lock(&xudc->lock); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci return ret; 225062306a36Sopenharmony_ci} 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic void set_feature_complete(struct usb_ep *ep, struct usb_request *req) 225362306a36Sopenharmony_ci{ 225462306a36Sopenharmony_ci struct tegra_xudc *xudc = req->context; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci if (xudc->test_mode_pattern) { 225762306a36Sopenharmony_ci xudc_writel(xudc, xudc->test_mode_pattern, PORT_TM); 225862306a36Sopenharmony_ci xudc->test_mode_pattern = 0; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci} 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_cistatic int tegra_xudc_ep0_set_feature(struct tegra_xudc *xudc, 226362306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 226662306a36Sopenharmony_ci u32 feature = le16_to_cpu(ctrl->wValue); 226762306a36Sopenharmony_ci u32 index = le16_to_cpu(ctrl->wIndex); 226862306a36Sopenharmony_ci u32 val, ep; 226962306a36Sopenharmony_ci int ret; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci if (le16_to_cpu(ctrl->wLength) != 0) 227262306a36Sopenharmony_ci return -EINVAL; 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 227562306a36Sopenharmony_ci case USB_RECIP_DEVICE: 227662306a36Sopenharmony_ci switch (feature) { 227762306a36Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 227862306a36Sopenharmony_ci if ((xudc->gadget.speed == USB_SPEED_SUPER) || 227962306a36Sopenharmony_ci (xudc->device_state == USB_STATE_DEFAULT)) 228062306a36Sopenharmony_ci return -EINVAL; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 228362306a36Sopenharmony_ci if (set) 228462306a36Sopenharmony_ci val |= PORTPM_RWE; 228562306a36Sopenharmony_ci else 228662306a36Sopenharmony_ci val &= ~PORTPM_RWE; 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 228962306a36Sopenharmony_ci break; 229062306a36Sopenharmony_ci case USB_DEVICE_U1_ENABLE: 229162306a36Sopenharmony_ci case USB_DEVICE_U2_ENABLE: 229262306a36Sopenharmony_ci if ((xudc->device_state != USB_STATE_CONFIGURED) || 229362306a36Sopenharmony_ci (xudc->gadget.speed != USB_SPEED_SUPER)) 229462306a36Sopenharmony_ci return -EINVAL; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 229762306a36Sopenharmony_ci if ((feature == USB_DEVICE_U1_ENABLE) && 229862306a36Sopenharmony_ci xudc->soc->u1_enable) { 229962306a36Sopenharmony_ci if (set) 230062306a36Sopenharmony_ci val |= PORTPM_U1E; 230162306a36Sopenharmony_ci else 230262306a36Sopenharmony_ci val &= ~PORTPM_U1E; 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci if ((feature == USB_DEVICE_U2_ENABLE) && 230662306a36Sopenharmony_ci xudc->soc->u2_enable) { 230762306a36Sopenharmony_ci if (set) 230862306a36Sopenharmony_ci val |= PORTPM_U2E; 230962306a36Sopenharmony_ci else 231062306a36Sopenharmony_ci val &= ~PORTPM_U2E; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 231462306a36Sopenharmony_ci break; 231562306a36Sopenharmony_ci case USB_DEVICE_TEST_MODE: 231662306a36Sopenharmony_ci if (xudc->gadget.speed != USB_SPEED_HIGH) 231762306a36Sopenharmony_ci return -EINVAL; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci if (!set) 232062306a36Sopenharmony_ci return -EINVAL; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci xudc->test_mode_pattern = index >> 8; 232362306a36Sopenharmony_ci break; 232462306a36Sopenharmony_ci default: 232562306a36Sopenharmony_ci return -EINVAL; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci break; 232962306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 233062306a36Sopenharmony_ci if (xudc->device_state != USB_STATE_CONFIGURED) 233162306a36Sopenharmony_ci return -EINVAL; 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci switch (feature) { 233462306a36Sopenharmony_ci case USB_INTRF_FUNC_SUSPEND: 233562306a36Sopenharmony_ci if (set) { 233662306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci if (index & USB_INTRF_FUNC_SUSPEND_RW) 233962306a36Sopenharmony_ci val |= PORTPM_FRWE; 234062306a36Sopenharmony_ci else 234162306a36Sopenharmony_ci val &= ~PORTPM_FRWE; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 234462306a36Sopenharmony_ci } 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci return tegra_xudc_ep0_delegate_req(xudc, ctrl); 234762306a36Sopenharmony_ci default: 234862306a36Sopenharmony_ci return -EINVAL; 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci break; 235262306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 235362306a36Sopenharmony_ci ep = (index & USB_ENDPOINT_NUMBER_MASK) * 2 + 235462306a36Sopenharmony_ci ((index & USB_DIR_IN) ? 1 : 0); 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci if ((xudc->device_state == USB_STATE_DEFAULT) || 235762306a36Sopenharmony_ci ((xudc->device_state == USB_STATE_ADDRESS) && 235862306a36Sopenharmony_ci (index != 0))) 235962306a36Sopenharmony_ci return -EINVAL; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci ret = __tegra_xudc_ep_set_halt(&xudc->ep[ep], set); 236262306a36Sopenharmony_ci if (ret < 0) 236362306a36Sopenharmony_ci return ret; 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci default: 236662306a36Sopenharmony_ci return -EINVAL; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci return tegra_xudc_ep0_queue_status(xudc, set_feature_complete); 237062306a36Sopenharmony_ci} 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_cistatic int tegra_xudc_ep0_get_status(struct tegra_xudc *xudc, 237362306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 237462306a36Sopenharmony_ci{ 237562306a36Sopenharmony_ci struct tegra_xudc_ep_context *ep_ctx; 237662306a36Sopenharmony_ci u32 val, ep, index = le16_to_cpu(ctrl->wIndex); 237762306a36Sopenharmony_ci u16 status = 0; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci if (!(ctrl->bRequestType & USB_DIR_IN)) 238062306a36Sopenharmony_ci return -EINVAL; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci if ((le16_to_cpu(ctrl->wValue) != 0) || 238362306a36Sopenharmony_ci (le16_to_cpu(ctrl->wLength) != 2)) 238462306a36Sopenharmony_ci return -EINVAL; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 238762306a36Sopenharmony_ci case USB_RECIP_DEVICE: 238862306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (xudc->selfpowered) 239162306a36Sopenharmony_ci status |= BIT(USB_DEVICE_SELF_POWERED); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if ((xudc->gadget.speed < USB_SPEED_SUPER) && 239462306a36Sopenharmony_ci (val & PORTPM_RWE)) 239562306a36Sopenharmony_ci status |= BIT(USB_DEVICE_REMOTE_WAKEUP); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) { 239862306a36Sopenharmony_ci if (val & PORTPM_U1E) 239962306a36Sopenharmony_ci status |= BIT(USB_DEV_STAT_U1_ENABLED); 240062306a36Sopenharmony_ci if (val & PORTPM_U2E) 240162306a36Sopenharmony_ci status |= BIT(USB_DEV_STAT_U2_ENABLED); 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci break; 240462306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 240562306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) { 240662306a36Sopenharmony_ci status |= USB_INTRF_STAT_FUNC_RW_CAP; 240762306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 240862306a36Sopenharmony_ci if (val & PORTPM_FRWE) 240962306a36Sopenharmony_ci status |= USB_INTRF_STAT_FUNC_RW; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci break; 241262306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 241362306a36Sopenharmony_ci ep = (index & USB_ENDPOINT_NUMBER_MASK) * 2 + 241462306a36Sopenharmony_ci ((index & USB_DIR_IN) ? 1 : 0); 241562306a36Sopenharmony_ci ep_ctx = &xudc->ep_context[ep]; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci if ((xudc->device_state != USB_STATE_CONFIGURED) && 241862306a36Sopenharmony_ci ((xudc->device_state != USB_STATE_ADDRESS) || (ep != 0))) 241962306a36Sopenharmony_ci return -EINVAL; 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci if (ep_ctx_read_state(ep_ctx) == EP_STATE_DISABLED) 242262306a36Sopenharmony_ci return -EINVAL; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (xudc_readl(xudc, EP_HALT) & BIT(ep)) 242562306a36Sopenharmony_ci status |= BIT(USB_ENDPOINT_HALT); 242662306a36Sopenharmony_ci break; 242762306a36Sopenharmony_ci default: 242862306a36Sopenharmony_ci return -EINVAL; 242962306a36Sopenharmony_ci } 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci xudc->status_buf = cpu_to_le16(status); 243262306a36Sopenharmony_ci return tegra_xudc_ep0_queue_data(xudc, &xudc->status_buf, 243362306a36Sopenharmony_ci sizeof(xudc->status_buf), 243462306a36Sopenharmony_ci no_op_complete); 243562306a36Sopenharmony_ci} 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_cistatic void set_sel_complete(struct usb_ep *ep, struct usb_request *req) 243862306a36Sopenharmony_ci{ 243962306a36Sopenharmony_ci /* Nothing to do with SEL values */ 244062306a36Sopenharmony_ci} 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_cistatic int tegra_xudc_ep0_set_sel(struct tegra_xudc *xudc, 244362306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 244462306a36Sopenharmony_ci{ 244562306a36Sopenharmony_ci if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE | 244662306a36Sopenharmony_ci USB_TYPE_STANDARD)) 244762306a36Sopenharmony_ci return -EINVAL; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci if (xudc->device_state == USB_STATE_DEFAULT) 245062306a36Sopenharmony_ci return -EINVAL; 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci if ((le16_to_cpu(ctrl->wIndex) != 0) || 245362306a36Sopenharmony_ci (le16_to_cpu(ctrl->wValue) != 0) || 245462306a36Sopenharmony_ci (le16_to_cpu(ctrl->wLength) != 6)) 245562306a36Sopenharmony_ci return -EINVAL; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci return tegra_xudc_ep0_queue_data(xudc, &xudc->sel_timing, 245862306a36Sopenharmony_ci sizeof(xudc->sel_timing), 245962306a36Sopenharmony_ci set_sel_complete); 246062306a36Sopenharmony_ci} 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_cistatic void set_isoch_delay_complete(struct usb_ep *ep, struct usb_request *req) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci /* Nothing to do with isoch delay */ 246562306a36Sopenharmony_ci} 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_cistatic int tegra_xudc_ep0_set_isoch_delay(struct tegra_xudc *xudc, 246862306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 246962306a36Sopenharmony_ci{ 247062306a36Sopenharmony_ci u32 delay = le16_to_cpu(ctrl->wValue); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE | 247362306a36Sopenharmony_ci USB_TYPE_STANDARD)) 247462306a36Sopenharmony_ci return -EINVAL; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci if ((delay > 65535) || (le16_to_cpu(ctrl->wIndex) != 0) || 247762306a36Sopenharmony_ci (le16_to_cpu(ctrl->wLength) != 0)) 247862306a36Sopenharmony_ci return -EINVAL; 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci xudc->isoch_delay = delay; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci return tegra_xudc_ep0_queue_status(xudc, set_isoch_delay_complete); 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_cistatic void set_address_complete(struct usb_ep *ep, struct usb_request *req) 248662306a36Sopenharmony_ci{ 248762306a36Sopenharmony_ci struct tegra_xudc *xudc = req->context; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci if ((xudc->device_state == USB_STATE_DEFAULT) && 249062306a36Sopenharmony_ci (xudc->dev_addr != 0)) { 249162306a36Sopenharmony_ci xudc->device_state = USB_STATE_ADDRESS; 249262306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 249362306a36Sopenharmony_ci } else if ((xudc->device_state == USB_STATE_ADDRESS) && 249462306a36Sopenharmony_ci (xudc->dev_addr == 0)) { 249562306a36Sopenharmony_ci xudc->device_state = USB_STATE_DEFAULT; 249662306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci} 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_cistatic int tegra_xudc_ep0_set_address(struct tegra_xudc *xudc, 250162306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 250262306a36Sopenharmony_ci{ 250362306a36Sopenharmony_ci struct tegra_xudc_ep *ep0 = &xudc->ep[0]; 250462306a36Sopenharmony_ci u32 val, addr = le16_to_cpu(ctrl->wValue); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE | 250762306a36Sopenharmony_ci USB_TYPE_STANDARD)) 250862306a36Sopenharmony_ci return -EINVAL; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci if ((addr > 127) || (le16_to_cpu(ctrl->wIndex) != 0) || 251162306a36Sopenharmony_ci (le16_to_cpu(ctrl->wLength) != 0)) 251262306a36Sopenharmony_ci return -EINVAL; 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci if (xudc->device_state == USB_STATE_CONFIGURED) 251562306a36Sopenharmony_ci return -EINVAL; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci dev_dbg(xudc->dev, "set address: %u\n", addr); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci xudc->dev_addr = addr; 252062306a36Sopenharmony_ci val = xudc_readl(xudc, CTRL); 252162306a36Sopenharmony_ci val &= ~(CTRL_DEVADDR_MASK); 252262306a36Sopenharmony_ci val |= CTRL_DEVADDR(addr); 252362306a36Sopenharmony_ci xudc_writel(xudc, val, CTRL); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci ep_ctx_write_devaddr(ep0->context, addr); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci return tegra_xudc_ep0_queue_status(xudc, set_address_complete); 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic int tegra_xudc_ep0_standard_req(struct tegra_xudc *xudc, 253162306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 253262306a36Sopenharmony_ci{ 253362306a36Sopenharmony_ci int ret; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci switch (ctrl->bRequest) { 253662306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 253762306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_GET_STATUS\n"); 253862306a36Sopenharmony_ci ret = tegra_xudc_ep0_get_status(xudc, ctrl); 253962306a36Sopenharmony_ci break; 254062306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 254162306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_SET_ADDRESS\n"); 254262306a36Sopenharmony_ci ret = tegra_xudc_ep0_set_address(xudc, ctrl); 254362306a36Sopenharmony_ci break; 254462306a36Sopenharmony_ci case USB_REQ_SET_SEL: 254562306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_SET_SEL\n"); 254662306a36Sopenharmony_ci ret = tegra_xudc_ep0_set_sel(xudc, ctrl); 254762306a36Sopenharmony_ci break; 254862306a36Sopenharmony_ci case USB_REQ_SET_ISOCH_DELAY: 254962306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); 255062306a36Sopenharmony_ci ret = tegra_xudc_ep0_set_isoch_delay(xudc, ctrl); 255162306a36Sopenharmony_ci break; 255262306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 255362306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 255462306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_CLEAR/SET_FEATURE\n"); 255562306a36Sopenharmony_ci ret = tegra_xudc_ep0_set_feature(xudc, ctrl); 255662306a36Sopenharmony_ci break; 255762306a36Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 255862306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB_REQ_SET_CONFIGURATION\n"); 255962306a36Sopenharmony_ci /* 256062306a36Sopenharmony_ci * In theory we need to clear RUN bit before status stage of 256162306a36Sopenharmony_ci * deconfig request sent, but this seems to be causing problems. 256262306a36Sopenharmony_ci * Clear RUN once all endpoints are disabled instead. 256362306a36Sopenharmony_ci */ 256462306a36Sopenharmony_ci fallthrough; 256562306a36Sopenharmony_ci default: 256662306a36Sopenharmony_ci ret = tegra_xudc_ep0_delegate_req(xudc, ctrl); 256762306a36Sopenharmony_ci break; 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci return ret; 257162306a36Sopenharmony_ci} 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic void tegra_xudc_handle_ep0_setup_packet(struct tegra_xudc *xudc, 257462306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl, 257562306a36Sopenharmony_ci u16 seq_num) 257662306a36Sopenharmony_ci{ 257762306a36Sopenharmony_ci int ret; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci xudc->setup_seq_num = seq_num; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci /* Ensure EP0 is unhalted. */ 258262306a36Sopenharmony_ci ep_unhalt(xudc, 0); 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci /* 258562306a36Sopenharmony_ci * On Tegra210, setup packets with sequence numbers 0xfffe or 0xffff 258662306a36Sopenharmony_ci * are invalid. Halt EP0 until we get a valid packet. 258762306a36Sopenharmony_ci */ 258862306a36Sopenharmony_ci if (xudc->soc->invalid_seq_num && 258962306a36Sopenharmony_ci (seq_num == 0xfffe || seq_num == 0xffff)) { 259062306a36Sopenharmony_ci dev_warn(xudc->dev, "invalid sequence number detected\n"); 259162306a36Sopenharmony_ci ep_halt(xudc, 0); 259262306a36Sopenharmony_ci return; 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci if (ctrl->wLength) 259662306a36Sopenharmony_ci xudc->setup_state = (ctrl->bRequestType & USB_DIR_IN) ? 259762306a36Sopenharmony_ci DATA_STAGE_XFER : DATA_STAGE_RECV; 259862306a36Sopenharmony_ci else 259962306a36Sopenharmony_ci xudc->setup_state = STATUS_STAGE_XFER; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 260262306a36Sopenharmony_ci ret = tegra_xudc_ep0_standard_req(xudc, ctrl); 260362306a36Sopenharmony_ci else 260462306a36Sopenharmony_ci ret = tegra_xudc_ep0_delegate_req(xudc, ctrl); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci if (ret < 0) { 260762306a36Sopenharmony_ci dev_warn(xudc->dev, "setup request failed: %d\n", ret); 260862306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 260962306a36Sopenharmony_ci ep_halt(xudc, 0); 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci} 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_cistatic void tegra_xudc_handle_ep0_event(struct tegra_xudc *xudc, 261462306a36Sopenharmony_ci struct tegra_xudc_trb *event) 261562306a36Sopenharmony_ci{ 261662306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl = (struct usb_ctrlrequest *)event; 261762306a36Sopenharmony_ci u16 seq_num = trb_read_seq_num(event); 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci if (xudc->setup_state != WAIT_FOR_SETUP) { 262062306a36Sopenharmony_ci /* 262162306a36Sopenharmony_ci * The controller is in the process of handling another 262262306a36Sopenharmony_ci * setup request. Queue subsequent requests and handle 262362306a36Sopenharmony_ci * the last one once the controller reports a sequence 262462306a36Sopenharmony_ci * number error. 262562306a36Sopenharmony_ci */ 262662306a36Sopenharmony_ci memcpy(&xudc->setup_packet.ctrl_req, ctrl, sizeof(*ctrl)); 262762306a36Sopenharmony_ci xudc->setup_packet.seq_num = seq_num; 262862306a36Sopenharmony_ci xudc->queued_setup_packet = true; 262962306a36Sopenharmony_ci } else { 263062306a36Sopenharmony_ci tegra_xudc_handle_ep0_setup_packet(xudc, ctrl, seq_num); 263162306a36Sopenharmony_ci } 263262306a36Sopenharmony_ci} 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_cistatic struct tegra_xudc_request * 263562306a36Sopenharmony_citrb_to_request(struct tegra_xudc_ep *ep, struct tegra_xudc_trb *trb) 263662306a36Sopenharmony_ci{ 263762306a36Sopenharmony_ci struct tegra_xudc_request *req; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci list_for_each_entry(req, &ep->queue, list) { 264062306a36Sopenharmony_ci if (!req->trbs_queued) 264162306a36Sopenharmony_ci break; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (trb_in_request(ep, req, trb)) 264462306a36Sopenharmony_ci return req; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci return NULL; 264862306a36Sopenharmony_ci} 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_cistatic void tegra_xudc_handle_transfer_completion(struct tegra_xudc *xudc, 265162306a36Sopenharmony_ci struct tegra_xudc_ep *ep, 265262306a36Sopenharmony_ci struct tegra_xudc_trb *event) 265362306a36Sopenharmony_ci{ 265462306a36Sopenharmony_ci struct tegra_xudc_request *req; 265562306a36Sopenharmony_ci struct tegra_xudc_trb *trb; 265662306a36Sopenharmony_ci bool short_packet; 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci short_packet = (trb_read_cmpl_code(event) == 265962306a36Sopenharmony_ci TRB_CMPL_CODE_SHORT_PACKET); 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci trb = trb_phys_to_virt(ep, trb_read_data_ptr(event)); 266262306a36Sopenharmony_ci req = trb_to_request(ep, trb); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci /* 266562306a36Sopenharmony_ci * TDs are complete on short packet or when the completed TRB is the 266662306a36Sopenharmony_ci * last TRB in the TD (the CHAIN bit is unset). 266762306a36Sopenharmony_ci */ 266862306a36Sopenharmony_ci if (req && (short_packet || (!trb_read_chain(trb) && 266962306a36Sopenharmony_ci (req->trbs_needed == req->trbs_queued)))) { 267062306a36Sopenharmony_ci struct tegra_xudc_trb *last = req->last_trb; 267162306a36Sopenharmony_ci unsigned int residual; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci residual = trb_read_transfer_len(event); 267462306a36Sopenharmony_ci req->usb_req.actual = req->usb_req.length - residual; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci dev_dbg(xudc->dev, "bytes transferred %u / %u\n", 267762306a36Sopenharmony_ci req->usb_req.actual, req->usb_req.length); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci tegra_xudc_req_done(ep, req, 0); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci if (ep->desc && usb_endpoint_xfer_control(ep->desc)) 268262306a36Sopenharmony_ci tegra_xudc_ep0_req_done(xudc); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci /* 268562306a36Sopenharmony_ci * Advance the dequeue pointer past the end of the current TD 268662306a36Sopenharmony_ci * on short packet completion. 268762306a36Sopenharmony_ci */ 268862306a36Sopenharmony_ci if (short_packet) { 268962306a36Sopenharmony_ci ep->deq_ptr = (last - ep->transfer_ring) + 1; 269062306a36Sopenharmony_ci if (ep->deq_ptr == XUDC_TRANSFER_RING_SIZE - 1) 269162306a36Sopenharmony_ci ep->deq_ptr = 0; 269262306a36Sopenharmony_ci } 269362306a36Sopenharmony_ci } else if (!req) { 269462306a36Sopenharmony_ci dev_warn(xudc->dev, "transfer event on dequeued request\n"); 269562306a36Sopenharmony_ci } 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci if (ep->desc) 269862306a36Sopenharmony_ci tegra_xudc_ep_kick_queue(ep); 269962306a36Sopenharmony_ci} 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_cistatic void tegra_xudc_handle_transfer_event(struct tegra_xudc *xudc, 270262306a36Sopenharmony_ci struct tegra_xudc_trb *event) 270362306a36Sopenharmony_ci{ 270462306a36Sopenharmony_ci unsigned int ep_index = trb_read_endpoint_id(event); 270562306a36Sopenharmony_ci struct tegra_xudc_ep *ep = &xudc->ep[ep_index]; 270662306a36Sopenharmony_ci struct tegra_xudc_trb *trb; 270762306a36Sopenharmony_ci u16 comp_code; 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci if (ep_ctx_read_state(ep->context) == EP_STATE_DISABLED) { 271062306a36Sopenharmony_ci dev_warn(xudc->dev, "transfer event on disabled EP %u\n", 271162306a36Sopenharmony_ci ep_index); 271262306a36Sopenharmony_ci return; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci /* Update transfer ring dequeue pointer. */ 271662306a36Sopenharmony_ci trb = trb_phys_to_virt(ep, trb_read_data_ptr(event)); 271762306a36Sopenharmony_ci comp_code = trb_read_cmpl_code(event); 271862306a36Sopenharmony_ci if (comp_code != TRB_CMPL_CODE_BABBLE_DETECTED_ERR) { 271962306a36Sopenharmony_ci ep->deq_ptr = (trb - ep->transfer_ring) + 1; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (ep->deq_ptr == XUDC_TRANSFER_RING_SIZE - 1) 272262306a36Sopenharmony_ci ep->deq_ptr = 0; 272362306a36Sopenharmony_ci ep->ring_full = false; 272462306a36Sopenharmony_ci } 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci switch (comp_code) { 272762306a36Sopenharmony_ci case TRB_CMPL_CODE_SUCCESS: 272862306a36Sopenharmony_ci case TRB_CMPL_CODE_SHORT_PACKET: 272962306a36Sopenharmony_ci tegra_xudc_handle_transfer_completion(xudc, ep, event); 273062306a36Sopenharmony_ci break; 273162306a36Sopenharmony_ci case TRB_CMPL_CODE_HOST_REJECTED: 273262306a36Sopenharmony_ci dev_info(xudc->dev, "stream rejected on EP %u\n", ep_index); 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci ep->stream_rejected = true; 273562306a36Sopenharmony_ci break; 273662306a36Sopenharmony_ci case TRB_CMPL_CODE_PRIME_PIPE_RECEIVED: 273762306a36Sopenharmony_ci dev_info(xudc->dev, "prime pipe received on EP %u\n", ep_index); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (ep->stream_rejected) { 274062306a36Sopenharmony_ci ep->stream_rejected = false; 274162306a36Sopenharmony_ci /* 274262306a36Sopenharmony_ci * An EP is stopped when a stream is rejected. Wait 274362306a36Sopenharmony_ci * for the EP to report that it is stopped and then 274462306a36Sopenharmony_ci * un-stop it. 274562306a36Sopenharmony_ci */ 274662306a36Sopenharmony_ci ep_wait_for_stopped(xudc, ep_index); 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci tegra_xudc_ep_ring_doorbell(ep); 274962306a36Sopenharmony_ci break; 275062306a36Sopenharmony_ci case TRB_CMPL_CODE_BABBLE_DETECTED_ERR: 275162306a36Sopenharmony_ci /* 275262306a36Sopenharmony_ci * Wait for the EP to be stopped so the controller stops 275362306a36Sopenharmony_ci * processing doorbells. 275462306a36Sopenharmony_ci */ 275562306a36Sopenharmony_ci ep_wait_for_stopped(xudc, ep_index); 275662306a36Sopenharmony_ci ep->enq_ptr = ep->deq_ptr; 275762306a36Sopenharmony_ci tegra_xudc_ep_nuke(ep, -EIO); 275862306a36Sopenharmony_ci fallthrough; 275962306a36Sopenharmony_ci case TRB_CMPL_CODE_STREAM_NUMP_ERROR: 276062306a36Sopenharmony_ci case TRB_CMPL_CODE_CTRL_DIR_ERR: 276162306a36Sopenharmony_ci case TRB_CMPL_CODE_INVALID_STREAM_TYPE_ERR: 276262306a36Sopenharmony_ci case TRB_CMPL_CODE_RING_UNDERRUN: 276362306a36Sopenharmony_ci case TRB_CMPL_CODE_RING_OVERRUN: 276462306a36Sopenharmony_ci case TRB_CMPL_CODE_ISOCH_BUFFER_OVERRUN: 276562306a36Sopenharmony_ci case TRB_CMPL_CODE_USB_TRANS_ERR: 276662306a36Sopenharmony_ci case TRB_CMPL_CODE_TRB_ERR: 276762306a36Sopenharmony_ci dev_err(xudc->dev, "completion error %#x on EP %u\n", 276862306a36Sopenharmony_ci comp_code, ep_index); 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci ep_halt(xudc, ep_index); 277162306a36Sopenharmony_ci break; 277262306a36Sopenharmony_ci case TRB_CMPL_CODE_CTRL_SEQNUM_ERR: 277362306a36Sopenharmony_ci dev_info(xudc->dev, "sequence number error\n"); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci /* 277662306a36Sopenharmony_ci * Kill any queued control request and skip to the last 277762306a36Sopenharmony_ci * setup packet we received. 277862306a36Sopenharmony_ci */ 277962306a36Sopenharmony_ci tegra_xudc_ep_nuke(ep, -EINVAL); 278062306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 278162306a36Sopenharmony_ci if (!xudc->queued_setup_packet) 278262306a36Sopenharmony_ci break; 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci tegra_xudc_handle_ep0_setup_packet(xudc, 278562306a36Sopenharmony_ci &xudc->setup_packet.ctrl_req, 278662306a36Sopenharmony_ci xudc->setup_packet.seq_num); 278762306a36Sopenharmony_ci xudc->queued_setup_packet = false; 278862306a36Sopenharmony_ci break; 278962306a36Sopenharmony_ci case TRB_CMPL_CODE_STOPPED: 279062306a36Sopenharmony_ci dev_dbg(xudc->dev, "stop completion code on EP %u\n", 279162306a36Sopenharmony_ci ep_index); 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci /* Disconnected. */ 279462306a36Sopenharmony_ci tegra_xudc_ep_nuke(ep, -ECONNREFUSED); 279562306a36Sopenharmony_ci break; 279662306a36Sopenharmony_ci default: 279762306a36Sopenharmony_ci dev_dbg(xudc->dev, "completion event %#x on EP %u\n", 279862306a36Sopenharmony_ci comp_code, ep_index); 279962306a36Sopenharmony_ci break; 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci} 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_cistatic void tegra_xudc_reset(struct tegra_xudc *xudc) 280462306a36Sopenharmony_ci{ 280562306a36Sopenharmony_ci struct tegra_xudc_ep *ep0 = &xudc->ep[0]; 280662306a36Sopenharmony_ci dma_addr_t deq_ptr; 280762306a36Sopenharmony_ci unsigned int i; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 281062306a36Sopenharmony_ci xudc->device_state = USB_STATE_DEFAULT; 281162306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci ep_unpause_all(xudc); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) 281662306a36Sopenharmony_ci tegra_xudc_ep_nuke(&xudc->ep[i], -ESHUTDOWN); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci /* 281962306a36Sopenharmony_ci * Reset sequence number and dequeue pointer to flush the transfer 282062306a36Sopenharmony_ci * ring. 282162306a36Sopenharmony_ci */ 282262306a36Sopenharmony_ci ep0->deq_ptr = ep0->enq_ptr; 282362306a36Sopenharmony_ci ep0->ring_full = false; 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci xudc->setup_seq_num = 0; 282662306a36Sopenharmony_ci xudc->queued_setup_packet = false; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci ep_ctx_write_rsvd(ep0->context, 0); 282962306a36Sopenharmony_ci ep_ctx_write_partial_td(ep0->context, 0); 283062306a36Sopenharmony_ci ep_ctx_write_splitxstate(ep0->context, 0); 283162306a36Sopenharmony_ci ep_ctx_write_seq_num(ep0->context, 0); 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci deq_ptr = trb_virt_to_phys(ep0, &ep0->transfer_ring[ep0->deq_ptr]); 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (!dma_mapping_error(xudc->dev, deq_ptr)) { 283662306a36Sopenharmony_ci ep_ctx_write_deq_ptr(ep0->context, deq_ptr); 283762306a36Sopenharmony_ci ep_ctx_write_dcs(ep0->context, ep0->pcs); 283862306a36Sopenharmony_ci } 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci ep_unhalt_all(xudc); 284162306a36Sopenharmony_ci ep_reload(xudc, 0); 284262306a36Sopenharmony_ci ep_unpause(xudc, 0); 284362306a36Sopenharmony_ci} 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_cistatic void tegra_xudc_port_connect(struct tegra_xudc *xudc) 284662306a36Sopenharmony_ci{ 284762306a36Sopenharmony_ci struct tegra_xudc_ep *ep0 = &xudc->ep[0]; 284862306a36Sopenharmony_ci u16 maxpacket; 284962306a36Sopenharmony_ci u32 val; 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci val = (xudc_readl(xudc, PORTSC) & PORTSC_PS_MASK) >> PORTSC_PS_SHIFT; 285262306a36Sopenharmony_ci switch (val) { 285362306a36Sopenharmony_ci case PORTSC_PS_LS: 285462306a36Sopenharmony_ci xudc->gadget.speed = USB_SPEED_LOW; 285562306a36Sopenharmony_ci break; 285662306a36Sopenharmony_ci case PORTSC_PS_FS: 285762306a36Sopenharmony_ci xudc->gadget.speed = USB_SPEED_FULL; 285862306a36Sopenharmony_ci break; 285962306a36Sopenharmony_ci case PORTSC_PS_HS: 286062306a36Sopenharmony_ci xudc->gadget.speed = USB_SPEED_HIGH; 286162306a36Sopenharmony_ci break; 286262306a36Sopenharmony_ci case PORTSC_PS_SS: 286362306a36Sopenharmony_ci xudc->gadget.speed = USB_SPEED_SUPER; 286462306a36Sopenharmony_ci break; 286562306a36Sopenharmony_ci default: 286662306a36Sopenharmony_ci xudc->gadget.speed = USB_SPEED_UNKNOWN; 286762306a36Sopenharmony_ci break; 286862306a36Sopenharmony_ci } 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci xudc->device_state = USB_STATE_DEFAULT; 287162306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci xudc->setup_state = WAIT_FOR_SETUP; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) 287662306a36Sopenharmony_ci maxpacket = 512; 287762306a36Sopenharmony_ci else 287862306a36Sopenharmony_ci maxpacket = 64; 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci ep_ctx_write_max_packet_size(ep0->context, maxpacket); 288162306a36Sopenharmony_ci tegra_xudc_ep0_desc.wMaxPacketSize = cpu_to_le16(maxpacket); 288262306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep0->usb_ep, maxpacket); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci if (!xudc->soc->u1_enable) { 288562306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 288662306a36Sopenharmony_ci val &= ~(PORTPM_U1TIMEOUT_MASK); 288762306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 288862306a36Sopenharmony_ci } 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (!xudc->soc->u2_enable) { 289162306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 289262306a36Sopenharmony_ci val &= ~(PORTPM_U2TIMEOUT_MASK); 289362306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 289462306a36Sopenharmony_ci } 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci if (xudc->gadget.speed <= USB_SPEED_HIGH) { 289762306a36Sopenharmony_ci val = xudc_readl(xudc, PORTPM); 289862306a36Sopenharmony_ci val &= ~(PORTPM_L1S_MASK); 289962306a36Sopenharmony_ci if (xudc->soc->lpm_enable) 290062306a36Sopenharmony_ci val |= PORTPM_L1S(PORTPM_L1S_ACCEPT); 290162306a36Sopenharmony_ci else 290262306a36Sopenharmony_ci val |= PORTPM_L1S(PORTPM_L1S_NYET); 290362306a36Sopenharmony_ci xudc_writel(xudc, val, PORTPM); 290462306a36Sopenharmony_ci } 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci val = xudc_readl(xudc, ST); 290762306a36Sopenharmony_ci if (val & ST_RC) 290862306a36Sopenharmony_ci xudc_writel(xudc, ST_RC, ST); 290962306a36Sopenharmony_ci} 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_cistatic void tegra_xudc_port_disconnect(struct tegra_xudc *xudc) 291262306a36Sopenharmony_ci{ 291362306a36Sopenharmony_ci tegra_xudc_reset(xudc); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci if (xudc->driver && xudc->driver->disconnect) { 291662306a36Sopenharmony_ci spin_unlock(&xudc->lock); 291762306a36Sopenharmony_ci xudc->driver->disconnect(&xudc->gadget); 291862306a36Sopenharmony_ci spin_lock(&xudc->lock); 291962306a36Sopenharmony_ci } 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci xudc->device_state = USB_STATE_NOTATTACHED; 292262306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci complete(&xudc->disconnect_complete); 292562306a36Sopenharmony_ci} 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_cistatic void tegra_xudc_port_reset(struct tegra_xudc *xudc) 292862306a36Sopenharmony_ci{ 292962306a36Sopenharmony_ci tegra_xudc_reset(xudc); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci if (xudc->driver) { 293262306a36Sopenharmony_ci spin_unlock(&xudc->lock); 293362306a36Sopenharmony_ci usb_gadget_udc_reset(&xudc->gadget, xudc->driver); 293462306a36Sopenharmony_ci spin_lock(&xudc->lock); 293562306a36Sopenharmony_ci } 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci tegra_xudc_port_connect(xudc); 293862306a36Sopenharmony_ci} 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_cistatic void tegra_xudc_port_suspend(struct tegra_xudc *xudc) 294162306a36Sopenharmony_ci{ 294262306a36Sopenharmony_ci dev_dbg(xudc->dev, "port suspend\n"); 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci xudc->resume_state = xudc->device_state; 294562306a36Sopenharmony_ci xudc->device_state = USB_STATE_SUSPENDED; 294662306a36Sopenharmony_ci usb_gadget_set_state(&xudc->gadget, xudc->device_state); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci if (xudc->driver->suspend) { 294962306a36Sopenharmony_ci spin_unlock(&xudc->lock); 295062306a36Sopenharmony_ci xudc->driver->suspend(&xudc->gadget); 295162306a36Sopenharmony_ci spin_lock(&xudc->lock); 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci} 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_cistatic void tegra_xudc_port_resume(struct tegra_xudc *xudc) 295662306a36Sopenharmony_ci{ 295762306a36Sopenharmony_ci dev_dbg(xudc->dev, "port resume\n"); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci tegra_xudc_resume_device_state(xudc); 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci if (xudc->driver->resume) { 296262306a36Sopenharmony_ci spin_unlock(&xudc->lock); 296362306a36Sopenharmony_ci xudc->driver->resume(&xudc->gadget); 296462306a36Sopenharmony_ci spin_lock(&xudc->lock); 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci} 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_cistatic inline void clear_port_change(struct tegra_xudc *xudc, u32 flag) 296962306a36Sopenharmony_ci{ 297062306a36Sopenharmony_ci u32 val; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci val = xudc_readl(xudc, PORTSC); 297362306a36Sopenharmony_ci val &= ~PORTSC_CHANGE_MASK; 297462306a36Sopenharmony_ci val |= flag; 297562306a36Sopenharmony_ci xudc_writel(xudc, val, PORTSC); 297662306a36Sopenharmony_ci} 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_cistatic void __tegra_xudc_handle_port_status(struct tegra_xudc *xudc) 297962306a36Sopenharmony_ci{ 298062306a36Sopenharmony_ci u32 portsc, porthalt; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci porthalt = xudc_readl(xudc, PORTHALT); 298362306a36Sopenharmony_ci if ((porthalt & PORTHALT_STCHG_REQ) && 298462306a36Sopenharmony_ci (porthalt & PORTHALT_HALT_LTSSM)) { 298562306a36Sopenharmony_ci dev_dbg(xudc->dev, "STCHG_REQ, PORTHALT = %#x\n", porthalt); 298662306a36Sopenharmony_ci porthalt &= ~PORTHALT_HALT_LTSSM; 298762306a36Sopenharmony_ci xudc_writel(xudc, porthalt, PORTHALT); 298862306a36Sopenharmony_ci } 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci portsc = xudc_readl(xudc, PORTSC); 299162306a36Sopenharmony_ci if ((portsc & PORTSC_PRC) && (portsc & PORTSC_PR)) { 299262306a36Sopenharmony_ci dev_dbg(xudc->dev, "PRC, PR, PORTSC = %#x\n", portsc); 299362306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_PRC | PORTSC_PED); 299462306a36Sopenharmony_ci#define TOGGLE_VBUS_WAIT_MS 100 299562306a36Sopenharmony_ci if (xudc->soc->port_reset_quirk) { 299662306a36Sopenharmony_ci schedule_delayed_work(&xudc->port_reset_war_work, 299762306a36Sopenharmony_ci msecs_to_jiffies(TOGGLE_VBUS_WAIT_MS)); 299862306a36Sopenharmony_ci xudc->wait_for_sec_prc = 1; 299962306a36Sopenharmony_ci } 300062306a36Sopenharmony_ci } 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci if ((portsc & PORTSC_PRC) && !(portsc & PORTSC_PR)) { 300362306a36Sopenharmony_ci dev_dbg(xudc->dev, "PRC, Not PR, PORTSC = %#x\n", portsc); 300462306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_PRC | PORTSC_PED); 300562306a36Sopenharmony_ci tegra_xudc_port_reset(xudc); 300662306a36Sopenharmony_ci cancel_delayed_work(&xudc->port_reset_war_work); 300762306a36Sopenharmony_ci xudc->wait_for_sec_prc = 0; 300862306a36Sopenharmony_ci } 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci portsc = xudc_readl(xudc, PORTSC); 301162306a36Sopenharmony_ci if (portsc & PORTSC_WRC) { 301262306a36Sopenharmony_ci dev_dbg(xudc->dev, "WRC, PORTSC = %#x\n", portsc); 301362306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_WRC | PORTSC_PED); 301462306a36Sopenharmony_ci if (!(xudc_readl(xudc, PORTSC) & PORTSC_WPR)) 301562306a36Sopenharmony_ci tegra_xudc_port_reset(xudc); 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci portsc = xudc_readl(xudc, PORTSC); 301962306a36Sopenharmony_ci if (portsc & PORTSC_CSC) { 302062306a36Sopenharmony_ci dev_dbg(xudc->dev, "CSC, PORTSC = %#x\n", portsc); 302162306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_CSC); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (portsc & PORTSC_CCS) 302462306a36Sopenharmony_ci tegra_xudc_port_connect(xudc); 302562306a36Sopenharmony_ci else 302662306a36Sopenharmony_ci tegra_xudc_port_disconnect(xudc); 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if (xudc->wait_csc) { 302962306a36Sopenharmony_ci cancel_delayed_work(&xudc->plc_reset_work); 303062306a36Sopenharmony_ci xudc->wait_csc = false; 303162306a36Sopenharmony_ci } 303262306a36Sopenharmony_ci } 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci portsc = xudc_readl(xudc, PORTSC); 303562306a36Sopenharmony_ci if (portsc & PORTSC_PLC) { 303662306a36Sopenharmony_ci u32 pls = (portsc & PORTSC_PLS_MASK) >> PORTSC_PLS_SHIFT; 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci dev_dbg(xudc->dev, "PLC, PORTSC = %#x\n", portsc); 303962306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_PLC); 304062306a36Sopenharmony_ci switch (pls) { 304162306a36Sopenharmony_ci case PORTSC_PLS_U3: 304262306a36Sopenharmony_ci tegra_xudc_port_suspend(xudc); 304362306a36Sopenharmony_ci break; 304462306a36Sopenharmony_ci case PORTSC_PLS_U0: 304562306a36Sopenharmony_ci if (xudc->gadget.speed < USB_SPEED_SUPER) 304662306a36Sopenharmony_ci tegra_xudc_port_resume(xudc); 304762306a36Sopenharmony_ci break; 304862306a36Sopenharmony_ci case PORTSC_PLS_RESUME: 304962306a36Sopenharmony_ci if (xudc->gadget.speed == USB_SPEED_SUPER) 305062306a36Sopenharmony_ci tegra_xudc_port_resume(xudc); 305162306a36Sopenharmony_ci break; 305262306a36Sopenharmony_ci case PORTSC_PLS_INACTIVE: 305362306a36Sopenharmony_ci schedule_delayed_work(&xudc->plc_reset_work, 305462306a36Sopenharmony_ci msecs_to_jiffies(TOGGLE_VBUS_WAIT_MS)); 305562306a36Sopenharmony_ci xudc->wait_csc = true; 305662306a36Sopenharmony_ci break; 305762306a36Sopenharmony_ci default: 305862306a36Sopenharmony_ci break; 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci } 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci if (portsc & PORTSC_CEC) { 306362306a36Sopenharmony_ci dev_warn(xudc->dev, "CEC, PORTSC = %#x\n", portsc); 306462306a36Sopenharmony_ci clear_port_change(xudc, PORTSC_CEC); 306562306a36Sopenharmony_ci } 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci dev_dbg(xudc->dev, "PORTSC = %#x\n", xudc_readl(xudc, PORTSC)); 306862306a36Sopenharmony_ci} 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_cistatic void tegra_xudc_handle_port_status(struct tegra_xudc *xudc) 307162306a36Sopenharmony_ci{ 307262306a36Sopenharmony_ci while ((xudc_readl(xudc, PORTSC) & PORTSC_CHANGE_MASK) || 307362306a36Sopenharmony_ci (xudc_readl(xudc, PORTHALT) & PORTHALT_STCHG_REQ)) 307462306a36Sopenharmony_ci __tegra_xudc_handle_port_status(xudc); 307562306a36Sopenharmony_ci} 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_cistatic void tegra_xudc_handle_event(struct tegra_xudc *xudc, 307862306a36Sopenharmony_ci struct tegra_xudc_trb *event) 307962306a36Sopenharmony_ci{ 308062306a36Sopenharmony_ci u32 type = trb_read_type(event); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci dump_trb(xudc, "EVENT", event); 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci switch (type) { 308562306a36Sopenharmony_ci case TRB_TYPE_PORT_STATUS_CHANGE_EVENT: 308662306a36Sopenharmony_ci tegra_xudc_handle_port_status(xudc); 308762306a36Sopenharmony_ci break; 308862306a36Sopenharmony_ci case TRB_TYPE_TRANSFER_EVENT: 308962306a36Sopenharmony_ci tegra_xudc_handle_transfer_event(xudc, event); 309062306a36Sopenharmony_ci break; 309162306a36Sopenharmony_ci case TRB_TYPE_SETUP_PACKET_EVENT: 309262306a36Sopenharmony_ci tegra_xudc_handle_ep0_event(xudc, event); 309362306a36Sopenharmony_ci break; 309462306a36Sopenharmony_ci default: 309562306a36Sopenharmony_ci dev_info(xudc->dev, "Unrecognized TRB type = %#x\n", type); 309662306a36Sopenharmony_ci break; 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci} 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_cistatic void tegra_xudc_process_event_ring(struct tegra_xudc *xudc) 310162306a36Sopenharmony_ci{ 310262306a36Sopenharmony_ci struct tegra_xudc_trb *event; 310362306a36Sopenharmony_ci dma_addr_t erdp; 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci while (true) { 310662306a36Sopenharmony_ci event = xudc->event_ring[xudc->event_ring_index] + 310762306a36Sopenharmony_ci xudc->event_ring_deq_ptr; 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci if (trb_read_cycle(event) != xudc->ccs) 311062306a36Sopenharmony_ci break; 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci tegra_xudc_handle_event(xudc, event); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci xudc->event_ring_deq_ptr++; 311562306a36Sopenharmony_ci if (xudc->event_ring_deq_ptr == XUDC_EVENT_RING_SIZE) { 311662306a36Sopenharmony_ci xudc->event_ring_deq_ptr = 0; 311762306a36Sopenharmony_ci xudc->event_ring_index++; 311862306a36Sopenharmony_ci } 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if (xudc->event_ring_index == XUDC_NR_EVENT_RINGS) { 312162306a36Sopenharmony_ci xudc->event_ring_index = 0; 312262306a36Sopenharmony_ci xudc->ccs = !xudc->ccs; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci erdp = xudc->event_ring_phys[xudc->event_ring_index] + 312762306a36Sopenharmony_ci xudc->event_ring_deq_ptr * sizeof(*event); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci xudc_writel(xudc, upper_32_bits(erdp), ERDPHI); 313062306a36Sopenharmony_ci xudc_writel(xudc, lower_32_bits(erdp) | ERDPLO_EHB, ERDPLO); 313162306a36Sopenharmony_ci} 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_cistatic irqreturn_t tegra_xudc_irq(int irq, void *data) 313462306a36Sopenharmony_ci{ 313562306a36Sopenharmony_ci struct tegra_xudc *xudc = data; 313662306a36Sopenharmony_ci unsigned long flags; 313762306a36Sopenharmony_ci u32 val; 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci val = xudc_readl(xudc, ST); 314062306a36Sopenharmony_ci if (!(val & ST_IP)) 314162306a36Sopenharmony_ci return IRQ_NONE; 314262306a36Sopenharmony_ci xudc_writel(xudc, ST_IP, ST); 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 314562306a36Sopenharmony_ci tegra_xudc_process_event_ring(xudc); 314662306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci return IRQ_HANDLED; 314962306a36Sopenharmony_ci} 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_cistatic int tegra_xudc_alloc_ep(struct tegra_xudc *xudc, unsigned int index) 315262306a36Sopenharmony_ci{ 315362306a36Sopenharmony_ci struct tegra_xudc_ep *ep = &xudc->ep[index]; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci ep->xudc = xudc; 315662306a36Sopenharmony_ci ep->index = index; 315762306a36Sopenharmony_ci ep->context = &xudc->ep_context[index]; 315862306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_ci /* 316162306a36Sopenharmony_ci * EP1 would be the input endpoint corresponding to EP0, but since 316262306a36Sopenharmony_ci * EP0 is bi-directional, EP1 is unused. 316362306a36Sopenharmony_ci */ 316462306a36Sopenharmony_ci if (index == 1) 316562306a36Sopenharmony_ci return 0; 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci ep->transfer_ring = dma_pool_alloc(xudc->transfer_ring_pool, 316862306a36Sopenharmony_ci GFP_KERNEL, 316962306a36Sopenharmony_ci &ep->transfer_ring_phys); 317062306a36Sopenharmony_ci if (!ep->transfer_ring) 317162306a36Sopenharmony_ci return -ENOMEM; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci if (index) { 317462306a36Sopenharmony_ci snprintf(ep->name, sizeof(ep->name), "ep%u%s", index / 2, 317562306a36Sopenharmony_ci (index % 2 == 0) ? "out" : "in"); 317662306a36Sopenharmony_ci ep->usb_ep.name = ep->name; 317762306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024); 317862306a36Sopenharmony_ci ep->usb_ep.max_streams = 16; 317962306a36Sopenharmony_ci ep->usb_ep.ops = &tegra_xudc_ep_ops; 318062306a36Sopenharmony_ci ep->usb_ep.caps.type_bulk = true; 318162306a36Sopenharmony_ci ep->usb_ep.caps.type_int = true; 318262306a36Sopenharmony_ci if (index & 1) 318362306a36Sopenharmony_ci ep->usb_ep.caps.dir_in = true; 318462306a36Sopenharmony_ci else 318562306a36Sopenharmony_ci ep->usb_ep.caps.dir_out = true; 318662306a36Sopenharmony_ci list_add_tail(&ep->usb_ep.ep_list, &xudc->gadget.ep_list); 318762306a36Sopenharmony_ci } else { 318862306a36Sopenharmony_ci strscpy(ep->name, "ep0", 3); 318962306a36Sopenharmony_ci ep->usb_ep.name = ep->name; 319062306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->usb_ep, 512); 319162306a36Sopenharmony_ci ep->usb_ep.ops = &tegra_xudc_ep0_ops; 319262306a36Sopenharmony_ci ep->usb_ep.caps.type_control = true; 319362306a36Sopenharmony_ci ep->usb_ep.caps.dir_in = true; 319462306a36Sopenharmony_ci ep->usb_ep.caps.dir_out = true; 319562306a36Sopenharmony_ci } 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci return 0; 319862306a36Sopenharmony_ci} 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_cistatic void tegra_xudc_free_ep(struct tegra_xudc *xudc, unsigned int index) 320162306a36Sopenharmony_ci{ 320262306a36Sopenharmony_ci struct tegra_xudc_ep *ep = &xudc->ep[index]; 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci /* 320562306a36Sopenharmony_ci * EP1 would be the input endpoint corresponding to EP0, but since 320662306a36Sopenharmony_ci * EP0 is bi-directional, EP1 is unused. 320762306a36Sopenharmony_ci */ 320862306a36Sopenharmony_ci if (index == 1) 320962306a36Sopenharmony_ci return; 321062306a36Sopenharmony_ci 321162306a36Sopenharmony_ci dma_pool_free(xudc->transfer_ring_pool, ep->transfer_ring, 321262306a36Sopenharmony_ci ep->transfer_ring_phys); 321362306a36Sopenharmony_ci} 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_cistatic int tegra_xudc_alloc_eps(struct tegra_xudc *xudc) 321662306a36Sopenharmony_ci{ 321762306a36Sopenharmony_ci struct usb_request *req; 321862306a36Sopenharmony_ci unsigned int i; 321962306a36Sopenharmony_ci int err; 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci xudc->ep_context = 322262306a36Sopenharmony_ci dma_alloc_coherent(xudc->dev, XUDC_NR_EPS * 322362306a36Sopenharmony_ci sizeof(*xudc->ep_context), 322462306a36Sopenharmony_ci &xudc->ep_context_phys, GFP_KERNEL); 322562306a36Sopenharmony_ci if (!xudc->ep_context) 322662306a36Sopenharmony_ci return -ENOMEM; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci xudc->transfer_ring_pool = 322962306a36Sopenharmony_ci dmam_pool_create(dev_name(xudc->dev), xudc->dev, 323062306a36Sopenharmony_ci XUDC_TRANSFER_RING_SIZE * 323162306a36Sopenharmony_ci sizeof(struct tegra_xudc_trb), 323262306a36Sopenharmony_ci sizeof(struct tegra_xudc_trb), 0); 323362306a36Sopenharmony_ci if (!xudc->transfer_ring_pool) { 323462306a36Sopenharmony_ci err = -ENOMEM; 323562306a36Sopenharmony_ci goto free_ep_context; 323662306a36Sopenharmony_ci } 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci INIT_LIST_HEAD(&xudc->gadget.ep_list); 323962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) { 324062306a36Sopenharmony_ci err = tegra_xudc_alloc_ep(xudc, i); 324162306a36Sopenharmony_ci if (err < 0) 324262306a36Sopenharmony_ci goto free_eps; 324362306a36Sopenharmony_ci } 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci req = tegra_xudc_ep_alloc_request(&xudc->ep[0].usb_ep, GFP_KERNEL); 324662306a36Sopenharmony_ci if (!req) { 324762306a36Sopenharmony_ci err = -ENOMEM; 324862306a36Sopenharmony_ci goto free_eps; 324962306a36Sopenharmony_ci } 325062306a36Sopenharmony_ci xudc->ep0_req = to_xudc_req(req); 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci return 0; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_cifree_eps: 325562306a36Sopenharmony_ci for (; i > 0; i--) 325662306a36Sopenharmony_ci tegra_xudc_free_ep(xudc, i - 1); 325762306a36Sopenharmony_cifree_ep_context: 325862306a36Sopenharmony_ci dma_free_coherent(xudc->dev, XUDC_NR_EPS * sizeof(*xudc->ep_context), 325962306a36Sopenharmony_ci xudc->ep_context, xudc->ep_context_phys); 326062306a36Sopenharmony_ci return err; 326162306a36Sopenharmony_ci} 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_cistatic void tegra_xudc_init_eps(struct tegra_xudc *xudc) 326462306a36Sopenharmony_ci{ 326562306a36Sopenharmony_ci xudc_writel(xudc, lower_32_bits(xudc->ep_context_phys), ECPLO); 326662306a36Sopenharmony_ci xudc_writel(xudc, upper_32_bits(xudc->ep_context_phys), ECPHI); 326762306a36Sopenharmony_ci} 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cistatic void tegra_xudc_free_eps(struct tegra_xudc *xudc) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci unsigned int i; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci tegra_xudc_ep_free_request(&xudc->ep[0].usb_ep, 327462306a36Sopenharmony_ci &xudc->ep0_req->usb_req); 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->ep); i++) 327762306a36Sopenharmony_ci tegra_xudc_free_ep(xudc, i); 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci dma_free_coherent(xudc->dev, XUDC_NR_EPS * sizeof(*xudc->ep_context), 328062306a36Sopenharmony_ci xudc->ep_context, xudc->ep_context_phys); 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_cistatic int tegra_xudc_alloc_event_ring(struct tegra_xudc *xudc) 328462306a36Sopenharmony_ci{ 328562306a36Sopenharmony_ci unsigned int i; 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->event_ring); i++) { 328862306a36Sopenharmony_ci xudc->event_ring[i] = 328962306a36Sopenharmony_ci dma_alloc_coherent(xudc->dev, XUDC_EVENT_RING_SIZE * 329062306a36Sopenharmony_ci sizeof(*xudc->event_ring[i]), 329162306a36Sopenharmony_ci &xudc->event_ring_phys[i], 329262306a36Sopenharmony_ci GFP_KERNEL); 329362306a36Sopenharmony_ci if (!xudc->event_ring[i]) 329462306a36Sopenharmony_ci goto free_dma; 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci return 0; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_cifree_dma: 330062306a36Sopenharmony_ci for (; i > 0; i--) { 330162306a36Sopenharmony_ci dma_free_coherent(xudc->dev, XUDC_EVENT_RING_SIZE * 330262306a36Sopenharmony_ci sizeof(*xudc->event_ring[i - 1]), 330362306a36Sopenharmony_ci xudc->event_ring[i - 1], 330462306a36Sopenharmony_ci xudc->event_ring_phys[i - 1]); 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci return -ENOMEM; 330762306a36Sopenharmony_ci} 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_cistatic void tegra_xudc_init_event_ring(struct tegra_xudc *xudc) 331062306a36Sopenharmony_ci{ 331162306a36Sopenharmony_ci unsigned int i; 331262306a36Sopenharmony_ci u32 val; 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->event_ring); i++) { 331562306a36Sopenharmony_ci memset(xudc->event_ring[i], 0, XUDC_EVENT_RING_SIZE * 331662306a36Sopenharmony_ci sizeof(*xudc->event_ring[i])); 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci val = xudc_readl(xudc, ERSTSZ); 331962306a36Sopenharmony_ci val &= ~(ERSTSZ_ERSTXSZ_MASK << ERSTSZ_ERSTXSZ_SHIFT(i)); 332062306a36Sopenharmony_ci val |= XUDC_EVENT_RING_SIZE << ERSTSZ_ERSTXSZ_SHIFT(i); 332162306a36Sopenharmony_ci xudc_writel(xudc, val, ERSTSZ); 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci xudc_writel(xudc, lower_32_bits(xudc->event_ring_phys[i]), 332462306a36Sopenharmony_ci ERSTXBALO(i)); 332562306a36Sopenharmony_ci xudc_writel(xudc, upper_32_bits(xudc->event_ring_phys[i]), 332662306a36Sopenharmony_ci ERSTXBAHI(i)); 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci val = lower_32_bits(xudc->event_ring_phys[0]); 333062306a36Sopenharmony_ci xudc_writel(xudc, val, ERDPLO); 333162306a36Sopenharmony_ci val |= EREPLO_ECS; 333262306a36Sopenharmony_ci xudc_writel(xudc, val, EREPLO); 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci val = upper_32_bits(xudc->event_ring_phys[0]); 333562306a36Sopenharmony_ci xudc_writel(xudc, val, ERDPHI); 333662306a36Sopenharmony_ci xudc_writel(xudc, val, EREPHI); 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci xudc->ccs = true; 333962306a36Sopenharmony_ci xudc->event_ring_index = 0; 334062306a36Sopenharmony_ci xudc->event_ring_deq_ptr = 0; 334162306a36Sopenharmony_ci} 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_cistatic void tegra_xudc_free_event_ring(struct tegra_xudc *xudc) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci unsigned int i; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xudc->event_ring); i++) { 334862306a36Sopenharmony_ci dma_free_coherent(xudc->dev, XUDC_EVENT_RING_SIZE * 334962306a36Sopenharmony_ci sizeof(*xudc->event_ring[i]), 335062306a36Sopenharmony_ci xudc->event_ring[i], 335162306a36Sopenharmony_ci xudc->event_ring_phys[i]); 335262306a36Sopenharmony_ci } 335362306a36Sopenharmony_ci} 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_cistatic void tegra_xudc_fpci_ipfs_init(struct tegra_xudc *xudc) 335662306a36Sopenharmony_ci{ 335762306a36Sopenharmony_ci u32 val; 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci if (xudc->soc->has_ipfs) { 336062306a36Sopenharmony_ci val = ipfs_readl(xudc, XUSB_DEV_CONFIGURATION_0); 336162306a36Sopenharmony_ci val |= XUSB_DEV_CONFIGURATION_0_EN_FPCI; 336262306a36Sopenharmony_ci ipfs_writel(xudc, val, XUSB_DEV_CONFIGURATION_0); 336362306a36Sopenharmony_ci usleep_range(10, 15); 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci /* Enable bus master */ 336762306a36Sopenharmony_ci val = XUSB_DEV_CFG_1_IO_SPACE_EN | XUSB_DEV_CFG_1_MEMORY_SPACE_EN | 336862306a36Sopenharmony_ci XUSB_DEV_CFG_1_BUS_MASTER_EN; 336962306a36Sopenharmony_ci fpci_writel(xudc, val, XUSB_DEV_CFG_1); 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci /* Program BAR0 space */ 337262306a36Sopenharmony_ci val = fpci_readl(xudc, XUSB_DEV_CFG_4); 337362306a36Sopenharmony_ci val &= ~(XUSB_DEV_CFG_4_BASE_ADDR_MASK); 337462306a36Sopenharmony_ci val |= xudc->phys_base & (XUSB_DEV_CFG_4_BASE_ADDR_MASK); 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci fpci_writel(xudc, val, XUSB_DEV_CFG_4); 337762306a36Sopenharmony_ci fpci_writel(xudc, upper_32_bits(xudc->phys_base), XUSB_DEV_CFG_5); 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci usleep_range(100, 200); 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci if (xudc->soc->has_ipfs) { 338262306a36Sopenharmony_ci /* Enable interrupt assertion */ 338362306a36Sopenharmony_ci val = ipfs_readl(xudc, XUSB_DEV_INTR_MASK_0); 338462306a36Sopenharmony_ci val |= XUSB_DEV_INTR_MASK_0_IP_INT_MASK; 338562306a36Sopenharmony_ci ipfs_writel(xudc, val, XUSB_DEV_INTR_MASK_0); 338662306a36Sopenharmony_ci } 338762306a36Sopenharmony_ci} 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_cistatic void tegra_xudc_device_params_init(struct tegra_xudc *xudc) 339062306a36Sopenharmony_ci{ 339162306a36Sopenharmony_ci u32 val, imod; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci if (xudc->soc->has_ipfs) { 339462306a36Sopenharmony_ci val = xudc_readl(xudc, BLCG); 339562306a36Sopenharmony_ci val |= BLCG_ALL; 339662306a36Sopenharmony_ci val &= ~(BLCG_DFPCI | BLCG_UFPCI | BLCG_FE | 339762306a36Sopenharmony_ci BLCG_COREPLL_PWRDN); 339862306a36Sopenharmony_ci val |= BLCG_IOPLL_0_PWRDN; 339962306a36Sopenharmony_ci val |= BLCG_IOPLL_1_PWRDN; 340062306a36Sopenharmony_ci val |= BLCG_IOPLL_2_PWRDN; 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci xudc_writel(xudc, val, BLCG); 340362306a36Sopenharmony_ci } 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci if (xudc->soc->port_speed_quirk) 340662306a36Sopenharmony_ci tegra_xudc_limit_port_speed(xudc); 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci /* Set a reasonable U3 exit timer value. */ 340962306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_PADCTL4); 341062306a36Sopenharmony_ci val &= ~(SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3_MASK); 341162306a36Sopenharmony_ci val |= SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3(0x5dc0); 341262306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_PADCTL4); 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci /* Default ping LFPS tBurst is too large. */ 341562306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT0); 341662306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT0_PING_TBURST_MASK); 341762306a36Sopenharmony_ci val |= SSPX_CORE_CNT0_PING_TBURST(0xa); 341862306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT0); 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci /* Default tPortConfiguration timeout is too small. */ 342162306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT30); 342262306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT30_LMPITP_TIMER_MASK); 342362306a36Sopenharmony_ci val |= SSPX_CORE_CNT30_LMPITP_TIMER(0x978); 342462306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT30); 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci if (xudc->soc->lpm_enable) { 342762306a36Sopenharmony_ci /* Set L1 resume duration to 95 us. */ 342862306a36Sopenharmony_ci val = xudc_readl(xudc, HSFSPI_COUNT13); 342962306a36Sopenharmony_ci val &= ~(HSFSPI_COUNT13_U2_RESUME_K_DURATION_MASK); 343062306a36Sopenharmony_ci val |= HSFSPI_COUNT13_U2_RESUME_K_DURATION(0x2c88); 343162306a36Sopenharmony_ci xudc_writel(xudc, val, HSFSPI_COUNT13); 343262306a36Sopenharmony_ci } 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci /* 343562306a36Sopenharmony_ci * Compliance suite appears to be violating polling LFPS tBurst max 343662306a36Sopenharmony_ci * of 1.4us. Send 1.45us instead. 343762306a36Sopenharmony_ci */ 343862306a36Sopenharmony_ci val = xudc_readl(xudc, SSPX_CORE_CNT32); 343962306a36Sopenharmony_ci val &= ~(SSPX_CORE_CNT32_POLL_TBURST_MAX_MASK); 344062306a36Sopenharmony_ci val |= SSPX_CORE_CNT32_POLL_TBURST_MAX(0xb0); 344162306a36Sopenharmony_ci xudc_writel(xudc, val, SSPX_CORE_CNT32); 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci /* Direct HS/FS port instance to RxDetect. */ 344462306a36Sopenharmony_ci val = xudc_readl(xudc, CFG_DEV_FE); 344562306a36Sopenharmony_ci val &= ~(CFG_DEV_FE_PORTREGSEL_MASK); 344662306a36Sopenharmony_ci val |= CFG_DEV_FE_PORTREGSEL(CFG_DEV_FE_PORTREGSEL_HSFS_PI); 344762306a36Sopenharmony_ci xudc_writel(xudc, val, CFG_DEV_FE); 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci val = xudc_readl(xudc, PORTSC); 345062306a36Sopenharmony_ci val &= ~(PORTSC_CHANGE_MASK | PORTSC_PLS_MASK); 345162306a36Sopenharmony_ci val |= PORTSC_LWS | PORTSC_PLS(PORTSC_PLS_RXDETECT); 345262306a36Sopenharmony_ci xudc_writel(xudc, val, PORTSC); 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci /* Direct SS port instance to RxDetect. */ 345562306a36Sopenharmony_ci val = xudc_readl(xudc, CFG_DEV_FE); 345662306a36Sopenharmony_ci val &= ~(CFG_DEV_FE_PORTREGSEL_MASK); 345762306a36Sopenharmony_ci val |= CFG_DEV_FE_PORTREGSEL_SS_PI & CFG_DEV_FE_PORTREGSEL_MASK; 345862306a36Sopenharmony_ci xudc_writel(xudc, val, CFG_DEV_FE); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci val = xudc_readl(xudc, PORTSC); 346162306a36Sopenharmony_ci val &= ~(PORTSC_CHANGE_MASK | PORTSC_PLS_MASK); 346262306a36Sopenharmony_ci val |= PORTSC_LWS | PORTSC_PLS(PORTSC_PLS_RXDETECT); 346362306a36Sopenharmony_ci xudc_writel(xudc, val, PORTSC); 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci /* Restore port instance. */ 346662306a36Sopenharmony_ci val = xudc_readl(xudc, CFG_DEV_FE); 346762306a36Sopenharmony_ci val &= ~(CFG_DEV_FE_PORTREGSEL_MASK); 346862306a36Sopenharmony_ci xudc_writel(xudc, val, CFG_DEV_FE); 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci /* 347162306a36Sopenharmony_ci * Enable INFINITE_SS_RETRY to prevent device from entering 347262306a36Sopenharmony_ci * Disabled.Error when attached to buggy SuperSpeed hubs. 347362306a36Sopenharmony_ci */ 347462306a36Sopenharmony_ci val = xudc_readl(xudc, CFG_DEV_FE); 347562306a36Sopenharmony_ci val |= CFG_DEV_FE_INFINITE_SS_RETRY; 347662306a36Sopenharmony_ci xudc_writel(xudc, val, CFG_DEV_FE); 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci /* Set interrupt moderation. */ 347962306a36Sopenharmony_ci imod = XUDC_INTERRUPT_MODERATION_US * 4; 348062306a36Sopenharmony_ci val = xudc_readl(xudc, RT_IMOD); 348162306a36Sopenharmony_ci val &= ~((RT_IMOD_IMODI_MASK) | (RT_IMOD_IMODC_MASK)); 348262306a36Sopenharmony_ci val |= (RT_IMOD_IMODI(imod) | RT_IMOD_IMODC(imod)); 348362306a36Sopenharmony_ci xudc_writel(xudc, val, RT_IMOD); 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci /* increase SSPI transaction timeout from 32us to 512us */ 348662306a36Sopenharmony_ci val = xudc_readl(xudc, CFG_DEV_SSPI_XFER); 348762306a36Sopenharmony_ci val &= ~(CFG_DEV_SSPI_XFER_ACKTIMEOUT_MASK); 348862306a36Sopenharmony_ci val |= CFG_DEV_SSPI_XFER_ACKTIMEOUT(0xf000); 348962306a36Sopenharmony_ci xudc_writel(xudc, val, CFG_DEV_SSPI_XFER); 349062306a36Sopenharmony_ci} 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_cistatic int tegra_xudc_phy_get(struct tegra_xudc *xudc) 349362306a36Sopenharmony_ci{ 349462306a36Sopenharmony_ci int err = 0, usb3_companion_port; 349562306a36Sopenharmony_ci unsigned int i, j; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci xudc->utmi_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys, 349862306a36Sopenharmony_ci sizeof(*xudc->utmi_phy), GFP_KERNEL); 349962306a36Sopenharmony_ci if (!xudc->utmi_phy) 350062306a36Sopenharmony_ci return -ENOMEM; 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci xudc->usb3_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys, 350362306a36Sopenharmony_ci sizeof(*xudc->usb3_phy), GFP_KERNEL); 350462306a36Sopenharmony_ci if (!xudc->usb3_phy) 350562306a36Sopenharmony_ci return -ENOMEM; 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci xudc->usbphy = devm_kcalloc(xudc->dev, xudc->soc->num_phys, 350862306a36Sopenharmony_ci sizeof(*xudc->usbphy), GFP_KERNEL); 350962306a36Sopenharmony_ci if (!xudc->usbphy) 351062306a36Sopenharmony_ci return -ENOMEM; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci xudc->vbus_nb.notifier_call = tegra_xudc_vbus_notify; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 351562306a36Sopenharmony_ci char phy_name[] = "usb.-."; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci /* Get USB2 phy */ 351862306a36Sopenharmony_ci snprintf(phy_name, sizeof(phy_name), "usb2-%d", i); 351962306a36Sopenharmony_ci xudc->utmi_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); 352062306a36Sopenharmony_ci if (IS_ERR(xudc->utmi_phy[i])) { 352162306a36Sopenharmony_ci err = PTR_ERR(xudc->utmi_phy[i]); 352262306a36Sopenharmony_ci dev_err_probe(xudc->dev, err, 352362306a36Sopenharmony_ci "failed to get PHY for phy-name usb2-%d\n", i); 352462306a36Sopenharmony_ci goto clean_up; 352562306a36Sopenharmony_ci } else if (xudc->utmi_phy[i]) { 352662306a36Sopenharmony_ci /* Get usb-phy, if utmi phy is available */ 352762306a36Sopenharmony_ci xudc->usbphy[i] = devm_usb_get_phy_by_node(xudc->dev, 352862306a36Sopenharmony_ci xudc->utmi_phy[i]->dev.of_node, 352962306a36Sopenharmony_ci NULL); 353062306a36Sopenharmony_ci if (IS_ERR(xudc->usbphy[i])) { 353162306a36Sopenharmony_ci err = PTR_ERR(xudc->usbphy[i]); 353262306a36Sopenharmony_ci dev_err_probe(xudc->dev, err, 353362306a36Sopenharmony_ci "failed to get usbphy-%d\n", i); 353462306a36Sopenharmony_ci goto clean_up; 353562306a36Sopenharmony_ci } 353662306a36Sopenharmony_ci } else if (!xudc->utmi_phy[i]) { 353762306a36Sopenharmony_ci /* if utmi phy is not available, ignore USB3 phy get */ 353862306a36Sopenharmony_ci continue; 353962306a36Sopenharmony_ci } 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci /* Get USB3 phy */ 354262306a36Sopenharmony_ci usb3_companion_port = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i); 354362306a36Sopenharmony_ci if (usb3_companion_port < 0) 354462306a36Sopenharmony_ci continue; 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci for (j = 0; j < xudc->soc->num_phys; j++) { 354762306a36Sopenharmony_ci snprintf(phy_name, sizeof(phy_name), "usb3-%d", j); 354862306a36Sopenharmony_ci xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); 354962306a36Sopenharmony_ci if (IS_ERR(xudc->usb3_phy[i])) { 355062306a36Sopenharmony_ci err = PTR_ERR(xudc->usb3_phy[i]); 355162306a36Sopenharmony_ci dev_err_probe(xudc->dev, err, 355262306a36Sopenharmony_ci "failed to get PHY for phy-name usb3-%d\n", j); 355362306a36Sopenharmony_ci goto clean_up; 355462306a36Sopenharmony_ci } else if (xudc->usb3_phy[i]) { 355562306a36Sopenharmony_ci int usb2_port = 355662306a36Sopenharmony_ci tegra_xusb_padctl_get_port_number(xudc->utmi_phy[i]); 355762306a36Sopenharmony_ci int usb3_port = 355862306a36Sopenharmony_ci tegra_xusb_padctl_get_port_number(xudc->usb3_phy[i]); 355962306a36Sopenharmony_ci if (usb3_port == usb3_companion_port) { 356062306a36Sopenharmony_ci dev_dbg(xudc->dev, "USB2 port %d is paired with USB3 port %d for device mode port %d\n", 356162306a36Sopenharmony_ci usb2_port, usb3_port, i); 356262306a36Sopenharmony_ci break; 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci } 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci } 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci return err; 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ciclean_up: 357162306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 357262306a36Sopenharmony_ci xudc->usb3_phy[i] = NULL; 357362306a36Sopenharmony_ci xudc->utmi_phy[i] = NULL; 357462306a36Sopenharmony_ci xudc->usbphy[i] = NULL; 357562306a36Sopenharmony_ci } 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci return err; 357862306a36Sopenharmony_ci} 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_cistatic void tegra_xudc_phy_exit(struct tegra_xudc *xudc) 358162306a36Sopenharmony_ci{ 358262306a36Sopenharmony_ci unsigned int i; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 358562306a36Sopenharmony_ci phy_exit(xudc->usb3_phy[i]); 358662306a36Sopenharmony_ci phy_exit(xudc->utmi_phy[i]); 358762306a36Sopenharmony_ci } 358862306a36Sopenharmony_ci} 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_cistatic int tegra_xudc_phy_init(struct tegra_xudc *xudc) 359162306a36Sopenharmony_ci{ 359262306a36Sopenharmony_ci int err; 359362306a36Sopenharmony_ci unsigned int i; 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 359662306a36Sopenharmony_ci err = phy_init(xudc->utmi_phy[i]); 359762306a36Sopenharmony_ci if (err < 0) { 359862306a36Sopenharmony_ci dev_err(xudc->dev, "UTMI PHY #%u initialization failed: %d\n", i, err); 359962306a36Sopenharmony_ci goto exit_phy; 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci err = phy_init(xudc->usb3_phy[i]); 360362306a36Sopenharmony_ci if (err < 0) { 360462306a36Sopenharmony_ci dev_err(xudc->dev, "USB3 PHY #%u initialization failed: %d\n", i, err); 360562306a36Sopenharmony_ci goto exit_phy; 360662306a36Sopenharmony_ci } 360762306a36Sopenharmony_ci } 360862306a36Sopenharmony_ci return 0; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ciexit_phy: 361162306a36Sopenharmony_ci tegra_xudc_phy_exit(xudc); 361262306a36Sopenharmony_ci return err; 361362306a36Sopenharmony_ci} 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_cistatic const char * const tegra210_xudc_supply_names[] = { 361662306a36Sopenharmony_ci "hvdd-usb", 361762306a36Sopenharmony_ci "avddio-usb", 361862306a36Sopenharmony_ci}; 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_cistatic const char * const tegra210_xudc_clock_names[] = { 362162306a36Sopenharmony_ci "dev", 362262306a36Sopenharmony_ci "ss", 362362306a36Sopenharmony_ci "ss_src", 362462306a36Sopenharmony_ci "hs_src", 362562306a36Sopenharmony_ci "fs_src", 362662306a36Sopenharmony_ci}; 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_cistatic const char * const tegra186_xudc_clock_names[] = { 362962306a36Sopenharmony_ci "dev", 363062306a36Sopenharmony_ci "ss", 363162306a36Sopenharmony_ci "ss_src", 363262306a36Sopenharmony_ci "fs_src", 363362306a36Sopenharmony_ci}; 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_cistatic struct tegra_xudc_soc tegra210_xudc_soc_data = { 363662306a36Sopenharmony_ci .supply_names = tegra210_xudc_supply_names, 363762306a36Sopenharmony_ci .num_supplies = ARRAY_SIZE(tegra210_xudc_supply_names), 363862306a36Sopenharmony_ci .clock_names = tegra210_xudc_clock_names, 363962306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(tegra210_xudc_clock_names), 364062306a36Sopenharmony_ci .num_phys = 4, 364162306a36Sopenharmony_ci .u1_enable = false, 364262306a36Sopenharmony_ci .u2_enable = true, 364362306a36Sopenharmony_ci .lpm_enable = false, 364462306a36Sopenharmony_ci .invalid_seq_num = true, 364562306a36Sopenharmony_ci .pls_quirk = true, 364662306a36Sopenharmony_ci .port_reset_quirk = true, 364762306a36Sopenharmony_ci .port_speed_quirk = false, 364862306a36Sopenharmony_ci .has_ipfs = true, 364962306a36Sopenharmony_ci}; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_cistatic struct tegra_xudc_soc tegra186_xudc_soc_data = { 365262306a36Sopenharmony_ci .clock_names = tegra186_xudc_clock_names, 365362306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names), 365462306a36Sopenharmony_ci .num_phys = 4, 365562306a36Sopenharmony_ci .u1_enable = true, 365662306a36Sopenharmony_ci .u2_enable = true, 365762306a36Sopenharmony_ci .lpm_enable = false, 365862306a36Sopenharmony_ci .invalid_seq_num = false, 365962306a36Sopenharmony_ci .pls_quirk = false, 366062306a36Sopenharmony_ci .port_reset_quirk = false, 366162306a36Sopenharmony_ci .port_speed_quirk = false, 366262306a36Sopenharmony_ci .has_ipfs = false, 366362306a36Sopenharmony_ci}; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_cistatic struct tegra_xudc_soc tegra194_xudc_soc_data = { 366662306a36Sopenharmony_ci .clock_names = tegra186_xudc_clock_names, 366762306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names), 366862306a36Sopenharmony_ci .num_phys = 4, 366962306a36Sopenharmony_ci .u1_enable = true, 367062306a36Sopenharmony_ci .u2_enable = true, 367162306a36Sopenharmony_ci .lpm_enable = true, 367262306a36Sopenharmony_ci .invalid_seq_num = false, 367362306a36Sopenharmony_ci .pls_quirk = false, 367462306a36Sopenharmony_ci .port_reset_quirk = false, 367562306a36Sopenharmony_ci .port_speed_quirk = true, 367662306a36Sopenharmony_ci .has_ipfs = false, 367762306a36Sopenharmony_ci}; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_cistatic struct tegra_xudc_soc tegra234_xudc_soc_data = { 368062306a36Sopenharmony_ci .clock_names = tegra186_xudc_clock_names, 368162306a36Sopenharmony_ci .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names), 368262306a36Sopenharmony_ci .num_phys = 4, 368362306a36Sopenharmony_ci .u1_enable = true, 368462306a36Sopenharmony_ci .u2_enable = true, 368562306a36Sopenharmony_ci .lpm_enable = true, 368662306a36Sopenharmony_ci .invalid_seq_num = false, 368762306a36Sopenharmony_ci .pls_quirk = false, 368862306a36Sopenharmony_ci .port_reset_quirk = false, 368962306a36Sopenharmony_ci .has_ipfs = false, 369062306a36Sopenharmony_ci}; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_cistatic const struct of_device_id tegra_xudc_of_match[] = { 369362306a36Sopenharmony_ci { 369462306a36Sopenharmony_ci .compatible = "nvidia,tegra210-xudc", 369562306a36Sopenharmony_ci .data = &tegra210_xudc_soc_data 369662306a36Sopenharmony_ci }, 369762306a36Sopenharmony_ci { 369862306a36Sopenharmony_ci .compatible = "nvidia,tegra186-xudc", 369962306a36Sopenharmony_ci .data = &tegra186_xudc_soc_data 370062306a36Sopenharmony_ci }, 370162306a36Sopenharmony_ci { 370262306a36Sopenharmony_ci .compatible = "nvidia,tegra194-xudc", 370362306a36Sopenharmony_ci .data = &tegra194_xudc_soc_data 370462306a36Sopenharmony_ci }, 370562306a36Sopenharmony_ci { 370662306a36Sopenharmony_ci .compatible = "nvidia,tegra234-xudc", 370762306a36Sopenharmony_ci .data = &tegra234_xudc_soc_data 370862306a36Sopenharmony_ci }, 370962306a36Sopenharmony_ci { } 371062306a36Sopenharmony_ci}; 371162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_xudc_of_match); 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_cistatic void tegra_xudc_powerdomain_remove(struct tegra_xudc *xudc) 371462306a36Sopenharmony_ci{ 371562306a36Sopenharmony_ci if (xudc->genpd_dl_ss) 371662306a36Sopenharmony_ci device_link_del(xudc->genpd_dl_ss); 371762306a36Sopenharmony_ci if (xudc->genpd_dl_device) 371862306a36Sopenharmony_ci device_link_del(xudc->genpd_dl_device); 371962306a36Sopenharmony_ci if (xudc->genpd_dev_ss) 372062306a36Sopenharmony_ci dev_pm_domain_detach(xudc->genpd_dev_ss, true); 372162306a36Sopenharmony_ci if (xudc->genpd_dev_device) 372262306a36Sopenharmony_ci dev_pm_domain_detach(xudc->genpd_dev_device, true); 372362306a36Sopenharmony_ci} 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_cistatic int tegra_xudc_powerdomain_init(struct tegra_xudc *xudc) 372662306a36Sopenharmony_ci{ 372762306a36Sopenharmony_ci struct device *dev = xudc->dev; 372862306a36Sopenharmony_ci int err; 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci xudc->genpd_dev_device = dev_pm_domain_attach_by_name(dev, "dev"); 373162306a36Sopenharmony_ci if (IS_ERR(xudc->genpd_dev_device)) { 373262306a36Sopenharmony_ci err = PTR_ERR(xudc->genpd_dev_device); 373362306a36Sopenharmony_ci dev_err(dev, "failed to get device power domain: %d\n", err); 373462306a36Sopenharmony_ci return err; 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci xudc->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "ss"); 373862306a36Sopenharmony_ci if (IS_ERR(xudc->genpd_dev_ss)) { 373962306a36Sopenharmony_ci err = PTR_ERR(xudc->genpd_dev_ss); 374062306a36Sopenharmony_ci dev_err(dev, "failed to get SuperSpeed power domain: %d\n", err); 374162306a36Sopenharmony_ci return err; 374262306a36Sopenharmony_ci } 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci xudc->genpd_dl_device = device_link_add(dev, xudc->genpd_dev_device, 374562306a36Sopenharmony_ci DL_FLAG_PM_RUNTIME | 374662306a36Sopenharmony_ci DL_FLAG_STATELESS); 374762306a36Sopenharmony_ci if (!xudc->genpd_dl_device) { 374862306a36Sopenharmony_ci dev_err(dev, "failed to add USB device link\n"); 374962306a36Sopenharmony_ci return -ENODEV; 375062306a36Sopenharmony_ci } 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci xudc->genpd_dl_ss = device_link_add(dev, xudc->genpd_dev_ss, 375362306a36Sopenharmony_ci DL_FLAG_PM_RUNTIME | 375462306a36Sopenharmony_ci DL_FLAG_STATELESS); 375562306a36Sopenharmony_ci if (!xudc->genpd_dl_ss) { 375662306a36Sopenharmony_ci dev_err(dev, "failed to add SuperSpeed device link\n"); 375762306a36Sopenharmony_ci return -ENODEV; 375862306a36Sopenharmony_ci } 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci return 0; 376162306a36Sopenharmony_ci} 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_cistatic int tegra_xudc_probe(struct platform_device *pdev) 376462306a36Sopenharmony_ci{ 376562306a36Sopenharmony_ci struct tegra_xudc *xudc; 376662306a36Sopenharmony_ci struct resource *res; 376762306a36Sopenharmony_ci unsigned int i; 376862306a36Sopenharmony_ci int err; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci xudc = devm_kzalloc(&pdev->dev, sizeof(*xudc), GFP_KERNEL); 377162306a36Sopenharmony_ci if (!xudc) 377262306a36Sopenharmony_ci return -ENOMEM; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci xudc->dev = &pdev->dev; 377562306a36Sopenharmony_ci platform_set_drvdata(pdev, xudc); 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci xudc->soc = of_device_get_match_data(&pdev->dev); 377862306a36Sopenharmony_ci if (!xudc->soc) 377962306a36Sopenharmony_ci return -ENODEV; 378062306a36Sopenharmony_ci 378162306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base"); 378262306a36Sopenharmony_ci xudc->base = devm_ioremap_resource(&pdev->dev, res); 378362306a36Sopenharmony_ci if (IS_ERR(xudc->base)) 378462306a36Sopenharmony_ci return PTR_ERR(xudc->base); 378562306a36Sopenharmony_ci xudc->phys_base = res->start; 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci xudc->fpci = devm_platform_ioremap_resource_byname(pdev, "fpci"); 378862306a36Sopenharmony_ci if (IS_ERR(xudc->fpci)) 378962306a36Sopenharmony_ci return PTR_ERR(xudc->fpci); 379062306a36Sopenharmony_ci 379162306a36Sopenharmony_ci if (xudc->soc->has_ipfs) { 379262306a36Sopenharmony_ci xudc->ipfs = devm_platform_ioremap_resource_byname(pdev, "ipfs"); 379362306a36Sopenharmony_ci if (IS_ERR(xudc->ipfs)) 379462306a36Sopenharmony_ci return PTR_ERR(xudc->ipfs); 379562306a36Sopenharmony_ci } 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci xudc->irq = platform_get_irq(pdev, 0); 379862306a36Sopenharmony_ci if (xudc->irq < 0) 379962306a36Sopenharmony_ci return xudc->irq; 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, xudc->irq, tegra_xudc_irq, 0, 380262306a36Sopenharmony_ci dev_name(&pdev->dev), xudc); 380362306a36Sopenharmony_ci if (err < 0) { 380462306a36Sopenharmony_ci dev_err(xudc->dev, "failed to claim IRQ#%u: %d\n", xudc->irq, 380562306a36Sopenharmony_ci err); 380662306a36Sopenharmony_ci return err; 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ci xudc->clks = devm_kcalloc(&pdev->dev, xudc->soc->num_clks, sizeof(*xudc->clks), 381062306a36Sopenharmony_ci GFP_KERNEL); 381162306a36Sopenharmony_ci if (!xudc->clks) 381262306a36Sopenharmony_ci return -ENOMEM; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_clks; i++) 381562306a36Sopenharmony_ci xudc->clks[i].id = xudc->soc->clock_names[i]; 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, xudc->clks); 381862306a36Sopenharmony_ci if (err) { 381962306a36Sopenharmony_ci dev_err_probe(xudc->dev, err, "failed to request clocks\n"); 382062306a36Sopenharmony_ci return err; 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci xudc->supplies = devm_kcalloc(&pdev->dev, xudc->soc->num_supplies, 382462306a36Sopenharmony_ci sizeof(*xudc->supplies), GFP_KERNEL); 382562306a36Sopenharmony_ci if (!xudc->supplies) 382662306a36Sopenharmony_ci return -ENOMEM; 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_supplies; i++) 382962306a36Sopenharmony_ci xudc->supplies[i].supply = xudc->soc->supply_names[i]; 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci err = devm_regulator_bulk_get(&pdev->dev, xudc->soc->num_supplies, 383262306a36Sopenharmony_ci xudc->supplies); 383362306a36Sopenharmony_ci if (err) { 383462306a36Sopenharmony_ci dev_err_probe(xudc->dev, err, "failed to request regulators\n"); 383562306a36Sopenharmony_ci return err; 383662306a36Sopenharmony_ci } 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci xudc->padctl = tegra_xusb_padctl_get(&pdev->dev); 383962306a36Sopenharmony_ci if (IS_ERR(xudc->padctl)) 384062306a36Sopenharmony_ci return PTR_ERR(xudc->padctl); 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci err = regulator_bulk_enable(xudc->soc->num_supplies, xudc->supplies); 384362306a36Sopenharmony_ci if (err) { 384462306a36Sopenharmony_ci dev_err(xudc->dev, "failed to enable regulators: %d\n", err); 384562306a36Sopenharmony_ci goto put_padctl; 384662306a36Sopenharmony_ci } 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci err = tegra_xudc_phy_get(xudc); 384962306a36Sopenharmony_ci if (err) 385062306a36Sopenharmony_ci goto disable_regulator; 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci err = tegra_xudc_powerdomain_init(xudc); 385362306a36Sopenharmony_ci if (err) 385462306a36Sopenharmony_ci goto put_powerdomains; 385562306a36Sopenharmony_ci 385662306a36Sopenharmony_ci err = tegra_xudc_phy_init(xudc); 385762306a36Sopenharmony_ci if (err) 385862306a36Sopenharmony_ci goto put_powerdomains; 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci err = tegra_xudc_alloc_event_ring(xudc); 386162306a36Sopenharmony_ci if (err) 386262306a36Sopenharmony_ci goto disable_phy; 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci err = tegra_xudc_alloc_eps(xudc); 386562306a36Sopenharmony_ci if (err) 386662306a36Sopenharmony_ci goto free_event_ring; 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_ci spin_lock_init(&xudc->lock); 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci init_completion(&xudc->disconnect_complete); 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_ci INIT_WORK(&xudc->usb_role_sw_work, tegra_xudc_usb_role_sw_work); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci INIT_DELAYED_WORK(&xudc->plc_reset_work, tegra_xudc_plc_reset_work); 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci INIT_DELAYED_WORK(&xudc->port_reset_war_work, 387762306a36Sopenharmony_ci tegra_xudc_port_reset_war_work); 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci xudc->gadget.ops = &tegra_xudc_gadget_ops; 388262306a36Sopenharmony_ci xudc->gadget.ep0 = &xudc->ep[0].usb_ep; 388362306a36Sopenharmony_ci xudc->gadget.name = "tegra-xudc"; 388462306a36Sopenharmony_ci xudc->gadget.max_speed = USB_SPEED_SUPER; 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci err = usb_add_gadget_udc(&pdev->dev, &xudc->gadget); 388762306a36Sopenharmony_ci if (err) { 388862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to add USB gadget: %d\n", err); 388962306a36Sopenharmony_ci goto free_eps; 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 389362306a36Sopenharmony_ci if (!xudc->usbphy[i]) 389462306a36Sopenharmony_ci continue; 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci usb_register_notifier(xudc->usbphy[i], &xudc->vbus_nb); 389762306a36Sopenharmony_ci tegra_xudc_update_data_role(xudc, xudc->usbphy[i]); 389862306a36Sopenharmony_ci } 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_ci return 0; 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_cifree_eps: 390362306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 390462306a36Sopenharmony_ci tegra_xudc_free_eps(xudc); 390562306a36Sopenharmony_cifree_event_ring: 390662306a36Sopenharmony_ci tegra_xudc_free_event_ring(xudc); 390762306a36Sopenharmony_cidisable_phy: 390862306a36Sopenharmony_ci tegra_xudc_phy_exit(xudc); 390962306a36Sopenharmony_ciput_powerdomains: 391062306a36Sopenharmony_ci tegra_xudc_powerdomain_remove(xudc); 391162306a36Sopenharmony_cidisable_regulator: 391262306a36Sopenharmony_ci regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies); 391362306a36Sopenharmony_ciput_padctl: 391462306a36Sopenharmony_ci tegra_xusb_padctl_put(xudc->padctl); 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci return err; 391762306a36Sopenharmony_ci} 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_cistatic void tegra_xudc_remove(struct platform_device *pdev) 392062306a36Sopenharmony_ci{ 392162306a36Sopenharmony_ci struct tegra_xudc *xudc = platform_get_drvdata(pdev); 392262306a36Sopenharmony_ci unsigned int i; 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci pm_runtime_get_sync(xudc->dev); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci cancel_delayed_work_sync(&xudc->plc_reset_work); 392762306a36Sopenharmony_ci cancel_work_sync(&xudc->usb_role_sw_work); 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci usb_del_gadget_udc(&xudc->gadget); 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci tegra_xudc_free_eps(xudc); 393262306a36Sopenharmony_ci tegra_xudc_free_event_ring(xudc); 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci tegra_xudc_powerdomain_remove(xudc); 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies); 393762306a36Sopenharmony_ci 393862306a36Sopenharmony_ci for (i = 0; i < xudc->soc->num_phys; i++) { 393962306a36Sopenharmony_ci phy_power_off(xudc->utmi_phy[i]); 394062306a36Sopenharmony_ci phy_power_off(xudc->usb3_phy[i]); 394162306a36Sopenharmony_ci } 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci tegra_xudc_phy_exit(xudc); 394462306a36Sopenharmony_ci 394562306a36Sopenharmony_ci pm_runtime_disable(xudc->dev); 394662306a36Sopenharmony_ci pm_runtime_put(xudc->dev); 394762306a36Sopenharmony_ci 394862306a36Sopenharmony_ci tegra_xusb_padctl_put(xudc->padctl); 394962306a36Sopenharmony_ci} 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc) 395262306a36Sopenharmony_ci{ 395362306a36Sopenharmony_ci unsigned long flags; 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci dev_dbg(xudc->dev, "entering ELPG\n"); 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci xudc->powergated = true; 396062306a36Sopenharmony_ci xudc->saved_regs.ctrl = xudc_readl(xudc, CTRL); 396162306a36Sopenharmony_ci xudc->saved_regs.portpm = xudc_readl(xudc, PORTPM); 396262306a36Sopenharmony_ci xudc_writel(xudc, 0, CTRL); 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci clk_bulk_disable_unprepare(xudc->soc->num_clks, xudc->clks); 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies); 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ci dev_dbg(xudc->dev, "entering ELPG done\n"); 397162306a36Sopenharmony_ci return 0; 397262306a36Sopenharmony_ci} 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_unpowergate(struct tegra_xudc *xudc) 397562306a36Sopenharmony_ci{ 397662306a36Sopenharmony_ci unsigned long flags; 397762306a36Sopenharmony_ci int err; 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci dev_dbg(xudc->dev, "exiting ELPG\n"); 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci err = regulator_bulk_enable(xudc->soc->num_supplies, 398262306a36Sopenharmony_ci xudc->supplies); 398362306a36Sopenharmony_ci if (err < 0) 398462306a36Sopenharmony_ci return err; 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci err = clk_bulk_prepare_enable(xudc->soc->num_clks, xudc->clks); 398762306a36Sopenharmony_ci if (err < 0) 398862306a36Sopenharmony_ci return err; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci tegra_xudc_fpci_ipfs_init(xudc); 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci tegra_xudc_device_params_init(xudc); 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_ci tegra_xudc_init_event_ring(xudc); 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci tegra_xudc_init_eps(xudc); 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci xudc_writel(xudc, xudc->saved_regs.portpm, PORTPM); 399962306a36Sopenharmony_ci xudc_writel(xudc, xudc->saved_regs.ctrl, CTRL); 400062306a36Sopenharmony_ci 400162306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 400262306a36Sopenharmony_ci xudc->powergated = false; 400362306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci dev_dbg(xudc->dev, "exiting ELPG done\n"); 400662306a36Sopenharmony_ci return 0; 400762306a36Sopenharmony_ci} 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_suspend(struct device *dev) 401062306a36Sopenharmony_ci{ 401162306a36Sopenharmony_ci struct tegra_xudc *xudc = dev_get_drvdata(dev); 401262306a36Sopenharmony_ci unsigned long flags; 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 401562306a36Sopenharmony_ci xudc->suspended = true; 401662306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 401762306a36Sopenharmony_ci 401862306a36Sopenharmony_ci flush_work(&xudc->usb_role_sw_work); 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci if (!pm_runtime_status_suspended(dev)) { 402162306a36Sopenharmony_ci /* Forcibly disconnect before powergating. */ 402262306a36Sopenharmony_ci tegra_xudc_device_mode_off(xudc); 402362306a36Sopenharmony_ci tegra_xudc_powergate(xudc); 402462306a36Sopenharmony_ci } 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_ci pm_runtime_disable(dev); 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci return 0; 402962306a36Sopenharmony_ci} 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_resume(struct device *dev) 403262306a36Sopenharmony_ci{ 403362306a36Sopenharmony_ci struct tegra_xudc *xudc = dev_get_drvdata(dev); 403462306a36Sopenharmony_ci unsigned long flags; 403562306a36Sopenharmony_ci int err; 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci err = tegra_xudc_unpowergate(xudc); 403862306a36Sopenharmony_ci if (err < 0) 403962306a36Sopenharmony_ci return err; 404062306a36Sopenharmony_ci 404162306a36Sopenharmony_ci spin_lock_irqsave(&xudc->lock, flags); 404262306a36Sopenharmony_ci xudc->suspended = false; 404362306a36Sopenharmony_ci spin_unlock_irqrestore(&xudc->lock, flags); 404462306a36Sopenharmony_ci 404562306a36Sopenharmony_ci schedule_work(&xudc->usb_role_sw_work); 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_ci pm_runtime_enable(dev); 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci return 0; 405062306a36Sopenharmony_ci} 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_runtime_suspend(struct device *dev) 405362306a36Sopenharmony_ci{ 405462306a36Sopenharmony_ci struct tegra_xudc *xudc = dev_get_drvdata(dev); 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_ci return tegra_xudc_powergate(xudc); 405762306a36Sopenharmony_ci} 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_cistatic int __maybe_unused tegra_xudc_runtime_resume(struct device *dev) 406062306a36Sopenharmony_ci{ 406162306a36Sopenharmony_ci struct tegra_xudc *xudc = dev_get_drvdata(dev); 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci return tegra_xudc_unpowergate(xudc); 406462306a36Sopenharmony_ci} 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_cistatic const struct dev_pm_ops tegra_xudc_pm_ops = { 406762306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(tegra_xudc_suspend, tegra_xudc_resume) 406862306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(tegra_xudc_runtime_suspend, 406962306a36Sopenharmony_ci tegra_xudc_runtime_resume, NULL) 407062306a36Sopenharmony_ci}; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_cistatic struct platform_driver tegra_xudc_driver = { 407362306a36Sopenharmony_ci .probe = tegra_xudc_probe, 407462306a36Sopenharmony_ci .remove_new = tegra_xudc_remove, 407562306a36Sopenharmony_ci .driver = { 407662306a36Sopenharmony_ci .name = "tegra-xudc", 407762306a36Sopenharmony_ci .pm = &tegra_xudc_pm_ops, 407862306a36Sopenharmony_ci .of_match_table = tegra_xudc_of_match, 407962306a36Sopenharmony_ci }, 408062306a36Sopenharmony_ci}; 408162306a36Sopenharmony_cimodule_platform_driver(tegra_xudc_driver); 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra XUSB Device Controller"); 408462306a36Sopenharmony_ciMODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 408562306a36Sopenharmony_ciMODULE_AUTHOR("Hui Fu <hfu@nvidia.com>"); 408662306a36Sopenharmony_ciMODULE_AUTHOR("Nagarjuna Kristam <nkristam@nvidia.com>"); 408762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4088