phy: phy-mt65xx-usb3: add support for new version phy
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Fri, 31 Mar 2017 07:35:31 +0000 (15:35 +0800)
committerKishon Vijay Abraham I <kishon@ti.com>
Mon, 10 Apr 2017 11:13:40 +0000 (16:43 +0530)
There are some variations from mt2701 to mt2712:
1. banks shared by multiple ports are put back into each port,
    such as SPLLC and U2FREQ;
2. add a new bank MISC for u2port, and CHIP for u3port;
3. bank's offset in each port are also rearranged;

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
drivers/phy/phy-mt65xx-usb3.c

index 34035721cf6276b3b9c323a299eeb8e561f4baf3..e99788babfb9d773c0428401657a485753e709d6 100644 (file)
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 
-/*
- * for sifslv2 register, but exclude port's;
- * relative to USB3_SIF2_BASE base address
- */
-#define SSUSB_SIFSLV_SPLLC             0x0000
-#define SSUSB_SIFSLV_U2FREQ            0x0100
-
-/* offsets of banks in each u2phy registers */
-#define SSUSB_SIFSLV_U2PHY_COM_BASE    0x0000
-/* offsets of banks in each u3phy registers */
-#define SSUSB_SIFSLV_U3PHYD_BASE       0x0000
-#define SSUSB_SIFSLV_U3PHYA_BASE       0x0200
-
-#define U3P_USBPHYACR0         (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000)
+/* 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 */
+/* u2 phy bank */
+#define SSUSB_SIFSLV_V1_U2PHY_COM      0x000
+/* u3 phy banks */
+#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
+/* u3 phy banks */
+#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
 #define PA0_RG_U2PLL_FORCE_ON          BIT(15)
 
-#define U3P_USBPHYACR2         (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0008)
+#define U3P_USBPHYACR2         0x008
 #define PA2_RG_SIF_U2PLL_FORCE_EN      BIT(18)
 
-#define U3P_USBPHYACR5         (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
+#define U3P_USBPHYACR5         0x014
 #define PA5_RG_U2_HSTX_SRCAL_EN        BIT(15)
 #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)
 
-#define U3P_USBPHYACR6         (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018)
+#define U3P_USBPHYACR6         0x018
 #define PA6_RG_U2_BC11_SW_EN           BIT(23)
 #define PA6_RG_U2_OTG_VBUSCMP_EN       BIT(20)
 #define PA6_RG_U2_SQTH         GENMASK(3, 0)
 #define PA6_RG_U2_SQTH_VAL(x)  (0xf & (x))
 
-#define U3P_U2PHYACR4          (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
+#define U3P_U2PHYACR4          0x020
 #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)
 
-#define U3D_U2PHYDCR0          (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0060)
+#define U3D_U2PHYDCR0          0x060
 #define P2C_RG_SIF_U2PLL_FORCE_ON      BIT(24)
 
-#define U3P_U2PHYDTM0          (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0068)
+#define U3P_U2PHYDTM0          0x068
 #define P2C_FORCE_UART_EN              BIT(26)
 #define P2C_FORCE_DATAIN               BIT(23)
 #define P2C_FORCE_DM_PULLDOWN          BIT(21)
                P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
                P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
 
-#define U3P_U2PHYDTM1          (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x006C)
+#define U3P_U2PHYDTM1          0x06C
 #define P2C_RG_UART_EN                 BIT(16)
 #define P2C_RG_VBUSVALID               BIT(5)
 #define P2C_RG_SESSEND                 BIT(4)
 #define P2C_RG_AVALID                  BIT(2)
 
-#define U3P_U3_PHYA_REG0       (SSUSB_SIFSLV_U3PHYA_BASE + 0x0000)
-#define P3A_RG_U3_VUSB10_ON            BIT(5)
-
-#define U3P_U3_PHYA_REG6       (SSUSB_SIFSLV_U3PHYA_BASE + 0x0018)
+#define U3P_U3_PHYA_REG6       0x018
 #define P3A_RG_TX_EIDLE_CM             GENMASK(31, 28)
 #define P3A_RG_TX_EIDLE_CM_VAL(x)      ((0xf & (x)) << 28)
 
