blob: 8aceb8ef178726f715e01c9b7767ceabdfdba5c0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Shaveta Leekhafa0123c2012-10-08 07:44:17 +00002/*
3 * Copyright 2012 Freescale Semiconductor, Inc.
Biwen Li3e9d3952020-05-01 20:04:17 +08004 * Copyright 2020 NXP
Shaveta Leekhafa0123c2012-10-08 07:44:17 +00005 */
6
7#include "vsc3316_3308.h"
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Shaveta Leekhafa0123c2012-10-08 07:44:17 +00009
10#define REVISION_ID_REG 0x7E
11#define INTERFACE_MODE_REG 0x79
12#define CURRENT_PAGE_REGISTER 0x7F
13#define CONNECTION_CONFIG_PAGE 0x00
14#define INPUT_STATE_REG 0x13
15#define GLOBAL_INPUT_ISE1 0x51
16#define GLOBAL_INPUT_ISE2 0x52
Shaohui Xie60c3b092014-11-13 11:27:49 +080017#define GLOBAL_INPUT_GAIN 0x53
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000018#define GLOBAL_INPUT_LOS 0x55
Shaohui Xie60c3b092014-11-13 11:27:49 +080019#define GLOBAL_OUTPUT_PE1 0x56
20#define GLOBAL_OUTPUT_PE2 0x57
21#define GLOBAL_OUTPUT_LEVEL 0x58
22#define GLOBAL_OUTPUT_TERMINATION 0x5A
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000023#define GLOBAL_CORE_CNTRL 0x5D
24#define OUTPUT_MODE_PAGE 0x23
25#define CORE_CONTROL_PAGE 0x25
26#define CORE_CONFIG_REG 0x75
27
28int vsc_if_enable(unsigned int vsc_addr)
29{
30 u8 data;
31
32 debug("VSC:Configuring VSC at I2C address 0x%2x"
33 " for 2-wire interface\n", vsc_addr);
34
35 /* enable 2-wire Serial InterFace (I2C) */
36 data = 0x02;
Biwen Li3e9d3952020-05-01 20:04:17 +080037#ifdef CONFIG_DM_I2C
38 int ret, bus_num = 0;
39 struct udevice *dev;
40
41 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
42 1, &dev);
43 if (ret) {
44 printf("%s: Cannot find udev for a bus %d\n", __func__,
45 bus_num);
46 return ret;
47 }
48
49 return dm_i2c_write(dev, INTERFACE_MODE_REG, &data, 1);
50#else
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000051 return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
Biwen Li3e9d3952020-05-01 20:04:17 +080052#endif
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000053}
54
Shaohui Xie3d8095e2013-08-19 18:43:07 +080055int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
Shaveta Leekhafa0123c2012-10-08 07:44:17 +000056 unsigned int num_con)
57{
58 unsigned int i;
59 u8 rev_id = 0;
60 int ret;
61
62 debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
63 " for Tx\n", vsc_addr);
64
Biwen Li3e9d3952020-05-01 20:04:17 +080065#ifdef CONFIG_DM_I2C
66 int bus_num = 0;
67 struct udevice *dev;
68
69 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
70 1, &dev);
71 if (ret) {
72 printf("%s: Cannot find udev for a bus %d\n", __func__,
73 bus_num);
74 return ret;
75 }
76
77 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
78 if (ret < 0) {
79 printf("VSC:0x%x could not read REV_ID from device.\n",
80 vsc_addr);
81 return ret;
82 }
83
84 if (rev_id != 0xab) {
85 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
86 vsc_addr);
87 return -ENODEV;
88 }
89
90 ret = vsc_if_enable(vsc_addr);
91 if (ret) {
92 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
93 vsc_addr);
94 return ret;
95 }
96
97 /* config connections - page 0x00 */
98 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
99
100 /* Making crosspoint connections, by connecting required
101 * input to output
102 */
103 for (i = 0; i < num_con ; i++)
104 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
105
106 /* input state - page 0x13 */
107 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
108 /* Configuring the required input of the switch */
109 for (i = 0; i < num_con ; i++)
110 dm_i2c_reg_write(dev, con_arr[i][0], 0x80);
111
112 /* Setting Global Input LOS threshold value */
113 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
114
115 /* config output mode - page 0x23 */
116 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
117 /* Turn ON the Output driver correspond to required output*/
118 for (i = 0; i < num_con ; i++)
119 dm_i2c_reg_write(dev, con_arr[i][1], 0);
120
121 /* configure global core control register, Turn on Global core power */
122 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
123
124#else
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000125 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
126 if (ret < 0) {
127 printf("VSC:0x%x could not read REV_ID from device.\n",
128 vsc_addr);
129 return ret;
130 }
131
132 if (rev_id != 0xab) {
133 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
134 vsc_addr);
135 return -ENODEV;
136 }
137
138 ret = vsc_if_enable(vsc_addr);
139 if (ret) {
140 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
141 vsc_addr);
142 return ret;
143 }
144
145 /* config connections - page 0x00 */
146 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
147
148 /* Making crosspoint connections, by connecting required
149 * input to output */
150 for (i = 0; i < num_con ; i++)
151 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
152
153 /* input state - page 0x13 */
154 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
155 /* Configuring the required input of the switch */
156 for (i = 0; i < num_con ; i++)
157 i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
158
159 /* Setting Global Input LOS threshold value */
160 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
161
162 /* config output mode - page 0x23 */
163 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
164 /* Turn ON the Output driver correspond to required output*/
165 for (i = 0; i < num_con ; i++)
166 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
167
168 /* configure global core control register, Turn on Global core power */
169 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
Biwen Li3e9d3952020-05-01 20:04:17 +0800170#endif
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000171
172 vsc_wp_config(vsc_addr);
173
174 return 0;
175}
176
Shaohui Xie60c3b092014-11-13 11:27:49 +0800177#ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
178int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
179 unsigned int num_con)
180{
181 unsigned int i;
182 u8 rev_id = 0;
183 int ret;
184
185 debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
186 vsc_addr);
187
Biwen Li3e9d3952020-05-01 20:04:17 +0800188#ifdef CONFIG_DM_I2C
189 int bus_num = 0;
190 struct udevice *dev;
191
192 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
193 1, &dev);
194 if (ret) {
195 printf("%s: Cannot find udev for a bus %d\n", __func__,
196 bus_num);
197 return ret;
198 }
199
200 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
201 if (ret < 0) {
202 printf("VSC:0x%x could not read REV_ID from device.\n",
203 vsc_addr);
204 return ret;
205 }
206
207 if (rev_id != 0xab) {
208 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
209 vsc_addr);
210 return -ENODEV;
211 }
212
213 ret = vsc_if_enable(vsc_addr);
214 if (ret) {
215 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
216 vsc_addr);
217 return ret;
218 }
219
220 /* config connections - page 0x00 */
221 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
222
223 /* Configure Global Input ISE */
224 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0);
225 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0);
226
227 /* Configure Tx/Rx Global Output PE1 */
228 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE1, 0);
229
230 /* Configure Tx/Rx Global Output PE2 */
231 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_PE2, 0);
232
233 /* Configure Tx/Rx Global Input GAIN */
234 dm_i2c_reg_write(dev, GLOBAL_INPUT_GAIN, 0x3F);
235
236 /* Setting Global Input LOS threshold value */
237 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0xE0);
238
239 /* Setting Global output termination */
240 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_TERMINATION, 0);
241
242 /* Configure Tx/Rx Global Output level */
243 if (vsc_addr == VSC3308_TX_ADDRESS)
244 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 4);
245 else
246 dm_i2c_reg_write(dev, GLOBAL_OUTPUT_LEVEL, 2);
247
248 /* Making crosspoint connections, by connecting required
249 * input to output
250 */
251 for (i = 0; i < num_con ; i++)
252 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
253
254 /* input state - page 0x13 */
255 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
256 /* Turning off all the required input of the switch */
257 for (i = 0; i < num_con; i++)
258 dm_i2c_reg_write(dev, con_arr[i][0], 1);
259
260 /* only turn on specific Tx/Rx requested by the XFI erratum */
261 if (vsc_addr == VSC3308_TX_ADDRESS) {
262 dm_i2c_reg_write(dev, 2, 0);
263 dm_i2c_reg_write(dev, 3, 0);
264 } else {
265 dm_i2c_reg_write(dev, 0, 0);
266 dm_i2c_reg_write(dev, 1, 0);
267 }
268
269 /* config output mode - page 0x23 */
270 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
271 /* Turn off the Output driver correspond to required output*/
272 for (i = 0; i < num_con ; i++)
273 dm_i2c_reg_write(dev, con_arr[i][1], 1);
274
275 /* only turn on specific Tx/Rx requested by the XFI erratum */
276 if (vsc_addr == VSC3308_TX_ADDRESS) {
277 dm_i2c_reg_write(dev, 0, 0);
278 dm_i2c_reg_write(dev, 1, 0);
279 } else {
280 dm_i2c_reg_write(dev, 3, 0);
281 dm_i2c_reg_write(dev, 4, 0);
282 }
283
284 /* configure global core control register, Turn on Global core power */
285 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
286#else
Shaohui Xie60c3b092014-11-13 11:27:49 +0800287 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
288 if (ret < 0) {
289 printf("VSC:0x%x could not read REV_ID from device.\n",
290 vsc_addr);
291 return ret;
292 }
293
294 if (rev_id != 0xab) {
295 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
296 vsc_addr);
297 return -ENODEV;
298 }
299
300 ret = vsc_if_enable(vsc_addr);
301 if (ret) {
302 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
303 vsc_addr);
304 return ret;
305 }
306
307 /* config connections - page 0x00 */
308 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
309
310 /* Configure Global Input ISE */
311 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0);
312 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0);
313
314 /* Configure Tx/Rx Global Output PE1 */
315 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
316
317 /* Configure Tx/Rx Global Output PE2 */
318 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
319
320 /* Configure Tx/Rx Global Input GAIN */
321 i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
322
323 /* Setting Global Input LOS threshold value */
324 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
325
326 /* Setting Global output termination */
327 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
328
329 /* Configure Tx/Rx Global Output level */
330 if (vsc_addr == VSC3308_TX_ADDRESS)
331 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
332 else
333 i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
334
335 /* Making crosspoint connections, by connecting required
336 * input to output */
337 for (i = 0; i < num_con ; i++)
338 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
339
340 /* input state - page 0x13 */
341 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
342 /* Turning off all the required input of the switch */
343 for (i = 0; i < num_con; i++)
344 i2c_reg_write(vsc_addr, con_arr[i][0], 1);
345
346 /* only turn on specific Tx/Rx requested by the XFI erratum */
347 if (vsc_addr == VSC3308_TX_ADDRESS) {
348 i2c_reg_write(vsc_addr, 2, 0);
349 i2c_reg_write(vsc_addr, 3, 0);
350 } else {
351 i2c_reg_write(vsc_addr, 0, 0);
352 i2c_reg_write(vsc_addr, 1, 0);
353 }
354
355 /* config output mode - page 0x23 */
356 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
357 /* Turn off the Output driver correspond to required output*/
358 for (i = 0; i < num_con ; i++)
359 i2c_reg_write(vsc_addr, con_arr[i][1], 1);
360
361 /* only turn on specific Tx/Rx requested by the XFI erratum */
362 if (vsc_addr == VSC3308_TX_ADDRESS) {
363 i2c_reg_write(vsc_addr, 0, 0);
364 i2c_reg_write(vsc_addr, 1, 0);
365 } else {
366 i2c_reg_write(vsc_addr, 3, 0);
367 i2c_reg_write(vsc_addr, 4, 0);
368 }
369
370 /* configure global core control register, Turn on Global core power */
371 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
Biwen Li3e9d3952020-05-01 20:04:17 +0800372#endif
Shaohui Xie60c3b092014-11-13 11:27:49 +0800373 vsc_wp_config(vsc_addr);
374
375 return 0;
376}
377#endif
378
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000379int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
380 unsigned int num_con)
381{
382 unsigned int i;
383 u8 rev_id = 0;
384 int ret;
385
386 debug("VSC:Initializing VSC3308 at I2C address 0x%x"
387 " for Tx\n", vsc_addr);
Biwen Li3e9d3952020-05-01 20:04:17 +0800388#ifdef CONFIG_DM_I2C
389 int bus_num = 0;
390 struct udevice *dev;
391
392 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
393 1, &dev);
394 if (ret) {
395 printf("%s: Cannot find udev for a bus %d\n", __func__,
396 bus_num);
397 return ret;
398 }
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000399
Biwen Li3e9d3952020-05-01 20:04:17 +0800400 ret = dm_i2c_read(dev, REVISION_ID_REG, &rev_id, 1);
401 if (ret < 0) {
402 printf("VSC:0x%x could not read REV_ID from device.\n",
403 vsc_addr);
404 return ret;
405 }
406
407 if (rev_id != 0xab) {
408 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
409 vsc_addr);
410 return -ENODEV;
411 }
412
413 ret = vsc_if_enable(vsc_addr);
414 if (ret) {
415 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
416 vsc_addr);
417 return ret;
418 }
419
420 /* config connections - page 0x00 */
421 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
422
423 /* Making crosspoint connections, by connecting required
424 * input to output
425 */
426 for (i = 0; i < num_con ; i++)
427 dm_i2c_reg_write(dev, con_arr[i][1], con_arr[i][0]);
428
429 /*Configure Global Input ISE and gain */
430 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE1, 0x12);
431 dm_i2c_reg_write(dev, GLOBAL_INPUT_ISE2, 0x12);
432
433 /* input state - page 0x13 */
434 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
435 /* Turning ON the required input of the switch */
436 for (i = 0; i < num_con ; i++)
437 dm_i2c_reg_write(dev, con_arr[i][0], 0);
438
439 /* Setting Global Input LOS threshold value */
440 dm_i2c_reg_write(dev, GLOBAL_INPUT_LOS, 0x60);
441
442 /* config output mode - page 0x23 */
443 dm_i2c_reg_write(dev, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
444 /* Turn ON the Output driver correspond to required output*/
445 for (i = 0; i < num_con ; i++)
446 dm_i2c_reg_write(dev, con_arr[i][1], 0);
447
448 /* configure global core control register, Turn on Global core power */
449 dm_i2c_reg_write(dev, GLOBAL_CORE_CNTRL, 0);
450#else
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000451 ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
452 if (ret < 0) {
453 printf("VSC:0x%x could not read REV_ID from device.\n",
454 vsc_addr);
455 return ret;
456 }
457
458 if (rev_id != 0xab) {
459 printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
460 vsc_addr);
461 return -ENODEV;
462 }
463
464 ret = vsc_if_enable(vsc_addr);
465 if (ret) {
466 printf("VSC:0x%x could not configured for 2-wire I/F.\n",
467 vsc_addr);
468 return ret;
469 }
470
471 /* config connections - page 0x00 */
472 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
473
474 /* Making crosspoint connections, by connecting required
475 * input to output */
476 for (i = 0; i < num_con ; i++)
477 i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
478
479 /*Configure Global Input ISE and gain */
480 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
481 i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
482
483 /* input state - page 0x13 */
484 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
485 /* Turning ON the required input of the switch */
486 for (i = 0; i < num_con ; i++)
487 i2c_reg_write(vsc_addr, con_arr[i][0], 0);
488
489 /* Setting Global Input LOS threshold value */
490 i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
491
492 /* config output mode - page 0x23 */
493 i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
494 /* Turn ON the Output driver correspond to required output*/
495 for (i = 0; i < num_con ; i++)
496 i2c_reg_write(vsc_addr, con_arr[i][1], 0);
497
498 /* configure global core control register, Turn on Global core power */
499 i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
Biwen Li3e9d3952020-05-01 20:04:17 +0800500#endif
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000501 vsc_wp_config(vsc_addr);
502
503 return 0;
504}
505
506void vsc_wp_config(unsigned int vsc_addr)
507{
508 debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
509
510 /* For new crosspoint configuration to occur, WP bit of
511 * CORE_CONFIG_REG should be set 1 and then reset to 0 */
Biwen Li3e9d3952020-05-01 20:04:17 +0800512#ifdef CONFIG_DM_I2C
513 int ret, bus_num = 0;
514 struct udevice *dev;
515
516 ret = i2c_get_chip_for_busnum(bus_num, vsc_addr,
517 1, &dev);
518 if (ret) {
519 printf("%s: Cannot find udev for a bus %d\n", __func__,
520 bus_num);
521 return;
522 }
523
524 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x01);
525 dm_i2c_reg_write(dev, CORE_CONFIG_REG, 0x0);
526#else
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000527 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
528 i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
Biwen Li3e9d3952020-05-01 20:04:17 +0800529#endif
Shaveta Leekhafa0123c2012-10-08 07:44:17 +0000530}