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