-#define U3P_U3_PHYA_REG9       (SSUSB_SIFSLV_U3PHYA_BASE + 0x0024)
+#define U3P_U3_PHYA_REG9       0x024
 #define P3A_RG_RX_DAC_MUX              GENMASK(5, 1)
 #define P3A_RG_RX_DAC_MUX_VAL(x)       ((0x1f & (x)) << 1)
 
-#define U3P_U3PHYA_DA_REG0     (SSUSB_SIFSLV_U3PHYA_BASE + 0x0100)
+#define U3P_U3_PHYA_DA_REG0    0x100
 #define P3A_RG_XTAL_EXT_EN_U3          GENMASK(11, 10)
 #define P3A_RG_XTAL_EXT_EN_U3_VAL(x)   ((0x3 & (x)) << 10)
 
-#define U3P_U3_PHYD_LFPS1              (SSUSB_SIFSLV_U3PHYD_BASE + 0x000c)
+#define U3P_U3_PHYD_LFPS1              0x00c
 #define P3D_RG_FWAKE_TH                GENMASK(21, 16)
 #define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
 
-#define U3P_PHYD_CDR1          (SSUSB_SIFSLV_U3PHYD_BASE + 0x005c)
+#define U3P_U3_PHYD_CDR1               0x05c
 #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)
 
-#define U3P_U3_PHYD_RXDET1             (SSUSB_SIFSLV_U3PHYD_BASE + 0x128)
+#define U3P_U3_PHYD_RXDET1             0x128
 #define P3D_RG_RXDET_STB2_SET          GENMASK(17, 9)
 #define P3D_RG_RXDET_STB2_SET_VAL(x)   ((0x1ff & (x)) << 9)
 
-#define U3P_U3_PHYD_RXDET2             (SSUSB_SIFSLV_U3PHYD_BASE + 0x12c)
+#define U3P_U3_PHYD_RXDET2             0x12c
 #define P3D_RG_RXDET_STB2_SET_P3       GENMASK(8, 0)
 #define P3D_RG_RXDET_STB2_SET_P3_VAL(x)        (0x1ff & (x))
 
-#define U3P_XTALCTL3           (SSUSB_SIFSLV_SPLLC + 0x0018)
+#define U3P_SPLLC_XTALCTL3             0x018
 #define XC3_RG_U3_XTAL_RX_PWD          BIT(9)
 #define XC3_RG_U3_FRC_XTAL_RX_PWD      BIT(8)
 
-#define U3P_U2FREQ_FMCR0       (SSUSB_SIFSLV_U2FREQ + 0x00)
+#define U3P_U2FREQ_FMCR0       0x00
 #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))
 
-#define U3P_U2FREQ_VALUE       (SSUSB_SIFSLV_U2FREQ + 0x0c)
+#define U3P_U2FREQ_VALUE       0x0c
 
-#define U3P_U2FREQ_FMMONR1     (SSUSB_SIFSLV_U2FREQ + 0x10)
+#define U3P_U2FREQ_FMMONR1     0x10
 #define P2F_USB_FM_VALID       BIT(0)
 #define P2F_RG_FRCK_EN         BIT(8)
 
 #define U3P_SR_COEF_DIVISOR    1000
 #define U3P_FM_DET_CYCLE_CNT   1024
 
