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