[U-Boot] [PATCH 0/6] GE: Move from ext4 to eeprom bootcounter

Writing to ext4 from U-Boot is dangerous in case of inconsistent filesystem state (i.e. due to power-loss). The current U-Boot code can modify the filesystem, so that it is no longer usable by Linux after fsck. This patchset avoids writing to the partition on GE devices by moving the boot counter to the last two bytes of VPD EEPROM (together with some VPD cleanups). It also adds non RTC device support to the i2c bootcounter driver.
-- Sebastian
Denis Zalevskiy (6): board: ge: Remove EEPROM bus param from read_vpd() board: ge: Move VPD EEPROM configuration to the defconfig bootcount: i2c: Add bus switching to the I2C bootcount driver bootcount: Configure length limit for I2C bootcount board: ge: Move VPD reading to the vpd_reader board: ge: Store bootcount in EEPROM on PPD and Bx50v3
board/ge/bx50v3/Kconfig | 2 + board/ge/bx50v3/bx50v3.c | 57 +++++----------------- board/ge/common/vpd_reader.c | 57 ++++++++++++++++++++-- board/ge/common/vpd_reader.h | 16 +++++-- board/ge/mx53ppd/Kconfig | 2 + board/ge/mx53ppd/mx53ppd.c | 50 ++++---------------- configs/ge_bx50v3_defconfig | 27 +++++++++-- configs/mx53ppd_defconfig | 29 ++++++++++-- drivers/bootcount/Kconfig | 21 ++++++++- drivers/bootcount/bootcount_i2c.c | 78 ++++++++++++++++++++++++++----- include/configs/ge_bx50v3.h | 6 +-- include/configs/mx53ppd.h | 6 +-- 12 files changed, 230 insertions(+), 121 deletions(-)

