2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-09-22 22:34:01 +03:00
/*
* phy - brcm - usb - init . c - Broadcom USB Phy chip specific init functions
*
* Copyright ( C ) 2014 - 2017 Broadcom
*/
/*
* This module contains USB PHY initialization for power up and S3 resume
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/soc/brcmstb/brcmstb.h>
# include "phy-brcm-usb-init.h"
# define PHY_PORTS 2
# define PHY_PORT_SELECT_0 0
# define PHY_PORT_SELECT_1 0x1000
/* Register definitions for the USB CTRL block */
# define USB_CTRL_SETUP 0x00
2022-10-06 00:30:15 +03:00
# define USB_CTRL_SETUP_BABO_MASK BIT(0)
# define USB_CTRL_SETUP_FNHW_MASK BIT(1)
# define USB_CTRL_SETUP_FNBO_MASK BIT(2)
# define USB_CTRL_SETUP_WABO_MASK BIT(3)
# define USB_CTRL_SETUP_IOC_MASK BIT(4)
# define USB_CTRL_SETUP_IPP_MASK BIT(5)
# define USB_CTRL_SETUP_SCB_CLIENT_SWAP_MASK BIT(13) /* option */
# define USB_CTRL_SETUP_SCB1_EN_MASK BIT(14) /* option */
# define USB_CTRL_SETUP_SCB2_EN_MASK BIT(15) /* option */
# define USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK BIT(17) /* option */
# define USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK BIT(16) /* option */
# define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) /* option */
# define USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK BIT(26) /* option */
# define USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK BIT(27) /* opt */
2023-06-15 23:06:17 +03:00
# define USB_CTRL_SETUP_OC_DISABLE_PORT0_MASK BIT(28)
# define USB_CTRL_SETUP_OC_DISABLE_PORT1_MASK BIT(29)
# define USB_CTRL_SETUP_OC_DISABLE_MASK GENMASK(29, 28) /* option */
# define USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK BIT(30)
# define USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK BIT(31)
2022-10-06 00:30:15 +03:00
# define USB_CTRL_SETUP_OC3_DISABLE_MASK GENMASK(31, 30) /* option */
2017-09-22 22:34:01 +03:00
# define USB_CTRL_PLL_CTL 0x04
2022-10-06 00:30:15 +03:00
# define USB_CTRL_PLL_CTL_PLL_SUSPEND_EN_MASK BIT(27)
# define USB_CTRL_PLL_CTL_PLL_RESETB_MASK BIT(30)
# define USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK BIT(31) /* option */
2017-09-22 22:34:01 +03:00
# define USB_CTRL_EBRIDGE 0x0c
2022-10-06 00:30:15 +03:00
# define USB_CTRL_EBRIDGE_EBR_SCB_SIZE_MASK GENMASK(11, 7) /* option */
# define USB_CTRL_EBRIDGE_ESTOP_SCB_REQ_MASK BIT(17) /* option */
2017-12-27 22:28:49 +03:00
# define USB_CTRL_OBRIDGE 0x10
2022-10-06 00:30:15 +03:00
# define USB_CTRL_OBRIDGE_LS_KEEP_ALIVE_MASK BIT(27)
2017-09-22 22:34:01 +03:00
# define USB_CTRL_MDIO 0x14
# define USB_CTRL_MDIO2 0x18
# define USB_CTRL_UTMI_CTL_1 0x2c
2022-10-06 00:30:15 +03:00
# define USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_MASK BIT(11)
# define USB_CTRL_UTMI_CTL_1_POWER_UP_FSM_EN_P1_MASK BIT(27)
2017-09-22 22:34:01 +03:00
# define USB_CTRL_USB_PM 0x34
2022-10-06 00:30:15 +03:00
# define USB_CTRL_USB_PM_RMTWKUP_EN_MASK BIT(0)
# define USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK GENMASK(21, 20) /* option */
# define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK BIT(22) /* option */
# define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK BIT(23) /* option */
# define USB_CTRL_USB_PM_USB20_HC_RESETB_MASK GENMASK(29, 28) /* option */
# define USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK BIT(30) /* option */
# define USB_CTRL_USB_PM_SOFT_RESET_MASK BIT(30) /* option */
# define USB_CTRL_USB_PM_USB_PWRDN_MASK BIT(31) /* option */
2020-01-03 21:18:02 +03:00
# define USB_CTRL_USB_PM_STATUS 0x38
2017-09-22 22:34:01 +03:00
# define USB_CTRL_USB30_CTL1 0x60
2022-10-06 00:30:15 +03:00
# define USB_CTRL_USB30_CTL1_PHY3_PLL_SEQ_START_MASK BIT(4)
# define USB_CTRL_USB30_CTL1_PHY3_RESETB_MASK BIT(16)
# define USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK BIT(17) /* option */
# define USB_CTRL_USB30_CTL1_USB3_IOC_MASK BIT(28) /* option */
# define USB_CTRL_USB30_CTL1_USB3_IPP_MASK BIT(29) /* option */
2017-09-22 22:34:01 +03:00
# define USB_CTRL_USB30_PCTL 0x70
2022-10-06 00:30:15 +03:00
# define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_MASK BIT(1)
# define USB_CTRL_USB30_PCTL_PHY3_IDDQ_OVERRIDE_MASK BIT(15)
# define USB_CTRL_USB30_PCTL_PHY3_SOFT_RESETB_P1_MASK BIT(17)
2017-09-22 22:34:01 +03:00
# define USB_CTRL_USB_DEVICE_CTL1 0x90
2022-10-06 00:30:15 +03:00
# define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK GENMASK(1, 0) /* option */
2017-09-22 22:34:01 +03:00
/* Register definitions for the XHCI EC block */
# define USB_XHCI_EC_IRAADR 0x658
# define USB_XHCI_EC_IRADAT 0x65c
enum brcm_family_type {
BRCM_FAMILY_3390A0 ,
2022-02-18 20:24:59 +03:00
BRCM_FAMILY_4908 ,
2017-09-22 22:34:01 +03:00
BRCM_FAMILY_7250B0 ,
BRCM_FAMILY_7271A0 ,
BRCM_FAMILY_7364A0 ,
BRCM_FAMILY_7366C0 ,
BRCM_FAMILY_74371A0 ,
BRCM_FAMILY_7439B0 ,
BRCM_FAMILY_7445D0 ,
BRCM_FAMILY_7260A0 ,
BRCM_FAMILY_7278A0 ,
BRCM_FAMILY_COUNT ,
} ;
# define USB_BRCM_FAMILY(chip) \
[ BRCM_FAMILY_ # # chip ] = __stringify ( chip )
static const char * family_names [ BRCM_FAMILY_COUNT ] = {
USB_BRCM_FAMILY ( 3390 A0 ) ,
2022-02-18 20:24:59 +03:00
USB_BRCM_FAMILY ( 4908 ) ,
2017-09-22 22:34:01 +03:00
USB_BRCM_FAMILY ( 7250 B0 ) ,
USB_BRCM_FAMILY ( 7271 A0 ) ,
USB_BRCM_FAMILY ( 7364 A0 ) ,
USB_BRCM_FAMILY ( 7366 C0 ) ,
USB_BRCM_FAMILY ( 74371 A0 ) ,
USB_BRCM_FAMILY ( 7439 B0 ) ,
USB_BRCM_FAMILY ( 7445 D0 ) ,
USB_BRCM_FAMILY ( 7260 A0 ) ,
USB_BRCM_FAMILY ( 7278 A0 ) ,
} ;
enum {
USB_CTRL_SETUP_SCB1_EN_SELECTOR ,
USB_CTRL_SETUP_SCB2_EN_SELECTOR ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR ,
USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_SELECTOR ,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR ,
USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR ,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR ,
USB_CTRL_USB_PM_USB_PWRDN_SELECTOR ,
USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_SELECTOR ,
USB_CTRL_USB30_CTL1_USB3_IOC_SELECTOR ,
USB_CTRL_USB30_CTL1_USB3_IPP_SELECTOR ,
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR ,
USB_CTRL_USB_PM_SOFT_RESET_SELECTOR ,
USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_SELECTOR ,
USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_SELECTOR ,
USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR ,
USB_CTRL_SETUP_ENDIAN_SELECTOR ,
USB_CTRL_SELECTOR_COUNT ,
} ;
# define USB_CTRL_MASK_FAMILY(params, reg, field) \
( params - > usb_reg_bits_map [ USB_CTRL_ # # reg # # _ # # field # # _SELECTOR ] )
# define USB_CTRL_SET_FAMILY(params, reg, field) \
usb_ctrl_set_family ( params , USB_CTRL_ # # reg , \
USB_CTRL_ # # reg # # _ # # field # # _SELECTOR )
# define USB_CTRL_UNSET_FAMILY(params, reg, field) \
usb_ctrl_unset_family ( params , USB_CTRL_ # # reg , \
USB_CTRL_ # # reg # # _ # # field # # _SELECTOR )
# define MDIO_USB2 0
# define MDIO_USB3 BIT(31)
# define USB_CTRL_SETUP_ENDIAN_BITS ( \
USB_CTRL_MASK ( SETUP , BABO ) | \
USB_CTRL_MASK ( SETUP , FNHW ) | \
USB_CTRL_MASK ( SETUP , FNBO ) | \
USB_CTRL_MASK ( SETUP , WABO ) )
# ifdef __LITTLE_ENDIAN
# define ENDIAN_SETTINGS ( \
USB_CTRL_MASK ( SETUP , BABO ) | \
USB_CTRL_MASK ( SETUP , FNHW ) )
# else
# define ENDIAN_SETTINGS ( \
USB_CTRL_MASK ( SETUP , FNHW ) | \
USB_CTRL_MASK ( SETUP , FNBO ) | \
USB_CTRL_MASK ( SETUP , WABO ) )
# endif
struct id_to_type {
u32 id ;
int type ;
} ;
static const struct id_to_type id_to_type_table [ ] = {
{ 0x33900000 , BRCM_FAMILY_3390A0 } ,
{ 0x72500010 , BRCM_FAMILY_7250B0 } ,
{ 0x72600000 , BRCM_FAMILY_7260A0 } ,
2020-01-03 21:17:59 +03:00
{ 0x72550000 , BRCM_FAMILY_7260A0 } ,
2017-09-22 22:34:01 +03:00
{ 0x72680000 , BRCM_FAMILY_7271A0 } ,
{ 0x72710000 , BRCM_FAMILY_7271A0 } ,
{ 0x73640000 , BRCM_FAMILY_7364A0 } ,
{ 0x73660020 , BRCM_FAMILY_7366C0 } ,
{ 0x07437100 , BRCM_FAMILY_74371A0 } ,
{ 0x74390010 , BRCM_FAMILY_7439B0 } ,
{ 0x74450030 , BRCM_FAMILY_7445D0 } ,
{ 0x72780000 , BRCM_FAMILY_7278A0 } ,
{ 0 , BRCM_FAMILY_7271A0 } , /* default */
} ;
static const u32
usb_reg_bits_map_table [ BRCM_FAMILY_COUNT ] [ USB_CTRL_SELECTOR_COUNT ] = {
/* 3390B0 */
[ BRCM_FAMILY_3390A0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK ,
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
2022-02-18 20:24:59 +03:00
/* 4908 */
[ BRCM_FAMILY_4908 ] = {
0 , /* USB_CTRL_SETUP_SCB1_EN_MASK */
0 , /* USB_CTRL_SETUP_SCB2_EN_MASK */
0 , /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
0 , /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
0 , /* USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK */
0 , /* USB_CTRL_SETUP ENDIAN bits */
} ,
2017-09-22 22:34:01 +03:00
/* 7250b0 */
[ BRCM_FAMILY_7250B0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK ,
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK ,
0 , /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7271a0 */
[ BRCM_FAMILY_7271A0 ] = {
0 , /* USB_CTRL_SETUP_SCB1_EN_MASK */
0 , /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK ,
USB_CTRL_USB_PM_SOFT_RESET_MASK ,
USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK ,
USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK ,
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7364a0 */
[ BRCM_FAMILY_7364A0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK ,
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK ,
0 , /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7366c0 */
[ BRCM_FAMILY_7366C0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 74371A0 */
[ BRCM_FAMILY_74371A0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK ,
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
2023-06-15 23:06:17 +03:00
0 , /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */
0 , /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */
2017-09-22 22:34:01 +03:00
0 , /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK ,
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB30_CTL1_USB3_IOC_MASK ,
USB_CTRL_USB30_CTL1_USB3_IPP_MASK ,
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
0 , /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7439B0 */
[ BRCM_FAMILY_7439B0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK ,
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7445d0 */
[ BRCM_FAMILY_7445D0 ] = {
USB_CTRL_SETUP_SCB1_EN_MASK ,
USB_CTRL_SETUP_SCB2_EN_MASK ,
USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK ,
0 , /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK ,
0 , /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB_PM_USB_PWRDN_MASK */
USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK ,
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
0 , /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
0 , /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7260a0 */
[ BRCM_FAMILY_7260A0 ] = {
0 , /* USB_CTRL_SETUP_SCB1_EN_MASK */
0 , /* USB_CTRL_SETUP_SCB2_EN_MASK */
USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK ,
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK ,
USB_CTRL_USB_PM_SOFT_RESET_MASK ,
USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK ,
USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK ,
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK ,
ENDIAN_SETTINGS , /* USB_CTRL_SETUP ENDIAN bits */
} ,
/* 7278a0 */
[ BRCM_FAMILY_7278A0 ] = {
0 , /* USB_CTRL_SETUP_SCB1_EN_MASK */
0 , /* USB_CTRL_SETUP_SCB2_EN_MASK */
0 , /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */
USB_CTRL_SETUP_STRAP_IPP_SEL_MASK ,
2023-06-15 23:06:17 +03:00
USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK ,
USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK ,
2017-09-22 22:34:01 +03:00
USB_CTRL_SETUP_OC3_DISABLE_MASK ,
0 , /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK ,
USB_CTRL_USB_PM_USB_PWRDN_MASK ,
0 , /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
0 , /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK ,
USB_CTRL_USB_PM_SOFT_RESET_MASK ,
0 , /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
0 , /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
0 , /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */
0 , /* USB_CTRL_SETUP ENDIAN bits */
} ,
} ;
static inline
void usb_ctrl_unset_family ( struct brcm_usb_init_params * params ,
u32 reg_offset , u32 field )
{
u32 mask ;
mask = params - > usb_reg_bits_map [ field ] ;
2020-01-03 21:18:06 +03:00
brcm_usb_ctrl_unset ( params - > regs [ BRCM_REGS_CTRL ] + reg_offset , mask ) ;
2017-09-22 22:34:01 +03:00
} ;
static inline
void usb_ctrl_set_family ( struct brcm_usb_init_params * params ,
u32 reg_offset , u32 field )
{
u32 mask ;
mask = params - > usb_reg_bits_map [ field ] ;
2020-01-03 21:18:06 +03:00
brcm_usb_ctrl_set ( params - > regs [ BRCM_REGS_CTRL ] + reg_offset , mask ) ;
2017-09-22 22:34:01 +03:00
} ;
static u32 brcmusb_usb_mdio_read ( void __iomem * ctrl_base , u32 reg , int mode )
{
u32 data ;
data = ( reg < < 16 ) | mode ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
data | = ( 1 < < 24 ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
data & = ~ ( 1 < < 24 ) ;
/* wait for the 60MHz parallel to serial shifter */
usleep_range ( 10 , 20 ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
/* wait for the 60MHz parallel to serial shifter */
usleep_range ( 10 , 20 ) ;
2020-01-03 21:18:03 +03:00
return brcm_usb_readl ( USB_CTRL_REG ( ctrl_base , MDIO2 ) ) & 0xffff ;
2017-09-22 22:34:01 +03:00
}
static void brcmusb_usb_mdio_write ( void __iomem * ctrl_base , u32 reg ,
u32 val , int mode )
{
u32 data ;
data = ( reg < < 16 ) | val | mode ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
data | = ( 1 < < 25 ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
data & = ~ ( 1 < < 25 ) ;
/* wait for the 60MHz parallel to serial shifter */
usleep_range ( 10 , 20 ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( data , USB_CTRL_REG ( ctrl_base , MDIO ) ) ;
2017-09-22 22:34:01 +03:00
/* wait for the 60MHz parallel to serial shifter */
usleep_range ( 10 , 20 ) ;
}
static void brcmusb_usb_phy_ldo_fix ( void __iomem * ctrl_base )
{
/* first disable FSM but also leave it that way */
/* to allow normal suspend/resume */
USB_CTRL_UNSET ( ctrl_base , UTMI_CTL_1 , POWER_UP_FSM_EN ) ;
USB_CTRL_UNSET ( ctrl_base , UTMI_CTL_1 , POWER_UP_FSM_EN_P1 ) ;
/* reset USB 2.0 PLL */
USB_CTRL_UNSET ( ctrl_base , PLL_CTL , PLL_RESETB ) ;
/* PLL reset period */
udelay ( 1 ) ;
USB_CTRL_SET ( ctrl_base , PLL_CTL , PLL_RESETB ) ;
/* Give PLL enough time to lock */
usleep_range ( 1000 , 2000 ) ;
}
static void brcmusb_usb2_eye_fix ( void __iomem * ctrl_base )
{
/* Increase USB 2.0 TX level to meet spec requirement */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x80a0 , MDIO_USB2 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x0a , 0xc6a0 , MDIO_USB2 ) ;
}
static void brcmusb_usb3_pll_fix ( void __iomem * ctrl_base )
{
/* Set correct window for PLL lock detect */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x8000 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x07 , 0x1503 , MDIO_USB3 ) ;
}
static void brcmusb_usb3_enable_pipe_reset ( void __iomem * ctrl_base )
{
u32 val ;
/* Re-enable USB 3.0 pipe reset */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x8000 , MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x0f , MDIO_USB3 ) | 0x200 ;
brcmusb_usb_mdio_write ( ctrl_base , 0x0f , val , MDIO_USB3 ) ;
}
static void brcmusb_usb3_enable_sigdet ( void __iomem * ctrl_base )
{
u32 val , ofs ;
int ii ;
ofs = 0 ;
for ( ii = 0 ; ii < PHY_PORTS ; + + ii ) {
/* Set correct default for sigdet */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , ( 0x8080 + ofs ) ,
MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x05 , MDIO_USB3 ) ;
val = ( val & ~ 0x800f ) | 0x800d ;
brcmusb_usb_mdio_write ( ctrl_base , 0x05 , val , MDIO_USB3 ) ;
ofs = PHY_PORT_SELECT_1 ;
}
}
static void brcmusb_usb3_enable_skip_align ( void __iomem * ctrl_base )
{
u32 val , ofs ;
int ii ;
ofs = 0 ;
for ( ii = 0 ; ii < PHY_PORTS ; + + ii ) {
/* Set correct default for SKIP align */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , ( 0x8060 + ofs ) ,
MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x01 , MDIO_USB3 ) | 0x200 ;
brcmusb_usb_mdio_write ( ctrl_base , 0x01 , val , MDIO_USB3 ) ;
ofs = PHY_PORT_SELECT_1 ;
}
}
static void brcmusb_usb3_unfreeze_aeq ( void __iomem * ctrl_base )
{
u32 val , ofs ;
int ii ;
ofs = 0 ;
for ( ii = 0 ; ii < PHY_PORTS ; + + ii ) {
/* Let EQ freeze after TSEQ */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , ( 0x80e0 + ofs ) ,
MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x01 , MDIO_USB3 ) ;
val & = ~ 0x0008 ;
brcmusb_usb_mdio_write ( ctrl_base , 0x01 , val , MDIO_USB3 ) ;
ofs = PHY_PORT_SELECT_1 ;
}
}
static void brcmusb_usb3_pll_54mhz ( struct brcm_usb_init_params * params )
{
u32 ofs ;
int ii ;
2020-01-03 21:18:06 +03:00
void __iomem * ctrl_base = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
/*
* On newer B53 based SoC ' s , the reference clock for the
* 3.0 PLL has been changed from 50 MHz to 54 MHz so the
* PLL needs to be reprogrammed .
* See SWLINUX - 4006.
*
* On the 7364 C0 , the reference clock for the
* 3.0 PLL has been changed from 50 MHz to 54 MHz to
* work around a MOCA issue .
* See SWLINUX - 4169.
*/
switch ( params - > selected_family ) {
case BRCM_FAMILY_3390A0 :
2022-02-18 20:24:59 +03:00
case BRCM_FAMILY_4908 :
2017-09-22 22:34:01 +03:00
case BRCM_FAMILY_7250B0 :
case BRCM_FAMILY_7366C0 :
case BRCM_FAMILY_74371A0 :
case BRCM_FAMILY_7439B0 :
case BRCM_FAMILY_7445D0 :
case BRCM_FAMILY_7260A0 :
return ;
case BRCM_FAMILY_7364A0 :
if ( BRCM_REV ( params - > family_id ) < 0x20 )
return ;
break ;
}
/* set USB 3.0 PLL to accept 54Mhz reference clock */
USB_CTRL_UNSET ( ctrl_base , USB30_CTL1 , PHY3_PLL_SEQ_START ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x8000 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x10 , 0x5784 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x11 , 0x01d0 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x12 , 0x1DE8 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x13 , 0xAA80 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x14 , 0x8826 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x15 , 0x0044 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x16 , 0x8000 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x17 , 0x0851 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x18 , 0x0000 , MDIO_USB3 ) ;
/* both ports */
ofs = 0 ;
for ( ii = 0 ; ii < PHY_PORTS ; + + ii ) {
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , ( 0x8040 + ofs ) ,
MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x03 , 0x0090 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x04 , 0x0134 , MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , ( 0x8020 + ofs ) ,
MDIO_USB3 ) ;
brcmusb_usb_mdio_write ( ctrl_base , 0x01 , 0x00e2 , MDIO_USB3 ) ;
ofs = PHY_PORT_SELECT_1 ;
}
/* restart PLL sequence */
USB_CTRL_SET ( ctrl_base , USB30_CTL1 , PHY3_PLL_SEQ_START ) ;
/* Give PLL enough time to lock */
usleep_range ( 1000 , 2000 ) ;
}
static void brcmusb_usb3_ssc_enable ( void __iomem * ctrl_base )
{
u32 val ;
/* Enable USB 3.0 TX spread spectrum */
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x8040 , MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x01 , MDIO_USB3 ) | 0xf ;
brcmusb_usb_mdio_write ( ctrl_base , 0x01 , val , MDIO_USB3 ) ;
/* Currently, USB 3.0 SSC is enabled via port 0 MDIO registers,
* which should have been adequate . However , due to a bug in the
* USB 3.0 PHY , it must be enabled via both ports ( HWUSB3DVT - 26 ) .
*/
brcmusb_usb_mdio_write ( ctrl_base , 0x1f , 0x9040 , MDIO_USB3 ) ;
val = brcmusb_usb_mdio_read ( ctrl_base , 0x01 , MDIO_USB3 ) | 0xf ;
brcmusb_usb_mdio_write ( ctrl_base , 0x01 , val , MDIO_USB3 ) ;
}
static void brcmusb_usb3_phy_workarounds ( struct brcm_usb_init_params * params )
{
2020-01-03 21:18:06 +03:00
void __iomem * ctrl_base = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
brcmusb_usb3_pll_fix ( ctrl_base ) ;
brcmusb_usb3_pll_54mhz ( params ) ;
brcmusb_usb3_ssc_enable ( ctrl_base ) ;
brcmusb_usb3_enable_pipe_reset ( ctrl_base ) ;
brcmusb_usb3_enable_sigdet ( ctrl_base ) ;
brcmusb_usb3_enable_skip_align ( ctrl_base ) ;
brcmusb_usb3_unfreeze_aeq ( ctrl_base ) ;
}
static void brcmusb_memc_fix ( struct brcm_usb_init_params * params )
{
u32 prid ;
if ( params - > selected_family ! = BRCM_FAMILY_7445D0 )
return ;
/*
* This is a workaround for HW7445 - 1869 where a DMA write ends up
* doing a read pre - fetch after the end of the DMA buffer . This
* causes a problem when the DMA buffer is at the end of physical
* memory , causing the pre - fetch read to access non - existent memory ,
* and the chip bondout has MEMC2 disabled . When the pre - fetch read
* tries to use the disabled MEMC2 , it hangs the bus . The workaround
* is to disable MEMC2 access in the usb controller which avoids
* the hang .
*/
prid = params - > product_id & 0xfffff000 ;
switch ( prid ) {
case 0x72520000 :
case 0x74480000 :
case 0x74490000 :
case 0x07252000 :
case 0x07448000 :
case 0x07449000 :
USB_CTRL_UNSET_FAMILY ( params , SETUP , SCB2_EN ) ;
}
}
static void brcmusb_usb3_otp_fix ( struct brcm_usb_init_params * params )
{
2020-01-03 21:18:06 +03:00
void __iomem * xhci_ec_base = params - > regs [ BRCM_REGS_XHCI_EC ] ;
2017-09-22 22:34:01 +03:00
u32 val ;
2019-10-15 19:03:32 +03:00
if ( params - > family_id ! = 0x74371000 | | ! xhci_ec_base )
2017-09-22 22:34:01 +03:00
return ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( 0xa20c , USB_XHCI_EC_REG ( xhci_ec_base , IRAADR ) ) ;
val = brcm_usb_readl ( USB_XHCI_EC_REG ( xhci_ec_base , IRADAT ) ) ;
2017-09-22 22:34:01 +03:00
/* set cfg_pick_ss_lock */
val | = ( 1 < < 27 ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( val , USB_XHCI_EC_REG ( xhci_ec_base , IRADAT ) ) ;
2017-09-22 22:34:01 +03:00
/* Reset USB 3.0 PHY for workaround to take effect */
2020-01-03 21:18:06 +03:00
USB_CTRL_UNSET ( params - > regs [ BRCM_REGS_CTRL ] , USB30_CTL1 , PHY3_RESETB ) ;
USB_CTRL_SET ( params - > regs [ BRCM_REGS_CTRL ] , USB30_CTL1 , PHY3_RESETB ) ;
2017-09-22 22:34:01 +03:00
}
static void brcmusb_xhci_soft_reset ( struct brcm_usb_init_params * params ,
int on_off )
{
/* Assert reset */
if ( on_off ) {
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , XHC_SOFT_RESETB ) )
USB_CTRL_UNSET_FAMILY ( params , USB_PM , XHC_SOFT_RESETB ) ;
else
USB_CTRL_UNSET_FAMILY ( params ,
USB30_CTL1 , XHC_SOFT_RESETB ) ;
} else { /* De-assert reset */
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , XHC_SOFT_RESETB ) )
USB_CTRL_SET_FAMILY ( params , USB_PM , XHC_SOFT_RESETB ) ;
else
USB_CTRL_SET_FAMILY ( params , USB30_CTL1 ,
XHC_SOFT_RESETB ) ;
}
}
/*
* Return the best map table family . The order is :
* - exact match of chip and major rev
* - exact match of chip and closest older major rev
* - default chip / rev .
* NOTE : The minor rev is always ignored .
*/
2020-01-03 21:18:03 +03:00
static enum brcm_family_type get_family_type (
2017-09-22 22:34:01 +03:00
struct brcm_usb_init_params * params )
{
int last_type = - 1 ;
u32 last_family = 0 ;
u32 family_no_major ;
unsigned int x ;
u32 family ;
family = params - > family_id & 0xfffffff0 ;
family_no_major = params - > family_id & 0xffffff00 ;
for ( x = 0 ; id_to_type_table [ x ] . id ; x + + ) {
if ( family = = id_to_type_table [ x ] . id )
return id_to_type_table [ x ] . type ;
if ( family_no_major = = ( id_to_type_table [ x ] . id & 0xffffff00 ) )
if ( family > id_to_type_table [ x ] . id & &
last_family < id_to_type_table [ x ] . id ) {
last_family = id_to_type_table [ x ] . id ;
last_type = id_to_type_table [ x ] . type ;
}
}
/* If no match, return the default family */
if ( last_type = = - 1 )
return id_to_type_table [ x ] . type ;
return last_type ;
}
2020-01-03 21:18:03 +03:00
static void usb_init_ipp ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
u32 reg ;
u32 orig_reg ;
/* Starting with the 7445d0, there are no longer separate 3.0
* versions of IOC and IPP .
*/
if ( USB_CTRL_MASK_FAMILY ( params , USB30_CTL1 , USB3_IOC ) ) {
if ( params - > ioc )
USB_CTRL_SET_FAMILY ( params , USB30_CTL1 , USB3_IOC ) ;
if ( params - > ipp = = 1 )
USB_CTRL_SET_FAMILY ( params , USB30_CTL1 , USB3_IPP ) ;
}
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-09-22 22:34:01 +03:00
orig_reg = reg ;
if ( USB_CTRL_MASK_FAMILY ( params , SETUP , STRAP_CC_DRD_MODE_ENABLE_SEL ) )
/* Never use the strap, it's going away. */
reg & = ~ ( USB_CTRL_MASK_FAMILY ( params ,
SETUP ,
STRAP_CC_DRD_MODE_ENABLE_SEL ) ) ;
if ( USB_CTRL_MASK_FAMILY ( params , SETUP , STRAP_IPP_SEL ) )
2020-01-03 21:18:03 +03:00
/* override ipp strap pin (if it exits) */
2017-09-22 22:34:01 +03:00
if ( params - > ipp ! = 2 )
reg & = ~ ( USB_CTRL_MASK_FAMILY ( params , SETUP ,
STRAP_IPP_SEL ) ) ;
/* Override the default OC and PP polarity */
reg & = ~ ( USB_CTRL_MASK ( SETUP , IPP ) | USB_CTRL_MASK ( SETUP , IOC ) ) ;
if ( params - > ioc )
reg | = USB_CTRL_MASK ( SETUP , IOC ) ;
2020-01-03 21:18:03 +03:00
if ( params - > ipp = = 1 )
2017-09-22 22:34:01 +03:00
reg | = USB_CTRL_MASK ( SETUP , IPP ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-09-22 22:34:01 +03:00
/*
* If we ' re changing IPP , make sure power is off long enough
* to turn off any connected devices .
*/
2020-01-03 21:18:03 +03:00
if ( ( reg ^ orig_reg ) & USB_CTRL_MASK ( SETUP , IPP ) )
2017-09-22 22:34:01 +03:00
msleep ( 50 ) ;
}
2020-01-03 21:18:11 +03:00
static void usb_wake_enable ( struct brcm_usb_init_params * params ,
bool enable )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
if ( enable )
USB_CTRL_SET ( ctrl , USB_PM , RMTWKUP_EN ) ;
else
USB_CTRL_UNSET ( ctrl , USB_PM , RMTWKUP_EN ) ;
}
2020-01-03 21:18:03 +03:00
static void usb_init_common ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
u32 reg ;
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
2020-01-03 21:18:02 +03:00
/* Clear any pending wake conditions */
2020-01-03 21:18:11 +03:00
usb_wake_enable ( params , false ) ;
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_PM_STATUS ) ) ;
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , USB_PM_STATUS ) ) ;
2020-01-03 21:18:02 +03:00
2017-09-22 22:34:01 +03:00
/* Take USB out of power down */
if ( USB_CTRL_MASK_FAMILY ( params , PLL_CTL , PLL_IDDQ_PWRDN ) ) {
USB_CTRL_UNSET_FAMILY ( params , PLL_CTL , PLL_IDDQ_PWRDN ) ;
/* 1 millisecond - for USB clocks to settle down */
usleep_range ( 1000 , 2000 ) ;
}
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , USB_PWRDN ) ) {
USB_CTRL_UNSET_FAMILY ( params , USB_PM , USB_PWRDN ) ;
/* 1 millisecond - for USB clocks to settle down */
usleep_range ( 1000 , 2000 ) ;
}
if ( params - > selected_family ! = BRCM_FAMILY_74371A0 & &
( BRCM_ID ( params - > family_id ) ! = 0x7364 ) )
/*
* HW7439 - 637 : 7439 a0 and its derivatives do not have large
* enough descriptor storage for this .
*/
USB_CTRL_SET_FAMILY ( params , SETUP , SS_EHCI64BIT_EN ) ;
/* Block auto PLL suspend by USB2 PHY (Sasi) */
USB_CTRL_SET ( ctrl , PLL_CTL , PLL_SUSPEND_EN ) ;
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-09-22 22:34:01 +03:00
if ( params - > selected_family = = BRCM_FAMILY_7364A0 )
/* Suppress overcurrent indication from USB30 ports for A0 */
reg | = USB_CTRL_MASK_FAMILY ( params , SETUP , OC3_DISABLE ) ;
brcmusb_usb_phy_ldo_fix ( ctrl ) ;
brcmusb_usb2_eye_fix ( ctrl ) ;
/*
2022-06-21 15:24:01 +03:00
* Make sure the second and third memory controller
2017-09-22 22:34:01 +03:00
* interfaces are enabled if they exist .
*/
if ( USB_CTRL_MASK_FAMILY ( params , SETUP , SCB1_EN ) )
reg | = USB_CTRL_MASK_FAMILY ( params , SETUP , SCB1_EN ) ;
if ( USB_CTRL_MASK_FAMILY ( params , SETUP , SCB2_EN ) )
reg | = USB_CTRL_MASK_FAMILY ( params , SETUP , SCB2_EN ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-09-22 22:34:01 +03:00
brcmusb_memc_fix ( params ) ;
2023-06-15 23:06:17 +03:00
/* Workaround for false positive OC for 7439b2 in DRD/Device mode */
if ( ( params - > family_id = = 0x74390012 ) & &
( params - > supported_port_modes ! = USB_CTLR_MODE_HOST ) ) {
USB_CTRL_SET ( ctrl , SETUP , OC_DISABLE_PORT1 ) ;
USB_CTRL_SET_FAMILY ( params , SETUP , OC3_DISABLE_PORT1 ) ;
}
2017-09-22 22:34:01 +03:00
if ( USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 , PORT_MODE ) ) {
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
2017-09-22 22:34:01 +03:00
reg & = ~ USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 ,
PORT_MODE ) ;
2022-10-06 00:30:13 +03:00
reg | = params - > port_mode ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
2017-09-22 22:34:01 +03:00
}
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , BDC_SOFT_RESETB ) ) {
2022-10-06 00:30:13 +03:00
switch ( params - > supported_port_modes ) {
2017-09-22 22:34:01 +03:00
case USB_CTLR_MODE_HOST :
USB_CTRL_UNSET_FAMILY ( params , USB_PM , BDC_SOFT_RESETB ) ;
break ;
default :
2017-12-27 22:28:51 +03:00
USB_CTRL_UNSET_FAMILY ( params , USB_PM , BDC_SOFT_RESETB ) ;
2017-09-22 22:34:01 +03:00
USB_CTRL_SET_FAMILY ( params , USB_PM , BDC_SOFT_RESETB ) ;
break ;
}
}
if ( USB_CTRL_MASK_FAMILY ( params , SETUP , CC_DRD_MODE_ENABLE ) ) {
2022-10-06 00:30:13 +03:00
if ( params - > supported_port_modes = = USB_CTLR_MODE_TYPEC_PD )
2017-09-22 22:34:01 +03:00
USB_CTRL_SET_FAMILY ( params , SETUP , CC_DRD_MODE_ENABLE ) ;
else
USB_CTRL_UNSET_FAMILY ( params , SETUP ,
CC_DRD_MODE_ENABLE ) ;
}
}
2020-01-03 21:18:03 +03:00
static void usb_init_eohci ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
u32 reg ;
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , USB20_HC_RESETB ) )
USB_CTRL_SET_FAMILY ( params , USB_PM , USB20_HC_RESETB ) ;
if ( params - > selected_family = = BRCM_FAMILY_7366C0 )
/*
* Don ' t enable this so the memory controller doesn ' t read
* into memory holes . NOTE : This bit is low true on 7366 C0 .
*/
2017-12-27 22:28:49 +03:00
USB_CTRL_SET ( ctrl , EBRIDGE , ESTOP_SCB_REQ ) ;
2017-09-22 22:34:01 +03:00
/* Setup the endian bits */
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-09-22 22:34:01 +03:00
reg & = ~ USB_CTRL_SETUP_ENDIAN_BITS ;
reg | = USB_CTRL_MASK_FAMILY ( params , SETUP , ENDIAN ) ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , SETUP ) ) ;
2017-12-27 22:28:49 +03:00
if ( params - > selected_family = = BRCM_FAMILY_7271A0 )
/* Enable LS keep alive fix for certain keyboards */
USB_CTRL_SET ( ctrl , OBRIDGE , LS_KEEP_ALIVE ) ;
2020-01-03 21:17:59 +03:00
if ( params - > family_id = = 0x72550000 ) {
/*
* Make the burst size 512 bytes to fix a hardware bug
* on the 7255 a0 . See HW7255 - 24.
*/
2020-01-03 21:18:03 +03:00
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , EBRIDGE ) ) ;
2020-01-03 21:17:59 +03:00
reg & = ~ USB_CTRL_MASK ( EBRIDGE , EBR_SCB_SIZE ) ;
reg | = 0x800 ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , EBRIDGE ) ) ;
2020-01-03 21:17:59 +03:00
}
2017-09-22 22:34:01 +03:00
}
2020-01-03 21:18:03 +03:00
static void usb_init_xhci ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2017-09-22 22:34:01 +03:00
2018-06-08 09:10:15 +03:00
USB_CTRL_UNSET ( ctrl , USB30_PCTL , PHY3_IDDQ_OVERRIDE ) ;
/* 1 millisecond - for USB clocks to settle down */
usleep_range ( 1000 , 2000 ) ;
2017-09-22 22:34:01 +03:00
if ( BRCM_ID ( params - > family_id ) = = 0x7366 ) {
/*
* The PHY3_SOFT_RESETB bits default to the wrong state .
*/
USB_CTRL_SET ( ctrl , USB30_PCTL , PHY3_SOFT_RESETB ) ;
USB_CTRL_SET ( ctrl , USB30_PCTL , PHY3_SOFT_RESETB_P1 ) ;
}
/*
* Kick start USB3 PHY
* Make sure it ' s low to insure a rising edge .
*/
USB_CTRL_UNSET ( ctrl , USB30_CTL1 , PHY3_PLL_SEQ_START ) ;
USB_CTRL_SET ( ctrl , USB30_CTL1 , PHY3_PLL_SEQ_START ) ;
brcmusb_usb3_phy_workarounds ( params ) ;
brcmusb_xhci_soft_reset ( params , 0 ) ;
brcmusb_usb3_otp_fix ( params ) ;
}
2020-01-03 21:18:03 +03:00
static void usb_uninit_common ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
if ( USB_CTRL_MASK_FAMILY ( params , USB_PM , USB_PWRDN ) )
USB_CTRL_SET_FAMILY ( params , USB_PM , USB_PWRDN ) ;
if ( USB_CTRL_MASK_FAMILY ( params , PLL_CTL , PLL_IDDQ_PWRDN ) )
USB_CTRL_SET_FAMILY ( params , PLL_CTL , PLL_IDDQ_PWRDN ) ;
2020-01-03 21:18:11 +03:00
if ( params - > wake_enabled )
usb_wake_enable ( params , true ) ;
2017-09-22 22:34:01 +03:00
}
2020-01-03 21:18:03 +03:00
static void usb_uninit_eohci ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
}
2020-01-03 21:18:03 +03:00
static void usb_uninit_xhci ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
brcmusb_xhci_soft_reset ( params , 1 ) ;
2020-01-03 21:18:06 +03:00
USB_CTRL_SET ( params - > regs [ BRCM_REGS_CTRL ] , USB30_PCTL ,
PHY3_IDDQ_OVERRIDE ) ;
2017-09-22 22:34:01 +03:00
}
2020-01-03 21:18:03 +03:00
static int usb_get_dual_select ( struct brcm_usb_init_params * params )
{
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 21:18:03 +03:00
u32 reg = 0 ;
pr_debug ( " %s \n " , __func__ ) ;
if ( USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 , PORT_MODE ) ) {
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
reg & = USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 ,
PORT_MODE ) ;
}
return reg ;
}
2022-10-06 00:30:13 +03:00
static void usb_set_dual_select ( struct brcm_usb_init_params * params )
2020-01-03 21:18:03 +03:00
{
2020-01-03 21:18:06 +03:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 21:18:03 +03:00
u32 reg ;
pr_debug ( " %s \n " , __func__ ) ;
if ( USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 , PORT_MODE ) ) {
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
reg & = ~ USB_CTRL_MASK_FAMILY ( params , USB_DEVICE_CTL1 ,
PORT_MODE ) ;
2022-10-06 00:30:13 +03:00
reg | = params - > port_mode ;
2020-01-03 21:18:03 +03:00
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
}
}
static const struct brcm_usb_init_ops bcm7445_ops = {
. init_ipp = usb_init_ipp ,
. init_common = usb_init_common ,
. init_eohci = usb_init_eohci ,
. init_xhci = usb_init_xhci ,
. uninit_common = usb_uninit_common ,
. uninit_eohci = usb_uninit_eohci ,
. uninit_xhci = usb_uninit_xhci ,
. get_dual_select = usb_get_dual_select ,
. set_dual_select = usb_set_dual_select ,
} ;
2022-02-18 20:24:59 +03:00
void brcm_usb_dvr_init_4908 ( struct brcm_usb_init_params * params )
{
int fam ;
fam = BRCM_FAMILY_4908 ;
params - > selected_family = fam ;
params - > usb_reg_bits_map =
& usb_reg_bits_map_table [ fam ] [ 0 ] ;
params - > family_name = family_names [ fam ] ;
params - > ops = & bcm7445_ops ;
}
2020-01-03 21:18:03 +03:00
void brcm_usb_dvr_init_7445 ( struct brcm_usb_init_params * params )
2017-09-22 22:34:01 +03:00
{
int fam ;
2020-01-03 21:18:03 +03:00
pr_debug ( " %s \n " , __func__ ) ;
fam = get_family_type ( params ) ;
2017-09-22 22:34:01 +03:00
params - > selected_family = fam ;
params - > usb_reg_bits_map =
& usb_reg_bits_map_table [ fam ] [ 0 ] ;
params - > family_name = family_names [ fam ] ;
2020-01-03 21:18:03 +03:00
params - > ops = & bcm7445_ops ;
2017-09-22 22:34:01 +03:00
}