uboot/board/ti/common/board_detect.c
<<
>>
Prefs
   1/*
   2 * Library to support early TI EVM EEPROM handling
   3 *
   4 * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
   5 *      Lokesh Vutla
   6 *      Steve Kipisz
   7 *
   8 * SPDX-License-Identifier:    GPL-2.0+
   9 */
  10
  11#include <common.h>
  12#include <asm/omap_common.h>
  13#include <i2c.h>
  14
  15#include "board_detect.h"
  16
  17/**
  18 * ti_i2c_eeprom_init - Initialize an i2c bus and probe for a device
  19 * @i2c_bus: i2c bus number to initialize
  20 * @dev_addr: Device address to probe for
  21 *
  22 * Return: 0 on success or corresponding error on failure.
  23 */
  24static int __maybe_unused ti_i2c_eeprom_init(int i2c_bus, int dev_addr)
  25{
  26        int rc;
  27
  28        if (i2c_bus >= 0) {
  29                rc = i2c_set_bus_num(i2c_bus);
  30                if (rc)
  31                        return rc;
  32        }
  33
  34        return i2c_probe(dev_addr);
  35}
  36
  37/**
  38 * ti_i2c_eeprom_read - Read data from an EEPROM
  39 * @dev_addr: The device address of the EEPROM
  40 * @offset: Offset to start reading in the EEPROM
  41 * @ep: Pointer to a buffer to read into
  42 * @epsize: Size of buffer
  43 *
  44 * Return: 0 on success or corresponding result of i2c_read
  45 */
  46static int __maybe_unused ti_i2c_eeprom_read(int dev_addr, int offset,
  47                                             uchar *ep, int epsize)
  48{
  49        return i2c_read(dev_addr, offset, 2, ep, epsize);
  50}
  51
  52/**
  53 * ti_eeprom_string_cleanup() - Handle eeprom programming errors
  54 * @s:  eeprom string (should be NULL terminated)
  55 *
  56 * Some Board manufacturers do not add a NULL termination at the
  57 * end of string, instead some binary information is kludged in, hence
  58 * convert the string to just printable characters of ASCII chart.
  59 */
  60static void __maybe_unused ti_eeprom_string_cleanup(char *s)
  61{
  62        int i, l;
  63
  64        l = strlen(s);
  65        for (i = 0; i < l; i++, s++)
  66                if (*s < ' ' || *s > '~') {
  67                        *s = 0;
  68                        break;
  69                }
  70}
  71
  72__weak void gpi2c_init(void)
  73{
  74}
  75
  76static int __maybe_unused ti_i2c_eeprom_get(int bus_addr, int dev_addr,
  77                                            u32 header, u32 size, uint8_t *ep)
  78{
  79        u32 byte, hdr_read;
  80        int rc;
  81
  82        gpi2c_init();
  83        rc = ti_i2c_eeprom_init(bus_addr, dev_addr);
  84        if (rc)
  85                return rc;
  86
  87        /*
  88         * Read the header first then only read the other contents.
  89         */
  90        byte = 2;
  91        rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read, 4);
  92        if (rc)
  93                return rc;
  94
  95        /* Corrupted data??? */
  96        if (hdr_read != header) {
  97                rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read, 4);
  98                /*
  99                 * read the eeprom header using i2c again, but use only a
 100                 * 1 byte address (some legacy boards need this..)
 101                 */
 102                byte = 1;
 103                if (rc)
 104                        rc = i2c_read(dev_addr, 0x0, byte, (uint8_t *)&hdr_read,
 105                                      4);
 106                if (rc)
 107                        return rc;
 108        }
 109        if (hdr_read != header)
 110                return -1;
 111
 112        rc = i2c_read(dev_addr, 0x0, byte, ep, size);
 113        if (rc)
 114                return rc;
 115
 116        return 0;
 117}
 118
 119int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
 120{
 121        int rc;
 122        struct ti_am_eeprom am_ep;
 123        struct ti_common_eeprom *ep;
 124
 125        ep = TI_EEPROM_DATA;
 126#ifndef CONFIG_SPL_BUILD
 127        if (ep->header == TI_EEPROM_HEADER_MAGIC)
 128                return 0; /* EEPROM has already been read */
 129#endif
 130
 131        /* Initialize with a known bad marker for i2c fails.. */
 132        ep->header = TI_DEAD_EEPROM_MAGIC;
 133        ep->name[0] = 0x0;
 134        ep->version[0] = 0x0;
 135        ep->serial[0] = 0x0;
 136        ep->config[0] = 0x0;
 137
 138        rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
 139                               sizeof(am_ep), (uint8_t *)&am_ep);
 140        if (rc)
 141                return rc;
 142
 143        ep->header = am_ep.header;
 144        strlcpy(ep->name, am_ep.name, TI_EEPROM_HDR_NAME_LEN + 1);
 145        ti_eeprom_string_cleanup(ep->name);
 146
 147        /* BeagleBone Green '1' eeprom, board_rev: 0x1a 0x00 0x00 0x00 */
 148        if (am_ep.version[0] == 0x1a && am_ep.version[1] == 0x00 &&
 149            am_ep.version[2] == 0x00 && am_ep.version[3] == 0x00)
 150                strlcpy(ep->version, "BBG1", TI_EEPROM_HDR_REV_LEN + 1);
 151        else
 152                strlcpy(ep->version, am_ep.version, TI_EEPROM_HDR_REV_LEN + 1);
 153        ti_eeprom_string_cleanup(ep->version);
 154        strlcpy(ep->serial, am_ep.serial, TI_EEPROM_HDR_SERIAL_LEN + 1);
 155        ti_eeprom_string_cleanup(ep->serial);
 156        strlcpy(ep->config, am_ep.config, TI_EEPROM_HDR_CONFIG_LEN + 1);
 157        ti_eeprom_string_cleanup(ep->config);
 158
 159        memcpy(ep->mac_addr, am_ep.mac_addr,
 160               TI_EEPROM_HDR_NO_OF_MAC_ADDR * TI_EEPROM_HDR_ETH_ALEN);
 161
 162        return 0;
 163}
 164
 165int __maybe_unused ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr)
 166{
 167        int rc, offset = 0;
 168        struct dra7_eeprom dra7_ep;
 169        struct ti_common_eeprom *ep;
 170
 171        ep = TI_EEPROM_DATA;
 172#ifndef CONFIG_SPL_BUILD
 173        if (ep->header == DRA7_EEPROM_HEADER_MAGIC)
 174                return 0; /* EEPROM has already been read */
 175#endif
 176
 177        /* Initialize with a known bad marker for i2c fails.. */
 178        ep->header = TI_DEAD_EEPROM_MAGIC;
 179        ep->name[0] = 0x0;
 180        ep->version[0] = 0x0;
 181        ep->serial[0] = 0x0;
 182        ep->config[0] = 0x0;
 183        ep->emif1_size = 0;
 184        ep->emif2_size = 0;
 185
 186        rc = ti_i2c_eeprom_get(bus_addr, dev_addr, DRA7_EEPROM_HEADER_MAGIC,
 187                               sizeof(dra7_ep), (uint8_t *)&dra7_ep);
 188        if (rc)
 189                return rc;
 190
 191        ep->header = dra7_ep.header;
 192        strlcpy(ep->name, dra7_ep.name, TI_EEPROM_HDR_NAME_LEN + 1);
 193        ti_eeprom_string_cleanup(ep->name);
 194
 195        offset = dra7_ep.version_major - 1;
 196
 197        /* Rev F is skipped */
 198        if (offset >= 5)
 199                offset = offset + 1;
 200        snprintf(ep->version, TI_EEPROM_HDR_REV_LEN + 1, "%c.%d",
 201                 'A' + offset, dra7_ep.version_minor);
 202        ti_eeprom_string_cleanup(ep->version);
 203        ep->emif1_size = (u64)dra7_ep.emif1_size;
 204        ep->emif2_size = (u64)dra7_ep.emif2_size;
 205        strlcpy(ep->config, dra7_ep.config, TI_EEPROM_HDR_CONFIG_LEN + 1);
 206        ti_eeprom_string_cleanup(ep->config);
 207
 208        return 0;
 209}
 210
 211bool __maybe_unused board_ti_is(char *name_tag)
 212{
 213        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 214
 215        if (ep->header == TI_DEAD_EEPROM_MAGIC)
 216                return false;
 217        return !strncmp(ep->name, name_tag, TI_EEPROM_HDR_NAME_LEN);
 218}
 219
 220bool __maybe_unused board_ti_rev_is(char *rev_tag, int cmp_len)
 221{
 222        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 223        int l;
 224
 225        if (ep->header == TI_DEAD_EEPROM_MAGIC)
 226                return false;
 227
 228        l = cmp_len > TI_EEPROM_HDR_REV_LEN ? TI_EEPROM_HDR_REV_LEN : cmp_len;
 229        return !strncmp(ep->version, rev_tag, l);
 230}
 231
 232char * __maybe_unused board_ti_get_rev(void)
 233{
 234        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 235
 236        /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
 237        return ep->version;
 238}
 239
 240char * __maybe_unused board_ti_get_config(void)
 241{
 242        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 243
 244        /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
 245        return ep->config;
 246}
 247
 248char * __maybe_unused board_ti_get_name(void)
 249{
 250        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 251
 252        /* if ep->header == TI_DEAD_EEPROM_MAGIC, this is empty already */
 253        return ep->name;
 254}
 255
 256void __maybe_unused
 257board_ti_get_eth_mac_addr(int index,
 258                          u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN])
 259{
 260        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 261
 262        if (ep->header == TI_DEAD_EEPROM_MAGIC)
 263                goto fail;
 264
 265        if (index < 0 || index >= TI_EEPROM_HDR_NO_OF_MAC_ADDR)
 266                goto fail;
 267
 268        memcpy(mac_addr, ep->mac_addr[index], TI_EEPROM_HDR_ETH_ALEN);
 269        return;
 270
 271fail:
 272        memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
 273}
 274
 275u64 __maybe_unused board_ti_get_emif1_size(void)
 276{
 277        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 278
 279        if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
 280                return 0;
 281
 282        return ep->emif1_size;
 283}
 284
 285u64 __maybe_unused board_ti_get_emif2_size(void)
 286{
 287        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 288
 289        if (ep->header != DRA7_EEPROM_HEADER_MAGIC)
 290                return 0;
 291
 292        return ep->emif2_size;
 293}
 294
 295void __maybe_unused set_board_info_env(char *name)
 296{
 297        char *unknown = "unknown";
 298        struct ti_common_eeprom *ep = TI_EEPROM_DATA;
 299
 300        if (name)
 301                setenv("board_name", name);
 302        else if (ep->name)
 303                setenv("board_name", ep->name);
 304        else
 305                setenv("board_name", unknown);
 306
 307        if (ep->version)
 308                setenv("board_rev", ep->version);
 309        else
 310                setenv("board_rev", unknown);
 311
 312        if (ep->serial)
 313                setenv("board_serial", ep->serial);
 314        else
 315                setenv("board_serial", unknown);
 316}
 317