@@ -201,10 +201,15 @@ struct ccsr_gur {
u32 gpporcr3;
u32 gpporcr4;
u8 res_030[0x60-0x30];
-#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT 2
+#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT 25
#define FSL_CHASSIS3_DCFG_FUSESR_VID_MASK 0x1F
-#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT 7
+#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT 20
#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK 0x1F
+#define FSL_CHASSIS3_DCFG_FUSESR_LOW_VID_SHIFT 2
+#define FSL_CHASSIS3_DCFG_FUSESR_LOW_VID_MASK 0x1F
+#define FSL_CHASSIS3_DCFG_FUSESR_LOW_ALTVID_SHIFT 7
+#define FSL_CHASSIS3_DCFG_FUSESR_LOW_ALTVID_MASK 0x1F
+ u8 res_030[0x60-0x30];
u32 dcfg_fusesr; /* Fuse status register */
u8 res_064[0x70-0x64];
u32 devdisr; /* Device disable control 1 */
@@ -11,6 +11,7 @@
#ifdef CONFIG_FSL_LSCH2
#include <asm/arch/immap_lsch2.h>
#elif defined(CONFIG_FSL_LSCH3)
+#include <asm/arch/soc.h>
#include <asm/arch/immap_lsch3.h>
#else
#include <asm/immap_85xx.h>
@@ -33,8 +34,42 @@ int __weak board_vdd_drop_compensation(void)
return 0;
}
+#if defined(CONFIG_VOL_MONITOR_LTC3882)
+/* Helper function to write a mV value as LTC L16 into the chip,
+ * returning a boolean for success */
+static int write_l16_mV_LTC3882(int i2caddress, int cmd, int mv)
+{
+ int wait, vdd_last, l16;
+ int ret;
+ u8 buf[2];
+
+ /* Scale mV to L16 */
+ l16 = mv;
+ l16 <<= 12;
+ l16 /= 1000;
+ debug("VID: cmd 0x%02x voltage write 0x%04x\n", cmd, l16);
+ buf[0] = (l16 & 0xff);
+ buf[1] = (l16 >> 8);
+
+ /* This code assumes that both channels run the very
+ * SAME voltage. This is likely true for LS2 style
+ * devices. For any other configuration, all hell will
+ * break loose!
+ */
+ ret = i2c_write(i2caddress, LTC3882_PAGE, 1,
+ (void *)"\377", 1);
+ if (!ret)
+ ret = i2c_write(i2caddress, cmd, 1,
+ (void *)&buf[0], 2);
+ if (!ret)
+ ret = i2c_write(i2caddress, LTC3882_PAGE, 1,
+ (void *)"\0", 1);
+ return ret;
+}
+#endif
+
/*
- * Get the i2c address configuration for the IR regulator chip
+ * Get the i2c address configuration for the regulator chip
*
* There are some variance in the RDB HW regarding the I2C address configuration
* for the IR regulator chip, which is likely a problem of external resistor
@@ -45,9 +80,13 @@ int __weak board_vdd_drop_compensation(void)
* 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
* 0x09 (Verified on T1040RDB-PA)
* 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
+ *
+ * For other types of regulator chips, we check the IDs before we
+ * return the address to avoid making damaging mistakes
*/
-static int find_ir_chip_on_i2c(void)
+static int find_vid_chip_on_i2c(void)
{
+#if defined(CONFIG_VOL_MONITOR_IR36021_READ) || defined(CONFIG_VOL_MONITOR_IR36021_SET)
int i2caddress;
int ret;
u8 byte;
@@ -63,6 +102,23 @@ static int find_ir_chip_on_i2c(void)
if ((ret >= 0) && (byte == IR36021_MFR_ID))
return i2caddress;
}
+#endif
+#if defined(CONFIG_VOL_MONITOR_LTC3882)
+ int i2caddress = I2C_VOL_MONITOR_ADDR;
+ int ret;
+ u8 buf[8];
+
+ ret = i2c_read(i2caddress,
+ LTC3882_MFR_ID, 1, (void *)&buf[0],
+ 4);
+ if (!ret && memcmp(buf, "\3LTC", 4) == 0) {
+ ret = i2c_read(i2caddress,
+ LTC3882_MFR_MODEL, 1, (void *)&buf[0],
+ 8);
+ if (!ret && memcmp(buf, "\7LTC3882", 8) == 0)
+ return i2caddress;
+ }
+#endif
return -1;
}
@@ -83,10 +139,15 @@ static int find_ir_chip_on_i2c(void)
#ifdef CONFIG_VOL_MONITOR_INA220
#define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
#define ADC_MIN_ACCURACY 4
-#else
+#endif
+#ifdef CONFIG_VOL_MONITOR_IR36021_READ
#define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */
#define ADC_MIN_ACCURACY 4
#endif
+#ifdef CONFIG_VOL_MONITOR_LTC3882
+#define WAIT_FOR_ADC 0
+#define ADC_MIN_ACCURACY 4
+#endif
#ifdef CONFIG_VOL_MONITOR_INA220
static int read_voltage_from_INA220(int i2caddress)
@@ -98,7 +159,7 @@ static int read_voltage_from_INA220(int i2caddress)
for (i = 0; i < NUM_READINGS; i++) {
ret = i2c_read(I2C_VOL_MONITOR_ADDR,
I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
- (void *)&buf, 2);
+ (void *)&buf[0], 2);
if (ret) {
printf("VID: failed to read core voltage\n");
return ret;
@@ -141,23 +202,43 @@ static int read_voltage_from_IR(int i2caddress)
printf("VID: Core voltage sensor error\n");
return -1;
}
- debug("VID: bus voltage reads 0x%02x\n", vol_mon);
- /* Resolution is 1/128V. We scale up here to get 1/128mV
- * and divide at the end
- */
- voltage_read += vol_mon * 1000;
+ debug("VID: Core voltage reads 0x%02x\n", vol_mon);
+ voltage_read += vol_mon;
udelay(WAIT_FOR_ADC);
}
/* Scale down to the real mV as IR resolution is 1/128V, rounding up */
+ voltage_read *= 1000;
voltage_read = DIV_ROUND_UP(voltage_read, 128);
/* calculate the average */
voltage_read /= NUM_READINGS;
- /* Compensate for a board specific voltage drop between regulator and
- * SoC before converting into an IR VID value
- */
- voltage_read -= board_vdd_drop_compensation();
+ return voltage_read;
+}
+#endif
+
+/* read voltage from LTC3882 */
+#ifdef CONFIG_VOL_MONITOR_LTC3882
+static int read_voltage_from_LTC3882(int i2caddress)
+{
+ int ret, voltage_read = 0;
+ int vol_mon;
+ u8 buf[2];
+
+ ret = i2c_read(i2caddress,
+ LTC3882_READ_VOUT, 1,
+ (void *)&buf[0], 2);
+ if (ret) {
+ printf("VID: failed to read core voltage\n");
+ return ret;
+ }
+ vol_mon = (buf[1] << 8) | buf[0];
+
+ /* Scale L16 to mV */
+ debug("VID: Core voltage reads 0x%04x\n", vol_mon);
+ vol_mon *= 1000;
+ voltage_read = DIV_ROUND_UP(vol_mon, 4096);
+ debug("VID: Core voltage reads as %d mV\n", voltage_read);
return voltage_read;
}
@@ -170,9 +251,19 @@ static int read_voltage(int i2caddress)
voltage_read = read_voltage_from_INA220(i2caddress);
#elif defined CONFIG_VOL_MONITOR_IR36021_READ
voltage_read = read_voltage_from_IR(i2caddress);
+#elif defined CONFIG_VOL_MONITOR_LTC3882
+ voltage_read = read_voltage_from_LTC3882(i2caddress);
#else
- return -1;
+ voltage_read = -1;
#endif
+ if (voltage_read >= 0)
+ {
+ /* Compensate for a board specific voltage drop between regulator and
+ * SoC before converting into an IR VID value
+ */
+ voltage_read -= board_vdd_drop_compensation();
+ }
+
return voltage_read;
}
@@ -198,6 +289,8 @@ static int wait_for_new_voltage(int vdd, int i2caddress)
for (timeout = 0;
abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
+ debug("VID: waiting for delta %d mV <-> %d mV to disappear\n", vdd, vdd_current);
+ udelay(1000);
vdd_current = read_voltage(i2caddress);
}
if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
@@ -216,18 +309,18 @@ static int wait_for_voltage_stable(int i2caddress)
int timeout, vdd_current, vdd;
vdd = read_voltage(i2caddress);
- udelay(NUM_READINGS * WAIT_FOR_ADC);
+ udelay(1000);
/* wait until voltage is stable */
vdd_current = read_voltage(i2caddress);
/* The maximum timeout is
- * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
+ * MAX_LOOP_WAIT_VOL_STABLE * (1000µs + NUM_READINGS * WAIT_FOR_ADC)
*/
for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
timeout > 0; timeout--) {
vdd = vdd_current;
- udelay(NUM_READINGS * WAIT_FOR_ADC);
+ udelay(1000);
vdd_current = read_voltage(i2caddress);
}
if (timeout == 0)
@@ -242,16 +335,27 @@ static int set_voltage_to_IR(int i2caddress, int vdd)
int wait, vdd_last;
int ret;
u8 vid;
+ u8 buf;
- /* Compensate for a board specific voltage drop between regulator and
- * SoC before converting into an IR VID value
- */
- vdd += board_vdd_drop_compensation();
-#ifdef CONFIG_FSL_LSCH2
- vid = DIV_ROUND_UP(vdd - 265, 5);
-#else
- vid = DIV_ROUND_UP(vdd - 245, 5);
-#endif
+ /* check if IR chip works in Intel mode*/
+ ret = i2c_read(i2caddress,
+ IR36021_INTEL_MODE_OOFSET,
+ 1, (void *)&buf, 1);
+ if (ret) {
+ printf("VID: failed to read IR chip mode.\n");
+ return -1;
+ }
+ if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
+ /* AMD SVI2 mode. */
+ /* An increase by 5 in the VID value causes a decrease
+ * by 4/128V in the output rail, -6.25mV per step.
+ * The scale appears to be 0V based starting from 0xf8.
+ */
+ vid = 248 - DIV_ROUND_UP(vdd * 4, 25);
+ } else {
+ /* Intel mode */
+ vid = DIV_ROUND_UP(vdd - 245, 5);
+ }
ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
1, (void *)&vid, sizeof(vid));
@@ -262,7 +366,35 @@ static int set_voltage_to_IR(int i2caddress, int vdd)
wait = wait_for_new_voltage(vdd, i2caddress);
if (wait < 0)
return -1;
- debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
+
+ debug("VID: Waited %d us\n", wait * (1000 + NUM_READINGS * WAIT_FOR_ADC));
+
+ vdd_last = wait_for_voltage_stable(i2caddress);
+ if (vdd_last < 0)
+ return -1;
+ debug("VID: Current voltage is %d mV\n", vdd_last);
+ return vdd_last;
+}
+#endif
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882
+/* Set the voltage to the LTC3882 chip */
+static int set_voltage_to_LTC3882(int i2caddress, int vdd)
+{
+ int wait, vdd_last;
+ int ret;
+
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_COMMAND,
+ vdd);
+ if (ret) {
+ printf("VID: failed to write VID\n");
+ return -1;
+ }
+ wait = wait_for_new_voltage(vdd, i2caddress);
+ if (wait < 0)
+ return -1;
+ debug("VID: Waited %d us\n", wait * (1000 + NUM_READINGS * WAIT_FOR_ADC));
vdd_last = wait_for_voltage_stable(i2caddress);
if (vdd_last < 0)
@@ -276,185 +408,110 @@ static int set_voltage(int i2caddress, int vdd)
{
int vdd_last = -1;
+ /* Compensate for a board specific voltage drop between regulator and
+ * SoC before converting into a VID value
+ */
+ vdd += board_vdd_drop_compensation();
#ifdef CONFIG_VOL_MONITOR_IR36021_SET
vdd_last = set_voltage_to_IR(i2caddress, vdd);
+#elif defined(CONFIG_VOL_MONITOR_LTC3882)
+ vdd_last = set_voltage_to_LTC3882(i2caddress, vdd);
#else
#error Specific voltage monitor must be defined
#endif
return vdd_last;
}
-#ifdef CONFIG_FSL_LSCH3
-int adjust_vdd(ulong vdd_override)
+#if defined(CONFIG_FSL_LSCH3)
+static bool soc_has_lowbitsinfusesr(struct ccsr_gur *gur)
{
- int re_enable = disable_interrupts();
- struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
- u32 fusesr;
- u8 vid, buf;
- int vdd_target, vdd_current, vdd_last;
- int ret, i2caddress;
- unsigned long vdd_string_override;
- char *vdd_string;
- static const uint16_t vdd[32] = {
- 10500,
- 0, /* reserved */
- 9750,
- 0, /* reserved */
- 9500,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 10000, /* 1.0000V */
- 0, /* reserved */
- 10250,
- 0, /* reserved */
- 10500,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- };
- struct vdd_drive {
- u8 vid;
- unsigned voltage;
- };
- ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
- if (ret) {
- debug("VID: I2C failed to switch channel\n");
- ret = -1;
- goto exit;
- }
- ret = find_ir_chip_on_i2c();
- if (ret < 0) {
- printf("VID: Could not find voltage regulator on I2C.\n");
- ret = -1;
- goto exit;
- } else {
- i2caddress = ret;
- debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
- }
+ u32 svr = in_le32(&gur->svr);
- /* check IR chip work on Intel mode*/
- ret = i2c_read(i2caddress,
- IR36021_INTEL_MODE_OOFSET,
- 1, (void *)&buf, 1);
- if (ret) {
- printf("VID: failed to read IR chip mode.\n");
- ret = -1;
- goto exit;
- }
- if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
- printf("VID: IR Chip is not used in Intel mode.\n");
- ret = -1;
- goto exit;
+ /* LS2088A derivatives have different FUSESR */
+ switch(SVR_SOC_VER(svr)) {
+ case SVR_LS2088A:
+ case SVR_LS2048A:
+ case SVR_LS2084A:
+ case SVR_LS2044A:
+ return true;
}
- /* get the voltage ID from fuse status register */
- fusesr = in_le32(&gur->dcfg_fusesr);
- vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
- FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
- if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
- vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
- FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
- }
- vdd_target = vdd[vid];
+ return false;
+}
+#endif
- /* check override variable for overriding VDD */
- vdd_string = env_get(CONFIG_VID_FLS_ENV);
- if (vdd_override == 0 && vdd_string &&
- !strict_strtoul(vdd_string, 10, &vdd_string_override))
- vdd_override = vdd_string_override;
+int vid_set_mv_limits(int absmax,
+ int marginhigh, int marginlow,
+ int ovfault, int ovwarn,
+ int uvwarn, int uvfault)
+{
+ int ret;
+ int i2caddress;
- if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
- vdd_target = vdd_override * 10; /* convert to 1/10 mV */
- debug("VDD override is %lu\n", vdd_override);
- } else if (vdd_override != 0) {
- printf("Invalid value.\n");
+ ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
+ if (ret) {
+ debug("VID: I2C failed to switch channel\n");
+ return ret;
}
+ i2caddress = find_vid_chip_on_i2c();
- /* divide and round up by 10 to get a value in mV */
- vdd_target = DIV_ROUND_UP(vdd_target, 10);
- if (vdd_target == 0) {
- debug("VID: VID not used\n");
- ret = 0;
- goto exit;
- } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) {
- /* Check vdd_target is in valid range */
- printf("VID: Target VID %d mV is not in range.\n",
- vdd_target);
+#if defined(CONFIG_VOL_MONITOR_LTC3882)
+ if (i2caddress >= 0) {
+ /* We need to program the voltage limits
+ * properly, or the chip may freak out on
+ * VID changes.
+ */
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_MAX,
+ absmax);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_MARGIN_HIGH,
+ marginhigh);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_MARGIN_LOW,
+ marginlow);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_OV_FAULT_LIMIT,
+ ovfault);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_OV_WARN_LIMIT,
+ ovwarn);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_UV_WARN_LIMIT,
+ uvwarn);
+ if (!ret)
+ ret = write_l16_mV_LTC3882(i2caddress,
+ LTC3882_VOUT_UV_FAULT_LIMIT,
+ uvfault);
+ } else
ret = -1;
- goto exit;
- } else {
- debug("VID: vid = %d mV\n", vdd_target);
- }
- /*
- * Read voltage monitor to check real voltage.
- */
- vdd_last = read_voltage(i2caddress);
- if (vdd_last < 0) {
- printf("VID: Couldn't read sensor abort VID adjustment\n");
- ret = -1;
- goto exit;
- }
- vdd_current = vdd_last;
- debug("VID: Core voltage is currently at %d mV\n", vdd_last);
- /*
- * Adjust voltage to at or one step above target.
- * As measurements are less precise than setting the values
- * we may run through dummy steps that cancel each other
- * when stepping up and then down.
- */
- while (vdd_last > 0 &&
- vdd_last < vdd_target) {
- vdd_current += IR_VDD_STEP_UP;
- vdd_last = set_voltage(i2caddress, vdd_current);
- }
- while (vdd_last > 0 &&
- vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
- vdd_current -= IR_VDD_STEP_DOWN;
- vdd_last = set_voltage(i2caddress, vdd_current);
- }
+#endif
+ if (ret)
+ printf("VID: Setting voltage limits failed! VID regulation may not be stable!\n");
- if (vdd_last > 0)
- printf("VID: Core voltage after adjustment is at %d mV\n",
- vdd_last);
- else
- ret = -1;
-exit:
- if (re_enable)
- enable_interrupts();
i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
+
return ret;
}
-#else /* !CONFIG_FSL_LSCH3 */
+
int adjust_vdd(ulong vdd_override)
{
int re_enable = disable_interrupts();
-#if defined(CONFIG_FSL_LSCH2)
+#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3)
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
#else
ccsr_gur_t __iomem *gur =
(void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
u32 fusesr;
- u8 vid, buf;
+ u8 vid;
int vdd_target, vdd_current, vdd_last;
int ret, i2caddress;
unsigned long vdd_string_override;
@@ -498,33 +555,22 @@ int adjust_vdd(ulong vdd_override)
ret = -1;
goto exit;
}
- ret = find_ir_chip_on_i2c();
+ ret = find_vid_chip_on_i2c();
if (ret < 0) {
printf("VID: Could not find voltage regulator on I2C.\n");
ret = -1;
goto exit;
} else {
i2caddress = ret;
- debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
- }
-
- /* check IR chip work on Intel mode*/
- ret = i2c_read(i2caddress,
- IR36021_INTEL_MODE_OOFSET,
- 1, (void *)&buf, 1);
- if (ret) {
- printf("VID: failed to read IR chip mode.\n");
- ret = -1;
- goto exit;
- }
- if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
- printf("VID: IR Chip is not used in Intel mode.\n");
- ret = -1;
- goto exit;
+ debug("VID: Voltage regulator found on I2C address 0x%02x\n", i2caddress);
}
/* get the voltage ID from fuse status register */
+#ifdef CONFIG_FSL_LSCH3
+ fusesr = in_le32(&gur->dcfg_fusesr);
+#else
fusesr = in_be32(&gur->dcfg_fusesr);
+#endif
/*
* VID is used according to the table below
* ---------------------------------------
@@ -549,6 +595,22 @@ int adjust_vdd(ulong vdd_override)
vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
}
+#elif defined(CONFIG_FSL_LSCH3)
+ if(soc_has_lowbitsinfusesr(gur)) {
+ vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_LOW_ALTVID_SHIFT) &
+ FSL_CHASSIS3_DCFG_FUSESR_LOW_ALTVID_MASK;
+ if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_LOW_ALTVID_MASK)) {
+ vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_LOW_VID_SHIFT) &
+ FSL_CHASSIS3_DCFG_FUSESR_LOW_VID_MASK;
+ }
+ } else {
+ vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
+ FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
+ if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
+ vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
+ FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
+ }
+ }
#else
vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
@@ -568,7 +630,7 @@ int adjust_vdd(ulong vdd_override)
vdd_target = vdd_override * 10; /* convert to 1/10 mV */
debug("VDD override is %lu\n", vdd_override);
} else if (vdd_override != 0) {
- printf("Invalid value.\n");
+ printf("VID: Invalid override value %lu mV.\n", vdd_override);
}
if (vdd_target == 0) {
debug("VID: VID not used\n");
@@ -577,7 +639,7 @@ int adjust_vdd(ulong vdd_override)
} else {
/* divide and round up by 10 to get a value in mV */
vdd_target = DIV_ROUND_UP(vdd_target, 10);
- debug("VID: vid = %d mV\n", vdd_target);
+ printf("VID: SoC target voltage = %d mV\n", vdd_target);
}
/*
@@ -598,19 +660,23 @@ int adjust_vdd(ulong vdd_override)
* when stepping up and then down.
*/
while (vdd_last > 0 &&
- vdd_last < vdd_target) {
+ vdd_last < vdd_target &&
+ vdd_current < vdd_target) {
vdd_current += IR_VDD_STEP_UP;
vdd_last = set_voltage(i2caddress, vdd_current);
}
while (vdd_last > 0 &&
- vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
+ vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1) &&
+ vdd_current > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
vdd_current -= IR_VDD_STEP_DOWN;
vdd_last = set_voltage(i2caddress, vdd_current);
}
- if (vdd_last > 0)
+ if (vdd_last > 0) {
printf("VID: Core voltage after adjustment is at %d mV\n",
vdd_last);
+ ret = 0;
+ }
else
ret = -1;
exit:
@@ -621,7 +687,6 @@ exit:
return ret;
}
-#endif
static int print_vdd(void)
{
@@ -629,16 +694,16 @@ static int print_vdd(void)
ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
if (ret) {
- debug("VID : I2c failed to switch channel\n");
+ debug("VID : I2C failed to switch channel\n");
return -1;
}
- ret = find_ir_chip_on_i2c();
+ ret = find_vid_chip_on_i2c();
if (ret < 0) {
printf("VID: Could not find voltage regulator on I2C.\n");
goto exit;
} else {
i2caddress = ret;
- debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
+ debug("VID: Chip found on I2C address 0x%02x\n", i2caddress);
}
/*
@@ -16,9 +16,28 @@
#define IR36021_INTEL_MODE 0x00
#define IR36021_AMD_MODE 0x20
+/* Declarations for the LTC3882 */
+#define LTC3882_PAGE 0x00
+#define LTC3882_VOUT_COMMAND 0x21
+#define LTC3882_VOUT_MAX 0x24
+#define LTC3882_VOUT_MARGIN_HIGH 0x25
+#define LTC3882_VOUT_MARGIN_LOW 0x26
+#define LTC3882_VOUT_OV_FAULT_LIMIT 0x40
+#define LTC3882_VOUT_OV_WARN_LIMIT 0x42
+#define LTC3882_VOUT_UV_WARN_LIMIT 0x43
+#define LTC3882_VOUT_UV_FAULT_LIMIT 0x44
+#define LTC3882_READ_VOUT 0x8B
+#define LTC3882_MFR_ID 0x99
+#define LTC3882_MFR_MODEL 0x9A
+
/* step the IR regulator in 5mV increments */
#define IR_VDD_STEP_DOWN 5
#define IR_VDD_STEP_UP 5
+
+int vid_set_mv_limits(int absmax,
+ int marginhigh, int marginlow,
+ int ovfault, int ovwarn,
+ int uvwarn, int uvfault);
int adjust_vdd(ulong vdd_override);
#endif /* __VID_H_ */