From: Denis Zalevskiy denis.zalevskiy@ge.com
The bus is statically defined, so remove redundant parameters from read_vpd() for PPD and Bx50v3.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- board/ge/bx50v3/bx50v3.c | 6 +++--- board/ge/mx53ppd/mx53ppd.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c index 33f7ee6e3be5..60d600c50c8b 100644 --- a/board/ge/bx50v3/bx50v3.c +++ b/board/ge/bx50v3/bx50v3.c @@ -624,14 +624,14 @@ static void process_vpd(struct vpd_cache *vpd) eth_env_set_enetaddr_by_index("eth", i210_index, vpd->mac2); }
-static int read_vpd(uint eeprom_bus) +static int read_vpd() { int res; int size = 1024; uint8_t *data; unsigned int current_i2c_bus = i2c_get_bus_num();
- res = i2c_set_bus_num(eeprom_bus); + res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); if (res < 0) return res;
@@ -715,7 +715,7 @@ int board_init(void) setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2); setup_i2c(3, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info3);
- read_vpd(CONFIG_SYS_I2C_EEPROM_BUS); + read_vpd();
set_confidx(&vpd);
diff --git a/board/ge/mx53ppd/mx53ppd.c b/board/ge/mx53ppd/mx53ppd.c index 0010998d66cf..317d7f69d5a1 100644 --- a/board/ge/mx53ppd/mx53ppd.c +++ b/board/ge/mx53ppd/mx53ppd.c @@ -329,7 +329,7 @@ static void process_vpd(struct vpd_cache *vpd) eth_env_set_enetaddr("ethaddr", vpd->mac1); }
-static int read_vpd(uint eeprom_bus) +static int read_vpd() { struct vpd_cache vpd; int res; @@ -337,7 +337,7 @@ static int read_vpd(uint eeprom_bus) u8 *data; unsigned int current_i2c_bus = i2c_get_bus_num();
- res = i2c_set_bus_num(eeprom_bus); + res = i2c_set_bus_num(VPD_EEPROM_BUS); if (res < 0) return res;
@@ -391,7 +391,7 @@ int board_late_init(void) { int res;
- read_vpd(VPD_EEPROM_BUS); + read_vpd();
res = clock_1GHz(); if (res != 0)

From: Denis Zalevskiy denis.zalevskiy@ge.com
Use standard configuration logic to define EEPROM constants. Names are based on VPD_EEPROM_ prefix because EEPROM_ is already used by i2c_eeprom driver.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- board/ge/bx50v3/Kconfig | 2 ++ board/ge/bx50v3/bx50v3.c | 17 ++++------------- board/ge/mx53ppd/Kconfig | 2 ++ board/ge/mx53ppd/mx53ppd.c | 14 ++++---------- configs/ge_bx50v3_defconfig | 9 +++++++++ configs/mx53ppd_defconfig | 10 ++++++++++ 6 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/board/ge/bx50v3/Kconfig b/board/ge/bx50v3/Kconfig index 993b0559302b..05938560abda 100644 --- a/board/ge/bx50v3/Kconfig +++ b/board/ge/bx50v3/Kconfig @@ -15,4 +15,6 @@ config SYS_SOC config SYS_CONFIG_NAME default "ge_bx50v3"
+source "board/ge/common/Kconfig" + endif diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c index 60d600c50c8b..c703aca7cab3 100644 --- a/board/ge/bx50v3/bx50v3.c +++ b/board/ge/bx50v3/bx50v3.c @@ -39,15 +39,6 @@ struct vpd_cache; static int confidx = 3; /* Default to b850v3. */ static struct vpd_cache vpd;
-#ifndef CONFIG_SYS_I2C_EEPROM_ADDR -# define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 -# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 -#endif - -#ifndef CONFIG_SYS_I2C_EEPROM_BUS -#define CONFIG_SYS_I2C_EEPROM_BUS 4 -#endif - #define NC_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \ PAD_CTL_HYS) @@ -627,11 +618,11 @@ static void process_vpd(struct vpd_cache *vpd) static int read_vpd() { int res; - int size = 1024; + static const int size = CONFIG_SYS_VPD_EEPROM_SIZE; uint8_t *data; unsigned int current_i2c_bus = i2c_get_bus_num();
- res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS); + res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS); if (res < 0) return res;
@@ -639,8 +630,8 @@ static int read_vpd() if (!data) return -ENOMEM;
- res = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0, - CONFIG_SYS_I2C_EEPROM_ADDR_LEN, data, size); + res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0, + CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN, data, size);
if (res == 0) { memset(&vpd, 0, sizeof(vpd)); diff --git a/board/ge/mx53ppd/Kconfig b/board/ge/mx53ppd/Kconfig index 781c1cf59f61..cc43d839cf92 100644 --- a/board/ge/mx53ppd/Kconfig +++ b/board/ge/mx53ppd/Kconfig @@ -14,4 +14,6 @@ config SYS_SOC config SYS_CONFIG_NAME default "mx53ppd"
+source "board/ge/common/Kconfig" + endif diff --git a/board/ge/mx53ppd/mx53ppd.c b/board/ge/mx53ppd/mx53ppd.c index 317d7f69d5a1..47f6e9649cbe 100644 --- a/board/ge/mx53ppd/mx53ppd.c +++ b/board/ge/mx53ppd/mx53ppd.c @@ -41,13 +41,6 @@
DECLARE_GLOBAL_DATA_PTR;
-/* Index of I2C1, SEGMENT 1 (see CONFIG_SYS_I2C_BUSES). */ -#define VPD_EEPROM_BUS 2 - -/* Address of 24C08 EEPROM. */ -#define VPD_EEPROM_ADDR 0x50 -#define VPD_EEPROM_ADDR_LEN 1 - static u32 mx53_dram_size[2];
phys_size_t get_effective_memsize(void) @@ -333,11 +326,11 @@ static int read_vpd() { struct vpd_cache vpd; int res; - int size = 1024; + static const int size = CONFIG_SYS_VPD_EEPROM_SIZE; u8 *data; unsigned int current_i2c_bus = i2c_get_bus_num();
- res = i2c_set_bus_num(VPD_EEPROM_BUS); + res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS); if (res < 0) return res;
@@ -345,7 +338,8 @@ static int read_vpd() if (!data) return -ENOMEM;
- res = i2c_read(VPD_EEPROM_ADDR, 0, VPD_EEPROM_ADDR_LEN, data, size); + res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0, + CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN, data, size); if (res == 0) { memset(&vpd, 0, sizeof(vpd)); vpd_reader(size, data, &vpd, vpd_callback); diff --git a/configs/ge_bx50v3_defconfig b/configs/ge_bx50v3_defconfig index a37df05d0994..829a39e08567 100644 --- a/configs/ge_bx50v3_defconfig +++ b/configs/ge_bx50v3_defconfig @@ -7,6 +7,15 @@ CONFIG_FIT=y CONFIG_BOOTDELAY=1 CONFIG_SYS_CONSOLE_IS_IN_ENV=y CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y + +# monitor's EEPROM is connected to the bus through the mux channel 1 +# (the number is the offset in CONFIG_SYS_I2C_BUSES) +CONFIG_SYS_VPD_EEPROM_I2C_BUS=4 +# Address of Atmel 24C08 EEPROM +CONFIG_SYS_VPD_EEPROM_I2C_ADDR=0x50 +CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN=1 +CONFIG_SYS_VPD_EEPROM_SIZE=1024 + CONFIG_SUPPORT_RAW_INITRD=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_LAST_STAGE_INIT=y diff --git a/configs/mx53ppd_defconfig b/configs/mx53ppd_defconfig index 8a0cc5d481ad..4a7e8eee0df1 100644 --- a/configs/mx53ppd_defconfig +++ b/configs/mx53ppd_defconfig @@ -8,6 +8,16 @@ CONFIG_BOOTDELAY=1 # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE=y + +# monitor's EEPROM is connected to the bus through the mux channel 1 +# (the number is the offset in CONFIG_SYS_I2C_BUSES) +# (there is also Frame EEPROM connected to the channel 4 (bus 4)) +CONFIG_SYS_VPD_EEPROM_I2C_BUS=2 +# Address of Atmel 24C08 EEPROM +CONFIG_SYS_VPD_EEPROM_I2C_ADDR=0x50 +CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN=1 +CONFIG_SYS_VPD_EEPROM_SIZE=1024 + CONFIG_SUPPORT_RAW_INITRD=y CONFIG_HUSH_PARSER=y CONFIG_CMD_BOOTZ=y

On Tue, Jun 26, 2018 at 07:43:00PM +0200, Sebastian Reichel wrote:
From: Denis Zalevskiy denis.zalevskiy@ge.com
Use standard configuration logic to define EEPROM constants. Names are based on VPD_EEPROM_ prefix because EEPROM_ is already used by i2c_eeprom driver.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk
board/ge/bx50v3/Kconfig | 2 ++ board/ge/bx50v3/bx50v3.c | 17 ++++------------- board/ge/mx53ppd/Kconfig | 2 ++ board/ge/mx53ppd/mx53ppd.c | 14 ++++---------- configs/ge_bx50v3_defconfig | 9 +++++++++ configs/mx53ppd_defconfig | 10 ++++++++++ 6 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/board/ge/bx50v3/Kconfig b/board/ge/bx50v3/Kconfig index 993b0559302b..05938560abda 100644 --- a/board/ge/bx50v3/Kconfig +++ b/board/ge/bx50v3/Kconfig @@ -15,4 +15,6 @@ config SYS_SOC config SYS_CONFIG_NAME default "ge_bx50v3"
+source "board/ge/common/Kconfig"
The new file board/ge/common/Kconfig is missing, please repost the series with the file added, thanks!

Hi Tom,
On Thu, Jul 19, 2018 at 04:31:01PM -0400, Tom Rini wrote:
On Tue, Jun 26, 2018 at 07:43:00PM +0200, Sebastian Reichel wrote:
From: Denis Zalevskiy denis.zalevskiy@ge.com
Use standard configuration logic to define EEPROM constants. Names are based on VPD_EEPROM_ prefix because EEPROM_ is already used by i2c_eeprom driver.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk
board/ge/bx50v3/Kconfig | 2 ++ board/ge/bx50v3/bx50v3.c | 17 ++++------------- board/ge/mx53ppd/Kconfig | 2 ++ board/ge/mx53ppd/mx53ppd.c | 14 ++++---------- configs/ge_bx50v3_defconfig | 9 +++++++++ configs/mx53ppd_defconfig | 10 ++++++++++ 6 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/board/ge/bx50v3/Kconfig b/board/ge/bx50v3/Kconfig index 993b0559302b..05938560abda 100644 --- a/board/ge/bx50v3/Kconfig +++ b/board/ge/bx50v3/Kconfig @@ -15,4 +15,6 @@ config SYS_SOC config SYS_CONFIG_NAME default "ge_bx50v3"
+source "board/ge/common/Kconfig"
The new file board/ge/common/Kconfig is missing, please repost the series with the file added, thanks!
Oops, I just wondered how my test-built worked, but it's just me being too stupid to read git output 😓
Untracked files: (use "git add <file>..." to include in what will be committed)
board/ge/common/Kconfig
Anyways, thanks for the review, I will resend the series!
-- Sebastian

From: Denis Zalevskiy denis.zalevskiy@ge.com
If there is an I2C mux, current bus should be switched before manipulating with I2C.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- drivers/bootcount/Kconfig | 15 ++++++- drivers/bootcount/bootcount_i2c.c | 70 +++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 9 deletions(-)
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index d335ed14b961..a5349a62fdc3 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -62,7 +62,9 @@ config BOOTCOUNT_I2C bool "Boot counter on I2C device" help Enable support for the bootcounter on an i2c (like RTC) device. - CONFIG_SYS_I2C_RTC_ADDR = i2c chip address + CONFIG_SYS_BOOTCOUNT_I2C_BUS = bus of the target I2C device, + CONFIG_SYS_I2C_RTC_ADDR is used as fallback + CONFIG_SYS_BOOTCOUNT_I2C_ADDR = target I2C device address CONFIG_SYS_BOOTCOUNT_ADDR = i2c addr which is used for the bootcounter.
@@ -119,4 +121,15 @@ config SYS_BOOTCOUNT_ADDR help Set the address used for reading and writing the boot counter.
+config SYS_BOOTCOUNT_I2C_BUS + int "I2C bootcounter device bus" + depends on BOOTCOUNT_I2C + help + I2C bus of the device used to store bootcounter + +config SYS_BOOTCOUNT_I2C_ADDR + hex "I2C bootcounter device address" + depends on BOOTCOUNT_I2C + help + I2C address of the device used to store bootcounter endif diff --git a/drivers/bootcount/bootcount_i2c.c b/drivers/bootcount/bootcount_i2c.c index e27b168c55cc..79d82ad451f3 100644 --- a/drivers/bootcount/bootcount_i2c.c +++ b/drivers/bootcount/bootcount_i2c.c @@ -9,36 +9,90 @@ #include <linux/compiler.h> #include <i2c.h>
+#ifndef CONFIG_SYS_BOOTCOUNT_I2C_ADDR +/* compatibility with the previous logic: + * previous version of driver used RTC device to store bootcount + */ +#define CONFIG_SYS_BOOTCOUNT_I2C_ADDR CONFIG_SYS_I2C_RTC_ADDR +#endif + #define BC_MAGIC 0xbc
+#ifdef CONFIG_SYS_BOOTCOUNT_I2C_BUS +static int bootcount_set_bus(void) +{ + unsigned int current_bus = i2c_get_bus_num(); + + assert(current_bus <= INT_MAX); + + int res = i2c_set_bus_num(CONFIG_SYS_BOOTCOUNT_I2C_BUS); + + if (res < 0) { + puts("Error switching I2C bus\n"); + return res; + } + return (int)current_bus; +} + +static void bootcount_set_bus_back(int prev_bus) +{ + if (i2c_set_bus_num(prev_bus) < 0) + puts("Can't switch I2C bus back\n"); +} +#else +static inline int bootcount_set_bus(void) { return 0; } + +static inline void bootcount_set_bus_back(int prev_bus __attribute__((unused))) +{ +} +#endif + void bootcount_store(ulong a) { + int prev_i2c_bus = bootcount_set_bus(); + + if (prev_i2c_bus < 0) + return; + unsigned char buf[3]; int ret;
buf[0] = BC_MAGIC; buf[1] = (a & 0xff); - ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR, - CONFIG_BOOTCOUNT_ALEN, buf, 2); + ret = i2c_write(CONFIG_SYS_BOOTCOUNT_I2C_ADDR, + CONFIG_SYS_BOOTCOUNT_ADDR, + CONFIG_BOOTCOUNT_ALEN, buf, 2); if (ret != 0) puts("Error writing bootcount\n"); + + bootcount_set_bus_back(prev_i2c_bus); }
ulong bootcount_load(void) { + ulong count = 0; + + int prev_i2c_bus = bootcount_set_bus(); + + if (prev_i2c_bus < 0) + return count; + unsigned char buf[3]; int ret;
- ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR, + ret = i2c_read(CONFIG_SYS_BOOTCOUNT_I2C_ADDR, + CONFIG_SYS_BOOTCOUNT_ADDR, CONFIG_BOOTCOUNT_ALEN, buf, 2); if (ret != 0) { puts("Error loading bootcount\n"); - return 0; + goto out; } if (buf[0] == BC_MAGIC) - return buf[1]; - - bootcount_store(0); + count = buf[1]; + else + bootcount_store(count);
- return 0; +out: + bootcount_set_bus_back(prev_i2c_bus); + return count; }

