WIP: kernel: generic: add NVMEM support to of_get_mac_address
authorPetr Štetiar <ynezz@true.cz>
Sat, 27 Apr 2019 12:01:57 +0000 (14:01 +0200)
committerPetr Štetiar <ynezz@true.cz>
Fri, 3 May 2019 06:59:24 +0000 (08:59 +0200)
TODO: add support for 4.19 kernel as well

Signed-off-by: Petr Štetiar <ynezz@true.cz>
target/linux/generic/backport-4.14/049-v5.0-mtd-add-support-for-reading-MTD-devices-via-the-nvme.patch [new file with mode: 0644]
target/linux/generic/backport-4.14/050-v5.0-net-ethernet-provide-nvmem_get_mac_address.patch [new file with mode: 0644]
target/linux/generic/backport-4.14/051-v5.0-nvmem-add-new-config-option.patch [new file with mode: 0644]
target/linux/generic/pending-4.14/480-mtd-set-rootfs-to-be-root-dev.patch
target/linux/generic/pending-4.14/682-nvmem-Update-the-OF-binding-to-use-a-subnode-for-the.patch [new file with mode: 0644]
target/linux/generic/pending-4.14/683-of_net-Add-NVMEM-support-to-of_get_mac_address.patch [new file with mode: 0644]

