[U-Boot] [PATCH 0/2] misc: i2c_eeprom: add paritioning and size query

Add ability to specify paritions for eeprom in device tree, and query eeprom device sizes. Each partition creates a child device, allowing board code to find the eeprom parition by name.
Robert Beckett (2): misc: i2c_eeprom: add fixed partitions support misc: i2c_eeprom: add size query
drivers/misc/i2c_eeprom.c | 243 +++++++++++++++++++++++++++++++++++--- include/i2c_eeprom.h | 12 ++ 2 files changed, 236 insertions(+), 19 deletions(-)

Add ability to partition eeprom via devicetree bindings
Signed-off-by: Robert Beckett bob.beckett@collabora.com ---
drivers/misc/i2c_eeprom.c | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index 8f2349ad5a..7add8fcc0f 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -7,6 +7,7 @@ #include <linux/err.h> #include <linux/kernel.h> #include <dm.h> +#include <dm/device-internal.h> #include <i2c.h> #include <i2c_eeprom.h>
@@ -82,6 +83,29 @@ static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) return 0; }
+static int i2c_eeprom_std_bind(struct udevice *dev) +{ + ofnode partitions = ofnode_find_subnode(dev_ofnode(dev), "partitions"); + ofnode partition; + const char *name; + + if (!ofnode_valid(partitions)) + return 0; + if (!ofnode_device_is_compatible(partitions, "fixed-partitions")) + return -ENOTSUPP; + + ofnode_for_each_subnode(partition, partitions) { + name = ofnode_get_name(partition); + if (!name) + continue; + + device_bind_ofnode(dev, DM_GET_DRIVER(i2c_eeprom_partition), + name, NULL, partition, NULL); + } + + return 0; +} + static int i2c_eeprom_std_probe(struct udevice *dev) { u8 test_byte; @@ -117,12 +141,86 @@ U_BOOT_DRIVER(i2c_eeprom_std) = { .name = "i2c_eeprom", .id = UCLASS_I2C_EEPROM, .of_match = i2c_eeprom_std_ids, + .bind = i2c_eeprom_std_bind, .probe = i2c_eeprom_std_probe, .ofdata_to_platdata = i2c_eeprom_std_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_eeprom), .ops = &i2c_eeprom_std_ops, };
+struct i2c_eeprom_partition { + u32 offset; + u32 size; +}; + +static int i2c_eeprom_partition_probe(struct udevice *dev) +{ + return 0; +} + +static int i2c_eeprom_partition_ofdata_to_platdata(struct udevice *dev) +{ + struct i2c_eeprom_partition *priv = dev_get_priv(dev); + u32 offset, size; + int ret; + + ret = dev_read_u32(dev, "offset", &offset); + if (ret) + return ret; + + ret = dev_read_u32(dev, "size", &size); + if (ret) + return ret; + + priv->offset = offset; + priv->size = size; + + return 0; +} + +static int i2c_eeprom_partition_read(struct udevice *dev, int offset, + u8 *buf, int size) +{ + struct i2c_eeprom_partition *priv = dev_get_priv(dev); + struct udevice *parent = dev_get_parent(dev); + + if (!parent) + return -ENODEV; + if (offset + size > priv->size) + return -EINVAL; + + return i2c_eeprom_read(parent, offset + priv->offset, buf, size); +} + +static int i2c_eeprom_partition_write(struct udevice *dev, int offset, + const u8 *buf, int size) +{ + struct i2c_eeprom_partition *priv = dev_get_priv(dev); + struct udevice *parent = dev_get_parent(dev); + + if (!parent) + return -ENODEV; + if (offset + size > priv->size) + return -EINVAL; + + return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf, + size); +} + +static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = { + .read = i2c_eeprom_partition_read, + .write = i2c_eeprom_partition_write, +}; + +U_BOOT_DRIVER(i2c_eeprom_partition) = { + .name = "i2c_eeprom_partition", + .id = UCLASS_I2C_EEPROM, + .probe = i2c_eeprom_partition_probe, + .ofdata_to_platdata = i2c_eeprom_partition_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct i2c_eeprom_partition), + .ops = &i2c_eeprom_partition_ops, +}; + UCLASS_DRIVER(i2c_eeprom) = { .id = UCLASS_I2C_EEPROM, .name = "i2c_eeprom",

Add ability to query size of eeprom device and partitions
Signed-off-by: Robert Beckett bob.beckett@collabora.com ---
drivers/misc/i2c_eeprom.c | 145 +++++++++++++++++++++++++++++++++----- include/i2c_eeprom.h | 12 ++++ 2 files changed, 138 insertions(+), 19 deletions(-)
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index 7add8fcc0f..c948ed937a 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -11,6 +11,11 @@ #include <i2c.h> #include <i2c_eeprom.h>
+struct i2c_eeprom_drv_data { + u32 size; /* size in bytes */ + u32 pagewidth; /* pagesize = 2^pagewidth */ +}; + int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size) { const struct i2c_eeprom_ops *ops = device_get_ops(dev); @@ -31,6 +36,16 @@ int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size) return ops->write(dev, offset, buf, size); }
+int i2c_eeprom_size(struct udevice *dev) +{ + const struct i2c_eeprom_ops *ops = device_get_ops(dev); + + if (!ops->size) + return -ENOSYS; + + return ops->size(dev); +} + static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf, int size) { @@ -60,25 +75,39 @@ static int i2c_eeprom_std_write(struct udevice *dev, int offset, return 0; }
+static int i2c_eeprom_std_size(struct udevice *dev) +{ + struct i2c_eeprom *priv = dev_get_priv(dev); + + return priv->size; +} + static const struct i2c_eeprom_ops i2c_eeprom_std_ops = { .read = i2c_eeprom_std_read, .write = i2c_eeprom_std_write, + .size = i2c_eeprom_std_size, };
static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) { struct i2c_eeprom *priv = dev_get_priv(dev); - u64 data = dev_get_driver_data(dev); + struct i2c_eeprom_drv_data *data = + (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev); u32 pagesize; + u32 size;
if (dev_read_u32(dev, "pagesize", &pagesize) == 0) { priv->pagesize = pagesize; - return 0; + } else { + /* 6 bit -> page size of up to 2^63 (should be sufficient) */ + priv->pagewidth = data->pagewidth; + priv->pagesize = (1 << priv->pagewidth); }
- /* 6 bit -> page size of up to 2^63 (should be sufficient) */ - priv->pagewidth = data & 0x3F; - priv->pagesize = (1 << priv->pagewidth); + if (dev_read_u32(dev, "size", &size) == 0) + priv->size = size; + else + priv->size = data->size;
return 0; } @@ -119,21 +148,91 @@ static int i2c_eeprom_std_probe(struct udevice *dev) return 0; }
+static const struct i2c_eeprom_drv_data eeprom_data = { + .size = 0, + .pagewidth = 0, +}; + +static const struct i2c_eeprom_drv_data mc24aa02e48_data = { + .size = 256, + .pagewidth = 3, +}; + +static const struct i2c_eeprom_drv_data atmel24c01a_data = { + .size = 128, + .pagewidth = 3, +}; + +static const struct i2c_eeprom_drv_data atmel24c02_data = { + .size = 256, + .pagewidth = 3, +}; + +static const struct i2c_eeprom_drv_data atmel24c04_data = { + .size = 512, + .pagewidth = 4, +}; + +static const struct i2c_eeprom_drv_data atmel24c08_data = { + .size = 1024, + .pagewidth = 4, +}; + +static const struct i2c_eeprom_drv_data atmel24c08a_data = { + .size = 1024, + .pagewidth = 4, +}; + +static const struct i2c_eeprom_drv_data atmel24c16a_data = { + .size = 2048, + .pagewidth = 4, +}; + +static const struct i2c_eeprom_drv_data atmel24mac402_data = { + .size = 256, + .pagewidth = 4, +}; + +static const struct i2c_eeprom_drv_data atmel24c32_data = { + .size = 4096, + .pagewidth = 5, +}; + +static const struct i2c_eeprom_drv_data atmel24c64_data = { + .size = 8192, + .pagewidth = 5, +}; + +static const struct i2c_eeprom_drv_data atmel24c128_data = { + .size = 16384, + .pagewidth = 6, +}; + +static const struct i2c_eeprom_drv_data atmel24c256_data = { + .size = 32768, + .pagewidth = 6, +}; + +static const struct i2c_eeprom_drv_data atmel24c512_data = { + .size = 65536, + .pagewidth = 6, +}; + static const struct udevice_id i2c_eeprom_std_ids[] = { - { .compatible = "i2c-eeprom", .data = 0 }, - { .compatible = "microchip,24aa02e48", .data = 3 }, - { .compatible = "atmel,24c01a", .data = 3 }, - { .compatible = "atmel,24c02", .data = 3 }, - { .compatible = "atmel,24c04", .data = 4 }, - { .compatible = "atmel,24c08", .data = 4 }, - { .compatible = "atmel,24c08a", .data = 4 }, - { .compatible = "atmel,24c16a", .data = 4 }, - { .compatible = "atmel,24mac402", .data = 4 }, - { .compatible = "atmel,24c32", .data = 5 }, - { .compatible = "atmel,24c64", .data = 5 }, - { .compatible = "atmel,24c128", .data = 6 }, - { .compatible = "atmel,24c256", .data = 6 }, - { .compatible = "atmel,24c512", .data = 6 }, + { .compatible = "i2c-eeprom", (ulong)&eeprom_data }, + { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data }, + { .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data }, + { .compatible = "atmel,24c02", (ulong)&atmel24c02_data }, + { .compatible = "atmel,24c04", (ulong)&atmel24c04_data }, + { .compatible = "atmel,24c08", (ulong)&atmel24c08_data }, + { .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data }, + { .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data }, + { .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data }, + { .compatible = "atmel,24c32", (ulong)&atmel24c32_data }, + { .compatible = "atmel,24c64", (ulong)&atmel24c64_data }, + { .compatible = "atmel,24c128", (ulong)&atmel24c128_data }, + { .compatible = "atmel,24c256", (ulong)&atmel24c256_data }, + { .compatible = "atmel,24c512", (ulong)&atmel24c512_data }, { } };
@@ -207,9 +306,17 @@ static int i2c_eeprom_partition_write(struct udevice *dev, int offset, size); }
+static int i2c_eeprom_partition_size(struct udevice *dev) +{ + struct i2c_eeprom_partition *priv = dev_get_priv(dev); + + return priv->size; +} + static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = { .read = i2c_eeprom_partition_read, .write = i2c_eeprom_partition_write, + .size = i2c_eeprom_partition_size, };
U_BOOT_DRIVER(i2c_eeprom_partition) = { diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h index 0fcdf3831b..b96254ae79 100644 --- a/include/i2c_eeprom.h +++ b/include/i2c_eeprom.h @@ -10,6 +10,7 @@ struct i2c_eeprom_ops { int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size); int (*write)(struct udevice *dev, int offset, const uint8_t *buf, int size); + int (*size)(struct udevice *dev); };
struct i2c_eeprom { @@ -17,6 +18,8 @@ struct i2c_eeprom { unsigned long pagesize; /* The EEPROM's page width in bits (pagesize = 2^pagewidth) */ unsigned pagewidth; + /* The EEPROM's capacity in bytes */ + unsigned long size; };
/* @@ -43,4 +46,13 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size); */ int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size);
+/* + * i2c_eeprom_size() - get size of I2C EEPROM chip + * + * @dev: Chip to query + * + * @return +ve size in bytes on success, -ve on failure + */ +int i2c_eeprom_size(struct udevice *dev); + #endif

