uboot/board/gateworks/venice/gsc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2021 Gateworks Corporation
   4 */
   5
   6#include <common.h>
   7#include <command.h>
   8#include <hang.h>
   9#include <hexdump.h>
  10#include <i2c.h>
  11#include <linux/delay.h>
  12#include <dm/uclass.h>
  13
  14#include "gsc.h"
  15
  16DECLARE_GLOBAL_DATA_PTR;
  17
  18struct venice_board_info som_info;
  19struct venice_board_info base_info;
  20char venice_model[32];
  21uint32_t venice_serial;
  22
  23/* return a mac address from EEPROM info */
  24int gsc_getmac(int index, uint8_t *address)
  25{
  26        int i, j;
  27        u32 maclow, machigh;
  28        u64 mac;
  29
  30        j = 0;
  31        if (som_info.macno) {
  32                maclow = som_info.mac[5];
  33                maclow |= som_info.mac[4] << 8;
  34                maclow |= som_info.mac[3] << 16;
  35                maclow |= som_info.mac[2] << 24;
  36                machigh = som_info.mac[1];
  37                machigh |= som_info.mac[0] << 8;
  38                mac = machigh;
  39                mac <<= 32;
  40                mac |= maclow;
  41                for (i = 0; i < som_info.macno; i++, j++) {
  42                        if (index == j)
  43                                goto out;
  44                }
  45        }
  46
  47        maclow = base_info.mac[5];
  48        maclow |= base_info.mac[4] << 8;
  49        maclow |= base_info.mac[3] << 16;
  50        maclow |= base_info.mac[2] << 24;
  51        machigh = base_info.mac[1];
  52        machigh |= base_info.mac[0] << 8;
  53        mac = machigh;
  54        mac <<= 32;
  55        mac |= maclow;
  56        for (i = 0; i < base_info.macno; i++, j++) {
  57                if (index == j)
  58                        goto out;
  59        }
  60
  61        return -EINVAL;
  62
  63out:
  64        mac += i;
  65        address[0] = (mac >> 40) & 0xff;
  66        address[1] = (mac >> 32) & 0xff;
  67        address[2] = (mac >> 24) & 0xff;
  68        address[3] = (mac >> 16) & 0xff;
  69        address[4] = (mac >> 8) & 0xff;
  70        address[5] = (mac >> 0) & 0xff;
  71
  72        return 0;
  73}
  74
  75/* System Controller registers */
  76enum {
  77        GSC_SC_CTRL0            = 0,
  78        GSC_SC_CTRL1            = 1,
  79        GSC_SC_STATUS           = 10,
  80        GSC_SC_FWCRC            = 12,
  81        GSC_SC_FWVER            = 14,
  82        GSC_SC_WP               = 15,
  83        GSC_SC_RST_CAUSE        = 16,
  84        GSC_SC_THERM_PROTECT    = 19,
  85};
  86
  87/* System Controller Control1 bits */
  88enum {
  89        GSC_SC_CTRL1_WDTIME     = 4, /* 1 = 60s timeout, 0 = 30s timeout */
  90        GSC_SC_CTRL1_WDEN       = 5, /* 1 = enable, 0 = disable */
  91        GSC_SC_CTRL1_BOOT_CHK   = 6, /* 1 = enable alt boot check */
  92        GSC_SC_CTRL1_WDDIS      = 7, /* 1 = disable boot watchdog */
  93};
  94
  95/* System Controller Interrupt bits */
  96enum {
  97        GSC_SC_IRQ_PB           = 0, /* Pushbutton switch */
  98        GSC_SC_IRQ_SECURE       = 1, /* Secure Key erase operation complete */
  99        GSC_SC_IRQ_EEPROM_WP    = 2, /* EEPROM write violation */
 100        GSC_SC_IRQ_GPIO         = 4, /* GPIO change */
 101        GSC_SC_IRQ_TAMPER       = 5, /* Tamper detect */
 102        GSC_SC_IRQ_WATCHDOG     = 6, /* Watchdog trip */
 103        GSC_SC_IRQ_PBLONG       = 7, /* Pushbutton long hold */
 104};
 105
 106/* System Controller WP bits */
 107enum {
 108        GSC_SC_WP_ALL           = 0, /* Write Protect All EEPROM regions */
 109        GSC_SC_WP_BOARDINFO     = 1, /* Write Protect Board Info region */
 110};
 111
 112/* System Controller Reset Cause */
 113enum {
 114        GSC_SC_RST_CAUSE_VIN            = 0,
 115        GSC_SC_RST_CAUSE_PB             = 1,
 116        GSC_SC_RST_CAUSE_WDT            = 2,
 117        GSC_SC_RST_CAUSE_CPU            = 3,
 118        GSC_SC_RST_CAUSE_TEMP_LOCAL     = 4,
 119        GSC_SC_RST_CAUSE_TEMP_REMOTE    = 5,
 120        GSC_SC_RST_CAUSE_SLEEP          = 6,
 121        GSC_SC_RST_CAUSE_BOOT_WDT       = 7,
 122        GSC_SC_RST_CAUSE_BOOT_WDT_MAN   = 8,
 123        GSC_SC_RST_CAUSE_SOFT_PWR       = 9,
 124        GSC_SC_RST_CAUSE_MAX            = 10,
 125};
 126
 127#include <dm/device.h>
 128static struct udevice *gsc_get_dev(int busno, int slave)
 129{
 130        struct udevice *dev, *bus;
 131        int ret;
 132
 133        ret = uclass_get_device_by_seq(UCLASS_I2C, busno, &bus);
 134        if (ret) {
 135                printf("GSC     : failed I2C%d probe: %d\n", busno, ret);
 136                return NULL;
 137        }
 138        ret = dm_i2c_probe(bus, slave, 0, &dev);
 139        if (ret)
 140                return NULL;
 141
 142        return dev;
 143}
 144
 145static int gsc_read_eeprom(int bus, int slave, int alen, struct venice_board_info *info)
 146{
 147        int i;
 148        int chksum;
 149        unsigned char *buf = (unsigned char *)info;
 150        struct udevice *dev;
 151        int ret;
 152
 153        /* probe device */
 154        dev = gsc_get_dev(bus, slave);
 155        if (!dev) {
 156                if (slave == GSC_EEPROM_ADDR)
 157                        puts("ERROR: Failed to probe EEPROM\n");
 158                return -ENODEV;
 159        }
 160
 161        /* read eeprom config section */
 162        memset(info, 0, sizeof(*info));
 163        ret = i2c_set_chip_offset_len(dev, alen);
 164        if (ret) {
 165                puts("EEPROM: Failed to set alen\n");
 166                return ret;
 167        }
 168        ret = dm_i2c_read(dev, 0x00, buf, sizeof(*info));
 169        if (ret) {
 170                if (slave == GSC_EEPROM_ADDR)
 171                        printf("EEPROM: Failed to read EEPROM\n");
 172                return ret;
 173        }
 174
 175        /* validate checksum */
 176        for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++)
 177                chksum += buf[i];
 178        if ((info->chksum[0] != chksum >> 8) ||
 179            (info->chksum[1] != (chksum & 0xff))) {
 180                printf("EEPROM: I2C%d@0x%02x: Invalid Checksum\n", bus, slave);
 181                print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info));
 182                memset(info, 0, sizeof(*info));
 183                return -EINVAL;
 184        }
 185
 186        /* sanity check valid model */
 187        if (info->model[0] != 'G' || info->model[1] != 'W') {
 188                printf("EEPROM: I2C%d@0x%02x: Invalid Model in EEPROM\n", bus, slave);
 189                print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info));
 190                memset(info, 0, sizeof(*info));
 191                return -EINVAL;
 192        }
 193
 194        return 0;
 195}
 196
 197static const char *gsc_get_rst_cause(struct udevice *dev)
 198{
 199        static char str[64];
 200        static const char * const names[] = {
 201                "VIN",
 202                "PB",
 203                "WDT",
 204                "CPU",
 205                "TEMP_L",
 206                "TEMP_R",
 207                "SLEEP",
 208                "BOOT_WDT1",
 209                "BOOT_WDT2",
 210                "SOFT_PWR",
 211        };
 212        unsigned char reg;
 213
 214        /* reset cause */
 215        str[0] = 0;
 216        if (!dm_i2c_read(dev, GSC_SC_RST_CAUSE, &reg, 1)) {
 217                if (reg < ARRAY_SIZE(names))
 218                        sprintf(str, "%s", names[reg]);
 219                else
 220                        sprintf(str, "0x%02x", reg);
 221        }
 222
 223        /* thermal protection */
 224        if (!dm_i2c_read(dev, GSC_SC_THERM_PROTECT, &reg, 1)) {
 225                strcat(str, " Thermal Protection ");
 226                if (reg & BIT(0))
 227                        strcat(str, "Enabled");
 228                else
 229                        strcat(str, "Disabled");
 230        }
 231
 232        return str;
 233}
 234
 235/* display hardware monitor ADC channels */
 236int gsc_hwmon(void)
 237{
 238        const void *fdt = gd->fdt_blob;
 239        struct udevice *dev;
 240        int node, reg, mode, len, val, offset;
 241        const char *label;
 242        u8 buf[2];
 243        int ret;
 244
 245        node = fdt_node_offset_by_compatible(fdt, -1, "gw,gsc-adc");
 246        if (node <= 0)
 247                return node;
 248
 249        /* probe device */
 250        dev = gsc_get_dev(GSC_BUSNO, GSC_HWMON_ADDR);
 251        if (!dev) {
 252                puts("ERROR: Failed to probe GSC HWMON\n");
 253                return -ENODEV;
 254        }
 255
 256        /* iterate over hwmon nodes */
 257        node = fdt_first_subnode(fdt, node);
 258        while (node > 0) {
 259                reg = fdtdec_get_int(fdt, node, "reg", -1);
 260                mode = fdtdec_get_int(fdt, node, "gw,mode", -1);
 261                offset = fdtdec_get_int(fdt, node, "gw,voltage-offset-microvolt", 0);
 262                label = fdt_stringlist_get(fdt, node, "label", 0, NULL);
 263
 264                if ((reg == -1) || (mode == -1) || !label)
 265                        printf("invalid dt:%s\n", fdt_get_name(fdt, node, NULL));
 266
 267                memset(buf, 0, sizeof(buf));
 268                ret = dm_i2c_read(dev, reg, buf, sizeof(buf));
 269                if (ret) {
 270                        printf("i2c error: %d\n", ret);
 271                        continue;
 272                }
 273                val = buf[0] | buf[1] << 8;
 274                if (val >= 0) {
 275                        const u32 *div;
 276                        int r[2];
 277
 278                        switch (mode) {
 279                        case 0: /* temperature (C*10) */
 280                                if (val > 0x8000)
 281                                        val -= 0xffff;
 282                                printf("%-8s: %d.%ldC\n", label, val / 10, abs(val % 10));
 283                                break;
 284                        case 1: /* prescaled voltage */
 285                                if (val != 0xffff)
 286                                        printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000);
 287                                break;
 288                        case 2: /* scaled based on ref volt and resolution */
 289                                val *= 2500;
 290                                val /= 1 << 12;
 291
 292                                /* apply pre-scaler voltage divider */
 293                                div  = fdt_getprop(fdt, node, "gw,voltage-divider-ohms", &len);
 294                                if (div && (len == sizeof(uint32_t) * 2)) {
 295                                        r[0] = fdt32_to_cpu(div[0]);
 296                                        r[1] = fdt32_to_cpu(div[1]);
 297                                        if (r[0] && r[1]) {
 298                                                val *= (r[0] + r[1]);
 299                                                val /= r[1];
 300                                        }
 301                                }
 302
 303                                /* adjust by offset */
 304                                val += (offset / 1000);
 305
 306                                printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000);
 307                                break;
 308                        }
 309                }
 310                node = fdt_next_subnode(fdt, node);
 311        }
 312
 313        return 0;
 314}
 315
 316/* determine BOM revision from model */
 317int get_bom_rev(const char *str)
 318{
 319        int  rev_bom = 0;
 320        int i;
 321
 322        for (i = strlen(str) - 1; i > 0; i--) {
 323                if (str[i] == '-')
 324                        break;
 325                if (str[i] >= '1' && str[i] <= '9') {
 326                        rev_bom = str[i] - '0';
 327                        break;
 328                }
 329        }
 330        return rev_bom;
 331}
 332
 333/* determine PCB revision from model */
 334char get_pcb_rev(const char *str)
 335{
 336        char rev_pcb = 'A';
 337        int i;
 338
 339        for (i = strlen(str) - 1; i > 0; i--) {
 340                if (str[i] == '-')
 341                        break;
 342                if (str[i] >= 'A') {
 343                        rev_pcb = str[i];
 344                        break;
 345                }
 346        }
 347        return rev_pcb;
 348}
 349
 350/*
 351 * get dt name based on model and detail level:
 352 *
 353 * For boards that are a combination of a SoM plus a Baseboard:
 354 *   Venice SoM part numbers are GW70xx where xx is:
 355 *    7000-7019: same PCB with som dt of '0x'
 356 *    7020-7039: same PCB with som dt of '2x'
 357 *    7040-7059: same PCB with som dt of '4x'
 358 *    7060-7079: same PCB with som dt of '6x'
 359 *    7080-7099: same PCB with som dt of '8x'
 360 *   Venice Baseboard part numbers are GW7xxx where xxx is:
 361 *    7100-7199: same PCB with base dt of '71xx'
 362 *    7200-7299: same PCB with base dt of '72xx'
 363 *    7300-7399: same PCB with base dt of '73xx'
 364 *    7400-7499: same PCB with base dt of '74xx'
 365 *    7500-7599: same PCB with base dt of '75xx'
 366 *    7600-7699: same PCB with base dt of '76xx'
 367 *    7700-7799: same PCB with base dt of '77xx'
 368 *    7800-7899: same PCB with base dt of '78xx'
 369 *   DT name is comprised of:
 370 *    gw<base dt>-<som dt>-[base-pcb-rev][base-bom-rev][som-pcb-rev][som-bom-rev]
 371 *
 372 * For board models from 7900-7999 each PCB is unique with its own dt:
 373 *   DT name is comprised:
 374 *    gw<model>-[pcb-rev][bom-rev]
 375 *
 376 */
 377#define snprintfcat(dest, sz, fmt, ...) \
 378        snprintf((dest) + strlen(dest), (sz) - strlen(dest), fmt, ##__VA_ARGS__)
 379const char *gsc_get_dtb_name(int level, char *buf, int sz)
 380{
 381        const char *pre = "imx8mm-venice-gw";
 382        int model, rev_pcb, rev_bom;
 383
 384        model = ((som_info.model[2] - '0') * 1000)
 385                + ((som_info.model[3] - '0') * 100)
 386                + ((som_info.model[4] - '0') * 10)
 387                + (som_info.model[5] - '0');
 388        rev_pcb = tolower(get_pcb_rev(som_info.model));
 389        rev_bom = get_bom_rev(som_info.model);
 390
 391        /* som + baseboard*/
 392        if (base_info.model[0]) {
 393                /* baseboard id: 7100-7199->71; 7200-7299->72; etc */
 394                int base = ((base_info.model[2] - '0') * 10) + (base_info.model[3] - '0');
 395                /* som id: 7000-7019->1; 7020-7039->2; etc */
 396                int som = ((model % 100) / 20) * 2;
 397                int rev_base_pcb = tolower(get_pcb_rev(base_info.model));
 398                int rev_base_bom = get_bom_rev(base_info.model);
 399
 400                snprintf(buf, sz, "%s%2dxx-%dx", pre, base, som);
 401                switch (level) {
 402                case 0: /* full model (ie gw73xx-0x-a1a1) */
 403                        if (rev_base_bom)
 404                                snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom);
 405                        else
 406                                snprintfcat(buf, sz, "-%c", rev_base_pcb);
 407                        if (rev_bom)
 408                                snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom);
 409                        else
 410                                snprintfcat(buf, sz, "%c", rev_pcb);
 411                        break;
 412                case 1: /* don't care about SoM revision */
 413                        if (rev_base_bom)
 414                                snprintfcat(buf, sz, "-%c%d", rev_base_pcb, rev_base_bom);
 415                        else
 416                                snprintfcat(buf, sz, "-%c", rev_base_pcb);
 417                        snprintfcat(buf, sz, "xx");
 418                        break;
 419                case 2: /* don't care about baseboard revision */
 420                        snprintfcat(buf, sz, "-xx");
 421                        if (rev_bom)
 422                                snprintfcat(buf, sz, "%c%d", rev_pcb, rev_bom);
 423                        else
 424                                snprintfcat(buf, sz, "%c", rev_pcb);
 425                        break;
 426                case 3: /* don't care about SoM/baseboard revision */
 427                        break;
 428                default:
 429                        return NULL;
 430                }
 431        } else {
 432                snprintf(buf, sz, "%s%04d", pre, model);
 433                switch (level) {
 434                case 0: /* full model wth PCB and BOM revision first (ie gw7901-a1) */
 435                        if (rev_bom)
 436                                snprintfcat(buf, sz, "-%c%d", rev_pcb, rev_bom);
 437                        else
 438                                snprintfcat(buf, sz, "-%c", rev_pcb);
 439                        break;
 440                case 1: /* don't care about BOM revision */
 441                        snprintfcat(buf, sz, "-%c", rev_pcb);
 442                        break;
 443                case 2: /* don't care about PCB or BOM revision */
 444                        break;
 445                default:
 446                        return NULL;
 447                }
 448        }
 449
 450        return buf;
 451}
 452
 453static int gsc_read(void)
 454{
 455        char rev_pcb;
 456        int rev_bom;
 457        int ret;
 458
 459        ret = gsc_read_eeprom(GSC_BUSNO, GSC_EEPROM_ADDR, 1, &som_info);
 460        if (ret) {
 461                memset(&som_info, 0, sizeof(som_info));
 462                return ret;
 463        }
 464
 465        /* read optional baseboard EEPROM */
 466        gsc_read_eeprom(BASEBOARD_EEPROM_BUSNO, BASEBOARD_EEPROM_ADDR,
 467                        2, &base_info);
 468
 469        /* create model strings */
 470        if (base_info.model[0]) {
 471                sprintf(venice_model, "GW%c%c%c%c-%c%c-",
 472                        som_info.model[2], /* family */
 473                        base_info.model[3], /* baseboard */
 474                        base_info.model[4], base_info.model[5], /* subload of baseboard */
 475                        som_info.model[4], som_info.model[5]); /* last 2digits of SOM */
 476
 477                /* baseboard revision */
 478                rev_pcb = get_pcb_rev(base_info.model);
 479                rev_bom = get_bom_rev(base_info.model);
 480                if (rev_bom)
 481                        sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom);
 482                else
 483                        sprintf(venice_model + strlen(venice_model), "%c", rev_pcb);
 484                /* som revision */
 485                rev_pcb = get_pcb_rev(som_info.model);
 486                rev_bom = get_bom_rev(som_info.model);
 487                if (rev_bom)
 488                        sprintf(venice_model + strlen(venice_model), "%c%d", rev_pcb, rev_bom);
 489                else
 490                        sprintf(venice_model + strlen(venice_model), "%c", rev_pcb);
 491        } else {
 492                strcpy(venice_model, som_info.model);
 493        }
 494        venice_serial = som_info.serial;
 495
 496        return 0;
 497}
 498
 499static int gsc_info(int verbose)
 500{
 501        struct udevice *dev;
 502        unsigned char buf[16];
 503
 504        printf("Model   : %s\n", venice_model);
 505        printf("Serial  : %d\n", som_info.serial);
 506        printf("MFGDate : %02x-%02x-%02x%02x\n",
 507               som_info.mfgdate[0], som_info.mfgdate[1],
 508               som_info.mfgdate[2], som_info.mfgdate[3]);
 509        if (base_info.model[0] && verbose > 1) {
 510                printf("SOM     : %s %d %02x-%02x-%02x%02x\n",
 511                       som_info.model, som_info.serial,
 512                       som_info.mfgdate[0], som_info.mfgdate[1],
 513                       som_info.mfgdate[2], som_info.mfgdate[3]);
 514                printf("BASE    : %s %d %02x-%02x-%02x%02x\n",
 515                       base_info.model, base_info.serial,
 516                       base_info.mfgdate[0], base_info.mfgdate[1],
 517                       base_info.mfgdate[2], base_info.mfgdate[3]);
 518        }
 519
 520        /* Display RTC */
 521        puts("RTC     : ");
 522        dev = gsc_get_dev(GSC_BUSNO, GSC_RTC_ADDR);
 523        if (!dev) {
 524                puts("Failed to probe GSC RTC\n");
 525        } else {
 526                dm_i2c_read(dev, 0, buf, 6);
 527                printf("%d\n", buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
 528        }
 529
 530        /* Display hwmon */
 531        gsc_hwmon();
 532
 533        return 0;
 534}
 535
 536int gsc_init(int quiet)
 537{
 538        unsigned char buf[16];
 539        struct udevice *dev;
 540        int ret;
 541
 542        /*
 543         * On a board with a missing/depleted backup battery for GSC, the
 544         * board may be ready to probe the GSC before its firmware is
 545         * running.  We will wait here indefinately for the GSC/EEPROM.
 546         */
 547        while (1) {
 548                /* probe device */
 549                dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR);
 550                if (dev)
 551                        break;
 552                mdelay(1);
 553        }
 554
 555        ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
 556        if (ret) {
 557                puts("ERROR: Failed reading GSC\n");
 558                return ret;
 559        }
 560        gsc_read();
 561
 562        /* banner */
 563        if (!quiet) {
 564                printf("GSC     : v%d 0x%04x", buf[GSC_SC_FWVER],
 565                       buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC + 1] << 8);
 566                printf(" RST:%s", gsc_get_rst_cause(dev));
 567                printf("\n");
 568                gsc_info(1);
 569        }
 570
 571        if (ret)
 572                hang();
 573
 574        return ((16 << som_info.sdram_size) / 1024);
 575}
 576
 577const char *gsc_get_model(void)
 578{
 579        return venice_model;
 580}
 581
 582uint32_t gsc_get_serial(void)
 583{
 584        return venice_serial;
 585}
 586
 587#if !(IS_ENABLED(CONFIG_SPL_BUILD))
 588static int gsc_sleep(unsigned long secs)
 589{
 590        unsigned char reg;
 591        struct udevice *dev;
 592        int ret;
 593
 594        /* probe device */
 595        dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR);
 596        if (!dev)
 597                return -ENODEV;
 598
 599        printf("GSC Sleeping for %ld seconds\n", secs);
 600        reg = (secs >> 24) & 0xff;
 601        ret = dm_i2c_write(dev, 9, &reg, 1);
 602        if (ret)
 603                goto err;
 604        reg = (secs >> 16) & 0xff;
 605        ret = dm_i2c_write(dev, 8, &reg, 1);
 606        if (ret)
 607                goto err;
 608        reg = (secs >> 8) & 0xff;
 609        ret = dm_i2c_write(dev, 7, &reg, 1);
 610        if (ret)
 611                goto err;
 612        reg = secs & 0xff;
 613        ret = dm_i2c_write(dev, 6, &reg, 1);
 614        if (ret)
 615                goto err;
 616        ret = dm_i2c_read(dev, GSC_SC_CTRL1, &reg, 1);
 617        if (ret)
 618                goto err;
 619        reg |= (1 << 2);
 620        ret = dm_i2c_write(dev, GSC_SC_CTRL1, &reg, 1);
 621        if (ret)
 622                goto err;
 623        reg &= ~(1 << 2);
 624        reg |= 0x3;
 625        ret = dm_i2c_write(dev, GSC_SC_CTRL1, &reg, 1);
 626        if (ret)
 627                goto err;
 628
 629        return 0;
 630
 631err:
 632        printf("i2c error\n");
 633        return ret;
 634}
 635
 636static int gsc_boot_wd_disable(void)
 637{
 638        u8 reg;
 639        struct udevice *dev;
 640        int ret;
 641
 642        /* probe device */
 643        dev = gsc_get_dev(GSC_BUSNO, GSC_SC_ADDR);
 644        if (!dev)
 645                return -ENODEV;
 646
 647        ret = dm_i2c_read(dev, GSC_SC_CTRL1, &reg, 1);
 648        if (ret)
 649                goto err;
 650        reg |= (1 << GSC_SC_CTRL1_WDDIS);
 651        reg &= ~(1 << GSC_SC_CTRL1_BOOT_CHK);
 652        ret = dm_i2c_write(dev, GSC_SC_CTRL1, &reg, 1);
 653        if (ret)
 654                goto err;
 655        puts("GSC     : boot watchdog disabled\n");
 656
 657        return 0;
 658
 659err:
 660        printf("i2c error");
 661        return ret;
 662}
 663
 664static int do_gsc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
 665{
 666        if (argc < 2)
 667                return gsc_info(2);
 668
 669        if (strcasecmp(argv[1], "sleep") == 0) {
 670                if (argc < 3)
 671                        return CMD_RET_USAGE;
 672                if (!gsc_sleep(dectoul(argv[2], NULL)))
 673                        return CMD_RET_SUCCESS;
 674        } else if (strcasecmp(argv[1], "hwmon") == 0) {
 675                if (!gsc_hwmon())
 676                        return CMD_RET_SUCCESS;
 677        } else if (strcasecmp(argv[1], "wd-disable") == 0) {
 678                if (!gsc_boot_wd_disable())
 679                        return CMD_RET_SUCCESS;
 680        }
 681
 682        return CMD_RET_USAGE;
 683}
 684
 685U_BOOT_CMD(gsc, 4, 1, do_gsc, "Gateworks System Controller",
 686           "[sleep <secs>]|[hwmon]|[wd-disable]\n");
 687#endif
 688