1
2
3
4
5
6
7#include <common.h>
8#include <command.h>
9#include <i2c.h>
10#include <asm/immap_85xx.h>
11#include "vid.h"
12
13DECLARE_GLOBAL_DATA_PTR;
14
15int __weak i2c_multiplexer_select_vid_channel(u8 channel)
16{
17 return 0;
18}
19
20
21
22
23
24int __weak board_vdd_drop_compensation(void)
25{
26 return 0;
27}
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42static int find_ir_chip_on_i2c(void)
43{
44 int i2caddress;
45 int ret;
46 u8 byte;
47 int i;
48 const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
49
50
51 for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
52 i2caddress = ir_i2c_addr[i];
53 ret = i2c_read(i2caddress,
54 IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
55 sizeof(byte));
56 if ((ret >= 0) && (byte == IR36021_MFR_ID))
57 return i2caddress;
58 }
59 return -1;
60}
61
62
63#define MAX_LOOP_WAIT_NEW_VOL 100
64
65#define MAX_LOOP_WAIT_VOL_STABLE 100
66
67
68
69
70
71#define NUM_READINGS 4
72
73
74
75
76#ifdef CONFIG_VOL_MONITOR_INA220
77#define WAIT_FOR_ADC 532
78#define ADC_MIN_ACCURACY 4
79#else
80#define WAIT_FOR_ADC 138
81#define ADC_MIN_ACCURACY 4
82#endif
83
84#ifdef CONFIG_VOL_MONITOR_INA220
85static int read_voltage_from_INA220(int i2caddress)
86{
87 int i, ret, voltage_read = 0;
88 u16 vol_mon;
89 u8 buf[2];
90
91 for (i = 0; i < NUM_READINGS; i++) {
92 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
93 I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
94 (void *)&buf, 2);
95 if (ret) {
96 printf("VID: failed to read core voltage\n");
97 return ret;
98 }
99 vol_mon = (buf[0] << 8) | buf[1];
100 if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
101 printf("VID: Core voltage sensor error\n");
102 return -1;
103 }
104 debug("VID: bus voltage reads 0x%04x\n", vol_mon);
105
106 voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
107 udelay(WAIT_FOR_ADC);
108 }
109
110 voltage_read /= NUM_READINGS;
111
112 return voltage_read;
113}
114#endif
115
116
117#ifdef CONFIG_VOL_MONITOR_IR36021_READ
118static int read_voltage_from_IR(int i2caddress)
119{
120 int i, ret, voltage_read = 0;
121 u16 vol_mon;
122 u8 buf;
123
124 for (i = 0; i < NUM_READINGS; i++) {
125 ret = i2c_read(i2caddress,
126 IR36021_LOOP1_VOUT_OFFSET,
127 1, (void *)&buf, 1);
128 if (ret) {
129 printf("VID: failed to read vcpu\n");
130 return ret;
131 }
132 vol_mon = buf;
133 if (!vol_mon) {
134 printf("VID: Core voltage sensor error\n");
135 return -1;
136 }
137 debug("VID: bus voltage reads 0x%02x\n", vol_mon);
138
139
140
141 voltage_read += vol_mon * 1000;
142 udelay(WAIT_FOR_ADC);
143 }
144
145 voltage_read = DIV_ROUND_UP(voltage_read, 128);
146
147
148 voltage_read /= NUM_READINGS;
149
150
151
152
153 voltage_read -= board_vdd_drop_compensation();
154
155 return voltage_read;
156}
157#endif
158
159static int read_voltage(int i2caddress)
160{
161 int voltage_read;
162#ifdef CONFIG_VOL_MONITOR_INA220
163 voltage_read = read_voltage_from_INA220(i2caddress);
164#elif defined CONFIG_VOL_MONITOR_IR36021_READ
165 voltage_read = read_voltage_from_IR(i2caddress);
166#else
167 return -1;
168#endif
169 return voltage_read;
170}
171
172
173
174
175
176
177static int wait_for_new_voltage(int vdd, int i2caddress)
178{
179 int timeout, vdd_current;
180
181 vdd_current = read_voltage(i2caddress);
182
183
184
185
186
187
188
189
190
191 for (timeout = 0;
192 abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
193 timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
194 vdd_current = read_voltage(i2caddress);
195 }
196 if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
197 printf("VID: Voltage adjustment timeout\n");
198 return -1;
199 }
200 return timeout;
201}
202
203
204
205
206
207static int wait_for_voltage_stable(int i2caddress)
208{
209 int timeout, vdd_current, vdd;
210
211 vdd = read_voltage(i2caddress);
212 udelay(NUM_READINGS * WAIT_FOR_ADC);
213
214
215 vdd_current = read_voltage(i2caddress);
216
217
218
219 for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
220 abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
221 timeout > 0; timeout--) {
222 vdd = vdd_current;
223 udelay(NUM_READINGS * WAIT_FOR_ADC);
224 vdd_current = read_voltage(i2caddress);
225 }
226 if (timeout == 0)
227 return -1;
228 return vdd_current;
229}
230
231#ifdef CONFIG_VOL_MONITOR_IR36021_SET
232
233static int set_voltage_to_IR(int i2caddress, int vdd)
234{
235 int wait, vdd_last;
236 int ret;
237 u8 vid;
238
239
240
241
242 vdd += board_vdd_drop_compensation();
243 vid = DIV_ROUND_UP(vdd - 245, 5);
244
245 ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
246 1, (void *)&vid, sizeof(vid));
247 if (ret) {
248 printf("VID: failed to write VID\n");
249 return -1;
250 }
251 wait = wait_for_new_voltage(vdd, i2caddress);
252 if (wait < 0)
253 return -1;
254 debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
255
256 vdd_last = wait_for_voltage_stable(i2caddress);
257 if (vdd_last < 0)
258 return -1;
259 debug("VID: Current voltage is %d mV\n", vdd_last);
260 return vdd_last;
261}
262#endif
263
264static int set_voltage(int i2caddress, int vdd)
265{
266 int vdd_last = -1;
267
268#ifdef CONFIG_VOL_MONITOR_IR36021_SET
269 vdd_last = set_voltage_to_IR(i2caddress, vdd);
270#else
271 #error Specific voltage monitor must be defined
272#endif
273 return vdd_last;
274}
275
276int adjust_vdd(ulong vdd_override)
277{
278 int re_enable = disable_interrupts();
279 ccsr_gur_t __iomem *gur =
280 (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
281 u32 fusesr;
282 u8 vid;
283 int vdd_target, vdd_current, vdd_last;
284 int ret, i2caddress;
285 unsigned long vdd_string_override;
286 char *vdd_string;
287 static const uint16_t vdd[32] = {
288 0,
289 9875,
290 9750,
291 9625,
292 9500,
293 9375,
294 9250,
295 9125,
296 9000,
297 8875,
298 8750,
299 8625,
300 8500,
301 8375,
302 8250,
303 8125,
304 10000,
305 10125,
306 10250,
307 10375,
308 10500,
309 10625,
310 10750,
311 10875,
312 11000,
313 0,
314 };
315 struct vdd_drive {
316 u8 vid;
317 unsigned voltage;
318 };
319
320 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
321 if (ret) {
322 debug("VID: I2C failed to switch channel\n");
323 ret = -1;
324 goto exit;
325 }
326 ret = find_ir_chip_on_i2c();
327 if (ret < 0) {
328 printf("VID: Could not find voltage regulator on I2C.\n");
329 ret = -1;
330 goto exit;
331 } else {
332 i2caddress = ret;
333 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
334 }
335
336
337 fusesr = in_be32(&gur->dcfg_fusesr);
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
356 FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
357 if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
358 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
359 FSL_CORENET_DCFG_FUSESR_VID_MASK;
360 }
361 vdd_target = vdd[vid];
362
363
364 vdd_string = getenv(CONFIG_VID_FLS_ENV);
365 if (vdd_override == 0 && vdd_string &&
366 !strict_strtoul(vdd_string, 10, &vdd_string_override))
367 vdd_override = vdd_string_override;
368 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
369 vdd_target = vdd_override * 10;
370 debug("VDD override is %lu\n", vdd_override);
371 } else if (vdd_override != 0) {
372 printf("Invalid value.\n");
373 }
374 if (vdd_target == 0) {
375 debug("VID: VID not used\n");
376 ret = 0;
377 goto exit;
378 } else {
379
380 vdd_target = DIV_ROUND_UP(vdd_target, 10);
381 debug("VID: vid = %d mV\n", vdd_target);
382 }
383
384
385
386
387 vdd_last = read_voltage(i2caddress);
388 if (vdd_last < 0) {
389 printf("VID: Couldn't read sensor abort VID adjustment\n");
390 ret = -1;
391 goto exit;
392 }
393 vdd_current = vdd_last;
394 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
395
396
397
398
399
400
401 while (vdd_last > 0 &&
402 vdd_last < vdd_target) {
403 vdd_current += IR_VDD_STEP_UP;
404 vdd_last = set_voltage(i2caddress, vdd_current);
405 }
406 while (vdd_last > 0 &&
407 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
408 vdd_current -= IR_VDD_STEP_DOWN;
409 vdd_last = set_voltage(i2caddress, vdd_current);
410 }
411
412 if (vdd_last > 0)
413 printf("VID: Core voltage after adjustment is at %d mV\n",
414 vdd_last);
415 else
416 ret = -1;
417exit:
418 if (re_enable)
419 enable_interrupts();
420 return ret;
421}
422
423static int print_vdd(void)
424{
425 int vdd_last, ret, i2caddress;
426
427 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
428 if (ret) {
429 debug("VID : I2c failed to switch channel\n");
430 return -1;
431 }
432 ret = find_ir_chip_on_i2c();
433 if (ret < 0) {
434 printf("VID: Could not find voltage regulator on I2C.\n");
435 return -1;
436 } else {
437 i2caddress = ret;
438 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
439 }
440
441
442
443
444 vdd_last = read_voltage(i2caddress);
445 if (vdd_last < 0) {
446 printf("VID: Couldn't read sensor abort VID adjustment\n");
447 return -1;
448 }
449 printf("VID: Core voltage is at %d mV\n", vdd_last);
450
451 return 0;
452}
453
454static int do_vdd_override(cmd_tbl_t *cmdtp,
455 int flag, int argc,
456 char * const argv[])
457{
458 ulong override;
459
460 if (argc < 2)
461 return CMD_RET_USAGE;
462
463 if (!strict_strtoul(argv[1], 10, &override))
464 adjust_vdd(override);
465 else
466 return CMD_RET_USAGE;
467 return 0;
468}
469
470static int do_vdd_read(cmd_tbl_t *cmdtp,
471 int flag, int argc,
472 char * const argv[])
473{
474 if (argc < 1)
475 return CMD_RET_USAGE;
476 print_vdd();
477
478 return 0;
479}
480
481U_BOOT_CMD(
482 vdd_override, 2, 0, do_vdd_override,
483 "override VDD",
484 " - override with the voltage specified in mV, eg. 1050"
485);
486
487U_BOOT_CMD(
488 vdd_read, 1, 0, do_vdd_read,
489 "read VDD",
490 " - Read the voltage specified in mV"
491)
492