+enum mt_phy_version {
+       MT_PHY_V1 = 1,
+       MT_PHY_V2,
+};
+
 struct mt65xx_phy_pdata {
        /* avoid RX sensitivity level degradation only for mt8173 */
        bool avoid_rx_sen_degradation;
+       enum mt_phy_version version;
+};
+
+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 */
 };
 
 struct mt65xx_phy_instance {
        struct phy *phy;
        void __iomem *port_base;
+       union {
+               struct u2phy_banks u2_banks;
+               struct u3phy_banks u3_banks;
+       };
        struct clk *ref_clk;    /* reference clock of anolog phy */
        u32 index;
        u8 type;
@@ -171,49 +199,53 @@ struct mt65xx_u3phy {
 static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *sif_base = u3phy->sif_base;
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *fmreg = u2_banks->fmreg;
+       void __iomem *com = u2_banks->com;
        int calibration_val;
        int fm_out;
        u32 tmp;
 
        /* enable USB ring oscillator */
-       tmp = readl(instance->port_base + U3P_USBPHYACR5);
+       tmp = readl(com + U3P_USBPHYACR5);
        tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
-       writel(tmp, instance->port_base + U3P_USBPHYACR5);
+       writel(tmp, com + U3P_USBPHYACR5);
        udelay(1);
 
        /*enable free run clock */
-       tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
+       tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
        tmp |= P2F_RG_FRCK_EN;
-       writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
+       writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
 
        /* set cycle count as 1024, and select u2 channel */
-       tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+       tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
        tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
        tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
-       tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
-       writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+       if (u3phy->pdata->version == MT_PHY_V1)
+               tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
+
+       writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
 
        /* enable frequency meter */
-       tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+       tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
        tmp |= P2F_RG_FREQDET_EN;
-       writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+       writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
 
        /* ignore return value */
-       readl_poll_timeout(sif_base + U3P_U2FREQ_FMMONR1, tmp,
-                 (tmp & P2F_USB_FM_VALID), 10, 200);
+       readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
+                          (tmp & P2F_USB_FM_VALID), 10, 200);
 
-       fm_out = readl(sif_base + U3P_U2FREQ_VALUE);
+       fm_out = readl(fmreg + U3P_U2FREQ_VALUE);
 
        /* disable frequency meter */
-       tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
+       tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
        tmp &= ~P2F_RG_FREQDET_EN;
-       writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
+       writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
 
        /*disable free run clock */
-       tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
+       tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
        tmp &= ~P2F_RG_FRCK_EN;
-       writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
+       writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
 
        if (fm_out) {
                /* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
@@ -228,63 +260,63 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
                instance->index, fm_out, calibration_val);
 
        /* set HS slew rate */
-       tmp = readl(instance->port_base + U3P_USBPHYACR5);
+       tmp = readl(com + U3P_USBPHYACR5);
        tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
        tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
-       writel(tmp, instance->port_base + U3P_USBPHYACR5);
+       writel(tmp, com + U3P_USBPHYACR5);
 
        /* disable USB ring oscillator */
-       tmp = readl(instance->port_base + U3P_USBPHYACR5);
+       tmp = readl(com + U3P_USBPHYACR5);
        tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
-       writel(tmp, instance->port_base + U3P_USBPHYACR5);
+       writel(tmp, com + U3P_USBPHYACR5);
 }
 
 static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *port_base = instance->port_base;
+       struct u3phy_banks *u3_banks = &instance->u3_banks;
        u32 tmp;
 
        /* gating PCIe Analog XTAL clock */
-       tmp = readl(u3phy->sif_base + U3P_XTALCTL3);
+       tmp = readl(u3_banks->spllc + U3P_SPLLC_XTALCTL3);
        tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
-       writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
+       writel(tmp, u3_banks->spllc + U3P_SPLLC_XTALCTL3);
 
        /* gating XSQ */
-       tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
+       tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
        tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
        tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
-       writel(tmp, port_base + U3P_U3PHYA_DA_REG0);
+       writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
 
-       tmp = readl(port_base + U3P_U3_PHYA_REG9);
+       tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG9);
        tmp &= ~P3A_RG_RX_DAC_MUX;
        tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
-       writel(tmp, port_base + U3P_U3_PHYA_REG9);
+       writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG9);
 
-       tmp = readl(port_base + U3P_U3_PHYA_REG6);
+       tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG6);
        tmp &= ~P3A_RG_TX_EIDLE_CM;
        tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
-       writel(tmp, port_base + U3P_U3_PHYA_REG6);
+       writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG6);
 
-       tmp = readl(port_base + U3P_PHYD_CDR1);
+       tmp = readl(u3_banks->phyd + U3P_U3_PHYD_CDR1);
        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);
-       writel(tmp, port_base + U3P_PHYD_CDR1);
+       writel(tmp, u3_banks->phyd + U3P_U3_PHYD_CDR1);
 
