uboot/board/gateworks/gw_ventana/gsc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2013 Gateworks Corporation
   4 *
   5 * Author: Tim Harvey <tharvey@gateworks.com>
   6 */
   7
   8#include <common.h>
   9#include <command.h>
  10#include <log.h>
  11#include <linux/delay.h>
  12#include <linux/errno.h>
  13#include <common.h>
  14#include <i2c.h>
  15#include <linux/ctype.h>
  16
  17#include <asm/arch/sys_proto.h>
  18
  19#include "ventana_eeprom.h"
  20#include "gsc.h"
  21
  22/*
  23 * The Gateworks System Controller will fail to ACK a master transaction if
  24 * it is busy, which can occur during its 1HZ timer tick while reading ADC's.
  25 * When this does occur, it will never be busy long enough to fail more than
  26 * 2 back-to-back transfers.  Thus we wrap i2c_read and i2c_write with
  27 * 3 retries.
  28 */
  29int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
  30{
  31        int retry = 3;
  32        int n = 0;
  33        int ret;
  34
  35        while (n++ < retry) {
  36                ret = i2c_read(chip, addr, alen, buf, len);
  37                if (!ret)
  38                        break;
  39                debug("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
  40                      n, ret);
  41                if (ret != -ENODEV)
  42                        break;
  43                mdelay(10);
  44        }
  45        return ret;
  46}
  47
  48int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
  49{
  50        int retry = 3;
  51        int n = 0;
  52        int ret;
  53
  54        while (n++ < retry) {
  55                ret = i2c_write(chip, addr, alen, buf, len);
  56                if (!ret)
  57                        break;
  58                debug("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
  59                      n, ret);
  60                if (ret != -ENODEV)
  61                        break;
  62                mdelay(10);
  63        }
  64        mdelay(100);
  65        return ret;
  66}
  67
  68static void read_hwmon(const char *name, uint reg, uint size)
  69{
  70        unsigned char buf[3];
  71        uint ui;
  72
  73        printf("%-8s:", name);
  74        memset(buf, 0, sizeof(buf));
  75        if (gsc_i2c_read(GSC_HWMON_ADDR, reg, 1, buf, size)) {
  76                puts("fRD\n");
  77        } else {
  78                ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
  79                if (size == 2 && ui > 0x8000)
  80                        ui -= 0xffff;
  81                if (ui == 0xffffff)
  82                        puts("invalid\n");
  83                else
  84                        printf("%d\n", ui);
  85        }
  86}
  87
  88int gsc_info(int verbose)
  89{
  90        unsigned char buf[16];
  91
  92        i2c_set_bus_num(0);
  93        if (gsc_i2c_read(GSC_SC_ADDR, 0, 1, buf, 16))
  94                return CMD_RET_FAILURE;
  95
  96        printf("GSC:   v%d", buf[GSC_SC_FWVER]);
  97        printf(" 0x%04x", buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC+1]<<8);
  98        printf(" WDT:%sabled", (buf[GSC_SC_CTRL1] & (1<<GSC_SC_CTRL1_WDEN))
  99                ? "en" : "dis");
 100        if (buf[GSC_SC_STATUS] & (1 << GSC_SC_IRQ_WATCHDOG)) {
 101                buf[GSC_SC_STATUS] &= ~(1 << GSC_SC_IRQ_WATCHDOG);
 102                puts(" WDT_RESET");
 103                gsc_i2c_write(GSC_SC_ADDR, GSC_SC_STATUS, 1,
 104                              &buf[GSC_SC_STATUS], 1);
 105        }
 106        if (!gsc_i2c_read(GSC_HWMON_ADDR, GSC_HWMON_TEMP, 1, buf, 2)) {
 107                int ui = buf[0] | buf[1]<<8;
 108                if (ui > 0x8000)
 109                        ui -= 0xffff;
 110                printf(" board temp at %dC", ui / 10);
 111        }
 112        puts("\n");
 113        if (!verbose)
 114                return CMD_RET_SUCCESS;
 115
 116        read_hwmon("Temp",     GSC_HWMON_TEMP, 2);
 117        read_hwmon("VIN",      GSC_HWMON_VIN, 3);
 118        read_hwmon("VBATT",    GSC_HWMON_VBATT, 3);
 119        read_hwmon("VDD_3P3",  GSC_HWMON_VDD_3P3, 3);
 120        read_hwmon("VDD_ARM",  GSC_HWMON_VDD_CORE, 3);
 121        read_hwmon("VDD_SOC",  GSC_HWMON_VDD_SOC, 3);
 122        read_hwmon("VDD_HIGH", GSC_HWMON_VDD_HIGH, 3);
 123        read_hwmon("VDD_DDR",  GSC_HWMON_VDD_DDR, 3);
 124        read_hwmon("VDD_5P0",  GSC_HWMON_VDD_5P0, 3);
 125        if (strncasecmp((const char*) ventana_info.model, "GW553", 5))
 126                read_hwmon("VDD_2P5",  GSC_HWMON_VDD_2P5, 3);
 127        read_hwmon("VDD_1P8",  GSC_HWMON_VDD_1P8, 3);
 128        read_hwmon("VDD_IO2",  GSC_HWMON_VDD_IO2, 3);
 129        switch (ventana_info.model[3]) {
 130        case '1': /* GW51xx */
 131                read_hwmon("VDD_IO3",  GSC_HWMON_VDD_IO4, 3); /* -C rev */
 132                break;
 133        case '2': /* GW52xx */
 134                break;
 135        case '3': /* GW53xx */
 136                read_hwmon("VDD_IO4",  GSC_HWMON_VDD_IO4, 3); /* -C rev */
 137                read_hwmon("VDD_GPS",  GSC_HWMON_VDD_IO3, 3);
 138                break;
 139        case '4': /* GW54xx */
 140                read_hwmon("VDD_IO3",  GSC_HWMON_VDD_IO4, 3); /* -C rev */
 141                read_hwmon("VDD_GPS",  GSC_HWMON_VDD_IO3, 3);
 142                break;
 143        case '5': /* GW55xx */
 144                break;
 145        case '6': /* GW560x */
 146                read_hwmon("VDD_IO4",  GSC_HWMON_VDD_IO4, 3);
 147                read_hwmon("VDD_GPS",  GSC_HWMON_VDD_IO3, 3);
 148                break;
 149        case '9': /* GW590x */
 150                read_hwmon("AMONBMON",  GSC_HWMON_VDD_IO3, 3);
 151                read_hwmon("BAT_VOLT",  GSC_HWMON_VDD_EXT, 3);
 152                read_hwmon("BAT_TEMP",  GSC_HWMON_VDD_IO4, 2);
 153        }
 154        return 0;
 155}
 156
 157/*
 158 *  The Gateworks System Controller implements a boot
 159 *  watchdog (always enabled) as a workaround for IMX6 boot related
 160 *  errata such as:
 161 *    ERR005768 - no fix scheduled
 162 *    ERR006282 - fixed in silicon r1.2
 163 *    ERR007117 - fixed in silicon r1.3
 164 *    ERR007220 - fixed in silicon r1.3
 165 *    ERR007926 - no fix scheduled
 166 *  see http://cache.freescale.com/files/32bit/doc/errata/IMX6DQCE.pdf
 167 *
 168 * Disable the boot watchdog
 169 */
 170int gsc_boot_wd_disable(void)
 171{
 172        u8 reg;
 173
 174        i2c_set_bus_num(CONFIG_I2C_GSC);
 175        if (!gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1)) {
 176                reg |= (1 << GSC_SC_CTRL1_WDDIS);
 177                if (!gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 178                        return 0;
 179        }
 180        puts("Error: could not disable GSC Watchdog\n");
 181        return 1;
 182}
 183
 184/* determine BOM revision from model */
 185int get_bom_rev(const char *str)
 186{
 187        int  rev_bom = 0;
 188        int i;
 189
 190        for (i = strlen(str) - 1; i > 0; i--) {
 191                if (str[i] == '-')
 192                        break;
 193                if (str[i] >= '1' && str[i] <= '9') {
 194                        rev_bom = str[i] - '0';
 195                        break;
 196                }
 197        }
 198        return rev_bom;
 199}
 200
 201/* determine PCB revision from model */
 202char get_pcb_rev(const char *str)
 203{
 204        char rev_pcb = 'A';
 205        int i;
 206
 207        for (i = strlen(str) - 1; i > 0; i--) {
 208                if (str[i] == '-')
 209                        break;
 210                if (str[i] >= 'A') {
 211                        rev_pcb = str[i];
 212                        break;
 213                }
 214        }
 215        return rev_pcb;
 216}
 217
 218/*
 219 * get dt name based on model and detail level:
 220 */
 221const char *gsc_get_dtb_name(int level, char *buf, int sz)
 222{
 223        const char *model = (const char *)ventana_info.model;
 224        const char *pre = is_mx6dq() ? "imx6q-" : "imx6dl-";
 225        int modelno, rev_pcb, rev_bom;
 226
 227        /* a few board models are dt equivalents to other models */
 228        if (strncasecmp(model, "gw5906", 6) == 0)
 229                model = "gw552x-d";
 230        else if (strncasecmp(model, "gw5908", 6) == 0)
 231                model = "gw53xx-f";
 232        else if (strncasecmp(model, "gw5905", 6) == 0)
 233                model = "gw5904-a";
 234
 235        modelno = ((model[2] - '0') * 1000)
 236                  + ((model[3] - '0') * 100)
 237                  + ((model[4] - '0') * 10)
 238                  + (model[5] - '0');
 239        rev_pcb = tolower(get_pcb_rev(model));
 240        rev_bom = get_bom_rev(model);
 241
 242        /* compare model/rev/bom in order of most specific to least */
 243        snprintf(buf, sz, "%s%04d", pre, modelno);
 244        switch (level) {
 245        case 0: /* full model first (ie gw5400-a1) */
 246                if (rev_bom) {
 247                        snprintf(buf, sz, "%sgw%04d-%c%d", pre, modelno, rev_pcb, rev_bom);
 248                        break;
 249                }
 250                fallthrough;
 251        case 1: /* don't care about bom rev (ie gw5400-a) */
 252                snprintf(buf, sz, "%sgw%04d-%c", pre, modelno, rev_pcb);
 253                break;
 254        case 2: /* don't care about the pcb rev (ie gw5400) */
 255                snprintf(buf, sz, "%sgw%04d", pre, modelno);
 256                break;
 257        case 3: /* look for generic model (ie gw540x) */
 258                snprintf(buf, sz, "%sgw%03dx", pre, modelno / 10);
 259                break;
 260        case 4: /* look for more generic model (ie gw54xx) */
 261                snprintf(buf, sz, "%sgw%02dxx", pre, modelno / 100);
 262                break;
 263        default: /* give up */
 264                return NULL;
 265        }
 266
 267        return buf;
 268}
 269
 270#if defined(CONFIG_CMD_GSC) && !defined(CONFIG_SPL_BUILD)
 271static int do_gsc_sleep(struct cmd_tbl *cmdtp, int flag, int argc,
 272                        char *const argv[])
 273{
 274        unsigned char reg;
 275        unsigned long secs = 0;
 276
 277        if (argc < 2)
 278                return CMD_RET_USAGE;
 279
 280        secs = simple_strtoul(argv[1], NULL, 10);
 281        printf("GSC Sleeping for %ld seconds\n", secs);
 282
 283        i2c_set_bus_num(0);
 284        reg = (secs >> 24) & 0xff;
 285        if (gsc_i2c_write(GSC_SC_ADDR, 9, 1, &reg, 1))
 286                goto error;
 287        reg = (secs >> 16) & 0xff;
 288        if (gsc_i2c_write(GSC_SC_ADDR, 8, 1, &reg, 1))
 289                goto error;
 290        reg = (secs >> 8) & 0xff;
 291        if (gsc_i2c_write(GSC_SC_ADDR, 7, 1, &reg, 1))
 292                goto error;
 293        reg = secs & 0xff;
 294        if (gsc_i2c_write(GSC_SC_ADDR, 6, 1, &reg, 1))
 295                goto error;
 296        if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 297                goto error;
 298        reg |= (1 << 2);
 299        if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 300                goto error;
 301        reg &= ~(1 << 2);
 302        reg |= 0x3;
 303        if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 304                goto error;
 305
 306        return CMD_RET_SUCCESS;
 307
 308error:
 309        printf("i2c error\n");
 310        return CMD_RET_FAILURE;
 311}
 312
 313static int do_gsc_wd(struct cmd_tbl *cmdtp, int flag, int argc,
 314                     char *const argv[])
 315{
 316        unsigned char reg;
 317
 318        if (argc < 2)
 319                return CMD_RET_USAGE;
 320
 321        if (strcasecmp(argv[1], "enable") == 0) {
 322                int timeout = 0;
 323
 324                if (argc > 2)
 325                        timeout = simple_strtoul(argv[2], NULL, 10);
 326                i2c_set_bus_num(0);
 327                if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 328                        return CMD_RET_FAILURE;
 329                reg &= ~((1 << GSC_SC_CTRL1_WDEN) | (1 << GSC_SC_CTRL1_WDTIME));
 330                if (timeout == 60)
 331                        reg |= (1 << GSC_SC_CTRL1_WDTIME);
 332                else
 333                        timeout = 30;
 334                reg |= (1 << GSC_SC_CTRL1_WDEN);
 335                if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 336                        return CMD_RET_FAILURE;
 337                printf("GSC Watchdog enabled with timeout=%d seconds\n",
 338                       timeout);
 339        } else if (strcasecmp(argv[1], "disable") == 0) {
 340                i2c_set_bus_num(0);
 341                if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 342                        return CMD_RET_FAILURE;
 343                reg &= ~((1 << GSC_SC_CTRL1_WDEN) | (1 << GSC_SC_CTRL1_WDTIME));
 344                if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
 345                        return CMD_RET_FAILURE;
 346                printf("GSC Watchdog disabled\n");
 347        } else {
 348                return CMD_RET_USAGE;
 349        }
 350        return CMD_RET_SUCCESS;
 351}
 352
 353static int do_gsc(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 354{
 355        if (argc < 2)
 356                return gsc_info(1);
 357
 358        if (strcasecmp(argv[1], "wd") == 0)
 359                return do_gsc_wd(cmdtp, flag, --argc, ++argv);
 360        else if (strcasecmp(argv[1], "sleep") == 0)
 361                return do_gsc_sleep(cmdtp, flag, --argc, ++argv);
 362
 363        return CMD_RET_USAGE;
 364}
 365
 366U_BOOT_CMD(
 367        gsc, 4, 1, do_gsc, "GSC configuration",
 368        "[wd enable [30|60]]|[wd disable]|[sleep <secs>]\n"
 369        );
 370
 371#endif /* CONFIG_CMD_GSC */
 372