13ad2737eSYing Zhang /*
23ad2737eSYing Zhang * Copyright 2014 Freescale Semiconductor, Inc.
33ad2737eSYing Zhang *
43ad2737eSYing Zhang * SPDX-License-Identifier: GPL-2.0+
53ad2737eSYing Zhang */
63ad2737eSYing Zhang
73ad2737eSYing Zhang #include <common.h>
83ad2737eSYing Zhang #include <command.h>
93ad2737eSYing Zhang #include <i2c.h>
1002b5d2edSShaohui Xie #include <asm/io.h>
11126fe70dSShaohui Xie #ifdef CONFIG_FSL_LSCH2
1202b5d2edSShaohui Xie #include <asm/arch/immap_lsch2.h>
13ed2530d0SRai Harninder #elif defined(CONFIG_FSL_LSCH3)
14ed2530d0SRai Harninder #include <asm/arch/immap_lsch3.h>
1502b5d2edSShaohui Xie #else
163ad2737eSYing Zhang #include <asm/immap_85xx.h>
1702b5d2edSShaohui Xie #endif
183ad2737eSYing Zhang #include "vid.h"
193ad2737eSYing Zhang
203ad2737eSYing Zhang DECLARE_GLOBAL_DATA_PTR;
213ad2737eSYing Zhang
i2c_multiplexer_select_vid_channel(u8 channel)223ad2737eSYing Zhang int __weak i2c_multiplexer_select_vid_channel(u8 channel)
233ad2737eSYing Zhang {
243ad2737eSYing Zhang return 0;
253ad2737eSYing Zhang }
263ad2737eSYing Zhang
273ad2737eSYing Zhang /*
283ad2737eSYing Zhang * Compensate for a board specific voltage drop between regulator and SoC
293ad2737eSYing Zhang * return a value in mV
303ad2737eSYing Zhang */
board_vdd_drop_compensation(void)313ad2737eSYing Zhang int __weak board_vdd_drop_compensation(void)
323ad2737eSYing Zhang {
333ad2737eSYing Zhang return 0;
343ad2737eSYing Zhang }
353ad2737eSYing Zhang
363ad2737eSYing Zhang /*
373ad2737eSYing Zhang * Get the i2c address configuration for the IR regulator chip
383ad2737eSYing Zhang *
393ad2737eSYing Zhang * There are some variance in the RDB HW regarding the I2C address configuration
403ad2737eSYing Zhang * for the IR regulator chip, which is likely a problem of external resistor
413ad2737eSYing Zhang * accuracy. So we just check each address in a hopefully non-intrusive mode
423ad2737eSYing Zhang * and use the first one that seems to work
433ad2737eSYing Zhang *
443ad2737eSYing Zhang * The IR chip can show up under the following addresses:
453ad2737eSYing Zhang * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
463ad2737eSYing Zhang * 0x09 (Verified on T1040RDB-PA)
472f66a828SYing Zhang * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
483ad2737eSYing Zhang */
find_ir_chip_on_i2c(void)493ad2737eSYing Zhang static int find_ir_chip_on_i2c(void)
503ad2737eSYing Zhang {
513ad2737eSYing Zhang int i2caddress;
523ad2737eSYing Zhang int ret;
533ad2737eSYing Zhang u8 byte;
543ad2737eSYing Zhang int i;
553ad2737eSYing Zhang const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
563ad2737eSYing Zhang
573ad2737eSYing Zhang /* Check all the address */
583ad2737eSYing Zhang for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
593ad2737eSYing Zhang i2caddress = ir_i2c_addr[i];
603ad2737eSYing Zhang ret = i2c_read(i2caddress,
613ad2737eSYing Zhang IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
623ad2737eSYing Zhang sizeof(byte));
633ad2737eSYing Zhang if ((ret >= 0) && (byte == IR36021_MFR_ID))
643ad2737eSYing Zhang return i2caddress;
653ad2737eSYing Zhang }
663ad2737eSYing Zhang return -1;
673ad2737eSYing Zhang }
683ad2737eSYing Zhang
693ad2737eSYing Zhang /* Maximum loop count waiting for new voltage to take effect */
703ad2737eSYing Zhang #define MAX_LOOP_WAIT_NEW_VOL 100
713ad2737eSYing Zhang /* Maximum loop count waiting for the voltage to be stable */
723ad2737eSYing Zhang #define MAX_LOOP_WAIT_VOL_STABLE 100
733ad2737eSYing Zhang /*
743ad2737eSYing Zhang * read_voltage from sensor on I2C bus
753ad2737eSYing Zhang * We use average of 4 readings, waiting for WAIT_FOR_ADC before
763ad2737eSYing Zhang * another reading
773ad2737eSYing Zhang */
783ad2737eSYing Zhang #define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */
793ad2737eSYing Zhang
803ad2737eSYing Zhang /* If an INA220 chip is available, we can use it to read back the voltage
813ad2737eSYing Zhang * as it may have a higher accuracy than the IR chip for the same purpose
823ad2737eSYing Zhang */
833ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_INA220
843ad2737eSYing Zhang #define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
853ad2737eSYing Zhang #define ADC_MIN_ACCURACY 4
863ad2737eSYing Zhang #else
873ad2737eSYing Zhang #define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */
883ad2737eSYing Zhang #define ADC_MIN_ACCURACY 4
893ad2737eSYing Zhang #endif
903ad2737eSYing Zhang
913ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_INA220
read_voltage_from_INA220(int i2caddress)923ad2737eSYing Zhang static int read_voltage_from_INA220(int i2caddress)
933ad2737eSYing Zhang {
943ad2737eSYing Zhang int i, ret, voltage_read = 0;
953ad2737eSYing Zhang u16 vol_mon;
963ad2737eSYing Zhang u8 buf[2];
973ad2737eSYing Zhang
983ad2737eSYing Zhang for (i = 0; i < NUM_READINGS; i++) {
993ad2737eSYing Zhang ret = i2c_read(I2C_VOL_MONITOR_ADDR,
1003ad2737eSYing Zhang I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
1013ad2737eSYing Zhang (void *)&buf, 2);
1023ad2737eSYing Zhang if (ret) {
1033ad2737eSYing Zhang printf("VID: failed to read core voltage\n");
1043ad2737eSYing Zhang return ret;
1053ad2737eSYing Zhang }
1063ad2737eSYing Zhang vol_mon = (buf[0] << 8) | buf[1];
1073ad2737eSYing Zhang if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
1083ad2737eSYing Zhang printf("VID: Core voltage sensor error\n");
1093ad2737eSYing Zhang return -1;
1103ad2737eSYing Zhang }
1113ad2737eSYing Zhang debug("VID: bus voltage reads 0x%04x\n", vol_mon);
1123ad2737eSYing Zhang /* LSB = 4mv */
1133ad2737eSYing Zhang voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
1143ad2737eSYing Zhang udelay(WAIT_FOR_ADC);
1153ad2737eSYing Zhang }
1163ad2737eSYing Zhang /* calculate the average */
1173ad2737eSYing Zhang voltage_read /= NUM_READINGS;
1183ad2737eSYing Zhang
1193ad2737eSYing Zhang return voltage_read;
1203ad2737eSYing Zhang }
1213ad2737eSYing Zhang #endif
1223ad2737eSYing Zhang
1233ad2737eSYing Zhang /* read voltage from IR */
1243ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_IR36021_READ
read_voltage_from_IR(int i2caddress)1253ad2737eSYing Zhang static int read_voltage_from_IR(int i2caddress)
1263ad2737eSYing Zhang {
1273ad2737eSYing Zhang int i, ret, voltage_read = 0;
1283ad2737eSYing Zhang u16 vol_mon;
1293ad2737eSYing Zhang u8 buf;
1303ad2737eSYing Zhang
1313ad2737eSYing Zhang for (i = 0; i < NUM_READINGS; i++) {
1323ad2737eSYing Zhang ret = i2c_read(i2caddress,
1333ad2737eSYing Zhang IR36021_LOOP1_VOUT_OFFSET,
1343ad2737eSYing Zhang 1, (void *)&buf, 1);
1353ad2737eSYing Zhang if (ret) {
1363ad2737eSYing Zhang printf("VID: failed to read vcpu\n");
1373ad2737eSYing Zhang return ret;
1383ad2737eSYing Zhang }
1393ad2737eSYing Zhang vol_mon = buf;
1403ad2737eSYing Zhang if (!vol_mon) {
1413ad2737eSYing Zhang printf("VID: Core voltage sensor error\n");
1423ad2737eSYing Zhang return -1;
1433ad2737eSYing Zhang }
1443ad2737eSYing Zhang debug("VID: bus voltage reads 0x%02x\n", vol_mon);
1453ad2737eSYing Zhang /* Resolution is 1/128V. We scale up here to get 1/128mV
1463ad2737eSYing Zhang * and divide at the end
1473ad2737eSYing Zhang */
1483ad2737eSYing Zhang voltage_read += vol_mon * 1000;
1493ad2737eSYing Zhang udelay(WAIT_FOR_ADC);
1503ad2737eSYing Zhang }
1513ad2737eSYing Zhang /* Scale down to the real mV as IR resolution is 1/128V, rounding up */
1523ad2737eSYing Zhang voltage_read = DIV_ROUND_UP(voltage_read, 128);
1533ad2737eSYing Zhang
1543ad2737eSYing Zhang /* calculate the average */
1553ad2737eSYing Zhang voltage_read /= NUM_READINGS;
1563ad2737eSYing Zhang
1573ad2737eSYing Zhang /* Compensate for a board specific voltage drop between regulator and
1583ad2737eSYing Zhang * SoC before converting into an IR VID value
1593ad2737eSYing Zhang */
1603ad2737eSYing Zhang voltage_read -= board_vdd_drop_compensation();
1613ad2737eSYing Zhang
1623ad2737eSYing Zhang return voltage_read;
1633ad2737eSYing Zhang }
1643ad2737eSYing Zhang #endif
1653ad2737eSYing Zhang
read_voltage(int i2caddress)1663ad2737eSYing Zhang static int read_voltage(int i2caddress)
1673ad2737eSYing Zhang {
1683ad2737eSYing Zhang int voltage_read;
1693ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_INA220
1703ad2737eSYing Zhang voltage_read = read_voltage_from_INA220(i2caddress);
1713ad2737eSYing Zhang #elif defined CONFIG_VOL_MONITOR_IR36021_READ
1723ad2737eSYing Zhang voltage_read = read_voltage_from_IR(i2caddress);
1733ad2737eSYing Zhang #else
1743ad2737eSYing Zhang return -1;
1753ad2737eSYing Zhang #endif
1763ad2737eSYing Zhang return voltage_read;
1773ad2737eSYing Zhang }
1783ad2737eSYing Zhang
1793ad2737eSYing Zhang /*
1803ad2737eSYing Zhang * We need to calculate how long before the voltage stops to drop
1813ad2737eSYing Zhang * or increase. It returns with the loop count. Each loop takes
1823ad2737eSYing Zhang * several readings (WAIT_FOR_ADC)
1833ad2737eSYing Zhang */
wait_for_new_voltage(int vdd,int i2caddress)1843ad2737eSYing Zhang static int wait_for_new_voltage(int vdd, int i2caddress)
1853ad2737eSYing Zhang {
1863ad2737eSYing Zhang int timeout, vdd_current;
1873ad2737eSYing Zhang
1883ad2737eSYing Zhang vdd_current = read_voltage(i2caddress);
1893ad2737eSYing Zhang /* wait until voltage starts to reach the target. Voltage slew
1903ad2737eSYing Zhang * rates by typical regulators will always lead to stable readings
1913ad2737eSYing Zhang * within each fairly long ADC interval in comparison to the
1923ad2737eSYing Zhang * intended voltage delta change until the target voltage is
1933ad2737eSYing Zhang * reached. The fairly small voltage delta change to any target
1943ad2737eSYing Zhang * VID voltage also means that this function will always complete
1953ad2737eSYing Zhang * within few iterations. If the timeout was ever reached, it would
1963ad2737eSYing Zhang * point to a serious failure in the regulator system.
1973ad2737eSYing Zhang */
1983ad2737eSYing Zhang for (timeout = 0;
1993ad2737eSYing Zhang abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
2003ad2737eSYing Zhang timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
2013ad2737eSYing Zhang vdd_current = read_voltage(i2caddress);
2023ad2737eSYing Zhang }
2033ad2737eSYing Zhang if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
2043ad2737eSYing Zhang printf("VID: Voltage adjustment timeout\n");
2053ad2737eSYing Zhang return -1;
2063ad2737eSYing Zhang }
2073ad2737eSYing Zhang return timeout;
2083ad2737eSYing Zhang }
2093ad2737eSYing Zhang
2103ad2737eSYing Zhang /*
2113ad2737eSYing Zhang * this function keeps reading the voltage until it is stable or until the
2123ad2737eSYing Zhang * timeout expires
2133ad2737eSYing Zhang */
wait_for_voltage_stable(int i2caddress)2143ad2737eSYing Zhang static int wait_for_voltage_stable(int i2caddress)
2153ad2737eSYing Zhang {
2163ad2737eSYing Zhang int timeout, vdd_current, vdd;
2173ad2737eSYing Zhang
2183ad2737eSYing Zhang vdd = read_voltage(i2caddress);
2193ad2737eSYing Zhang udelay(NUM_READINGS * WAIT_FOR_ADC);
2203ad2737eSYing Zhang
2213ad2737eSYing Zhang /* wait until voltage is stable */
2223ad2737eSYing Zhang vdd_current = read_voltage(i2caddress);
2233ad2737eSYing Zhang /* The maximum timeout is
2243ad2737eSYing Zhang * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
2253ad2737eSYing Zhang */
2263ad2737eSYing Zhang for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
2273ad2737eSYing Zhang abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
2283ad2737eSYing Zhang timeout > 0; timeout--) {
2293ad2737eSYing Zhang vdd = vdd_current;
2303ad2737eSYing Zhang udelay(NUM_READINGS * WAIT_FOR_ADC);
2313ad2737eSYing Zhang vdd_current = read_voltage(i2caddress);
2323ad2737eSYing Zhang }
2333ad2737eSYing Zhang if (timeout == 0)
2343ad2737eSYing Zhang return -1;
2353ad2737eSYing Zhang return vdd_current;
2363ad2737eSYing Zhang }
2373ad2737eSYing Zhang
2383ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_IR36021_SET
2393ad2737eSYing Zhang /* Set the voltage to the IR chip */
set_voltage_to_IR(int i2caddress,int vdd)2403ad2737eSYing Zhang static int set_voltage_to_IR(int i2caddress, int vdd)
2413ad2737eSYing Zhang {
2423ad2737eSYing Zhang int wait, vdd_last;
2433ad2737eSYing Zhang int ret;
2443ad2737eSYing Zhang u8 vid;
2453ad2737eSYing Zhang
2463ad2737eSYing Zhang /* Compensate for a board specific voltage drop between regulator and
2473ad2737eSYing Zhang * SoC before converting into an IR VID value
2483ad2737eSYing Zhang */
2493ad2737eSYing Zhang vdd += board_vdd_drop_compensation();
250126fe70dSShaohui Xie #ifdef CONFIG_FSL_LSCH2
25102b5d2edSShaohui Xie vid = DIV_ROUND_UP(vdd - 265, 5);
25202b5d2edSShaohui Xie #else
2533ad2737eSYing Zhang vid = DIV_ROUND_UP(vdd - 245, 5);
25402b5d2edSShaohui Xie #endif
2553ad2737eSYing Zhang
2563ad2737eSYing Zhang ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
2573ad2737eSYing Zhang 1, (void *)&vid, sizeof(vid));
2583ad2737eSYing Zhang if (ret) {
2593ad2737eSYing Zhang printf("VID: failed to write VID\n");
2603ad2737eSYing Zhang return -1;
2613ad2737eSYing Zhang }
2623ad2737eSYing Zhang wait = wait_for_new_voltage(vdd, i2caddress);
2633ad2737eSYing Zhang if (wait < 0)
2643ad2737eSYing Zhang return -1;
2653ad2737eSYing Zhang debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
2663ad2737eSYing Zhang
2673ad2737eSYing Zhang vdd_last = wait_for_voltage_stable(i2caddress);
2683ad2737eSYing Zhang if (vdd_last < 0)
2693ad2737eSYing Zhang return -1;
2703ad2737eSYing Zhang debug("VID: Current voltage is %d mV\n", vdd_last);
2713ad2737eSYing Zhang return vdd_last;
2723ad2737eSYing Zhang }
2733ad2737eSYing Zhang #endif
2743ad2737eSYing Zhang
set_voltage(int i2caddress,int vdd)2753ad2737eSYing Zhang static int set_voltage(int i2caddress, int vdd)
2763ad2737eSYing Zhang {
2773ad2737eSYing Zhang int vdd_last = -1;
2783ad2737eSYing Zhang
2793ad2737eSYing Zhang #ifdef CONFIG_VOL_MONITOR_IR36021_SET
2803ad2737eSYing Zhang vdd_last = set_voltage_to_IR(i2caddress, vdd);
2813ad2737eSYing Zhang #else
2823ad2737eSYing Zhang #error Specific voltage monitor must be defined
2833ad2737eSYing Zhang #endif
2843ad2737eSYing Zhang return vdd_last;
2853ad2737eSYing Zhang }
2863ad2737eSYing Zhang
28729ca713cSPriyanka Jain #ifdef CONFIG_FSL_LSCH3
adjust_vdd(ulong vdd_override)2883ad2737eSYing Zhang int adjust_vdd(ulong vdd_override)
2893ad2737eSYing Zhang {
2903ad2737eSYing Zhang int re_enable = disable_interrupts();
29129ca713cSPriyanka Jain struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
29229ca713cSPriyanka Jain u32 fusesr;
29329ca713cSPriyanka Jain u8 vid, buf;
29429ca713cSPriyanka Jain int vdd_target, vdd_current, vdd_last;
29529ca713cSPriyanka Jain int ret, i2caddress;
29629ca713cSPriyanka Jain unsigned long vdd_string_override;
29729ca713cSPriyanka Jain char *vdd_string;
29829ca713cSPriyanka Jain static const uint16_t vdd[32] = {
29929ca713cSPriyanka Jain 10500,
30029ca713cSPriyanka Jain 0, /* reserved */
30129ca713cSPriyanka Jain 9750,
30229ca713cSPriyanka Jain 0, /* reserved */
30329ca713cSPriyanka Jain 9500,
30429ca713cSPriyanka Jain 0, /* reserved */
30529ca713cSPriyanka Jain 0, /* reserved */
30629ca713cSPriyanka Jain 0, /* reserved */
30729ca713cSPriyanka Jain 0, /* reserved */
30829ca713cSPriyanka Jain 0, /* reserved */
30929ca713cSPriyanka Jain 0, /* reserved */
31029ca713cSPriyanka Jain 0, /* reserved */
31129ca713cSPriyanka Jain 0, /* reserved */
31229ca713cSPriyanka Jain 0, /* reserved */
31329ca713cSPriyanka Jain 0, /* reserved */
31429ca713cSPriyanka Jain 0, /* reserved */
31529ca713cSPriyanka Jain 10000, /* 1.0000V */
31629ca713cSPriyanka Jain 0, /* reserved */
31729ca713cSPriyanka Jain 10250,
31829ca713cSPriyanka Jain 0, /* reserved */
31929ca713cSPriyanka Jain 10500,
32029ca713cSPriyanka Jain 0, /* reserved */
32129ca713cSPriyanka Jain 0, /* reserved */
32229ca713cSPriyanka Jain 0, /* reserved */
32329ca713cSPriyanka Jain 0, /* reserved */
32429ca713cSPriyanka Jain 0, /* reserved */
32529ca713cSPriyanka Jain 0, /* reserved */
32629ca713cSPriyanka Jain 0, /* reserved */
32729ca713cSPriyanka Jain 0, /* reserved */
32829ca713cSPriyanka Jain 0, /* reserved */
32929ca713cSPriyanka Jain 0, /* reserved */
33029ca713cSPriyanka Jain 0, /* reserved */
33129ca713cSPriyanka Jain };
33229ca713cSPriyanka Jain struct vdd_drive {
33329ca713cSPriyanka Jain u8 vid;
33429ca713cSPriyanka Jain unsigned voltage;
33529ca713cSPriyanka Jain };
33629ca713cSPriyanka Jain
33729ca713cSPriyanka Jain ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
33829ca713cSPriyanka Jain if (ret) {
33929ca713cSPriyanka Jain debug("VID: I2C failed to switch channel\n");
34029ca713cSPriyanka Jain ret = -1;
34129ca713cSPriyanka Jain goto exit;
34229ca713cSPriyanka Jain }
34329ca713cSPriyanka Jain ret = find_ir_chip_on_i2c();
34429ca713cSPriyanka Jain if (ret < 0) {
34529ca713cSPriyanka Jain printf("VID: Could not find voltage regulator on I2C.\n");
34629ca713cSPriyanka Jain ret = -1;
34729ca713cSPriyanka Jain goto exit;
34829ca713cSPriyanka Jain } else {
34929ca713cSPriyanka Jain i2caddress = ret;
35029ca713cSPriyanka Jain debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
35129ca713cSPriyanka Jain }
35229ca713cSPriyanka Jain
35329ca713cSPriyanka Jain /* check IR chip work on Intel mode*/
35429ca713cSPriyanka Jain ret = i2c_read(i2caddress,
35529ca713cSPriyanka Jain IR36021_INTEL_MODE_OOFSET,
35629ca713cSPriyanka Jain 1, (void *)&buf, 1);
35729ca713cSPriyanka Jain if (ret) {
35829ca713cSPriyanka Jain printf("VID: failed to read IR chip mode.\n");
35929ca713cSPriyanka Jain ret = -1;
36029ca713cSPriyanka Jain goto exit;
36129ca713cSPriyanka Jain }
36229ca713cSPriyanka Jain if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
36329ca713cSPriyanka Jain printf("VID: IR Chip is not used in Intel mode.\n");
36429ca713cSPriyanka Jain ret = -1;
36529ca713cSPriyanka Jain goto exit;
36629ca713cSPriyanka Jain }
36729ca713cSPriyanka Jain
36829ca713cSPriyanka Jain /* get the voltage ID from fuse status register */
36929ca713cSPriyanka Jain fusesr = in_le32(&gur->dcfg_fusesr);
37029ca713cSPriyanka Jain vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
37129ca713cSPriyanka Jain FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
37229ca713cSPriyanka Jain if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
37329ca713cSPriyanka Jain vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
37429ca713cSPriyanka Jain FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
37529ca713cSPriyanka Jain }
37629ca713cSPriyanka Jain vdd_target = vdd[vid];
37729ca713cSPriyanka Jain
37829ca713cSPriyanka Jain /* check override variable for overriding VDD */
379*00caae6dSSimon Glass vdd_string = env_get(CONFIG_VID_FLS_ENV);
38029ca713cSPriyanka Jain if (vdd_override == 0 && vdd_string &&
38129ca713cSPriyanka Jain !strict_strtoul(vdd_string, 10, &vdd_string_override))
38229ca713cSPriyanka Jain vdd_override = vdd_string_override;
38329ca713cSPriyanka Jain
38429ca713cSPriyanka Jain if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
38529ca713cSPriyanka Jain vdd_target = vdd_override * 10; /* convert to 1/10 mV */
38629ca713cSPriyanka Jain debug("VDD override is %lu\n", vdd_override);
38729ca713cSPriyanka Jain } else if (vdd_override != 0) {
38829ca713cSPriyanka Jain printf("Invalid value.\n");
38929ca713cSPriyanka Jain }
39029ca713cSPriyanka Jain
39129ca713cSPriyanka Jain /* divide and round up by 10 to get a value in mV */
39229ca713cSPriyanka Jain vdd_target = DIV_ROUND_UP(vdd_target, 10);
39329ca713cSPriyanka Jain if (vdd_target == 0) {
39429ca713cSPriyanka Jain debug("VID: VID not used\n");
39529ca713cSPriyanka Jain ret = 0;
39629ca713cSPriyanka Jain goto exit;
39729ca713cSPriyanka Jain } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) {
39829ca713cSPriyanka Jain /* Check vdd_target is in valid range */
39929ca713cSPriyanka Jain printf("VID: Target VID %d mV is not in range.\n",
40029ca713cSPriyanka Jain vdd_target);
40129ca713cSPriyanka Jain ret = -1;
40229ca713cSPriyanka Jain goto exit;
40329ca713cSPriyanka Jain } else {
40429ca713cSPriyanka Jain debug("VID: vid = %d mV\n", vdd_target);
40529ca713cSPriyanka Jain }
40629ca713cSPriyanka Jain
40729ca713cSPriyanka Jain /*
40829ca713cSPriyanka Jain * Read voltage monitor to check real voltage.
40929ca713cSPriyanka Jain */
41029ca713cSPriyanka Jain vdd_last = read_voltage(i2caddress);
41129ca713cSPriyanka Jain if (vdd_last < 0) {
41229ca713cSPriyanka Jain printf("VID: Couldn't read sensor abort VID adjustment\n");
41329ca713cSPriyanka Jain ret = -1;
41429ca713cSPriyanka Jain goto exit;
41529ca713cSPriyanka Jain }
41629ca713cSPriyanka Jain vdd_current = vdd_last;
41729ca713cSPriyanka Jain debug("VID: Core voltage is currently at %d mV\n", vdd_last);
41829ca713cSPriyanka Jain /*
41929ca713cSPriyanka Jain * Adjust voltage to at or one step above target.
42029ca713cSPriyanka Jain * As measurements are less precise than setting the values
42129ca713cSPriyanka Jain * we may run through dummy steps that cancel each other
42229ca713cSPriyanka Jain * when stepping up and then down.
42329ca713cSPriyanka Jain */
42429ca713cSPriyanka Jain while (vdd_last > 0 &&
42529ca713cSPriyanka Jain vdd_last < vdd_target) {
42629ca713cSPriyanka Jain vdd_current += IR_VDD_STEP_UP;
42729ca713cSPriyanka Jain vdd_last = set_voltage(i2caddress, vdd_current);
42829ca713cSPriyanka Jain }
42929ca713cSPriyanka Jain while (vdd_last > 0 &&
43029ca713cSPriyanka Jain vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
43129ca713cSPriyanka Jain vdd_current -= IR_VDD_STEP_DOWN;
43229ca713cSPriyanka Jain vdd_last = set_voltage(i2caddress, vdd_current);
43329ca713cSPriyanka Jain }
43429ca713cSPriyanka Jain
43529ca713cSPriyanka Jain if (vdd_last > 0)
43629ca713cSPriyanka Jain printf("VID: Core voltage after adjustment is at %d mV\n",
43729ca713cSPriyanka Jain vdd_last);
43829ca713cSPriyanka Jain else
43929ca713cSPriyanka Jain ret = -1;
44029ca713cSPriyanka Jain exit:
44129ca713cSPriyanka Jain if (re_enable)
44229ca713cSPriyanka Jain enable_interrupts();
44329ca713cSPriyanka Jain i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
44429ca713cSPriyanka Jain return ret;
44529ca713cSPriyanka Jain }
44629ca713cSPriyanka Jain #else /* !CONFIG_FSL_LSCH3 */
adjust_vdd(ulong vdd_override)44729ca713cSPriyanka Jain int adjust_vdd(ulong vdd_override)
44829ca713cSPriyanka Jain {
44929ca713cSPriyanka Jain int re_enable = disable_interrupts();
45029ca713cSPriyanka Jain #if defined(CONFIG_FSL_LSCH2)
45102b5d2edSShaohui Xie struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
45202b5d2edSShaohui Xie #else
4533ad2737eSYing Zhang ccsr_gur_t __iomem *gur =
4543ad2737eSYing Zhang (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
45502b5d2edSShaohui Xie #endif
4563ad2737eSYing Zhang u32 fusesr;
457cabe4d2fSYing Zhang u8 vid, buf;
4583ad2737eSYing Zhang int vdd_target, vdd_current, vdd_last;
4593ad2737eSYing Zhang int ret, i2caddress;
4603ad2737eSYing Zhang unsigned long vdd_string_override;
4613ad2737eSYing Zhang char *vdd_string;
4623ad2737eSYing Zhang static const uint16_t vdd[32] = {
4633ad2737eSYing Zhang 0, /* unused */
4643ad2737eSYing Zhang 9875, /* 0.9875V */
4653ad2737eSYing Zhang 9750,
4663ad2737eSYing Zhang 9625,
4673ad2737eSYing Zhang 9500,
4683ad2737eSYing Zhang 9375,
4693ad2737eSYing Zhang 9250,
4703ad2737eSYing Zhang 9125,
4713ad2737eSYing Zhang 9000,
4723ad2737eSYing Zhang 8875,
4733ad2737eSYing Zhang 8750,
4743ad2737eSYing Zhang 8625,
4753ad2737eSYing Zhang 8500,
4763ad2737eSYing Zhang 8375,
4773ad2737eSYing Zhang 8250,
4783ad2737eSYing Zhang 8125,
4793ad2737eSYing Zhang 10000, /* 1.0000V */
4803ad2737eSYing Zhang 10125,
4813ad2737eSYing Zhang 10250,
4823ad2737eSYing Zhang 10375,
4833ad2737eSYing Zhang 10500,
4843ad2737eSYing Zhang 10625,
4853ad2737eSYing Zhang 10750,
4863ad2737eSYing Zhang 10875,
4873ad2737eSYing Zhang 11000,
4883ad2737eSYing Zhang 0, /* reserved */
4893ad2737eSYing Zhang };
4903ad2737eSYing Zhang struct vdd_drive {
4913ad2737eSYing Zhang u8 vid;
4923ad2737eSYing Zhang unsigned voltage;
4933ad2737eSYing Zhang };
4943ad2737eSYing Zhang
4953ad2737eSYing Zhang ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
4963ad2737eSYing Zhang if (ret) {
4973ad2737eSYing Zhang debug("VID: I2C failed to switch channel\n");
4983ad2737eSYing Zhang ret = -1;
4993ad2737eSYing Zhang goto exit;
5003ad2737eSYing Zhang }
5013ad2737eSYing Zhang ret = find_ir_chip_on_i2c();
5023ad2737eSYing Zhang if (ret < 0) {
5033ad2737eSYing Zhang printf("VID: Could not find voltage regulator on I2C.\n");
5043ad2737eSYing Zhang ret = -1;
5053ad2737eSYing Zhang goto exit;
5063ad2737eSYing Zhang } else {
5073ad2737eSYing Zhang i2caddress = ret;
5083ad2737eSYing Zhang debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
5093ad2737eSYing Zhang }
5103ad2737eSYing Zhang
511cabe4d2fSYing Zhang /* check IR chip work on Intel mode*/
512cabe4d2fSYing Zhang ret = i2c_read(i2caddress,
513cabe4d2fSYing Zhang IR36021_INTEL_MODE_OOFSET,
514cabe4d2fSYing Zhang 1, (void *)&buf, 1);
515cabe4d2fSYing Zhang if (ret) {
516cabe4d2fSYing Zhang printf("VID: failed to read IR chip mode.\n");
517cabe4d2fSYing Zhang ret = -1;
518cabe4d2fSYing Zhang goto exit;
519cabe4d2fSYing Zhang }
520cabe4d2fSYing Zhang if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
521cabe4d2fSYing Zhang printf("VID: IR Chip is not used in Intel mode.\n");
522cabe4d2fSYing Zhang ret = -1;
523cabe4d2fSYing Zhang goto exit;
524cabe4d2fSYing Zhang }
525cabe4d2fSYing Zhang
5263ad2737eSYing Zhang /* get the voltage ID from fuse status register */
5273ad2737eSYing Zhang fusesr = in_be32(&gur->dcfg_fusesr);
5283ad2737eSYing Zhang /*
5293ad2737eSYing Zhang * VID is used according to the table below
5303ad2737eSYing Zhang * ---------------------------------------
5313ad2737eSYing Zhang * | DA_V |
5323ad2737eSYing Zhang * |-------------------------------------|
5333ad2737eSYing Zhang * | 5b00000 | 5b00001-5b11110 | 5b11111 |
5343ad2737eSYing Zhang * ---------------+---------+-----------------+---------|
5353ad2737eSYing Zhang * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
5363ad2737eSYing Zhang * | A |----------+---------+-----------------+---------|
5373ad2737eSYing Zhang * | _ | 5b00001 |VID = | VID = |VID = |
5383ad2737eSYing Zhang * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
5393ad2737eSYing Zhang * | _ | 5b11110 | | | |
5403ad2737eSYing Zhang * | A |----------+---------+-----------------+---------|
5413ad2737eSYing Zhang * | L | 5b11111 | No VID | VID = DA_V | NO VID |
5423ad2737eSYing Zhang * | T | | | | |
5433ad2737eSYing Zhang * ------------------------------------------------------
5443ad2737eSYing Zhang */
545126fe70dSShaohui Xie #ifdef CONFIG_FSL_LSCH2
54602b5d2edSShaohui Xie vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
54702b5d2edSShaohui Xie FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
54802b5d2edSShaohui Xie if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
54902b5d2edSShaohui Xie vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
55002b5d2edSShaohui Xie FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
55102b5d2edSShaohui Xie }
55202b5d2edSShaohui Xie #else
5533ad2737eSYing Zhang vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
5543ad2737eSYing Zhang FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
5553ad2737eSYing Zhang if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
5563ad2737eSYing Zhang vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
5573ad2737eSYing Zhang FSL_CORENET_DCFG_FUSESR_VID_MASK;
5583ad2737eSYing Zhang }
55902b5d2edSShaohui Xie #endif
5603ad2737eSYing Zhang vdd_target = vdd[vid];
5613ad2737eSYing Zhang
5623ad2737eSYing Zhang /* check override variable for overriding VDD */
563*00caae6dSSimon Glass vdd_string = env_get(CONFIG_VID_FLS_ENV);
5643ad2737eSYing Zhang if (vdd_override == 0 && vdd_string &&
5653ad2737eSYing Zhang !strict_strtoul(vdd_string, 10, &vdd_string_override))
5663ad2737eSYing Zhang vdd_override = vdd_string_override;
5673ad2737eSYing Zhang if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
5683ad2737eSYing Zhang vdd_target = vdd_override * 10; /* convert to 1/10 mV */
5693ad2737eSYing Zhang debug("VDD override is %lu\n", vdd_override);
5703ad2737eSYing Zhang } else if (vdd_override != 0) {
5713ad2737eSYing Zhang printf("Invalid value.\n");
5723ad2737eSYing Zhang }
5733ad2737eSYing Zhang if (vdd_target == 0) {
5743ad2737eSYing Zhang debug("VID: VID not used\n");
5753ad2737eSYing Zhang ret = 0;
5763ad2737eSYing Zhang goto exit;
5773ad2737eSYing Zhang } else {
5783ad2737eSYing Zhang /* divide and round up by 10 to get a value in mV */
5793ad2737eSYing Zhang vdd_target = DIV_ROUND_UP(vdd_target, 10);
5803ad2737eSYing Zhang debug("VID: vid = %d mV\n", vdd_target);
5813ad2737eSYing Zhang }
5823ad2737eSYing Zhang
5833ad2737eSYing Zhang /*
5843ad2737eSYing Zhang * Read voltage monitor to check real voltage.
5853ad2737eSYing Zhang */
5863ad2737eSYing Zhang vdd_last = read_voltage(i2caddress);
5873ad2737eSYing Zhang if (vdd_last < 0) {
5883ad2737eSYing Zhang printf("VID: Couldn't read sensor abort VID adjustment\n");
5893ad2737eSYing Zhang ret = -1;
5903ad2737eSYing Zhang goto exit;
5913ad2737eSYing Zhang }
5923ad2737eSYing Zhang vdd_current = vdd_last;
5933ad2737eSYing Zhang debug("VID: Core voltage is currently at %d mV\n", vdd_last);
5943ad2737eSYing Zhang /*
5953ad2737eSYing Zhang * Adjust voltage to at or one step above target.
5963ad2737eSYing Zhang * As measurements are less precise than setting the values
5973ad2737eSYing Zhang * we may run through dummy steps that cancel each other
5983ad2737eSYing Zhang * when stepping up and then down.
5993ad2737eSYing Zhang */
6003ad2737eSYing Zhang while (vdd_last > 0 &&
6013ad2737eSYing Zhang vdd_last < vdd_target) {
6023ad2737eSYing Zhang vdd_current += IR_VDD_STEP_UP;
6033ad2737eSYing Zhang vdd_last = set_voltage(i2caddress, vdd_current);
6043ad2737eSYing Zhang }
6053ad2737eSYing Zhang while (vdd_last > 0 &&
6063ad2737eSYing Zhang vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
6073ad2737eSYing Zhang vdd_current -= IR_VDD_STEP_DOWN;
6083ad2737eSYing Zhang vdd_last = set_voltage(i2caddress, vdd_current);
6093ad2737eSYing Zhang }
6103ad2737eSYing Zhang
6113ad2737eSYing Zhang if (vdd_last > 0)
6123ad2737eSYing Zhang printf("VID: Core voltage after adjustment is at %d mV\n",
6133ad2737eSYing Zhang vdd_last);
6143ad2737eSYing Zhang else
6153ad2737eSYing Zhang ret = -1;
6163ad2737eSYing Zhang exit:
6173ad2737eSYing Zhang if (re_enable)
6183ad2737eSYing Zhang enable_interrupts();
6191be8d10bSWenbin Song
6201be8d10bSWenbin Song i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
6211be8d10bSWenbin Song
6223ad2737eSYing Zhang return ret;
6233ad2737eSYing Zhang }
62429ca713cSPriyanka Jain #endif
6253ad2737eSYing Zhang
print_vdd(void)6263ad2737eSYing Zhang static int print_vdd(void)
6273ad2737eSYing Zhang {
6283ad2737eSYing Zhang int vdd_last, ret, i2caddress;
6293ad2737eSYing Zhang
6303ad2737eSYing Zhang ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
6313ad2737eSYing Zhang if (ret) {
6323ad2737eSYing Zhang debug("VID : I2c failed to switch channel\n");
6333ad2737eSYing Zhang return -1;
6343ad2737eSYing Zhang }
6353ad2737eSYing Zhang ret = find_ir_chip_on_i2c();
6363ad2737eSYing Zhang if (ret < 0) {
6373ad2737eSYing Zhang printf("VID: Could not find voltage regulator on I2C.\n");
6381be8d10bSWenbin Song goto exit;
6393ad2737eSYing Zhang } else {
6403ad2737eSYing Zhang i2caddress = ret;
6413ad2737eSYing Zhang debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
6423ad2737eSYing Zhang }
6433ad2737eSYing Zhang
6443ad2737eSYing Zhang /*
6453ad2737eSYing Zhang * Read voltage monitor to check real voltage.
6463ad2737eSYing Zhang */
6473ad2737eSYing Zhang vdd_last = read_voltage(i2caddress);
6483ad2737eSYing Zhang if (vdd_last < 0) {
6493ad2737eSYing Zhang printf("VID: Couldn't read sensor abort VID adjustment\n");
6501be8d10bSWenbin Song goto exit;
6513ad2737eSYing Zhang }
6523ad2737eSYing Zhang printf("VID: Core voltage is at %d mV\n", vdd_last);
6531be8d10bSWenbin Song exit:
6541be8d10bSWenbin Song i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
6553ad2737eSYing Zhang
6561be8d10bSWenbin Song return ret < 0 ? -1 : 0;
6571be8d10bSWenbin Song
6583ad2737eSYing Zhang }
6593ad2737eSYing Zhang
do_vdd_override(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])6603ad2737eSYing Zhang static int do_vdd_override(cmd_tbl_t *cmdtp,
6613ad2737eSYing Zhang int flag, int argc,
6623ad2737eSYing Zhang char * const argv[])
6633ad2737eSYing Zhang {
6643ad2737eSYing Zhang ulong override;
6653ad2737eSYing Zhang
6663ad2737eSYing Zhang if (argc < 2)
6673ad2737eSYing Zhang return CMD_RET_USAGE;
6683ad2737eSYing Zhang
6693ad2737eSYing Zhang if (!strict_strtoul(argv[1], 10, &override))
6703ad2737eSYing Zhang adjust_vdd(override); /* the value is checked by callee */
6713ad2737eSYing Zhang else
6723ad2737eSYing Zhang return CMD_RET_USAGE;
6733ad2737eSYing Zhang return 0;
6743ad2737eSYing Zhang }
6753ad2737eSYing Zhang
do_vdd_read(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])6763ad2737eSYing Zhang static int do_vdd_read(cmd_tbl_t *cmdtp,
6773ad2737eSYing Zhang int flag, int argc,
6783ad2737eSYing Zhang char * const argv[])
6793ad2737eSYing Zhang {
6803ad2737eSYing Zhang if (argc < 1)
6813ad2737eSYing Zhang return CMD_RET_USAGE;
6823ad2737eSYing Zhang print_vdd();
6833ad2737eSYing Zhang
6843ad2737eSYing Zhang return 0;
6853ad2737eSYing Zhang }
6863ad2737eSYing Zhang
6873ad2737eSYing Zhang U_BOOT_CMD(
6883ad2737eSYing Zhang vdd_override, 2, 0, do_vdd_override,
6893ad2737eSYing Zhang "override VDD",
6903ad2737eSYing Zhang " - override with the voltage specified in mV, eg. 1050"
6913ad2737eSYing Zhang );
6923ad2737eSYing Zhang
6933ad2737eSYing Zhang U_BOOT_CMD(
6943ad2737eSYing Zhang vdd_read, 1, 0, do_vdd_read,
6953ad2737eSYing Zhang "read VDD",
6963ad2737eSYing Zhang " - Read the voltage specified in mV"
6973ad2737eSYing Zhang )
698