From fd0e523037439520813db7c57df5bd37cdf40f7e Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Mon, 3 Feb 2025 00:10:18 +0100
Subject: [PATCH 1/2] nvmem: core: generalize "mac-base" cells handling

Generalize support of "mac-base" nvmem cells and provide a GPL symbol to
permit also other NVMEM layout driver to parse mac-base cells.

It's VERY COMMON for some specially formatted NVMEM to expose a mac
address in ASCII format or HEX format hence prevent code duplication by
exposing a common helper.

Such helper will change the nvmem_info_cell and apply the correct post
process function to correctly parse the mac address.

Since the API requires OF and is only related to layout, move the
function in layouts.c to correctly handle non-OF NVMEM.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/nvmem/core.c           | 79 +--------------------------------
 drivers/nvmem/layouts.c        | 80 ++++++++++++++++++++++++++++++++++
 include/linux/nvmem-provider.h |  4 ++
 3 files changed, 86 insertions(+), 77 deletions(-)

--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -7,12 +7,9 @@
  */
 
 #include <linux/device.h>
-#include <linux/ctype.h>
-#include <linux/etherdevice.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
-#include <linux/if_ether.h>
 #include <linux/init.h>
 #include <linux/kref.h>
 #include <linux/module.h>
@@ -814,62 +811,6 @@ static int nvmem_validate_keepouts(struc
 	return 0;
 }
 
-static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
-				   void *buf, size_t bytes)
-{
-	if (WARN_ON(bytes != ETH_ALEN))
-		return -EINVAL;
-
-	if (index)
-		eth_addr_add(buf, index);
-
-	return 0;
-}
-
-static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset,
-				     void *buf, size_t bytes)
-{
-	u8 mac[ETH_ALEN];
-
-	if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
-		return -EINVAL;
-
-	if (!mac_pton(buf, mac))
-		return -EINVAL;
-
-	if (index)
-		eth_addr_add(mac, index);
-
-	ether_addr_copy(buf, mac);
-
-	return 0;
-}
-
-static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
-				   void *buf, size_t bytes)
-{
-	u8 mac[ETH_ALEN], *hexstr;
-	int i;
-
-	if (WARN_ON(bytes != 2 * ETH_ALEN))
-		return -EINVAL;
-
-	hexstr = (u8 *)buf;
-	for (i = 0; i < ETH_ALEN; i++) {
-		if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
-			return -EINVAL;
-
-		mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
-	}
-
-	if (index)
-		eth_addr_add(mac, index);
-
-	ether_addr_copy(buf, mac);
-
-	return 0;
-}
-
 static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
 {
 	struct device *dev = &nvmem->dev;
@@ -911,24 +852,8 @@ static int nvmem_add_cells_from_dt(struc
 		if (nvmem->fixup_dt_cell_info)
 			nvmem->fixup_dt_cell_info(nvmem, &info);
 
-		if (of_device_is_compatible(np, "fixed-layout")) {
-			if (of_device_is_compatible(child, "mac-base")) {
-				if (info.bytes == ETH_ALEN) {
-					info.raw_len = info.bytes;
-					info.bytes = ETH_ALEN;
-					info.read_post_process = nvmem_mac_base_raw_read;
-				} else if (info.bytes == 2 * ETH_ALEN) {
-					info.raw_len = info.bytes;
-					info.bytes = ETH_ALEN;
-					info.read_post_process = nvmem_mac_base_hex_read;
-				} else if (info.bytes == 3 * ETH_ALEN - 1) {
-					info.raw_len = info.bytes;
-					info.bytes = ETH_ALEN;
-					info.read_post_process = nvmem_mac_base_ascii_read;
-				}
-
-			}
-		}
+		if (of_device_is_compatible(np, "fixed-layout"))
+			nvmem_layout_parse_mac_base(&info);
 
 		ret = nvmem_add_one_cell(nvmem, &info);
 		kfree(info.name);
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -6,8 +6,11 @@
  * Author: Miquel Raynal <miquel.raynal@bootlin.com
  */
 
+#include <linux/ctype.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
@@ -21,6 +24,83 @@
 #define to_nvmem_layout_device(_dev) \
 	container_of((_dev), struct nvmem_layout, dev)
 
+static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
+				   void *buf, size_t bytes)
+{
+	if (WARN_ON(bytes != ETH_ALEN))
+		return -EINVAL;
+
+	if (index)
+		eth_addr_add(buf, index);
+
+	return 0;
+}
+
+static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset,
+				     void *buf, size_t bytes)
+{
+	u8 mac[ETH_ALEN];
+
+	if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
+		return -EINVAL;
+
+	if (!mac_pton(buf, mac))
+		return -EINVAL;
+
+	if (index)
+		eth_addr_add(mac, index);
+
+	ether_addr_copy(buf, mac);
+
+	return 0;
+}
+
+static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
+				   void *buf, size_t bytes)
+{
+	u8 mac[ETH_ALEN], *hexstr;
+	int i;
+
+	if (WARN_ON(bytes != 2 * ETH_ALEN))
+		return -EINVAL;
+
+	hexstr = (u8 *)buf;
+	for (i = 0; i < ETH_ALEN; i++) {
+		if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
+			return -EINVAL;
+
+		mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
+	}
+
+	if (index)
+		eth_addr_add(mac, index);
+
+	ether_addr_copy(buf, mac);
+
+	return 0;
+}
+
+void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info)
+{
+	if (!of_device_is_compatible(info->np, "mac-base"))
+		return;
+
+	if (info->bytes == ETH_ALEN) {
+		info->raw_len = info->bytes;
+		info->bytes = ETH_ALEN;
+		info->read_post_process = nvmem_mac_base_raw_read;
+	} else if (info->bytes == 2 * ETH_ALEN) {
+		info->raw_len = info->bytes;
+		info->bytes = ETH_ALEN;
+		info->read_post_process = nvmem_mac_base_hex_read;
+	} else if (info->bytes == 3 * ETH_ALEN - 1) {
+		info->raw_len = info->bytes;
+		info->bytes = ETH_ALEN;
+		info->read_post_process = nvmem_mac_base_ascii_read;
+	}
+}
+EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base);
+
 static int nvmem_layout_bus_match(struct device *dev, const struct device_driver *drv)
 {
 	return of_driver_match_device(dev, drv);
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -242,6 +242,8 @@ static inline void nvmem_layout_unregist
 
 #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
 
+void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info);
+
 /**
  * of_nvmem_layout_get_container() - Get OF node of layout container
  *
@@ -254,6 +256,8 @@ struct device_node *of_nvmem_layout_get_
 
 #else  /* CONFIG_NVMEM && CONFIG_OF */
 
+static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {}
+
 static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
 {
 	return NULL;