Hello Robert,
Am 28.10.2019 um 19:29 schrieb Robert Beckett:
Add ability to query size of eeprom device and partitions
Signed-off-by: Robert Beckett bob.beckett@collabora.com
drivers/misc/i2c_eeprom.c | 145 +++++++++++++++++++++++++++++++++----- include/i2c_eeprom.h | 12 ++++ 2 files changed, 138 insertions(+), 19 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko

Hello Robert,
Am 28.10.2019 um 19:29 schrieb Robert Beckett:
Add ability to query size of eeprom device and partitions
Signed-off-by: Robert Beckett bob.beckett@collabora.com
drivers/misc/i2c_eeprom.c | 145 +++++++++++++++++++++++++++++++++----- include/i2c_eeprom.h | 12 ++++ 2 files changed, 138 insertions(+), 19 deletions(-)
Applied to u-boot-i2c next branch.
Thanks!
bye, Heiko

Hello Robert,
Am 28.10.2019 um 19:29 schrieb Robert Beckett:
Add ability to partition eeprom via devicetree bindings
Signed-off-by: Robert Beckett bob.beckett@collabora.com
drivers/misc/i2c_eeprom.c | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
Reviewed-by: Heiko Schocher hs@denx.de
Remark: I just wondering that there is no MTD support for i2c eeproms in MTD (also not in linux) ... okay, flash has blocked base access, while i2c eeprom can have byte accesses ... but does this really is a show stopper for adding i2c eeproms to MTD layer?
You already use the MTD "fixed-partitions" property, which is fine.
May it s worth to look into using mtd layer also for i2c eeproms?
bye, Heiko

