drivers/mtd/nvmxip: introduce NVM XIP block storage emulation

add block storage emulation for NVM XIP flash devices

Some paltforms such as Corstone-1000 need to see NVM XIP raw flash
as a block storage device with read only capability.

Here NVM flash devices are devices with addressable
memory (e.g: QSPI NOR flash).

The implementation is generic and can be used by different platforms.

Two drivers are provided as follows.

  nvmxip-blk :

    a generic block driver allowing to read from the XIP flash

  nvmxip Uclass driver :

        When a device is described in the DT and associated with
        UCLASS_NVMXIP, the Uclass creates a block device and binds it with
	 the nvmxip-blk.

Platforms can use multiple NVM XIP devices at the same time by defining a
DT node for each one of them.

Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
diff --git a/drivers/mtd/nvmxip/nvmxip-uclass.c b/drivers/mtd/nvmxip/nvmxip-uclass.c
new file mode 100644
index 0000000..9f96041
--- /dev/null
+++ b/drivers/mtd/nvmxip/nvmxip-uclass.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ *   Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include "nvmxip.h"
+
+/* LBA Macros */
+
+#define DEFAULT_LBA_SHIFT 10 /* 1024 bytes per block */
+#define DEFAULT_LBA_COUNT 1024 /* block count */
+
+#define DEFAULT_LBA_SZ BIT(DEFAULT_LBA_SHIFT)
+
+/**
+ * nvmxip_post_bind() - post binding treatments
+ * @dev:	the NVMXIP device
+ *
+ * Create and probe a child block device.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int nvmxip_post_bind(struct udevice *udev)
+{
+	int ret;
+	struct udevice *bdev = NULL;
+	char bdev_name[NVMXIP_BLKDEV_NAME_SZ + 1];
+	int devnum;
+
+	devnum = uclass_id_count(UCLASS_NVMXIP);
+	snprintf(bdev_name, NVMXIP_BLKDEV_NAME_SZ, "blk#%d", devnum);
+
+	ret = blk_create_devicef(udev, NVMXIP_BLKDRV_NAME, bdev_name, UCLASS_NVMXIP,
+				 devnum, DEFAULT_LBA_SZ,
+				 DEFAULT_LBA_COUNT, &bdev);
+	if (ret) {
+		log_err("[%s]: failure during creation of the block device %s, error %d\n",
+			udev->name, bdev_name, ret);
+		return ret;
+	}
+
+	ret = blk_probe_or_unbind(bdev);
+	if (ret) {
+		log_err("[%s]: failure during probing the block device %s, error %d\n",
+			udev->name, bdev_name, ret);
+		return ret;
+	}
+
+	log_info("[%s]: the block device %s ready for use\n", udev->name, bdev_name);
+
+	return 0;
+}
+
+UCLASS_DRIVER(nvmxip) = {
+	.name	   = "nvmxip",
+	.id	   = UCLASS_NVMXIP,
+	.post_bind = nvmxip_post_bind,
+};