1a7c30e62SVinod Koul // SPDX-License-Identifier: GPL-2.0
2a7c30e62SVinod Koul // Copyright (c) 2018-19, Linaro Limited
3a7c30e62SVinod Koul 
4a7c30e62SVinod Koul #include <linux/module.h>
5a7c30e62SVinod Koul #include <linux/of.h>
6a7c30e62SVinod Koul #include <linux/of_device.h>
7a7c30e62SVinod Koul #include <linux/platform_device.h>
8a7c30e62SVinod Koul #include <linux/phy.h>
9ee8daccaSBartosz Golaszewski #include <linux/property.h>
10*97f73bc5SBartosz Golaszewski 
11a7c30e62SVinod Koul #include "stmmac.h"
12a7c30e62SVinod Koul #include "stmmac_platform.h"
13a7c30e62SVinod Koul 
14a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG		0x0
15a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG		0x4
16b6837619SAndrew Halaney #define SDCC_TEST_CTL			0x8
17a7c30e62SVinod Koul #define SDCC_HC_REG_DDR_CONFIG		0xC
18a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG2		0x10
19a7c30e62SVinod Koul #define SDC4_STATUS			0x14
20a7c30e62SVinod Koul #define SDCC_USR_CTL			0x18
21a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG2		0x1C
22a7c30e62SVinod Koul #define RGMII_IO_MACRO_DEBUG1		0x20
23a7c30e62SVinod Koul #define EMAC_SYSTEM_LOW_POWER_DEBUG	0x28
24a7c30e62SVinod Koul 
25a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG fields */
26a7c30e62SVinod Koul #define RGMII_CONFIG_FUNC_CLK_EN		BIT(30)
27a7c30e62SVinod Koul #define RGMII_CONFIG_POS_NEG_DATA_SEL		BIT(23)
28a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_RX_INT		GENMASK(21, 20)
29a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_TX_INT		GENMASK(19, 17)
30a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_9		GENMASK(16, 8)
31a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_2		GENMASK(7, 6)
32a7c30e62SVinod Koul #define RGMII_CONFIG_INTF_SEL			GENMASK(5, 4)
33a7c30e62SVinod Koul #define RGMII_CONFIG_BYPASS_TX_ID_EN		BIT(3)
34a7c30e62SVinod Koul #define RGMII_CONFIG_LOOPBACK_EN		BIT(2)
35a7c30e62SVinod Koul #define RGMII_CONFIG_PROG_SWAP			BIT(1)
36a7c30e62SVinod Koul #define RGMII_CONFIG_DDR_MODE			BIT(0)
37a7c30e62SVinod Koul 
38a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG fields */
39a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_RST			BIT(30)
40a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_PDN			BIT(29)
41a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_MCLK_FREQ		GENMASK(26, 24)
42a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_SELEXT		GENMASK(23, 20)
43a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EXT_EN		BIT(19)
44a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CK_OUT_EN		BIT(18)
45a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EN			BIT(17)
46a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_EN			BIT(16)
47a7c30e62SVinod Koul #define SDCC_DLL_MCLK_GATING_EN			BIT(5)
48a7c30e62SVinod Koul #define SDCC_DLL_CDR_FINE_PHASE			GENMASK(3, 2)
49a7c30e62SVinod Koul 
50a7c30e62SVinod Koul /* SDCC_HC_REG_DDR_CONFIG fields */
51a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_DLY_EN		BIT(31)
52a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY	GENMASK(26, 21)
53a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE	GENMASK(29, 27)
54a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN	BIT(30)
55b6837619SAndrew Halaney #define SDCC_DDR_CONFIG_TCXO_CYCLES_CNT		GENMASK(11, 9)
56a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_RCLK_DLY		GENMASK(8, 0)
57a7c30e62SVinod Koul 
58a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG2 fields */
59a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS		BIT(21)
60a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC		GENMASK(17, 10)
61a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL	GENMASK(3, 2)
62a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW	BIT(1)
63a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_CAL_EN		BIT(0)
64a7c30e62SVinod Koul 
65a7c30e62SVinod Koul /* SDC4_STATUS bits */
66a7c30e62SVinod Koul #define SDC4_STATUS_DLL_LOCK			BIT(7)
67a7c30e62SVinod Koul 
68a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG2 fields */
69a7c30e62SVinod Koul #define RGMII_CONFIG2_RSVD_CONFIG15		GENMASK(31, 17)
70a7c30e62SVinod Koul #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG		BIT(16)
71a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN	BIT(13)
72a7c30e62SVinod Koul #define RGMII_CONFIG2_CLK_DIVIDE_SEL		BIT(12)
73a7c30e62SVinod Koul #define RGMII_CONFIG2_RX_PROG_SWAP		BIT(7)
74a7c30e62SVinod Koul #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL	BIT(6)
75a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN	BIT(5)
76a7c30e62SVinod Koul 
77a7c30e62SVinod Koul struct ethqos_emac_por {
78a7c30e62SVinod Koul 	unsigned int offset;
79a7c30e62SVinod Koul 	unsigned int value;
80a7c30e62SVinod Koul };
81a7c30e62SVinod Koul 
82fd4a5177SVinod Koul struct ethqos_emac_driver_data {
83fd4a5177SVinod Koul 	const struct ethqos_emac_por *por;
84fd4a5177SVinod Koul 	unsigned int num_por;
85030f1d59SAndrew Halaney 	bool rgmii_config_loopback_en;
86b6837619SAndrew Halaney 	bool has_emac3;
87b6837619SAndrew Halaney 	struct dwmac4_addrs dwmac4_addrs;
88fd4a5177SVinod Koul };
89fd4a5177SVinod Koul 
90a7c30e62SVinod Koul struct qcom_ethqos {
91a7c30e62SVinod Koul 	struct platform_device *pdev;
92a7c30e62SVinod Koul 	void __iomem *rgmii_base;
93a7c30e62SVinod Koul 
94a7c30e62SVinod Koul 	unsigned int rgmii_clk_rate;
95a7c30e62SVinod Koul 	struct clk *rgmii_clk;
96a7c30e62SVinod Koul 	unsigned int speed;
97a7c30e62SVinod Koul 
98a7c30e62SVinod Koul 	const struct ethqos_emac_por *por;
99a7c30e62SVinod Koul 	unsigned int num_por;
100030f1d59SAndrew Halaney 	bool rgmii_config_loopback_en;
101b6837619SAndrew Halaney 	bool has_emac3;
102a7c30e62SVinod Koul };
103a7c30e62SVinod Koul 
104a7c30e62SVinod Koul static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset)
105a7c30e62SVinod Koul {
106a7c30e62SVinod Koul 	return readl(ethqos->rgmii_base + offset);
107a7c30e62SVinod Koul }
108a7c30e62SVinod Koul 
109a7c30e62SVinod Koul static void rgmii_writel(struct qcom_ethqos *ethqos,
110a7c30e62SVinod Koul 			 int value, unsigned int offset)
111a7c30e62SVinod Koul {
112a7c30e62SVinod Koul 	writel(value, ethqos->rgmii_base + offset);
113a7c30e62SVinod Koul }
114a7c30e62SVinod Koul 
115a7c30e62SVinod Koul static void rgmii_updatel(struct qcom_ethqos *ethqos,
116a7c30e62SVinod Koul 			  int mask, int val, unsigned int offset)
117a7c30e62SVinod Koul {
118a7c30e62SVinod Koul 	unsigned int temp;
119a7c30e62SVinod Koul 
120a7c30e62SVinod Koul 	temp =  rgmii_readl(ethqos, offset);
121a7c30e62SVinod Koul 	temp = (temp & ~(mask)) | val;
122a7c30e62SVinod Koul 	rgmii_writel(ethqos, temp, offset);
123a7c30e62SVinod Koul }
124a7c30e62SVinod Koul 
1254047b9dbSBhupesh Sharma static void rgmii_dump(void *priv)
126a7c30e62SVinod Koul {
1274047b9dbSBhupesh Sharma 	struct qcom_ethqos *ethqos = priv;
128302555a0SBartosz Golaszewski 	struct device *dev = &ethqos->pdev->dev;
1294047b9dbSBhupesh Sharma 
130302555a0SBartosz Golaszewski 	dev_dbg(dev, "Rgmii register dump\n");
131302555a0SBartosz Golaszewski 	dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %x\n",
132a7c30e62SVinod Koul 		rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG));
133302555a0SBartosz Golaszewski 	dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %x\n",
134a7c30e62SVinod Koul 		rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG));
135302555a0SBartosz Golaszewski 	dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %x\n",
136a7c30e62SVinod Koul 		rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG));
137302555a0SBartosz Golaszewski 	dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n",
138a7c30e62SVinod Koul 		rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2));
139302555a0SBartosz Golaszewski 	dev_dbg(dev, "SDC4_STATUS: %x\n",
140a7c30e62SVinod Koul 		rgmii_readl(ethqos, SDC4_STATUS));
141302555a0SBartosz Golaszewski 	dev_dbg(dev, "SDCC_USR_CTL: %x\n",
142a7c30e62SVinod Koul 		rgmii_readl(ethqos, SDCC_USR_CTL));
143302555a0SBartosz Golaszewski 	dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %x\n",
144a7c30e62SVinod Koul 		rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2));
145302555a0SBartosz Golaszewski 	dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %x\n",
146a7c30e62SVinod Koul 		rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1));
147302555a0SBartosz Golaszewski 	dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n",
148a7c30e62SVinod Koul 		rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG));
149a7c30e62SVinod Koul }
150a7c30e62SVinod Koul 
151a7c30e62SVinod Koul /* Clock rates */
152a7c30e62SVinod Koul #define RGMII_1000_NOM_CLK_FREQ			(250 * 1000 * 1000UL)
153a7c30e62SVinod Koul #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ	 (50 * 1000 * 1000UL)
154a7c30e62SVinod Koul #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ	  (5 * 1000 * 1000UL)
155a7c30e62SVinod Koul 
156a7c30e62SVinod Koul static void
157a7c30e62SVinod Koul ethqos_update_rgmii_clk(struct qcom_ethqos *ethqos, unsigned int speed)
158a7c30e62SVinod Koul {
159a7c30e62SVinod Koul 	switch (speed) {
160a7c30e62SVinod Koul 	case SPEED_1000:
161a7c30e62SVinod Koul 		ethqos->rgmii_clk_rate =  RGMII_1000_NOM_CLK_FREQ;
162a7c30e62SVinod Koul 		break;
163a7c30e62SVinod Koul 
164a7c30e62SVinod Koul 	case SPEED_100:
165a7c30e62SVinod Koul 		ethqos->rgmii_clk_rate =  RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ;
166a7c30e62SVinod Koul 		break;
167a7c30e62SVinod Koul 
168a7c30e62SVinod Koul 	case SPEED_10:
169a7c30e62SVinod Koul 		ethqos->rgmii_clk_rate =  RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ;
170a7c30e62SVinod Koul 		break;
171a7c30e62SVinod Koul 	}
172a7c30e62SVinod Koul 
173a7c30e62SVinod Koul 	clk_set_rate(ethqos->rgmii_clk, ethqos->rgmii_clk_rate);
174a7c30e62SVinod Koul }
175a7c30e62SVinod Koul 
176a7c30e62SVinod Koul static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos)
177a7c30e62SVinod Koul {
178a7c30e62SVinod Koul 	rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN,
179a7c30e62SVinod Koul 		      RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG);
180a7c30e62SVinod Koul }
181a7c30e62SVinod Koul 
182a7c30e62SVinod Koul static const struct ethqos_emac_por emac_v2_3_0_por[] = {
183a7c30e62SVinod Koul 	{ .offset = RGMII_IO_MACRO_CONFIG,	.value = 0x00C01343 },
184a7c30e62SVinod Koul 	{ .offset = SDCC_HC_REG_DLL_CONFIG,	.value = 0x2004642C },
185a7c30e62SVinod Koul 	{ .offset = SDCC_HC_REG_DDR_CONFIG,	.value = 0x00000000 },
186a7c30e62SVinod Koul 	{ .offset = SDCC_HC_REG_DLL_CONFIG2,	.value = 0x00200000 },
187a7c30e62SVinod Koul 	{ .offset = SDCC_USR_CTL,		.value = 0x00010800 },
188a7c30e62SVinod Koul 	{ .offset = RGMII_IO_MACRO_CONFIG2,	.value = 0x00002060 },
189a7c30e62SVinod Koul };
190a7c30e62SVinod Koul 
191fd4a5177SVinod Koul static const struct ethqos_emac_driver_data emac_v2_3_0_data = {
192fd4a5177SVinod Koul 	.por = emac_v2_3_0_por,
193fd4a5177SVinod Koul 	.num_por = ARRAY_SIZE(emac_v2_3_0_por),
194030f1d59SAndrew Halaney 	.rgmii_config_loopback_en = true,
195b6837619SAndrew Halaney 	.has_emac3 = false,
196fd4a5177SVinod Koul };
197fd4a5177SVinod Koul 
198d90b3120SVinod Koul static const struct ethqos_emac_por emac_v2_1_0_por[] = {
199d90b3120SVinod Koul 	{ .offset = RGMII_IO_MACRO_CONFIG,	.value = 0x40C01343 },
200d90b3120SVinod Koul 	{ .offset = SDCC_HC_REG_DLL_CONFIG,	.value = 0x2004642C },
201d90b3120SVinod Koul 	{ .offset = SDCC_HC_REG_DDR_CONFIG,	.value = 0x00000000 },
202d90b3120SVinod Koul 	{ .offset = SDCC_HC_REG_DLL_CONFIG2,	.value = 0x00200000 },
203d90b3120SVinod Koul 	{ .offset = SDCC_USR_CTL,		.value = 0x00010800 },
204d90b3120SVinod Koul 	{ .offset = RGMII_IO_MACRO_CONFIG2,	.value = 0x00002060 },
205d90b3120SVinod Koul };
206d90b3120SVinod Koul 
207d90b3120SVinod Koul static const struct ethqos_emac_driver_data emac_v2_1_0_data = {
208d90b3120SVinod Koul 	.por = emac_v2_1_0_por,
209d90b3120SVinod Koul 	.num_por = ARRAY_SIZE(emac_v2_1_0_por),
210030f1d59SAndrew Halaney 	.rgmii_config_loopback_en = false,
211b6837619SAndrew Halaney 	.has_emac3 = false,
212b6837619SAndrew Halaney };
213b6837619SAndrew Halaney 
214b6837619SAndrew Halaney static const struct ethqos_emac_por emac_v3_0_0_por[] = {
215b6837619SAndrew Halaney 	{ .offset = RGMII_IO_MACRO_CONFIG,	.value = 0x40c01343 },
216b6837619SAndrew Halaney 	{ .offset = SDCC_HC_REG_DLL_CONFIG,	.value = 0x2004642c },
217b6837619SAndrew Halaney 	{ .offset = SDCC_HC_REG_DDR_CONFIG,	.value = 0x80040800 },
218b6837619SAndrew Halaney 	{ .offset = SDCC_HC_REG_DLL_CONFIG2,	.value = 0x00200000 },
219b6837619SAndrew Halaney 	{ .offset = SDCC_USR_CTL,		.value = 0x00010800 },
220b6837619SAndrew Halaney 	{ .offset = RGMII_IO_MACRO_CONFIG2,	.value = 0x00002060 },
221b6837619SAndrew Halaney };
222b6837619SAndrew Halaney 
223b6837619SAndrew Halaney static const struct ethqos_emac_driver_data emac_v3_0_0_data = {
224b6837619SAndrew Halaney 	.por = emac_v3_0_0_por,
225b6837619SAndrew Halaney 	.num_por = ARRAY_SIZE(emac_v3_0_0_por),
226b6837619SAndrew Halaney 	.rgmii_config_loopback_en = false,
227b6837619SAndrew Halaney 	.has_emac3 = true,
228b6837619SAndrew Halaney 	.dwmac4_addrs = {
229b6837619SAndrew Halaney 		.dma_chan = 0x00008100,
230b6837619SAndrew Halaney 		.dma_chan_offset = 0x1000,
231b6837619SAndrew Halaney 		.mtl_chan = 0x00008000,
232b6837619SAndrew Halaney 		.mtl_chan_offset = 0x1000,
233b6837619SAndrew Halaney 		.mtl_ets_ctrl = 0x00008010,
234b6837619SAndrew Halaney 		.mtl_ets_ctrl_offset = 0x1000,
235b6837619SAndrew Halaney 		.mtl_txq_weight = 0x00008018,
236b6837619SAndrew Halaney 		.mtl_txq_weight_offset = 0x1000,
237b6837619SAndrew Halaney 		.mtl_send_slp_cred = 0x0000801c,
238b6837619SAndrew Halaney 		.mtl_send_slp_cred_offset = 0x1000,
239b6837619SAndrew Halaney 		.mtl_high_cred = 0x00008020,
240b6837619SAndrew Halaney 		.mtl_high_cred_offset = 0x1000,
241b6837619SAndrew Halaney 		.mtl_low_cred = 0x00008024,
242b6837619SAndrew Halaney 		.mtl_low_cred_offset = 0x1000,
243b6837619SAndrew Halaney 	},
244d90b3120SVinod Koul };
245d90b3120SVinod Koul 
246a7c30e62SVinod Koul static int ethqos_dll_configure(struct qcom_ethqos *ethqos)
247a7c30e62SVinod Koul {
248302555a0SBartosz Golaszewski 	struct device *dev = &ethqos->pdev->dev;
249a7c30e62SVinod Koul 	unsigned int val;
250a7c30e62SVinod Koul 	int retry = 1000;
251a7c30e62SVinod Koul 
252a7c30e62SVinod Koul 	/* Set CDR_EN */
253a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN,
254a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG);
255a7c30e62SVinod Koul 
256a7c30e62SVinod Koul 	/* Set CDR_EXT_EN */
257a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN,
258a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG);
259a7c30e62SVinod Koul 
260a7c30e62SVinod Koul 	/* Clear CK_OUT_EN */
261a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN,
262a7c30e62SVinod Koul 		      0, SDCC_HC_REG_DLL_CONFIG);
263a7c30e62SVinod Koul 
264a7c30e62SVinod Koul 	/* Set DLL_EN */
265a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN,
266a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG);
267a7c30e62SVinod Koul 
268b6837619SAndrew Halaney 	if (!ethqos->has_emac3) {
269a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN,
270a7c30e62SVinod Koul 			      0, SDCC_HC_REG_DLL_CONFIG);
271a7c30e62SVinod Koul 
272a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE,
273a7c30e62SVinod Koul 			      0, SDCC_HC_REG_DLL_CONFIG);
274b6837619SAndrew Halaney 	}
275a7c30e62SVinod Koul 
276a7c30e62SVinod Koul 	/* Wait for CK_OUT_EN clear */
277a7c30e62SVinod Koul 	do {
278a7c30e62SVinod Koul 		val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG);
279a7c30e62SVinod Koul 		val &= SDCC_DLL_CONFIG_CK_OUT_EN;
280a7c30e62SVinod Koul 		if (!val)
281a7c30e62SVinod Koul 			break;
282a7c30e62SVinod Koul 		mdelay(1);
283a7c30e62SVinod Koul 		retry--;
284a7c30e62SVinod Koul 	} while (retry > 0);
285a7c30e62SVinod Koul 	if (!retry)
286302555a0SBartosz Golaszewski 		dev_err(dev, "Clear CK_OUT_EN timedout\n");
287a7c30e62SVinod Koul 
288a7c30e62SVinod Koul 	/* Set CK_OUT_EN */
289a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN,
290a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG);
291a7c30e62SVinod Koul 
292a7c30e62SVinod Koul 	/* Wait for CK_OUT_EN set */
293a7c30e62SVinod Koul 	retry = 1000;
294a7c30e62SVinod Koul 	do {
295a7c30e62SVinod Koul 		val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG);
296a7c30e62SVinod Koul 		val &= SDCC_DLL_CONFIG_CK_OUT_EN;
297a7c30e62SVinod Koul 		if (val)
298a7c30e62SVinod Koul 			break;
299a7c30e62SVinod Koul 		mdelay(1);
300a7c30e62SVinod Koul 		retry--;
301a7c30e62SVinod Koul 	} while (retry > 0);
302a7c30e62SVinod Koul 	if (!retry)
303302555a0SBartosz Golaszewski 		dev_err(dev, "Set CK_OUT_EN timedout\n");
304a7c30e62SVinod Koul 
305a7c30e62SVinod Koul 	/* Set DDR_CAL_EN */
306a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN,
307a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2);
308a7c30e62SVinod Koul 
309b6837619SAndrew Halaney 	if (!ethqos->has_emac3) {
310a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS,
311a7c30e62SVinod Koul 			      0, SDCC_HC_REG_DLL_CONFIG2);
312a7c30e62SVinod Koul 
313a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC,
314a7c30e62SVinod Koul 			      0x1A << 10, SDCC_HC_REG_DLL_CONFIG2);
315a7c30e62SVinod Koul 
316a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL,
317a7c30e62SVinod Koul 			      BIT(2), SDCC_HC_REG_DLL_CONFIG2);
318a7c30e62SVinod Koul 
319a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW,
320a7c30e62SVinod Koul 			      SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW,
321a7c30e62SVinod Koul 			      SDCC_HC_REG_DLL_CONFIG2);
322b6837619SAndrew Halaney 	}
323a7c30e62SVinod Koul 
324a7c30e62SVinod Koul 	return 0;
325a7c30e62SVinod Koul }
326a7c30e62SVinod Koul 
327a7c30e62SVinod Koul static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos)
328a7c30e62SVinod Koul {
329302555a0SBartosz Golaszewski 	struct device *dev = &ethqos->pdev->dev;
330164a9ebeSAndrew Halaney 	int phase_shift;
331164a9ebeSAndrew Halaney 	int phy_mode;
332030f1d59SAndrew Halaney 	int loopback;
333164a9ebeSAndrew Halaney 
334164a9ebeSAndrew Halaney 	/* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */
335302555a0SBartosz Golaszewski 	phy_mode = device_get_phy_mode(dev);
336164a9ebeSAndrew Halaney 	if (phy_mode == PHY_INTERFACE_MODE_RGMII_ID ||
337164a9ebeSAndrew Halaney 	    phy_mode == PHY_INTERFACE_MODE_RGMII_TXID)
338164a9ebeSAndrew Halaney 		phase_shift = 0;
339164a9ebeSAndrew Halaney 	else
340164a9ebeSAndrew Halaney 		phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN;
341164a9ebeSAndrew Halaney 
342a7c30e62SVinod Koul 	/* Disable loopback mode */
343a7c30e62SVinod Koul 	rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN,
344a7c30e62SVinod Koul 		      0, RGMII_IO_MACRO_CONFIG2);
345a7c30e62SVinod Koul 
346030f1d59SAndrew Halaney 	/* Determine if this platform wants loopback enabled after programming */
347030f1d59SAndrew Halaney 	if (ethqos->rgmii_config_loopback_en)
348030f1d59SAndrew Halaney 		loopback = RGMII_CONFIG_LOOPBACK_EN;
349030f1d59SAndrew Halaney 	else
350030f1d59SAndrew Halaney 		loopback = 0;
351030f1d59SAndrew Halaney 
352a7c30e62SVinod Koul 	/* Select RGMII, write 0 to interface select */
353a7c30e62SVinod Koul 	rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL,
354a7c30e62SVinod Koul 		      0, RGMII_IO_MACRO_CONFIG);
355a7c30e62SVinod Koul 
356a7c30e62SVinod Koul 	switch (ethqos->speed) {
357a7c30e62SVinod Koul 	case SPEED_1000:
358a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE,
359a7c30e62SVinod Koul 			      RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG);
360a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN,
361a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG);
362a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL,
363a7c30e62SVinod Koul 			      RGMII_CONFIG_POS_NEG_DATA_SEL,
364a7c30e62SVinod Koul 			      RGMII_IO_MACRO_CONFIG);
365a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP,
366a7c30e62SVinod Koul 			      RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG);
367a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL,
368a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
369164a9ebeSAndrew Halaney 
370a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN,
371164a9ebeSAndrew Halaney 			      phase_shift, RGMII_IO_MACRO_CONFIG2);
372a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15,
373a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
374a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP,
375a7c30e62SVinod Koul 			      RGMII_CONFIG2_RX_PROG_SWAP,
376a7c30e62SVinod Koul 			      RGMII_IO_MACRO_CONFIG2);
377a7c30e62SVinod Koul 
378b6837619SAndrew Halaney 		/* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns,
379b6837619SAndrew Halaney 		 * in practice this becomes PRG_RCLK_DLY = 52 * 4 / 2 * RX delay ns
380b6837619SAndrew Halaney 		 */
381b6837619SAndrew Halaney 		if (ethqos->has_emac3) {
382b6837619SAndrew Halaney 			/* 0.9 ns */
383b6837619SAndrew Halaney 			rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY,
384b6837619SAndrew Halaney 				      115, SDCC_HC_REG_DDR_CONFIG);
385b6837619SAndrew Halaney 		} else {
386b6837619SAndrew Halaney 			/* 1.8 ns */
387a7c30e62SVinod Koul 			rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY,
388a7c30e62SVinod Koul 				      57, SDCC_HC_REG_DDR_CONFIG);
389b6837619SAndrew Halaney 		}
390a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN,
391a7c30e62SVinod Koul 			      SDCC_DDR_CONFIG_PRG_DLY_EN,
392a7c30e62SVinod Koul 			      SDCC_HC_REG_DDR_CONFIG);
393a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN,
394030f1d59SAndrew Halaney 			      loopback, RGMII_IO_MACRO_CONFIG);
395a7c30e62SVinod Koul 		break;
396a7c30e62SVinod Koul 
397a7c30e62SVinod Koul 	case SPEED_100:
398a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE,
399a7c30e62SVinod Koul 			      RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG);
400a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN,
401a7c30e62SVinod Koul 			      RGMII_CONFIG_BYPASS_TX_ID_EN,
402a7c30e62SVinod Koul 			      RGMII_IO_MACRO_CONFIG);
403a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL,
404a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG);
405a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP,
406a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG);
407a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL,
408a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
409a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN,
410164a9ebeSAndrew Halaney 			      phase_shift, RGMII_IO_MACRO_CONFIG2);
411a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2,
412a7c30e62SVinod Koul 			      BIT(6), RGMII_IO_MACRO_CONFIG);
413a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15,
414a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
415b6837619SAndrew Halaney 
416b6837619SAndrew Halaney 		if (ethqos->has_emac3)
417b6837619SAndrew Halaney 			rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP,
418b6837619SAndrew Halaney 				      RGMII_CONFIG2_RX_PROG_SWAP,
419b6837619SAndrew Halaney 				      RGMII_IO_MACRO_CONFIG2);
420b6837619SAndrew Halaney 		else
421a7c30e62SVinod Koul 			rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP,
422a7c30e62SVinod Koul 				      0, RGMII_IO_MACRO_CONFIG2);
423b6837619SAndrew Halaney 
424a7c30e62SVinod Koul 		/* Write 0x5 to PRG_RCLK_DLY_CODE */
425a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
426a7c30e62SVinod Koul 			      (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG);
427a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY,
428a7c30e62SVinod Koul 			      SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY,
429a7c30e62SVinod Koul 			      SDCC_HC_REG_DDR_CONFIG);
430a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN,
431a7c30e62SVinod Koul 			      SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN,
432a7c30e62SVinod Koul 			      SDCC_HC_REG_DDR_CONFIG);
433a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN,
434030f1d59SAndrew Halaney 			      loopback, RGMII_IO_MACRO_CONFIG);
435a7c30e62SVinod Koul 		break;
436a7c30e62SVinod Koul 
437a7c30e62SVinod Koul 	case SPEED_10:
438a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE,
439a7c30e62SVinod Koul 			      RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG);
440a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN,
441a7c30e62SVinod Koul 			      RGMII_CONFIG_BYPASS_TX_ID_EN,
442a7c30e62SVinod Koul 			      RGMII_IO_MACRO_CONFIG);
443a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL,
444a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG);
445a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP,
446a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG);
447a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL,
448a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
449a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN,
450164a9ebeSAndrew Halaney 			      phase_shift, RGMII_IO_MACRO_CONFIG2);
451a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9,
452a7c30e62SVinod Koul 			      BIT(12) | GENMASK(9, 8),
453a7c30e62SVinod Koul 			      RGMII_IO_MACRO_CONFIG);
454a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15,
455a7c30e62SVinod Koul 			      0, RGMII_IO_MACRO_CONFIG2);
456b6837619SAndrew Halaney 		if (ethqos->has_emac3)
457b6837619SAndrew Halaney 			rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP,
458b6837619SAndrew Halaney 				      RGMII_CONFIG2_RX_PROG_SWAP,
459b6837619SAndrew Halaney 				      RGMII_IO_MACRO_CONFIG2);
460b6837619SAndrew Halaney 		else
461a7c30e62SVinod Koul 			rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP,
462a7c30e62SVinod Koul 				      0, RGMII_IO_MACRO_CONFIG2);
463a7c30e62SVinod Koul 		/* Write 0x5 to PRG_RCLK_DLY_CODE */
464a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
465a7c30e62SVinod Koul 			      (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG);
466a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY,
467a7c30e62SVinod Koul 			      SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY,
468a7c30e62SVinod Koul 			      SDCC_HC_REG_DDR_CONFIG);
469a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN,
470a7c30e62SVinod Koul 			      SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN,
471a7c30e62SVinod Koul 			      SDCC_HC_REG_DDR_CONFIG);
472a7c30e62SVinod Koul 		rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN,
473030f1d59SAndrew Halaney 			      loopback, RGMII_IO_MACRO_CONFIG);
474a7c30e62SVinod Koul 		break;
475a7c30e62SVinod Koul 	default:
476302555a0SBartosz Golaszewski 		dev_err(dev, "Invalid speed %d\n", ethqos->speed);
477a7c30e62SVinod Koul 		return -EINVAL;
478a7c30e62SVinod Koul 	}
479a7c30e62SVinod Koul 
480a7c30e62SVinod Koul 	return 0;
481a7c30e62SVinod Koul }
482a7c30e62SVinod Koul 
483a7c30e62SVinod Koul static int ethqos_configure(struct qcom_ethqos *ethqos)
484a7c30e62SVinod Koul {
485302555a0SBartosz Golaszewski 	struct device *dev = &ethqos->pdev->dev;
486a7c30e62SVinod Koul 	volatile unsigned int dll_lock;
487a7c30e62SVinod Koul 	unsigned int i, retry = 1000;
488a7c30e62SVinod Koul 
489a7c30e62SVinod Koul 	/* Reset to POR values and enable clk */
490a7c30e62SVinod Koul 	for (i = 0; i < ethqos->num_por; i++)
491a7c30e62SVinod Koul 		rgmii_writel(ethqos, ethqos->por[i].value,
492a7c30e62SVinod Koul 			     ethqos->por[i].offset);
493a7c30e62SVinod Koul 	ethqos_set_func_clk_en(ethqos);
494a7c30e62SVinod Koul 
495a7c30e62SVinod Koul 	/* Initialize the DLL first */
496a7c30e62SVinod Koul 
497a7c30e62SVinod Koul 	/* Set DLL_RST */
498a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST,
499a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG);
500a7c30e62SVinod Koul 
501a7c30e62SVinod Koul 	/* Set PDN */
502a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN,
503a7c30e62SVinod Koul 		      SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG);
504a7c30e62SVinod Koul 
505b6837619SAndrew Halaney 	if (ethqos->has_emac3) {
506b6837619SAndrew Halaney 		if (ethqos->speed == SPEED_1000) {
507b6837619SAndrew Halaney 			rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL);
508b6837619SAndrew Halaney 			rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL);
509b6837619SAndrew Halaney 			rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2);
510b6837619SAndrew Halaney 		} else {
511b6837619SAndrew Halaney 			rgmii_writel(ethqos, 0x40010800, SDCC_USR_CTL);
512b6837619SAndrew Halaney 			rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2);
513b6837619SAndrew Halaney 		}
514b6837619SAndrew Halaney 	}
515b6837619SAndrew Halaney 
516a7c30e62SVinod Koul 	/* Clear DLL_RST */
517a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0,
518a7c30e62SVinod Koul 		      SDCC_HC_REG_DLL_CONFIG);
519a7c30e62SVinod Koul 
520a7c30e62SVinod Koul 	/* Clear PDN */
521a7c30e62SVinod Koul 	rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0,
522a7c30e62SVinod Koul 		      SDCC_HC_REG_DLL_CONFIG);
523a7c30e62SVinod Koul 
524a7c30e62SVinod Koul 	if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) {
525a7c30e62SVinod Koul 		/* Set DLL_EN */
526a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN,
527a7c30e62SVinod Koul 			      SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG);
528a7c30e62SVinod Koul 
529a7c30e62SVinod Koul 		/* Set CK_OUT_EN */
530a7c30e62SVinod Koul 		rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN,
531a7c30e62SVinod Koul 			      SDCC_DLL_CONFIG_CK_OUT_EN,
532a7c30e62SVinod Koul 			      SDCC_HC_REG_DLL_CONFIG);
533a7c30e62SVinod Koul 
534a7c30e62SVinod Koul 		/* Set USR_CTL bit 26 with mask of 3 bits */
535b6837619SAndrew Halaney 		if (!ethqos->has_emac3)
536b6837619SAndrew Halaney 			rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26),
537b6837619SAndrew Halaney 				      SDCC_USR_CTL);
538a7c30e62SVinod Koul 
539a7c30e62SVinod Koul 		/* wait for DLL LOCK */
540a7c30e62SVinod Koul 		do {
541a7c30e62SVinod Koul 			mdelay(1);
542a7c30e62SVinod Koul 			dll_lock = rgmii_readl(ethqos, SDC4_STATUS);
543a7c30e62SVinod Koul 			if (dll_lock & SDC4_STATUS_DLL_LOCK)
544a7c30e62SVinod Koul 				break;
5457d10f077SDejin Zheng 			retry--;
546a7c30e62SVinod Koul 		} while (retry > 0);
547a7c30e62SVinod Koul 		if (!retry)
548302555a0SBartosz Golaszewski 			dev_err(dev, "Timeout while waiting for DLL lock\n");
549a7c30e62SVinod Koul 	}
550a7c30e62SVinod Koul 
551a7c30e62SVinod Koul 	if (ethqos->speed == SPEED_1000)
552a7c30e62SVinod Koul 		ethqos_dll_configure(ethqos);
553a7c30e62SVinod Koul 
554a7c30e62SVinod Koul 	ethqos_rgmii_macro_init(ethqos);
555a7c30e62SVinod Koul 
556a7c30e62SVinod Koul 	return 0;
557a7c30e62SVinod Koul }
558a7c30e62SVinod Koul 
559a7c30e62SVinod Koul static void ethqos_fix_mac_speed(void *priv, unsigned int speed)
560a7c30e62SVinod Koul {
561a7c30e62SVinod Koul 	struct qcom_ethqos *ethqos = priv;
562a7c30e62SVinod Koul 
563a7c30e62SVinod Koul 	ethqos->speed = speed;
564a7c30e62SVinod Koul 	ethqos_update_rgmii_clk(ethqos, speed);
565a7c30e62SVinod Koul 	ethqos_configure(ethqos);
566a7c30e62SVinod Koul }
567a7c30e62SVinod Koul 
5686c950ca7SBhupesh Sharma static int ethqos_clks_config(void *priv, bool enabled)
5696c950ca7SBhupesh Sharma {
5706c950ca7SBhupesh Sharma 	struct qcom_ethqos *ethqos = priv;
5716c950ca7SBhupesh Sharma 	int ret = 0;
5726c950ca7SBhupesh Sharma 
5736c950ca7SBhupesh Sharma 	if (enabled) {
5746c950ca7SBhupesh Sharma 		ret = clk_prepare_enable(ethqos->rgmii_clk);
5756c950ca7SBhupesh Sharma 		if (ret) {
5766c950ca7SBhupesh Sharma 			dev_err(&ethqos->pdev->dev, "rgmii_clk enable failed\n");
5776c950ca7SBhupesh Sharma 			return ret;
5786c950ca7SBhupesh Sharma 		}
579ffba2123SBjorn Andersson 
580ffba2123SBjorn Andersson 		/* Enable functional clock to prevent DMA reset to timeout due
581ffba2123SBjorn Andersson 		 * to lacking PHY clock after the hardware block has been power
582ffba2123SBjorn Andersson 		 * cycled. The actual configuration will be adjusted once
583ffba2123SBjorn Andersson 		 * ethqos_fix_mac_speed() is invoked.
584ffba2123SBjorn Andersson 		 */
585ffba2123SBjorn Andersson 		ethqos_set_func_clk_en(ethqos);
5866c950ca7SBhupesh Sharma 	} else {
5876c950ca7SBhupesh Sharma 		clk_disable_unprepare(ethqos->rgmii_clk);
5886c950ca7SBhupesh Sharma 	}
5896c950ca7SBhupesh Sharma 
5906c950ca7SBhupesh Sharma 	return ret;
5916c950ca7SBhupesh Sharma }
5926c950ca7SBhupesh Sharma 
5939fc68f23SBartosz Golaszewski static void ethqos_clks_disable(void *data)
5949fc68f23SBartosz Golaszewski {
5959fc68f23SBartosz Golaszewski 	ethqos_clks_config(data, false);
5969fc68f23SBartosz Golaszewski }
5979fc68f23SBartosz Golaszewski 
598a7c30e62SVinod Koul static int qcom_ethqos_probe(struct platform_device *pdev)
599a7c30e62SVinod Koul {
600a7c30e62SVinod Koul 	struct device_node *np = pdev->dev.of_node;
6017b5e64a9SBartosz Golaszewski 	const struct ethqos_emac_driver_data *data;
602a7c30e62SVinod Koul 	struct plat_stmmacenet_data *plat_dat;
603a7c30e62SVinod Koul 	struct stmmac_resources stmmac_res;
604302555a0SBartosz Golaszewski 	struct device *dev = &pdev->dev;
605a7c30e62SVinod Koul 	struct qcom_ethqos *ethqos;
606a7c30e62SVinod Koul 	int ret;
607a7c30e62SVinod Koul 
608a7c30e62SVinod Koul 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
609a7c30e62SVinod Koul 	if (ret)
610a7c30e62SVinod Koul 		return ret;
611a7c30e62SVinod Koul 
61283216e39SMichael Walle 	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
613a7c30e62SVinod Koul 	if (IS_ERR(plat_dat)) {
614302555a0SBartosz Golaszewski 		dev_err(dev, "dt configuration failed\n");
615a7c30e62SVinod Koul 		return PTR_ERR(plat_dat);
616a7c30e62SVinod Koul 	}
617a7c30e62SVinod Koul 
6186c950ca7SBhupesh Sharma 	plat_dat->clks_config = ethqos_clks_config;
6196c950ca7SBhupesh Sharma 
620302555a0SBartosz Golaszewski 	ethqos = devm_kzalloc(dev, sizeof(*ethqos), GFP_KERNEL);
621a7c30e62SVinod Koul 	if (!ethqos) {
622a7c30e62SVinod Koul 		ret = -ENOMEM;
6239bc58060SBartosz Golaszewski 		goto out_config_dt;
624a7c30e62SVinod Koul 	}
625a7c30e62SVinod Koul 
626a7c30e62SVinod Koul 	ethqos->pdev = pdev;
6273a5a32b5SYang Yingliang 	ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii");
628a7c30e62SVinod Koul 	if (IS_ERR(ethqos->rgmii_base)) {
629a7c30e62SVinod Koul 		ret = PTR_ERR(ethqos->rgmii_base);
6309bc58060SBartosz Golaszewski 		goto out_config_dt;
631a7c30e62SVinod Koul 	}
632a7c30e62SVinod Koul 
633302555a0SBartosz Golaszewski 	data = of_device_get_match_data(dev);
634fd4a5177SVinod Koul 	ethqos->por = data->por;
635fd4a5177SVinod Koul 	ethqos->num_por = data->num_por;
636030f1d59SAndrew Halaney 	ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en;
637b6837619SAndrew Halaney 	ethqos->has_emac3 = data->has_emac3;
638a7c30e62SVinod Koul 
639302555a0SBartosz Golaszewski 	ethqos->rgmii_clk = devm_clk_get(dev, "rgmii");
6408f4ebaaaSWei Yongjun 	if (IS_ERR(ethqos->rgmii_clk)) {
6418f4ebaaaSWei Yongjun 		ret = PTR_ERR(ethqos->rgmii_clk);
6429bc58060SBartosz Golaszewski 		goto out_config_dt;
643a7c30e62SVinod Koul 	}
644a7c30e62SVinod Koul 
6456c950ca7SBhupesh Sharma 	ret = ethqos_clks_config(ethqos, true);
646a7c30e62SVinod Koul 	if (ret)
6479bc58060SBartosz Golaszewski 		goto out_config_dt;
648a7c30e62SVinod Koul 
649302555a0SBartosz Golaszewski 	ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos);
6509fc68f23SBartosz Golaszewski 	if (ret)
6519bc58060SBartosz Golaszewski 		goto out_config_dt;
6529fc68f23SBartosz Golaszewski 
653a7c30e62SVinod Koul 	ethqos->speed = SPEED_1000;
654a7c30e62SVinod Koul 	ethqos_update_rgmii_clk(ethqos, SPEED_1000);
655a7c30e62SVinod Koul 	ethqos_set_func_clk_en(ethqos);
656a7c30e62SVinod Koul 
657a7c30e62SVinod Koul 	plat_dat->bsp_priv = ethqos;
658a7c30e62SVinod Koul 	plat_dat->fix_mac_speed = ethqos_fix_mac_speed;
6594047b9dbSBhupesh Sharma 	plat_dat->dump_debug_regs = rgmii_dump;
660a7c30e62SVinod Koul 	plat_dat->has_gmac4 = 1;
6619bc00973SBartosz Golaszewski 	if (ethqos->has_emac3)
662b6837619SAndrew Halaney 		plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
663a7c30e62SVinod Koul 	plat_dat->pmt = 1;
664a7c30e62SVinod Koul 	plat_dat->tso_en = of_property_read_bool(np, "snps,tso");
66554aa39a5SAndrey Konovalov 	if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
66654aa39a5SAndrey Konovalov 		plat_dat->rx_clk_runs_in_lpi = 1;
667a7c30e62SVinod Koul 
668302555a0SBartosz Golaszewski 	ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res);
669a7c30e62SVinod Koul 	if (ret)
6709bc58060SBartosz Golaszewski 		goto out_config_dt;
671a7c30e62SVinod Koul 
672a7c30e62SVinod Koul 	return ret;
673a7c30e62SVinod Koul 
6749bc58060SBartosz Golaszewski out_config_dt:
675a7c30e62SVinod Koul 	stmmac_remove_config_dt(pdev, plat_dat);
676a7c30e62SVinod Koul 
677a7c30e62SVinod Koul 	return ret;
678a7c30e62SVinod Koul }
679a7c30e62SVinod Koul 
680a7c30e62SVinod Koul static const struct of_device_id qcom_ethqos_match[] = {
681fd4a5177SVinod Koul 	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data},
682b6837619SAndrew Halaney 	{ .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data},
683d90b3120SVinod Koul 	{ .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data},
684a7c30e62SVinod Koul 	{ }
685a7c30e62SVinod Koul };
686a7c30e62SVinod Koul MODULE_DEVICE_TABLE(of, qcom_ethqos_match);
687a7c30e62SVinod Koul 
688a7c30e62SVinod Koul static struct platform_driver qcom_ethqos_driver = {
689a7c30e62SVinod Koul 	.probe  = qcom_ethqos_probe,
6909fc68f23SBartosz Golaszewski 	.remove_new = stmmac_pltfr_remove,
691a7c30e62SVinod Koul 	.driver = {
692a7c30e62SVinod Koul 		.name           = "qcom-ethqos",
693a7c30e62SVinod Koul 		.pm		= &stmmac_pltfr_pm_ops,
694dc54e450SKrzysztof Kozlowski 		.of_match_table = qcom_ethqos_match,
695a7c30e62SVinod Koul 	},
696a7c30e62SVinod Koul };
697a7c30e62SVinod Koul module_platform_driver(qcom_ethqos_driver);
698a7c30e62SVinod Koul 
699a7c30e62SVinod Koul MODULE_DESCRIPTION("Qualcomm ETHQOS driver");
700a7c30e62SVinod Koul MODULE_LICENSE("GPL v2");
701