/*
* Copyright 2014 Freescale Semiconductor, Inc.
* Copyright 2020 NXP
+ * Copyright 2020 Stephen Carlson <stcarlso@linux.microsoft.com>
*/
#include <common.h>
#include <linux/delay.h>
#include "vid.h"
+/* Voltages are generally handled in mV to keep them as integers */
+#define MV_PER_V 1000
+
+/*
+ * Select the channel on the I2C mux (on some NXP boards) that contains
+ * the voltage regulator to use for VID. Return 0 for success or nonzero
+ * for failure.
+ */
int __weak i2c_multiplexer_select_vid_channel(u8 channel)
{
return 0;
}
/*
- * Compensate for a board specific voltage drop between regulator and SoC
- * return a value in mV
+ * Compensate for a board specific voltage drop between regulator and SoC.
+ * Returns the voltage offset in mV.
*/
int __weak board_vdd_drop_compensation(void)
{
}
/*
- * Board specific settings for specific voltage value
+ * Performs any board specific adjustments after the VID voltage has been
+ * set. Return 0 for success or nonzero for failure.
*/
int __weak board_adjust_vdd(int vdd)
{
return 0;
}
+/*
+ * Processor specific method of converting the fuse value read from VID
+ * registers into the core voltage to supply. Return the voltage in mV.
+ */
+u16 __weak soc_get_fuse_vid(int vid_index)
+{
+ /* Default VDD for Layerscape Chassis 1 devices */
+ static const u16 vdd[32] = {
+ 0, /* unused */
+ 9875, /* 0.9875V */
+ 9750,
+ 9625,
+ 9500,
+ 9375,
+ 9250,
+ 9125,
+ 9000,
+ 8875,
+ 8750,
+ 8625,
+ 8500,
+ 8375,
+ 8250,
+ 8125,
+ 10000, /* 1.0000V */
+ 10125,
+ 10250,
+ 10375,
+ 10500,
+ 10625,
+ 10750,
+ 10875,
+ 11000,
+ 0, /* reserved */
+ };
+ return vdd[vid_index];
+}
+
+#ifndef I2C_VOL_MONITOR_ADDR
+#define I2C_VOL_MONITOR_ADDR 0
+#endif
+
+#if CONFIG_IS_ENABLED(DM_I2C)
+#define DEVICE_HANDLE_T struct udevice *
+
+#ifndef I2C_VOL_MONITOR_BUS
+#define I2C_VOL_MONITOR_BUS 0
+#endif
+
+/* If DM is in use, retrieve the udevice chip for the specified bus number */
+static int vid_get_device(int address, DEVICE_HANDLE_T *dev)
+{
+ int ret = i2c_get_chip_for_busnum(I2C_VOL_MONITOR_BUS, address, 1, dev);
+
+ if (ret)
+ printf("VID: Bus %d has no device with address 0x%02X\n",
+ I2C_VOL_MONITOR_BUS, address);
+ return ret;
+}
+
+#define I2C_READ(dev, register, data, length) \
+ dm_i2c_read(dev, register, data, length)
+#define I2C_WRITE(dev, register, data, length) \
+ dm_i2c_write(dev, register, data, length)
+#else
+#define DEVICE_HANDLE_T int
+
+/* If DM is not in use, I2C addresses are passed directly */
+static int vid_get_device(int address, DEVICE_HANDLE_T *dev)
+{
+ *dev = address;
+ return 0;
+}
+
+#define I2C_READ(dev, register, data, length) \
+ i2c_read(dev, register, 1, data, length)
+#define I2C_WRITE(dev, register, data, length) \
+ i2c_write(dev, register, 1, data, length)
+#endif
+
#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
defined(CONFIG_VOL_MONITOR_IR36021_READ)
/*
*/
static int find_ir_chip_on_i2c(void)
{
- int i2caddress;
- int ret;
- u8 byte;
- int i;
+ int i2caddress, ret, i;
+ u8 mfrID;
const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
-#if CONFIG_IS_ENABLED(DM_I2C)
- struct udevice *dev;
-#endif
+ DEVICE_HANDLE_T dev;
/* Check all the address */
for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
i2caddress = ir_i2c_addr[i];
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_read(i2caddress,
- IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
- sizeof(byte));
-#else
- ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
- if (!ret)
- ret = dm_i2c_read(dev, IR36021_MFR_ID_OFFSET,
- (void *)&byte, sizeof(byte));
-#endif
- if ((ret >= 0) && (byte == IR36021_MFR_ID))
- return i2caddress;
+ ret = vid_get_device(i2caddress, &dev);
+ if (!ret) {
+ ret = I2C_READ(dev, IR36021_MFR_ID_OFFSET,
+ (void *)&mfrID, sizeof(mfrID));
+ /* If manufacturer ID matches the IR36021 */
+ if (!ret && mfrID == IR36021_MFR_ID)
+ return i2caddress;
+ }
}
return -1;
}
int i, ret, voltage_read = 0;
u16 vol_mon;
u8 buf[2];
-#if CONFIG_IS_ENABLED(DM_I2C)
- struct udevice *dev;
-#endif
+ DEVICE_HANDLE_T dev;
+
+ /* Open device handle */
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
+ return ret;
for (i = 0; i < NUM_READINGS; i++) {
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_read(I2C_VOL_MONITOR_ADDR,
- I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
- (void *)&buf, 2);
-#else
- ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
- if (!ret)
- ret = dm_i2c_read(dev, I2C_VOL_MONITOR_BUS_V_OFFSET,
- (void *)&buf, 2);
-#endif
+ ret = I2C_READ(dev, I2C_VOL_MONITOR_BUS_V_OFFSET,
+ (void *)&buf[0], sizeof(buf));
if (ret) {
printf("VID: failed to read core voltage\n");
return ret;
}
+
vol_mon = (buf[0] << 8) | buf[1];
if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
printf("VID: Core voltage sensor error\n");
return -1;
}
+
debug("VID: bus voltage reads 0x%04x\n", vol_mon);
/* LSB = 4mv */
voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
udelay(WAIT_FOR_ADC);
}
+
/* calculate the average */
voltage_read /= NUM_READINGS;
}
#endif
-/* read voltage from IR */
#ifdef CONFIG_VOL_MONITOR_IR36021_READ
+/* read voltage from IR */
static int read_voltage_from_IR(int i2caddress)
{
int i, ret, voltage_read = 0;
u16 vol_mon;
u8 buf;
-#if CONFIG_IS_ENABLED(DM_I2C)
- struct udevice *dev;
-#endif
+ DEVICE_HANDLE_T dev;
+
+ /* Open device handle */
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
+ return ret;
for (i = 0; i < NUM_READINGS; i++) {
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_read(i2caddress,
- IR36021_LOOP1_VOUT_OFFSET,
- 1, (void *)&buf, 1);
-#else
- ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
- if (!ret)
- ret = dm_i2c_read(dev, IR36021_LOOP1_VOUT_OFFSET,
- (void *)&buf, 1);
-#endif
+ ret = I2C_READ(dev, IR36021_LOOP1_VOUT_OFFSET, (void *)&buf,
+ sizeof(buf));
if (ret) {
- printf("VID: failed to read vcpu\n");
+ printf("VID: failed to read core voltage\n");
return ret;
}
vol_mon = buf;
/* Resolution is 1/128V. We scale up here to get 1/128mV
* and divide at the end
*/
- voltage_read += vol_mon * 1000;
+ voltage_read += vol_mon * MV_PER_V;
udelay(WAIT_FOR_ADC);
}
/* Scale down to the real mV as IR resolution is 1/128V, rounding up */
}
#endif
-#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
-/* read the current value of the LTC Regulator Voltage */
-static int read_voltage_from_LTC(int i2caddress)
-{
- int ret, vcode = 0;
- u8 chan = PWM_CHANNEL0;
+#if defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_READ) || \
+ defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_SET)
-#if !CONFIG_IS_ENABLED(DM_I2C)
- /* select the PAGE 0 using PMBus commands PAGE for VDD*/
- ret = i2c_write(I2C_VOL_MONITOR_ADDR,
- PMBUS_CMD_PAGE, 1, &chan, 1);
-#else
- struct udevice *dev;
+/*
+ * The message displayed if the VOUT exponent causes a resolution
+ * worse than 1.0 V (if exponent is >= 0).
+ */
+#define VOUT_WARNING "VID: VOUT_MODE exponent has resolution worse than 1 V!\n"
- ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
- if (!ret)
- ret = dm_i2c_write(dev, PMBUS_CMD_PAGE, &chan, 1);
-#endif
+/* Checks the PMBus voltage monitor for the format used for voltage values */
+static int get_pmbus_multiplier(DEVICE_HANDLE_T dev)
+{
+ u8 mode;
+ int exponent, multiplier, ret;
+
+ ret = I2C_READ(dev, PMBUS_CMD_VOUT_MODE, &mode, sizeof(mode));
if (ret) {
- printf("VID: failed to select VDD Page 0\n");
+ printf("VID: unable to determine voltage multiplier\n");
+ return 1;
+ }
+
+ /* Upper 3 bits is mode, lower 5 bits is exponent */
+ exponent = (int)mode & 0x1F;
+ mode >>= 5;
+ switch (mode) {
+ case 0:
+ /* Linear, 5 bit twos component exponent */
+ if (exponent & 0x10) {
+ multiplier = 1 << (16 - (exponent & 0xF));
+ } else {
+ /* If exponent is >= 0, then resolution is 1 V! */
+ printf(VOUT_WARNING);
+ multiplier = 1;
+ }
+ break;
+ case 1:
+ /* VID code identifier */
+ printf("VID: custom VID codes are not supported\n");
+ multiplier = MV_PER_V;
+ break;
+ default:
+ /* Direct, in mV */
+ multiplier = MV_PER_V;
+ break;
+ }
+
+ debug("VID: calculated multiplier is %d\n", multiplier);
+ return multiplier;
+}
+#endif
+
+#if defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_READ)
+static int read_voltage_from_pmbus(int i2caddress)
+{
+ int ret, multiplier, vout;
+ u8 channel = PWM_CHANNEL0;
+ u16 vcode;
+ DEVICE_HANDLE_T dev;
+
+ /* Open device handle */
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
return ret;
- }
-#if !CONFIG_IS_ENABLED(DM_I2C)
- /*read the output voltage using PMBus command READ_VOUT*/
- ret = i2c_read(I2C_VOL_MONITOR_ADDR,
- PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2);
-#else
- ret = dm_i2c_read(dev, PMBUS_CMD_READ_VOUT, (void *)&vcode, 2);
+ /* Select the right page */
+ ret = I2C_WRITE(dev, PMBUS_CMD_PAGE, &channel, sizeof(channel));
if (ret) {
- printf("VID: failed to read the volatge\n");
+ printf("VID: failed to select VDD page %d\n", channel);
return ret;
}
-#endif
+
+ /* VOUT is little endian */
+ ret = I2C_READ(dev, PMBUS_CMD_READ_VOUT, (void *)&vcode, sizeof(vcode));
if (ret) {
- printf("VID: failed to read the volatge\n");
+ printf("VID: failed to read core voltage\n");
return ret;
}
- /* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */
- vcode = DIV_ROUND_UP(vcode * 1000, 4096);
-
- return vcode;
+ /* Scale down to the real mV */
+ multiplier = get_pmbus_multiplier(dev);
+ vout = (int)vcode;
+ /* Multiplier 1000 (direct mode) requires no change to convert */
+ if (multiplier != MV_PER_V)
+ vout = DIV_ROUND_UP(vout * MV_PER_V, multiplier);
+ return vout - board_vdd_drop_compensation();
}
#endif
{
int voltage_read;
#ifdef CONFIG_VOL_MONITOR_INA220
- voltage_read = read_voltage_from_INA220(i2caddress);
+ voltage_read = read_voltage_from_INA220(I2C_VOL_MONITOR_ADDR);
#elif defined CONFIG_VOL_MONITOR_IR36021_READ
voltage_read = read_voltage_from_IR(i2caddress);
-#elif defined CONFIG_VOL_MONITOR_LTC3882_READ
- voltage_read = read_voltage_from_LTC(i2caddress);
+#elif defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_READ)
+ voltage_read = read_voltage_from_pmbus(i2caddress);
#else
- return -1;
+ voltage_read = -1;
#endif
return voltage_read;
}
}
/*
- * this function keeps reading the voltage until it is stable or until the
+ * Blocks and reads the VID voltage until it stabilizes, or the
* timeout expires
*/
static int wait_for_voltage_stable(int i2caddress)
vdd = read_voltage(i2caddress);
udelay(NUM_READINGS * WAIT_FOR_ADC);
- /* wait until voltage is stable */
vdd_current = read_voltage(i2caddress);
- /* The maximum timeout is
+ /*
+ * The maximum timeout is
* MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
*/
for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
return vdd_current;
}
-/* Set the voltage to the IR chip */
+/* Sets the VID voltage using the IR36021 */
static int set_voltage_to_IR(int i2caddress, int vdd)
{
int wait, vdd_last;
int ret;
u8 vid;
+ DEVICE_HANDLE_T dev;
+
+ /* Open device handle */
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
+ return ret;
/* Compensate for a board specific voltage drop between regulator and
* SoC before converting into an IR VID value
vid = DIV_ROUND_UP(vdd - 245, 5);
#endif
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
- 1, (void *)&vid, sizeof(vid));
-#else
- struct udevice *dev;
-
- ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
- if (!ret)
- ret = dm_i2c_write(dev, IR36021_LOOP1_MANUAL_ID_OFFSET,
- (void *)&vid, sizeof(vid));
-
-#endif
+ ret = I2C_WRITE(dev, IR36021_LOOP1_MANUAL_ID_OFFSET, (void *)&vid,
+ sizeof(vid));
if (ret) {
- printf("VID: failed to write VID\n");
+ printf("VID: failed to write new voltage\n");
return -1;
}
wait = wait_for_new_voltage(vdd, i2caddress);
debug("VID: Current voltage is %d mV\n", vdd_last);
return vdd_last;
}
-
#endif
-#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
-/* this function sets the VDD and returns the value set */
-static int set_voltage_to_LTC(int i2caddress, int vdd)
+#if defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_SET)
+static int set_voltage_to_pmbus(int i2caddress, int vdd)
{
int ret, vdd_last, vdd_target = vdd;
- int count = 100, temp = 0;
+ int count = MAX_LOOP_WAIT_NEW_VOL, temp = 0, multiplier;
unsigned char value;
- /* Scale up to the LTC resolution is 1/4096V */
- vdd = (vdd * 4096) / 1000;
+ /* The data to be sent with the PMBus command PAGE_PLUS_WRITE */
+ u8 buffer[5] = { 0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND, 0, 0 };
+ DEVICE_HANDLE_T dev;
- /* 5-byte buffer which needs to be sent following the
- * PMBus command PAGE_PLUS_WRITE.
- */
- u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND,
- vdd & 0xFF, (vdd & 0xFF00) >> 8};
+ /* Open device handle */
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
+ return ret;
+
+ /* Scale up to the proper value for the VOUT command, little endian */
+ multiplier = get_pmbus_multiplier(dev);
+ vdd += board_vdd_drop_compensation();
+ if (multiplier != MV_PER_V)
+ vdd = DIV_ROUND_UP(vdd * multiplier, MV_PER_V);
+ buffer[3] = vdd & 0xFF;
+ buffer[4] = (vdd & 0xFF00) >> 8;
- /* Write the desired voltage code to the regulator */
-#if !CONFIG_IS_ENABLED(DM_I2C)
/* Check write protect state */
- ret = i2c_read(I2C_VOL_MONITOR_ADDR,
- PMBUS_CMD_WRITE_PROTECT, 1,
- (void *)&value, sizeof(value));
+ ret = I2C_READ(dev, PMBUS_CMD_WRITE_PROTECT, (void *)&value,
+ sizeof(value));
if (ret)
goto exit;
if (value != EN_WRITE_ALL_CMD) {
value = EN_WRITE_ALL_CMD;
- ret = i2c_write(I2C_VOL_MONITOR_ADDR,
- PMBUS_CMD_WRITE_PROTECT, 1,
+ ret = I2C_WRITE(dev, PMBUS_CMD_WRITE_PROTECT,
(void *)&value, sizeof(value));
if (ret)
goto exit;
}
- ret = i2c_write(I2C_VOL_MONITOR_ADDR,
- PMBUS_CMD_PAGE_PLUS_WRITE, 1,
- (void *)&buff, sizeof(buff));
-#else
- struct udevice *dev;
-
- ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
- if (!ret) {
- /* Check write protect state */
- ret = dm_i2c_read(dev,
- PMBUS_CMD_WRITE_PROTECT,
- (void *)&value, sizeof(value));
- if (ret)
- goto exit;
-
- if (value != EN_WRITE_ALL_CMD) {
- value = EN_WRITE_ALL_CMD;
- ret = dm_i2c_write(dev,
- PMBUS_CMD_WRITE_PROTECT,
- (void *)&value, sizeof(value));
- if (ret)
- goto exit;
- }
-
- ret = dm_i2c_write(dev, PMBUS_CMD_PAGE_PLUS_WRITE,
- (void *)&buff, sizeof(buff));
- }
-#endif
-exit:
+ /* Write the desired voltage code to the regulator */
+ ret = I2C_WRITE(dev, PMBUS_CMD_PAGE_PLUS_WRITE, (void *)&buffer[0],
+ sizeof(buffer));
if (ret) {
- printf("VID: I2C failed to write to the volatge regulator\n");
+ printf("VID: I2C failed to write to the voltage regulator\n");
return -1;
}
- /* Wait for the volatge to get to the desired value */
+exit:
+ /* Wait for the voltage to get to the desired value */
do {
- vdd_last = read_voltage_from_LTC(i2caddress);
+ vdd_last = read_voltage_from_pmbus(i2caddress);
if (vdd_last < 0) {
printf("VID: Couldn't read sensor abort VID adjust\n");
return -1;
#ifdef CONFIG_VOL_MONITOR_IR36021_SET
vdd_last = set_voltage_to_IR(i2caddress, vdd);
-#elif defined CONFIG_VOL_MONITOR_LTC3882_SET
- vdd_last = set_voltage_to_LTC(i2caddress, vdd);
+#elif defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
+ defined(CONFIG_VOL_MONITOR_LTC3882_SET)
+ vdd_last = set_voltage_to_pmbus(i2caddress, vdd);
#else
#error Specific voltage monitor must be defined
#endif
return vdd_last;
}
-#ifdef CONFIG_FSL_LSCH3
int adjust_vdd(ulong vdd_override)
{
int re_enable = disable_interrupts();
+#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3)
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
- u32 fusesr;
-#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
- defined(CONFIG_VOL_MONITOR_IR36021_READ)
- u8 vid, buf;
#else
- u8 vid;
+ ccsr_gur_t __iomem *gur =
+ (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
- int vdd_target, vdd_current, vdd_last;
- int ret, i2caddress = 0;
+ u8 vid;
+ u32 fusesr;
+ int vdd_current, vdd_last, vdd_target;
+ int ret, i2caddress = I2C_VOL_MONITOR_ADDR;
unsigned long vdd_string_override;
char *vdd_string;
-#if defined(CONFIG_ARCH_LX2160A) || defined(CONFIG_ARCH_LX2162A)
- static const u16 vdd[32] = {
- 8250,
- 7875,
- 7750,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 8000,
- 8125,
- 8250,
- 0, /* reserved */
- 8500,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- };
-#else
-#ifdef CONFIG_ARCH_LS1088A
- static const uint16_t vdd[32] = {
- 10250,
- 9875,
- 9750,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 9000,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 10000, /* 1.0000V */
- 10125,
- 10250,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- };
-#else
- static const uint16_t vdd[32] = {
- 10500,
- 0, /* reserved */
- 9750,
- 0, /* reserved */
- 9500,
- 0, /* reserved */
- 0, /* reserved */
- 0, /* reserved */
- 9000, /* 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 */
- };
-#endif
-#endif
- 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;
- }
#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
defined(CONFIG_VOL_MONITOR_IR36021_READ)
- 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);
- }
-
- /* check IR chip work on Intel mode*/
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_read(i2caddress,
- IR36021_INTEL_MODE_OOFSET,
- 1, (void *)&buf, 1);
-#else
- struct udevice *dev;
-
- ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
- if (!ret)
- ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
- (void *)&buf, 1);
-#endif
- 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;
- }
+ u8 buf;
+ DEVICE_HANDLE_T dev;
#endif
- /* get the voltage ID from fuse status register */
+ /*
+ * VID is used according to the table below
+ * ---------------------------------------
+ * | DA_V |
+ * |-------------------------------------|
+ * | 5b00000 | 5b00001-5b11110 | 5b11111 |
+ * ---------------+---------+-----------------+---------|
+ * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
+ * | A |----------+---------+-----------------+---------|
+ * | _ | 5b00001 |VID = | VID = |VID = |
+ * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
+ * | _ | 5b11110 | | | |
+ * | A |----------+---------+-----------------+---------|
+ * | L | 5b11111 | No VID | VID = DA_V | NO VID |
+ * | T | | | | |
+ * ------------------------------------------------------
+ */
+#if defined(CONFIG_FSL_LSCH3)
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)) {
+ 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];
-
- /* 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;
-
- 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");
+ FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
}
-
- /* 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);
- 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;
+#elif defined(CONFIG_FSL_LSCH2)
+ fusesr = in_be32(&gur->dcfg_fusesr);
+ vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
+ FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
+ if (vid == 0 || vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK) {
+ vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
+ FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
}
- vdd_current = vdd_last;
- debug("VID: Core voltage is currently at %d mV\n", vdd_last);
-
-#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
- /* Set the target voltage */
- vdd_last = vdd_current = set_voltage(i2caddress, vdd_target);
#else
- /*
- * 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);
+ fusesr = in_be32(&gur->dcfg_fusesr);
+ vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
+ FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
+ if (vid == 0 || vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK) {
+ vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
+ FSL_CORENET_DCFG_FUSESR_VID_MASK;
}
-
#endif
- if (board_adjust_vdd(vdd_target) < 0) {
- ret = -1;
- goto exit;
- }
-
- 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)
- 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;
- int vdd_target, vdd_current, vdd_last;
- int ret, i2caddress;
- unsigned long vdd_string_override;
- char *vdd_string;
- static const uint16_t vdd[32] = {
- 0, /* unused */
- 9875, /* 0.9875V */
- 9750,
- 9625,
- 9500,
- 9375,
- 9250,
- 9125,
- 9000,
- 8875,
- 8750,
- 8625,
- 8500,
- 8375,
- 8250,
- 8125,
- 10000, /* 1.0000V */
- 10125,
- 10250,
- 10375,
- 10500,
- 10625,
- 10750,
- 10875,
- 11000,
- 0, /* reserved */
- };
- struct vdd_drive {
- u8 vid;
- unsigned voltage;
- };
+ vdd_target = soc_get_fuse_vid((int)vid);
ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
if (ret) {
ret = -1;
goto exit;
}
+
#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
defined(CONFIG_VOL_MONITOR_IR36021_READ)
ret = find_ir_chip_on_i2c();
debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
}
- /* check IR chip work on Intel mode*/
-#if !CONFIG_IS_ENABLED(DM_I2C)
- ret = i2c_read(i2caddress,
- IR36021_INTEL_MODE_OOFSET,
- 1, (void *)&buf, 1);
-#else
- struct udevice *dev;
+ ret = vid_get_device(i2caddress, &dev);
+ if (ret)
+ return ret;
- ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
- if (!ret)
- ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
- (void *)&buf, 1);
-#endif
+ /* check IR chip work on Intel mode */
+ ret = I2C_READ(dev, IR36021_INTEL_MODE_OFFSET, (void *)&buf,
+ sizeof(buf));
if (ret) {
printf("VID: failed to read IR chip mode.\n");
ret = -1;
}
#endif
- /* get the voltage ID from fuse status register */
- fusesr = in_be32(&gur->dcfg_fusesr);
- /*
- * VID is used according to the table below
- * ---------------------------------------
- * | DA_V |
- * |-------------------------------------|
- * | 5b00000 | 5b00001-5b11110 | 5b11111 |
- * ---------------+---------+-----------------+---------|
- * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
- * | A |----------+---------+-----------------+---------|
- * | _ | 5b00001 |VID = | VID = |VID = |
- * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
- * | _ | 5b11110 | | | |
- * | A |----------+---------+-----------------+---------|
- * | L | 5b11111 | No VID | VID = DA_V | NO VID |
- * | T | | | | |
- * ------------------------------------------------------
- */
-#ifdef CONFIG_FSL_LSCH2
- vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
- FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
- if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
- vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
- FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
- }
-#else
- vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
- FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
- if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
- vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
- FSL_CORENET_DCFG_FUSESR_VID_MASK;
- }
-#endif
- vdd_target = vdd[vid];
-
/* check override variable for overriding VDD */
vdd_string = env_get(CONFIG_VID_FLS_ENV);
+ debug("VID: Initial VDD value is %d mV\n",
+ DIV_ROUND_UP(vdd_target, 10));
if (vdd_override == 0 && vdd_string &&
!strict_strtoul(vdd_string, 10, &vdd_string_override))
vdd_override = vdd_string_override;
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);
+ debug("VID: VDD override is %lu\n", vdd_override);
} else if (vdd_override != 0) {
- printf("Invalid value.\n");
+ printf("VID: Invalid VDD value.\n");
}
if (vdd_target == 0) {
debug("VID: VID not used\n");
}
vdd_current = vdd_last;
debug("VID: Core voltage is currently at %d mV\n", vdd_last);
+
+#if defined(CONFIG_VOL_MONITOR_LTC3882_SET) || \
+ defined(CONFIG_VOL_MONITOR_ISL68233_SET)
+ /* Set the target voltage */
+ vdd_current = set_voltage(i2caddress, vdd_target);
+ vdd_last = vdd_current;
+#else
/*
* Adjust voltage to at or one step above target.
* As measurements are less precise than setting the values
vdd_current -= IR_VDD_STEP_DOWN;
vdd_last = set_voltage(i2caddress, vdd_current);
}
+#endif
+
+ /* Board specific adjustments */
+ if (board_adjust_vdd(vdd_target) < 0) {
+ ret = -1;
+ goto exit;
+ }
if (vdd_last > 0)
printf("VID: Core voltage after adjustment is at %d mV\n",
return ret;
}
-#endif
static int print_vdd(void)
{
- int vdd_last, ret, i2caddress = 0;
+ int vdd_last, ret, i2caddress = I2C_VOL_MONITOR_ADDR;
ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
if (ret) {