diff --git a/arch/arm/boards/phytec-som-am335x/board.c b/arch/arm/boards/phytec-som-am335x/board.c index 0d73ed9e0..77ed950e4 100644 --- a/arch/arm/boards/phytec-som-am335x/board.c +++ b/arch/arm/boards/phytec-som-am335x/board.c @@ -32,6 +32,9 @@ #include #include #include +#include + +#include "sob_odu_eeprom.h" static int physom_coredevice_init(void) { @@ -124,3 +127,58 @@ static int physom_devices_init(void) return 0; } device_initcall(physom_devices_init); + +#define CRCPOLY_LE 0xedb88320 +static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p, + size_t len, u32 polynomial) +{ + int i; + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); + } + return crc; +} +u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) +{ + return crc32_le_generic(crc, p, len, CRCPOLY_LE); +} + +static int sob_odu_eeprom_init(void) +{ + struct sob_odu_eeprom soe; + uint32_t crc32_comp; + struct cdev *cdev; + int ret; + + if (!of_machine_is_compatible("sysmocom,odu")) + return 0; + + cdev = cdev_by_name("eeprom0"); + if (!cdev) + return -ENODEV; + + ret = cdev_read(cdev, &soe, sizeof(soe), 0, 0); + if (ret < 0) + return ret; + + if (soe.magic != SOBJB_EE_MAGIC || soe.version != SOBJB_EE_VERSION) { + pr_err("EEPROM magic/version wrong\n"); + return -EINVAL; + } + crc32_comp = crc32_le(0xffffffff, (void *)(&soe) + 8, sizeof(soe)-8); + if (soe.crc32 != crc32_comp) { + pr_err("EEPROM CRC32 mismatch (eeprom=0x%08x, computed=0x%08x)\n", + soe.crc32, crc32_comp); + return -EINVAL; + } + pr_info("SOB-ODU board v%u, serial number %u, mfg %u, hw_options=0x%08x\n", + soe.model, soe.serial, soe.manuf_date, soe.hw_options); + + eth_register_ethaddr(0, soe.mac_eth0); + eth_register_ethaddr(1, soe.mac_eth1); + + return 0; +} +late_initcall(sob_odu_eeprom_init); diff --git a/arch/arm/boards/phytec-som-am335x/sob_odu_eeprom.h b/arch/arm/boards/phytec-som-am335x/sob_odu_eeprom.h new file mode 100644 index 000000000..982f126bd --- /dev/null +++ b/arch/arm/boards/phytec-som-am335x/sob_odu_eeprom.h @@ -0,0 +1,28 @@ +#pragma once + +#define MAC_ADDR_LEN 6 + +#define SOBJB_EE_MAGIC 0x50b0d0ee +#define SOBJB_EE_VERSION 1 + +#define SOB_ODU_V1 1 +#define SOB_ODU_V2 2 +#define SOB_ODU_V3 3 + +struct sob_odu_eeprom { + uint32_t magic; /* SOBJB_EE_MAGIC */ + uint32_t crc32; /* crc32_le */ + + uint16_t len; /* sizeof(struct sob_odu_eeprom) */ + uint8_t version; /* SOBJB_EE_VERSION */ + uint8_t model; /* SOB_ODU_V* */ + + uint32_t serial; + uint32_t manuf_date; + uint32_t hw_options; + + uint8_t mac_eth0[MAC_ADDR_LEN]; + uint8_t mac_eth1[MAC_ADDR_LEN]; + uint8_t mac_wlan0[MAC_ADDR_LEN]; + uint8_t mac_wlan1[MAC_ADDR_LEN]; +} __attribute__ ((packed));