diff --git a/target/linux/generic/backport-4.14/049-v5.0-mtd-add-support-for-reading-MTD-devices-via-the-nvme.patch b/target/linux/generic/backport-4.14/049-v5.0-mtd-add-support-for-reading-MTD-devices-via-the-nvme.patch
new file mode 100644 (file)
index 0000000..72a25bb
--- /dev/null
@@ -0,0 +1,156 @@
+From cb2ee4b00e8ec29913ca407aee929ea9a118dede Mon Sep 17 00:00:00 2001
+From: Alban Bedel <albeu@free.fr>
+Date: Tue, 13 Nov 2018 15:01:10 +0100
+Subject: [PATCH 4/5] mtd: add support for reading MTD devices via the nvmem
+ API
+
+Allow drivers that use the nvmem API to read data stored on MTD devices.
+For this the mtd devices are registered as read-only NVMEM providers.
+
+We don't support device tree systems for now.
+
+Signed-off-by: Alban Bedel <albeu@free.fr>
+[Bartosz:
+  - include linux/nvmem-provider.h
+  - set the name of the nvmem provider
+  - set no_of_node to true in nvmem_config
+  - don't check the return value of nvmem_unregister() - it cannot fail
+  - tweaked the commit message]
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Acked-by: Boris Brezillon <boris.brezillon@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/Kconfig     |  1 +
+ drivers/mtd/mtdcore.c   | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/mtd.h |  2 ++
+ 3 files changed, 59 insertions(+)
+
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 5a2d717..34c2e84 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -1,5 +1,6 @@
+ menuconfig MTD
+       tristate "Memory Technology Device (MTD) support"
++      imply NVMEM
+       depends on GENERIC_IO
+       help
+         Memory Technology Devices are flash, RAM and similar chips, often
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index e7ea842..791310c 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -41,6 +41,7 @@
+ #include <linux/reboot.h>
+ #include <linux/leds.h>
+ #include <linux/debugfs.h>
++#include <linux/nvmem-provider.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -478,6 +479,50 @@ int mtd_pairing_groups(struct mtd_info *mtd)
+ }
+ EXPORT_SYMBOL_GPL(mtd_pairing_groups);
++static int mtd_nvmem_reg_read(void *priv, unsigned int offset,
++                            void *val, size_t bytes)
++{
++      struct mtd_info *mtd = priv;
++      size_t retlen;
++      int err;
++
++      err = mtd_read(mtd, offset, bytes, &retlen, val);
++      if (err && err != -EUCLEAN)
++              return err;
++
++      return retlen == bytes ? 0 : -EIO;
++}
++
++static int mtd_nvmem_add(struct mtd_info *mtd)
++{
++      struct nvmem_config config = {};
++
++      config.dev = &mtd->dev;
++      config.name = mtd->name;
++      config.owner = THIS_MODULE;
++      config.reg_read = mtd_nvmem_reg_read;
++      config.size = mtd->size;
++      config.word_size = 1;
++      config.stride = 1;
++      config.read_only = true;
++      config.root_only = true;
++      config.no_of_node = true;
++      config.priv = mtd;
++
++      mtd->nvmem = nvmem_register(&config);
++      if (IS_ERR(mtd->nvmem)) {
++              /* Just ignore if there is no NVMEM support in the kernel */
++              if (PTR_ERR(mtd->nvmem) == -ENOSYS) {
++                      mtd->nvmem = NULL;
++              } else {
++                      dev_err(&mtd->dev, "Failed to register NVMEM device\n");
++                      return PTR_ERR(mtd->nvmem);
++              }
++      }
++
++      return 0;
++}
++
+ static struct dentry *dfs_dir_mtd;
+ /**
+@@ -555,6 +600,11 @@ int add_mtd_device(struct mtd_info *mtd)
+       if (error)
+               goto fail_added;
++      /* Add the nvmem provider */
++      error = mtd_nvmem_add(mtd);
++      if (error)
++              goto fail_nvmem_add;
++
+       if (!IS_ERR_OR_NULL(dfs_dir_mtd)) {
+               mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd);
+               if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) {
+@@ -580,6 +630,8 @@ int add_mtd_device(struct mtd_info *mtd)
+       __module_get(THIS_MODULE);
+       return 0;
++fail_nvmem_add:
++      device_unregister(&mtd->dev);
+ fail_added:
+       of_node_put(mtd_get_of_node(mtd));
+       idr_remove(&mtd_idr, i);
+@@ -622,6 +674,10 @@ int del_mtd_device(struct mtd_info *mtd)
+                      mtd->index, mtd->name, mtd->usecount);
+               ret = -EBUSY;
+       } else {
++              /* Try to remove the NVMEM provider */
++              if (mtd->nvmem)
++                      nvmem_unregister(mtd->nvmem);
++
+               device_unregister(&mtd->dev);
+               idr_remove(&mtd_idr, mtd->index);
+diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
+index 6cd0f6b..5a1100d 100644
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -25,6 +25,7 @@
+ #include <linux/notifier.h>
+ #include <linux/device.h>
+ #include <linux/of.h>
++#include <linux/nvmem-provider.h>
+ #include <mtd/mtd-abi.h>
+@@ -356,6 +357,7 @@ struct mtd_info {
+       struct device dev;
+       int usecount;
+       struct mtd_debug_info dbg;
++      struct nvmem_device *nvmem;
+ };
+ int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
+-- 
+1.9.1
+
diff --git a/target/linux/generic/backport-4.14/050-v5.0-net-ethernet-provide-nvmem_get_mac_address.patch b/target/linux/generic/backport-4.14/050-v5.0-net-ethernet-provide-nvmem_get_mac_address.patch
new file mode 100644 (file)
index 0000000..0a20b41
--- /dev/null
@@ -0,0 +1,84 @@
+From b1b8792114e159a5cc4d60c770f159fa834f8ab5 Mon Sep 17 00:00:00 2001
+From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Date: Fri, 30 Nov 2018 09:20:57 +0100
+Subject: [PATCH 3/5] net: ethernet: provide nvmem_get_mac_address()
+
+We already have of_get_nvmem_mac_address() but some non-DT systems want
+to read the MAC address from NVMEM too. Implement a generalized routine
+that takes struct device as argument.
+
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/etherdevice.h |  1 +
+ net/ethernet/eth.c          | 38 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 39 insertions(+)
+
+diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
+index c643cc7..4ed4e48 100644
+--- a/include/linux/etherdevice.h
++++ b/include/linux/etherdevice.h
+@@ -32,6 +32,7 @@
+ struct device;
+ int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr);
+ unsigned char *arch_get_platform_mac_address(void);
++int nvmem_get_mac_address(struct device *dev, void *addrbuf);
+ u32 eth_get_headlen(void *data, unsigned int max_len);
+ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
+ extern const struct header_ops eth_header_ops;
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index eaeba9b..c212b79 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -47,6 +47,7 @@
+ #include <linux/inet.h>
+ #include <linux/ip.h>
+ #include <linux/netdevice.h>
++#include <linux/nvmem-consumer.h>
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/errno.h>
+@@ -548,3 +549,40 @@ int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)
+       return 0;
+ }
+ EXPORT_SYMBOL(eth_platform_get_mac_address);
++
++/**
++ * Obtain the MAC address from an nvmem cell named 'mac-address' associated
++ * with given device.
++ *
++ * @dev:      Device with which the mac-address cell is associated.
++ * @addrbuf:  Buffer to which the MAC address will be copied on success.
++ *
++ * Returns 0 on success or a negative error number on failure.
++ */
++int nvmem_get_mac_address(struct device *dev, void *addrbuf)
++{
++      struct nvmem_cell *cell;
++      const void *mac;
++      size_t len;
++
++      cell = nvmem_cell_get(dev, "mac-address");
++      if (IS_ERR(cell))
++              return PTR_ERR(cell);
++
++      mac = nvmem_cell_read(cell, &len);
++      nvmem_cell_put(cell);
++
++      if (IS_ERR(mac))
++              return PTR_ERR(mac);
++
++      if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
++              kfree(mac);
++              return -EINVAL;
++      }
++
++      ether_addr_copy(addrbuf, mac);
++      kfree(mac);
++
++      return 0;
++}
++EXPORT_SYMBOL(nvmem_get_mac_address);
+-- 
+1.9.1
+
diff --git a/target/linux/generic/backport-4.14/051-v5.0-nvmem-add-new-config-option.patch b/target/linux/generic/backport-4.14/051-v5.0-nvmem-add-new-config-option.patch
new file mode 100644 (file)
index 0000000..0ab8a42
--- /dev/null
@@ -0,0 +1,40 @@
+From 51d1095b4db38d3f323d1db2f6b3f547c460f3d8 Mon Sep 17 00:00:00 2001
+From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Date: Fri, 30 Nov 2018 11:53:25 +0000
+Subject: [PATCH 5/5] nvmem: add new config option
+
+We want to add nvmem support for MTD. TI DaVinci is the first platform
+that will be using it, but only in non-DT mode. In order not to
+introduce any new interface to supporting of which we would have to
+commit - add a new config option that tells nvmem not to use the DT
+node of the parent device.
+
+This way we won't be creating nvmem devices corresponding with MTD
+partitions defined in device tree. By default MTD will set this new
+field to true.
+
+Once a set of bindings for MTD nvmem cells is agreed upon, we'll be
+able to remove this option.
+
+Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/nvmem-provider.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
+index 497706f..5707f37 100644
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -31,6 +31,7 @@ struct nvmem_config {
+       int                     ncells;
+       bool                    read_only;
+       bool                    root_only;
++      bool                    no_of_node;
+       nvmem_reg_read_t        reg_read;
+       nvmem_reg_write_t       reg_write;
+       int     size;
+-- 
+1.9.1
+
index 6cddaf01b75cb58cfb377f568f2c375af87e2f1b..1c7a399a7437417bf7e9e5cf3e5f47412f2322cc 100644 (file)
@@ -12,15 +12,15 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
 
 --- a/drivers/mtd/mtdcore.c
 +++ b/drivers/mtd/mtdcore.c
-@@ -41,6 +41,7 @@
- #include <linux/reboot.h>
+@@ -42,6 +42,7 @@
  #include <linux/leds.h>
  #include <linux/debugfs.h>
+ #include <linux/nvmem-provider.h>
 +#include <linux/root_dev.h>
  
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/partitions.h>
-@@ -578,6 +579,15 @@ int add_mtd_device(struct mtd_info *mtd)
+@@ -628,6 +629,15 @@ int add_mtd_device(struct mtd_info *mtd)
           of this try_ nonsense, and no bitching about it
           either. :) */
        __module_get(THIS_MODULE);
