The new tricordereeprom command can read and write the eeprom for hardware detection on tricorder devices. Signed-off-by: Andreas Bießmann <andreas.biessmann@corscience.de>master
parent
deac6d664b
commit
459f1da88b
@ -0,0 +1,251 @@ |
||||
/*
|
||||
* (C) Copyright 2013 |
||||
* Corscience GmbH & Co. KG, <www.corscience.de> |
||||
* Andreas Bießmann <andreas.biessmann@corscience.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
#include <common.h> |
||||
#include <i2c.h> |
||||
|
||||
#include "tricorder-eeprom.h" |
||||
|
||||
static inline void warn_wrong_value(const char *msg, unsigned int a, |
||||
unsigned int b) |
||||
{ |
||||
printf("Expected EEPROM %s %08x, got %08x\n", msg, a, b); |
||||
} |
||||
|
||||
static int handle_eeprom_v0(struct tricorder_eeprom *eeprom) |
||||
{ |
||||
struct tricorder_eeprom_v0 { |
||||
uint32_t magic; |
||||
uint16_t length; |
||||
uint16_t version; |
||||
char board_name[TRICORDER_BOARD_NAME_LENGTH]; |
||||
char board_version[TRICORDER_BOARD_VERSION_LENGTH]; |
||||
char board_serial[TRICORDER_BOARD_SERIAL_LENGTH]; |
||||
uint32_t crc32; |
||||
} __packed eepromv0; |
||||
uint32_t crc; |
||||
|
||||
printf("Old EEPROM (v0), consider rewrite!\n"); |
||||
|
||||
if (be16_to_cpu(eeprom->length) != sizeof(eepromv0)) { |
||||
warn_wrong_value("length", sizeof(eepromv0), |
||||
be16_to_cpu(eeprom->length)); |
||||
return 1; |
||||
} |
||||
|
||||
memcpy(&eepromv0, eeprom, sizeof(eepromv0)); |
||||
|
||||
crc = crc32(0L, (unsigned char *)&eepromv0, |
||||
sizeof(eepromv0) - sizeof(eepromv0.crc32)); |
||||
if (be32_to_cpu(eepromv0.crc32) != crc) { |
||||
warn_wrong_value("CRC", be32_to_cpu(eepromv0.crc32), |
||||
crc); |
||||
return 1; |
||||
} |
||||
|
||||
/* Ok the content is correct, do the conversion */ |
||||
memset(eeprom->interface_version, 0x0, |
||||
TRICORDER_INTERFACE_VERSION_LENGTH); |
||||
crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE); |
||||
eeprom->crc32 = cpu_to_be32(crc); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int handle_eeprom_v1(struct tricorder_eeprom *eeprom) |
||||
{ |
||||
uint32_t crc; |
||||
|
||||
if (be16_to_cpu(eeprom->length) != TRICORDER_EEPROM_SIZE) { |
||||
warn_wrong_value("length", TRICORDER_EEPROM_SIZE, |
||||
be16_to_cpu(eeprom->length)); |
||||
return 1; |
||||
} |
||||
|
||||
crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE); |
||||
if (be32_to_cpu(eeprom->crc32) != crc) { |
||||
warn_wrong_value("CRC", be32_to_cpu(eeprom->crc32), crc); |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom) |
||||
{ |
||||
#ifdef CONFIG_SYS_EEPROM_BUS_NUM |
||||
unsigned int bus = i2c_get_bus_num(); |
||||
i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM); |
||||
#endif |
||||
|
||||
memset(eeprom, 0, TRICORDER_EEPROM_SIZE); |
||||
|
||||
i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE); |
||||
#ifdef CONFIG_SYS_EEPROM_BUS_NUM |
||||
i2c_set_bus_num(bus); |
||||
#endif |
||||
|
||||
if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) { |
||||
warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC, |
||||
be32_to_cpu(eeprom->magic)); |
||||
return 1; |
||||
} |
||||
|
||||
switch (be16_to_cpu(eeprom->version)) { |
||||
case 0: |
||||
return handle_eeprom_v0(eeprom); |
||||
case 1: |
||||
return handle_eeprom_v1(eeprom); |
||||
default: |
||||
warn_wrong_value("version", TRICORDER_EEPROM_VERSION, |
||||
be16_to_cpu(eeprom->version)); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
#if !defined(CONFIG_SPL) |
||||
int tricorder_eeprom_read(unsigned devaddr) |
||||
{ |
||||
struct tricorder_eeprom eeprom; |
||||
int ret = tricorder_get_eeprom(devaddr, &eeprom); |
||||
|
||||
if (ret) |
||||
return ret; |
||||
|
||||
printf("Board type: %.*s\n", |
||||
sizeof(eeprom.board_name), eeprom.board_name); |
||||
printf("Board version: %.*s\n", |
||||
sizeof(eeprom.board_version), eeprom.board_version); |
||||
printf("Board serial: %.*s\n", |
||||
sizeof(eeprom.board_serial), eeprom.board_serial); |
||||
printf("Board interface version: %.*s\n", |
||||
sizeof(eeprom.interface_version), |
||||
eeprom.interface_version); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int tricorder_eeprom_write(unsigned devaddr, const char *name, |
||||
const char *version, const char *serial, const char *interface) |
||||
{ |
||||
struct tricorder_eeprom eeprom, eeprom_verify; |
||||
size_t length; |
||||
uint32_t crc; |
||||
int ret; |
||||
unsigned char *p; |
||||
int i; |
||||
#ifdef CONFIG_SYS_EEPROM_BUS_NUM |
||||
unsigned int bus; |
||||
#endif |
||||
|
||||
memset(eeprom, 0, TRICORDER_EEPROM_SIZE); |
||||
memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE); |
||||
|
||||
eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC); |
||||
eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE); |
||||
eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION); |
||||
|
||||
length = min(sizeof(eeprom.board_name), strlen(name)); |
||||
strncpy(eeprom.board_name, name, length); |
||||
|
||||
length = min(sizeof(eeprom.board_version), strlen(version)); |
||||
strncpy(eeprom.board_version, version, length); |
||||
|
||||
length = min(sizeof(eeprom.board_serial), strlen(serial)); |
||||
strncpy(eeprom.board_serial, serial, length); |
||||
|
||||
if (interface) { |
||||
length = min(sizeof(eeprom.interface_version), |
||||
strlen(interface)); |
||||
strncpy(eeprom.interface_version, interface, length); |
||||
} |
||||
|
||||
crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE); |
||||
eeprom.crc32 = cpu_to_be32(crc); |
||||
|
||||
#if defined(DEBUG) |
||||
puts("Tricorder EEPROM content:\n"); |
||||
print_buffer(0, &eeprom, 1, sizeof(eeprom), 16); |
||||
#endif |
||||
|
||||
#ifdef CONFIG_SYS_EEPROM_BUS_NUM |
||||
bus = i2c_get_bus_num(); |
||||
i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM); |
||||
#endif |
||||
|
||||
/* do page write to the eeprom */ |
||||
for (i = 0, p = (unsigned char *)&eeprom; |
||||
i < sizeof(eeprom); |
||||
i += 32, p += 32) { |
||||
ret = i2c_write(devaddr, i, CONFIG_SYS_I2C_EEPROM_ADDR_LEN, |
||||
p, min(sizeof(eeprom) - i, 32)); |
||||
if (ret) |
||||
break; |
||||
udelay(5000); /* 5ms write cycle timing */ |
||||
} |
||||
|
||||
ret = i2c_read(devaddr, 0, 2, (unsigned char *)&eeprom_verify, |
||||
TRICORDER_EEPROM_SIZE); |
||||
|
||||
if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) { |
||||
printf("Tricorder: Could not verify EEPROM content!\n"); |
||||
ret = 1; |
||||
} |
||||
|
||||
#ifdef CONFIG_SYS_EEPROM_BUS_NUM |
||||
i2c_set_bus_num(bus); |
||||
#endif |
||||
return ret; |
||||
} |
||||
|
||||
int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
||||
{ |
||||
if (argc == 3) { |
||||
ulong dev_addr = simple_strtoul(argv[2], NULL, 16); |
||||
eeprom_init(); |
||||
if (strcmp(argv[1], "read") == 0) { |
||||
int rcode; |
||||
|
||||
rcode = tricorder_eeprom_read(dev_addr); |
||||
|
||||
return rcode; |
||||
} |
||||
} else if (argc == 6 || argc == 7) { |
||||
ulong dev_addr = simple_strtoul(argv[2], NULL, 16); |
||||
char *name = argv[3]; |
||||
char *version = argv[4]; |
||||
char *serial = argv[5]; |
||||
char *interface = NULL; |
||||
eeprom_init(); |
||||
|
||||
if (argc == 7) |
||||
interface = argv[6]; |
||||
|
||||
if (strcmp(argv[1], "write") == 0) { |
||||
int rcode; |
||||
|
||||
rcode = tricorder_eeprom_write(dev_addr, name, version, |
||||
serial, interface); |
||||
|
||||
return rcode; |
||||
} |
||||
} |
||||
|
||||
return CMD_RET_USAGE; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
tricordereeprom, 7, 1, do_tricorder_eeprom, |
||||
"Tricorder EEPROM", |
||||
"read devaddr\n" |
||||
" - read Tricorder EEPROM at devaddr and print content\n" |
||||
"tricordereeprom write devaddr name version serial [interface]\n" |
||||
" - write Tricorder EEPROM at devaddr with 'name', 'version'" |
||||
"and 'serial'\n" |
||||
" optional add an HW interface parameter" |
||||
); |
||||
#endif /* CONFIG_SPL */ |
@ -0,0 +1,41 @@ |
||||
/*
|
||||
* (C) Copyright 2013 |
||||
* Corscience GmbH & Co. KG, <www.corscience.de> |
||||
* Andreas Bießmann <andreas.biessmann@corscience.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
#ifndef TRICORDER_EEPROM_H_ |
||||
#define TRICORDER_EEPROM_H_ |
||||
|
||||
#include <linux/compiler.h> |
||||
|
||||
#define TRICORDER_EEPROM_MAGIC 0xc2a94f52 |
||||
#define TRICORDER_EEPROM_VERSION 1 |
||||
|
||||
#define TRICORDER_BOARD_NAME_LENGTH 12 |
||||
#define TRICORDER_BOARD_VERSION_LENGTH 4 |
||||
#define TRICORDER_BOARD_SERIAL_LENGTH 12 |
||||
#define TRICORDER_INTERFACE_VERSION_LENGTH 4 |
||||
|
||||
struct tricorder_eeprom { |
||||
uint32_t magic; |
||||
uint16_t length; |
||||
uint16_t version; |
||||
char board_name[TRICORDER_BOARD_NAME_LENGTH]; |
||||
char board_version[TRICORDER_BOARD_VERSION_LENGTH]; |
||||
char board_serial[TRICORDER_BOARD_SERIAL_LENGTH]; |
||||
char interface_version[TRICORDER_INTERFACE_VERSION_LENGTH]; |
||||
uint32_t crc32; |
||||
} __packed; |
||||
|
||||
#define TRICORDER_EEPROM_SIZE sizeof(struct tricorder_eeprom) |
||||
#define TRICORDER_EEPROM_CRC_SIZE (TRICORDER_EEPROM_SIZE - \ |
||||
sizeof(uint32_t)) |
||||
|
||||
/**
|
||||
* @brief read eeprom information from a specific eeprom address |
||||
*/ |
||||
int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom); |
||||
|
||||
#endif /* TRICORDER_EEPROM_H_ */ |
Loading…
Reference in new issue