-       tmp = readl(port_base + U3P_U3_PHYD_LFPS1);
+       tmp = readl(u3_banks->phyd + U3P_U3_PHYD_LFPS1);
        tmp &= ~P3D_RG_FWAKE_TH;
        tmp |= P3D_RG_FWAKE_TH_VAL(0x34);
-       writel(tmp, port_base + U3P_U3_PHYD_LFPS1);
+       writel(tmp, u3_banks->phyd + U3P_U3_PHYD_LFPS1);
 
-       tmp = readl(port_base + U3P_U3_PHYD_RXDET1);
+       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, port_base + U3P_U3_PHYD_RXDET1);
+       writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
 
-       tmp = readl(port_base + U3P_U3_PHYD_RXDET2);
+       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, port_base + U3P_U3_PHYD_RXDET2);
+       writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
 
        dev_dbg(u3phy->dev, "%s(%d)\n", __func__, instance->index);
 }
@@ -292,51 +324,52 @@ static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy,
 static void phy_instance_init(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *port_base = instance->port_base;
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *com = u2_banks->com;
        u32 index = instance->index;
        u32 tmp;
 
        /* switch to USB function. (system register, force ip into usb mode) */
-       tmp = readl(port_base + U3P_U2PHYDTM0);
+       tmp = readl(com + U3P_U2PHYDTM0);
        tmp &= ~P2C_FORCE_UART_EN;
        tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
-       writel(tmp, port_base + U3P_U2PHYDTM0);
+       writel(tmp, com + U3P_U2PHYDTM0);
 
-       tmp = readl(port_base + U3P_U2PHYDTM1);
+       tmp = readl(com + U3P_U2PHYDTM1);
        tmp &= ~P2C_RG_UART_EN;
-       writel(tmp, port_base + U3P_U2PHYDTM1);
+       writel(tmp, com + U3P_U2PHYDTM1);
 
        if (!index) {
-               tmp = readl(port_base + U3P_U2PHYACR4);
+               tmp = readl(com + U3P_U2PHYACR4);
                tmp &= ~P2C_U2_GPIO_CTR_MSK;
-               writel(tmp, port_base + U3P_U2PHYACR4);
+               writel(tmp, com + U3P_U2PHYACR4);
        }
 
        if (u3phy->pdata->avoid_rx_sen_degradation) {
                if (!index) {
-                       tmp = readl(port_base + U3P_USBPHYACR2);
+                       tmp = readl(com + U3P_USBPHYACR2);
                        tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
-                       writel(tmp, port_base + U3P_USBPHYACR2);
+                       writel(tmp, com + U3P_USBPHYACR2);
 
-                       tmp = readl(port_base + U3D_U2PHYDCR0);
+                       tmp = readl(com + U3D_U2PHYDCR0);
                        tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
-                       writel(tmp, port_base + U3D_U2PHYDCR0);
+                       writel(tmp, com + U3D_U2PHYDCR0);
                } else {
-                       tmp = readl(port_base + U3D_U2PHYDCR0);
+                       tmp = readl(com + U3D_U2PHYDCR0);
                        tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
-                       writel(tmp, port_base + U3D_U2PHYDCR0);
+                       writel(tmp, com + U3D_U2PHYDCR0);
 
-                       tmp = readl(port_base + U3P_U2PHYDTM0);
+                       tmp = readl(com + U3P_U2PHYDTM0);
                        tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
-                       writel(tmp, port_base + U3P_U2PHYDTM0);
+                       writel(tmp, com + U3P_U2PHYDTM0);
                }
        }
 
-       tmp = readl(port_base + U3P_USBPHYACR6);
+       tmp = readl(com + U3P_USBPHYACR6);
        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);
-       writel(tmp, port_base + U3P_USBPHYACR6);
+       writel(tmp, com + U3P_USBPHYACR6);
 
        dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
 }
@@ -344,41 +377,42 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
 static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *port_base = instance->port_base;
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *com = u2_banks->com;
        u32 index = instance->index;
        u32 tmp;
 
        /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
-       tmp = readl(port_base + U3P_U2PHYDTM0);
+       tmp = readl(com + U3P_U2PHYDTM0);
        tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
        tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
