diff options
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | arch/sandbox/dts/sandbox.dts | 1 | ||||
-rw-r--r-- | arch/sandbox/dts/sandbox64.dts | 1 | ||||
-rw-r--r-- | arch/sandbox/dts/test.dts | 34 | ||||
-rw-r--r-- | board/sandbox/sandbox.env | 4 | ||||
-rw-r--r-- | configs/sandbox64_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_flattree_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_noinst_defconfig | 1 | ||||
-rw-r--r-- | configs/sandbox_spl_defconfig | 3 | ||||
-rw-r--r-- | doc/api/index.rst | 1 | ||||
-rw-r--r-- | doc/api/nvmem.rst | 10 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 16 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/i2c_eeprom.c | 3 | ||||
-rw-r--r-- | drivers/misc/i2c_eeprom_emul.c | 4 | ||||
-rw-r--r-- | drivers/misc/misc_sandbox.c | 3 | ||||
-rw-r--r-- | drivers/misc/nvmem.c | 142 | ||||
-rw-r--r-- | drivers/net/sandbox.c | 10 | ||||
-rw-r--r-- | drivers/rtc/i2c_rtc_emul.c | 10 | ||||
-rw-r--r-- | include/i2c_eeprom.h | 27 | ||||
-rw-r--r-- | include/nvmem.h | 134 | ||||
-rw-r--r-- | net/dsa-uclass.c | 6 | ||||
-rw-r--r-- | net/eth-uclass.c | 13 | ||||
-rw-r--r-- | test/dm/eth.c | 29 | ||||
-rw-r--r-- | test/dm/test-fdt.c | 2 |
26 files changed, 436 insertions, 29 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 28e4d382386..4ccefb7a11c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1091,6 +1091,13 @@ F: cmd/nvme.c F: include/nvme.h F: doc/develop/driver-model/nvme.rst +NVMEM +M: Sean Anderson <seanga2@gmail.com> +S: Maintained +F: doc/api/nvmem.rst +F: drivers/misc/nvmem.c +F: include/nvmem.h + NXP C45 TJA11XX PHY DRIVER M: Radu Pirea <radu-nicolae.pirea@oss.nxp.com> S: Maintained diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 18fde1c8c6f..21f00fcab5e 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -63,7 +63,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 00]; }; host-fs { diff --git a/arch/sandbox/dts/sandbox64.dts b/arch/sandbox/dts/sandbox64.dts index ec53106af9d..3eb04570891 100644 --- a/arch/sandbox/dts/sandbox64.dts +++ b/arch/sandbox/dts/sandbox64.dts @@ -58,7 +58,6 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x0 0x10002000 0x0 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 00]; }; i2c_0: i2c@0 { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8f93775ff4a..e068d0c8c56 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -28,6 +28,9 @@ ethernet3 = ð_3; ethernet4 = &dsa_eth0; ethernet5 = ð_5; + ethernet6 = "/eth@10004000"; + ethernet7 = &swp_1; + ethernet8 = &phy_eth0; gpio1 = &gpio_a; gpio2 = &gpio_b; gpio3 = &gpio_c; @@ -524,31 +527,31 @@ eth@10002000 { compatible = "sandbox,eth"; reg = <0x10002000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 00]; }; eth_5: eth@10003000 { compatible = "sandbox,eth"; reg = <0x10003000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 11]; + nvmem-cells = <ð5_addr>; + nvmem-cell-names = "mac-address"; }; eth_3: sbe5 { compatible = "sandbox,eth"; reg = <0x10005000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 33]; + nvmem-cells = <ð3_addr>; + nvmem-cell-names = "mac-address"; }; eth@10004000 { compatible = "sandbox,eth"; reg = <0x10004000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 22]; }; phy_eth0: phy-test-eth { compatible = "sandbox,eth"; reg = <0x10007000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 77]; + mac-address = [ 02 00 11 22 33 49 ]; phy-handle = <ðphy1>; phy-mode = "2500base-x"; }; @@ -556,7 +559,8 @@ dsa_eth0: dsa-test-eth { compatible = "sandbox,eth"; reg = <0x10006000 0x1000>; - fake-host-hwaddr = [00 00 66 44 22 66]; + nvmem-cells = <ð4_addr>; + nvmem-cell-names = "mac-address"; }; dsa-test { @@ -700,6 +704,8 @@ pinctrl-0 = <&pinmux_i2c0_pins>; eeprom@2c { + #address-cells = <1>; + #size-cells = <1>; reg = <0x2c>; compatible = "i2c-eeprom"; sandbox,emul = <&emul_eeprom>; @@ -711,12 +717,22 @@ reg = <10 2>; }; }; + + eth3_addr: mac-address@24 { + reg = <24 6>; + }; }; rtc_0: rtc@43 { + #address-cells = <1>; + #size-cells = <1>; reg = <0x43>; compatible = "sandbox-rtc"; sandbox,emul = <&emul0>; + + eth4_addr: mac-address@40 { + reg = <0x40 6>; + }; }; rtc_1: rtc@61 { @@ -898,7 +914,13 @@ }; misc-test { + #address-cells = <1>; + #size-cells = <1>; compatible = "sandbox,misc_sandbox"; + + eth5_addr: mac-address@10 { + reg = <0x10 6>; + }; }; mmc2 { diff --git a/board/sandbox/sandbox.env b/board/sandbox/sandbox.env index b4c04635a48..a2c19702d64 100644 --- a/board/sandbox/sandbox.env +++ b/board/sandbox/sandbox.env @@ -6,10 +6,6 @@ stdout=serial,vidconsole stderr=serial,vidconsole ethaddr=02:00:11:22:33:44 -eth2addr=02:00:11:22:33:48 -eth3addr=02:00:11:22:33:45 -eth4addr=02:00:11:22:33:48 -eth5addr=02:00:11:22:33:46 eth6addr=02:00:11:22:33:47 ipaddr=192.0.2.1 diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index d7f22b39ae5..fc7e100eaaf 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -144,6 +144,7 @@ CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y CONFIG_MISC=y +CONFIG_NVMEM=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index c509a924e6b..d10cd289884 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -188,6 +188,7 @@ CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y CONFIG_MISC=y +CONFIG_NVMEM=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 80a4be47eba..6eb4e348a26 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -117,6 +117,7 @@ CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y CONFIG_MISC=y +CONFIG_NVMEM=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig index c718374ed58..9ee70c29c1a 100644 --- a/configs/sandbox_noinst_defconfig +++ b/configs/sandbox_noinst_defconfig @@ -144,6 +144,7 @@ CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y CONFIG_MISC=y +CONFIG_NVMEM=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 45a6b81a3d2..ec2d26d4436 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -145,6 +145,8 @@ CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y CONFIG_MISC=y +CONFIG_NVMEM=y +CONFIG_SPL_NVMEM=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y @@ -153,6 +155,7 @@ CONFIG_CROS_EC_SPI=y CONFIG_P2SB=y CONFIG_PWRSEQ=y CONFIG_SPL_PWRSEQ=y +CONFIG_I2C_EEPROM=y CONFIG_MMC_SANDBOX=y CONFIG_SPI_FLASH_SANDBOX=y CONFIG_SPI_FLASH_ATMEL=y diff --git a/doc/api/index.rst b/doc/api/index.rst index 72fea981b72..a9338cfef9f 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -14,6 +14,7 @@ U-Boot API documentation linker_lists lmb logging + nvmem pinctrl rng sandbox diff --git a/doc/api/nvmem.rst b/doc/api/nvmem.rst new file mode 100644 index 00000000000..d9237846524 --- /dev/null +++ b/doc/api/nvmem.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +NVMEM API +========= + +.. kernel-doc:: include/nvmem.h + :doc: Design + +.. kernel-doc:: include/nvmem.h + :internal: diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 419ddd31c0b..f368d52c561 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -43,6 +43,22 @@ config VPL_MISC set of generic read, write and ioctl methods may be used to access the device. +config NVMEM + bool "NVMEM support" + help + This adds support for a common interface to different types of + non-volatile memory. Consumers can use nvmem-cells properties to look + up hardware configuration data such as MAC addresses and calibration + settings. + +config SPL_NVMEM + bool "NVMEM support in SPL" + help + This adds support for a common interface to different types of + non-volatile memory. Consumers can use nvmem-cells properties to look + up hardware configuration data such as MAC addresses and calibration + settings. + config ALTERA_SYSID bool "Altera Sysid support" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7a6047f64f9..6c790308937 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -4,6 +4,7 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-$(CONFIG_$(SPL_TPL_)MISC) += misc-uclass.o +obj-$(CONFIG_$(SPL_TPL_)NVMEM) += nvmem.o obj-$(CONFIG_$(SPL_TPL_)CROS_EC) += cros_ec.o obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index 89a450d0f8d..4302e180acd 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -33,7 +33,8 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size) return ops->read(dev, offset, buf, size); } -int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size) +int i2c_eeprom_write(struct udevice *dev, int offset, const uint8_t *buf, + int size) { const struct i2c_eeprom_ops *ops = device_get_ops(dev); diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c index 85b127c406c..6f32087ede5 100644 --- a/drivers/misc/i2c_eeprom_emul.c +++ b/drivers/misc/i2c_eeprom_emul.c @@ -171,11 +171,15 @@ static int sandbox_i2c_eeprom_probe(struct udevice *dev) { struct sandbox_i2c_flash_plat_data *plat = dev_get_plat(dev); struct sandbox_i2c_flash *priv = dev_get_priv(dev); + /* For eth3 */ + const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x45 }; priv->data = calloc(1, plat->size); if (!priv->data) return -ENOMEM; + memcpy(&priv->data[24], mac, sizeof(mac)); + return 0; } diff --git a/drivers/misc/misc_sandbox.c b/drivers/misc/misc_sandbox.c index 0e4292fd0aa..31cde2dbac0 100644 --- a/drivers/misc/misc_sandbox.c +++ b/drivers/misc/misc_sandbox.c @@ -112,8 +112,11 @@ static const struct misc_ops misc_sandbox_ops = { int misc_sandbox_probe(struct udevice *dev) { struct misc_sandbox_priv *priv = dev_get_priv(dev); + /* For eth5 */ + const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x46 }; priv->enabled = true; + memcpy(&priv->mem[16], mac, sizeof(mac)); return 0; } diff --git a/drivers/misc/nvmem.c b/drivers/misc/nvmem.c new file mode 100644 index 00000000000..5a2bd1f9f72 --- /dev/null +++ b/drivers/misc/nvmem.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com> + */ + +#include <common.h> +#include <i2c_eeprom.h> +#include <linker_lists.h> +#include <misc.h> +#include <nvmem.h> +#include <rtc.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <dm/read.h> +#include <dm/uclass.h> + +int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size) +{ + dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size); + if (size != cell->size) + return -EINVAL; + + switch (cell->nvmem->driver->id) { + case UCLASS_I2C_EEPROM: + return i2c_eeprom_read(cell->nvmem, cell->offset, buf, size); + case UCLASS_MISC: { + int ret = misc_read(cell->nvmem, cell->offset, buf, size); + + if (ret < 0) + return ret; + if (ret != size) + return -EIO; + return 0; + } + case UCLASS_RTC: + return dm_rtc_read(cell->nvmem, cell->offset, buf, size); + default: + return -ENOSYS; + } +} + +int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size) +{ + dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size); + if (size != cell->size) + return -EINVAL; + + switch (cell->nvmem->driver->id) { + case UCLASS_I2C_EEPROM: + return i2c_eeprom_write(cell->nvmem, cell->offset, buf, size); + case UCLASS_MISC: { + int ret = misc_write(cell->nvmem, cell->offset, buf, size); + + if (ret < 0) + return ret; + if (ret != size) + return -EIO; + return 0; + } + case UCLASS_RTC: + return dm_rtc_write(cell->nvmem, cell->offset, buf, size); + default: + return -ENOSYS; + } +} + +/** + * nvmem_get_device() - Get an nvmem device for a cell + * @node: ofnode of the nvmem device + * @cell: Cell to look up + * + * Try to find a nvmem-compatible device by going through the nvmem interfaces. + * + * Return: + * * 0 on success + * * -ENODEV if we didn't find anything + * * A negative error if there was a problem looking up the device + */ +static int nvmem_get_device(ofnode node, struct nvmem_cell *cell) +{ + int i, ret; + enum uclass_id ids[] = { + UCLASS_I2C_EEPROM, + UCLASS_MISC, + UCLASS_RTC, + }; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + ret = uclass_get_device_by_ofnode(ids[i], node, &cell->nvmem); + if (!ret) + return 0; + if (ret != -ENODEV && ret != -EPFNOSUPPORT) + return ret; + } + + return -ENODEV; +} + +int nvmem_cell_get_by_index(struct udevice *dev, int index, + struct nvmem_cell *cell) +{ + fdt_addr_t offset; + fdt_size_t size = FDT_SIZE_T_NONE; + int ret; + struct ofnode_phandle_args args; + + dev_dbg(dev, "%s: index=%d\n", __func__, index); + + ret = dev_read_phandle_with_args(dev, "nvmem-cells", NULL, 0, index, + &args); + if (ret) + return ret; + + ret = nvmem_get_device(ofnode_get_parent(args.node), cell); + if (ret) + return ret; + + offset = ofnode_get_addr_size_index_notrans(args.node, 0, &size); + if (offset == FDT_ADDR_T_NONE || size == FDT_SIZE_T_NONE) { + dev_dbg(cell->nvmem, "missing address or size for %s\n", + ofnode_get_name(args.node)); + return -EINVAL; + } + + cell->offset = offset; + cell->size = size; + return 0; +} + +int nvmem_cell_get_by_name(struct udevice *dev, const char *name, + struct nvmem_cell *cell) +{ + int index; + + dev_dbg(dev, "%s, name=%s\n", __func__, name); + + index = dev_read_stringlist_search(dev, "nvmem-cell-names", name); + if (index < 0) + return index; + + return nvmem_cell_get_by_index(dev, index, cell); +} diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 37459dfa0a4..13022addb6a 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -395,9 +395,11 @@ static void sb_eth_stop(struct udevice *dev) static int sb_eth_write_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); + struct eth_sandbox_priv *priv = dev_get_priv(dev); debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, pdata->enetaddr); + memcpy(priv->fake_host_hwaddr, pdata->enetaddr, ARP_HLEN); return 0; } @@ -419,16 +421,8 @@ static int sb_eth_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct eth_sandbox_priv *priv = dev_get_priv(dev); - const u8 *mac; pdata->iobase = dev_read_addr(dev); - - mac = dev_read_u8_array_ptr(dev, "fake-host-hwaddr", ARP_HLEN); - if (!mac) { - printf("'fake-host-hwaddr' is missing from the DT\n"); - return -EINVAL; - } - memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN); priv->disabled = false; priv->tx_handler = sb_default_handler; diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index ba418c25daf..c307d6036dd 100644 --- a/drivers/rtc/i2c_rtc_emul.c +++ b/drivers/rtc/i2c_rtc_emul.c @@ -203,6 +203,15 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev) return 0; } +static int sandbox_i2c_rtc_probe(struct udevice *dev) +{ + const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x48 }; + struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev); + + memcpy(&plat->reg[0x40], mac, sizeof(mac)); + return 0; +} + static const struct udevice_id sandbox_i2c_rtc_ids[] = { { .compatible = "sandbox,i2c-rtc-emul" }, { } @@ -213,6 +222,7 @@ U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = { .id = UCLASS_I2C_EMUL, .of_match = sandbox_i2c_rtc_ids, .bind = sandbox_i2c_rtc_bind, + .probe = sandbox_i2c_rtc_probe, .priv_auto = sizeof(struct sandbox_i2c_rtc), .plat_auto = sizeof(struct sandbox_i2c_rtc_plat_data), .ops = &sandbox_i2c_rtc_emul_ops, diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h index 3ad565684fe..32dcb034973 100644 --- a/include/i2c_eeprom.h +++ b/include/i2c_eeprom.h @@ -6,6 +6,8 @@ #ifndef __I2C_EEPROM #define __I2C_EEPROM +struct udevice; + 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, @@ -20,6 +22,7 @@ struct i2c_eeprom { unsigned long size; }; +#if CONFIG_IS_ENABLED(I2C_EEPROM) /* * i2c_eeprom_read() - read bytes from an I2C EEPROM chip * @@ -42,7 +45,8 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size); * * Return: 0 on success, -ve on failure */ -int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size); +int i2c_eeprom_write(struct udevice *dev, int offset, const uint8_t *buf, + int size); /* * i2c_eeprom_size() - get size of I2C EEPROM chip @@ -53,4 +57,25 @@ int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size); */ int i2c_eeprom_size(struct udevice *dev); +#else /* !I2C_EEPROM */ + +static inline int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, + int size) +{ + return -ENOSYS; +} + +static inline int i2c_eeprom_write(struct udevice *dev, int offset, + const uint8_t *buf, int size) +{ + return -ENOSYS; +} + +static inline int i2c_eeprom_size(struct udevice *dev) +{ + return -ENOSYS; +} + +#endif /* I2C_EEPROM */ + #endif diff --git a/include/nvmem.h b/include/nvmem.h new file mode 100644 index 00000000000..822e698bdd4 --- /dev/null +++ b/include/nvmem.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2022 Sean Anderson <sean.anderson@seco.com> + */ + +#ifndef NVMEM_H +#define NVMEM_H + +/** + * DOC: Design + * + * The NVMEM subsystem is a "meta-uclass" in that it abstracts over several + * different uclasses all with read/write APIs. One approach to implementing + * this could be to add a new sub-device for each nvmem-style device of + * UCLASS_NVMEM. This subsystem has taken the approach of using the existing + * access methods (i2c_eeprom_write, misc_write, etc.) directly. This has the + * advantage of not requiring an extra device/driver, saving on binary size and + * runtime memory usage. On the other hand, it is not idiomatic. Similar + * efforts should generally use a new uclass. + */ + +/** + * struct nvmem_cell - One datum within non-volatile memory + * @nvmem: The backing storage device + * @offset: The offset of the cell from the start of @nvmem + * @size: The size of the cell, in bytes + */ +struct nvmem_cell { + struct udevice *nvmem; + unsigned int offset; + size_t size; +}; + +struct udevice; + +#if CONFIG_IS_ENABLED(NVMEM) + +/** + * nvmem_cell_read() - Read the value of an nvmem cell + * @cell: The nvmem cell to read + * @buf: The buffer to read into + * @size: The size of @buf + * + * Return: + * * 0 on success + * * -EINVAL if @buf is not the same size as @cell. + * * -ENOSYS if CONFIG_NVMEM is disabled + * * A negative error if there was a problem reading the underlying storage + */ +int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size); + +/** + * nvmem_cell_write() - Write a value to an nvmem cell + * @cell: The nvmem cell to write + * @buf: The buffer to write from + * @size: The size of @buf + * + * Return: + * * 0 on success + * * -EINVAL if @buf is not the same size as @cell + * * -ENOSYS if @cell is read-only, or if CONFIG_NVMEM is disabled + * * A negative error if there was a problem writing the underlying storage + */ +int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size); + +/** + * nvmem_cell_get_by_index() - Get an nvmem cell from a given device and index + * @dev: The device that uses the nvmem cell + * @index: The index of the cell in nvmem-cells + * @cell: The cell to initialize + * + * Look up the nvmem cell referenced by the phandle at @index in nvmem-cells in + * @dev. + * + * Return: + * * 0 on success + * * -EINVAL if the regs property is missing, empty, or undersized + * * -ENODEV if the nvmem device is missing or unimplemented + * * -ENOSYS if CONFIG_NVMEM is disabled + * * A negative error if there was a problem reading nvmem-cells or getting the + * device + */ +int nvmem_cell_get_by_index(struct udevice *dev, int index, + struct nvmem_cell *cell); + +/** + * nvmem_cell_get_by_name() - Get an nvmem cell from a given device and name + * @dev: The device that uses the nvmem cell + * @name: The name of the nvmem cell + * @cell: The cell to initialize + * + * Look up the nvmem cell referenced by @name in the nvmem-cell-names property + * of @dev. + * + * Return: + * * 0 on success + * * -EINVAL if the regs property is missing, empty, or undersized + * * -ENODEV if the nvmem device is missing or unimplemented + * * -ENODATA if @name is not in nvmem-cell-names + * * -ENOSYS if CONFIG_NVMEM is disabled + * * A negative error if there was a problem reading nvmem-cell-names, + * nvmem-cells, or getting the device + */ +int nvmem_cell_get_by_name(struct udevice *dev, const char *name, + struct nvmem_cell *cell); + +#else /* CONFIG_NVMEM */ + +static inline int nvmem_cell_read(struct nvmem_cell *cell, void *buf, int size) +{ + return -ENOSYS; +} + +static inline int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, + int size) +{ + return -ENOSYS; +} + +static inline int nvmem_cell_get_by_index(struct udevice *dev, int index, + struct nvmem_cell *cell) +{ + return -ENOSYS; +} + +static inline int nvmem_cell_get_by_name(struct udevice *dev, const char *name, + struct nvmem_cell *cell) +{ + return -ENOSYS; +} + +#endif /* CONFIG_NVMEM */ + +#endif /* NVMEM_H */ diff --git a/net/dsa-uclass.c b/net/dsa-uclass.c index 9ff55a02fb2..3bf4351c847 100644 --- a/net/dsa-uclass.c +++ b/net/dsa-uclass.c @@ -477,8 +477,10 @@ static int dsa_pre_probe(struct udevice *dev) return -ENODEV; } - uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node, - &priv->master_dev); + err = uclass_get_device_by_ofnode(UCLASS_ETH, pdata->master_node, + &priv->master_dev); + if (err) + return err; /* Simulate a probing event for the CPU port */ if (ops->port_probe) { diff --git a/net/eth-uclass.c b/net/eth-uclass.c index bcefc54ded8..0f6b45b002c 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -14,6 +14,7 @@ #include <env.h> #include <log.h> #include <net.h> +#include <nvmem.h> #include <asm/global_data.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> @@ -507,17 +508,21 @@ static bool eth_dev_get_mac_address(struct udevice *dev, u8 mac[ARP_HLEN]) { #if CONFIG_IS_ENABLED(OF_CONTROL) const uint8_t *p; + struct nvmem_cell mac_cell; p = dev_read_u8_array_ptr(dev, "mac-address", ARP_HLEN); if (!p) p = dev_read_u8_array_ptr(dev, "local-mac-address", ARP_HLEN); - if (!p) - return false; + if (p) { + memcpy(mac, p, ARP_HLEN); + return true; + } - memcpy(mac, p, ARP_HLEN); + if (nvmem_cell_get_by_name(dev, "mac-address", &mac_cell)) + return false; - return true; + return !nvmem_cell_read(&mac_cell, mac, ARP_HLEN); #else return false; #endif diff --git a/test/dm/eth.c b/test/dm/eth.c index e4ee6956106..5437f9ea4a0 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -147,6 +147,35 @@ static int dm_test_eth_act(struct unit_test_state *uts) } DM_TEST(dm_test_eth_act, UT_TESTF_SCAN_FDT); +/* Ensure that all addresses are loaded properly */ +static int dm_test_ethaddr(struct unit_test_state *uts) +{ + static const char *const addr[] = { + "02:00:11:22:33:44", + "02:00:11:22:33:48", /* dsa slave */ + "02:00:11:22:33:45", + "02:00:11:22:33:48", /* dsa master */ + "02:00:11:22:33:46", + "02:00:11:22:33:47", + "02:00:11:22:33:48", /* dsa slave */ + "02:00:11:22:33:49", + }; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + char addrname[10]; + + if (i) + snprintf(addrname, sizeof(addrname), "eth%daddr", i + 1); + else + strcpy(addrname, "ethaddr"); + ut_asserteq_str(addr[i], env_get(addrname)); + } + + return 0; +} +DM_TEST(dm_test_ethaddr, UT_TESTF_SCAN_FDT); + /* The asserts include a return on fail; cleanup in the caller */ static int _dm_test_eth_rotate1(struct unit_test_state *uts) { diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index e1de066226c..f9e81747595 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -184,7 +184,7 @@ static int dm_test_alias_highest_id(struct unit_test_state *uts) int ret; ret = dev_read_alias_highest_id("ethernet"); - ut_asserteq(5, ret); + ut_asserteq(8, ret); ret = dev_read_alias_highest_id("gpio"); ut_asserteq(3, ret); |