blob: ed0d9b471cad02140bff6a14c6233e41bb08c1d5 [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.
Ying Zhang8876a512014-10-31 18:06:18 +08004 */
5
6#include <common.h>
7#include <command.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -06008#include <env.h>
Ying Zhang8876a512014-10-31 18:06:18 +08009#include <i2c.h>
Simon Glass8f3f7612019-11-14 12:57:42 -070010#include <irq_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080012#include <asm/io.h>
Shaohui Xie085ac1c2016-09-07 17:56:14 +080013#ifdef CONFIG_FSL_LSCH2
Shaohui Xiedd335672015-11-11 17:58:37 +080014#include <asm/arch/immap_lsch2.h>
Rai Harninder6aa1f3b2016-03-23 17:04:38 +053015#elif defined(CONFIG_FSL_LSCH3)
16#include <asm/arch/immap_lsch3.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080017#else
Ying Zhang8876a512014-10-31 18:06:18 +080018#include <asm/immap_85xx.h>
Shaohui Xiedd335672015-11-11 17:58:37 +080019#endif
Simon Glassdbd79542020-05-10 11:40:11 -060020#include <linux/delay.h>
Ying Zhang8876a512014-10-31 18:06:18 +080021#include "vid.h"
22
Ying Zhang8876a512014-10-31 18:06:18 +080023int __weak i2c_multiplexer_select_vid_channel(u8 channel)
24{
25 return 0;
26}
27
28/*
29 * Compensate for a board specific voltage drop between regulator and SoC
30 * return a value in mV
31 */
32int __weak board_vdd_drop_compensation(void)
33{
34 return 0;
35}
36
37/*
Rajesh Bhagatc3a662f2018-01-17 16:13:02 +053038 * Board specific settings for specific voltage value
39 */
40int __weak board_adjust_vdd(int vdd)
41{
42 return 0;
43}
44
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +053045#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
46 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Rajesh Bhagatc3a662f2018-01-17 16:13:02 +053047/*
Ying Zhang8876a512014-10-31 18:06:18 +080048 * Get the i2c address configuration for the IR regulator chip
49 *
50 * There are some variance in the RDB HW regarding the I2C address configuration
51 * for the IR regulator chip, which is likely a problem of external resistor
52 * accuracy. So we just check each address in a hopefully non-intrusive mode
53 * and use the first one that seems to work
54 *
55 * The IR chip can show up under the following addresses:
56 * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
57 * 0x09 (Verified on T1040RDB-PA)
Ying Zhangff779052016-01-22 12:15:13 +080058 * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
Ying Zhang8876a512014-10-31 18:06:18 +080059 */
60static int find_ir_chip_on_i2c(void)
61{
62 int i2caddress;
63 int ret;
64 u8 byte;
65 int i;
66 const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
Chuanhua Han37c2c5e2019-07-10 21:00:20 +080067#ifdef CONFIG_DM_I2C
68 struct udevice *dev;
69#endif
Ying Zhang8876a512014-10-31 18:06:18 +080070
71 /* Check all the address */
72 for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
73 i2caddress = ir_i2c_addr[i];
Chuanhua Han37c2c5e2019-07-10 21:00:20 +080074#ifndef CONFIG_DM_I2C
Ying Zhang8876a512014-10-31 18:06:18 +080075 ret = i2c_read(i2caddress,
76 IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
77 sizeof(byte));
Chuanhua Han37c2c5e2019-07-10 21:00:20 +080078#else
79 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
80 if (!ret)
81 ret = dm_i2c_read(dev, IR36021_MFR_ID_OFFSET,
82 (void *)&byte, sizeof(byte));
83#endif
Ying Zhang8876a512014-10-31 18:06:18 +080084 if ((ret >= 0) && (byte == IR36021_MFR_ID))
85 return i2caddress;
86 }
87 return -1;
88}
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +053089#endif
Ying Zhang8876a512014-10-31 18:06:18 +080090
91/* Maximum loop count waiting for new voltage to take effect */
92#define MAX_LOOP_WAIT_NEW_VOL 100
93/* Maximum loop count waiting for the voltage to be stable */
94#define MAX_LOOP_WAIT_VOL_STABLE 100
95/*
96 * read_voltage from sensor on I2C bus
97 * We use average of 4 readings, waiting for WAIT_FOR_ADC before
98 * another reading
99 */
100#define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */
101
102/* If an INA220 chip is available, we can use it to read back the voltage
103 * as it may have a higher accuracy than the IR chip for the same purpose
104 */
105#ifdef CONFIG_VOL_MONITOR_INA220
106#define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
107#define ADC_MIN_ACCURACY 4
108#else
109#define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */
110#define ADC_MIN_ACCURACY 4
111#endif
112
113#ifdef CONFIG_VOL_MONITOR_INA220
114static int read_voltage_from_INA220(int i2caddress)
115{
116 int i, ret, voltage_read = 0;
117 u16 vol_mon;
118 u8 buf[2];
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800119#ifdef CONFIG_DM_I2C
120 struct udevice *dev;
121#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800122
123 for (i = 0; i < NUM_READINGS; i++) {
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800124#ifndef CONFIG_DM_I2C
Ying Zhang8876a512014-10-31 18:06:18 +0800125 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
126 I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
127 (void *)&buf, 2);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800128#else
129 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
130 if (!ret)
131 ret = dm_i2c_read(dev, I2C_VOL_MONITOR_BUS_V_OFFSET,
132 (void *)&buf, 2);
133#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800134 if (ret) {
135 printf("VID: failed to read core voltage\n");
136 return ret;
137 }
138 vol_mon = (buf[0] << 8) | buf[1];
139 if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
140 printf("VID: Core voltage sensor error\n");
141 return -1;
142 }
143 debug("VID: bus voltage reads 0x%04x\n", vol_mon);
144 /* LSB = 4mv */
145 voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
146 udelay(WAIT_FOR_ADC);
147 }
148 /* calculate the average */
149 voltage_read /= NUM_READINGS;
150
151 return voltage_read;
152}
153#endif
154
155/* read voltage from IR */
156#ifdef CONFIG_VOL_MONITOR_IR36021_READ
157static int read_voltage_from_IR(int i2caddress)
158{
159 int i, ret, voltage_read = 0;
160 u16 vol_mon;
161 u8 buf;
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800162#ifdef CONFIG_DM_I2C
163 struct udevice *dev;
164#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800165
166 for (i = 0; i < NUM_READINGS; i++) {
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800167#ifndef CONFIG_DM_I2C
Ying Zhang8876a512014-10-31 18:06:18 +0800168 ret = i2c_read(i2caddress,
169 IR36021_LOOP1_VOUT_OFFSET,
170 1, (void *)&buf, 1);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800171#else
172 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
173 if (!ret)
174 ret = dm_i2c_read(dev, IR36021_LOOP1_VOUT_OFFSET,
175 (void *)&buf, 1);
176#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800177 if (ret) {
178 printf("VID: failed to read vcpu\n");
179 return ret;
180 }
181 vol_mon = buf;
182 if (!vol_mon) {
183 printf("VID: Core voltage sensor error\n");
184 return -1;
185 }
186 debug("VID: bus voltage reads 0x%02x\n", vol_mon);
187 /* Resolution is 1/128V. We scale up here to get 1/128mV
188 * and divide at the end
189 */
190 voltage_read += vol_mon * 1000;
191 udelay(WAIT_FOR_ADC);
192 }
193 /* Scale down to the real mV as IR resolution is 1/128V, rounding up */
194 voltage_read = DIV_ROUND_UP(voltage_read, 128);
195
196 /* calculate the average */
197 voltage_read /= NUM_READINGS;
198
199 /* Compensate for a board specific voltage drop between regulator and
200 * SoC before converting into an IR VID value
201 */
202 voltage_read -= board_vdd_drop_compensation();
203
204 return voltage_read;
205}
206#endif
207
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530208#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
209/* read the current value of the LTC Regulator Voltage */
210static int read_voltage_from_LTC(int i2caddress)
211{
212 int ret, vcode = 0;
213 u8 chan = PWM_CHANNEL0;
214
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800215#ifndef CONFIG_DM_I2C
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530216 /* select the PAGE 0 using PMBus commands PAGE for VDD*/
217 ret = i2c_write(I2C_VOL_MONITOR_ADDR,
218 PMBUS_CMD_PAGE, 1, &chan, 1);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800219#else
220 struct udevice *dev;
221
222 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
223 if (!ret)
224 ret = dm_i2c_write(dev, PMBUS_CMD_PAGE, &chan, 1);
225#endif
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530226 if (ret) {
227 printf("VID: failed to select VDD Page 0\n");
228 return ret;
229 }
230
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800231#ifndef CONFIG_DM_I2C
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530232 /*read the output voltage using PMBus command READ_VOUT*/
233 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
234 PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800235#else
236 ret = dm_i2c_read(dev, PMBUS_CMD_READ_VOUT, (void *)&vcode, 2);
237 if (ret) {
238 printf("VID: failed to read the volatge\n");
239 return ret;
240 }
241#endif
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530242 if (ret) {
243 printf("VID: failed to read the volatge\n");
244 return ret;
245 }
246
247 /* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */
248 vcode = DIV_ROUND_UP(vcode * 1000, 4096);
249
250 return vcode;
251}
252#endif
253
Ying Zhang8876a512014-10-31 18:06:18 +0800254static int read_voltage(int i2caddress)
255{
256 int voltage_read;
257#ifdef CONFIG_VOL_MONITOR_INA220
258 voltage_read = read_voltage_from_INA220(i2caddress);
259#elif defined CONFIG_VOL_MONITOR_IR36021_READ
260 voltage_read = read_voltage_from_IR(i2caddress);
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530261#elif defined CONFIG_VOL_MONITOR_LTC3882_READ
262 voltage_read = read_voltage_from_LTC(i2caddress);
Ying Zhang8876a512014-10-31 18:06:18 +0800263#else
264 return -1;
265#endif
266 return voltage_read;
267}
268
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530269#ifdef CONFIG_VOL_MONITOR_IR36021_SET
Ying Zhang8876a512014-10-31 18:06:18 +0800270/*
271 * We need to calculate how long before the voltage stops to drop
272 * or increase. It returns with the loop count. Each loop takes
273 * several readings (WAIT_FOR_ADC)
274 */
275static int wait_for_new_voltage(int vdd, int i2caddress)
276{
277 int timeout, vdd_current;
278
279 vdd_current = read_voltage(i2caddress);
280 /* wait until voltage starts to reach the target. Voltage slew
281 * rates by typical regulators will always lead to stable readings
282 * within each fairly long ADC interval in comparison to the
283 * intended voltage delta change until the target voltage is
284 * reached. The fairly small voltage delta change to any target
285 * VID voltage also means that this function will always complete
286 * within few iterations. If the timeout was ever reached, it would
287 * point to a serious failure in the regulator system.
288 */
289 for (timeout = 0;
290 abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
291 timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
292 vdd_current = read_voltage(i2caddress);
293 }
294 if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
295 printf("VID: Voltage adjustment timeout\n");
296 return -1;
297 }
298 return timeout;
299}
300
301/*
302 * this function keeps reading the voltage until it is stable or until the
303 * timeout expires
304 */
305static int wait_for_voltage_stable(int i2caddress)
306{
307 int timeout, vdd_current, vdd;
308
309 vdd = read_voltage(i2caddress);
310 udelay(NUM_READINGS * WAIT_FOR_ADC);
311
312 /* wait until voltage is stable */
313 vdd_current = read_voltage(i2caddress);
314 /* The maximum timeout is
315 * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
316 */
317 for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
318 abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
319 timeout > 0; timeout--) {
320 vdd = vdd_current;
321 udelay(NUM_READINGS * WAIT_FOR_ADC);
322 vdd_current = read_voltage(i2caddress);
323 }
324 if (timeout == 0)
325 return -1;
326 return vdd_current;
327}
328
Ying Zhang8876a512014-10-31 18:06:18 +0800329/* Set the voltage to the IR chip */
330static int set_voltage_to_IR(int i2caddress, int vdd)
331{
332 int wait, vdd_last;
333 int ret;
334 u8 vid;
335
336 /* Compensate for a board specific voltage drop between regulator and
337 * SoC before converting into an IR VID value
338 */
339 vdd += board_vdd_drop_compensation();
Shaohui Xie085ac1c2016-09-07 17:56:14 +0800340#ifdef CONFIG_FSL_LSCH2
Shaohui Xiedd335672015-11-11 17:58:37 +0800341 vid = DIV_ROUND_UP(vdd - 265, 5);
342#else
Ying Zhang8876a512014-10-31 18:06:18 +0800343 vid = DIV_ROUND_UP(vdd - 245, 5);
Shaohui Xiedd335672015-11-11 17:58:37 +0800344#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800345
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800346#ifndef CONFIG_DM_I2C
Ying Zhang8876a512014-10-31 18:06:18 +0800347 ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
348 1, (void *)&vid, sizeof(vid));
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800349#else
350 struct udevice *dev;
351
352 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
353 if (!ret)
354 ret = dm_i2c_write(dev, IR36021_LOOP1_MANUAL_ID_OFFSET,
355 (void *)&vid, sizeof(vid));
356
357#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800358 if (ret) {
359 printf("VID: failed to write VID\n");
360 return -1;
361 }
362 wait = wait_for_new_voltage(vdd, i2caddress);
363 if (wait < 0)
364 return -1;
365 debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
366
367 vdd_last = wait_for_voltage_stable(i2caddress);
368 if (vdd_last < 0)
369 return -1;
370 debug("VID: Current voltage is %d mV\n", vdd_last);
371 return vdd_last;
372}
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530373
374#endif
375
376#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
377/* this function sets the VDD and returns the value set */
378static int set_voltage_to_LTC(int i2caddress, int vdd)
379{
380 int ret, vdd_last, vdd_target = vdd;
Priyanka Jainaf89d242018-10-11 05:11:23 +0000381 int count = 100, temp = 0;
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530382
383 /* Scale up to the LTC resolution is 1/4096V */
384 vdd = (vdd * 4096) / 1000;
385
386 /* 5-byte buffer which needs to be sent following the
387 * PMBus command PAGE_PLUS_WRITE.
388 */
389 u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND,
390 vdd & 0xFF, (vdd & 0xFF00) >> 8};
391
392 /* Write the desired voltage code to the regulator */
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800393#ifndef CONFIG_DM_I2C
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530394 ret = i2c_write(I2C_VOL_MONITOR_ADDR,
395 PMBUS_CMD_PAGE_PLUS_WRITE, 1, (void *)&buff, 5);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800396#else
397 struct udevice *dev;
398
399 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
400 if (!ret)
401 ret = dm_i2c_write(dev, PMBUS_CMD_PAGE_PLUS_WRITE,
402 (void *)&buff, 5);
403#endif
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530404 if (ret) {
405 printf("VID: I2C failed to write to the volatge regulator\n");
406 return -1;
407 }
408
409 /* Wait for the volatge to get to the desired value */
410 do {
411 vdd_last = read_voltage_from_LTC(i2caddress);
412 if (vdd_last < 0) {
413 printf("VID: Couldn't read sensor abort VID adjust\n");
414 return -1;
415 }
Priyanka Jainaf89d242018-10-11 05:11:23 +0000416 count--;
417 temp = vdd_last - vdd_target;
418 } while ((abs(temp) > 2) && (count > 0));
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530419
420 return vdd_last;
421}
Ying Zhang8876a512014-10-31 18:06:18 +0800422#endif
423
424static int set_voltage(int i2caddress, int vdd)
425{
426 int vdd_last = -1;
427
428#ifdef CONFIG_VOL_MONITOR_IR36021_SET
429 vdd_last = set_voltage_to_IR(i2caddress, vdd);
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530430#elif defined CONFIG_VOL_MONITOR_LTC3882_SET
431 vdd_last = set_voltage_to_LTC(i2caddress, vdd);
Ying Zhang8876a512014-10-31 18:06:18 +0800432#else
433 #error Specific voltage monitor must be defined
434#endif
435 return vdd_last;
436}
437
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530438#ifdef CONFIG_FSL_LSCH3
439int adjust_vdd(ulong vdd_override)
440{
441 int re_enable = disable_interrupts();
442 struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
443 u32 fusesr;
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530444#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
445 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530446 u8 vid, buf;
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530447#else
448 u8 vid;
449#endif
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530450 int vdd_target, vdd_current, vdd_last;
451 int ret, i2caddress;
452 unsigned long vdd_string_override;
453 char *vdd_string;
Priyanka Jainc6a6fac2018-10-11 05:22:34 +0000454#ifdef CONFIG_ARCH_LX2160A
455 static const u16 vdd[32] = {
456 8250,
457 7875,
458 7750,
459 0, /* reserved */
460 0, /* reserved */
461 0, /* reserved */
462 0, /* reserved */
463 0, /* reserved */
464 0, /* reserved */
465 0, /* reserved */
466 0, /* reserved */
467 0, /* reserved */
468 0, /* reserved */
469 0, /* reserved */
470 0, /* reserved */
471 0, /* reserved */
472 8000,
473 8125,
474 8250,
475 0, /* reserved */
476 8500,
477 0, /* reserved */
478 0, /* reserved */
479 0, /* reserved */
480 0, /* reserved */
481 0, /* reserved */
482 0, /* reserved */
483 0, /* reserved */
484 0, /* reserved */
485 0, /* reserved */
486 0, /* reserved */
487 0, /* reserved */
488 };
489#else
Rajesh Bhagatd600b312018-01-17 16:13:01 +0530490#ifdef CONFIG_ARCH_LS1088A
491 static const uint16_t vdd[32] = {
492 10250,
493 9875,
494 9750,
495 0, /* reserved */
496 0, /* reserved */
497 0, /* reserved */
498 0, /* reserved */
499 0, /* reserved */
500 9000,
501 0, /* reserved */
502 0, /* reserved */
503 0, /* reserved */
504 0, /* reserved */
505 0, /* reserved */
506 0, /* reserved */
507 0, /* reserved */
508 10000, /* 1.0000V */
509 10125,
510 10250,
511 0, /* reserved */
512 0, /* reserved */
513 0, /* reserved */
514 0, /* reserved */
515 0, /* reserved */
516 0, /* reserved */
517 0, /* reserved */
518 0, /* reserved */
519 0, /* reserved */
520 0, /* reserved */
521 0, /* reserved */
522 0, /* reserved */
523 0, /* reserved */
524 };
525
526#else
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530527 static const uint16_t vdd[32] = {
528 10500,
529 0, /* reserved */
530 9750,
531 0, /* reserved */
532 9500,
533 0, /* reserved */
534 0, /* reserved */
535 0, /* reserved */
536 0, /* reserved */
537 0, /* reserved */
538 0, /* reserved */
Priyanka Jainfd9b7422018-05-09 12:54:38 +0530539 9000, /* reserved */
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530540 0, /* reserved */
541 0, /* reserved */
542 0, /* reserved */
543 0, /* reserved */
544 10000, /* 1.0000V */
545 0, /* reserved */
546 10250,
547 0, /* reserved */
548 10500,
549 0, /* reserved */
550 0, /* reserved */
551 0, /* reserved */
552 0, /* reserved */
553 0, /* reserved */
554 0, /* reserved */
555 0, /* reserved */
556 0, /* reserved */
557 0, /* reserved */
558 0, /* reserved */
559 0, /* reserved */
560 };
Rajesh Bhagatd600b312018-01-17 16:13:01 +0530561#endif
Priyanka Jainc6a6fac2018-10-11 05:22:34 +0000562#endif
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530563 struct vdd_drive {
564 u8 vid;
565 unsigned voltage;
566 };
567
568 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
569 if (ret) {
570 debug("VID: I2C failed to switch channel\n");
571 ret = -1;
572 goto exit;
573 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530574#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
575 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530576 ret = find_ir_chip_on_i2c();
577 if (ret < 0) {
578 printf("VID: Could not find voltage regulator on I2C.\n");
579 ret = -1;
580 goto exit;
581 } else {
582 i2caddress = ret;
583 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
584 }
585
586 /* check IR chip work on Intel mode*/
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800587#ifndef CONFIG_DM_I2C
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530588 ret = i2c_read(i2caddress,
589 IR36021_INTEL_MODE_OOFSET,
590 1, (void *)&buf, 1);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800591#else
592 struct udevice *dev;
593
594 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
595 if (!ret)
596 ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
597 (void *)&buf, 1);
598#endif
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530599 if (ret) {
600 printf("VID: failed to read IR chip mode.\n");
601 ret = -1;
602 goto exit;
603 }
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800604
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530605 if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
606 printf("VID: IR Chip is not used in Intel mode.\n");
607 ret = -1;
608 goto exit;
609 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530610#endif
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530611
612 /* get the voltage ID from fuse status register */
613 fusesr = in_le32(&gur->dcfg_fusesr);
614 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
615 FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
616 if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
617 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
618 FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
619 }
620 vdd_target = vdd[vid];
621
622 /* check override variable for overriding VDD */
Simon Glass64b723f2017-08-03 12:22:12 -0600623 vdd_string = env_get(CONFIG_VID_FLS_ENV);
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530624 if (vdd_override == 0 && vdd_string &&
625 !strict_strtoul(vdd_string, 10, &vdd_string_override))
626 vdd_override = vdd_string_override;
627
628 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
629 vdd_target = vdd_override * 10; /* convert to 1/10 mV */
630 debug("VDD override is %lu\n", vdd_override);
631 } else if (vdd_override != 0) {
632 printf("Invalid value.\n");
633 }
634
635 /* divide and round up by 10 to get a value in mV */
636 vdd_target = DIV_ROUND_UP(vdd_target, 10);
637 if (vdd_target == 0) {
638 debug("VID: VID not used\n");
639 ret = 0;
640 goto exit;
641 } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) {
642 /* Check vdd_target is in valid range */
643 printf("VID: Target VID %d mV is not in range.\n",
644 vdd_target);
645 ret = -1;
646 goto exit;
647 } else {
648 debug("VID: vid = %d mV\n", vdd_target);
649 }
650
651 /*
652 * Read voltage monitor to check real voltage.
653 */
654 vdd_last = read_voltage(i2caddress);
655 if (vdd_last < 0) {
656 printf("VID: Couldn't read sensor abort VID adjustment\n");
657 ret = -1;
658 goto exit;
659 }
660 vdd_current = vdd_last;
661 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530662
663#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
664 /* Set the target voltage */
665 vdd_last = vdd_current = set_voltage(i2caddress, vdd_target);
666#else
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530667 /*
668 * Adjust voltage to at or one step above target.
669 * As measurements are less precise than setting the values
670 * we may run through dummy steps that cancel each other
671 * when stepping up and then down.
672 */
673 while (vdd_last > 0 &&
674 vdd_last < vdd_target) {
675 vdd_current += IR_VDD_STEP_UP;
676 vdd_last = set_voltage(i2caddress, vdd_current);
677 }
678 while (vdd_last > 0 &&
679 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
680 vdd_current -= IR_VDD_STEP_DOWN;
681 vdd_last = set_voltage(i2caddress, vdd_current);
682 }
683
Rajesh Bhagat170eecf2018-01-17 16:13:05 +0530684#endif
Rajesh Bhagatc3a662f2018-01-17 16:13:02 +0530685 if (board_adjust_vdd(vdd_target) < 0) {
686 ret = -1;
687 goto exit;
688 }
689
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530690 if (vdd_last > 0)
691 printf("VID: Core voltage after adjustment is at %d mV\n",
692 vdd_last);
693 else
694 ret = -1;
695exit:
696 if (re_enable)
697 enable_interrupts();
698 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
699 return ret;
700}
701#else /* !CONFIG_FSL_LSCH3 */
Ying Zhang8876a512014-10-31 18:06:18 +0800702int adjust_vdd(ulong vdd_override)
703{
704 int re_enable = disable_interrupts();
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530705#if defined(CONFIG_FSL_LSCH2)
Shaohui Xiedd335672015-11-11 17:58:37 +0800706 struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
707#else
Ying Zhang8876a512014-10-31 18:06:18 +0800708 ccsr_gur_t __iomem *gur =
709 (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
Shaohui Xiedd335672015-11-11 17:58:37 +0800710#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800711 u32 fusesr;
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800712 u8 vid, buf;
Ying Zhang8876a512014-10-31 18:06:18 +0800713 int vdd_target, vdd_current, vdd_last;
714 int ret, i2caddress;
715 unsigned long vdd_string_override;
716 char *vdd_string;
717 static const uint16_t vdd[32] = {
718 0, /* unused */
719 9875, /* 0.9875V */
720 9750,
721 9625,
722 9500,
723 9375,
724 9250,
725 9125,
726 9000,
727 8875,
728 8750,
729 8625,
730 8500,
731 8375,
732 8250,
733 8125,
734 10000, /* 1.0000V */
735 10125,
736 10250,
737 10375,
738 10500,
739 10625,
740 10750,
741 10875,
742 11000,
743 0, /* reserved */
744 };
745 struct vdd_drive {
746 u8 vid;
747 unsigned voltage;
748 };
749
750 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
751 if (ret) {
752 debug("VID: I2C failed to switch channel\n");
753 ret = -1;
754 goto exit;
755 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530756#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
757 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang8876a512014-10-31 18:06:18 +0800758 ret = find_ir_chip_on_i2c();
759 if (ret < 0) {
760 printf("VID: Could not find voltage regulator on I2C.\n");
761 ret = -1;
762 goto exit;
763 } else {
764 i2caddress = ret;
765 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
766 }
767
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800768 /* check IR chip work on Intel mode*/
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800769#ifndef CONFIG_DM_I2C
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800770 ret = i2c_read(i2caddress,
771 IR36021_INTEL_MODE_OOFSET,
772 1, (void *)&buf, 1);
Chuanhua Han37c2c5e2019-07-10 21:00:20 +0800773#else
774 struct udevice *dev;
775
776 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
777 if (!ret)
778 ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
779 (void *)&buf, 1);
780#endif
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800781 if (ret) {
782 printf("VID: failed to read IR chip mode.\n");
783 ret = -1;
784 goto exit;
785 }
786 if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
787 printf("VID: IR Chip is not used in Intel mode.\n");
788 ret = -1;
789 goto exit;
790 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530791#endif
Ying Zhang7ad5eff2016-01-22 12:15:12 +0800792
Ying Zhang8876a512014-10-31 18:06:18 +0800793 /* get the voltage ID from fuse status register */
794 fusesr = in_be32(&gur->dcfg_fusesr);
795 /*
796 * VID is used according to the table below
797 * ---------------------------------------
798 * | DA_V |
799 * |-------------------------------------|
800 * | 5b00000 | 5b00001-5b11110 | 5b11111 |
801 * ---------------+---------+-----------------+---------|
802 * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
803 * | A |----------+---------+-----------------+---------|
804 * | _ | 5b00001 |VID = | VID = |VID = |
805 * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
806 * | _ | 5b11110 | | | |
807 * | A |----------+---------+-----------------+---------|
808 * | L | 5b11111 | No VID | VID = DA_V | NO VID |
809 * | T | | | | |
810 * ------------------------------------------------------
811 */
Shaohui Xie085ac1c2016-09-07 17:56:14 +0800812#ifdef CONFIG_FSL_LSCH2
Shaohui Xiedd335672015-11-11 17:58:37 +0800813 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
814 FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
815 if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
816 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
817 FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
818 }
819#else
Ying Zhang8876a512014-10-31 18:06:18 +0800820 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
821 FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
822 if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
823 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
824 FSL_CORENET_DCFG_FUSESR_VID_MASK;
825 }
Shaohui Xiedd335672015-11-11 17:58:37 +0800826#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800827 vdd_target = vdd[vid];
828
829 /* check override variable for overriding VDD */
Simon Glass64b723f2017-08-03 12:22:12 -0600830 vdd_string = env_get(CONFIG_VID_FLS_ENV);
Ying Zhang8876a512014-10-31 18:06:18 +0800831 if (vdd_override == 0 && vdd_string &&
832 !strict_strtoul(vdd_string, 10, &vdd_string_override))
833 vdd_override = vdd_string_override;
834 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
835 vdd_target = vdd_override * 10; /* convert to 1/10 mV */
836 debug("VDD override is %lu\n", vdd_override);
837 } else if (vdd_override != 0) {
838 printf("Invalid value.\n");
839 }
840 if (vdd_target == 0) {
841 debug("VID: VID not used\n");
842 ret = 0;
843 goto exit;
844 } else {
845 /* divide and round up by 10 to get a value in mV */
846 vdd_target = DIV_ROUND_UP(vdd_target, 10);
847 debug("VID: vid = %d mV\n", vdd_target);
848 }
849
850 /*
851 * Read voltage monitor to check real voltage.
852 */
853 vdd_last = read_voltage(i2caddress);
854 if (vdd_last < 0) {
855 printf("VID: Couldn't read sensor abort VID adjustment\n");
856 ret = -1;
857 goto exit;
858 }
859 vdd_current = vdd_last;
860 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
861 /*
862 * Adjust voltage to at or one step above target.
863 * As measurements are less precise than setting the values
864 * we may run through dummy steps that cancel each other
865 * when stepping up and then down.
866 */
867 while (vdd_last > 0 &&
868 vdd_last < vdd_target) {
869 vdd_current += IR_VDD_STEP_UP;
870 vdd_last = set_voltage(i2caddress, vdd_current);
871 }
872 while (vdd_last > 0 &&
873 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
874 vdd_current -= IR_VDD_STEP_DOWN;
875 vdd_last = set_voltage(i2caddress, vdd_current);
876 }
877
878 if (vdd_last > 0)
879 printf("VID: Core voltage after adjustment is at %d mV\n",
880 vdd_last);
881 else
882 ret = -1;
883exit:
884 if (re_enable)
885 enable_interrupts();
Wenbin Song44ad75c2016-03-09 13:38:23 +0800886
887 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
888
Ying Zhang8876a512014-10-31 18:06:18 +0800889 return ret;
890}
Priyanka Jainf9088dd2017-01-19 11:12:27 +0530891#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800892
893static int print_vdd(void)
894{
895 int vdd_last, ret, i2caddress;
896
897 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
898 if (ret) {
899 debug("VID : I2c failed to switch channel\n");
900 return -1;
901 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530902#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
903 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang8876a512014-10-31 18:06:18 +0800904 ret = find_ir_chip_on_i2c();
905 if (ret < 0) {
906 printf("VID: Could not find voltage regulator on I2C.\n");
Wenbin Song44ad75c2016-03-09 13:38:23 +0800907 goto exit;
Ying Zhang8876a512014-10-31 18:06:18 +0800908 } else {
909 i2caddress = ret;
910 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
911 }
Rajesh Bhagate6cd8d52018-01-17 16:13:03 +0530912#endif
Ying Zhang8876a512014-10-31 18:06:18 +0800913
914 /*
915 * Read voltage monitor to check real voltage.
916 */
917 vdd_last = read_voltage(i2caddress);
918 if (vdd_last < 0) {
919 printf("VID: Couldn't read sensor abort VID adjustment\n");
Wenbin Song44ad75c2016-03-09 13:38:23 +0800920 goto exit;
Ying Zhang8876a512014-10-31 18:06:18 +0800921 }
922 printf("VID: Core voltage is at %d mV\n", vdd_last);
Wenbin Song44ad75c2016-03-09 13:38:23 +0800923exit:
924 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
925
926 return ret < 0 ? -1 : 0;
Ying Zhang8876a512014-10-31 18:06:18 +0800927
Ying Zhang8876a512014-10-31 18:06:18 +0800928}
929
Simon Glassed38aef2020-05-10 11:40:03 -0600930static int do_vdd_override(struct cmd_tbl *cmdtp,
Ying Zhang8876a512014-10-31 18:06:18 +0800931 int flag, int argc,
Simon Glassed38aef2020-05-10 11:40:03 -0600932 char *const argv[])
Ying Zhang8876a512014-10-31 18:06:18 +0800933{
934 ulong override;
935
936 if (argc < 2)
937 return CMD_RET_USAGE;
938
939 if (!strict_strtoul(argv[1], 10, &override))
940 adjust_vdd(override); /* the value is checked by callee */
941 else
942 return CMD_RET_USAGE;
943 return 0;
944}
945
Simon Glassed38aef2020-05-10 11:40:03 -0600946static int do_vdd_read(struct cmd_tbl *cmdtp, int flag, int argc,
947 char *const argv[])
Ying Zhang8876a512014-10-31 18:06:18 +0800948{
949 if (argc < 1)
950 return CMD_RET_USAGE;
951 print_vdd();
952
953 return 0;
954}
955
956U_BOOT_CMD(
957 vdd_override, 2, 0, do_vdd_override,
958 "override VDD",
959 " - override with the voltage specified in mV, eg. 1050"
960);
961
962U_BOOT_CMD(
963 vdd_read, 1, 0, do_vdd_read,
964 "read VDD",
965 " - Read the voltage specified in mV"
966)