From patchwork Thu Apr 4 10:58:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Romanov X-Patchwork-Id: 1919770 X-Patchwork-Delegate: dario.binacchi@amarulasolutions.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=salutedevices.com header.i=@salutedevices.com header.a=rsa-sha256 header.s=mail header.b=nZlCVJaE; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4V9LP26932z1yYn for ; Thu, 4 Apr 2024 23:23:02 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 5BA9D8843C; Thu, 4 Apr 2024 14:22:37 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=salutedevices.com header.i=@salutedevices.com header.b="nZlCVJaE"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 412BF88415; Thu, 4 Apr 2024 12:58:39 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mx1.sberdevices.ru (mx1.sberdevices.ru [37.18.73.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 9DB4988436 for ; Thu, 4 Apr 2024 12:58:35 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=avromanov@salutedevices.com Received: from p-infra-ksmg-sc-msk01 (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 16FC4100018; Thu, 4 Apr 2024 13:58:35 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 16FC4100018 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1712228315; bh=PzL1M3/XY5p9G39RKLSSWRAqoSElVpFJ1QUGhmUVIHQ=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=nZlCVJaEUVpvW/U7PCPSrxAoG7UQKmclqWaRmI15XlSoeMq5PtkuzV410yNbboMbY C4e6MGN/IQqGbc34Vj0u70GZNB7Sd/Zvy4Kkt0f3Oe1cppC/rZKUMg6iUuSHQy7FDs Su0Xya+gv04N1FSm/50C5Zco2aKrdOlTyYOpvmNZdNuAqhMFqE4/aBk8VsQy6gt5pd qN28oWlThCr8rWqfc9PaOqXpDgC3UxXeIzAftMlip3SMmfGNd0Azcp4n3hNPzWu0Pu lJxXRHo7Oc+RRx93tof3IgkxtdC/rB5yRxRmzpRHTLCj8fKX/2ldOd+r5CicqUJ9D0 aLZncii2jKqbg== Received: from smtp.sberdevices.ru (p-i-exch-sc-m02.sberdevices.ru [172.16.192.103]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Thu, 4 Apr 2024 13:58:34 +0300 (MSK) Received: from user-A520M-DS3H.sigma.sbrf.ru (100.64.160.123) by p-i-exch-sc-m02.sberdevices.ru (172.16.192.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.40; Thu, 4 Apr 2024 13:58:33 +0300 From: Alexey Romanov To: , , , , , , , , , , , , , , , , , CC: , , Alexey Romanov Subject: [PATCH v3 2/3] drivers: introduce mtdblock abstraction Date: Thu, 4 Apr 2024 13:58:12 +0300 Message-ID: <20240404105813.1520732-3-avromanov@salutedevices.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240404105813.1520732-1-avromanov@salutedevices.com> References: <20240404105813.1520732-1-avromanov@salutedevices.com> MIME-Version: 1.0 X-Originating-IP: [100.64.160.123] X-ClientProxiedBy: p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) To p-i-exch-sc-m02.sberdevices.ru (172.16.192.103) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 184578 [Apr 04 2024] X-KSMG-AntiSpam-Version: 6.1.0.4 X-KSMG-AntiSpam-Envelope-From: avromanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 14 0.3.14 5a0c43d8a1c3c0e5b0916cc02a90d4b950c01f96, {Tracking_from_domain_doesnt_match_to}, 100.64.160.123:7.1.2; salutedevices.com:7.1.1; d41d8cd98f00b204e9800998ecf8427e.com:7.1.1; smtp.sberdevices.ru:7.1.1,5.0.1; 127.0.0.199:7.1.2, FromAlignment: s, ApMailHostAddress: 100.64.160.123 X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2024/04/04 07:34:00 #24651931 X-KSMG-AntiVirus-Status: Clean, skipped X-Mailman-Approved-At: Thu, 04 Apr 2024 14:22:35 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean MTD block - abstraction over MTD subsystem, allowing to read and write in blocks using BLK UCLASS. Signed-off-by: Alexey Romanov --- 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..e56fa49064 --- /dev/null +++ b/drivers/mtd/mtdblock.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MTD block - abstraction over MTD subsystem, allowing + * to read and write in blocks using BLK UCLASS. + * + * - Read algorithm: + * + * 1. Convert start block number to start address. + * 2. 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: + * + * 1. Convert start block number to start address. + * 2. Round this address down by mtd->erasesize. + * + * Erase addr Start addr + * | | + * v v + * +----------------+----------------+----------------+ + * | blksz | blksz | blksz | + * +----------------+----------------+----------------+ + * + * 3. Calculate offset between this two addresses. + * 4. 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 + * + * 5. Copy data from user buffer to temporary buffer with offset, + * calculated at step 3. + * 6. Erase and write mtd->erasesize bytes at erase address + * pointer using mtd_erase/mtd_write(). + * 7. Add to erase address pointer mtd->erasesize bytes. + * 8. goto 1 until the requested number of blocks have + * been written. + * + * (C) Copyright 2024 SaluteDevices, Inc. + * + * Author: Alexey Romanov + */ + +#include +#include +#include +#include +#include + +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_blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + 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_blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + 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_blk_read, + .write = mtd_blk_write, +}; + +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 #endif #include +#if IS_ENABLED(CONFIG_BLK) +#include +#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);