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] = hextoul((char *)cp1, NULL);
 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] = hextoul((char *)cp1, NULL);
 258                        cp1 += 3;
 259                }
 260        }
 261#endif
 262
 263#if defined(CONFIG_DFU_OVER_USB)
 264        /* read vid and pid for dfu mode */
 265        if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
 266                                        (uchar *)"vid", buf,
 267                                        MAX_STRING_LENGTH)) {
 268                factory_dat.usb_vendor_id = hextoul((char *)buf, NULL);
 269        }
 270
 271        if (0 <= get_factory_record_val(cp, size, (uchar *)"USBD1",
 272                                        (uchar *)"pid", buf,
 273                                        MAX_STRING_LENGTH)) {
 274                factory_dat.usb_product_id = hextoul((char *)buf, NULL);
 275        }
 276        printf("DFU USB: VID = 0x%4x, PID = 0x%4x\n", factory_dat.usb_vendor_id,
 277               factory_dat.usb_product_id);
 278#endif
 279#if defined(CONFIG_VIDEO)
 280        if (0 <= get_factory_record_val(cp, size, (uchar *)"DISP1",
 281                                        (uchar *)"name", factory_dat.disp_name,
 282                                        MAX_STRING_LENGTH)) {
 283                debug("display name: %s\n", factory_dat.disp_name);
 284        }
 285#endif
 286        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 287                                        (uchar *)"num", factory_dat.serial,
 288                                        MAX_STRING_LENGTH)) {
 289                debug("serial number: %s\n", factory_dat.serial);
 290        }
 291        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 292                                        (uchar *)"ver", buf,
 293                                        MAX_STRING_LENGTH)) {
 294                factory_dat.version = hextoul((char *)buf, NULL);
 295                debug("version number: %d\n", factory_dat.version);
 296        }
 297        /* Get ASN from factory set if available */
 298        if (0 <= get_factory_record_val(cp, size, (uchar *)"DEV",
 299                                        (uchar *)"id", factory_dat.asn,
 300                                        MAX_STRING_LENGTH)) {
 301                debug("factoryset asn: %s\n", factory_dat.asn);
 302        } else {
 303                factory_dat.asn[0] = 0;
 304        }
 305        /* Get COMP/ver from factory set if available */
 306        if (0 <= get_factory_record_val(cp, size, (uchar *)"COMP",
 307                                        (uchar *)"ver",
 308                                        factory_dat.comp_version,
 309                                        MAX_STRING_LENGTH)) {
 310                debug("factoryset COMP/ver: %s\n", factory_dat.comp_version);
 311        } else {
 312                strcpy((char *)factory_dat.comp_version, "1.0");
 313        }
 314
 315        return 0;
 316
 317err:
 318        printf("Could not read the EEPROM; something fundamentally wrong on the I2C bus.\n");
 319        return 1;
 320}
 321
 322static int get_mac_from_efuse(uint8_t mac[6])
 323{
 324#ifdef CONFIG_AM33XX
 325        struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
 326        uint32_t mac_hi, mac_lo;
 327
 328        mac_lo = readl(&cdev->macid0l);
 329        mac_hi = readl(&cdev->macid0h);
 330
 331        mac[0] = mac_hi & 0xFF;
 332        mac[1] = (mac_hi & 0xFF00) >> 8;
 333        mac[2] = (mac_hi & 0xFF0000) >> 16;
 334        mac[3] = (mac_hi & 0xFF000000) >> 24;
 335        mac[4] = mac_lo & 0xFF;
 336        mac[5] = (mac_lo & 0xFF00) >> 8;
 337#else
 338        /* unhandled */
 339        memset(mac, 0, 6);
 340#endif
 341        if (!is_valid_ethaddr(mac)) {
 342                puts("Warning: ethaddr not set by FactorySet or E-fuse. ");
 343                puts("Set <ethaddr> variable to overcome this.\n");
 344                return -1;
 345        }
 346        return 0;
 347}
 348
 349static int factoryset_mac_env_set(void)
 350{
 351        uint8_t mac_addr[6];
 352
 353        /* Set mac from factoryset or try reading E-fuse */
 354        debug("FactorySet: Set mac address\n");
 355        if (is_valid_ethaddr(factory_dat.mac)) {
 356                memcpy(mac_addr, factory_dat.mac, 6);
 357        } else {
 358                debug("Warning: FactorySet: <ethaddr> not set. Fallback to E-fuse\n");
 359                if (get_mac_from_efuse(mac_addr) < 0)
 360                        return -1;
 361        }
 362
 363        eth_env_set_enetaddr("ethaddr", mac_addr);
 364
 365#if CONFIG_IS_ENABLED(TARGET_GIEDI) || CONFIG_IS_ENABLED(TARGET_DENEB)
 366        eth_env_set_enetaddr("eth1addr", mac_addr);
 367
 368        /* wlan mac */
 369        if (is_valid_ethaddr(factory_dat.mac_wlan))
 370                eth_env_set_enetaddr("eth2addr", factory_dat.mac_wlan);
 371#endif
 372        return 0;
 373}
 374
 375static void factoryset_dtb_env_set(void)
 376{
 377        /* Set ASN in environment*/
 378        if (factory_dat.asn[0] != 0) {
 379                env_set("dtb_name", (char *)factory_dat.asn);
 380        } else {
 381                /* dtb suffix gets added in load script */
 382                env_set("dtb_name", "default");
 383        }
 384}
 385
 386int factoryset_env_set(void)
 387{
 388        int ret = 0;
 389
 390        factoryset_dtb_env_set();
 391
 392        if (factoryset_mac_env_set() < 0)
 393                ret = -1;
 394
 395        return ret;
 396}
 397
 398int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
 399{
 400        put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor);
 401        put_unaligned(factory_dat.usb_product_id, &dev->idProduct);
 402        g_dnl_set_serialnumber((char *)factory_dat.serial);
 403
 404        return 0;
 405}
 406
 407int g_dnl_get_board_bcd_device_number(int gcnum)
 408{
 409        return factory_dat.version;
 410}
 411#endif /* defined(CONFIG_SPL_BUILD) */
 412