board: colibri_imx6: check for and report ecc errors in fuses
authorGerard Salvatella <gerard.salvatella@toradex.com>
Fri, 8 Feb 2019 17:42:29 +0000 (18:42 +0100)
committerStefano Babic <sbabic@denx.de>
Sat, 13 Apr 2019 18:30:09 +0000 (20:30 +0200)
The PMIC on the Colibri iMX6 may have ECC errors in fuses that will
prevent correct settings. Up to one bit error per fuse bank can be
reported and corrected by the ECC logic. Two bit errors can only be
reported.

Signed-off-by: Gerard Salvatella <gerard.salvatella@toradex.com>
Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
board/toradex/colibri_imx6/pf0100.c
board/toradex/colibri_imx6/pf0100.h

index 09c3cc950aebe5886f55edcd3195303652d3f391..e744243297b0af03f45d2233d7674ea40f2eea0d 100644 (file)
@@ -21,6 +21,8 @@
 /* define for PMIC register dump */
 /*#define DEBUG */
 
+#define WARNBAR "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
+
 /* use GPIO: EXT_IO1 to switch on VPGM, ON: 1 */
 static __maybe_unused iomux_v3_cfg_t const pmic_prog_pads[] = {
        MX6_PAD_NANDF_D3__GPIO2_IO03 | MUX_PAD_CTRL(NO_PAD_CTRL),
@@ -42,6 +44,55 @@ unsigned pmic_init(void)
                       PFUZE100_I2C_ADDR);
                return 0;
        }
