2020-01-03 13:18:05 -05:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018, Broadcom */
/*
* This module contains USB PHY initialization for power up and S3 resume
* for newer Synopsys based USB hardware first used on the bcm7216 .
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/soc/brcmstb/brcmstb.h>
# include "phy-brcm-usb-init.h"
2020-01-03 13:18:06 -05:00
# define PHY_LOCK_TIMEOUT_MS 200
/* Register definitions for syscon piarbctl registers */
# define PIARBCTL_CAM 0x00
# define PIARBCTL_SPLITTER 0x04
# define PIARBCTL_MISC 0x08
# define PIARBCTL_MISC_SECURE_MASK 0x80000000
# define PIARBCTL_MISC_USB_SELECT_MASK 0x40000000
# define PIARBCTL_MISC_USB_4G_SDRAM_MASK 0x20000000
# define PIARBCTL_MISC_USB_PRIORITY_MASK 0x000f0000
# define PIARBCTL_MISC_USB_MEM_PAGE_MASK 0x0000f000
# define PIARBCTL_MISC_CAM1_MEM_PAGE_MASK 0x00000f00
# define PIARBCTL_MISC_CAM0_MEM_PAGE_MASK 0x000000f0
# define PIARBCTL_MISC_SATA_PRIORITY_MASK 0x0000000f
# define PIARBCTL_MISC_USB_ONLY_MASK \
( PIARBCTL_MISC_USB_SELECT_MASK | \
PIARBCTL_MISC_USB_4G_SDRAM_MASK | \
PIARBCTL_MISC_USB_PRIORITY_MASK | \
PIARBCTL_MISC_USB_MEM_PAGE_MASK )
2020-01-03 13:18:05 -05:00
/* Register definitions for the USB CTRL block */
# define USB_CTRL_SETUP 0x00
# define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK 0x02000000
# define USB_CTRL_SETUP_SCB2_EN_MASK 0x00008000
2020-01-03 13:18:06 -05:00
# define USB_CTRL_SETUP_tca_drv_sel_MASK 0x01000000
2020-01-03 13:18:05 -05:00
# define USB_CTRL_SETUP_SCB1_EN_MASK 0x00004000
# define USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK 0x00000200
# define USB_CTRL_SETUP_IPP_MASK 0x00000020
# define USB_CTRL_SETUP_IOC_MASK 0x00000010
# define USB_CTRL_USB_PM 0x04
# define USB_CTRL_USB_PM_USB_PWRDN_MASK 0x80000000
# define USB_CTRL_USB_PM_SOFT_RESET_MASK 0x40000000
# define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK 0x00800000
# define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK 0x00400000
2022-02-14 19:24:21 -08:00
# define USB_CTRL_USB_PM_XHC_PME_EN_MASK 0x00000010
# define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK 0x00000008
2020-01-03 13:18:05 -05:00
# define USB_CTRL_USB_PM_STATUS 0x08
# define USB_CTRL_USB_DEVICE_CTL1 0x10
# define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003
2020-01-03 13:18:11 -05:00
# define USB_CTRL_TEST_PORT_CTL 0x30
# define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK 0x000000ff
# define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK 0x0000002e
# define USB_CTRL_TP_DIAG1 0x34
# define USB_CTLR_TP_DIAG1_wake_MASK 0x00000002
# define USB_CTRL_CTLR_CSHCR 0x50
# define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK 0x00040000
2020-01-03 13:18:05 -05:00
2020-01-03 13:18:06 -05:00
/* Register definitions for the USB_PHY block in 7211b0 */
2020-01-03 13:18:11 -05:00
# define USB_PHY_PLL_CTL 0x00
# define USB_PHY_PLL_CTL_PLL_RESETB_MASK 0x40000000
2020-01-03 13:18:06 -05:00
# define USB_PHY_PLL_LDO_CTL 0x08
# define USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK 0x00000004
2020-01-03 13:18:11 -05:00
# define USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK 0x00000002
# define USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK 0x00000001
2020-01-03 13:18:06 -05:00
# define USB_PHY_UTMI_CTL_1 0x04
2020-01-03 13:18:08 -05:00
# define USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK 0x00000800
2020-01-03 13:18:06 -05:00
# define USB_PHY_UTMI_CTL_1_PHY_MODE_MASK 0x0000000c
# define USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT 2
2020-01-03 13:18:11 -05:00
# define USB_PHY_IDDQ 0x1c
# define USB_PHY_IDDQ_phy_iddq_MASK 0x00000001
2020-01-03 13:18:06 -05:00
# define USB_PHY_STATUS 0x20
# define USB_PHY_STATUS_pll_lock_MASK 0x00000001
/* Register definitions for the MDIO registers in the DWC2 block of
* the 7211 b0 .
* NOTE : The PHY ' s MDIO registers are only accessible through the
* legacy DesignWare USB controller even though it ' s not being used .
*/
# define USB_GMDIOCSR 0
# define USB_GMDIOGEN 4
2020-01-03 13:18:09 -05:00
/* Register definitions for the BDC EC block in 7211b0 */
# define BDC_EC_AXIRDA 0x0c
# define BDC_EC_AXIRDA_RTS_MASK 0xf0000000
# define BDC_EC_AXIRDA_RTS_SHIFT 28
2020-01-03 13:18:06 -05:00
static void usb_mdio_write_7211b0 ( struct brcm_usb_init_params * params ,
uint8_t addr , uint16_t data )
{
void __iomem * usb_mdio = params - > regs [ BRCM_REGS_USB_MDIO ] ;
addr & = 0x1f ; /* 5-bit address */
brcm_usb_writel ( 0xffffffff , usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
brcm_usb_writel ( 0x59020000 | ( addr < < 18 ) | data ,
usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
brcm_usb_writel ( 0x00000000 , usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
}
static uint16_t __maybe_unused usb_mdio_read_7211b0 (
struct brcm_usb_init_params * params , uint8_t addr )
{
void __iomem * usb_mdio = params - > regs [ BRCM_REGS_USB_MDIO ] ;
addr & = 0x1f ; /* 5-bit address */
brcm_usb_writel ( 0xffffffff , usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
brcm_usb_writel ( 0x69020000 | ( addr < < 18 ) , usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
brcm_usb_writel ( 0x00000000 , usb_mdio + USB_GMDIOGEN ) ;
while ( brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & ( 1 < < 31 ) )
;
return brcm_usb_readl ( usb_mdio + USB_GMDIOCSR ) & 0xffff ;
}
static void usb2_eye_fix_7211b0 ( struct brcm_usb_init_params * params )
{
/* select bank */
usb_mdio_write_7211b0 ( params , 0x1f , 0x80a0 ) ;
/* Set the eye */
usb_mdio_write_7211b0 ( params , 0x0a , 0xc6a0 ) ;
}
2020-01-03 13:18:05 -05:00
static void xhci_soft_reset ( struct brcm_usb_init_params * params ,
int on_off )
{
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
/* Assert reset */
if ( on_off )
USB_CTRL_UNSET ( ctrl , USB_PM , XHC_SOFT_RESETB ) ;
/* De-assert reset */
else
USB_CTRL_SET ( ctrl , USB_PM , XHC_SOFT_RESETB ) ;
}
static void usb_init_ipp ( struct brcm_usb_init_params * params )
{
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
u32 reg ;
u32 orig_reg ;
pr_debug ( " %s \n " , __func__ ) ;
orig_reg = reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , SETUP ) ) ;
if ( params - > ipp ! = 2 )
/* override ipp strap pin (if it exits) */
reg & = ~ ( USB_CTRL_MASK ( 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 ) ;
if ( params - > ipp = = 1 )
reg | = USB_CTRL_MASK ( SETUP , IPP ) ;
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , SETUP ) ) ;
/*
* If we ' re changing IPP , make sure power is off long enough
* to turn off any connected devices .
*/
if ( ( reg ^ orig_reg ) & USB_CTRL_MASK ( SETUP , IPP ) )
msleep ( 50 ) ;
}
2020-01-03 13:18:06 -05:00
static void syscon_piarbctl_init ( struct regmap * rmap )
{
/* Switch from legacy USB OTG controller to new STB USB controller */
regmap_update_bits ( rmap , PIARBCTL_MISC , PIARBCTL_MISC_USB_ONLY_MASK ,
PIARBCTL_MISC_USB_SELECT_MASK |
PIARBCTL_MISC_USB_4G_SDRAM_MASK ) ;
}
2020-01-03 13:18:05 -05:00
static void usb_init_common ( struct brcm_usb_init_params * params )
{
u32 reg ;
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
pr_debug ( " %s \n " , __func__ ) ;
if ( USB_CTRL_MASK ( USB_DEVICE_CTL1 , PORT_MODE ) ) {
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
reg & = ~ USB_CTRL_MASK ( USB_DEVICE_CTL1 , PORT_MODE ) ;
reg | = params - > mode ;
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
}
switch ( params - > mode ) {
case USB_CTLR_MODE_HOST :
USB_CTRL_UNSET ( ctrl , USB_PM , BDC_SOFT_RESETB ) ;
break ;
default :
USB_CTRL_UNSET ( ctrl , USB_PM , BDC_SOFT_RESETB ) ;
USB_CTRL_SET ( ctrl , USB_PM , BDC_SOFT_RESETB ) ;
break ;
}
}
2020-01-03 13:18:11 -05:00
static void usb_wake_enable_7211b0 ( struct brcm_usb_init_params * params ,
bool enable )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
if ( enable )
USB_CTRL_SET ( ctrl , CTLR_CSHCR , ctl_pme_en ) ;
else
USB_CTRL_UNSET ( ctrl , CTLR_CSHCR , ctl_pme_en ) ;
}
2022-02-14 19:24:21 -08:00
static void usb_wake_enable_7216 ( struct brcm_usb_init_params * params ,
bool enable )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
if ( enable )
USB_CTRL_SET ( ctrl , USB_PM , XHC_PME_EN ) ;
else
USB_CTRL_UNSET ( ctrl , USB_PM , XHC_PME_EN ) ;
}
2020-01-03 13:18:06 -05:00
static void usb_init_common_7211b0 ( struct brcm_usb_init_params * params )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
void __iomem * usb_phy = params - > regs [ BRCM_REGS_USB_PHY ] ;
2020-01-03 13:18:09 -05:00
void __iomem * bdc_ec = params - > regs [ BRCM_REGS_BDC_EC ] ;
2020-01-03 13:18:06 -05:00
int timeout_ms = PHY_LOCK_TIMEOUT_MS ;
u32 reg ;
if ( params - > syscon_piarbctl )
syscon_piarbctl_init ( params - > syscon_piarbctl ) ;
2020-01-03 13:18:11 -05:00
USB_CTRL_UNSET ( ctrl , USB_PM , USB_PWRDN ) ;
usb_wake_enable_7211b0 ( params , false ) ;
if ( ! params - > wake_enabled ) {
/* undo possible suspend settings */
brcm_usb_writel ( 0 , usb_phy + USB_PHY_IDDQ ) ;
reg = brcm_usb_readl ( usb_phy + USB_PHY_PLL_CTL ) ;
reg | = USB_PHY_PLL_CTL_PLL_RESETB_MASK ;
brcm_usb_writel ( reg , usb_phy + USB_PHY_PLL_CTL ) ;
/* temporarily enable FSM so PHY comes up properly */
reg = brcm_usb_readl ( usb_phy + USB_PHY_UTMI_CTL_1 ) ;
reg | = USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK ;
brcm_usb_writel ( reg , usb_phy + USB_PHY_UTMI_CTL_1 ) ;
}
2020-01-03 13:18:06 -05:00
/* Init the PHY */
2020-01-03 13:18:11 -05:00
reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK ;
2020-01-03 13:18:06 -05:00
brcm_usb_writel ( reg , usb_phy + USB_PHY_PLL_LDO_CTL ) ;
/* wait for lock */
while ( timeout_ms - - > 0 ) {
reg = brcm_usb_readl ( usb_phy + USB_PHY_STATUS ) ;
if ( reg & USB_PHY_STATUS_pll_lock_MASK )
break ;
usleep_range ( 1000 , 2000 ) ;
}
/* Set the PHY_MODE */
reg = brcm_usb_readl ( usb_phy + USB_PHY_UTMI_CTL_1 ) ;
reg & = ~ USB_PHY_UTMI_CTL_1_PHY_MODE_MASK ;
reg | = params - > mode < < USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT ;
brcm_usb_writel ( reg , usb_phy + USB_PHY_UTMI_CTL_1 ) ;
usb_init_common ( params ) ;
2020-01-03 13:18:09 -05:00
/*
* The BDC controller will get occasional failures with
* the default " Read Transaction Size " of 6 ( 1024 bytes ) .
* Set it to 4 ( 256 bytes ) .
*/
if ( ( params - > mode ! = USB_CTLR_MODE_HOST ) & & bdc_ec ) {
reg = brcm_usb_readl ( bdc_ec + BDC_EC_AXIRDA ) ;
reg & = ~ BDC_EC_AXIRDA_RTS_MASK ;
reg | = ( 0x4 < < BDC_EC_AXIRDA_RTS_SHIFT ) ;
brcm_usb_writel ( reg , bdc_ec + BDC_EC_AXIRDA ) ;
}
2020-01-03 13:18:08 -05:00
/*
* Disable FSM , otherwise the PHY will auto suspend when no
* device is connected and will be reset on resume .
*/
reg = brcm_usb_readl ( usb_phy + USB_PHY_UTMI_CTL_1 ) ;
reg & = ~ USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK ;
brcm_usb_writel ( reg , usb_phy + USB_PHY_UTMI_CTL_1 ) ;
2020-01-03 13:18:06 -05:00
usb2_eye_fix_7211b0 ( params ) ;
}
2022-02-14 19:24:21 -08:00
static void usb_init_common_7216 ( struct brcm_usb_init_params * params )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
USB_CTRL_UNSET ( ctrl , USB_PM , XHC_S2_CLK_SWITCH_EN ) ;
USB_CTRL_UNSET ( ctrl , USB_PM , USB_PWRDN ) ;
/* 1 millisecond - for USB clocks to settle down */
usleep_range ( 1000 , 2000 ) ;
usb_wake_enable_7216 ( params , false ) ;
usb_init_common ( params ) ;
}
2020-01-03 13:18:05 -05:00
static void usb_init_xhci ( struct brcm_usb_init_params * params )
{
pr_debug ( " %s \n " , __func__ ) ;
xhci_soft_reset ( params , 0 ) ;
}
2022-02-14 19:24:21 -08:00
static void usb_uninit_common_7216 ( struct brcm_usb_init_params * params )
2020-01-03 13:18:05 -05:00
{
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
pr_debug ( " %s \n " , __func__ ) ;
2022-02-14 19:24:21 -08:00
if ( ! params - > wake_enabled ) {
USB_CTRL_SET ( ctrl , USB_PM , USB_PWRDN ) ;
2020-01-03 13:18:05 -05:00
2022-02-14 19:24:21 -08:00
/* Switch to using slower clock during suspend to save power */
USB_CTRL_SET ( ctrl , USB_PM , XHC_S2_CLK_SWITCH_EN ) ;
} else {
usb_wake_enable_7216 ( params , true ) ;
}
2020-01-03 13:18:05 -05:00
}
2020-01-03 13:18:11 -05:00
static void usb_uninit_common_7211b0 ( struct brcm_usb_init_params * params )
{
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
void __iomem * usb_phy = params - > regs [ BRCM_REGS_USB_PHY ] ;
u32 reg ;
pr_debug ( " %s \n " , __func__ ) ;
if ( params - > wake_enabled ) {
USB_CTRL_SET ( ctrl , TEST_PORT_CTL , TPOUT_SEL_PME_GEN ) ;
usb_wake_enable_7211b0 ( params , true ) ;
} else {
USB_CTRL_SET ( ctrl , USB_PM , USB_PWRDN ) ;
brcm_usb_writel ( 0 , usb_phy + USB_PHY_PLL_LDO_CTL ) ;
reg = brcm_usb_readl ( usb_phy + USB_PHY_PLL_CTL ) ;
reg & = ~ USB_PHY_PLL_CTL_PLL_RESETB_MASK ;
brcm_usb_writel ( reg , usb_phy + USB_PHY_PLL_CTL ) ;
brcm_usb_writel ( USB_PHY_IDDQ_phy_iddq_MASK ,
usb_phy + USB_PHY_IDDQ ) ;
}
}
2020-01-03 13:18:05 -05:00
static void usb_uninit_xhci ( struct brcm_usb_init_params * params )
{
pr_debug ( " %s \n " , __func__ ) ;
2020-01-03 13:18:11 -05:00
if ( ! params - > wake_enabled )
xhci_soft_reset ( params , 1 ) ;
2020-01-03 13:18:05 -05:00
}
static int usb_get_dual_select ( struct brcm_usb_init_params * params )
{
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
u32 reg = 0 ;
pr_debug ( " %s \n " , __func__ ) ;
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
reg & = USB_CTRL_MASK ( USB_DEVICE_CTL1 , PORT_MODE ) ;
return reg ;
}
static void usb_set_dual_select ( struct brcm_usb_init_params * params , int mode )
{
2020-01-03 13:18:06 -05:00
void __iomem * ctrl = params - > regs [ BRCM_REGS_CTRL ] ;
2020-01-03 13:18:05 -05:00
u32 reg ;
pr_debug ( " %s \n " , __func__ ) ;
reg = brcm_usb_readl ( USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
reg & = ~ USB_CTRL_MASK ( USB_DEVICE_CTL1 , PORT_MODE ) ;
reg | = mode ;
brcm_usb_writel ( reg , USB_CTRL_REG ( ctrl , USB_DEVICE_CTL1 ) ) ;
}
static const struct brcm_usb_init_ops bcm7216_ops = {
. init_ipp = usb_init_ipp ,
2022-02-14 19:24:21 -08:00
. init_common = usb_init_common_7216 ,
2020-01-03 13:18:05 -05:00
. init_xhci = usb_init_xhci ,
2022-02-14 19:24:21 -08:00
. uninit_common = usb_uninit_common_7216 ,
2020-01-03 13:18:05 -05:00
. uninit_xhci = usb_uninit_xhci ,
. get_dual_select = usb_get_dual_select ,
. set_dual_select = usb_set_dual_select ,
} ;
2020-01-03 13:18:06 -05:00
static const struct brcm_usb_init_ops bcm7211b0_ops = {
. init_ipp = usb_init_ipp ,
. init_common = usb_init_common_7211b0 ,
. init_xhci = usb_init_xhci ,
2020-01-03 13:18:11 -05:00
. uninit_common = usb_uninit_common_7211b0 ,
2020-01-03 13:18:06 -05:00
. uninit_xhci = usb_uninit_xhci ,
. get_dual_select = usb_get_dual_select ,
. set_dual_select = usb_set_dual_select ,
} ;
2020-01-03 13:18:05 -05:00
void brcm_usb_dvr_init_7216 ( struct brcm_usb_init_params * params )
{
pr_debug ( " %s \n " , __func__ ) ;
params - > family_name = " 7216 " ;
params - > ops = & bcm7216_ops ;
2022-02-14 19:24:21 -08:00
params - > suspend_with_clocks = true ;
2020-01-03 13:18:05 -05:00
}
2020-01-03 13:18:06 -05:00
void brcm_usb_dvr_init_7211b0 ( struct brcm_usb_init_params * params )
{
pr_debug ( " %s \n " , __func__ ) ;
params - > family_name = " 7211 " ;
params - > ops = & bcm7211b0_ops ;
2020-01-03 13:18:11 -05:00
params - > suspend_with_clocks = true ;
2020-01-03 13:18:06 -05:00
}