/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __LINUX_USB_DWC3_MSM_H #define __LINUX_USB_DWC3_MSM_H #include #include #include /* used for struct usb_phy flags */ #define PHY_HOST_MODE BIT(0) #define DEVICE_IN_SS_MODE BIT(1) #define PHY_LANE_A BIT(2) #define PHY_LANE_B BIT(3) #define PHY_HSFS_MODE BIT(4) #define PHY_LS_MODE BIT(5) #define EUD_SPOOF_DISCONNECT BIT(6) #define EUD_SPOOF_CONNECT BIT(7) #define PHY_SUS_OVERRIDE BIT(8) #define PHY_DP_MODE BIT(9) #define PHY_USB_DP_CONCURRENT_MODE BIT(10) /* * The following are bit fields describing the USB BAM options. * These bit fields are set by function drivers that wish to queue * usb_requests with sps/bam parameters. */ #define MSM_TX_PIPE_ID_OFS (16) #define MSM_SPS_MODE BIT(5) #define MSM_IS_FINITE_TRANSFER BIT(6) #define MSM_PRODUCER BIT(7) #define MSM_DISABLE_WB BIT(8) #define MSM_ETD_IOC BIT(9) #define MSM_INTERNAL_MEM BIT(10) #define MSM_VENDOR_ID BIT(16) /* EBC TRB parameters */ #define EBC_TRB_SIZE 16384 /* Operations codes for GSI enabled EPs */ enum gsi_ep_op { GSI_EP_OP_CONFIG = 0, GSI_EP_OP_STARTXFER, GSI_EP_OP_STORE_DBL_INFO, GSI_EP_OP_ENABLE_GSI, GSI_EP_OP_UPDATEXFER, GSI_EP_OP_RING_DB, GSI_EP_OP_ENDXFER, GSI_EP_OP_GET_CH_INFO, GSI_EP_OP_GET_XFER_IDX, GSI_EP_OP_PREPARE_TRBS, GSI_EP_OP_FREE_TRBS, GSI_EP_OP_SET_CLR_BLOCK_DBL, GSI_EP_OP_CHECK_FOR_SUSPEND, GSI_EP_OP_DISABLE, }; enum usb_hw_ep_mode { USB_EP_NONE, USB_EP_BAM, USB_EP_GSI, USB_EP_EBC, }; enum dwc3_notify_event { DWC3_CONTROLLER_ERROR_EVENT, DWC3_CONTROLLER_RESET_EVENT, DWC3_CONTROLLER_POST_RESET_EVENT, DWC3_CORE_PM_SUSPEND_EVENT, DWC3_CORE_PM_RESUME_EVENT, DWC3_CONTROLLER_CONNDONE_EVENT, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, DWC3_CONTROLLER_PULLUP_ENTER, DWC3_CONTROLLER_PULLUP_EXIT, /* USB GSI event buffer related notification */ DWC3_GSI_EVT_BUF_ALLOC, DWC3_GSI_EVT_BUF_SETUP, DWC3_GSI_EVT_BUF_CLEANUP, DWC3_GSI_EVT_BUF_CLEAR, DWC3_GSI_EVT_BUF_FREE, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, DWC3_IMEM_UPDATE_PID, }; /* * @buf_base_addr: Base pointer to buffer allocated for each GSI enabled EP. * TRBs point to buffers that are split from this pool. The size of the * buffer is num_bufs times buf_len. num_bufs and buf_len are determined based on desired performance and aggregation size. * @dma: DMA address corresponding to buf_base_addr. * @num_bufs: Number of buffers associated with the GSI enabled EP. This * corresponds to the number of non-zlp TRBs allocated for the EP. * The value is determined based on desired performance for the EP. * @buf_len: Size of each individual buffer is determined based on aggregation * negotiated as per the protocol. In case of no aggregation supported by * the protocol, we use default values. * @db_reg_phs_addr_lsb: IPA channel doorbell register's physical address LSB * @mapped_db_reg_phs_addr_lsb: doorbell LSB IOVA address mapped with IOMMU * @db_reg_phs_addr_msb: IPA channel doorbell register's physical address MSB * @ep_intr_num: Interrupter number for EP. */ struct usb_gsi_request { void *buf_base_addr; dma_addr_t dma; size_t num_bufs; size_t buf_len; u32 db_reg_phs_addr_lsb; dma_addr_t mapped_db_reg_phs_addr_lsb; u32 db_reg_phs_addr_msb; u8 ep_intr_num; struct sg_table sgt_trb_xfer_ring; struct sg_table sgt_data_buff; }; /* * @last_trb_addr: Address (LSB - based on alignment restrictions) of * last TRB in queue. Used to identify rollover case. * @const_buffer_size: TRB buffer size in KB (similar to IPA aggregation * configuration). Must be aligned to Max USB Packet Size. * Should be 1 <= const_buffer_size <= 31. * @depcmd_low_addr: Used by GSI hardware to write "Update Transfer" cmd * @depcmd_hi_addr: Used to write "Update Transfer" command. * @gevntcount_low_addr: GEVNCOUNT low address for GSI hardware to read and * clear processed events. * @gevntcount_hi_addr: GEVNCOUNT high address. * @xfer_ring_len: length of transfer ring in bytes (must be integral * multiple of TRB size - 16B for xDCI). * @xfer_ring_base_addr: physical base address of transfer ring. Address must * be aligned to xfer_ring_len rounded to power of two. * @ch_req: Used to pass request specific info for certain operations on GSI EP */ struct gsi_channel_info { u16 last_trb_addr; u8 const_buffer_size; u32 depcmd_low_addr; u8 depcmd_hi_addr; u32 gevntcount_low_addr; u8 gevntcount_hi_addr; u16 xfer_ring_len; u64 xfer_ring_base_addr; struct usb_gsi_request *ch_req; }; struct dwc3; extern void *dwc_trace_ipc_log_ctxt; /** * usb_gadget_autopm_get - increment PM-usage counter of usb gadget's parent * device. * @gadget: usb gadget whose parent device counter is incremented * * This routine should be called by function driver when it wants to use * gadget's parent device and needs to guarantee that it is not suspended. In * addition, the routine prevents subsequent autosuspends of gadget's parent * device. However if the autoresume fails then the counter is re-decremented. * * This routine can run only in process context. */ static inline int usb_gadget_autopm_get(struct usb_gadget *gadget) { int status = -ENODEV; if (!gadget || !gadget->dev.parent) return status; status = pm_runtime_get_sync(gadget->dev.parent); if (status < 0) pm_runtime_put_sync(gadget->dev.parent); if (status > 0) status = 0; return status; } /** * usb_gadget_autopm_get_async - increment PM-usage counter of usb gadget's * parent device. * @gadget: usb gadget whose parent device counter is incremented * * This routine increments @gadget parent device PM usage counter and queue an * autoresume request if the device is suspended. It does not autoresume device * directly (it only queues a request). After a successful call, the device may * not yet be resumed. * * This routine can run in atomic context. */ static inline int usb_gadget_autopm_get_async(struct usb_gadget *gadget) { int status = -ENODEV; if (!gadget || !gadget->dev.parent) return status; status = pm_runtime_get(gadget->dev.parent); if (status < 0 && status != -EINPROGRESS) pm_runtime_put_noidle(gadget->dev.parent); if (status > 0 || status == -EINPROGRESS) status = 0; return status; } /** * usb_gadget_autopm_get_noresume - increment PM-usage counter of usb gadget's * parent device. * @gadget: usb gadget whose parent device counter is incremented * * This routine increments PM-usage count of @gadget parent device but does not * carry out an autoresume. * * This routine can run in atomic context. */ static inline void usb_gadget_autopm_get_noresume(struct usb_gadget *gadget) { if (gadget && gadget->dev.parent) pm_runtime_get_noresume(gadget->dev.parent); } /** * usb_gadget_autopm_put - decrement PM-usage counter of usb gadget's parent * device. * @gadget: usb gadget whose parent device counter is decremented. * * This routine should be called by function driver when it is finished using * @gadget parent device and wants to allow it to autosuspend. It decrements * PM-usage counter of @gadget parent device, when the counter reaches 0, a * delayed autosuspend request is attempted. * * This routine can run only in process context. */ static inline void usb_gadget_autopm_put(struct usb_gadget *gadget) { if (gadget && gadget->dev.parent) pm_runtime_put_sync(gadget->dev.parent); } /** * usb_gadget_autopm_put_async - decrement PM-usage counter of usb gadget's * parent device. * @gadget: usb gadget whose parent device counter is decremented. * * This routine decrements PM-usage counter of @gadget parent device and * schedules a delayed autosuspend request if the counter is <= 0. * * This routine can run in atomic context. */ static inline void usb_gadget_autopm_put_async(struct usb_gadget *gadget) { if (gadget && gadget->dev.parent) pm_runtime_put(gadget->dev.parent); } /** * usb_gadget_autopm_put_no_suspend - decrement PM-usage counter of usb gadget 's * parent device. * @gadget: usb gadget whose parent device counter is decremented. * * This routine decrements PM-usage counter of @gadget parent device but does * not carry out an autosuspend. * * This routine can run in atomic context. */ static inline void usb_gadget_autopm_put_no_suspend(struct usb_gadget *gadget) { if (gadget && gadget->dev.parent) pm_runtime_put_noidle(gadget->dev.parent); } #if IS_ENABLED(CONFIG_USB_DWC3_MSM) void dwc3_msm_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value); int usb_gsi_ep_op(struct usb_ep *ep, void *op_data, enum gsi_ep_op op); int msm_ep_config(struct usb_ep *ep, struct usb_request *request, u32 bam_opts); int msm_ep_unconfig(struct usb_ep *ep); void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable); int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size, u8 dst_pipe_idx); int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); int dwc3_msm_set_dp_mode(struct device *dev, bool connected, int lanes); int dwc3_msm_release_ss_lane(struct device *dev); int msm_ep_update_ops(struct usb_ep *ep); int msm_ep_clear_ops(struct usb_ep *ep); int msm_ep_set_mode(struct usb_ep *ep, enum usb_hw_ep_mode mode); int dwc3_core_stop_hw_active_transfers(struct dwc3 *dwc); #else void dwc3_msm_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value) { } static inline int usb_gsi_ep_op(struct usb_ep *ep, void *op_data, enum gsi_ep_op op) { return 0; } static inline int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size, u8 dst_pipe_idx) { return -ENODEV; } static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request, u32 bam_opts) { return -ENODEV; } static inline int msm_ep_unconfig(struct usb_ep *ep) { return -ENODEV; } static inline void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable) { } static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) { return false; } static inline int dwc3_msm_set_dp_mode(struct device *dev, bool connected, int lanes) { return -ENODEV; } static inline int dwc3_msm_release_ss_lane(struct device *dev) { return -ENODEV; } int msm_ep_update_ops(struct usb_ep *ep) { return -ENODEV; } int msm_ep_clear_ops(struct usb_ep *ep) { return -ENODEV; } int msm_ep_set_mode(struct usb_ep *ep, enum usb_hw_ep_mode mode) { return -ENODEV; } inline int dwc3_core_stop_hw_active_transfers(struct dwc3 *dwc) { return 0; } #endif #ifdef CONFIG_ARM64 int dwc3_msm_kretprobe_init(void); void dwc3_msm_kretprobe_exit(void); #else int dwc3_msm_kretprobe_init(void) { return 0; } void dwc3_msm_kretprobe_exit(void) { } #endif #endif /* __LINUX_USB_DWC3_MSM_H */