-       writel(tmp, port_base + U3P_U2PHYDTM0);
+       writel(tmp, com + U3P_U2PHYDTM0);
 
        /* OTG Enable */
-       tmp = readl(port_base + U3P_USBPHYACR6);
+       tmp = readl(com + U3P_USBPHYACR6);
        tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
-       writel(tmp, port_base + U3P_USBPHYACR6);
+       writel(tmp, com + U3P_USBPHYACR6);
 
        if (!index) {
                /* switch 100uA current to SSUSB */
-               tmp = readl(port_base + U3P_USBPHYACR5);
+               tmp = readl(com + U3P_USBPHYACR5);
                tmp |= PA5_RG_U2_HS_100U_U3_EN;
-               writel(tmp, port_base + U3P_USBPHYACR5);
+               writel(tmp, com + U3P_USBPHYACR5);
        }
 
-       tmp = readl(port_base + U3P_U2PHYDTM1);
+       tmp = readl(com + U3P_U2PHYDTM1);
        tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
        tmp &= ~P2C_RG_SESSEND;
-       writel(tmp, port_base + U3P_U2PHYDTM1);
+       writel(tmp, com + U3P_U2PHYDTM1);
 
        if (u3phy->pdata->avoid_rx_sen_degradation && index) {
-               tmp = readl(port_base + U3D_U2PHYDCR0);
+               tmp = readl(com + U3D_U2PHYDCR0);
                tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
-               writel(tmp, port_base + U3D_U2PHYDCR0);
+               writel(tmp, com + U3D_U2PHYDCR0);
 
-               tmp = readl(port_base + U3P_U2PHYDTM0);
+               tmp = readl(com + U3P_U2PHYDTM0);
                tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
-               writel(tmp, port_base + U3P_U2PHYDTM0);
+               writel(tmp, com + U3P_U2PHYDTM0);
        }
        dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
 }
@@ -386,42 +420,43 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
 static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *port_base = instance->port_base;
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *com = u2_banks->com;
        u32 index = instance->index;
        u32 tmp;
 
-       tmp = readl(port_base + U3P_U2PHYDTM0);
+       tmp = readl(com + U3P_U2PHYDTM0);
        tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
        tmp |= P2C_FORCE_SUSPENDM;
-       writel(tmp, port_base + U3P_U2PHYDTM0);
+       writel(tmp, com + U3P_U2PHYDTM0);
 
        /* OTG Disable */
-       tmp = readl(port_base + U3P_USBPHYACR6);
+       tmp = readl(com + U3P_USBPHYACR6);
        tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
-       writel(tmp, port_base + U3P_USBPHYACR6);
+       writel(tmp, com + U3P_USBPHYACR6);
 
        if (!index) {
                /* switch 100uA current back to USB2.0 */
-               tmp = readl(port_base + U3P_USBPHYACR5);
+               tmp = readl(com + U3P_USBPHYACR5);
                tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
-               writel(tmp, port_base + U3P_USBPHYACR5);
+               writel(tmp, com + U3P_USBPHYACR5);
        }
 
        /* let suspendm=0, set utmi into analog power down */
-       tmp = readl(port_base + U3P_U2PHYDTM0);
+       tmp = readl(com + U3P_U2PHYDTM0);
        tmp &= ~P2C_RG_SUSPENDM;
-       writel(tmp, port_base + U3P_U2PHYDTM0);
+       writel(tmp, com + U3P_U2PHYDTM0);
        udelay(1);
 
-       tmp = readl(port_base + U3P_U2PHYDTM1);
+       tmp = readl(com + U3P_U2PHYDTM1);
        tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
        tmp |= P2C_RG_SESSEND;
-       writel(tmp, port_base + U3P_U2PHYDTM1);
+       writel(tmp, com + U3P_U2PHYDTM1);
 
        if (u3phy->pdata->avoid_rx_sen_degradation && index) {
-               tmp = readl(port_base + U3D_U2PHYDCR0);
+               tmp = readl(com + U3D_U2PHYDCR0);
                tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
-               writel(tmp, port_base + U3D_U2PHYDCR0);
+               writel(tmp, com + U3D_U2PHYDCR0);
        }
 
        dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