+
+       /* check for errors in PMIC fuses */
+       if (dm_i2c_read(dev, PFUZE100_INTSTAT3, &val, 1) < 0) {
+               puts("i2c pmic INTSTAT3 register read failed\n");
+               return 0;
+       }
+       if (val & PFUZE100_BIT_OTP_ECCI) {
+               puts("\n" WARNBAR);
+               puts("WARNING: ecc errors found in pmic fuse banks\n");
+               puts(WARNBAR);
+       }
+       if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE1, &val, 1) < 0) {
+               puts("i2c pmic ECC_SE1 register read failed\n");
+               return 0;
+       }
+       if (val & PFUZE100_BITS_ECC_SE1) {
+               puts(WARNBAR);
+               puts("WARNING: ecc has made bit corrections in banks 1 to 5\n");
+               puts(WARNBAR);
+       }
+       if (dm_i2c_read(dev, PFUZE100_OTP_ECC_SE2, &val, 1) < 0) {
+               puts("i2c pmic ECC_SE2 register read failed\n");
+               return 0;
+       }
+       if (val & PFUZE100_BITS_ECC_SE2) {
+               puts(WARNBAR);
+               puts("WARNING: ecc has made bit corrections in banks 6 to 10\n"
+                   );
+               puts(WARNBAR);
+       }
+       if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE1, &val, 1) < 0) {
+               puts("i2c pmic ECC_DE register read failed\n");
+               return 0;
+       }
+       if (val & PFUZE100_BITS_ECC_DE1) {
+               puts(WARNBAR);
+               puts("ERROR: banks 1 to 5 have uncorrectable bits\n");
+               puts(WARNBAR);
+       }
+       if (dm_i2c_read(dev, PFUZE100_OTP_ECC_DE2, &val, 1) < 0) {
+               puts("i2c pmic ECC_DE register read failed\n");
+               return 0;
+       }
+       if (val & PFUZE100_BITS_ECC_DE2) {
+               puts(WARNBAR);
+               puts("ERROR: banks 6 to 10 have uncorrectable bits\n");
+               puts(WARNBAR);
+       }
+
        /* get device ident */
        if (dm_i2c_read(dev, PFUZE100_DEVICEID, &devid, 1) < 0) {
                puts("i2c pmic devid read failed\n");
index c0efb79bbc987761b37dffcff84d4b6b214886e7..925762051104b828f689d477db809cc182ac8592 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Copyright (C) 2014-2016, Toradex AG
+ * Copyright (C) 2014-2019, Toradex AG
  */
 
 /*
 #ifndef PF0100_H_
 #define PF0100_H_
 
+/* bit definitions */
+#define PFUZE100_BIT_0                 (0x01 << 0)
+#define PFUZE100_BIT_1                 (0x01 << 1)
+#define PFUZE100_BIT_2                 (0x01 << 2)
+#define PFUZE100_BIT_3                 (0x01 << 3)
+#define PFUZE100_BIT_4                 (0x01 << 4)
+#define PFUZE100_BIT_5                 (0x01 << 5)
+#define PFUZE100_BIT_6                 (0x01 << 6)
+#define PFUZE100_BIT_7                 (0x01 << 7)
+
 /* 7-bit I2C bus slave address */
 #define PFUZE100_I2C_ADDR              (0x08)
 /* Register Addresses */
 #define PFUZE100_DEVICEID              (0x0)
 #define PFUZE100_REVID                 (0x3)
+#define PFUZE100_INTSTAT3              (0xe)
+#define PFUZE100_BIT_OTP_ECCI          PFUZE100_BIT_7
 #define PFUZE100_SW1AMODE              (0x23)
 #define PFUZE100_SW1ACON               36
 #define PFUZE100_SW1ACON_SPEED_VAL     (0x1<<6)        /*default */
 #define PFUZE100_PAGE_REGISTER_PAGE2   (0x02 & PFUZE100_PAGE_REGISTER_PAGE_M)
 
 /* extended page 1 */
+#define PFUZE100_OTP_ECC_SE1           0x8a
+#define PFUZE100_BIT_ECC1_SE           PFUZE100_BIT_0
+#define PFUZE100_BIT_ECC2_SE           PFUZE100_BIT_1
+#define PFUZE100_BIT_ECC3_SE           PFUZE100_BIT_2
+#define PFUZE100_BIT_ECC4_SE           PFUZE100_BIT_3
+#define PFUZE100_BIT_ECC5_SE           PFUZE100_BIT_4
+#define PFUZE100_BITS_ECC_SE1          ((PFUZE100_BIT_ECC1_SE) | \
+                                       (PFUZE100_BIT_ECC2_SE) | \
+                                       (PFUZE100_BIT_ECC3_SE) | \
+                                       (PFUZE100_BIT_ECC4_SE) | \
+                                       (PFUZE100_BIT_ECC5_SE))
+#define PFUZE100_OTP_ECC_SE2           0x8b
+#define PFUZE100_BIT_ECC6_SE           PFUZE100_BIT_0
+#define PFUZE100_BIT_ECC7_SE           PFUZE100_BIT_1
+#define PFUZE100_BIT_ECC8_SE           PFUZE100_BIT_2
+#define PFUZE100_BIT_ECC9_SE           PFUZE100_BIT_3
+#define PFUZE100_BIT_ECC10_SE          PFUZE100_BIT_4
+#define PFUZE100_BITS_ECC_SE2          ((PFUZE100_BIT_ECC6_SE) | \
+                                       (PFUZE100_BIT_ECC7_SE) | \
+                                       (PFUZE100_BIT_ECC8_SE) | \
+                                       (PFUZE100_BIT_ECC9_SE) | \
+                                       (PFUZE100_BIT_ECC10_SE))
+#define PFUZE100_OTP_ECC_DE1           0x8c
+#define PFUZE100_BIT_ECC1_DE           PFUZE100_BIT_0
+#define PFUZE100_BIT_ECC2_DE           PFUZE100_BIT_1
+#define PFUZE100_BIT_ECC3_DE           PFUZE100_BIT_2
+#define PFUZE100_BIT_ECC4_DE           PFUZE100_BIT_3
+#define PFUZE100_BIT_ECC5_DE           PFUZE100_BIT_4
+#define PFUZE100_BITS_ECC_DE1          ((PFUZE100_BIT_ECC1_DE) | \
+                                       (PFUZE100_BIT_ECC2_DE) | \
+                                       (PFUZE100_BIT_ECC3_DE) | \
+                                       (PFUZE100_BIT_ECC4_DE) | \
+                                       (PFUZE100_BIT_ECC5_DE))
+#define PFUZE100_OTP_ECC_DE2           0x8d
+#define PFUZE100_BIT_ECC6_DE           PFUZE100_BIT_0
+#define PFUZE100_BIT_ECC7_DE           PFUZE100_BIT_1
+#define PFUZE100_BIT_ECC8_DE           PFUZE100_BIT_2
+#define PFUZE100_BIT_ECC9_DE           PFUZE100_BIT_3
+#define PFUZE100_BIT_ECC10_DE          PFUZE100_BIT_4
+#define PFUZE100_BITS_ECC_DE2          ((PFUZE100_BIT_ECC6_DE) | \
+                                       (PFUZE100_BIT_ECC7_DE) | \
+                                       (PFUZE100_BIT_ECC8_DE) | \
+                                       (PFUZE100_BIT_ECC9_DE) | \
+                                       (PFUZE100_BIT_ECC10_DE))
 #define PFUZE100_FUSE_POR1             0xe4
 #define PFUZE100_FUSE_POR2             0xe5
 #define PFUZE100_FUSE_POR3             0xe6
 #define PFUZE100_FUSE_POR_M            (0x1 << 1)
 
-
 /* output some informational messages, return the number FUSE_POR=1 */
 /* i.e. 0: unprogrammed, 3: programmed, other: undefined prog. state */
 unsigned pmic_init(void);