diff options
author | Abdellatif El Khlifi | 2023-04-17 10:11:52 +0100 |
---|---|---|
committer | Tom Rini | 2023-04-27 17:01:14 -0400 |
commit | f37af2760ea92cec3fbdcfceb6df7be57a618165 (patch) | |
tree | 07b0dfdb08e51202c3d8b3304c94aeb29afffa75 /drivers/mtd/nvmxip | |
parent | b197f1f05dee730e173a0756cb1a5f2be5d3ba5b (diff) |
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>
Diffstat (limited to 'drivers/mtd/nvmxip')
-rw-r--r-- | drivers/mtd/nvmxip/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/Makefile | 7 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip-uclass.c | 67 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip.c | 119 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip.h | 32 |
5 files changed, 238 insertions, 0 deletions
diff --git a/drivers/mtd/nvmxip/Kconfig b/drivers/mtd/nvmxip/Kconfig new file mode 100644 index 00000000000..ef53fc3c790 --- /dev/null +++ b/drivers/mtd/nvmxip/Kconfig @@ -0,0 +1,13 @@ +# 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> + +config NVMXIP + bool "NVM XIP devices support" + select BLK + help + This option allows the emulation of a block storage device + on top of a direct access non volatile memory XIP flash devices. + This support provides the read operation. diff --git a/drivers/mtd/nvmxip/Makefile b/drivers/mtd/nvmxip/Makefile new file mode 100644 index 00000000000..07890982c7e --- /dev/null +++ b/drivers/mtd/nvmxip/Makefile @@ -0,0 +1,7 @@ +# 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> + +obj-y += nvmxip-uclass.o nvmxip.o diff --git a/drivers/mtd/nvmxip/nvmxip-uclass.c b/drivers/mtd/nvmxip/nvmxip-uclass.c new file mode 100644 index 00000000000..9f96041e3d8 --- /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, +}; diff --git a/drivers/mtd/nvmxip/nvmxip.c b/drivers/mtd/nvmxip/nvmxip.c new file mode 100644 index 00000000000..a359e3b4822 --- /dev/null +++ b/drivers/mtd/nvmxip/nvmxip.c @@ -0,0 +1,119 @@ +// 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 <mapmem.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include "nvmxip.h" + +/** + * nvmxip_mmio_rawread() - read from the XIP flash + * @address: address of the data + * @value: pointer to where storing the value read + * + * Read raw data from the XIP flash. + * + * Return: + * + * Always return 0. + */ +static int nvmxip_mmio_rawread(const phys_addr_t address, u64 *value) +{ + *value = readq(address); + return 0; +} + +/** + * nvmxip_blk_read() - block device read operation + * @dev: the block device + * @blknr: first block number to read from + * @blkcnt: number of blocks to read + * @buffer: destination buffer + * + * Read data from the block storage device. + * + * Return: + * + * number of blocks read on success. Otherwise, failure + */ +static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, void *buffer) +{ + struct nvmxip_plat *plat = dev_get_plat(dev->parent); + struct blk_desc *desc = dev_get_uclass_plat(dev); + /* number of the u64 words to read */ + u32 qwords = (blkcnt * desc->blksz) / sizeof(u64); + /* physical address of the first block to read */ + phys_addr_t blkaddr = plat->phys_base + blknr * desc->blksz; + u64 *virt_blkaddr; + u64 *pdst = buffer; + uint qdata_idx; + + if (!pdst) + return -EINVAL; + + log_debug("[%s]: reading from blknr: %lu , blkcnt: %lu\n", dev->name, blknr, blkcnt); + + virt_blkaddr = map_sysmem(blkaddr, 0); + + /* assumption: the data is virtually contiguous */ + + for (qdata_idx = 0 ; qdata_idx < qwords ; qdata_idx++) + nvmxip_mmio_rawread((phys_addr_t)(virt_blkaddr + qdata_idx), pdst++); + + log_debug("[%s]: src[0]: 0x%llx , dst[0]: 0x%llx , src[-1]: 0x%llx , dst[-1]: 0x%llx\n", + dev->name, + *virt_blkaddr, + *(u64 *)buffer, + *(u64 *)((u8 *)virt_blkaddr + desc->blksz * blkcnt - sizeof(u64)), + *(u64 *)((u8 *)buffer + desc->blksz * blkcnt - sizeof(u64))); + + unmap_sysmem(virt_blkaddr); + + return blkcnt; +} + +/** + * nvmxip_blk_probe() - block storage device probe + * @dev: the block storage device + * + * Initialize the block storage descriptor. + * + * Return: + * + * Always return 0. + */ +static int nvmxip_blk_probe(struct udevice *dev) +{ + struct nvmxip_plat *plat = dev_get_plat(dev->parent); + struct blk_desc *desc = dev_get_uclass_plat(dev); + + desc->lba = plat->lba; + desc->log2blksz = plat->lba_shift; + desc->blksz = BIT(plat->lba_shift); + desc->bdev = dev; + + log_debug("[%s]: block storage layout\n lbas: %lu , log2blksz: %d, blksz: %lu\n", + dev->name, desc->lba, desc->log2blksz, desc->blksz); + + return 0; +} + +static const struct blk_ops nvmxip_blk_ops = { + .read = nvmxip_blk_read, +}; + +U_BOOT_DRIVER(nvmxip_blk) = { + .name = NVMXIP_BLKDRV_NAME, + .id = UCLASS_BLK, + .probe = nvmxip_blk_probe, + .ops = &nvmxip_blk_ops, +}; diff --git a/drivers/mtd/nvmxip/nvmxip.h b/drivers/mtd/nvmxip/nvmxip.h new file mode 100644 index 00000000000..f4ef37725d2 --- /dev/null +++ b/drivers/mtd/nvmxip/nvmxip.h @@ -0,0 +1,32 @@ +/* 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> + */ + +#ifndef __DRIVER_NVMXIP_H__ +#define __DRIVER_NVMXIP_H__ + +#include <blk.h> + +#define NVMXIP_BLKDRV_NAME "nvmxip-blk" +#define NVMXIP_BLKDEV_NAME_SZ 20 + +/** + * struct nvmxip_plat - the NVMXIP driver plat + * + * @phys_base: NVM XIP device base address + * @lba_shift: block size shift count + * @lba: number of blocks + * + * The NVMXIP information read from the DT. + */ +struct nvmxip_plat { + phys_addr_t phys_base; + u32 lba_shift; + lbaint_t lba; +}; + +#endif /* __DRIVER_NVMXIP_H__ */ |