18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics 2018
48c2ecf20Sopenharmony_ci * Author: Christophe Kerello <christophe.kerello@st.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/mtd/rawnand.h>
178c2ecf20Sopenharmony_ci#include <linux/of_address.h>
188c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/regmap.h>
218c2ecf20Sopenharmony_ci#include <linux/reset.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Bad block marker length */
248c2ecf20Sopenharmony_ci#define FMC2_BBM_LEN			2
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* ECC step size */
278c2ecf20Sopenharmony_ci#define FMC2_ECC_STEP_SIZE		512
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* BCHDSRx registers length */
308c2ecf20Sopenharmony_ci#define FMC2_BCHDSRS_LEN		20
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* HECCR length */
338c2ecf20Sopenharmony_ci#define FMC2_HECCR_LEN			4
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Max requests done for a 8k nand page size */
368c2ecf20Sopenharmony_ci#define FMC2_MAX_SG			16
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* Max chip enable */
398c2ecf20Sopenharmony_ci#define FMC2_MAX_CE			2
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Max ECC buffer length */
428c2ecf20Sopenharmony_ci#define FMC2_MAX_ECC_BUF_LEN		(FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define FMC2_TIMEOUT_MS			5000
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* Timings */
478c2ecf20Sopenharmony_ci#define FMC2_THIZ			1
488c2ecf20Sopenharmony_ci#define FMC2_TIO			8000
498c2ecf20Sopenharmony_ci#define FMC2_TSYNC			3000
508c2ecf20Sopenharmony_ci#define FMC2_PCR_TIMING_MASK		0xf
518c2ecf20Sopenharmony_ci#define FMC2_PMEM_PATT_TIMING_MASK	0xff
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* FMC2 Controller Registers */
548c2ecf20Sopenharmony_ci#define FMC2_BCR1			0x0
558c2ecf20Sopenharmony_ci#define FMC2_PCR			0x80
568c2ecf20Sopenharmony_ci#define FMC2_SR				0x84
578c2ecf20Sopenharmony_ci#define FMC2_PMEM			0x88
588c2ecf20Sopenharmony_ci#define FMC2_PATT			0x8c
598c2ecf20Sopenharmony_ci#define FMC2_HECCR			0x94
608c2ecf20Sopenharmony_ci#define FMC2_ISR			0x184
618c2ecf20Sopenharmony_ci#define FMC2_ICR			0x188
628c2ecf20Sopenharmony_ci#define FMC2_CSQCR			0x200
638c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1			0x204
648c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2			0x208
658c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3			0x20c
668c2ecf20Sopenharmony_ci#define FMC2_CSQAR1			0x210
678c2ecf20Sopenharmony_ci#define FMC2_CSQAR2			0x214
688c2ecf20Sopenharmony_ci#define FMC2_CSQIER			0x220
698c2ecf20Sopenharmony_ci#define FMC2_CSQISR			0x224
708c2ecf20Sopenharmony_ci#define FMC2_CSQICR			0x228
718c2ecf20Sopenharmony_ci#define FMC2_CSQEMSR			0x230
728c2ecf20Sopenharmony_ci#define FMC2_BCHIER			0x250
738c2ecf20Sopenharmony_ci#define FMC2_BCHISR			0x254
748c2ecf20Sopenharmony_ci#define FMC2_BCHICR			0x258
758c2ecf20Sopenharmony_ci#define FMC2_BCHPBR1			0x260
768c2ecf20Sopenharmony_ci#define FMC2_BCHPBR2			0x264
778c2ecf20Sopenharmony_ci#define FMC2_BCHPBR3			0x268
788c2ecf20Sopenharmony_ci#define FMC2_BCHPBR4			0x26c
798c2ecf20Sopenharmony_ci#define FMC2_BCHDSR0			0x27c
808c2ecf20Sopenharmony_ci#define FMC2_BCHDSR1			0x280
818c2ecf20Sopenharmony_ci#define FMC2_BCHDSR2			0x284
828c2ecf20Sopenharmony_ci#define FMC2_BCHDSR3			0x288
838c2ecf20Sopenharmony_ci#define FMC2_BCHDSR4			0x28c
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* Register: FMC2_BCR1 */
868c2ecf20Sopenharmony_ci#define FMC2_BCR1_FMC2EN		BIT(31)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Register: FMC2_PCR */
898c2ecf20Sopenharmony_ci#define FMC2_PCR_PWAITEN		BIT(1)
908c2ecf20Sopenharmony_ci#define FMC2_PCR_PBKEN			BIT(2)
918c2ecf20Sopenharmony_ci#define FMC2_PCR_PWID			GENMASK(5, 4)
928c2ecf20Sopenharmony_ci#define FMC2_PCR_PWID_BUSWIDTH_8	0
938c2ecf20Sopenharmony_ci#define FMC2_PCR_PWID_BUSWIDTH_16	1
948c2ecf20Sopenharmony_ci#define FMC2_PCR_ECCEN			BIT(6)
958c2ecf20Sopenharmony_ci#define FMC2_PCR_ECCALG			BIT(8)
968c2ecf20Sopenharmony_ci#define FMC2_PCR_TCLR			GENMASK(12, 9)
978c2ecf20Sopenharmony_ci#define FMC2_PCR_TCLR_DEFAULT		0xf
988c2ecf20Sopenharmony_ci#define FMC2_PCR_TAR			GENMASK(16, 13)
998c2ecf20Sopenharmony_ci#define FMC2_PCR_TAR_DEFAULT		0xf
1008c2ecf20Sopenharmony_ci#define FMC2_PCR_ECCSS			GENMASK(19, 17)
1018c2ecf20Sopenharmony_ci#define FMC2_PCR_ECCSS_512		1
1028c2ecf20Sopenharmony_ci#define FMC2_PCR_ECCSS_2048		3
1038c2ecf20Sopenharmony_ci#define FMC2_PCR_BCHECC			BIT(24)
1048c2ecf20Sopenharmony_ci#define FMC2_PCR_WEN			BIT(25)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* Register: FMC2_SR */
1078c2ecf20Sopenharmony_ci#define FMC2_SR_NWRF			BIT(6)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/* Register: FMC2_PMEM */
1108c2ecf20Sopenharmony_ci#define FMC2_PMEM_MEMSET		GENMASK(7, 0)
1118c2ecf20Sopenharmony_ci#define FMC2_PMEM_MEMWAIT		GENMASK(15, 8)
1128c2ecf20Sopenharmony_ci#define FMC2_PMEM_MEMHOLD		GENMASK(23, 16)
1138c2ecf20Sopenharmony_ci#define FMC2_PMEM_MEMHIZ		GENMASK(31, 24)
1148c2ecf20Sopenharmony_ci#define FMC2_PMEM_DEFAULT		0x0a0a0a0a
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/* Register: FMC2_PATT */
1178c2ecf20Sopenharmony_ci#define FMC2_PATT_ATTSET		GENMASK(7, 0)
1188c2ecf20Sopenharmony_ci#define FMC2_PATT_ATTWAIT		GENMASK(15, 8)
1198c2ecf20Sopenharmony_ci#define FMC2_PATT_ATTHOLD		GENMASK(23, 16)
1208c2ecf20Sopenharmony_ci#define FMC2_PATT_ATTHIZ		GENMASK(31, 24)
1218c2ecf20Sopenharmony_ci#define FMC2_PATT_DEFAULT		0x0a0a0a0a
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/* Register: FMC2_ISR */
1248c2ecf20Sopenharmony_ci#define FMC2_ISR_IHLF			BIT(1)
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Register: FMC2_ICR */
1278c2ecf20Sopenharmony_ci#define FMC2_ICR_CIHLF			BIT(1)
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCR */
1308c2ecf20Sopenharmony_ci#define FMC2_CSQCR_CSQSTART		BIT(0)
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCFGR1 */
1338c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2EN		BIT(1)
1348c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_DMADEN		BIT(2)
1358c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_ACYNBR		GENMASK(6, 4)
1368c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_CMD1		GENMASK(15, 8)
1378c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2		GENMASK(23, 16)
1388c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_CMD1T		BIT(24)
1398c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR1_CMD2T		BIT(25)
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCFGR2 */
1428c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_SQSDTEN		BIT(0)
1438c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2EN		BIT(1)
1448c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_DMASEN		BIT(2)
1458c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD1		GENMASK(15, 8)
1468c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2		GENMASK(23, 16)
1478c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD1T		BIT(24)
1488c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR2_RCMD2T		BIT(25)
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCFGR3 */
1518c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_SNBR		GENMASK(13, 8)
1528c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_AC1T		BIT(16)
1538c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_AC2T		BIT(17)
1548c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_AC3T		BIT(18)
1558c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_AC4T		BIT(19)
1568c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_AC5T		BIT(20)
1578c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_SDT		BIT(21)
1588c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_RAC1T		BIT(22)
1598c2ecf20Sopenharmony_ci#define FMC2_CSQCFGR3_RAC2T		BIT(23)
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCAR1 */
1628c2ecf20Sopenharmony_ci#define FMC2_CSQCAR1_ADDC1		GENMASK(7, 0)
1638c2ecf20Sopenharmony_ci#define FMC2_CSQCAR1_ADDC2		GENMASK(15, 8)
1648c2ecf20Sopenharmony_ci#define FMC2_CSQCAR1_ADDC3		GENMASK(23, 16)
1658c2ecf20Sopenharmony_ci#define FMC2_CSQCAR1_ADDC4		GENMASK(31, 24)
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/* Register: FMC2_CSQCAR2 */
1688c2ecf20Sopenharmony_ci#define FMC2_CSQCAR2_ADDC5		GENMASK(7, 0)
1698c2ecf20Sopenharmony_ci#define FMC2_CSQCAR2_NANDCEN		GENMASK(11, 10)
1708c2ecf20Sopenharmony_ci#define FMC2_CSQCAR2_SAO		GENMASK(31, 16)
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* Register: FMC2_CSQIER */
1738c2ecf20Sopenharmony_ci#define FMC2_CSQIER_TCIE		BIT(0)
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* Register: FMC2_CSQICR */
1768c2ecf20Sopenharmony_ci#define FMC2_CSQICR_CLEAR_IRQ		GENMASK(4, 0)
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/* Register: FMC2_CSQEMSR */
1798c2ecf20Sopenharmony_ci#define FMC2_CSQEMSR_SEM		GENMASK(15, 0)
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/* Register: FMC2_BCHIER */
1828c2ecf20Sopenharmony_ci#define FMC2_BCHIER_DERIE		BIT(1)
1838c2ecf20Sopenharmony_ci#define FMC2_BCHIER_EPBRIE		BIT(4)
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* Register: FMC2_BCHICR */
1868c2ecf20Sopenharmony_ci#define FMC2_BCHICR_CLEAR_IRQ		GENMASK(4, 0)
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* Register: FMC2_BCHDSR0 */
1898c2ecf20Sopenharmony_ci#define FMC2_BCHDSR0_DUE		BIT(0)
1908c2ecf20Sopenharmony_ci#define FMC2_BCHDSR0_DEF		BIT(1)
1918c2ecf20Sopenharmony_ci#define FMC2_BCHDSR0_DEN		GENMASK(7, 4)
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* Register: FMC2_BCHDSR1 */
1948c2ecf20Sopenharmony_ci#define FMC2_BCHDSR1_EBP1		GENMASK(12, 0)
1958c2ecf20Sopenharmony_ci#define FMC2_BCHDSR1_EBP2		GENMASK(28, 16)
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/* Register: FMC2_BCHDSR2 */
1988c2ecf20Sopenharmony_ci#define FMC2_BCHDSR2_EBP3		GENMASK(12, 0)
1998c2ecf20Sopenharmony_ci#define FMC2_BCHDSR2_EBP4		GENMASK(28, 16)
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/* Register: FMC2_BCHDSR3 */
2028c2ecf20Sopenharmony_ci#define FMC2_BCHDSR3_EBP5		GENMASK(12, 0)
2038c2ecf20Sopenharmony_ci#define FMC2_BCHDSR3_EBP6		GENMASK(28, 16)
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/* Register: FMC2_BCHDSR4 */
2068c2ecf20Sopenharmony_ci#define FMC2_BCHDSR4_EBP7		GENMASK(12, 0)
2078c2ecf20Sopenharmony_ci#define FMC2_BCHDSR4_EBP8		GENMASK(28, 16)
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cienum stm32_fmc2_ecc {
2108c2ecf20Sopenharmony_ci	FMC2_ECC_HAM = 1,
2118c2ecf20Sopenharmony_ci	FMC2_ECC_BCH4 = 4,
2128c2ecf20Sopenharmony_ci	FMC2_ECC_BCH8 = 8
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cienum stm32_fmc2_irq_state {
2168c2ecf20Sopenharmony_ci	FMC2_IRQ_UNKNOWN = 0,
2178c2ecf20Sopenharmony_ci	FMC2_IRQ_BCH,
2188c2ecf20Sopenharmony_ci	FMC2_IRQ_SEQ
2198c2ecf20Sopenharmony_ci};
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistruct stm32_fmc2_timings {
2228c2ecf20Sopenharmony_ci	u8 tclr;
2238c2ecf20Sopenharmony_ci	u8 tar;
2248c2ecf20Sopenharmony_ci	u8 thiz;
2258c2ecf20Sopenharmony_ci	u8 twait;
2268c2ecf20Sopenharmony_ci	u8 thold_mem;
2278c2ecf20Sopenharmony_ci	u8 tset_mem;
2288c2ecf20Sopenharmony_ci	u8 thold_att;
2298c2ecf20Sopenharmony_ci	u8 tset_att;
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistruct stm32_fmc2_nand {
2338c2ecf20Sopenharmony_ci	struct nand_chip chip;
2348c2ecf20Sopenharmony_ci	struct stm32_fmc2_timings timings;
2358c2ecf20Sopenharmony_ci	int ncs;
2368c2ecf20Sopenharmony_ci	int cs_used[FMC2_MAX_CE];
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return container_of(chip, struct stm32_fmc2_nand, chip);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistruct stm32_fmc2_nfc {
2458c2ecf20Sopenharmony_ci	struct nand_controller base;
2468c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand nand;
2478c2ecf20Sopenharmony_ci	struct device *dev;
2488c2ecf20Sopenharmony_ci	struct device *cdev;
2498c2ecf20Sopenharmony_ci	struct regmap *regmap;
2508c2ecf20Sopenharmony_ci	void __iomem *data_base[FMC2_MAX_CE];
2518c2ecf20Sopenharmony_ci	void __iomem *cmd_base[FMC2_MAX_CE];
2528c2ecf20Sopenharmony_ci	void __iomem *addr_base[FMC2_MAX_CE];
2538c2ecf20Sopenharmony_ci	phys_addr_t io_phys_addr;
2548c2ecf20Sopenharmony_ci	phys_addr_t data_phys_addr[FMC2_MAX_CE];
2558c2ecf20Sopenharmony_ci	struct clk *clk;
2568c2ecf20Sopenharmony_ci	u8 irq_state;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	struct dma_chan *dma_tx_ch;
2598c2ecf20Sopenharmony_ci	struct dma_chan *dma_rx_ch;
2608c2ecf20Sopenharmony_ci	struct dma_chan *dma_ecc_ch;
2618c2ecf20Sopenharmony_ci	struct sg_table dma_data_sg;
2628c2ecf20Sopenharmony_ci	struct sg_table dma_ecc_sg;
2638c2ecf20Sopenharmony_ci	u8 *ecc_buf;
2648c2ecf20Sopenharmony_ci	int dma_ecc_len;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	struct completion complete;
2678c2ecf20Sopenharmony_ci	struct completion dma_data_complete;
2688c2ecf20Sopenharmony_ci	struct completion dma_ecc_complete;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	u8 cs_assigned;
2718c2ecf20Sopenharmony_ci	int cs_sel;
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_controller *base)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	return container_of(base, struct stm32_fmc2_nfc, base);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_timings_init(struct nand_chip *chip)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
2828c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
2838c2ecf20Sopenharmony_ci	struct stm32_fmc2_timings *timings = &nand->timings;
2848c2ecf20Sopenharmony_ci	u32 pmem, patt;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* Set tclr/tar timings */
2878c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_PCR,
2888c2ecf20Sopenharmony_ci			   FMC2_PCR_TCLR | FMC2_PCR_TAR,
2898c2ecf20Sopenharmony_ci			   FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) |
2908c2ecf20Sopenharmony_ci			   FIELD_PREP(FMC2_PCR_TAR, timings->tar));
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Set tset/twait/thold/thiz timings in common bank */
2938c2ecf20Sopenharmony_ci	pmem = FIELD_PREP(FMC2_PMEM_MEMSET, timings->tset_mem);
2948c2ecf20Sopenharmony_ci	pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait);
2958c2ecf20Sopenharmony_ci	pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem);
2968c2ecf20Sopenharmony_ci	pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz);
2978c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_PMEM, pmem);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* Set tset/twait/thold/thiz timings in attribut bank */
3008c2ecf20Sopenharmony_ci	patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att);
3018c2ecf20Sopenharmony_ci	patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait);
3028c2ecf20Sopenharmony_ci	patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att);
3038c2ecf20Sopenharmony_ci	patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz);
3048c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_PATT, patt);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_setup(struct nand_chip *chip)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
3108c2ecf20Sopenharmony_ci	u32 pcr = 0, pcr_mask;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* Configure ECC algorithm (default configuration is Hamming) */
3138c2ecf20Sopenharmony_ci	pcr_mask = FMC2_PCR_ECCALG;
3148c2ecf20Sopenharmony_ci	pcr_mask |= FMC2_PCR_BCHECC;
3158c2ecf20Sopenharmony_ci	if (chip->ecc.strength == FMC2_ECC_BCH8) {
3168c2ecf20Sopenharmony_ci		pcr |= FMC2_PCR_ECCALG;
3178c2ecf20Sopenharmony_ci		pcr |= FMC2_PCR_BCHECC;
3188c2ecf20Sopenharmony_ci	} else if (chip->ecc.strength == FMC2_ECC_BCH4) {
3198c2ecf20Sopenharmony_ci		pcr |= FMC2_PCR_ECCALG;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* Set buswidth */
3238c2ecf20Sopenharmony_ci	pcr_mask |= FMC2_PCR_PWID;
3248c2ecf20Sopenharmony_ci	if (chip->options & NAND_BUSWIDTH_16)
3258c2ecf20Sopenharmony_ci		pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Set ECC sector size */
3288c2ecf20Sopenharmony_ci	pcr_mask |= FMC2_PCR_ECCSS;
3298c2ecf20Sopenharmony_ci	pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
3378c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
3388c2ecf20Sopenharmony_ci	struct dma_slave_config dma_cfg;
3398c2ecf20Sopenharmony_ci	int ret;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (nand->cs_used[chipnr] == nfc->cs_sel)
3428c2ecf20Sopenharmony_ci		return 0;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	nfc->cs_sel = nand->cs_used[chipnr];
3458c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_setup(chip);
3468c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_timings_init(chip);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (nfc->dma_tx_ch && nfc->dma_rx_ch) {
3498c2ecf20Sopenharmony_ci		memset(&dma_cfg, 0, sizeof(dma_cfg));
3508c2ecf20Sopenharmony_ci		dma_cfg.src_addr = nfc->data_phys_addr[nfc->cs_sel];
3518c2ecf20Sopenharmony_ci		dma_cfg.dst_addr = nfc->data_phys_addr[nfc->cs_sel];
3528c2ecf20Sopenharmony_ci		dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
3538c2ecf20Sopenharmony_ci		dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
3548c2ecf20Sopenharmony_ci		dma_cfg.src_maxburst = 32;
3558c2ecf20Sopenharmony_ci		dma_cfg.dst_maxburst = 32;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg);
3588c2ecf20Sopenharmony_ci		if (ret) {
3598c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "tx DMA engine slave config failed\n");
3608c2ecf20Sopenharmony_ci			return ret;
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		ret = dmaengine_slave_config(nfc->dma_rx_ch, &dma_cfg);
3648c2ecf20Sopenharmony_ci		if (ret) {
3658c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "rx DMA engine slave config failed\n");
3668c2ecf20Sopenharmony_ci			return ret;
3678c2ecf20Sopenharmony_ci		}
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (nfc->dma_ecc_ch) {
3718c2ecf20Sopenharmony_ci		/*
3728c2ecf20Sopenharmony_ci		 * Hamming: we read HECCR register
3738c2ecf20Sopenharmony_ci		 * BCH4/BCH8: we read BCHDSRSx registers
3748c2ecf20Sopenharmony_ci		 */
3758c2ecf20Sopenharmony_ci		memset(&dma_cfg, 0, sizeof(dma_cfg));
3768c2ecf20Sopenharmony_ci		dma_cfg.src_addr = nfc->io_phys_addr;
3778c2ecf20Sopenharmony_ci		dma_cfg.src_addr += chip->ecc.strength == FMC2_ECC_HAM ?
3788c2ecf20Sopenharmony_ci				    FMC2_HECCR : FMC2_BCHDSR0;
3798c2ecf20Sopenharmony_ci		dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		ret = dmaengine_slave_config(nfc->dma_ecc_ch, &dma_cfg);
3828c2ecf20Sopenharmony_ci		if (ret) {
3838c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "ECC DMA engine slave config failed\n");
3848c2ecf20Sopenharmony_ci			return ret;
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		/* Calculate ECC length needed for one sector */
3888c2ecf20Sopenharmony_ci		nfc->dma_ecc_len = chip->ecc.strength == FMC2_ECC_HAM ?
3898c2ecf20Sopenharmony_ci				   FMC2_HECCR_LEN : FMC2_BCHDSRS_LEN;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	u32 pcr;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) :
4008c2ecf20Sopenharmony_ci		    FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN,
4088c2ecf20Sopenharmony_ci			   enable ? FMC2_PCR_ECCEN : 0);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	nfc->irq_state = FMC2_IRQ_SEQ;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_CSQIER,
4168c2ecf20Sopenharmony_ci			   FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	nfc->irq_state = FMC2_IRQ_UNKNOWN;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	nfc->irq_state = FMC2_IRQ_BCH;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (mode == NAND_ECC_WRITE)
4368c2ecf20Sopenharmony_ci		regmap_update_bits(nfc->regmap, FMC2_BCHIER,
4378c2ecf20Sopenharmony_ci				   FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE);
4388c2ecf20Sopenharmony_ci	else
4398c2ecf20Sopenharmony_ci		regmap_update_bits(nfc->regmap, FMC2_BCHIER,
4408c2ecf20Sopenharmony_ci				   FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_BCHIER,
4468c2ecf20Sopenharmony_ci			   FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	nfc->irq_state = FMC2_IRQ_UNKNOWN;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci/*
4578c2ecf20Sopenharmony_ci * Enable ECC logic and reset syndrome/parity bits previously calculated
4588c2ecf20Sopenharmony_ci * Syndrome/parity bits is cleared by setting the ECCEN bit to 0
4598c2ecf20Sopenharmony_ci */
4608c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_set_ecc(nfc, false);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (chip->ecc.strength != FMC2_ECC_HAM) {
4678c2ecf20Sopenharmony_ci		regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN,
4688c2ecf20Sopenharmony_ci				   mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		reinit_completion(&nfc->complete);
4718c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_clear_bch_irq(nfc);
4728c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_enable_bch_irq(nfc, mode);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_set_ecc(nfc, true);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci/*
4798c2ecf20Sopenharmony_ci * ECC Hamming calculation
4808c2ecf20Sopenharmony_ci * ECC is 3 bytes for 512 bytes of data (supports error correction up to
4818c2ecf20Sopenharmony_ci * max of 1-bit)
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	ecc[0] = ecc_sta;
4868c2ecf20Sopenharmony_ci	ecc[1] = ecc_sta >> 8;
4878c2ecf20Sopenharmony_ci	ecc[2] = ecc_sta >> 16;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data,
4918c2ecf20Sopenharmony_ci					u8 *ecc)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
4948c2ecf20Sopenharmony_ci	u32 sr, heccr;
4958c2ecf20Sopenharmony_ci	int ret;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr,
4988c2ecf20Sopenharmony_ci				       sr & FMC2_SR_NWRF, 1,
4998c2ecf20Sopenharmony_ci				       1000 * FMC2_TIMEOUT_MS);
5008c2ecf20Sopenharmony_ci	if (ret) {
5018c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "ham timeout\n");
5028c2ecf20Sopenharmony_ci		return ret;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	regmap_read(nfc->regmap, FMC2_HECCR, &heccr);
5068c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_ham_set_ecc(heccr, ecc);
5078c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_set_ecc(nfc, false);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return 0;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_ham_correct(struct nand_chip *chip, u8 *dat,
5138c2ecf20Sopenharmony_ci				      u8 *read_ecc, u8 *calc_ecc)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	u8 bit_position = 0, b0, b1, b2;
5168c2ecf20Sopenharmony_ci	u32 byte_addr = 0, b;
5178c2ecf20Sopenharmony_ci	u32 i, shifting = 1;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/* Indicate which bit and byte is faulty (if any) */
5208c2ecf20Sopenharmony_ci	b0 = read_ecc[0] ^ calc_ecc[0];
5218c2ecf20Sopenharmony_ci	b1 = read_ecc[1] ^ calc_ecc[1];
5228c2ecf20Sopenharmony_ci	b2 = read_ecc[2] ^ calc_ecc[2];
5238c2ecf20Sopenharmony_ci	b = b0 | (b1 << 8) | (b2 << 16);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* No errors */
5268c2ecf20Sopenharmony_ci	if (likely(!b))
5278c2ecf20Sopenharmony_ci		return 0;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* Calculate bit position */
5308c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
5318c2ecf20Sopenharmony_ci		switch (b % 4) {
5328c2ecf20Sopenharmony_ci		case 2:
5338c2ecf20Sopenharmony_ci			bit_position += shifting;
5348c2ecf20Sopenharmony_ci		case 1:
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci		default:
5378c2ecf20Sopenharmony_ci			return -EBADMSG;
5388c2ecf20Sopenharmony_ci		}
5398c2ecf20Sopenharmony_ci		shifting <<= 1;
5408c2ecf20Sopenharmony_ci		b >>= 2;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* Calculate byte position */
5448c2ecf20Sopenharmony_ci	shifting = 1;
5458c2ecf20Sopenharmony_ci	for (i = 0; i < 9; i++) {
5468c2ecf20Sopenharmony_ci		switch (b % 4) {
5478c2ecf20Sopenharmony_ci		case 2:
5488c2ecf20Sopenharmony_ci			byte_addr += shifting;
5498c2ecf20Sopenharmony_ci		case 1:
5508c2ecf20Sopenharmony_ci			break;
5518c2ecf20Sopenharmony_ci		default:
5528c2ecf20Sopenharmony_ci			return -EBADMSG;
5538c2ecf20Sopenharmony_ci		}
5548c2ecf20Sopenharmony_ci		shifting <<= 1;
5558c2ecf20Sopenharmony_ci		b >>= 2;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	/* Flip the bit */
5598c2ecf20Sopenharmony_ci	dat[byte_addr] ^= (1 << bit_position);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return 1;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci/*
5658c2ecf20Sopenharmony_ci * ECC BCH calculation and correction
5668c2ecf20Sopenharmony_ci * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to
5678c2ecf20Sopenharmony_ci * max of 4-bit/8-bit)
5688c2ecf20Sopenharmony_ci */
5698c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data,
5708c2ecf20Sopenharmony_ci					u8 *ecc)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
5738c2ecf20Sopenharmony_ci	u32 bchpbr;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* Wait until the BCH code is ready */
5768c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&nfc->complete,
5778c2ecf20Sopenharmony_ci					 msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
5788c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "bch timeout\n");
5798c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_disable_bch_irq(nfc);
5808c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	/* Read parity bits */
5848c2ecf20Sopenharmony_ci	regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr);
5858c2ecf20Sopenharmony_ci	ecc[0] = bchpbr;
5868c2ecf20Sopenharmony_ci	ecc[1] = bchpbr >> 8;
5878c2ecf20Sopenharmony_ci	ecc[2] = bchpbr >> 16;
5888c2ecf20Sopenharmony_ci	ecc[3] = bchpbr >> 24;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr);
5918c2ecf20Sopenharmony_ci	ecc[4] = bchpbr;
5928c2ecf20Sopenharmony_ci	ecc[5] = bchpbr >> 8;
5938c2ecf20Sopenharmony_ci	ecc[6] = bchpbr >> 16;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (chip->ecc.strength == FMC2_ECC_BCH8) {
5968c2ecf20Sopenharmony_ci		ecc[7] = bchpbr >> 24;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr);
5998c2ecf20Sopenharmony_ci		ecc[8] = bchpbr;
6008c2ecf20Sopenharmony_ci		ecc[9] = bchpbr >> 8;
6018c2ecf20Sopenharmony_ci		ecc[10] = bchpbr >> 16;
6028c2ecf20Sopenharmony_ci		ecc[11] = bchpbr >> 24;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr);
6058c2ecf20Sopenharmony_ci		ecc[12] = bchpbr;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_set_ecc(nfc, false);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	u32 bchdsr0 = ecc_sta[0];
6168c2ecf20Sopenharmony_ci	u32 bchdsr1 = ecc_sta[1];
6178c2ecf20Sopenharmony_ci	u32 bchdsr2 = ecc_sta[2];
6188c2ecf20Sopenharmony_ci	u32 bchdsr3 = ecc_sta[3];
6198c2ecf20Sopenharmony_ci	u32 bchdsr4 = ecc_sta[4];
6208c2ecf20Sopenharmony_ci	u16 pos[8];
6218c2ecf20Sopenharmony_ci	int i, den;
6228c2ecf20Sopenharmony_ci	unsigned int nb_errs = 0;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* No errors found */
6258c2ecf20Sopenharmony_ci	if (likely(!(bchdsr0 & FMC2_BCHDSR0_DEF)))
6268c2ecf20Sopenharmony_ci		return 0;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/* Too many errors detected */
6298c2ecf20Sopenharmony_ci	if (unlikely(bchdsr0 & FMC2_BCHDSR0_DUE))
6308c2ecf20Sopenharmony_ci		return -EBADMSG;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	pos[0] = FIELD_GET(FMC2_BCHDSR1_EBP1, bchdsr1);
6338c2ecf20Sopenharmony_ci	pos[1] = FIELD_GET(FMC2_BCHDSR1_EBP2, bchdsr1);
6348c2ecf20Sopenharmony_ci	pos[2] = FIELD_GET(FMC2_BCHDSR2_EBP3, bchdsr2);
6358c2ecf20Sopenharmony_ci	pos[3] = FIELD_GET(FMC2_BCHDSR2_EBP4, bchdsr2);
6368c2ecf20Sopenharmony_ci	pos[4] = FIELD_GET(FMC2_BCHDSR3_EBP5, bchdsr3);
6378c2ecf20Sopenharmony_ci	pos[5] = FIELD_GET(FMC2_BCHDSR3_EBP6, bchdsr3);
6388c2ecf20Sopenharmony_ci	pos[6] = FIELD_GET(FMC2_BCHDSR4_EBP7, bchdsr4);
6398c2ecf20Sopenharmony_ci	pos[7] = FIELD_GET(FMC2_BCHDSR4_EBP8, bchdsr4);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	den = FIELD_GET(FMC2_BCHDSR0_DEN, bchdsr0);
6428c2ecf20Sopenharmony_ci	for (i = 0; i < den; i++) {
6438c2ecf20Sopenharmony_ci		if (pos[i] < eccsize * 8) {
6448c2ecf20Sopenharmony_ci			change_bit(pos[i], (unsigned long *)dat);
6458c2ecf20Sopenharmony_ci			nb_errs++;
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	return nb_errs;
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat,
6538c2ecf20Sopenharmony_ci				      u8 *read_ecc, u8 *calc_ecc)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
6568c2ecf20Sopenharmony_ci	u32 ecc_sta[5];
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/* Wait until the decoding error is ready */
6598c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&nfc->complete,
6608c2ecf20Sopenharmony_ci					 msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
6618c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "bch timeout\n");
6628c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_disable_bch_irq(nfc);
6638c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	regmap_bulk_read(nfc->regmap, FMC2_BCHDSR0, ecc_sta, 5);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_set_ecc(nfc, false);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	return stm32_fmc2_nfc_bch_decode(chip->ecc.size, dat, ecc_sta);
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_read_page(struct nand_chip *chip, u8 *buf,
6748c2ecf20Sopenharmony_ci				    int oob_required, int page)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
6778c2ecf20Sopenharmony_ci	int ret, i, s, stat, eccsize = chip->ecc.size;
6788c2ecf20Sopenharmony_ci	int eccbytes = chip->ecc.bytes;
6798c2ecf20Sopenharmony_ci	int eccsteps = chip->ecc.steps;
6808c2ecf20Sopenharmony_ci	int eccstrength = chip->ecc.strength;
6818c2ecf20Sopenharmony_ci	u8 *p = buf;
6828c2ecf20Sopenharmony_ci	u8 *ecc_calc = chip->ecc.calc_buf;
6838c2ecf20Sopenharmony_ci	u8 *ecc_code = chip->ecc.code_buf;
6848c2ecf20Sopenharmony_ci	unsigned int max_bitflips = 0;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	ret = nand_read_page_op(chip, page, 0, NULL, 0);
6878c2ecf20Sopenharmony_ci	if (ret)
6888c2ecf20Sopenharmony_ci		return ret;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	for (i = mtd->writesize + FMC2_BBM_LEN, s = 0; s < eccsteps;
6918c2ecf20Sopenharmony_ci	     s++, i += eccbytes, p += eccsize) {
6928c2ecf20Sopenharmony_ci		chip->ecc.hwctl(chip, NAND_ECC_READ);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		/* Read the nand page sector (512 bytes) */
6958c2ecf20Sopenharmony_ci		ret = nand_change_read_column_op(chip, s * eccsize, p,
6968c2ecf20Sopenharmony_ci						 eccsize, false);
6978c2ecf20Sopenharmony_ci		if (ret)
6988c2ecf20Sopenharmony_ci			return ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		/* Read the corresponding ECC bytes */
7018c2ecf20Sopenharmony_ci		ret = nand_change_read_column_op(chip, i, ecc_code,
7028c2ecf20Sopenharmony_ci						 eccbytes, false);
7038c2ecf20Sopenharmony_ci		if (ret)
7048c2ecf20Sopenharmony_ci			return ret;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci		/* Correct the data */
7078c2ecf20Sopenharmony_ci		stat = chip->ecc.correct(chip, p, ecc_code, ecc_calc);
7088c2ecf20Sopenharmony_ci		if (stat == -EBADMSG)
7098c2ecf20Sopenharmony_ci			/* Check for empty pages with bitflips */
7108c2ecf20Sopenharmony_ci			stat = nand_check_erased_ecc_chunk(p, eccsize,
7118c2ecf20Sopenharmony_ci							   ecc_code, eccbytes,
7128c2ecf20Sopenharmony_ci							   NULL, 0,
7138c2ecf20Sopenharmony_ci							   eccstrength);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci		if (stat < 0) {
7168c2ecf20Sopenharmony_ci			mtd->ecc_stats.failed++;
7178c2ecf20Sopenharmony_ci		} else {
7188c2ecf20Sopenharmony_ci			mtd->ecc_stats.corrected += stat;
7198c2ecf20Sopenharmony_ci			max_bitflips = max_t(unsigned int, max_bitflips, stat);
7208c2ecf20Sopenharmony_ci		}
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/* Read oob */
7248c2ecf20Sopenharmony_ci	if (oob_required) {
7258c2ecf20Sopenharmony_ci		ret = nand_change_read_column_op(chip, mtd->writesize,
7268c2ecf20Sopenharmony_ci						 chip->oob_poi, mtd->oobsize,
7278c2ecf20Sopenharmony_ci						 false);
7288c2ecf20Sopenharmony_ci		if (ret)
7298c2ecf20Sopenharmony_ci			return ret;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	return max_bitflips;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci/* Sequencer read/write configuration */
7368c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page,
7378c2ecf20Sopenharmony_ci					int raw, bool write_data)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
7408c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
7418c2ecf20Sopenharmony_ci	u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN;
7428c2ecf20Sopenharmony_ci	/*
7438c2ecf20Sopenharmony_ci	 * cfg[0] => csqcfgr1, cfg[1] => csqcfgr2, cfg[2] => csqcfgr3
7448c2ecf20Sopenharmony_ci	 * cfg[3] => csqar1, cfg[4] => csqar2
7458c2ecf20Sopenharmony_ci	 */
7468c2ecf20Sopenharmony_ci	u32 cfg[5];
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN,
7498c2ecf20Sopenharmony_ci			   write_data ? FMC2_PCR_WEN : 0);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/*
7528c2ecf20Sopenharmony_ci	 * - Set Program Page/Page Read command
7538c2ecf20Sopenharmony_ci	 * - Enable DMA request data
7548c2ecf20Sopenharmony_ci	 * - Set timings
7558c2ecf20Sopenharmony_ci	 */
7568c2ecf20Sopenharmony_ci	cfg[0] = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T;
7578c2ecf20Sopenharmony_ci	if (write_data)
7588c2ecf20Sopenharmony_ci		cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN);
7598c2ecf20Sopenharmony_ci	else
7608c2ecf20Sopenharmony_ci		cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) |
7618c2ecf20Sopenharmony_ci			  FMC2_CSQCFGR1_CMD2EN |
7628c2ecf20Sopenharmony_ci			  FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) |
7638c2ecf20Sopenharmony_ci			  FMC2_CSQCFGR1_CMD2T;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	/*
7668c2ecf20Sopenharmony_ci	 * - Set Random Data Input/Random Data Read command
7678c2ecf20Sopenharmony_ci	 * - Enable the sequencer to access the Spare data area
7688c2ecf20Sopenharmony_ci	 * - Enable  DMA request status decoding for read
7698c2ecf20Sopenharmony_ci	 * - Set timings
7708c2ecf20Sopenharmony_ci	 */
7718c2ecf20Sopenharmony_ci	if (write_data)
7728c2ecf20Sopenharmony_ci		cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN);
7738c2ecf20Sopenharmony_ci	else
7748c2ecf20Sopenharmony_ci		cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) |
7758c2ecf20Sopenharmony_ci			 FMC2_CSQCFGR2_RCMD2EN |
7768c2ecf20Sopenharmony_ci			 FIELD_PREP(FMC2_CSQCFGR2_RCMD2, NAND_CMD_RNDOUTSTART) |
7778c2ecf20Sopenharmony_ci			 FMC2_CSQCFGR2_RCMD1T |
7788c2ecf20Sopenharmony_ci			 FMC2_CSQCFGR2_RCMD2T;
7798c2ecf20Sopenharmony_ci	if (!raw) {
7808c2ecf20Sopenharmony_ci		cfg[1] |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN;
7818c2ecf20Sopenharmony_ci		cfg[1] |= FMC2_CSQCFGR2_SQSDTEN;
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	/*
7858c2ecf20Sopenharmony_ci	 * - Set the number of sectors to be written
7868c2ecf20Sopenharmony_ci	 * - Set timings
7878c2ecf20Sopenharmony_ci	 */
7888c2ecf20Sopenharmony_ci	cfg[2] = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1);
7898c2ecf20Sopenharmony_ci	if (write_data) {
7908c2ecf20Sopenharmony_ci		cfg[2] |= FMC2_CSQCFGR3_RAC2T;
7918c2ecf20Sopenharmony_ci		if (chip->options & NAND_ROW_ADDR_3)
7928c2ecf20Sopenharmony_ci			cfg[2] |= FMC2_CSQCFGR3_AC5T;
7938c2ecf20Sopenharmony_ci		else
7948c2ecf20Sopenharmony_ci			cfg[2] |= FMC2_CSQCFGR3_AC4T;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	/*
7988c2ecf20Sopenharmony_ci	 * Set the fourth first address cycles
7998c2ecf20Sopenharmony_ci	 * Byte 1 and byte 2 => column, we start at 0x0
8008c2ecf20Sopenharmony_ci	 * Byte 3 and byte 4 => page
8018c2ecf20Sopenharmony_ci	 */
8028c2ecf20Sopenharmony_ci	cfg[3] = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page);
8038c2ecf20Sopenharmony_ci	cfg[3] |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	/*
8068c2ecf20Sopenharmony_ci	 * - Set chip enable number
8078c2ecf20Sopenharmony_ci	 * - Set ECC byte offset in the spare area
8088c2ecf20Sopenharmony_ci	 * - Calculate the number of address cycles to be issued
8098c2ecf20Sopenharmony_ci	 * - Set byte 5 of address cycle if needed
8108c2ecf20Sopenharmony_ci	 */
8118c2ecf20Sopenharmony_ci	cfg[4] = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel);
8128c2ecf20Sopenharmony_ci	if (chip->options & NAND_BUSWIDTH_16)
8138c2ecf20Sopenharmony_ci		cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1);
8148c2ecf20Sopenharmony_ci	else
8158c2ecf20Sopenharmony_ci		cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset);
8168c2ecf20Sopenharmony_ci	if (chip->options & NAND_ROW_ADDR_3) {
8178c2ecf20Sopenharmony_ci		cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5);
8188c2ecf20Sopenharmony_ci		cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16);
8198c2ecf20Sopenharmony_ci	} else {
8208c2ecf20Sopenharmony_ci		cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4);
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	regmap_bulk_write(nfc->regmap, FMC2_CSQCFGR1, cfg, 5);
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_dma_callback(void *arg)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	complete((struct completion *)arg);
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci/* Read/write data from/to a page */
8328c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
8338c2ecf20Sopenharmony_ci			       int raw, bool write_data)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
8368c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *desc_data, *desc_ecc;
8378c2ecf20Sopenharmony_ci	struct scatterlist *sg;
8388c2ecf20Sopenharmony_ci	struct dma_chan *dma_ch = nfc->dma_rx_ch;
8398c2ecf20Sopenharmony_ci	enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE;
8408c2ecf20Sopenharmony_ci	enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM;
8418c2ecf20Sopenharmony_ci	int eccsteps = chip->ecc.steps;
8428c2ecf20Sopenharmony_ci	int eccsize = chip->ecc.size;
8438c2ecf20Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(FMC2_TIMEOUT_MS);
8448c2ecf20Sopenharmony_ci	const u8 *p = buf;
8458c2ecf20Sopenharmony_ci	int s, ret;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	/* Configure DMA data */
8488c2ecf20Sopenharmony_ci	if (write_data) {
8498c2ecf20Sopenharmony_ci		dma_data_dir = DMA_TO_DEVICE;
8508c2ecf20Sopenharmony_ci		dma_transfer_dir = DMA_MEM_TO_DEV;
8518c2ecf20Sopenharmony_ci		dma_ch = nfc->dma_tx_ch;
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	for_each_sg(nfc->dma_data_sg.sgl, sg, eccsteps, s) {
8558c2ecf20Sopenharmony_ci		sg_set_buf(sg, p, eccsize);
8568c2ecf20Sopenharmony_ci		p += eccsize;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	ret = dma_map_sg(nfc->dev, nfc->dma_data_sg.sgl,
8608c2ecf20Sopenharmony_ci			 eccsteps, dma_data_dir);
8618c2ecf20Sopenharmony_ci	if (ret < 0)
8628c2ecf20Sopenharmony_ci		return ret;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	desc_data = dmaengine_prep_slave_sg(dma_ch, nfc->dma_data_sg.sgl,
8658c2ecf20Sopenharmony_ci					    eccsteps, dma_transfer_dir,
8668c2ecf20Sopenharmony_ci					    DMA_PREP_INTERRUPT);
8678c2ecf20Sopenharmony_ci	if (!desc_data) {
8688c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8698c2ecf20Sopenharmony_ci		goto err_unmap_data;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	reinit_completion(&nfc->dma_data_complete);
8738c2ecf20Sopenharmony_ci	reinit_completion(&nfc->complete);
8748c2ecf20Sopenharmony_ci	desc_data->callback = stm32_fmc2_nfc_dma_callback;
8758c2ecf20Sopenharmony_ci	desc_data->callback_param = &nfc->dma_data_complete;
8768c2ecf20Sopenharmony_ci	ret = dma_submit_error(dmaengine_submit(desc_data));
8778c2ecf20Sopenharmony_ci	if (ret)
8788c2ecf20Sopenharmony_ci		goto err_unmap_data;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	dma_async_issue_pending(dma_ch);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	if (!write_data && !raw) {
8838c2ecf20Sopenharmony_ci		/* Configure DMA ECC status */
8848c2ecf20Sopenharmony_ci		p = nfc->ecc_buf;
8858c2ecf20Sopenharmony_ci		for_each_sg(nfc->dma_ecc_sg.sgl, sg, eccsteps, s) {
8868c2ecf20Sopenharmony_ci			sg_set_buf(sg, p, nfc->dma_ecc_len);
8878c2ecf20Sopenharmony_ci			p += nfc->dma_ecc_len;
8888c2ecf20Sopenharmony_ci		}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci		ret = dma_map_sg(nfc->dev, nfc->dma_ecc_sg.sgl,
8918c2ecf20Sopenharmony_ci				 eccsteps, dma_data_dir);
8928c2ecf20Sopenharmony_ci		if (ret < 0)
8938c2ecf20Sopenharmony_ci			goto err_unmap_data;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci		desc_ecc = dmaengine_prep_slave_sg(nfc->dma_ecc_ch,
8968c2ecf20Sopenharmony_ci						   nfc->dma_ecc_sg.sgl,
8978c2ecf20Sopenharmony_ci						   eccsteps, dma_transfer_dir,
8988c2ecf20Sopenharmony_ci						   DMA_PREP_INTERRUPT);
8998c2ecf20Sopenharmony_ci		if (!desc_ecc) {
9008c2ecf20Sopenharmony_ci			ret = -ENOMEM;
9018c2ecf20Sopenharmony_ci			goto err_unmap_ecc;
9028c2ecf20Sopenharmony_ci		}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		reinit_completion(&nfc->dma_ecc_complete);
9058c2ecf20Sopenharmony_ci		desc_ecc->callback = stm32_fmc2_nfc_dma_callback;
9068c2ecf20Sopenharmony_ci		desc_ecc->callback_param = &nfc->dma_ecc_complete;
9078c2ecf20Sopenharmony_ci		ret = dma_submit_error(dmaengine_submit(desc_ecc));
9088c2ecf20Sopenharmony_ci		if (ret)
9098c2ecf20Sopenharmony_ci			goto err_unmap_ecc;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		dma_async_issue_pending(nfc->dma_ecc_ch);
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_clear_seq_irq(nfc);
9158c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_enable_seq_irq(nfc);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	/* Start the transfer */
9188c2ecf20Sopenharmony_ci	regmap_update_bits(nfc->regmap, FMC2_CSQCR,
9198c2ecf20Sopenharmony_ci			   FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Wait end of sequencer transfer */
9228c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&nfc->complete, timeout)) {
9238c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "seq timeout\n");
9248c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_disable_seq_irq(nfc);
9258c2ecf20Sopenharmony_ci		dmaengine_terminate_all(dma_ch);
9268c2ecf20Sopenharmony_ci		if (!write_data && !raw)
9278c2ecf20Sopenharmony_ci			dmaengine_terminate_all(nfc->dma_ecc_ch);
9288c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
9298c2ecf20Sopenharmony_ci		goto err_unmap_ecc;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* Wait DMA data transfer completion */
9338c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&nfc->dma_data_complete, timeout)) {
9348c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "data DMA timeout\n");
9358c2ecf20Sopenharmony_ci		dmaengine_terminate_all(dma_ch);
9368c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/* Wait DMA ECC transfer completion */
9408c2ecf20Sopenharmony_ci	if (!write_data && !raw) {
9418c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&nfc->dma_ecc_complete,
9428c2ecf20Sopenharmony_ci						 timeout)) {
9438c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "ECC DMA timeout\n");
9448c2ecf20Sopenharmony_ci			dmaengine_terminate_all(nfc->dma_ecc_ch);
9458c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
9468c2ecf20Sopenharmony_ci		}
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cierr_unmap_ecc:
9508c2ecf20Sopenharmony_ci	if (!write_data && !raw)
9518c2ecf20Sopenharmony_ci		dma_unmap_sg(nfc->dev, nfc->dma_ecc_sg.sgl,
9528c2ecf20Sopenharmony_ci			     eccsteps, dma_data_dir);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cierr_unmap_data:
9558c2ecf20Sopenharmony_ci	dma_unmap_sg(nfc->dev, nfc->dma_data_sg.sgl, eccsteps, dma_data_dir);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return ret;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write(struct nand_chip *chip, const u8 *buf,
9618c2ecf20Sopenharmony_ci				    int oob_required, int page, int raw)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
9648c2ecf20Sopenharmony_ci	int ret;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* Configure the sequencer */
9678c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_rw_page_init(chip, page, raw, true);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/* Write the page */
9708c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_xfer(chip, buf, raw, true);
9718c2ecf20Sopenharmony_ci	if (ret)
9728c2ecf20Sopenharmony_ci		return ret;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/* Write oob */
9758c2ecf20Sopenharmony_ci	if (oob_required) {
9768c2ecf20Sopenharmony_ci		ret = nand_change_write_column_op(chip, mtd->writesize,
9778c2ecf20Sopenharmony_ci						  chip->oob_poi, mtd->oobsize,
9788c2ecf20Sopenharmony_ci						  false);
9798c2ecf20Sopenharmony_ci		if (ret)
9808c2ecf20Sopenharmony_ci			return ret;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return nand_prog_page_end_op(chip);
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write_page(struct nand_chip *chip, const u8 *buf,
9878c2ecf20Sopenharmony_ci					 int oob_required, int page)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	int ret;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs);
9928c2ecf20Sopenharmony_ci	if (ret)
9938c2ecf20Sopenharmony_ci		return ret;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, false);
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip,
9998c2ecf20Sopenharmony_ci					     const u8 *buf, int oob_required,
10008c2ecf20Sopenharmony_ci					     int page)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	int ret;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs);
10058c2ecf20Sopenharmony_ci	if (ret)
10068c2ecf20Sopenharmony_ci		return ret;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, true);
10098c2ecf20Sopenharmony_ci}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci/* Get a status indicating which sectors have errors */
10128c2ecf20Sopenharmony_cistatic u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc)
10138c2ecf20Sopenharmony_ci{
10148c2ecf20Sopenharmony_ci	u32 csqemsr;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr);
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_correct(struct nand_chip *chip, u8 *dat,
10228c2ecf20Sopenharmony_ci				      u8 *read_ecc, u8 *calc_ecc)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
10258c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
10268c2ecf20Sopenharmony_ci	int eccbytes = chip->ecc.bytes;
10278c2ecf20Sopenharmony_ci	int eccsteps = chip->ecc.steps;
10288c2ecf20Sopenharmony_ci	int eccstrength = chip->ecc.strength;
10298c2ecf20Sopenharmony_ci	int i, s, eccsize = chip->ecc.size;
10308c2ecf20Sopenharmony_ci	u32 *ecc_sta = (u32 *)nfc->ecc_buf;
10318c2ecf20Sopenharmony_ci	u16 sta_map = stm32_fmc2_nfc_get_mapping_status(nfc);
10328c2ecf20Sopenharmony_ci	unsigned int max_bitflips = 0;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, dat += eccsize) {
10358c2ecf20Sopenharmony_ci		int stat = 0;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		if (eccstrength == FMC2_ECC_HAM) {
10388c2ecf20Sopenharmony_ci			/* Ecc_sta = FMC2_HECCR */
10398c2ecf20Sopenharmony_ci			if (sta_map & BIT(s)) {
10408c2ecf20Sopenharmony_ci				stm32_fmc2_nfc_ham_set_ecc(*ecc_sta,
10418c2ecf20Sopenharmony_ci							   &calc_ecc[i]);
10428c2ecf20Sopenharmony_ci				stat = stm32_fmc2_nfc_ham_correct(chip, dat,
10438c2ecf20Sopenharmony_ci								  &read_ecc[i],
10448c2ecf20Sopenharmony_ci								  &calc_ecc[i]);
10458c2ecf20Sopenharmony_ci			}
10468c2ecf20Sopenharmony_ci			ecc_sta++;
10478c2ecf20Sopenharmony_ci		} else {
10488c2ecf20Sopenharmony_ci			/*
10498c2ecf20Sopenharmony_ci			 * Ecc_sta[0] = FMC2_BCHDSR0
10508c2ecf20Sopenharmony_ci			 * Ecc_sta[1] = FMC2_BCHDSR1
10518c2ecf20Sopenharmony_ci			 * Ecc_sta[2] = FMC2_BCHDSR2
10528c2ecf20Sopenharmony_ci			 * Ecc_sta[3] = FMC2_BCHDSR3
10538c2ecf20Sopenharmony_ci			 * Ecc_sta[4] = FMC2_BCHDSR4
10548c2ecf20Sopenharmony_ci			 */
10558c2ecf20Sopenharmony_ci			if (sta_map & BIT(s))
10568c2ecf20Sopenharmony_ci				stat = stm32_fmc2_nfc_bch_decode(eccsize, dat,
10578c2ecf20Sopenharmony_ci								 ecc_sta);
10588c2ecf20Sopenharmony_ci			ecc_sta += 5;
10598c2ecf20Sopenharmony_ci		}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		if (stat == -EBADMSG)
10628c2ecf20Sopenharmony_ci			/* Check for empty pages with bitflips */
10638c2ecf20Sopenharmony_ci			stat = nand_check_erased_ecc_chunk(dat, eccsize,
10648c2ecf20Sopenharmony_ci							   &read_ecc[i],
10658c2ecf20Sopenharmony_ci							   eccbytes,
10668c2ecf20Sopenharmony_ci							   NULL, 0,
10678c2ecf20Sopenharmony_ci							   eccstrength);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		if (stat < 0) {
10708c2ecf20Sopenharmony_ci			mtd->ecc_stats.failed++;
10718c2ecf20Sopenharmony_ci		} else {
10728c2ecf20Sopenharmony_ci			mtd->ecc_stats.corrected += stat;
10738c2ecf20Sopenharmony_ci			max_bitflips = max_t(unsigned int, max_bitflips, stat);
10748c2ecf20Sopenharmony_ci		}
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	return max_bitflips;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_read_page(struct nand_chip *chip, u8 *buf,
10818c2ecf20Sopenharmony_ci					int oob_required, int page)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
10848c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
10858c2ecf20Sopenharmony_ci	u8 *ecc_calc = chip->ecc.calc_buf;
10868c2ecf20Sopenharmony_ci	u8 *ecc_code = chip->ecc.code_buf;
10878c2ecf20Sopenharmony_ci	u16 sta_map;
10888c2ecf20Sopenharmony_ci	int ret;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs);
10918c2ecf20Sopenharmony_ci	if (ret)
10928c2ecf20Sopenharmony_ci		return ret;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	/* Configure the sequencer */
10958c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_rw_page_init(chip, page, 0, false);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	/* Read the page */
10988c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_xfer(chip, buf, 0, false);
10998c2ecf20Sopenharmony_ci	if (ret)
11008c2ecf20Sopenharmony_ci		return ret;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	sta_map = stm32_fmc2_nfc_get_mapping_status(nfc);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	/* Check if errors happen */
11058c2ecf20Sopenharmony_ci	if (likely(!sta_map)) {
11068c2ecf20Sopenharmony_ci		if (oob_required)
11078c2ecf20Sopenharmony_ci			return nand_change_read_column_op(chip, mtd->writesize,
11088c2ecf20Sopenharmony_ci							  chip->oob_poi,
11098c2ecf20Sopenharmony_ci							  mtd->oobsize, false);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci		return 0;
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	/* Read oob */
11158c2ecf20Sopenharmony_ci	ret = nand_change_read_column_op(chip, mtd->writesize,
11168c2ecf20Sopenharmony_ci					 chip->oob_poi, mtd->oobsize, false);
11178c2ecf20Sopenharmony_ci	if (ret)
11188c2ecf20Sopenharmony_ci		return ret;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
11218c2ecf20Sopenharmony_ci					 chip->ecc.total);
11228c2ecf20Sopenharmony_ci	if (ret)
11238c2ecf20Sopenharmony_ci		return ret;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	/* Correct data */
11268c2ecf20Sopenharmony_ci	return chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_seq_read_page_raw(struct nand_chip *chip, u8 *buf,
11308c2ecf20Sopenharmony_ci					    int oob_required, int page)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
11338c2ecf20Sopenharmony_ci	int ret;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs);
11368c2ecf20Sopenharmony_ci	if (ret)
11378c2ecf20Sopenharmony_ci		return ret;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* Configure the sequencer */
11408c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_rw_page_init(chip, page, 1, false);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	/* Read the page */
11438c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_xfer(chip, buf, 1, false);
11448c2ecf20Sopenharmony_ci	if (ret)
11458c2ecf20Sopenharmony_ci		return ret;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	/* Read oob */
11488c2ecf20Sopenharmony_ci	if (oob_required)
11498c2ecf20Sopenharmony_ci		return nand_change_read_column_op(chip, mtd->writesize,
11508c2ecf20Sopenharmony_ci						  chip->oob_poi, mtd->oobsize,
11518c2ecf20Sopenharmony_ci						  false);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	return 0;
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic irqreturn_t stm32_fmc2_nfc_irq(int irq, void *dev_id)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = (struct stm32_fmc2_nfc *)dev_id;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (nfc->irq_state == FMC2_IRQ_SEQ)
11618c2ecf20Sopenharmony_ci		/* Sequencer is used */
11628c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_disable_seq_irq(nfc);
11638c2ecf20Sopenharmony_ci	else if (nfc->irq_state == FMC2_IRQ_BCH)
11648c2ecf20Sopenharmony_ci		/* BCH is used */
11658c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_disable_bch_irq(nfc);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	complete(&nfc->complete);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_read_data(struct nand_chip *chip, void *buf,
11738c2ecf20Sopenharmony_ci				     unsigned int len, bool force_8bit)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
11768c2ecf20Sopenharmony_ci	void __iomem *io_addr_r = nfc->data_base[nfc->cs_sel];
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (force_8bit && chip->options & NAND_BUSWIDTH_16)
11798c2ecf20Sopenharmony_ci		/* Reconfigure bus width to 8-bit */
11808c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_set_buswidth_16(nfc, false);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) {
11838c2ecf20Sopenharmony_ci		if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) {
11848c2ecf20Sopenharmony_ci			*(u8 *)buf = readb_relaxed(io_addr_r);
11858c2ecf20Sopenharmony_ci			buf += sizeof(u8);
11868c2ecf20Sopenharmony_ci			len -= sizeof(u8);
11878c2ecf20Sopenharmony_ci		}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci		if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32)) &&
11908c2ecf20Sopenharmony_ci		    len >= sizeof(u16)) {
11918c2ecf20Sopenharmony_ci			*(u16 *)buf = readw_relaxed(io_addr_r);
11928c2ecf20Sopenharmony_ci			buf += sizeof(u16);
11938c2ecf20Sopenharmony_ci			len -= sizeof(u16);
11948c2ecf20Sopenharmony_ci		}
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	/* Buf is aligned */
11988c2ecf20Sopenharmony_ci	while (len >= sizeof(u32)) {
11998c2ecf20Sopenharmony_ci		*(u32 *)buf = readl_relaxed(io_addr_r);
12008c2ecf20Sopenharmony_ci		buf += sizeof(u32);
12018c2ecf20Sopenharmony_ci		len -= sizeof(u32);
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* Read remaining bytes */
12058c2ecf20Sopenharmony_ci	if (len >= sizeof(u16)) {
12068c2ecf20Sopenharmony_ci		*(u16 *)buf = readw_relaxed(io_addr_r);
12078c2ecf20Sopenharmony_ci		buf += sizeof(u16);
12088c2ecf20Sopenharmony_ci		len -= sizeof(u16);
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	if (len)
12128c2ecf20Sopenharmony_ci		*(u8 *)buf = readb_relaxed(io_addr_r);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	if (force_8bit && chip->options & NAND_BUSWIDTH_16)
12158c2ecf20Sopenharmony_ci		/* Reconfigure bus width to 16-bit */
12168c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_set_buswidth_16(nfc, true);
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_write_data(struct nand_chip *chip, const void *buf,
12208c2ecf20Sopenharmony_ci				      unsigned int len, bool force_8bit)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
12238c2ecf20Sopenharmony_ci	void __iomem *io_addr_w = nfc->data_base[nfc->cs_sel];
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	if (force_8bit && chip->options & NAND_BUSWIDTH_16)
12268c2ecf20Sopenharmony_ci		/* Reconfigure bus width to 8-bit */
12278c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_set_buswidth_16(nfc, false);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) {
12308c2ecf20Sopenharmony_ci		if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) {
12318c2ecf20Sopenharmony_ci			writeb_relaxed(*(u8 *)buf, io_addr_w);
12328c2ecf20Sopenharmony_ci			buf += sizeof(u8);
12338c2ecf20Sopenharmony_ci			len -= sizeof(u8);
12348c2ecf20Sopenharmony_ci		}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32)) &&
12378c2ecf20Sopenharmony_ci		    len >= sizeof(u16)) {
12388c2ecf20Sopenharmony_ci			writew_relaxed(*(u16 *)buf, io_addr_w);
12398c2ecf20Sopenharmony_ci			buf += sizeof(u16);
12408c2ecf20Sopenharmony_ci			len -= sizeof(u16);
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	/* Buf is aligned */
12458c2ecf20Sopenharmony_ci	while (len >= sizeof(u32)) {
12468c2ecf20Sopenharmony_ci		writel_relaxed(*(u32 *)buf, io_addr_w);
12478c2ecf20Sopenharmony_ci		buf += sizeof(u32);
12488c2ecf20Sopenharmony_ci		len -= sizeof(u32);
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	/* Write remaining bytes */
12528c2ecf20Sopenharmony_ci	if (len >= sizeof(u16)) {
12538c2ecf20Sopenharmony_ci		writew_relaxed(*(u16 *)buf, io_addr_w);
12548c2ecf20Sopenharmony_ci		buf += sizeof(u16);
12558c2ecf20Sopenharmony_ci		len -= sizeof(u16);
12568c2ecf20Sopenharmony_ci	}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	if (len)
12598c2ecf20Sopenharmony_ci		writeb_relaxed(*(u8 *)buf, io_addr_w);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (force_8bit && chip->options & NAND_BUSWIDTH_16)
12628c2ecf20Sopenharmony_ci		/* Reconfigure bus width to 16-bit */
12638c2ecf20Sopenharmony_ci		stm32_fmc2_nfc_set_buswidth_16(nfc, true);
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip,
12678c2ecf20Sopenharmony_ci				  unsigned long timeout_ms)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
12708c2ecf20Sopenharmony_ci	const struct nand_sdr_timings *timings;
12718c2ecf20Sopenharmony_ci	u32 isr, sr;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* Check if there is no pending requests to the NAND flash */
12748c2ecf20Sopenharmony_ci	if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr,
12758c2ecf20Sopenharmony_ci				     sr & FMC2_SR_NWRF, 1,
12768c2ecf20Sopenharmony_ci				     1000 * FMC2_TIMEOUT_MS))
12778c2ecf20Sopenharmony_ci		dev_warn(nfc->dev, "Waitrdy timeout\n");
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	/* Wait tWB before R/B# signal is low */
12808c2ecf20Sopenharmony_ci	timings = nand_get_sdr_timings(nand_get_interface_config(chip));
12818c2ecf20Sopenharmony_ci	ndelay(PSEC_TO_NSEC(timings->tWB_max));
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	/* R/B# signal is low, clear high level flag */
12848c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	/* Wait R/B# signal is high */
12878c2ecf20Sopenharmony_ci	return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr,
12888c2ecf20Sopenharmony_ci					isr & FMC2_ISR_IHLF, 5,
12898c2ecf20Sopenharmony_ci					1000 * FMC2_TIMEOUT_MS);
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_exec_op(struct nand_chip *chip,
12938c2ecf20Sopenharmony_ci				  const struct nand_operation *op,
12948c2ecf20Sopenharmony_ci				  bool check_only)
12958c2ecf20Sopenharmony_ci{
12968c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
12978c2ecf20Sopenharmony_ci	const struct nand_op_instr *instr = NULL;
12988c2ecf20Sopenharmony_ci	unsigned int op_id, i, timeout;
12998c2ecf20Sopenharmony_ci	int ret;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (check_only)
13028c2ecf20Sopenharmony_ci		return 0;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_select_chip(chip, op->cs);
13058c2ecf20Sopenharmony_ci	if (ret)
13068c2ecf20Sopenharmony_ci		return ret;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	for (op_id = 0; op_id < op->ninstrs; op_id++) {
13098c2ecf20Sopenharmony_ci		instr = &op->instrs[op_id];
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		switch (instr->type) {
13128c2ecf20Sopenharmony_ci		case NAND_OP_CMD_INSTR:
13138c2ecf20Sopenharmony_ci			writeb_relaxed(instr->ctx.cmd.opcode,
13148c2ecf20Sopenharmony_ci				       nfc->cmd_base[nfc->cs_sel]);
13158c2ecf20Sopenharmony_ci			break;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci		case NAND_OP_ADDR_INSTR:
13188c2ecf20Sopenharmony_ci			for (i = 0; i < instr->ctx.addr.naddrs; i++)
13198c2ecf20Sopenharmony_ci				writeb_relaxed(instr->ctx.addr.addrs[i],
13208c2ecf20Sopenharmony_ci					       nfc->addr_base[nfc->cs_sel]);
13218c2ecf20Sopenharmony_ci			break;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		case NAND_OP_DATA_IN_INSTR:
13248c2ecf20Sopenharmony_ci			stm32_fmc2_nfc_read_data(chip, instr->ctx.data.buf.in,
13258c2ecf20Sopenharmony_ci						 instr->ctx.data.len,
13268c2ecf20Sopenharmony_ci						 instr->ctx.data.force_8bit);
13278c2ecf20Sopenharmony_ci			break;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci		case NAND_OP_DATA_OUT_INSTR:
13308c2ecf20Sopenharmony_ci			stm32_fmc2_nfc_write_data(chip, instr->ctx.data.buf.out,
13318c2ecf20Sopenharmony_ci						  instr->ctx.data.len,
13328c2ecf20Sopenharmony_ci						  instr->ctx.data.force_8bit);
13338c2ecf20Sopenharmony_ci			break;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci		case NAND_OP_WAITRDY_INSTR:
13368c2ecf20Sopenharmony_ci			timeout = instr->ctx.waitrdy.timeout_ms;
13378c2ecf20Sopenharmony_ci			ret = stm32_fmc2_nfc_waitrdy(chip, timeout);
13388c2ecf20Sopenharmony_ci			break;
13398c2ecf20Sopenharmony_ci		}
13408c2ecf20Sopenharmony_ci	}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	return ret;
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	u32 pcr;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	regmap_read(nfc->regmap, FMC2_PCR, &pcr);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	/* Set CS used to undefined */
13528c2ecf20Sopenharmony_ci	nfc->cs_sel = -1;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	/* Enable wait feature and nand flash memory bank */
13558c2ecf20Sopenharmony_ci	pcr |= FMC2_PCR_PWAITEN;
13568c2ecf20Sopenharmony_ci	pcr |= FMC2_PCR_PBKEN;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	/* Set buswidth to 8 bits mode for identification */
13598c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_PWID;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	/* ECC logic is disabled */
13628c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_ECCEN;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/* Default mode */
13658c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_ECCALG;
13668c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_BCHECC;
13678c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_WEN;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	/* Set default ECC sector size */
13708c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_ECCSS;
13718c2ecf20Sopenharmony_ci	pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_2048);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	/* Set default tclr/tar timings */
13748c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_TCLR;
13758c2ecf20Sopenharmony_ci	pcr |= FIELD_PREP(FMC2_PCR_TCLR, FMC2_PCR_TCLR_DEFAULT);
13768c2ecf20Sopenharmony_ci	pcr &= ~FMC2_PCR_TAR;
13778c2ecf20Sopenharmony_ci	pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* Enable FMC2 controller */
13808c2ecf20Sopenharmony_ci	if (nfc->dev == nfc->cdev)
13818c2ecf20Sopenharmony_ci		regmap_update_bits(nfc->regmap, FMC2_BCR1,
13828c2ecf20Sopenharmony_ci				   FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_PCR, pcr);
13858c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT);
13868c2ecf20Sopenharmony_ci	regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT);
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip,
13908c2ecf20Sopenharmony_ci					const struct nand_sdr_timings *sdrt)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
13938c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
13948c2ecf20Sopenharmony_ci	struct stm32_fmc2_timings *tims = &nand->timings;
13958c2ecf20Sopenharmony_ci	unsigned long hclk = clk_get_rate(nfc->clk);
13968c2ecf20Sopenharmony_ci	unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
13978c2ecf20Sopenharmony_ci	unsigned long timing, tar, tclr, thiz, twait;
13988c2ecf20Sopenharmony_ci	unsigned long tset_mem, tset_att, thold_mem, thold_att;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	tar = max_t(unsigned long, hclkp, sdrt->tAR_min);
14018c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(tar, hclkp) - 1;
14028c2ecf20Sopenharmony_ci	tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min);
14058c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(tclr, hclkp) - 1;
14068c2ecf20Sopenharmony_ci	tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	tims->thiz = FMC2_THIZ;
14098c2ecf20Sopenharmony_ci	thiz = (tims->thiz + 1) * hclkp;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/*
14128c2ecf20Sopenharmony_ci	 * tWAIT > tRP
14138c2ecf20Sopenharmony_ci	 * tWAIT > tWP
14148c2ecf20Sopenharmony_ci	 * tWAIT > tREA + tIO
14158c2ecf20Sopenharmony_ci	 */
14168c2ecf20Sopenharmony_ci	twait = max_t(unsigned long, hclkp, sdrt->tRP_min);
14178c2ecf20Sopenharmony_ci	twait = max_t(unsigned long, twait, sdrt->tWP_min);
14188c2ecf20Sopenharmony_ci	twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO);
14198c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(twait, hclkp);
14208c2ecf20Sopenharmony_ci	tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	/*
14238c2ecf20Sopenharmony_ci	 * tSETUP_MEM > tCS - tWAIT
14248c2ecf20Sopenharmony_ci	 * tSETUP_MEM > tALS - tWAIT
14258c2ecf20Sopenharmony_ci	 * tSETUP_MEM > tDS - (tWAIT - tHIZ)
14268c2ecf20Sopenharmony_ci	 */
14278c2ecf20Sopenharmony_ci	tset_mem = hclkp;
14288c2ecf20Sopenharmony_ci	if (sdrt->tCS_min > twait && (tset_mem < sdrt->tCS_min - twait))
14298c2ecf20Sopenharmony_ci		tset_mem = sdrt->tCS_min - twait;
14308c2ecf20Sopenharmony_ci	if (sdrt->tALS_min > twait && (tset_mem < sdrt->tALS_min - twait))
14318c2ecf20Sopenharmony_ci		tset_mem = sdrt->tALS_min - twait;
14328c2ecf20Sopenharmony_ci	if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
14338c2ecf20Sopenharmony_ci	    (tset_mem < sdrt->tDS_min - (twait - thiz)))
14348c2ecf20Sopenharmony_ci		tset_mem = sdrt->tDS_min - (twait - thiz);
14358c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(tset_mem, hclkp);
14368c2ecf20Sopenharmony_ci	tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	/*
14398c2ecf20Sopenharmony_ci	 * tHOLD_MEM > tCH
14408c2ecf20Sopenharmony_ci	 * tHOLD_MEM > tREH - tSETUP_MEM
14418c2ecf20Sopenharmony_ci	 * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
14428c2ecf20Sopenharmony_ci	 */
14438c2ecf20Sopenharmony_ci	thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min);
14448c2ecf20Sopenharmony_ci	if (sdrt->tREH_min > tset_mem &&
14458c2ecf20Sopenharmony_ci	    (thold_mem < sdrt->tREH_min - tset_mem))
14468c2ecf20Sopenharmony_ci		thold_mem = sdrt->tREH_min - tset_mem;
14478c2ecf20Sopenharmony_ci	if ((sdrt->tRC_min > tset_mem + twait) &&
14488c2ecf20Sopenharmony_ci	    (thold_mem < sdrt->tRC_min - (tset_mem + twait)))
14498c2ecf20Sopenharmony_ci		thold_mem = sdrt->tRC_min - (tset_mem + twait);
14508c2ecf20Sopenharmony_ci	if ((sdrt->tWC_min > tset_mem + twait) &&
14518c2ecf20Sopenharmony_ci	    (thold_mem < sdrt->tWC_min - (tset_mem + twait)))
14528c2ecf20Sopenharmony_ci		thold_mem = sdrt->tWC_min - (tset_mem + twait);
14538c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(thold_mem, hclkp);
14548c2ecf20Sopenharmony_ci	tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	/*
14578c2ecf20Sopenharmony_ci	 * tSETUP_ATT > tCS - tWAIT
14588c2ecf20Sopenharmony_ci	 * tSETUP_ATT > tCLS - tWAIT
14598c2ecf20Sopenharmony_ci	 * tSETUP_ATT > tALS - tWAIT
14608c2ecf20Sopenharmony_ci	 * tSETUP_ATT > tRHW - tHOLD_MEM
14618c2ecf20Sopenharmony_ci	 * tSETUP_ATT > tDS - (tWAIT - tHIZ)
14628c2ecf20Sopenharmony_ci	 */
14638c2ecf20Sopenharmony_ci	tset_att = hclkp;
14648c2ecf20Sopenharmony_ci	if (sdrt->tCS_min > twait && (tset_att < sdrt->tCS_min - twait))
14658c2ecf20Sopenharmony_ci		tset_att = sdrt->tCS_min - twait;
14668c2ecf20Sopenharmony_ci	if (sdrt->tCLS_min > twait && (tset_att < sdrt->tCLS_min - twait))
14678c2ecf20Sopenharmony_ci		tset_att = sdrt->tCLS_min - twait;
14688c2ecf20Sopenharmony_ci	if (sdrt->tALS_min > twait && (tset_att < sdrt->tALS_min - twait))
14698c2ecf20Sopenharmony_ci		tset_att = sdrt->tALS_min - twait;
14708c2ecf20Sopenharmony_ci	if (sdrt->tRHW_min > thold_mem &&
14718c2ecf20Sopenharmony_ci	    (tset_att < sdrt->tRHW_min - thold_mem))
14728c2ecf20Sopenharmony_ci		tset_att = sdrt->tRHW_min - thold_mem;
14738c2ecf20Sopenharmony_ci	if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
14748c2ecf20Sopenharmony_ci	    (tset_att < sdrt->tDS_min - (twait - thiz)))
14758c2ecf20Sopenharmony_ci		tset_att = sdrt->tDS_min - (twait - thiz);
14768c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(tset_att, hclkp);
14778c2ecf20Sopenharmony_ci	tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	/*
14808c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tALH
14818c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tCH
14828c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tCLH
14838c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tCOH
14848c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tDH
14858c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
14868c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tADL - tSETUP_MEM
14878c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tWH - tSETUP_MEM
14888c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tWHR - tSETUP_MEM
14898c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
14908c2ecf20Sopenharmony_ci	 * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
14918c2ecf20Sopenharmony_ci	 */
14928c2ecf20Sopenharmony_ci	thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min);
14938c2ecf20Sopenharmony_ci	thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min);
14948c2ecf20Sopenharmony_ci	thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min);
14958c2ecf20Sopenharmony_ci	thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min);
14968c2ecf20Sopenharmony_ci	thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min);
14978c2ecf20Sopenharmony_ci	if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) &&
14988c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem))
14998c2ecf20Sopenharmony_ci		thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem;
15008c2ecf20Sopenharmony_ci	if (sdrt->tADL_min > tset_mem &&
15018c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tADL_min - tset_mem))
15028c2ecf20Sopenharmony_ci		thold_att = sdrt->tADL_min - tset_mem;
15038c2ecf20Sopenharmony_ci	if (sdrt->tWH_min > tset_mem &&
15048c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tWH_min - tset_mem))
15058c2ecf20Sopenharmony_ci		thold_att = sdrt->tWH_min - tset_mem;
15068c2ecf20Sopenharmony_ci	if (sdrt->tWHR_min > tset_mem &&
15078c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tWHR_min - tset_mem))
15088c2ecf20Sopenharmony_ci		thold_att = sdrt->tWHR_min - tset_mem;
15098c2ecf20Sopenharmony_ci	if ((sdrt->tRC_min > tset_att + twait) &&
15108c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tRC_min - (tset_att + twait)))
15118c2ecf20Sopenharmony_ci		thold_att = sdrt->tRC_min - (tset_att + twait);
15128c2ecf20Sopenharmony_ci	if ((sdrt->tWC_min > tset_att + twait) &&
15138c2ecf20Sopenharmony_ci	    (thold_att < sdrt->tWC_min - (tset_att + twait)))
15148c2ecf20Sopenharmony_ci		thold_att = sdrt->tWC_min - (tset_att + twait);
15158c2ecf20Sopenharmony_ci	timing = DIV_ROUND_UP(thold_att, hclkp);
15168c2ecf20Sopenharmony_ci	tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr,
15208c2ecf20Sopenharmony_ci					  const struct nand_interface_config *conf)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	const struct nand_sdr_timings *sdrt;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	sdrt = nand_get_sdr_timings(conf);
15258c2ecf20Sopenharmony_ci	if (IS_ERR(sdrt))
15268c2ecf20Sopenharmony_ci		return PTR_ERR(sdrt);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (conf->timings.mode > 3)
15298c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
15328c2ecf20Sopenharmony_ci		return 0;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_calc_timings(chip, sdrt);
15358c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_timings_init(chip);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	return 0;
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	int ret = 0;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx");
15458c2ecf20Sopenharmony_ci	if (IS_ERR(nfc->dma_tx_ch)) {
15468c2ecf20Sopenharmony_ci		ret = PTR_ERR(nfc->dma_tx_ch);
15478c2ecf20Sopenharmony_ci		if (ret != -ENODEV && ret != -EPROBE_DEFER)
15488c2ecf20Sopenharmony_ci			dev_err(nfc->dev,
15498c2ecf20Sopenharmony_ci				"failed to request tx DMA channel: %d\n", ret);
15508c2ecf20Sopenharmony_ci		nfc->dma_tx_ch = NULL;
15518c2ecf20Sopenharmony_ci		goto err_dma;
15528c2ecf20Sopenharmony_ci	}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx");
15558c2ecf20Sopenharmony_ci	if (IS_ERR(nfc->dma_rx_ch)) {
15568c2ecf20Sopenharmony_ci		ret = PTR_ERR(nfc->dma_rx_ch);
15578c2ecf20Sopenharmony_ci		if (ret != -ENODEV && ret != -EPROBE_DEFER)
15588c2ecf20Sopenharmony_ci			dev_err(nfc->dev,
15598c2ecf20Sopenharmony_ci				"failed to request rx DMA channel: %d\n", ret);
15608c2ecf20Sopenharmony_ci		nfc->dma_rx_ch = NULL;
15618c2ecf20Sopenharmony_ci		goto err_dma;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc");
15658c2ecf20Sopenharmony_ci	if (IS_ERR(nfc->dma_ecc_ch)) {
15668c2ecf20Sopenharmony_ci		ret = PTR_ERR(nfc->dma_ecc_ch);
15678c2ecf20Sopenharmony_ci		if (ret != -ENODEV && ret != -EPROBE_DEFER)
15688c2ecf20Sopenharmony_ci			dev_err(nfc->dev,
15698c2ecf20Sopenharmony_ci				"failed to request ecc DMA channel: %d\n", ret);
15708c2ecf20Sopenharmony_ci		nfc->dma_ecc_ch = NULL;
15718c2ecf20Sopenharmony_ci		goto err_dma;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	ret = sg_alloc_table(&nfc->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL);
15758c2ecf20Sopenharmony_ci	if (ret)
15768c2ecf20Sopenharmony_ci		return ret;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	/* Allocate a buffer to store ECC status registers */
15798c2ecf20Sopenharmony_ci	nfc->ecc_buf = devm_kzalloc(nfc->dev, FMC2_MAX_ECC_BUF_LEN, GFP_KERNEL);
15808c2ecf20Sopenharmony_ci	if (!nfc->ecc_buf)
15818c2ecf20Sopenharmony_ci		return -ENOMEM;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	ret = sg_alloc_table(&nfc->dma_data_sg, FMC2_MAX_SG, GFP_KERNEL);
15848c2ecf20Sopenharmony_ci	if (ret)
15858c2ecf20Sopenharmony_ci		return ret;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	init_completion(&nfc->dma_data_complete);
15888c2ecf20Sopenharmony_ci	init_completion(&nfc->dma_ecc_complete);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	return 0;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_cierr_dma:
15938c2ecf20Sopenharmony_ci	if (ret == -ENODEV) {
15948c2ecf20Sopenharmony_ci		dev_warn(nfc->dev,
15958c2ecf20Sopenharmony_ci			 "DMAs not defined in the DT, polling mode is used\n");
15968c2ecf20Sopenharmony_ci		ret = 0;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	return ret;
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_cistatic void stm32_fmc2_nfc_nand_callbacks_setup(struct nand_chip *chip)
16038c2ecf20Sopenharmony_ci{
16048c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	/*
16078c2ecf20Sopenharmony_ci	 * Specific callbacks to read/write a page depending on
16088c2ecf20Sopenharmony_ci	 * the mode (polling/sequencer) and the algo used (Hamming, BCH).
16098c2ecf20Sopenharmony_ci	 */
16108c2ecf20Sopenharmony_ci	if (nfc->dma_tx_ch && nfc->dma_rx_ch && nfc->dma_ecc_ch) {
16118c2ecf20Sopenharmony_ci		/* DMA => use sequencer mode callbacks */
16128c2ecf20Sopenharmony_ci		chip->ecc.correct = stm32_fmc2_nfc_seq_correct;
16138c2ecf20Sopenharmony_ci		chip->ecc.write_page = stm32_fmc2_nfc_seq_write_page;
16148c2ecf20Sopenharmony_ci		chip->ecc.read_page = stm32_fmc2_nfc_seq_read_page;
16158c2ecf20Sopenharmony_ci		chip->ecc.write_page_raw = stm32_fmc2_nfc_seq_write_page_raw;
16168c2ecf20Sopenharmony_ci		chip->ecc.read_page_raw = stm32_fmc2_nfc_seq_read_page_raw;
16178c2ecf20Sopenharmony_ci	} else {
16188c2ecf20Sopenharmony_ci		/* No DMA => use polling mode callbacks */
16198c2ecf20Sopenharmony_ci		chip->ecc.hwctl = stm32_fmc2_nfc_hwctl;
16208c2ecf20Sopenharmony_ci		if (chip->ecc.strength == FMC2_ECC_HAM) {
16218c2ecf20Sopenharmony_ci			/* Hamming is used */
16228c2ecf20Sopenharmony_ci			chip->ecc.calculate = stm32_fmc2_nfc_ham_calculate;
16238c2ecf20Sopenharmony_ci			chip->ecc.correct = stm32_fmc2_nfc_ham_correct;
16248c2ecf20Sopenharmony_ci			chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK;
16258c2ecf20Sopenharmony_ci		} else {
16268c2ecf20Sopenharmony_ci			/* BCH is used */
16278c2ecf20Sopenharmony_ci			chip->ecc.calculate = stm32_fmc2_nfc_bch_calculate;
16288c2ecf20Sopenharmony_ci			chip->ecc.correct = stm32_fmc2_nfc_bch_correct;
16298c2ecf20Sopenharmony_ci			chip->ecc.read_page = stm32_fmc2_nfc_read_page;
16308c2ecf20Sopenharmony_ci		}
16318c2ecf20Sopenharmony_ci	}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	/* Specific configurations depending on the algo used */
16348c2ecf20Sopenharmony_ci	if (chip->ecc.strength == FMC2_ECC_HAM)
16358c2ecf20Sopenharmony_ci		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 4 : 3;
16368c2ecf20Sopenharmony_ci	else if (chip->ecc.strength == FMC2_ECC_BCH8)
16378c2ecf20Sopenharmony_ci		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 14 : 13;
16388c2ecf20Sopenharmony_ci	else
16398c2ecf20Sopenharmony_ci		chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
16438c2ecf20Sopenharmony_ci					struct mtd_oob_region *oobregion)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct nand_chip *chip = mtd_to_nand(mtd);
16468c2ecf20Sopenharmony_ci	struct nand_ecc_ctrl *ecc = &chip->ecc;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	if (section)
16498c2ecf20Sopenharmony_ci		return -ERANGE;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	oobregion->length = ecc->total;
16528c2ecf20Sopenharmony_ci	oobregion->offset = FMC2_BBM_LEN;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	return 0;
16558c2ecf20Sopenharmony_ci}
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_ooblayout_free(struct mtd_info *mtd, int section,
16588c2ecf20Sopenharmony_ci					 struct mtd_oob_region *oobregion)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	struct nand_chip *chip = mtd_to_nand(mtd);
16618c2ecf20Sopenharmony_ci	struct nand_ecc_ctrl *ecc = &chip->ecc;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	if (section)
16648c2ecf20Sopenharmony_ci		return -ERANGE;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	oobregion->length = mtd->oobsize - ecc->total - FMC2_BBM_LEN;
16678c2ecf20Sopenharmony_ci	oobregion->offset = ecc->total + FMC2_BBM_LEN;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	return 0;
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cistatic const struct mtd_ooblayout_ops stm32_fmc2_nfc_ooblayout_ops = {
16738c2ecf20Sopenharmony_ci	.ecc = stm32_fmc2_nfc_ooblayout_ecc,
16748c2ecf20Sopenharmony_ci	.free = stm32_fmc2_nfc_ooblayout_free,
16758c2ecf20Sopenharmony_ci};
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_calc_ecc_bytes(int step_size, int strength)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	/* Hamming */
16808c2ecf20Sopenharmony_ci	if (strength == FMC2_ECC_HAM)
16818c2ecf20Sopenharmony_ci		return 4;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	/* BCH8 */
16848c2ecf20Sopenharmony_ci	if (strength == FMC2_ECC_BCH8)
16858c2ecf20Sopenharmony_ci		return 14;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* BCH4 */
16888c2ecf20Sopenharmony_ci	return 8;
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ciNAND_ECC_CAPS_SINGLE(stm32_fmc2_nfc_ecc_caps, stm32_fmc2_nfc_calc_ecc_bytes,
16928c2ecf20Sopenharmony_ci		     FMC2_ECC_STEP_SIZE,
16938c2ecf20Sopenharmony_ci		     FMC2_ECC_HAM, FMC2_ECC_BCH4, FMC2_ECC_BCH8);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip)
16968c2ecf20Sopenharmony_ci{
16978c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
16988c2ecf20Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
16998c2ecf20Sopenharmony_ci	int ret;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	/*
17028c2ecf20Sopenharmony_ci	 * Only NAND_ECC_ENGINE_TYPE_ON_HOST mode is actually supported
17038c2ecf20Sopenharmony_ci	 * Hamming => ecc.strength = 1
17048c2ecf20Sopenharmony_ci	 * BCH4 => ecc.strength = 4
17058c2ecf20Sopenharmony_ci	 * BCH8 => ecc.strength = 8
17068c2ecf20Sopenharmony_ci	 * ECC sector size = 512
17078c2ecf20Sopenharmony_ci	 */
17088c2ecf20Sopenharmony_ci	if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
17098c2ecf20Sopenharmony_ci		dev_err(nfc->dev,
17108c2ecf20Sopenharmony_ci			"nand_ecc_engine_type is not well defined in the DT\n");
17118c2ecf20Sopenharmony_ci		return -EINVAL;
17128c2ecf20Sopenharmony_ci	}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	/* Default ECC settings in case they are not set in the device tree */
17158c2ecf20Sopenharmony_ci	if (!chip->ecc.size)
17168c2ecf20Sopenharmony_ci		chip->ecc.size = FMC2_ECC_STEP_SIZE;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if (!chip->ecc.strength)
17198c2ecf20Sopenharmony_ci		chip->ecc.strength = FMC2_ECC_BCH8;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	ret = nand_ecc_choose_conf(chip, &stm32_fmc2_nfc_ecc_caps,
17228c2ecf20Sopenharmony_ci				   mtd->oobsize - FMC2_BBM_LEN);
17238c2ecf20Sopenharmony_ci	if (ret) {
17248c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "no valid ECC settings set\n");
17258c2ecf20Sopenharmony_ci		return ret;
17268c2ecf20Sopenharmony_ci	}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	if (mtd->writesize / chip->ecc.size > FMC2_MAX_SG) {
17298c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "nand page size is not supported\n");
17308c2ecf20Sopenharmony_ci		return -EINVAL;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	if (chip->bbt_options & NAND_BBT_USE_FLASH)
17348c2ecf20Sopenharmony_ci		chip->bbt_options |= NAND_BBT_NO_OOB;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_nand_callbacks_setup(chip);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	mtd_set_ooblayout(mtd, &stm32_fmc2_nfc_ooblayout_ops);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_setup(chip);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	return 0;
17438c2ecf20Sopenharmony_ci}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_cistatic const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = {
17468c2ecf20Sopenharmony_ci	.attach_chip = stm32_fmc2_nfc_attach_chip,
17478c2ecf20Sopenharmony_ci	.exec_op = stm32_fmc2_nfc_exec_op,
17488c2ecf20Sopenharmony_ci	.setup_interface = stm32_fmc2_nfc_setup_interface,
17498c2ecf20Sopenharmony_ci};
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,
17528c2ecf20Sopenharmony_ci				      struct device_node *dn)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = &nfc->nand;
17558c2ecf20Sopenharmony_ci	u32 cs;
17568c2ecf20Sopenharmony_ci	int ret, i;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	if (!of_get_property(dn, "reg", &nand->ncs))
17598c2ecf20Sopenharmony_ci		return -EINVAL;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	nand->ncs /= sizeof(u32);
17628c2ecf20Sopenharmony_ci	if (!nand->ncs) {
17638c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "invalid reg property size\n");
17648c2ecf20Sopenharmony_ci		return -EINVAL;
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	for (i = 0; i < nand->ncs; i++) {
17688c2ecf20Sopenharmony_ci		ret = of_property_read_u32_index(dn, "reg", i, &cs);
17698c2ecf20Sopenharmony_ci		if (ret) {
17708c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "could not retrieve reg property: %d\n",
17718c2ecf20Sopenharmony_ci				ret);
17728c2ecf20Sopenharmony_ci			return ret;
17738c2ecf20Sopenharmony_ci		}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci		if (cs >= FMC2_MAX_CE) {
17768c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "invalid reg value: %d\n", cs);
17778c2ecf20Sopenharmony_ci			return -EINVAL;
17788c2ecf20Sopenharmony_ci		}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci		if (nfc->cs_assigned & BIT(cs)) {
17818c2ecf20Sopenharmony_ci			dev_err(nfc->dev, "cs already assigned: %d\n", cs);
17828c2ecf20Sopenharmony_ci			return -EINVAL;
17838c2ecf20Sopenharmony_ci		}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci		nfc->cs_assigned |= BIT(cs);
17868c2ecf20Sopenharmony_ci		nand->cs_used[i] = cs;
17878c2ecf20Sopenharmony_ci	}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	nand_set_flash_node(&nand->chip, dn);
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	return 0;
17928c2ecf20Sopenharmony_ci}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc)
17958c2ecf20Sopenharmony_ci{
17968c2ecf20Sopenharmony_ci	struct device_node *dn = nfc->dev->of_node;
17978c2ecf20Sopenharmony_ci	struct device_node *child;
17988c2ecf20Sopenharmony_ci	int nchips = of_get_child_count(dn);
17998c2ecf20Sopenharmony_ci	int ret = 0;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	if (!nchips) {
18028c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "NAND chip not defined\n");
18038c2ecf20Sopenharmony_ci		return -EINVAL;
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	if (nchips > 1) {
18078c2ecf20Sopenharmony_ci		dev_err(nfc->dev, "too many NAND chips defined\n");
18088c2ecf20Sopenharmony_ci		return -EINVAL;
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	for_each_child_of_node(dn, child) {
18128c2ecf20Sopenharmony_ci		ret = stm32_fmc2_nfc_parse_child(nfc, child);
18138c2ecf20Sopenharmony_ci		if (ret < 0) {
18148c2ecf20Sopenharmony_ci			of_node_put(child);
18158c2ecf20Sopenharmony_ci			return ret;
18168c2ecf20Sopenharmony_ci		}
18178c2ecf20Sopenharmony_ci	}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	return ret;
18208c2ecf20Sopenharmony_ci}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc)
18238c2ecf20Sopenharmony_ci{
18248c2ecf20Sopenharmony_ci	struct device *dev = nfc->dev;
18258c2ecf20Sopenharmony_ci	bool ebi_found = false;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	if (dev->parent && of_device_is_compatible(dev->parent->of_node,
18288c2ecf20Sopenharmony_ci						   "st,stm32mp1-fmc2-ebi"))
18298c2ecf20Sopenharmony_ci		ebi_found = true;
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) {
18328c2ecf20Sopenharmony_ci		if (ebi_found) {
18338c2ecf20Sopenharmony_ci			nfc->cdev = dev->parent;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci			return 0;
18368c2ecf20Sopenharmony_ci		}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci		return -EINVAL;
18398c2ecf20Sopenharmony_ci	}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	if (ebi_found)
18428c2ecf20Sopenharmony_ci		return -EINVAL;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	nfc->cdev = dev;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	return 0;
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_probe(struct platform_device *pdev)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
18528c2ecf20Sopenharmony_ci	struct reset_control *rstc;
18538c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc;
18548c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand;
18558c2ecf20Sopenharmony_ci	struct resource *res;
18568c2ecf20Sopenharmony_ci	struct mtd_info *mtd;
18578c2ecf20Sopenharmony_ci	struct nand_chip *chip;
18588c2ecf20Sopenharmony_ci	struct resource cres;
18598c2ecf20Sopenharmony_ci	int chip_cs, mem_region, ret, irq;
18608c2ecf20Sopenharmony_ci	int start_region = 0;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
18638c2ecf20Sopenharmony_ci	if (!nfc)
18648c2ecf20Sopenharmony_ci		return -ENOMEM;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	nfc->dev = dev;
18678c2ecf20Sopenharmony_ci	nand_controller_init(&nfc->base);
18688c2ecf20Sopenharmony_ci	nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_set_cdev(nfc);
18718c2ecf20Sopenharmony_ci	if (ret)
18728c2ecf20Sopenharmony_ci		return ret;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_parse_dt(nfc);
18758c2ecf20Sopenharmony_ci	if (ret)
18768c2ecf20Sopenharmony_ci		return ret;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres);
18798c2ecf20Sopenharmony_ci	if (ret)
18808c2ecf20Sopenharmony_ci		return ret;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	nfc->io_phys_addr = cres.start;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	nfc->regmap = device_node_to_regmap(nfc->cdev->of_node);
18858c2ecf20Sopenharmony_ci	if (IS_ERR(nfc->regmap))
18868c2ecf20Sopenharmony_ci		return PTR_ERR(nfc->regmap);
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	if (nfc->dev == nfc->cdev)
18898c2ecf20Sopenharmony_ci		start_region = 1;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
18928c2ecf20Sopenharmony_ci	     chip_cs++, mem_region += 3) {
18938c2ecf20Sopenharmony_ci		if (!(nfc->cs_assigned & BIT(chip_cs)))
18948c2ecf20Sopenharmony_ci			continue;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_MEM, mem_region);
18978c2ecf20Sopenharmony_ci		nfc->data_base[chip_cs] = devm_ioremap_resource(dev, res);
18988c2ecf20Sopenharmony_ci		if (IS_ERR(nfc->data_base[chip_cs]))
18998c2ecf20Sopenharmony_ci			return PTR_ERR(nfc->data_base[chip_cs]);
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci		nfc->data_phys_addr[chip_cs] = res->start;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_MEM,
19048c2ecf20Sopenharmony_ci					    mem_region + 1);
19058c2ecf20Sopenharmony_ci		nfc->cmd_base[chip_cs] = devm_ioremap_resource(dev, res);
19068c2ecf20Sopenharmony_ci		if (IS_ERR(nfc->cmd_base[chip_cs]))
19078c2ecf20Sopenharmony_ci			return PTR_ERR(nfc->cmd_base[chip_cs]);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_MEM,
19108c2ecf20Sopenharmony_ci					    mem_region + 2);
19118c2ecf20Sopenharmony_ci		nfc->addr_base[chip_cs] = devm_ioremap_resource(dev, res);
19128c2ecf20Sopenharmony_ci		if (IS_ERR(nfc->addr_base[chip_cs]))
19138c2ecf20Sopenharmony_ci			return PTR_ERR(nfc->addr_base[chip_cs]);
19148c2ecf20Sopenharmony_ci	}
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
19178c2ecf20Sopenharmony_ci	if (irq < 0)
19188c2ecf20Sopenharmony_ci		return irq;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, irq, stm32_fmc2_nfc_irq, 0,
19218c2ecf20Sopenharmony_ci			       dev_name(dev), nfc);
19228c2ecf20Sopenharmony_ci	if (ret) {
19238c2ecf20Sopenharmony_ci		dev_err(dev, "failed to request irq\n");
19248c2ecf20Sopenharmony_ci		return ret;
19258c2ecf20Sopenharmony_ci	}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	init_completion(&nfc->complete);
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	nfc->clk = devm_clk_get(nfc->cdev, NULL);
19308c2ecf20Sopenharmony_ci	if (IS_ERR(nfc->clk))
19318c2ecf20Sopenharmony_ci		return PTR_ERR(nfc->clk);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(nfc->clk);
19348c2ecf20Sopenharmony_ci	if (ret) {
19358c2ecf20Sopenharmony_ci		dev_err(dev, "can not enable the clock\n");
19368c2ecf20Sopenharmony_ci		return ret;
19378c2ecf20Sopenharmony_ci	}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	rstc = devm_reset_control_get(dev, NULL);
19408c2ecf20Sopenharmony_ci	if (IS_ERR(rstc)) {
19418c2ecf20Sopenharmony_ci		ret = PTR_ERR(rstc);
19428c2ecf20Sopenharmony_ci		if (ret == -EPROBE_DEFER)
19438c2ecf20Sopenharmony_ci			goto err_clk_disable;
19448c2ecf20Sopenharmony_ci	} else {
19458c2ecf20Sopenharmony_ci		reset_control_assert(rstc);
19468c2ecf20Sopenharmony_ci		reset_control_deassert(rstc);
19478c2ecf20Sopenharmony_ci	}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	ret = stm32_fmc2_nfc_dma_setup(nfc);
19508c2ecf20Sopenharmony_ci	if (ret)
19518c2ecf20Sopenharmony_ci		goto err_release_dma;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_init(nfc);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	nand = &nfc->nand;
19568c2ecf20Sopenharmony_ci	chip = &nand->chip;
19578c2ecf20Sopenharmony_ci	mtd = nand_to_mtd(chip);
19588c2ecf20Sopenharmony_ci	mtd->dev.parent = dev;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	chip->controller = &nfc->base;
19618c2ecf20Sopenharmony_ci	chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE |
19628c2ecf20Sopenharmony_ci			 NAND_USES_DMA;
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	/* Scan to find existence of the device */
19658c2ecf20Sopenharmony_ci	ret = nand_scan(chip, nand->ncs);
19668c2ecf20Sopenharmony_ci	if (ret)
19678c2ecf20Sopenharmony_ci		goto err_release_dma;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	ret = mtd_device_register(mtd, NULL, 0);
19708c2ecf20Sopenharmony_ci	if (ret)
19718c2ecf20Sopenharmony_ci		goto err_nand_cleanup;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, nfc);
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	return 0;
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_cierr_nand_cleanup:
19788c2ecf20Sopenharmony_ci	nand_cleanup(chip);
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cierr_release_dma:
19818c2ecf20Sopenharmony_ci	if (nfc->dma_ecc_ch)
19828c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_ecc_ch);
19838c2ecf20Sopenharmony_ci	if (nfc->dma_tx_ch)
19848c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_tx_ch);
19858c2ecf20Sopenharmony_ci	if (nfc->dma_rx_ch)
19868c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_rx_ch);
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	sg_free_table(&nfc->dma_data_sg);
19898c2ecf20Sopenharmony_ci	sg_free_table(&nfc->dma_ecc_sg);
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_cierr_clk_disable:
19928c2ecf20Sopenharmony_ci	clk_disable_unprepare(nfc->clk);
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	return ret;
19958c2ecf20Sopenharmony_ci}
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_cistatic int stm32_fmc2_nfc_remove(struct platform_device *pdev)
19988c2ecf20Sopenharmony_ci{
19998c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev);
20008c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = &nfc->nand;
20018c2ecf20Sopenharmony_ci	struct nand_chip *chip = &nand->chip;
20028c2ecf20Sopenharmony_ci	int ret;
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	ret = mtd_device_unregister(nand_to_mtd(chip));
20058c2ecf20Sopenharmony_ci	WARN_ON(ret);
20068c2ecf20Sopenharmony_ci	nand_cleanup(chip);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (nfc->dma_ecc_ch)
20098c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_ecc_ch);
20108c2ecf20Sopenharmony_ci	if (nfc->dma_tx_ch)
20118c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_tx_ch);
20128c2ecf20Sopenharmony_ci	if (nfc->dma_rx_ch)
20138c2ecf20Sopenharmony_ci		dma_release_channel(nfc->dma_rx_ch);
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	sg_free_table(&nfc->dma_data_sg);
20168c2ecf20Sopenharmony_ci	sg_free_table(&nfc->dma_ecc_sg);
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	clk_disable_unprepare(nfc->clk);
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	return 0;
20218c2ecf20Sopenharmony_ci}
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_cistatic int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev)
20248c2ecf20Sopenharmony_ci{
20258c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev);
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	clk_disable_unprepare(nfc->clk);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	pinctrl_pm_select_sleep_state(dev);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	return 0;
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_cistatic int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev)
20358c2ecf20Sopenharmony_ci{
20368c2ecf20Sopenharmony_ci	struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev);
20378c2ecf20Sopenharmony_ci	struct stm32_fmc2_nand *nand = &nfc->nand;
20388c2ecf20Sopenharmony_ci	int chip_cs, ret;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	pinctrl_pm_select_default_state(dev);
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(nfc->clk);
20438c2ecf20Sopenharmony_ci	if (ret) {
20448c2ecf20Sopenharmony_ci		dev_err(dev, "can not enable the clock\n");
20458c2ecf20Sopenharmony_ci		return ret;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	stm32_fmc2_nfc_init(nfc);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) {
20518c2ecf20Sopenharmony_ci		if (!(nfc->cs_assigned & BIT(chip_cs)))
20528c2ecf20Sopenharmony_ci			continue;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		nand_reset(&nand->chip, chip_cs);
20558c2ecf20Sopenharmony_ci	}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	return 0;
20588c2ecf20Sopenharmony_ci}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
20618c2ecf20Sopenharmony_ci			 stm32_fmc2_nfc_resume);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_cistatic const struct of_device_id stm32_fmc2_nfc_match[] = {
20648c2ecf20Sopenharmony_ci	{.compatible = "st,stm32mp15-fmc2"},
20658c2ecf20Sopenharmony_ci	{.compatible = "st,stm32mp1-fmc2-nfc"},
20668c2ecf20Sopenharmony_ci	{}
20678c2ecf20Sopenharmony_ci};
20688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cistatic struct platform_driver stm32_fmc2_nfc_driver = {
20718c2ecf20Sopenharmony_ci	.probe	= stm32_fmc2_nfc_probe,
20728c2ecf20Sopenharmony_ci	.remove	= stm32_fmc2_nfc_remove,
20738c2ecf20Sopenharmony_ci	.driver	= {
20748c2ecf20Sopenharmony_ci		.name = "stm32_fmc2_nfc",
20758c2ecf20Sopenharmony_ci		.of_match_table = stm32_fmc2_nfc_match,
20768c2ecf20Sopenharmony_ci		.pm = &stm32_fmc2_nfc_pm_ops,
20778c2ecf20Sopenharmony_ci	},
20788c2ecf20Sopenharmony_ci};
20798c2ecf20Sopenharmony_cimodule_platform_driver(stm32_fmc2_nfc_driver);
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:stm32_fmc2_nfc");
20828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
20838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 NFC driver");
20848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
2085