blob: 20f5421da0bad444ce6baf02714cc1b0a5a0a738 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ying Zhang3ad27372014-10-31 18:06:18 +08002/*
3 * Copyright 2014 Freescale Semiconductor, Inc.
Meenakshi Aggarwal3a187cf2020-10-29 19:16:16 +05304 * Copyright 2020 NXP
Ying Zhang3ad27372014-10-31 18:06:18 +08005 */
6
7#include <common.h>
8#include <command.h>
Simon Glass7b51b572019-08-01 09:46:52 -06009#include <env.h>
Ying Zhang3ad27372014-10-31 18:06:18 +080010#include <i2c.h>
Simon Glass36bf4462019-11-14 12:57:42 -070011#include <irq_func.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
Shaohui Xie02b5d2e2015-11-11 17:58:37 +080013#include <asm/io.h>
Shaohui Xie126fe702016-09-07 17:56:14 +080014#ifdef CONFIG_FSL_LSCH2
Shaohui Xie02b5d2e2015-11-11 17:58:37 +080015#include <asm/arch/immap_lsch2.h>
Rai Harnindered2530d2016-03-23 17:04:38 +053016#elif defined(CONFIG_FSL_LSCH3)
17#include <asm/arch/immap_lsch3.h>
Shaohui Xie02b5d2e2015-11-11 17:58:37 +080018#else
Ying Zhang3ad27372014-10-31 18:06:18 +080019#include <asm/immap_85xx.h>
Shaohui Xie02b5d2e2015-11-11 17:58:37 +080020#endif
Simon Glassc05ed002020-05-10 11:40:11 -060021#include <linux/delay.h>
Ying Zhang3ad27372014-10-31 18:06:18 +080022#include "vid.h"
23
Ying Zhang3ad27372014-10-31 18:06:18 +080024int __weak i2c_multiplexer_select_vid_channel(u8 channel)
25{
26 return 0;
27}
28
29/*
30 * Compensate for a board specific voltage drop between regulator and SoC
31 * return a value in mV
32 */
33int __weak board_vdd_drop_compensation(void)
34{
35 return 0;
36}
37
38/*
Rajesh Bhagat36075702018-01-17 16:13:02 +053039 * Board specific settings for specific voltage value
40 */
41int __weak board_adjust_vdd(int vdd)
42{
43 return 0;
44}
45
Rajesh Bhagat94583162018-01-17 16:13:03 +053046#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
47 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Rajesh Bhagat36075702018-01-17 16:13:02 +053048/*
Ying Zhang3ad27372014-10-31 18:06:18 +080049 * Get the i2c address configuration for the IR regulator chip
50 *
51 * There are some variance in the RDB HW regarding the I2C address configuration
52 * for the IR regulator chip, which is likely a problem of external resistor
53 * accuracy. So we just check each address in a hopefully non-intrusive mode
54 * and use the first one that seems to work
55 *
56 * The IR chip can show up under the following addresses:
57 * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
58 * 0x09 (Verified on T1040RDB-PA)
Ying Zhang2f66a822016-01-22 12:15:13 +080059 * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
Ying Zhang3ad27372014-10-31 18:06:18 +080060 */
61static int find_ir_chip_on_i2c(void)
62{
63 int i2caddress;
64 int ret;
65 u8 byte;
66 int i;
67 const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
Igor Opaniuk2147a162021-02-09 13:52:45 +020068#if CONFIG_IS_ENABLED(DM_I2C)
Chuanhua Han0eba65d2019-07-10 21:00:20 +080069 struct udevice *dev;
70#endif
Ying Zhang3ad27372014-10-31 18:06:18 +080071
72 /* Check all the address */
73 for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
74 i2caddress = ir_i2c_addr[i];
Igor Opaniuk2147a162021-02-09 13:52:45 +020075#if !CONFIG_IS_ENABLED(DM_I2C)
Ying Zhang3ad27372014-10-31 18:06:18 +080076 ret = i2c_read(i2caddress,
77 IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
78 sizeof(byte));
Chuanhua Han0eba65d2019-07-10 21:00:20 +080079#else
80 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
81 if (!ret)
82 ret = dm_i2c_read(dev, IR36021_MFR_ID_OFFSET,
83 (void *)&byte, sizeof(byte));
84#endif
Ying Zhang3ad27372014-10-31 18:06:18 +080085 if ((ret >= 0) && (byte == IR36021_MFR_ID))
86 return i2caddress;
87 }
88 return -1;
89}
Rajesh Bhagat94583162018-01-17 16:13:03 +053090#endif
Ying Zhang3ad27372014-10-31 18:06:18 +080091
92/* Maximum loop count waiting for new voltage to take effect */
93#define MAX_LOOP_WAIT_NEW_VOL 100
94/* Maximum loop count waiting for the voltage to be stable */
95#define MAX_LOOP_WAIT_VOL_STABLE 100
96/*
97 * read_voltage from sensor on I2C bus
98 * We use average of 4 readings, waiting for WAIT_FOR_ADC before
99 * another reading
100 */
101#define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */
102
103/* If an INA220 chip is available, we can use it to read back the voltage
104 * as it may have a higher accuracy than the IR chip for the same purpose
105 */
106#ifdef CONFIG_VOL_MONITOR_INA220
107#define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
108#define ADC_MIN_ACCURACY 4
109#else
110#define WAIT_FOR_ADC 138 /* wait for 138 microseconds for ADC */
111#define ADC_MIN_ACCURACY 4
112#endif
113
114#ifdef CONFIG_VOL_MONITOR_INA220
115static int read_voltage_from_INA220(int i2caddress)
116{
117 int i, ret, voltage_read = 0;
118 u16 vol_mon;
119 u8 buf[2];
Igor Opaniuk2147a162021-02-09 13:52:45 +0200120#if CONFIG_IS_ENABLED(DM_I2C)
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800121 struct udevice *dev;
122#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800123
124 for (i = 0; i < NUM_READINGS; i++) {
Igor Opaniuk2147a162021-02-09 13:52:45 +0200125#if !CONFIG_IS_ENABLED(DM_I2C)
Ying Zhang3ad27372014-10-31 18:06:18 +0800126 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
127 I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
128 (void *)&buf, 2);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800129#else
130 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
131 if (!ret)
132 ret = dm_i2c_read(dev, I2C_VOL_MONITOR_BUS_V_OFFSET,
133 (void *)&buf, 2);
134#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800135 if (ret) {
136 printf("VID: failed to read core voltage\n");
137 return ret;
138 }
139 vol_mon = (buf[0] << 8) | buf[1];
140 if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
141 printf("VID: Core voltage sensor error\n");
142 return -1;
143 }
144 debug("VID: bus voltage reads 0x%04x\n", vol_mon);
145 /* LSB = 4mv */
146 voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
147 udelay(WAIT_FOR_ADC);
148 }
149 /* calculate the average */
150 voltage_read /= NUM_READINGS;
151
152 return voltage_read;
153}
154#endif
155
156/* read voltage from IR */
157#ifdef CONFIG_VOL_MONITOR_IR36021_READ
158static int read_voltage_from_IR(int i2caddress)
159{
160 int i, ret, voltage_read = 0;
161 u16 vol_mon;
162 u8 buf;
Igor Opaniuk2147a162021-02-09 13:52:45 +0200163#if CONFIG_IS_ENABLED(DM_I2C)
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800164 struct udevice *dev;
165#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800166
167 for (i = 0; i < NUM_READINGS; i++) {
Igor Opaniuk2147a162021-02-09 13:52:45 +0200168#if !CONFIG_IS_ENABLED(DM_I2C)
Ying Zhang3ad27372014-10-31 18:06:18 +0800169 ret = i2c_read(i2caddress,
170 IR36021_LOOP1_VOUT_OFFSET,
171 1, (void *)&buf, 1);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800172#else
173 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
174 if (!ret)
175 ret = dm_i2c_read(dev, IR36021_LOOP1_VOUT_OFFSET,
176 (void *)&buf, 1);
177#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800178 if (ret) {
179 printf("VID: failed to read vcpu\n");
180 return ret;
181 }
182 vol_mon = buf;
183 if (!vol_mon) {
184 printf("VID: Core voltage sensor error\n");
185 return -1;
186 }
187 debug("VID: bus voltage reads 0x%02x\n", vol_mon);
188 /* Resolution is 1/128V. We scale up here to get 1/128mV
189 * and divide at the end
190 */
191 voltage_read += vol_mon * 1000;
192 udelay(WAIT_FOR_ADC);
193 }
194 /* Scale down to the real mV as IR resolution is 1/128V, rounding up */
195 voltage_read = DIV_ROUND_UP(voltage_read, 128);
196
197 /* calculate the average */
198 voltage_read /= NUM_READINGS;
199
200 /* Compensate for a board specific voltage drop between regulator and
201 * SoC before converting into an IR VID value
202 */
203 voltage_read -= board_vdd_drop_compensation();
204
205 return voltage_read;
206}
207#endif
208
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530209#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
210/* read the current value of the LTC Regulator Voltage */
211static int read_voltage_from_LTC(int i2caddress)
212{
213 int ret, vcode = 0;
214 u8 chan = PWM_CHANNEL0;
215
Igor Opaniuk2147a162021-02-09 13:52:45 +0200216#if !CONFIG_IS_ENABLED(DM_I2C)
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530217 /* select the PAGE 0 using PMBus commands PAGE for VDD*/
218 ret = i2c_write(I2C_VOL_MONITOR_ADDR,
219 PMBUS_CMD_PAGE, 1, &chan, 1);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800220#else
221 struct udevice *dev;
222
223 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
224 if (!ret)
225 ret = dm_i2c_write(dev, PMBUS_CMD_PAGE, &chan, 1);
226#endif
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530227 if (ret) {
228 printf("VID: failed to select VDD Page 0\n");
229 return ret;
230 }
231
Igor Opaniuk2147a162021-02-09 13:52:45 +0200232#if !CONFIG_IS_ENABLED(DM_I2C)
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530233 /*read the output voltage using PMBus command READ_VOUT*/
234 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
235 PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800236#else
237 ret = dm_i2c_read(dev, PMBUS_CMD_READ_VOUT, (void *)&vcode, 2);
238 if (ret) {
239 printf("VID: failed to read the volatge\n");
240 return ret;
241 }
242#endif
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530243 if (ret) {
244 printf("VID: failed to read the volatge\n");
245 return ret;
246 }
247
248 /* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */
249 vcode = DIV_ROUND_UP(vcode * 1000, 4096);
250
251 return vcode;
252}
253#endif
254
Ying Zhang3ad27372014-10-31 18:06:18 +0800255static int read_voltage(int i2caddress)
256{
257 int voltage_read;
258#ifdef CONFIG_VOL_MONITOR_INA220
259 voltage_read = read_voltage_from_INA220(i2caddress);
260#elif defined CONFIG_VOL_MONITOR_IR36021_READ
261 voltage_read = read_voltage_from_IR(i2caddress);
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530262#elif defined CONFIG_VOL_MONITOR_LTC3882_READ
263 voltage_read = read_voltage_from_LTC(i2caddress);
Ying Zhang3ad27372014-10-31 18:06:18 +0800264#else
265 return -1;
266#endif
267 return voltage_read;
268}
269
Rajesh Bhagat94583162018-01-17 16:13:03 +0530270#ifdef CONFIG_VOL_MONITOR_IR36021_SET
Ying Zhang3ad27372014-10-31 18:06:18 +0800271/*
272 * We need to calculate how long before the voltage stops to drop
273 * or increase. It returns with the loop count. Each loop takes
274 * several readings (WAIT_FOR_ADC)
275 */
276static int wait_for_new_voltage(int vdd, int i2caddress)
277{
278 int timeout, vdd_current;
279
280 vdd_current = read_voltage(i2caddress);
281 /* wait until voltage starts to reach the target. Voltage slew
282 * rates by typical regulators will always lead to stable readings
283 * within each fairly long ADC interval in comparison to the
284 * intended voltage delta change until the target voltage is
285 * reached. The fairly small voltage delta change to any target
286 * VID voltage also means that this function will always complete
287 * within few iterations. If the timeout was ever reached, it would
288 * point to a serious failure in the regulator system.
289 */
290 for (timeout = 0;
291 abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
292 timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
293 vdd_current = read_voltage(i2caddress);
294 }
295 if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
296 printf("VID: Voltage adjustment timeout\n");
297 return -1;
298 }
299 return timeout;
300}
301
302/*
303 * this function keeps reading the voltage until it is stable or until the
304 * timeout expires
305 */
306static int wait_for_voltage_stable(int i2caddress)
307{
308 int timeout, vdd_current, vdd;
309
310 vdd = read_voltage(i2caddress);
311 udelay(NUM_READINGS * WAIT_FOR_ADC);
312
313 /* wait until voltage is stable */
314 vdd_current = read_voltage(i2caddress);
315 /* The maximum timeout is
316 * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
317 */
318 for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
319 abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
320 timeout > 0; timeout--) {
321 vdd = vdd_current;
322 udelay(NUM_READINGS * WAIT_FOR_ADC);
323 vdd_current = read_voltage(i2caddress);
324 }
325 if (timeout == 0)
326 return -1;
327 return vdd_current;
328}
329
Ying Zhang3ad27372014-10-31 18:06:18 +0800330/* Set the voltage to the IR chip */
331static int set_voltage_to_IR(int i2caddress, int vdd)
332{
333 int wait, vdd_last;
334 int ret;
335 u8 vid;
336
337 /* Compensate for a board specific voltage drop between regulator and
338 * SoC before converting into an IR VID value
339 */
340 vdd += board_vdd_drop_compensation();
Shaohui Xie126fe702016-09-07 17:56:14 +0800341#ifdef CONFIG_FSL_LSCH2
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800342 vid = DIV_ROUND_UP(vdd - 265, 5);
343#else
Ying Zhang3ad27372014-10-31 18:06:18 +0800344 vid = DIV_ROUND_UP(vdd - 245, 5);
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800345#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800346
Igor Opaniuk2147a162021-02-09 13:52:45 +0200347#if !CONFIG_IS_ENABLED(DM_I2C)
Ying Zhang3ad27372014-10-31 18:06:18 +0800348 ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
349 1, (void *)&vid, sizeof(vid));
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800350#else
351 struct udevice *dev;
352
353 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
354 if (!ret)
355 ret = dm_i2c_write(dev, IR36021_LOOP1_MANUAL_ID_OFFSET,
356 (void *)&vid, sizeof(vid));
357
358#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800359 if (ret) {
360 printf("VID: failed to write VID\n");
361 return -1;
362 }
363 wait = wait_for_new_voltage(vdd, i2caddress);
364 if (wait < 0)
365 return -1;
366 debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
367
368 vdd_last = wait_for_voltage_stable(i2caddress);
369 if (vdd_last < 0)
370 return -1;
371 debug("VID: Current voltage is %d mV\n", vdd_last);
372 return vdd_last;
373}
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530374
375#endif
376
377#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
378/* this function sets the VDD and returns the value set */
379static int set_voltage_to_LTC(int i2caddress, int vdd)
380{
381 int ret, vdd_last, vdd_target = vdd;
Priyanka Jaindf182a42018-10-11 05:11:23 +0000382 int count = 100, temp = 0;
Biwen Li02670312020-10-12 20:07:35 +0800383 unsigned char value;
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530384
385 /* Scale up to the LTC resolution is 1/4096V */
386 vdd = (vdd * 4096) / 1000;
387
388 /* 5-byte buffer which needs to be sent following the
389 * PMBus command PAGE_PLUS_WRITE.
390 */
391 u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND,
392 vdd & 0xFF, (vdd & 0xFF00) >> 8};
393
394 /* Write the desired voltage code to the regulator */
Igor Opaniuk2147a162021-02-09 13:52:45 +0200395#if !CONFIG_IS_ENABLED(DM_I2C)
Biwen Li02670312020-10-12 20:07:35 +0800396 /* Check write protect state */
397 ret = i2c_read(I2C_VOL_MONITOR_ADDR,
398 PMBUS_CMD_WRITE_PROTECT, 1,
399 (void *)&value, sizeof(value));
400 if (ret)
401 goto exit;
402
403 if (value != EN_WRITE_ALL_CMD) {
404 value = EN_WRITE_ALL_CMD;
405 ret = i2c_write(I2C_VOL_MONITOR_ADDR,
406 PMBUS_CMD_WRITE_PROTECT, 1,
407 (void *)&value, sizeof(value));
408 if (ret)
409 goto exit;
410 }
411
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530412 ret = i2c_write(I2C_VOL_MONITOR_ADDR,
Biwen Li02670312020-10-12 20:07:35 +0800413 PMBUS_CMD_PAGE_PLUS_WRITE, 1,
414 (void *)&buff, sizeof(buff));
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800415#else
416 struct udevice *dev;
417
418 ret = i2c_get_chip_for_busnum(0, I2C_VOL_MONITOR_ADDR, 1, &dev);
Biwen Li02670312020-10-12 20:07:35 +0800419 if (!ret) {
420 /* Check write protect state */
421 ret = dm_i2c_read(dev,
422 PMBUS_CMD_WRITE_PROTECT,
423 (void *)&value, sizeof(value));
424 if (ret)
425 goto exit;
426
427 if (value != EN_WRITE_ALL_CMD) {
428 value = EN_WRITE_ALL_CMD;
429 ret = dm_i2c_write(dev,
430 PMBUS_CMD_WRITE_PROTECT,
431 (void *)&value, sizeof(value));
432 if (ret)
433 goto exit;
434 }
435
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800436 ret = dm_i2c_write(dev, PMBUS_CMD_PAGE_PLUS_WRITE,
Biwen Li02670312020-10-12 20:07:35 +0800437 (void *)&buff, sizeof(buff));
438 }
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800439#endif
Biwen Li02670312020-10-12 20:07:35 +0800440exit:
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530441 if (ret) {
442 printf("VID: I2C failed to write to the volatge regulator\n");
443 return -1;
444 }
445
446 /* Wait for the volatge to get to the desired value */
447 do {
448 vdd_last = read_voltage_from_LTC(i2caddress);
449 if (vdd_last < 0) {
450 printf("VID: Couldn't read sensor abort VID adjust\n");
451 return -1;
452 }
Priyanka Jaindf182a42018-10-11 05:11:23 +0000453 count--;
454 temp = vdd_last - vdd_target;
455 } while ((abs(temp) > 2) && (count > 0));
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530456
457 return vdd_last;
458}
Ying Zhang3ad27372014-10-31 18:06:18 +0800459#endif
460
461static int set_voltage(int i2caddress, int vdd)
462{
463 int vdd_last = -1;
464
465#ifdef CONFIG_VOL_MONITOR_IR36021_SET
466 vdd_last = set_voltage_to_IR(i2caddress, vdd);
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530467#elif defined CONFIG_VOL_MONITOR_LTC3882_SET
468 vdd_last = set_voltage_to_LTC(i2caddress, vdd);
Ying Zhang3ad27372014-10-31 18:06:18 +0800469#else
470 #error Specific voltage monitor must be defined
471#endif
472 return vdd_last;
473}
474
Priyanka Jain29ca7132017-01-19 11:12:27 +0530475#ifdef CONFIG_FSL_LSCH3
Ying Zhang3ad27372014-10-31 18:06:18 +0800476int adjust_vdd(ulong vdd_override)
477{
478 int re_enable = disable_interrupts();
Priyanka Jain29ca7132017-01-19 11:12:27 +0530479 struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
480 u32 fusesr;
Rajesh Bhagat94583162018-01-17 16:13:03 +0530481#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
482 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Priyanka Jain29ca7132017-01-19 11:12:27 +0530483 u8 vid, buf;
Rajesh Bhagat94583162018-01-17 16:13:03 +0530484#else
485 u8 vid;
486#endif
Priyanka Jain29ca7132017-01-19 11:12:27 +0530487 int vdd_target, vdd_current, vdd_last;
Priyanka Singhf6cb8372020-10-27 15:50:14 +0530488 int ret, i2caddress = 0;
Priyanka Jain29ca7132017-01-19 11:12:27 +0530489 unsigned long vdd_string_override;
490 char *vdd_string;
Meenakshi Aggarwal3a187cf2020-10-29 19:16:16 +0530491#if defined(CONFIG_ARCH_LX2160A) || defined(CONFIG_ARCH_LX2162A)
Priyanka Jaindb1e3df2018-10-11 05:22:34 +0000492 static const u16 vdd[32] = {
493 8250,
494 7875,
495 7750,
496 0, /* reserved */
497 0, /* reserved */
498 0, /* reserved */
499 0, /* reserved */
500 0, /* reserved */
501 0, /* reserved */
502 0, /* reserved */
503 0, /* reserved */
504 0, /* reserved */
505 0, /* reserved */
506 0, /* reserved */
507 0, /* reserved */
508 0, /* reserved */
509 8000,
510 8125,
511 8250,
512 0, /* reserved */
513 8500,
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 0, /* reserved */
525 };
526#else
Rajesh Bhagatc535ad42018-01-17 16:13:01 +0530527#ifdef CONFIG_ARCH_LS1088A
528 static const uint16_t vdd[32] = {
529 10250,
530 9875,
531 9750,
532 0, /* reserved */
533 0, /* reserved */
534 0, /* reserved */
535 0, /* reserved */
536 0, /* reserved */
537 9000,
538 0, /* reserved */
539 0, /* reserved */
540 0, /* reserved */
541 0, /* reserved */
542 0, /* reserved */
543 0, /* reserved */
544 0, /* reserved */
545 10000, /* 1.0000V */
546 10125,
547 10250,
548 0, /* reserved */
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 0, /* reserved */
561 };
562
563#else
Priyanka Jain29ca7132017-01-19 11:12:27 +0530564 static const uint16_t vdd[32] = {
565 10500,
566 0, /* reserved */
567 9750,
568 0, /* reserved */
569 9500,
570 0, /* reserved */
571 0, /* reserved */
572 0, /* reserved */
Priyanka Jain49119482018-05-09 12:54:38 +0530573 9000, /* reserved */
Priyanka Jain29ca7132017-01-19 11:12:27 +0530574 0, /* reserved */
575 0, /* reserved */
576 0, /* reserved */
577 0, /* reserved */
Martin Kaistraada19fd2020-08-21 13:44:13 +0200578 0, /* reserved */
579 0, /* reserved */
580 0, /* reserved */
Priyanka Jain29ca7132017-01-19 11:12:27 +0530581 10000, /* 1.0000V */
582 0, /* reserved */
583 10250,
584 0, /* reserved */
585 10500,
586 0, /* reserved */
587 0, /* reserved */
588 0, /* reserved */
589 0, /* reserved */
590 0, /* reserved */
591 0, /* reserved */
592 0, /* reserved */
593 0, /* reserved */
594 0, /* reserved */
595 0, /* reserved */
596 0, /* reserved */
597 };
Rajesh Bhagatc535ad42018-01-17 16:13:01 +0530598#endif
Priyanka Jaindb1e3df2018-10-11 05:22:34 +0000599#endif
Priyanka Jain29ca7132017-01-19 11:12:27 +0530600 struct vdd_drive {
601 u8 vid;
602 unsigned voltage;
603 };
604
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 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530611#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
612 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Priyanka Jain29ca7132017-01-19 11:12:27 +0530613 ret = find_ir_chip_on_i2c();
614 if (ret < 0) {
615 printf("VID: Could not find voltage regulator on I2C.\n");
616 ret = -1;
617 goto exit;
618 } else {
619 i2caddress = ret;
620 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
621 }
622
623 /* check IR chip work on Intel mode*/
Igor Opaniuk2147a162021-02-09 13:52:45 +0200624#if !CONFIG_IS_ENABLED(DM_I2C)
Priyanka Jain29ca7132017-01-19 11:12:27 +0530625 ret = i2c_read(i2caddress,
626 IR36021_INTEL_MODE_OOFSET,
627 1, (void *)&buf, 1);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800628#else
629 struct udevice *dev;
630
631 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
632 if (!ret)
633 ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
634 (void *)&buf, 1);
635#endif
Priyanka Jain29ca7132017-01-19 11:12:27 +0530636 if (ret) {
637 printf("VID: failed to read IR chip mode.\n");
638 ret = -1;
639 goto exit;
640 }
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800641
Priyanka Jain29ca7132017-01-19 11:12:27 +0530642 if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
643 printf("VID: IR Chip is not used in Intel mode.\n");
644 ret = -1;
645 goto exit;
646 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530647#endif
Priyanka Jain29ca7132017-01-19 11:12:27 +0530648
649 /* get the voltage ID from fuse status register */
650 fusesr = in_le32(&gur->dcfg_fusesr);
651 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
652 FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
653 if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
654 vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
655 FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
656 }
657 vdd_target = vdd[vid];
658
659 /* check override variable for overriding VDD */
Simon Glass00caae62017-08-03 12:22:12 -0600660 vdd_string = env_get(CONFIG_VID_FLS_ENV);
Priyanka Jain29ca7132017-01-19 11:12:27 +0530661 if (vdd_override == 0 && vdd_string &&
662 !strict_strtoul(vdd_string, 10, &vdd_string_override))
663 vdd_override = vdd_string_override;
664
665 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
666 vdd_target = vdd_override * 10; /* convert to 1/10 mV */
667 debug("VDD override is %lu\n", vdd_override);
668 } else if (vdd_override != 0) {
669 printf("Invalid value.\n");
670 }
671
672 /* divide and round up by 10 to get a value in mV */
673 vdd_target = DIV_ROUND_UP(vdd_target, 10);
674 if (vdd_target == 0) {
675 debug("VID: VID not used\n");
676 ret = 0;
677 goto exit;
678 } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) {
679 /* Check vdd_target is in valid range */
680 printf("VID: Target VID %d mV is not in range.\n",
681 vdd_target);
682 ret = -1;
683 goto exit;
684 } else {
685 debug("VID: vid = %d mV\n", vdd_target);
686 }
687
688 /*
689 * Read voltage monitor to check real voltage.
690 */
691 vdd_last = read_voltage(i2caddress);
692 if (vdd_last < 0) {
693 printf("VID: Couldn't read sensor abort VID adjustment\n");
694 ret = -1;
695 goto exit;
696 }
697 vdd_current = vdd_last;
698 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530699
700#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
701 /* Set the target voltage */
702 vdd_last = vdd_current = set_voltage(i2caddress, vdd_target);
703#else
Priyanka Jain29ca7132017-01-19 11:12:27 +0530704 /*
705 * Adjust voltage to at or one step above target.
706 * As measurements are less precise than setting the values
707 * we may run through dummy steps that cancel each other
708 * when stepping up and then down.
709 */
710 while (vdd_last > 0 &&
711 vdd_last < vdd_target) {
712 vdd_current += IR_VDD_STEP_UP;
713 vdd_last = set_voltage(i2caddress, vdd_current);
714 }
715 while (vdd_last > 0 &&
716 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
717 vdd_current -= IR_VDD_STEP_DOWN;
718 vdd_last = set_voltage(i2caddress, vdd_current);
719 }
720
Rajesh Bhagat23a12cb2018-01-17 16:13:05 +0530721#endif
Rajesh Bhagat36075702018-01-17 16:13:02 +0530722 if (board_adjust_vdd(vdd_target) < 0) {
723 ret = -1;
724 goto exit;
725 }
726
Priyanka Jain29ca7132017-01-19 11:12:27 +0530727 if (vdd_last > 0)
728 printf("VID: Core voltage after adjustment is at %d mV\n",
729 vdd_last);
730 else
731 ret = -1;
732exit:
733 if (re_enable)
734 enable_interrupts();
735 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
736 return ret;
737}
738#else /* !CONFIG_FSL_LSCH3 */
739int adjust_vdd(ulong vdd_override)
740{
741 int re_enable = disable_interrupts();
742#if defined(CONFIG_FSL_LSCH2)
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800743 struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
744#else
Ying Zhang3ad27372014-10-31 18:06:18 +0800745 ccsr_gur_t __iomem *gur =
746 (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800747#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800748 u32 fusesr;
Ying Zhangcabe4d22016-01-22 12:15:12 +0800749 u8 vid, buf;
Ying Zhang3ad27372014-10-31 18:06:18 +0800750 int vdd_target, vdd_current, vdd_last;
751 int ret, i2caddress;
752 unsigned long vdd_string_override;
753 char *vdd_string;
754 static const uint16_t vdd[32] = {
755 0, /* unused */
756 9875, /* 0.9875V */
757 9750,
758 9625,
759 9500,
760 9375,
761 9250,
762 9125,
763 9000,
764 8875,
765 8750,
766 8625,
767 8500,
768 8375,
769 8250,
770 8125,
771 10000, /* 1.0000V */
772 10125,
773 10250,
774 10375,
775 10500,
776 10625,
777 10750,
778 10875,
779 11000,
780 0, /* reserved */
781 };
782 struct vdd_drive {
783 u8 vid;
784 unsigned voltage;
785 };
786
787 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
788 if (ret) {
789 debug("VID: I2C failed to switch channel\n");
790 ret = -1;
791 goto exit;
792 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530793#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
794 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang3ad27372014-10-31 18:06:18 +0800795 ret = find_ir_chip_on_i2c();
796 if (ret < 0) {
797 printf("VID: Could not find voltage regulator on I2C.\n");
798 ret = -1;
799 goto exit;
800 } else {
801 i2caddress = ret;
802 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
803 }
804
Ying Zhangcabe4d22016-01-22 12:15:12 +0800805 /* check IR chip work on Intel mode*/
Igor Opaniuk2147a162021-02-09 13:52:45 +0200806#if !CONFIG_IS_ENABLED(DM_I2C)
Ying Zhangcabe4d22016-01-22 12:15:12 +0800807 ret = i2c_read(i2caddress,
808 IR36021_INTEL_MODE_OOFSET,
809 1, (void *)&buf, 1);
Chuanhua Han0eba65d2019-07-10 21:00:20 +0800810#else
811 struct udevice *dev;
812
813 ret = i2c_get_chip_for_busnum(0, i2caddress, 1, &dev);
814 if (!ret)
815 ret = dm_i2c_read(dev, IR36021_INTEL_MODE_OOFSET,
816 (void *)&buf, 1);
817#endif
Ying Zhangcabe4d22016-01-22 12:15:12 +0800818 if (ret) {
819 printf("VID: failed to read IR chip mode.\n");
820 ret = -1;
821 goto exit;
822 }
823 if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
824 printf("VID: IR Chip is not used in Intel mode.\n");
825 ret = -1;
826 goto exit;
827 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530828#endif
Ying Zhangcabe4d22016-01-22 12:15:12 +0800829
Ying Zhang3ad27372014-10-31 18:06:18 +0800830 /* get the voltage ID from fuse status register */
831 fusesr = in_be32(&gur->dcfg_fusesr);
832 /*
833 * VID is used according to the table below
834 * ---------------------------------------
835 * | DA_V |
836 * |-------------------------------------|
837 * | 5b00000 | 5b00001-5b11110 | 5b11111 |
838 * ---------------+---------+-----------------+---------|
839 * | D | 5b00000 | NO VID | VID = DA_V | NO VID |
840 * | A |----------+---------+-----------------+---------|
841 * | _ | 5b00001 |VID = | VID = |VID = |
842 * | V | ~ | DA_V_ALT| DA_V_ALT | DA_A_VLT|
843 * | _ | 5b11110 | | | |
844 * | A |----------+---------+-----------------+---------|
845 * | L | 5b11111 | No VID | VID = DA_V | NO VID |
846 * | T | | | | |
847 * ------------------------------------------------------
848 */
Shaohui Xie126fe702016-09-07 17:56:14 +0800849#ifdef CONFIG_FSL_LSCH2
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800850 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
851 FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
852 if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
853 vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
854 FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
855 }
856#else
Ying Zhang3ad27372014-10-31 18:06:18 +0800857 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
858 FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
859 if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
860 vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
861 FSL_CORENET_DCFG_FUSESR_VID_MASK;
862 }
Shaohui Xie02b5d2e2015-11-11 17:58:37 +0800863#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800864 vdd_target = vdd[vid];
865
866 /* check override variable for overriding VDD */
Simon Glass00caae62017-08-03 12:22:12 -0600867 vdd_string = env_get(CONFIG_VID_FLS_ENV);
Ying Zhang3ad27372014-10-31 18:06:18 +0800868 if (vdd_override == 0 && vdd_string &&
869 !strict_strtoul(vdd_string, 10, &vdd_string_override))
870 vdd_override = vdd_string_override;
871 if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
872 vdd_target = vdd_override * 10; /* convert to 1/10 mV */
873 debug("VDD override is %lu\n", vdd_override);
874 } else if (vdd_override != 0) {
875 printf("Invalid value.\n");
876 }
877 if (vdd_target == 0) {
878 debug("VID: VID not used\n");
879 ret = 0;
880 goto exit;
881 } else {
882 /* divide and round up by 10 to get a value in mV */
883 vdd_target = DIV_ROUND_UP(vdd_target, 10);
884 debug("VID: vid = %d mV\n", vdd_target);
885 }
886
887 /*
888 * Read voltage monitor to check real voltage.
889 */
890 vdd_last = read_voltage(i2caddress);
891 if (vdd_last < 0) {
892 printf("VID: Couldn't read sensor abort VID adjustment\n");
893 ret = -1;
894 goto exit;
895 }
896 vdd_current = vdd_last;
897 debug("VID: Core voltage is currently at %d mV\n", vdd_last);
898 /*
899 * Adjust voltage to at or one step above target.
900 * As measurements are less precise than setting the values
901 * we may run through dummy steps that cancel each other
902 * when stepping up and then down.
903 */
904 while (vdd_last > 0 &&
905 vdd_last < vdd_target) {
906 vdd_current += IR_VDD_STEP_UP;
907 vdd_last = set_voltage(i2caddress, vdd_current);
908 }
909 while (vdd_last > 0 &&
910 vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
911 vdd_current -= IR_VDD_STEP_DOWN;
912 vdd_last = set_voltage(i2caddress, vdd_current);
913 }
914
915 if (vdd_last > 0)
916 printf("VID: Core voltage after adjustment is at %d mV\n",
917 vdd_last);
918 else
919 ret = -1;
920exit:
921 if (re_enable)
922 enable_interrupts();
Wenbin Song1be8d102016-03-09 13:38:23 +0800923
924 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
925
Ying Zhang3ad27372014-10-31 18:06:18 +0800926 return ret;
927}
Priyanka Jain29ca7132017-01-19 11:12:27 +0530928#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800929
930static int print_vdd(void)
931{
Priyanka Singhf3555bd2020-10-16 14:45:44 +0530932 int vdd_last, ret, i2caddress = 0;
Ying Zhang3ad27372014-10-31 18:06:18 +0800933
934 ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
935 if (ret) {
936 debug("VID : I2c failed to switch channel\n");
937 return -1;
938 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530939#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
940 defined(CONFIG_VOL_MONITOR_IR36021_READ)
Ying Zhang3ad27372014-10-31 18:06:18 +0800941 ret = find_ir_chip_on_i2c();
942 if (ret < 0) {
943 printf("VID: Could not find voltage regulator on I2C.\n");
Wenbin Song1be8d102016-03-09 13:38:23 +0800944 goto exit;
Ying Zhang3ad27372014-10-31 18:06:18 +0800945 } else {
946 i2caddress = ret;
947 debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
948 }
Rajesh Bhagat94583162018-01-17 16:13:03 +0530949#endif
Ying Zhang3ad27372014-10-31 18:06:18 +0800950
951 /*
952 * Read voltage monitor to check real voltage.
953 */
954 vdd_last = read_voltage(i2caddress);
955 if (vdd_last < 0) {
956 printf("VID: Couldn't read sensor abort VID adjustment\n");
Wenbin Song1be8d102016-03-09 13:38:23 +0800957 goto exit;
Ying Zhang3ad27372014-10-31 18:06:18 +0800958 }
959 printf("VID: Core voltage is at %d mV\n", vdd_last);
Wenbin Song1be8d102016-03-09 13:38:23 +0800960exit:
961 i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
Ying Zhang3ad27372014-10-31 18:06:18 +0800962
Wenbin Song1be8d102016-03-09 13:38:23 +0800963 return ret < 0 ? -1 : 0;
964
Ying Zhang3ad27372014-10-31 18:06:18 +0800965}
966
Simon Glass09140112020-05-10 11:40:03 -0600967static int do_vdd_override(struct cmd_tbl *cmdtp,
Ying Zhang3ad27372014-10-31 18:06:18 +0800968 int flag, int argc,
Simon Glass09140112020-05-10 11:40:03 -0600969 char *const argv[])
Ying Zhang3ad27372014-10-31 18:06:18 +0800970{
971 ulong override;
972
973 if (argc < 2)
974 return CMD_RET_USAGE;
975
976 if (!strict_strtoul(argv[1], 10, &override))
977 adjust_vdd(override); /* the value is checked by callee */
978 else
979 return CMD_RET_USAGE;
980 return 0;
981}
982
Simon Glass09140112020-05-10 11:40:03 -0600983static int do_vdd_read(struct cmd_tbl *cmdtp, int flag, int argc,
984 char *const argv[])
Ying Zhang3ad27372014-10-31 18:06:18 +0800985{
986 if (argc < 1)
987 return CMD_RET_USAGE;
988 print_vdd();
989
990 return 0;
991}
992
993U_BOOT_CMD(
994 vdd_override, 2, 0, do_vdd_override,
995 "override VDD",
996 " - override with the voltage specified in mV, eg. 1050"
997);
998
999U_BOOT_CMD(
1000 vdd_read, 1, 0, do_vdd_read,
1001 "read VDD",
1002 " - Read the voltage specified in mV"
1003)