From patchwork Tue Apr 30 11:11:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keguang Zhang via B4 Relay X-Patchwork-Id: 1929426 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=hvxQf4R2; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=DxCGMtml; 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 4VTHb66Jbzz23jG for ; Tue, 30 Apr 2024 21:12:00 +1000 (AEST) 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:Reply-To:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References: Message-Id:MIME-Version:Subject:Date:From:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=S/eI2SYgMyujYEATbhflq4r1YvSvO0CXe7TvPTH+WyM=; b=hvxQf4R2U9O+3z iKZz+6QAjSFEh36YiozsSBgJGDhq8Mf9VfKoAfIUSsuD4A2HgLUTLVwJShYj8sEBDUq/ay3i+Aa2G AsrR0VBa/k+vdufmjqeKej17gDA2Sh164dlV3jiFF12jrBYhdOkMV2jS4jfj21mudDR2vcLr6pZ3D AByQ2sa4soW2Lj4p1B0G4LMbvBx9FYLfK+QaRLVrv7SOemTnfCiayQ9MnIADU13LJZjHbvRBjyKQ3 KbrDyVLLB/5wsWn2gR8Wc9ARchqtI0HjNJxTBdZ8kNO6bpjoTCUepDJKYNdzG9SxdsQRi0k5JIlGo FeJPmpjUIFejslusuKew==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOd-000000068au-00HK; Tue, 30 Apr 2024 11:11:39 +0000 Received: from dfw.source.kernel.org ([139.178.84.217]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOZ-000000068YH-0KDp for linux-mtd@lists.infradead.org; Tue, 30 Apr 2024 11:11:37 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 02E4F6146C; Tue, 30 Apr 2024 11:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPS id 9FF69C4AF18; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1714475493; bh=2v7bw47Y8yac0BNl8kfbTVNGSFn6BD1G1x5HiyR04yk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=DxCGMtmliiMPZwmnrapARnExGI0flvG1XUX7bZf5eucZyez/5PfJd06nSDkxd7BKF z2GN+1anL6VUi0y2Sn0EO3lx1fKyLvLUXViar6a8rAHj/cI2ypIGjdUsRN9/08LOID dwvaK0x7yQpd5yS5OrJ1NCqssT4k7VJbA2mkC+XEHAPyY8TOnWf2aGG+RmDSj+E7eM YGSqUumO+lbjxJBnwAw0n7OHaOEeAtCe9EG6kLqipR5xZnrU63uFDXbC0LqQjCia/V 5KWHAACsDZj0jqrAkd+p9mIG+l5RDlLnuq/86jm+T1jiyOnVaFpPD/0GL1b1mVaIgu u6C3MwZalUzAw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8EBC7C19F53; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) From: Keguang Zhang via B4 Relay Date: Tue, 30 Apr 2024 19:11:10 +0800 Subject: [PATCH v7 1/3] dt-bindings: mtd: Add Loongson-1 NAND Controller MIME-Version: 1.0 Message-Id: <20240430-loongson1-nand-v7-1-60787c314fa4@gmail.com> References: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> In-Reply-To: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mips@vger.kernel.org, devicetree@vger.kernel.org, Keguang Zhang X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1714475491; l=1981; i=keguang.zhang@gmail.com; s=20231129; h=from:subject:message-id; bh=051ksmvBr0UxivFTnhR9mHkGLTvP/HWsibHv4Ii5zR4=; b=NWQWxMYBcUQhSr4sUNOhXWIGbWl7BRPCIJSTrLjZgsIWxIHm3C9M+lhuZdk/KQNJpnjN3ND9V SRKmhBxJgE8ATTyAVc/nwE9e/VrZByAA7jsUZAdTZ+9zynIXp2rjo5v X-Developer-Key: i=keguang.zhang@gmail.com; a=ed25519; pk=FMKGj/JgKll/MgClpNZ3frIIogsh5e5r8CeW2mr+WLs= X-Endpoint-Received: by B4 Relay for keguang.zhang@gmail.com/20231129 with auth_id=102 X-Original-From: Keguang Zhang X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240430_041135_401009_CFDB9BDE X-CRM114-Status: GOOD ( 11.27 ) X-Spam-Score: -2.7 (--) 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: Keguang Zhang Add devicetree binding document for Loongson-1 NAND Controller. Signed-off-by: Keguang Zhang --- Changes in v7: - rename the file to loongson,ls1b-nfc.yaml Content analysis details: (-2.7 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at https://www.dnswl.org/, high trust [139.178.84.217 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -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 -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 2.5 FREEMAIL_FORGED_REPLYTO Freemail in Reply-To, but not From 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: , Reply-To: keguang.zhang@gmail.com Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Keguang Zhang Add devicetree binding document for Loongson-1 NAND Controller. Signed-off-by: Keguang Zhang --- Changes in v7: - rename the file to loongson,ls1b-nfc.yaml Changes in v6: - A newly added patch --- .../devicetree/bindings/mtd/loongson,ls1b-nfc.yaml | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/loongson,ls1b-nfc.yaml b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nfc.yaml new file mode 100644 index 000000000000..a69f22b9fd9e --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nfc.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/loongson,ls1b-nfc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-1 NAND Controller + +maintainers: + - Keguang Zhang + +allOf: + - $ref: nand-controller.yaml + +properties: + compatible: + oneOf: + - const: loongson,ls1b-nfc + - items: + - enum: + - loongson,ls1a-nfc + - loongson,ls1c-nfc + - const: loongson,ls1b-nfc + + reg: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + const: rxtx + +patternProperties: + "^nand@[0-3]$": + type: object + $ref: raw-nand-chip.yaml + + unevaluatedProperties: false + +required: + - compatible + - reg + - dmas + - dma-names + +unevaluatedProperties: false + +examples: + - | + nand-controller@1fe78000 { + compatible = "loongson,ls1b-nfc"; + reg = <0x1fe78000 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + + dmas = <&dma 0>; + dma-names = "rxtx"; + + nand@0 { + reg = <0>; + nand-use-soft-ecc-engine; + nand-ecc-algo = "hamming"; + }; + }; From patchwork Tue Apr 30 11:11:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keguang Zhang via B4 Relay X-Patchwork-Id: 1929428 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=ZK4clXXP; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=eKuhx1K+; 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 4VTHb70JwYz23tY for ; Tue, 30 Apr 2024 21:12:00 +1000 (AEST) 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:Reply-To:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References: Message-Id:MIME-Version:Subject:Date:From:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=mHy6HLZYXbf6fLOCLOUXBSDYKb7u4BV7m+jIPAKoDlY=; b=ZK4clXXPCLvOZq p9hj3DDmAwZ+d8E5s4vV13emh2dBssEoTKqSBha7zkHqtJvdWFY8Oy1Sgkq09jOQ0UNiVmOxdbyxO QluMRUbCG7C4FyLJgBP9cFz6xfWuhbNSDDhQlg8HBAuNy2PF1dDRzK6+Osz7/fntwNVLu0TzQ11mZ TQ8aDq/6QCIjydahFO0G0nwczuo0zyssjlVFTxPM62TTGVboVCdqR9he/alk/ruNplYNFWMv+I2oi 9hCe0ZT3tVgaopfMh+mmS8NQ8TFMz1HdYomALDq4aDzigVFAV02GbnZlPAXPKc+ZuEBWCcp5+saib +EmELYkgOdNYY/6wGkGQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOf-000000068be-0cUj; Tue, 30 Apr 2024 11:11:41 +0000 Received: from dfw.source.kernel.org ([2604:1380:4641:c500::1]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOZ-000000068YQ-1Zgd for linux-mtd@lists.infradead.org; Tue, 30 Apr 2024 11:11:37 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 5055860C75; Tue, 30 Apr 2024 11:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPS id A6393C4AF1A; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1714475493; bh=2n6RKhZ6Alf/wZaO1MKOWwaDevD0k3b+5zSEVw4UWKs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=eKuhx1K+SwtgMP71K/LghjaKXGuYS90nfXBjhKShGHvmuGy54dtW31bs4aznwXVR8 +Xq3Ts6cFAtynwNPEjMa/cxE0Ieql0KT+Mz0A6Q2H8ZJivSQy9CgnMy95/6AkC2101 2Q0CLoHSinF6U5aoP6Lvei/5WkCoZqob+tf+B+7h/xdqAf/g9kBNsg0eP8V6IdxbuK NwWAE/QeISov9QZlHSnPn6SY4SkzlY8CAuoJFo+iq9/6QJHydHNYeEq4VhlbtdXgWx Jbgj7JphcSX7ZKcszIA0CgCPRKI3Anpr41p6ywaBsem4nPoJ7I9qHFc/4hIezW16zZ l8g04i9weF70w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97D70C4345F; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) From: Keguang Zhang via B4 Relay Date: Tue, 30 Apr 2024 19:11:11 +0800 Subject: [PATCH v7 2/3] mtd: rawnand: Enable monolithic read when reading subpages MIME-Version: 1.0 Message-Id: <20240430-loongson1-nand-v7-2-60787c314fa4@gmail.com> References: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> In-Reply-To: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mips@vger.kernel.org, devicetree@vger.kernel.org, Keguang Zhang X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1714475491; l=2188; i=keguang.zhang@gmail.com; s=20231129; h=from:subject:message-id; bh=wxQD1HBRVqdAYZRkfcNz/OdgGE3Cin/b3Ag8hRQf9EE=; b=qDOtiX5d4aKcQL2FPn2OyNayDTvIp5rLphjmsU/ftUr6P5kvU+uapKzBtmSJ/WRUiabEBChwh aCMaYeMxjLVBrdMF8NlJVpvxvgOeSPpm4aw4cFeheZOOjofdE3W3IPl X-Developer-Key: i=keguang.zhang@gmail.com; a=ed25519; pk=FMKGj/JgKll/MgClpNZ3frIIogsh5e5r8CeW2mr+WLs= X-Endpoint-Received: by B4 Relay for keguang.zhang@gmail.com/20231129 with auth_id=102 X-Original-From: Keguang Zhang X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240430_041135_637173_D262AE31 X-CRM114-Status: GOOD ( 12.88 ) X-Spam-Score: 0.0 (/) 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: Keguang Zhang nand_read_subpage() reads data and ECC data by two separate operations. This patch allows the NAND controllers who support monolithic page read to do subpage read by a single operation, which is more [...] Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [2604:1380:4641:c500:0:0:0:1 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -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 -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 2.5 FREEMAIL_FORGED_REPLYTO Freemail in Reply-To, but not From 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: , Reply-To: keguang.zhang@gmail.com Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Keguang Zhang nand_read_subpage() reads data and ECC data by two separate operations. This patch allows the NAND controllers who support monolithic page read to do subpage read by a single operation, which is more effective than nand_read_subpage(). --- Changes in v7: - None Changes in v6: - A newly added patch Signed-off-by: Keguang Zhang --- drivers/mtd/nand/raw/nand_base.c | 5 +++-- include/linux/mtd/rawnand.h | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d7dbbd469b89..eeb654c6b4fc 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -3630,7 +3630,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, oob_required, page); else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && - !oob) + !NAND_HAS_MONOLITHIC_READ(chip) && !oob) ret = chip->ecc.read_subpage(chip, col, bytes, bufpoi, page); else @@ -3648,7 +3648,8 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, * partial pages or when a bounce buffer is required. */ if (use_bounce_buf) { - if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && + if ((!NAND_HAS_SUBPAGE_READ(chip) || + NAND_HAS_MONOLITHIC_READ(chip)) && !oob && !(mtd->ecc_stats.failed - ecc_stats.failed) && (ops->mode != MTD_OPS_RAW)) { chip->pagecache.page = realpage; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index e84522e31301..92d3ab491c9c 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -150,6 +150,11 @@ struct gpio_desc; /* Device needs 3rd row address cycle */ #define NAND_ROW_ADDR_3 BIT(14) +/* Device supports monolithic reads */ +#define NAND_MONOLITHIC_READ BIT(15) +/* Macros to identify the above */ +#define NAND_HAS_MONOLITHIC_READ(chip) ((chip->options & NAND_MONOLITHIC_READ)) + /* Non chip related options */ /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN BIT(16) From patchwork Tue Apr 30 11:11:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keguang Zhang via B4 Relay X-Patchwork-Id: 1929429 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=dYOLtHj3; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=THiciaHf; 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 4VTHb66nZXz23ny for ; Tue, 30 Apr 2024 21:12:01 +1000 (AEST) 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:Reply-To:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References: Message-Id:MIME-Version:Subject:Date:From:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=x7was1nJwZbocfN26Qu9B75D0umlbtQKGbvydVrAHmU=; b=dYOLtHj31tENkc HEujOJZed8WCFgD6hy3nPzJGLmeppioXCklAjRxRV7NFgwlnZnyRpuCklXpbYPs4l7Pm6JO4SjE/g c+xyjdCQxfkjK8lOi7JC+kDVxNeJrbwvbIErtbzOs2S5MGCED5Jj6+isiWQPF5GfKIkAf31QLCZtN ID5uo4mHpaymrPU818/PxwsUTtStxbNEeQW7Fqdz5kKhZhmFtK5AS4PERyNBV9CgW3vFTKXEUOfL+ DWNjOQaRZTUxbjhlR3mfhcHdsJnHeuZRym2IQrZJzWjdddkElXBfNaBsftUNkOO+PCL6zl0uTCJoI YkWzNcAVcC23b7YeHx1g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOh-000000068cR-31HK; Tue, 30 Apr 2024 11:11:43 +0000 Received: from dfw.source.kernel.org ([139.178.84.217]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1s1lOZ-000000068Yv-0jRP for linux-mtd@lists.infradead.org; Tue, 30 Apr 2024 11:11:39 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 8576B614AE; Tue, 30 Apr 2024 11:11:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPS id B2B8AC4AF1C; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1714475493; bh=9+gjLfc6jrbyBzXiBpA5wn8w6zOzuDxImbrVhw7lHjs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=THiciaHfA1N05BHhjK0RSd8180Y3pbFLIqTXAe63/h4povlVKxeVwLQHu2BhKg7Ua Q7U71JpQBRbOkqKKNWKrjR8wzrzpfotKpzncZQ60IfDP+V5oFVkalD3iiAxOswxcRw BWoDii5v2jsX2RC5B9pHqzIlxzBXgs635HvCkrRxm3XA2jmVrH+UcXMDKGrtBcE+1k gaaAoN2GeTzwndexm+1APKt5RlDfM+sHT/K2l1TsJVAo8VxPNNKSMxvfin6zOZxYz1 jNTu0EAaQzDDB9VGAWL/wr5wepGsAE5h/EkU3zYwr8E/mX1dPaOYsEhGWHmGhyexFN ukwYXykFO3xvw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A47D4C25B5C; Tue, 30 Apr 2024 11:11:33 +0000 (UTC) From: Keguang Zhang via B4 Relay Date: Tue, 30 Apr 2024 19:11:12 +0800 Subject: [PATCH v7 3/3] mtd: rawnand: Add Loongson-1 NAND Controller driver MIME-Version: 1.0 Message-Id: <20240430-loongson1-nand-v7-3-60787c314fa4@gmail.com> References: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> In-Reply-To: <20240430-loongson1-nand-v7-0-60787c314fa4@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mips@vger.kernel.org, devicetree@vger.kernel.org, Keguang Zhang X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1714475491; l=23506; i=keguang.zhang@gmail.com; s=20231129; h=from:subject:message-id; bh=Pj2lE4qTrYmpHR+aTnNrgi1a+WH7HfnG2Gsddi4X528=; b=2hkCMX2U/FEEx4eXV3SQN+JUNVlFRVSdqhtTYrzTV5xBxQtHzr/bPzEFANaomqKlR0Pbz61qO yopO4AaiuiBAaaFZk7nLj2QT1c2qDi0ia9sQyrZaFTEbuN6RWvx7/x+ X-Developer-Key: i=keguang.zhang@gmail.com; a=ed25519; pk=FMKGj/JgKll/MgClpNZ3frIIogsh5e5r8CeW2mr+WLs= X-Endpoint-Received: by B4 Relay for keguang.zhang@gmail.com/20231129 with auth_id=102 X-Original-From: Keguang Zhang X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240430_041135_785807_68F99D56 X-CRM114-Status: GOOD ( 27.56 ) X-Spam-Score: -2.7 (--) 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: Keguang Zhang This patch adds NAND Controller driver for Loongson-1 SoCs. Signed-off-by: Keguang Zhang --- Changes in v7: - Rename the dependency to LOONGSON1_APB_DMA Content analysis details: (-2.7 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at https://www.dnswl.org/, high trust [139.178.84.217 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -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 -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 2.5 FREEMAIL_FORGED_REPLYTO Freemail in Reply-To, but not From 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: , Reply-To: keguang.zhang@gmail.com Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Keguang Zhang This patch adds NAND Controller driver for Loongson-1 SoCs. Signed-off-by: Keguang Zhang --- Changes in v7: - Rename the dependency to LOONGSON1_APB_DMA Changes in v6: - Amend Kconfig - Add DT support - Use DT data instead of platform data - Remove MAX_ID_SIZE - Remove case NAND_OP_CMD_INSTR in ls1x_nand_set_controller() - Move ECC configuration to ls1x_nand_attach_chip() - Rename variable "nand" to "ls1x" - Rename variable "nc" to "nfc" - Some minor fixes - Link to v5: https://lore.kernel.org/all/20210520224213.7907-1-keguang.zhang@gmail.com Changes in v5: - Update the driver to fit the raw NAND framework. - Implement exec_op() instead of legacy cmdfunc(). - Use dma_request_chan() instead of dma_request_channel(). - Some minor fixes and cleanups. Changes in v4: - Retrieve the controller from nand_hw_control. Changes in v3: - Replace __raw_readl/__raw_writel with readl/writel. - Split ls1x_nand into two structures: ls1x_nand_chip and ls1x_nand_controller. Changes in v2: - Modify the dependency in Kconfig due to the changes of DMA module. --- drivers/mtd/nand/raw/Kconfig | 7 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/loongson1_nand.c | 748 ++++++++++++++++++++++++++++++++++ 3 files changed, 756 insertions(+) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index cbf8ae85e1ae..822bb7a2cea9 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -449,6 +449,13 @@ config MTD_NAND_RENESAS Enables support for the NAND controller found on Renesas R-Car Gen3 and RZ/N1 SoC families. +config MTD_NAND_LOONGSON1 + tristate "Loongson1 NAND controller" + depends on LOONGSON1_APB_DMA || COMPILE_TEST + select REGMAP_MMIO + help + Enables support for NAND controller on Loongson1 SoCs. + comment "Misc" config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 25120a4afada..b3c65cab819c 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_INTEL_LGM) += intel-nand-controller.o obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o obj-$(CONFIG_MTD_NAND_RENESAS) += renesas-nand-controller.o +obj-$(CONFIG_MTD_NAND_LOONGSON1) += loongson1_nand.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o diff --git a/drivers/mtd/nand/raw/loongson1_nand.c b/drivers/mtd/nand/raw/loongson1_nand.c new file mode 100644 index 000000000000..d0f66a81ba0b --- /dev/null +++ b/drivers/mtd/nand/raw/loongson1_nand.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * NAND Controller Driver for Loongson-1 SoC + * + * Copyright (C) 2015-2024 Keguang Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Loongson-1 NAND Controller Registers */ +#define NAND_CMD 0x0 +#define NAND_ADDR1 0x4 +#define NAND_ADDR2 0x8 +#define NAND_TIMING 0xc +#define NAND_IDL 0x10 +#define NAND_IDH_STATUS 0x14 +#define NAND_PARAM 0x18 +#define NAND_OP_NUM 0x1c +#define MAX_DUMP_REGS 0x20 + +#define NAND_DMA_ADDR 0x40 + +/* NAND Command Register Bits */ +#define OP_DONE BIT(10) +#define OP_SPARE BIT(9) +#define OP_MAIN BIT(8) +#define CMD_STATUS BIT(7) +#define CMD_RESET BIT(6) +#define CMD_READID BIT(5) +#define BLOCKS_ERASE BIT(4) +#define CMD_ERASE BIT(3) +#define CMD_WRITE BIT(2) +#define CMD_READ BIT(1) +#define CMD_VALID BIT(0) + +#define MAX_ADDR_CYC 5U + +#define WAIT_CYCLE_MASK GENMASK(7, 0) +#define HOLD_CYCLE_MASK GENMASK(15, 8) +#define CELL_SIZE_MASK GENMASK(11, 8) + +#define BITS_PER_WORD (4 * BITS_PER_BYTE) + +/* macros for registers read/write */ +#define nand_readl(nfc, off) \ + readl((nfc)->reg_base + (off)) + +#define nand_writel(nfc, off, val) \ + writel((val), (nfc)->reg_base + (off)) + +struct ls1x_nfc_data { + unsigned int status_field; + unsigned int op_scope_field; + unsigned int hold_cycle; + unsigned int wait_cycle; + void (*parse_address)(struct nand_chip *chip, const u8 *addrs, + unsigned int naddrs, int cmd); +}; + +struct ls1x_nfc { + void __iomem *reg_base; + struct regmap *regmap; + const struct ls1x_nfc_data *data; + __le32 addr1_reg; + __le32 addr2_reg; + + char *buf; + unsigned int len; + unsigned int rdy_timeout; + + /* DMA Engine stuff */ + struct dma_chan *dma_chan; + dma_cookie_t dma_cookie; + struct completion dma_complete; +}; + +struct ls1x_nand { + struct device *dev; + struct nand_chip chip; + struct nand_controller controller; + struct ls1x_nfc nfc; +}; + +static const struct regmap_config ls1x_nand_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static inline void ls1b_nand_parse_address(struct nand_chip *chip, + const u8 *addrs, + unsigned int naddrs, int cmd) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + unsigned int page_shift = chip->page_shift + 1; + int i; + + nfc->addr1_reg = 0; + nfc->addr2_reg = 0; + + if (cmd == CMD_ERASE) { + page_shift = chip->page_shift; + + for (i = 0; i < min(MAX_ADDR_CYC - 2, naddrs); i++) + nfc->addr1_reg |= + (u32)addrs[i] << (page_shift + BITS_PER_BYTE * i); + if (i == MAX_ADDR_CYC - 2) + nfc->addr2_reg |= + (u32)addrs[i] >> (BITS_PER_WORD - page_shift - + BITS_PER_BYTE * (i - 1)); + + return; + } + + for (i = 0; i < min(2U, naddrs); i++) + nfc->addr1_reg |= (u32)addrs[i] << BITS_PER_BYTE * i; + for (i = 2; i < min(MAX_ADDR_CYC, naddrs); i++) + nfc->addr1_reg |= + (u32)addrs[i] << (page_shift + BITS_PER_BYTE * (i - 2)); + if (i == MAX_ADDR_CYC) + nfc->addr2_reg |= + (u32)addrs[i] >> (BITS_PER_WORD - page_shift - + BITS_PER_BYTE * (i - 1)); +} + +static inline void ls1c_nand_parse_address(struct nand_chip *chip, + const u8 *addrs, + unsigned int naddrs, int cmd) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + int i; + + nfc->addr1_reg = 0; + nfc->addr2_reg = 0; + + if (cmd == CMD_ERASE) { + for (i = 0; i < min(MAX_ADDR_CYC, naddrs); i++) + nfc->addr2_reg |= (u32)addrs[i] << BITS_PER_BYTE * i; + + return; + } + + for (i = 0; i < min(MAX_ADDR_CYC, naddrs); i++) { + if (i < 2) + nfc->addr1_reg |= (u32)addrs[i] << BITS_PER_BYTE * i; + else + nfc->addr2_reg |= + (u32)addrs[i] << BITS_PER_BYTE * (i - 2); + } +} + +static int ls1x_nand_set_controller(struct nand_chip *chip, + const struct nand_subop *subop, int cmd) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + unsigned int op_id; + + nfc->buf = NULL; + nfc->len = 0; + nfc->rdy_timeout = 0; + + for (op_id = 0; op_id < subop->ninstrs; op_id++) { + const struct nand_op_instr *instr = &subop->instrs[op_id]; + unsigned int offset, naddrs; + const u8 *addrs; + + switch (instr->type) { + case NAND_OP_ADDR_INSTR: + offset = nand_subop_get_addr_start_off(subop, op_id); + naddrs = nand_subop_get_num_addr_cyc(subop, op_id); + addrs = &instr->ctx.addr.addrs[offset]; + + nfc->data->parse_address(chip, addrs, naddrs, cmd); + /* set NAND address */ + nand_writel(nfc, NAND_ADDR1, nfc->addr1_reg); + nand_writel(nfc, NAND_ADDR2, nfc->addr2_reg); + break; + case NAND_OP_DATA_IN_INSTR: + case NAND_OP_DATA_OUT_INSTR: + offset = nand_subop_get_data_start_off(subop, op_id); + nfc->len = nand_subop_get_data_len(subop, op_id); + if (instr->type == NAND_OP_DATA_IN_INSTR) + nfc->buf = + (void *)instr->ctx.data.buf.in + offset; + else if (instr->type == NAND_OP_DATA_OUT_INSTR) + nfc->buf = + (void *)instr->ctx.data.buf.out + offset; + + if (cmd & (CMD_READID | CMD_STATUS)) + break; + + if (!IS_ALIGNED((u32)nfc->buf, chip->buf_align)) { + dev_err(ls1x->dev, + "nfc->buf %px is not aligned!\n", + nfc->buf); + return -EOPNOTSUPP; + } else if (!IS_ALIGNED(nfc->len, chip->buf_align)) { + dev_err(ls1x->dev, + "nfc->len %u is not aligned!\n", + nfc->len); + return -EOPNOTSUPP; + } + + /* set NAND data length */ + nand_writel(nfc, NAND_OP_NUM, nfc->len); + + if (nfc->data->op_scope_field) { + int op_scope = nfc->len << ffs(nfc->data->op_scope_field); + + regmap_update_bits(nfc->regmap, NAND_PARAM, + nfc->data->op_scope_field, + op_scope); + } + + break; + case NAND_OP_WAITRDY_INSTR: + nfc->rdy_timeout = instr->ctx.waitrdy.timeout_ms; + break; + default: + break; + } + } + + /* set NAND erase block count */ + if (cmd & CMD_ERASE) + nand_writel(nfc, NAND_OP_NUM, 1); + /* set NAND operation region */ + if (nfc->buf && nfc->len) + cmd |= OP_SPARE | OP_MAIN; + + /* set NAND command */ + nand_writel(nfc, NAND_CMD, cmd); + /* Trigger operation */ + regmap_write_bits(nfc->regmap, NAND_CMD, CMD_VALID, CMD_VALID); + + return 0; +} + +static void ls1x_nand_dma_callback(void *data) +{ + struct ls1x_nand *ls1x = (struct ls1x_nand *)data; + struct ls1x_nfc *nfc = &ls1x->nfc; + enum dma_status status; + + status = dmaengine_tx_status(nfc->dma_chan, nfc->dma_cookie, NULL); + if (likely(status == DMA_COMPLETE)) + dev_dbg(ls1x->dev, "DMA complete with cookie=%d\n", + nfc->dma_cookie); + else + dev_err(ls1x->dev, "DMA error with cookie=%d\n", + nfc->dma_cookie); + + complete(&nfc->dma_complete); +} + +static int ls1x_nand_dma_transfer(struct ls1x_nand *ls1x, bool is_write) +{ + struct ls1x_nfc *nfc = &ls1x->nfc; + struct dma_chan *chan = nfc->dma_chan; + struct dma_async_tx_descriptor *desc; + enum dma_data_direction data_dir = + is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + enum dma_transfer_direction xfer_dir = + is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + dma_addr_t dma_addr; + int ret; + + dma_addr = dma_map_single(chan->device->dev, nfc->buf, nfc->len, + data_dir); + if (dma_mapping_error(chan->device->dev, dma_addr)) { + dev_err(ls1x->dev, "failed to map DMA buffer!\n"); + return -ENXIO; + } + + desc = dmaengine_prep_slave_single(chan, dma_addr, nfc->len, xfer_dir, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(ls1x->dev, "failed to prepare DMA descriptor!\n"); + ret = PTR_ERR(desc); + goto err; + } + desc->callback = ls1x_nand_dma_callback; + desc->callback_param = ls1x; + + nfc->dma_cookie = dmaengine_submit(desc); + ret = dma_submit_error(nfc->dma_cookie); + if (ret) { + dev_err(ls1x->dev, "failed to submit DMA descriptor!\n"); + goto err; + } + + dev_dbg(ls1x->dev, "issue DMA with cookie=%d\n", nfc->dma_cookie); + dma_async_issue_pending(chan); + + ret = wait_for_completion_timeout(&nfc->dma_complete, + msecs_to_jiffies(nfc->rdy_timeout)); + if (ret <= 0) { + dev_err(ls1x->dev, "DMA timeout!%u\n", nfc->rdy_timeout); + dmaengine_terminate_all(chan); + ret = -EIO; + } + ret = 0; +err: + dma_unmap_single(chan->device->dev, dma_addr, nfc->len, data_dir); + + return ret; +} + +static inline int ls1x_nand_wait_for_op_done(struct ls1x_nfc *nfc) +{ + unsigned int val; + int ret = 0; + + /* Wait for operation done */ + if (nfc->rdy_timeout) + ret = regmap_read_poll_timeout(nfc->regmap, NAND_CMD, val, + val & OP_DONE, 0, + nfc->rdy_timeout * 1000); + + return ret; +} + +static int ls1x_nand_reset_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + int ret; + + ls1x_nand_set_controller(chip, subop, CMD_RESET); + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) + dev_err(ls1x->dev, "CMD_RESET failed! %d\n", ret); + + return ret; +} + +static int ls1x_nand_read_id_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + long long idl = 0; + int i, ret; + + ls1x_nand_set_controller(chip, subop, CMD_READID); + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) { + dev_err(ls1x->dev, "CMD_READID failed! %d\n", ret); + print_hex_dump_debug("REG: ", DUMP_PREFIX_OFFSET, 16, 4, + nfc->reg_base, MAX_DUMP_REGS, false); + return ret; + } + + idl = __be32_to_cpu(nand_readl(nfc, NAND_IDL)); + memset(nfc->buf, 0x0, nfc->len); + + for (i = 0; i < nfc->len; i++) { + if (i > 0) + nfc->buf[i] = (char)(idl >> (i - 1) * BITS_PER_BYTE); + else + nfc->buf[i] = (char)nand_readl(nfc, NAND_IDH_STATUS); + } + + return ret; +} + +static int ls1x_nand_erase_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + int ret; + + ls1x_nand_set_controller(chip, subop, CMD_ERASE); + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) { + dev_err(ls1x->dev, "CMD_ERASE failed! %d\n", ret); + print_hex_dump_debug("REG: ", DUMP_PREFIX_OFFSET, 16, 4, + nfc->reg_base, MAX_DUMP_REGS, false); + } + + return ret; +} + +static int ls1x_nand_read_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + bool is_write = false; + int ret; + + ls1x_nand_set_controller(chip, subop, CMD_READ); + + ret = ls1x_nand_dma_transfer(ls1x, is_write); + if (ret) + return ret; + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) { + dev_err(ls1x->dev, "CMD_READ failed! %d\n", ret); + print_hex_dump_debug("REG: ", DUMP_PREFIX_OFFSET, 16, 4, + nfc->reg_base, MAX_DUMP_REGS, false); + } + + return ret; +} + +static int ls1x_nand_write_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + bool is_write = true; + int ret; + + ls1x_nand_set_controller(chip, subop, CMD_WRITE); + + ret = ls1x_nand_dma_transfer(ls1x, is_write); + if (ret) + return ret; + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) { + dev_err(ls1x->dev, "CMD_WRITE failed! %d\n", ret); + print_hex_dump_debug("REG: ", DUMP_PREFIX_OFFSET, 16, 4, + nfc->reg_base, MAX_DUMP_REGS, false); + } + + return ret; +} + +static int ls1x_nand_read_status_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + int val, ret; + + ls1x_nand_set_controller(chip, subop, CMD_STATUS); + + ret = ls1x_nand_wait_for_op_done(nfc); + if (ret) { + dev_err(ls1x->dev, "CMD_STATUS failed! %d\n", ret); + return ret; + } + + val = nand_readl(nfc, NAND_IDH_STATUS) & ~nfc->data->status_field; + nfc->buf[0] = val << ffs(nfc->data->status_field); + + return ret; +} + +static const struct nand_op_parser ls1x_nand_op_parser = NAND_OP_PARSER( + NAND_OP_PARSER_PATTERN( + ls1x_nand_reset_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), + NAND_OP_PARSER_PATTERN( + ls1x_nand_read_id_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)), + NAND_OP_PARSER_PATTERN( + ls1x_nand_erase_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), + NAND_OP_PARSER_PATTERN( + ls1x_nand_read_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 0)), + NAND_OP_PARSER_PATTERN( + ls1x_nand_write_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 0), + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), + NAND_OP_PARSER_PATTERN( + ls1x_nand_read_status_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)), + ); + +static int ls1x_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, bool check_only) +{ + return nand_op_parser_exec_op(chip, &ls1x_nand_op_parser, op, + check_only); +} + +static int ls1x_nand_attach_chip(struct nand_chip *chip) +{ + struct ls1x_nand *ls1x = nand_get_controller_data(chip); + struct ls1x_nfc *nfc = &ls1x->nfc; + u64 chipsize = nanddev_target_size(&chip->base); + int cell_size = 0; + + switch (chipsize) { + case SZ_128M: + cell_size = 0x0; + break; + case SZ_256M: + cell_size = 0x1; + break; + case SZ_512M: + cell_size = 0x2; + break; + case SZ_1G: + cell_size = 0x3; + break; + case SZ_2G: + cell_size = 0x4; + break; + case SZ_4G: + cell_size = 0x5; + break; + case (SZ_2G * SZ_4G): /* 8G */ + cell_size = 0x6; + break; + case (SZ_4G * SZ_4G): /* 16G */ + cell_size = 0x7; + break; + default: + dev_err(ls1x->dev, "unsupported chip size: %llu MB\n", + chipsize); + break; + } + + /* Set cell size */ + regmap_update_bits(nfc->regmap, NAND_PARAM, CELL_SIZE_MASK, + FIELD_PREP(CELL_SIZE_MASK, cell_size)); + + regmap_update_bits(nfc->regmap, NAND_TIMING, HOLD_CYCLE_MASK, + FIELD_PREP(HOLD_CYCLE_MASK, nfc->data->hold_cycle)); + regmap_update_bits(nfc->regmap, NAND_TIMING, WAIT_CYCLE_MASK, + FIELD_PREP(WAIT_CYCLE_MASK, nfc->data->wait_cycle)); + + chip->ecc.read_page_raw = nand_monolithic_read_page_raw; + chip->ecc.write_page_raw = nand_monolithic_write_page_raw; + chip->options |= NAND_MONOLITHIC_READ; + + return 0; +} + +static const struct nand_controller_ops ls1x_nfc_ops = { + .exec_op = ls1x_nand_exec_op, + .attach_chip = ls1x_nand_attach_chip, +}; + +static void ls1x_nand_controller_cleanup(struct ls1x_nand *ls1x) +{ + if (ls1x->nfc.dma_chan) + dma_release_channel(ls1x->nfc.dma_chan); +} + +static int ls1x_nand_controller_init(struct ls1x_nand *ls1x, + struct platform_device *pdev) +{ + struct ls1x_nfc *nfc = &ls1x->nfc; + struct dma_slave_config cfg; + int ret; + + nfc->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(nfc->reg_base)) + return PTR_ERR(nfc->reg_base); + + nfc->regmap = devm_regmap_init_mmio(ls1x->dev, nfc->reg_base, + &ls1x_nand_regmap_config); + if (IS_ERR(nfc->regmap)) + return dev_err_probe(ls1x->dev, PTR_ERR(nfc->regmap), + "failed to init regmap\n"); + + nfc->dma_chan = dma_request_chan(ls1x->dev, "rxtx"); + if (IS_ERR(nfc->dma_chan)) + return dev_err_probe(ls1x->dev, PTR_ERR(nfc->dma_chan), + "failed to request DMA channel\n"); + dev_info(ls1x->dev, "got %s for %s access\n", + dma_chan_name(nfc->dma_chan), dev_name(ls1x->dev)); + + cfg.src_addr = CPHYSADDR(nfc->reg_base + NAND_DMA_ADDR); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr = CPHYSADDR(nfc->reg_base + NAND_DMA_ADDR); + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + ret = dmaengine_slave_config(nfc->dma_chan, &cfg); + if (ret) { + dev_err(ls1x->dev, "failed to config DMA channel\n"); + dma_release_channel(nfc->dma_chan); + return ret; + } + + init_completion(&nfc->dma_complete); + + return 0; +} + +static int ls1x_nand_chip_init(struct ls1x_nand *ls1x) +{ + int nchips = of_get_child_count(ls1x->dev->of_node); + struct device_node *chip_np; + struct nand_chip *chip = &ls1x->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret = 0; + + if (nchips != 1) + return dev_err_probe(ls1x->dev, -EINVAL, + "Currently one NAND chip supported\n"); + + chip_np = of_get_next_child(ls1x->dev->of_node, NULL); + if (!chip_np) + return dev_err_probe(ls1x->dev, -ENODEV, + "failed to get child node for NAND chip\n"); + + chip->controller = &ls1x->controller; + chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | NAND_BROKEN_XD; + chip->buf_align = 4; + nand_set_controller_data(chip, ls1x); + nand_set_flash_node(chip, chip_np); + + mtd->dev.parent = ls1x->dev; + mtd->name = "ls1x-nand"; + mtd->owner = THIS_MODULE; + + ret = nand_scan(chip, 1); + if (ret) { + of_node_put(chip_np); + return ret; + } + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(ls1x->dev, "failed to register MTD device! %d\n", ret); + nand_cleanup(chip); + of_node_put(chip_np); + } + + return ret; +} + +static int ls1x_nand_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct ls1x_nfc_data *data; + struct ls1x_nand *ls1x; + int ret; + + data = of_device_get_match_data(&pdev->dev); + if (!data) + return -ENODEV; + + ls1x = devm_kzalloc(dev, sizeof(*ls1x), GFP_KERNEL); + if (!ls1x) + return -ENOMEM; + + ls1x->nfc.data = data; + ls1x->dev = dev; + ls1x->controller.ops = &ls1x_nfc_ops; + nand_controller_init(&ls1x->controller); + + ret = ls1x_nand_controller_init(ls1x, pdev); + if (ret) + return ret; + + ret = ls1x_nand_chip_init(ls1x); + if (ret) + goto err; + + platform_set_drvdata(pdev, ls1x); + + return 0; +err: + ls1x_nand_controller_cleanup(ls1x); + return ret; +} + +static int ls1x_nand_remove(struct platform_device *pdev) +{ + struct ls1x_nand *ls1x = platform_get_drvdata(pdev); + struct nand_chip *chip = &ls1x->chip; + int ret; + + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); + ls1x_nand_controller_cleanup(ls1x); + + return 0; +} + +static const struct ls1x_nfc_data ls1b_nfc_data = { + .status_field = GENMASK(15, 8), + .hold_cycle = 0x2, + .wait_cycle = 0xc, + .parse_address = ls1b_nand_parse_address, +}; + +static const struct ls1x_nfc_data ls1c_nfc_data = { + .status_field = GENMASK(23, 16), + .op_scope_field = GENMASK(29, 16), + .hold_cycle = 0x2, + .wait_cycle = 0xc, + .parse_address = ls1c_nand_parse_address, +}; + +static const struct of_device_id ls1x_nfc_match[] = { + { .compatible = "loongson,ls1b-nfc", .data = &ls1b_nfc_data }, + { .compatible = "loongson,ls1c-nfc", .data = &ls1c_nfc_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls1x_nfc_match); + +static struct platform_driver ls1x_nand_driver = { + .probe = ls1x_nand_probe, + .remove = ls1x_nand_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = ls1x_nfc_match, + }, +}; + +module_platform_driver(ls1x_nand_driver); + +MODULE_AUTHOR("Keguang Zhang "); +MODULE_DESCRIPTION("Loongson-1 NAND Controller driver"); +MODULE_LICENSE("GPL");