
On 07.03.24 14:07, Alexey Romanov wrote:
MTD block - abstraction over MTD subsystem, allowing to read and write in blocks using BLK UCLASS.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/block/blk-uclass.c | 1 + drivers/mtd/Makefile | 1 + drivers/mtd/mtdblock.c | 227 +++++++++++++++++++++++++++++++++++++ include/linux/mtd/mtd.h | 12 ++ 4 files changed, 241 insertions(+) create mode 100644 drivers/mtd/mtdblock.c
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 77066da352..ab0a9105c9 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -37,6 +37,7 @@ static struct { { UCLASS_PVBLOCK, "pvblock" }, { UCLASS_BLKMAP, "blkmap" }, { UCLASS_RKMTD, "rkmtd" },
{ UCLASS_MTD, "mtd" }, };
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index c638980ea2..993b122ac4 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -26,6 +26,7 @@ obj-y += onenand/ obj-y += spi/ obj-$(CONFIG_MTD_UBI) += ubi/ obj-$(CONFIG_NVMXIP) += nvmxip/ +obj-$(CONFIG_BLK) += mtdblock.o
#SPL/TPL build else diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c new file mode 100644 index 0000000000..b409674173 --- /dev/null +++ b/drivers/mtd/mtdblock.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0+
nits:
GPL-2.0-or-later see https://spdx.org/licenses/GPL-2.0-or-later.html
+/*
- MTD block - abstraction over MTD subsystem, allowing
- to read and write in blocks using BLK UCLASS.
- Read algorithm:
- Convert start block number to start address.
- Read block_dev->blksz bytes using mtd_read() and
add to start address pointer block_dev->blksz bytes,
until the requested number of blocks have been read.
- Write algorithm:
- Convert start block number to start address.
- Round this address down by mtd->erasesize.
- Erase addr Start addr
| |
v v
+----------------+----------------+----------------+
| blksz | blksz | blksz |
+----------------+----------------+----------------+
- Calculate offset between this two addresses.
- Read mtd->erasesize bytes using mtd_read() into
temporary buffer from erase address.
- Erase addr Start addr
| |
v v
+----------------+----------------+----------------+
| blksz | blksz | blksz |
+----------------+----------------+----------------+
^
|
|
- mtd_read()
- from here
- Copy data from user buffer to temporary buffer with offset,
calculated at step 3.
- Erase and write mtd->erasesize bytes at erase address
pointer using mtd_erase/mtd_write().
- Add to erase address pointer mtd->erasesize bytes.
- goto 1 until the requested number of blocks have
been written.
- (C) Copyright 2024 SaluteDevices, Inc.
- Author: Alexey Romanov avromanov@salutedevices.com
- */
+#include <blk.h> +#include <part.h> +#include <dm/device.h> +#include <dm/device-internal.h> +#include <linux/mtd/mtd.h>
+int mtd_bind(struct udevice *dev, struct mtd_info **mtd) +{
- struct blk_desc *bdesc;
- struct udevice *bdev;
- int ret;
- ret = blk_create_devicef(dev, "mtd_blk", "blk", UCLASS_MTD,
dev_seq(dev), 512, 0, &bdev);
- if (ret) {
pr_err("Cannot create block device\n");
return ret;
- }
- bdesc = dev_get_uclass_plat(bdev);
- dev_set_priv(bdev, mtd);
- bdesc->bdev = bdev;
- bdesc->part_type = PART_TYPE_MTD;
- return 0;
+}
+static ulong mtd_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
nits:
Reading bread I thought of nutrition. How about mtd_blk_read()?
void *dst)
+{
- struct blk_desc *block_dev = dev_get_uclass_plat(dev);
- struct mtd_info *mtd = blk_desc_to_mtd(block_dev);
- unsigned int sect_size = block_dev->blksz;
- lbaint_t cur = start;
- ulong read_cnt = 0;
- while (read_cnt < blkcnt) {
int ret;
loff_t sect_start = cur * sect_size;
size_t retlen;
ret = mtd_read(mtd, sect_start, sect_size, &retlen, dst);
if (ret)
return ret;
if (retlen != sect_size) {
pr_err("mtdblock: failed to read block 0x%lx\n", cur);
return -EIO;
}
cur++;
dst += sect_size;
read_cnt++;
- }
- return read_cnt;
+}
+static int mtd_erase_write(struct mtd_info *mtd, uint64_t start, const void *src) +{
- int ret;
- size_t retlen;
- struct erase_info erase = { 0 };
- erase.mtd = mtd;
- erase.addr = start;
- erase.len = mtd->erasesize;
- ret = mtd_erase(mtd, &erase);
- if (ret)
return ret;
- ret = mtd_write(mtd, start, mtd->erasesize, &retlen, src);
- if (ret)
return ret;
- if (retlen != mtd->erasesize) {
pr_err("mtdblock: failed to read block at 0x%llx\n", start);
return -EIO;
- }
- return 0;
+}
+static ulong mtd_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
mtd_blk_write()?
Best regards
Heinrich
const void *src)
+{
- struct blk_desc *block_dev = dev_get_uclass_plat(dev);
- struct mtd_info *mtd = blk_desc_to_mtd(block_dev);
- unsigned int sect_size = block_dev->blksz;
- lbaint_t cur = start, blocks_todo = blkcnt;
- ulong write_cnt = 0;
- u8 *buf;
- int ret = 0;
- buf = malloc(mtd->erasesize);
- if (!buf)
return -ENOMEM;
- while (blocks_todo > 0) {
loff_t sect_start = cur * sect_size;
loff_t erase_start = ALIGN_DOWN(sect_start, mtd->erasesize);
u32 offset = sect_start - erase_start;
size_t cur_size = min_t(size_t, mtd->erasesize - offset,
blocks_todo * sect_size);
size_t retlen;
lbaint_t written;
ret = mtd_read(mtd, erase_start, mtd->erasesize, &retlen, buf);
if (ret)
goto out;
if (retlen != mtd->erasesize) {
pr_err("mtdblock: failed to read block 0x%lx\n", cur);
ret = -EIO;
goto out;
}
memcpy(buf + offset, src, cur_size);
ret = mtd_erase_write(mtd, erase_start, buf);
if (ret)
goto out;
written = cur_size / sect_size;
blocks_todo -= written;
cur += written;
src += cur_size;
write_cnt += written;
- }
+out:
- free(buf);
- if (ret)
return ret;
- return write_cnt;
+}
+static int mtd_blk_probe(struct udevice *dev) +{
- struct blk_desc *bdesc;
- struct mtd_info *mtd;
- int ret;
- ret = device_probe(dev);
- if (ret) {
pr_err("Probing %s failed (err=%d)\n", dev->name, ret);
return ret;
- }
- bdesc = dev_get_uclass_plat(dev);
- mtd = blk_desc_to_mtd(bdesc);
- if (mtd_type_is_nand(mtd))
pr_warn("MTD device '%s' is NAND, please use UBI devices instead\n",
mtd->name);
- return 0;
+}
+static const struct blk_ops mtd_blk_ops = {
- .read = mtd_bread,
- .write = mtd_bwrite,
+};
+U_BOOT_DRIVER(mtd_blk) = {
- .name = "mtd_blk",
- .id = UCLASS_BLK,
- .ops = &mtd_blk_ops,
- .probe = mtd_blk_probe,
+}; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 09f5269887..9b997fadd1 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -26,6 +26,9 @@ #include <dm/device.h> #endif #include <dm/ofnode.h> +#if IS_ENABLED(CONFIG_BLK) +#include <blk.h> +#endif
#define MAX_MTD_DEVICES 32 #endif @@ -412,6 +415,15 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+#if IS_ENABLED(CONFIG_BLK) +static inline struct mtd_info *blk_desc_to_mtd(struct blk_desc *bdesc) +{
- return *((struct mtd_info **)dev_get_priv(bdesc->bdev));
+}
+int mtd_bind(struct udevice *dev, struct mtd_info **mtd); +#endif
- int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);