blob: ebd6418fd472c2cc1ebefb2d90e0f3552225cb80 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Max Krummenacher3b74ccf2016-11-30 19:43:08 +01002/*
Marcel Ziswilera22d71c2019-02-08 18:12:12 +01003 * Copyright (C) 2014-2019, Toradex AG
Max Krummenacher3b74ccf2016-11-30 19:43:08 +01004 */
5
6/*
7 * Helpers for Freescale PMIC PF0100
8*/
9
10#include <common.h>
11#include <i2c.h>
12#include <asm/arch/imx-regs.h>
13#include <asm/arch/iomux.h>
14#include <asm/arch/mx6-pins.h>
15#include <asm/gpio.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020016#include <asm/mach-imx/iomux-v3.h>
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010017
18#include "pf0100_otp.inc"
19#include "pf0100.h"
20
21/* define for PMIC register dump */
22/*#define DEBUG */
23
Gerard Salvatella60f13512019-02-08 18:12:26 +010024#define WARNBAR "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
25
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010026/* use Apalis GPIO1 to switch on VPGM, ON: 1 */
Tom Rinic9515392018-01-03 09:19:17 -050027static __maybe_unused iomux_v3_cfg_t const pmic_prog_pads[] = {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010028 MX6_PAD_NANDF_D4__GPIO2_IO04 | MUX_PAD_CTRL(NO_PAD_CTRL),
29# define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 4)
30};
31
32unsigned pmic_init(void)
33{
Marcel Ziswilera22d71c2019-02-08 18:12:12 +010034 int rc;
35 struct udevice *dev = NULL;
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010036 unsigned programmed = 0;
37 uchar bus = 1;
38 uchar devid, revid, val;
39
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +010040 puts("PMIC: ");
Marcel Ziswilera22d71c2019-02-08 18:12:12 +010041 rc = i2c_get_chip_for_busnum(bus, PFUZE100_I2C_ADDR, 1, &dev);
42 if (rc) {
43 printf("failed to get device for PMIC at address 0x%x\n",
44 PFUZE100_I2C_ADDR);
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010045 return 0;
46 }
Gerard Salvatella60f13512019-02-08 18:12:26 +010047
48 /* check for errors in PMIC fuses */
49 if (dm_i2c_read(dev, PFUZE100_INTSTAT3, &val, 1) < 0) {
50 puts("i2c pmic INTSTAT3 register read failed\n");
51 return 0;
52 }
53 if (val & PFUZE100_BIT_OTP_ECCI) {
54 puts("\n" WARNBAR);
55 puts("WARNING: ecc errors found in pmic fuse banks\n");
56 puts(WARNBAR);
57 }
58 if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE1, &val, 1) < 0) {
59 puts("i2c pmic ECC_SE1 register read failed\n");
60 return 0;
61 }
62 if (val & PFUZE100_BITS_ECC_SE1) {
63 puts(WARNBAR);
64 puts("WARNING: ecc has made bit corrections in banks 1 to 5\n");
65 puts(WARNBAR);
66 }
67 if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE2, &val, 1) < 0) {
68 puts("i2c pmic ECC_SE2 register read failed\n");
69 return 0;
70 }
71 if (val & PFUZE100_BITS_ECC_SE2) {
72 puts(WARNBAR);
73 puts("WARNING: ecc has made bit corrections in banks 6 to 10\n"
74 );
75 puts(WARNBAR);
76 }
77 if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE1, &val, 1) < 0) {
78 puts("i2c pmic ECC_DE register read failed\n");
79 return 0;
80 }
81 if (val & PFUZE100_BITS_ECC_DE1) {
82 puts(WARNBAR);
83 puts("ERROR: banks 1 to 5 have uncorrectable bits\n");
84 puts(WARNBAR);
85 }
86 if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE2, &val, 1) < 0) {
87 puts("i2c pmic ECC_DE register read failed\n");
88 return 0;
89 }
90 if (val & PFUZE100_BITS_ECC_DE2) {
91 puts(WARNBAR);
92 puts("ERROR: banks 6 to 10 have uncorrectable bits\n");
93 puts(WARNBAR);
94 }
95
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010096 /* get device ident */
Marcel Ziswilera22d71c2019-02-08 18:12:12 +010097 if (dm_i2c_read(dev, PFUZE100_DEVICEID, &devid, 1) < 0) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +010098 puts("i2c pmic devid read failed\n");
99 return 0;
100 }
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100101 if (dm_i2c_read(dev, PFUZE100_REVID, &revid, 1) < 0) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100102 puts("i2c pmic revid read failed\n");
103 return 0;
104 }
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100105 printf("device id: 0x%.2x, revision id: 0x%.2x, ", devid, revid);
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100106
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100107 /* get device programmed state */
108 val = PFUZE100_PAGE_REGISTER_PAGE1;
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100109 if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100110 puts("i2c write failed\n");
111 return 0;
112 }
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100113 if (dm_i2c_read(dev, PFUZE100_FUSE_POR1, &val, 1) < 0) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100114 puts("i2c fuse_por read failed\n");
115 return 0;
116 }
117 if (val & PFUZE100_FUSE_POR_M)
118 programmed++;
119
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100120 if (dm_i2c_read(dev, PFUZE100_FUSE_POR2, &val, 1) < 0) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100121 puts("i2c fuse_por read failed\n");
122 return programmed;
123 }
124 if (val & PFUZE100_FUSE_POR_M)
125 programmed++;
126
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100127 if (dm_i2c_read(dev, PFUZE100_FUSE_POR3, &val, 1) < 0) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100128 puts("i2c fuse_por read failed\n");
129 return programmed;
130 }
131 if (val & PFUZE100_FUSE_POR_M)
132 programmed++;
133
134 switch (programmed) {
135 case 0:
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100136 puts("not programmed\n");
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100137 break;
138 case 3:
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100139 puts("programmed\n");
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100140 break;
141 default:
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100142 puts("undefined programming state\n");
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100143 break;
144 }
145
146 /* The following is needed during production */
147 if (programmed != 3) {
148 /* set VGEN1 to 1.2V */
149 val = PFUZE100_VGEN1_VAL;
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100150 if (dm_i2c_write(dev, PFUZE100_VGEN1CTL, &val, 1)) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100151 puts("i2c write failed\n");
152 return programmed;
153 }
154
155 /* set SWBST to 5.0V */
156 val = PFUZE100_SWBST_VAL;
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100157 if (dm_i2c_write(dev, PFUZE100_SWBSTCTL, &val, 1))
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100158 puts("i2c write failed\n");
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100159 }
160
161#ifdef DEBUG
162 {
163 unsigned int i, j;
164
165 for (i = 0; i < 16; i++)
166 printf("\t%x", i);
167 for (j = 0; j < 0x80; ) {
168 printf("\n%2x", j);
169 for (i = 0; i < 16; i++) {
170 dm_i2c_read(dev, j + i, &val, 1);
171 printf("\t%2x", val);
172 }
173 j += 0x10;
174 }
175 printf("\nEXT Page 1");
176
177 val = PFUZE100_PAGE_REGISTER_PAGE1;
178 if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
179 puts("i2c write failed\n");
180 return 0;
181 }
182
183 for (j = 0x80; j < 0x100; ) {
184 printf("\n%2x", j);
185 for (i = 0; i < 16; i++) {
186 dm_i2c_read(dev, j + i, &val, 1);
187 printf("\t%2x", val);
188 }
189 j += 0x10;
190 }
191 printf("\nEXT Page 2");
192
193 val = PFUZE100_PAGE_REGISTER_PAGE2;
194 if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
195 puts("i2c write failed\n");
196 return 0;
197 }
198
199 for (j = 0x80; j < 0x100; ) {
200 printf("\n%2x", j);
201 for (i = 0; i < 16; i++) {
202 dm_i2c_read(dev, j + i, &val, 1);
203 printf("\t%2x", val);
204 }
205 j += 0x10;
206 }
207 printf("\n");
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100208 }
Marcel Ziswilerfcaa3112019-02-08 18:12:20 +0100209#endif /* DEBUG */
210
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100211 return programmed;
212}
213
Tom Rinic9515392018-01-03 09:19:17 -0500214#ifndef CONFIG_SPL_BUILD
215static int pf0100_prog(void)
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100216{
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100217 int rc;
218 struct udevice *dev = NULL;
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100219 unsigned char bus = 1;
220 unsigned char val;
221 unsigned int i;
222
223 if (pmic_init() == 3) {
224 puts("PMIC already programmed, exiting\n");
225 return CMD_RET_FAILURE;
226 }
227 /* set up gpio to manipulate vprog, initially off */
228 imx_iomux_v3_setup_multiple_pads(pmic_prog_pads,
229 ARRAY_SIZE(pmic_prog_pads));
230 gpio_direction_output(PMIC_PROG_VOLTAGE, 0);
231
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100232 rc = i2c_get_chip_for_busnum(bus, PFUZE100_I2C_ADDR, 1, &dev);
233 if (rc) {
234 printf("failed to get device for PMIC at address 0x%x\n",
235 PFUZE100_I2C_ADDR);
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100236 return CMD_RET_FAILURE;
237 }
238
239 for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) {
240 switch (pmic_otp_prog[i].cmd) {
241 case pmic_i2c:
242 val = (unsigned char) (pmic_otp_prog[i].value & 0xff);
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100243 if (dm_i2c_write(dev, pmic_otp_prog[i].reg, &val, 1)) {
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100244 printf("i2c write failed, reg 0x%2x, value 0x%2x\n",
245 pmic_otp_prog[i].reg, val);
246 return CMD_RET_FAILURE;
247 }
248 break;
249 case pmic_delay:
250 udelay(pmic_otp_prog[i].value * 1000);
251 break;
252 case pmic_vpgm:
253 gpio_direction_output(PMIC_PROG_VOLTAGE,
254 pmic_otp_prog[i].value);
255 break;
256 case pmic_pwr:
257 /* TODO */
258 break;
259 }
260 }
261 return CMD_RET_SUCCESS;
262}
263
Tom Rinic9515392018-01-03 09:19:17 -0500264static int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc,
Max Krummenacher3b74ccf2016-11-30 19:43:08 +0100265 char * const argv[])
266{
267 int ret;
268 puts("Programming PMIC OTP...");
269 ret = pf0100_prog();
270 if (ret == CMD_RET_SUCCESS)
271 puts("done.\n");
272 else
273 puts("failed.\n");
274 return ret;
275}
276
277U_BOOT_CMD(
278 pf0100_otp_prog, 1, 0, do_pf0100_prog,
279 "Program the OTP fuses on the PMIC PF0100",
280 ""
281);
Marcel Ziswilera22d71c2019-02-08 18:12:12 +0100282#endif /* CONFIG_SPL_BUILD */