From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 374822DECC2 for ; Fri, 20 Feb 2026 16:10:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603836; cv=none; b=goptqeuSf2UEjWCnlAct3Sh9ava4vvl2hjwOnwi2A7okDrM2OSkVO668cfkKJnH6uXlVjPXduSOJSuxEvb6RpJW2GEQAhxkvvGzYKP/ovJrfobYmNr6eEXCmkOMG3eV+vPsIpkX895ntt6ziwcj3I4VlA4Qw9+bWipFuxurMoFo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603836; c=relaxed/simple; bh=dttikJiZfkeAyckrKqao9r8VP9Ys24xHfHOxt5mVMVE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MJ55YE5BNbKb9RSeSrTii8+Nr+B/wfIiDKTJLBS/WdM9nV6f7eSl/uPYhhj9J37bMutziDKFsVUTR63RoH60Ees5H7EXe/j7JKTURsDzR90ek7yAcvGDPHZajn4TcdPtu2us7Aaq3j/ZFv6BzrrIZGvd3NGySCXgu7sjZ+yH4cA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=a6i2RJyL; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="a6i2RJyL" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id A2ED84E40945; Fri, 20 Feb 2026 16:10:33 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 795395FA8F; Fri, 20 Feb 2026 16:10:33 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7882910368D1C; Fri, 20 Feb 2026 17:10:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603832; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=sc1ud4NvoSk2r2XkR507CAgHdz72HRaNe5gFe/sJK8E=; b=a6i2RJyL2lZNjW2hv3kXp3DpYkrzMP6CA6mYlLELH1wOzZVx5Ruuh0ikaKvklhk+jzm0aL enWEmtR5phIczunvjo4Z5LVL5aisAdukPwHJiil4v9lza1fiNHJP9PJa/K5NWl6DBktl4l YGksdqN/u2vlgxvEwGBv9OJQb/Wc3KYVx/VBAiTtA5WRIpju7vlbgwgEv9f7JBZz32zt/z sIfpn/4MaE1gPj6JXtmMyWCo58FaY4azt7vapiW30EHX/+TIto0tXaPW9ebANNa4SYBFtB jnoYN1RMgS38Qi75XgMp+pmfQPCCjnR7bndOLgZxo/eouTa1n0O+AKrgWABZnw== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 1/6] mtd: rawnand: sunxi: fix sunxi_nand_ooblayout_free Date: Fri, 20 Feb 2026 17:10:06 +0100 Message-ID: <20260220161011.999642-2-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The available length is really USER_DATA_LEN - 2 instead of just 2 (the user data length minus the BBM length) That doesn't change anything now, but if USER_DATA_LEN changes, it will. Signed-off-by: Richard Genoud --- drivers/mtd/nand/raw/sunxi_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index 9dcdc93734cb..c420909b944b 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1761,12 +1761,12 @@ static int sunxi_nand_ooblayout_free(struct mtd_inf= o *mtd, int section, =20 /* * The first 2 bytes are used for BB markers, hence we - * only have 2 bytes available in the first user data + * only have USER_DATA_SZ - 2 bytes available in the first user data * section. */ if (!section && ecc->engine_type =3D=3D NAND_ECC_ENGINE_TYPE_ON_HOST) { oobregion->offset =3D 2; - oobregion->length =3D 2; + oobregion->length =3D USER_DATA_SZ - 2; =20 return 0; } From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EA6B2E0938 for ; Fri, 20 Feb 2026 16:10:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603838; cv=none; b=ZCr/BtXDQXFFN3uvDfUQR/gwzoVMrZdtMbMf4TxxoEb2pJQt9Yr1go1+HVNKqXQpQdivbrMlAfrHi8uPyKdN9VMhDVs0nlTShB+kACLaO56l5Tci4olb6+ujAN8HqaLPUAaDbiFoZj7u7mJf8aApzXFbCkV3x2CLXVAnOW1Xndg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603838; c=relaxed/simple; bh=/Nlxg6memL0C4+QlfWCbaOQc+Kl0SfzSqE1to0+e4og=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QIvfLeIGXHOP9Gdt/b1OGU5WlJIb2ICKAlDloPEU76DLK3qYuKeOQdrPGunfMJEWpoh1b1ftccVdAC4btq0w4Dd9gdv7uHWcrUuZRGlrpMYUD2K69N7HGSgOevEJX1tETzSJwlkeZb6m9hovvqHqt8J4BsEAzZt3ePcIaiMccnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=yy/o5J0X; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="yy/o5J0X" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 58F914E40967; Fri, 20 Feb 2026 16:10:35 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 2E2805FA8F; Fri, 20 Feb 2026 16:10:35 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 11F2910368D43; Fri, 20 Feb 2026 17:10:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603834; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=bnU1GLfsfh6CTuL5hdpsi/Zvec+WPL6baVdsR4hhOyQ=; b=yy/o5J0XBww1iLBwk2qM0/8qfK8FUIErpAb29xMB6xB2FobmoCiJbtVgK/FZ+wDrrXF0P+ njhPMJNplLyLIB7+KYrygmL+RyVWFvbHIcqY9A4CFiysiGWy08osrA+c1/TVAK8SUEPEzI N710nB7agg9msOKBVoM27xacCCcWsfN14B95EnrsIyepj7tTQmMPZ2rC83mFxH+8Z4ZgxO 8OG0/Jih4OyZ+CMrlLqc3mCScD8l0Lc3NZxcTyE9QH3Cagx1b9k5KQ6GgtLr/6TzH7dEES svi5zgiVh1YWubpWhRU1yS2t6hC/umNoVXuE+qmtE4YnbTz4vSbA7T9iRrCq7g== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 2/6] mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob Date: Fri, 20 Feb 2026 17:10:07 +0100 Message-ID: <20260220161011.999642-3-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" When dumping the OOB, the bytes at the end where actually copied from the beginning of the OOB instead of current_offset. That leads to something like: OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b instead of: OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff (example with BCH16, user data [8,0], no scrambling) *cur_off (offset from the beginning of the page) was compared to offset (offset from the beginning of the OOB), and then, the nand_change_read_column_op() sets the current position to the beginning of the OOB instead of OOB+offset Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME = mode") Signed-off-by: Richard Genoud Reviewed-by: Jernej Skrabec --- drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index c420909b944b..9c6e0625e34f 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1054,9 +1054,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct na= nd_chip *nand, if (len <=3D 0) return; =20 - if (!cur_off || *cur_off !=3D offset) - nand_change_read_column_op(nand, mtd->writesize, NULL, 0, - false); + if (!cur_off || *cur_off !=3D (offset + mtd->writesize)) + nand_change_read_column_op(nand, mtd->writesize + offset, + NULL, 0, false); =20 if (!randomize) sunxi_nfc_read_buf(nand, oob + offset, len); From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 04F572E9730 for ; Fri, 20 Feb 2026 16:10:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603839; cv=none; b=IvwTpG32QMOgEGP5WKTtq6ku5CizY8N2nLg+CvbuISdDpzki3zQLWRRMZOJTPh/aVMutQHc1r3oVqkVsB22+BW62hjQB2whN2flSG6PtIVLtyYfha2iEXCl09uRsOOE5Fy/ocYwZPWTR/xBwj+k62b+rMPgAaUp32PlZHeELA4M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603839; c=relaxed/simple; bh=+VJHFh1qK87zMJKzbtM/dyXlBA1sY8uPf+MwVLl9UIc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=usDgGNoEqpv7DA97JVXT3ooo7niZUWJufMHjjg2H/y4A78teJUXTaBUX9sgNAga+TjAWeyNoVUh689W6P+k3M/2JD9PgIME+NnOCd0jSzO+rTE9OcyKXP02RWGtedJ9zlxUsz7rjTbtO63CR7d9W+L64Z4Yx082Cpbka15kvip8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=sHDQeCgn; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="sHDQeCgn" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 8058EC16543; Fri, 20 Feb 2026 16:10:49 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id A26835FA8F; Fri, 20 Feb 2026 16:10:36 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 9149C10368D47; Fri, 20 Feb 2026 17:10:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603835; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=5Kma/dQTmZIgX72gFxn/OuuMgzz0tSVOS/9inwwwNmo=; b=sHDQeCgn5sygMr4vwv4OD7wil38NEv5yfweX8rCtUpz8/kUeTJ4GAalBkzAk0Gg386lbVI xURYIDJLOgTo/cTYkiPhW2PJsSmhNi3ZVWPdeZDzUrDLazd7LN0Ljy9OE1WdKHZ1aY8faK /ORDFlZM7CiIdswgtCAMdtEl9mSi6KXFvZ7zzUi/FwMrXgWC9iYiOVjzc733bwA3tdXqem V1Xn1rr+TdqDY+wxE86qlpR51qay8ZDMio2lRCZjP//3d3wI00xKemifZ7aLCRE/k0dgKR SfpPGjrjrTFf95ihDcAqxZICe2m+jzles+Cz0D7iGM9rtUYP6UHMdrTx2LyONw== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 3/6] mtd: rawnand: sunxi: do not count BBM bytes twice Date: Fri, 20 Feb 2026 17:10:08 +0100 Message-ID: <20260220161011.999642-4-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" BBM is part of USER_DATA section, so we should remove it twice This was working ok because we are on the safe size, advertising that there was 2 bytes less available than reality. But we can't change old platforms, since it may lead to a different ECC strength, so, introduce a legacy flag for old platforms, and switch the new platforms to the correct count. Signed-off-by: Richard Genoud --- drivers/mtd/nand/raw/sunxi_nand.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index 9c6e0625e34f..99d305bbda53 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -281,6 +281,8 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(str= uct nand_chip *nand) * @has_ecc_block_512: If the ECC can handle 512B or only 1024B chuncks * @has_ecc_clk: If the controller needs an ECC clock. * @has_mbus_clk: If the controller needs a mbus clock. + * @legacy_max_strength:If the maximize strength function was off by 2 byt= es + * NB: this should not be used in new controllers * @reg_io_data: I/O data register * @reg_ecc_err_cnt: ECC error counter register * @reg_user_data: User data register @@ -310,6 +312,7 @@ struct sunxi_nfc_caps { bool has_ecc_block_512; bool has_ecc_clk; bool has_mbus_clk; + bool legacy_max_strength; unsigned int reg_io_data; unsigned int reg_ecc_err_cnt; unsigned int reg_user_data; @@ -1811,10 +1814,22 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_= chip *nand, ecc->size =3D 1024; nsectors =3D mtd->writesize / ecc->size; =20 - /* Reserve 2 bytes for the BBM */ - bytes =3D (mtd->oobsize - 2) / nsectors; + /* + * The 2 BBM bytes should not be removed from the grand total, + * because they are part of the USER_DATA_SZ. + * But we can't modify that for older platform since it may + * result in a stronger ECC at the end, and break the + * compatibility. + */ + if (nfc->caps->legacy_max_strength) + bytes =3D (mtd->oobsize - 2) / nsectors; + else + bytes =3D mtd->oobsize / nsectors; =20 - /* 4 non-ECC bytes are added before each ECC bytes section */ + /* + * USER_DATA_SZ non-ECC bytes are added before each ECC bytes + * section, they contain the 2 BBM bytes + */ bytes -=3D USER_DATA_SZ; =20 /* and bytes has to be even. */ @@ -2379,6 +2394,7 @@ static const u8 sunxi_user_data_len_h6[] =3D { =20 static const struct sunxi_nfc_caps sunxi_nfc_a10_caps =3D { .has_ecc_block_512 =3D true, + .legacy_max_strength =3D true, .reg_io_data =3D NFC_REG_A10_IO_DATA, .reg_ecc_err_cnt =3D NFC_REG_A10_ECC_ERR_CNT, .reg_user_data =3D NFC_REG_A10_USER_DATA, @@ -2400,6 +2416,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps= =3D { static const struct sunxi_nfc_caps sunxi_nfc_a23_caps =3D { .has_mdma =3D true, .has_ecc_block_512 =3D true, + .legacy_max_strength =3D true, .reg_io_data =3D NFC_REG_A23_IO_DATA, .reg_ecc_err_cnt =3D NFC_REG_A10_ECC_ERR_CNT, .reg_user_data =3D NFC_REG_A10_USER_DATA, From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB8D62E92BC for ; Fri, 20 Feb 2026 16:10:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603843; cv=none; b=oK9YURSHFNvf8GXpZAypE28V9GWfqMyHYpKxwCYPofAj4zXfH/xrQjUh4K+njHsvmBO5fZuq7v7eLmNfEQC4dzR9/BS7AdrJY9oLzUty/ZWmd0WUCYB33Lx+dg4ZDWYgTXUFwBUPGBnyCs0j6QIa0Sjv0uVH+bfee3S4QiPw/B4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603843; c=relaxed/simple; bh=5W/1OpfJsz5Okun9JADdKci255cYWEN3kmucMXgI7v4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ANjsSiD9JtQ1SgNUXNGTZx+iN90RCYg6zBek4KypVM0ot0Uxn3Fxzx5TTEwhpeTK+G9tJREZMxnN7orXnw6oeV5DlgkcK7PQ/3aJaq/m9GlurmbLC8t7N1TE+PcNhRJGl/T40wIVdtOOT8RIVZya9OtWuC9HRsf7LLIyl2utw6c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=XoZudrdU; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="XoZudrdU" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 8163D4E40945; Fri, 20 Feb 2026 16:10:38 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 563005FA8F; Fri, 20 Feb 2026 16:10:38 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 492B810368D45; Fri, 20 Feb 2026 17:10:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603837; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=kwjIfxJ8VNKkkqo4t0mWwpyEaLWQDyzfgT0yAJ2gX2E=; b=XoZudrdU9MU8FqiGo0MY7wjqPVjn/PHA5ebsam9oLxnojF2wMpeWVz8KZaBkFDhX0dcbBL uJPWsghim8fLkbuNDV0Q18OEIkIzq+LSM07yAxQR6P8F8gM7WnumCzk8WnNIsteajcyTWT hehwbRQWfn5hTdOAIXXsMAcdlea0F1LkEXzdsECoYKZcGohd14vNHxfNxrtGNYn6/LpgwQ tyiDXGQL6MN1la8r9gOHBPLVW9YsaOl38LiqNcN/cufurMz9gQeOPbeHTwbuUG5J88n1v3 ZHqs/c2OIUNpj575epYSLATY/Ih5FCQe1R+oeH/QYKK+zL33YdDJJAVFv8jjJA== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 4/6] mtd: rawnand: sunxi: replace hard coded value by a define - take2 Date: Fri, 20 Feb 2026 17:10:09 +0100 Message-ID: <20260220161011.999642-5-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The user data length (4) has been replaced almost all over the file, but 2 places were forgotten. The user data is placed before the ECC, for each step. So, in sunxi_nfc_hw_ecc_read_extra_oob(), the offset of the user data in OOB is indeed ((ecc->bytes + USER_DATA_SZ) * ecc->steps); And in sunxi_nand_ooblayout_ecc(), the offset of the ECC chunk in OOB is the same offset plus the current user data size: section * (ecc->bytes + USER_DATA_SZ) + USER_DATA_SZ; Fixes: 1be7ac78b72f ("mtd: rawnand: sunxi: Replace hard coded value by a de= fine") Signed-off-by: Richard Genoud Reviewed-by: Jernej Skrabec --- drivers/mtd/nand/raw/sunxi_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index 99d305bbda53..5d925b59b618 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1051,7 +1051,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct na= nd_chip *nand, { struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; - int offset =3D ((ecc->bytes + 4) * ecc->steps); + int offset =3D ((ecc->bytes + USER_DATA_SZ) * ecc->steps); int len =3D mtd->oobsize - offset; =20 if (len <=3D 0) @@ -1747,7 +1747,7 @@ static int sunxi_nand_ooblayout_ecc(struct mtd_info *= mtd, int section, if (section >=3D ecc->steps) return -ERANGE; =20 - oobregion->offset =3D section * (ecc->bytes + USER_DATA_SZ) + 4; + oobregion->offset =3D section * (ecc->bytes + USER_DATA_SZ) + USER_DATA_S= Z; oobregion->length =3D ecc->bytes; =20 return 0; From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C2832EB859 for ; Fri, 20 Feb 2026 16:10:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603844; cv=none; b=trJGb6UkCd1Rxfw8u3ClLpMdO8Ynmaoq4wW8igGwE2lWX1KcBnPZgRhxyjtyTK7uAZcD+Mcklcvmv0DNrdystEyny6n2kTbqLglHGiYF9shNaCgsYCM+Vl5QZC1YL9EcHlaOVRHrwONekgS+Hp163VALNgEHIF6P6l32Zjbi72Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603844; c=relaxed/simple; bh=6voLoD89XuLbGcVGmJ8G1iu/7ztbHj67VpMEPPMRKEQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YFFIUsGteZssWwS5JpgDJ0xghKSZgS1i9C+YwrZT3r+DUgB2Gtm/ayb7ZPD3x5rH66CEtIb3V44wjmMOXZKaa8SbaD9bZszK0WArhRy8hEiHjPDHuzF09OscuU9lUQjNxHt/G0ceoK8mpiRlACrpuhZwjCMlk6kBgM+4b/GMj9Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=Lj5W7Kbt; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="Lj5W7Kbt" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 2A98F1A0B1B; Fri, 20 Feb 2026 16:10:40 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 003BE5FA8F; Fri, 20 Feb 2026 16:10:40 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D30C310368D48; Fri, 20 Feb 2026 17:10:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603839; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=A5F3mFDukX3wj83GSepuRxgZnuBzHMueQF9c9toBDfY=; b=Lj5W7KbtqwKU37vaJfTiVFtRTUjoCePRvQlMFqlRH7v3m5GqNK0QGkxqtcUgn9zf/HRVEs 7K+veFwvtoP8IHxreJCU9s1u/BjamBBe5Xe/OYRUi8GdsFGTduUld+ZhbKVCEIOMLnMLJn PaOBrJ1F+wKXlPk23nvVzWaJjVgW5B/TZojfo1ezipkc+ikNtSi68jEKGL01lQLAJ26C73 FvzYwB66hXHUH5wdQNxPDh4csyOHzzOoQDcN8rb3H0E1K3kuZ0CY7bkLtNd9Wsk7PixFh1 XG/LYGjOAcmGN297A3CThZalfydYlcHuw5MabsmgKr6bcaQAsCBa7z3zR4lnQg== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 5/6] mtd: rawnand: sunxi: make the code mode self-explanatory Date: Fri, 20 Feb 2026 17:10:10 +0100 Message-ID: <20260220161011.999642-6-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" In sunxi_nfc_hw_ecc_{read,write}_chunk(), the ECC step was force to 0, the reason is not trivial to get when reading the code. The explanation is that, from the NAND flash controller perspective, we are indeed at step 0 for user data length and ECC errors. Just add a const value with an explanation to clarify things. Signed-off-by: Richard Genoud Acked-by: Jernej Skrabec --- drivers/mtd/nand/raw/sunxi_nand.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index 5d925b59b618..b3a0f70dd4e9 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -969,6 +969,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip= *nand, u32 pattern_found; bool erased; int ret; + /* From the controller point of view, we are at step 0 */ + const int nfc_step =3D 0; =20 if (*cur_off !=3D data_off) nand_change_read_column_op(nand, data_off, NULL, 0, false); @@ -983,7 +985,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip= *nand, return ret; =20 sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, 0); + sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, nfc_step); sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, @@ -999,10 +1001,9 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_ch= ip *nand, pattern_found =3D readl(nfc->regs + nfc->caps->reg_pat_found); pattern_found =3D field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found); =20 - ret =3D sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, 0, - readl(nfc->regs + NFC_REG_ECC_ST), - pattern_found, - &erased); + ret =3D sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, + nfc_step, readl(nfc->regs + NFC_REG_ECC_ST), + pattern_found, &erased); if (erased) return 1; =20 @@ -1035,7 +1036,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_ch= ip *nand, sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + USER_DATA_SZ, true, page); =20 - sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, 0, + sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, nfc_step, bbm, page); } } @@ -1213,6 +1214,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_c= hip *nand, struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct nand_ecc_ctrl *ecc =3D &nand->ecc; int ret; + /* From the controller point of view, we are at step 0 */ + const int nfc_step =3D 0; =20 if (data_off !=3D *cur_off) nand_change_write_column_op(nand, data_off, NULL, 0, false); @@ -1229,8 +1232,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_c= hip *nand, sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, 0); - sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, 0, bbm, page); + sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, nfc_step); + sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, nfc_step, bbm, page); =20 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | NFC_ECC_OP, From nobody Fri Apr 3 11:10:50 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E8C2F2765F5 for ; Fri, 20 Feb 2026 16:10:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603848; cv=none; b=petWW4A76ZyuOJKWHBnY+ZfhYna10+6gPbP76aVQUlIENdFHZs+tYVpZBCjDM2L8yB2975dcBgg1tHyGYhhNa1JAOU7vfyb6fkYWfZieNOYLwRNSmYpL1QBkEv0DwCycKuqlbWy/PBn+2TIaMBin6wWPdOgTCKnLsY3dwNxF5mc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771603848; c=relaxed/simple; bh=BiZdS9RgwOHOUtBfydEGsSsjYoAMncUEaaGdTaxbCyM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ed8z+QujBdo7/lYFJ1JItrVsk6UQGwV7Dd00clFa4X2baLHAxeEIOabIA6wXcgH4Nl4r9ohc26dPy6kc3mZLN5vLCE9zxOjjQxDi3z4SV3Re+Kt3mQfK9dqkG1W5VnSNmIYs0kZiWvRGZSDLiYDUfM0DZ02oYvo1kkiZEjt79Yo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=yhJmCVCP; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="yhJmCVCP" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id A8AF54E4096B; Fri, 20 Feb 2026 16:10:41 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 795C05FA8F; Fri, 20 Feb 2026 16:10:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 8E30D10368D4B; Fri, 20 Feb 2026 17:10:39 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1771603840; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=UqpZTvvt0fMC9dbVr1f07YoDPUQAVg+MQ+VVonZm8Rg=; b=yhJmCVCP4qGYwVk0PIeSeCC4BajSstWTbNZUl9vo/aqAc8S8AmHnbGcj2djGfofCrIcg1t yKj+sLKvZ3huTs1myiFylrcqIgvEv/JD8yRhGrOA3Yiu79ojkERc07e6iH0mad2DfiJULo T5xqOCkFQYNiOjwm7pXBfyN2M8oAZMxtGfsK9MFNMQDRF1CoZXKUGWHsZTjjF2t54gh748 abBuKQK9uPFvZfN7pl2Dp8AyS6jkj9BHGAjfz01HspZY0JTtwKiWCqQttpy4tcDbBceL4E N5ouJfQ/9Qj8kbTRFG25pm9yGiTqCEurEMJsTmcs6XJI7FqXMLOsXX8uov390Q== From: Richard Genoud To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: Wentao Liang , Maxime Ripard , Thomas Petazzoni , linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, Richard Genoud Subject: [PATCH 6/6] mtd: rawnand: sunxi: introduce variable user data length Date: Fri, 20 Feb 2026 17:10:11 +0100 Message-ID: <20260220161011.999642-7-richard.genoud@bootlin.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260220161011.999642-1-richard.genoud@bootlin.com> References: <20260220161011.999642-1-richard.genoud@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" In Allwinner SoCs, user data can be added in OOB before each ECC data. For older SoCs like A10, the user data size was the size of a register (4 bytes) and was mandatory before each ECC step. So, the A10 OOB Layout is: [4Bytes USER_DATA_STEP0] [ECC_STEP0 bytes] [4bytes USER_DATA_STEP1] [ECC_STEP1 bytes] ... NB: the BBM is stored at the beginning of the USER_DATA_STEP0. Now, for H6/H616 NAND flash controller, this user data can have a different size for each step. And the vendor has chosen a different layout from the one on A10, using 8 bytes for step 0 and nothing for further steps: [8bytes USER_DATA_STEP0] [ECC_STEP0 bytes] [ECC_STEP1 bytes]... (Still with BBM stored at the beginning of the USER_DATA_STEP0) In order to be compatible with this layout, the current one for H6/H616 has to be changed. Fixes: 88fd4e4deae8 ("mtd: rawnand: sunxi: Add support for H616 nand contro= ller") Signed-off-by: Richard Genoud --- drivers/mtd/nand/raw/sunxi_nand.c | 267 ++++++++++++++++++++++-------- 1 file changed, 201 insertions(+), 66 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi= _nand.c index b3a0f70dd4e9..0b6be18a0aaa 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -213,17 +213,6 @@ =20 #define NFC_MAX_CS 7 =20 -/* - * On A10/A23, this is the size of the NDFC User Data Register, containing= the - * mandatory user data bytes following the ECC for each ECC step. - * Thus, for each ECC step, we need the ECC bytes + USER_DATA_SZ. - * Those bits are currently unsused, and kept as default value 0xffffffff. - * - * On H6/H616, this size became configurable, from 0 bytes to 32, via the - * USER_DATA_LEN registers. - */ -#define USER_DATA_SZ 4 - /** * struct sunxi_nand_chip_sel - stores information related to NAND Chip Se= lect * @@ -306,6 +295,7 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(str= uct nand_chip *nand) * bytes to write * @nuser_data_tab: Size of @user_data_len_tab * @sram_size: Size of the NAND controller SRAM + * @user_data_len Function returning the user data length for a step */ struct sunxi_nfc_caps { bool has_mdma; @@ -332,6 +322,7 @@ struct sunxi_nfc_caps { unsigned int nuser_data_tab; unsigned int max_ecc_steps; int sram_size; + unsigned int (*user_data_len)(int step); }; =20 /** @@ -830,11 +821,40 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8= *buf) } =20 static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8= *oob, - int step, bool bbm, int page) + int step, bool bbm, int page, + unsigned int user_data_sz) { struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + u32 user_data; =20 - sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(nfc, step)= ), oob); + if (!nfc->caps->reg_user_data_len) { + /* + * For A10, the user data for step n is in the nth + * REG_USER_DATA + */ + user_data =3D readl(nfc->regs + NFC_REG_USER_DATA(nfc, step)); + sunxi_nfc_user_data_to_buf(user_data, oob); + } else { + /* + * For H6 NAND controller, the user data for all steps is + * contained in 32 user data registers, but not at a specific + * offset for each step, they are just concatenated. + */ + unsigned int user_data_off =3D 0; + unsigned int reg_off; + u8 *ptr =3D oob; + unsigned int i; + + for (i =3D 0; i < step; i++) + user_data_off +=3D nfc->caps->user_data_len(i); + + user_data_off /=3D 4; + for (i =3D 0; i < user_data_sz / 4; i++, ptr +=3D 4) { + reg_off =3D NFC_REG_USER_DATA(nfc, user_data_off + i); + user_data =3D readl(nfc->regs + reg_off); + sunxi_nfc_user_data_to_buf(user_data, ptr); + } + } =20 /* De-randomize the Bad Block Marker. */ if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) @@ -893,17 +913,45 @@ static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struc= t nand_chip *nand, bool bbm, int page) { struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); - u8 user_data[USER_DATA_SZ]; + unsigned int user_data_sz =3D nfc->caps->user_data_len(step); + u8 *user_data =3D NULL; =20 /* Randomize the Bad Block Marker. */ if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) { - memcpy(user_data, oob, sizeof(user_data)); + user_data =3D kmalloc(user_data_sz, GFP_KERNEL); + memcpy(user_data, oob, user_data_sz); sunxi_nfc_randomize_bbm(nand, page, user_data); oob =3D user_data; } =20 - writel(sunxi_nfc_buf_to_user_data(oob), - nfc->regs + NFC_REG_USER_DATA(nfc, step)); + if (!nfc->caps->reg_user_data_len) { + /* + * For A10, the user data for step n is in the nth + * REG_USER_DATA + */ + writel(sunxi_nfc_buf_to_user_data(oob), + nfc->regs + NFC_REG_USER_DATA(nfc, step)); + } else { + /* + * For H6 NAND controller, the user data for all steps is + * contained in 32 user data registers, but not at a specific + * offset for each step, they are just concatenated. + */ + unsigned int user_data_off =3D 0; + const u8 *ptr =3D oob; + unsigned int i; + + for (i =3D 0; i < step; i++) + user_data_off +=3D nfc->caps->user_data_len(i); + + user_data_off /=3D 4; + for (i =3D 0; i < user_data_sz / 4; i++, ptr +=3D 4) { + writel(sunxi_nfc_buf_to_user_data(ptr), + nfc->regs + NFC_REG_USER_DATA(nfc, user_data_off + i)); + } + } + + kfree(user_data); } =20 static void sunxi_nfc_hw_ecc_update_stats(struct nand_chip *nand, @@ -924,6 +972,7 @@ static int sunxi_nfc_hw_ecc_correct(struct nand_chip *n= and, u8 *data, u8 *oob, bool *erased) { struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + unsigned int user_data_sz =3D nfc->caps->user_data_len(step); struct nand_ecc_ctrl *ecc =3D &nand->ecc; u32 tmp; =20 @@ -946,7 +995,7 @@ static int sunxi_nfc_hw_ecc_correct(struct nand_chip *n= and, u8 *data, u8 *oob, memset(data, pattern, ecc->size); =20 if (oob) - memset(oob, pattern, ecc->bytes + USER_DATA_SZ); + memset(oob, pattern, ecc->bytes + user_data_sz); =20 return 0; } @@ -961,12 +1010,14 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_c= hip *nand, u8 *oob, int oob_off, int *cur_off, unsigned int *max_bitflips, - bool bbm, bool oob_required, int page) + int step, bool oob_required, int page) { struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + unsigned int user_data_sz =3D nfc->caps->user_data_len(step); struct nand_ecc_ctrl *ecc =3D &nand->ecc; int raw_mode =3D 0; u32 pattern_found; + bool bbm =3D !step; bool erased; int ret; /* From the controller point of view, we are at step 0 */ @@ -984,8 +1035,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chi= p *nand, if (ret) return ret; =20 - sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, nfc_step); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, nfc_step); sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, @@ -996,7 +1046,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chi= p *nand, if (ret) return ret; =20 - *cur_off =3D oob_off + ecc->bytes + USER_DATA_SZ; + *cur_off =3D oob_off + ecc->bytes + user_data_sz; =20 pattern_found =3D readl(nfc->regs + nfc->caps->reg_pat_found); pattern_found =3D field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found); @@ -1020,10 +1070,10 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_= chip *nand, ecc->size); =20 nand_change_read_column_op(nand, oob_off, oob, - ecc->bytes + USER_DATA_SZ, false); + ecc->bytes + user_data_sz, false); =20 ret =3D nand_check_erased_ecc_chunk(data, ecc->size, oob, - ecc->bytes + USER_DATA_SZ, + ecc->bytes + user_data_sz, NULL, 0, ecc->strength); if (ret >=3D 0) raw_mode =3D 1; @@ -1033,11 +1083,11 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_= chip *nand, if (oob_required) { nand_change_read_column_op(nand, oob_off, NULL, 0, false); - sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + USER_DATA_SZ, + sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + user_data_sz, true, page); =20 sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, nfc_step, - bbm, page); + bbm, page, user_data_sz); } } =20 @@ -1046,13 +1096,41 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_= chip *nand, return raw_mode; } =20 +/* + * Returns the offset of the OOB for each step. + * (it includes the user data before the ECC data.) + */ +static int sunxi_get_oob_offset(struct sunxi_nfc *nfc, + struct nand_ecc_ctrl *ecc, int step) +{ + int ecc_off =3D step * ecc->bytes; + int i; + + for (i =3D 0; i < step; i++) + ecc_off +=3D nfc->caps->user_data_len(i); + + return ecc_off; +} + +/* + * Returns the offset of the ECC for each step. + * So, it's the same as sunxi_get_oob_offset(), + * but it skips the next user data. + */ +static int sunxi_get_ecc_offset(struct sunxi_nfc *nfc, + struct nand_ecc_ctrl *ecc, int step) +{ + return sunxi_get_oob_offset(nfc, ecc, step) + nfc->caps->user_data_len(st= ep); +} + static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, u8 *oob, int *cur_off, bool randomize, int page) { + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; - int offset =3D ((ecc->bytes + USER_DATA_SZ) * ecc->steps); + int offset =3D sunxi_get_oob_offset(nfc, ecc, ecc->steps); int len =3D mtd->oobsize - offset; =20 if (len <=3D 0) @@ -1096,7 +1174,8 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct na= nd_chip *nand, uint8_t *buf =20 sunxi_nfc_hw_ecc_enable(nand); sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, 0); + for (i =3D 0; i < nchunks; i++) + sunxi_nfc_set_user_data_len(nfc, nfc->caps->user_data_len(i), i); sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); =20 @@ -1131,7 +1210,8 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct na= nd_chip *nand, uint8_t *buf =20 for (i =3D 0; i < nchunks; i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + unsigned int user_data_sz =3D nfc->caps->user_data_len(i); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); u8 *data =3D buf + data_off; u8 *oob =3D nand->oob_poi + oob_off; bool erased; @@ -1149,10 +1229,10 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct = nand_chip *nand, uint8_t *buf /* TODO: use DMA to retrieve OOB */ nand_change_read_column_op(nand, mtd->writesize + oob_off, - oob, ecc->bytes + USER_DATA_SZ, false); + oob, ecc->bytes + user_data_sz, false); =20 - sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, - !i, page); + sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, !i, + page, user_data_sz); } =20 if (erased) @@ -1164,7 +1244,8 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct na= nd_chip *nand, uint8_t *buf if (status & NFC_ECC_ERR_MSK(nfc)) { for (i =3D 0; i < nchunks; i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + unsigned int user_data_sz =3D nfc->caps->user_data_len(i); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); u8 *data =3D buf + data_off; u8 *oob =3D nand->oob_poi + oob_off; =20 @@ -1184,10 +1265,10 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct = nand_chip *nand, uint8_t *buf /* TODO: use DMA to retrieve OOB */ nand_change_read_column_op(nand, mtd->writesize + oob_off, - oob, ecc->bytes + USER_DATA_SZ, false); + oob, ecc->bytes + user_data_sz, false); =20 ret =3D nand_check_erased_ecc_chunk(data, ecc->size, oob, - ecc->bytes + USER_DATA_SZ, + ecc->bytes + user_data_sz, NULL, 0, ecc->strength); if (ret >=3D 0) @@ -1208,11 +1289,13 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct = nand_chip *nand, uint8_t *buf static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, const u8 *data, int data_off, const u8 *oob, int oob_off, - int *cur_off, bool bbm, + int *cur_off, int step, int page) { struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + unsigned int user_data_sz =3D nfc->caps->user_data_len(step); struct nand_ecc_ctrl *ecc =3D &nand->ecc; + bool bbm =3D !step; int ret; /* From the controller point of view, we are at step 0 */ const int nfc_step =3D 0; @@ -1231,8 +1314,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_c= hip *nand, =20 sunxi_nfc_randomizer_config(nand, page, false); sunxi_nfc_randomizer_enable(nand); - sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, nfc_step); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, nfc_step); sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, nfc_step, bbm, page); =20 writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | @@ -1244,7 +1326,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_c= hip *nand, if (ret) return ret; =20 - *cur_off =3D oob_off + ecc->bytes + USER_DATA_SZ; + *cur_off =3D oob_off + ecc->bytes + user_data_sz; =20 return 0; } @@ -1255,7 +1337,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct n= and_chip *nand, { struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; - int offset =3D ((ecc->bytes + USER_DATA_SZ) * ecc->steps); + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + int offset =3D sunxi_get_oob_offset(nfc, ecc, ecc->steps); int len =3D mtd->oobsize - offset; =20 if (len <=3D 0) @@ -1274,6 +1357,7 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct n= and_chip *nand, static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf, int oob_required, int page) { + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; unsigned int max_bitflips =3D 0; @@ -1286,16 +1370,17 @@ static int sunxi_nfc_hw_ecc_read_page(struct nand_c= hip *nand, uint8_t *buf, =20 sunxi_nfc_hw_ecc_enable(nand); =20 + sunxi_nfc_reset_user_data_len(nfc); for (i =3D 0; i < ecc->steps; i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); u8 *data =3D buf + data_off; u8 *oob =3D nand->oob_poi + oob_off; =20 ret =3D sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, oob, oob_off + mtd->writesize, &cur_off, &max_bitflips, - !i, oob_required, page); + i, oob_required, page); if (ret < 0) return ret; else if (ret) @@ -1333,6 +1418,7 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct nand_= chip *nand, u32 data_offs, u32 readlen, u8 *bufpoi, int page) { + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; int ret, i, cur_off =3D 0; @@ -1344,17 +1430,18 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct nan= d_chip *nand, =20 sunxi_nfc_hw_ecc_enable(nand); =20 + sunxi_nfc_reset_user_data_len(nfc); for (i =3D data_offs / ecc->size; i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); u8 *data =3D bufpoi + data_off; u8 *oob =3D nand->oob_poi + oob_off; =20 ret =3D sunxi_nfc_hw_ecc_read_chunk(nand, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, &max_bitflips, !i, + &cur_off, &max_bitflips, i, false, page); if (ret < 0) return ret; @@ -1389,6 +1476,7 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_ch= ip *nand, const uint8_t *buf, int oob_required, int page) { + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; int ret, i, cur_off =3D 0; @@ -1399,15 +1487,16 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_= chip *nand, =20 sunxi_nfc_hw_ecc_enable(nand); =20 + sunxi_nfc_reset_user_data_len(nfc); for (i =3D 0; i < ecc->steps; i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); const u8 *data =3D buf + data_off; const u8 *oob =3D nand->oob_poi + oob_off; =20 ret =3D sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, !i, page); + &cur_off, i, page); if (ret) return ret; } @@ -1426,6 +1515,7 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct nand= _chip *nand, const u8 *buf, int oob_required, int page) { + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_ecc_ctrl *ecc =3D &nand->ecc; int ret, i, cur_off =3D 0; @@ -1436,16 +1526,17 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct na= nd_chip *nand, =20 sunxi_nfc_hw_ecc_enable(nand); =20 + sunxi_nfc_reset_user_data_len(nfc); for (i =3D data_offs / ecc->size; i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { int data_off =3D i * ecc->size; - int oob_off =3D i * (ecc->bytes + USER_DATA_SZ); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); const u8 *data =3D buf + data_off; const u8 *oob =3D nand->oob_poi + oob_off; =20 ret =3D sunxi_nfc_hw_ecc_write_chunk(nand, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, !i, page); + &cur_off, i, page); if (ret) return ret; } @@ -1479,10 +1570,12 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct n= and_chip *nand, =20 sunxi_nfc_reset_user_data_len(nfc); for (i =3D 0; i < ecc->steps; i++) { - const u8 *oob =3D nand->oob_poi + (i * (ecc->bytes + USER_DATA_SZ)); + unsigned int user_data_sz =3D nfc->caps->user_data_len(i); + int oob_off =3D sunxi_get_oob_offset(nfc, ecc, i); + const u8 *oob =3D nand->oob_poi + oob_off; =20 sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, i, !i, page); - sunxi_nfc_set_user_data_len(nfc, USER_DATA_SZ, i); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, i); } =20 nand_prog_page_begin_op(nand, page, 0, NULL, 0); @@ -1746,11 +1839,12 @@ static int sunxi_nand_ooblayout_ecc(struct mtd_info= *mtd, int section, { struct nand_chip *nand =3D mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc =3D &nand->ecc; + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); =20 if (section >=3D ecc->steps) return -ERANGE; =20 - oobregion->offset =3D section * (ecc->bytes + USER_DATA_SZ) + USER_DATA_S= Z; + oobregion->offset =3D sunxi_get_ecc_offset(nfc, ecc, section); oobregion->length =3D ecc->bytes; =20 return 0; @@ -1761,18 +1855,20 @@ static int sunxi_nand_ooblayout_free(struct mtd_inf= o *mtd, int section, { struct nand_chip *nand =3D mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc =3D &nand->ecc; + struct sunxi_nfc *nfc =3D to_sunxi_nfc(nand->controller); + unsigned int user_data_sz =3D nfc->caps->user_data_len(section); =20 if (section > ecc->steps) return -ERANGE; =20 /* * The first 2 bytes are used for BB markers, hence we - * only have USER_DATA_SZ - 2 bytes available in the first user data + * only have user_data_sz - 2 bytes available in the first user data * section. */ if (!section && ecc->engine_type =3D=3D NAND_ECC_ENGINE_TYPE_ON_HOST) { oobregion->offset =3D 2; - oobregion->length =3D USER_DATA_SZ - 2; + oobregion->length =3D user_data_sz - 2; =20 return 0; } @@ -1784,10 +1880,10 @@ static int sunxi_nand_ooblayout_free(struct mtd_inf= o *mtd, int section, if (section =3D=3D ecc->steps && ecc->engine_type =3D=3D NAND_ECC_ENGINE_= TYPE_ON_HOST) return -ERANGE; =20 - oobregion->offset =3D section * (ecc->bytes + USER_DATA_SZ); + oobregion->offset =3D sunxi_get_ecc_offset(nfc, ecc, section); =20 if (section < ecc->steps) - oobregion->length =3D USER_DATA_SZ; + oobregion->length =3D user_data_sz; else oobregion->length =3D mtd->oobsize - oobregion->offset; =20 @@ -1808,14 +1904,18 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_= chip *nand, const u8 *strengths =3D nfc->caps->ecc_strengths; struct mtd_info *mtd =3D nand_to_mtd(nand); struct nand_device *nanddev =3D mtd_to_nanddev(mtd); + int total_user_data_sz =3D 0; int nsectors; int i; =20 - if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { - int bytes; + ecc->size =3D 1024; + nsectors =3D mtd->writesize / ecc->size; =20 - ecc->size =3D 1024; - nsectors =3D mtd->writesize / ecc->size; + for (i =3D 0; i < nsectors; i++) + total_user_data_sz +=3D nfc->caps->user_data_len(i); + + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { + int bytes =3D mtd->oobsize; =20 /* * The 2 BBM bytes should not be removed from the grand total, @@ -1825,15 +1925,15 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_= chip *nand, * compatibility. */ if (nfc->caps->legacy_max_strength) - bytes =3D (mtd->oobsize - 2) / nsectors; - else - bytes =3D mtd->oobsize / nsectors; + bytes -=3D 2; + + bytes -=3D total_user_data_sz; =20 /* - * USER_DATA_SZ non-ECC bytes are added before each ECC bytes - * section, they contain the 2 BBM bytes + * Once all user data has been subtracted, the rest can be used + * for ECC bytes */ - bytes -=3D USER_DATA_SZ; + bytes /=3D nsectors; =20 /* and bytes has to be even. */ if (bytes % 2) @@ -1886,7 +1986,7 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_ch= ip *nand, =20 nsectors =3D mtd->writesize / ecc->size; =20 - if (mtd->oobsize < ((ecc->bytes + USER_DATA_SZ) * nsectors)) + if (mtd->oobsize < (ecc->bytes * nsectors + total_user_data_sz)) return -EINVAL; =20 ecc->read_oob =3D sunxi_nfc_hw_ecc_read_oob; @@ -2383,6 +2483,38 @@ static void sunxi_nfc_remove(struct platform_device = *pdev) dma_release_channel(nfc->dmac); } =20 +static unsigned int sunxi_user_data_len_h616(int step) +{ + /* + * On H6/H616, the user data size became configurable, + * from 0 bytes to 32, via the USER_DATA_LEN registers. + * + * In H616 vendor image, the user data length is 8 byte on step 0 + * (that includes the BBM) and 0 bytes for the rest. + * So the OOB layout is: + * [BBM] [BBM] [6bytes USER_DATA_STEP0] [ECC_STEP0 bytes] [ECC_STEP1 byte= s]... + */ + if (step =3D=3D 0) + return 8; + return 0; +} + +static unsigned int sunxi_user_data_len_a10(int step) +{ + /* + * On A10/A23, this is the size of the NDFC User Data Register, + * containing the mandatory user data bytes preceding the ECC for each + * ECC step (and including the BBM) + * Thus, for each ECC step, we need USER_DATA_SZ + ECC bytes. + * + * So the layout is: + * [BBM] [BBM] [2Bytes USER_DATA_STEP0] [ECC_STEP0 bytes] + * [4bytes USER_DATA_STEP1] [ECC_step1 bytes]... + */ + + return 4; +} + static const u8 sunxi_ecc_strengths_a10[] =3D { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; @@ -2414,6 +2546,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps= =3D { .nstrengths =3D ARRAY_SIZE(sunxi_ecc_strengths_a10), .max_ecc_steps =3D 16, .sram_size =3D 1024, + .user_data_len =3D &sunxi_user_data_len_a10, }; =20 static const struct sunxi_nfc_caps sunxi_nfc_a23_caps =3D { @@ -2436,6 +2569,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a23_caps= =3D { .nstrengths =3D ARRAY_SIZE(sunxi_ecc_strengths_a10), .max_ecc_steps =3D 16, .sram_size =3D 1024, + .user_data_len =3D &sunxi_user_data_len_a10, }; =20 static const struct sunxi_nfc_caps sunxi_nfc_h616_caps =3D { @@ -2460,6 +2594,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_h616_cap= s =3D { .nuser_data_tab =3D ARRAY_SIZE(sunxi_user_data_len_h6), .max_ecc_steps =3D 32, .sram_size =3D 8192, + .user_data_len =3D &sunxi_user_data_len_h616, }; =20 static const struct of_device_id sunxi_nfc_ids[] =3D {