/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include struct usb_dwc3 { u32 sbuscfg0; u32 sbuscfg1; u32 txthrcfg; u32 rxthrcfg; u32 ctl; u32 pmsts; u32 sts; u32 uctl1; u32 snpsid; u32 gpio; u32 uid; u32 uctl; u64 buserraddr; u64 prtbimap; u8 reserved1[32]; u32 dbgfifospace; u32 dbgltssm; u32 dbglnmcc; u32 dbgbmu; u32 dbglspmux; u32 dbglsp; u32 dbgepinfo0; u32 dbgepinfo1; u64 prtbimap_hs; u64 prtbimap_fs; u8 reserved2[112]; u32 usb2phycfg; u8 reserved3[124]; u32 usb2phyacc; u8 reserved4[60]; u32 usb3pipectl; u8 reserved5[60]; }; check_member(usb_dwc3, usb2phycfg, 0x100); check_member(usb_dwc3, usb3pipectl, 0x1c0); struct usb_dwc3_cfg { struct usb_dwc3 *usb_host_dwc3; u32 *usb3_bcr; u32 *qusb2phy_bcr; u32 *gcc_usb3phy_bcr_reg; u32 *gcc_qmpphy_bcr_reg; }; static struct usb_dwc3_cfg usb_port0 = { .usb_host_dwc3 = (void *)USB_HOST_DWC3_BASE, .usb3_bcr = &gcc->usb30_prim_bcr, .qusb2phy_bcr = &gcc->qusb2phy_prim_bcr, .gcc_usb3phy_bcr_reg = &gcc->usb3_dp_phy_prim_bcr, .gcc_qmpphy_bcr_reg = &gcc->usb3_phy_prim_bcr, }; static void reset_usb(struct usb_dwc3_cfg *dwc3) { /* Assert Core reset */ clock_reset_bcr(dwc3->usb3_bcr, 1); /* Assert HS PHY reset */ clock_reset_bcr(dwc3->qusb2phy_bcr, 1); /* Assert QMP PHY reset */ clock_reset_bcr(dwc3->gcc_usb3phy_bcr_reg, 1); clock_reset_bcr(dwc3->gcc_qmpphy_bcr_reg, 1); } void reset_usb0(void) { /* Before Resetting PHY, put Core in Reset */ printk(BIOS_INFO, "Starting DWC3 and PHY resets for USB(0)\n"); reset_usb(&usb_port0); } static void setup_dwc3(struct usb_dwc3 *dwc3) { /* core exits U1/U2/U3 only in PHY power state P1/P2/P3 respectively */ clrsetbits32(&dwc3->usb3pipectl, DWC3_GUSB3PIPECTL_DELAYP1TRANS, DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX); /* * Configure USB phy interface of DWC3 core. * 1. Select UTMI+ PHY with 16-bit interface. * 2. Set USBTRDTIM to the corresponding value * according to the UTMI+ PHY interface. */ clrsetbits32(&dwc3->usb2phycfg, (DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK | DWC3_GUSB2PHYCFG_PHYIF_MASK), (DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT))); clrsetbits32(&dwc3->ctl, (DWC3_GCTL_SCALEDOWN_MASK | DWC3_GCTL_DISSCRAMBLE), DWC3_GCTL_U2EXIT_LFPS | DWC3_GCTL_DSBLCLKGTNG); /* configure controller in Host mode */ clrsetbits32(&dwc3->ctl, (DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)), DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST)); printk(BIOS_SPEW, "Configure USB in Host mode\n"); } /* Initialization of DWC3 Core and PHY */ static void setup_usb_host(struct usb_dwc3_cfg *dwc3, void *board_data) { /* Clear core reset. */ clock_reset_bcr(dwc3->usb3_bcr, 0); /* Clear QUSB PHY reset. */ clock_reset_bcr(dwc3->qusb2phy_bcr, 0); /* Initialize HS PHY */ hs_usb_phy_init(board_data); /* Clear QMP PHY resets. */ clock_reset_bcr(dwc3->gcc_usb3phy_bcr_reg, 0); clock_reset_bcr(dwc3->gcc_qmpphy_bcr_reg, 0); /* Initialize QMP PHY */ ss_qmp_phy_init(); setup_dwc3(dwc3->usb_host_dwc3); printk(BIOS_INFO, "DWC3 and PHY setup finished\n"); } void setup_usb_host0(void *board_data) { printk(BIOS_INFO, "Setting up USB HOST0 controller.\n"); setup_usb_host(&usb_port0, board_data); }