diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/blk-uclass.c | 1 | ||||
-rw-r--r-- | drivers/mtd/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mtd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/Kconfig | 19 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/Makefile | 8 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip-uclass.c | 74 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip.c | 119 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip.h | 32 | ||||
-rw-r--r-- | drivers/mtd/nvmxip/nvmxip_qspi.c | 70 |
9 files changed, 326 insertions, 0 deletions
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index cb73faaedaf..614b975e25c 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -28,6 +28,7 @@ static struct { { UCLASS_AHCI, "sata" }, { UCLASS_HOST, "host" }, { UCLASS_NVME, "nvme" }, + { UCLASS_NVMXIP, "nvmxip" }, { UCLASS_EFI_MEDIA, "efi" }, { UCLASS_EFI_LOADER, "efiloader" }, { UCLASS_VIRTIO, "virtio" }, diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index af45ef00dae..5fa88dae5f3 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -270,4 +270,6 @@ source "drivers/mtd/spi/Kconfig" source "drivers/mtd/ubi/Kconfig" +source "drivers/mtd/nvmxip/Kconfig" + endmenu diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 3a78590aaaa..c638980ea2b 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,6 +25,7 @@ obj-y += nand/ obj-y += onenand/ obj-y += spi/ obj-$(CONFIG_MTD_UBI) += ubi/ +obj-$(CONFIG_NVMXIP) += nvmxip/ #SPL/TPL build else diff --git a/drivers/mtd/nvmxip/Kconfig b/drivers/mtd/nvmxip/Kconfig new file mode 100644 index 00000000000..3ef71050264 --- /dev/null +++ b/drivers/mtd/nvmxip/Kconfig @@ -0,0 +1,19 @@ +# 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. + +config NVMXIP_QSPI + bool "QSPI XIP support" + select NVMXIP + help + This option allows the emulation of a block storage device on top of a QSPI XIP flash diff --git a/drivers/mtd/nvmxip/Makefile b/drivers/mtd/nvmxip/Makefile new file mode 100644 index 00000000000..54eacc102e6 --- /dev/null +++ b/drivers/mtd/nvmxip/Makefile @@ -0,0 +1,8 @@ +# 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 +obj-$(CONFIG_NVMXIP_QSPI) += nvmxip_qspi.o diff --git a/drivers/mtd/nvmxip/nvmxip-uclass.c b/drivers/mtd/nvmxip/nvmxip-uclass.c new file mode 100644 index 00000000000..6d8eb177b50 --- /dev/null +++ b/drivers/mtd/nvmxip/nvmxip-uclass.c @@ -0,0 +1,74 @@ +// 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> +#if CONFIG_IS_ENABLED(SANDBOX64) +#include <asm/test.h> +#endif +#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; + +#if CONFIG_IS_ENABLED(SANDBOX64) + sandbox_set_enable_memio(true); +#endif + + 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__ */ diff --git a/drivers/mtd/nvmxip/nvmxip_qspi.c b/drivers/mtd/nvmxip/nvmxip_qspi.c new file mode 100644 index 00000000000..7221fd1cb46 --- /dev/null +++ b/drivers/mtd/nvmxip/nvmxip_qspi.c @@ -0,0 +1,70 @@ +// 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 <fdt_support.h> +#include <linux/errno.h> +#include "nvmxip.h" + +#include <asm/global_data.h> +DECLARE_GLOBAL_DATA_PTR; + +#define NVMXIP_QSPI_DRV_NAME "nvmxip_qspi" + +/** + * nvmxip_qspi_of_to_plat() -read from DT + * @dev: the NVMXIP device + * + * Read from the DT the NVMXIP information. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int nvmxip_qspi_of_to_plat(struct udevice *dev) +{ + struct nvmxip_plat *plat = dev_get_plat(dev); + int ret; + + plat->phys_base = (phys_addr_t)dev_read_addr(dev); + if (plat->phys_base == FDT_ADDR_T_NONE) { + log_err("[%s]: can not get base address from device tree\n", dev->name); + return -EINVAL; + } + + ret = dev_read_u32(dev, "lba_shift", &plat->lba_shift); + if (ret) { + log_err("[%s]: can not get lba_shift from device tree\n", dev->name); + return -EINVAL; + } + + ret = dev_read_u32(dev, "lba", (u32 *)&plat->lba); + if (ret) { + log_err("[%s]: can not get lba from device tree\n", dev->name); + return -EINVAL; + } + + log_debug("[%s]: XIP device base addr: 0x%llx , lba_shift: %d , lbas: %lu\n", + dev->name, plat->phys_base, plat->lba_shift, plat->lba); + + return 0; +} + +static const struct udevice_id nvmxip_qspi_ids[] = { + { .compatible = "nvmxip,qspi" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(nvmxip_qspi) = { + .name = NVMXIP_QSPI_DRV_NAME, + .id = UCLASS_NVMXIP, + .of_match = nvmxip_qspi_ids, + .of_to_plat = nvmxip_qspi_of_to_plat, + .plat_auto = sizeof(struct nvmxip_plat), +}; |