blob: 5b6a470ca145738186b976bb0e10c41d4273d40a [file] [log] [blame]
Chunfeng Yun3003cfa2018-06-29 10:20:27 +08001// SPDX-License-Identifier: GPL-2.0
Chunfeng Yundc7f1902015-09-29 11:01:36 +08002/*
3 * Copyright (c) 2015 MediaTek Inc.
4 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
5 *
Chunfeng Yundc7f1902015-09-29 11:01:36 +08006 */
7
8#include <dt-bindings/phy/phy.h>
9#include <linux/clk.h>
10#include <linux/delay.h>
11#include <linux/io.h>
Chunfeng Yun75f072f2015-12-04 10:11:05 +080012#include <linux/iopoll.h>
Chunfeng Yundc7f1902015-09-29 11:01:36 +080013#include <linux/module.h>
14#include <linux/of_address.h>
Chunfeng Yune4b227c2017-12-28 16:40:36 +053015#include <linux/of_device.h>
Chunfeng Yundc7f1902015-09-29 11:01:36 +080016#include <linux/phy/phy.h>
17#include <linux/platform_device.h>
18
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080019/* version V1 sub-banks offset base address */
20/* banks shared by multiple phys */
21#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
22#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
Chunfeng Yun554a56f2017-09-21 18:31:48 +080023#define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080024/* u2 phy bank */
25#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
Ryder Lee4ab26cb2017-08-03 18:01:01 +080026/* u3/pcie/sata phy banks */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080027#define SSUSB_SIFSLV_V1_U3PHYD 0x000
28#define SSUSB_SIFSLV_V1_U3PHYA 0x200
Chunfeng Yundc7f1902015-09-29 11:01:36 +080029
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080030/* version V2 sub-banks offset base address */
31/* u2 phy banks */
32#define SSUSB_SIFSLV_V2_MISC 0x000
33#define SSUSB_SIFSLV_V2_U2FREQ 0x100
34#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +080035/* u3/pcie/sata phy banks */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080036#define SSUSB_SIFSLV_V2_SPLLC 0x000
37#define SSUSB_SIFSLV_V2_CHIP 0x100
38#define SSUSB_SIFSLV_V2_U3PHYD 0x200
39#define SSUSB_SIFSLV_V2_U3PHYA 0x400
Chunfeng Yundc7f1902015-09-29 11:01:36 +080040
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080041#define U3P_USBPHYACR0 0x000
Chunfeng Yundc7f1902015-09-29 11:01:36 +080042#define PA0_RG_U2PLL_FORCE_ON BIT(15)
Chunfeng Yunc0250fe2017-03-31 15:35:32 +080043#define PA0_RG_USB20_INTR_EN BIT(5)
Chunfeng Yundc7f1902015-09-29 11:01:36 +080044
Chunfeng Yun8158e912018-06-29 10:20:29 +080045#define U3P_USBPHYACR1 0x004
46#define PA1_RG_VRT_SEL GENMASK(14, 12)
47#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
48#define PA1_RG_TERM_SEL GENMASK(10, 8)
49#define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
50
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080051#define U3P_USBPHYACR2 0x008
Chunfeng Yundc7f1902015-09-29 11:01:36 +080052#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
53
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080054#define U3P_USBPHYACR5 0x014
Chunfeng Yun75f072f2015-12-04 10:11:05 +080055#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
Chunfeng Yundc7f1902015-09-29 11:01:36 +080056#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
57#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
58#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
59
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080060#define U3P_USBPHYACR6 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +080061#define PA6_RG_U2_BC11_SW_EN BIT(23)
62#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
Chunfeng Yun43f53b12015-12-04 10:08:56 +080063#define PA6_RG_U2_SQTH GENMASK(3, 0)
64#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
Chunfeng Yundc7f1902015-09-29 11:01:36 +080065
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080066#define U3P_U2PHYACR4 0x020
Chunfeng Yundc7f1902015-09-29 11:01:36 +080067#define P2C_RG_USB20_GPIO_CTL BIT(9)
68#define P2C_USB20_GPIO_MODE BIT(8)
69#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
70
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080071#define U3D_U2PHYDCR0 0x060
Chunfeng Yundc7f1902015-09-29 11:01:36 +080072#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
73
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080074#define U3P_U2PHYDTM0 0x068
Chunfeng Yundc7f1902015-09-29 11:01:36 +080075#define P2C_FORCE_UART_EN BIT(26)
76#define P2C_FORCE_DATAIN BIT(23)
77#define P2C_FORCE_DM_PULLDOWN BIT(21)
78#define P2C_FORCE_DP_PULLDOWN BIT(20)
79#define P2C_FORCE_XCVRSEL BIT(19)
80#define P2C_FORCE_SUSPENDM BIT(18)
81#define P2C_FORCE_TERMSEL BIT(17)
82#define P2C_RG_DATAIN GENMASK(13, 10)
83#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
84#define P2C_RG_DMPULLDOWN BIT(7)
85#define P2C_RG_DPPULLDOWN BIT(6)
86#define P2C_RG_XCVRSEL GENMASK(5, 4)
87#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
88#define P2C_RG_SUSPENDM BIT(3)
89#define P2C_RG_TERMSEL BIT(2)
90#define P2C_DTM0_PART_MASK \
91 (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
92 P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
93 P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
94 P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
95
Chunfeng Yun8d6e19572017-03-31 15:35:31 +080096#define U3P_U2PHYDTM1 0x06C
Chunfeng Yundc7f1902015-09-29 11:01:36 +080097#define P2C_RG_UART_EN BIT(16)
Chunfeng Yun5954a102017-09-21 18:31:49 +080098#define P2C_FORCE_IDDIG BIT(9)
Chunfeng Yundc7f1902015-09-29 11:01:36 +080099#define P2C_RG_VBUSVALID BIT(5)
100#define P2C_RG_SESSEND BIT(4)
101#define P2C_RG_AVALID BIT(2)
Chunfeng Yun5954a102017-09-21 18:31:49 +0800102#define P2C_RG_IDDIG BIT(1)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800103
Chunfeng Yund4f97f12018-06-29 10:20:30 +0800104#define U3P_U2PHYBC12C 0x080
105#define P2C_RG_CHGDT_EN BIT(0)
106
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800107#define U3P_U3_CHIP_GPIO_CTLD 0x0c
108#define P3C_REG_IP_SW_RST BIT(31)
109#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
110#define P3C_FORCE_IP_SW_RST BIT(29)
111
112#define U3P_U3_CHIP_GPIO_CTLE 0x10
113#define P3C_RG_SWRST_U3_PHYD BIT(25)
114#define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
115
116#define U3P_U3_PHYA_REG0 0x000
117#define P3A_RG_CLKDRV_OFF GENMASK(3, 2)
118#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
119
120#define U3P_U3_PHYA_REG1 0x004
121#define P3A_RG_CLKDRV_AMP GENMASK(31, 29)
122#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29)
123
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800124#define U3P_U3_PHYA_REG6 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800125#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
126#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
127
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800128#define U3P_U3_PHYA_REG9 0x024
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800129#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
130#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
131
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800132#define U3P_U3_PHYA_DA_REG0 0x100
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800133#define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16)
134#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16)
135#define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12)
136#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800137#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
138#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
139
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800140#define U3P_U3_PHYA_DA_REG4 0x108
141#define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19)
142#define P3A_RG_PLL_BC_PE2H GENMASK(7, 6)
143#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6)
144
145#define U3P_U3_PHYA_DA_REG5 0x10c
146#define P3A_RG_PLL_BR_PE2H GENMASK(29, 28)
147#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28)
148#define P3A_RG_PLL_IC_PE2H GENMASK(15, 12)
149#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12)
150
151#define U3P_U3_PHYA_DA_REG6 0x110
152#define P3A_RG_PLL_IR_PE2H GENMASK(19, 16)
153#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16)
154
155#define U3P_U3_PHYA_DA_REG7 0x114
156#define P3A_RG_PLL_BP_PE2H GENMASK(19, 16)
157#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16)
158
159#define U3P_U3_PHYA_DA_REG20 0x13c
160#define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16)
161#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16)
162
163#define U3P_U3_PHYA_DA_REG25 0x148
164#define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0)
165#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x))
166
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800167#define U3P_U3_PHYD_LFPS1 0x00c
Chunfeng Yun98cd83a2017-03-31 15:35:28 +0800168#define P3D_RG_FWAKE_TH GENMASK(21, 16)
169#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
170
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800171#define U3P_U3_PHYD_CDR1 0x05c
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800172#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
173#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
174#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
175#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
176
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800177#define U3P_U3_PHYD_RXDET1 0x128
Chunfeng Yun1969f692017-03-31 15:35:27 +0800178#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
179#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
180
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800181#define U3P_U3_PHYD_RXDET2 0x12c
Chunfeng Yun1969f692017-03-31 15:35:27 +0800182#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
183#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
184
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800185#define U3P_SPLLC_XTALCTL3 0x018
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800186#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
187#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
188
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800189#define U3P_U2FREQ_FMCR0 0x00
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800190#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
191#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
192#define P2F_RG_FREQDET_EN BIT(24)
193#define P2F_RG_CYCLECNT GENMASK(23, 0)
194#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
195
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800196#define U3P_U2FREQ_VALUE 0x0c
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800197
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800198#define U3P_U2FREQ_FMMONR1 0x10
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800199#define P2F_USB_FM_VALID BIT(0)
200#define P2F_RG_FRCK_EN BIT(8)
201
202#define U3P_REF_CLK 26 /* MHZ */
203#define U3P_SLEW_RATE_COEF 28
204#define U3P_SR_COEF_DIVISOR 1000
205#define U3P_FM_DET_CYCLE_CNT 1024
206
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800207/* SATA register setting */
208#define PHYD_CTRL_SIGNAL_MODE4 0x1c
209/* CDR Charge Pump P-path current adjustment */
210#define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20)
211#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20)
212#define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8)
213#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8)
214
215#define PHYD_DESIGN_OPTION2 0x24
216/* Symbol lock count selection */
217#define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4)
218#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4)
219
220#define PHYD_DESIGN_OPTION9 0x40
221/* COMWAK GAP width window */
222#define RG_TG_MAX_MSK GENMASK(20, 16)
223#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16)
224/* COMINIT GAP width window */
225#define RG_T2_MAX_MSK GENMASK(13, 8)
226#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8)
227/* COMWAK GAP width window */
228#define RG_TG_MIN_MSK GENMASK(7, 5)
229#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5)
230/* COMINIT GAP width window */
231#define RG_T2_MIN_MSK GENMASK(4, 0)
232#define RG_T2_MIN_VAL(x) (0x1f & (x))
233
234#define ANA_RG_CTRL_SIGNAL1 0x4c
235/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */
236#define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8)
237#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8)
238
239#define ANA_RG_CTRL_SIGNAL4 0x58
240#define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20)
241#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20)
242/* Loop filter R1 resistance adjustment for Gen1 speed */
243#define RG_CDR_BR_GEN2_MSK GENMASK(10, 8)
244#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8)
245
246#define ANA_RG_CTRL_SIGNAL6 0x60
247/* I-path capacitance adjustment for Gen1 */
248#define RG_CDR_BC_GEN1_MSK GENMASK(28, 24)
249#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24)
250#define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0)
251#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x))
252
253#define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c
254/* RX Gen1 LEQ tuning step */
255#define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8)
256#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8)
257
258#define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8
259#define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16)
260#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16)
261
262#define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc
263#define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0)
264#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x))
265
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800266enum mtk_phy_version {
267 MTK_PHY_V1 = 1,
268 MTK_PHY_V2,
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800269};
270
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800271struct mtk_phy_pdata {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800272 /* avoid RX sensitivity level degradation only for mt8173 */
273 bool avoid_rx_sen_degradation;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800274 enum mtk_phy_version version;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800275};
276
277struct u2phy_banks {
278 void __iomem *misc;
279 void __iomem *fmreg;
280 void __iomem *com;
281};
282
283struct u3phy_banks {
284 void __iomem *spllc;
285 void __iomem *chip;
286 void __iomem *phyd; /* include u3phyd_bank2 */
287 void __iomem *phya; /* include u3phya_da */
Chunfeng Yune1d76532016-04-20 08:14:02 +0800288};
289
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800290struct mtk_phy_instance {
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800291 struct phy *phy;
292 void __iomem *port_base;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800293 union {
294 struct u2phy_banks u2_banks;
295 struct u3phy_banks u3_banks;
296 };
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800297 struct clk *ref_clk; /* reference clock of anolog phy */
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800298 u32 index;
299 u8 type;
Chunfeng Yun8158e912018-06-29 10:20:29 +0800300 int eye_src;
301 int eye_vrt;
302 int eye_term;
Chunfeng Yund4f97f12018-06-29 10:20:30 +0800303 bool bc12_en;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800304};
305
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800306struct mtk_tphy {
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800307 struct device *dev;
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800308 void __iomem *sif_base; /* only shared sif */
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800309 /* deprecated, use @ref_clk instead in phy instance */
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800310 struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800311 const struct mtk_phy_pdata *pdata;
312 struct mtk_phy_instance **phys;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800313 int nphys;
Chunfeng Yun8833ebf42018-03-12 13:25:39 +0800314 int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
315 int src_coef; /* coefficient for slew rate calibrate */
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800316};
317
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800318static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
319 struct mtk_phy_instance *instance)
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800320{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800321 struct u2phy_banks *u2_banks = &instance->u2_banks;
322 void __iomem *fmreg = u2_banks->fmreg;
323 void __iomem *com = u2_banks->com;
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800324 int calibration_val;
325 int fm_out;
326 u32 tmp;
327
Chunfeng Yun8158e912018-06-29 10:20:29 +0800328 /* use force value */
329 if (instance->eye_src)
330 return;
331
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800332 /* enable USB ring oscillator */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800333 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800334 tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800335 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800336 udelay(1);
337
338 /*enable free run clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800339 tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800340 tmp |= P2F_RG_FRCK_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800341 writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800342
343 /* set cycle count as 1024, and select u2 channel */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800344 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800345 tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
346 tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800347 if (tphy->pdata->version == MTK_PHY_V1)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800348 tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
349
350 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800351
352 /* enable frequency meter */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800353 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800354 tmp |= P2F_RG_FREQDET_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800355 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800356
357 /* ignore return value */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800358 readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
359 (tmp & P2F_USB_FM_VALID), 10, 200);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800360
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800361 fm_out = readl(fmreg + U3P_U2FREQ_VALUE);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800362
363 /* disable frequency meter */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800364 tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800365 tmp &= ~P2F_RG_FREQDET_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800366 writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800367
368 /*disable free run clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800369 tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800370 tmp &= ~P2F_RG_FRCK_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800371 writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800372
373 if (fm_out) {
Chunfeng Yun8833ebf42018-03-12 13:25:39 +0800374 /* ( 1024 / FM_OUT ) x reference clock frequency x coef */
375 tmp = tphy->src_ref_clk * tphy->src_coef;
376 tmp = (tmp * U3P_FM_DET_CYCLE_CNT) / fm_out;
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800377 calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR);
378 } else {
379 /* if FM detection fail, set default value */
380 calibration_val = 4;
381 }
Chunfeng Yun8833ebf42018-03-12 13:25:39 +0800382 dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d (clk:%d, coef:%d)\n",
383 instance->index, fm_out, calibration_val,
384 tphy->src_ref_clk, tphy->src_coef);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800385
386 /* set HS slew rate */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800387 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800388 tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
389 tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800390 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800391
392 /* disable USB ring oscillator */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800393 tmp = readl(com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800394 tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800395 writel(tmp, com + U3P_USBPHYACR5);
Chunfeng Yun75f072f2015-12-04 10:11:05 +0800396}
397
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800398static void u3_phy_instance_init(struct mtk_tphy *tphy,
399 struct mtk_phy_instance *instance)
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800400{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800401 struct u3phy_banks *u3_banks = &instance->u3_banks;
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800402 u32 tmp;
403
404 /* gating PCIe Analog XTAL clock */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800405 tmp = readl(u3_banks->spllc + U3P_SPLLC_XTALCTL3);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800406 tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800407 writel(tmp, u3_banks->spllc + U3P_SPLLC_XTALCTL3);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800408
409 /* gating XSQ */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800410 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800411 tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
412 tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800413 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800414
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800415 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG9);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800416 tmp &= ~P3A_RG_RX_DAC_MUX;
417 tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800418 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG9);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800419
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800420 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG6);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800421 tmp &= ~P3A_RG_TX_EIDLE_CM;
422 tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800423 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG6);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800424
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800425 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_CDR1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800426 tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
427 tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800428 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_CDR1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800429
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800430 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_LFPS1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800431 tmp &= ~P3D_RG_FWAKE_TH;
432 tmp |= P3D_RG_FWAKE_TH_VAL(0x34);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800433 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_LFPS1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800434
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800435 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800436 tmp &= ~P3D_RG_RXDET_STB2_SET;
437 tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800438 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800439
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800440 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800441 tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
442 tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800443 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800444
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800445 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800446}
447
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800448static void u2_phy_instance_init(struct mtk_tphy *tphy,
449 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800450{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800451 struct u2phy_banks *u2_banks = &instance->u2_banks;
452 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800453 u32 index = instance->index;
454 u32 tmp;
455
Chunfeng Yun00c00922017-12-07 19:53:34 +0800456 /* switch to USB function, and enable usb pll */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800457 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yun00c00922017-12-07 19:53:34 +0800458 tmp &= ~(P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800459 tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800460 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800461
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800462 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800463 tmp &= ~P2C_RG_UART_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800464 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800465
Chunfeng Yunc0250fe2017-03-31 15:35:32 +0800466 tmp = readl(com + U3P_USBPHYACR0);
467 tmp |= PA0_RG_USB20_INTR_EN;
468 writel(tmp, com + U3P_USBPHYACR0);
469
470 /* disable switch 100uA current to SSUSB */
471 tmp = readl(com + U3P_USBPHYACR5);
472 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
473 writel(tmp, com + U3P_USBPHYACR5);
474
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800475 if (!index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800476 tmp = readl(com + U3P_U2PHYACR4);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800477 tmp &= ~P2C_U2_GPIO_CTR_MSK;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800478 writel(tmp, com + U3P_U2PHYACR4);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800479 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800480
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800481 if (tphy->pdata->avoid_rx_sen_degradation) {
Chunfeng Yune1d76532016-04-20 08:14:02 +0800482 if (!index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800483 tmp = readl(com + U3P_USBPHYACR2);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800484 tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800485 writel(tmp, com + U3P_USBPHYACR2);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800486
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800487 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800488 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800489 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800490 } else {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800491 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800492 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800493 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800494
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800495 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800496 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800497 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yune1d76532016-04-20 08:14:02 +0800498 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800499 }
500
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800501 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yun43f53b12015-12-04 10:08:56 +0800502 tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
503 tmp &= ~PA6_RG_U2_SQTH;
504 tmp |= PA6_RG_U2_SQTH_VAL(2);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800505 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800506
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800507 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800508}
509
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800510static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
511 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800512{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800513 struct u2phy_banks *u2_banks = &instance->u2_banks;
514 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800515 u32 index = instance->index;
516 u32 tmp;
517
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800518 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yun00c00922017-12-07 19:53:34 +0800519 tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800520 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800521
522 /* OTG Enable */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800523 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800524 tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800525 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800526
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800527 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800528 tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
529 tmp &= ~P2C_RG_SESSEND;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800530 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800531
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800532 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800533 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800534 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800535 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800536
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800537 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800538 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800539 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800540 }
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800541 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800542}
543
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800544static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
545 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800546{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800547 struct u2phy_banks *u2_banks = &instance->u2_banks;
548 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800549 u32 index = instance->index;
550 u32 tmp;
551
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800552 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800553 tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800554 writel(tmp, com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800555
556 /* OTG Disable */
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800557 tmp = readl(com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800558 tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800559 writel(tmp, com + U3P_USBPHYACR6);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800560
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800561 tmp = readl(com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800562 tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
563 tmp |= P2C_RG_SESSEND;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800564 writel(tmp, com + U3P_U2PHYDTM1);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800565
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800566 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun00c00922017-12-07 19:53:34 +0800567 tmp = readl(com + U3P_U2PHYDTM0);
568 tmp &= ~(P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM);
569 writel(tmp, com + U3P_U2PHYDTM0);
570
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800571 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800572 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800573 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800574 }
575
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800576 dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800577}
578
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800579static void u2_phy_instance_exit(struct mtk_tphy *tphy,
580 struct mtk_phy_instance *instance)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800581{
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800582 struct u2phy_banks *u2_banks = &instance->u2_banks;
583 void __iomem *com = u2_banks->com;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800584 u32 index = instance->index;
585 u32 tmp;
586
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800587 if (tphy->pdata->avoid_rx_sen_degradation && index) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800588 tmp = readl(com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800589 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800590 writel(tmp, com + U3D_U2PHYDCR0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800591
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800592 tmp = readl(com + U3P_U2PHYDTM0);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800593 tmp &= ~P2C_FORCE_SUSPENDM;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800594 writel(tmp, com + U3P_U2PHYDTM0);
595 }
596}
597
Chunfeng Yun5954a102017-09-21 18:31:49 +0800598static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
599 struct mtk_phy_instance *instance,
600 enum phy_mode mode)
601{
602 struct u2phy_banks *u2_banks = &instance->u2_banks;
603 u32 tmp;
604
605 tmp = readl(u2_banks->com + U3P_U2PHYDTM1);
606 switch (mode) {
607 case PHY_MODE_USB_DEVICE:
608 tmp |= P2C_FORCE_IDDIG | P2C_RG_IDDIG;
609 break;
610 case PHY_MODE_USB_HOST:
611 tmp |= P2C_FORCE_IDDIG;
612 tmp &= ~P2C_RG_IDDIG;
613 break;
614 case PHY_MODE_USB_OTG:
615 tmp &= ~(P2C_FORCE_IDDIG | P2C_RG_IDDIG);
616 break;
617 default:
618 return;
619 }
620 writel(tmp, u2_banks->com + U3P_U2PHYDTM1);
621}
622
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800623static void pcie_phy_instance_init(struct mtk_tphy *tphy,
624 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800625{
626 struct u3phy_banks *u3_banks = &instance->u3_banks;
627 u32 tmp;
628
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800629 if (tphy->pdata->version != MTK_PHY_V1)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800630 return;
631
632 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
633 tmp &= ~(P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H);
634 tmp |= P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2);
635 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
636
637 /* ref clk drive */
638 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG1);
639 tmp &= ~P3A_RG_CLKDRV_AMP;
640 tmp |= P3A_RG_CLKDRV_AMP_VAL(0x4);
641 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG1);
642
643 tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
644 tmp &= ~P3A_RG_CLKDRV_OFF;
645 tmp |= P3A_RG_CLKDRV_OFF_VAL(0x1);
646 writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0);
647
648 /* SSC delta -5000ppm */
649 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG20);
650 tmp &= ~P3A_RG_PLL_DELTA1_PE2H;
651 tmp |= P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c);
652 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG20);
653
654 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG25);
655 tmp &= ~P3A_RG_PLL_DELTA_PE2H;
656 tmp |= P3A_RG_PLL_DELTA_PE2H_VAL(0x36);
657 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG25);
658
659 /* change pll BW 0.6M */
660 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG5);
661 tmp &= ~(P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H);
662 tmp |= P3A_RG_PLL_BR_PE2H_VAL(0x1) | P3A_RG_PLL_IC_PE2H_VAL(0x1);
663 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG5);
664
665 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG4);
666 tmp &= ~(P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H);
667 tmp |= P3A_RG_PLL_BC_PE2H_VAL(0x3);
668 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG4);
669
670 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG6);
671 tmp &= ~P3A_RG_PLL_IR_PE2H;
672 tmp |= P3A_RG_PLL_IR_PE2H_VAL(0x2);
673 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG6);
674
675 tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG7);
676 tmp &= ~P3A_RG_PLL_BP_PE2H;
677 tmp |= P3A_RG_PLL_BP_PE2H_VAL(0xa);
678 writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG7);
679
680 /* Tx Detect Rx Timing: 10us -> 5us */
681 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
682 tmp &= ~P3D_RG_RXDET_STB2_SET;
683 tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
684 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
685
686 tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
687 tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
688 tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);
689 writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
690
691 /* wait for PCIe subsys register to active */
692 usleep_range(2500, 3000);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800693 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800694}
695
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800696static void pcie_phy_instance_power_on(struct mtk_tphy *tphy,
697 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800698{
699 struct u3phy_banks *bank = &instance->u3_banks;
700 u32 tmp;
701
702 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
Chunfeng Yun40363252018-03-12 13:25:38 +0800703 tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800704 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
705
706 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
707 tmp &= ~(P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD);
708 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE);
709}
710
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800711static void pcie_phy_instance_power_off(struct mtk_tphy *tphy,
712 struct mtk_phy_instance *instance)
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800713
714{
715 struct u3phy_banks *bank = &instance->u3_banks;
716 u32 tmp;
717
718 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
719 tmp |= P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST;
720 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
721
722 tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
723 tmp |= P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD;
724 writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE);
725}
726
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800727static void sata_phy_instance_init(struct mtk_tphy *tphy,
728 struct mtk_phy_instance *instance)
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800729{
730 struct u3phy_banks *u3_banks = &instance->u3_banks;
731 void __iomem *phyd = u3_banks->phyd;
732 u32 tmp;
733
734 /* charge current adjustment */
735 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL6);
736 tmp &= ~(RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK);
737 tmp |= RG_CDR_BIRLTR_GEN1_VAL(0x6) | RG_CDR_BC_GEN1_VAL(0x1a);
738 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL6);
739
740 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL4);
741 tmp &= ~RG_CDR_BIRLTD0_GEN1_MSK;
742 tmp |= RG_CDR_BIRLTD0_GEN1_VAL(0x18);
743 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL4);
744
745 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL5);
746 tmp &= ~RG_CDR_BIRLTD0_GEN3_MSK;
747 tmp |= RG_CDR_BIRLTD0_GEN3_VAL(0x06);
748 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL5);
749
750 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL4);
751 tmp &= ~(RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK);
752 tmp |= RG_CDR_BICLTR_GEN1_VAL(0x0c) | RG_CDR_BR_GEN2_VAL(0x07);
753 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL4);
754
755 tmp = readl(phyd + PHYD_CTRL_SIGNAL_MODE4);
756 tmp &= ~(RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK);
757 tmp |= RG_CDR_BICLTD0_GEN1_VAL(0x08) | RG_CDR_BICLTD1_GEN1_VAL(0x02);
758 writel(tmp, phyd + PHYD_CTRL_SIGNAL_MODE4);
759
760 tmp = readl(phyd + PHYD_DESIGN_OPTION2);
761 tmp &= ~RG_LOCK_CNT_SEL_MSK;
762 tmp |= RG_LOCK_CNT_SEL_VAL(0x02);
763 writel(tmp, phyd + PHYD_DESIGN_OPTION2);
764
765 tmp = readl(phyd + PHYD_DESIGN_OPTION9);
766 tmp &= ~(RG_T2_MIN_MSK | RG_TG_MIN_MSK |
767 RG_T2_MAX_MSK | RG_TG_MAX_MSK);
768 tmp |= RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04) |
769 RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e);
770 writel(tmp, phyd + PHYD_DESIGN_OPTION9);
771
772 tmp = readl(phyd + ANA_RG_CTRL_SIGNAL1);
773 tmp &= ~RG_IDRV_0DB_GEN1_MSK;
774 tmp |= RG_IDRV_0DB_GEN1_VAL(0x20);
775 writel(tmp, phyd + ANA_RG_CTRL_SIGNAL1);
776
777 tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL1);
778 tmp &= ~RG_EQ_DLEQ_LFI_GEN1_MSK;
779 tmp |= RG_EQ_DLEQ_LFI_GEN1_VAL(0x03);
780 writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL1);
781
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800782 dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800783}
784
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800785static void phy_v1_banks_init(struct mtk_tphy *tphy,
786 struct mtk_phy_instance *instance)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800787{
788 struct u2phy_banks *u2_banks = &instance->u2_banks;
789 struct u3phy_banks *u3_banks = &instance->u3_banks;
790
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800791 switch (instance->type) {
792 case PHY_TYPE_USB2:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800793 u2_banks->misc = NULL;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800794 u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800795 u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800796 break;
797 case PHY_TYPE_USB3:
798 case PHY_TYPE_PCIE:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800799 u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
Chunfeng Yun554a56f2017-09-21 18:31:48 +0800800 u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800801 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
802 u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800803 break;
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800804 case PHY_TYPE_SATA:
805 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
806 break;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800807 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800808 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800809 return;
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800810 }
811}
812
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800813static void phy_v2_banks_init(struct mtk_tphy *tphy,
814 struct mtk_phy_instance *instance)
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800815{
816 struct u2phy_banks *u2_banks = &instance->u2_banks;
817 struct u3phy_banks *u3_banks = &instance->u3_banks;
818
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800819 switch (instance->type) {
820 case PHY_TYPE_USB2:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800821 u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
822 u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
823 u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800824 break;
825 case PHY_TYPE_USB3:
826 case PHY_TYPE_PCIE:
Chunfeng Yun8d6e19572017-03-31 15:35:31 +0800827 u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
828 u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
829 u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
830 u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800831 break;
832 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800833 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800834 return;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800835 }
836}
837
Chunfeng Yun8158e912018-06-29 10:20:29 +0800838static void phy_parse_property(struct mtk_tphy *tphy,
839 struct mtk_phy_instance *instance)
840{
841 struct device *dev = &instance->phy->dev;
842
843 if (instance->type != PHY_TYPE_USB2)
844 return;
845
Chunfeng Yund4f97f12018-06-29 10:20:30 +0800846 instance->bc12_en = device_property_read_bool(dev, "mediatek,bc12");
Chunfeng Yun8158e912018-06-29 10:20:29 +0800847 device_property_read_u32(dev, "mediatek,eye-src",
848 &instance->eye_src);
849 device_property_read_u32(dev, "mediatek,eye-vrt",
850 &instance->eye_vrt);
851 device_property_read_u32(dev, "mediatek,eye-term",
852 &instance->eye_term);
Chunfeng Yund4f97f12018-06-29 10:20:30 +0800853 dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d\n",
854 instance->bc12_en, instance->eye_src,
855 instance->eye_vrt, instance->eye_term);
Chunfeng Yun8158e912018-06-29 10:20:29 +0800856}
857
858static void u2_phy_props_set(struct mtk_tphy *tphy,
859 struct mtk_phy_instance *instance)
860{
861 struct u2phy_banks *u2_banks = &instance->u2_banks;
862 void __iomem *com = u2_banks->com;
863 u32 tmp;
864
Chunfeng Yund4f97f12018-06-29 10:20:30 +0800865 if (instance->bc12_en) {
866 tmp = readl(com + U3P_U2PHYBC12C);
867 tmp |= P2C_RG_CHGDT_EN; /* BC1.2 path Enable */
868 writel(tmp, com + U3P_U2PHYBC12C);
869 }
Chunfeng Yun8158e912018-06-29 10:20:29 +0800870
871 if (instance->eye_src) {
872 tmp = readl(com + U3P_USBPHYACR5);
873 tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
874 tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src);
875 writel(tmp, com + U3P_USBPHYACR5);
876 }
877
878 if (instance->eye_vrt) {
879 tmp = readl(com + U3P_USBPHYACR1);
880 tmp &= ~PA1_RG_VRT_SEL;
881 tmp |= PA1_RG_VRT_SEL_VAL(instance->eye_vrt);
882 writel(tmp, com + U3P_USBPHYACR1);
883 }
884
885 if (instance->eye_term) {
886 tmp = readl(com + U3P_USBPHYACR1);
887 tmp &= ~PA1_RG_TERM_SEL;
888 tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
889 writel(tmp, com + U3P_USBPHYACR1);
890 }
891}
892
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800893static int mtk_phy_init(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800894{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800895 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
896 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800897 int ret;
898
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800899 ret = clk_prepare_enable(tphy->u3phya_ref);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800900 if (ret) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800901 dev_err(tphy->dev, "failed to enable u3phya_ref\n");
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800902 return ret;
903 }
904
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800905 ret = clk_prepare_enable(instance->ref_clk);
906 if (ret) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800907 dev_err(tphy->dev, "failed to enable ref_clk\n");
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800908 return ret;
909 }
910
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800911 switch (instance->type) {
912 case PHY_TYPE_USB2:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800913 u2_phy_instance_init(tphy, instance);
Chunfeng Yun8158e912018-06-29 10:20:29 +0800914 u2_phy_props_set(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800915 break;
916 case PHY_TYPE_USB3:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800917 u3_phy_instance_init(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800918 break;
919 case PHY_TYPE_PCIE:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800920 pcie_phy_instance_init(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800921 break;
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800922 case PHY_TYPE_SATA:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800923 sata_phy_instance_init(tphy, instance);
Ryder Lee4ab26cb2017-08-03 18:01:01 +0800924 break;
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800925 default:
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800926 dev_err(tphy->dev, "incompatible PHY type\n");
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800927 return -EINVAL;
928 }
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800929
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800930 return 0;
931}
932
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800933static int mtk_phy_power_on(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800934{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800935 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
936 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800937
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800938 if (instance->type == PHY_TYPE_USB2) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800939 u2_phy_instance_power_on(tphy, instance);
940 hs_slew_rate_calibrate(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800941 } else if (instance->type == PHY_TYPE_PCIE) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800942 pcie_phy_instance_power_on(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800943 }
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800944
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800945 return 0;
946}
947
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800948static int mtk_phy_power_off(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800949{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800950 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
951 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800952
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800953 if (instance->type == PHY_TYPE_USB2)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800954 u2_phy_instance_power_off(tphy, instance);
Ryder Lee44a6d6c2017-08-03 18:01:00 +0800955 else if (instance->type == PHY_TYPE_PCIE)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800956 pcie_phy_instance_power_off(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800957
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800958 return 0;
959}
960
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800961static int mtk_phy_exit(struct phy *phy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800962{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800963 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
964 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800965
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800966 if (instance->type == PHY_TYPE_USB2)
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800967 u2_phy_instance_exit(tphy, instance);
Chunfeng Yun04466ef2017-03-31 15:35:29 +0800968
Chunfeng Yun15de15c2017-03-31 15:35:30 +0800969 clk_disable_unprepare(instance->ref_clk);
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800970 clk_disable_unprepare(tphy->u3phya_ref);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800971 return 0;
972}
973
Grygorii Strashko79a5a182018-11-19 19:24:20 -0600974static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
Chunfeng Yun5954a102017-09-21 18:31:49 +0800975{
976 struct mtk_phy_instance *instance = phy_get_drvdata(phy);
977 struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
978
979 if (instance->type == PHY_TYPE_USB2)
980 u2_phy_instance_set_mode(tphy, instance, mode);
981
982 return 0;
983}
984
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800985static struct phy *mtk_phy_xlate(struct device *dev,
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800986 struct of_phandle_args *args)
987{
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800988 struct mtk_tphy *tphy = dev_get_drvdata(dev);
989 struct mtk_phy_instance *instance = NULL;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800990 struct device_node *phy_np = args->np;
991 int index;
992
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800993 if (args->args_count != 1) {
994 dev_err(dev, "invalid number of cells in 'phy' property\n");
995 return ERR_PTR(-EINVAL);
996 }
997
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +0800998 for (index = 0; index < tphy->nphys; index++)
999 if (phy_np == tphy->phys[index]->phy->dev.of_node) {
1000 instance = tphy->phys[index];
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001001 break;
1002 }
1003
1004 if (!instance) {
1005 dev_err(dev, "failed to find appropriate phy\n");
1006 return ERR_PTR(-EINVAL);
1007 }
1008
1009 instance->type = args->args[0];
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001010 if (!(instance->type == PHY_TYPE_USB2 ||
Ryder Lee44a6d6c2017-08-03 18:01:00 +08001011 instance->type == PHY_TYPE_USB3 ||
Ryder Lee4ab26cb2017-08-03 18:01:01 +08001012 instance->type == PHY_TYPE_PCIE ||
1013 instance->type == PHY_TYPE_SATA)) {
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001014 dev_err(dev, "unsupported device type: %d\n", instance->type);
1015 return ERR_PTR(-EINVAL);
1016 }
1017
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001018 if (tphy->pdata->version == MTK_PHY_V1) {
1019 phy_v1_banks_init(tphy, instance);
1020 } else if (tphy->pdata->version == MTK_PHY_V2) {
1021 phy_v2_banks_init(tphy, instance);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001022 } else {
1023 dev_err(dev, "phy version is not supported\n");
1024 return ERR_PTR(-EINVAL);
1025 }
1026
Chunfeng Yun8158e912018-06-29 10:20:29 +08001027 phy_parse_property(tphy, instance);
1028
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001029 return instance->phy;
1030}
1031
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001032static const struct phy_ops mtk_tphy_ops = {
1033 .init = mtk_phy_init,
1034 .exit = mtk_phy_exit,
1035 .power_on = mtk_phy_power_on,
1036 .power_off = mtk_phy_power_off,
Chunfeng Yun5954a102017-09-21 18:31:49 +08001037 .set_mode = mtk_phy_set_mode,
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001038 .owner = THIS_MODULE,
1039};
1040
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001041static const struct mtk_phy_pdata tphy_v1_pdata = {
Chunfeng Yune1d76532016-04-20 08:14:02 +08001042 .avoid_rx_sen_degradation = false,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001043 .version = MTK_PHY_V1,
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001044};
1045
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001046static const struct mtk_phy_pdata tphy_v2_pdata = {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001047 .avoid_rx_sen_degradation = false,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001048 .version = MTK_PHY_V2,
Chunfeng Yune1d76532016-04-20 08:14:02 +08001049};
1050
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001051static const struct mtk_phy_pdata mt8173_pdata = {
Chunfeng Yune1d76532016-04-20 08:14:02 +08001052 .avoid_rx_sen_degradation = true,
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001053 .version = MTK_PHY_V1,
Chunfeng Yune1d76532016-04-20 08:14:02 +08001054};
1055
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001056static const struct of_device_id mtk_tphy_id_table[] = {
Ryder Lee44a6d6c2017-08-03 18:01:00 +08001057 { .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
Ryder Lee4ab26cb2017-08-03 18:01:01 +08001058 { .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
Chunfeng Yune1d76532016-04-20 08:14:02 +08001059 { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
Ryder Lee44a6d6c2017-08-03 18:01:00 +08001060 { .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata },
Ryder Lee4ab26cb2017-08-03 18:01:01 +08001061 { .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },
Chunfeng Yune1d76532016-04-20 08:14:02 +08001062 { },
1063};
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001064MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
Chunfeng Yune1d76532016-04-20 08:14:02 +08001065
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001066static int mtk_tphy_probe(struct platform_device *pdev)
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001067{
1068 struct device *dev = &pdev->dev;
1069 struct device_node *np = dev->of_node;
1070 struct device_node *child_np;
1071 struct phy_provider *provider;
1072 struct resource *sif_res;
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001073 struct mtk_tphy *tphy;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001074 struct resource res;
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001075 int port, retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001076
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001077 tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL);
1078 if (!tphy)
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001079 return -ENOMEM;
1080
Chunfeng Yune4b227c2017-12-28 16:40:36 +05301081 tphy->pdata = of_device_get_match_data(dev);
1082 if (!tphy->pdata)
1083 return -EINVAL;
1084
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001085 tphy->nphys = of_get_child_count(np);
1086 tphy->phys = devm_kcalloc(dev, tphy->nphys,
1087 sizeof(*tphy->phys), GFP_KERNEL);
1088 if (!tphy->phys)
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001089 return -ENOMEM;
1090
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001091 tphy->dev = dev;
1092 platform_set_drvdata(pdev, tphy);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001093
Chunfeng Yun93a04f42017-12-07 19:53:35 +08001094 sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1095 /* SATA phy of V1 needn't it if not shared with PCIe or USB */
1096 if (sif_res && tphy->pdata->version == MTK_PHY_V1) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001097 /* get banks shared by multiple phys */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001098 tphy->sif_base = devm_ioremap_resource(dev, sif_res);
1099 if (IS_ERR(tphy->sif_base)) {
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001100 dev_err(dev, "failed to remap sif regs\n");
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001101 return PTR_ERR(tphy->sif_base);
Chunfeng Yun8d6e19572017-03-31 15:35:31 +08001102 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001103 }
1104
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001105 /* it's deprecated, make it optional for backward compatibility */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001106 tphy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
1107 if (IS_ERR(tphy->u3phya_ref)) {
1108 if (PTR_ERR(tphy->u3phya_ref) == -EPROBE_DEFER)
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001109 return -EPROBE_DEFER;
1110
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001111 tphy->u3phya_ref = NULL;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001112 }
1113
Chunfeng Yun8833ebf42018-03-12 13:25:39 +08001114 tphy->src_ref_clk = U3P_REF_CLK;
1115 tphy->src_coef = U3P_SLEW_RATE_COEF;
1116 /* update parameters of slew rate calibrate if exist */
1117 device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
1118 &tphy->src_ref_clk);
1119 device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef);
1120
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001121 port = 0;
1122 for_each_child_of_node(np, child_np) {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001123 struct mtk_phy_instance *instance;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001124 struct phy *phy;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001125
1126 instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001127 if (!instance) {
1128 retval = -ENOMEM;
1129 goto put_child;
1130 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001131
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001132 tphy->phys[port] = instance;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001133
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001134 phy = devm_phy_create(dev, child_np, &mtk_tphy_ops);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001135 if (IS_ERR(phy)) {
1136 dev_err(dev, "failed to create phy\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001137 retval = PTR_ERR(phy);
1138 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001139 }
1140
1141 retval = of_address_to_resource(child_np, 0, &res);
1142 if (retval) {
1143 dev_err(dev, "failed to get address resource(id-%d)\n",
1144 port);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001145 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001146 }
1147
1148 instance->port_base = devm_ioremap_resource(&phy->dev, &res);
1149 if (IS_ERR(instance->port_base)) {
1150 dev_err(dev, "failed to remap phy regs\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001151 retval = PTR_ERR(instance->port_base);
1152 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001153 }
1154
1155 instance->phy = phy;
1156 instance->index = port;
1157 phy_set_drvdata(phy, instance);
1158 port++;
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001159
1160 /* if deprecated clock is provided, ignore instance's one */
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001161 if (tphy->u3phya_ref)
Chunfeng Yun15de15c2017-03-31 15:35:30 +08001162 continue;
1163
1164 instance->ref_clk = devm_clk_get(&phy->dev, "ref");
1165 if (IS_ERR(instance->ref_clk)) {
1166 dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
1167 retval = PTR_ERR(instance->ref_clk);
1168 goto put_child;
1169 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001170 }
1171
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001172 provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001173
1174 return PTR_ERR_OR_ZERO(provider);
Julia Lawall2bb80cc2015-11-16 12:33:15 +01001175put_child:
1176 of_node_put(child_np);
1177 return retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001178}
1179
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001180static struct platform_driver mtk_tphy_driver = {
1181 .probe = mtk_tphy_probe,
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001182 .driver = {
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001183 .name = "mtk-tphy",
1184 .of_match_table = mtk_tphy_id_table,
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001185 },
1186};
1187
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001188module_platform_driver(mtk_tphy_driver);
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001189
1190MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
Chunfeng Yuncd4ec4b2017-08-03 18:01:02 +08001191MODULE_DESCRIPTION("MediaTek T-PHY driver");
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001192MODULE_LICENSE("GPL v2");