diff options
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r-- | drivers/usb/dwc2/core.c | 7 | ||||
-rw-r--r-- | drivers/usb/dwc2/core.h | 190 | ||||
-rw-r--r-- | drivers/usb/dwc2/core_intr.c | 8 | ||||
-rw-r--r-- | drivers/usb/dwc2/debug.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc2/debugfs.c | 100 | ||||
-rw-r--r-- | drivers/usb/dwc2/gadget.c | 355 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.c | 16 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.h | 14 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_ddma.c | 1 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_intr.c | 12 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_queue.c | 5 | ||||
-rw-r--r-- | drivers/usb/dwc2/hw.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc2/params.c | 14 | ||||
-rw-r--r-- | drivers/usb/dwc2/pci.c | 10 |
14 files changed, 454 insertions, 282 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 18a0a1771289..1c36a6a9dd63 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -419,6 +419,8 @@ static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, /** * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce * filter is enabled. + * + * @hsotg: Programming view of DWC_otg controller */ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) { @@ -564,6 +566,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) * If a force is done, it requires a IDDIG debounce filter delay if * the filter is configured and enabled. We poll the current mode of * the controller to account for this delay. + * + * @hsotg: Programming view of DWC_otg controller + * @host: Host mode flag */ void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) { @@ -610,6 +615,8 @@ void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) * or not because the value of the connector ID status is affected by * the force mode. We only need to call this once during probe if * dr_mode == OTG. + * + * @hsotg: Programming view of DWC_otg controller */ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) { diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index d83be5651f87..4a56ac772a3c 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -164,12 +164,11 @@ struct dwc2_hsotg_req; * and has yet to be completed (maybe due to data move, or simply * awaiting an ack from the core all the data has been completed). * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. * @dir_in: Set to true if this endpoint is of the IN direction, which * means that it is sending data to the Host. * @index: The index for the endpoint registers. * @mc: Multi Count - number of transactions per microframe - * @interval - Interval for periodic endpoints, in frames or microframes. + * @interval: Interval for periodic endpoints, in frames or microframes. * @name: The name array passed to the USB core. * @halted: Set if the endpoint has been halted. * @periodic: Set if this is a periodic ep, such as Interrupt @@ -178,10 +177,11 @@ struct dwc2_hsotg_req; * @desc_list_dma: The DMA address of descriptor chain currently in use. * @desc_list: Pointer to descriptor DMA chain head currently in use. * @desc_count: Count of entries within the DMA descriptor chain of EP. - * @isoc_chain_num: Number of ISOC chain currently in use - either 0 or 1. * @next_desc: index of next free descriptor in the ISOC chain under SW control. + * @compl_desc: index of next descriptor to be completed by xFerComplete * @total_data: The total number of data bytes done. * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_index: For Dedicated FIFO operation, only FIFO0 can be used for EP0. * @fifo_load: The amount of data loaded into the FIFO (periodic IN) * @last_load: The offset of data for the last start of request. * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN @@ -231,8 +231,8 @@ struct dwc2_hsotg_ep { struct dwc2_dma_desc *desc_list; u8 desc_count; - unsigned char isoc_chain_num; unsigned int next_desc; + unsigned int compl_desc; char name[10]; }; @@ -380,6 +380,12 @@ enum dwc2_ep0_state { * is FS. * 0 - No (default) * 1 - Yes + * @ipg_isoc_en: Indicates the IPG supports is enabled or disabled. + * 0 - Disable (default) + * 1 - Enable + * @acg_enable: For enabling Active Clock Gating in the controller + * 0 - No + * 1 - Yes * @ulpi_fs_ls: Make ULPI phy operate in FS/LS mode only * 0 - No (default) * 1 - Yes @@ -511,6 +517,7 @@ struct dwc2_core_params { bool hird_threshold_en; u8 hird_threshold; bool activate_stm_fs_transceiver; + bool ipg_isoc_en; u16 max_packet_count; u32 max_transfer_size; u32 ahbcfg; @@ -548,7 +555,7 @@ struct dwc2_core_params { * * The values that are not in dwc2_core_params are documented below. * - * @op_mode Mode of Operation + * @op_mode: Mode of Operation * 0 - HNP- and SRP-Capable OTG (Host & Device) * 1 - SRP-Capable OTG (Host & Device) * 2 - Non-HNP and Non-SRP Capable OTG (Host & Device) @@ -556,43 +563,102 @@ struct dwc2_core_params { * 4 - Non-OTG Device * 5 - SRP-Capable Host * 6 - Non-OTG Host - * @arch Architecture + * @arch: Architecture * 0 - Slave only * 1 - External DMA * 2 - Internal DMA - * @power_optimized Are power optimizations enabled? - * @num_dev_ep Number of device endpoints available - * @num_dev_in_eps Number of device IN endpoints available - * @num_dev_perio_in_ep Number of device periodic IN endpoints - * available - * @dev_token_q_depth Device Mode IN Token Sequence Learning Queue + * @ipg_isoc_en: This feature indicates that the controller supports + * the worst-case scenario of Rx followed by Rx + * Interpacket Gap (IPG) (32 bitTimes) as per the utmi + * specification for any token following ISOC OUT token. + * 0 - Don't support + * 1 - Support + * @power_optimized: Are power optimizations enabled? + * @num_dev_ep: Number of device endpoints available + * @num_dev_in_eps: Number of device IN endpoints available + * @num_dev_perio_in_ep: Number of device periodic IN endpoints + * available + * @dev_token_q_depth: Device Mode IN Token Sequence Learning Queue * Depth * 0 to 30 - * @host_perio_tx_q_depth + * @host_perio_tx_q_depth: * Host Mode Periodic Request Queue Depth * 2, 4 or 8 - * @nperio_tx_q_depth + * @nperio_tx_q_depth: * Non-Periodic Request Queue Depth * 2, 4 or 8 - * @hs_phy_type High-speed PHY interface type + * @hs_phy_type: High-speed PHY interface type * 0 - High-speed interface not supported * 1 - UTMI+ * 2 - ULPI * 3 - UTMI+ and ULPI - * @fs_phy_type Full-speed PHY interface type + * @fs_phy_type: Full-speed PHY interface type * 0 - Full speed interface not supported * 1 - Dedicated full speed interface * 2 - FS pins shared with UTMI+ pins * 3 - FS pins shared with ULPI pins * @total_fifo_size: Total internal RAM for FIFOs (bytes) - * @hibernation Is hibernation enabled? - * @utmi_phy_data_width UTMI+ PHY data width + * @hibernation: Is hibernation enabled? + * @utmi_phy_data_width: UTMI+ PHY data width * 0 - 8 bits * 1 - 16 bits * 2 - 8 or 16 bits * @snpsid: Value from SNPSID register * @dev_ep_dirs: Direction of device endpoints (GHWCFG1) - * @g_tx_fifo_size[] Power-on values of TxFIFO sizes + * @g_tx_fifo_size: Power-on values of TxFIFO sizes + * @dma_desc_enable: When DMA mode is enabled, specifies whether to use + * address DMA mode or descriptor DMA mode for accessing + * the data FIFOs. The driver will automatically detect the + * value for this if none is specified. + * 0 - Address DMA + * 1 - Descriptor DMA (default, if available) + * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters + * 1 - Allow dynamic FIFO sizing (default, if available) + * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs + * are enabled for non-periodic IN endpoints in device + * mode. + * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO + * in host mode when dynamic FIFO sizing is enabled + * 16 to 32768 + * Actual maximum value is autodetected and also + * the default. + * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in + * host mode when dynamic FIFO sizing is enabled + * 16 to 32768 + * Actual maximum value is autodetected and also + * the default. + * @max_transfer_size: The maximum transfer size supported, in bytes + * 2047 to 65,535 + * Actual maximum value is autodetected and also + * the default. + * @max_packet_count: The maximum number of packets in a transfer + * 15 to 511 + * Actual maximum value is autodetected and also + * the default. + * @host_channels: The number of host channel registers to use + * 1 to 16 + * Actual maximum value is autodetected and also + * the default. + * @dev_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO + * in device mode when dynamic FIFO sizing is enabled + * 16 to 32768 + * Actual maximum value is autodetected and also + * the default. + * @i2c_enable: Specifies whether to use the I2Cinterface for a full + * speed PHY. This parameter is only applicable if phy_type + * is FS. + * 0 - No (default) + * 1 - Yes + * @acg_enable: For enabling Active Clock Gating in the controller + * 0 - Disable + * 1 - Enable + * @lpm_mode: For enabling Link Power Management in the controller + * 0 - Disable + * 1 - Enable + * @rx_fifo_size: Number of 4-byte words in the Rx FIFO when dynamic + * FIFO sizing is enabled 16 to 32768 + * Actual maximum value is autodetected and also + * the default. */ struct dwc2_hw_params { unsigned op_mode:3; @@ -622,6 +688,7 @@ struct dwc2_hw_params { unsigned hibernation:1; unsigned utmi_phy_data_width:2; unsigned lpm_mode:1; + unsigned ipg_isoc_en:1; u32 snpsid; u32 dev_ep_dirs; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; @@ -642,7 +709,11 @@ struct dwc2_hw_params { * @gi2cctl: Backup of GI2CCTL register * @glpmcfg: Backup of GLPMCFG register * @gdfifocfg: Backup of GDFIFOCFG register + * @pcgcctl: Backup of PCGCCTL register + * @pcgcctl1: Backup of PCGCCTL1 register + * @dtxfsiz: Backup of DTXFSIZ registers for each endpoint * @gpwrdn: Backup of GPWRDN register + * @valid: True if registers values backuped. */ struct dwc2_gregs_backup { u32 gotgctl; @@ -675,6 +746,7 @@ struct dwc2_gregs_backup { * @doeptsiz: Backup of DOEPTSIZ register * @doepdma: Backup of DOEPDMA register * @dtxfsiz: Backup of DTXFSIZ registers for each endpoint + * @valid: True if registers values backuped. */ struct dwc2_dregs_backup { u32 dcfg; @@ -698,9 +770,10 @@ struct dwc2_dregs_backup { * @hcfg: Backup of HCFG register * @haintmsk: Backup of HAINTMSK register * @hcintmsk: Backup of HCINTMSK register - * @hptr0: Backup of HPTR0 register + * @hprt0: Backup of HPTR0 register * @hfir: Backup of HFIR register * @hptxfsiz: Backup of HPTXFSIZ register + * @valid: True if registers values backuped. */ struct dwc2_hregs_backup { u32 hcfg; @@ -800,7 +873,7 @@ struct dwc2_hregs_backup { * @regs: Pointer to controller regs * @hw_params: Parameters that were autodetected from the * hardware registers - * @core_params: Parameters that define how the core should be configured + * @params: Parameters that define how the core should be configured * @op_state: The operational State, during transitions (a_host=> * a_peripheral and b_device=>b_host) this may not match * the core, but allows the software to determine @@ -809,10 +882,13 @@ struct dwc2_hregs_backup { * - USB_DR_MODE_PERIPHERAL * - USB_DR_MODE_HOST * - USB_DR_MODE_OTG - * @hcd_enabled Host mode sub-driver initialization indicator. - * @gadget_enabled Peripheral mode sub-driver initialization indicator. - * @ll_hw_enabled Status of low-level hardware resources. + * @hcd_enabled: Host mode sub-driver initialization indicator. + * @gadget_enabled: Peripheral mode sub-driver initialization indicator. + * @ll_hw_enabled: Status of low-level hardware resources. * @hibernated: True if core is hibernated + * @frame_number: Frame number read from the core. For both device + * and host modes. The value ranges are from 0 + * to HFNUM_MAX_FRNUM. * @phy: The otg phy transceiver structure for phy control. * @uphy: The otg phy transceiver structure for old USB phy * control. @@ -832,13 +908,25 @@ struct dwc2_hregs_backup { * interrupt * @wkp_timer: Timer object for handling Wakeup Detected interrupt * @lx_state: Lx state of connected device - * @gregs_backup: Backup of global registers during suspend - * @dregs_backup: Backup of device registers during suspend - * @hregs_backup: Backup of host registers during suspend + * @gr_backup: Backup of global registers during suspend + * @dr_backup: Backup of device registers during suspend + * @hr_backup: Backup of host registers during suspend * * These are for host mode: * * @flags: Flags for handling root port state changes + * @flags.d32: Contain all root port flags + * @flags.b: Separate root port flags from each other + * @flags.b.port_connect_status_change: True if root port connect status + * changed + * @flags.b.port_connect_status: True if device connected to root port + * @flags.b.port_reset_change: True if root port reset status changed + * @flags.b.port_enable_change: True if root port enable status changed + * @flags.b.port_suspend_change: True if root port suspend status changed + * @flags.b.port_over_current_change: True if root port over current state + * changed. + * @flags.b.port_l1_change: True if root port l1 status changed + * @flags.b.reserved: Reserved bits of root port register * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule. * Transfers associated with these QHs are not currently * assigned to a host channel. @@ -847,6 +935,9 @@ struct dwc2_hregs_backup { * assigned to a host channel. * @non_periodic_qh_ptr: Pointer to next QH to process in the active * non-periodic schedule + * @non_periodic_sched_waiting: Waiting QHs in the non-periodic schedule. + * Transfers associated with these QHs are not currently + * assigned to a host channel. * @periodic_sched_inactive: Inactive QHs in the periodic schedule. This is a * list of QHs for periodic transfers that are _not_ * scheduled for the next frame. Each QH in the list has an @@ -886,8 +977,6 @@ struct dwc2_hregs_backup { * @hs_periodic_bitmap: Bitmap used by the microframe scheduler any time the * host is in high speed mode; low speed schedules are * stored elsewhere since we need one per TT. - * @frame_number: Frame number read from the core at SOF. The value ranges - * from 0 to HFNUM_MAX_FRNUM. * @periodic_qh_count: Count of periodic QHs, if using several eps. Used for * SOF enable/disable. * @free_hc_list: Free host channels in the controller. This is a list of @@ -898,8 +987,8 @@ struct dwc2_hregs_backup { * host channel is available for non-periodic transactions. * @non_periodic_channels: Number of host channels assigned to non-periodic * transfers - * @available_host_channels Number of host channels available for the microframe - * scheduler to use + * @available_host_channels: Number of host channels available for the + * microframe scheduler to use * @hc_ptr_array: Array of pointers to the host channel descriptors. * Allows accessing a host channel descriptor given the * host channel number. This is useful in interrupt @@ -922,9 +1011,6 @@ struct dwc2_hregs_backup { * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. * @num_of_eps: Number of available EPs (excluding EP0) * @debug_root: Root directrory for debugfs. - * @debug_file: Main status file for debugfs. - * @debug_testmode: Testmode status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. * @ep0_reply: Request used for ep0 reply. * @ep0_buff: Buffer for EP0 reply data, if needed. * @ctrl_buff: Buffer for EP0 control requests. @@ -939,7 +1025,37 @@ struct dwc2_hregs_backup { * @ctrl_in_desc: EP0 IN data phase desc chain pointer * @ctrl_out_desc_dma: EP0 OUT data phase desc chain DMA address * @ctrl_out_desc: EP0 OUT data phase desc chain pointer - * @eps: The endpoints being supplied to the gadget framework + * @irq: Interrupt request line number + * @clk: Pointer to otg clock + * @reset: Pointer to dwc2 reset controller + * @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10. + * @regset: A pointer to a struct debugfs_regset32, which contains + * a pointer to an array of register definitions, the + * array size and the base address where the register bank + * is to be found. + * @bus_suspended: True if bus is suspended + * @last_frame_num: Number of last frame. Range from 0 to 32768 + * @frame_num_array: Used only if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is + * defined, for missed SOFs tracking. Array holds that + * frame numbers, which not equal to last_frame_num +1 + * @last_frame_num_array: Used only if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is + * defined, for missed SOFs tracking. + * If current_frame_number != last_frame_num+1 + * then last_frame_num added to this array + * @frame_num_idx: Actual size of frame_num_array and last_frame_num_array + * @dumped_frame_num_array: 1 - if missed SOFs frame numbers dumbed + * 0 - if missed SOFs frame numbers not dumbed + * @fifo_mem: Total internal RAM for FIFOs (bytes) + * @fifo_map: Each bit intend for concrete fifo. If that bit is set, + * then that fifo is used + * @gadget: Represents a usb slave device + * @connected: Used in slave mode. True if device connected with host + * @eps_in: The IN endpoints being supplied to the gadget framework + * @eps_out: The OUT endpoints being supplied to the gadget framework + * @new_connection: Used in host mode. True if there are new connected + * device + * @enabled: Indicates the enabling state of controller + * */ struct dwc2_hsotg { struct device *dev; @@ -954,6 +1070,7 @@ struct dwc2_hsotg { unsigned int gadget_enabled:1; unsigned int ll_hw_enabled:1; unsigned int hibernated:1; + u16 frame_number; struct phy *phy; struct usb_phy *uphy; @@ -985,6 +1102,7 @@ struct dwc2_hsotg { /* DWC OTG HW Release versions */ #define DWC2_CORE_REV_2_71a 0x4f54271a +#define DWC2_CORE_REV_2_72a 0x4f54272a #define DWC2_CORE_REV_2_80a 0x4f54280a #define DWC2_CORE_REV_2_90a 0x4f54290a #define DWC2_CORE_REV_2_91a 0x4f54291a @@ -992,6 +1110,7 @@ struct dwc2_hsotg { #define DWC2_CORE_REV_2_94a 0x4f54294a #define DWC2_CORE_REV_3_00a 0x4f54300a #define DWC2_CORE_REV_3_10a 0x4f54310a +#define DWC2_CORE_REV_4_00a 0x4f54400a #define DWC2_FS_IOT_REV_1_00a 0x5531100a #define DWC2_HS_IOT_REV_1_00a 0x5532100a @@ -1027,7 +1146,6 @@ struct dwc2_hsotg { u16 periodic_usecs; unsigned long hs_periodic_bitmap[ DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)]; - u16 frame_number; u16 periodic_qh_count; bool bus_suspended; bool new_connection; diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 2982a155734d..cc90b58b6b3c 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -778,6 +778,14 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) goto out; } + /* Reading current frame number value in device or host modes. */ + if (dwc2_is_device_mode(hsotg)) + hsotg->frame_number = (dwc2_readl(hsotg->regs + DSTS) + & DSTS_SOFFN_MASK) >> DSTS_SOFFN_SHIFT; + else + hsotg->frame_number = (dwc2_readl(hsotg->regs + HFNUM) + & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT; + gintsts = dwc2_read_common_intr(hsotg); if (gintsts & ~GINTSTS_PRTINT) retval = IRQ_HANDLED; diff --git a/drivers/usb/dwc2/debug.h b/drivers/usb/dwc2/debug.h index 6f23219c13cb..a8c565b6bc34 100644 --- a/drivers/usb/dwc2/debug.h +++ b/drivers/usb/dwc2/debug.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * debug.h - Designware USB2 DRD controller debug header * * Copyright (C) 2015 Intel Corporation diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 58c691f882a8..d0bdb7997557 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * debugfs.c - Designware USB2 DRD controller debugfs * * Copyright (C) 2015 Intel Corporation @@ -16,12 +16,13 @@ #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) + /** - * testmode_write - debugfs: change usb test mode - * @seq: The seq file to write to. - * @v: Unused parameter. - * - * This debugfs entry modify the current usb test mode. + * testmode_write() - change usb test mode state. + * @file: The file to write to. + * @ubuf: The buffer where user wrote. + * @count: The ubuf size. + * @ppos: Unused parameter. */ static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) @@ -55,9 +56,9 @@ static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t } /** - * testmode_show - debugfs: show usb test mode state - * @seq: The seq file to write to. - * @v: Unused parameter. + * testmode_show() - debugfs: show usb test mode state + * @s: The seq file to write to. + * @unused: Unused parameter. * * This debugfs entry shows which usb test mode is currently enabled. */ @@ -293,52 +294,30 @@ DEFINE_SHOW_ATTRIBUTE(ep); static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) { struct dentry *root; - struct dentry *file; unsigned int epidx; root = hsotg->debug_root; /* create general state file */ - - file = debugfs_create_file("state", 0444, root, hsotg, &state_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create state\n", __func__); - - file = debugfs_create_file("testmode", 0644, root, hsotg, - &testmode_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create testmode\n", - __func__); - - file = debugfs_create_file("fifo", 0444, root, hsotg, &fifo_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); + debugfs_create_file("state", 0444, root, hsotg, &state_fops); + debugfs_create_file("testmode", 0644, root, hsotg, &testmode_fops); + debugfs_create_file("fifo", 0444, root, hsotg, &fifo_fops); /* Create one file for each out endpoint */ for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { struct dwc2_hsotg_ep *ep; ep = hsotg->eps_out[epidx]; - if (ep) { - file = debugfs_create_file(ep->name, 0444, - root, ep, &ep_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "failed to create %s debug file\n", - ep->name); - } + if (ep) + debugfs_create_file(ep->name, 0444, root, ep, &ep_fops); } /* Create one file for each in endpoint. EP0 is handled with out eps */ for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) { struct dwc2_hsotg_ep *ep; ep = hsotg->eps_in[epidx]; - if (ep) { - file = debugfs_create_file(ep->name, 0444, - root, ep, &ep_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "failed to create %s debug file\n", - ep->name); - } + if (ep) + debugfs_create_file(ep->name, 0444, root, ep, &ep_fops); } } #else @@ -368,7 +347,7 @@ static const struct debugfs_reg32 dwc2_regs[] = { dump_register(GINTSTS), dump_register(GINTMSK), dump_register(GRXSTSR), - dump_register(GRXSTSP), + /* Omit GRXSTSP */ dump_register(GRXFSIZ), dump_register(GNPTXFSIZ), dump_register(GNPTXSTS), @@ -710,6 +689,7 @@ static int params_show(struct seq_file *seq, void *v) print_param(seq, p, phy_ulpi_ddr); print_param(seq, p, phy_ulpi_ext_vbus); print_param(seq, p, i2c_enable); + print_param(seq, p, ipg_isoc_en); print_param(seq, p, ulpi_fs_ls); print_param(seq, p, host_support_fs_ls_low_power); print_param(seq, p, host_ls_low_power_phy_clk); @@ -790,32 +770,14 @@ DEFINE_SHOW_ATTRIBUTE(dr_mode); int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { int ret; - struct dentry *file; + struct dentry *root; - hsotg->debug_root = debugfs_create_dir(dev_name(hsotg->dev), NULL); - if (!hsotg->debug_root) { - ret = -ENOMEM; - goto err0; - } + root = debugfs_create_dir(dev_name(hsotg->dev), NULL); + hsotg->debug_root = root; - file = debugfs_create_file("params", 0444, - hsotg->debug_root, - hsotg, ¶ms_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create params\n", __func__); - - file = debugfs_create_file("hw_params", 0444, - hsotg->debug_root, - hsotg, &hw_params_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create hw_params\n", - __func__); - - file = debugfs_create_file("dr_mode", 0444, - hsotg->debug_root, - hsotg, &dr_mode_fops); - if (IS_ERR(file)) - dev_err(hsotg->dev, "%s: failed to create dr_mode\n", __func__); + debugfs_create_file("params", 0444, root, hsotg, ¶ms_fops); + debugfs_create_file("hw_params", 0444, root, hsotg, &hw_params_fops); + debugfs_create_file("dr_mode", 0444, root, hsotg, &dr_mode_fops); /* Add gadget debugfs nodes */ dwc2_hsotg_create_debug(hsotg); @@ -824,24 +786,18 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) GFP_KERNEL); if (!hsotg->regset) { ret = -ENOMEM; - goto err1; + goto err; } hsotg->regset->regs = dwc2_regs; hsotg->regset->nregs = ARRAY_SIZE(dwc2_regs); hsotg->regset->base = hsotg->regs; - file = debugfs_create_regset32("regdump", 0444, hsotg->debug_root, - hsotg->regset); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_regset32("regdump", 0444, root, hsotg->regset); return 0; -err1: +err: debugfs_remove_recursive(hsotg->debug_root); -err0: return ret; } diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 6c32bf26e48e..f0d9ccf1d665 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * @@ -107,7 +107,6 @@ static inline bool using_desc_dma(struct dwc2_hsotg *hsotg) /** * dwc2_gadget_incr_frame_num - Increments the targeted frame number. * @hs_ep: The endpoint - * @increment: The value to increment by * * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. * If an overrun occurs it will wrap the value and set the frame_overrun flag. @@ -190,6 +189,8 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, /** * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode + * + * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) { @@ -204,6 +205,8 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) /** * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for * device mode TX FIFOs + * + * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) { @@ -227,6 +230,8 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) /** * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode * TX FIFOs + * + * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) { @@ -327,6 +332,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) } /** + * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure * @ep: USB endpoint to allocate request for. * @flags: Allocation flags * @@ -793,9 +799,7 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, * @dma_buff: usb requests dma buffer. * @len: usb request transfer length. * - * Finds out index of first free entry either in the bottom or up half of - * descriptor chain depend on which is under SW control and not processed - * by HW. Then fills that descriptor with the data of the arrived usb request, + * Fills next free descriptor with the data of the arrived usb request, * frame info, sets Last and IOC bits increments next_desc. If filled * descriptor is not the first one, removes L bit from the previous descriptor * status. @@ -810,34 +814,17 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, u32 mask = 0; maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); - if (len > maxsize) { - dev_err(hsotg->dev, "wrong len %d\n", len); - return -EINVAL; - } - - /* - * If SW has already filled half of chain, then return and wait for - * the other chain to be processed by HW. - */ - if (hs_ep->next_desc == MAX_DMA_DESC_NUM_GENERIC / 2) - return -EBUSY; - - /* Increment frame number by interval for IN */ - if (hs_ep->dir_in) - dwc2_gadget_incr_frame_num(hs_ep); - index = (MAX_DMA_DESC_NUM_GENERIC / 2) * hs_ep->isoc_chain_num + - hs_ep->next_desc; + index = hs_ep->next_desc; + desc = &hs_ep->desc_list[index]; - /* Sanity check of calculated index */ - if ((hs_ep->isoc_chain_num && index > MAX_DMA_DESC_NUM_GENERIC) || - (!hs_ep->isoc_chain_num && index > MAX_DMA_DESC_NUM_GENERIC / 2)) { - dev_err(hsotg->dev, "wrong index %d for iso chain\n", index); - return -EINVAL; + /* Check if descriptor chain full */ + if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) == + DEV_DMA_BUFF_STS_HREADY) { + dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); + return 1; } - desc = &hs_ep->desc_list[index]; - /* Clear L bit of previous desc if more than one entries in the chain */ if (hs_ep->next_desc) hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; @@ -865,8 +852,14 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, desc->status &= ~DEV_DMA_BUFF_STS_MASK; desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); + /* Increment frame number by interval for IN */ + if (hs_ep->dir_in) + dwc2_gadget_incr_frame_num(hs_ep); + /* Update index of last configured entry in the chain */ hs_ep->next_desc++; + if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_GENERIC) + hs_ep->next_desc = 0; return 0; } @@ -875,11 +868,8 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA * @hs_ep: The isochronous endpoint. * - * Prepare first descriptor chain for isochronous endpoints. Afterwards + * Prepare descriptor chain for isochronous endpoints. Afterwards * write DMA address to HW and enable the endpoint. - * - * Switch between descriptor chains via isoc_chain_num to give SW opportunity - * to prepare second descriptor chain while first one is being processed by HW. */ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) { @@ -887,24 +877,34 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) struct dwc2_hsotg_req *hs_req, *treq; int index = hs_ep->index; int ret; + int i; u32 dma_reg; u32 depctl; u32 ctrl; + struct dwc2_dma_desc *desc; if (list_empty(&hs_ep->queue)) { dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); return; } + /* Initialize descriptor chain by Host Busy status */ + for (i = 0; i < MAX_DMA_DESC_NUM_GENERIC; i++) { + desc = &hs_ep->desc_list[i]; + desc->status = 0; + desc->status |= (DEV_DMA_BUFF_STS_HBUSY + << DEV_DMA_BUFF_STS_SHIFT); + } + + hs_ep->next_desc = 0; list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, hs_req->req.length); - if (ret) { - dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); + if (ret) break; - } } + hs_ep->compl_desc = 0; depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); @@ -914,10 +914,6 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) ctrl = dwc2_readl(hsotg->regs + depctl); ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; dwc2_writel(ctrl, hsotg->regs + depctl); - - /* Switch ISOC descriptor chain number being processed by SW*/ - hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1; - hs_ep->next_desc = 0; } /** @@ -1235,7 +1231,7 @@ static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; u32 target_frame = hs_ep->target_frame; - u32 current_frame = dwc2_hsotg_read_frameno(hsotg); + u32 current_frame = hsotg->frame_number; bool frame_overrun = hs_ep->frame_overrun; if (!frame_overrun && current_frame >= target_frame) @@ -1291,6 +1287,9 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, struct dwc2_hsotg *hs = hs_ep->parent; bool first; int ret; + u32 maxsize = 0; + u32 mask = 0; + dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", ep->name, req, req->length, req->buf, req->no_interrupt, @@ -1308,6 +1307,24 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, req->actual = 0; req->status = -EINPROGRESS; + /* In DDMA mode for ISOC's don't queue request if length greater + * than descriptor limits. + */ + if (using_desc_dma(hs) && hs_ep->isochronous) { + maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); + if (hs_ep->dir_in && req->length > maxsize) { + dev_err(hs->dev, "wrong length %d (maxsize=%d)\n", + req->length, maxsize); + return -EINVAL; + } + + if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) { + dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n", + req->length, hs_ep->ep.maxpacket); + return -EINVAL; + } + } + ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); if (ret) return ret; @@ -1330,17 +1347,15 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, /* * Handle DDMA isochronous transfers separately - just add new entry - * to the half of descriptor chain that is not processed by HW. + * to the descriptor chain. * Transfer will be started once SW gets either one of NAK or * OutTknEpDis interrupts. */ - if (using_desc_dma(hs) && hs_ep->isochronous && - hs_ep->target_frame != TARGET_FRAME_INITIAL) { - ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, - hs_req->req.length); - if (ret) - dev_dbg(hs->dev, "%s: ISO desc chain full\n", __func__); - + if (using_desc_dma(hs) && hs_ep->isochronous) { + if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { + dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + hs_req->req.length); + } return 0; } @@ -1350,8 +1365,15 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, return 0; } - while (dwc2_gadget_target_frame_elapsed(hs_ep)) + /* Update current frame number value. */ + hs->frame_number = dwc2_hsotg_read_frameno(hs); + while (dwc2_gadget_target_frame_elapsed(hs_ep)) { dwc2_gadget_incr_frame_num(hs_ep); + /* Update current frame number value once more as it + * changes here. + */ + hs->frame_number = dwc2_hsotg_read_frameno(hs); + } if (hs_ep->target_frame != TARGET_FRAME_INITIAL) dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); @@ -2011,108 +2033,75 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, * @hs_ep: The endpoint the request was on. * * Get first request from the ep queue, determine descriptor on which complete - * happened. SW based on isoc_chain_num discovers which half of the descriptor - * chain is currently in use by HW, adjusts dma_address and calculates index - * of completed descriptor based on the value of DEPDMA register. Update actual - * length of request, giveback to gadget. + * happened. SW discovers which descriptor currently in use by HW, adjusts + * dma_address and calculates index of completed descriptor based on the value + * of DEPDMA register. Update actual length of request, giveback to gadget. */ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; struct dwc2_hsotg_req *hs_req; struct usb_request *ureq; - int index; - dma_addr_t dma_addr; - u32 dma_reg; - u32 depdma; u32 desc_sts; u32 mask; - hs_req = get_ep_head(hs_ep); - if (!hs_req) { - dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); - return; - } - ureq = &hs_req->req; - - dma_addr = hs_ep->desc_list_dma; - - /* - * If lower half of descriptor chain is currently use by SW, - * that means higher half is being processed by HW, so shift - * DMA address to higher half of descriptor chain. - */ - if (!hs_ep->isoc_chain_num) - dma_addr += sizeof(struct dwc2_dma_desc) * - (MAX_DMA_DESC_NUM_GENERIC / 2); - - dma_reg = hs_ep->dir_in ? DIEPDMA(hs_ep->index) : DOEPDMA(hs_ep->index); - depdma = dwc2_readl(hsotg->regs + dma_reg); + desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; - index = (depdma - dma_addr) / sizeof(struct dwc2_dma_desc) - 1; - desc_sts = hs_ep->desc_list[index].status; + /* Process only descriptors with buffer status set to DMA done */ + while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >> + DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) { - mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : - DEV_DMA_ISOC_RX_NBYTES_MASK; - ureq->actual = ureq->length - - ((desc_sts & mask) >> DEV_DMA_ISOC_NBYTES_SHIFT); + hs_req = get_ep_head(hs_ep); + if (!hs_req) { + dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); + return; + } + ureq = &hs_req->req; + + /* Check completion status */ + if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT == + DEV_DMA_STS_SUCC) { + mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : + DEV_DMA_ISOC_RX_NBYTES_MASK; + ureq->actual = ureq->length - ((desc_sts & mask) >> + DEV_DMA_ISOC_NBYTES_SHIFT); + + /* Adjust actual len for ISOC Out if len is + * not align of 4 + */ + if (!hs_ep->dir_in && ureq->length & 0x3) + ureq->actual += 4 - (ureq->length & 0x3); + } - /* Adjust actual length for ISOC Out if length is not align of 4 */ - if (!hs_ep->dir_in && ureq->length & 0x3) - ureq->actual += 4 - (ureq->length & 0x3); + dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); - dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); + hs_ep->compl_desc++; + if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_GENERIC - 1)) + hs_ep->compl_desc = 0; + desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; + } } /* - * dwc2_gadget_start_next_isoc_ddma - start next isoc request, if any. - * @hs_ep: The isochronous endpoint to be re-enabled. + * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. + * @hs_ep: The isochronous endpoint. * - * If ep has been disabled due to last descriptor servicing (IN endpoint) or - * BNA (OUT endpoint) check the status of other half of descriptor chain that - * was under SW control till HW was busy and restart the endpoint if needed. + * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA + * interrupt. Reset target frame and next_desc to allow to start + * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS + * interrupt for OUT direction. */ -static void dwc2_gadget_start_next_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) +static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; - u32 depctl; - u32 dma_reg; - u32 ctrl; - u32 dma_addr = hs_ep->desc_list_dma; - unsigned char index = hs_ep->index; - - dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); - depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); - ctrl = dwc2_readl(hsotg->regs + depctl); + if (!hs_ep->dir_in) + dwc2_flush_rx_fifo(hsotg); + dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0); - /* - * EP was disabled if HW has processed last descriptor or BNA was set. - * So restart ep if SW has prepared new descriptor chain in ep_queue - * routine while HW was busy. - */ - if (!(ctrl & DXEPCTL_EPENA)) { - if (!hs_ep->next_desc) { - dev_dbg(hsotg->dev, "%s: No more ISOC requests\n", - __func__); - return; - } - - dma_addr += sizeof(struct dwc2_dma_desc) * - (MAX_DMA_DESC_NUM_GENERIC / 2) * - hs_ep->isoc_chain_num; - dwc2_writel(dma_addr, hsotg->regs + dma_reg); - - ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; - dwc2_writel(ctrl, hsotg->regs + depctl); - - /* Switch ISOC descriptor chain number being processed by SW*/ - hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1; - hs_ep->next_desc = 0; - - dev_dbg(hsotg->dev, "%s: Restarted isochronous endpoint\n", - __func__); - } + hs_ep->target_frame = TARGET_FRAME_INITIAL; + hs_ep->next_desc = 0; + hs_ep->compl_desc = 0; } /** @@ -2441,6 +2430,7 @@ static u32 dwc2_hsotg_ep0_mps(unsigned int mps) * @ep: The index number of the endpoint * @mps: The maximum packet size in bytes * @mc: The multicount value + * @dir_in: True if direction is in. * * Configure the maximum packet size for the given endpoint, updating * the hardware control registers to reflect this. @@ -2731,6 +2721,8 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); dwc2_gadget_incr_frame_num(hs_ep); + /* Update current frame number value. */ + hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); } while (dwc2_gadget_target_frame_elapsed(hs_ep)); dwc2_gadget_start_next_request(hs_ep); @@ -2738,7 +2730,7 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) /** * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS - * @hs_ep: The endpoint on which interrupt is asserted. + * @ep: The endpoint on which interrupt is asserted. * * This is starting point for ISOC-OUT transfer, synchronization done with * first out token received from host while corresponding EP is disabled. @@ -2763,7 +2755,7 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) */ tmp = dwc2_hsotg_read_frameno(hsotg); - dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA); + dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), 0); if (using_desc_dma(hsotg)) { if (ep->target_frame == TARGET_FRAME_INITIAL) { @@ -2816,18 +2808,25 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; + u32 tmp; if (!dir_in || !hs_ep->isochronous) return; if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { - hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); + tmp = dwc2_hsotg_read_frameno(hsotg); if (using_desc_dma(hsotg)) { + dwc2_hsotg_complete_request(hsotg, hs_ep, + get_ep_head(hs_ep), 0); + + hs_ep->target_frame = tmp; + dwc2_gadget_incr_frame_num(hs_ep); dwc2_gadget_start_isoc_ddma(hs_ep); return; } + hs_ep->target_frame = tmp; if (hs_ep->interval > 1) { u32 ctrl = dwc2_readl(hsotg->regs + DIEPCTL(hs_ep->index)); @@ -2843,7 +2842,8 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) get_ep_head(hs_ep), 0); } - dwc2_gadget_incr_frame_num(hs_ep); + if (!using_desc_dma(hsotg)) + dwc2_gadget_incr_frame_num(hs_ep); } /** @@ -2901,9 +2901,9 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, /* In DDMA handle isochronous requests separately */ if (using_desc_dma(hsotg) && hs_ep->isochronous) { - dwc2_gadget_complete_isoc_request_ddma(hs_ep); - /* Try to start next isoc request */ - dwc2_gadget_start_next_isoc_ddma(hs_ep); + /* XferCompl set along with BNA */ + if (!(ints & DXEPINT_BNAINTR)) + dwc2_gadget_complete_isoc_request_ddma(hs_ep); } else if (dir_in) { /* * We get OutDone from the FIFO, so we only @@ -2978,15 +2978,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (ints & DXEPINT_BNAINTR) { dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); - - /* - * Try to start next isoc request, if any. - * Sometimes the endpoint remains enabled after BNA interrupt - * assertion, which is not expected, hence we can enter here - * couple of times. - */ if (hs_ep->isochronous) - dwc2_gadget_start_next_isoc_ddma(hs_ep); + dwc2_gadget_handle_isoc_bna(hs_ep); } if (dir_in && !hs_ep->isochronous) { @@ -3197,6 +3190,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) /** * dwc2_hsotg_core_init - issue softreset to the core * @hsotg: The device state + * @is_usb_reset: Usb resetting flag * * Issue a soft reset to the core, and await the core finishing it. */ @@ -3259,6 +3253,9 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dcfg |= DCFG_DEVSPD_HS; } + if (hsotg->params.ipg_isoc_en) + dcfg |= DCFG_IPG_ISOC_SUPPORDED; + dwc2_writel(dcfg, hsotg->regs + DCFG); /* Clear any pending OTG interrupts */ @@ -3320,8 +3317,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, hsotg->regs + DOEPMSK); /* Enable BNA interrupt for DDMA */ - if (using_desc_dma(hsotg)) + if (using_desc_dma(hsotg)) { dwc2_set_bit(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK); + dwc2_set_bit(hsotg->regs + DIEPMSK, DIEPMSK_BNAININTRMSK); + } dwc2_writel(0, hsotg->regs + DAINTMSK); @@ -3427,7 +3426,7 @@ static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); - for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + for (idx = 1; idx < hsotg->num_of_eps; idx++) { hs_ep = hsotg->eps_in[idx]; /* Proceed only unmasked ISOC EPs */ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) @@ -3473,7 +3472,7 @@ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) daintmsk = dwc2_readl(hsotg->regs + DAINTMSK); daintmsk >>= DAINT_OUTEP_SHIFT; - for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + for (idx = 1; idx < hsotg->num_of_eps; idx++) { hs_ep = hsotg->eps_out[idx]; /* Proceed only unmasked ISOC EPs */ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) @@ -3647,7 +3646,7 @@ irq_retry: dwc2_writel(gintmsk, hsotg->regs + GINTMSK); dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); - for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + for (idx = 1; idx < hsotg->num_of_eps; idx++) { hs_ep = hsotg->eps_out[idx]; /* Proceed only unmasked ISOC EPs */ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk)) @@ -3789,6 +3788,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, unsigned int dir_in; unsigned int i, val, size; int ret = 0; + unsigned char ep_type; dev_dbg(hsotg->dev, "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", @@ -3807,9 +3807,26 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, return -EINVAL; } + ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; mps = usb_endpoint_maxp(desc); mc = usb_endpoint_maxp_mult(desc); + /* ISOC IN in DDMA supported bInterval up to 10 */ + if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && + dir_in && desc->bInterval > 10) { + dev_err(hsotg->dev, + "%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__); + return -EINVAL; + } + + /* High bandwidth ISOC OUT in DDMA not supported */ + if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && + !dir_in && mc > 1) { + dev_err(hsotg->dev, + "%s: ISOC OUT, DDMA: HB not supported!\n", __func__); + return -EINVAL; + } + /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); @@ -3850,15 +3867,15 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, hs_ep->halted = 0; hs_ep->interval = desc->bInterval; - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (ep_type) { case USB_ENDPOINT_XFER_ISOC: epctrl |= DXEPCTL_EPTYPE_ISO; epctrl |= DXEPCTL_SETEVENFR; hs_ep->isochronous = 1; hs_ep->interval = 1 << (desc->bInterval - 1); hs_ep->target_frame = TARGET_FRAME_INITIAL; - hs_ep->isoc_chain_num = 0; hs_ep->next_desc = 0; + hs_ep->compl_desc = 0; if (dir_in) { hs_ep->periodic = 1; mask = dwc2_readl(hsotg->regs + DIEPMSK); @@ -3928,6 +3945,27 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, if (index && !hs_ep->isochronous) epctrl |= DXEPCTL_SETD0PID; + /* WA for Full speed ISOC IN in DDMA mode. + * By Clear NAK status of EP, core will send ZLP + * to IN token and assert NAK interrupt relying + * on TxFIFO status only + */ + + if (hsotg->gadget.speed == USB_SPEED_FULL && + hs_ep->isochronous && dir_in) { + /* The WA applies only to core versions from 2.72a + * to 4.00a (including both). Also for FS_IOT_1.00a + * and HS_IOT_1.00a. + */ + u32 gsnpsid = dwc2_readl(hsotg->regs + GSNPSID); + + if ((gsnpsid >= DWC2_CORE_REV_2_72a && + gsnpsid <= DWC2_CORE_REV_4_00a) || + gsnpsid == DWC2_FS_IOT_REV_1_00a || + gsnpsid == DWC2_HS_IOT_REV_1_00a) + epctrl |= DXEPCTL_CNAK; + } + dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", __func__, epctrl); @@ -4280,7 +4318,6 @@ err: /** * dwc2_hsotg_udc_stop - stop the udc * @gadget: The usb gadget state - * @driver: The usb gadget driver * * Stop udc hw block and stay tunned for future transmissions */ @@ -4432,6 +4469,7 @@ static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { * @hsotg: The device state. * @hs_ep: The endpoint to be initialised. * @epnum: The endpoint number + * @dir_in: True if direction is in. * * Initialise the given endpoint (as part of the probe and device state * creation) to give to the gadget driver. Setup the endpoint name, any @@ -4505,7 +4543,7 @@ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, /** * dwc2_hsotg_hw_cfg - read HW configuration registers - * @param: The device state + * @hsotg: Programming view of the DWC_otg controller * * Read the USB core HW configuration registers */ @@ -4561,7 +4599,8 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) /** * dwc2_hsotg_dump - dump state of the udc - * @param: The device state + * @hsotg: Programming view of the DWC_otg controller + * */ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) { @@ -4612,7 +4651,8 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) /** * dwc2_gadget_init - init function for gadget - * @dwc2: The data structure for the DWC2 driver. + * @hsotg: Programming view of the DWC_otg controller + * */ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) { @@ -4709,7 +4749,8 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) /** * dwc2_hsotg_remove - remove function for hsotg driver - * @pdev: The platform information for the driver + * @hsotg: Programming view of the DWC_otg controller + * */ int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) { @@ -4990,7 +5031,7 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) * * @hsotg: Programming view of the DWC_otg controller * @rem_wakeup: indicates whether resume is initiated by Device or Host. - * @param reset: indicates whether resume is initiated by Reset. + * @reset: indicates whether resume is initiated by Reset. * * Return non-zero if failed to exit from hibernation. */ diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 190f95964000..1faefea16cec 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -358,9 +358,14 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) { + int ret; + hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); - if (IS_ERR(hsotg->vbus_supply)) - return 0; + if (IS_ERR(hsotg->vbus_supply)) { + ret = PTR_ERR(hsotg->vbus_supply); + hsotg->vbus_supply = NULL; + return ret == -ENODEV ? 0 : ret; + } return regulator_enable(hsotg->vbus_supply); } @@ -592,7 +597,7 @@ u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg) * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination * buffer * - * @core_if: Programming view of DWC_otg controller + * @hsotg: Programming view of DWC_otg controller * @dest: Destination buffer for the packet * @bytes: Number of bytes to copy to the destination */ @@ -4082,7 +4087,6 @@ static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) * then the refcount for the structure will go to 0 and we'll free it. * * @hsotg: The HCD state structure for the DWC OTG controller. - * @qh: The QH structure. * @context: The priv pointer from a struct dwc2_hcd_urb. * @mem_flags: Flags for allocating memory. * @ttport: We'll return this device's port number here. That's used to @@ -4342,9 +4346,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) spin_unlock_irqrestore(&hsotg->lock, flags); - dwc2_vbus_supply_init(hsotg); - - return 0; + return dwc2_vbus_supply_init(hsotg); } /* diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 96a9da5fb202..7db1ee7e7a77 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -80,7 +80,7 @@ struct dwc2_qh; * @xfer_count: Number of bytes transferred so far * @start_pkt_count: Packet count at start of transfer * @xfer_started: True if the transfer has been started - * @ping: True if a PING request should be issued on this channel + * @do_ping: True if a PING request should be issued on this channel * @error_state: True if the error count for this transaction is non-zero * @halt_on_queue: True if this channel should be halted the next time a * request is queued for the channel. This is necessary in @@ -102,7 +102,7 @@ struct dwc2_qh; * @schinfo: Scheduling micro-frame bitmap * @ntd: Number of transfer descriptors for the transfer * @halt_status: Reason for halting the host channel - * @hcint Contents of the HCINT register when the interrupt came + * @hcint: Contents of the HCINT register when the interrupt came * @qh: QH for the transfer being processed by this channel * @hc_list_entry: For linking to list of host channels * @desc_list_addr: Current QH's descriptor list DMA address @@ -237,7 +237,7 @@ struct dwc2_tt { /** * struct dwc2_hs_transfer_time - Info about a transfer on the high speed bus. * - * @start_schedule_usecs: The start time on the main bus schedule. Note that + * @start_schedule_us: The start time on the main bus schedule. Note that * the main bus schedule is tightly packed and this * time should be interpreted as tightly packed (so * uFrame 0 starts at 0 us, uFrame 1 starts at 100 us @@ -301,7 +301,6 @@ struct dwc2_hs_transfer_time { * "struct dwc2_tt". Not used if this device is high * speed. Note that this is in "schedule slice" which * is tightly packed. - * @ls_duration_us: Duration on the low speed bus schedule. * @ntd: Actual number of transfer descriptors in a list * @qtd_list: List of QTDs for this QH * @channel: Host channel currently processing transfers for this QH @@ -315,7 +314,7 @@ struct dwc2_hs_transfer_time { * descriptor * @unreserve_timer: Timer for releasing periodic reservation. * @wait_timer: Timer used to wait before re-queuing. - * @dwc2_tt: Pointer to our tt info (or NULL if no tt). + * @dwc_tt: Pointer to our tt info (or NULL if no tt). * @ttport: Port number within our tt. * @tt_buffer_dirty True if clear_tt_buffer_complete is pending * @unreserve_pending: True if we planned to unreserve but haven't yet. @@ -325,6 +324,7 @@ struct dwc2_hs_transfer_time { * periodic transfers and is ignored for periodic ones. * @wait_timer_cancel: Set to true to cancel the wait_timer. * + * @tt_buffer_dirty: True if EP's TT buffer is not clean. * A Queue Head (QH) holds the static characteristics of an endpoint and * maintains a list of transfers (QTDs) for that endpoint. A QH structure may * be entered in either the non-periodic or periodic schedule. @@ -400,6 +400,10 @@ struct dwc2_qh { * @urb: URB for this transfer * @qh: Queue head for this QTD * @qtd_list_entry: For linking to the QH's list of QTDs + * @isoc_td_first: Index of first activated isochronous transfer + * descriptor in Descriptor DMA mode + * @isoc_td_last: Index of last activated isochronous transfer + * descriptor in Descriptor DMA mode * * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, * interrupt, or isochronous transfer. A single QTD is created for each URB diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c index 28c8898b3b66..74f11c823f79 100644 --- a/drivers/usb/dwc2/hcd_ddma.c +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -332,6 +332,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, * * @hsotg: The HCD state structure for the DWC OTG controller * @qh: The QH to init + * @mem_flags: Indicates the type of memory allocation * * Return: 0 if successful, negative error code otherwise * diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index a5dfd9d8bd9a..fbea5e3fb947 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -478,6 +478,12 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg, * of the URB based on the number of bytes transferred via the host channel. * Sets the URB status if the data transfer is finished. * + * @hsotg: Programming view of the DWC_otg controller + * @chan: Programming view of host channel + * @chnum: Channel number + * @urb: Processing URB + * @qtd: Queue transfer descriptor + * * Return: 1 if the data transfer specified by the URB is completely finished, * 0 otherwise */ @@ -566,6 +572,12 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, * halt_status. Completes the Isochronous URB if all the URB frames have been * completed. * + * @hsotg: Programming view of the DWC_otg controller + * @chan: Programming view of host channel + * @chnum: Channel number + * @halt_status: Reason for halting a host channel + * @qtd: Queue transfer descriptor + * * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE. */ diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index e34ad5e65350..d7c3d6c776d8 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -679,6 +679,7 @@ static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * * @hsotg: The HCD state structure for the DWC OTG controller. * @qh: QH for the periodic transfer. + * @index: Transfer index */ static void dwc2_hs_pmap_unschedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, int index) @@ -1276,7 +1277,7 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * release the reservation. This worker is called after the appropriate * delay. * - * @work: Pointer to a qh unreserve_work. + * @t: Address to a qh unreserve_work. */ static void dwc2_unreserve_timer_fn(struct timer_list *t) { @@ -1631,7 +1632,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * @hsotg: The HCD state structure for the DWC OTG controller * @urb: Holds the information about the device/endpoint needed * to initialize the QH - * @atomic_alloc: Flag to do atomic allocation if needed + * @mem_flags: Flags for allocating memory. * * Return: Pointer to the newly allocated QH, or NULL on error */ diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 38391e48351f..0ca8e7bc7aaf 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -311,6 +311,7 @@ #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 #define GHWCFG4_ACG_SUPPORTED BIT(12) +#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 @@ -424,6 +425,7 @@ #define DCFG_EPMISCNT_SHIFT 18 #define DCFG_EPMISCNT_LIMIT 0x1f #define DCFG_EPMISCNT(_x) ((_x) << 18) +#define DCFG_IPG_ISOC_SUPPORDED BIT(17) #define DCFG_PERFRINT_MASK (0x3 << 11) #define DCFG_PERFRINT_SHIFT 11 #define DCFG_PERFRINT_LIMIT 0x3 diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index f03e41879224..af075d4da895 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -70,6 +70,7 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) GAHBCFG_HBSTLEN_SHIFT; p->uframe_sched = false; p->change_speed_quirk = true; + p->power_down = false; } static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) @@ -269,6 +270,9 @@ static void dwc2_set_param_power_down(struct dwc2_hsotg *hsotg) /** * dwc2_set_default_params() - Set all core parameters to their * auto-detected default values. + * + * @hsotg: Programming view of the DWC_otg controller + * */ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) { @@ -298,6 +302,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) p->besl = true; p->hird_threshold_en = true; p->hird_threshold = 4; + p->ipg_isoc_en = false; p->max_packet_count = hw->max_packet_count; p->max_transfer_size = hw->max_transfer_size; p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; @@ -338,6 +343,8 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) /** * dwc2_get_device_properties() - Read in device properties. * + * @hsotg: Programming view of the DWC_otg controller + * * Read in the device properties and adjust core parameters if needed. */ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) @@ -549,7 +556,7 @@ static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) } #define CHECK_RANGE(_param, _min, _max, _def) do { \ - if ((hsotg->params._param) < (_min) || \ + if ((int)(hsotg->params._param) < (_min) || \ (hsotg->params._param) > (_max)) { \ dev_warn(hsotg->dev, "%s: Invalid parameter %s=%d\n", \ __func__, #_param, hsotg->params._param); \ @@ -579,6 +586,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo); CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo); CHECK_BOOL(i2c_enable, hw->i2c_enable); + CHECK_BOOL(ipg_isoc_en, hw->ipg_isoc_en); CHECK_BOOL(acg_enable, hw->acg_enable); CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a)); CHECK_BOOL(lpm, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_80a)); @@ -688,6 +696,9 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg) /** * During device initialization, read various hardware configuration * registers and interpret the contents. + * + * @hsotg: Programming view of the DWC_otg controller + * */ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) { @@ -772,6 +783,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >> GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); + hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); /* fifo sizes */ hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index 7f21747007f1..d257c541e51b 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -77,6 +77,12 @@ static int dwc2_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc2) return 0; } +/** + * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI + * driver + * + * @pci: The programming view of DWC_otg PCI + */ static void dwc2_pci_remove(struct pci_dev *pci) { struct dwc2_pci_glue *glue = pci_get_drvdata(pci); @@ -141,8 +147,10 @@ static int dwc2_pci_probe(struct pci_dev *pci, goto err; glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); - if (!glue) + if (!glue) { + ret = -ENOMEM; goto err; + } ret = platform_device_add(dwc2); if (ret) { |