@@ -35,4 +35,4 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
 +
        return 0;
  
- fail_added:
+ fail_nvmem_add:
diff --git a/target/linux/generic/pending-4.14/682-nvmem-Update-the-OF-binding-to-use-a-subnode-for-the.patch b/target/linux/generic/pending-4.14/682-nvmem-Update-the-OF-binding-to-use-a-subnode-for-the.patch
new file mode 100644 (file)
index 0000000..4f6b2e3
--- /dev/null
@@ -0,0 +1,131 @@
+From 8be2f132b705013e7938d03894aefac03d5983ed Mon Sep 17 00:00:00 2001
+From: Alban Bedel <albeu@free.fr>
+Date: Sun, 25 Mar 2018 00:24:57 +0100
+Subject: [PATCH] nvmem: Update the OF binding to use a subnode for the cells
+ list
+
+Having the cells as subnodes of the provider device without any
+compatible property might clash with other bindings. To avoid this
+problem update the binding to have all the cells in a 'nvmem-cells'
+subnode with a 'nvmem-cells' compatible string. This new binding
+guarantee that we can turn any kind of device in a nvmem provider.
+
+While discouraged for new uses the old scheme is still supported for
+backward compatibility.
+
+Signed-off-by: Alban Bedel <albeu@free.fr>
+---
+ Documentation/devicetree/bindings/nvmem/nvmem.txt | 63 +++++++++++++++--------
+ drivers/nvmem/core.c                              | 10 ++++
+ 2 files changed, 52 insertions(+), 21 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
+index b52bc11..51bb3ca 100644
+--- a/Documentation/devicetree/bindings/nvmem/nvmem.txt
++++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
+@@ -11,14 +11,29 @@ these data from, and where they are stored on the storage device.
+ This document is here to document this.
+ = Data providers =
+-Contains bindings specific to provider drivers and data cells as children
+-of this node.
++A data provider should have a subnode named 'nvmem-cells' that contains
++a subnodes for each data cells.
++
++For backward compatibility the nvmem data cells can be direct children
++of the data provider. This use is discouraged as it can conflict with
++other bindings.
+ Optional properties:
+  read-only: Mark the provider as read only.
++= Data cells list =
++The data cells list node should be named 'nvmem-cells' and have a
++child node for each data cell.
++
++Required properties:
++ compatible: Must be "nvmem-cells"
++ #address-cells: <1> if the provider use 32 bit addressing,
++                 <2> for 64 bits addressing
++ #size-cells: <1> if the provider use 32 bit sizes,
++              <2> for 64 bits sizes
++
+ = Data cells =
+-These are the child nodes of the provider which contain data cell
++These are the child nodes of the nvmem-cells node which contain data cell
+ information like offset and size in nvmem provider.
+ Required properties:
+@@ -37,24 +52,30 @@ For example:
+               ...
+               /* Data cells */
+-              tsens_calibration: calib@404 {
+-                      reg = <0x404 0x10>;
+-              };
+-
+-              tsens_calibration_bckp: calib_bckp@504 {
+-                      reg = <0x504 0x11>;
+-                      bits = <6 128>
+-              };
+-
+-              pvs_version: pvs-version@6 {
+-                      reg = <0x6 0x2>
+-                      bits = <7 2>
+-              };
+-
+-              speed_bin: speed-bin@c{
+-                      reg = <0xc 0x1>;
+-                      bits = <2 3>;
+-
++              nvmem-cells {
++                      compatible = "nvmem-cells";
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++
++                      tsens_calibration: calib@404 {
++                              reg = <0x404 0x10>;
++                      };
++
++                      tsens_calibration_bckp: calib_bckp@504 {
++                              reg = <0x504 0x11>;
++                              bits = <6 128>
++                      };
++
++                      pvs_version: pvs-version@6 {
++                              reg = <0x6 0x2>
++                              bits = <7 2>
++                      };
++
++                      speed_bin: speed-bin@c{
++                              reg = <0xc 0x1>;
++                              bits = <2 3>;
++
++                      };
+               };
+               ...
+       };
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index 635886e..76d1339 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -788,6 +788,16 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+       if (!nvmem_np)
+               return ERR_PTR(-EINVAL);
++      /* Devices using the new binding have all the cells in
++       * a subnode with compatible = "nvmem-cells". In this
++       * case the device will be the parent of this node.
++       */
++      if (of_device_is_compatible(nvmem_np, "nvmem-cells")) {
++              nvmem_np = of_get_next_parent(nvmem_np);
++              if (!nvmem_np)
++                      return ERR_PTR(-EINVAL);
++      }
++
+       nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+       of_node_put(nvmem_np);
+       if (IS_ERR(nvmem))
+-- 
+1.9.1
+
diff --git a/target/linux/generic/pending-4.14/683-of_net-Add-NVMEM-support-to-of_get_mac_address.patch b/target/linux/generic/pending-4.14/683-of_net-Add-NVMEM-support-to-of_get_mac_address.patch
new file mode 100644 (file)
index 0000000..2f5f68d
--- /dev/null
@@ -0,0 +1,135 @@
+From 5ea133a9a158506663ddd71888792e1bd6d1861c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Thu, 18 Apr 2019 00:45:02 +0200
+Subject: [PATCH] of_net: Add NVMEM support to of_get_mac_address
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Many embedded devices have information such as MAC addresses stored
+inside NVMEMs like EEPROMs and so on. Currently there are only two
+drivers in the tree which benefit from NVMEM bindings.
+
+Adding support for NVMEM into every other driver would mean adding a lot
+of repetitive code. This patch allows us to configure MAC addresses in
+various devices like ethernet and wireless adapters directly from
+of_get_mac_address, which is already used by almost every driver in the
+tree.
+
+Predecessor of this patch which used directly MTD layer has originated
+in OpenWrt some time ago and supports already about 497 use cases in 357
+device tree files.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: John Crispin <john@phrozen.org>
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ drivers/of/of_net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 61 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
+index d3065ce..c415cd8 100644
+--- a/drivers/of/of_net.c
++++ b/drivers/of/of_net.c
+@@ -8,8 +8,10 @@
+ #include <linux/etherdevice.h>
+ #include <linux/kernel.h>
+ #include <linux/of_net.h>
++#include <linux/of_platform.h>
+ #include <linux/phy.h>
+ #include <linux/export.h>
++#include <linux/device.h>
+ #include <linux/mtd/mtd.h>
+ /**
+@@ -121,12 +123,59 @@ static const void *of_get_mac_address_mtd(struct device_node *np)
+       return NULL;
+ }
++static const void *of_get_mac_addr_nvmem(struct device_node *np)
++{
++      int ret;
++      u8 mac[ETH_ALEN];
++      struct property *pp;
++      struct platform_device *pdev = of_find_device_by_node(np);
++
++      if (!pdev)
++              return ERR_PTR(-ENODEV);
++
++      ret = nvmem_get_mac_address(&pdev->dev, &mac);
++      if (ret)
++              return ERR_PTR(ret);
++
++      pp = devm_kzalloc(&pdev->dev, sizeof(*pp), GFP_KERNEL);
++      if (!pp)
++              return ERR_PTR(-ENOMEM);
++
++      pp->name = "nvmem-mac-address";
++      pp->length = ETH_ALEN;
++      pp->value = devm_kmemdup(&pdev->dev, mac, ETH_ALEN, GFP_KERNEL);
++      if (!pp->value) {
++              ret = -ENOMEM;
++              goto free;
++      }
++
++      ret = of_add_property(np, pp);
++      if (ret)
++              goto free;
++
++      return pp->value;
++free:
++      devm_kfree(&pdev->dev, pp->value);
++      devm_kfree(&pdev->dev, pp);
++
++      return ERR_PTR(ret);
++}
++
++static inline bool of_has_nvmem_mac_addr(struct device_node *np)
++{
++      int index = of_property_match_string(np, "nvmem-cell-names",
++                                           "mac-address");
++      return of_parse_phandle(np, "nvmem-cells", index) != NULL;
++}
++
+ /**
+  * Search the device tree for the best MAC address to use.  'mac-address' is
+  * checked first, because that is supposed to contain to "most recent" MAC
+  * address. If that isn't set, then 'local-mac-address' is checked next,
+- * because that is the default address.  If that isn't set, then the obsolete
+- * 'address' is checked, just in case we're using an old device tree.
++ * because that is the default address. If that isn't set, then the obsolete
++ * 'address' is checked, just in case we're using an old device tree. If any
++ * of the above isn't set, then try to get MAC address from nvmem cell named
++ * 'mac-address'.
+  *
+  * Note that the 'address' property is supposed to contain a virtual address of
+  * the register set, but some DTS files have redefined that property to be the
+@@ -139,8 +188,8 @@ static const void *of_get_mac_address_mtd(struct device_node *np)
+  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
+  * but is all zeros.
+  *
+- * If a mtd-mac-address property exists, try to fetch the MAC address from the
+- * specified mtd device, and store it as a 'mac-address' property
++ * Return: Will be a valid pointer on success, NULL in case there wasn't
++ *         'mac-address' nvmem cell node found, and ERR_PTR in case of error.
+ */
+ const void *of_get_mac_address(struct device_node *np)
+ {
+@@ -158,6 +207,13 @@ const void *of_get_mac_address(struct device_node *np)
+       if (addr)
+               return addr;
+-      return of_get_mac_addr(np, "address");
++      addr = of_get_mac_addr(np, "address");
++      if (addr)
++              return addr;
++
++      if (!of_has_nvmem_mac_addr(np))
++              return NULL;
++
++      return of_get_mac_addr_nvmem(np);
+ }
+ EXPORT_SYMBOL(of_get_mac_address);
+-- 
+1.9.1
+