From patchwork Sat Oct 17 19:53:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 3670 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id 4972F1C2254 for ; Sat, 17 Oct 2026 21:53:36 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=gmail.com; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-26738-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-26738-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 2071D3933F for ; Sat, 17 Oct 2026 19:53:16 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D9F9B47A88E; Sat, 17 Oct 2026 19:53:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aDwbqF5A" X-Original-To: linux-sunxi@lists.linux.dev Received: from mail-ot1-f53.google.com (mail-ot1-f53.google.com [209.85.210.53]) (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 CE348248F72 for ; Sat, 17 Oct 2026 19:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792266795; cv=none; b=kT5WOEHxkLJYX34068UIuQpVIyYWClyaCMb0dRhYk5UHry1fXMMjcLOxkl7Iy/hygKHUYROUx2zLTujQ/Z4ybIRAR3n9yQp4dOhJRGWhhGTDbmHk+3Wkav4jc2Jegqq5Ubq7Eicpk0PweKWq0YRggisXKpVqYNHDZFqsUAGNeSw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1792266795; c=relaxed/simple; bh=GV2IeXg9Zq5O8ipbm51muo9ULIjiv+n4/kbqUlzqrm0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Erh3aMtPC5UkHU055MFMYxnihEzrRDFrZH4BSVqfRc371xgkTLFczGlCEkpJES3Sh9NxWBchuPmtnkRUyI5XCoeQHXoWRxA0rmiZdCXR/Rb+Ps/Xuiicc/UZ46F2uVgEz/Pt2zIHomVym6EeRDXI/hCPbxlLRwT9BPmtfXz7kc4= 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=aDwbqF5A; arc=none smtp.client-ip=209.85.210.53 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-f53.google.com with SMTP id 46e09a7af769-845f3fa7f38so219509a34.3 for ; Sat, 17 Oct 2026 12:53:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792266792; x=1792871592; darn=lists.linux.dev; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=4P4PvF1h4nH9aNU08hyrkF4dkUmnUPpBIVg5VJpyCM8=; b=aDwbqF5AmBzvlOeVJQvO9QS6OQzdXP0QO/icjMn/59ngGYoBxNa38DCCw5oGhsbNFK JYTS6CWk4wQQ1hIVfBCoxhIGCxs7i4AuhcQawcZGSrko9q65ASMbHDL4MjfYa7svZbRt wJHlSAks9l9T7+hbSbGMNlRsxJHL9BvIa5+HDCoARwOTG5SyqXh/advMWcsQgCyeSmJz s7vK2bvoEzPzE0UvuNryOmeDWiodocjdh/DCMlywVpOuTOupPw/8AznppngFQMFz7xt4 t8K9ke9LFHOttfIz43S6OfDL9S4GXMVKC6XH9hmkG11Athzev8VBlKKb+1gIP8Gi88g4 k+vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792266792; x=1792871592; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=4P4PvF1h4nH9aNU08hyrkF4dkUmnUPpBIVg5VJpyCM8=; b=c02hO/hoE/jYbKGyfIi51mGPA1Gl1n290rRMYmeDPielPNCBE1CWKn8pO7MXukQ4cI /Hw7KuAVZcemaJaRrfrv518sm5GYt4lA469kKdpgqikcQ/KKsplXscT6AVQ3WQv7rxhl XXyj/w2KxvXySTpTyoOiOv98SAd0JKwu63UhAicFKOladakrYwZMuoQGOCWjdtRENjcu UnA/DNj2kE6laBiCFuuuIQxjRNHx2DhdIfJ/HpVW/bslJlZWBg0uGJbUcjCBFwvVYuyP 72CRkByUWB+M1NQR3N8hcqZ65gJ6ssqpnrf5pONL2T5CPZ5bAeMvgCyNSaXTVsqNGbm/ U/ng== X-Forwarded-Encrypted: i=1; AKwUvBw/zewuq/D2HHtXuAiw0vO6OBvJqulXHhMIjwb2KRa+V0j7DEeKlBRUg95nGkuK7vhTT7yxEmIbZhu5Cw==@lists.linux.dev X-Gm-Message-State: AFq9FYJc0UqAvr9Ngqcqrv1jKxDLu/MTGJt6y2wxDGIh4TIwQW92muJF 3qzSa2Z8QY6tWnbyT03q+y5ysFEzwC1Ob7IxhygYb5K+V0KIM6CNieVz X-Gm-Gg: AYBFou01FAmjws+XcMnpVeHXd/2g5Yp366IT78hDOqXEpdvtcNuzZrB6x3CkSRG87n5 LPe6l2WIk2VV3RkTYAt1PxAPLW/57AHImFCgWMFchpF6q2PEumvqn+x8oCTI7UEcM6bXvlUbFhW kU5x381tlY9iFwO/+t7TqPXhMWnJtgubcttpLsanVOKX/Xm6KSjQXahLi62rwmb/jWvQAW59SNJ tVj7dlQkMbjJbqT08f65yjDv4nnb4Li+0o9KwEiKMvh2QXi+QsHz6peu5+oLJnZiAi3k26wOYzt VQ+/ik40Qk9WGGK0JUWEPZc+fftAt4S1MpZlgWZPmlVO57WMpa1hYtGSn3l9e044dqqOlUZUJzN QCcoevbOkpiyk1i8ze0QwJclcmMpUe8fhOyjhAtErmqI85n82zgIvCkHgiWwUI+X1L8GA2uAXMa lT8PQpT8fetmqagJFWXczCTSOA8d5od/ipj9WrpIfAxR+GRs7Gr6E3oEb7Fm0oaVqXNnMkupJfe bKIP17Jyfq0j+v0taf08M6Ivl6aj5d8U5LKlLw6uTiiyOMAOCQyBT3YBbYVqwsBm1F4lDg5si1v nJALfg5y5NoEdaNqNg7ZNrcwjrK6xreyMphjxEgoQeKHkeE1AGYCdXi7bbvTP1Uu5UtfXmzKbXA Aefe4/nvnCXRoHWBL/W5d5ZVfuGZDteo7OqkUl/FRIfln X-Received: by 2002:a05:6830:83b4:b0:7fa:5c68:d050 with SMTP id 46e09a7af769-845009804d7mr3324399a34.26.1792266791655; Sat, 17 Oct 2026 12:53:11 -0700 (PDT) Received: from james-x399.tailafd1a.ts.net (174-29-1-49.hlrn.qwest.net. [174.29.1.49]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-842a6e12dfasm4829795a34.24.2026.10.17.12.53.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 17 Oct 2026 12:53:10 -0700 (PDT) From: James Hilliard To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Sebastian Andrzej Siewior , Clark Williams , Steven Rostedt , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: James Hilliard , 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, Sashiko Subject: [PATCH v9 12/18] mtd: rawnand: sunxi: bound DMA batches by the user-data register bank Date: Sat, 17 Oct 2026 13:53:01 -0600 Message-ID: <20261017-submit-sunxi-nand-vendor-oob-layout-v1-v9-12-5af9a1be16ef@gmail.com> In-Reply-To: <20261017-submit-sunxi-nand-vendor-oob-layout-v1-v9-0-b624c09e3ee5@gmail.com> References: <20261017-submit-sunxi-nand-vendor-oob-layout-v1-v9-0-b624c09e3ee5@gmail.com> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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") Reported-by: Sashiko Closes: https://lore.kernel.org/r/20260909085138.9A98A1F00A3D@smtp.kernel.org Closes: https://lore.kernel.org/r/20260914031929.2E7091F000FF@smtp.kernel.org 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 ab9ff470062a..69e92fe21040 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 */ @@ -969,7 +970,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) @@ -1394,30 +1424,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; @@ -1425,7 +1457,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); @@ -1457,10 +1494,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) @@ -1766,71 +1825,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 ? */