File Index
Files and directories
Sign in
FILE

phy-qcom-sgmii-eth.c

File preview with syntax highlighting.

linux-6.19.14/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c C
  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
 28struct qcom_dwmac_sgmii_phy_data {
 29	struct regmap *regmap;
 30	struct clk *refclk;
 31	int speed;
 32};
 33
 34static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap)
 35{
 36	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01);
 37	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01);
 38
 39	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F);
 40	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06);
 41	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16);
 42	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36);
 43	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A);
 44	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0A);
 45	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1A);
 46	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x82);
 47	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55);
 48	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55);
 49	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03);
 50	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0x24);
 51
 52	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02);
 53	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00);
 54	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x04);
 55	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00);
 56	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0A);
 57	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00);
 58	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9);
 59	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E);
 60	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11);
 61
 62	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x05);
 63	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A);
 64	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09);
 65	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x09);
 66	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05);
 67	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00);
 68	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12);
 69	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C);
 70
 71	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A);
 72	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06);
 73	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A);
 74	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F);
 75	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00);
 76	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01);
 77	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81);
 78	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80);
 79	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x04);
 80	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08);
 81	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F);
 82	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04);
 83	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00);
 84	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A);
 85	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A);
 86	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80);
 87	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01);
 88	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20);
 89	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17);
 90	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00);
 91	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F);
 92	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E);
 93	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x05);
 94	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0xE0);
 95	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8);
 96	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8);
 97	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x09);
 98	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB1);
 99	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0);
100	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8);
101	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8);
102	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09);
103	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1);
104	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0);
105	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8);
106	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8);
107	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B);
108	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7);
109	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C);
110
111	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C);
112	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F);
113	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03);
114	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83);
115	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08);
116	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x0C);
117	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00);
118
119	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01);
120}
121
122static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap)
123{
124	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01);
125	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01);
126
127	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F);
128	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06);
129	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16);
130	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36);
131	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A);
132	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x1A);
133	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x41);
134	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x7A);
135	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x00);
136	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x20);
137	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x01);
138	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0xA1);
139
140	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02);
141	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00);
142	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x03);
143	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00);
144	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x05);
145	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00);
146	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD);
147	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C);
148	regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11);
149
150	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x04);
151	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A);
152	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09);
153	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x02);
154	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05);
155	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00);
156	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12);
157	regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C);
158
159	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A);
160	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06);
161	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A);
162	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F);
163	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00);
164	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01);
165	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81);
166	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80);
167	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x00);
168	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08);
169	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F);
170	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04);
171	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00);
172	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A);
173	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A);
174	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80);
175	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01);
176	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20);
177	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17);
178	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00);
179	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F);
180	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E);
181	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x18);
182	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0x18);
183	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8);
184	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8);
185	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x0C);
186	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB8);
187	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0);
188	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8);
189	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8);
190	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09);
191	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1);
192	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0);
193	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8);
194	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8);
195	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B);
196	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7);
197	regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C);
198
199	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C);
200	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F);
201	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03);
202	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83);
203	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08);
204	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x8C);
205	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00);
206
207	regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01);
208}
209
210static inline int
211qcom_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
220static 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(data->regmap);
230		break;
231	case SPEED_2500:
232		qcom_dwmac_sgmii_phy_init_2p5g(data->regmap);
233		break;
234	}
235
236	if (qcom_dwmac_sgmii_phy_poll_status(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(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(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(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
267static 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(data->refclk);
272}
273
274static 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(data->regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08);
279	regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01);
280	udelay(100);
281	regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00);
282	regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01);
283
284	clk_disable_unprepare(data->refclk);
285
286	return 0;
287}
288
289static 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
299static 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
307static 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
315static 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, sizeof(*data), GFP_KERNEL);
324	if (!data)
325		return -ENOMEM;
326
327	data->speed = SPEED_10;
328
329	base = devm_platform_ioremap_resource(pdev, 0);
330	if (IS_ERR(base))
331		return PTR_ERR(base);
332
333	data->regmap = devm_regmap_init_mmio(dev, base,
334					     &qcom_dwmac_sgmii_phy_regmap_cfg);
335	if (IS_ERR(data->regmap))
336		return PTR_ERR(data->regmap);
337
338	phy = devm_phy_create(dev, NULL, &qcom_dwmac_sgmii_phy_ops);
339	if (IS_ERR(phy))
340		return PTR_ERR(phy);
341
342	data->refclk = devm_clk_get(dev, "sgmi_ref");
343	if (IS_ERR(data->refclk))
344		return PTR_ERR(data->refclk);
345
346	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
347	if (IS_ERR(provider))
348		return PTR_ERR(provider);
349
350	phy_set_drvdata(phy, data);
351
352	return 0;
353}
354
355static const struct of_device_id qcom_dwmac_sgmii_phy_of_match[] = {
356	{ .compatible = "qcom,sa8775p-dwmac-sgmii-phy" },
357	{ },
358};
359MODULE_DEVICE_TABLE(of, qcom_dwmac_sgmii_phy_of_match);
360
361static 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
369module_platform_driver(qcom_dwmac_sgmii_phy_driver);
370
371MODULE_DESCRIPTION("Qualcomm DWMAC SGMII PHY driver");
372MODULE_LICENSE("GPL");
~/ Read-only file preview.