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