From: Denis Zalevskiy denis.zalevskiy@ge.com
Bootcount driver should verify size against the maximum available space. New configuration parameter adds this capability and keeps backward compatibility by providing default value.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- drivers/bootcount/Kconfig | 6 ++++++ drivers/bootcount/bootcount_i2c.c | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index a5349a62fdc3..e7f2e1ef65e0 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -132,4 +132,10 @@ config SYS_BOOTCOUNT_I2C_ADDR depends on BOOTCOUNT_I2C help I2C address of the device used to store bootcounter + +config BOOTCOUNT_I2C_LEN + int "Maximum length of bootcounter in bytes" + default 2 + depends on BOOTCOUNT_I2C + endif diff --git a/drivers/bootcount/bootcount_i2c.c b/drivers/bootcount/bootcount_i2c.c index 79d82ad451f3..a8bb611eea9e 100644 --- a/drivers/bootcount/bootcount_i2c.c +++ b/drivers/bootcount/bootcount_i2c.c @@ -54,14 +54,15 @@ void bootcount_store(ulong a) if (prev_i2c_bus < 0) return;
- unsigned char buf[3]; + unsigned char buf[2]; int ret;
+ BUILD_BUG_ON(CONFIG_BOOTCOUNT_I2C_LEN < sizeof(buf)); buf[0] = BC_MAGIC; buf[1] = (a & 0xff); ret = i2c_write(CONFIG_SYS_BOOTCOUNT_I2C_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR, - CONFIG_BOOTCOUNT_ALEN, buf, 2); + CONFIG_BOOTCOUNT_ALEN, buf, sizeof(buf)); if (ret != 0) puts("Error writing bootcount\n");
@@ -77,12 +78,13 @@ ulong bootcount_load(void) if (prev_i2c_bus < 0) return count;
- unsigned char buf[3]; + unsigned char buf[2]; int ret;
+ BUILD_BUG_ON(CONFIG_BOOTCOUNT_I2C_LEN < sizeof(buf)); ret = i2c_read(CONFIG_SYS_BOOTCOUNT_I2C_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR, - CONFIG_BOOTCOUNT_ALEN, buf, 2); + CONFIG_BOOTCOUNT_ALEN, buf, sizeof(buf)); if (ret != 0) { puts("Error loading bootcount\n"); goto out;

From: Denis Zalevskiy denis.zalevskiy@ge.com
Merge functionality duplicated in bx50v3 and mx53ppd: the logic is the same except that process_vpd is called at different phases. Also read_vpd could end up in error, so there is no VPD data in this case - it shouldn't be processed.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- board/ge/bx50v3/bx50v3.c | 48 +++++++++--------------------------- board/ge/common/vpd_reader.c | 37 ++++++++++++++++++++++++--- board/ge/common/vpd_reader.h | 16 ++++++++---- board/ge/mx53ppd/mx53ppd.c | 44 +++++++-------------------------- 4 files changed, 65 insertions(+), 80 deletions(-)
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c index c703aca7cab3..917baaea7129 100644 --- a/board/ge/bx50v3/bx50v3.c +++ b/board/ge/bx50v3/bx50v3.c @@ -34,8 +34,6 @@ #include "../../../drivers/net/e1000.h" DECLARE_GLOBAL_DATA_PTR;
-struct vpd_cache; - static int confidx = 3; /* Default to b850v3. */ static struct vpd_cache vpd;
@@ -553,6 +551,7 @@ int overwrite_console(void) #define VPD_MAC_ADDRESS_LENGTH 6
struct vpd_cache { + bool is_read; u8 product_id; u8 has; unsigned char mac1[VPD_MAC_ADDRESS_LENGTH]; @@ -562,11 +561,9 @@ struct vpd_cache { /* * Extracts MAC and product information from the VPD. */ -static int vpd_callback(void *userdata, u8 id, u8 version, u8 type, +static int vpd_callback(struct vpd_cache *vpd, u8 id, u8 version, u8 type, size_t size, u8 const *data) { - struct vpd_cache *vpd = (struct vpd_cache *)userdata; - if (id == VPD_BLOCK_HWID && version == 1 && type != VPD_TYPE_INVALID && size >= 1) { vpd->product_id = data[0]; @@ -590,6 +587,11 @@ static void process_vpd(struct vpd_cache *vpd) int fec_index = -1; int i210_index = -1;
+ if (!vpd->is_read) { + printf("VPD wasn't read"); + return; + } + switch (vpd->product_id) { case VPD_PRODUCT_B450: env_set("confidx", "1"); @@ -615,35 +617,6 @@ static void process_vpd(struct vpd_cache *vpd) eth_env_set_enetaddr_by_index("eth", i210_index, vpd->mac2); }
-static int read_vpd() -{ - int res; - static const int size = CONFIG_SYS_VPD_EEPROM_SIZE; - uint8_t *data; - unsigned int current_i2c_bus = i2c_get_bus_num(); - - res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS); - if (res < 0) - return res; - - data = (uint8_t *)malloc(size); - if (!data) - return -ENOMEM; - - res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0, - CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN, data, size); - - if (res == 0) { - memset(&vpd, 0, sizeof(vpd)); - vpd_reader(size, data, &vpd, vpd_callback); - } - - free(data); - - i2c_set_bus_num(current_i2c_bus); - return res; -} - int board_eth_init(bd_t *bis) { setup_iomux_enet(); @@ -706,9 +679,10 @@ int board_init(void) setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2); setup_i2c(3, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info3);
- read_vpd(); - - set_confidx(&vpd); + if (!read_vpd(&vpd, vpd_callback)) { + vpd.is_read = true; + set_confidx(&vpd); + }
gpio_direction_output(SUS_S3_OUT, 1); gpio_direction_output(WIFI_EN, 1); diff --git a/board/ge/common/vpd_reader.c b/board/ge/common/vpd_reader.c index 7367427993b3..60f81342f9bc 100644 --- a/board/ge/common/vpd_reader.c +++ b/board/ge/common/vpd_reader.c @@ -6,6 +6,7 @@
#include "vpd_reader.h"
+#include <i2c.h> #include <linux/bch.h> #include <stdlib.h>
@@ -106,9 +107,9 @@ static const size_t HEADER_BLOCK_ECC_LEN = 4;
static const u8 ECC_BLOCK_ID = 0xFF;
-int vpd_reader(size_t size, u8 *data, void *userdata, - int (*fn)(void *userdata, u8 id, u8 version, u8 type, - size_t size, u8 const *data)) +static int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata, + int (*fn)(struct vpd_cache *, u8 id, u8 version, u8 type, + size_t size, u8 const *data)) { if (size < HEADER_BLOCK_LEN || !data || !fn) return -EINVAL; @@ -195,3 +196,33 @@ int vpd_reader(size_t size, u8 *data, void *userdata, return ret; } } + +int read_vpd(struct vpd_cache *cache, + int (*process_block)(struct vpd_cache *, u8 id, u8 version, + u8 type, size_t size, u8 const *data)) +{ + static const size_t size = CONFIG_SYS_VPD_EEPROM_SIZE; + + int res; + u8 *data; + unsigned int current_i2c_bus = i2c_get_bus_num(); + + res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS); + if (res < 0) + return res; + + data = malloc(size); + if (!data) + return -ENOMEM; + + res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0, + CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN, + data, size); + if (res == 0) + res = vpd_reader(size, data, cache, process_block); + + free(data); + + i2c_set_bus_num(current_i2c_bus); + return res; +} diff --git a/board/ge/common/vpd_reader.h b/board/ge/common/vpd_reader.h index 4abba8f5de72..f5e90dbf6629 100644 --- a/board/ge/common/vpd_reader.h +++ b/board/ge/common/vpd_reader.h @@ -6,12 +6,18 @@
#include "common.h"
+struct vpd_cache; + /* - * Read VPD from given data, verify content, and call callback - * for each vital product data block. + * Read VPD from given data, verify content, call callback for each vital + * product data block. + * + * cache: structure used by process block to store VPD information + * process_block: callback called for each VPD data block * * Returns Non-zero on error. Negative numbers encode errno. */ -int vpd_reader(size_t size, u8 *data, void *userdata, - int (*fn)(void *userdata, u8 id, u8 version, u8 type, - size_t size, u8 const *data)); +int read_vpd(struct vpd_cache *cache, + int (*process_block)(struct vpd_cache *, + u8 id, u8 version, u8 type, + size_t size, u8 const *data)); diff --git a/board/ge/mx53ppd/mx53ppd.c b/board/ge/mx53ppd/mx53ppd.c index 47f6e9649cbe..e196bc118a76 100644 --- a/board/ge/mx53ppd/mx53ppd.c +++ b/board/ge/mx53ppd/mx53ppd.c @@ -291,11 +291,9 @@ struct vpd_cache { /* * Extracts MAC and product information from the VPD. */ -static int vpd_callback(void *userdata, u8 id, u8 version, u8 type, size_t size, - u8 const *data) +static int vpd_callback(struct vpd_cache *vpd, u8 id, u8 version, u8 type, + size_t size, const u8 *data) { - struct vpd_cache *vpd = (struct vpd_cache *)userdata; - if (id == VPD_BLOCK_HWID && version == 1 && type != VPD_TYPE_INVALID && size >= 1) { vpd->product_id = data[0]; @@ -322,36 +320,6 @@ static void process_vpd(struct vpd_cache *vpd) eth_env_set_enetaddr("ethaddr", vpd->mac1); }
-static int read_vpd() -{ - struct vpd_cache vpd; - int res; - static const int size = CONFIG_SYS_VPD_EEPROM_SIZE; - u8 *data; - unsigned int current_i2c_bus = i2c_get_bus_num(); - - res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS); - if (res < 0) - return res; - - data = malloc(size); - if (!data) - return -ENOMEM; - - res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0, - CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN, data, size); - if (res == 0) { - memset(&vpd, 0, sizeof(vpd)); - vpd_reader(size, data, &vpd, vpd_callback); - process_vpd(&vpd); - } - - free(data); - - i2c_set_bus_num(current_i2c_bus); - return res; -} - int board_init(void) { gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; @@ -384,8 +352,14 @@ int misc_init_r(void) int board_late_init(void) { int res; + struct vpd_cache vpd;
- read_vpd(); + memset(&vpd, 0, sizeof(vpd)); + res = read_vpd(&vpd, vpd_callback); + if (!res) + process_vpd(&vpd); + else + printf("Can't read VPD");
res = clock_1GHz(); if (res != 0)

From: Denis Zalevskiy denis.zalevskiy@ge.com
u-boot's ext3/4 write/modify functionality sometimes corrupts filesystem in the case if it requires recovery (e.g. after unexpected shutdown) and we want to avoid the only filesystem modification we have - bootcounter writing. So, bootcounter will be stored in the EEPROM where VPD is stored.
Signed-off-by: Denis Zalevskiy denis.zalevskiy@ge.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.co.uk --- board/ge/common/vpd_reader.c | 20 ++++++++++++++++++++ configs/ge_bx50v3_defconfig | 18 ++++++++++++++---- configs/mx53ppd_defconfig | 19 +++++++++++++++---- include/configs/ge_bx50v3.h | 6 +++--- include/configs/mx53ppd.h | 6 +++--- 5 files changed, 55 insertions(+), 14 deletions(-)
diff --git a/board/ge/common/vpd_reader.c b/board/ge/common/vpd_reader.c index 60f81342f9bc..7f1f8bca1baf 100644 --- a/board/ge/common/vpd_reader.c +++ b/board/ge/common/vpd_reader.c @@ -6,6 +6,7 @@
#include "vpd_reader.h"
+#include <linux/bug.h> #include <i2c.h> #include <linux/bch.h> #include <stdlib.h> @@ -201,7 +202,26 @@ int read_vpd(struct vpd_cache *cache, int (*process_block)(struct vpd_cache *, u8 id, u8 version, u8 type, size_t size, u8 const *data)) { +#if defined(CONFIG_BOOTCOUNT_I2C) && \ + (CONFIG_SYS_BOOTCOUNT_I2C_BUS == CONFIG_SYS_VPD_EEPROM_I2C_BUS) && \ + ((CONFIG_SYS_BOOTCOUNT_I2C_ADDR & 0xf0) == CONFIG_SYS_VPD_EEPROM_I2C_ADDR) + /* + * bootcount is expected to reside at the end of EEPROM + * + * check is hard-wired to the logic of the 24C08 EEPROM 256-bytes + * page-wise (4 pages) i2c_address/bootcount_address structure combined + * with raw I2C access, so the I2C address and offset are combined into: + * + * i2c_addr = (device_i2c_addr | page), + * offset = (offset - (page * 256))) + */ + BUILD_BUG_ON((CONFIG_SYS_BOOTCOUNT_I2C_ADDR & 0x0f) * 256 + + CONFIG_SYS_BOOTCOUNT_ADDR + CONFIG_BOOTCOUNT_I2C_LEN != + CONFIG_SYS_VPD_EEPROM_SIZE); + static const size_t size = CONFIG_SYS_BOOTCOUNT_ADDR; +#else static const size_t size = CONFIG_SYS_VPD_EEPROM_SIZE; +#endif
int res; u8 *data; diff --git a/configs/ge_bx50v3_defconfig b/configs/ge_bx50v3_defconfig index 829a39e08567..32a9200ea988 100644 --- a/configs/ge_bx50v3_defconfig +++ b/configs/ge_bx50v3_defconfig @@ -16,6 +16,20 @@ CONFIG_SYS_VPD_EEPROM_I2C_ADDR=0x50 CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN=1 CONFIG_SYS_VPD_EEPROM_SIZE=1024
+CONFIG_BOOTCOUNT_I2C=y +CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_SYS_BOOTCOUNT_I2C_BUS=4 +# bootcount is stored in VPD EEPROM +# we are using generic driver instead of EEPROM one (while should use it) +# at the end of VPD EEPROM: (SYS_VPD_EEPROM_SIZE - CONFIG_BOOTCOUNT_I2C_LEN) +# so, the address is 0x3FE: +# ("VPD EEPROM chip address" | "3rd 256-byte page"): +CONFIG_SYS_BOOTCOUNT_I2C_ADDR=0x53 +# (+ "offset in the page"): +CONFIG_SYS_BOOTCOUNT_ADDR=0xfe +CONFIG_BOOTCOUNT_I2C_LEN=2 +CONFIG_BOOTCOUNT_ALEN=1 + CONFIG_SUPPORT_RAW_INITRD=y CONFIG_BOARD_EARLY_INIT_F=y CONFIG_LAST_STAGE_INIT=y @@ -35,10 +49,6 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_FS_GENERIC=y CONFIG_DOS_PARTITION=y CONFIG_ENV_IS_IN_SPI_FLASH=y -CONFIG_BOOTCOUNT_LIMIT=y -CONFIG_BOOTCOUNT_EXT=y -CONFIG_SYS_BOOTCOUNT_EXT_DEVPART="1:5" -CONFIG_SYS_BOOTCOUNT_ADDR=0x7000A000 CONFIG_FSL_ESDHC=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y diff --git a/configs/mx53ppd_defconfig b/configs/mx53ppd_defconfig index 4a7e8eee0df1..43672d88e202 100644 --- a/configs/mx53ppd_defconfig +++ b/configs/mx53ppd_defconfig @@ -18,6 +18,21 @@ CONFIG_SYS_VPD_EEPROM_I2C_ADDR=0x50 CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN=1 CONFIG_SYS_VPD_EEPROM_SIZE=1024
+CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_BOOTCOUNT_I2C=y +# using bus where monitor's EEPROM is connected to +CONFIG_SYS_BOOTCOUNT_I2C_BUS=2 +# bootcount is stored in Monitor's VPD EEPROM +# we are using generic driver instead of EEPROM one (while should use it) +# at the end of VPD EEPROM: (SYS_VPD_EEPROM_SIZE - CONFIG_BOOTCOUNT_I2C_LEN) +# so, the address is 0x3FE: +# ("VPD EEPROM chip address" | "3rd 256-byte page"): +CONFIG_SYS_BOOTCOUNT_I2C_ADDR=0x53 +# (+ "offset in the page"): +CONFIG_SYS_BOOTCOUNT_ADDR=0xfe +CONFIG_BOOTCOUNT_I2C_LEN=2 +CONFIG_BOOTCOUNT_ALEN=1 + CONFIG_SUPPORT_RAW_INITRD=y CONFIG_HUSH_PARSER=y CONFIG_CMD_BOOTZ=y @@ -33,10 +48,6 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_ENV_IS_IN_MMC=y -CONFIG_BOOTCOUNT_LIMIT=y -CONFIG_BOOTCOUNT_EXT=y -CONFIG_SYS_BOOTCOUNT_EXT_DEVPART="0:5" -CONFIG_SYS_BOOTCOUNT_ADDR=0x7000A000 CONFIG_FSL_ESDHC=y CONFIG_NETDEVICES=y CONFIG_RTC_S35392A=y diff --git a/include/configs/ge_bx50v3.h b/include/configs/ge_bx50v3.h index 307ec0101c0a..5576fd33d48d 100644 --- a/include/configs/ge_bx50v3.h +++ b/include/configs/ge_bx50v3.h @@ -118,9 +118,9 @@ "setenv stdout vga; " \ "echo "\n\n\n\n " $msg; " \ "setenv stdout serial; " \ - "mw.b 0x7000A000 0xbc; " \ - "mw.b 0x7000A001 0x00; " \ - "ext4write ${dev} ${devnum}:5 0x7000A000 /boot/failures 2\0" \ + "i2c dev 4; " \ + "i2c mw.b 53 fe bc; " \ + "i2c mw.b 53 ff 00; \0" \ "altbootcmd=" \ "run doquiet; " \ "setenv partnum 1; run hasfirstboot || setenv partnum 2; " \ diff --git a/include/configs/mx53ppd.h b/include/configs/mx53ppd.h index 338f1434f2cc..549efc10c5e9 100644 --- a/include/configs/mx53ppd.h +++ b/include/configs/mx53ppd.h @@ -130,9 +130,9 @@ "setenv stdout vga; " \ "echo "\n\n\n\n " $msg; " \ "setenv stdout serial; " \ - "mw.b 0x7000A000 0xbc; " \ - "mw.b 0x7000A001 0x00; " \ - "ext4write ${dev} ${devnum}:5 0x7000A000 /boot/failures 2\0" \ + "i2c dev 2; " \ + "i2c mw.b 53 fe bc; " \ + "i2c mw.b 53 ff 00; \0" \ "altbootcmd=" \ "run doquiet; " \ "setenv partnum 1; run hasfirstboot || setenv partnum 2; " \
participants (2)
-
Sebastian Reichel
-
Tom Rini