]>
Commit | Line | Data |
---|---|---|
3ad2737e YZ |
1 | /* |
2 | * Copyright 2014 Freescale Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <command.h> | |
9 | #include <i2c.h> | |
02b5d2ed | 10 | #include <asm/io.h> |
126fe70d | 11 | #ifdef CONFIG_FSL_LSCH2 |
02b5d2ed | 12 | #include <asm/arch/immap_lsch2.h> |
ed2530d0 RH |
13 | #elif defined(CONFIG_FSL_LSCH3) |
14 | #include <asm/arch/immap_lsch3.h> | |
02b5d2ed | 15 | #else |
3ad2737e | 16 | #include <asm/immap_85xx.h> |
02b5d2ed | 17 | #endif |
3ad2737e YZ |
18 | #include "vid.h" |
19 | ||
20 | DECLARE_GLOBAL_DATA_PTR; | |
21 | ||
22 | int __weak i2c_multiplexer_select_vid_channel(u8 channel) | |
23 | { | |
24 | return 0; | |
25 | } | |
26 | ||
27 | /* | |
28 | * Compensate for a board specific voltage drop between regulator and SoC | |
29 | * return a value in mV | |
30 | */ | |
31 | int __weak board_vdd_drop_compensation(void) | |
32 | { | |
33 | return 0; | |
34 | } | |
35 | ||
3607570b RB |
36 | /* |
37 | * Board specific settings for specific voltage value | |
38 | */ | |
39 | int __weak board_adjust_vdd(int vdd) | |
40 | { | |
41 | return 0; | |
42 | } | |
43 | ||
9458316a RB |
44 | #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ |
45 | defined(CONFIG_VOL_MONITOR_IR36021_READ) | |
3ad2737e YZ |
46 | /* |
47 | * Get the i2c address configuration for the IR regulator chip | |
48 | * | |
49 | * There are some variance in the RDB HW regarding the I2C address configuration | |
50 | * for the IR regulator chip, which is likely a problem of external resistor | |
51 | * accuracy. So we just check each address in a hopefully non-intrusive mode | |
52 | * and use the first one that seems to work | |
53 | * | |
54 | * The IR chip can show up under the following addresses: | |
55 | * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA) | |
56 | * 0x09 (Verified on T1040RDB-PA) | |
2f66a828 | 57 | * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB) |
3ad2737e YZ |
58 | */ |
59 | static int find_ir_chip_on_i2c(void) | |
60 | { | |
61 | int i2caddress; | |
62 | int ret; | |
63 | u8 byte; | |
64 | int i; | |
65 | const int ir_i2c_addr[] = {0x38, 0x08, 0x09}; | |
66 | ||
67 | /* Check all the address */ | |
68 | for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) { | |
69 | i2caddress = ir_i2c_addr[i]; | |
70 | ret = i2c_read(i2caddress, | |
71 | IR36021_MFR_ID_OFFSET, 1, (void *)&byte, | |
72 | sizeof(byte)); | |
73 | if ((ret >= 0) && (byte == IR36021_MFR_ID)) | |
74 | return i2caddress; | |
75 | } | |
76 | return -1; | |
77 | } | |
9458316a | 78 | #endif |
3ad2737e YZ |
79 | |
80 | /* Maximum loop count waiting for new voltage to take effect */ | |
81 | #define MAX_LOOP_WAIT_NEW_VOL 100 | |
82 | /* Maximum loop count waiting for the voltage to be stable */ | |
83 | #define MAX_LOOP_WAIT_VOL_STABLE 100 | |
84 | /* | |
85 | * read_voltage from sensor on I2C bus | |
86 | * We use average of 4 readings, waiting for WAIT_FOR_ADC before | |
87 | * another reading | |
88 | */ | |
89 | #define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */ | |
90 | ||
91 | /* If an INA220 chip is available, we can use it to read back the voltage | |
92 | * as it may have a higher accuracy than the IR chip for the same purpose | |
93 | */ | |
94 | #ifdef CONFIG_VOL_MONITOR_INA220 | |
95 | #define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */ | |
96 | #define ADC_MIN_ACCURACY 4 | |
97 | #else | |
98 | #define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */ | |
99 | #define ADC_MIN_ACCURACY 4 | |
100 | #endif | |
101 | ||
102 | #ifdef CONFIG_VOL_MONITOR_INA220 | |
103 | static int read_voltage_from_INA220(int i2caddress) | |
104 | { | |
105 | int i, ret, voltage_read = 0; | |
106 | u16 vol_mon; | |
107 | u8 buf[2]; | |
108 | ||
109 | for (i = 0; i < NUM_READINGS; i++) { | |
110 | ret = i2c_read(I2C_VOL_MONITOR_ADDR, | |
111 | I2C_VOL_MONITOR_BUS_V_OFFSET, 1, | |
112 | (void *)&buf, 2); | |
113 | if (ret) { | |
114 | printf("VID: failed to read core voltage\n"); | |
115 | return ret; | |
116 | } | |
117 | vol_mon = (buf[0] << 8) | buf[1]; | |
118 | if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) { | |
119 | printf("VID: Core voltage sensor error\n"); | |
120 | return -1; | |
121 | } | |
122 | debug("VID: bus voltage reads 0x%04x\n", vol_mon); | |
123 | /* LSB = 4mv */ | |
124 | voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4; | |
125 | udelay(WAIT_FOR_ADC); | |
126 | } | |
127 | /* calculate the average */ | |
128 | voltage_read /= NUM_READINGS; | |
129 | ||
130 | return voltage_read; | |
131 | } | |
132 | #endif | |
133 | ||
134 | /* read voltage from IR */ | |
135 | #ifdef CONFIG_VOL_MONITOR_IR36021_READ | |
136 | static int read_voltage_from_IR(int i2caddress) | |
137 | { | |
138 | int i, ret, voltage_read = 0; | |
139 | u16 vol_mon; | |
140 | u8 buf; | |
141 | ||
142 | for (i = 0; i < NUM_READINGS; i++) { | |
143 | ret = i2c_read(i2caddress, | |
144 | IR36021_LOOP1_VOUT_OFFSET, | |
145 | 1, (void *)&buf, 1); | |
146 | if (ret) { | |
147 | printf("VID: failed to read vcpu\n"); | |
148 | return ret; | |
149 | } | |
150 | vol_mon = buf; | |
151 | if (!vol_mon) { | |
152 | printf("VID: Core voltage sensor error\n"); | |
153 | return -1; | |
154 | } | |
155 | debug("VID: bus voltage reads 0x%02x\n", vol_mon); | |
156 | /* Resolution is 1/128V. We scale up here to get 1/128mV | |
157 | * and divide at the end | |
158 | */ | |
159 | voltage_read += vol_mon * 1000; | |
160 | udelay(WAIT_FOR_ADC); | |
161 | } | |
162 | /* Scale down to the real mV as IR resolution is 1/128V, rounding up */ | |
163 | voltage_read = DIV_ROUND_UP(voltage_read, 128); | |
164 | ||
165 | /* calculate the average */ | |
166 | voltage_read /= NUM_READINGS; | |
167 | ||
168 | /* Compensate for a board specific voltage drop between regulator and | |
169 | * SoC before converting into an IR VID value | |
170 | */ | |
171 | voltage_read -= board_vdd_drop_compensation(); | |
172 | ||
173 | return voltage_read; | |
174 | } | |
175 | #endif | |
176 | ||
177 | static int read_voltage(int i2caddress) | |
178 | { | |
179 | int voltage_read; | |
180 | #ifdef CONFIG_VOL_MONITOR_INA220 | |
181 | voltage_read = read_voltage_from_INA220(i2caddress); | |
182 | #elif defined CONFIG_VOL_MONITOR_IR36021_READ | |
183 | voltage_read = read_voltage_from_IR(i2caddress); | |
184 | #else | |
185 | return -1; | |
186 | #endif | |
187 | return voltage_read; | |
188 | } | |
189 | ||
9458316a | 190 | #ifdef CONFIG_VOL_MONITOR_IR36021_SET |
3ad2737e YZ |
191 | /* |
192 | * We need to calculate how long before the voltage stops to drop | |
193 | * or increase. It returns with the loop count. Each loop takes | |
194 | * several readings (WAIT_FOR_ADC) | |
195 | */ | |
196 | static int wait_for_new_voltage(int vdd, int i2caddress) | |
197 | { | |
198 | int timeout, vdd_current; | |
199 | ||
200 | vdd_current = read_voltage(i2caddress); | |
201 | /* wait until voltage starts to reach the target. Voltage slew | |
202 | * rates by typical regulators will always lead to stable readings | |
203 | * within each fairly long ADC interval in comparison to the | |
204 | * intended voltage delta change until the target voltage is | |
205 | * reached. The fairly small voltage delta change to any target | |
206 | * VID voltage also means that this function will always complete | |
207 | * within few iterations. If the timeout was ever reached, it would | |
208 | * point to a serious failure in the regulator system. | |
209 | */ | |
210 | for (timeout = 0; | |
211 | abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) && | |
212 | timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) { | |
213 | vdd_current = read_voltage(i2caddress); | |
214 | } | |
215 | if (timeout >= MAX_LOOP_WAIT_NEW_VOL) { | |
216 | printf("VID: Voltage adjustment timeout\n"); | |
217 | return -1; | |
218 | } | |
219 | return timeout; | |
220 | } | |
221 | ||
222 | /* | |
223 | * this function keeps reading the voltage until it is stable or until the | |
224 | * timeout expires | |
225 | */ | |
226 | static int wait_for_voltage_stable(int i2caddress) | |
227 | { | |
228 | int timeout, vdd_current, vdd; | |
229 | ||
230 | vdd = read_voltage(i2caddress); | |
231 | udelay(NUM_READINGS * WAIT_FOR_ADC); | |
232 | ||
233 | /* wait until voltage is stable */ | |
234 | vdd_current = read_voltage(i2caddress); | |
235 | /* The maximum timeout is | |
236 | * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC | |
237 | */ | |
238 | for (timeout = MAX_LOOP_WAIT_VOL_STABLE; | |
239 | abs(vdd - vdd_current) > ADC_MIN_ACCURACY && | |
240 | timeout > 0; timeout--) { | |
241 | vdd = vdd_current; | |
242 | udelay(NUM_READINGS * WAIT_FOR_ADC); | |
243 | vdd_current = read_voltage(i2caddress); | |
244 | } | |
245 | if (timeout == 0) | |
246 | return -1; | |
247 | return vdd_current; | |
248 | } | |
249 | ||
3ad2737e YZ |
250 | /* Set the voltage to the IR chip */ |
251 | static int set_voltage_to_IR(int i2caddress, int vdd) | |
252 | { | |
253 | int wait, vdd_last; | |
254 | int ret; | |
255 | u8 vid; | |
256 | ||
257 | /* Compensate for a board specific voltage drop between regulator and | |
258 | * SoC before converting into an IR VID value | |
259 | */ | |
260 | vdd += board_vdd_drop_compensation(); | |
126fe70d | 261 | #ifdef CONFIG_FSL_LSCH2 |
02b5d2ed SX |
262 | vid = DIV_ROUND_UP(vdd - 265, 5); |
263 | #else | |
3ad2737e | 264 | vid = DIV_ROUND_UP(vdd - 245, 5); |
02b5d2ed | 265 | #endif |
3ad2737e YZ |
266 | |
267 | ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET, | |
268 | 1, (void *)&vid, sizeof(vid)); | |
269 | if (ret) { | |
270 | printf("VID: failed to write VID\n"); | |
271 | return -1; | |
272 | } | |
273 | wait = wait_for_new_voltage(vdd, i2caddress); | |
274 | if (wait < 0) | |
275 | return -1; | |
276 | debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC); | |
277 | ||
278 | vdd_last = wait_for_voltage_stable(i2caddress); | |
279 | if (vdd_last < 0) | |
280 | return -1; | |
281 | debug("VID: Current voltage is %d mV\n", vdd_last); | |
282 | return vdd_last; | |
283 | } | |
284 | #endif | |
285 | ||
286 | static int set_voltage(int i2caddress, int vdd) | |
287 | { | |
288 | int vdd_last = -1; | |
289 | ||
290 | #ifdef CONFIG_VOL_MONITOR_IR36021_SET | |
291 | vdd_last = set_voltage_to_IR(i2caddress, vdd); | |
292 | #else | |
293 | #error Specific voltage monitor must be defined | |
294 | #endif | |
295 | return vdd_last; | |
296 | } | |
297 | ||
29ca713c | 298 | #ifdef CONFIG_FSL_LSCH3 |
3ad2737e YZ |
299 | int adjust_vdd(ulong vdd_override) |
300 | { | |
301 | int re_enable = disable_interrupts(); | |
29ca713c PJ |
302 | struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); |
303 | u32 fusesr; | |
9458316a RB |
304 | #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ |
305 | defined(CONFIG_VOL_MONITOR_IR36021_READ) | |
29ca713c | 306 | u8 vid, buf; |
9458316a RB |
307 | #else |
308 | u8 vid; | |
309 | #endif | |
29ca713c PJ |
310 | int vdd_target, vdd_current, vdd_last; |
311 | int ret, i2caddress; | |
312 | unsigned long vdd_string_override; | |
313 | char *vdd_string; | |
c535ad4e RB |
314 | #ifdef CONFIG_ARCH_LS1088A |
315 | static const uint16_t vdd[32] = { | |
316 | 10250, | |
317 | 9875, | |
318 | 9750, | |
319 | 0, /* reserved */ | |
320 | 0, /* reserved */ | |
321 | 0, /* reserved */ | |
322 | 0, /* reserved */ | |
323 | 0, /* reserved */ | |
324 | 9000, | |
325 | 0, /* reserved */ | |
326 | 0, /* reserved */ | |
327 | 0, /* reserved */ | |
328 | 0, /* reserved */ | |
329 | 0, /* reserved */ | |
330 | 0, /* reserved */ | |
331 | 0, /* reserved */ | |
332 | 10000, /* 1.0000V */ | |
333 | 10125, | |
334 | 10250, | |
335 | 0, /* reserved */ | |
336 | 0, /* reserved */ | |
337 | 0, /* reserved */ | |
338 | 0, /* reserved */ | |
339 | 0, /* reserved */ | |
340 | 0, /* reserved */ | |
341 | 0, /* reserved */ | |
342 | 0, /* reserved */ | |
343 | 0, /* reserved */ | |
344 | 0, /* reserved */ | |
345 | 0, /* reserved */ | |
346 | 0, /* reserved */ | |
347 | 0, /* reserved */ | |
348 | }; | |
349 | ||
350 | #else | |
29ca713c PJ |
351 | static const uint16_t vdd[32] = { |
352 | 10500, | |
353 | 0, /* reserved */ | |
354 | 9750, | |
355 | 0, /* reserved */ | |
356 | 9500, | |
357 | 0, /* reserved */ | |
358 | 0, /* reserved */ | |
359 | 0, /* reserved */ | |
360 | 0, /* reserved */ | |
361 | 0, /* reserved */ | |
362 | 0, /* reserved */ | |
363 | 0, /* reserved */ | |
364 | 0, /* reserved */ | |
365 | 0, /* reserved */ | |
366 | 0, /* reserved */ | |
367 | 0, /* reserved */ | |
368 | 10000, /* 1.0000V */ | |
369 | 0, /* reserved */ | |
370 | 10250, | |
371 | 0, /* reserved */ | |
372 | 10500, | |
373 | 0, /* reserved */ | |
374 | 0, /* reserved */ | |
375 | 0, /* reserved */ | |
376 | 0, /* reserved */ | |
377 | 0, /* reserved */ | |
378 | 0, /* reserved */ | |
379 | 0, /* reserved */ | |
380 | 0, /* reserved */ | |
381 | 0, /* reserved */ | |
382 | 0, /* reserved */ | |
383 | 0, /* reserved */ | |
384 | }; | |
c535ad4e | 385 | #endif |
29ca713c PJ |
386 | struct vdd_drive { |
387 | u8 vid; | |
388 | unsigned voltage; | |
389 | }; | |
390 | ||
391 | ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR); | |
392 | if (ret) { | |
393 | debug("VID: I2C failed to switch channel\n"); | |
394 | ret = -1; | |
395 | goto exit; | |
396 | } | |
9458316a RB |
397 | #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ |
398 | defined(CONFIG_VOL_MONITOR_IR36021_READ) | |
29ca713c PJ |
399 | ret = find_ir_chip_on_i2c(); |
400 | if (ret < 0) { | |
401 | printf("VID: Could not find voltage regulator on I2C.\n"); | |
402 | ret = -1; | |
403 | goto exit; | |
404 | } else { | |
405 | i2caddress = ret; | |
406 | debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress); | |
407 | } | |
408 | ||
409 | /* check IR chip work on Intel mode*/ | |
410 | ret = i2c_read(i2caddress, | |
411 | IR36021_INTEL_MODE_OOFSET, | |
412 | 1, (void *)&buf, 1); | |
413 | if (ret) { | |
414 | printf("VID: failed to read IR chip mode.\n"); | |
415 | ret = -1; | |
416 | goto exit; | |
417 | } | |
418 | if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) { | |
419 | printf("VID: IR Chip is not used in Intel mode.\n"); | |
420 | ret = -1; | |
421 | goto exit; | |
422 | } | |
9458316a | 423 | #endif |
29ca713c PJ |
424 | |
425 | /* get the voltage ID from fuse status register */ | |
426 | fusesr = in_le32(&gur->dcfg_fusesr); | |
427 | vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) & | |
428 | FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK; | |
429 | if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) { | |
430 | vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) & | |
431 | FSL_CHASSIS3_DCFG_FUSESR_VID_MASK; | |
432 | } | |
433 | vdd_target = vdd[vid]; | |
434 | ||
435 | /* check override variable for overriding VDD */ | |
00caae6d | 436 | vdd_string = env_get(CONFIG_VID_FLS_ENV); |
29ca713c PJ |
437 | if (vdd_override == 0 && vdd_string && |
438 | !strict_strtoul(vdd_string, 10, &vdd_string_override)) | |
439 | vdd_override = vdd_string_override; | |
440 | ||
441 | if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) { | |
442 | vdd_target = vdd_override * 10; /* convert to 1/10 mV */ | |
443 | debug("VDD override is %lu\n", vdd_override); | |
444 | } else if (vdd_override != 0) { | |
445 | printf("Invalid value.\n"); | |
446 | } | |
447 | ||
448 | /* divide and round up by 10 to get a value in mV */ | |
449 | vdd_target = DIV_ROUND_UP(vdd_target, 10); | |
450 | if (vdd_target == 0) { | |
451 | debug("VID: VID not used\n"); | |
452 | ret = 0; | |
453 | goto exit; | |
454 | } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) { | |
455 | /* Check vdd_target is in valid range */ | |
456 | printf("VID: Target VID %d mV is not in range.\n", | |
457 | vdd_target); | |
458 | ret = -1; | |
459 | goto exit; | |
460 | } else { | |
461 | debug("VID: vid = %d mV\n", vdd_target); | |
462 | } | |
463 | ||
464 | /* | |
465 | * Read voltage monitor to check real voltage. | |
466 | */ | |
467 | vdd_last = read_voltage(i2caddress); | |
468 | if (vdd_last < 0) { | |
469 | printf("VID: Couldn't read sensor abort VID adjustment\n"); | |
470 | ret = -1; | |
471 | goto exit; | |
472 | } | |
473 | vdd_current = vdd_last; | |
474 | debug("VID: Core voltage is currently at %d mV\n", vdd_last); | |
475 | /* | |
476 | * Adjust voltage to at or one step above target. | |
477 | * As measurements are less precise than setting the values | |
478 | * we may run through dummy steps that cancel each other | |
479 | * when stepping up and then down. | |
480 | */ | |
481 | while (vdd_last > 0 && | |
482 | vdd_last < vdd_target) { | |
483 | vdd_current += IR_VDD_STEP_UP; | |
484 | vdd_last = set_voltage(i2caddress, vdd_current); | |
485 | } | |
486 | while (vdd_last > 0 && | |
487 | vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) { | |
488 | vdd_current -= IR_VDD_STEP_DOWN; | |
489 | vdd_last = set_voltage(i2caddress, vdd_current); | |
490 | } | |
491 | ||
3607570b RB |
492 | if (board_adjust_vdd(vdd_target) < 0) { |
493 | ret = -1; | |
494 | goto exit; | |
495 | } | |
496 | ||
29ca713c PJ |
497 | if (vdd_last > 0) |
498 | printf("VID: Core voltage after adjustment is at %d mV\n", | |
499 | vdd_last); | |
500 | else | |
501 | ret = -1; | |
502 | exit: | |
503 | if (re_enable) | |
504 | enable_interrupts(); | |
505 | i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT); | |
506 | return ret; | |
507 | } | |
508 | #else /* !CONFIG_FSL_LSCH3 */ | |
509 | int adjust_vdd(ulong vdd_override) | |
510 | { | |
511 | int re_enable = disable_interrupts(); | |
512 | #if defined(CONFIG_FSL_LSCH2) | |
02b5d2ed SX |
513 | struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); |
514 | #else | |
3ad2737e YZ |
515 | ccsr_gur_t __iomem *gur = |
516 | (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); | |
02b5d2ed | 517 | #endif |
3ad2737e | 518 | u32 fusesr; |
cabe4d2f | 519 | u8 vid, buf; |
3ad2737e YZ |
520 | int vdd_target, vdd_current, vdd_last; |
521 | int ret, i2caddress; | |
522 | unsigned long vdd_string_override; | |
523 | char *vdd_string; | |
524 | static const uint16_t vdd[32] = { | |
525 | 0, /* unused */ | |
526 | 9875, /* 0.9875V */ | |
527 | 9750, | |
528 | 9625, | |
529 | 9500, | |
530 | 9375, | |
531 | 9250, | |
532 | 9125, | |
533 | 9000, | |
534 | 8875, | |
535 | 8750, | |
536 | 8625, | |
537 | 8500, | |
538 | 8375, | |
539 | 8250, | |
540 | 8125, | |
541 | 10000, /* 1.0000V */ | |
542 | 10125, | |
543 | 10250, | |
544 | 10375, | |
545 | 10500, | |
546 | 10625, | |
547 | 10750, | |
548 | 10875, | |
549 | 11000, | |
550 | 0, /* reserved */ | |
551 | }; | |
552 | struct vdd_drive { | |
553 | u8 vid; | |
554 | unsigned voltage; | |
555 | }; | |
556 | ||
557 | ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR); | |
558 | if (ret) { | |
559 | debug("VID: I2C failed to switch channel\n"); | |
560 | ret = -1; | |
561 | goto exit; | |
562 | } | |
9458316a RB |
563 | #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ |
564 | defined(CONFIG_VOL_MONITOR_IR36021_READ) | |
3ad2737e YZ |
565 | ret = find_ir_chip_on_i2c(); |
566 | if (ret < 0) { | |
567 | printf("VID: Could not find voltage regulator on I2C.\n"); | |
568 | ret = -1; | |
569 | goto exit; | |
570 | } else { | |
571 | i2caddress = ret; | |
572 | debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress); | |
573 | } | |
574 | ||
cabe4d2f YZ |
575 | /* check IR chip work on Intel mode*/ |
576 | ret = i2c_read(i2caddress, | |
577 | IR36021_INTEL_MODE_OOFSET, | |
578 | 1, (void *)&buf, 1); | |
579 | if (ret) { | |
580 | printf("VID: failed to read IR chip mode.\n"); | |
581 | ret = -1; | |
582 | goto exit; | |
583 | } | |
584 | if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) { | |
585 | printf("VID: IR Chip is not used in Intel mode.\n"); | |
586 | ret = -1; | |
587 | goto exit; | |
588 | } | |
9458316a | 589 | #endif |
cabe4d2f | 590 | |
3ad2737e YZ |
591 | /* get the voltage ID from fuse status register */ |
592 | fusesr = in_be32(&gur->dcfg_fusesr); | |
593 | /* | |
594 | * VID is used according to the table below | |
595 | * --------------------------------------- | |
596 | * | DA_V | | |
597 | * |-------------------------------------| | |
598 | * | 5b00000 | 5b00001-5b11110 | 5b11111 | | |
599 | * ---------------+---------+-----------------+---------| | |
600 | * | D | 5b00000 | NO VID | VID = DA_V | NO VID | | |
601 | * | A |----------+---------+-----------------+---------| | |
602 | * | _ | 5b00001 |VID = | VID = |VID = | | |
603 | * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT| | |
604 | * | _ | 5b11110 | | | | | |
605 | * | A |----------+---------+-----------------+---------| | |
606 | * | L | 5b11111 | No VID | VID = DA_V | NO VID | | |
607 | * | T | | | | | | |
608 | * ------------------------------------------------------ | |
609 | */ | |
126fe70d | 610 | #ifdef CONFIG_FSL_LSCH2 |
02b5d2ed SX |
611 | vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) & |
612 | FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK; | |
613 | if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) { | |
614 | vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) & | |
615 | FSL_CHASSIS2_DCFG_FUSESR_VID_MASK; | |
616 | } | |
617 | #else | |
3ad2737e YZ |
618 | vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) & |
619 | FSL_CORENET_DCFG_FUSESR_ALTVID_MASK; | |
620 | if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) { | |
621 | vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) & | |
622 | FSL_CORENET_DCFG_FUSESR_VID_MASK; | |
623 | } | |
02b5d2ed | 624 | #endif |
3ad2737e YZ |
625 | vdd_target = vdd[vid]; |
626 | ||
627 | /* check override variable for overriding VDD */ | |
00caae6d | 628 | vdd_string = env_get(CONFIG_VID_FLS_ENV); |
3ad2737e YZ |
629 | if (vdd_override == 0 && vdd_string && |
630 | !strict_strtoul(vdd_string, 10, &vdd_string_override)) | |
631 | vdd_override = vdd_string_override; | |
632 | if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) { | |
633 | vdd_target = vdd_override * 10; /* convert to 1/10 mV */ | |
634 | debug("VDD override is %lu\n", vdd_override); | |
635 | } else if (vdd_override != 0) { | |
636 | printf("Invalid value.\n"); | |
637 | } | |
638 | if (vdd_target == 0) { | |
639 | debug("VID: VID not used\n"); | |
640 | ret = 0; | |
641 | goto exit; | |
642 | } else { | |
643 | /* divide and round up by 10 to get a value in mV */ | |
644 | vdd_target = DIV_ROUND_UP(vdd_target, 10); | |
645 | debug("VID: vid = %d mV\n", vdd_target); | |
646 | } | |
647 | ||
648 | /* | |
649 | * Read voltage monitor to check real voltage. | |
650 | */ | |
651 | vdd_last = read_voltage(i2caddress); | |
652 | if (vdd_last < 0) { | |
653 | printf("VID: Couldn't read sensor abort VID adjustment\n"); | |
654 | ret = -1; | |
655 | goto exit; | |
656 | } | |
657 | vdd_current = vdd_last; | |
658 | debug("VID: Core voltage is currently at %d mV\n", vdd_last); | |
659 | /* | |
660 | * Adjust voltage to at or one step above target. | |
661 | * As measurements are less precise than setting the values | |
662 | * we may run through dummy steps that cancel each other | |
663 | * when stepping up and then down. | |
664 | */ | |
665 | while (vdd_last > 0 && | |
666 | vdd_last < vdd_target) { | |
667 | vdd_current += IR_VDD_STEP_UP; | |
668 | vdd_last = set_voltage(i2caddress, vdd_current); | |
669 | } | |
670 | while (vdd_last > 0 && | |
671 | vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) { | |
672 | vdd_current -= IR_VDD_STEP_DOWN; | |
673 | vdd_last = set_voltage(i2caddress, vdd_current); | |
674 | } | |
675 | ||
676 | if (vdd_last > 0) | |
677 | printf("VID: Core voltage after adjustment is at %d mV\n", | |
678 | vdd_last); | |
679 | else | |
680 | ret = -1; | |
681 | exit: | |
682 | if (re_enable) | |
683 | enable_interrupts(); | |
1be8d10b WS |
684 | |
685 | i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT); | |
686 | ||
3ad2737e YZ |
687 | return ret; |
688 | } | |
29ca713c | 689 | #endif |
3ad2737e YZ |
690 | |
691 | static int print_vdd(void) | |
692 | { | |
693 | int vdd_last, ret, i2caddress; | |
694 | ||
695 | ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR); | |
696 | if (ret) { | |
697 | debug("VID : I2c failed to switch channel\n"); | |
698 | return -1; | |
699 | } | |
9458316a RB |
700 | #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ |
701 | defined(CONFIG_VOL_MONITOR_IR36021_READ) | |
3ad2737e YZ |
702 | ret = find_ir_chip_on_i2c(); |
703 | if (ret < 0) { | |
704 | printf("VID: Could not find voltage regulator on I2C.\n"); | |
1be8d10b | 705 | goto exit; |
3ad2737e YZ |
706 | } else { |
707 | i2caddress = ret; | |
708 | debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress); | |
709 | } | |
9458316a | 710 | #endif |
3ad2737e YZ |
711 | |
712 | /* | |
713 | * Read voltage monitor to check real voltage. | |
714 | */ | |
715 | vdd_last = read_voltage(i2caddress); | |
716 | if (vdd_last < 0) { | |
717 | printf("VID: Couldn't read sensor abort VID adjustment\n"); | |
1be8d10b | 718 | goto exit; |
3ad2737e YZ |
719 | } |
720 | printf("VID: Core voltage is at %d mV\n", vdd_last); | |
1be8d10b WS |
721 | exit: |
722 | i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT); | |
723 | ||
724 | return ret < 0 ? -1 : 0; | |
3ad2737e | 725 | |
3ad2737e YZ |
726 | } |
727 | ||
728 | static int do_vdd_override(cmd_tbl_t *cmdtp, | |
729 | int flag, int argc, | |
730 | char * const argv[]) | |
731 | { | |
732 | ulong override; | |
733 | ||
734 | if (argc < 2) | |
735 | return CMD_RET_USAGE; | |
736 | ||
737 | if (!strict_strtoul(argv[1], 10, &override)) | |
738 | adjust_vdd(override); /* the value is checked by callee */ | |
739 | else | |
740 | return CMD_RET_USAGE; | |
741 | return 0; | |
742 | } | |
743 | ||
744 | static int do_vdd_read(cmd_tbl_t *cmdtp, | |
745 | int flag, int argc, | |
746 | char * const argv[]) | |
747 | { | |
748 | if (argc < 1) | |
749 | return CMD_RET_USAGE; | |
750 | print_vdd(); | |
751 | ||
752 | return 0; | |
753 | } | |
754 | ||
755 | U_BOOT_CMD( | |
756 | vdd_override, 2, 0, do_vdd_override, | |
757 | "override VDD", | |
758 | " - override with the voltage specified in mV, eg. 1050" | |
759 | ); | |
760 | ||
761 | U_BOOT_CMD( | |
762 | vdd_read, 1, 0, do_vdd_read, | |
763 | "read VDD", | |
764 | " - Read the voltage specified in mV" | |
765 | ) |