uboot/board/compulab/common/eeprom.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2011 CompuLab, Ltd. <www.compulab.co.il>
   3 *
   4 * Authors: Nikita Kiryanov <nikita@compulab.co.il>
   5 *          Igor Grinberg <grinberg@compulab.co.il>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <i2c.h>
  12#include "eeprom.h"
  13
  14#ifndef CONFIG_SYS_I2C_EEPROM_ADDR
  15# define CONFIG_SYS_I2C_EEPROM_ADDR     0x50
  16# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
  17#endif
  18
  19#ifndef CONFIG_SYS_I2C_EEPROM_BUS
  20#define CONFIG_SYS_I2C_EEPROM_BUS       0
  21#endif
  22
  23#define EEPROM_LAYOUT_VER_OFFSET        44
  24#define BOARD_SERIAL_OFFSET             20
  25#define BOARD_SERIAL_OFFSET_LEGACY      8
  26#define BOARD_REV_OFFSET                0
  27#define BOARD_REV_OFFSET_LEGACY         6
  28#define BOARD_REV_SIZE                  2
  29#define PRODUCT_NAME_OFFSET             128
  30#define PRODUCT_NAME_SIZE               16
  31#define MAC_ADDR_OFFSET                 4
  32#define MAC_ADDR_OFFSET_LEGACY          0
  33
  34#define LAYOUT_INVALID  0
  35#define LAYOUT_LEGACY   0xff
  36
  37static int cl_eeprom_bus;
  38static int cl_eeprom_layout; /* Implicitly LAYOUT_INVALID */
  39
  40static int cl_eeprom_read(uint offset, uchar *buf, int len)
  41{
  42        int res;
  43        unsigned int current_i2c_bus = i2c_get_bus_num();
  44
  45        res = i2c_set_bus_num(cl_eeprom_bus);
  46        if (res < 0)
  47                return res;
  48
  49        res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, offset,
  50                        CONFIG_SYS_I2C_EEPROM_ADDR_LEN, buf, len);
  51
  52        i2c_set_bus_num(current_i2c_bus);
  53
  54        return res;
  55}
  56
  57static int cl_eeprom_setup(uint eeprom_bus)
  58{
  59        int res;
  60
  61        /*
  62         * We know the setup was already done when the layout is set to a valid
  63         * value and we're using the same bus as before.
  64         */
  65        if (cl_eeprom_layout != LAYOUT_INVALID && eeprom_bus == cl_eeprom_bus)
  66                return 0;
  67
  68        cl_eeprom_bus = eeprom_bus;
  69        res = cl_eeprom_read(EEPROM_LAYOUT_VER_OFFSET,
  70                             (uchar *)&cl_eeprom_layout, 1);
  71        if (res) {
  72                cl_eeprom_layout = LAYOUT_INVALID;
  73                return res;
  74        }
  75
  76        if (cl_eeprom_layout == 0 || cl_eeprom_layout >= 0x20)
  77                cl_eeprom_layout = LAYOUT_LEGACY;
  78
  79        return 0;
  80}
  81
  82void get_board_serial(struct tag_serialnr *serialnr)
  83{
  84        u32 serial[2];
  85        uint offset;
  86
  87        memset(serialnr, 0, sizeof(*serialnr));
  88
  89        if (cl_eeprom_setup(CONFIG_SYS_I2C_EEPROM_BUS))
  90                return;
  91
  92        offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
  93                BOARD_SERIAL_OFFSET : BOARD_SERIAL_OFFSET_LEGACY;
  94
  95        if (cl_eeprom_read(offset, (uchar *)serial, 8))
  96                return;
  97
  98        if (serial[0] != 0xffffffff && serial[1] != 0xffffffff) {
  99                serialnr->low = serial[0];
 100                serialnr->high = serial[1];
 101        }
 102}
 103
 104/*
 105 * Routine: cl_eeprom_read_mac_addr
 106 * Description: read mac address and store it in buf.
 107 */
 108int cl_eeprom_read_mac_addr(uchar *buf, uint eeprom_bus)
 109{
 110        uint offset;
 111        int err;
 112
 113        err = cl_eeprom_setup(eeprom_bus);
 114        if (err)
 115                return err;
 116
 117        offset = (cl_eeprom_layout != LAYOUT_LEGACY) ?
 118                        MAC_ADDR_OFFSET : MAC_ADDR_OFFSET_LEGACY;
 119
 120        return cl_eeprom_read(offset, buf, 6);
 121}
 122
 123static u32 board_rev;
 124
 125/*
 126 * Routine: cl_eeprom_get_board_rev
 127 * Description: read system revision from eeprom
 128 */
 129u32 cl_eeprom_get_board_rev(uint eeprom_bus)
 130{
 131        char str[5]; /* Legacy representation can contain at most 4 digits */
 132        uint offset = BOARD_REV_OFFSET_LEGACY;
 133
 134        if (board_rev)
 135                return board_rev;
 136
 137        if (cl_eeprom_setup(eeprom_bus))
 138                return 0;
 139
 140        if (cl_eeprom_layout != LAYOUT_LEGACY)
 141                offset = BOARD_REV_OFFSET;
 142
 143        if (cl_eeprom_read(offset, (uchar *)&board_rev, BOARD_REV_SIZE))
 144                return 0;
 145
 146        /*
 147         * Convert legacy syntactic representation to semantic
 148         * representation. i.e. for rev 1.00: 0x100 --> 0x64
 149         */
 150        if (cl_eeprom_layout == LAYOUT_LEGACY) {
 151                sprintf(str, "%x", board_rev);
 152                board_rev = simple_strtoul(str, NULL, 10);
 153        }
 154
 155        return board_rev;
 156};
 157
 158/*
 159 * Routine: cl_eeprom_get_board_rev
 160 * Description: read system revision from eeprom
 161 *
 162 * @buf: buffer to store the product name
 163 * @eeprom_bus: i2c bus num of the eeprom
 164 *
 165 * @return: 0 on success, < 0 on failure
 166 */
 167int cl_eeprom_get_product_name(uchar *buf, uint eeprom_bus)
 168{
 169        int err;
 170
 171        if (buf == NULL)
 172                return -EINVAL;
 173
 174        err = cl_eeprom_setup(eeprom_bus);
 175        if (err)
 176                return err;
 177
 178        err = cl_eeprom_read(PRODUCT_NAME_OFFSET, buf, PRODUCT_NAME_SIZE);
 179        if (!err) /* Protect ourselves from invalid data (unterminated str) */
 180                buf[PRODUCT_NAME_SIZE - 1] = '\0';
 181
 182        return err;
 183}
 184