Hello Robert,
Am 28.10.2019 um 19:29 schrieb Robert Beckett:
Add ability to partition eeprom via devicetree bindings
Signed-off-by: Robert Beckett bob.beckett@collabora.com
drivers/misc/i2c_eeprom.c | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
Applied to u-boot-i2c next branch.
Thanks!
bye, Heiko

HI Robert and Heiko,
po 28. 10. 2019 v 19:32 odesílatel Robert Beckett bob.beckett@collabora.com napsal:
Add ability to specify paritions for eeprom in device tree, and query eeprom device sizes. Each partition creates a child device, allowing board code to find the eeprom parition by name.
Robert Beckett (2): misc: i2c_eeprom: add fixed partitions support misc: i2c_eeprom: add size query
drivers/misc/i2c_eeprom.c | 243 +++++++++++++++++++++++++++++++++++--- include/i2c_eeprom.h | 12 ++ 2 files changed, 236 insertions(+), 19 deletions(-)
What's the recommended way to work with i2c_eeprom_partitions?
I have them probed but curious how I should work with them. i2c 1 [ + ] i2c_mux_bus_drv | | |-- i2c@ff030000->i2c-mux@74->i2c@0 i2c_eeprom 0 [ + ] i2c_eeprom | | | `-- eeprom@54 i2c_eeprom 1 [ ] i2c_eeprom_partition | | | |-- board-sn@0 i2c_eeprom 2 [ ] i2c_eeprom_partition | | | |-- eth-mac@20 i2c_eeprom 3 [ ] i2c_eeprom_partition | | | |-- board-name@d0 i2c_eeprom 4 [ ] i2c_eeprom_partition | | | `-- board-revision@e0
Is there any u-boot command for reading values from these partitions? Or are you just referencing them by fdt_path_offset/uclass_get_device_by_of_offset?
Thanks, Michal

