138 lines
3.9 KiB
C
138 lines
3.9 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
/*
|
||
|
* xHCI host controller exynos driver
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "xhci.h"
|
||
|
#include "../dwc3/dwc3-exynos.h"
|
||
|
|
||
|
/*
|
||
|
* Sometimes deadlock occurred between hub_event and remove_hcd.
|
||
|
* In order to prevent it, waiting for completion of hub_event was added.
|
||
|
* This is a timeout (300msec) value for the waiting.
|
||
|
*/
|
||
|
#define XHCI_HUB_EVENT_TIMEOUT (300)
|
||
|
|
||
|
#define XHCI_USE_URAM_FOR_EXYNOS_AUDIO BIT_ULL(62)
|
||
|
#define XHCI_L2_SUPPORT BIT_ULL(63)
|
||
|
|
||
|
#define PORTSC_OFFSET 0x430
|
||
|
|
||
|
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
|
||
|
|
||
|
/* EXYNOS uram memory map */
|
||
|
#if defined(CONFIG_SOC_S5E9925)
|
||
|
#define EXYNOS_URAM_ABOX_EVT_RING_ADDR 0x02a00000
|
||
|
#define EXYNOS_URAM_ISOC_OUT_RING_ADDR 0x02a01000
|
||
|
#define EXYNOS_URAM_ISOC_IN_RING_ADDR 0x02a02000
|
||
|
#define EXYNOS_URAM_DEVICE_CTX_ADDR 0x02a03000
|
||
|
#define EXYNOS_URAM_DCBAA_ADDR 0x02a03880
|
||
|
#define EXYNOS_URAM_ABOX_ERST_SEG_ADDR 0x02a03C80
|
||
|
#elif defined(CONFIG_SOC_S5E8825)
|
||
|
#define EXYNOS_URAM_ABOX_EVT_RING_ADDR 0x13300000
|
||
|
#define EXYNOS_URAM_ISOC_OUT_RING_ADDR 0x13301000
|
||
|
#define EXYNOS_URAM_ISOC_IN_RING_ADDR 0x13302000
|
||
|
#define EXYNOS_URAM_DEVICE_CTX_ADDR 0x13303000
|
||
|
#define EXYNOS_URAM_DCBAA_ADDR 0x13303880
|
||
|
#define EXYNOS_URAM_ABOX_ERST_SEG_ADDR 0x13303C80
|
||
|
#else
|
||
|
#error
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
enum usb_port_state {
|
||
|
PORT_EMPTY = 0, /* OTG only */
|
||
|
PORT_USB2, /* usb 2.0 device only */
|
||
|
PORT_USB3, /* usb 3.0 device only */
|
||
|
PORT_HUB, /* usb hub single */
|
||
|
PORT_DP /* DP device */
|
||
|
};
|
||
|
|
||
|
struct xhci_hcd_exynos {
|
||
|
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
|
||
|
struct xhci_intr_reg __iomem *ir_set_audio;
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
|
||
|
struct xhci_ring *event_ring_audio;
|
||
|
struct xhci_erst erst_audio;
|
||
|
dma_addr_t save_dma;
|
||
|
void *save_addr;
|
||
|
dma_addr_t out_dma;
|
||
|
void *out_addr;
|
||
|
dma_addr_t in_dma;
|
||
|
void *in_addr;
|
||
|
#endif
|
||
|
struct device *dev;
|
||
|
struct usb_hcd *hcd;
|
||
|
struct usb_hcd *shared_hcd;
|
||
|
|
||
|
struct wakeup_source *main_wakelock; /* Wakelock for HS HCD */
|
||
|
struct wakeup_source *shared_wakelock; /* Wakelock for SS HCD */
|
||
|
|
||
|
void __iomem *usb3_portsc;
|
||
|
spinlock_t xhcioff_lock;
|
||
|
int port_off_done;
|
||
|
int port_set_delayed;
|
||
|
u32 portsc_control_priority;
|
||
|
enum usb_port_state port_state;
|
||
|
int usb3_phy_control;
|
||
|
|
||
|
struct usb_xhci_pre_alloc *xhci_alloc;
|
||
|
struct phy *phy_usb2;
|
||
|
struct phy *phy_usb3;
|
||
|
|
||
|
/* This flag is used to check first allocation for URAM */
|
||
|
bool exynos_uram_ctx_alloc;
|
||
|
bool exynos_uram_isoc_out_alloc;
|
||
|
bool exynos_uram_isoc_in_alloc;
|
||
|
u8 *usb_audio_ctx_addr;
|
||
|
u8 *usb_audio_isoc_out_addr;
|
||
|
u8 *usb_audio_isoc_in_addr;
|
||
|
|
||
|
};
|
||
|
|
||
|
struct usb_phy_roothub {
|
||
|
struct phy *phy;
|
||
|
struct list_head list;
|
||
|
};
|
||
|
|
||
|
struct xhci_exynos_priv {
|
||
|
const char *firmware_name;
|
||
|
unsigned long long quirks;
|
||
|
struct xhci_vendor_data *vendor_data;
|
||
|
int (*plat_setup)(struct usb_hcd *);
|
||
|
void (*plat_start)(struct usb_hcd *);
|
||
|
int (*init_quirk)(struct usb_hcd *);
|
||
|
int (*suspend_quirk)(struct usb_hcd *);
|
||
|
int (*resume_quirk)(struct usb_hcd *);
|
||
|
struct xhci_hcd_exynos *xhci_exynos;
|
||
|
};
|
||
|
|
||
|
#define hcd_to_xhci_exynos_priv(h) ((struct xhci_exynos_priv *)hcd_to_xhci(h)->priv)
|
||
|
#define xhci_to_exynos_priv(x) ((struct xhci_exynos_priv *)(x)->priv)
|
||
|
|
||
|
extern int is_otg_only;
|
||
|
extern int exynos_usbdrd_phy_vendor_set(struct phy *phy, int is_enable,
|
||
|
int is_cancel);
|
||
|
extern int get_idle_ip_index(void);
|
||
|
|
||
|
#ifdef CONFIG_SND_EXYNOS_USB_AUDIO
|
||
|
int xhci_store_hw_info(struct usb_hcd *hcd, struct usb_device *udev);
|
||
|
int xhci_set_deq(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
|
||
|
unsigned int last_ep, struct usb_device *udev);
|
||
|
#endif
|
||
|
|
||
|
int xhci_hub_check_speed(struct usb_hcd *hcd);
|
||
|
int xhci_check_usbl2_support(struct usb_hcd *hcd);
|
||
|
int xhci_wake_lock(struct usb_hcd *hcd, int is_lock);
|
||
|
void xhci_usb_parse_endpoint(struct usb_device *udev, struct usb_endpoint_descriptor *desc, int size);
|
||
|
|
||
|
extern int exynos_usbdrd_phy_vendor_set(struct phy *phy, int is_enable,
|
||
|
int is_cancel);
|
||
|
extern int exynos_usbdrd_phy_tune(struct phy *phy, int phy_state);
|
||
|
void usb_power_notify_control(int owner, int on);
|