uboot/board/siemens/common/factoryset.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *
   4 * Read FactorySet information from EEPROM into global structure.
   5 * (C) Copyright 2013 Siemens Schweiz AG
   6 */
   7
   8#if !defined(CONFIG_SPL_BUILD)
   9
  10#include <common.h>
  11#include <env.h>
  12#include <dm.h>
  13#include <env_internal.h>
  14#include <i2c.h>
  15#include <log.h>
  16#include <asm/io.h>
  17#if !CONFIG_IS_ENABLED(TARGET_GIEDI) && !CONFIG_IS_ENABLED(TARGET_DENEB)
  18#include <asm/arch/cpu.h>
  19#endif
  20#include <asm/arch/sys_proto.h>
  21#include <asm/unaligned.h>
  22#include <net.h>
  23#include <errno.h>
  24#include <g_dnl.h>
  25#include "factoryset.h"
  26
  27#define EEPR_PG_SZ              0x80
  28#define EEPROM_FATORYSET_OFFSET 0x400
  29#define OFF_PG            EEPROM_FATORYSET_OFFSET/EEPR_PG_SZ
  30
  31/* Global variable that contains necessary information from FactorySet */
  32struct factorysetcontainer factory_dat;
  33
  34#define fact_get_char(i) *((char *)&eeprom_buf[i])
  35
  36static int fact_match(unsigned char *eeprom_buf, uchar *s1, int i2)
  37{
  38        if (s1 == NULL)
  39                return -1;
  40
  41        while (*s1 == fact_get_char(i2++))
  42                if (*s1++ == '=')
  43                        return i2;
  44
  45        if (*s1 == '\0' && fact_get_char(i2-1) == '=')
  46                return i2;
  47
  48        return -1;
  49}
  50
  51static int get_factory_val(unsigned char *eeprom_buf, int size, uchar *name,
  52                        uchar *buf, int len)
  53{
  54        int i, nxt = 0;
  55
  56        for (i = 0; fact_get_char(i) != '\0'; i = nxt + 1) {
  57                int val, n;
  58
  59                for (nxt = i; fact_get_char(nxt) != '\0'; ++nxt) {
  60                        if (nxt >= size)
  61                                return -1;
  62                }
  63
  64                val = fact_match(eeprom_buf, (uchar *)name, i);
  65                if (val < 0)
  66                        continue;
  67
  68                /* found; copy out */
  69                for (n = 0; n < len; ++n, ++buf) {
  70                        *buf = fact_get_char(val++);
  71                        if (*buf == '\0')
  72                                return n;
  73                }
  74
  75                if (n)
  76                        *--buf = '\0';
  77
  78                printf("env_buf [%d bytes] too small for value of \"%s\"\n",
  79                       len, name);
  80
  81                return n;
  82        }
  83        return -1;
  84}
  85
  86static
  87int get_factory_record_val(unsigned char *eeprom_buf, int size, uchar *record,
  88        uchar *name, uchar *buf, int len)
  89{
  90        int ret = -1;
  91        int i, nxt = 0;
  92        int c;
  93        unsigned char end = 0xff;
  94        unsigned char tmp;
  95
  96        for (i = 0; fact_get_char(i) != end; i = nxt) {
  97                nxt = i + 1;
  98                if (fact_get_char(i) == '>') {
  99                        int pos;
 100                        int endpos;
 101                        int z;
 102                        int level = 0;
 103
 104                        c = strncmp((char *)&eeprom_buf[i + 1], (char *)record,
 105                                    strlen((char *)record));
 106                        if (c == 0) {
 107                                /* record found */
 108                                pos = i + strlen((char *)record) + 2;
 109                                nxt = pos;
 110                                /* search for "<" */
 111                                c = -1;
 112                                for (z = pos; fact_get_char(z) != end; z++) {
 113                                        if (fact_get_char(z) == '<') {
 114                                                if (level == 0) {
 115                                                        endpos = z;
 116                                                        nxt = endpos;
 117                                                        c = 0;
 118                                                        break;
 119                                                } else {
 120                                                        level--;
 121                                                }
 122                                        }
 123                                        if (fact_get_char(z) == '>')
 124                                                level++;
 125                                }
 126                        } else {
 127                                continue;
 128                        }
 129                        if (c == 0) {
 130                                /* end found -> call get_factory_val */
 131                                tmp = eeprom_buf[endpos];
 132                                eeprom_buf[endpos] = end;
 133                                ret = get_factory_val(&eeprom_buf[pos],
 134                                        endpos - pos, name, buf, len);
 135                                /* fix buffer */
 136                                eeprom_buf[endpos] = tmp;
 137                                debug("%s: %s.%s = %s\n",
 138                                      __func__, record, name, buf);
 139                                return ret;
 140                        }
 141                }
 142        }
 143        return ret;
 144}
 145
 146int factoryset_read_eeprom(int i2c_addr)
 147{
 148        int i, pages = 0, size = 0;
 149        unsigned char eeprom_buf[0x3c00], hdr[4], buf[MAX_STRING_LENGTH];
 150        unsigned char *cp, *cp1;
 151#if CONFIG_IS_ENABLED(DM_I2C)
 152        struct udevice *bus, *dev;
 153        int ret;
 154#endif
 155
 156#if defined(CONFIG_DFU_OVER_USB)
 157        factory_dat.usb_vendor_id = CONFIG_USB_GADGET_VENDOR_NUM;
 158        factory_dat.usb_product_id = CONFIG_USB_GADGET_PRODUCT_NUM;
 159#endif
 160
 161#if CONFIG_IS_ENABLED(DM_I2C)
 162        ret = uclass_get_device_by_seq(UCLASS_I2C, EEPROM_I2C_BUS, &bus);
 163        if (ret)
 164                goto err;
 165
 166        ret = dm_i2c_probe(bus, i2c_addr, 0, &dev);
 167        if (ret)
 168                goto err;
 169
 170        ret = i2c_set_chip_offset_len(dev, 2);
 171        if (ret)
 172                goto err;
 173
 174        ret = dm_i2c_read(dev, EEPROM_FATORYSET_OFFSET, hdr, sizeof(hdr));
 175        if (ret)
 176                goto err;
 177#else
 178        if (i2c_probe(i2c_addr))
 179                goto err;
 180
 181        if (i2c_read(i2c_addr, EEPROM_FATORYSET_OFFSET, 2, hdr, sizeof(hdr)))
 182                goto err;
 183#endif
 184
 185        if ((hdr[0] != 0x99) || (hdr[1] != 0x80)) {
 186                printf("FactorySet is not right in eeprom.\n");
 187                return 1;
 188        }
 189
 190        /* get FactorySet size */
 191        size = (hdr[2] << 8) + hdr[3] + sizeof(hdr);
 192        if (size > 0x3bfa)
 193                size = 0x3bfa;
 194
 195        pages = size / EEPR_PG_SZ;
 196
 197        /*
 198         * read the eeprom using i2c
 199         * I can not read entire eeprom in once, so separate into several
 200         * times. Furthermore, fetch eeprom take longer time, so we fetch
 201         * data after every time we got a record from eeprom
 202         */
 203        debug("Read eeprom page :\n");
 204        for (i = 0; i < pages; i++) {
 205#if CONFIG_IS_ENABLED(DM_I2C)
 206                ret = dm_i2c_read(dev, (OFF_PG + i) * EEPR_PG_SZ,
 207                                  eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ);
 208                if (ret)
 209                        goto err;
 210#else
 211                if (i2c_read(i2c_addr, (OFF_PG + i) * EEPR_PG_SZ, 2,
 212                             eeprom_buf + (i * EEPR_PG_SZ), EEPR_PG_SZ))
 213                        goto err;
 214#endif
 215        }
 216
 217        if (size % EEPR_PG_SZ) {
 218#if CONFIG_IS_ENABLED(DM_I2C)
 219                ret = dm_i2c_read(dev, (OFF_PG + pages) * EEPR_PG_SZ,
 220                                  eeprom_buf + (pages * EEPR_PG_SZ),
 221                                  size % EEPR_PG_SZ);
 222                if (ret)
 223                        goto err;
 224#else
 225                if (i2c_read(i2c_addr, (OFF_PG + pages) * EEPR_PG_SZ, 2,
 226                             eeprom_buf + (pages * EEPR_PG_SZ),
 227                             (size % EEPR_PG_SZ)))
 228                        goto err;
 229#endif
 230        }
 231
 232        /* we do below just for eeprom align */
 233        for (i = 0; i < size; i++)
 234                if (eeprom_buf[i] == '\n')
 235                        eeprom_buf[i] = 0;
 236
 237        /* skip header */
 238        size -= sizeof(hdr);
 239        cp = (uchar *)eeprom_buf + sizeof(hdr);
 240
 241        /* get mac address */
 242        get_factory_record_val(cp, size, (uchar *)"ETH1", (uchar *)"mac",
 243                               buf, MAX_STRING_LENGTH);
 244        cp1 = buf;
 245        for (i = 0; i < 6; i++) {
 246                factory_dat.mac[i] = simple_strtoul((char *)cp1, NULL, 16);
 247                cp1 += 3;
 248        }
 249
 250#if CONFIG_IS_ENABLED(TARGET_GIEDI) || CONFIG_IS_ENABLED(TARGET_DENEB)
 251        /* get mac address for WLAN */
 252        ret = get_factory_record_val(cp, size, (uchar *)"WLAN1", (uchar *)"mac",
 253                                     buf, MAX_STRING_LENGTH);
 254        if (ret > 0) {
 255                cp1 = buf;
 256                for (i = 0; i < 6; i++) {
 257                        factory_dat.mac_wlan[i] = simple_strtoul((char *)cp1,
 258                                                                 NULL, 16);
 259                        cp1 += 3;
 260                }
 261        }
 262#endif
 263
 264#if defined(CONFIG_DFU_OVER_USB)
 265        /* read vid and pid for dfu mode */
 266        if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
 267                                        (uchar *)"vid", buf,
 268                                        MAX_STRING_LENGTH)) {
 269                factory_dat.usb_vendor_id = simple_strtoul((char *)buf,
 270                                                           NULL, 16);
 271        }
 272
 273        if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
 274                                        (uchar *)"pid", buf,
 275                                        MAX_STRING_LENGTH)) {
 276                factory_dat.usb_product_id = simple_strtoul((char *)buf,
 277                                                            NULL, 16);
 278        }
 279        printf("DFU USB: VID = 0x%4x, PID = 0x%4x\n", factory_dat.usb_vendor_id,
 280               factory_dat.usb_product_id);
 281#endif
 282#if defined(CONFIG_VIDEO)
 283        if (0 <= get_factory_record_val(cp, size, (uchar *)"DISP1",
 284                                        (uchar *)"name", factory_dat.disp_name,
 285                                        MAX_STRING_LENGTH)) {
 286                debug("display name: %s\n", factory_dat.disp_name);
 287        }
 288#endif
 289        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 290                                        (uchar *)"num", factory_dat.serial,
 291                                        MAX_STRING_LENGTH)) {
 292                debug("serial number: %s\n", factory_dat.serial);
 293        }
 294        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 295                                        (uchar *)"ver", buf,
 296                                        MAX_STRING_LENGTH)) {
 297                factory_dat.version = simple_strtoul((char *)buf,
 298                                                            NULL, 16);
 299                debug("version number: %d\n", factory_dat.version);
 300        }
 301        /* Get ASN from factory set if available */
 302        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 303                                        (uchar *)"id", factory_dat.asn,
 304                                        MAX_STRING_LENGTH)) {
 305                debug("factoryset asn: %s\n", factory_dat.asn);
 306        } else {
 307                factory_dat.asn[0] = 0;
 308        }
 309        /* Get COMP/ver from factory set if available */
 310        if (0 <= get_factory_record_val(cp, size, (uchar *)"COMP",
 311                                        (uchar *)"ver",
 312                                        factory_dat.comp_version,
 313                                        MAX_STRING_LENGTH)) {
 314                debug("factoryset COMP/ver: %s\n", factory_dat.comp_version);
 315        } else {
 316                strcpy((char *)factory_dat.comp_version, "1.0");
 317        }
 318
 319        return 0;
 320
 321err:
 322        printf("Could not read the EEPROM; something fundamentally wrong on the I2C bus.\n");
 323        return 1;
 324}
 325
 326static int get_mac_from_efuse(uint8_t mac[6])
 327{
 328#ifdef CONFIG_AM33XX
 329        struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
 330        uint32_t mac_hi, mac_lo;
 331
 332        mac_lo = readl(&cdev->macid0l);
 333        mac_hi = readl(&cdev->macid0h);
 334
 335        mac[0] = mac_hi & 0xFF;
 336        mac[1] = (mac_hi & 0xFF00) >> 8;
 337        mac[2] = (mac_hi & 0xFF0000) >> 16;
 338        mac[3] = (mac_hi & 0xFF000000) >> 24;
 339        mac[4] = mac_lo & 0xFF;
 340        mac[5] = (mac_lo & 0xFF00) >> 8;
 341#else
 342        /* unhandled */
 343        memset(mac, 0, 6);
 344#endif
 345        if (!is_valid_ethaddr(mac)) {
 346                puts("Warning: ethaddr not set by FactorySet or E-fuse. ");
 347                puts("Set <ethaddr> variable to overcome this.\n");
 348                return -1;
 349        }
 350        return 0;
 351}
 352
 353static int factoryset_mac_env_set(void)
 354{
 355        uint8_t mac_addr[6];
 356
 357        /* Set mac from factoryset or try reading E-fuse */
 358        debug("FactorySet: Set mac address\n");
 359        if (is_valid_ethaddr(factory_dat.mac)) {
 360                memcpy(mac_addr, factory_dat.mac, 6);
 361        } else {
 362                debug("Warning: FactorySet: <ethaddr> not set. Fallback to E-fuse\n");
 363                if (get_mac_from_efuse(mac_addr) < 0)
 364                        return -1;
 365        }
 366
 367        eth_env_set_enetaddr("ethaddr", mac_addr);
 368
 369#if CONFIG_IS_ENABLED(TARGET_GIEDI) || CONFIG_IS_ENABLED(TARGET_DENEB)
 370        eth_env_set_enetaddr("eth1addr", mac_addr);
 371
 372        /* wlan mac */
 373        if (is_valid_ethaddr(factory_dat.mac_wlan))
 374                eth_env_set_enetaddr("eth2addr", factory_dat.mac_wlan);
 375#endif
 376        return 0;
 377}
 378
 379static void factoryset_dtb_env_set(void)
 380{
 381        /* Set ASN in environment*/
 382        if (factory_dat.asn[0] != 0) {
 383                env_set("dtb_name", (char *)factory_dat.asn);
 384        } else {
 385                /* dtb suffix gets added in load script */
 386                env_set("dtb_name", "default");
 387        }
 388}
 389
 390int factoryset_env_set(void)
 391{
 392        int ret = 0;
 393
 394        factoryset_dtb_env_set();
 395
 396        if (factoryset_mac_env_set() < 0)
 397                ret = -1;
 398
 399        return ret;
 400}
 401
 402int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
 403{
 404        put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor);
 405        put_unaligned(factory_dat.usb_product_id, &dev->idProduct);
 406        g_dnl_set_serialnumber((char *)factory_dat.serial);
 407
 408        return 0;
 409}
 410
 411int g_dnl_get_board_bcd_device_number(int gcnum)
 412{
 413        return factory_dat.version;
 414}
 415#endif /* defined(CONFIG_SPL_BUILD) */
 416