1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Synopsys G210 Test Chip driver
4  *
5  * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
6  *
7  * Authors: Joao Pinto <jpinto@synopsys.com>
8  */
9 
10 #include <linux/module.h>
11 
12 #include <ufs/ufshcd.h>
13 #include <ufs/unipro.h>
14 
15 #include "ufshcd-dwc.h"
16 #include "ufshci-dwc.h"
17 #include "tc-dwc-g210.h"
18 
19 /**
20  * tc_dwc_g210_setup_40bit_rmmi()
21  * This function configures Synopsys TC specific atributes (40-bit RMMI)
22  * @hba: Pointer to drivers structure
23  *
24  * Returns 0 on success or non-zero value on failure
25  */
tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba * hba)26 static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba)
27 {
28 	static const struct ufshcd_dme_attr_val setup_attrs[] = {
29 		{ UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL },
30 		{ UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL },
31 		{ UIC_ARG_MIB(CDIRECTCTRL6), 0x80, DME_LOCAL },
32 		{ UIC_ARG_MIB(CBDIVFACTOR), 0x08, DME_LOCAL },
33 		{ UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL },
34 		{ UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL },
35 		{ UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL },
36 		{ UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01,
37 								DME_LOCAL },
38 		{ UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19,
39 								DME_LOCAL },
40 		{ UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x14,
41 								DME_LOCAL },
42 		{ UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
43 								DME_LOCAL },
44 		{ UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01,
45 								DME_LOCAL },
46 		{ UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19,
47 								DME_LOCAL },
48 		{ UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 4,
49 								DME_LOCAL },
50 		{ UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
51 								DME_LOCAL },
52 		{ UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL },
53 		{ UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL },
54 		{ UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
55 								DME_LOCAL },
56 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03,
57 								DME_LOCAL },
58 		{ UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16,
59 								DME_LOCAL },
60 		{ UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42,
61 								DME_LOCAL },
62 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4,
63 								DME_LOCAL },
64 		{ UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01,
65 								DME_LOCAL },
66 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01,
67 								DME_LOCAL },
68 		{ UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28,
69 								DME_LOCAL },
70 		{ UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E,
71 								DME_LOCAL },
72 		{ UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
73 								DME_LOCAL },
74 		{ UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
75 								DME_LOCAL },
76 		{ UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL },
77 	};
78 
79 	return ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
80 						ARRAY_SIZE(setup_attrs));
81 }
82 
83 /**
84  * tc_dwc_g210_setup_20bit_rmmi_lane0()
85  * This function configures Synopsys TC 20-bit RMMI Lane 0
86  * @hba: Pointer to drivers structure
87  *
88  * Returns 0 on success or non-zero value on failure
89  */
tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba * hba)90 static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba)
91 {
92 	static const struct ufshcd_dme_attr_val setup_attrs[] = {
93 		{ UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01,
94 								DME_LOCAL },
95 		{ UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19,
96 								DME_LOCAL },
97 		{ UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19,
98 								DME_LOCAL },
99 		{ UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x12,
100 								DME_LOCAL },
101 		{ UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
102 								DME_LOCAL },
103 		{ UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01,
104 								DME_LOCAL },
105 		{ UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 2,
106 								DME_LOCAL },
107 		{ UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
108 								DME_LOCAL },
109 		{ UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL },
110 		{ UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL },
111 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03,
112 								DME_LOCAL },
113 		{ UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16,
114 								DME_LOCAL },
115 		{ UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42,
116 								DME_LOCAL },
117 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4,
118 								DME_LOCAL },
119 		{ UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01,
120 								DME_LOCAL },
121 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01,
122 								DME_LOCAL },
123 		{ UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28,
124 								DME_LOCAL },
125 		{ UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E,
126 								DME_LOCAL },
127 		{ UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
128 								DME_LOCAL },
129 		{ UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL },
130 	};
131 
132 	return ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
133 						ARRAY_SIZE(setup_attrs));
134 }
135 
136 /**
137  * tc_dwc_g210_setup_20bit_rmmi_lane1()
138  * This function configures Synopsys TC 20-bit RMMI Lane 1
139  * @hba: Pointer to drivers structure
140  *
141  * Returns 0 on success or non-zero value on failure
142  */
tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba * hba)143 static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba)
144 {
145 	int connected_rx_lanes = 0;
146 	int connected_tx_lanes = 0;
147 	int ret = 0;
148 
149 	static const struct ufshcd_dme_attr_val setup_tx_attrs[] = {
150 		{ UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN1_TX), 0x0d,
151 								DME_LOCAL },
152 		{ UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN1_TX), 0x19,
153 								DME_LOCAL },
154 		{ UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN1_TX), 0x12,
155 								DME_LOCAL },
156 		{ UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
157 								DME_LOCAL },
158 	};
159 
160 	static const struct ufshcd_dme_attr_val setup_rx_attrs[] = {
161 		{ UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN1_RX), 0x01,
162 								DME_LOCAL },
163 		{ UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN1_RX), 0x19,
164 								DME_LOCAL },
165 		{ UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN1_RX), 2,
166 								DME_LOCAL },
167 		{ UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN1_RX), 0x80,
168 								DME_LOCAL },
169 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN1_RX), 0x03,
170 								DME_LOCAL },
171 		{ UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN1_RX), 0x16,
172 								DME_LOCAL },
173 		{ UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN1_RX), 0x42,
174 								DME_LOCAL },
175 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN1_RX), 0xa4,
176 								DME_LOCAL },
177 		{ UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN1_RX), 0x01,
178 								DME_LOCAL },
179 		{ UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN1_RX), 0x01,
180 								DME_LOCAL },
181 		{ UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN1_RX), 0x28,
182 								DME_LOCAL },
183 		{ UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN1_RX), 0x1E,
184 								DME_LOCAL },
185 		{ UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN1_RX), 0x2f,
186 								DME_LOCAL },
187 	};
188 
189 	/* Get the available lane count */
190 	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILRXDATALANES),
191 			&connected_rx_lanes);
192 	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES),
193 			&connected_tx_lanes);
194 
195 	if (connected_tx_lanes == 2) {
196 
197 		ret = ufshcd_dwc_dme_set_attrs(hba, setup_tx_attrs,
198 						ARRAY_SIZE(setup_tx_attrs));
199 
200 		if (ret)
201 			goto out;
202 	}
203 
204 	if (connected_rx_lanes == 2) {
205 		ret = ufshcd_dwc_dme_set_attrs(hba, setup_rx_attrs,
206 						ARRAY_SIZE(setup_rx_attrs));
207 	}
208 
209 out:
210 	return ret;
211 }
212 
213 /**
214  * tc_dwc_g210_setup_20bit_rmmi()
215  * This function configures Synopsys TC specific atributes (20-bit RMMI)
216  * @hba: Pointer to drivers structure
217  *
218  * Returns 0 on success or non-zero value on failure
219  */
tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba * hba)220 static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba)
221 {
222 	int ret = 0;
223 
224 	static const struct ufshcd_dme_attr_val setup_attrs[] = {
225 		{ UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL },
226 		{ UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL },
227 		{ UIC_ARG_MIB(CDIRECTCTRL6), 0xc0, DME_LOCAL },
228 		{ UIC_ARG_MIB(CBDIVFACTOR), 0x44, DME_LOCAL },
229 		{ UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL },
230 		{ UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL },
231 		{ UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL },
232 	};
233 
234 	ret = ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
235 						ARRAY_SIZE(setup_attrs));
236 	if (ret)
237 		goto out;
238 
239 	/* Lane 0 configuration*/
240 	ret = tc_dwc_g210_setup_20bit_rmmi_lane0(hba);
241 	if (ret)
242 		goto out;
243 
244 	/* Lane 1 configuration*/
245 	ret = tc_dwc_g210_setup_20bit_rmmi_lane1(hba);
246 	if (ret)
247 		goto out;
248 
249 out:
250 	return ret;
251 }
252 
253 /**
254  * tc_dwc_g210_config_40_bit()
255  * This function configures Local (host) Synopsys 40-bit TC specific attributes
256  *
257  * @hba: Pointer to drivers structure
258  *
259  * Returns 0 on success non-zero value on failure
260  */
tc_dwc_g210_config_40_bit(struct ufs_hba * hba)261 int tc_dwc_g210_config_40_bit(struct ufs_hba *hba)
262 {
263 	int ret = 0;
264 
265 	dev_info(hba->dev, "Configuring Test Chip 40-bit RMMI\n");
266 	ret = tc_dwc_g210_setup_40bit_rmmi(hba);
267 	if (ret) {
268 		dev_err(hba->dev, "Configuration failed\n");
269 		goto out;
270 	}
271 
272 	/* To write Shadow register bank to effective configuration block */
273 	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
274 	if (ret)
275 		goto out;
276 
277 	/* To configure Debug OMC */
278 	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01);
279 
280 out:
281 	return ret;
282 }
283 EXPORT_SYMBOL(tc_dwc_g210_config_40_bit);
284 
285 /**
286  * tc_dwc_g210_config_20_bit()
287  * This function configures Local (host) Synopsys 20-bit TC specific attributes
288  *
289  * @hba: Pointer to drivers structure
290  *
291  * Returns 0 on success non-zero value on failure
292  */
tc_dwc_g210_config_20_bit(struct ufs_hba * hba)293 int tc_dwc_g210_config_20_bit(struct ufs_hba *hba)
294 {
295 	int ret = 0;
296 
297 	dev_info(hba->dev, "Configuring Test Chip 20-bit RMMI\n");
298 	ret = tc_dwc_g210_setup_20bit_rmmi(hba);
299 	if (ret) {
300 		dev_err(hba->dev, "Configuration failed\n");
301 		goto out;
302 	}
303 
304 	/* To write Shadow register bank to effective configuration block */
305 	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
306 	if (ret)
307 		goto out;
308 
309 	/* To configure Debug OMC */
310 	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01);
311 
312 out:
313 	return ret;
314 }
315 EXPORT_SYMBOL(tc_dwc_g210_config_20_bit);
316 
317 MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
318 MODULE_DESCRIPTION("Synopsys G210 Test Chip driver");
319 MODULE_LICENSE("Dual BSD/GPL");
320