@@ -430,18 +465,55 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
 static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
        struct mt65xx_phy_instance *instance)
 {
-       void __iomem *port_base = instance->port_base;
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *com = u2_banks->com;
        u32 index = instance->index;
        u32 tmp;
 
        if (u3phy->pdata->avoid_rx_sen_degradation && index) {
-               tmp = readl(port_base + U3D_U2PHYDCR0);
+               tmp = readl(com + U3D_U2PHYDCR0);
                tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
-               writel(tmp, port_base + U3D_U2PHYDCR0);
+               writel(tmp, com + U3D_U2PHYDCR0);
 
-               tmp = readl(port_base + U3P_U2PHYDTM0);
+               tmp = readl(com + U3P_U2PHYDTM0);
                tmp &= ~P2C_FORCE_SUSPENDM;
-               writel(tmp, port_base + U3P_U2PHYDTM0);
+               writel(tmp, com + U3P_U2PHYDTM0);
+       }
+}
+
+static void phy_v1_banks_init(struct mt65xx_u3phy *u3phy,
+                             struct mt65xx_phy_instance *instance)
+{
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+       if (instance->type == PHY_TYPE_USB2) {
+               u2_banks->misc = NULL;
+               u2_banks->fmreg = u3phy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
+               u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
+       } else if (instance->type == PHY_TYPE_USB3) {
+               u3_banks->spllc = u3phy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
+               u3_banks->chip = NULL;
+               u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
+               u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
+       }
+}
+
+static void phy_v2_banks_init(struct mt65xx_u3phy *u3phy,
+                             struct mt65xx_phy_instance *instance)
+{
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       struct u3phy_banks *u3_banks = &instance->u3_banks;
+
+       if (instance->type == PHY_TYPE_USB2) {
+               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;
+       } else if (instance->type == PHY_TYPE_USB3) {
+               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;
        }
 }
 
@@ -515,7 +587,6 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
        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);
@@ -533,13 +604,21 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
        }
 
        instance->type = args->args[0];
-
        if (!(instance->type == PHY_TYPE_USB2 ||
              instance->type == PHY_TYPE_USB3)) {
                dev_err(dev, "unsupported device type: %d\n", instance->type);
                return ERR_PTR(-EINVAL);
        }
 
+       if (u3phy->pdata->version == MT_PHY_V1) {
+               phy_v1_banks_init(u3phy, instance);
+       } else if (u3phy->pdata->version == MT_PHY_V2) {
+               phy_v2_banks_init(u3phy, instance);
+       } else {
+               dev_err(dev, "phy version is not supported\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        return instance->phy;
 }
 
@@ -553,14 +632,22 @@ static const struct phy_ops mt65xx_u3phy_ops = {
 
 static const struct mt65xx_phy_pdata mt2701_pdata = {
        .avoid_rx_sen_degradation = false,
+       .version = MT_PHY_V1,
+};
+
+static const struct mt65xx_phy_pdata mt2712_pdata = {
+       .avoid_rx_sen_degradation = false,
+       .version = MT_PHY_V2,
 };
 
 static const struct mt65xx_phy_pdata mt8173_pdata = {
        .avoid_rx_sen_degradation = true,
+       .version = MT_PHY_V1,
 };
 
 static const struct of_device_id mt65xx_u3phy_id_table[] = {
        { .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
+       { .compatible = "mediatek,mt2712-u3phy", .data = &mt2712_pdata },
        { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
        { },
 };
@@ -596,11 +683,14 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
        u3phy->dev = dev;
        platform_set_drvdata(pdev, u3phy);
 
-       sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
-       if (IS_ERR(u3phy->sif_base)) {
-               dev_err(dev, "failed to remap sif regs\n");
-               return PTR_ERR(u3phy->sif_base);
+       if (u3phy->pdata->version == MT_PHY_V1) {
+               /* get banks shared by multiple phys */
+               sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
+               if (IS_ERR(u3phy->sif_base)) {
+                       dev_err(dev, "failed to remap sif regs\n");
+                       return PTR_ERR(u3phy->sif_base);
+               }
        }
 
        /* it's deprecated, make it optional for backward compatibility */