2018-06-29 10:20:27 +08:00
// SPDX-License-Identifier: GPL-2.0
2015-09-29 11:01:36 +08:00
/*
* Copyright ( c ) 2015 MediaTek Inc .
* Author : Chunfeng Yun < chunfeng . yun @ mediatek . com >
*
*/
# include <dt-bindings/phy/phy.h>
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/io.h>
2015-12-04 10:11:05 +08:00
# include <linux/iopoll.h>
2015-09-29 11:01:36 +08:00
# include <linux/module.h>
# include <linux/of_address.h>
2017-12-28 16:40:36 +05:30
# include <linux/of_device.h>
2015-09-29 11:01:36 +08:00
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
2017-03-31 15:35:31 +08:00
/* version V1 sub-banks offset base address */
/* banks shared by multiple phys */
# define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
# define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
2017-09-21 18:31:48 +08:00
# define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */
2017-03-31 15:35:31 +08:00
/* u2 phy bank */
# define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
2017-08-03 18:01:01 +08:00
/* u3/pcie/sata phy banks */
2017-03-31 15:35:31 +08:00
# define SSUSB_SIFSLV_V1_U3PHYD 0x000
# define SSUSB_SIFSLV_V1_U3PHYA 0x200
/* version V2 sub-banks offset base address */
/* u2 phy banks */
# define SSUSB_SIFSLV_V2_MISC 0x000
# define SSUSB_SIFSLV_V2_U2FREQ 0x100
# define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
2017-08-03 18:01:02 +08:00
/* u3/pcie/sata phy banks */
2017-03-31 15:35:31 +08:00
# define SSUSB_SIFSLV_V2_SPLLC 0x000
# define SSUSB_SIFSLV_V2_CHIP 0x100
# define SSUSB_SIFSLV_V2_U3PHYD 0x200
# define SSUSB_SIFSLV_V2_U3PHYA 0x400
# define U3P_USBPHYACR0 0x000
2015-09-29 11:01:36 +08:00
# define PA0_RG_U2PLL_FORCE_ON BIT(15)
2017-03-31 15:35:32 +08:00
# define PA0_RG_USB20_INTR_EN BIT(5)
2015-09-29 11:01:36 +08:00
2018-06-29 10:20:29 +08:00
# define U3P_USBPHYACR1 0x004
# define PA1_RG_VRT_SEL GENMASK(14, 12)
# define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
# define PA1_RG_TERM_SEL GENMASK(10, 8)
# define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
2017-03-31 15:35:31 +08:00
# define U3P_USBPHYACR2 0x008
2015-09-29 11:01:36 +08:00
# define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
2017-03-31 15:35:31 +08:00
# define U3P_USBPHYACR5 0x014
2015-12-04 10:11:05 +08:00
# define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
2015-09-29 11:01:36 +08:00
# define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
# define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
# define PA5_RG_U2_HS_100U_U3_EN BIT(11)
2017-03-31 15:35:31 +08:00
# define U3P_USBPHYACR6 0x018
2015-09-29 11:01:36 +08:00
# define PA6_RG_U2_BC11_SW_EN BIT(23)
# define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
2015-12-04 10:08:56 +08:00
# define PA6_RG_U2_SQTH GENMASK(3, 0)
# define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
# define U3P_U2PHYACR4 0x020
2015-09-29 11:01:36 +08:00
# define P2C_RG_USB20_GPIO_CTL BIT(9)
# define P2C_USB20_GPIO_MODE BIT(8)
# define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
2017-03-31 15:35:31 +08:00
# define U3D_U2PHYDCR0 0x060
2015-09-29 11:01:36 +08:00
# define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
2017-03-31 15:35:31 +08:00
# define U3P_U2PHYDTM0 0x068
2015-09-29 11:01:36 +08:00
# define P2C_FORCE_UART_EN BIT(26)
# define P2C_FORCE_DATAIN BIT(23)
# define P2C_FORCE_DM_PULLDOWN BIT(21)
# define P2C_FORCE_DP_PULLDOWN BIT(20)
# define P2C_FORCE_XCVRSEL BIT(19)
# define P2C_FORCE_SUSPENDM BIT(18)
# define P2C_FORCE_TERMSEL BIT(17)
# define P2C_RG_DATAIN GENMASK(13, 10)
# define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
# define P2C_RG_DMPULLDOWN BIT(7)
# define P2C_RG_DPPULLDOWN BIT(6)
# define P2C_RG_XCVRSEL GENMASK(5, 4)
# define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
# define P2C_RG_SUSPENDM BIT(3)
# define P2C_RG_TERMSEL BIT(2)
# define P2C_DTM0_PART_MASK \
( P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL )
2017-03-31 15:35:31 +08:00
# define U3P_U2PHYDTM1 0x06C
2015-09-29 11:01:36 +08:00
# define P2C_RG_UART_EN BIT(16)
2017-09-21 18:31:49 +08:00
# define P2C_FORCE_IDDIG BIT(9)
2015-09-29 11:01:36 +08:00
# define P2C_RG_VBUSVALID BIT(5)
# define P2C_RG_SESSEND BIT(4)
# define P2C_RG_AVALID BIT(2)
2017-09-21 18:31:49 +08:00
# define P2C_RG_IDDIG BIT(1)
2015-09-29 11:01:36 +08:00
2018-06-29 10:20:30 +08:00
# define U3P_U2PHYBC12C 0x080
# define P2C_RG_CHGDT_EN BIT(0)
2017-08-03 18:01:00 +08:00
# define U3P_U3_CHIP_GPIO_CTLD 0x0c
# define P3C_REG_IP_SW_RST BIT(31)
# define P3C_MCU_BUS_CK_GATE_EN BIT(30)
# define P3C_FORCE_IP_SW_RST BIT(29)
# define U3P_U3_CHIP_GPIO_CTLE 0x10
# define P3C_RG_SWRST_U3_PHYD BIT(25)
# define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
# define U3P_U3_PHYA_REG0 0x000
# define P3A_RG_CLKDRV_OFF GENMASK(3, 2)
# define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
# define U3P_U3_PHYA_REG1 0x004
# define P3A_RG_CLKDRV_AMP GENMASK(31, 29)
# define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYA_REG6 0x018
2015-09-29 11:01:36 +08:00
# define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
# define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYA_REG9 0x024
2015-09-29 11:01:36 +08:00
# define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
# define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYA_DA_REG0 0x100
2017-08-03 18:01:00 +08:00
# define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16)
# define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16)
# define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12)
# define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12)
2015-09-29 11:01:36 +08:00
# define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
# define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
2017-08-03 18:01:00 +08:00
# define U3P_U3_PHYA_DA_REG4 0x108
# define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19)
# define P3A_RG_PLL_BC_PE2H GENMASK(7, 6)
# define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6)
# define U3P_U3_PHYA_DA_REG5 0x10c
# define P3A_RG_PLL_BR_PE2H GENMASK(29, 28)
# define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28)
# define P3A_RG_PLL_IC_PE2H GENMASK(15, 12)
# define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12)
# define U3P_U3_PHYA_DA_REG6 0x110
# define P3A_RG_PLL_IR_PE2H GENMASK(19, 16)
# define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16)
# define U3P_U3_PHYA_DA_REG7 0x114
# define P3A_RG_PLL_BP_PE2H GENMASK(19, 16)
# define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16)
# define U3P_U3_PHYA_DA_REG20 0x13c
# define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16)
# define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16)
# define U3P_U3_PHYA_DA_REG25 0x148
# define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0)
# define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x))
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYD_LFPS1 0x00c
2017-03-31 15:35:28 +08:00
# define P3D_RG_FWAKE_TH GENMASK(21, 16)
# define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYD_CDR1 0x05c
2015-09-29 11:01:36 +08:00
# define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
# define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
# define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
# define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYD_RXDET1 0x128
2017-03-31 15:35:27 +08:00
# define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
# define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
2017-03-31 15:35:31 +08:00
# define U3P_U3_PHYD_RXDET2 0x12c
2017-03-31 15:35:27 +08:00
# define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
# define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
2017-03-31 15:35:31 +08:00
# define U3P_SPLLC_XTALCTL3 0x018
2015-09-29 11:01:36 +08:00
# define XC3_RG_U3_XTAL_RX_PWD BIT(9)
# define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
2017-03-31 15:35:31 +08:00
# define U3P_U2FREQ_FMCR0 0x00
2015-12-04 10:11:05 +08:00
# define P2F_RG_MONCLK_SEL GENMASK(27, 26)
# define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
# define P2F_RG_FREQDET_EN BIT(24)
# define P2F_RG_CYCLECNT GENMASK(23, 0)
# define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
2017-03-31 15:35:31 +08:00
# define U3P_U2FREQ_VALUE 0x0c
2015-12-04 10:11:05 +08:00
2017-03-31 15:35:31 +08:00
# define U3P_U2FREQ_FMMONR1 0x10
2015-12-04 10:11:05 +08:00
# define P2F_USB_FM_VALID BIT(0)
# define P2F_RG_FRCK_EN BIT(8)
# define U3P_REF_CLK 26 /* MHZ */
# define U3P_SLEW_RATE_COEF 28
# define U3P_SR_COEF_DIVISOR 1000
# define U3P_FM_DET_CYCLE_CNT 1024
2017-08-03 18:01:01 +08:00
/* SATA register setting */
# define PHYD_CTRL_SIGNAL_MODE4 0x1c
/* CDR Charge Pump P-path current adjustment */
# define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20)
# define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20)
# define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8)
# define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8)
# define PHYD_DESIGN_OPTION2 0x24
/* Symbol lock count selection */
# define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4)
# define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4)
# define PHYD_DESIGN_OPTION9 0x40
/* COMWAK GAP width window */
# define RG_TG_MAX_MSK GENMASK(20, 16)
# define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16)
/* COMINIT GAP width window */
# define RG_T2_MAX_MSK GENMASK(13, 8)
# define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8)
/* COMWAK GAP width window */
# define RG_TG_MIN_MSK GENMASK(7, 5)
# define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5)
/* COMINIT GAP width window */
# define RG_T2_MIN_MSK GENMASK(4, 0)
# define RG_T2_MIN_VAL(x) (0x1f & (x))
# define ANA_RG_CTRL_SIGNAL1 0x4c
/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */
# define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8)
# define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8)
# define ANA_RG_CTRL_SIGNAL4 0x58
# define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20)
# define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20)
/* Loop filter R1 resistance adjustment for Gen1 speed */
# define RG_CDR_BR_GEN2_MSK GENMASK(10, 8)
# define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8)
# define ANA_RG_CTRL_SIGNAL6 0x60
/* I-path capacitance adjustment for Gen1 */
# define RG_CDR_BC_GEN1_MSK GENMASK(28, 24)
# define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24)
# define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0)
# define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x))
# define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c
/* RX Gen1 LEQ tuning step */
# define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8)
# define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8)
# define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8
# define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16)
# define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16)
# define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc
# define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0)
# define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x))
2017-08-03 18:01:02 +08:00
enum mtk_phy_version {
MTK_PHY_V1 = 1 ,
MTK_PHY_V2 ,
2017-03-31 15:35:31 +08:00
} ;
2017-08-03 18:01:02 +08:00
struct mtk_phy_pdata {
2016-04-20 08:14:02 +08:00
/* avoid RX sensitivity level degradation only for mt8173 */
bool avoid_rx_sen_degradation ;
2017-08-03 18:01:02 +08:00
enum mtk_phy_version version ;
2017-03-31 15:35:31 +08:00
} ;
struct u2phy_banks {
void __iomem * misc ;
void __iomem * fmreg ;
void __iomem * com ;
} ;
struct u3phy_banks {
void __iomem * spllc ;
void __iomem * chip ;
void __iomem * phyd ; /* include u3phyd_bank2 */
void __iomem * phya ; /* include u3phya_da */
2016-04-20 08:14:02 +08:00
} ;
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance {
2015-09-29 11:01:36 +08:00
struct phy * phy ;
void __iomem * port_base ;
2017-03-31 15:35:31 +08:00
union {
struct u2phy_banks u2_banks ;
struct u3phy_banks u3_banks ;
} ;
2017-03-31 15:35:30 +08:00
struct clk * ref_clk ; /* reference clock of anolog phy */
2015-09-29 11:01:36 +08:00
u32 index ;
u8 type ;
2018-06-29 10:20:29 +08:00
int eye_src ;
int eye_vrt ;
int eye_term ;
2018-06-29 10:20:30 +08:00
bool bc12_en ;
2015-09-29 11:01:36 +08:00
} ;
2017-08-03 18:01:02 +08:00
struct mtk_tphy {
2015-09-29 11:01:36 +08:00
struct device * dev ;
2017-03-31 15:35:29 +08:00
void __iomem * sif_base ; /* only shared sif */
2017-03-31 15:35:30 +08:00
/* deprecated, use @ref_clk instead in phy instance */
2015-09-29 11:01:36 +08:00
struct clk * u3phya_ref ; /* reference clock of usb3 anolog phy */
2017-08-03 18:01:02 +08:00
const struct mtk_phy_pdata * pdata ;
struct mtk_phy_instance * * phys ;
2015-09-29 11:01:36 +08:00
int nphys ;
2018-03-12 13:25:39 +08:00
int src_ref_clk ; /* MHZ, reference clock for slew rate calibrate */
int src_coef ; /* coefficient for slew rate calibrate */
2015-09-29 11:01:36 +08:00
} ;
2017-08-03 18:01:02 +08:00
static void hs_slew_rate_calibrate ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2015-12-04 10:11:05 +08:00
{
2017-03-31 15:35:31 +08:00
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * fmreg = u2_banks - > fmreg ;
void __iomem * com = u2_banks - > com ;
2015-12-04 10:11:05 +08:00
int calibration_val ;
int fm_out ;
u32 tmp ;
2018-06-29 10:20:29 +08:00
/* use force value */
if ( instance - > eye_src )
return ;
2015-12-04 10:11:05 +08:00
/* enable USB ring oscillator */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
tmp | = PA5_RG_U2_HSTX_SRCAL_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
udelay ( 1 ) ;
/*enable free run clock */
2017-03-31 15:35:31 +08:00
tmp = readl ( fmreg + U3P_U2FREQ_FMMONR1 ) ;
2015-12-04 10:11:05 +08:00
tmp | = P2F_RG_FRCK_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , fmreg + U3P_U2FREQ_FMMONR1 ) ;
2015-12-04 10:11:05 +08:00
/* set cycle count as 1024, and select u2 channel */
2017-03-31 15:35:31 +08:00
tmp = readl ( fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
tmp & = ~ ( P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL ) ;
tmp | = P2F_RG_CYCLECNT_VAL ( U3P_FM_DET_CYCLE_CNT ) ;
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > version = = MTK_PHY_V1 )
2017-03-31 15:35:31 +08:00
tmp | = P2F_RG_MONCLK_SEL_VAL ( instance - > index > > 1 ) ;
writel ( tmp , fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
/* enable frequency meter */
2017-03-31 15:35:31 +08:00
tmp = readl ( fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
tmp | = P2F_RG_FREQDET_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
/* ignore return value */
2017-03-31 15:35:31 +08:00
readl_poll_timeout ( fmreg + U3P_U2FREQ_FMMONR1 , tmp ,
( tmp & P2F_USB_FM_VALID ) , 10 , 200 ) ;
2015-12-04 10:11:05 +08:00
2017-03-31 15:35:31 +08:00
fm_out = readl ( fmreg + U3P_U2FREQ_VALUE ) ;
2015-12-04 10:11:05 +08:00
/* disable frequency meter */
2017-03-31 15:35:31 +08:00
tmp = readl ( fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
tmp & = ~ P2F_RG_FREQDET_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , fmreg + U3P_U2FREQ_FMCR0 ) ;
2015-12-04 10:11:05 +08:00
/*disable free run clock */
2017-03-31 15:35:31 +08:00
tmp = readl ( fmreg + U3P_U2FREQ_FMMONR1 ) ;
2015-12-04 10:11:05 +08:00
tmp & = ~ P2F_RG_FRCK_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , fmreg + U3P_U2FREQ_FMMONR1 ) ;
2015-12-04 10:11:05 +08:00
if ( fm_out ) {
2018-03-12 13:25:39 +08:00
/* ( 1024 / FM_OUT ) x reference clock frequency x coef */
tmp = tphy - > src_ref_clk * tphy - > src_coef ;
tmp = ( tmp * U3P_FM_DET_CYCLE_CNT ) / fm_out ;
2015-12-04 10:11:05 +08:00
calibration_val = DIV_ROUND_CLOSEST ( tmp , U3P_SR_COEF_DIVISOR ) ;
} else {
/* if FM detection fail, set default value */
calibration_val = 4 ;
}
2018-03-12 13:25:39 +08:00
dev_dbg ( tphy - > dev , " phy:%d, fm_out:%d, calib:%d (clk:%d, coef:%d) \n " ,
instance - > index , fm_out , calibration_val ,
tphy - > src_ref_clk , tphy - > src_coef ) ;
2015-12-04 10:11:05 +08:00
/* set HS slew rate */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
tmp & = ~ PA5_RG_U2_HSTX_SRCTRL ;
tmp | = PA5_RG_U2_HSTX_SRCTRL_VAL ( calibration_val ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
/* disable USB ring oscillator */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
tmp & = ~ PA5_RG_U2_HSTX_SRCAL_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR5 ) ;
2015-12-04 10:11:05 +08:00
}
2017-08-03 18:01:02 +08:00
static void u3_phy_instance_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-03-31 15:35:29 +08:00
{
2017-03-31 15:35:31 +08:00
struct u3phy_banks * u3_banks = & instance - > u3_banks ;
2017-03-31 15:35:29 +08:00
u32 tmp ;
/* gating PCIe Analog XTAL clock */
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > spllc + U3P_SPLLC_XTALCTL3 ) ;
2017-03-31 15:35:29 +08:00
tmp | = XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > spllc + U3P_SPLLC_XTALCTL3 ) ;
2017-03-31 15:35:29 +08:00
/* gating XSQ */
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG0 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3A_RG_XTAL_EXT_EN_U3 ;
tmp | = P3A_RG_XTAL_EXT_EN_U3_VAL ( 2 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG0 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_REG9 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3A_RG_RX_DAC_MUX ;
tmp | = P3A_RG_RX_DAC_MUX_VAL ( 4 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_REG9 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_REG6 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3A_RG_TX_EIDLE_CM ;
tmp | = P3A_RG_TX_EIDLE_CM_VAL ( 0xe ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_REG6 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_CDR1 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ ( P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1 ) ;
tmp | = P3D_RG_CDR_BIR_LTD0_VAL ( 0xc ) | P3D_RG_CDR_BIR_LTD1_VAL ( 0x3 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_CDR1 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_LFPS1 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3D_RG_FWAKE_TH ;
tmp | = P3D_RG_FWAKE_TH_VAL ( 0x34 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_LFPS1 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_RXDET1 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3D_RG_RXDET_STB2_SET ;
tmp | = P3D_RG_RXDET_STB2_SET_VAL ( 0x10 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_RXDET1 ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_RXDET2 ) ;
2017-03-31 15:35:29 +08:00
tmp & = ~ P3D_RG_RXDET_STB2_SET_P3 ;
tmp | = P3D_RG_RXDET_STB2_SET_P3_VAL ( 0x10 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_RXDET2 ) ;
2017-03-31 15:35:29 +08:00
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , instance - > index ) ;
2017-03-31 15:35:29 +08:00
}
2017-08-03 18:01:02 +08:00
static void u2_phy_instance_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2015-09-29 11:01:36 +08:00
{
2017-03-31 15:35:31 +08:00
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * com = u2_banks - > com ;
2015-09-29 11:01:36 +08:00
u32 index = instance - > index ;
u32 tmp ;
2017-12-07 19:53:34 +08:00
/* switch to USB function, and enable usb pll */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2017-12-07 19:53:34 +08:00
tmp & = ~ ( P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM ) ;
2015-09-29 11:01:36 +08:00
tmp | = P2C_RG_XCVRSEL_VAL ( 1 ) | P2C_RG_DATAIN_VAL ( 0 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ P2C_RG_UART_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:32 +08:00
tmp = readl ( com + U3P_USBPHYACR0 ) ;
tmp | = PA0_RG_USB20_INTR_EN ;
writel ( tmp , com + U3P_USBPHYACR0 ) ;
/* disable switch 100uA current to SSUSB */
tmp = readl ( com + U3P_USBPHYACR5 ) ;
tmp & = ~ PA5_RG_U2_HS_100U_U3_EN ;
writel ( tmp , com + U3P_USBPHYACR5 ) ;
2015-09-29 11:01:36 +08:00
if ( ! index ) {
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYACR4 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ P2C_U2_GPIO_CTR_MSK ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYACR4 ) ;
2016-04-20 08:14:02 +08:00
}
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > avoid_rx_sen_degradation ) {
2016-04-20 08:14:02 +08:00
if ( ! index ) {
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR2 ) ;
2016-04-20 08:14:02 +08:00
tmp | = PA2_RG_SIF_U2PLL_FORCE_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR2 ) ;
2016-04-20 08:14:02 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3D_U2PHYDCR0 ) ;
2016-04-20 08:14:02 +08:00
tmp & = ~ P2C_RG_SIF_U2PLL_FORCE_ON ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3D_U2PHYDCR0 ) ;
2016-04-20 08:14:02 +08:00
} else {
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3D_U2PHYDCR0 ) ;
2016-04-20 08:14:02 +08:00
tmp | = P2C_RG_SIF_U2PLL_FORCE_ON ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3D_U2PHYDCR0 ) ;
2016-04-20 08:14:02 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2016-04-20 08:14:02 +08:00
tmp | = P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2016-04-20 08:14:02 +08:00
}
2015-09-29 11:01:36 +08:00
}
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR6 ) ;
2015-12-04 10:08:56 +08:00
tmp & = ~ PA6_RG_U2_BC11_SW_EN ; /* DP/DM BC1.1 path Disable */
tmp & = ~ PA6_RG_U2_SQTH ;
tmp | = PA6_RG_U2_SQTH_VAL ( 2 ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR6 ) ;
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , index ) ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
static void u2_phy_instance_power_on ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2015-09-29 11:01:36 +08:00
{
2017-03-31 15:35:31 +08:00
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * com = u2_banks - > com ;
2015-09-29 11:01:36 +08:00
u32 index = instance - > index ;
u32 tmp ;
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2017-12-07 19:53:34 +08:00
tmp & = ~ ( P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
/* OTG Enable */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR6 ) ;
2015-09-29 11:01:36 +08:00
tmp | = PA6_RG_U2_OTG_VBUSCMP_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR6 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
tmp | = P2C_RG_VBUSVALID | P2C_RG_AVALID ;
tmp & = ~ P2C_RG_SESSEND ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > avoid_rx_sen_degradation & & index ) {
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
tmp | = P2C_RG_SIF_U2PLL_FORCE_ON ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
tmp | = P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , index ) ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
static void u2_phy_instance_power_off ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2015-09-29 11:01:36 +08:00
{
2017-03-31 15:35:31 +08:00
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * com = u2_banks - > com ;
2015-09-29 11:01:36 +08:00
u32 index = instance - > index ;
u32 tmp ;
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ ( P2C_RG_XCVRSEL | P2C_RG_DATAIN ) ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
/* OTG Disable */
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_USBPHYACR6 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ PA6_RG_U2_OTG_VBUSCMP_EN ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_USBPHYACR6 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ ( P2C_RG_VBUSVALID | P2C_RG_AVALID ) ;
tmp | = P2C_RG_SESSEND ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM1 ) ;
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > avoid_rx_sen_degradation & & index ) {
2017-12-07 19:53:34 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
tmp & = ~ ( P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM ) ;
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ P2C_RG_SIF_U2PLL_FORCE_ON ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , index ) ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
static void u2_phy_instance_exit ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2015-09-29 11:01:36 +08:00
{
2017-03-31 15:35:31 +08:00
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * com = u2_banks - > com ;
2015-09-29 11:01:36 +08:00
u32 index = instance - > index ;
u32 tmp ;
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > avoid_rx_sen_degradation & & index ) {
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ P2C_RG_SIF_U2PLL_FORCE_ON ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3D_U2PHYDCR0 ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:31 +08:00
tmp = readl ( com + U3P_U2PHYDTM0 ) ;
2015-09-29 11:01:36 +08:00
tmp & = ~ P2C_FORCE_SUSPENDM ;
2017-03-31 15:35:31 +08:00
writel ( tmp , com + U3P_U2PHYDTM0 ) ;
}
}
2017-09-21 18:31:49 +08:00
static void u2_phy_instance_set_mode ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance ,
enum phy_mode mode )
{
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
u32 tmp ;
tmp = readl ( u2_banks - > com + U3P_U2PHYDTM1 ) ;
switch ( mode ) {
case PHY_MODE_USB_DEVICE :
tmp | = P2C_FORCE_IDDIG | P2C_RG_IDDIG ;
break ;
case PHY_MODE_USB_HOST :
tmp | = P2C_FORCE_IDDIG ;
tmp & = ~ P2C_RG_IDDIG ;
break ;
case PHY_MODE_USB_OTG :
tmp & = ~ ( P2C_FORCE_IDDIG | P2C_RG_IDDIG ) ;
break ;
default :
return ;
}
writel ( tmp , u2_banks - > com + U3P_U2PHYDTM1 ) ;
}
2017-08-03 18:01:02 +08:00
static void pcie_phy_instance_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-08-03 18:01:00 +08:00
{
struct u3phy_banks * u3_banks = & instance - > u3_banks ;
u32 tmp ;
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > version ! = MTK_PHY_V1 )
2017-08-03 18:01:00 +08:00
return ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG0 ) ;
tmp & = ~ ( P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H ) ;
tmp | = P3A_RG_XTAL_EXT_PE1H_VAL ( 0x2 ) | P3A_RG_XTAL_EXT_PE2H_VAL ( 0x2 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG0 ) ;
/* ref clk drive */
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_REG1 ) ;
tmp & = ~ P3A_RG_CLKDRV_AMP ;
tmp | = P3A_RG_CLKDRV_AMP_VAL ( 0x4 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_REG1 ) ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_REG0 ) ;
tmp & = ~ P3A_RG_CLKDRV_OFF ;
tmp | = P3A_RG_CLKDRV_OFF_VAL ( 0x1 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_REG0 ) ;
/* SSC delta -5000ppm */
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG20 ) ;
tmp & = ~ P3A_RG_PLL_DELTA1_PE2H ;
tmp | = P3A_RG_PLL_DELTA1_PE2H_VAL ( 0x3c ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG20 ) ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG25 ) ;
tmp & = ~ P3A_RG_PLL_DELTA_PE2H ;
tmp | = P3A_RG_PLL_DELTA_PE2H_VAL ( 0x36 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG25 ) ;
/* change pll BW 0.6M */
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG5 ) ;
tmp & = ~ ( P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H ) ;
tmp | = P3A_RG_PLL_BR_PE2H_VAL ( 0x1 ) | P3A_RG_PLL_IC_PE2H_VAL ( 0x1 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG5 ) ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG4 ) ;
tmp & = ~ ( P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H ) ;
tmp | = P3A_RG_PLL_BC_PE2H_VAL ( 0x3 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG4 ) ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG6 ) ;
tmp & = ~ P3A_RG_PLL_IR_PE2H ;
tmp | = P3A_RG_PLL_IR_PE2H_VAL ( 0x2 ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG6 ) ;
tmp = readl ( u3_banks - > phya + U3P_U3_PHYA_DA_REG7 ) ;
tmp & = ~ P3A_RG_PLL_BP_PE2H ;
tmp | = P3A_RG_PLL_BP_PE2H_VAL ( 0xa ) ;
writel ( tmp , u3_banks - > phya + U3P_U3_PHYA_DA_REG7 ) ;
/* Tx Detect Rx Timing: 10us -> 5us */
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_RXDET1 ) ;
tmp & = ~ P3D_RG_RXDET_STB2_SET ;
tmp | = P3D_RG_RXDET_STB2_SET_VAL ( 0x10 ) ;
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_RXDET1 ) ;
tmp = readl ( u3_banks - > phyd + U3P_U3_PHYD_RXDET2 ) ;
tmp & = ~ P3D_RG_RXDET_STB2_SET_P3 ;
tmp | = P3D_RG_RXDET_STB2_SET_P3_VAL ( 0x10 ) ;
writel ( tmp , u3_banks - > phyd + U3P_U3_PHYD_RXDET2 ) ;
/* wait for PCIe subsys register to active */
usleep_range ( 2500 , 3000 ) ;
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , instance - > index ) ;
2017-08-03 18:01:00 +08:00
}
2017-08-03 18:01:02 +08:00
static void pcie_phy_instance_power_on ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-08-03 18:01:00 +08:00
{
struct u3phy_banks * bank = & instance - > u3_banks ;
u32 tmp ;
tmp = readl ( bank - > chip + U3P_U3_CHIP_GPIO_CTLD ) ;
2018-03-12 13:25:38 +08:00
tmp & = ~ ( P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST ) ;
2017-08-03 18:01:00 +08:00
writel ( tmp , bank - > chip + U3P_U3_CHIP_GPIO_CTLD ) ;
tmp = readl ( bank - > chip + U3P_U3_CHIP_GPIO_CTLE ) ;
tmp & = ~ ( P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD ) ;
writel ( tmp , bank - > chip + U3P_U3_CHIP_GPIO_CTLE ) ;
}
2017-08-03 18:01:02 +08:00
static void pcie_phy_instance_power_off ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-08-03 18:01:00 +08:00
{
struct u3phy_banks * bank = & instance - > u3_banks ;
u32 tmp ;
tmp = readl ( bank - > chip + U3P_U3_CHIP_GPIO_CTLD ) ;
tmp | = P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST ;
writel ( tmp , bank - > chip + U3P_U3_CHIP_GPIO_CTLD ) ;
tmp = readl ( bank - > chip + U3P_U3_CHIP_GPIO_CTLE ) ;
tmp | = P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD ;
writel ( tmp , bank - > chip + U3P_U3_CHIP_GPIO_CTLE ) ;
}
2017-08-03 18:01:02 +08:00
static void sata_phy_instance_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-08-03 18:01:01 +08:00
{
struct u3phy_banks * u3_banks = & instance - > u3_banks ;
void __iomem * phyd = u3_banks - > phyd ;
u32 tmp ;
/* charge current adjustment */
tmp = readl ( phyd + ANA_RG_CTRL_SIGNAL6 ) ;
tmp & = ~ ( RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK ) ;
tmp | = RG_CDR_BIRLTR_GEN1_VAL ( 0x6 ) | RG_CDR_BC_GEN1_VAL ( 0x1a ) ;
writel ( tmp , phyd + ANA_RG_CTRL_SIGNAL6 ) ;
tmp = readl ( phyd + ANA_EQ_EYE_CTRL_SIGNAL4 ) ;
tmp & = ~ RG_CDR_BIRLTD0_GEN1_MSK ;
tmp | = RG_CDR_BIRLTD0_GEN1_VAL ( 0x18 ) ;
writel ( tmp , phyd + ANA_EQ_EYE_CTRL_SIGNAL4 ) ;
tmp = readl ( phyd + ANA_EQ_EYE_CTRL_SIGNAL5 ) ;
tmp & = ~ RG_CDR_BIRLTD0_GEN3_MSK ;
tmp | = RG_CDR_BIRLTD0_GEN3_VAL ( 0x06 ) ;
writel ( tmp , phyd + ANA_EQ_EYE_CTRL_SIGNAL5 ) ;
tmp = readl ( phyd + ANA_RG_CTRL_SIGNAL4 ) ;
tmp & = ~ ( RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK ) ;
tmp | = RG_CDR_BICLTR_GEN1_VAL ( 0x0c ) | RG_CDR_BR_GEN2_VAL ( 0x07 ) ;
writel ( tmp , phyd + ANA_RG_CTRL_SIGNAL4 ) ;
tmp = readl ( phyd + PHYD_CTRL_SIGNAL_MODE4 ) ;
tmp & = ~ ( RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK ) ;
tmp | = RG_CDR_BICLTD0_GEN1_VAL ( 0x08 ) | RG_CDR_BICLTD1_GEN1_VAL ( 0x02 ) ;
writel ( tmp , phyd + PHYD_CTRL_SIGNAL_MODE4 ) ;
tmp = readl ( phyd + PHYD_DESIGN_OPTION2 ) ;
tmp & = ~ RG_LOCK_CNT_SEL_MSK ;
tmp | = RG_LOCK_CNT_SEL_VAL ( 0x02 ) ;
writel ( tmp , phyd + PHYD_DESIGN_OPTION2 ) ;
tmp = readl ( phyd + PHYD_DESIGN_OPTION9 ) ;
tmp & = ~ ( RG_T2_MIN_MSK | RG_TG_MIN_MSK |
RG_T2_MAX_MSK | RG_TG_MAX_MSK ) ;
tmp | = RG_T2_MIN_VAL ( 0x12 ) | RG_TG_MIN_VAL ( 0x04 ) |
RG_T2_MAX_VAL ( 0x31 ) | RG_TG_MAX_VAL ( 0x0e ) ;
writel ( tmp , phyd + PHYD_DESIGN_OPTION9 ) ;
tmp = readl ( phyd + ANA_RG_CTRL_SIGNAL1 ) ;
tmp & = ~ RG_IDRV_0DB_GEN1_MSK ;
tmp | = RG_IDRV_0DB_GEN1_VAL ( 0x20 ) ;
writel ( tmp , phyd + ANA_RG_CTRL_SIGNAL1 ) ;
tmp = readl ( phyd + ANA_EQ_EYE_CTRL_SIGNAL1 ) ;
tmp & = ~ RG_EQ_DLEQ_LFI_GEN1_MSK ;
tmp | = RG_EQ_DLEQ_LFI_GEN1_VAL ( 0x03 ) ;
writel ( tmp , phyd + ANA_EQ_EYE_CTRL_SIGNAL1 ) ;
2017-08-03 18:01:02 +08:00
dev_dbg ( tphy - > dev , " %s(%d) \n " , __func__ , instance - > index ) ;
2017-08-03 18:01:01 +08:00
}
2017-08-03 18:01:02 +08:00
static void phy_v1_banks_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-03-31 15:35:31 +08:00
{
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
struct u3phy_banks * u3_banks = & instance - > u3_banks ;
2017-08-03 18:01:00 +08:00
switch ( instance - > type ) {
case PHY_TYPE_USB2 :
2017-03-31 15:35:31 +08:00
u2_banks - > misc = NULL ;
2017-08-03 18:01:02 +08:00
u2_banks - > fmreg = tphy - > sif_base + SSUSB_SIFSLV_V1_U2FREQ ;
2017-03-31 15:35:31 +08:00
u2_banks - > com = instance - > port_base + SSUSB_SIFSLV_V1_U2PHY_COM ;
2017-08-03 18:01:00 +08:00
break ;
case PHY_TYPE_USB3 :
case PHY_TYPE_PCIE :
2017-08-03 18:01:02 +08:00
u3_banks - > spllc = tphy - > sif_base + SSUSB_SIFSLV_V1_SPLLC ;
2017-09-21 18:31:48 +08:00
u3_banks - > chip = tphy - > sif_base + SSUSB_SIFSLV_V1_CHIP ;
2017-03-31 15:35:31 +08:00
u3_banks - > phyd = instance - > port_base + SSUSB_SIFSLV_V1_U3PHYD ;
u3_banks - > phya = instance - > port_base + SSUSB_SIFSLV_V1_U3PHYA ;
2017-08-03 18:01:00 +08:00
break ;
2017-08-03 18:01:01 +08:00
case PHY_TYPE_SATA :
u3_banks - > phyd = instance - > port_base + SSUSB_SIFSLV_V1_U3PHYD ;
break ;
2017-08-03 18:01:00 +08:00
default :
2017-08-03 18:01:02 +08:00
dev_err ( tphy - > dev , " incompatible PHY type \n " ) ;
2017-08-03 18:01:00 +08:00
return ;
2017-03-31 15:35:31 +08:00
}
}
2017-08-03 18:01:02 +08:00
static void phy_v2_banks_init ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
2017-03-31 15:35:31 +08:00
{
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
struct u3phy_banks * u3_banks = & instance - > u3_banks ;
2017-08-03 18:01:00 +08:00
switch ( instance - > type ) {
case PHY_TYPE_USB2 :
2017-03-31 15:35:31 +08:00
u2_banks - > misc = instance - > port_base + SSUSB_SIFSLV_V2_MISC ;
u2_banks - > fmreg = instance - > port_base + SSUSB_SIFSLV_V2_U2FREQ ;
u2_banks - > com = instance - > port_base + SSUSB_SIFSLV_V2_U2PHY_COM ;
2017-08-03 18:01:00 +08:00
break ;
case PHY_TYPE_USB3 :
case PHY_TYPE_PCIE :
2017-03-31 15:35:31 +08:00
u3_banks - > spllc = instance - > port_base + SSUSB_SIFSLV_V2_SPLLC ;
u3_banks - > chip = instance - > port_base + SSUSB_SIFSLV_V2_CHIP ;
u3_banks - > phyd = instance - > port_base + SSUSB_SIFSLV_V2_U3PHYD ;
u3_banks - > phya = instance - > port_base + SSUSB_SIFSLV_V2_U3PHYA ;
2017-08-03 18:01:00 +08:00
break ;
default :
2017-08-03 18:01:02 +08:00
dev_err ( tphy - > dev , " incompatible PHY type \n " ) ;
2017-08-03 18:01:00 +08:00
return ;
2015-09-29 11:01:36 +08:00
}
}
2018-06-29 10:20:29 +08:00
static void phy_parse_property ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
{
struct device * dev = & instance - > phy - > dev ;
if ( instance - > type ! = PHY_TYPE_USB2 )
return ;
2018-06-29 10:20:30 +08:00
instance - > bc12_en = device_property_read_bool ( dev , " mediatek,bc12 " ) ;
2018-06-29 10:20:29 +08:00
device_property_read_u32 ( dev , " mediatek,eye-src " ,
& instance - > eye_src ) ;
device_property_read_u32 ( dev , " mediatek,eye-vrt " ,
& instance - > eye_vrt ) ;
device_property_read_u32 ( dev , " mediatek,eye-term " ,
& instance - > eye_term ) ;
2018-06-29 10:20:30 +08:00
dev_dbg ( dev , " bc12:%d, src:%d, vrt:%d, term:%d \n " ,
instance - > bc12_en , instance - > eye_src ,
instance - > eye_vrt , instance - > eye_term ) ;
2018-06-29 10:20:29 +08:00
}
static void u2_phy_props_set ( struct mtk_tphy * tphy ,
struct mtk_phy_instance * instance )
{
struct u2phy_banks * u2_banks = & instance - > u2_banks ;
void __iomem * com = u2_banks - > com ;
u32 tmp ;
2018-06-29 10:20:30 +08:00
if ( instance - > bc12_en ) {
tmp = readl ( com + U3P_U2PHYBC12C ) ;
tmp | = P2C_RG_CHGDT_EN ; /* BC1.2 path Enable */
writel ( tmp , com + U3P_U2PHYBC12C ) ;
}
2018-06-29 10:20:29 +08:00
if ( instance - > eye_src ) {
tmp = readl ( com + U3P_USBPHYACR5 ) ;
tmp & = ~ PA5_RG_U2_HSTX_SRCTRL ;
tmp | = PA5_RG_U2_HSTX_SRCTRL_VAL ( instance - > eye_src ) ;
writel ( tmp , com + U3P_USBPHYACR5 ) ;
}
if ( instance - > eye_vrt ) {
tmp = readl ( com + U3P_USBPHYACR1 ) ;
tmp & = ~ PA1_RG_VRT_SEL ;
tmp | = PA1_RG_VRT_SEL_VAL ( instance - > eye_vrt ) ;
writel ( tmp , com + U3P_USBPHYACR1 ) ;
}
if ( instance - > eye_term ) {
tmp = readl ( com + U3P_USBPHYACR1 ) ;
tmp & = ~ PA1_RG_TERM_SEL ;
tmp | = PA1_RG_TERM_SEL_VAL ( instance - > eye_term ) ;
writel ( tmp , com + U3P_USBPHYACR1 ) ;
}
}
2017-08-03 18:01:02 +08:00
static int mtk_phy_init ( struct phy * phy )
2015-09-29 11:01:36 +08:00
{
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance * instance = phy_get_drvdata ( phy ) ;
struct mtk_tphy * tphy = dev_get_drvdata ( phy - > dev . parent ) ;
2015-09-29 11:01:36 +08:00
int ret ;
2017-08-03 18:01:02 +08:00
ret = clk_prepare_enable ( tphy - > u3phya_ref ) ;
2015-09-29 11:01:36 +08:00
if ( ret ) {
2017-08-03 18:01:02 +08:00
dev_err ( tphy - > dev , " failed to enable u3phya_ref \n " ) ;
2015-09-29 11:01:36 +08:00
return ret ;
}
2017-03-31 15:35:30 +08:00
ret = clk_prepare_enable ( instance - > ref_clk ) ;
if ( ret ) {
2017-08-03 18:01:02 +08:00
dev_err ( tphy - > dev , " failed to enable ref_clk \n " ) ;
2017-03-31 15:35:30 +08:00
return ret ;
}
2017-08-03 18:01:00 +08:00
switch ( instance - > type ) {
case PHY_TYPE_USB2 :
2017-08-03 18:01:02 +08:00
u2_phy_instance_init ( tphy , instance ) ;
2018-06-29 10:20:29 +08:00
u2_phy_props_set ( tphy , instance ) ;
2017-08-03 18:01:00 +08:00
break ;
case PHY_TYPE_USB3 :
2017-08-03 18:01:02 +08:00
u3_phy_instance_init ( tphy , instance ) ;
2017-08-03 18:01:00 +08:00
break ;
case PHY_TYPE_PCIE :
2017-08-03 18:01:02 +08:00
pcie_phy_instance_init ( tphy , instance ) ;
2017-08-03 18:01:00 +08:00
break ;
2017-08-03 18:01:01 +08:00
case PHY_TYPE_SATA :
2017-08-03 18:01:02 +08:00
sata_phy_instance_init ( tphy , instance ) ;
2017-08-03 18:01:01 +08:00
break ;
2017-08-03 18:01:00 +08:00
default :
2017-08-03 18:01:02 +08:00
dev_err ( tphy - > dev , " incompatible PHY type \n " ) ;
2017-08-03 18:01:00 +08:00
return - EINVAL ;
}
2017-03-31 15:35:29 +08:00
2015-09-29 11:01:36 +08:00
return 0 ;
}
2017-08-03 18:01:02 +08:00
static int mtk_phy_power_on ( struct phy * phy )
2015-09-29 11:01:36 +08:00
{
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance * instance = phy_get_drvdata ( phy ) ;
struct mtk_tphy * tphy = dev_get_drvdata ( phy - > dev . parent ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:29 +08:00
if ( instance - > type = = PHY_TYPE_USB2 ) {
2017-08-03 18:01:02 +08:00
u2_phy_instance_power_on ( tphy , instance ) ;
hs_slew_rate_calibrate ( tphy , instance ) ;
2017-08-03 18:01:00 +08:00
} else if ( instance - > type = = PHY_TYPE_PCIE ) {
2017-08-03 18:01:02 +08:00
pcie_phy_instance_power_on ( tphy , instance ) ;
2017-03-31 15:35:29 +08:00
}
2017-08-03 18:01:00 +08:00
2015-09-29 11:01:36 +08:00
return 0 ;
}
2017-08-03 18:01:02 +08:00
static int mtk_phy_power_off ( struct phy * phy )
2015-09-29 11:01:36 +08:00
{
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance * instance = phy_get_drvdata ( phy ) ;
struct mtk_tphy * tphy = dev_get_drvdata ( phy - > dev . parent ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:29 +08:00
if ( instance - > type = = PHY_TYPE_USB2 )
2017-08-03 18:01:02 +08:00
u2_phy_instance_power_off ( tphy , instance ) ;
2017-08-03 18:01:00 +08:00
else if ( instance - > type = = PHY_TYPE_PCIE )
2017-08-03 18:01:02 +08:00
pcie_phy_instance_power_off ( tphy , instance ) ;
2017-03-31 15:35:29 +08:00
2015-09-29 11:01:36 +08:00
return 0 ;
}
2017-08-03 18:01:02 +08:00
static int mtk_phy_exit ( struct phy * phy )
2015-09-29 11:01:36 +08:00
{
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance * instance = phy_get_drvdata ( phy ) ;
struct mtk_tphy * tphy = dev_get_drvdata ( phy - > dev . parent ) ;
2015-09-29 11:01:36 +08:00
2017-03-31 15:35:29 +08:00
if ( instance - > type = = PHY_TYPE_USB2 )
2017-08-03 18:01:02 +08:00
u2_phy_instance_exit ( tphy , instance ) ;
2017-03-31 15:35:29 +08:00
2017-03-31 15:35:30 +08:00
clk_disable_unprepare ( instance - > ref_clk ) ;
2017-08-03 18:01:02 +08:00
clk_disable_unprepare ( tphy - > u3phya_ref ) ;
2015-09-29 11:01:36 +08:00
return 0 ;
}
2017-09-21 18:31:49 +08:00
static int mtk_phy_set_mode ( struct phy * phy , enum phy_mode mode )
{
struct mtk_phy_instance * instance = phy_get_drvdata ( phy ) ;
struct mtk_tphy * tphy = dev_get_drvdata ( phy - > dev . parent ) ;
if ( instance - > type = = PHY_TYPE_USB2 )
u2_phy_instance_set_mode ( tphy , instance , mode ) ;
return 0 ;
}
2017-08-03 18:01:02 +08:00
static struct phy * mtk_phy_xlate ( struct device * dev ,
2015-09-29 11:01:36 +08:00
struct of_phandle_args * args )
{
2017-08-03 18:01:02 +08:00
struct mtk_tphy * tphy = dev_get_drvdata ( dev ) ;
struct mtk_phy_instance * instance = NULL ;
2015-09-29 11:01:36 +08:00
struct device_node * phy_np = args - > np ;
int index ;
if ( args - > args_count ! = 1 ) {
dev_err ( dev , " invalid number of cells in 'phy' property \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
2017-08-03 18:01:02 +08:00
for ( index = 0 ; index < tphy - > nphys ; index + + )
if ( phy_np = = tphy - > phys [ index ] - > phy - > dev . of_node ) {
instance = tphy - > phys [ index ] ;
2015-09-29 11:01:36 +08:00
break ;
}
if ( ! instance ) {
dev_err ( dev , " failed to find appropriate phy \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
instance - > type = args - > args [ 0 ] ;
if ( ! ( instance - > type = = PHY_TYPE_USB2 | |
2017-08-03 18:01:00 +08:00
instance - > type = = PHY_TYPE_USB3 | |
2017-08-03 18:01:01 +08:00
instance - > type = = PHY_TYPE_PCIE | |
instance - > type = = PHY_TYPE_SATA ) ) {
2015-09-29 11:01:36 +08:00
dev_err ( dev , " unsupported device type: %d \n " , instance - > type ) ;
return ERR_PTR ( - EINVAL ) ;
}
2017-08-03 18:01:02 +08:00
if ( tphy - > pdata - > version = = MTK_PHY_V1 ) {
phy_v1_banks_init ( tphy , instance ) ;
} else if ( tphy - > pdata - > version = = MTK_PHY_V2 ) {
phy_v2_banks_init ( tphy , instance ) ;
2017-03-31 15:35:31 +08:00
} else {
dev_err ( dev , " phy version is not supported \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
2018-06-29 10:20:29 +08:00
phy_parse_property ( tphy , instance ) ;
2015-09-29 11:01:36 +08:00
return instance - > phy ;
}
2017-08-03 18:01:02 +08:00
static const struct phy_ops mtk_tphy_ops = {
. init = mtk_phy_init ,
. exit = mtk_phy_exit ,
. power_on = mtk_phy_power_on ,
. power_off = mtk_phy_power_off ,
2017-09-21 18:31:49 +08:00
. set_mode = mtk_phy_set_mode ,
2015-09-29 11:01:36 +08:00
. owner = THIS_MODULE ,
} ;
2017-08-03 18:01:02 +08:00
static const struct mtk_phy_pdata tphy_v1_pdata = {
2016-04-20 08:14:02 +08:00
. avoid_rx_sen_degradation = false ,
2017-08-03 18:01:02 +08:00
. version = MTK_PHY_V1 ,
2017-03-31 15:35:31 +08:00
} ;
2017-08-03 18:01:02 +08:00
static const struct mtk_phy_pdata tphy_v2_pdata = {
2017-03-31 15:35:31 +08:00
. avoid_rx_sen_degradation = false ,
2017-08-03 18:01:02 +08:00
. version = MTK_PHY_V2 ,
2016-04-20 08:14:02 +08:00
} ;
2017-08-03 18:01:02 +08:00
static const struct mtk_phy_pdata mt8173_pdata = {
2016-04-20 08:14:02 +08:00
. avoid_rx_sen_degradation = true ,
2017-08-03 18:01:02 +08:00
. version = MTK_PHY_V1 ,
2016-04-20 08:14:02 +08:00
} ;
2017-08-03 18:01:02 +08:00
static const struct of_device_id mtk_tphy_id_table [ ] = {
2017-08-03 18:01:00 +08:00
{ . compatible = " mediatek,mt2701-u3phy " , . data = & tphy_v1_pdata } ,
2017-08-03 18:01:01 +08:00
{ . compatible = " mediatek,mt2712-u3phy " , . data = & tphy_v2_pdata } ,
2016-04-20 08:14:02 +08:00
{ . compatible = " mediatek,mt8173-u3phy " , . data = & mt8173_pdata } ,
2017-08-03 18:01:00 +08:00
{ . compatible = " mediatek,generic-tphy-v1 " , . data = & tphy_v1_pdata } ,
2017-08-03 18:01:01 +08:00
{ . compatible = " mediatek,generic-tphy-v2 " , . data = & tphy_v2_pdata } ,
2016-04-20 08:14:02 +08:00
{ } ,
} ;
2017-08-03 18:01:02 +08:00
MODULE_DEVICE_TABLE ( of , mtk_tphy_id_table ) ;
2016-04-20 08:14:02 +08:00
2017-08-03 18:01:02 +08:00
static int mtk_tphy_probe ( struct platform_device * pdev )
2015-09-29 11:01:36 +08:00
{
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
struct device_node * child_np ;
struct phy_provider * provider ;
struct resource * sif_res ;
2017-08-03 18:01:02 +08:00
struct mtk_tphy * tphy ;
2015-09-29 11:01:36 +08:00
struct resource res ;
2015-11-16 12:33:15 +01:00
int port , retval ;
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
tphy = devm_kzalloc ( dev , sizeof ( * tphy ) , GFP_KERNEL ) ;
if ( ! tphy )
2015-09-29 11:01:36 +08:00
return - ENOMEM ;
2017-12-28 16:40:36 +05:30
tphy - > pdata = of_device_get_match_data ( dev ) ;
if ( ! tphy - > pdata )
return - EINVAL ;
2017-08-03 18:01:02 +08:00
tphy - > nphys = of_get_child_count ( np ) ;
tphy - > phys = devm_kcalloc ( dev , tphy - > nphys ,
sizeof ( * tphy - > phys ) , GFP_KERNEL ) ;
if ( ! tphy - > phys )
2015-09-29 11:01:36 +08:00
return - ENOMEM ;
2017-08-03 18:01:02 +08:00
tphy - > dev = dev ;
platform_set_drvdata ( pdev , tphy ) ;
2015-09-29 11:01:36 +08:00
2017-12-07 19:53:35 +08:00
sif_res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
/* SATA phy of V1 needn't it if not shared with PCIe or USB */
if ( sif_res & & tphy - > pdata - > version = = MTK_PHY_V1 ) {
2017-03-31 15:35:31 +08:00
/* get banks shared by multiple phys */
2017-08-03 18:01:02 +08:00
tphy - > sif_base = devm_ioremap_resource ( dev , sif_res ) ;
if ( IS_ERR ( tphy - > sif_base ) ) {
2017-03-31 15:35:31 +08:00
dev_err ( dev , " failed to remap sif regs \n " ) ;
2017-08-03 18:01:02 +08:00
return PTR_ERR ( tphy - > sif_base ) ;
2017-03-31 15:35:31 +08:00
}
2015-09-29 11:01:36 +08:00
}
2017-03-31 15:35:30 +08:00
/* it's deprecated, make it optional for backward compatibility */
2017-08-03 18:01:02 +08:00
tphy - > u3phya_ref = devm_clk_get ( dev , " u3phya_ref " ) ;
if ( IS_ERR ( tphy - > u3phya_ref ) ) {
if ( PTR_ERR ( tphy - > u3phya_ref ) = = - EPROBE_DEFER )
2017-03-31 15:35:30 +08:00
return - EPROBE_DEFER ;
2017-08-03 18:01:02 +08:00
tphy - > u3phya_ref = NULL ;
2015-09-29 11:01:36 +08:00
}
2018-03-12 13:25:39 +08:00
tphy - > src_ref_clk = U3P_REF_CLK ;
tphy - > src_coef = U3P_SLEW_RATE_COEF ;
/* update parameters of slew rate calibrate if exist */
device_property_read_u32 ( dev , " mediatek,src-ref-clk-mhz " ,
& tphy - > src_ref_clk ) ;
device_property_read_u32 ( dev , " mediatek,src-coef " , & tphy - > src_coef ) ;
2015-09-29 11:01:36 +08:00
port = 0 ;
for_each_child_of_node ( np , child_np ) {
2017-08-03 18:01:02 +08:00
struct mtk_phy_instance * instance ;
2015-09-29 11:01:36 +08:00
struct phy * phy ;
instance = devm_kzalloc ( dev , sizeof ( * instance ) , GFP_KERNEL ) ;
2015-11-16 12:33:15 +01:00
if ( ! instance ) {
retval = - ENOMEM ;
goto put_child ;
}
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
tphy - > phys [ port ] = instance ;
2015-09-29 11:01:36 +08:00
2017-08-03 18:01:02 +08:00
phy = devm_phy_create ( dev , child_np , & mtk_tphy_ops ) ;
2015-09-29 11:01:36 +08:00
if ( IS_ERR ( phy ) ) {
dev_err ( dev , " failed to create phy \n " ) ;
2015-11-16 12:33:15 +01:00
retval = PTR_ERR ( phy ) ;
goto put_child ;
2015-09-29 11:01:36 +08:00
}
retval = of_address_to_resource ( child_np , 0 , & res ) ;
if ( retval ) {
dev_err ( dev , " failed to get address resource(id-%d) \n " ,
port ) ;
2015-11-16 12:33:15 +01:00
goto put_child ;
2015-09-29 11:01:36 +08:00
}
instance - > port_base = devm_ioremap_resource ( & phy - > dev , & res ) ;
if ( IS_ERR ( instance - > port_base ) ) {
dev_err ( dev , " failed to remap phy regs \n " ) ;
2015-11-16 12:33:15 +01:00
retval = PTR_ERR ( instance - > port_base ) ;
goto put_child ;
2015-09-29 11:01:36 +08:00
}
instance - > phy = phy ;
instance - > index = port ;
phy_set_drvdata ( phy , instance ) ;
port + + ;
2017-03-31 15:35:30 +08:00
/* if deprecated clock is provided, ignore instance's one */
2017-08-03 18:01:02 +08:00
if ( tphy - > u3phya_ref )
2017-03-31 15:35:30 +08:00
continue ;
instance - > ref_clk = devm_clk_get ( & phy - > dev , " ref " ) ;
if ( IS_ERR ( instance - > ref_clk ) ) {
dev_err ( dev , " failed to get ref_clk(id-%d) \n " , port ) ;
retval = PTR_ERR ( instance - > ref_clk ) ;
goto put_child ;
}
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
provider = devm_of_phy_provider_register ( dev , mtk_phy_xlate ) ;
2015-09-29 11:01:36 +08:00
return PTR_ERR_OR_ZERO ( provider ) ;
2015-11-16 12:33:15 +01:00
put_child :
of_node_put ( child_np ) ;
return retval ;
2015-09-29 11:01:36 +08:00
}
2017-08-03 18:01:02 +08:00
static struct platform_driver mtk_tphy_driver = {
. probe = mtk_tphy_probe ,
2015-09-29 11:01:36 +08:00
. driver = {
2017-08-03 18:01:02 +08:00
. name = " mtk-tphy " ,
. of_match_table = mtk_tphy_id_table ,
2015-09-29 11:01:36 +08:00
} ,
} ;
2017-08-03 18:01:02 +08:00
module_platform_driver ( mtk_tphy_driver ) ;
2015-09-29 11:01:36 +08:00
MODULE_AUTHOR ( " Chunfeng Yun <chunfeng.yun@mediatek.com> " ) ;
2017-08-03 18:01:02 +08:00
MODULE_DESCRIPTION ( " MediaTek T-PHY driver " ) ;
2015-09-29 11:01:36 +08:00
MODULE_LICENSE ( " GPL v2 " ) ;