Merge tag 'efi-2020-07-rc6' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/u-boot.git] / board / freescale / common / vsc3316_3308.c
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
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 #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
51         return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
52 #endif
53 }
54
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 #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
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
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 #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
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
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 #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         }
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
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 #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
527         i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
528         i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
529 #endif
530 }