xref: /arm-trusted-firmware/drivers/st/fmc/stm32_fmc2_nand.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <limits.h>
10*91f16700Schasinglulu #include <stdint.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <common/debug.h>
13*91f16700Schasinglulu #include <drivers/clk.h>
14*91f16700Schasinglulu #include <drivers/delay_timer.h>
15*91f16700Schasinglulu #include <drivers/raw_nand.h>
16*91f16700Schasinglulu #include <drivers/st/stm32_fmc2_nand.h>
17*91f16700Schasinglulu #include <drivers/st/stm32_gpio.h>
18*91f16700Schasinglulu #include <drivers/st/stm32mp_reset.h>
19*91f16700Schasinglulu #include <lib/mmio.h>
20*91f16700Schasinglulu #include <lib/utils_def.h>
21*91f16700Schasinglulu #include <libfdt.h>
22*91f16700Schasinglulu 
23*91f16700Schasinglulu #include <platform_def.h>
24*91f16700Schasinglulu 
25*91f16700Schasinglulu /* Timeout for device interface reset */
26*91f16700Schasinglulu #define TIMEOUT_US_1_MS			1000U
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /* FMC2 Compatibility */
29*91f16700Schasinglulu #define DT_FMC2_EBI_COMPAT		"st,stm32mp1-fmc2-ebi"
30*91f16700Schasinglulu #define DT_FMC2_NFC_COMPAT		"st,stm32mp1-fmc2-nfc"
31*91f16700Schasinglulu #define MAX_CS				2U
32*91f16700Schasinglulu #define MAX_BANK			5U
33*91f16700Schasinglulu 
34*91f16700Schasinglulu /* FMC2 Controller Registers */
35*91f16700Schasinglulu #define FMC2_BCR1			0x00U
36*91f16700Schasinglulu #define FMC2_PCR			0x80U
37*91f16700Schasinglulu #define FMC2_SR				0x84U
38*91f16700Schasinglulu #define FMC2_PMEM			0x88U
39*91f16700Schasinglulu #define FMC2_PATT			0x8CU
40*91f16700Schasinglulu #define FMC2_HECCR			0x94U
41*91f16700Schasinglulu #define FMC2_BCHISR			0x254U
42*91f16700Schasinglulu #define FMC2_BCHICR			0x258U
43*91f16700Schasinglulu #define FMC2_BCHDSR0			0x27CU
44*91f16700Schasinglulu #define FMC2_BCHDSR1			0x280U
45*91f16700Schasinglulu #define FMC2_BCHDSR2			0x284U
46*91f16700Schasinglulu #define FMC2_BCHDSR3			0x288U
47*91f16700Schasinglulu #define FMC2_BCHDSR4			0x28CU
48*91f16700Schasinglulu 
49*91f16700Schasinglulu /* FMC2_BCR1 register */
50*91f16700Schasinglulu #define FMC2_BCR1_FMC2EN		BIT(31)
51*91f16700Schasinglulu /* FMC2_PCR register */
52*91f16700Schasinglulu #define FMC2_PCR_PWAITEN		BIT(1)
53*91f16700Schasinglulu #define FMC2_PCR_PBKEN			BIT(2)
54*91f16700Schasinglulu #define FMC2_PCR_PWID_MASK		GENMASK_32(5, 4)
55*91f16700Schasinglulu #define FMC2_PCR_PWID(x)		(((x) << 4) & FMC2_PCR_PWID_MASK)
56*91f16700Schasinglulu #define FMC2_PCR_PWID_8			0x0U
57*91f16700Schasinglulu #define FMC2_PCR_PWID_16		0x1U
58*91f16700Schasinglulu #define FMC2_PCR_ECCEN			BIT(6)
59*91f16700Schasinglulu #define FMC2_PCR_ECCALG			BIT(8)
60*91f16700Schasinglulu #define FMC2_PCR_TCLR_MASK		GENMASK_32(12, 9)
61*91f16700Schasinglulu #define FMC2_PCR_TCLR(x)		(((x) << 9) & FMC2_PCR_TCLR_MASK)
62*91f16700Schasinglulu #define FMC2_PCR_TCLR_DEFAULT		0xFU
63*91f16700Schasinglulu #define FMC2_PCR_TAR_MASK		GENMASK_32(16, 13)
64*91f16700Schasinglulu #define FMC2_PCR_TAR(x)			(((x) << 13) & FMC2_PCR_TAR_MASK)
65*91f16700Schasinglulu #define FMC2_PCR_TAR_DEFAULT		0xFU
66*91f16700Schasinglulu #define FMC2_PCR_ECCSS_MASK		GENMASK_32(19, 17)
67*91f16700Schasinglulu #define FMC2_PCR_ECCSS(x)		(((x) << 17) & FMC2_PCR_ECCSS_MASK)
68*91f16700Schasinglulu #define FMC2_PCR_ECCSS_512		0x1U
69*91f16700Schasinglulu #define FMC2_PCR_ECCSS_2048		0x3U
70*91f16700Schasinglulu #define FMC2_PCR_BCHECC			BIT(24)
71*91f16700Schasinglulu #define FMC2_PCR_WEN			BIT(25)
72*91f16700Schasinglulu /* FMC2_SR register */
73*91f16700Schasinglulu #define FMC2_SR_NWRF			BIT(6)
74*91f16700Schasinglulu /* FMC2_PMEM register*/
75*91f16700Schasinglulu #define FMC2_PMEM_MEMSET(x)		(((x) & GENMASK_32(7, 0)) << 0)
76*91f16700Schasinglulu #define FMC2_PMEM_MEMWAIT(x)		(((x) & GENMASK_32(7, 0)) << 8)
77*91f16700Schasinglulu #define FMC2_PMEM_MEMHOLD(x)		(((x) & GENMASK_32(7, 0)) << 16)
78*91f16700Schasinglulu #define FMC2_PMEM_MEMHIZ(x)		(((x) & GENMASK_32(7, 0)) << 24)
79*91f16700Schasinglulu #define FMC2_PMEM_DEFAULT		0x0A0A0A0AU
80*91f16700Schasinglulu /* FMC2_PATT register */
81*91f16700Schasinglulu #define FMC2_PATT_ATTSET(x)		(((x) & GENMASK_32(7, 0)) << 0)
82*91f16700Schasinglulu #define FMC2_PATT_ATTWAIT(x)		(((x) & GENMASK_32(7, 0)) << 8)
83*91f16700Schasinglulu #define FMC2_PATT_ATTHOLD(x)		(((x) & GENMASK_32(7, 0)) << 16)
84*91f16700Schasinglulu #define FMC2_PATT_ATTHIZ(x)		(((x) & GENMASK_32(7, 0)) << 24)
85*91f16700Schasinglulu #define FMC2_PATT_DEFAULT		0x0A0A0A0AU
86*91f16700Schasinglulu /* FMC2_BCHISR register */
87*91f16700Schasinglulu #define FMC2_BCHISR_DERF		BIT(1)
88*91f16700Schasinglulu /* FMC2_BCHICR register */
89*91f16700Schasinglulu #define FMC2_BCHICR_CLEAR_IRQ		GENMASK_32(4, 0)
90*91f16700Schasinglulu /* FMC2_BCHDSR0 register */
91*91f16700Schasinglulu #define FMC2_BCHDSR0_DUE		BIT(0)
92*91f16700Schasinglulu #define FMC2_BCHDSR0_DEF		BIT(1)
93*91f16700Schasinglulu #define FMC2_BCHDSR0_DEN_MASK		GENMASK_32(7, 4)
94*91f16700Schasinglulu #define FMC2_BCHDSR0_DEN_SHIFT		4U
95*91f16700Schasinglulu /* FMC2_BCHDSR1 register */
96*91f16700Schasinglulu #define FMC2_BCHDSR1_EBP1_MASK		GENMASK_32(12, 0)
97*91f16700Schasinglulu #define FMC2_BCHDSR1_EBP2_MASK		GENMASK_32(28, 16)
98*91f16700Schasinglulu #define FMC2_BCHDSR1_EBP2_SHIFT		16U
99*91f16700Schasinglulu /* FMC2_BCHDSR2 register */
100*91f16700Schasinglulu #define FMC2_BCHDSR2_EBP3_MASK		GENMASK_32(12, 0)
101*91f16700Schasinglulu #define FMC2_BCHDSR2_EBP4_MASK		GENMASK_32(28, 16)
102*91f16700Schasinglulu #define FMC2_BCHDSR2_EBP4_SHIFT		16U
103*91f16700Schasinglulu /* FMC2_BCHDSR3 register */
104*91f16700Schasinglulu #define FMC2_BCHDSR3_EBP5_MASK		GENMASK_32(12, 0)
105*91f16700Schasinglulu #define FMC2_BCHDSR3_EBP6_MASK		GENMASK_32(28, 16)
106*91f16700Schasinglulu #define FMC2_BCHDSR3_EBP6_SHIFT		16U
107*91f16700Schasinglulu /* FMC2_BCHDSR4 register */
108*91f16700Schasinglulu #define FMC2_BCHDSR4_EBP7_MASK		GENMASK_32(12, 0)
109*91f16700Schasinglulu #define FMC2_BCHDSR4_EBP8_MASK		GENMASK_32(28, 16)
110*91f16700Schasinglulu #define FMC2_BCHDSR4_EBP8_SHIFT		16U
111*91f16700Schasinglulu 
112*91f16700Schasinglulu /* Timings */
113*91f16700Schasinglulu #define FMC2_THIZ			0x01U
114*91f16700Schasinglulu #define FMC2_TIO			8000U
115*91f16700Schasinglulu #define FMC2_TSYNC			3000U
116*91f16700Schasinglulu #define FMC2_PCR_TIMING_MASK		GENMASK_32(3, 0)
117*91f16700Schasinglulu #define FMC2_PMEM_PATT_TIMING_MASK	GENMASK_32(7, 0)
118*91f16700Schasinglulu 
119*91f16700Schasinglulu #define FMC2_BBM_LEN			2U
120*91f16700Schasinglulu #define FMC2_MAX_ECC_BYTES		14U
121*91f16700Schasinglulu #define TIMEOUT_US_10_MS		10000U
122*91f16700Schasinglulu #define FMC2_PSEC_PER_MSEC		(1000UL * 1000UL * 1000UL)
123*91f16700Schasinglulu 
124*91f16700Schasinglulu enum stm32_fmc2_ecc {
125*91f16700Schasinglulu 	FMC2_ECC_HAM = 1U,
126*91f16700Schasinglulu 	FMC2_ECC_BCH4 = 4U,
127*91f16700Schasinglulu 	FMC2_ECC_BCH8 = 8U
128*91f16700Schasinglulu };
129*91f16700Schasinglulu 
130*91f16700Schasinglulu struct stm32_fmc2_cs_reg {
131*91f16700Schasinglulu 	uintptr_t data_base;
132*91f16700Schasinglulu 	uintptr_t cmd_base;
133*91f16700Schasinglulu 	uintptr_t addr_base;
134*91f16700Schasinglulu };
135*91f16700Schasinglulu 
136*91f16700Schasinglulu struct stm32_fmc2_nand_timings {
137*91f16700Schasinglulu 	uint8_t tclr;
138*91f16700Schasinglulu 	uint8_t tar;
139*91f16700Schasinglulu 	uint8_t thiz;
140*91f16700Schasinglulu 	uint8_t twait;
141*91f16700Schasinglulu 	uint8_t thold_mem;
142*91f16700Schasinglulu 	uint8_t tset_mem;
143*91f16700Schasinglulu 	uint8_t thold_att;
144*91f16700Schasinglulu 	uint8_t tset_att;
145*91f16700Schasinglulu };
146*91f16700Schasinglulu 
147*91f16700Schasinglulu struct stm32_fmc2_nfc {
148*91f16700Schasinglulu 	uintptr_t reg_base;
149*91f16700Schasinglulu 	struct stm32_fmc2_cs_reg cs[MAX_CS];
150*91f16700Schasinglulu 	unsigned long clock_id;
151*91f16700Schasinglulu 	unsigned int reset_id;
152*91f16700Schasinglulu 	uint8_t cs_sel;
153*91f16700Schasinglulu };
154*91f16700Schasinglulu 
155*91f16700Schasinglulu static struct stm32_fmc2_nfc stm32_fmc2;
156*91f16700Schasinglulu 
157*91f16700Schasinglulu static uintptr_t fmc2_base(void)
158*91f16700Schasinglulu {
159*91f16700Schasinglulu 	return stm32_fmc2.reg_base;
160*91f16700Schasinglulu }
161*91f16700Schasinglulu 
162*91f16700Schasinglulu static void stm32_fmc2_nand_setup_timing(void)
163*91f16700Schasinglulu {
164*91f16700Schasinglulu 	struct stm32_fmc2_nand_timings tims;
165*91f16700Schasinglulu 	unsigned long hclk = clk_get_rate(stm32_fmc2.clock_id);
166*91f16700Schasinglulu 	unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
167*91f16700Schasinglulu 	unsigned long timing, tar, tclr, thiz, twait;
168*91f16700Schasinglulu 	unsigned long tset_mem, tset_att, thold_mem, thold_att;
169*91f16700Schasinglulu 	uint32_t pcr, pmem, patt;
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	tar = MAX(hclkp, NAND_TAR_MIN);
172*91f16700Schasinglulu 	timing = div_round_up(tar, hclkp) - 1U;
173*91f16700Schasinglulu 	tims.tar = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	tclr = MAX(hclkp, NAND_TCLR_MIN);
176*91f16700Schasinglulu 	timing = div_round_up(tclr, hclkp) - 1U;
177*91f16700Schasinglulu 	tims.tclr = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
178*91f16700Schasinglulu 
179*91f16700Schasinglulu 	tims.thiz = FMC2_THIZ;
180*91f16700Schasinglulu 	thiz = (tims.thiz + 1U) * hclkp;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	/*
183*91f16700Schasinglulu 	 * tWAIT > tRP
184*91f16700Schasinglulu 	 * tWAIT > tWP
185*91f16700Schasinglulu 	 * tWAIT > tREA + tIO
186*91f16700Schasinglulu 	 */
187*91f16700Schasinglulu 	twait = MAX(hclkp, NAND_TRP_MIN);
188*91f16700Schasinglulu 	twait = MAX(twait, NAND_TWP_MIN);
189*91f16700Schasinglulu 	twait = MAX(twait, NAND_TREA_MAX + FMC2_TIO);
190*91f16700Schasinglulu 	timing = div_round_up(twait, hclkp);
191*91f16700Schasinglulu 	tims.twait = CLAMP(timing, 1UL,
192*91f16700Schasinglulu 			   (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
193*91f16700Schasinglulu 
194*91f16700Schasinglulu 	/*
195*91f16700Schasinglulu 	 * tSETUP_MEM > tCS - tWAIT
196*91f16700Schasinglulu 	 * tSETUP_MEM > tALS - tWAIT
197*91f16700Schasinglulu 	 * tSETUP_MEM > tDS - (tWAIT - tHIZ)
198*91f16700Schasinglulu 	 */
199*91f16700Schasinglulu 	tset_mem = hclkp;
200*91f16700Schasinglulu 	if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
201*91f16700Schasinglulu 		tset_mem = NAND_TCS_MIN - twait;
202*91f16700Schasinglulu 	}
203*91f16700Schasinglulu 	if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
204*91f16700Schasinglulu 	    (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
205*91f16700Schasinglulu 		tset_mem = NAND_TDS_MIN - (twait - thiz);
206*91f16700Schasinglulu 	}
207*91f16700Schasinglulu 	timing = div_round_up(tset_mem, hclkp);
208*91f16700Schasinglulu 	tims.tset_mem = CLAMP(timing, 1UL,
209*91f16700Schasinglulu 			      (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	/*
212*91f16700Schasinglulu 	 * tHOLD_MEM > tCH
213*91f16700Schasinglulu 	 * tHOLD_MEM > tREH - tSETUP_MEM
214*91f16700Schasinglulu 	 * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
215*91f16700Schasinglulu 	 */
216*91f16700Schasinglulu 	thold_mem = MAX(hclkp, NAND_TCH_MIN);
217*91f16700Schasinglulu 	if ((tset_mem < NAND_TREH_MIN) &&
218*91f16700Schasinglulu 	    (thold_mem < (NAND_TREH_MIN - tset_mem))) {
219*91f16700Schasinglulu 		thold_mem = NAND_TREH_MIN - tset_mem;
220*91f16700Schasinglulu 	}
221*91f16700Schasinglulu 	if (((tset_mem + twait) < NAND_TRC_MIN) &&
222*91f16700Schasinglulu 	    (thold_mem < (NAND_TRC_MIN - (tset_mem + twait)))) {
223*91f16700Schasinglulu 		thold_mem = NAND_TRC_MIN  - (tset_mem + twait);
224*91f16700Schasinglulu 	}
225*91f16700Schasinglulu 	if (((tset_mem + twait) < NAND_TWC_MIN) &&
226*91f16700Schasinglulu 	    (thold_mem < (NAND_TWC_MIN - (tset_mem + twait)))) {
227*91f16700Schasinglulu 		thold_mem = NAND_TWC_MIN - (tset_mem + twait);
228*91f16700Schasinglulu 	}
229*91f16700Schasinglulu 	timing = div_round_up(thold_mem, hclkp);
230*91f16700Schasinglulu 	tims.thold_mem = CLAMP(timing, 1UL,
231*91f16700Schasinglulu 			       (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 	/*
234*91f16700Schasinglulu 	 * tSETUP_ATT > tCS - tWAIT
235*91f16700Schasinglulu 	 * tSETUP_ATT > tCLS - tWAIT
236*91f16700Schasinglulu 	 * tSETUP_ATT > tALS - tWAIT
237*91f16700Schasinglulu 	 * tSETUP_ATT > tRHW - tHOLD_MEM
238*91f16700Schasinglulu 	 * tSETUP_ATT > tDS - (tWAIT - tHIZ)
239*91f16700Schasinglulu 	 */
240*91f16700Schasinglulu 	tset_att = hclkp;
241*91f16700Schasinglulu 	if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
242*91f16700Schasinglulu 		tset_att = NAND_TCS_MIN - twait;
243*91f16700Schasinglulu 	}
244*91f16700Schasinglulu 	if ((thold_mem < NAND_TRHW_MIN) &&
245*91f16700Schasinglulu 	    (tset_att < (NAND_TRHW_MIN - thold_mem))) {
246*91f16700Schasinglulu 		tset_att = NAND_TRHW_MIN - thold_mem;
247*91f16700Schasinglulu 	}
248*91f16700Schasinglulu 	if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
249*91f16700Schasinglulu 	    (tset_att < (NAND_TDS_MIN - (twait - thiz)))) {
250*91f16700Schasinglulu 		tset_att = NAND_TDS_MIN - (twait - thiz);
251*91f16700Schasinglulu 	}
252*91f16700Schasinglulu 	timing = div_round_up(tset_att, hclkp);
253*91f16700Schasinglulu 	tims.tset_att = CLAMP(timing, 1UL,
254*91f16700Schasinglulu 			      (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
255*91f16700Schasinglulu 
256*91f16700Schasinglulu 	/*
257*91f16700Schasinglulu 	 * tHOLD_ATT > tALH
258*91f16700Schasinglulu 	 * tHOLD_ATT > tCH
259*91f16700Schasinglulu 	 * tHOLD_ATT > tCLH
260*91f16700Schasinglulu 	 * tHOLD_ATT > tCOH
261*91f16700Schasinglulu 	 * tHOLD_ATT > tDH
262*91f16700Schasinglulu 	 * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
263*91f16700Schasinglulu 	 * tHOLD_ATT > tADL - tSETUP_MEM
264*91f16700Schasinglulu 	 * tHOLD_ATT > tWH - tSETUP_MEM
265*91f16700Schasinglulu 	 * tHOLD_ATT > tWHR - tSETUP_MEM
266*91f16700Schasinglulu 	 * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
267*91f16700Schasinglulu 	 * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
268*91f16700Schasinglulu 	 */
269*91f16700Schasinglulu 	thold_att = MAX(hclkp, NAND_TALH_MIN);
270*91f16700Schasinglulu 	thold_att = MAX(thold_att, NAND_TCH_MIN);
271*91f16700Schasinglulu 	thold_att = MAX(thold_att, NAND_TCLH_MIN);
272*91f16700Schasinglulu 	thold_att = MAX(thold_att, NAND_TCOH_MIN);
273*91f16700Schasinglulu 	thold_att = MAX(thold_att, NAND_TDH_MIN);
274*91f16700Schasinglulu 	if (((NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC) > tset_mem) &&
275*91f16700Schasinglulu 	    (thold_att < (NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem))) {
276*91f16700Schasinglulu 		thold_att = NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem;
277*91f16700Schasinglulu 	}
278*91f16700Schasinglulu 	if ((tset_mem < NAND_TADL_MIN) &&
279*91f16700Schasinglulu 	    (thold_att < (NAND_TADL_MIN - tset_mem))) {
280*91f16700Schasinglulu 		thold_att = NAND_TADL_MIN - tset_mem;
281*91f16700Schasinglulu 	}
282*91f16700Schasinglulu 	if ((tset_mem < NAND_TWH_MIN) &&
283*91f16700Schasinglulu 	    (thold_att < (NAND_TWH_MIN - tset_mem))) {
284*91f16700Schasinglulu 		thold_att = NAND_TWH_MIN - tset_mem;
285*91f16700Schasinglulu 	}
286*91f16700Schasinglulu 	if ((tset_mem < NAND_TWHR_MIN) &&
287*91f16700Schasinglulu 	    (thold_att < (NAND_TWHR_MIN - tset_mem))) {
288*91f16700Schasinglulu 		thold_att = NAND_TWHR_MIN - tset_mem;
289*91f16700Schasinglulu 	}
290*91f16700Schasinglulu 	if (((tset_att + twait) < NAND_TRC_MIN) &&
291*91f16700Schasinglulu 	    (thold_att < (NAND_TRC_MIN - (tset_att + twait)))) {
292*91f16700Schasinglulu 		thold_att = NAND_TRC_MIN - (tset_att + twait);
293*91f16700Schasinglulu 	}
294*91f16700Schasinglulu 	if (((tset_att + twait) < NAND_TWC_MIN) &&
295*91f16700Schasinglulu 	    (thold_att < (NAND_TWC_MIN - (tset_att + twait)))) {
296*91f16700Schasinglulu 		thold_att = NAND_TWC_MIN - (tset_att + twait);
297*91f16700Schasinglulu 	}
298*91f16700Schasinglulu 	timing = div_round_up(thold_att, hclkp);
299*91f16700Schasinglulu 	tims.thold_att = CLAMP(timing, 1UL,
300*91f16700Schasinglulu 			       (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 	VERBOSE("NAND timings: %u - %u - %u - %u - %u - %u - %u - %u\n",
303*91f16700Schasinglulu 		tims.tclr, tims.tar, tims.thiz, tims.twait,
304*91f16700Schasinglulu 		tims.thold_mem, tims.tset_mem,
305*91f16700Schasinglulu 		tims.thold_att, tims.tset_att);
306*91f16700Schasinglulu 
307*91f16700Schasinglulu 	/* Set tclr/tar timings */
308*91f16700Schasinglulu 	pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
309*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_TCLR_MASK;
310*91f16700Schasinglulu 	pcr |= FMC2_PCR_TCLR(tims.tclr);
311*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_TAR_MASK;
312*91f16700Schasinglulu 	pcr |= FMC2_PCR_TAR(tims.tar);
313*91f16700Schasinglulu 
314*91f16700Schasinglulu 	/* Set tset/twait/thold/thiz timings in common bank */
315*91f16700Schasinglulu 	pmem = FMC2_PMEM_MEMSET(tims.tset_mem);
316*91f16700Schasinglulu 	pmem |= FMC2_PMEM_MEMWAIT(tims.twait);
317*91f16700Schasinglulu 	pmem |=	FMC2_PMEM_MEMHOLD(tims.thold_mem);
318*91f16700Schasinglulu 	pmem |= FMC2_PMEM_MEMHIZ(tims.thiz);
319*91f16700Schasinglulu 
320*91f16700Schasinglulu 	/* Set tset/twait/thold/thiz timings in attribute bank */
321*91f16700Schasinglulu 	patt = FMC2_PATT_ATTSET(tims.tset_att);
322*91f16700Schasinglulu 	patt |= FMC2_PATT_ATTWAIT(tims.twait);
323*91f16700Schasinglulu 	patt |= FMC2_PATT_ATTHOLD(tims.thold_att);
324*91f16700Schasinglulu 	patt |= FMC2_PATT_ATTHIZ(tims.thiz);
325*91f16700Schasinglulu 
326*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
327*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PMEM, pmem);
328*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PATT, patt);
329*91f16700Schasinglulu }
330*91f16700Schasinglulu 
331*91f16700Schasinglulu static void stm32_fmc2_set_buswidth_16(bool set)
332*91f16700Schasinglulu {
333*91f16700Schasinglulu 	mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_PWID_MASK,
334*91f16700Schasinglulu 			   (set ? FMC2_PCR_PWID(FMC2_PCR_PWID_16) : 0U));
335*91f16700Schasinglulu }
336*91f16700Schasinglulu 
337*91f16700Schasinglulu static void stm32_fmc2_set_ecc(bool enable)
338*91f16700Schasinglulu {
339*91f16700Schasinglulu 	mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_ECCEN,
340*91f16700Schasinglulu 			   (enable ? FMC2_PCR_ECCEN : 0U));
341*91f16700Schasinglulu }
342*91f16700Schasinglulu 
343*91f16700Schasinglulu static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
344*91f16700Schasinglulu 				  uint8_t *ecc)
345*91f16700Schasinglulu {
346*91f16700Schasinglulu 	uint8_t xor_ecc_ones;
347*91f16700Schasinglulu 	uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b;
348*91f16700Schasinglulu 	union {
349*91f16700Schasinglulu 		uint32_t val;
350*91f16700Schasinglulu 		uint8_t  bytes[4];
351*91f16700Schasinglulu 	} xor_ecc;
352*91f16700Schasinglulu 
353*91f16700Schasinglulu 	/* Page size--------ECC_Code Size
354*91f16700Schasinglulu 	 * 256---------------22 bits LSB  (ECC_CODE & 0x003FFFFF)
355*91f16700Schasinglulu 	 * 512---------------24 bits      (ECC_CODE & 0x00FFFFFF)
356*91f16700Schasinglulu 	 * 1024--------------26 bits      (ECC_CODE & 0x03FFFFFF)
357*91f16700Schasinglulu 	 * 2048--------------28 bits      (ECC_CODE & 0x0FFFFFFF)
358*91f16700Schasinglulu 	 * 4096--------------30 bits      (ECC_CODE & 0x3FFFFFFF)
359*91f16700Schasinglulu 	 * 8192--------------32 bits      (ECC_CODE & 0xFFFFFFFF)
360*91f16700Schasinglulu 	 */
361*91f16700Schasinglulu 
362*91f16700Schasinglulu 	/* For Page size 512, ECC_Code size 24 bits */
363*91f16700Schasinglulu 	xor_ecc_1b = ecc[0] ^ eccbuffer[0];
364*91f16700Schasinglulu 	xor_ecc_2b = ecc[1] ^ eccbuffer[1];
365*91f16700Schasinglulu 	xor_ecc_3b = ecc[2] ^ eccbuffer[2];
366*91f16700Schasinglulu 
367*91f16700Schasinglulu 	xor_ecc.val = 0U;
368*91f16700Schasinglulu 	xor_ecc.bytes[2] = xor_ecc_3b;
369*91f16700Schasinglulu 	xor_ecc.bytes[1] = xor_ecc_2b;
370*91f16700Schasinglulu 	xor_ecc.bytes[0] = xor_ecc_1b;
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	if (xor_ecc.val == 0U) {
373*91f16700Schasinglulu 		return 0; /* No Error */
374*91f16700Schasinglulu 	}
375*91f16700Schasinglulu 
376*91f16700Schasinglulu 	xor_ecc_ones = __builtin_popcount(xor_ecc.val);
377*91f16700Schasinglulu 	if (xor_ecc_ones < 23U) {
378*91f16700Schasinglulu 		if (xor_ecc_ones == 12U) {
379*91f16700Schasinglulu 			uint16_t bit_address, byte_address;
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 			/* Correctable ERROR */
382*91f16700Schasinglulu 			bit_address = ((xor_ecc_1b >> 1) & BIT(0)) |
383*91f16700Schasinglulu 				      ((xor_ecc_1b >> 2) & BIT(1)) |
384*91f16700Schasinglulu 				      ((xor_ecc_1b >> 3) & BIT(2));
385*91f16700Schasinglulu 
386*91f16700Schasinglulu 			byte_address = ((xor_ecc_1b >> 7) & BIT(0)) |
387*91f16700Schasinglulu 				       ((xor_ecc_2b) & BIT(1)) |
388*91f16700Schasinglulu 				       ((xor_ecc_2b >> 1) & BIT(2)) |
389*91f16700Schasinglulu 				       ((xor_ecc_2b >> 2) & BIT(3)) |
390*91f16700Schasinglulu 				       ((xor_ecc_2b >> 3) & BIT(4)) |
391*91f16700Schasinglulu 				       ((xor_ecc_3b << 4) & BIT(5)) |
392*91f16700Schasinglulu 				       ((xor_ecc_3b << 3) & BIT(6)) |
393*91f16700Schasinglulu 				       ((xor_ecc_3b << 2) & BIT(7)) |
394*91f16700Schasinglulu 				       ((xor_ecc_3b << 1) & BIT(8));
395*91f16700Schasinglulu 
396*91f16700Schasinglulu 			/* Correct bit error in the data */
397*91f16700Schasinglulu 			buffer[byte_address] =
398*91f16700Schasinglulu 				buffer[byte_address] ^ BIT(bit_address);
399*91f16700Schasinglulu 			VERBOSE("Hamming: 1 ECC error corrected\n");
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 			return 0;
402*91f16700Schasinglulu 		}
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 		/* Non Correctable ERROR */
405*91f16700Schasinglulu 		ERROR("%s: Uncorrectable ECC Errors\n", __func__);
406*91f16700Schasinglulu 		return -1;
407*91f16700Schasinglulu 	}
408*91f16700Schasinglulu 
409*91f16700Schasinglulu 	/* ECC ERROR */
410*91f16700Schasinglulu 	ERROR("%s: Hamming correction error\n", __func__);
411*91f16700Schasinglulu 	return -1;
412*91f16700Schasinglulu }
413*91f16700Schasinglulu 
414*91f16700Schasinglulu 
415*91f16700Schasinglulu static int stm32_fmc2_ham_calculate(uint8_t *buffer, uint8_t *ecc)
416*91f16700Schasinglulu {
417*91f16700Schasinglulu 	uint32_t heccr;
418*91f16700Schasinglulu 	uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
419*91f16700Schasinglulu 
420*91f16700Schasinglulu 	while ((mmio_read_32(fmc2_base() + FMC2_SR) & FMC2_SR_NWRF) == 0U) {
421*91f16700Schasinglulu 		if (timeout_elapsed(timeout)) {
422*91f16700Schasinglulu 			return -ETIMEDOUT;
423*91f16700Schasinglulu 		}
424*91f16700Schasinglulu 	}
425*91f16700Schasinglulu 
426*91f16700Schasinglulu 	heccr = mmio_read_32(fmc2_base() + FMC2_HECCR);
427*91f16700Schasinglulu 
428*91f16700Schasinglulu 	ecc[0] = heccr;
429*91f16700Schasinglulu 	ecc[1] = heccr >> 8;
430*91f16700Schasinglulu 	ecc[2] = heccr >> 16;
431*91f16700Schasinglulu 
432*91f16700Schasinglulu 	/* Disable ECC */
433*91f16700Schasinglulu 	stm32_fmc2_set_ecc(false);
434*91f16700Schasinglulu 
435*91f16700Schasinglulu 	return 0;
436*91f16700Schasinglulu }
437*91f16700Schasinglulu 
438*91f16700Schasinglulu static int stm32_fmc2_bch_correct(uint8_t *buffer, unsigned int eccsize)
439*91f16700Schasinglulu {
440*91f16700Schasinglulu 	uint32_t bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4;
441*91f16700Schasinglulu 	uint16_t pos[8];
442*91f16700Schasinglulu 	int i, den;
443*91f16700Schasinglulu 	uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 	while ((mmio_read_32(fmc2_base() + FMC2_BCHISR) &
446*91f16700Schasinglulu 		FMC2_BCHISR_DERF) == 0U) {
447*91f16700Schasinglulu 		if (timeout_elapsed(timeout)) {
448*91f16700Schasinglulu 			return -ETIMEDOUT;
449*91f16700Schasinglulu 		}
450*91f16700Schasinglulu 	}
451*91f16700Schasinglulu 
452*91f16700Schasinglulu 	bchdsr0 = mmio_read_32(fmc2_base() + FMC2_BCHDSR0);
453*91f16700Schasinglulu 	bchdsr1 = mmio_read_32(fmc2_base() + FMC2_BCHDSR1);
454*91f16700Schasinglulu 	bchdsr2 = mmio_read_32(fmc2_base() + FMC2_BCHDSR2);
455*91f16700Schasinglulu 	bchdsr3 = mmio_read_32(fmc2_base() + FMC2_BCHDSR3);
456*91f16700Schasinglulu 	bchdsr4 = mmio_read_32(fmc2_base() + FMC2_BCHDSR4);
457*91f16700Schasinglulu 
458*91f16700Schasinglulu 	/* Disable ECC */
459*91f16700Schasinglulu 	stm32_fmc2_set_ecc(false);
460*91f16700Schasinglulu 
461*91f16700Schasinglulu 	/* No error found */
462*91f16700Schasinglulu 	if ((bchdsr0 & FMC2_BCHDSR0_DEF) == 0U) {
463*91f16700Schasinglulu 		return 0;
464*91f16700Schasinglulu 	}
465*91f16700Schasinglulu 
466*91f16700Schasinglulu 	/* Too many errors detected */
467*91f16700Schasinglulu 	if ((bchdsr0 & FMC2_BCHDSR0_DUE) != 0U) {
468*91f16700Schasinglulu 		return -EBADMSG;
469*91f16700Schasinglulu 	}
470*91f16700Schasinglulu 
471*91f16700Schasinglulu 	pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK;
472*91f16700Schasinglulu 	pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT;
473*91f16700Schasinglulu 	pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK;
474*91f16700Schasinglulu 	pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT;
475*91f16700Schasinglulu 	pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK;
476*91f16700Schasinglulu 	pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT;
477*91f16700Schasinglulu 	pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK;
478*91f16700Schasinglulu 	pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT;
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT;
481*91f16700Schasinglulu 	for (i = 0; i < den; i++) {
482*91f16700Schasinglulu 		if (pos[i] < (eccsize * 8U)) {
483*91f16700Schasinglulu 			uint8_t bitmask = BIT(pos[i] % 8U);
484*91f16700Schasinglulu 			uint32_t offset = pos[i] / 8U;
485*91f16700Schasinglulu 
486*91f16700Schasinglulu 			*(buffer + offset) ^= bitmask;
487*91f16700Schasinglulu 		}
488*91f16700Schasinglulu 	}
489*91f16700Schasinglulu 
490*91f16700Schasinglulu 	return 0;
491*91f16700Schasinglulu }
492*91f16700Schasinglulu 
493*91f16700Schasinglulu static void stm32_fmc2_hwctl(struct nand_device *nand)
494*91f16700Schasinglulu {
495*91f16700Schasinglulu 	stm32_fmc2_set_ecc(false);
496*91f16700Schasinglulu 
497*91f16700Schasinglulu 	if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
498*91f16700Schasinglulu 		mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
499*91f16700Schasinglulu 		mmio_write_32(fmc2_base() + FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
500*91f16700Schasinglulu 	}
501*91f16700Schasinglulu 
502*91f16700Schasinglulu 	stm32_fmc2_set_ecc(true);
503*91f16700Schasinglulu }
504*91f16700Schasinglulu 
505*91f16700Schasinglulu static int stm32_fmc2_read_page(struct nand_device *nand,
506*91f16700Schasinglulu 				unsigned int page, uintptr_t buffer)
507*91f16700Schasinglulu {
508*91f16700Schasinglulu 	unsigned int eccsize = nand->ecc.size;
509*91f16700Schasinglulu 	unsigned int eccbytes = nand->ecc.bytes;
510*91f16700Schasinglulu 	unsigned int eccsteps = nand->page_size / eccsize;
511*91f16700Schasinglulu 	uint8_t ecc_corr[FMC2_MAX_ECC_BYTES];
512*91f16700Schasinglulu 	uint8_t ecc_cal[FMC2_MAX_ECC_BYTES] = {0U};
513*91f16700Schasinglulu 	uint8_t *p;
514*91f16700Schasinglulu 	unsigned int i;
515*91f16700Schasinglulu 	unsigned int s;
516*91f16700Schasinglulu 	int ret;
517*91f16700Schasinglulu 
518*91f16700Schasinglulu 	VERBOSE(">%s page %u buffer %lx\n", __func__, page, buffer);
519*91f16700Schasinglulu 
520*91f16700Schasinglulu 	ret = nand_read_page_cmd(page, 0U, 0U, 0U);
521*91f16700Schasinglulu 	if (ret != 0) {
522*91f16700Schasinglulu 		return ret;
523*91f16700Schasinglulu 	}
524*91f16700Schasinglulu 
525*91f16700Schasinglulu 	for (s = 0U, i = nand->page_size + FMC2_BBM_LEN, p = (uint8_t *)buffer;
526*91f16700Schasinglulu 	     s < eccsteps;
527*91f16700Schasinglulu 	     s++, i += eccbytes, p += eccsize) {
528*91f16700Schasinglulu 		stm32_fmc2_hwctl(nand);
529*91f16700Schasinglulu 
530*91f16700Schasinglulu 		/* Read the NAND page sector (512 bytes) */
531*91f16700Schasinglulu 		ret = nand_change_read_column_cmd(s * eccsize, (uintptr_t)p,
532*91f16700Schasinglulu 						  eccsize);
533*91f16700Schasinglulu 		if (ret != 0) {
534*91f16700Schasinglulu 			return ret;
535*91f16700Schasinglulu 		}
536*91f16700Schasinglulu 
537*91f16700Schasinglulu 		if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
538*91f16700Schasinglulu 			ret = stm32_fmc2_ham_calculate(p, ecc_cal);
539*91f16700Schasinglulu 			if (ret != 0) {
540*91f16700Schasinglulu 				return ret;
541*91f16700Schasinglulu 			}
542*91f16700Schasinglulu 		}
543*91f16700Schasinglulu 
544*91f16700Schasinglulu 		/* Read the corresponding ECC bytes */
545*91f16700Schasinglulu 		ret = nand_change_read_column_cmd(i, (uintptr_t)ecc_corr,
546*91f16700Schasinglulu 						  eccbytes);
547*91f16700Schasinglulu 		if (ret != 0) {
548*91f16700Schasinglulu 			return ret;
549*91f16700Schasinglulu 		}
550*91f16700Schasinglulu 
551*91f16700Schasinglulu 		/* Correct the data */
552*91f16700Schasinglulu 		if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
553*91f16700Schasinglulu 			ret = stm32_fmc2_ham_correct(p, ecc_corr, ecc_cal);
554*91f16700Schasinglulu 		} else {
555*91f16700Schasinglulu 			ret = stm32_fmc2_bch_correct(p, eccsize);
556*91f16700Schasinglulu 		}
557*91f16700Schasinglulu 
558*91f16700Schasinglulu 		if (ret != 0) {
559*91f16700Schasinglulu 			return ret;
560*91f16700Schasinglulu 		}
561*91f16700Schasinglulu 	}
562*91f16700Schasinglulu 
563*91f16700Schasinglulu 	return 0;
564*91f16700Schasinglulu }
565*91f16700Schasinglulu 
566*91f16700Schasinglulu static void stm32_fmc2_read_data(struct nand_device *nand,
567*91f16700Schasinglulu 				 uint8_t *buff, unsigned int length,
568*91f16700Schasinglulu 				 bool use_bus8)
569*91f16700Schasinglulu {
570*91f16700Schasinglulu 	uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
571*91f16700Schasinglulu 
572*91f16700Schasinglulu 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
573*91f16700Schasinglulu 		stm32_fmc2_set_buswidth_16(false);
574*91f16700Schasinglulu 	}
575*91f16700Schasinglulu 
576*91f16700Schasinglulu 	if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
577*91f16700Schasinglulu 		*buff = mmio_read_8(data_base);
578*91f16700Schasinglulu 		buff += sizeof(uint8_t);
579*91f16700Schasinglulu 		length -= sizeof(uint8_t);
580*91f16700Schasinglulu 	}
581*91f16700Schasinglulu 
582*91f16700Schasinglulu 	if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
583*91f16700Schasinglulu 	    (length >= sizeof(uint16_t))) {
584*91f16700Schasinglulu 		*(uint16_t *)buff = mmio_read_16(data_base);
585*91f16700Schasinglulu 		buff += sizeof(uint16_t);
586*91f16700Schasinglulu 		length -= sizeof(uint16_t);
587*91f16700Schasinglulu 	}
588*91f16700Schasinglulu 
589*91f16700Schasinglulu 	/* 32bit aligned */
590*91f16700Schasinglulu 	while (length >= sizeof(uint32_t)) {
591*91f16700Schasinglulu 		*(uint32_t *)buff = mmio_read_32(data_base);
592*91f16700Schasinglulu 		buff += sizeof(uint32_t);
593*91f16700Schasinglulu 		length -= sizeof(uint32_t);
594*91f16700Schasinglulu 	}
595*91f16700Schasinglulu 
596*91f16700Schasinglulu 	/* Read remaining bytes */
597*91f16700Schasinglulu 	if (length >= sizeof(uint16_t)) {
598*91f16700Schasinglulu 		*(uint16_t *)buff = mmio_read_16(data_base);
599*91f16700Schasinglulu 		buff += sizeof(uint16_t);
600*91f16700Schasinglulu 		length -= sizeof(uint16_t);
601*91f16700Schasinglulu 	}
602*91f16700Schasinglulu 
603*91f16700Schasinglulu 	if (length != 0U) {
604*91f16700Schasinglulu 		*buff = mmio_read_8(data_base);
605*91f16700Schasinglulu 	}
606*91f16700Schasinglulu 
607*91f16700Schasinglulu 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
608*91f16700Schasinglulu 		/* Reconfigure bus width to 16-bit */
609*91f16700Schasinglulu 		stm32_fmc2_set_buswidth_16(true);
610*91f16700Schasinglulu 	}
611*91f16700Schasinglulu }
612*91f16700Schasinglulu 
613*91f16700Schasinglulu static void stm32_fmc2_write_data(struct nand_device *nand,
614*91f16700Schasinglulu 				  uint8_t *buff, unsigned int length,
615*91f16700Schasinglulu 				  bool use_bus8)
616*91f16700Schasinglulu {
617*91f16700Schasinglulu 	uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
618*91f16700Schasinglulu 
619*91f16700Schasinglulu 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
620*91f16700Schasinglulu 		/* Reconfigure bus width to 8-bit */
621*91f16700Schasinglulu 		stm32_fmc2_set_buswidth_16(false);
622*91f16700Schasinglulu 	}
623*91f16700Schasinglulu 
624*91f16700Schasinglulu 	if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
625*91f16700Schasinglulu 		mmio_write_8(data_base, *buff);
626*91f16700Schasinglulu 		buff += sizeof(uint8_t);
627*91f16700Schasinglulu 		length -= sizeof(uint8_t);
628*91f16700Schasinglulu 	}
629*91f16700Schasinglulu 
630*91f16700Schasinglulu 	if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
631*91f16700Schasinglulu 	    (length >= sizeof(uint16_t))) {
632*91f16700Schasinglulu 		mmio_write_16(data_base, *(uint16_t *)buff);
633*91f16700Schasinglulu 		buff += sizeof(uint16_t);
634*91f16700Schasinglulu 		length -= sizeof(uint16_t);
635*91f16700Schasinglulu 	}
636*91f16700Schasinglulu 
637*91f16700Schasinglulu 	/* 32bits aligned */
638*91f16700Schasinglulu 	while (length >= sizeof(uint32_t)) {
639*91f16700Schasinglulu 		mmio_write_32(data_base, *(uint32_t *)buff);
640*91f16700Schasinglulu 		buff += sizeof(uint32_t);
641*91f16700Schasinglulu 		length -= sizeof(uint32_t);
642*91f16700Schasinglulu 	}
643*91f16700Schasinglulu 
644*91f16700Schasinglulu 	/* Read remaining bytes */
645*91f16700Schasinglulu 	if (length >= sizeof(uint16_t)) {
646*91f16700Schasinglulu 		mmio_write_16(data_base, *(uint16_t *)buff);
647*91f16700Schasinglulu 		buff += sizeof(uint16_t);
648*91f16700Schasinglulu 		length -= sizeof(uint16_t);
649*91f16700Schasinglulu 	}
650*91f16700Schasinglulu 
651*91f16700Schasinglulu 	if (length != 0U) {
652*91f16700Schasinglulu 		mmio_write_8(data_base, *buff);
653*91f16700Schasinglulu 	}
654*91f16700Schasinglulu 
655*91f16700Schasinglulu 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
656*91f16700Schasinglulu 		/* Reconfigure bus width to 16-bit */
657*91f16700Schasinglulu 		stm32_fmc2_set_buswidth_16(true);
658*91f16700Schasinglulu 	}
659*91f16700Schasinglulu }
660*91f16700Schasinglulu 
661*91f16700Schasinglulu static void stm32_fmc2_ctrl_init(void)
662*91f16700Schasinglulu {
663*91f16700Schasinglulu 	uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
664*91f16700Schasinglulu 	uint32_t bcr1 = mmio_read_32(fmc2_base() + FMC2_BCR1);
665*91f16700Schasinglulu 
666*91f16700Schasinglulu 	/* Enable wait feature and NAND flash memory bank */
667*91f16700Schasinglulu 	pcr |= FMC2_PCR_PWAITEN;
668*91f16700Schasinglulu 	pcr |= FMC2_PCR_PBKEN;
669*91f16700Schasinglulu 
670*91f16700Schasinglulu 	/* Set buswidth to 8 bits mode for identification */
671*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_PWID_MASK;
672*91f16700Schasinglulu 
673*91f16700Schasinglulu 	/* ECC logic is disabled */
674*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_ECCEN;
675*91f16700Schasinglulu 
676*91f16700Schasinglulu 	/* Default mode */
677*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_ECCALG;
678*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_BCHECC;
679*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_WEN;
680*91f16700Schasinglulu 
681*91f16700Schasinglulu 	/* Set default ECC sector size */
682*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_ECCSS_MASK;
683*91f16700Schasinglulu 	pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
684*91f16700Schasinglulu 
685*91f16700Schasinglulu 	/* Set default TCLR/TAR timings */
686*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_TCLR_MASK;
687*91f16700Schasinglulu 	pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT);
688*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_TAR_MASK;
689*91f16700Schasinglulu 	pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT);
690*91f16700Schasinglulu 
691*91f16700Schasinglulu 	/* Enable FMC2 controller */
692*91f16700Schasinglulu 	bcr1 |= FMC2_BCR1_FMC2EN;
693*91f16700Schasinglulu 
694*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_BCR1, bcr1);
695*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
696*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PMEM, FMC2_PMEM_DEFAULT);
697*91f16700Schasinglulu 	mmio_write_32(fmc2_base() + FMC2_PATT, FMC2_PATT_DEFAULT);
698*91f16700Schasinglulu }
699*91f16700Schasinglulu 
700*91f16700Schasinglulu static int stm32_fmc2_exec(struct nand_req *req)
701*91f16700Schasinglulu {
702*91f16700Schasinglulu 	int ret = 0;
703*91f16700Schasinglulu 
704*91f16700Schasinglulu 	switch (req->type & NAND_REQ_MASK) {
705*91f16700Schasinglulu 	case NAND_REQ_CMD:
706*91f16700Schasinglulu 		VERBOSE("Write CMD %x\n", (uint8_t)req->type);
707*91f16700Schasinglulu 		mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].cmd_base,
708*91f16700Schasinglulu 			     (uint8_t)req->type);
709*91f16700Schasinglulu 		break;
710*91f16700Schasinglulu 	case NAND_REQ_ADDR:
711*91f16700Schasinglulu 		VERBOSE("Write ADDR %x\n", *(req->addr));
712*91f16700Schasinglulu 		mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].addr_base,
713*91f16700Schasinglulu 			     *(req->addr));
714*91f16700Schasinglulu 		break;
715*91f16700Schasinglulu 	case NAND_REQ_DATAIN:
716*91f16700Schasinglulu 		VERBOSE("Read data\n");
717*91f16700Schasinglulu 		stm32_fmc2_read_data(req->nand, req->addr, req->length,
718*91f16700Schasinglulu 				     ((req->type & NAND_REQ_BUS_WIDTH_8) !=
719*91f16700Schasinglulu 				      0U));
720*91f16700Schasinglulu 		break;
721*91f16700Schasinglulu 	case NAND_REQ_DATAOUT:
722*91f16700Schasinglulu 		VERBOSE("Write data\n");
723*91f16700Schasinglulu 		stm32_fmc2_write_data(req->nand, req->addr, req->length,
724*91f16700Schasinglulu 				      ((req->type & NAND_REQ_BUS_WIDTH_8) !=
725*91f16700Schasinglulu 				      0U));
726*91f16700Schasinglulu 		break;
727*91f16700Schasinglulu 	case NAND_REQ_WAIT:
728*91f16700Schasinglulu 		VERBOSE("WAIT Ready\n");
729*91f16700Schasinglulu 		ret = nand_wait_ready(req->delay_ms);
730*91f16700Schasinglulu 		break;
731*91f16700Schasinglulu 	default:
732*91f16700Schasinglulu 		ret = -EINVAL;
733*91f16700Schasinglulu 		break;
734*91f16700Schasinglulu 	};
735*91f16700Schasinglulu 
736*91f16700Schasinglulu 	return ret;
737*91f16700Schasinglulu }
738*91f16700Schasinglulu 
739*91f16700Schasinglulu static void stm32_fmc2_setup(struct nand_device *nand)
740*91f16700Schasinglulu {
741*91f16700Schasinglulu 	uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
742*91f16700Schasinglulu 
743*91f16700Schasinglulu 	/* Set buswidth */
744*91f16700Schasinglulu 	pcr &= ~FMC2_PCR_PWID_MASK;
745*91f16700Schasinglulu 	if (nand->buswidth == NAND_BUS_WIDTH_16) {
746*91f16700Schasinglulu 		pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_16);
747*91f16700Schasinglulu 	}
748*91f16700Schasinglulu 
749*91f16700Schasinglulu 	if (nand->ecc.mode == NAND_ECC_HW) {
750*91f16700Schasinglulu 		nand->mtd_read_page = stm32_fmc2_read_page;
751*91f16700Schasinglulu 
752*91f16700Schasinglulu 		pcr &= ~FMC2_PCR_ECCALG;
753*91f16700Schasinglulu 		pcr &= ~FMC2_PCR_BCHECC;
754*91f16700Schasinglulu 
755*91f16700Schasinglulu 		pcr &= ~FMC2_PCR_ECCSS_MASK;
756*91f16700Schasinglulu 		pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
757*91f16700Schasinglulu 
758*91f16700Schasinglulu 		switch (nand->ecc.max_bit_corr) {
759*91f16700Schasinglulu 		case FMC2_ECC_HAM:
760*91f16700Schasinglulu 			nand->ecc.bytes = 3;
761*91f16700Schasinglulu 			break;
762*91f16700Schasinglulu 		case FMC2_ECC_BCH8:
763*91f16700Schasinglulu 			pcr |= FMC2_PCR_ECCALG;
764*91f16700Schasinglulu 			pcr |= FMC2_PCR_BCHECC;
765*91f16700Schasinglulu 			nand->ecc.bytes = 13;
766*91f16700Schasinglulu 			break;
767*91f16700Schasinglulu 		default:
768*91f16700Schasinglulu 			/* Use FMC2 ECC BCH4 */
769*91f16700Schasinglulu 			pcr |= FMC2_PCR_ECCALG;
770*91f16700Schasinglulu 			nand->ecc.bytes = 7;
771*91f16700Schasinglulu 			break;
772*91f16700Schasinglulu 		}
773*91f16700Schasinglulu 
774*91f16700Schasinglulu 		if ((nand->buswidth & NAND_BUS_WIDTH_16) != 0) {
775*91f16700Schasinglulu 			nand->ecc.bytes++;
776*91f16700Schasinglulu 		}
777*91f16700Schasinglulu 	}
778*91f16700Schasinglulu 
779*91f16700Schasinglulu 	mmio_write_32(stm32_fmc2.reg_base + FMC2_PCR, pcr);
780*91f16700Schasinglulu }
781*91f16700Schasinglulu 
782*91f16700Schasinglulu static const struct nand_ctrl_ops ctrl_ops = {
783*91f16700Schasinglulu 	.setup = stm32_fmc2_setup,
784*91f16700Schasinglulu 	.exec = stm32_fmc2_exec
785*91f16700Schasinglulu };
786*91f16700Schasinglulu 
787*91f16700Schasinglulu int stm32_fmc2_init(void)
788*91f16700Schasinglulu {
789*91f16700Schasinglulu 	int fmc_ebi_node;
790*91f16700Schasinglulu 	int fmc_nfc_node;
791*91f16700Schasinglulu 	int fmc_flash_node = 0;
792*91f16700Schasinglulu 	int nchips = 0;
793*91f16700Schasinglulu 	unsigned int i;
794*91f16700Schasinglulu 	void *fdt = NULL;
795*91f16700Schasinglulu 	const fdt32_t *cuint;
796*91f16700Schasinglulu 	struct dt_node_info info;
797*91f16700Schasinglulu 	uintptr_t bank_address[MAX_BANK] = { 0, 0, 0, 0, 0 };
798*91f16700Schasinglulu 	uint8_t bank_assigned = 0;
799*91f16700Schasinglulu 	uint8_t bank;
800*91f16700Schasinglulu 	int ret;
801*91f16700Schasinglulu 
802*91f16700Schasinglulu 	if (fdt_get_address(&fdt) == 0) {
803*91f16700Schasinglulu 		return -FDT_ERR_NOTFOUND;
804*91f16700Schasinglulu 	}
805*91f16700Schasinglulu 
806*91f16700Schasinglulu 	fmc_ebi_node = dt_get_node(&info, -1, DT_FMC2_EBI_COMPAT);
807*91f16700Schasinglulu 	if (fmc_ebi_node < 0) {
808*91f16700Schasinglulu 		return fmc_ebi_node;
809*91f16700Schasinglulu 	}
810*91f16700Schasinglulu 
811*91f16700Schasinglulu 	if (info.status == DT_DISABLED) {
812*91f16700Schasinglulu 		return -FDT_ERR_NOTFOUND;
813*91f16700Schasinglulu 	}
814*91f16700Schasinglulu 
815*91f16700Schasinglulu 	stm32_fmc2.reg_base = info.base;
816*91f16700Schasinglulu 
817*91f16700Schasinglulu 	if ((info.clock < 0) || (info.reset < 0)) {
818*91f16700Schasinglulu 		return -FDT_ERR_BADVALUE;
819*91f16700Schasinglulu 	}
820*91f16700Schasinglulu 
821*91f16700Schasinglulu 	stm32_fmc2.clock_id = (unsigned long)info.clock;
822*91f16700Schasinglulu 	stm32_fmc2.reset_id = (unsigned int)info.reset;
823*91f16700Schasinglulu 
824*91f16700Schasinglulu 	cuint = fdt_getprop(fdt, fmc_ebi_node, "ranges", NULL);
825*91f16700Schasinglulu 	if (cuint == NULL) {
826*91f16700Schasinglulu 		return -FDT_ERR_BADVALUE;
827*91f16700Schasinglulu 	}
828*91f16700Schasinglulu 
829*91f16700Schasinglulu 	for (i = 0U; i < MAX_BANK; i++) {
830*91f16700Schasinglulu 		bank = fdt32_to_cpu(*cuint);
831*91f16700Schasinglulu 		if ((bank >= MAX_BANK) || ((bank_assigned & BIT(bank)) != 0U)) {
832*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
833*91f16700Schasinglulu 		}
834*91f16700Schasinglulu 		bank_assigned |= BIT(bank);
835*91f16700Schasinglulu 		bank_address[bank] = fdt32_to_cpu(*(cuint + 2));
836*91f16700Schasinglulu 		cuint += 4;
837*91f16700Schasinglulu 	}
838*91f16700Schasinglulu 
839*91f16700Schasinglulu 	/* Pinctrl initialization */
840*91f16700Schasinglulu 	if (dt_set_pinctrl_config(fmc_ebi_node) != 0) {
841*91f16700Schasinglulu 		return -FDT_ERR_BADVALUE;
842*91f16700Schasinglulu 	}
843*91f16700Schasinglulu 
844*91f16700Schasinglulu 	/* Parse NFC controller node */
845*91f16700Schasinglulu 	fmc_nfc_node = fdt_node_offset_by_compatible(fdt, fmc_ebi_node,
846*91f16700Schasinglulu 						     DT_FMC2_NFC_COMPAT);
847*91f16700Schasinglulu 	if (fmc_nfc_node < 0) {
848*91f16700Schasinglulu 		return fmc_nfc_node;
849*91f16700Schasinglulu 	}
850*91f16700Schasinglulu 
851*91f16700Schasinglulu 	if (fdt_get_status(fmc_nfc_node) == DT_DISABLED) {
852*91f16700Schasinglulu 		return -FDT_ERR_NOTFOUND;
853*91f16700Schasinglulu 	}
854*91f16700Schasinglulu 
855*91f16700Schasinglulu 	cuint = fdt_getprop(fdt, fmc_nfc_node, "reg", NULL);
856*91f16700Schasinglulu 	if (cuint == NULL) {
857*91f16700Schasinglulu 		return -FDT_ERR_BADVALUE;
858*91f16700Schasinglulu 	}
859*91f16700Schasinglulu 
860*91f16700Schasinglulu 	for (i = 0U; i < MAX_CS; i++) {
861*91f16700Schasinglulu 		bank = fdt32_to_cpu(*cuint);
862*91f16700Schasinglulu 		if (bank >= MAX_BANK) {
863*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
864*91f16700Schasinglulu 		}
865*91f16700Schasinglulu 		stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*(cuint + 1)) +
866*91f16700Schasinglulu 					     bank_address[bank];
867*91f16700Schasinglulu 
868*91f16700Schasinglulu 		bank = fdt32_to_cpu(*(cuint + 3));
869*91f16700Schasinglulu 		if (bank >= MAX_BANK) {
870*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
871*91f16700Schasinglulu 		}
872*91f16700Schasinglulu 		stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 4)) +
873*91f16700Schasinglulu 					    bank_address[bank];
874*91f16700Schasinglulu 
875*91f16700Schasinglulu 		bank = fdt32_to_cpu(*(cuint + 6));
876*91f16700Schasinglulu 		if (bank >= MAX_BANK) {
877*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
878*91f16700Schasinglulu 		}
879*91f16700Schasinglulu 		stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 7)) +
880*91f16700Schasinglulu 					     bank_address[bank];
881*91f16700Schasinglulu 
882*91f16700Schasinglulu 		cuint += 9;
883*91f16700Schasinglulu 	}
884*91f16700Schasinglulu 
885*91f16700Schasinglulu 	/* Parse flash nodes */
886*91f16700Schasinglulu 	fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
887*91f16700Schasinglulu 		nchips++;
888*91f16700Schasinglulu 	}
889*91f16700Schasinglulu 
890*91f16700Schasinglulu 	if (nchips != 1) {
891*91f16700Schasinglulu 		WARN("Only one SLC NAND device supported\n");
892*91f16700Schasinglulu 		return -FDT_ERR_BADVALUE;
893*91f16700Schasinglulu 	}
894*91f16700Schasinglulu 
895*91f16700Schasinglulu 	fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
896*91f16700Schasinglulu 		/* Get chip select */
897*91f16700Schasinglulu 		cuint = fdt_getprop(fdt, fmc_flash_node, "reg", NULL);
898*91f16700Schasinglulu 		if (cuint == NULL) {
899*91f16700Schasinglulu 			WARN("Chip select not well defined\n");
900*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
901*91f16700Schasinglulu 		}
902*91f16700Schasinglulu 
903*91f16700Schasinglulu 		stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
904*91f16700Schasinglulu 		if (stm32_fmc2.cs_sel >= MAX_CS) {
905*91f16700Schasinglulu 			return -FDT_ERR_BADVALUE;
906*91f16700Schasinglulu 		}
907*91f16700Schasinglulu 
908*91f16700Schasinglulu 		VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
909*91f16700Schasinglulu 	}
910*91f16700Schasinglulu 
911*91f16700Schasinglulu 	/* Enable Clock */
912*91f16700Schasinglulu 	clk_enable(stm32_fmc2.clock_id);
913*91f16700Schasinglulu 
914*91f16700Schasinglulu 	/* Reset IP */
915*91f16700Schasinglulu 	ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
916*91f16700Schasinglulu 	if (ret != 0) {
917*91f16700Schasinglulu 		panic();
918*91f16700Schasinglulu 	}
919*91f16700Schasinglulu 	ret = stm32mp_reset_deassert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
920*91f16700Schasinglulu 	if (ret != 0) {
921*91f16700Schasinglulu 		panic();
922*91f16700Schasinglulu 	}
923*91f16700Schasinglulu 
924*91f16700Schasinglulu 	/* Setup default IP registers */
925*91f16700Schasinglulu 	stm32_fmc2_ctrl_init();
926*91f16700Schasinglulu 
927*91f16700Schasinglulu 	/* Setup default timings */
928*91f16700Schasinglulu 	stm32_fmc2_nand_setup_timing();
929*91f16700Schasinglulu 
930*91f16700Schasinglulu 	/* Init NAND RAW framework */
931*91f16700Schasinglulu 	nand_raw_ctrl_init(&ctrl_ops);
932*91f16700Schasinglulu 
933*91f16700Schasinglulu 	return 0;
934*91f16700Schasinglulu }
935