1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2023, Linaro Limited |
4 | */ |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/ethtool.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of.h> |
10 | #include <linux/phy/phy.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/regmap.h> |
13 | |
14 | #include "phy-qcom-qmp-pcs-sgmii.h" |
15 | #include "phy-qcom-qmp-qserdes-com-v5.h" |
16 | #include "phy-qcom-qmp-qserdes-txrx-v5.h" |
17 | |
18 | #define QSERDES_QMP_PLL 0x0 |
19 | #define QSERDES_RX 0x600 |
20 | #define QSERDES_TX 0x400 |
21 | #define QSERDES_PCS 0xc00 |
22 | |
23 | #define QSERDES_COM_C_READY BIT(0) |
24 | #define QSERDES_PCS_READY BIT(0) |
25 | #define QSERDES_PCS_SGMIIPHY_READY BIT(7) |
26 | #define QSERDES_COM_C_PLL_LOCKED BIT(1) |
27 | |
28 | struct qcom_dwmac_sgmii_phy_data { |
29 | struct regmap *regmap; |
30 | struct clk *refclk; |
31 | int speed; |
32 | }; |
33 | |
34 | static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap) |
35 | { |
36 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x01); |
37 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, val: 0x01); |
38 | |
39 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, val: 0x0F); |
40 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, val: 0x06); |
41 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, val: 0x16); |
42 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, val: 0x36); |
43 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, val: 0x1A); |
44 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, val: 0x0A); |
45 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, val: 0x1A); |
46 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, val: 0x82); |
47 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, val: 0x55); |
48 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, val: 0x55); |
49 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, val: 0x03); |
50 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, val: 0x24); |
51 | |
52 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, val: 0x02); |
53 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, val: 0x00); |
54 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, val: 0x04); |
55 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, val: 0x00); |
56 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, val: 0x0A); |
57 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, val: 0x00); |
58 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, val: 0xB9); |
59 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, val: 0x1E); |
60 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, val: 0x11); |
61 | |
62 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, val: 0x05); |
63 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, val: 0x0A); |
64 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, val: 0x09); |
65 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, val: 0x09); |
66 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, val: 0x05); |
67 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, val: 0x00); |
68 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, val: 0x12); |
69 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, val: 0x0C); |
70 | |
71 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, val: 0x0A); |
72 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, val: 0x06); |
73 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, val: 0x0A); |
74 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, val: 0x7F); |
75 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, val: 0x00); |
76 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, val: 0x01); |
77 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, val: 0x81); |
78 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, val: 0x80); |
79 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, val: 0x04); |
80 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, val: 0x08); |
81 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, val: 0x0F); |
82 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, val: 0x04); |
83 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, val: 0x00); |
84 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, val: 0x4A); |
85 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, val: 0x0A); |
86 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, val: 0x80); |
87 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, val: 0x01); |
88 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, val: 0x20); |
89 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, val: 0x17); |
90 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, val: 0x00); |
91 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, val: 0x0F); |
92 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, val: 0x1E); |
93 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, val: 0x05); |
94 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, val: 0xE0); |
95 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, val: 0xC8); |
96 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, val: 0xC8); |
97 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, val: 0x09); |
98 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, val: 0xB1); |
99 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, val: 0xE0); |
100 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, val: 0xC8); |
101 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, val: 0xC8); |
102 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, val: 0x09); |
103 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, val: 0xB1); |
104 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, val: 0xE0); |
105 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, val: 0xC8); |
106 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, val: 0xC8); |
107 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, val: 0x3B); |
108 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, val: 0xB7); |
109 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, val: 0x0C); |
110 | |
111 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, val: 0x0C); |
112 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, val: 0x1F); |
113 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, val: 0x03); |
114 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, val: 0x83); |
115 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, val: 0x08); |
116 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, val: 0x0C); |
117 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x00); |
118 | |
119 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_PHY_START, val: 0x01); |
120 | } |
121 | |
122 | static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap) |
123 | { |
124 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x01); |
125 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, val: 0x01); |
126 | |
127 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, val: 0x0F); |
128 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, val: 0x06); |
129 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, val: 0x16); |
130 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, val: 0x36); |
131 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, val: 0x1A); |
132 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, val: 0x1A); |
133 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, val: 0x41); |
134 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, val: 0x7A); |
135 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, val: 0x00); |
136 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, val: 0x20); |
137 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, val: 0x01); |
138 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, val: 0xA1); |
139 | |
140 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, val: 0x02); |
141 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, val: 0x00); |
142 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, val: 0x03); |
143 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, val: 0x00); |
144 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, val: 0x05); |
145 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, val: 0x00); |
146 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, val: 0xCD); |
147 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, val: 0x1C); |
148 | regmap_write(map: regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, val: 0x11); |
149 | |
150 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, val: 0x04); |
151 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, val: 0x0A); |
152 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, val: 0x09); |
153 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, val: 0x02); |
154 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, val: 0x05); |
155 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, val: 0x00); |
156 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, val: 0x12); |
157 | regmap_write(map: regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, val: 0x0C); |
158 | |
159 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, val: 0x0A); |
160 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, val: 0x06); |
161 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, val: 0x0A); |
162 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, val: 0x7F); |
163 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, val: 0x00); |
164 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, val: 0x01); |
165 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, val: 0x81); |
166 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, val: 0x80); |
167 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, val: 0x00); |
168 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, val: 0x08); |
169 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, val: 0x0F); |
170 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, val: 0x04); |
171 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, val: 0x00); |
172 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, val: 0x4A); |
173 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, val: 0x0A); |
174 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, val: 0x80); |
175 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, val: 0x01); |
176 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, val: 0x20); |
177 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, val: 0x17); |
178 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, val: 0x00); |
179 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, val: 0x0F); |
180 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, val: 0x1E); |
181 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, val: 0x18); |
182 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, val: 0x18); |
183 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, val: 0xC8); |
184 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, val: 0xC8); |
185 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, val: 0x0C); |
186 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, val: 0xB8); |
187 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, val: 0xE0); |
188 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, val: 0xC8); |
189 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, val: 0xC8); |
190 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, val: 0x09); |
191 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, val: 0xB1); |
192 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, val: 0xE0); |
193 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, val: 0xC8); |
194 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, val: 0xC8); |
195 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, val: 0x3B); |
196 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, val: 0xB7); |
197 | regmap_write(map: regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, val: 0x0C); |
198 | |
199 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, val: 0x0C); |
200 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, val: 0x1F); |
201 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, val: 0x03); |
202 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, val: 0x83); |
203 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, val: 0x08); |
204 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, val: 0x8C); |
205 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x00); |
206 | |
207 | regmap_write(map: regmap, QSERDES_PCS + QPHY_PCS_PHY_START, val: 0x01); |
208 | } |
209 | |
210 | static inline int |
211 | qcom_dwmac_sgmii_phy_poll_status(struct regmap *regmap, unsigned int reg, |
212 | unsigned int bit) |
213 | { |
214 | unsigned int val; |
215 | |
216 | return regmap_read_poll_timeout(regmap, reg, val, |
217 | val & bit, 1500, 750000); |
218 | } |
219 | |
220 | static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) |
221 | { |
222 | struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); |
223 | struct device *dev = phy->dev.parent; |
224 | |
225 | switch (data->speed) { |
226 | case SPEED_10: |
227 | case SPEED_100: |
228 | case SPEED_1000: |
229 | qcom_dwmac_sgmii_phy_init_1g(regmap: data->regmap); |
230 | break; |
231 | case SPEED_2500: |
232 | qcom_dwmac_sgmii_phy_init_2p5g(regmap: data->regmap); |
233 | break; |
234 | } |
235 | |
236 | if (qcom_dwmac_sgmii_phy_poll_status(regmap: data->regmap, |
237 | QSERDES_QMP_PLL + QSERDES_V5_COM_C_READY_STATUS, |
238 | QSERDES_COM_C_READY)) { |
239 | dev_err(dev, "QSERDES_COM_C_READY_STATUS timed-out" ); |
240 | return -ETIMEDOUT; |
241 | } |
242 | |
243 | if (qcom_dwmac_sgmii_phy_poll_status(regmap: data->regmap, |
244 | QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, |
245 | QSERDES_PCS_READY)) { |
246 | dev_err(dev, "PCS_READY timed-out" ); |
247 | return -ETIMEDOUT; |
248 | } |
249 | |
250 | if (qcom_dwmac_sgmii_phy_poll_status(regmap: data->regmap, |
251 | QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, |
252 | QSERDES_PCS_SGMIIPHY_READY)) { |
253 | dev_err(dev, "SGMIIPHY_READY timed-out" ); |
254 | return -ETIMEDOUT; |
255 | } |
256 | |
257 | if (qcom_dwmac_sgmii_phy_poll_status(regmap: data->regmap, |
258 | QSERDES_QMP_PLL + QSERDES_V5_COM_CMN_STATUS, |
259 | QSERDES_COM_C_PLL_LOCKED)) { |
260 | dev_err(dev, "PLL Lock Status timed-out" ); |
261 | return -ETIMEDOUT; |
262 | } |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy) |
268 | { |
269 | struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); |
270 | |
271 | return clk_prepare_enable(clk: data->refclk); |
272 | } |
273 | |
274 | static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy) |
275 | { |
276 | struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); |
277 | |
278 | regmap_write(map: data->regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, val: 0x08); |
279 | regmap_write(map: data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x01); |
280 | udelay(100); |
281 | regmap_write(map: data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, val: 0x00); |
282 | regmap_write(map: data->regmap, QSERDES_PCS + QPHY_PCS_PHY_START, val: 0x01); |
283 | |
284 | clk_disable_unprepare(clk: data->refclk); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int qcom_dwmac_sgmii_phy_set_speed(struct phy *phy, int speed) |
290 | { |
291 | struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); |
292 | |
293 | if (speed != data->speed) |
294 | data->speed = speed; |
295 | |
296 | return qcom_dwmac_sgmii_phy_calibrate(phy); |
297 | } |
298 | |
299 | static const struct phy_ops qcom_dwmac_sgmii_phy_ops = { |
300 | .power_on = qcom_dwmac_sgmii_phy_power_on, |
301 | .power_off = qcom_dwmac_sgmii_phy_power_off, |
302 | .set_speed = qcom_dwmac_sgmii_phy_set_speed, |
303 | .calibrate = qcom_dwmac_sgmii_phy_calibrate, |
304 | .owner = THIS_MODULE, |
305 | }; |
306 | |
307 | static const struct regmap_config qcom_dwmac_sgmii_phy_regmap_cfg = { |
308 | .reg_bits = 32, |
309 | .val_bits = 32, |
310 | .reg_stride = 4, |
311 | .use_relaxed_mmio = true, |
312 | .disable_locking = true, |
313 | }; |
314 | |
315 | static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev) |
316 | { |
317 | struct qcom_dwmac_sgmii_phy_data *data; |
318 | struct device *dev = &pdev->dev; |
319 | struct phy_provider *provider; |
320 | void __iomem *base; |
321 | struct phy *phy; |
322 | |
323 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
324 | if (!data) |
325 | return -ENOMEM; |
326 | |
327 | data->speed = SPEED_10; |
328 | |
329 | base = devm_platform_ioremap_resource(pdev, index: 0); |
330 | if (IS_ERR(ptr: base)) |
331 | return PTR_ERR(ptr: base); |
332 | |
333 | data->regmap = devm_regmap_init_mmio(dev, base, |
334 | &qcom_dwmac_sgmii_phy_regmap_cfg); |
335 | if (IS_ERR(ptr: data->regmap)) |
336 | return PTR_ERR(ptr: data->regmap); |
337 | |
338 | phy = devm_phy_create(dev, NULL, ops: &qcom_dwmac_sgmii_phy_ops); |
339 | if (IS_ERR(ptr: phy)) |
340 | return PTR_ERR(ptr: phy); |
341 | |
342 | data->refclk = devm_clk_get(dev, id: "sgmi_ref" ); |
343 | if (IS_ERR(ptr: data->refclk)) |
344 | return PTR_ERR(ptr: data->refclk); |
345 | |
346 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
347 | if (IS_ERR(ptr: provider)) |
348 | return PTR_ERR(ptr: provider); |
349 | |
350 | phy_set_drvdata(phy, data); |
351 | |
352 | return 0; |
353 | } |
354 | |
355 | static const struct of_device_id qcom_dwmac_sgmii_phy_of_match[] = { |
356 | { .compatible = "qcom,sa8775p-dwmac-sgmii-phy" }, |
357 | { }, |
358 | }; |
359 | MODULE_DEVICE_TABLE(of, qcom_dwmac_sgmii_phy_of_match); |
360 | |
361 | static struct platform_driver qcom_dwmac_sgmii_phy_driver = { |
362 | .probe = qcom_dwmac_sgmii_phy_probe, |
363 | .driver = { |
364 | .name = "qcom-dwmac-sgmii-phy" , |
365 | .of_match_table = qcom_dwmac_sgmii_phy_of_match, |
366 | } |
367 | }; |
368 | |
369 | module_platform_driver(qcom_dwmac_sgmii_phy_driver); |
370 | |
371 | MODULE_DESCRIPTION("Qualcomm DWMAC SGMII PHY driver" ); |
372 | MODULE_LICENSE("GPL" ); |
373 | |