blob: 84cb43fad56a457c2747dbe5e747e992db8916a7 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ying Zhang8876a512014-10-31 18:06:18 +08002/*
3 * Copyright 2014 Freescale Semiconductor, Inc.
Priyanka Singhadfb3a62021-04-19 11:15:04 +05304 * Copyright 2020-21 NXP
Stephen Carlsonc3301a22021-02-08 11:11:29 +01005 * Copyright 2020 Stephen Carlson <stcarlso@linux.microsoft.com>
Ying Zhang8876a512014-10-31 18:06:18 +08006 */
7
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <config.h>
Ying Zhang8876a512014-10-31 18:06:18 +08009#include <command.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060010#include <env.h>
Ying Zhang8876a512014-10-31 18:06:18 +080011#include <i2c.h>
Simon Glass8f3f7612019-11-14 12:57:42 -070012#include <irq_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060014#include <vsprintf.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080015#include <asm/io.h>
Shaohui Xie085ac1c2016-09-07 17:56:14 +080016#ifdef CONFIG_FSL_LSCH2
Shaohui Xiedd335672015-11-11 17:58:37 +080017#include <asm/arch/immap_lsch2.h>
Rai Harninder6aa1f3b2016-03-23 17:04:38 +053018#elif defined(CONFIG_FSL_LSCH3)
19#include <asm/arch/immap_lsch3.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080020#else
Ying Zhang8876a512014-10-31 18:06:18 +080021#include <asm/immap_85xx.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080022#endif
Simon Glassdbd79542020-05-10 11:40:11 -060023#include <linux/delay.h>
Stephen Carlsone36d49c2021-06-22 16:35:20 -070024#include "i2c_common.h"
Ying Zhang8876a512014-10-31 18:06:18 +080025#include "vid.h"
26
Stephen Carlsone36d49c2021-06-22 16:35:20 -070027#ifndef I2C_VOL_MONITOR_BUS
28#define I2C_VOL_MONITOR_BUS 0
29#endif
30
Stephen Carlsonc3301a22021-02-08 11:11:29 +010031/* Voltages are generally handled in mV to keep them as integers */
32#define MV_PER_V 1000
33
34/*
35 * Select the channel on the I2C mux (on some NXP boards) that contains
36 * the voltage regulator to use for VID. Return 0 for success or nonzero
37 * for failure.
38 */
Ying Zhang8876a512014-10-31 18:06:18 +080039int __weak i2c_multiplexer_select_vid_channel(u8 channel)
40{
41 return 0;
42}
43
44/*
Stephen Carlsonc3301a22021-02-08 11:11:29 +010045 * Compensate for a board specific voltage drop between regulator and SoC.
46 * Returns the voltage offset in mV.
Ying Zhang8876a512014-10-31 18:06:18 +080047 */
48int __weak board_vdd_drop_compensation(void)
49{
50 return 0;
51}
52
53/*
Stephen Carlsonc3301a22021-02-08 11:11:29 +010054 * Performs any board specific adjustments after the VID voltage has been
55 * set. Return 0 for success or nonzero for failure.
Rajesh Bhagatc3a662f2018-01-17 16:13:02 +053056 */
57int __weak board_adjust_vdd(int vdd)
58{
Stephen Carlsonc3301a22021-02-08 11:11:29 +010059 return 0;
60}
61
62/*
63 * Processor specific method of converting the fuse value read from VID
64 * registers into the core voltage to supply. Return the voltage in mV.
65 */
66u16 __weak soc_get_fuse_vid(int vid_index)
67{
68 /* Default VDD for Layerscape Chassis 1 devices */
69 static const u16 vdd[32] = {
70 0, /* unused */
71 9875, /* 0.9875V */
72 9750,
73 9625,
74 9500,
75 9375,
76 9250,
77 9125,
78 9000,
79 8875,
80 8750,
81 8625,
82 8500,
83 8375,
84 8250,
85 8125,
86 10000, /* 1.0000V */
87 10125,
88 10250,
89 10375,
90 10500,
91 10625,
92 10750,
93 10875,
94 11000,
95 0, /* reserved */
96 };
97 return vdd[vid_index];
98}
99
100#ifndef I2C_VOL_MONITOR_ADDR
101#define I2C_VOL_MONITOR_ADDR 0
102#endif
103
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530104#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
105 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Rajesh Bhagatc3a662f2018-01-17 16:13:02 +0530106/*
Ying Zhang8876a512014-10-31 18:06:18 +0800107 * Get the i2c address configuration for the IR regulator chip
108 *
109 * There are some variance in the RDB HW regarding the I2C address configuration
110 * for the IR regulator chip, which is likely a problem of external resistor
111 * accuracy. So we just check each address in a hopefully non-intrusive mode
112 * and use the first one that seems to work
113 *
114 * The IR chip can show up under the following addresses:
115 * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
116 * 0x09 (Verified on T1040RDB-PA)
Ying Zhangff779052016-01-22 12:15:13 +0800117 * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
Ying Zhang8876a512014-10-31 18:06:18 +0800118 */
119static int find_ir_chip_on_i2c(void)
120{
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100121 int i2caddress, ret, i;
122 u8 mfrID;
Ying Zhang8876a512014-10-31 18:06:18 +0800123 const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100124 DEVICE_HANDLE_T dev;
Ying Zhang8876a512014-10-31 18:06:18 +0800125
126 /* Check all the address */
127 for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
128 i2caddress = ir_i2c_addr[i];
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700129 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100130 if (!ret) {
131 ret = I2C_READ(dev, IR36021_MFR_ID_OFFSET,
132 (void *)&mfrID, sizeof(mfrID));
133 /* If manufacturer ID matches the IR36021 */
134 if (!ret && mfrID == IR36021_MFR_ID)
135 return i2caddress;
136 }
Ying Zhang8876a512014-10-31 18:06:18 +0800137 }
138 return -1;
139}
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530140#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800141
142/* Maximum loop count waiting for new voltage to take effect */
143#define MAX_LOOP_WAIT_NEW_VOL 100
144/* Maximum loop count waiting for the voltage to be stable */
145#define MAX_LOOP_WAIT_VOL_STABLE 100
146/*
147 * read_voltage from sensor on I2C bus
148 * We use average of 4 readings, waiting for WAIT_FOR_ADC before
149 * another reading
150 */
151#define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */
152
153/* If an INA220 chip is available, we can use it to read back the voltage
154 * as it may have a higher accuracy than the IR chip for the same purpose
155 */
156#ifdef CONFIG_VOL_MONITOR_INA220
157#define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
158#define ADC_MIN_ACCURACY 4
159#else
160#define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */
161#define ADC_MIN_ACCURACY 4
162#endif
163
164#ifdef CONFIG_VOL_MONITOR_INA220
165static int read_voltage_from_INA220(int i2caddress)
166{
167 int i, ret, voltage_read = 0;
168 u16 vol_mon;
169 u8 buf[2];
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100170 DEVICE_HANDLE_T dev;
171
172 /* Open device handle */
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700173 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100174 if (ret)
175 return ret;
Ying Zhang8876a512014-10-31 18:06:18 +0800176
177 for (i = 0; i < NUM_READINGS; i++) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100178 ret = I2C_READ(dev, I2C_VOL_MONITOR_BUS_V_OFFSET,
179 (void *)&buf[0], sizeof(buf));
Ying Zhang8876a512014-10-31 18:06:18 +0800180 if (ret) {
181 printf("VID: failed to read core voltage\n");
182 return ret;
183 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100184
Ying Zhang8876a512014-10-31 18:06:18 +0800185 vol_mon = (buf[0] << 8) | buf[1];
186 if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
187 printf("VID: Core voltage sensor error\n");
188 return -1;
189 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100190
Ying Zhang8876a512014-10-31 18:06:18 +0800191 debug("VID: bus voltage reads 0x%04x\n", vol_mon);
192 /* LSB = 4mv */
193 voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
194 udelay(WAIT_FOR_ADC);
195 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100196
Ying Zhang8876a512014-10-31 18:06:18 +0800197 /* calculate the average */
198 voltage_read /= NUM_READINGS;
199
200 return voltage_read;
201}
202#endif
203
Ying Zhang8876a512014-10-31 18:06:18 +0800204#ifdef CONFIG_VOL_MONITOR_IR36021_READ
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100205/* read voltage from IR */
Ying Zhang8876a512014-10-31 18:06:18 +0800206static int read_voltage_from_IR(int i2caddress)
207{
208 int i, ret, voltage_read = 0;
209 u16 vol_mon;
210 u8 buf;
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100211 DEVICE_HANDLE_T dev;
212
213 /* Open device handle */
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700214 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100215 if (ret)
216 return ret;
Ying Zhang8876a512014-10-31 18:06:18 +0800217
218 for (i = 0; i < NUM_READINGS; i++) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100219 ret = I2C_READ(dev, IR36021_LOOP1_VOUT_OFFSET, (void *)&buf,
220 sizeof(buf));
Ying Zhang8876a512014-10-31 18:06:18 +0800221 if (ret) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100222 printf("VID: failed to read core voltage\n");
Ying Zhang8876a512014-10-31 18:06:18 +0800223 return ret;
224 }
225 vol_mon = buf;
226 if (!vol_mon) {
227 printf("VID: Core voltage sensor error\n");
228 return -1;
229 }
230 debug("VID: bus voltage reads 0x%02x\n", vol_mon);
231 /* Resolution is 1/128V. We scale up here to get 1/128mV
232 * and divide at the end
233 */
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100234 voltage_read += vol_mon * MV_PER_V;
Ying Zhang8876a512014-10-31 18:06:18 +0800235 udelay(WAIT_FOR_ADC);
236 }
237 /* Scale down to the real mV as IR resolution is 1/128V, rounding up */
238 voltage_read = DIV_ROUND_UP(voltage_read, 128);
239
240 /* calculate the average */
241 voltage_read /= NUM_READINGS;
242
243 /* Compensate for a board specific voltage drop between regulator and
244 * SoC before converting into an IR VID value
245 */
246 voltage_read -= board_vdd_drop_compensation();
247
248 return voltage_read;
249}
250#endif
251
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100252#if defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
253 defined(CONFIG_VOL_MONITOR_LTC3882_READ) || \
254 defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
255 defined(CONFIG_VOL_MONITOR_LTC3882_SET)
256
257/*
258 * The message displayed if the VOUT exponent causes a resolution
259 * worse than 1.0 V (if exponent is >= 0).
260 */
261#define VOUT_WARNING "VID: VOUT_MODE exponent has resolution worse than 1 V!\n"
262
263/* Checks the PMBus voltage monitor for the format used for voltage values */
264static int get_pmbus_multiplier(DEVICE_HANDLE_T dev)
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530265{
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100266 u8 mode;
267 int exponent, multiplier, ret;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530268
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100269 ret = I2C_READ(dev, PMBUS_CMD_VOUT_MODE, &mode, sizeof(mode));
270 if (ret) {
271 printf("VID: unable to determine voltage multiplier\n");
272 return 1;
273 }
274
275 /* Upper 3 bits is mode, lower 5 bits is exponent */
276 exponent = (int)mode & 0x1F;
277 mode >>= 5;
278 switch (mode) {
279 case 0:
280 /* Linear, 5 bit twos component exponent */
281 if (exponent & 0x10) {
282 multiplier = 1 << (16 - (exponent & 0xF));
283 } else {
284 /* If exponent is >= 0, then resolution is 1 V! */
285 printf(VOUT_WARNING);
286 multiplier = 1;
287 }
288 break;
289 case 1:
290 /* VID code identifier */
291 printf("VID: custom VID codes are not supported\n");
292 multiplier = MV_PER_V;
293 break;
294 default:
295 /* Direct, in mV */
296 multiplier = MV_PER_V;
297 break;
298 }
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800299
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100300 debug("VID: calculated multiplier is %d\n", multiplier);
301 return multiplier;
302}
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800303#endif
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100304
305#if defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
306 defined(CONFIG_VOL_MONITOR_LTC3882_READ)
307static int read_voltage_from_pmbus(int i2caddress)
308{
309 int ret, multiplier, vout;
310 u8 channel = PWM_CHANNEL0;
311 u16 vcode;
312 DEVICE_HANDLE_T dev;
313
314 /* Open device handle */
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700315 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100316 if (ret)
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530317 return ret;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530318
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100319 /* Select the right page */
320 ret = I2C_WRITE(dev, PMBUS_CMD_PAGE, &channel, sizeof(channel));
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800321 if (ret) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100322 printf("VID: failed to select VDD page %d\n", channel);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800323 return ret;
324 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100325
326 /* VOUT is little endian */
327 ret = I2C_READ(dev, PMBUS_CMD_READ_VOUT, (void *)&vcode, sizeof(vcode));
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530328 if (ret) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100329 printf("VID: failed to read core voltage\n");
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530330 return ret;
331 }
332
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100333 /* Scale down to the real mV */
334 multiplier = get_pmbus_multiplier(dev);
335 vout = (int)vcode;
336 /* Multiplier 1000 (direct mode) requires no change to convert */
337 if (multiplier != MV_PER_V)
338 vout = DIV_ROUND_UP(vout * MV_PER_V, multiplier);
339 return vout - board_vdd_drop_compensation();
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530340}
341#endif
342
Ying Zhang8876a512014-10-31 18:06:18 +0800343static int read_voltage(int i2caddress)
344{
345 int voltage_read;
346#ifdef CONFIG_VOL_MONITOR_INA220
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100347 voltage_read = read_voltage_from_INA220(I2C_VOL_MONITOR_ADDR);
Ying Zhang8876a512014-10-31 18:06:18 +0800348#elif defined CONFIG_VOL_MONITOR_IR36021_READ
349 voltage_read = read_voltage_from_IR(i2caddress);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100350#elif defined(CONFIG_VOL_MONITOR_ISL68233_READ) || \
351 defined(CONFIG_VOL_MONITOR_LTC3882_READ)
352 voltage_read = read_voltage_from_pmbus(i2caddress);
Ying Zhang8876a512014-10-31 18:06:18 +0800353#else
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100354 voltage_read = -1;
Ying Zhang8876a512014-10-31 18:06:18 +0800355#endif
356 return voltage_read;
357}
358
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530359#ifdef CONFIG_VOL_MONITOR_IR36021_SET
Ying Zhang8876a512014-10-31 18:06:18 +0800360/*
361 * We need to calculate how long before the voltage stops to drop
362 * or increase. It returns with the loop count. Each loop takes
363 * several readings (WAIT_FOR_ADC)
364 */
365static int wait_for_new_voltage(int vdd, int i2caddress)
366{
367 int timeout, vdd_current;
368
369 vdd_current = read_voltage(i2caddress);
370 /* wait until voltage starts to reach the target. Voltage slew
371 * rates by typical regulators will always lead to stable readings
372 * within each fairly long ADC interval in comparison to the
373 * intended voltage delta change until the target voltage is
374 * reached. The fairly small voltage delta change to any target
375 * VID voltage also means that this function will always complete
376 * within few iterations. If the timeout was ever reached, it would
377 * point to a serious failure in the regulator system.
378 */
379 for (timeout = 0;
380 abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
381 timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
382 vdd_current = read_voltage(i2caddress);
383 }
384 if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
385 printf("VID: Voltage adjustment timeout\n");
386 return -1;
387 }
388 return timeout;
389}
390
391/*
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100392 * Blocks and reads the VID voltage until it stabilizes, or the
Ying Zhang8876a512014-10-31 18:06:18 +0800393 * timeout expires
394 */
395static int wait_for_voltage_stable(int i2caddress)
396{
397 int timeout, vdd_current, vdd;
398
399 vdd = read_voltage(i2caddress);
400 udelay(NUM_READINGS * WAIT_FOR_ADC);
401
Ying Zhang8876a512014-10-31 18:06:18 +0800402 vdd_current = read_voltage(i2caddress);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100403 /*
404 * The maximum timeout is
Ying Zhang8876a512014-10-31 18:06:18 +0800405 * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
406 */
407 for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
408 abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
409 timeout > 0; timeout--) {
410 vdd = vdd_current;
411 udelay(NUM_READINGS * WAIT_FOR_ADC);
412 vdd_current = read_voltage(i2caddress);
413 }
414 if (timeout == 0)
415 return -1;
416 return vdd_current;
417}
418
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100419/* Sets the VID voltage using the IR36021 */
Ying Zhang8876a512014-10-31 18:06:18 +0800420static int set_voltage_to_IR(int i2caddress, int vdd)
421{
422 int wait, vdd_last;
423 int ret;
424 u8 vid;
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100425 DEVICE_HANDLE_T dev;
426
427 /* Open device handle */
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700428 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100429 if (ret)
430 return ret;
Ying Zhang8876a512014-10-31 18:06:18 +0800431
432 /* Compensate for a board specific voltage drop between regulator and
433 * SoC before converting into an IR VID value
434 */
435 vdd += board_vdd_drop_compensation();
Shaohui Xie085ac1c2016-09-07 17:56:14 +0800436#ifdef CONFIG_FSL_LSCH2
Shaohui Xiedd335672015-11-11 17:58:37 +0800437 vid = DIV_ROUND_UP(vdd - 265, 5);
438#else
Ying Zhang8876a512014-10-31 18:06:18 +0800439 vid = DIV_ROUND_UP(vdd - 245, 5);
Shaohui Xiedd335672015-11-11 17:58:37 +0800440#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800441
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100442 ret = I2C_WRITE(dev, IR36021_LOOP1_MANUAL_ID_OFFSET, (void *)&vid,
443 sizeof(vid));
Ying Zhang8876a512014-10-31 18:06:18 +0800444 if (ret) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100445 printf("VID: failed to write new voltage\n");
Ying Zhang8876a512014-10-31 18:06:18 +0800446 return -1;
447 }
448 wait = wait_for_new_voltage(vdd, i2caddress);
449 if (wait < 0)
450 return -1;
451 debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
452
453 vdd_last = wait_for_voltage_stable(i2caddress);
454 if (vdd_last < 0)
455 return -1;
456 debug("VID: Current voltage is %d mV\n", vdd_last);
457 return vdd_last;
458}
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530459#endif
460
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100461#if defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
462 defined(CONFIG_VOL_MONITOR_LTC3882_SET)
463static int set_voltage_to_pmbus(int i2caddress, int vdd)
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530464{
465 int ret, vdd_last, vdd_target = vdd;
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100466 int count = MAX_LOOP_WAIT_NEW_VOL, temp = 0, multiplier;
Biwen Li71ecd382020-10-12 20:07:35 +0800467 unsigned char value;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530468
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100469 /* The data to be sent with the PMBus command PAGE_PLUS_WRITE */
470 u8 buffer[5] = { 0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND, 0, 0 };
471 DEVICE_HANDLE_T dev;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530472
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100473 /* Open device handle */
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700474 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100475 if (ret)
476 return ret;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530477
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100478 /* Scale up to the proper value for the VOUT command, little endian */
479 multiplier = get_pmbus_multiplier(dev);
480 vdd += board_vdd_drop_compensation();
481 if (multiplier != MV_PER_V)
482 vdd = DIV_ROUND_UP(vdd * multiplier, MV_PER_V);
483 buffer[3] = vdd & 0xFF;
484 buffer[4] = (vdd & 0xFF00) >> 8;
485
Biwen Li71ecd382020-10-12 20:07:35 +0800486 /* Check write protect state */
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100487 ret = I2C_READ(dev, PMBUS_CMD_WRITE_PROTECT, (void *)&value,
488 sizeof(value));
Biwen Li71ecd382020-10-12 20:07:35 +0800489 if (ret)
490 goto exit;
491
492 if (value != EN_WRITE_ALL_CMD) {
493 value = EN_WRITE_ALL_CMD;
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100494 ret = I2C_WRITE(dev, PMBUS_CMD_WRITE_PROTECT,
Biwen Li71ecd382020-10-12 20:07:35 +0800495 (void *)&value, sizeof(value));
496 if (ret)
497 goto exit;
498 }
499
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100500 /* Write the desired voltage code to the regulator */
501 ret = I2C_WRITE(dev, PMBUS_CMD_PAGE_PLUS_WRITE, (void *)&buffer[0],
502 sizeof(buffer));
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530503 if (ret) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100504 printf("VID: I2C failed to write to the voltage regulator\n");
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530505 return -1;
506 }
507
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100508exit:
509 /* Wait for the voltage to get to the desired value */
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530510 do {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100511 vdd_last = read_voltage_from_pmbus(i2caddress);
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530512 if (vdd_last < 0) {
513 printf("VID: Couldn't read sensor abort VID adjust\n");
514 return -1;
515 }
Priyanka Jainaf89d242018-10-11 05:11:23 +0000516 count--;
517 temp = vdd_last - vdd_target;
518 } while ((abs(temp) > 2) && (count > 0));
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530519
520 return vdd_last;
521}
Ying Zhang8876a512014-10-31 18:06:18 +0800522#endif
523
524static int set_voltage(int i2caddress, int vdd)
525{
526 int vdd_last = -1;
527
528#ifdef CONFIG_VOL_MONITOR_IR36021_SET
529 vdd_last = set_voltage_to_IR(i2caddress, vdd);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100530#elif defined(CONFIG_VOL_MONITOR_ISL68233_SET) || \
531 defined(CONFIG_VOL_MONITOR_LTC3882_SET)
532 vdd_last = set_voltage_to_pmbus(i2caddress, vdd);
Ying Zhang8876a512014-10-31 18:06:18 +0800533#else
534 #error Specific voltage monitor must be defined
535#endif
536 return vdd_last;
537}
538
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530539int adjust_vdd(ulong vdd_override)
540{
541 int re_enable = disable_interrupts();
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100542#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3)
Tom Rini376b88a2022-10-28 20:27:13 -0400543 struct ccsr_gur *gur = (void *)(CFG_SYS_FSL_GUTS_ADDR);
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530544#else
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100545 ccsr_gur_t __iomem *gur =
Tom Rinid5c3bf22022-10-28 20:27:12 -0400546 (void __iomem *)(CFG_SYS_MPC85xx_GUTS_ADDR);
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530547#endif
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100548 u8 vid;
549 u32 fusesr;
550 int vdd_current, vdd_last, vdd_target;
551 int ret, i2caddress = I2C_VOL_MONITOR_ADDR;
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530552 unsigned long vdd_string_override;
553 char *vdd_string;
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530554
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530555#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
556 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100557 u8 buf;
558 DEVICE_HANDLE_T dev;
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530559#endif
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530560
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100561 /*
562 * VID is used according to the table below
563 * ---------------------------------------
564 * | DA_V |
565 * |-------------------------------------|
566 * | 5b00000 | 5b00001-5b11110 | 5b11111 |
567 * ---------------+---------+-----------------+---------|
568 * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
569 * | A |----------+---------+-----------------+---------|
570 * | _ | 5b00001 |VID = | VID = |VID = |
571 * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
572 * | _ | 5b11110 | | | |
573 * | A |----------+---------+-----------------+---------|
574 * | L | 5b11111 | No VID | VID = DA_V | NO VID |
575 * | T | | | | |
576 * ------------------------------------------------------
577 */
578#if defined(CONFIG_FSL_LSCH3)
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530579 fusesr = in_le32(&gur->dcfg_fusesr);
580 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100581 FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
582 if (vid == 0 || vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK) {
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530583 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100584 FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530585 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100586#elif defined(CONFIG_FSL_LSCH2)
587 fusesr = in_be32(&gur->dcfg_fusesr);
588 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
589 FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
590 if (vid == 0 || vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK) {
591 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
592 FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530593 }
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530594#else
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100595 fusesr = in_be32(&gur->dcfg_fusesr);
596 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
597 FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
598 if (vid == 0 || vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK) {
599 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
600 FSL_CORENET_DCFG_FUSESR_VID_MASK;
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530601 }
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530602#endif
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100603 vdd_target = soc_get_fuse_vid((int)vid);
Ying Zhang8876a512014-10-31 18:06:18 +0800604
605 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
606 if (ret) {
607 debug("VID: I2C failed to switch channel\n");
608 ret = -1;
609 goto exit;
610 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100611
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530612#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
613 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang8876a512014-10-31 18:06:18 +0800614 ret = find_ir_chip_on_i2c();
615 if (ret < 0) {
616 printf("VID: Could not find voltage regulator on I2C.\n");
617 ret = -1;
618 goto exit;
619 } else {
620 i2caddress = ret;
621 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
622 }
623
Stephen Carlsone36d49c2021-06-22 16:35:20 -0700624 ret = fsl_i2c_get_device(i2caddress, I2C_VOL_MONITOR_BUS, &dev);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100625 if (ret)
626 return ret;
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800627
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100628 /* check IR chip work on Intel mode */
629 ret = I2C_READ(dev, IR36021_INTEL_MODE_OFFSET, (void *)&buf,
630 sizeof(buf));
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800631 if (ret) {
632 printf("VID: failed to read IR chip mode.\n");
633 ret = -1;
634 goto exit;
635 }
636 if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
637 printf("VID: IR Chip is not used in Intel mode.\n");
638 ret = -1;
639 goto exit;
640 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530641#endif
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800642
Ying Zhang8876a512014-10-31 18:06:18 +0800643 /* check override variable for overriding VDD */
Simon Glass64b723f2017-08-03 12:22:12 -0600644 vdd_string = env_get(CONFIG_VID_FLS_ENV);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100645 debug("VID: Initial VDD value is %d mV\n",
646 DIV_ROUND_UP(vdd_target, 10));
Ying Zhang8876a512014-10-31 18:06:18 +0800647 if (vdd_override == 0 && vdd_string &&
648 !strict_strtoul(vdd_string, 10, &vdd_string_override))
649 vdd_override = vdd_string_override;
650 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
651 vdd_target = vdd_override * 10; /* convert to 1/10 mV */
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100652 debug("VID: VDD override is %lu\n", vdd_override);
Ying Zhang8876a512014-10-31 18:06:18 +0800653 } else if (vdd_override != 0) {
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100654 printf("VID: Invalid VDD value.\n");
Ying Zhang8876a512014-10-31 18:06:18 +0800655 }
656 if (vdd_target == 0) {
657 debug("VID: VID not used\n");
658 ret = 0;
659 goto exit;
660 } else {
661 /* divide and round up by 10 to get a value in mV */
662 vdd_target = DIV_ROUND_UP(vdd_target, 10);
663 debug("VID: vid = %d mV\n", vdd_target);
664 }
665
666 /*
667 * Read voltage monitor to check real voltage.
668 */
669 vdd_last = read_voltage(i2caddress);
670 if (vdd_last < 0) {
671 printf("VID: Couldn't read sensor abort VID adjustment\n");
672 ret = -1;
673 goto exit;
674 }
675 vdd_current = vdd_last;
676 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100677
678#if defined(CONFIG_VOL_MONITOR_LTC3882_SET) || \
679 defined(CONFIG_VOL_MONITOR_ISL68233_SET)
680 /* Set the target voltage */
681 vdd_current = set_voltage(i2caddress, vdd_target);
682 vdd_last = vdd_current;
683#else
Ying Zhang8876a512014-10-31 18:06:18 +0800684 /*
685 * Adjust voltage to at or one step above target.
686 * As measurements are less precise than setting the values
687 * we may run through dummy steps that cancel each other
688 * when stepping up and then down.
689 */
690 while (vdd_last > 0 &&
691 vdd_last < vdd_target) {
692 vdd_current += IR_VDD_STEP_UP;
693 vdd_last = set_voltage(i2caddress, vdd_current);
694 }
695 while (vdd_last > 0 &&
696 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
697 vdd_current -= IR_VDD_STEP_DOWN;
698 vdd_last = set_voltage(i2caddress, vdd_current);
699 }
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100700#endif
701
702 /* Board specific adjustments */
703 if (board_adjust_vdd(vdd_target) < 0) {
704 ret = -1;
705 goto exit;
706 }
Ying Zhang8876a512014-10-31 18:06:18 +0800707
708 if (vdd_last > 0)
709 printf("VID: Core voltage after adjustment is at %d mV\n",
710 vdd_last);
711 else
712 ret = -1;
713exit:
714 if (re_enable)
715 enable_interrupts();
Wenbin Song44ad75c2016-03-09 13:38:23 +0800716
717 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
718
Ying Zhang8876a512014-10-31 18:06:18 +0800719 return ret;
720}
721
722static int print_vdd(void)
723{
Stephen Carlsonc3301a22021-02-08 11:11:29 +0100724 int vdd_last, ret, i2caddress = I2C_VOL_MONITOR_ADDR;
Ying Zhang8876a512014-10-31 18:06:18 +0800725
726 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
727 if (ret) {
728 debug("VID : I2c failed to switch channel\n");
729 return -1;
730 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530731#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
732 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang8876a512014-10-31 18:06:18 +0800733 ret = find_ir_chip_on_i2c();
734 if (ret < 0) {
735 printf("VID: Could not find voltage regulator on I2C.\n");
Wenbin Song44ad75c2016-03-09 13:38:23 +0800736 goto exit;
Ying Zhang8876a512014-10-31 18:06:18 +0800737 } else {
738 i2caddress = ret;
739 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
740 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530741#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800742
743 /*
744 * Read voltage monitor to check real voltage.
745 */
746 vdd_last = read_voltage(i2caddress);
747 if (vdd_last < 0) {
748 printf("VID: Couldn't read sensor abort VID adjustment\n");
Wenbin Song44ad75c2016-03-09 13:38:23 +0800749 goto exit;
Ying Zhang8876a512014-10-31 18:06:18 +0800750 }
751 printf("VID: Core voltage is at %d mV\n", vdd_last);
Wenbin Song44ad75c2016-03-09 13:38:23 +0800752exit:
753 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
754
755 return ret < 0 ? -1 : 0;
Ying Zhang8876a512014-10-31 18:06:18 +0800756}
757
Simon Glassed38aef2020-05-10 11:40:03 -0600758static int do_vdd_override(struct cmd_tbl *cmdtp,
Ying Zhang8876a512014-10-31 18:06:18 +0800759 int flag, int argc,
Simon Glassed38aef2020-05-10 11:40:03 -0600760 char *const argv[])
Ying Zhang8876a512014-10-31 18:06:18 +0800761{
762 ulong override;
Priyanka Singhadfb3a62021-04-19 11:15:04 +0530763 int ret = 0;
Ying Zhang8876a512014-10-31 18:06:18 +0800764
765 if (argc < 2)
766 return CMD_RET_USAGE;
767
Priyanka Singhadfb3a62021-04-19 11:15:04 +0530768 if (!strict_strtoul(argv[1], 10, &override)) {
769 ret = adjust_vdd(override);
770 if (ret < 0)
771 return CMD_RET_FAILURE;
772 } else
Ying Zhang8876a512014-10-31 18:06:18 +0800773 return CMD_RET_USAGE;
774 return 0;
775}
776
Simon Glassed38aef2020-05-10 11:40:03 -0600777static int do_vdd_read(struct cmd_tbl *cmdtp, int flag, int argc,
778 char *const argv[])
Ying Zhang8876a512014-10-31 18:06:18 +0800779{
780 if (argc < 1)
781 return CMD_RET_USAGE;
782 print_vdd();
783
784 return 0;
785}
786
787U_BOOT_CMD(
788 vdd_override, 2, 0, do_vdd_override,
789 "override VDD",
790 " - override with the voltage specified in mV, eg. 1050"
791);
792
793U_BOOT_CMD(
794 vdd_read, 1, 0, do_vdd_read,
795 "read VDD",
796 " - Read the voltage specified in mV"
Simon Glass761d6022023-11-18 14:04:52 -0700797);