On 28. 05. 20 11:27, Michal Simek wrote:
HI Robert and Heiko,
po 28. 10. 2019 v 19:32 odesílatel Robert Beckett bob.beckett@collabora.com napsal:
Add ability to specify paritions for eeprom in device tree, and query eeprom device sizes. Each partition creates a child device, allowing board code to find the eeprom parition by name.
Robert Beckett (2): misc: i2c_eeprom: add fixed partitions support misc: i2c_eeprom: add size query
drivers/misc/i2c_eeprom.c | 243 +++++++++++++++++++++++++++++++++++--- include/i2c_eeprom.h | 12 ++ 2 files changed, 236 insertions(+), 19 deletions(-)
What's the recommended way to work with i2c_eeprom_partitions?
I have them probed but curious how I should work with them. i2c 1 [ + ] i2c_mux_bus_drv | | |-- i2c@ff030000->i2c-mux@74->i2c@0 i2c_eeprom 0 [ + ] i2c_eeprom | | | `-- eeprom@54 i2c_eeprom 1 [ ] i2c_eeprom_partition | | | |-- board-sn@0 i2c_eeprom 2 [ ] i2c_eeprom_partition | | | |-- eth-mac@20 i2c_eeprom 3 [ ] i2c_eeprom_partition | | | |-- board-name@d0 i2c_eeprom 4 [ ] i2c_eeprom_partition | | | `-- board-revision@e0
Is there any u-boot command for reading values from these partitions? Or are you just referencing them by fdt_path_offset/uclass_get_device_by_of_offset?
I think I found that path you use.
13 bootcount { 14 compatible = "u-boot,bootcount-i2c-eeprom"; 15 i2c-eeprom = <&bootcount>; 16 };
24 &eeprom { 25 partitions { 26 compatible = "fixed-partitions"; 27 28 vpd { 29 offset = <0>; 30 size = <1022>; 31 }; 32 32 33 bootcount: bootcount { 34 offset = <1022>; 35 size = <2>; 36 }; 37 }; 38 };
I am curious about these offset/size properties which you are using here which are out of dt spec in the kernel. https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/Doc...
Why not just to use reg property which does exactly it?
Anyway and then you use link to bootcount and code in drivers/bootcount/i2c-eeprom.c to read it.
Thanks, Michal
participants (3)
-
Heiko Schocher
-
Michal Simek
-
Robert Beckett