1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2012 Freescale Semiconductor, Inc.
4  * Copyright 2020 NXP
5  */
6 
7 #include "vsc3316_3308.h"
8 #include <log.h>
9 
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
17 #define GLOBAL_INPUT_GAIN		0x53
18 #define GLOBAL_INPUT_LOS		0x55
19 #define GLOBAL_OUTPUT_PE1		0x56
20 #define GLOBAL_OUTPUT_PE2		0x57
21 #define GLOBAL_OUTPUT_LEVEL		0x58
22 #define GLOBAL_OUTPUT_TERMINATION	0x5A
23 #define GLOBAL_CORE_CNTRL		0x5D
24 #define OUTPUT_MODE_PAGE		0x23
25 #define CORE_CONTROL_PAGE		0x25
26 #define CORE_CONFIG_REG		0x75
27 
vsc_if_enable(unsigned int vsc_addr)28 int 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;
37 #if CONFIG_IS_ENABLED(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
51 	return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
52 #endif
53 }
54 
vsc3316_config(unsigned int vsc_addr,int8_t con_arr[][2],unsigned int num_con)55 int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
56 		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 
65 #if CONFIG_IS_ENABLED(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
125 	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);
170 #endif
171 
172 	vsc_wp_config(vsc_addr);
173 
174 	return 0;
175 }
176 
177 #ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
vsc3308_config_adjust(unsigned int vsc_addr,const int8_t con_arr[][2],unsigned int num_con)178 int 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 
188 #if CONFIG_IS_ENABLED(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
287 	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);
372 #endif
373 	vsc_wp_config(vsc_addr);
374 
375 	return 0;
376 }
377 #endif
378 
vsc3308_config(unsigned int vsc_addr,const int8_t con_arr[][2],unsigned int num_con)379 int 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);
388 #if CONFIG_IS_ENABLED(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 	}
399 
400 	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
451 	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);
500 #endif
501 	vsc_wp_config(vsc_addr);
502 
503 	return 0;
504 }
505 
vsc_wp_config(unsigned int vsc_addr)506 void 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 */
512 #if CONFIG_IS_ENABLED(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
527 	i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
528 	i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
529 #endif
530 }
531