]>
Commit | Line | Data |
---|---|---|
a7c30e62 VK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2018-19, Linaro Limited | |
3 | ||
4 | #include <linux/module.h> | |
5 | #include <linux/of.h> | |
a8aa20a6 | 6 | #include <linux/of_net.h> |
a7c30e62 VK |
7 | #include <linux/platform_device.h> |
8 | #include <linux/phy.h> | |
0dec3b48 | 9 | #include <linux/phy/phy.h> |
97f73bc5 | 10 | |
a7c30e62 VK |
11 | #include "stmmac.h" |
12 | #include "stmmac_platform.h" | |
13 | ||
14 | #define RGMII_IO_MACRO_CONFIG 0x0 | |
15 | #define SDCC_HC_REG_DLL_CONFIG 0x4 | |
b6837619 | 16 | #define SDCC_TEST_CTL 0x8 |
a7c30e62 VK |
17 | #define SDCC_HC_REG_DDR_CONFIG 0xC |
18 | #define SDCC_HC_REG_DLL_CONFIG2 0x10 | |
19 | #define SDC4_STATUS 0x14 | |
20 | #define SDCC_USR_CTL 0x18 | |
21 | #define RGMII_IO_MACRO_CONFIG2 0x1C | |
22 | #define RGMII_IO_MACRO_DEBUG1 0x20 | |
23 | #define EMAC_SYSTEM_LOW_POWER_DEBUG 0x28 | |
24 | ||
25 | /* RGMII_IO_MACRO_CONFIG fields */ | |
26 | #define RGMII_CONFIG_FUNC_CLK_EN BIT(30) | |
27 | #define RGMII_CONFIG_POS_NEG_DATA_SEL BIT(23) | |
28 | #define RGMII_CONFIG_GPIO_CFG_RX_INT GENMASK(21, 20) | |
29 | #define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17) | |
30 | #define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8) | |
31 | #define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6) | |
32 | #define RGMII_CONFIG_INTF_SEL GENMASK(5, 4) | |
33 | #define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3) | |
34 | #define RGMII_CONFIG_LOOPBACK_EN BIT(2) | |
35 | #define RGMII_CONFIG_PROG_SWAP BIT(1) | |
36 | #define RGMII_CONFIG_DDR_MODE BIT(0) | |
981d947b | 37 | #define RGMII_CONFIG_SGMII_CLK_DVDR GENMASK(18, 10) |
a7c30e62 VK |
38 | |
39 | /* SDCC_HC_REG_DLL_CONFIG fields */ | |
40 | #define SDCC_DLL_CONFIG_DLL_RST BIT(30) | |
41 | #define SDCC_DLL_CONFIG_PDN BIT(29) | |
42 | #define SDCC_DLL_CONFIG_MCLK_FREQ GENMASK(26, 24) | |
43 | #define SDCC_DLL_CONFIG_CDR_SELEXT GENMASK(23, 20) | |
44 | #define SDCC_DLL_CONFIG_CDR_EXT_EN BIT(19) | |
45 | #define SDCC_DLL_CONFIG_CK_OUT_EN BIT(18) | |
46 | #define SDCC_DLL_CONFIG_CDR_EN BIT(17) | |
47 | #define SDCC_DLL_CONFIG_DLL_EN BIT(16) | |
48 | #define SDCC_DLL_MCLK_GATING_EN BIT(5) | |
49 | #define SDCC_DLL_CDR_FINE_PHASE GENMASK(3, 2) | |
50 | ||
51 | /* SDCC_HC_REG_DDR_CONFIG fields */ | |
52 | #define SDCC_DDR_CONFIG_PRG_DLY_EN BIT(31) | |
53 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21) | |
54 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27) | |
55 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30) | |
b6837619 | 56 | #define SDCC_DDR_CONFIG_TCXO_CYCLES_CNT GENMASK(11, 9) |
a7c30e62 VK |
57 | #define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0) |
58 | ||
59 | /* SDCC_HC_REG_DLL_CONFIG2 fields */ | |
60 | #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS BIT(21) | |
61 | #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC GENMASK(17, 10) | |
62 | #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL GENMASK(3, 2) | |
63 | #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW BIT(1) | |
64 | #define SDCC_DLL_CONFIG2_DDR_CAL_EN BIT(0) | |
65 | ||
66 | /* SDC4_STATUS bits */ | |
67 | #define SDC4_STATUS_DLL_LOCK BIT(7) | |
68 | ||
69 | /* RGMII_IO_MACRO_CONFIG2 fields */ | |
70 | #define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17) | |
71 | #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16) | |
72 | #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN BIT(13) | |
73 | #define RGMII_CONFIG2_CLK_DIVIDE_SEL BIT(12) | |
74 | #define RGMII_CONFIG2_RX_PROG_SWAP BIT(7) | |
75 | #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) | |
76 | #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) | |
77 | ||
463120c3 BG |
78 | /* MAC_CTRL_REG bits */ |
79 | #define ETHQOS_MAC_CTRL_SPEED_MODE BIT(14) | |
80 | #define ETHQOS_MAC_CTRL_PORT_SEL BIT(15) | |
81 | ||
981d947b SS |
82 | #define SGMII_10M_RX_CLK_DVDR 0x31 |
83 | ||
a7c30e62 VK |
84 | struct ethqos_emac_por { |
85 | unsigned int offset; | |
86 | unsigned int value; | |
87 | }; | |
88 | ||
fd4a5177 VK |
89 | struct ethqos_emac_driver_data { |
90 | const struct ethqos_emac_por *por; | |
91 | unsigned int num_por; | |
030f1d59 | 92 | bool rgmii_config_loopback_en; |
8c4d92e8 | 93 | bool has_emac_ge_3; |
feeb2716 | 94 | const char *link_clk_name; |
8c4d92e8 | 95 | bool has_integrated_pcs; |
b6837619 | 96 | struct dwmac4_addrs dwmac4_addrs; |
fd4a5177 VK |
97 | }; |
98 | ||
a7c30e62 VK |
99 | struct qcom_ethqos { |
100 | struct platform_device *pdev; | |
101 | void __iomem *rgmii_base; | |
463120c3 | 102 | void __iomem *mac_base; |
25c4a076 | 103 | int (*configure_func)(struct qcom_ethqos *ethqos); |
a7c30e62 | 104 | |
feeb2716 BG |
105 | unsigned int link_clk_rate; |
106 | struct clk *link_clk; | |
0dec3b48 | 107 | struct phy *serdes_phy; |
a7c30e62 | 108 | unsigned int speed; |
a8aa20a6 | 109 | phy_interface_t phy_mode; |
a7c30e62 VK |
110 | |
111 | const struct ethqos_emac_por *por; | |
112 | unsigned int num_por; | |
030f1d59 | 113 | bool rgmii_config_loopback_en; |
8c4d92e8 | 114 | bool has_emac_ge_3; |
a7c30e62 VK |
115 | }; |
116 | ||
117 | static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) | |
118 | { | |
119 | return readl(ethqos->rgmii_base + offset); | |
120 | } | |
121 | ||
122 | static void rgmii_writel(struct qcom_ethqos *ethqos, | |
123 | int value, unsigned int offset) | |
124 | { | |
125 | writel(value, ethqos->rgmii_base + offset); | |
126 | } | |
127 | ||
128 | static void rgmii_updatel(struct qcom_ethqos *ethqos, | |
129 | int mask, int val, unsigned int offset) | |
130 | { | |
131 | unsigned int temp; | |
132 | ||
f2b17585 | 133 | temp = rgmii_readl(ethqos, offset); |
a7c30e62 VK |
134 | temp = (temp & ~(mask)) | val; |
135 | rgmii_writel(ethqos, temp, offset); | |
136 | } | |
137 | ||
4047b9db | 138 | static void rgmii_dump(void *priv) |
a7c30e62 | 139 | { |
4047b9db | 140 | struct qcom_ethqos *ethqos = priv; |
302555a0 | 141 | struct device *dev = ðqos->pdev->dev; |
4047b9db | 142 | |
302555a0 BG |
143 | dev_dbg(dev, "Rgmii register dump\n"); |
144 | dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %x\n", | |
a7c30e62 | 145 | rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG)); |
302555a0 | 146 | dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", |
a7c30e62 | 147 | rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG)); |
302555a0 | 148 | dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", |
a7c30e62 | 149 | rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG)); |
302555a0 | 150 | dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", |
a7c30e62 | 151 | rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2)); |
302555a0 | 152 | dev_dbg(dev, "SDC4_STATUS: %x\n", |
a7c30e62 | 153 | rgmii_readl(ethqos, SDC4_STATUS)); |
302555a0 | 154 | dev_dbg(dev, "SDCC_USR_CTL: %x\n", |
a7c30e62 | 155 | rgmii_readl(ethqos, SDCC_USR_CTL)); |
302555a0 | 156 | dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %x\n", |
a7c30e62 | 157 | rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2)); |
302555a0 | 158 | dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %x\n", |
a7c30e62 | 159 | rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1)); |
302555a0 | 160 | dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", |
a7c30e62 VK |
161 | rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); |
162 | } | |
163 | ||
164 | /* Clock rates */ | |
165 | #define RGMII_1000_NOM_CLK_FREQ (250 * 1000 * 1000UL) | |
166 | #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ (50 * 1000 * 1000UL) | |
167 | #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL) | |
168 | ||
169 | static void | |
feeb2716 | 170 | ethqos_update_link_clk(struct qcom_ethqos *ethqos, unsigned int speed) |
a7c30e62 VK |
171 | { |
172 | switch (speed) { | |
173 | case SPEED_1000: | |
feeb2716 | 174 | ethqos->link_clk_rate = RGMII_1000_NOM_CLK_FREQ; |
a7c30e62 VK |
175 | break; |
176 | ||
177 | case SPEED_100: | |
feeb2716 | 178 | ethqos->link_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; |
a7c30e62 VK |
179 | break; |
180 | ||
181 | case SPEED_10: | |
feeb2716 | 182 | ethqos->link_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; |
a7c30e62 VK |
183 | break; |
184 | } | |
185 | ||
feeb2716 | 186 | clk_set_rate(ethqos->link_clk, ethqos->link_clk_rate); |
a7c30e62 VK |
187 | } |
188 | ||
189 | static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) | |
190 | { | |
191 | rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN, | |
192 | RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); | |
193 | } | |
194 | ||
195 | static const struct ethqos_emac_por emac_v2_3_0_por[] = { | |
196 | { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, | |
197 | { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, | |
198 | { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, | |
199 | { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, | |
200 | { .offset = SDCC_USR_CTL, .value = 0x00010800 }, | |
201 | { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, | |
202 | }; | |
203 | ||
fd4a5177 VK |
204 | static const struct ethqos_emac_driver_data emac_v2_3_0_data = { |
205 | .por = emac_v2_3_0_por, | |
206 | .num_por = ARRAY_SIZE(emac_v2_3_0_por), | |
030f1d59 | 207 | .rgmii_config_loopback_en = true, |
8c4d92e8 | 208 | .has_emac_ge_3 = false, |
fd4a5177 VK |
209 | }; |
210 | ||
d90b3120 VK |
211 | static const struct ethqos_emac_por emac_v2_1_0_por[] = { |
212 | { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40C01343 }, | |
213 | { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, | |
214 | { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, | |
215 | { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, | |
216 | { .offset = SDCC_USR_CTL, .value = 0x00010800 }, | |
217 | { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, | |
218 | }; | |
219 | ||
220 | static const struct ethqos_emac_driver_data emac_v2_1_0_data = { | |
221 | .por = emac_v2_1_0_por, | |
222 | .num_por = ARRAY_SIZE(emac_v2_1_0_por), | |
030f1d59 | 223 | .rgmii_config_loopback_en = false, |
8c4d92e8 | 224 | .has_emac_ge_3 = false, |
b6837619 AH |
225 | }; |
226 | ||
227 | static const struct ethqos_emac_por emac_v3_0_0_por[] = { | |
228 | { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40c01343 }, | |
229 | { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642c }, | |
230 | { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, | |
231 | { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, | |
232 | { .offset = SDCC_USR_CTL, .value = 0x00010800 }, | |
233 | { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, | |
234 | }; | |
235 | ||
236 | static const struct ethqos_emac_driver_data emac_v3_0_0_data = { | |
237 | .por = emac_v3_0_0_por, | |
238 | .num_por = ARRAY_SIZE(emac_v3_0_0_por), | |
239 | .rgmii_config_loopback_en = false, | |
8c4d92e8 BG |
240 | .has_emac_ge_3 = true, |
241 | .dwmac4_addrs = { | |
242 | .dma_chan = 0x00008100, | |
243 | .dma_chan_offset = 0x1000, | |
244 | .mtl_chan = 0x00008000, | |
245 | .mtl_chan_offset = 0x1000, | |
246 | .mtl_ets_ctrl = 0x00008010, | |
247 | .mtl_ets_ctrl_offset = 0x1000, | |
248 | .mtl_txq_weight = 0x00008018, | |
249 | .mtl_txq_weight_offset = 0x1000, | |
250 | .mtl_send_slp_cred = 0x0000801c, | |
251 | .mtl_send_slp_cred_offset = 0x1000, | |
252 | .mtl_high_cred = 0x00008020, | |
253 | .mtl_high_cred_offset = 0x1000, | |
254 | .mtl_low_cred = 0x00008024, | |
255 | .mtl_low_cred_offset = 0x1000, | |
256 | }, | |
257 | }; | |
258 | ||
259 | static const struct ethqos_emac_por emac_v4_0_0_por[] = { | |
260 | { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40c01343 }, | |
261 | { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642c }, | |
262 | { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, | |
263 | { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, | |
264 | { .offset = SDCC_USR_CTL, .value = 0x00010800 }, | |
265 | { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, | |
266 | }; | |
267 | ||
268 | static const struct ethqos_emac_driver_data emac_v4_0_0_data = { | |
269 | .por = emac_v4_0_0_por, | |
270 | .num_por = ARRAY_SIZE(emac_v3_0_0_por), | |
271 | .rgmii_config_loopback_en = false, | |
272 | .has_emac_ge_3 = true, | |
273 | .link_clk_name = "phyaux", | |
274 | .has_integrated_pcs = true, | |
b6837619 AH |
275 | .dwmac4_addrs = { |
276 | .dma_chan = 0x00008100, | |
277 | .dma_chan_offset = 0x1000, | |
278 | .mtl_chan = 0x00008000, | |
279 | .mtl_chan_offset = 0x1000, | |
280 | .mtl_ets_ctrl = 0x00008010, | |
281 | .mtl_ets_ctrl_offset = 0x1000, | |
282 | .mtl_txq_weight = 0x00008018, | |
283 | .mtl_txq_weight_offset = 0x1000, | |
284 | .mtl_send_slp_cred = 0x0000801c, | |
285 | .mtl_send_slp_cred_offset = 0x1000, | |
286 | .mtl_high_cred = 0x00008020, | |
287 | .mtl_high_cred_offset = 0x1000, | |
288 | .mtl_low_cred = 0x00008024, | |
289 | .mtl_low_cred_offset = 0x1000, | |
290 | }, | |
d90b3120 VK |
291 | }; |
292 | ||
a7c30e62 VK |
293 | static int ethqos_dll_configure(struct qcom_ethqos *ethqos) |
294 | { | |
302555a0 | 295 | struct device *dev = ðqos->pdev->dev; |
a7c30e62 VK |
296 | unsigned int val; |
297 | int retry = 1000; | |
298 | ||
299 | /* Set CDR_EN */ | |
300 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, | |
301 | SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); | |
302 | ||
303 | /* Set CDR_EXT_EN */ | |
304 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, | |
305 | SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG); | |
306 | ||
307 | /* Clear CK_OUT_EN */ | |
308 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
309 | 0, SDCC_HC_REG_DLL_CONFIG); | |
310 | ||
311 | /* Set DLL_EN */ | |
312 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, | |
313 | SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); | |
314 | ||
8c4d92e8 | 315 | if (!ethqos->has_emac_ge_3) { |
b6837619 AH |
316 | rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, |
317 | 0, SDCC_HC_REG_DLL_CONFIG); | |
a7c30e62 | 318 | |
b6837619 AH |
319 | rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, |
320 | 0, SDCC_HC_REG_DLL_CONFIG); | |
321 | } | |
a7c30e62 VK |
322 | |
323 | /* Wait for CK_OUT_EN clear */ | |
324 | do { | |
325 | val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); | |
326 | val &= SDCC_DLL_CONFIG_CK_OUT_EN; | |
327 | if (!val) | |
328 | break; | |
329 | mdelay(1); | |
330 | retry--; | |
331 | } while (retry > 0); | |
332 | if (!retry) | |
302555a0 | 333 | dev_err(dev, "Clear CK_OUT_EN timedout\n"); |
a7c30e62 VK |
334 | |
335 | /* Set CK_OUT_EN */ | |
336 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
337 | SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); | |
338 | ||
339 | /* Wait for CK_OUT_EN set */ | |
340 | retry = 1000; | |
341 | do { | |
342 | val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); | |
343 | val &= SDCC_DLL_CONFIG_CK_OUT_EN; | |
344 | if (val) | |
345 | break; | |
346 | mdelay(1); | |
347 | retry--; | |
348 | } while (retry > 0); | |
349 | if (!retry) | |
302555a0 | 350 | dev_err(dev, "Set CK_OUT_EN timedout\n"); |
a7c30e62 VK |
351 | |
352 | /* Set DDR_CAL_EN */ | |
353 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, | |
354 | SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); | |
355 | ||
8c4d92e8 | 356 | if (!ethqos->has_emac_ge_3) { |
b6837619 AH |
357 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, |
358 | 0, SDCC_HC_REG_DLL_CONFIG2); | |
a7c30e62 | 359 | |
b6837619 AH |
360 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, |
361 | 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); | |
a7c30e62 | 362 | |
b6837619 AH |
363 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, |
364 | BIT(2), SDCC_HC_REG_DLL_CONFIG2); | |
a7c30e62 | 365 | |
b6837619 AH |
366 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, |
367 | SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, | |
368 | SDCC_HC_REG_DLL_CONFIG2); | |
369 | } | |
a7c30e62 VK |
370 | |
371 | return 0; | |
372 | } | |
373 | ||
374 | static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) | |
375 | { | |
302555a0 | 376 | struct device *dev = ðqos->pdev->dev; |
164a9ebe | 377 | int phase_shift; |
030f1d59 | 378 | int loopback; |
164a9ebe AH |
379 | |
380 | /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ | |
25c4a076 BG |
381 | if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID || |
382 | ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) | |
164a9ebe AH |
383 | phase_shift = 0; |
384 | else | |
385 | phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; | |
386 | ||
a7c30e62 VK |
387 | /* Disable loopback mode */ |
388 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, | |
389 | 0, RGMII_IO_MACRO_CONFIG2); | |
390 | ||
030f1d59 AH |
391 | /* Determine if this platform wants loopback enabled after programming */ |
392 | if (ethqos->rgmii_config_loopback_en) | |
393 | loopback = RGMII_CONFIG_LOOPBACK_EN; | |
394 | else | |
395 | loopback = 0; | |
396 | ||
a7c30e62 VK |
397 | /* Select RGMII, write 0 to interface select */ |
398 | rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, | |
399 | 0, RGMII_IO_MACRO_CONFIG); | |
400 | ||
401 | switch (ethqos->speed) { | |
402 | case SPEED_1000: | |
403 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
404 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
405 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
406 | 0, RGMII_IO_MACRO_CONFIG); | |
407 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
408 | RGMII_CONFIG_POS_NEG_DATA_SEL, | |
409 | RGMII_IO_MACRO_CONFIG); | |
410 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
411 | RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG); | |
412 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
413 | 0, RGMII_IO_MACRO_CONFIG2); | |
164a9ebe | 414 | |
a7c30e62 | 415 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, |
164a9ebe | 416 | phase_shift, RGMII_IO_MACRO_CONFIG2); |
a7c30e62 VK |
417 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, |
418 | 0, RGMII_IO_MACRO_CONFIG2); | |
419 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
420 | RGMII_CONFIG2_RX_PROG_SWAP, | |
421 | RGMII_IO_MACRO_CONFIG2); | |
422 | ||
b6837619 AH |
423 | /* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns, |
424 | * in practice this becomes PRG_RCLK_DLY = 52 * 4 / 2 * RX delay ns | |
425 | */ | |
8c4d92e8 | 426 | if (ethqos->has_emac_ge_3) { |
b6837619 AH |
427 | /* 0.9 ns */ |
428 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, | |
429 | 115, SDCC_HC_REG_DDR_CONFIG); | |
430 | } else { | |
431 | /* 1.8 ns */ | |
432 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, | |
433 | 57, SDCC_HC_REG_DDR_CONFIG); | |
434 | } | |
a7c30e62 VK |
435 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, |
436 | SDCC_DDR_CONFIG_PRG_DLY_EN, | |
437 | SDCC_HC_REG_DDR_CONFIG); | |
030f1d59 AH |
438 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, |
439 | loopback, RGMII_IO_MACRO_CONFIG); | |
a7c30e62 VK |
440 | break; |
441 | ||
442 | case SPEED_100: | |
443 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
444 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
445 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
446 | RGMII_CONFIG_BYPASS_TX_ID_EN, | |
447 | RGMII_IO_MACRO_CONFIG); | |
448 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
449 | 0, RGMII_IO_MACRO_CONFIG); | |
450 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
451 | 0, RGMII_IO_MACRO_CONFIG); | |
452 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
453 | 0, RGMII_IO_MACRO_CONFIG2); | |
454 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
164a9ebe | 455 | phase_shift, RGMII_IO_MACRO_CONFIG2); |
a7c30e62 VK |
456 | rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, |
457 | BIT(6), RGMII_IO_MACRO_CONFIG); | |
458 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, | |
459 | 0, RGMII_IO_MACRO_CONFIG2); | |
b6837619 | 460 | |
8c4d92e8 | 461 | if (ethqos->has_emac_ge_3) |
b6837619 AH |
462 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, |
463 | RGMII_CONFIG2_RX_PROG_SWAP, | |
464 | RGMII_IO_MACRO_CONFIG2); | |
465 | else | |
466 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
467 | 0, RGMII_IO_MACRO_CONFIG2); | |
468 | ||
a7c30e62 VK |
469 | /* Write 0x5 to PRG_RCLK_DLY_CODE */ |
470 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, | |
471 | (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); | |
472 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
473 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
474 | SDCC_HC_REG_DDR_CONFIG); | |
475 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
476 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
477 | SDCC_HC_REG_DDR_CONFIG); | |
030f1d59 AH |
478 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, |
479 | loopback, RGMII_IO_MACRO_CONFIG); | |
a7c30e62 VK |
480 | break; |
481 | ||
482 | case SPEED_10: | |
483 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
484 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
485 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
486 | RGMII_CONFIG_BYPASS_TX_ID_EN, | |
487 | RGMII_IO_MACRO_CONFIG); | |
488 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
489 | 0, RGMII_IO_MACRO_CONFIG); | |
490 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
491 | 0, RGMII_IO_MACRO_CONFIG); | |
492 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
493 | 0, RGMII_IO_MACRO_CONFIG2); | |
494 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
164a9ebe | 495 | phase_shift, RGMII_IO_MACRO_CONFIG2); |
a7c30e62 VK |
496 | rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, |
497 | BIT(12) | GENMASK(9, 8), | |
498 | RGMII_IO_MACRO_CONFIG); | |
499 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, | |
500 | 0, RGMII_IO_MACRO_CONFIG2); | |
8c4d92e8 | 501 | if (ethqos->has_emac_ge_3) |
b6837619 AH |
502 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, |
503 | RGMII_CONFIG2_RX_PROG_SWAP, | |
504 | RGMII_IO_MACRO_CONFIG2); | |
505 | else | |
506 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
507 | 0, RGMII_IO_MACRO_CONFIG2); | |
a7c30e62 VK |
508 | /* Write 0x5 to PRG_RCLK_DLY_CODE */ |
509 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, | |
510 | (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); | |
511 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
512 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
513 | SDCC_HC_REG_DDR_CONFIG); | |
514 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
515 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
516 | SDCC_HC_REG_DDR_CONFIG); | |
517 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, | |
030f1d59 | 518 | loopback, RGMII_IO_MACRO_CONFIG); |
a7c30e62 VK |
519 | break; |
520 | default: | |
302555a0 | 521 | dev_err(dev, "Invalid speed %d\n", ethqos->speed); |
a7c30e62 VK |
522 | return -EINVAL; |
523 | } | |
524 | ||
525 | return 0; | |
526 | } | |
527 | ||
25c4a076 | 528 | static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) |
a7c30e62 | 529 | { |
302555a0 | 530 | struct device *dev = ðqos->pdev->dev; |
a7c30e62 VK |
531 | volatile unsigned int dll_lock; |
532 | unsigned int i, retry = 1000; | |
533 | ||
534 | /* Reset to POR values and enable clk */ | |
535 | for (i = 0; i < ethqos->num_por; i++) | |
536 | rgmii_writel(ethqos, ethqos->por[i].value, | |
537 | ethqos->por[i].offset); | |
538 | ethqos_set_func_clk_en(ethqos); | |
539 | ||
540 | /* Initialize the DLL first */ | |
541 | ||
542 | /* Set DLL_RST */ | |
543 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, | |
544 | SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); | |
545 | ||
546 | /* Set PDN */ | |
547 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, | |
548 | SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); | |
549 | ||
8c4d92e8 | 550 | if (ethqos->has_emac_ge_3) { |
b6837619 AH |
551 | if (ethqos->speed == SPEED_1000) { |
552 | rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL); | |
553 | rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL); | |
554 | rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); | |
555 | } else { | |
556 | rgmii_writel(ethqos, 0x40010800, SDCC_USR_CTL); | |
557 | rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); | |
558 | } | |
559 | } | |
560 | ||
a7c30e62 VK |
561 | /* Clear DLL_RST */ |
562 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, | |
563 | SDCC_HC_REG_DLL_CONFIG); | |
564 | ||
565 | /* Clear PDN */ | |
566 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0, | |
567 | SDCC_HC_REG_DLL_CONFIG); | |
568 | ||
569 | if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { | |
570 | /* Set DLL_EN */ | |
571 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, | |
572 | SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); | |
573 | ||
574 | /* Set CK_OUT_EN */ | |
575 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
576 | SDCC_DLL_CONFIG_CK_OUT_EN, | |
577 | SDCC_HC_REG_DLL_CONFIG); | |
578 | ||
579 | /* Set USR_CTL bit 26 with mask of 3 bits */ | |
8c4d92e8 | 580 | if (!ethqos->has_emac_ge_3) |
b6837619 AH |
581 | rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), |
582 | SDCC_USR_CTL); | |
a7c30e62 VK |
583 | |
584 | /* wait for DLL LOCK */ | |
585 | do { | |
586 | mdelay(1); | |
587 | dll_lock = rgmii_readl(ethqos, SDC4_STATUS); | |
588 | if (dll_lock & SDC4_STATUS_DLL_LOCK) | |
589 | break; | |
7d10f077 | 590 | retry--; |
a7c30e62 VK |
591 | } while (retry > 0); |
592 | if (!retry) | |
302555a0 | 593 | dev_err(dev, "Timeout while waiting for DLL lock\n"); |
a7c30e62 VK |
594 | } |
595 | ||
596 | if (ethqos->speed == SPEED_1000) | |
597 | ethqos_dll_configure(ethqos); | |
598 | ||
599 | ethqos_rgmii_macro_init(ethqos); | |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
981d947b SS |
604 | /* On interface toggle MAC registers gets reset. |
605 | * Configure MAC block for SGMII on ethernet phy link up | |
606 | */ | |
463120c3 BG |
607 | static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) |
608 | { | |
609 | int val; | |
610 | ||
611 | val = readl(ethqos->mac_base + MAC_CTRL_REG); | |
612 | ||
613 | switch (ethqos->speed) { | |
614 | case SPEED_1000: | |
615 | val &= ~ETHQOS_MAC_CTRL_PORT_SEL; | |
616 | rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, | |
617 | RGMII_CONFIG2_RGMII_CLK_SEL_CFG, | |
618 | RGMII_IO_MACRO_CONFIG2); | |
619 | break; | |
620 | case SPEED_100: | |
621 | val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE; | |
622 | break; | |
623 | case SPEED_10: | |
624 | val |= ETHQOS_MAC_CTRL_PORT_SEL; | |
625 | val &= ~ETHQOS_MAC_CTRL_SPEED_MODE; | |
981d947b SS |
626 | rgmii_updatel(ethqos, RGMII_CONFIG_SGMII_CLK_DVDR, |
627 | FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR, | |
628 | SGMII_10M_RX_CLK_DVDR), | |
629 | RGMII_IO_MACRO_CONFIG); | |
463120c3 BG |
630 | break; |
631 | } | |
632 | ||
633 | writel(val, ethqos->mac_base + MAC_CTRL_REG); | |
634 | ||
635 | return val; | |
636 | } | |
637 | ||
25c4a076 BG |
638 | static int ethqos_configure(struct qcom_ethqos *ethqos) |
639 | { | |
640 | return ethqos->configure_func(ethqos); | |
641 | } | |
642 | ||
1fc04a0b | 643 | static void ethqos_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) |
a7c30e62 VK |
644 | { |
645 | struct qcom_ethqos *ethqos = priv; | |
646 | ||
647 | ethqos->speed = speed; | |
feeb2716 | 648 | ethqos_update_link_clk(ethqos, speed); |
a7c30e62 VK |
649 | ethqos_configure(ethqos); |
650 | } | |
651 | ||
0dec3b48 BG |
652 | static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) |
653 | { | |
654 | struct qcom_ethqos *ethqos = priv; | |
655 | int ret; | |
656 | ||
657 | ret = phy_init(ethqos->serdes_phy); | |
658 | if (ret) | |
659 | return ret; | |
660 | ||
661 | ret = phy_power_on(ethqos->serdes_phy); | |
662 | if (ret) | |
663 | return ret; | |
664 | ||
665 | return phy_set_speed(ethqos->serdes_phy, ethqos->speed); | |
666 | } | |
667 | ||
668 | static void qcom_ethqos_serdes_powerdown(struct net_device *ndev, void *priv) | |
669 | { | |
670 | struct qcom_ethqos *ethqos = priv; | |
671 | ||
672 | phy_power_off(ethqos->serdes_phy); | |
673 | phy_exit(ethqos->serdes_phy); | |
674 | } | |
675 | ||
6c950ca7 BS |
676 | static int ethqos_clks_config(void *priv, bool enabled) |
677 | { | |
678 | struct qcom_ethqos *ethqos = priv; | |
679 | int ret = 0; | |
680 | ||
681 | if (enabled) { | |
feeb2716 | 682 | ret = clk_prepare_enable(ethqos->link_clk); |
6c950ca7 | 683 | if (ret) { |
feeb2716 | 684 | dev_err(ðqos->pdev->dev, "link_clk enable failed\n"); |
6c950ca7 BS |
685 | return ret; |
686 | } | |
ffba2123 BA |
687 | |
688 | /* Enable functional clock to prevent DMA reset to timeout due | |
689 | * to lacking PHY clock after the hardware block has been power | |
690 | * cycled. The actual configuration will be adjusted once | |
691 | * ethqos_fix_mac_speed() is invoked. | |
692 | */ | |
693 | ethqos_set_func_clk_en(ethqos); | |
6c950ca7 | 694 | } else { |
feeb2716 | 695 | clk_disable_unprepare(ethqos->link_clk); |
6c950ca7 BS |
696 | } |
697 | ||
698 | return ret; | |
699 | } | |
700 | ||
9fc68f23 BG |
701 | static void ethqos_clks_disable(void *data) |
702 | { | |
703 | ethqos_clks_config(data, false); | |
704 | } | |
705 | ||
db845b9b AH |
706 | static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv) |
707 | { | |
708 | struct plat_stmmacenet_data *plat_dat = priv->plat; | |
709 | int err; | |
710 | ||
711 | if (!plat_dat->clk_ptp_ref) | |
712 | return; | |
713 | ||
714 | /* Max the PTP ref clock out to get the best resolution possible */ | |
715 | err = clk_set_rate(plat_dat->clk_ptp_ref, ULONG_MAX); | |
716 | if (err) | |
717 | netdev_err(priv->dev, "Failed to max out clk_ptp_ref: %d\n", err); | |
718 | plat_dat->clk_ptp_rate = clk_get_rate(plat_dat->clk_ptp_ref); | |
719 | ||
720 | netdev_dbg(priv->dev, "PTP rate %d\n", plat_dat->clk_ptp_rate); | |
721 | } | |
722 | ||
a7c30e62 VK |
723 | static int qcom_ethqos_probe(struct platform_device *pdev) |
724 | { | |
725 | struct device_node *np = pdev->dev.of_node; | |
7b5e64a9 | 726 | const struct ethqos_emac_driver_data *data; |
a7c30e62 VK |
727 | struct plat_stmmacenet_data *plat_dat; |
728 | struct stmmac_resources stmmac_res; | |
302555a0 | 729 | struct device *dev = &pdev->dev; |
a7c30e62 | 730 | struct qcom_ethqos *ethqos; |
a7c30e62 VK |
731 | int ret; |
732 | ||
733 | ret = stmmac_get_platform_resources(pdev, &stmmac_res); | |
734 | if (ret) | |
27381e72 AH |
735 | return dev_err_probe(dev, ret, |
736 | "Failed to get platform resources\n"); | |
a7c30e62 | 737 | |
061425d9 | 738 | plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); |
a7c30e62 | 739 | if (IS_ERR(plat_dat)) { |
b2f3d915 AH |
740 | return dev_err_probe(dev, PTR_ERR(plat_dat), |
741 | "dt configuration failed\n"); | |
a7c30e62 VK |
742 | } |
743 | ||
6c950ca7 BS |
744 | plat_dat->clks_config = ethqos_clks_config; |
745 | ||
302555a0 | 746 | ethqos = devm_kzalloc(dev, sizeof(*ethqos), GFP_KERNEL); |
061425d9 BG |
747 | if (!ethqos) |
748 | return -ENOMEM; | |
a7c30e62 | 749 | |
a8aa20a6 AH |
750 | ret = of_get_phy_mode(np, ðqos->phy_mode); |
751 | if (ret) | |
752 | return dev_err_probe(dev, ret, "Failed to get phy mode\n"); | |
25c4a076 BG |
753 | switch (ethqos->phy_mode) { |
754 | case PHY_INTERFACE_MODE_RGMII: | |
755 | case PHY_INTERFACE_MODE_RGMII_ID: | |
756 | case PHY_INTERFACE_MODE_RGMII_RXID: | |
757 | case PHY_INTERFACE_MODE_RGMII_TXID: | |
758 | ethqos->configure_func = ethqos_configure_rgmii; | |
759 | break; | |
463120c3 BG |
760 | case PHY_INTERFACE_MODE_SGMII: |
761 | ethqos->configure_func = ethqos_configure_sgmii; | |
762 | break; | |
25c4a076 | 763 | default: |
27381e72 AH |
764 | dev_err(dev, "Unsupported phy mode %s\n", |
765 | phy_modes(ethqos->phy_mode)); | |
061425d9 | 766 | return -EINVAL; |
25c4a076 BG |
767 | } |
768 | ||
a7c30e62 | 769 | ethqos->pdev = pdev; |
3a5a32b5 | 770 | ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); |
061425d9 | 771 | if (IS_ERR(ethqos->rgmii_base)) |
27381e72 AH |
772 | return dev_err_probe(dev, PTR_ERR(ethqos->rgmii_base), |
773 | "Failed to map rgmii resource\n"); | |
a7c30e62 | 774 | |
463120c3 BG |
775 | ethqos->mac_base = stmmac_res.addr; |
776 | ||
302555a0 | 777 | data = of_device_get_match_data(dev); |
fd4a5177 VK |
778 | ethqos->por = data->por; |
779 | ethqos->num_por = data->num_por; | |
030f1d59 | 780 | ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; |
8c4d92e8 | 781 | ethqos->has_emac_ge_3 = data->has_emac_ge_3; |
a7c30e62 | 782 | |
feeb2716 | 783 | ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii"); |
061425d9 | 784 | if (IS_ERR(ethqos->link_clk)) |
27381e72 AH |
785 | return dev_err_probe(dev, PTR_ERR(ethqos->link_clk), |
786 | "Failed to get link_clk\n"); | |
a7c30e62 | 787 | |
6c950ca7 | 788 | ret = ethqos_clks_config(ethqos, true); |
a7c30e62 | 789 | if (ret) |
061425d9 | 790 | return ret; |
a7c30e62 | 791 | |
302555a0 | 792 | ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos); |
9fc68f23 | 793 | if (ret) |
061425d9 | 794 | return ret; |
9fc68f23 | 795 | |
0dec3b48 | 796 | ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes"); |
061425d9 | 797 | if (IS_ERR(ethqos->serdes_phy)) |
27381e72 AH |
798 | return dev_err_probe(dev, PTR_ERR(ethqos->serdes_phy), |
799 | "Failed to get serdes phy\n"); | |
0dec3b48 | 800 | |
a7c30e62 | 801 | ethqos->speed = SPEED_1000; |
feeb2716 | 802 | ethqos_update_link_clk(ethqos, SPEED_1000); |
a7c30e62 VK |
803 | ethqos_set_func_clk_en(ethqos); |
804 | ||
805 | plat_dat->bsp_priv = ethqos; | |
806 | plat_dat->fix_mac_speed = ethqos_fix_mac_speed; | |
4047b9db | 807 | plat_dat->dump_debug_regs = rgmii_dump; |
db845b9b | 808 | plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config; |
a7c30e62 | 809 | plat_dat->has_gmac4 = 1; |
8c4d92e8 | 810 | if (ethqos->has_emac_ge_3) |
9bc00973 | 811 | plat_dat->dwmac4_addrs = &data->dwmac4_addrs; |
a7c30e62 | 812 | plat_dat->pmt = 1; |
68861a3b BG |
813 | if (of_property_read_bool(np, "snps,tso")) |
814 | plat_dat->flags |= STMMAC_FLAG_TSO_EN; | |
54aa39a5 | 815 | if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) |
743dd1db | 816 | plat_dat->flags |= STMMAC_FLAG_RX_CLK_RUNS_IN_LPI; |
d26979f1 BG |
817 | if (data->has_integrated_pcs) |
818 | plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS; | |
a7c30e62 | 819 | |
0dec3b48 BG |
820 | if (ethqos->serdes_phy) { |
821 | plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup; | |
822 | plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; | |
823 | } | |
824 | ||
4194f32a | 825 | return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); |
a7c30e62 VK |
826 | } |
827 | ||
a7c30e62 | 828 | static const struct of_device_id qcom_ethqos_match[] = { |
fd4a5177 | 829 | { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, |
8c4d92e8 | 830 | { .compatible = "qcom,sa8775p-ethqos", .data = &emac_v4_0_0_data}, |
b6837619 | 831 | { .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data}, |
d90b3120 | 832 | { .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data}, |
a7c30e62 VK |
833 | { } |
834 | }; | |
835 | MODULE_DEVICE_TABLE(of, qcom_ethqos_match); | |
836 | ||
837 | static struct platform_driver qcom_ethqos_driver = { | |
838 | .probe = qcom_ethqos_probe, | |
a7c30e62 VK |
839 | .driver = { |
840 | .name = "qcom-ethqos", | |
841 | .pm = &stmmac_pltfr_pm_ops, | |
dc54e450 | 842 | .of_match_table = qcom_ethqos_match, |
a7c30e62 VK |
843 | }, |
844 | }; | |
845 | module_platform_driver(qcom_ethqos_driver); | |
846 | ||
847 | MODULE_DESCRIPTION("Qualcomm ETHQOS driver"); | |
848 | MODULE_LICENSE("GPL v2"); |