From patchwork Sun Oct 20 13:27:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?U2t5TGFrZSBIdWFuZyAo6buD5ZWf5r6kKQ==?= X-Patchwork-Id: 1999587 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; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=c6Not95p; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=RHerWdWA; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XWfTW3g81z1xvV for ; Mon, 21 Oct 2024 00:30:55 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=0PzV2XvPHJmqaHMNlSvExbNnPXG2TXNuG3ieDrY8NYo=; b=c6Not95pOqyOHo mWcEBHwI/X+1oh29HoN3XxB7/qnA5/NR85pcDFzs6hLUFi2f821dhEOdSr5KDRGT2JsoBcYtxO51U x6tDueCB3WMceACKLTfikj8HVm/sE1G+obe8BxAvKMlgj6v/P3iTqRS6Mp+uplZ7rICG2SzDsjYfX n/iobZc6g3DM8P6P2LJ08oBr3d8UtzSXc9epQpzjcLU6AUMgoX9l21L/eXfkKater36cRD0Mw/ARn 2NxNd5oOm1aD2YrMrVpkZiWVA3jQNojL3tjH3Lam7O2QFiCsKdOz+q93Mq9b326hjP8PMj294oDNW rHN98A/DthSmVCBf2PkQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1t2W18-00000004vvH-0is2; Sun, 20 Oct 2024 13:30:46 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1t2Vye-00000004vXG-1pRu; Sun, 20 Oct 2024 13:28:14 +0000 X-UUID: 24d01e588ee711ef82ff63e91e7eb18c-20241020 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=4GWSP202kE1ugZwHMnGXy7L1M5++8SvxO/XWigtfn0E=; b=RHerWdWA9uXm4hrWuoj4mZUIJoqV+ZgLLiIUbmXXIKQ5kDUxBKu2t6XlQG09vuCpLVdVhDxNjE6IWNB+NwHMJF+O/ZNk2kBjqxdrxCsBCSOWEtR9wDP8gan4BcPL/D1Ge/JwcbFUAlFnTTTcCO+iMjRXCh9pzye5Mu4ylOOrorw=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:f4786091-faa8-4c1a-b5f0-fa47ed707694,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:9e498941-8751-41b2-98dd-475503d45150,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 24d01e588ee711ef82ff63e91e7eb18c-20241020 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1090033545; Sun, 20 Oct 2024 06:28:07 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Sun, 20 Oct 2024 21:28:04 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Sun, 20 Oct 2024 21:28:04 +0800 From: Sky Huang To: Matthias Brugger , Miquel Raynal , AngeloGioacchino Del Regno , Richard Weinberger , Vignesh Raghavendra , Daniel Golle , Chia-Lin Kao , "Mika Westerberg" , Cheng Ming Lin , , , , CC: Steven Liu , Sky.Huang Subject: [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Date: Sun, 20 Oct 2024 21:27:19 +0800 Message-ID: <20241020132722.20565-2-SkyLake.Huang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> References: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--11.493500-8.000000 X-TMASE-MatchedRID: dY/STlX7LWI0Z9sXcK7F6V3oTRqVXDv5sXPI9D4Uri5aW2Ktn+I8/v5Q PMcorVJC8AyWk2NFMNZM8qdoCvOVvj13WcdbGR6Qtw+xHnsmQjPDHSNFHFxB801KG1YrOQW/Oqn cbTLK4XiFuNbf28fb6PCUhGX/S6sVNngTMoCUVRTkKCFOKwAEzO3+iQEtoSj401IIGqgAbw3Z6K rkcB2NwXa9QqC2Cxib3BTxUdcaKkIfE8yM4pjsD23U7j2vVURrxEHRux+uk8hfNjF5BHUO+5hdg toyVDGsvXehZr+2YIXDWemDa0iNuN+SRkUpHtt1peNVPeL5BOo= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--11.493500-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 893E3C62F29F17B06B98F8A0F5729048C8707D38DE12E4F30D58DAF9AF2EB93C2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241020_062812_512689_B713C826 X-CRM114-Status: GOOD ( 21.28 ) X-Spam-Score: -2.1 (--) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: "Sky.Huang" Create drivers/mtd/nand/param.c so ONFI parameter page & CASN page can both use nanddev_crc16() and nanddev_bit_wise_majority() directly like this: * For ONFI Parameter page: onfi_crc16() -> nanddev_c [...] Content analysis details: (-2.1 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in sa-accredit.habeas.com] 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in sa-trusted.bondedsender.org] 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in bl.score.senderscore.com] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: "Sky.Huang" Create drivers/mtd/nand/param.c so ONFI parameter page & CASN page can both use nanddev_crc16() and nanddev_bit_wise_majority() directly like this: * For ONFI Parameter page: onfi_crc16() -> nanddev_crc16() * For CASN page: nanddev_crc16() nanddev_bit_wise_majority() is same as nand_bit_wise_majority(). nanddev_crc16() is same as onfi_crc16(). But there are lots of onfi_crc16() call, so keep onfi_crc16() there and hook it to nanddev_crc16(). Signed-off-by: Sky Huang --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/param.c | 52 ++++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/nand_onfi.c | 43 ++------------------------ include/linux/mtd/param.h | 20 ++++++++++++ 4 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 drivers/mtd/nand/param.c create mode 100644 include/linux/mtd/param.h diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 19e1291ac4d5..790bde0148d1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -nandcore-objs := core.o bbt.o +nandcore-objs := core.o bbt.o param.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o diff --git a/drivers/mtd/nand/param.c b/drivers/mtd/nand/param.c new file mode 100644 index 000000000000..f67b9fe633d9 --- /dev/null +++ b/drivers/mtd/nand/param.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang + */ + +#include + +u16 nanddev_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* + * Recover data with bit-wise majority + */ +void nanddev_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize) +{ + int i, j, k; + + for (i = 0; i < bufsize; i++) { + u8 val = 0; + + for (j = 0; j < 8; j++) { + unsigned int cnt = 0; + + for (k = 0; k < nsrcbufs; k++) { + const u8 *srcbuf = srcbufs[k]; + + if (srcbuf[i] & BIT(j)) + cnt++; + } + + if (cnt > nsrcbufs / 2) + val |= BIT(j); + } + + ((u8 *)dstbuf)[i] = val; + } +} diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 861975e44b55..5d330dd53e8f 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -12,6 +12,7 @@ * This file contains all ONFI helpers. */ +#include #include #include "internals.h" @@ -20,14 +21,7 @@ u16 onfi_crc16(u16 crc, u8 const *p, size_t len) { - int i; - while (len--) { - crc ^= *p++ << 8; - for (i = 0; i < 8; i++) - crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); - } - - return crc; + return nanddev_crc16(crc, p, len); } /* Parse the Extended Parameter Page. */ @@ -107,37 +101,6 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, return ret; } -/* - * Recover data with bit-wise majority - */ -static void nand_bit_wise_majority(const void **srcbufs, - unsigned int nsrcbufs, - void *dstbuf, - unsigned int bufsize) -{ - int i, j, k; - - for (i = 0; i < bufsize; i++) { - u8 val = 0; - - for (j = 0; j < 8; j++) { - unsigned int cnt = 0; - - for (k = 0; k < nsrcbufs; k++) { - const u8 *srcbuf = srcbufs[k]; - - if (srcbuf[i] & BIT(j)) - cnt++; - } - - if (cnt > nsrcbufs / 2) - val |= BIT(j); - } - - ((u8 *)dstbuf)[i] = val; - } -} - /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -200,7 +163,7 @@ int nand_onfi_detect(struct nand_chip *chip) srcbufs[j] = pbuf + j; pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n"); - nand_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf, + nanddev_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf, sizeof(*pbuf)); crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)pbuf, 254); diff --git a/include/linux/mtd/param.h b/include/linux/mtd/param.h new file mode 100644 index 000000000000..39636f66f1b4 --- /dev/null +++ b/include/linux/mtd/param.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang + */ + +#ifndef __LINUX_NAND_PARAM +#define __LINUX_NAND_PARAM + +#include + +u16 nanddev_crc16(u16 crc, u8 const *p, size_t len); +void nanddev_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize); + +#endif /* __LINUX_NAND_PARAM */ + From patchwork Sun Oct 20 13:27:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?U2t5TGFrZSBIdWFuZyAo6buD5ZWf5r6kKQ==?= X-Patchwork-Id: 1999588 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; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=LU4jMxAz; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=WldJ++BG; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XWfWD60Mgz1xvV for ; Mon, 21 Oct 2024 00:32:24 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=lYOwUl1Ll5XmwBFImM3jyvDA/ZwLqE7DTC+zzFawQ9Y=; b=LU4jMxAz47pwt/ ipQ8le70CateEAZP+aj0YOf9b/qNSjuALe3kVUNuKZ7T8CWznVPcFCekIxUDHktDz5a9p/d3jMSyk lxnlaeOWyXbVFKzgnG4ce4b2emfILmtbgWCEFi9uZzeQCY/IyIxneJBtk/qHJlTYNs8E4AqHace9L FC79H/EcWfGmmlFV3TlDfc5UQL8rKjU1MJP3JT8Z7sfJWzCIlGl00nfrfrI+g8PG+vPgASqp+sGB3 uomIQqpQ3Mn0sRJu9cz93LEMLLtzw487D1UohcifIqZWIp1HEYxIcjWTnYa7g8G3MBR8zcRwvWqJ7 wGQR+kIAZx6jHBlJ8JqQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1t2W2a-00000004w8A-0BEk; Sun, 20 Oct 2024 13:32:16 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1t2Vz3-00000004vcQ-17WY; Sun, 20 Oct 2024 13:28:39 +0000 X-UUID: 33925bfe8ee711ef82ff63e91e7eb18c-20241020 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=u4Q+MpwvDdBjqr/mZ0lChqQSwuAsSECFSr3oxS9NmH4=; b=WldJ++BGMIeqr7QJZLXsYfFpempzCIrhA07pdDrI7FO7eS8EAP9rMkb/CxMo9BOR6n1EzamikZ6fnVonM5Ghvs7et9p1mEDuFvf9UExHzIYduQeggV6SJ5rxQz9tGxDQW4R8tj7UOq+m1h5H847mxqdrS1aCrZZaxWtXw5HP8uk=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:e60f6cd1-447c-4014-8305-012ea204429d,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:60255925-9cd9-4037-af6e-f4241b90f84d,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULS X-UUID: 33925bfe8ee711ef82ff63e91e7eb18c-20241020 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 436932117; Sun, 20 Oct 2024 06:28:32 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS09N1.mediatek.inc (172.21.101.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Sun, 20 Oct 2024 21:28:29 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Sun, 20 Oct 2024 21:28:29 +0800 From: Sky Huang To: Matthias Brugger , Miquel Raynal , AngeloGioacchino Del Regno , Richard Weinberger , Vignesh Raghavendra , Daniel Golle , Chia-Lin Kao , Mika Westerberg , Cheng Ming Lin , , , , CC: Steven Liu , Sky Huang Subject: [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs. Date: Sun, 20 Oct 2024 21:27:20 +0800 Message-ID: <20241020132722.20565-3-SkyLake.Huang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> References: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241020_062837_341048_ECDF5AAC X-CRM114-Status: GOOD ( 13.42 ) X-Spam-Score: -2.1 (--) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: "Sky Huang" This patch adds CASN page definition. You can see corresponding table in CASN page application note referred in cover letter. (https://github.com/mtk-openwrt/doc/blob/ main/CASN%20Page%20Introduction. [...] Content analysis details: (-2.1 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in sa-trusted.bondedsender.org] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in sa-accredit.habeas.com] 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.184 listed in bl.score.senderscore.com] 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: "Sky Huang" This patch adds CASN page definition. You can see corresponding table in CASN page application note referred in cover letter. (https://github.com/mtk-openwrt/doc/blob/ main/CASN%20Page%20Introduction.pdf) Signed-off-by: Sky Huang --- include/linux/mtd/casn.h | 191 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 include/linux/mtd/casn.h diff --git a/include/linux/mtd/casn.h b/include/linux/mtd/casn.h new file mode 100644 index 000000000000..65ebd23c17c1 --- /dev/null +++ b/include/linux/mtd/casn.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang + */ + +#ifndef __LINUX_MTD_CASN_H +#define __LINUX_MTD_CASN_H + +#define CASN_CRC_BASE 0x4341 +#define CASN_SIGNATURE 0x4341534EU +#define SPINAND_CASN_V1_CRC_OFS (254) +#define CASN_PAGE_V1_COPIES (3) + +#define SDR_READ_1_1_1 BIT(0) +#define SDR_READ_1_1_1_FAST BIT(1) +#define SDR_READ_1_1_2 BIT(2) +#define SDR_READ_1_2_2 BIT(3) +#define SDR_READ_1_1_4 BIT(4) +#define SDR_READ_1_4_4 BIT(5) +#define SDR_READ_1_1_8 BIT(6) +#define SDR_READ_1_8_8 BIT(7) + +#define SDR_WRITE_1_1_1 BIT(0) +#define SDR_WRITE_1_1_4 BIT(1) + +#define SDR_UPDATE_1_1_1 BIT(0) +#define SDR_UPDATE_1_1_4 BIT(1) + +struct op_slice { + u8 cmd_opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 dummy_nbytes : 4; + u8 addr_nbytes : 4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 addr_nbytes : 4; + u8 dummy_nbytes : 4; +#endif +}; + +struct SPINAND_FLAGS { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 has_qe_bit : 1; + u8 has_cr_feat_bit : 1; + u8 conti_read_cap : 1; + u8 on_die_ecc : 1; + u8 legacy_ecc_status : 1; + u8 adv_ecc_status : 1; + u8 ecc_parity_readable : 1; + u8 ecc_alg : 1; /* ECC algorithm */ +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 ecc_alg : 1; /* ECC algorithm */ + u8 ecc_parity_readable : 1; + u8 adv_ecc_status : 1; + u8 legacy_ecc_status : 1; + u8 on_die_ecc : 1; + u8 conti_read_cap : 1; + u8 has_cr_feat_bit : 1; + u8 has_qe_bit : 1; +#endif +}; + +struct ADV_ECC_STATUS { + u8 cmd; + u8 addr; + u8 addr_nbytes; + u8 addr_buswidth; + u8 dummy_nbytes; + u8 dummy_buswidth; + u8 status_nbytes; + u16 status_mask; + u8 pre_op; /* pre-process operator */ + u8 pre_mask; /* pre-process mask */ +} __packed; + +struct CASN_OOB { + u8 layout_type; + + /* OOB free layout */ + u8 free_start; + u8 free_length; + u8 bbm_length; + + /* ECC parity layout */ + u8 ecc_parity_start; + u8 ecc_parity_space; + u8 ecc_parity_real_length; +}; + +enum oob_overall { + OOB_DISCRETE = 0, + OOB_CONTINUOUS, +}; + +struct nand_casn { + /* CASN signature must be 4 chars: 'C','A','S','N' */ + union { + u8 sig[4]; + u32 signature; + }; + + u8 version; + char manufacturer[13]; + char model[16]; + + __be32 bits_per_cell; + __be32 bytes_per_page; + __be32 spare_bytes_per_page; + __be32 pages_per_block; + __be32 blocks_per_lun; + __be32 max_bb_per_lun; + __be32 planes_per_lun; + __be32 luns_per_target; + __be32 total_target; + + __be32 ecc_strength; + __be32 ecc_step_size; + + u8 flags; + u8 reserved1; + + __be16 sdr_read_cap; + struct op_slice sdr_read_1_1_1; + struct op_slice sdr_read_1_1_1_fast; + struct op_slice sdr_read_1_1_2; + struct op_slice sdr_read_1_2_2; + struct op_slice sdr_read_1_1_4; + struct op_slice sdr_read_1_4_4; + struct op_slice sdr_read_1_1_8; + struct op_slice sdr_read_1_8_8; + + struct op_slice sdr_cont_read_1_1_1; + struct op_slice sdr_cont_read_1_1_1_fast; + struct op_slice sdr_cont_read_1_1_2; + struct op_slice sdr_cont_read_1_2_2; + struct op_slice sdr_cont_read_1_1_4; + struct op_slice sdr_cont_read_1_4_4; + struct op_slice sdr_cont_read_1_1_8; + struct op_slice sdr_cont_read_1_8_8; + + __be16 ddr_read_cap; + struct op_slice ddr_read_1_1_1; + struct op_slice ddr_read_1_1_1_fast; + struct op_slice ddr_read_1_1_2; + struct op_slice ddr_read_1_2_2; + struct op_slice ddr_read_1_1_4; + struct op_slice ddr_read_1_4_4; + struct op_slice ddr_read_1_1_8; + struct op_slice ddr_read_1_8_8; + + struct op_slice ddr_cont_read_1_1_1; + struct op_slice ddr_cont_read_1_1_1_fast; + struct op_slice ddr_cont_read_1_1_2; + struct op_slice ddr_cont_read_1_2_2; + struct op_slice ddr_cont_read_1_1_4; + struct op_slice ddr_cont_read_1_4_4; + struct op_slice ddr_cont_read_1_1_8; + struct op_slice ddr_cont_read_1_8_8; + + u8 sdr_write_cap; + struct op_slice sdr_write_1_1_1; + struct op_slice sdr_write_1_1_4; + struct op_slice reserved2[6]; + u8 ddr_write_cap; + struct op_slice reserved3[8]; + + u8 sdr_update_cap; + struct op_slice sdr_update_1_1_1; + struct op_slice sdr_update_1_1_4; + struct op_slice reserved4[6]; + u8 ddr_update_cap; + struct op_slice reserved5[8]; + + struct CASN_OOB casn_oob; + + /* Advanced ECC status CMD0 (higher bits) */ + struct ADV_ECC_STATUS ecc_status_high; + /* Advanced ECC status CMD1 (lower bits) */ + struct ADV_ECC_STATUS ecc_status_low; + + u8 advecc_noerr_status; + u8 advecc_uncor_status; + u8 advecc_post_op; + u8 advecc_post_mask; + + u8 reserved6[5]; + __be16 crc; +} __packed; + +#endif /* __LINUX_MTD_CASN_H */ From patchwork Sun Oct 20 13:27:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?U2t5TGFrZSBIdWFuZyAo6buD5ZWf5r6kKQ==?= X-Patchwork-Id: 1999589 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; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=l+IMB8HI; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=jpyzAVCH; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XWfXy484Hz1xwK for ; Mon, 21 Oct 2024 00:33:54 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ylAjrvvf29Pp9QoT7qYCwgqRGaTzTbmiRaQBAUOHpxY=; b=l+IMB8HI9uLpuS AC524wIJmpBpnvKm1pAw6kq2b2cBJ4j+aaKOUNGm9b3unakFCZwNCuUk3mp5ygTaqqHPX+NJHDD01 H3Q5FyElXAeDV1+kQ1QfpEZTlzW34CmE/n0Hlsp85Ogup6L/0HkRS1Wu7C28xXetQHWCv/tdF8feH LrVh6hB5yLqlEF9Exx1u8F8KiCgZtQ2MtaXoOEtZ1mCXrX9+HyEY/FHCaBU6l4MiIywrcaUrTGJu7 3U0Z9nt6sw0b/Ib7PDoEXJqISNXRp4emA/2iWuXjlpsrazdb61jC2TcTboJwnP2NsN8MrmImCSz/y bi4xYp+In1iEdSPvm7+Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1t2W41-00000004wHq-0Odr; Sun, 20 Oct 2024 13:33:45 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1t2VzG-00000004vdj-07po; Sun, 20 Oct 2024 13:28:53 +0000 X-UUID: 3b91e3108ee711ef9048ed6ed365623b-20241020 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=2G1oHhlieHVhAY567gkNMmzlsnu2+sPvTe7p5o7ZsNk=; b=jpyzAVCHpGKDVyz8vX5qobQk0Iy/BG/4AZxBSHZzpLF6NiWwCoPA1CY3Jgz8U5ZOfSsT0tvaXCY0kvBTQyH4yyAsk0IzDtkEbXhTw6x8s1L3mIpnt7G0FNjZ2FfeG/Fbv8eVkJRfwYBftE6e+ARw0CE1OTGhow+KHp60/tUgeWo=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:108a9adc-8b7f-4de6-9e44-1b51ddabe879,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:af255925-9cd9-4037-af6e-f4241b90f84d,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 3b91e3108ee711ef9048ed6ed365623b-20241020 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1982015101; Sun, 20 Oct 2024 06:28:45 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by MTKMBS14N2.mediatek.inc (172.21.101.76) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Sun, 20 Oct 2024 21:28:42 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Sun, 20 Oct 2024 21:28:42 +0800 From: Sky Huang To: Matthias Brugger , Miquel Raynal , AngeloGioacchino Del Regno , Richard Weinberger , Vignesh Raghavendra , Daniel Golle , Chia-Lin Kao , "Mika Westerberg" , Cheng Ming Lin , , , , CC: Steven Liu , Sky Huang Subject: [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags. Date: Sun, 20 Oct 2024 21:27:21 +0800 Message-ID: <20241020132722.20565-4-SkyLake.Huang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> References: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--2.446200-8.000000 X-TMASE-MatchedRID: oCsWEly1aNNM4VjZ76ar2LMjW/sniEQKmX+W7bzPOQF+YesuCgkiXJpx JPA5ZIe+2lO9wdJIjwWwYEHOVohSR8a1KU/oEEOPogGd8wIUGIJo3Yq5PCwLAhL6MU7t349bo7e vliYi17DYcB744kzEdqnConkZyCes/Y8bXtyBbJB0CDjJ3XioBPBkYT/50xzWf7dwGsQvXvzIrf 3gn7w8oqP8wcVXpl7OgzXM/1S8rGibGHSBj+j5Wd35+5/2RxqmCv3j7wdXxBibKItl61J/yZ+in TK0bC9eKrauXd3MZDX371moSn0VOL9msMtG43RP5Oy4n7TTsM8D5mBwNiJFK4Dro/jMlndlBrNs Id/ubdefkcesyQmuoXXWg7RXgpNfEi71zuMNe2ygzDosNXeeAhdGg+ZY7eN6THB2Q+oKru8MTI3 4nyF36MJL1aANdU8Knqg/VrSZEiM= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--2.446200-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 7EF0422110CF8F2371BA6587828AFCBCFFF5F5E629928B88ECDE63BE23BB0CB12000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241020_062850_208328_CC139373 X-CRM114-Status: GOOD ( 15.65 ) X-Spam-Score: -2.1 (--) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: "Sky Huang" This patch adds SPINAND CASN page manipulation macros for SPI-NAND driver to use. Also, some important flag bits, like SPINAND_SUPR_CR(continuous read), are added to show the SPI-NAND device's capabil [...] Content analysis details: (-2.1 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in sa-accredit.habeas.com] 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in sa-trusted.bondedsender.org] 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in bl.score.senderscore.com] 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: "Sky Huang" This patch adds SPINAND CASN page manipulation macros for SPI-NAND driver to use. Also, some important flag bits, like SPINAND_SUPR_CR(continuous read), are added to show the SPI-NAND device's capability. Signed-off-by: Sky Huang --- include/linux/mtd/spinand.h | 100 +++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 702e5fb13dae..de97994c357b 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -62,6 +62,59 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) +/* Macros for CASN */ +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_OP(fast, naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X2_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_DUALIO_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 2), \ + SPI_MEM_OP_DUMMY(ndummy, 2), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X4_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_QUADIO_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 4), \ + SPI_MEM_OP_DUMMY(ndummy, 4), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +#define SPINAND_CASN_PROG_LOAD(reset, naddr, addr, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(len, buf, 1)) + +#define SPINAND_CASN_PROG_LOAD_X4(reset, naddr, addr, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(len, buf, 4)) + +#define SPINAND_CASN_ADVECC_OP(casn_adv_ecc_status, buf) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(casn_adv_ecc_status.cmd, 1), \ + SPI_MEM_OP_ADDR(casn_adv_ecc_status.addr_nbytes, \ + casn_adv_ecc_status.addr, \ + casn_adv_ecc_status.addr_buswidth), \ + SPI_MEM_OP_DUMMY(casn_adv_ecc_status.dummy_nbytes, \ + casn_adv_ecc_status.dummy_buswidth), \ + SPI_MEM_OP_DATA_IN(casn_adv_ecc_status.status_nbytes, buf, 1)) +/* Macros for CASN end */ + #define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ @@ -312,8 +365,11 @@ struct spinand_ecc_info { #define SPINAND_HAS_QE_BIT BIT(0) #define SPINAND_HAS_CR_FEAT_BIT BIT(1) -#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) -#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) +#define SPINAND_SUP_CR BIT(2) +#define SPINAND_SUP_ON_DIE_ECC BIT(3) +#define SPINAND_SUP_LEGACY_ECC_STATUS BIT(4) +#define SPINAND_SUP_ADV_ECC_STATUS BIT(5) +#define SPINAND_ECC_PARITY_READABLE BIT(6) /** * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure @@ -406,6 +462,28 @@ struct spinand_dirmap { struct spi_mem_dirmap_desc *rdesc_ecc; }; +/** + * struct CASN_ADVECC - CASN's advanced ECC description + * @cmd: Command to access SPI-NAND on-chip ECC status registers + * @mask: Mask to access SPI-NAND on-chip ECC status registers. + * ADV_ECC_STATUS->status_nbytes | CASN_ADVECC->mask + * 1 | 0 to 0xff + * 2 | 0 to 0xffff + * @shift: How many bits to shift to get on-chip ECC status + * @pre_op: This comes from CASN page's ADV_ECC_STATUS's pre_op. + * After reading on-chip ECC status, we need to do some math + * operations if this is specified. + * @pre_mask: This comes from CASN page's ADV_ECC_STATUS's pre_mask. + * This is used in companion with pre_op above. + */ +struct CASN_ADVECC { + u8 cmd; + u16 mask; + u8 shift; + u8 pre_op; + u8 pre_mask; +}; + /** * struct spinand_device - SPI NAND device instance * @base: NAND device instance @@ -464,6 +542,23 @@ struct spinand_device { u8 *oobbuf; u8 *scratchbuf; const struct spinand_manufacturer *manufacturer; + + bool use_casn; + struct nand_casn *casn; + struct spi_mem_op *advecc_high_ops; /* ops to read higher part of advanced ECC status*/ + struct spi_mem_op *advecc_low_ops; + struct CASN_OOB *casn_oob; + struct CASN_ADVECC *advecc_high; + struct CASN_ADVECC *advecc_low; + + u8 advecc_low_bitcnt; + u8 advecc_noerr_status; + u8 advecc_uncor_status; + u8 advecc_post_op; + u8 advecc_post_mask; + + size_t (*eccsr_math_op[4])(size_t, size_t); + void *priv; bool cont_read_possible; @@ -539,3 +634,4 @@ int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val); int spinand_select_target(struct spinand_device *spinand, unsigned int target); #endif /* __LINUX_MTD_SPINAND_H */ + From patchwork Sun Oct 20 13:27:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?U2t5TGFrZSBIdWFuZyAo6buD5ZWf5r6kKQ==?= X-Patchwork-Id: 1999590 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; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=1n1z3vls; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=SQC9+Cvn; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XWfZl4tqmz1xwK for ; Mon, 21 Oct 2024 00:35:27 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=45/jlbbMrPBYYvdjTcP8M5lVZVeYJ/wfsOSc274ScDo=; b=1n1z3vls1YpM9a KPdVOV8d/l/wqQqIm3OinkyMStjgeo0iDCkY4P4D/jOEiJ9d9IJ3pR1z96mUEAViGEvoYiL/W/fJ8 n5oA2kM1WoZw2KhaW9v3M/1pj4kpftt8lGqgLlMLwhOkpPiWL8/PK9HyAgD9g4p9FTVrKj4oETP5Q QZmuYt2X7q2EYn/yemaxAnNMBgN8QaDTIer5uyZbaHOHUq4MkYgxXerZo8wYygG12LZcgIflhPIkW OYIw/I0ToMLtHReyxq+PDHy8mZ9taH2F7YoLDrwMRM7wCUsZz8YDdx5Kkb2dOPVq1Yyi2fAieGaWg DDeeiIwvejIwKUxd4K6w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1t2W5S-00000004wU5-0QTw; Sun, 20 Oct 2024 13:35:14 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1t2VzY-00000004vil-03an; Sun, 20 Oct 2024 13:29:10 +0000 X-UUID: 468336168ee711ef9048ed6ed365623b-20241020 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=ICByNUPg0Iy6Y7kVIRAl7dHZrrdeU90KoDn/qQyaETA=; b=SQC9+Cvnz7/+an9Y0ByBPnBcsR9WkIdcEtInQSZU/F5GanvH6wLVIsqHSAbGO1YkF5fBE5ONhIhT9VJ6SWG0v8GTN1Ru04OU0CYu+3OQ2auewF8GgvbT86bk+RdC8jfXpDal8b/0Qq0cZWS+EBnfJQX/YaNv3Q6SLQ2qOsn9LoY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.42,REQID:47a63205-bb36-43c8-8875-7f31305b369a,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:b0fcdc3,CLOUDID:ab4a8941-8751-41b2-98dd-475503d45150,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES :1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: 468336168ee711ef9048ed6ed365623b-20241020 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1707849671; Sun, 20 Oct 2024 06:29:04 -0700 Received: from mtkmbs13n1.mediatek.inc (172.21.101.193) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Sun, 20 Oct 2024 21:29:01 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Sun, 20 Oct 2024 21:29:00 +0800 From: Sky Huang To: Matthias Brugger , Miquel Raynal , AngeloGioacchino Del Regno , Richard Weinberger , Vignesh Raghavendra , Daniel Golle , Chia-Lin Kao , "Mika Westerberg" , Cheng Ming Lin , , , , CC: Steven Liu , Sky Huang Subject: [RFC PATCH nand/next 4/4] mtd: nand: spi: Add CASN page support Date: Sun, 20 Oct 2024 21:27:22 +0800 Message-ID: <20241020132722.20565-5-SkyLake.Huang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> References: <20241020132722.20565-1-SkyLake.Huang@mediatek.com> MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--9.444200-8.000000 X-TMASE-MatchedRID: /bKxxJqDGVcwE0n9oAwkPXtItsHAduPxBGvINcfHqhdNZ/CnTeI8lmEj qlizhhlNpJ0OYMrT0yma/3zDweDPK1SU1d+VJ4IjGVyS87Wb4lyscK/K2DlvjsA0eOJZYj7tx+W T4fjiMGeFuNbf28fb6Lrw3PfJA6xhZz86fqAj7POEJ5wBUYI5/ZnaxzJFBx6vXCmcAC8DBrPQ1I IT+AWI0blK18H/cd3hp8qiS2HjSrPM2WV/gPPibLE3FpMbg63SKVrLOZD1BXTxxaAXDrCns0Z3u pZH64zDo+u9XRmCBoTuKpag/ZE3vbPmM/zWNUUfEdFsavUQKAeYZJKiXhR6LUYx760ONDcWhzQH k5Qv+7VS2oPdDIIOObiW/VRR7ZTRZ1otclUep4/d+fuf9kcaplo1rFkFFs1ayGbI60ZH8Wb6rx1 jnOZw+qrnKAj6elaaIp2nL7ZFABfMHUInqqZ02s36paW7ZnFo5Y0kb0hqatzRziMbBeTI+R6AtY tAKdbYZflHUyH8MzPv6gcLh2moHiBPHVH0QwOY9Ib/6w+1lWSjkoGZwmjMNpsoi2XrUn/JUTdY/ mdfTXtJKW4mDlJsMcK21zBg2KlfyMdyHKes7lse67lDQhMclzJ9Yj2F3cvEMgX+XpjX0UPPTy7H 7An6Fg== X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--9.444200-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 91FD138A61C70715A0CA3900CBE42C26709F1E28979A36A6B50440177768D9C72000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241020_062908_160942_F759886D X-CRM114-Status: GOOD ( 25.03 ) X-Spam-Score: -2.1 (--) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: "Sky Huang" This patch implements how CASN page detection works for SPI-NAND and how CASN page interprets ECC information of all SPI-NAND flash vendors. Probe flow will become like this: * If CASN page exists, check its validity. --> If a certain CASN page is valid, we will know the SPI-NAND device's information, including memory organization, flash o [...] Content analysis details: (-2.1 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in sa-trusted.bondedsender.org] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in sa-accredit.habeas.com] 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [216.200.240.185 listed in bl.score.senderscore.com] 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: "Sky Huang" This patch implements how CASN page detection works for SPI-NAND and how CASN page interprets ECC information of all SPI-NAND flash vendors. Probe flow will become like this: * If CASN page exists, check its validity. --> If a certain CASN page is valid, we will know the SPI-NAND device's information, including memory organization, flash on-chip ECC engine's design, etc. * If CASN page doesn't exist, switch to reading ID spinand_dump_casn() can be moved to sysfs, debugfs or something else later, I guess. Signed-off-by: Sky Huang --- drivers/mtd/nand/spi/core.c | 741 +++++++++++++++++++++++++++++++++++- 1 file changed, 729 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4d76f9f71a0e..7d7408e00b5e 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -9,10 +9,13 @@ #define pr_fmt(fmt) "spi-nand: " fmt +#include #include #include #include #include +#include +#include #include #include #include @@ -20,6 +23,8 @@ #include #include +extern void sanitize_string(uint8_t *s, size_t len); + static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg, @@ -200,6 +205,63 @@ static int spinand_ecc_enable(struct spinand_device *spinand, enable ? CFG_ECC_ENABLE : 0); } +static size_t eccsr_none_op(size_t val, size_t mask) { return val; } +static size_t eccsr_and_op(size_t val, size_t mask) { return val & mask; } +static size_t eccsr_add_op(size_t val, size_t mask) { return val + mask; } +static size_t eccsr_minus_op(size_t val, size_t mask) { return val - mask; } +static size_t eccsr_mul_op(size_t val, size_t mask) { return val * mask; } + +static void spinand_read_adv_ecc(struct spinand_device *spinand, + struct spi_mem_op *ops, u16 *eccsr, + u16 mask, u8 shift, + u8 pre_op, u8 pre_mask) +{ + u8 *p = spinand->scratchbuf; + + spi_mem_exec_op(spinand->spimem, ops); + + if (likely(mask <= 0xff)) + *eccsr += (*p & mask) >> shift; + else + *eccsr += (((*p << 8) | (*p+1)) & mask) >> shift; + + *eccsr = spinand->eccsr_math_op[pre_op](*eccsr, pre_mask); +} + +static int spinand_casn_get_ecc_status(struct spinand_device *spinand, + u8 status) +{ + struct mtd_info *mtd = spinand_to_mtd(spinand); + struct CASN_ADVECC *ah = spinand->advecc_high; + struct CASN_ADVECC *al = spinand->advecc_low; + u16 eccsr_high = 0; + u16 eccsr_low = 0; + u32 eccsr = 0; + + if (al->cmd) { + spinand_read_adv_ecc(spinand, + spinand->advecc_low_ops, &eccsr_low, + al->mask, al->shift, + al->pre_op, al->pre_mask); + eccsr += eccsr_low; + } + if (ah->cmd) { + spinand_read_adv_ecc(spinand, + spinand->advecc_high_ops, &eccsr_high, + ah->mask, ah->shift, + ah->pre_op, ah->pre_mask); + eccsr += eccsr_high << spinand->advecc_low_bitcnt; + } + + if (eccsr == spinand->advecc_noerr_status) + return 0; + else if (eccsr == spinand->advecc_uncor_status) + return -EBADMSG; + eccsr = spinand->eccsr_math_op[spinand->advecc_post_op](eccsr, spinand->advecc_post_mask); + + return eccsr > mtd->ecc_strength ? mtd->ecc_strength : eccsr; +} + static int spinand_cont_read_enable(struct spinand_device *spinand, bool enable) { @@ -1149,6 +1211,242 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, return -EOPNOTSUPP; } +static int spinand_check_casn_validity(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct device *dev = &spinand->spimem->spi->dev; + + if (be32_to_cpu(casn->bits_per_cell) != 1) { + dev_err(dev, "[CASN] bits-per-cell must be 1\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->bytes_per_page)) { + case 2048: + case 4096: + break; + default: + dev_err(dev, "[CASN] page size must be 2048/4096\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->spare_bytes_per_page)) { + case 64: + case 96: + case 128: + case 256: + break; + default: + dev_err(dev, "[CASN] spare size must be 64/128/256\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->pages_per_block)) { + case 64: + case 128: + break; + default: + dev_err(dev, "[CASN] pages_per_block must be 64/128\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->blocks_per_lun)) { + case 1024: + if (be32_to_cpu(casn->max_bb_per_lun) != 20) { + dev_err(dev, "[CASN] max_bb_per_lun must be 20 when blocks_per_lun is 1024\n"); + return -EINVAL; + } + break; + case 2048: + if (be32_to_cpu(casn->max_bb_per_lun) != 40) { + dev_err(dev, "[CASN] max_bb_per_lun must be 40 when blocks_per_lun is 2048\n"); + return -EINVAL; + } + break; + case 4096: + if (be32_to_cpu(casn->max_bb_per_lun) != 80) { + dev_err(dev, "[CASN] max_bb_per_lun must be 80 when blocks_per_lun is 4096\n"); + return -EINVAL; + } + break; + default: + dev_err(dev, "[CASN] blocks_per_lun must be 1024/2048/4096\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->planes_per_lun)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] planes_per_lun must be 1/2\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->luns_per_target)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] luns_per_target must be 1/2\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->total_target)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] ntargets must be 1/2\n"); + return -EINVAL; + } + + if (casn->casn_oob.layout_type != OOB_CONTINUOUS && + casn->casn_oob.layout_type != OOB_DISCRETE) { + dev_err(dev, "[CASN] OOB layout type isn't correct.\n"); + return -EINVAL; + } + + if (casn->ecc_status_high.status_nbytes > 2 || + casn->ecc_status_low.status_nbytes > 2) { + dev_err(dev, "[CASN] ADVECC status nbytes must be no more than 2\n"); + return -EINVAL; + } + + return 0; +} + +static int spinand_check_casn(struct spinand_device *spinand, + struct nand_casn *casn, unsigned int *sel) +{ + struct device *dev = &spinand->spimem->spi->dev; + uint16_t crc = be16_to_cpu(casn->crc); + uint16_t crc_compute; + int ret = 0; + int i; + + /* There are 3 copies of CASN Pages V1. Choose one avabilable copy + * first. If none of the copies is available, try to recover. + */ + for (i = 0; i < CASN_PAGE_V1_COPIES; i++) { + if (be32_to_cpu(casn[i].signature) != CASN_SIGNATURE) { + ret = -EINVAL; + continue; + } + crc_compute = nanddev_crc16(CASN_CRC_BASE, (u8 *)(casn + i), + SPINAND_CASN_V1_CRC_OFS); + dev_dbg(dev, "CASN COPY %d CRC read: 0x%x, compute: 0x%x\n", + i, crc, crc_compute); + if (crc != crc_compute) { + ret = -EBADMSG; + continue; + } + ret = spinand_check_casn_validity(spinand, casn + i); + if (ret < 0) + continue; + *sel = i; + break; + } + + if (i == CASN_PAGE_V1_COPIES && ret == -EBADMSG) { + const void *srcbufs[CASN_PAGE_V1_COPIES]; + int j; + + for (j = 0; j < CASN_PAGE_V1_COPIES; j++) + srcbufs[j] = casn + j; + dev_info(dev, "Couldn't find a valid CASN page, try bitwise majority to recover it\n"); + nanddev_bit_wise_majority(srcbufs, CASN_PAGE_V1_COPIES, casn, + sizeof(*casn)); + crc_compute = nanddev_crc16(CASN_CRC_BASE, (uint8_t *)casn, + SPINAND_CASN_V1_CRC_OFS); + if (crc_compute != crc) { + dev_err(dev, "CASN page recovery failed, aborting\n"); + return -EBADMSG; + } + ret = spinand_check_casn_validity(spinand, casn + i); + if (ret < 0) + return ret; + dev_info(dev, "CASN page recovery succeeded\n"); + *sel = 0; + } + + return ret; +} + +static int spinand_casn_detect(struct spinand_device *spinand, + struct nand_casn *casn, unsigned int *sel) +{ + struct device *dev = &spinand->spimem->spi->dev; + uint8_t casn_offset[3] = {0x0, 0x1, 0x4}; + struct nand_page_io_req req; + struct spi_mem_op op; + struct nand_pos pos; + int check_ret = 0; + uint8_t status; + int final_ret; + int ret = 0; + u8 cfg_reg; + int i; + + ret = spinand_read_reg_op(spinand, REG_CFG, &cfg_reg); + if (ret) + return ret; + + ret = spinand_write_reg_op(spinand, REG_CFG, cfg_reg | BIT(6)); + if (ret) + return ret; + + memset(&pos, 0, sizeof(pos)); + + req = (struct nand_page_io_req){ + .pos = pos, + .dataoffs = 0, + .datalen = 256 * CASN_PAGE_V1_COPIES, + .databuf.in = (u8 *)casn, + .mode = MTD_OPS_AUTO_OOB, + }; + + for (i = 0; i < sizeof(casn_offset)/sizeof(uint8_t); i++) { + req.pos.page = casn_offset[i]; + ret = spinand_load_page_op(spinand, &req); + if (ret) + goto finish; + + ret = spinand_wait(spinand, + SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, + &status); + if (ret < 0) + goto finish; + + op = (struct spi_mem_op) SPINAND_PAGE_READ_FROM_CACHE_OP( + false, 768, 1, (u8 *)casn, 256 * CASN_PAGE_V1_COPIES); + ret = spi_mem_exec_op(spinand->spimem, &op); + if (ret < 0) + goto finish; + + check_ret = spinand_check_casn(spinand, casn, sel); + if (!check_ret) + break; + } + +finish: + /* We need to restore configuration register. */ + final_ret = spinand_write_reg_op(spinand, REG_CFG, cfg_reg); + if (final_ret) + return final_ret; + + if (check_ret) { + dev_err(dev, "CASN page check failed\n"); + return check_ret; + } + + if (ret) + dev_err(dev, "CASN page read failed\n"); + + return ret; +} + static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; @@ -1180,7 +1478,7 @@ static int spinand_id_detect(struct spinand_device *spinand) static int spinand_manufacturer_init(struct spinand_device *spinand) { - if (spinand->manufacturer->ops->init) + if (!spinand->use_casn && spinand->manufacturer->ops->init) return spinand->manufacturer->ops->init(spinand); return 0; @@ -1189,7 +1487,7 @@ static int spinand_manufacturer_init(struct spinand_device *spinand) static void spinand_manufacturer_cleanup(struct spinand_device *spinand) { /* Release manufacturer private data */ - if (spinand->manufacturer->ops->cleanup) + if (!spinand->use_casn && spinand->manufacturer->ops->cleanup) return spinand->manufacturer->ops->cleanup(spinand); } @@ -1293,37 +1591,456 @@ int spinand_match_and_init(struct spinand_device *spinand, return -ENOTSUPP; } +static int spinand_casn_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int sectionp; + struct CASN_OOB *co = spinand->casn_oob; + + sectionp = spinand->base.memorg.pagesize/mtd->ecc_step_size; + if (section >= sectionp) + return -ERANGE; + + if (co->layout_type == OOB_DISCRETE) { + region->offset = co->ecc_parity_start + + (co->free_length + co->ecc_parity_space) + * section; + } else if (co->layout_type == OOB_CONTINUOUS) { + region->offset = co->ecc_parity_start + co->ecc_parity_space * section; + } + region->length = co->ecc_parity_real_length; + + return 0; +} + +static int spinand_casn_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int sectionp; + struct CASN_OOB *co = spinand->casn_oob; + + sectionp = spinand->base.memorg.pagesize/mtd->ecc_step_size; + if (section >= sectionp) + return -ERANGE; + + if (!section) { + region->offset = co->free_start + co->bbm_length; + region->length = co->free_length - co->bbm_length; + } else { + if (co->layout_type == OOB_DISCRETE) { + region->offset = co->free_start + + (co->free_length + + co->ecc_parity_space) * section; + } else if (co->layout_type == OOB_CONTINUOUS) { + region->offset = co->free_start + + co->free_length * section; + } + region->length = co->free_length; + } + + return 0; +} + +static const struct mtd_ooblayout_ops spinand_casn_ooblayout = { + .ecc = spinand_casn_ooblayout_ecc, + .free = spinand_casn_ooblayout_free, +}; + +static int spinand_set_read_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_read_cache_variants; + u16 sdr_read_cap = be16_to_cpu(casn->sdr_read_cap); + struct spi_mem_op *read_ops; + const struct spi_mem_op *op; + int i = 0; + + read_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight16(sdr_read_cap), + GFP_KERNEL); + if (!read_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_READ_1_4_4, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_QUADIO_OP( + casn->sdr_read_1_4_4.addr_nbytes, 0, + casn->sdr_read_1_4_4.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_4, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_X4_OP( + casn->sdr_read_1_1_4.addr_nbytes, 0, + casn->sdr_read_1_1_4.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_2_2, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_DUALIO_OP( + casn->sdr_read_1_2_2.addr_nbytes, 0, + casn->sdr_read_1_2_2.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_2, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_X2_OP( + casn->sdr_read_1_1_2.addr_nbytes, 0, + casn->sdr_read_1_1_2.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_1_FAST, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_OP( + true, casn->sdr_read_1_1_1_fast.addr_nbytes, 0, + casn->sdr_read_1_1_1_fast.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_1, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_OP( + false, casn->sdr_read_1_1_1.addr_nbytes, 0, + casn->sdr_read_1_1_1.dummy_nbytes, NULL, 0 + ); + i++; + } + + casn_read_cache_variants = (struct spinand_op_variants){ + .ops = read_ops, + .nops = hweight16(sdr_read_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_read_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, read_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.read_cache = op; + + return 0; +} + +static int spinand_set_write_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_write_cache_variants; + struct spi_mem_op *write_ops; + const struct spi_mem_op *op; + int i = 0; + + write_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight8(casn->sdr_write_cap), + GFP_KERNEL); + if (!write_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_WRITE_1_1_4, casn->sdr_write_cap)) { + write_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD_X4( + true, casn->sdr_write_1_1_4.addr_nbytes, 0, + NULL, 0); + i++; + } + if (FIELD_GET(SDR_WRITE_1_1_1, casn->sdr_write_cap)) { + write_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD( + true, casn->sdr_write_1_1_1.addr_nbytes, 0, + NULL, 0); + i++; + } + + casn_write_cache_variants = (struct spinand_op_variants){ + .ops = write_ops, + .nops = hweight8(casn->sdr_write_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_write_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, write_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.write_cache = op; + + return 0; +} + +static int spinand_set_update_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_update_cache_variants; + struct spi_mem_op *update_ops; + const struct spi_mem_op *op; + int i = 0; + + update_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight8(casn->sdr_update_cap), + GFP_KERNEL); + if (!update_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_UPDATE_1_1_4, casn->sdr_update_cap)) { + update_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD_X4( + false, casn->sdr_update_1_1_4.addr_nbytes, 0, + NULL, 0); + i++; + } + if (FIELD_GET(SDR_UPDATE_1_1_1, casn->sdr_update_cap)) { + update_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD( + false, casn->sdr_update_1_1_1.addr_nbytes, 0, + NULL, 0); + i++; + } + + casn_update_cache_variants = (struct spinand_op_variants){ + .ops = update_ops, + .nops = hweight8(casn->sdr_update_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_update_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, update_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.update_cache = op; + + return 0; +} + +static int spinand_init_via_casn(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u32 val; + int ret; + int i; + + /* Set members of nand->memorg via CASN. */ + for (i = 0; i < 9; i++) { + val = be32_to_cpu(*(&casn->bits_per_cell + i)); + memcpy((u32 *)&nand->memorg.bits_per_cell + i, &val, sizeof(u32)); + } + nand->ecc.requirements.strength = be32_to_cpu(casn->ecc_strength); + nand->ecc.requirements.step_size = be32_to_cpu(casn->ecc_step_size); + spinand->flags = casn->flags; + + if (spinand->flags & SPINAND_SUP_ADV_ECC_STATUS) { + spinand->eccinfo = (struct spinand_ecc_info) { + &spinand_casn_get_ecc_status, &spinand_casn_ooblayout}; + } else { + spinand->eccinfo = (struct spinand_ecc_info) { + NULL, &spinand_casn_ooblayout }; + } + + spinand->advecc_high_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op), + GFP_KERNEL); + if (!spinand->advecc_high_ops) + return -ENOMEM; + spinand->advecc_low_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op), + GFP_KERNEL); + if (!spinand->advecc_low_ops) + return -ENOMEM; + spinand->casn_oob = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_OOB), + GFP_KERNEL); + if (!spinand->casn_oob) + return -ENOMEM; + spinand->advecc_high = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_ADVECC), + GFP_KERNEL); + if (!spinand->advecc_high) + return -ENOMEM; + spinand->advecc_low = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_ADVECC), + GFP_KERNEL); + if (!spinand->advecc_low) + return -ENOMEM; + + *spinand->advecc_high_ops = (struct spi_mem_op) + SPINAND_CASN_ADVECC_OP(casn->ecc_status_high, spinand->scratchbuf); + *spinand->advecc_low_ops = (struct spi_mem_op) + SPINAND_CASN_ADVECC_OP(casn->ecc_status_low, spinand->scratchbuf); + + memcpy(spinand->casn_oob, &casn->casn_oob, sizeof(struct CASN_OOB)); + + spinand->advecc_high->cmd = casn->ecc_status_high.cmd; + spinand->advecc_high->mask = be16_to_cpu(casn->ecc_status_high.status_mask); + spinand->advecc_high->shift = spinand->advecc_high->mask ? + ffs(spinand->advecc_high->mask)-1 : 0; + spinand->advecc_high->pre_op = casn->ecc_status_high.pre_op; + spinand->advecc_high->pre_mask = casn->ecc_status_high.pre_mask; + + spinand->advecc_low->cmd = casn->ecc_status_low.cmd; + spinand->advecc_low->mask = be16_to_cpu(casn->ecc_status_low.status_mask); + spinand->advecc_low->shift = spinand->advecc_low->mask ? + ffs(spinand->advecc_low->mask)-1 : 0; + spinand->advecc_low->pre_op = casn->ecc_status_low.pre_op; + spinand->advecc_low->pre_mask = casn->ecc_status_low.pre_mask; + + spinand->advecc_low_bitcnt = hweight16(spinand->advecc_low->mask); + + spinand->advecc_noerr_status = casn->advecc_noerr_status; + spinand->advecc_uncor_status = casn->advecc_uncor_status; + spinand->advecc_post_op = casn->advecc_post_op; + spinand->advecc_post_mask = casn->advecc_post_mask; + spinand->eccsr_math_op[0] = eccsr_none_op; + spinand->eccsr_math_op[1] = eccsr_and_op; + spinand->eccsr_math_op[2] = eccsr_add_op; + spinand->eccsr_math_op[3] = eccsr_minus_op; + spinand->eccsr_math_op[4] = eccsr_mul_op; + + ret = spinand_set_read_op_variants(spinand, casn); + if (ret < 0) + return ret; + ret = spinand_set_write_op_variants(spinand, casn); + if (ret < 0) + return ret; + ret = spinand_set_update_op_variants(spinand, casn); + if (ret < 0) + return ret; + + return 0; +} + +static void spinand_dump_casn(struct spinand_device *spinand, struct nand_casn *casn) +{ + int i; + + dev_dbg(&spinand->spimem->spi->dev, + "---Start dumping full CASN page---\n"); + for (i = 0; i < 64; i++) + pr_debug("0x%08x", *((u32 *)casn + i)); + + pr_debug("** Dump critical fields **\n"); + pr_debug("signature: 0x%04x\n", be32_to_cpu(casn->signature)); + pr_debug("version: v%u.%u\n", casn->version >> 4, casn->version & 0xf); + pr_debug("[Memory Organization]\n"); + pr_debug(" bits_per_cell: %d\n", be32_to_cpu(casn->bits_per_cell)); + pr_debug(" bytes_per_page: %d\n", be32_to_cpu(casn->bytes_per_page)); + pr_debug(" spare_bytes_per_page: %d\n", + be32_to_cpu(casn->spare_bytes_per_page)); + pr_debug(" pages_per_block: %d\n", + be32_to_cpu(casn->pages_per_block)); + pr_debug(" blocks_per_lun: %d\n", be32_to_cpu(casn->blocks_per_lun)); + pr_debug(" max_bb_per_lun: %d\n", be32_to_cpu(casn->max_bb_per_lun)); + pr_debug(" planes_per_lun: %d\n", be32_to_cpu(casn->planes_per_lun)); + pr_debug(" luns_per_target: %d\n", + be32_to_cpu(casn->luns_per_target)); + pr_debug(" total_target: %d\n", be32_to_cpu(casn->total_target)); + pr_debug("[flags]\n"); + pr_debug(" 0. Have QE bit? %s\n", + casn->flags & SPINAND_HAS_QE_BIT ? "Yes" : "No"); + pr_debug(" 1. Have continuous read feature bit? %s\n", + casn->flags & SPINAND_HAS_CR_FEAT_BIT ? "Yes" : "No"); + pr_debug(" 2. Support continuous read? %s\n", + casn->flags & SPINAND_SUP_CR ? "Yes" : "No"); + pr_debug(" 3. Support on-die ECC? %s\n", + casn->flags & SPINAND_SUP_ON_DIE_ECC ? "Yes" : "No"); + pr_debug(" 4. Support legacy ECC status? %s\n", + casn->flags & SPINAND_SUP_LEGACY_ECC_STATUS ? "Yes" : "No"); + pr_debug(" 5. Support advanced ECC status? %s\n", + casn->flags & SPINAND_SUP_ADV_ECC_STATUS ? "Yes" : "No"); + pr_debug(" 6. ECC parity readable? %s\n", + casn->flags & SPINAND_ECC_PARITY_READABLE ? "Yes" : "No"); + pr_debug("[R/W ability]\n"); + pr_debug(" read ability: %x\n", be16_to_cpu(casn->sdr_read_cap)); + pr_debug(" write ability: %x\n", casn->sdr_write_cap); + pr_debug(" update ability: %x\n", casn->sdr_update_cap); + pr_debug("advanced ECC no error state: %x\n", + casn->advecc_noerr_status); + pr_debug("advecced ECC uncorrectable state: %x\n", + casn->advecc_uncor_status); + pr_debug("CRC: 0x%04x\n", be16_to_cpu(casn->crc)); + + dev_dbg(&spinand->spimem->spi->dev, + "---Dumping full CASN page ends here.---\n"); +} + static int spinand_detect(struct spinand_device *spinand) { - struct device *dev = &spinand->spimem->spi->dev; struct nand_device *nand = spinand_to_nand(spinand); + struct device *dev = &spinand->spimem->spi->dev; + struct nand_casn *casn; + char manufacturer[14]; + unsigned int sel = 0; + char model[17]; int ret; ret = spinand_reset_op(spinand); if (ret) return ret; - ret = spinand_id_detect(spinand); - if (ret) { - dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, - spinand->id.data); - return ret; + spinand->use_casn = false; + casn = kzalloc((sizeof(struct nand_casn) * CASN_PAGE_V1_COPIES), GFP_KERNEL); + if (!casn) + return -ENOMEM; + + ret = spinand_casn_detect(spinand, casn, &sel); + if (!ret) { + spinand->use_casn = true; + strscpy(manufacturer, casn[sel].manufacturer, sizeof(manufacturer)-1); + sanitize_string(manufacturer, sizeof(manufacturer)); + strscpy(model, casn[sel].model, sizeof(model)-1); + sanitize_string(model, sizeof(model)); + + spinand_dump_casn(spinand, casn + sel); + + ret = spinand_init_via_casn(spinand, casn + sel); + if (ret) + dev_err(dev, "Initializing spinand via CASN fails: %d\n", ret); + } + + if (ret < 0) { + dev_warn(dev, "Fallback to read ID\n"); + + ret = spinand_reset_op(spinand); + if (ret) + goto free_casn; + ret = spinand_id_detect(spinand); + if (ret) { + dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, + spinand->id.data); + goto free_casn; + } } if (nand->memorg.ntargets > 1 && !spinand->select_target) { dev_err(dev, "SPI NANDs with more than one die must implement ->select_target()\n"); - return -EINVAL; + ret = -EINVAL; + goto free_casn; + } + + if (spinand->use_casn) { + dev_info(&spinand->spimem->spi->dev, + "%s %s SPI NAND was found.\n", manufacturer, model); + } else { + dev_info(&spinand->spimem->spi->dev, + "%s SPI NAND was found.\n", spinand->manufacturer->name); } - dev_info(&spinand->spimem->spi->dev, - "%s SPI NAND was found.\n", spinand->manufacturer->name); dev_info(&spinand->spimem->spi->dev, "%llu MiB, block size: %zu KiB, page size: %zu, OOB size: %u\n", nanddev_size(nand) >> 20, nanddev_eraseblock_size(nand) >> 10, nanddev_page_size(nand), nanddev_per_page_oobsize(nand)); - return 0; +free_casn: + kfree(casn); + + return ret; } static int spinand_init_flash(struct spinand_device *spinand)