arm: fsl: common: Improve NXP VID driver PMBus support

This patch adds support for more PMBus compatible devices to the NXP
drivers for its QorIQ family devices. At runtime, the voltage regulator is
queried over I2C, and the required voltage multiplier determined. This
change supports the DIRECT and LINEAR PMBus voltage reporting modes.

Previously, the driver only supported a few specific devices such as the
IR36021 and LTC3882, so this change allows the QorIQ series to be used
with a much larger variety of core voltage regulator devices.

checkpatch warning "Use if (IS_DEFINED (...))" was ignored to maintain
consistency with the existing code.

Signed-off-by: Stephen Carlson <stcarlso@linux.microsoft.com>
Signed-off-by: Wasim Khan <wasim.khan@nxp.com>
Tested-by: Wasim Khan <wasim.khan@nxp.com>
[Rebased]
Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c
index 20f5421..6e82962 100644
--- a/board/freescale/common/vid.c
+++ b/board/freescale/common/vid.c
@@ -2,6 +2,7 @@
 /*
  * Copyright 2014 Freescale Semiconductor, Inc.
  * Copyright 2020 NXP
+ * Copyright 2020 Stephen Carlson <stcarlso@linux.microsoft.com>
  */
 
 #include <common.h>
@@ -21,14 +22,22 @@
 #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)
 {
@@ -36,13 +45,94 @@
 }
 
 /*
- * 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)
 /*
@@ -60,30 +150,22 @@
  */
 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;
 }
@@ -117,35 +199,33 @@
 	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;
 
@@ -153,30 +233,25 @@
 }
 #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;
@@ -188,7 +263,7 @@
 		/* 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 */
@@ -206,49 +281,94 @@
 }
 #endif
 
-#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
-/* read the current value of the LTC Regulator Voltage */
-static int read_voltage_from_LTC(int i2caddress)
+#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)
+
+/*
+ * 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"
+
+/* Checks the PMBus voltage monitor for the format used for voltage values */
+static int get_pmbus_multiplier(DEVICE_HANDLE_T dev)
 {
-	int  ret, vcode = 0;
-	u8 chan = PWM_CHANNEL0;
+	u8 mode;
+	int exponent, multiplier, ret;
 
-#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;
+	ret = I2C_READ(dev, PMBUS_CMD_VOUT_MODE, &mode, sizeof(mode));
+	if (ret) {
+		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;
+	}
 
-	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);
+	debug("VID: calculated multiplier is %d\n", multiplier);
+	return multiplier;
+}
 #endif
-	if (ret) {
-		printf("VID: failed to select VDD Page 0\n");
+
+#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
 
@@ -256,13 +376,14 @@
 {
 	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;
 }
@@ -300,7 +421,7 @@
 }
 
 /*
- * 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)
@@ -310,9 +431,9 @@
 	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;
@@ -327,12 +448,18 @@
 	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
@@ -344,20 +471,10 @@
 	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);
@@ -371,81 +488,59 @@
 	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;
 
-	/* Write the desired voltage code to the regulator */
-#if !CONFIG_IS_ENABLED(DM_I2C)
+	/* 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;
+
 	/* 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;
@@ -464,325 +559,80 @@
 
 #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) {
@@ -790,6 +640,7 @@
 		ret = -1;
 		goto exit;
 	}
+
 #if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
 	defined(CONFIG_VOL_MONITOR_IR36021_READ)
 	ret = find_ir_chip_on_i2c();
@@ -802,19 +653,13 @@
 		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;
@@ -827,52 +672,18 @@
 	}
 #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");
@@ -895,6 +706,13 @@
 	}
 	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
@@ -911,6 +729,13 @@
 		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",
@@ -925,11 +750,10 @@
 
 	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) {