blob: 721a2a1c97ef43299c3e143744297764943b4b92 [file] [log] [blame]
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001/*
2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <dt-bindings/phy/phy.h>
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/io.h>
Chunfeng Yun75f072f2015-12-04 10:11:05 +080020#include <linux/iopoll.h>
Chunfeng Yundc7f1902015-09-29 11:01:36 +080021#include <linux/module.h>
22#include <linux/of_address.h>
23#include <linux/phy/phy.h>
24#include <linux/platform_device.h>
25
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080026/* version V1 sub-banks offset base address */
27/* banks shared by multiple phys */
28#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
29#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
Chunfeng Yun554a56f2017-09-21 18:31:48 +080030#define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080031/* u2 phy bank */
32#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
Ryder Lee4ab26cb2017-08-03 18:01:01 +080033/* u3/pcie/sata phy banks */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080034#define SSUSB_SIFSLV_V1_U3PHYD 0x000
35#define SSUSB_SIFSLV_V1_U3PHYA 0x200
Chunfeng Yundc7f1902015-09-29 11:01:36 +080036
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080037/* version V2 sub-banks offset base address */
38/* u2 phy banks */
39#define SSUSB_SIFSLV_V2_MISC 0x000
40#define SSUSB_SIFSLV_V2_U2FREQ 0x100
41#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +080042/* u3/pcie/sata phy banks */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080043#define SSUSB_SIFSLV_V2_SPLLC 0x000
44#define SSUSB_SIFSLV_V2_CHIP 0x100
45#define SSUSB_SIFSLV_V2_U3PHYD 0x200
46#define SSUSB_SIFSLV_V2_U3PHYA 0x400
Chunfeng Yundc7f1902015-09-29 11:01:36 +080047
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080048#define U3P_USBPHYACR0 0x000
Chunfeng Yundc7f1902015-09-29 11:01:36 +080049#define PA0_RG_U2PLL_FORCE_ON BIT(15)
Chunfeng Yunc0250fe2017-03-31 15:35:32 +080050#define PA0_RG_USB20_INTR_EN BIT(5)
Chunfeng Yundc7f1902015-09-29 11:01:36 +080051
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080052#define U3P_USBPHYACR2 0x008
Chunfeng Yundc7f1902015-09-29 11:01:36 +080053#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
54
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080055#define U3P_USBPHYACR5 0x014
Chunfeng Yun75f072f2015-12-04 10:11:05 +080056#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
Chunfeng Yundc7f1902015-09-29 11:01:36 +080057#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
58#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
59#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
60
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080061#define U3P_USBPHYACR6 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +080062#define PA6_RG_U2_BC11_SW_EN BIT(23)
63#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
Chunfeng Yun43f53b12015-12-04 10:08:56 +080064#define PA6_RG_U2_SQTH GENMASK(3, 0)
65#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
Chunfeng Yundc7f1902015-09-29 11:01:36 +080066
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080067#define U3P_U2PHYACR4 0x020
Chunfeng Yundc7f1902015-09-29 11:01:36 +080068#define P2C_RG_USB20_GPIO_CTL BIT(9)
69#define P2C_USB20_GPIO_MODE BIT(8)
70#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
71
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080072#define U3D_U2PHYDCR0 0x060
Chunfeng Yundc7f1902015-09-29 11:01:36 +080073#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
74
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080075#define U3P_U2PHYDTM0 0x068
Chunfeng Yundc7f1902015-09-29 11:01:36 +080076#define P2C_FORCE_UART_EN BIT(26)
77#define P2C_FORCE_DATAIN BIT(23)
78#define P2C_FORCE_DM_PULLDOWN BIT(21)
79#define P2C_FORCE_DP_PULLDOWN BIT(20)
80#define P2C_FORCE_XCVRSEL BIT(19)
81#define P2C_FORCE_SUSPENDM BIT(18)
82#define P2C_FORCE_TERMSEL BIT(17)
83#define P2C_RG_DATAIN GENMASK(13, 10)
84#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
85#define P2C_RG_DMPULLDOWN BIT(7)
86#define P2C_RG_DPPULLDOWN BIT(6)
87#define P2C_RG_XCVRSEL GENMASK(5, 4)
88#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
89#define P2C_RG_SUSPENDM BIT(3)
90#define P2C_RG_TERMSEL BIT(2)
91#define P2C_DTM0_PART_MASK \
92 (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
93 P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
94 P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
95 P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
96
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080097#define U3P_U2PHYDTM1 0x06C
Chunfeng Yundc7f1902015-09-29 11:01:36 +080098#define P2C_RG_UART_EN BIT(16)
99#define P2C_RG_VBUSVALID BIT(5)
100#define P2C_RG_SESSEND BIT(4)
101#define P2C_RG_AVALID BIT(2)
102
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800103#define U3P_U3_CHIP_GPIO_CTLD 0x0c
104#define P3C_REG_IP_SW_RST BIT(31)
105#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
106#define P3C_FORCE_IP_SW_RST BIT(29)
107
108#define U3P_U3_CHIP_GPIO_CTLE 0x10
109#define P3C_RG_SWRST_U3_PHYD BIT(25)
110#define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
111
112#define U3P_U3_PHYA_REG0 0x000
113#define P3A_RG_CLKDRV_OFF GENMASK(3, 2)
114#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
115
116#define U3P_U3_PHYA_REG1 0x004
117#define P3A_RG_CLKDRV_AMP GENMASK(31, 29)
118#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29)
119
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800120#define U3P_U3_PHYA_REG6 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800121#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
122#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
123
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800124#define U3P_U3_PHYA_REG9 0x024
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800125#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
126#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
127
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800128#define U3P_U3_PHYA_DA_REG0 0x100
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800129#define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16)
130#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16)
131#define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12)
132#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800133#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
134#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
135
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800136#define U3P_U3_PHYA_DA_REG4 0x108
137#define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19)
138#define P3A_RG_PLL_BC_PE2H GENMASK(7, 6)
139#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6)
140
141#define U3P_U3_PHYA_DA_REG5 0x10c
142#define P3A_RG_PLL_BR_PE2H GENMASK(29, 28)
143#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28)
144#define P3A_RG_PLL_IC_PE2H GENMASK(15, 12)
145#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12)
146
147#define U3P_U3_PHYA_DA_REG6 0x110
148#define P3A_RG_PLL_IR_PE2H GENMASK(19, 16)
149#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16)
150
151#define U3P_U3_PHYA_DA_REG7 0x114
152#define P3A_RG_PLL_BP_PE2H GENMASK(19, 16)
153#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16)
154
155#define U3P_U3_PHYA_DA_REG20 0x13c
156#define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16)
157#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16)
158
159#define U3P_U3_PHYA_DA_REG25 0x148
160#define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0)
161#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x))
162
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800163#define U3P_U3_PHYD_LFPS1 0x00c
Chunfeng Yun98cd83a2017-03-31 15:35:28 +0800164#define P3D_RG_FWAKE_TH GENMASK(21, 16)
165#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
166
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800167#define U3P_U3_PHYD_CDR1 0x05c
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800168#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
169#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
170#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
171#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
172
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800173#define U3P_U3_PHYD_RXDET1 0x128
Chunfeng Yun1969f692017-03-31 15:35:27 +0800174#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
175#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
176
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800177#define U3P_U3_PHYD_RXDET2 0x12c
Chunfeng Yun1969f692017-03-31 15:35:27 +0800178#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
179#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
180
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800181#define U3P_SPLLC_XTALCTL3 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800182#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
183#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
184
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800185#define U3P_U2FREQ_FMCR0 0x00
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800186#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
187#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
188#define P2F_RG_FREQDET_EN BIT(24)
189#define P2F_RG_CYCLECNT GENMASK(23, 0)
190#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
191
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800192#define U3P_U2FREQ_VALUE 0x0c
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800193
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800194#define U3P_U2FREQ_FMMONR1 0x10
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800195#define P2F_USB_FM_VALID BIT(0)
196#define P2F_RG_FRCK_EN BIT(8)
197
198#define U3P_REF_CLK 26 /* MHZ */
199#define U3P_SLEW_RATE_COEF 28
200#define U3P_SR_COEF_DIVISOR 1000
201#define U3P_FM_DET_CYCLE_CNT 1024
202
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800203/* SATA register setting */
204#define PHYD_CTRL_SIGNAL_MODE4 0x1c
205/* CDR Charge Pump P-path current adjustment */
206#define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20)
207#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20)
208#define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8)
209#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8)
210
211#define PHYD_DESIGN_OPTION2 0x24
212/* Symbol lock count selection */
213#define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4)
214#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4)
215
216#define PHYD_DESIGN_OPTION9 0x40
217/* COMWAK GAP width window */
218#define RG_TG_MAX_MSK GENMASK(20, 16)
219#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16)
220/* COMINIT GAP width window */
221#define RG_T2_MAX_MSK GENMASK(13, 8)
222#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8)
223/* COMWAK GAP width window */
224#define RG_TG_MIN_MSK GENMASK(7, 5)
225#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5)
226/* COMINIT GAP width window */
227#define RG_T2_MIN_MSK GENMASK(4, 0)
228#define RG_T2_MIN_VAL(x) (0x1f & (x))
229
230#define ANA_RG_CTRL_SIGNAL1 0x4c
231/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */
232#define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8)
233#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8)
234
235#define ANA_RG_CTRL_SIGNAL4 0x58
236#define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20)
237#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20)
238/* Loop filter R1 resistance adjustment for Gen1 speed */
239#define RG_CDR_BR_GEN2_MSK GENMASK(10, 8)
240#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8)
241
242#define ANA_RG_CTRL_SIGNAL6 0x60
243/* I-path capacitance adjustment for Gen1 */
244#define RG_CDR_BC_GEN1_MSK GENMASK(28, 24)
245#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24)
246#define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0)
247#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x))
248
249#define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c
250/* RX Gen1 LEQ tuning step */
251#define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8)
252#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8)
253
254#define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8
255#define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16)
256#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16)
257
258#define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc
259#define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0)
260#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x))
261
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800262enum mtk_phy_version {
263 MTK_PHY_V1 = 1,
264 MTK_PHY_V2,
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800265};
266
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800267struct mtk_phy_pdata {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800268 /* avoid RX sensitivity level degradation only for mt8173 */
269 bool avoid_rx_sen_degradation;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800270 enum mtk_phy_version version;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800271};
272
273struct u2phy_banks {
274 void __iomem *misc;
275 void __iomem *fmreg;
276 void __iomem *com;
277};
278
279struct u3phy_banks {
280 void __iomem *spllc;
281 void __iomem *chip;
282 void __iomem *phyd; /* include u3phyd_bank2 */
283 void __iomem *phya; /* include u3phya_da */
Chunfeng Yune1d76532016-04-20 08:14:02 +0800284};
285
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800286struct mtk_phy_instance {
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800287 struct phy *phy;
288 void __iomem *port_base;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800289 union {
290 struct u2phy_banks u2_banks;
291 struct u3phy_banks u3_banks;
292 };
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800293 struct clk *ref_clk; /* reference clock of anolog phy */
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800294 u32 index;
295 u8 type;
296};
297
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800298struct mtk_tphy {
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800299 struct device *dev;
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800300 void __iomem *sif_base; /* only shared sif */
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800301 /* deprecated, use @ref_clk instead in phy instance */
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800302 struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800303 const struct mtk_phy_pdata *pdata;
304 struct mtk_phy_instance **phys;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800305 int nphys;
306};
307
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800308static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
309 struct mtk_phy_instance *instance)
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800310{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800311 struct u2phy_banks *u2_banks = &instance->u2_banks;
312 void __iomem *fmreg = u2_banks->fmreg;
313 void __iomem *com = u2_banks->com;
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800314 int calibration_val;
315 int fm_out;
316 u32 tmp;
317
318 /* enable USB ring oscillator */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800319 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800320 tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800321 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800322 udelay(1);
323
324 /*enable free run clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800325 tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800326 tmp |= P2F_RG_FRCK_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800327 writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800328
329 /* set cycle count as 1024, and select u2 channel */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800330 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800331 tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
332 tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800333 if (tphy->pdata->version == MTK_PHY_V1)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800334 tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
335
336 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800337
338 /* enable frequency meter */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800339 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800340 tmp |= P2F_RG_FREQDET_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800341 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800342
343 /* ignore return value */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800344 readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
345 (tmp & P2F_USB_FM_VALID), 10, 200);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800346
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800347 fm_out = readl(fmreg + U3P_U2FREQ_VALUE);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800348
349 /* disable frequency meter */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800350 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800351 tmp &= ~P2F_RG_FREQDET_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800352 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800353
354 /*disable free run clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800355 tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800356 tmp &= ~P2F_RG_FRCK_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800357 writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800358
359 if (fm_out) {
360 /* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
361 tmp = U3P_FM_DET_CYCLE_CNT * U3P_REF_CLK * U3P_SLEW_RATE_COEF;
362 tmp /= fm_out;
363 calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR);
364 } else {
365 /* if FM detection fail, set default value */
366 calibration_val = 4;
367 }
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800368 dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d\n",
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800369 instance->index, fm_out, calibration_val);
370
371 /* set HS slew rate */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800372 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800373 tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
374 tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800375 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800376
377 /* disable USB ring oscillator */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800378 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800379 tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800380 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800381}
382
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800383static void u3_phy_instance_init(struct mtk_tphy *tphy,
384 struct mtk_phy_instance *instance)
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800385{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800386 struct u3phy_banks *u3_banks = &instance->u3_banks;
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800387 u32 tmp;
388
389 /* gating PCIe Analog XTAL clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800390 tmp = readl(u3_banks->spllc + U3P_SPLLC_XTALCTL3);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800391 tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800392 writel(tmp, u3_banks->spllc + U3P_SPLLC_XTALCTL3);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800393
394 /* gating XSQ */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800395 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800396 tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
397 tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800398 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800399
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800400 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG9);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800401 tmp &= ~P3A_RG_RX_DAC_MUX;
402 tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800403 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG9);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800404
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800405 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG6);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800406 tmp &= ~P3A_RG_TX_EIDLE_CM;
407 tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800408 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG6);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800409
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800410 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_CDR1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800411 tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
412 tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800413 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_CDR1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800414
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800415 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_LFPS1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800416 tmp &= ~P3D_RG_FWAKE_TH;
417 tmp |= P3D_RG_FWAKE_TH_VAL(0x34);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800418 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_LFPS1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800419
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800420 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800421 tmp &= ~P3D_RG_RXDET_STB2_SET;
422 tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800423 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800424
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800425 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800426 tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
427 tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800428 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800429
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800430 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800431}
432
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800433static void u2_phy_instance_init(struct mtk_tphy *tphy,
434 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800435{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800436 struct u2phy_banks *u2_banks = &instance->u2_banks;
437 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800438 u32 index = instance->index;
439 u32 tmp;
440
441 /* switch to USB function. (system register, force ip into usb mode) */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800442 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800443 tmp &= ~P2C_FORCE_UART_EN;
444 tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800445 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800446
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800447 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800448 tmp &= ~P2C_RG_UART_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800449 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800450
Chunfeng Yunc0250fe2017-03-31 15:35:32 +0800451 tmp = readl(com + U3P_USBPHYACR0);
452 tmp |= PA0_RG_USB20_INTR_EN;
453 writel(tmp, com + U3P_USBPHYACR0);
454
455 /* disable switch 100uA current to SSUSB */
456 tmp = readl(com + U3P_USBPHYACR5);
457 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
458 writel(tmp, com + U3P_USBPHYACR5);
459
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800460 if (!index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800461 tmp = readl(com + U3P_U2PHYACR4);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800462 tmp &= ~P2C_U2_GPIO_CTR_MSK;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800463 writel(tmp, com + U3P_U2PHYACR4);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800464 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800465
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800466 if (tphy->pdata->avoid_rx_sen_degradation) {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800467 if (!index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800468 tmp = readl(com + U3P_USBPHYACR2);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800469 tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800470 writel(tmp, com + U3P_USBPHYACR2);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800471
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800472 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800473 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800474 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800475 } else {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800476 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800477 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800478 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800479
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800480 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800481 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800482 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800483 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800484 }
485
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800486 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yun43f53b12015-12-04 10:08:56 +0800487 tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
488 tmp &= ~PA6_RG_U2_SQTH;
489 tmp |= PA6_RG_U2_SQTH_VAL(2);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800490 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800491
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800492 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800493}
494
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800495static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
496 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800497{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800498 struct u2phy_banks *u2_banks = &instance->u2_banks;
499 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800500 u32 index = instance->index;
501 u32 tmp;
502
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800503 /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800504 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800505 tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
506 tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800507 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800508
509 /* OTG Enable */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800510 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800511 tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800512 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800513
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800514 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800515 tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
516 tmp &= ~P2C_RG_SESSEND;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800517 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800518
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800519 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800520 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800521 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800522 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800523
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800524 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800525 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800526 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800527 }
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800528 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800529}
530
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800531static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
532 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800533{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800534 struct u2phy_banks *u2_banks = &instance->u2_banks;
535 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800536 u32 index = instance->index;
537 u32 tmp;
538
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800539 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800540 tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
541 tmp |= P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800542 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800543
544 /* OTG Disable */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800545 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800546 tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800547 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800548
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800549 /* let suspendm=0, set utmi into analog power down */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800550 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800551 tmp &= ~P2C_RG_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800552 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800553 udelay(1);
554
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800555 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800556 tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
557 tmp |= P2C_RG_SESSEND;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800558 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800559
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800560 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800561 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800562 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800563 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800564 }
565
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800566 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800567}
568
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800569static void u2_phy_instance_exit(struct mtk_tphy *tphy,
570 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800571{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800572 struct u2phy_banks *u2_banks = &instance->u2_banks;
573 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800574 u32 index = instance->index;
575 u32 tmp;
576
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800577 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800578 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800579 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800580 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800581
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800582 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800583 tmp &= ~P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800584 writel(tmp, com + U3P_U2PHYDTM0);
585 }
586}
587
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800588static void pcie_phy_instance_init(struct mtk_tphy *tphy,
589 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800590{
591 struct u3phy_banks *u3_banks = &instance->u3_banks;
592 u32 tmp;
593
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800594 if (tphy->pdata->version != MTK_PHY_V1)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800595 return;
596
597 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
598 tmp &= ~(P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H);
599 tmp |= P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2);
600 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
601
602 /* ref clk drive */
603 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG1);
604 tmp &= ~P3A_RG_CLKDRV_AMP;
605 tmp |= P3A_RG_CLKDRV_AMP_VAL(0x4);
606 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG1);
607
608 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
609 tmp &= ~P3A_RG_CLKDRV_OFF;
610 tmp |= P3A_RG_CLKDRV_OFF_VAL(0x1);
611 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0);
612
613 /* SSC delta -5000ppm */
614 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG20);
615 tmp &= ~P3A_RG_PLL_DELTA1_PE2H;
616 tmp |= P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c);
617 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG20);
618
619 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG25);
620 tmp &= ~P3A_RG_PLL_DELTA_PE2H;
621 tmp |= P3A_RG_PLL_DELTA_PE2H_VAL(0x36);
622 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG25);
623
624 /* change pll BW 0.6M */
625 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG5);
626 tmp &= ~(P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H);
627 tmp |= P3A_RG_PLL_BR_PE2H_VAL(0x1) | P3A_RG_PLL_IC_PE2H_VAL(0x1);
628 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG5);
629
630 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG4);
631 tmp &= ~(P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H);
632 tmp |= P3A_RG_PLL_BC_PE2H_VAL(0x3);
633 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG4);
634
635 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG6);
636 tmp &= ~P3A_RG_PLL_IR_PE2H;
637 tmp |= P3A_RG_PLL_IR_PE2H_VAL(0x2);
638 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG6);
639
640 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG7);
641 tmp &= ~P3A_RG_PLL_BP_PE2H;
642 tmp |= P3A_RG_PLL_BP_PE2H_VAL(0xa);
643 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG7);
644
645 /* Tx Detect Rx Timing: 10us -> 5us */
646 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
647 tmp &= ~P3D_RG_RXDET_STB2_SET;
648 tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
649 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
650
651 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
652 tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
653 tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);
654 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
655
656 /* wait for PCIe subsys register to active */
657 usleep_range(2500, 3000);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800658 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800659}
660
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800661static void pcie_phy_instance_power_on(struct mtk_tphy *tphy,
662 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800663{
664 struct u3phy_banks *bank = &instance->u3_banks;
665 u32 tmp;
666
667 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
668 tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_MCU_BUS_CK_GATE_EN |
669 P3C_REG_IP_SW_RST);
670 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
671
672 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
673 tmp &= ~(P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD);
674 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE);
675}
676
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800677static void pcie_phy_instance_power_off(struct mtk_tphy *tphy,
678 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800679
680{
681 struct u3phy_banks *bank = &instance->u3_banks;
682 u32 tmp;
683
684 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
685 tmp |= P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST;
686 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
687
688 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
689 tmp |= P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD;
690 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE);
691}
692
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800693static void sata_phy_instance_init(struct mtk_tphy *tphy,
694 struct mtk_phy_instance *instance)
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800695{
696 struct u3phy_banks *u3_banks = &instance->u3_banks;
697 void __iomem *phyd = u3_banks->phyd;
698 u32 tmp;
699
700 /* charge current adjustment */
701 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL6);
702 tmp &= ~(RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK);
703 tmp |= RG_CDR_BIRLTR_GEN1_VAL(0x6) | RG_CDR_BC_GEN1_VAL(0x1a);
704 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL6);
705
706 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL4);
707 tmp &= ~RG_CDR_BIRLTD0_GEN1_MSK;
708 tmp |= RG_CDR_BIRLTD0_GEN1_VAL(0x18);
709 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL4);
710
711 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL5);
712 tmp &= ~RG_CDR_BIRLTD0_GEN3_MSK;
713 tmp |= RG_CDR_BIRLTD0_GEN3_VAL(0x06);
714 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL5);
715
716 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL4);
717 tmp &= ~(RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK);
718 tmp |= RG_CDR_BICLTR_GEN1_VAL(0x0c) | RG_CDR_BR_GEN2_VAL(0x07);
719 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL4);
720
721 tmp = readl(phyd + PHYD_CTRL_SIGNAL_MODE4);
722 tmp &= ~(RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK);
723 tmp |= RG_CDR_BICLTD0_GEN1_VAL(0x08) | RG_CDR_BICLTD1_GEN1_VAL(0x02);
724 writel(tmp, phyd + PHYD_CTRL_SIGNAL_MODE4);
725
726 tmp = readl(phyd + PHYD_DESIGN_OPTION2);
727 tmp &= ~RG_LOCK_CNT_SEL_MSK;
728 tmp |= RG_LOCK_CNT_SEL_VAL(0x02);
729 writel(tmp, phyd + PHYD_DESIGN_OPTION2);
730
731 tmp = readl(phyd + PHYD_DESIGN_OPTION9);
732 tmp &= ~(RG_T2_MIN_MSK | RG_TG_MIN_MSK |
733 RG_T2_MAX_MSK | RG_TG_MAX_MSK);
734 tmp |= RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04) |
735 RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e);
736 writel(tmp, phyd + PHYD_DESIGN_OPTION9);
737
738 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL1);
739 tmp &= ~RG_IDRV_0DB_GEN1_MSK;
740 tmp |= RG_IDRV_0DB_GEN1_VAL(0x20);
741 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL1);
742
743 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL1);
744 tmp &= ~RG_EQ_DLEQ_LFI_GEN1_MSK;
745 tmp |= RG_EQ_DLEQ_LFI_GEN1_VAL(0x03);
746 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL1);
747
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800748 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800749}
750
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800751static void phy_v1_banks_init(struct mtk_tphy *tphy,
752 struct mtk_phy_instance *instance)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800753{
754 struct u2phy_banks *u2_banks = &instance->u2_banks;
755 struct u3phy_banks *u3_banks = &instance->u3_banks;
756
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800757 switch (instance->type) {
758 case PHY_TYPE_USB2:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800759 u2_banks->misc = NULL;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800760 u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800761 u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800762 break;
763 case PHY_TYPE_USB3:
764 case PHY_TYPE_PCIE:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800765 u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
Chunfeng Yun554a56f2017-09-21 18:31:48 +0800766 u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800767 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
768 u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800769 break;
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800770 case PHY_TYPE_SATA:
771 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
772 break;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800773 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800774 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800775 return;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800776 }
777}
778
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800779static void phy_v2_banks_init(struct mtk_tphy *tphy,
780 struct mtk_phy_instance *instance)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800781{
782 struct u2phy_banks *u2_banks = &instance->u2_banks;
783 struct u3phy_banks *u3_banks = &instance->u3_banks;
784
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800785 switch (instance->type) {
786 case PHY_TYPE_USB2:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800787 u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
788 u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
789 u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800790 break;
791 case PHY_TYPE_USB3:
792 case PHY_TYPE_PCIE:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800793 u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
794 u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
795 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
796 u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800797 break;
798 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800799 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800800 return;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800801 }
802}
803
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800804static int mtk_phy_init(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800805{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800806 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
807 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800808 int ret;
809
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800810 ret = clk_prepare_enable(tphy->u3phya_ref);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800811 if (ret) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800812 dev_err(tphy->dev, "failed to enable u3phya_ref\n");
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800813 return ret;
814 }
815
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800816 ret = clk_prepare_enable(instance->ref_clk);
817 if (ret) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800818 dev_err(tphy->dev, "failed to enable ref_clk\n");
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800819 return ret;
820 }
821
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800822 switch (instance->type) {
823 case PHY_TYPE_USB2:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800824 u2_phy_instance_init(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800825 break;
826 case PHY_TYPE_USB3:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800827 u3_phy_instance_init(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800828 break;
829 case PHY_TYPE_PCIE:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800830 pcie_phy_instance_init(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800831 break;
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800832 case PHY_TYPE_SATA:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800833 sata_phy_instance_init(tphy, instance);
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800834 break;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800835 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800836 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800837 return -EINVAL;
838 }
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800839
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800840 return 0;
841}
842
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800843static int mtk_phy_power_on(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800844{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800845 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
846 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800847
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800848 if (instance->type == PHY_TYPE_USB2) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800849 u2_phy_instance_power_on(tphy, instance);
850 hs_slew_rate_calibrate(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800851 } else if (instance->type == PHY_TYPE_PCIE) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800852 pcie_phy_instance_power_on(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800853 }
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800854
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800855 return 0;
856}
857
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800858static int mtk_phy_power_off(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800859{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800860 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
861 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800862
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800863 if (instance->type == PHY_TYPE_USB2)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800864 u2_phy_instance_power_off(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800865 else if (instance->type == PHY_TYPE_PCIE)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800866 pcie_phy_instance_power_off(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800867
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800868 return 0;
869}
870
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800871static int mtk_phy_exit(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800872{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800873 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
874 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800875
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800876 if (instance->type == PHY_TYPE_USB2)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800877 u2_phy_instance_exit(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800878
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800879 clk_disable_unprepare(instance->ref_clk);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800880 clk_disable_unprepare(tphy->u3phya_ref);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800881 return 0;
882}
883
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800884static struct phy *mtk_phy_xlate(struct device *dev,
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800885 struct of_phandle_args *args)
886{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800887 struct mtk_tphy *tphy = dev_get_drvdata(dev);
888 struct mtk_phy_instance *instance = NULL;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800889 struct device_node *phy_np = args->np;
890 int index;
891
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800892 if (args->args_count != 1) {
893 dev_err(dev, "invalid number of cells in 'phy' property\n");
894 return ERR_PTR(-EINVAL);
895 }
896
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800897 for (index = 0; index < tphy->nphys; index++)
898 if (phy_np == tphy->phys[index]->phy->dev.of_node) {
899 instance = tphy->phys[index];
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800900 break;
901 }
902
903 if (!instance) {
904 dev_err(dev, "failed to find appropriate phy\n");
905 return ERR_PTR(-EINVAL);
906 }
907
908 instance->type = args->args[0];
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800909 if (!(instance->type == PHY_TYPE_USB2 ||
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800910 instance->type == PHY_TYPE_USB3 ||
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800911 instance->type == PHY_TYPE_PCIE ||
912 instance->type == PHY_TYPE_SATA)) {
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800913 dev_err(dev, "unsupported device type: %d\n", instance->type);
914 return ERR_PTR(-EINVAL);
915 }
916
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800917 if (tphy->pdata->version == MTK_PHY_V1) {
918 phy_v1_banks_init(tphy, instance);
919 } else if (tphy->pdata->version == MTK_PHY_V2) {
920 phy_v2_banks_init(tphy, instance);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800921 } else {
922 dev_err(dev, "phy version is not supported\n");
923 return ERR_PTR(-EINVAL);
924 }
925
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800926 return instance->phy;
927}
928
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800929static const struct phy_ops mtk_tphy_ops = {
930 .init = mtk_phy_init,
931 .exit = mtk_phy_exit,
932 .power_on = mtk_phy_power_on,
933 .power_off = mtk_phy_power_off,
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800934 .owner = THIS_MODULE,
935};
936
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800937static const struct mtk_phy_pdata tphy_v1_pdata = {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800938 .avoid_rx_sen_degradation = false,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800939 .version = MTK_PHY_V1,
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800940};
941
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800942static const struct mtk_phy_pdata tphy_v2_pdata = {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800943 .avoid_rx_sen_degradation = false,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800944 .version = MTK_PHY_V2,
Chunfeng Yune1d76532016-04-20 08:14:02 +0800945};
946
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800947static const struct mtk_phy_pdata mt8173_pdata = {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800948 .avoid_rx_sen_degradation = true,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800949 .version = MTK_PHY_V1,
Chunfeng Yune1d76532016-04-20 08:14:02 +0800950};
951
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800952static const struct of_device_id mtk_tphy_id_table[] = {
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800953 { .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800954 { .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
Chunfeng Yune1d76532016-04-20 08:14:02 +0800955 { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800956 { .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata },
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800957 { .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },
Chunfeng Yune1d76532016-04-20 08:14:02 +0800958 { },
959};
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800960MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800961
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800962static int mtk_tphy_probe(struct platform_device *pdev)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800963{
Chunfeng Yune1d76532016-04-20 08:14:02 +0800964 const struct of_device_id *match;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800965 struct device *dev = &pdev->dev;
966 struct device_node *np = dev->of_node;
967 struct device_node *child_np;
968 struct phy_provider *provider;
969 struct resource *sif_res;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800970 struct mtk_tphy *tphy;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800971 struct resource res;
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100972 int port, retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800973
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800974 match = of_match_node(mtk_tphy_id_table, pdev->dev.of_node);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800975 if (!match)
976 return -EINVAL;
977
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800978 tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL);
979 if (!tphy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800980 return -ENOMEM;
981
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800982 tphy->pdata = match->data;
983 tphy->nphys = of_get_child_count(np);
984 tphy->phys = devm_kcalloc(dev, tphy->nphys,
985 sizeof(*tphy->phys), GFP_KERNEL);
986 if (!tphy->phys)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800987 return -ENOMEM;
988
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800989 tphy->dev = dev;
990 platform_set_drvdata(pdev, tphy);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800991
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800992 if (tphy->pdata->version == MTK_PHY_V1) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800993 /* get banks shared by multiple phys */
994 sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800995 tphy->sif_base = devm_ioremap_resource(dev, sif_res);
996 if (IS_ERR(tphy->sif_base)) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800997 dev_err(dev, "failed to remap sif regs\n");
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800998 return PTR_ERR(tphy->sif_base);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800999 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001000 }
1001
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001002 /* it's deprecated, make it optional for backward compatibility */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001003 tphy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
1004 if (IS_ERR(tphy->u3phya_ref)) {
1005 if (PTR_ERR(tphy->u3phya_ref) == -EPROBE_DEFER)
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001006 return -EPROBE_DEFER;
1007
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001008 tphy->u3phya_ref = NULL;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001009 }
1010
1011 port = 0;
1012 for_each_child_of_node(np, child_np) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001013 struct mtk_phy_instance *instance;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001014 struct phy *phy;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001015
1016 instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001017 if (!instance) {
1018 retval = -ENOMEM;
1019 goto put_child;
1020 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001021
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001022 tphy->phys[port] = instance;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001023
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001024 phy = devm_phy_create(dev, child_np, &mtk_tphy_ops);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001025 if (IS_ERR(phy)) {
1026 dev_err(dev, "failed to create phy\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001027 retval = PTR_ERR(phy);
1028 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001029 }
1030
1031 retval = of_address_to_resource(child_np, 0, &res);
1032 if (retval) {
1033 dev_err(dev, "failed to get address resource(id-%d)\n",
1034 port);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001035 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001036 }
1037
1038 instance->port_base = devm_ioremap_resource(&phy->dev, &res);
1039 if (IS_ERR(instance->port_base)) {
1040 dev_err(dev, "failed to remap phy regs\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001041 retval = PTR_ERR(instance->port_base);
1042 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001043 }
1044
1045 instance->phy = phy;
1046 instance->index = port;
1047 phy_set_drvdata(phy, instance);
1048 port++;
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001049
1050 /* if deprecated clock is provided, ignore instance's one */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001051 if (tphy->u3phya_ref)
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001052 continue;
1053
1054 instance->ref_clk = devm_clk_get(&phy->dev, "ref");
1055 if (IS_ERR(instance->ref_clk)) {
1056 dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
1057 retval = PTR_ERR(instance->ref_clk);
1058 goto put_child;
1059 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001060 }
1061
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001062 provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001063
1064 return PTR_ERR_OR_ZERO(provider);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001065put_child:
1066 of_node_put(child_np);
1067 return retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001068}
1069
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001070static struct platform_driver mtk_tphy_driver = {
1071 .probe = mtk_tphy_probe,
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001072 .driver = {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001073 .name = "mtk-tphy",
1074 .of_match_table = mtk_tphy_id_table,
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001075 },
1076};
1077
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001078module_platform_driver(mtk_tphy_driver);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001079
1080MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001081MODULE_DESCRIPTION("MediaTek T-PHY driver");
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001082MODULE_LICENSE("GPL v2");