From patchwork Fri Oct 16 03:45:26 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 3644 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114]) by mxe881.netcup.net (Postfix) with ESMTPS id CECD71C1CBB for ; Fri, 16 Oct 2026 05:49:50 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=gmail.com; spf=pass (sender IP is 172.105.105.114) smtp.mailfrom=linux-sunxi+bounces-26686-noreply=patchwork.local@lists.linux.dev smtp.helo=tor.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.105.105.114 as permitted sender) client-ip=172.105.105.114; envelope-from=linux-sunxi+bounces-26686-noreply=patchwork.local@lists.linux.dev; helo=tor.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by tor.lore.kernel.org (Postfix) with ESMTP id 29F5344091 for ; Fri, 16 Oct 2026 03:46:30 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E018C39792A; Fri, 16 Oct 2026 03:45:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZhyKiVBH" X-Original-To: linux-sunxi@lists.linux.dev Received: from mail-ot1-f46.google.com (mail-ot1-f46.google.com [209.85.210.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93A703B8BDA for ; Fri, 16 Oct 2026 03:45:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792122349; cv=none; b=TzZr717ACk+2mqo6Uq4Wf5kuddC6iq94+jwOl/09bbaGLS44fTRYEnUEuIMkBgSYgVaajeZT3tl5AfMK88e9yt1SPXiPXDHURQnZbKfce2r5Js2AdCJDnGzYFs4vcCg/dSuRhoUVd3KeDzXzbSJ/KwFoLtsS0pDp2GCPGUpkwYU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792122349; c=relaxed/simple; bh=7IlRb7p3+mxoJYiFONd9hyYYAjrV4/WLWy/JUlReLeA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IeNmpWC+b1w2UsbUdJUAs9uXu/JDY6tYgMmz5o/V21mwEdGD7ll+eSU0XH6AtZT+wz3ONMp5dUiS37H5IL5mE6CC76SM+hSY4UKkv8fuzPBGNtFqD3iY5Z64H6qGOsXivXuwi8HV4Fdb74DdlWmtxL9rJpVO0aNRwnZ1XBjfZB4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZhyKiVBH; arc=none smtp.client-ip=209.85.210.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ot1-f46.google.com with SMTP id 46e09a7af769-82478760557so2035352a34.3 for ; Thu, 15 Oct 2026 20:45:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792122346; x=1792727146; darn=lists.linux.dev; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=mIhYiFHKevI+TgLh8D6/Es11X0vbpNIS3dQbtC4YQf8=; b=ZhyKiVBHmEGJQciSC4TGXSxMdELm8qNMdYKjKSMKuH3KXKoShWJJhK6fmdgsSxWPFD 9pCITqNX4B7voKj1Lx1Yua+ijmmn/Nhtnk9950m7Ixjs2mLr02Gk3kW5DXMi01m1xC87 IDTLvCVXcBG4edS5+Fl/T+bBwgbNdFyyEZlJZY9H+OK+ZFPCblkCVZF2PFnc9wms4gWV xzBVWSSnMC2VtnaN4b5S9RnTupHFo0b3LDvcM1ZlDSO8GFDyAwyu3zGiF4BaQoaLglNq MMxX4pA44EB4j/XRKpLD9L/8PzE6fSlEMN/3Hp/nHUaSkaNwb1rEPOmz6tb1eAff1hNa UaaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792122346; x=1792727146; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=mIhYiFHKevI+TgLh8D6/Es11X0vbpNIS3dQbtC4YQf8=; b=v2W8syotu9XDlIRJrf5SmT1liJCZwss5TY6JcNEBqGo9bDqLzjKrrN4oUABrO5gxab ZzQBcZUeRW2zWXFOG+C6NslyQX9f6W+7m/v0nFhtyafvNsGVXVdgab1W9ye+DLBUvOt0 6PMt9bNfaxlhWdDC84LJQOoQovPV4UddpbMm8Dsut9IB6pM3Mb3r3FbpECtmLj3zCV63 iBWNpMokGay8ceh+gdK/zBTD2ZCpEQ6fJqFYrj996sR4afo5bo6SMW6Ni8FsGXTe4bu9 veKhPDBi0lY43KC2RgB5NImkkuNK0VF17/9KqNYCA0sP1rk3P4Olw8Fx4Xg28g8v7/pe HG0A== X-Forwarded-Encrypted: i=1; AKwUvBzB/IxlT4nxoFt089IV9dWJYGJDP1ypFbRs2vwRiJnROnhVdTA9wAZIn5r5yFDmdHHbpn4eYYFvgS5wIw==@lists.linux.dev X-Gm-Message-State: AFq9FYJxE8Y6Wg8AyYtVs1t7s5w6xtQ/PRcKBU21fC44Uk2PnydVGNeB lIReTeFMzVedDm1aP/YVuWgm2MKl2Y1/Ufn4A81F4qJTU/XLGUaiN6K6 X-Gm-Gg: AYBFou1ugHP0/YG1JkGc7farTcFvu/XouI3c5MLGP9Epf0enhjvirre0YX5x0AVmt7y WaylpS1w89UvzcjWWOB2UQw/By4FC5qyyz1gY8Tt1BKZ1X53NOIqGjlQSA4+GU1imi6xMnZ9LAm KMfB39xXANPo8G57pEMATIEJU2YT5DnCBWzWKZXCynLHgFx5cqeT+TbqtyBX6R+0tRYJNoXb3/m EVxpBm73o1IoGLMBJXrYZRJ0cw9Qp3JZKtiqMo/Q/ZAJzFOeLh6js+X7Lw/QrFhtSxWCaRWOc9u 0CQi1k3Oxtzf/qX1hSF2WTw8SWXOU/Uxt5CNjIKqlyTvnVGutdIWeumr4TuWtmxrXswrAN+O94D ri9LIvTqTGwMlSXCgKfFREVvIV6fLuDXoAkJlinrjfALXMZ4+rggqdzLqm48kG261SFa2DXE6dS fFh65qdRk0gTTS0SyVuSoL+YcL4bOz09VAzau3xJEnt4/tCv0shonbriAxS2Nc/KJwDdvU9C5ql Xlzpn6r87MI9qhtErbLoYLGXk71hqnakTLvDIzC0hvCuPwBglK8OZracWY2WGJ9qiGBIWM4DUOm jlVDm+1lB43XXEgil5LXVt0xpJKBRbChsLbFabEIikRocNMGSLRf4pCyQD2N124Mupz++WsbpGb DrHBOE0vIj3zCDcAJq79D/g== X-Received: by 2002:a05:6830:44a3:b0:806:e047:cd6e with SMTP id 46e09a7af769-83094e783b4mr18588745a34.8.1792122346290; Thu, 15 Oct 2026 20:45:46 -0700 (PDT) Received: from [127.0.1.1] (174-29-1-49.hlrn.qwest.net. [174.29.1.49]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-8429b57870fsm834402a34.0.2026.10.15.20.45.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Oct 2026 20:45:45 -0700 (PDT) From: James Hilliard Date: Thu, 15 Oct 2026 21:45:26 -0600 Subject: [PATCH v8 11/17] mtd: rawnand: sunxi: bound DMA batches by the user-data register bank Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20261015-submit-sunxi-nand-vendor-oob-layout-v1-v8-11-8ba4881fbee8@gmail.com> References: <20261015-submit-sunxi-nand-vendor-oob-layout-v1-v8-0-8ba4881fbee8@gmail.com> In-Reply-To: <20261015-submit-sunxi-nand-vendor-oob-layout-v1-v8-0-8ba4881fbee8@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Sebastian Andrzej Siewior , Clark Williams , Steven Rostedt , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Maxime Ripard , Richard Genoud , Boris Brezillon , Masahiro Yamada , Brian Norris , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-rt-devel@lists.linux.dev, devicetree@vger.kernel.org, James Hilliard X-Mailer: b4 0.15.2 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= H6/H616 store ECC-protected OOB metadata, called user data, in 32 four-byte registers. The fields for successive ECC steps are concatenated in that 128-byte bank. However, the existing allocator fills the OOB space left after parity, allowing up to 32 user-data bytes per step without limiting the page total. A whole-page DMA transfer can exceed the bank. For example, 16 KiB main data plus 1280 OOB bytes with BCH40/1024 leaves 160 user-data bytes; with 1664 OOB bytes it allocates 512. Register accesses then extend beyond the user-data bank. PIO can handle these layouts because it reuses register zero for each step. Capping the page's allocation would instead move parity offsets on flash and break compatibility with pages written through PIO. Split DMA transfers without changing that allocation or the logical main-data and OOB offsets. Fill the first batch up to the 128-byte limit. Transfer each remaining step in a separate batch, using hardware slot and user-data register zero after explicitly selecting its main column and spare-area base. PAGE_OP generates later main-data columns from hardware slot numbers, not relative to the selected initial column. A multi-slot batch starting partway through a page would therefore revisit an earlier column. Single-slot later batches avoid those generated column changes. Pages that already fit keep one DMA batch. Program length fields from the batch's logical starting step, and consume its protected OOB and ECC status before reusing the registers. Keep erased state, correction counts and trailing OOB handling page-wide. On a failed DMA read, discard all partial statistics before the existing PIO retry. Use one page-read setup or program-begin for the whole page, and send program-end only after every batch and any trailing OOB succeed. A write may fall back to PIO only if DMA preparation fails before its first batch; never retry a write after part of the page has been transferred. Raw access and the OOB layout reported to MTD remain unchanged. Fixes: 54dcd6aa69db ("mtd: rawnand: sunxi: introduce maximize variable user data length") Signed-off-by: James Hilliard --- drivers/mtd/nand/raw/sunxi_nand.c | 202 ++++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 63 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 34c1c5037b11..8d523dc43093 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -54,6 +54,7 @@ #define NFC_REG_H6_RDATA_1 0x004C #define NFC_REG_A10_USER_DATA 0x0050 #define NFC_REG_H6_USER_DATA 0x0080 +#define NFC_H6_USER_DATA_REGS 32 #define NFC_REG_USER_DATA(nfc, x) (nfc->caps->reg_user_data + ((x) * 4)) #define NFC_REG_H6_USER_DATA_LEN 0x0070 /* A USER_DATA_LEN register can hold the length of 8 USER_DATA registers */ @@ -958,7 +959,36 @@ static u8 sunxi_nfc_user_data_sz(struct sunxi_nand_chip *sunxi_nand, int step) return sunxi_nand->user_data_bytes[step]; } -/* PIO uses register zero; DMA concatenates user data within each transfer. */ +/* Keep the on-flash layout, but fit each DMA batch in the user-data bank. */ +static int sunxi_nfc_dma_batch_steps(struct nand_chip *nand, + int first_step, int end_step) +{ + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + unsigned int user_data_sz = 0; + int i; + + if (!nfc->caps->reg_user_data_len) + return end_step - first_step; + + /* + * PAGE_OP generates main-data columns from hardware slot zero, not + * from the initial column. Use only slot zero after the first batch, + * so the explicit column change selects each remaining logical step. + */ + if (first_step) + return 1; + + for (i = first_step; i < end_step; i++) { + user_data_sz += sunxi_nfc_user_data_sz(sunxi_nand, i); + if (user_data_sz > NFC_H6_USER_DATA_REGS * sizeof(u32)) + break; + } + + return i - first_step; +} + +/* PIO uses register zero; DMA concatenates user data within each batch. */ static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8 *oob, unsigned int reg_index, bool bbm, int page, unsigned int user_data_sz) @@ -1377,30 +1407,32 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, pattern_found, step, 1); } -static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, u8 *buf, - int oob_required, int page, int nchunks) +static int sunxi_nfc_hw_ecc_read_batch_dma(struct nand_chip *nand, + struct sunxi_nfc_ecc_read *read, + int first_step, int nchunks) { struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct mtd_info *mtd = nand_to_mtd(nand); struct nand_ecc_ctrl *ecc = &nand->ecc; - struct sunxi_nfc_ecc_read read = { - .buf = buf, - .page = page, - .oob_required = oob_required, - .dma = true, - }; - unsigned int corrected = mtd->ecc_stats.corrected; - unsigned int failed = mtd->ecc_stats.failed; struct scatterlist sg; + int page = read->page; int ret, i; u32 status, pattern_found, wait; + if (first_step) { + ret = sunxi_nfc_read_column(nand, page, first_step * ecc->size, + NULL, 0); + if (ret) + return ret; + } + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); if (ret) return ret; - ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, nchunks, + ret = sunxi_nfc_dma_op_prepare(nfc, read->buf + first_step * ecc->size, + ecc->size, nchunks, DMA_FROM_DEVICE, &sg); if (ret) return ret; @@ -1408,7 +1440,12 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, u8 *buf, sunxi_nfc_hw_ecc_enable(nand); sunxi_nfc_reset_user_data_len(nfc); for (i = 0; i < nchunks; i++) - sunxi_nfc_set_user_data_len(nfc, sunxi_nfc_user_data_sz(sunxi_nand, i), i); + sunxi_nfc_set_user_data_len(nfc, + sunxi_nfc_user_data_sz(sunxi_nand, first_step + i), i); + /* exec_op() restores the page's spare base during column changes. */ + if (first_step) + writel(mtd->writesize + sunxi_get_oob_offset(sunxi_nand, ecc, first_step), + nfc->regs + NFC_REG_SPARE_AREA(nfc)); sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); @@ -1440,10 +1477,32 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, u8 *buf, status = readl(nfc->regs + NFC_REG_ECC_ST); pattern_found = readl(nfc->regs + nfc->caps->reg_pat_found); pattern_found = field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found); - ret = sunxi_nand->oob_ops->read_batch(nand, &read, status, pattern_found, - 0, nchunks); - if (ret) - goto err_stats; + + return sunxi_nand->oob_ops->read_batch(nand, read, status, pattern_found, + first_step, nchunks); +} + +static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, u8 *buf, + int oob_required, int page, int nchunks) +{ + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct mtd_info *mtd = nand_to_mtd(nand); + struct sunxi_nfc_ecc_read read = { + .buf = buf, + .page = page, + .oob_required = oob_required, + .dma = true, + }; + unsigned int corrected = mtd->ecc_stats.corrected; + unsigned int failed = mtd->ecc_stats.failed; + int first_step, batch_steps, ret; + + for (first_step = 0; first_step < nchunks; first_step += batch_steps) { + batch_steps = sunxi_nfc_dma_batch_steps(nand, first_step, nchunks); + ret = sunxi_nfc_hw_ecc_read_batch_dma(nand, &read, first_step, batch_steps); + if (ret) + goto err_stats; + } ret = sunxi_nand->oob_ops->finish_read(nand, &read, NULL); if (ret < 0) @@ -1749,71 +1808,88 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand, { struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct mtd_info *mtd = nand_to_mtd(nand); struct nand_ecc_ctrl *ecc = &nand->ecc; struct scatterlist sg; - unsigned int reg_index = 0; u32 wait; - int ret, i; + int first_step, batch_steps, ret, i; sunxi_nfc_select_chip(nand, nand->cur_cs); - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; + for (first_step = 0; first_step < ecc->steps; first_step += batch_steps) { + unsigned int reg_index = 0; - ret = sunxi_nfc_dma_op_prepare(nfc, buf, ecc->size, ecc->steps, - DMA_TO_DEVICE, &sg); - if (ret) - goto pio_fallback; + batch_steps = sunxi_nfc_dma_batch_steps(nand, first_step, ecc->steps); + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return ret; - sunxi_nfc_reset_user_data_len(nfc); - for (i = 0; i < ecc->steps; i++) { - unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, i); - int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); - const u8 *oob = nand->oob_poi + oob_off; + ret = sunxi_nfc_dma_op_prepare(nfc, buf + first_step * ecc->size, + ecc->size, batch_steps, DMA_TO_DEVICE, &sg); + if (ret) { + /* Only retry before any part of the page has been transferred. */ + if (first_step) + return ret; + goto pio_fallback; + } - sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, reg_index, !i, page, - user_data_sz); - sunxi_nfc_set_user_data_len(nfc, user_data_sz, i); - reg_index += user_data_sz / 4; - } + sunxi_nfc_reset_user_data_len(nfc); + for (i = first_step; i < first_step + batch_steps; i++) { + unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, i); + int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); + const u8 *oob = nand->oob_poi + oob_off; - ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0); - if (ret) { - sunxi_nfc_dma_op_abort(nfc); - sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg); - return ret; - } + sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, reg_index, !i, + page, user_data_sz); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, i - first_step); + reg_index += user_data_sz / 4; + } - sunxi_nfc_hw_ecc_enable(nand); - sunxi_nfc_randomizer_config(nand, page, false); - sunxi_nfc_randomizer_enable(nand); + if (first_step) + ret = nand_change_write_column_op(nand, first_step * ecc->size, + NULL, 0, false); + else + ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0); + if (ret) { + sunxi_nfc_dma_op_abort(nfc); + sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg); + return ret; + } - writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG, - nfc->regs + NFC_REG_WCMD_SET); + /* exec_op() restores the page's spare base during column changes. */ + if (first_step) + writel(mtd->writesize + sunxi_get_oob_offset(sunxi_nand, ecc, first_step), + nfc->regs + NFC_REG_SPARE_AREA(nfc)); + sunxi_nfc_hw_ecc_enable(nand); + sunxi_nfc_randomizer_config(nand, page, false); + sunxi_nfc_randomizer_enable(nand); - wait = NFC_CMD_INT_FLAG; + writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG, + nfc->regs + NFC_REG_WCMD_SET); - if (nfc->use_mdma) - wait |= NFC_DMA_INT_FLAG; - else - dma_async_issue_pending(nfc->dmac); + wait = NFC_CMD_INT_FLAG; - writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | - NFC_DATA_TRANS | NFC_ACCESS_DIR, - nfc->regs + NFC_REG_CMD); + if (nfc->use_mdma) + wait |= NFC_DMA_INT_FLAG; + else + dma_async_issue_pending(nfc->dmac); - ret = sunxi_nfc_wait_events(nfc, wait, false, 0); - if (ret) - sunxi_nfc_dma_op_abort(nfc); + writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | + NFC_DATA_TRANS | NFC_ACCESS_DIR, + nfc->regs + NFC_REG_CMD); - sunxi_nfc_randomizer_disable(nand); - sunxi_nfc_hw_ecc_disable(nand); + ret = sunxi_nfc_wait_events(nfc, wait, false, 0); + if (ret) + sunxi_nfc_dma_op_abort(nfc); - sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg); + sunxi_nfc_randomizer_disable(nand); + sunxi_nfc_hw_ecc_disable(nand); - if (ret) - return ret; + sunxi_nfc_dma_op_cleanup(nfc, DMA_TO_DEVICE, &sg); + + if (ret) + return ret; + } if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) { /* TODO: use DMA to transfer extra OOB bytes ? */