uboot/board/toradex/colibri_imx6/pf0100.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2014-2019, Toradex AG
   4 */
   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>
  16#include <asm/mach-imx/iomux-v3.h>
  17
  18#include "pf0100_otp.inc"
  19#include "pf0100.h"
  20
  21/* define for PMIC register dump */
  22/*#define DEBUG */
  23
  24#define WARNBAR "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
  25
  26/* use GPIO: EXT_IO1 to switch on VPGM, ON: 1 */
  27static __maybe_unused iomux_v3_cfg_t const pmic_prog_pads[] = {
  28        MX6_PAD_NANDF_D3__GPIO2_IO03 | MUX_PAD_CTRL(NO_PAD_CTRL),
  29#       define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 3)
  30};
  31
  32unsigned pmic_init(void)
  33{
  34        int rc;
  35        struct udevice *dev = NULL;
  36        unsigned programmed = 0;
  37        uchar bus = 1;
  38        uchar devid, revid, val;
  39
  40        puts("PMIC:  ");
  41        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);
  45                return 0;
  46        }
  47
  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
  96        /* get device ident */
  97        if (dm_i2c_read(dev, PFUZE100_DEVICEID, &devid, 1) < 0) {
  98                puts("i2c pmic devid read failed\n");
  99                return 0;
 100        }
 101        if (dm_i2c_read(dev, PFUZE100_REVID, &revid, 1) < 0) {
 102                puts("i2c pmic revid read failed\n");
 103                return 0;
 104        }
 105        printf("device id: 0x%.2x, revision id: 0x%.2x, ", devid, revid);
 106
 107        /* get device programmed state */
 108        val = PFUZE100_PAGE_REGISTER_PAGE1;
 109        if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 110                puts("i2c write failed\n");
 111                return 0;
 112        }
 113        if (dm_i2c_read(dev, PFUZE100_FUSE_POR1, &val, 1) < 0) {
 114                puts("i2c fuse_por read failed\n");
 115                return 0;
 116        }
 117        if (val & PFUZE100_FUSE_POR_M)
 118                programmed++;
 119
 120        if (dm_i2c_read(dev, PFUZE100_FUSE_POR2, &val, 1) < 0) {
 121                puts("i2c fuse_por read failed\n");
 122                return programmed;
 123        }
 124        if (val & PFUZE100_FUSE_POR_M)
 125                programmed++;
 126
 127        if (dm_i2c_read(dev, PFUZE100_FUSE_POR3, &val, 1) < 0) {
 128                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:
 136                puts("not programmed\n");
 137                break;
 138        case 3:
 139                puts("programmed\n");
 140                break;
 141        default:
 142                puts("undefined programming state\n");
 143                break;
 144        }
 145
 146#ifdef DEBUG
 147        {
 148                unsigned int i, j;
 149
 150                for (i = 0; i < 16; i++)
 151                        printf("\t%x", i);
 152                for (j = 0; j < 0x80; ) {
 153                        printf("\n%2x", j);
 154                        for (i = 0; i < 16; i++) {
 155                                dm_i2c_read(dev, j + i, &val, 1);
 156                                printf("\t%2x", val);
 157                        }
 158                        j += 0x10;
 159                }
 160                printf("\nEXT Page 1");
 161
 162                val = PFUZE100_PAGE_REGISTER_PAGE1;
 163                if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 164                        puts("i2c write failed\n");
 165                        return 0;
 166                }
 167
 168                for (j = 0x80; j < 0x100; ) {
 169                        printf("\n%2x", j);
 170                        for (i = 0; i < 16; i++) {
 171                                dm_i2c_read(dev, j + i, &val, 1);
 172                                printf("\t%2x", val);
 173                        }
 174                        j += 0x10;
 175                }
 176                printf("\nEXT Page 2");
 177
 178                val = PFUZE100_PAGE_REGISTER_PAGE2;
 179                if (dm_i2c_write(dev, PFUZE100_PAGE_REGISTER, &val, 1)) {
 180                        puts("i2c write failed\n");
 181                        return 0;
 182                }
 183
 184                for (j = 0x80; j < 0x100; ) {
 185                        printf("\n%2x", j);
 186                        for (i = 0; i < 16; i++) {
 187                                dm_i2c_read(dev, j + i, &val, 1);
 188                                printf("\t%2x", val);
 189                        }
 190                        j += 0x10;
 191                }
 192                printf("\n");
 193        }
 194#endif /* DEBUG */
 195
 196        return programmed;
 197}
 198
 199#ifndef CONFIG_SPL_BUILD
 200static int pf0100_prog(void)
 201{
 202        int rc;
 203        struct udevice *dev = NULL;
 204        unsigned char bus = 1;
 205        unsigned char val;
 206        unsigned int i;
 207
 208        if (pmic_init() == 3) {
 209                puts("PMIC already programmed, exiting\n");
 210                return CMD_RET_FAILURE;
 211        }
 212        /* set up gpio to manipulate vprog, initially off */
 213        imx_iomux_v3_setup_multiple_pads(pmic_prog_pads,
 214                                         ARRAY_SIZE(pmic_prog_pads));
 215        gpio_direction_output(PMIC_PROG_VOLTAGE, 0);
 216
 217        rc = i2c_get_chip_for_busnum(bus, PFUZE100_I2C_ADDR, 1, &dev);
 218        if (rc) {
 219                printf("failed to get device for PMIC at address 0x%x\n",
 220                       PFUZE100_I2C_ADDR);
 221                return CMD_RET_FAILURE;
 222        }
 223
 224        for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) {
 225                switch (pmic_otp_prog[i].cmd) {
 226                case pmic_i2c:
 227                        val = (unsigned char) (pmic_otp_prog[i].value & 0xff);
 228                        if (dm_i2c_write(dev, pmic_otp_prog[i].reg, &val, 1)) {
 229                                printf("i2c write failed, reg 0x%2x, value 0x%2x\n",
 230                                       pmic_otp_prog[i].reg, val);
 231                                return CMD_RET_FAILURE;
 232                        }
 233                        break;
 234                case pmic_delay:
 235                        udelay(pmic_otp_prog[i].value * 1000);
 236                        break;
 237                case pmic_vpgm:
 238                        gpio_direction_output(PMIC_PROG_VOLTAGE,
 239                                              pmic_otp_prog[i].value);
 240                        break;
 241                case pmic_pwr:
 242                        /* TODO */
 243                        break;
 244                }
 245        }
 246        return CMD_RET_SUCCESS;
 247}
 248
 249static int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc,
 250                char * const argv[])
 251{
 252        int ret;
 253        puts("Programming PMIC OTP...");
 254        ret = pf0100_prog();
 255        if (ret == CMD_RET_SUCCESS)
 256                puts("done.\n");
 257        else
 258                puts("failed.\n");
 259        return ret;
 260}
 261
 262U_BOOT_CMD(
 263        pf0100_otp_prog, 1, 0, do_pf0100_prog,
 264        "Program the OTP fuses on the PMIC PF0100",
 265        ""
 266);
 267#endif /* CONFIG_SPL_BUILD */
 268