2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2015-11-24 13:09:55 +02:00
/*
* MediaTek xHCI Host Controller Driver
*
* Copyright ( c ) 2015 MediaTek Inc .
* Author :
* Chunfeng Yun < chunfeng . yun @ mediatek . com >
*/
# include <linux/dma-mapping.h>
# include <linux/iopoll.h>
# include <linux/kernel.h>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
2021-04-10 13:10:04 +08:00
# include <linux/pm_wakeirq.h>
2015-11-24 13:09:55 +02:00
# include <linux/regmap.h>
# include <linux/regulator/consumer.h>
# include "xhci.h"
# include "xhci-mtk.h"
/* ip_pw_ctrl0 register */
# define CTRL0_IP_SW_RST BIT(0)
/* ip_pw_ctrl1 register */
# define CTRL1_IP_HOST_PDN BIT(0)
/* ip_pw_ctrl2 register */
# define CTRL2_IP_DEV_PDN BIT(0)
/* ip_pw_sts1 register */
# define STS1_IP_SLEEP_STS BIT(30)
2017-10-13 16:26:35 +08:00
# define STS1_U3_MAC_RST BIT(16)
2015-11-24 13:09:55 +02:00
# define STS1_XHCI_RST BIT(11)
# define STS1_SYS125_RST BIT(10)
# define STS1_REF_RST BIT(8)
# define STS1_SYSPLL_STABLE BIT(0)
/* ip_xhci_cap register */
# define CAP_U3_PORT_NUM(p) ((p) & 0xff)
# define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff)
/* u3_ctrl_p register */
# define CTRL_U3_PORT_HOST_SEL BIT(2)
# define CTRL_U3_PORT_PDN BIT(1)
# define CTRL_U3_PORT_DIS BIT(0)
/* u2_ctrl_p register */
# define CTRL_U2_PORT_HOST_SEL BIT(2)
# define CTRL_U2_PORT_PDN BIT(1)
# define CTRL_U2_PORT_DIS BIT(0)
/* u2_phy_pll register */
# define CTRL_U2_FORCE_PLL_STB BIT(28)
2021-08-17 16:36:29 +08:00
/* xHCI CSR */
# define LS_EOF_CFG 0x930
# define LSEOF_OFFSET 0x89
# define FS_EOF_CFG 0x934
# define FSEOF_OFFSET 0x2e
# define SS_GEN1_EOF_CFG 0x93c
# define SSG1EOF_OFFSET 0x78
# define HFCNTR_CFG 0x944
# define ITP_DELTA_CLK (0xa << 1)
# define ITP_DELTA_CLK_MASK GENMASK(5, 1)
# define FRMCNT_LEV1_RANG (0x12b << 8)
# define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
# define SS_GEN2_EOF_CFG 0x990
# define SSG2EOF_OFFSET 0x3c
# define XSEOF_OFFSET_MASK GENMASK(11, 0)
2018-01-03 16:53:20 +08:00
/* usb remote wakeup registers in syscon */
2021-03-23 15:02:48 +08:00
2018-01-03 16:53:20 +08:00
/* mt8173 etc */
# define PERI_WK_CTRL1 0x4
# define WC1_IS_C(x) (((x) & 0xf) << 26) /* cycle debounce */
# define WC1_IS_EN BIT(25)
# define WC1_IS_P BIT(6) /* polarity for ip sleep */
2021-03-23 15:02:48 +08:00
/* mt8183 */
# define PERI_WK_CTRL0 0x0
# define WC0_IS_C(x) ((u32)(((x) & 0xf) << 28)) /* cycle debounce */
# define WC0_IS_P BIT(12) /* polarity */
# define WC0_IS_EN BIT(6)
2021-03-23 15:02:49 +08:00
/* mt8192 */
# define WC0_SSUSB0_CDEN BIT(6)
# define WC0_IS_SPM_EN BIT(1)
2022-01-28 14:29:00 +08:00
/* mt8195 */
# define PERI_WK_CTRL0_8195 0x04
# define WC0_IS_P_95 BIT(30) /* polarity */
# define WC0_IS_C_95(x) ((u32)(((x) & 0x7) << 27))
# define WC0_IS_EN_P3_95 BIT(26)
# define WC0_IS_EN_P2_95 BIT(25)
# define WC0_IS_EN_P1_95 BIT(24)
# define PERI_WK_CTRL1_8195 0x20
# define WC1_IS_C_95(x) ((u32)(((x) & 0xf) << 28))
# define WC1_IS_P_95 BIT(12)
# define WC1_IS_EN_P0_95 BIT(6)
2018-01-03 16:53:20 +08:00
/* mt2712 etc */
# define PERI_SSUSB_SPM_CTRL 0x0
# define SSC_IP_SLEEP_EN BIT(4)
# define SSC_SPM_INT_EN BIT(1)
enum ssusb_uwk_vers {
SSUSB_UWK_V1 = 1 ,
SSUSB_UWK_V2 ,
2021-03-23 15:02:48 +08:00
SSUSB_UWK_V1_1 = 101 , /* specific revision 1.01 */
2021-03-23 15:02:49 +08:00
SSUSB_UWK_V1_2 , /* specific revision 1.2 */
2022-01-28 14:29:00 +08:00
SSUSB_UWK_V1_3 , /* mt8195 IP0 */
SSUSB_UWK_V1_4 , /* mt8195 IP1 */
SSUSB_UWK_V1_5 , /* mt8195 IP2 */
SSUSB_UWK_V1_6 , /* mt8195 IP3 */
2015-11-24 13:09:55 +02:00
} ;
2021-08-17 16:36:29 +08:00
/*
* MT8195 has 4 controllers , the controller1 ~ 3 ' s default SOF / ITP interval
* is calculated from the frame counter clock 24 M , but in fact , the clock
* is 48 M , add workaround for it .
*/
static void xhci_mtk_set_frame_interval ( struct xhci_hcd_mtk * mtk )
{
struct device * dev = mtk - > dev ;
struct usb_hcd * hcd = mtk - > hcd ;
u32 value ;
if ( ! of_device_is_compatible ( dev - > of_node , " mediatek,mt8195-xhci " ) )
return ;
value = readl ( hcd - > regs + HFCNTR_CFG ) ;
value & = ~ ( ITP_DELTA_CLK_MASK | FRMCNT_LEV1_RANG_MASK ) ;
value | = ( ITP_DELTA_CLK | FRMCNT_LEV1_RANG ) ;
writel ( value , hcd - > regs + HFCNTR_CFG ) ;
value = readl ( hcd - > regs + LS_EOF_CFG ) ;
value & = ~ XSEOF_OFFSET_MASK ;
value | = LSEOF_OFFSET ;
writel ( value , hcd - > regs + LS_EOF_CFG ) ;
value = readl ( hcd - > regs + FS_EOF_CFG ) ;
value & = ~ XSEOF_OFFSET_MASK ;
value | = FSEOF_OFFSET ;
writel ( value , hcd - > regs + FS_EOF_CFG ) ;
value = readl ( hcd - > regs + SS_GEN1_EOF_CFG ) ;
value & = ~ XSEOF_OFFSET_MASK ;
value | = SSG1EOF_OFFSET ;
writel ( value , hcd - > regs + SS_GEN1_EOF_CFG ) ;
value = readl ( hcd - > regs + SS_GEN2_EOF_CFG ) ;
value & = ~ XSEOF_OFFSET_MASK ;
value | = SSG2EOF_OFFSET ;
writel ( value , hcd - > regs + SS_GEN2_EOF_CFG ) ;
}
2015-11-24 13:09:55 +02:00
static int xhci_mtk_host_enable ( struct xhci_hcd_mtk * mtk )
{
struct mu3c_ippc_regs __iomem * ippc = mtk - > ippc_regs ;
u32 value , check_val ;
2020-08-08 14:49:06 +02:00
int u3_ports_disabled = 0 ;
2015-11-24 13:09:55 +02:00
int ret ;
int i ;
2016-10-19 10:28:22 +08:00
if ( ! mtk - > has_ippc )
return 0 ;
2015-11-24 13:09:55 +02:00
/* power on host ip */
value = readl ( & ippc - > ip_pw_ctr1 ) ;
value & = ~ CTRL1_IP_HOST_PDN ;
writel ( value , & ippc - > ip_pw_ctr1 ) ;
2017-10-13 16:26:36 +08:00
/* power on and enable u3 ports except skipped ones */
2015-11-24 13:09:55 +02:00
for ( i = 0 ; i < mtk - > num_u3_ports ; i + + ) {
2017-10-13 16:26:36 +08:00
if ( ( 0x1 < < i ) & mtk - > u3p_dis_msk ) {
2020-08-08 14:49:06 +02:00
u3_ports_disabled + + ;
2017-10-13 16:26:36 +08:00
continue ;
}
2015-11-24 13:09:55 +02:00
value = readl ( & ippc - > u3_ctrl_p [ i ] ) ;
value & = ~ ( CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS ) ;
value | = CTRL_U3_PORT_HOST_SEL ;
writel ( value , & ippc - > u3_ctrl_p [ i ] ) ;
}
2021-08-17 16:36:24 +08:00
/* power on and enable all u2 ports except skipped ones */
2015-11-24 13:09:55 +02:00
for ( i = 0 ; i < mtk - > num_u2_ports ; i + + ) {
2021-08-17 16:36:24 +08:00
if ( BIT ( i ) & mtk - > u2p_dis_msk )
continue ;
2015-11-24 13:09:55 +02:00
value = readl ( & ippc - > u2_ctrl_p [ i ] ) ;
value & = ~ ( CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS ) ;
value | = CTRL_U2_PORT_HOST_SEL ;
writel ( value , & ippc - > u2_ctrl_p [ i ] ) ;
}
/*
* wait for clocks to be stable , and clock domains reset to
* be inactive after power on and enable ports
*/
check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
STS1_SYS125_RST | STS1_XHCI_RST ;
2020-08-08 14:49:06 +02:00
if ( mtk - > num_u3_ports > u3_ports_disabled )
2017-10-13 16:26:35 +08:00
check_val | = STS1_U3_MAC_RST ;
2015-11-24 13:09:55 +02:00
ret = readl_poll_timeout ( & ippc - > ip_pw_sts1 , value ,
( check_val = = ( value & check_val ) ) , 100 , 20000 ) ;
if ( ret ) {
dev_err ( mtk - > dev , " clocks are not stable (0x%x) \n " , value ) ;
return ret ;
}
return 0 ;
}
static int xhci_mtk_host_disable ( struct xhci_hcd_mtk * mtk )
{
struct mu3c_ippc_regs __iomem * ippc = mtk - > ippc_regs ;
u32 value ;
int ret ;
int i ;
2016-10-19 10:28:22 +08:00
if ( ! mtk - > has_ippc )
return 0 ;
2017-10-13 16:26:36 +08:00
/* power down u3 ports except skipped ones */
2015-11-24 13:09:55 +02:00
for ( i = 0 ; i < mtk - > num_u3_ports ; i + + ) {
2017-10-13 16:26:36 +08:00
if ( ( 0x1 < < i ) & mtk - > u3p_dis_msk )
continue ;
2015-11-24 13:09:55 +02:00
value = readl ( & ippc - > u3_ctrl_p [ i ] ) ;
value | = CTRL_U3_PORT_PDN ;
writel ( value , & ippc - > u3_ctrl_p [ i ] ) ;
}
2021-08-17 16:36:24 +08:00
/* power down all u2 ports except skipped ones */
2015-11-24 13:09:55 +02:00
for ( i = 0 ; i < mtk - > num_u2_ports ; i + + ) {
2021-08-17 16:36:24 +08:00
if ( BIT ( i ) & mtk - > u2p_dis_msk )
continue ;
2015-11-24 13:09:55 +02:00
value = readl ( & ippc - > u2_ctrl_p [ i ] ) ;
value | = CTRL_U2_PORT_PDN ;
writel ( value , & ippc - > u2_ctrl_p [ i ] ) ;
}
/* power down host ip */
value = readl ( & ippc - > ip_pw_ctr1 ) ;
value | = CTRL1_IP_HOST_PDN ;
writel ( value , & ippc - > ip_pw_ctr1 ) ;
/* wait for host ip to sleep */
ret = readl_poll_timeout ( & ippc - > ip_pw_sts1 , value ,
( value & STS1_IP_SLEEP_STS ) , 100 , 100000 ) ;
2021-11-02 10:50:04 +08:00
if ( ret )
2015-11-24 13:09:55 +02:00
dev_err ( mtk - > dev , " ip sleep failed!!! \n " ) ;
2021-11-02 10:50:04 +08:00
else /* workaound for platforms using low level latch */
usleep_range ( 100 , 200 ) ;
return ret ;
2015-11-24 13:09:55 +02:00
}
static int xhci_mtk_ssusb_config ( struct xhci_hcd_mtk * mtk )
{
struct mu3c_ippc_regs __iomem * ippc = mtk - > ippc_regs ;
u32 value ;
2016-10-19 10:28:22 +08:00
if ( ! mtk - > has_ippc )
return 0 ;
2015-11-24 13:09:55 +02:00
/* reset whole ip */
value = readl ( & ippc - > ip_pw_ctr0 ) ;
value | = CTRL0_IP_SW_RST ;
writel ( value , & ippc - > ip_pw_ctr0 ) ;
udelay ( 1 ) ;
value = readl ( & ippc - > ip_pw_ctr0 ) ;
value & = ~ CTRL0_IP_SW_RST ;
writel ( value , & ippc - > ip_pw_ctr0 ) ;
/*
* device ip is default power - on in fact
* power down device ip , otherwise ip - sleep will fail
*/
value = readl ( & ippc - > ip_pw_ctr2 ) ;
value | = CTRL2_IP_DEV_PDN ;
writel ( value , & ippc - > ip_pw_ctr2 ) ;
value = readl ( & ippc - > ip_xhci_cap ) ;
mtk - > num_u3_ports = CAP_U3_PORT_NUM ( value ) ;
mtk - > num_u2_ports = CAP_U2_PORT_NUM ( value ) ;
dev_dbg ( mtk - > dev , " %s u2p:%d, u3p:%d \n " , __func__ ,
mtk - > num_u2_ports , mtk - > num_u3_ports ) ;
return xhci_mtk_host_enable ( mtk ) ;
}
/* only clocks can be turn off for ip-sleep wakeup mode */
2018-01-03 16:53:20 +08:00
static void usb_wakeup_ip_sleep_set ( struct xhci_hcd_mtk * mtk , bool enable )
2015-11-24 13:09:55 +02:00
{
2018-01-03 16:53:20 +08:00
u32 reg , msk , val ;
switch ( mtk - > uwk_vers ) {
case SSUSB_UWK_V1 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL1 ;
msk = WC1_IS_EN | WC1_IS_C ( 0xf ) | WC1_IS_P ;
val = enable ? ( WC1_IS_EN | WC1_IS_C ( 0x8 ) ) : 0 ;
break ;
2021-03-23 15:02:48 +08:00
case SSUSB_UWK_V1_1 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL0 ;
msk = WC0_IS_EN | WC0_IS_C ( 0xf ) | WC0_IS_P ;
2021-11-02 10:50:04 +08:00
val = enable ? ( WC0_IS_EN | WC0_IS_C ( 0x1 ) ) : 0 ;
2021-03-23 15:02:48 +08:00
break ;
2021-03-23 15:02:49 +08:00
case SSUSB_UWK_V1_2 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL0 ;
msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN ;
val = enable ? msk : 0 ;
break ;
2022-01-28 14:29:00 +08:00
case SSUSB_UWK_V1_3 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL1_8195 ;
msk = WC1_IS_EN_P0_95 | WC1_IS_C_95 ( 0xf ) | WC1_IS_P_95 ;
val = enable ? ( WC1_IS_EN_P0_95 | WC1_IS_C_95 ( 0x1 ) ) : 0 ;
break ;
case SSUSB_UWK_V1_4 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL0_8195 ;
msk = WC0_IS_EN_P1_95 | WC0_IS_C_95 ( 0x7 ) | WC0_IS_P_95 ;
val = enable ? ( WC0_IS_EN_P1_95 | WC0_IS_C_95 ( 0x1 ) ) : 0 ;
break ;
case SSUSB_UWK_V1_5 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL0_8195 ;
msk = WC0_IS_EN_P2_95 | WC0_IS_C_95 ( 0x7 ) | WC0_IS_P_95 ;
val = enable ? ( WC0_IS_EN_P2_95 | WC0_IS_C_95 ( 0x1 ) ) : 0 ;
break ;
case SSUSB_UWK_V1_6 :
reg = mtk - > uwk_reg_base + PERI_WK_CTRL0_8195 ;
msk = WC0_IS_EN_P3_95 | WC0_IS_C_95 ( 0x7 ) | WC0_IS_P_95 ;
val = enable ? ( WC0_IS_EN_P3_95 | WC0_IS_C_95 ( 0x1 ) ) : 0 ;
break ;
2018-01-03 16:53:20 +08:00
case SSUSB_UWK_V2 :
reg = mtk - > uwk_reg_base + PERI_SSUSB_SPM_CTRL ;
msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN ;
val = enable ? msk : 0 ;
break ;
default :
return ;
2018-01-13 01:46:49 +08:00
}
2018-01-03 16:53:20 +08:00
regmap_update_bits ( mtk - > uwk , reg , msk , val ) ;
2015-11-24 13:09:55 +02:00
}
2018-01-03 16:53:20 +08:00
static int usb_wakeup_of_property_parse ( struct xhci_hcd_mtk * mtk ,
struct device_node * dn )
2015-11-24 13:09:55 +02:00
{
2018-01-03 16:53:20 +08:00
struct of_phandle_args args ;
int ret ;
2015-11-24 13:09:55 +02:00
2018-01-03 16:53:20 +08:00
/* Wakeup function is optional */
mtk - > uwk_en = of_property_read_bool ( dn , " wakeup-source " ) ;
if ( ! mtk - > uwk_en )
return 0 ;
2015-11-24 13:09:55 +02:00
2018-01-03 16:53:20 +08:00
ret = of_parse_phandle_with_fixed_args ( dn ,
" mediatek,syscon-wakeup " , 2 , 0 , & args ) ;
if ( ret )
return ret ;
2015-11-24 13:09:55 +02:00
2018-01-03 16:53:20 +08:00
mtk - > uwk_reg_base = args . args [ 0 ] ;
mtk - > uwk_vers = args . args [ 1 ] ;
mtk - > uwk = syscon_node_to_regmap ( args . np ) ;
of_node_put ( args . np ) ;
dev_info ( mtk - > dev , " uwk - reg:0x%x, version:%d \n " ,
mtk - > uwk_reg_base , mtk - > uwk_vers ) ;
2015-11-24 13:09:55 +02:00
2018-01-03 16:53:20 +08:00
return PTR_ERR_OR_ZERO ( mtk - > uwk ) ;
2015-11-24 13:09:55 +02:00
}
2018-01-03 16:53:20 +08:00
static void usb_wakeup_set ( struct xhci_hcd_mtk * mtk , bool enable )
2015-11-24 13:09:55 +02:00
{
2018-01-03 16:53:20 +08:00
if ( mtk - > uwk_en )
usb_wakeup_ip_sleep_set ( mtk , enable ) ;
2015-11-24 13:09:55 +02:00
}
2021-04-10 13:10:05 +08:00
static int xhci_mtk_clks_get ( struct xhci_hcd_mtk * mtk )
{
struct clk_bulk_data * clks = mtk - > clks ;
clks [ 0 ] . id = " sys_ck " ;
clks [ 1 ] . id = " xhci_ck " ;
clks [ 2 ] . id = " ref_ck " ;
clks [ 3 ] . id = " mcu_ck " ;
clks [ 4 ] . id = " dma_ck " ;
return devm_clk_bulk_get_optional ( mtk - > dev , BULK_CLKS_NUM , clks ) ;
}
2022-02-14 12:19:05 +01:00
static int xhci_mtk_vregs_get ( struct xhci_hcd_mtk * mtk )
2015-11-24 13:09:55 +02:00
{
2022-02-14 12:19:05 +01:00
struct regulator_bulk_data * supplies = mtk - > supplies ;
2015-11-24 13:09:55 +02:00
2022-02-14 12:19:05 +01:00
supplies [ 0 ] . supply = " vbus " ;
supplies [ 1 ] . supply = " vusb33 " ;
2015-11-24 13:09:55 +02:00
2022-02-14 12:19:05 +01:00
return devm_regulator_bulk_get ( mtk - > dev , BULK_VREGS_NUM , supplies ) ;
2015-11-24 13:09:55 +02:00
}
static void xhci_mtk_quirks ( struct device * dev , struct xhci_hcd * xhci )
{
struct usb_hcd * hcd = xhci_to_hcd ( xhci ) ;
struct xhci_hcd_mtk * mtk = hcd_to_mtk ( hcd ) ;
/*
* As of now platform drivers don ' t provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
xhci - > quirks | = XHCI_PLAT ;
xhci - > quirks | = XHCI_MTK_HOST ;
/*
* MTK host controller gives a spurious successful event after a
* short transfer . Ignore it .
*/
xhci - > quirks | = XHCI_SPURIOUS_SUCCESS ;
if ( mtk - > lpm_support )
xhci - > quirks | = XHCI_LPM_SUPPORT ;
2021-03-31 17:05:53 +08:00
if ( mtk - > u2_lpm_disable )
xhci - > quirks | = XHCI_HW_LPM_DISABLE ;
2021-03-31 17:05:52 +08:00
/*
* MTK xHCI 0.96 : PSA is 1 by default even if doesn ' t support stream ,
* and it ' s 3 when support it .
*/
if ( xhci - > hci_version < 0x100 & & HCC_MAX_PSA ( xhci - > hcc_params ) = = 4 )
xhci - > quirks | = XHCI_BROKEN_STREAMS ;
2015-11-24 13:09:55 +02:00
}
/* called during probe() after chip reset completes */
static int xhci_mtk_setup ( struct usb_hcd * hcd )
{
struct xhci_hcd_mtk * mtk = hcd_to_mtk ( hcd ) ;
int ret ;
if ( usb_hcd_is_primary_hcd ( hcd ) ) {
ret = xhci_mtk_ssusb_config ( mtk ) ;
if ( ret )
return ret ;
2021-08-17 16:36:29 +08:00
/* workaround only for mt8195 */
xhci_mtk_set_frame_interval ( mtk ) ;
2016-10-19 10:28:22 +08:00
}
ret = xhci_gen_setup ( hcd , xhci_mtk_quirks ) ;
if ( ret )
return ret ;
2021-11-02 10:50:03 +08:00
if ( usb_hcd_is_primary_hcd ( hcd ) )
2015-11-24 13:09:55 +02:00
ret = xhci_mtk_sch_init ( mtk ) ;
2016-10-19 10:28:22 +08:00
return ret ;
2015-11-24 13:09:55 +02:00
}
2021-03-08 10:52:03 +08:00
static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
. reset = xhci_mtk_setup ,
2021-03-08 10:52:04 +08:00
. add_endpoint = xhci_mtk_add_ep ,
. drop_endpoint = xhci_mtk_drop_ep ,
2021-03-08 10:52:03 +08:00
. check_bandwidth = xhci_mtk_check_bandwidth ,
. reset_bandwidth = xhci_mtk_reset_bandwidth ,
} ;
static struct hc_driver __read_mostly xhci_mtk_hc_driver ;
2015-11-24 13:09:55 +02:00
static int xhci_mtk_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct device_node * node = dev - > of_node ;
struct xhci_hcd_mtk * mtk ;
const struct hc_driver * driver ;
struct xhci_hcd * xhci ;
struct resource * res ;
struct usb_hcd * hcd ;
int ret = - ENODEV ;
2021-04-10 13:10:04 +08:00
int wakeup_irq ;
2015-11-24 13:09:55 +02:00
int irq ;
if ( usb_disabled ( ) )
return - ENODEV ;
driver = & xhci_mtk_hc_driver ;
mtk = devm_kzalloc ( dev , sizeof ( * mtk ) , GFP_KERNEL ) ;
if ( ! mtk )
return - ENOMEM ;
mtk - > dev = dev ;
2022-02-14 12:19:05 +01:00
ret = xhci_mtk_vregs_get ( mtk ) ;
if ( ret )
return dev_err_probe ( dev , ret , " Failed to get regulators \n " ) ;
2015-11-24 13:09:55 +02:00
2017-10-13 16:26:38 +08:00
ret = xhci_mtk_clks_get ( mtk ) ;
if ( ret )
return ret ;
2017-01-18 14:08:24 +08:00
2021-04-10 13:10:04 +08:00
irq = platform_get_irq_byname_optional ( pdev , " host " ) ;
if ( irq < 0 ) {
if ( irq = = - EPROBE_DEFER )
return irq ;
/* for backward compatibility */
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
}
wakeup_irq = platform_get_irq_byname_optional ( pdev , " wakeup " ) ;
if ( wakeup_irq = = - EPROBE_DEFER )
return wakeup_irq ;
2015-11-24 13:09:55 +02:00
mtk - > lpm_support = of_property_read_bool ( node , " usb3-lpm-capable " ) ;
2021-03-31 17:05:53 +08:00
mtk - > u2_lpm_disable = of_property_read_bool ( node , " usb2-lpm-disable " ) ;
2017-10-13 16:26:36 +08:00
/* optional property, ignore the error if it does not exist */
of_property_read_u32 ( node , " mediatek,u3p-dis-msk " ,
& mtk - > u3p_dis_msk ) ;
2021-08-17 16:36:24 +08:00
of_property_read_u32 ( node , " mediatek,u2p-dis-msk " ,
& mtk - > u2p_dis_msk ) ;
2015-11-24 13:09:55 +02:00
ret = usb_wakeup_of_property_parse ( mtk , node ) ;
2018-01-03 16:53:20 +08:00
if ( ret ) {
dev_err ( dev , " failed to parse uwk property \n " ) ;
2015-11-24 13:09:55 +02:00
return ret ;
2018-01-03 16:53:20 +08:00
}
2015-11-24 13:09:55 +02:00
2021-04-10 13:10:04 +08:00
pm_runtime_set_active ( dev ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_set_autosuspend_delay ( dev , 4000 ) ;
2015-11-24 13:09:55 +02:00
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
2022-02-14 12:19:05 +01:00
ret = regulator_bulk_enable ( BULK_VREGS_NUM , mtk - > supplies ) ;
2015-11-24 13:09:55 +02:00
if ( ret )
goto disable_pm ;
2021-04-10 13:10:05 +08:00
ret = clk_bulk_prepare_enable ( BULK_CLKS_NUM , mtk - > clks ) ;
2015-11-24 13:09:55 +02:00
if ( ret )
goto disable_ldos ;
hcd = usb_create_hcd ( driver , dev , dev_name ( dev ) ) ;
if ( ! hcd ) {
ret = - ENOMEM ;
goto disable_clk ;
}
/*
* USB 2.0 roothub is stored in the platform_device .
* Swap it with mtk HCD .
*/
mtk - > hcd = platform_get_drvdata ( pdev ) ;
platform_set_drvdata ( pdev , mtk ) ;
2016-10-19 10:28:22 +08:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " mac " ) ;
2015-11-24 13:09:55 +02:00
hcd - > regs = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( hcd - > regs ) ) {
ret = PTR_ERR ( hcd - > regs ) ;
goto put_usb2_hcd ;
}
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = resource_size ( res ) ;
2016-10-19 10:28:22 +08:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " ippc " ) ;
if ( res ) { /* ippc register is optional */
mtk - > ippc_regs = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( mtk - > ippc_regs ) ) {
ret = PTR_ERR ( mtk - > ippc_regs ) ;
goto put_usb2_hcd ;
}
mtk - > has_ippc = true ;
2015-11-24 13:09:55 +02:00
}
device_init_wakeup ( dev , true ) ;
xhci = hcd_to_xhci ( hcd ) ;
xhci - > main_hcd = hcd ;
2017-12-08 17:59:13 +02:00
/*
* imod_interval is the interrupt moderation value in nanoseconds .
* The increment interval is 8 times as much as that defined in
* the xHCI spec on MTK ' s controller .
*/
xhci - > imod_interval = 5000 ;
device_property_read_u32 ( dev , " imod-interval-ns " , & xhci - > imod_interval ) ;
2015-11-24 13:09:55 +02:00
xhci - > shared_hcd = usb_create_shared_hcd ( driver , dev ,
dev_name ( dev ) , hcd ) ;
if ( ! xhci - > shared_hcd ) {
ret = - ENOMEM ;
2018-03-03 22:43:06 +01:00
goto disable_device_wakeup ;
2015-11-24 13:09:55 +02:00
}
ret = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
if ( ret )
goto put_usb3_hcd ;
2021-03-31 17:05:52 +08:00
if ( HCC_MAX_PSA ( xhci - > hcc_params ) > = 4 & &
! ( xhci - > quirks & XHCI_BROKEN_STREAMS ) )
2017-03-09 15:39:34 +02:00
xhci - > shared_hcd - > can_do_streams = 1 ;
2015-11-24 13:09:55 +02:00
ret = usb_add_hcd ( xhci - > shared_hcd , irq , IRQF_SHARED ) ;
if ( ret )
goto dealloc_usb2_hcd ;
2021-04-10 13:10:04 +08:00
if ( wakeup_irq > 0 ) {
2021-10-25 15:01:54 +08:00
ret = dev_pm_set_dedicated_wake_irq_reverse ( dev , wakeup_irq ) ;
2021-04-10 13:10:04 +08:00
if ( ret ) {
dev_err ( dev , " set wakeup irq %d failed \n " , wakeup_irq ) ;
goto dealloc_usb3_hcd ;
}
dev_info ( dev , " wakeup irq %d \n " , wakeup_irq ) ;
}
device_enable_async_suspend ( dev ) ;
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
pm_runtime_forbid ( dev ) ;
2015-11-24 13:09:55 +02:00
return 0 ;
2021-04-10 13:10:04 +08:00
dealloc_usb3_hcd :
usb_remove_hcd ( xhci - > shared_hcd ) ;
xhci - > shared_hcd = NULL ;
2015-11-24 13:09:55 +02:00
dealloc_usb2_hcd :
usb_remove_hcd ( hcd ) ;
put_usb3_hcd :
xhci_mtk_sch_exit ( mtk ) ;
usb_put_hcd ( xhci - > shared_hcd ) ;
2018-03-03 22:43:06 +01:00
disable_device_wakeup :
2015-11-24 13:09:55 +02:00
device_init_wakeup ( dev , false ) ;
put_usb2_hcd :
usb_put_hcd ( hcd ) ;
disable_clk :
2021-04-10 13:10:05 +08:00
clk_bulk_disable_unprepare ( BULK_CLKS_NUM , mtk - > clks ) ;
2015-11-24 13:09:55 +02:00
disable_ldos :
2022-02-14 12:19:05 +01:00
regulator_bulk_disable ( BULK_VREGS_NUM , mtk - > supplies ) ;
2015-11-24 13:09:55 +02:00
disable_pm :
2021-08-17 16:36:23 +08:00
pm_runtime_put_noidle ( dev ) ;
2015-11-24 13:09:55 +02:00
pm_runtime_disable ( dev ) ;
return ret ;
}
2021-04-10 13:10:04 +08:00
static int xhci_mtk_remove ( struct platform_device * pdev )
2015-11-24 13:09:55 +02:00
{
2021-04-10 13:10:04 +08:00
struct xhci_hcd_mtk * mtk = platform_get_drvdata ( pdev ) ;
2015-11-24 13:09:55 +02:00
struct usb_hcd * hcd = mtk - > hcd ;
struct xhci_hcd * xhci = hcd_to_xhci ( hcd ) ;
2018-11-09 17:21:17 +02:00
struct usb_hcd * shared_hcd = xhci - > shared_hcd ;
2021-04-10 13:10:04 +08:00
struct device * dev = & pdev - > dev ;
2015-11-24 13:09:55 +02:00
2021-04-10 13:10:04 +08:00
pm_runtime_get_sync ( dev ) ;
xhci - > xhc_state | = XHCI_STATE_REMOVING ;
dev_pm_clear_wake_irq ( dev ) ;
device_init_wakeup ( dev , false ) ;
2020-06-24 16:59:47 +03:00
2018-11-09 17:21:17 +02:00
usb_remove_hcd ( shared_hcd ) ;
xhci - > shared_hcd = NULL ;
2015-11-24 13:09:55 +02:00
usb_remove_hcd ( hcd ) ;
2018-11-09 17:21:17 +02:00
usb_put_hcd ( shared_hcd ) ;
2015-11-24 13:09:55 +02:00
usb_put_hcd ( hcd ) ;
xhci_mtk_sch_exit ( mtk ) ;
2021-04-10 13:10:05 +08:00
clk_bulk_disable_unprepare ( BULK_CLKS_NUM , mtk - > clks ) ;
2022-02-14 12:19:05 +01:00
regulator_bulk_disable ( BULK_VREGS_NUM , mtk - > supplies ) ;
2015-11-24 13:09:55 +02:00
2021-04-10 13:10:04 +08:00
pm_runtime_disable ( dev ) ;
pm_runtime_put_noidle ( dev ) ;
pm_runtime_set_suspended ( dev ) ;
2015-11-24 13:09:55 +02:00
return 0 ;
}
2016-03-02 16:24:04 +01:00
static int __maybe_unused xhci_mtk_suspend ( struct device * dev )
2015-11-24 13:09:55 +02:00
{
struct xhci_hcd_mtk * mtk = dev_get_drvdata ( dev ) ;
2016-01-26 17:50:10 +02:00
struct usb_hcd * hcd = mtk - > hcd ;
struct xhci_hcd * xhci = hcd_to_xhci ( hcd ) ;
2021-04-10 13:10:02 +08:00
int ret ;
2016-01-26 17:50:10 +02:00
xhci_dbg ( xhci , " %s: stop port polling \n " , __func__ ) ;
clear_bit ( HCD_FLAG_POLL_RH , & hcd - > flags ) ;
del_timer_sync ( & hcd - > rh_timer ) ;
clear_bit ( HCD_FLAG_POLL_RH , & xhci - > shared_hcd - > flags ) ;
del_timer_sync ( & xhci - > shared_hcd - > rh_timer ) ;
2015-11-24 13:09:55 +02:00
2021-04-10 13:10:02 +08:00
ret = xhci_mtk_host_disable ( mtk ) ;
if ( ret )
goto restart_poll_rh ;
2021-04-10 13:10:05 +08:00
clk_bulk_disable_unprepare ( BULK_CLKS_NUM , mtk - > clks ) ;
2018-01-03 16:53:20 +08:00
usb_wakeup_set ( mtk , true ) ;
2015-11-24 13:09:55 +02:00
return 0 ;
2021-04-10 13:10:02 +08:00
restart_poll_rh :
xhci_dbg ( xhci , " %s: restart port polling \n " , __func__ ) ;
set_bit ( HCD_FLAG_POLL_RH , & xhci - > shared_hcd - > flags ) ;
usb_hcd_poll_rh_status ( xhci - > shared_hcd ) ;
set_bit ( HCD_FLAG_POLL_RH , & hcd - > flags ) ;
usb_hcd_poll_rh_status ( hcd ) ;
return ret ;
2015-11-24 13:09:55 +02:00
}
2016-03-02 16:24:04 +01:00
static int __maybe_unused xhci_mtk_resume ( struct device * dev )
2015-11-24 13:09:55 +02:00
{
struct xhci_hcd_mtk * mtk = dev_get_drvdata ( dev ) ;
2016-01-26 17:50:10 +02:00
struct usb_hcd * hcd = mtk - > hcd ;
struct xhci_hcd * xhci = hcd_to_xhci ( hcd ) ;
2021-04-10 13:10:02 +08:00
int ret ;
2015-11-24 13:09:55 +02:00
2018-01-03 16:53:20 +08:00
usb_wakeup_set ( mtk , false ) ;
2021-04-10 13:10:05 +08:00
ret = clk_bulk_prepare_enable ( BULK_CLKS_NUM , mtk - > clks ) ;
2021-04-10 13:10:02 +08:00
if ( ret )
goto enable_wakeup ;
ret = xhci_mtk_host_enable ( mtk ) ;
if ( ret )
goto disable_clks ;
2016-01-26 17:50:10 +02:00
xhci_dbg ( xhci , " %s: restart port polling \n " , __func__ ) ;
set_bit ( HCD_FLAG_POLL_RH , & xhci - > shared_hcd - > flags ) ;
usb_hcd_poll_rh_status ( xhci - > shared_hcd ) ;
2018-10-01 18:36:08 +03:00
set_bit ( HCD_FLAG_POLL_RH , & hcd - > flags ) ;
usb_hcd_poll_rh_status ( hcd ) ;
2015-11-24 13:09:55 +02:00
return 0 ;
2021-04-10 13:10:02 +08:00
disable_clks :
2021-04-10 13:10:05 +08:00
clk_bulk_disable_unprepare ( BULK_CLKS_NUM , mtk - > clks ) ;
2021-04-10 13:10:02 +08:00
enable_wakeup :
usb_wakeup_set ( mtk , true ) ;
return ret ;
2015-11-24 13:09:55 +02:00
}
2021-04-10 13:10:04 +08:00
static int __maybe_unused xhci_mtk_runtime_suspend ( struct device * dev )
{
struct xhci_hcd_mtk * mtk = dev_get_drvdata ( dev ) ;
struct xhci_hcd * xhci = hcd_to_xhci ( mtk - > hcd ) ;
int ret = 0 ;
if ( xhci - > xhc_state )
return - ESHUTDOWN ;
2021-04-16 14:48:26 +08:00
if ( device_may_wakeup ( dev ) )
ret = xhci_mtk_suspend ( dev ) ;
2021-04-10 13:10:04 +08:00
/* -EBUSY: let PM automatically reschedule another autosuspend */
return ret ? - EBUSY : 0 ;
}
static int __maybe_unused xhci_mtk_runtime_resume ( struct device * dev )
{
struct xhci_hcd_mtk * mtk = dev_get_drvdata ( dev ) ;
struct xhci_hcd * xhci = hcd_to_xhci ( mtk - > hcd ) ;
int ret = 0 ;
if ( xhci - > xhc_state )
return - ESHUTDOWN ;
if ( device_may_wakeup ( dev ) )
ret = xhci_mtk_resume ( dev ) ;
return ret ;
}
2015-11-24 13:09:55 +02:00
static const struct dev_pm_ops xhci_mtk_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( xhci_mtk_suspend , xhci_mtk_resume )
2021-04-10 13:10:04 +08:00
SET_RUNTIME_PM_OPS ( xhci_mtk_runtime_suspend ,
xhci_mtk_runtime_resume , NULL )
2015-11-24 13:09:55 +02:00
} ;
2021-04-10 13:10:04 +08:00
# define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL)
2015-11-24 13:09:55 +02:00
static const struct of_device_id mtk_xhci_of_match [ ] = {
{ . compatible = " mediatek,mt8173-xhci " } ,
2021-08-17 16:36:29 +08:00
{ . compatible = " mediatek,mt8195-xhci " } ,
2017-08-30 19:34:09 +08:00
{ . compatible = " mediatek,mtk-xhci " } ,
2015-11-24 13:09:55 +02:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mtk_xhci_of_match ) ;
static struct platform_driver mtk_xhci_driver = {
. probe = xhci_mtk_probe ,
. remove = xhci_mtk_remove ,
. driver = {
. name = " xhci-mtk " ,
. pm = DEV_PM_OPS ,
2021-03-23 15:02:50 +08:00
. of_match_table = mtk_xhci_of_match ,
2015-11-24 13:09:55 +02:00
} ,
} ;
static int __init xhci_mtk_init ( void )
{
xhci_init_driver ( & xhci_mtk_hc_driver , & xhci_mtk_overrides ) ;
return platform_driver_register ( & mtk_xhci_driver ) ;
}
module_init ( xhci_mtk_init ) ;
static void __exit xhci_mtk_exit ( void )
{
platform_driver_unregister ( & mtk_xhci_driver ) ;
}
module_exit ( xhci_mtk_exit ) ;
MODULE_AUTHOR ( " Chunfeng Yun <chunfeng.yun@mediatek.com> " ) ;
MODULE_DESCRIPTION ( " MediaTek xHCI Host Controller Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;