From 22c1813f5ca209549e22954668b9b3f3a5283cd5 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Wed, 28 Aug 2024 09:56:53 -0400 Subject: [PATCH 1/3] devicetree: Add nvmem-consumer Adds property nvmem-cells for referencing a node that stores some configuration information. A typical use case is the reading of MAC address from an EEPROM device. The referenced node is child of the non-volatile memory device. The address of the referenced node stores address/offset where the configuration is stored. Th nvmem-cells phandle could be pointing to a child of an eeprom node or an efuse register. Currently it is upto the devicetree driver to call the correct API for reading the configuration data. Future work could be to write an nvmem-producer driver abstraction that calls correct api for flash/eeprom. Signed-off-by: Andriy Gelman --- dts/bindings/mtd/nvmem-consumer.yaml | 15 +++++ include/zephyr/devicetree/nvmem.h | 97 ++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 dts/bindings/mtd/nvmem-consumer.yaml create mode 100644 include/zephyr/devicetree/nvmem.h diff --git a/dts/bindings/mtd/nvmem-consumer.yaml b/dts/bindings/mtd/nvmem-consumer.yaml new file mode 100644 index 0000000000000..a2fcb40ae72ed --- /dev/null +++ b/dts/bindings/mtd/nvmem-consumer.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024, Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +include: base.yaml + +properties: + nvmem-cell-names: + type: string-array + description: + Names for each nvmem-cells specified. + + nvmem-cells: + type: phandles + description: + List of phandle to the nvmem data cells. diff --git a/include/zephyr/devicetree/nvmem.h b/include/zephyr/devicetree/nvmem.h new file mode 100644 index 0000000000000..41a74cba44f94 --- /dev/null +++ b/include/zephyr/devicetree/nvmem.h @@ -0,0 +1,97 @@ +/** + * @file + * @brief NVMEM Devicetree macro public API header file. + */ + +/* + * Copyright (c) 2024, Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DEVICETREE_NVMEM_H_ +#define INCLUDE_ZEPHYR_DEVICETREE_NVMEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup devicetree-nvmem Devicetree NVMEM API + * @ingroup devicetree + * @{ + */ + +/** + * @brief Get the pointer to the nvmem device from the nvmem-cells property + * + * Example devicetree fragment: + * + * mac_eeprom: mac_eeprom@2 { + * #address-cells = <1>; + * #size-cells = <1>; + * mac_address: mac_address@fa { + * reg = <0xfa 0x06>; + * }; + * }; + * + * eth: ethernet { + * nvmem-cells = <&mac_address>; + * nvmem-cell-names = "mac-address"; + * }; + * + * Example usage: + * + * DT_NVMEM_DEV_BY_IDX(DT_NODELABEL(eth), 0) // DEVICE_DT_GET(DT_NODELABEL(mac_eeprom)) + * + * @param node_id node identifier for a node with nvmem-cells property + * @param idx index into the nvmem-cells proprty + * @return the pointer to the nvmem device at index idx + */ + +#define DT_NVMEM_DEV_BY_IDX(node_id, idx) \ + DEVICE_DT_GET(DT_PARENT(DT_PHANDLE_BY_IDX(node_id, nvmem_cells, idx))) + +/** + * @brief Get the target address referenced by the nvmem-cells property + * + * Example devicetree fragment: + * + * mac_eeprom: mac_eeprom@2 { + * status = "okay"; + * + * #address-cells = <1>; + * #size-cells = <1>; + * + * mac_address: mac_address@fa { + * reg = <0xfa 0x06>; + * }; + * }; + * + * eth: ethernet@ { + * ... + * nvmem-cells = <&mac_address>; + * nvmem-cell-names = "mac-address"; + * ... + * }; + * + * Example usage: + * + * DT_NVMEM_ADDR_BY_IDX(DT_NODELABEL(eth), 0) // 0xfa + * + * @param node_id node identifier for a node with nvmem-cells property + * @param idx index into the nvmem-cells property + * @return the address of the nvmem device where the information is stored + */ + +#define DT_NVMEM_ADDR_BY_IDX(node_id, idx) DT_REG_ADDR(DT_PHANDLE_BY_IDX(node_id, nvmem_cells, idx)) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDE_ZEPHYR_DEVICETREE_NVMEM_H_ */ From aa69f570f975f03ae1ed5323b400961755ab3e33 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Wed, 28 Aug 2024 10:12:22 -0400 Subject: [PATCH 2/3] drivers: eth_xmc4xxx: Use nvmem-cells for reading MAC from eeprom Adds an option to load the MAC address from an external EEPROM chip, for example from Microchip 25AA02E48 (atmel,at25) which come pre-programmed with a unique MAC. The priority for setting the MAC address in the driver is: (1) local-mac-address from devicetree (2) Eeprom address (3) Random address Signed-off-by: Andriy Gelman --- drivers/ethernet/eth_xmc4xxx.c | 32 ++++++++++++++++++- .../ethernet/infineon,xmc4xxx-ethernet.yaml | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_xmc4xxx.c b/drivers/ethernet/eth_xmc4xxx.c index f2197099e27c7..52187d948ced8 100644 --- a/drivers/ethernet/eth_xmc4xxx.c +++ b/drivers/ethernet/eth_xmc4xxx.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -799,6 +801,31 @@ static inline int eth_xmc4xxx_init_timestamp_control_reg(ETH_GLOBAL_TypeDef *reg return 0; } +static int eth_xmc4xxx_get_mac_address_eeprom(const struct device *dev) +{ +#if DT_INST_NODE_HAS_PROP(0, nvmem_cells) + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct device *eeprom_dev = DT_NVMEM_DEV_BY_IDX(DT_DRV_INST(0), 0); + uint16_t addr = DT_NVMEM_ADDR_BY_IDX(DT_DRV_INST(0), 0); + + int ret; + + if (!device_is_ready(eeprom_dev)) { + LOG_ERR("EEPROM device not ready."); + return -ENODEV; + } + + ret = eeprom_read(eeprom_dev, addr, dev_data->mac_addr, sizeof(dev_data->mac_addr)); + if (ret < 0) { + LOG_ERR("Error reading MAC address from EEPROM [%d]", ret); + } + + return ret; +#else + return -ENODEV; +#endif +} + static int eth_xmc4xxx_init(const struct device *dev) { struct eth_xmc4xxx_data *dev_data = dev->data; @@ -867,7 +894,10 @@ static int eth_xmc4xxx_init(const struct device *dev) eth_xmc4xxx_mask_unused_interrupts(dev_cfg->regs); #if !DT_INST_NODE_HAS_PROP(0, local_mac_address) - gen_random_mac(dev_data->mac_addr, INFINEON_OUI_B0, INFINEON_OUI_B1, INFINEON_OUI_B2); + if (eth_xmc4xxx_get_mac_address_eeprom(dev) < 0) { + gen_random_mac(dev_data->mac_addr, INFINEON_OUI_B0, INFINEON_OUI_B1, + INFINEON_OUI_B2); + } #endif eth_xmc4xxx_set_mac_address(dev_cfg->regs, dev_data->mac_addr); diff --git a/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml index c526fe89055e3..f3af3aab5ed1e 100644 --- a/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml +++ b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml @@ -8,6 +8,7 @@ compatible: "infineon,xmc4xxx-ethernet" include: - name: ethernet-controller.yaml - name: pinctrl-device.yaml + - name: nvmem-consumer.yaml properties: interrupts: From 2178fbba327764d90fafdf35778b8b9f2605de57 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Wed, 28 Aug 2024 16:11:04 -0400 Subject: [PATCH 3/3] drivers: eth_sam_gmac: Use nvmem-consumer to read MAC address Boards sam_e70_xplained, same54_xpro and sam_v71_xult are updated to use nvem-consumer. Signed-off-by: Andriy Gelman --- .../sam/sam_e70_xplained/Kconfig.defconfig | 15 ++-------- .../sam_e70_xplained-common.dtsi | 15 ++++++++-- .../atmel/sam/sam_v71_xult/Kconfig.defconfig | 14 ++-------- .../sam/sam_v71_xult/sam_v71_xult-common.dtsi | 15 ++++++++-- .../atmel/sam0/same54_xpro/Kconfig.defconfig | 15 ++-------- boards/atmel/sam0/same54_xpro/same54_xpro.dts | 15 ++++++++-- drivers/ethernet/Kconfig.sam_gmac | 26 +++-------------- drivers/ethernet/eth_sam_gmac.c | 28 +++++++++---------- dts/bindings/ethernet/atmel,gmac-common.yaml | 1 + .../boards/sam_e70_xplained_same70q21.conf | 2 -- 10 files changed, 63 insertions(+), 83 deletions(-) diff --git a/boards/atmel/sam/sam_e70_xplained/Kconfig.defconfig b/boards/atmel/sam/sam_e70_xplained/Kconfig.defconfig index 59f0676d06b57..a32341ba2f0e8 100644 --- a/boards/atmel/sam/sam_e70_xplained/Kconfig.defconfig +++ b/boards/atmel/sam/sam_e70_xplained/Kconfig.defconfig @@ -3,21 +3,10 @@ # Copyright (c) 2016 Piotr Mienkowski # SPDX-License-Identifier: Apache-2.0 -if ETH_SAM_GMAC - # Read MAC address from AT24MAC402 EEPROM - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS - default 0x9A - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS_SIZE - default 1 - -config ETH_SAM_GMAC_MAC_I2C_EEPROM +config ETH_SAM_GMAC_MAC_EEPROM default y - select I2C - -endif # ETH_SAM_GMAC + depends on ETH_SAM_GMAC if NETWORKING diff --git a/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi b/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi index d6190e050f979..0677228f0abc1 100644 --- a/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi +++ b/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi @@ -79,8 +79,18 @@ pinctrl-names = "default"; eeprom: eeprom@5f { - compatible = "atmel,24mac402"; + compatible = "atmel,at24", "atmel,24mac402"; reg = <0x5f>; + size = <256>; + pagesize = <16>; + address-width = <8>; + timeout = <5>; + + #address-cells = <1>; + #size-cells = <1>; + mac_address: mac_address@9a { + reg = <0x9a 0x06>; + }; }; }; @@ -126,7 +136,8 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&gmac_rmii>; pinctrl-names = "default"; - mac-eeprom = <&eeprom>; + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; phy-handle = <&phy>; }; diff --git a/boards/atmel/sam/sam_v71_xult/Kconfig.defconfig b/boards/atmel/sam/sam_v71_xult/Kconfig.defconfig index 5c860149dc8b9..9268a4a874e36 100644 --- a/boards/atmel/sam/sam_v71_xult/Kconfig.defconfig +++ b/boards/atmel/sam/sam_v71_xult/Kconfig.defconfig @@ -4,21 +4,11 @@ # Copyright (c) 2016 Piotr Mienkowski # SPDX-License-Identifier: Apache-2.0 -if ETH_SAM_GMAC # Read MAC address from AT24MAC402 EEPROM - -config ETH_SAM_GMAC_MAC_I2C_EEPROM +config ETH_SAM_GMAC_MAC_EEPROM default y - select I2C - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS - default 0x9A - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS_SIZE - default 1 - -endif # ETH_SAM_GMAC + depends on ETH_SAM_GMAC if NETWORKING diff --git a/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi b/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi index f6981455b5122..df7fca719d088 100644 --- a/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi +++ b/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi @@ -179,8 +179,18 @@ pinctrl-names = "default"; eeprom: eeprom@5f { - compatible = "atmel,24mac402"; + compatible = "atmel,at24", "atmel,24mac402"; reg = <0x5f>; + size = <256>; + pagesize = <16>; + address-width = <8>; + timeout = <5>; + + #address-cells = <1>; + #size-cells = <1>; + mac_address: mac_address@9a { + reg = <0x9a 0x06>; + }; }; }; @@ -235,7 +245,8 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&gmac_rmii>; pinctrl-names = "default"; - mac-eeprom = <&eeprom>; + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; phy-handle = <&phy>; }; diff --git a/boards/atmel/sam0/same54_xpro/Kconfig.defconfig b/boards/atmel/sam0/same54_xpro/Kconfig.defconfig index 17f73bc5ce43f..61d39a79f7641 100644 --- a/boards/atmel/sam0/same54_xpro/Kconfig.defconfig +++ b/boards/atmel/sam0/same54_xpro/Kconfig.defconfig @@ -4,21 +4,10 @@ # Copyright (c) 2024 Gerson Fernando Budke # SPDX-License-Identifier: Apache-2.0 -if ETH_SAM_GMAC - # Read MAC address from AT24MAC402 EEPROM - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS - default 0x9A - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS_SIZE - default 1 - -config ETH_SAM_GMAC_MAC_I2C_EEPROM +config ETH_SAM_GMAC_MAC_EEPROM default y - select I2C - -endif # ETH_SAM_GMAC + depends on ETH_SAM_GMAC if NETWORKING diff --git a/boards/atmel/sam0/same54_xpro/same54_xpro.dts b/boards/atmel/sam0/same54_xpro/same54_xpro.dts index f8d957727cd4d..97c362d6c6a8a 100644 --- a/boards/atmel/sam0/same54_xpro/same54_xpro.dts +++ b/boards/atmel/sam0/same54_xpro/same54_xpro.dts @@ -104,8 +104,18 @@ pinctrl-names = "default"; eeprom: eeprom@5e { - compatible = "atmel,24mac402"; + compatible = "atmel,at24", "atmel,24mac402"; reg = <0x5e>; + size = <256>; + pagesize = <16>; + address-width = <8>; + timeout = <5>; + + #address-cells = <1>; + #size-cells = <1>; + mac_address: mac_address@9a { + reg = <0x9a 0x06>; + }; }; }; @@ -126,7 +136,8 @@ zephyr_udc0: &usb0 { pinctrl-0 = <&gmac_rmii>; pinctrl-names = "default"; - mac-eeprom = <&eeprom>; + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; phy-handle = <&phy>; }; diff --git a/drivers/ethernet/Kconfig.sam_gmac b/drivers/ethernet/Kconfig.sam_gmac index 7037c313a00fb..ffc3e12cdd118 100644 --- a/drivers/ethernet/Kconfig.sam_gmac +++ b/drivers/ethernet/Kconfig.sam_gmac @@ -73,29 +73,11 @@ config ETH_SAM_GMAC_BUF_RX_COUNT fit at least two Ethernet frames: one being received by the GMAC module and the other being processed by the higher layer networking stack. -config ETH_SAM_GMAC_MAC_I2C_EEPROM - bool "Read from an I2C EEPROM" +config ETH_SAM_GMAC_MAC_EEPROM + bool "MAC eeprom" + select EEPROM help - Read MAC address from an I2C EEPROM. - -if ETH_SAM_GMAC_MAC_I2C_EEPROM - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS - hex "I2C EEPROM internal address" - range 0 0xffffffff - help - Internal address of the EEPROM chip where the MAC address is stored. - Chips with 1 to 4 byte internal address size are supported. Address - size has to be configured in a separate Kconfig option. - -config ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS_SIZE - int "I2C EEPROM internal address size" - default 1 - range 1 4 - help - Size (in bytes) of the internal EEPROM address. - -endif # ETH_SAM_GMAC_MAC_I2C_EEPROM + Enable reading MAC address from external flash memory. config PTP_CLOCK_SAM_GMAC bool "SAM GMAC PTP clock driver support" diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index c7d90bb6e30be..4f10b68948534 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -43,7 +43,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include +#include +#include #include #include #include @@ -1729,24 +1730,21 @@ static int eth_initialize(const struct device *dev) return retval; } -#if DT_INST_NODE_HAS_PROP(0, mac_eeprom) -static void get_mac_addr_from_i2c_eeprom(uint8_t mac_addr[6]) +#if DT_INST_NODE_HAS_PROP(0, nvmem_cells) && defined(CONFIG_ETH_SAM_GMAC_MAC_EEPROM) +static void get_mac_addr_from_eeprom(uint8_t mac_addr[6]) { - uint32_t iaddr = CONFIG_ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS; int ret; - const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(DT_INST_PHANDLE(0, mac_eeprom)); + const struct device *eeprom_dev = DT_NVMEM_DEV_BY_IDX(DT_DRV_INST(0), 0); + uint32_t addr = DT_NVMEM_ADDR_BY_IDX(DT_DRV_INST(0), 0); - if (!device_is_ready(i2c.bus)) { - LOG_ERR("Bus device is not ready"); + if (!device_is_ready(eeprom_dev)) { + LOG_ERR("EEPROM device not ready."); return; } - ret = i2c_write_read_dt(&i2c, - &iaddr, CONFIG_ETH_SAM_GMAC_MAC_I2C_INT_ADDRESS_SIZE, - mac_addr, 6); - - if (ret != 0) { - LOG_ERR("I2C: failed to read MAC addr"); + ret = eeprom_read(eeprom_dev, addr, mac_addr, 6); + if (ret < 0) { + LOG_ERR("Error reading MAC address from EEPROM [%d]", ret); return; } } @@ -1754,8 +1752,8 @@ static void get_mac_addr_from_i2c_eeprom(uint8_t mac_addr[6]) static void generate_mac(uint8_t mac_addr[6]) { -#if DT_INST_NODE_HAS_PROP(0, mac_eeprom) - get_mac_addr_from_i2c_eeprom(mac_addr); +#if DT_INST_NODE_HAS_PROP(0, nvmem_cells) && defined(CONFIG_ETH_SAM_GMAC_MAC_EEPROM) + get_mac_addr_from_eeprom(mac_addr); #elif DT_INST_PROP(0, zephyr_random_mac_address) gen_random_mac(mac_addr, ATMEL_OUI_B0, ATMEL_OUI_B1, ATMEL_OUI_B2); #endif diff --git a/dts/bindings/ethernet/atmel,gmac-common.yaml b/dts/bindings/ethernet/atmel,gmac-common.yaml index 0975647e1875c..fb03d2570a440 100644 --- a/dts/bindings/ethernet/atmel,gmac-common.yaml +++ b/dts/bindings/ethernet/atmel,gmac-common.yaml @@ -5,6 +5,7 @@ include: - name: ethernet-controller.yaml - name: pinctrl-device.yaml + - name: nvmem-consumer.yaml properties: reg: diff --git a/samples/net/gptp/boards/sam_e70_xplained_same70q21.conf b/samples/net/gptp/boards/sam_e70_xplained_same70q21.conf index d4118583c5072..3cbf10cba5f30 100644 --- a/samples/net/gptp/boards/sam_e70_xplained_same70q21.conf +++ b/samples/net/gptp/boards/sam_e70_xplained_same70q21.conf @@ -1,4 +1,2 @@ # GMAC driver settings CONFIG_PTP_CLOCK_SAM_GMAC=y - -CONFIG_ETH_SAM_GMAC_MAC_I2C_EEPROM=y