xref: /rk3399_ARM-atf/drivers/st/fmc/stm32_fmc2_nand.c (revision 44966000ec11e22ae2d580d0291d6e1cd613895d)
1695f7df8SLionel Debieve /*
29fe181c6SYann Gautier  * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
3695f7df8SLionel Debieve  *
4695f7df8SLionel Debieve  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
5695f7df8SLionel Debieve  */
6695f7df8SLionel Debieve 
7695f7df8SLionel Debieve #include <assert.h>
8695f7df8SLionel Debieve #include <errno.h>
9695f7df8SLionel Debieve #include <limits.h>
10695f7df8SLionel Debieve #include <stdint.h>
11695f7df8SLionel Debieve 
12695f7df8SLionel Debieve #include <libfdt.h>
13695f7df8SLionel Debieve 
14695f7df8SLionel Debieve #include <platform_def.h>
15695f7df8SLionel Debieve 
16695f7df8SLionel Debieve #include <common/debug.h>
17695f7df8SLionel Debieve #include <drivers/delay_timer.h>
18695f7df8SLionel Debieve #include <drivers/raw_nand.h>
19695f7df8SLionel Debieve #include <drivers/st/stm32_fmc2_nand.h>
20695f7df8SLionel Debieve #include <drivers/st/stm32_gpio.h>
21695f7df8SLionel Debieve #include <drivers/st/stm32mp_reset.h>
22695f7df8SLionel Debieve #include <lib/mmio.h>
23695f7df8SLionel Debieve #include <lib/utils_def.h>
24695f7df8SLionel Debieve 
2545c70e68SEtienne Carriere /* Timeout for device interface reset */
2645c70e68SEtienne Carriere #define TIMEOUT_US_1_MS			1000U
2745c70e68SEtienne Carriere 
28695f7df8SLionel Debieve /* FMC2 Compatibility */
29695f7df8SLionel Debieve #define DT_FMC2_COMPAT			"st,stm32mp15-fmc2"
30695f7df8SLionel Debieve #define MAX_CS				2U
31695f7df8SLionel Debieve 
32695f7df8SLionel Debieve /* FMC2 Controller Registers */
33695f7df8SLionel Debieve #define FMC2_BCR1			0x00U
34695f7df8SLionel Debieve #define FMC2_PCR			0x80U
35695f7df8SLionel Debieve #define FMC2_SR				0x84U
36695f7df8SLionel Debieve #define FMC2_PMEM			0x88U
37695f7df8SLionel Debieve #define FMC2_PATT			0x8CU
38695f7df8SLionel Debieve #define FMC2_HECCR			0x94U
39695f7df8SLionel Debieve #define FMC2_BCHISR			0x254U
40*44966000SLionel Debieve #define FMC2_BCHICR			0x258U
41695f7df8SLionel Debieve #define FMC2_BCHDSR0			0x27CU
42695f7df8SLionel Debieve #define FMC2_BCHDSR1			0x280U
43695f7df8SLionel Debieve #define FMC2_BCHDSR2			0x284U
44695f7df8SLionel Debieve #define FMC2_BCHDSR3			0x288U
45695f7df8SLionel Debieve #define FMC2_BCHDSR4			0x28CU
46695f7df8SLionel Debieve 
47695f7df8SLionel Debieve /* FMC2_BCR1 register */
48695f7df8SLionel Debieve #define FMC2_BCR1_FMC2EN		BIT(31)
49695f7df8SLionel Debieve /* FMC2_PCR register */
50695f7df8SLionel Debieve #define FMC2_PCR_PWAITEN		BIT(1)
51695f7df8SLionel Debieve #define FMC2_PCR_PBKEN			BIT(2)
52695f7df8SLionel Debieve #define FMC2_PCR_PWID_MASK		GENMASK_32(5, 4)
53695f7df8SLionel Debieve #define FMC2_PCR_PWID(x)		(((x) << 4) & FMC2_PCR_PWID_MASK)
54695f7df8SLionel Debieve #define FMC2_PCR_PWID_8			0x0U
55695f7df8SLionel Debieve #define FMC2_PCR_PWID_16		0x1U
56695f7df8SLionel Debieve #define FMC2_PCR_ECCEN			BIT(6)
57695f7df8SLionel Debieve #define FMC2_PCR_ECCALG			BIT(8)
58695f7df8SLionel Debieve #define FMC2_PCR_TCLR_MASK		GENMASK_32(12, 9)
59695f7df8SLionel Debieve #define FMC2_PCR_TCLR(x)		(((x) << 9) & FMC2_PCR_TCLR_MASK)
60695f7df8SLionel Debieve #define FMC2_PCR_TCLR_DEFAULT		0xFU
61695f7df8SLionel Debieve #define FMC2_PCR_TAR_MASK		GENMASK_32(16, 13)
62695f7df8SLionel Debieve #define FMC2_PCR_TAR(x)			(((x) << 13) & FMC2_PCR_TAR_MASK)
63695f7df8SLionel Debieve #define FMC2_PCR_TAR_DEFAULT		0xFU
64695f7df8SLionel Debieve #define FMC2_PCR_ECCSS_MASK		GENMASK_32(19, 17)
65695f7df8SLionel Debieve #define FMC2_PCR_ECCSS(x)		(((x) << 17) & FMC2_PCR_ECCSS_MASK)
66695f7df8SLionel Debieve #define FMC2_PCR_ECCSS_512		0x1U
67695f7df8SLionel Debieve #define FMC2_PCR_ECCSS_2048		0x3U
68695f7df8SLionel Debieve #define FMC2_PCR_BCHECC			BIT(24)
69695f7df8SLionel Debieve #define FMC2_PCR_WEN			BIT(25)
70695f7df8SLionel Debieve /* FMC2_SR register */
71695f7df8SLionel Debieve #define FMC2_SR_NWRF			BIT(6)
72695f7df8SLionel Debieve /* FMC2_PMEM register*/
73695f7df8SLionel Debieve #define FMC2_PMEM_MEMSET(x)		(((x) & GENMASK_32(7, 0)) << 0)
74695f7df8SLionel Debieve #define FMC2_PMEM_MEMWAIT(x)		(((x) & GENMASK_32(7, 0)) << 8)
75695f7df8SLionel Debieve #define FMC2_PMEM_MEMHOLD(x)		(((x) & GENMASK_32(7, 0)) << 16)
76695f7df8SLionel Debieve #define FMC2_PMEM_MEMHIZ(x)		(((x) & GENMASK_32(7, 0)) << 24)
77695f7df8SLionel Debieve #define FMC2_PMEM_DEFAULT		0x0A0A0A0AU
78695f7df8SLionel Debieve /* FMC2_PATT register */
79695f7df8SLionel Debieve #define FMC2_PATT_ATTSET(x)		(((x) & GENMASK_32(7, 0)) << 0)
80695f7df8SLionel Debieve #define FMC2_PATT_ATTWAIT(x)		(((x) & GENMASK_32(7, 0)) << 8)
81695f7df8SLionel Debieve #define FMC2_PATT_ATTHOLD(x)		(((x) & GENMASK_32(7, 0)) << 16)
82695f7df8SLionel Debieve #define FMC2_PATT_ATTHIZ(x)		(((x) & GENMASK_32(7, 0)) << 24)
83695f7df8SLionel Debieve #define FMC2_PATT_DEFAULT		0x0A0A0A0AU
84695f7df8SLionel Debieve /* FMC2_BCHISR register */
85695f7df8SLionel Debieve #define FMC2_BCHISR_DERF		BIT(1)
86*44966000SLionel Debieve /* FMC2_BCHICR register */
87*44966000SLionel Debieve #define FMC2_BCHICR_CLEAR_IRQ		GENMASK_32(4, 0)
88695f7df8SLionel Debieve /* FMC2_BCHDSR0 register */
89695f7df8SLionel Debieve #define FMC2_BCHDSR0_DUE		BIT(0)
90695f7df8SLionel Debieve #define FMC2_BCHDSR0_DEF		BIT(1)
91695f7df8SLionel Debieve #define FMC2_BCHDSR0_DEN_MASK		GENMASK_32(7, 4)
92695f7df8SLionel Debieve #define FMC2_BCHDSR0_DEN_SHIFT		4U
93695f7df8SLionel Debieve /* FMC2_BCHDSR1 register */
94695f7df8SLionel Debieve #define FMC2_BCHDSR1_EBP1_MASK		GENMASK_32(12, 0)
95695f7df8SLionel Debieve #define FMC2_BCHDSR1_EBP2_MASK		GENMASK_32(28, 16)
96695f7df8SLionel Debieve #define FMC2_BCHDSR1_EBP2_SHIFT		16U
97695f7df8SLionel Debieve /* FMC2_BCHDSR2 register */
98695f7df8SLionel Debieve #define FMC2_BCHDSR2_EBP3_MASK		GENMASK_32(12, 0)
99695f7df8SLionel Debieve #define FMC2_BCHDSR2_EBP4_MASK		GENMASK_32(28, 16)
100695f7df8SLionel Debieve #define FMC2_BCHDSR2_EBP4_SHIFT		16U
101695f7df8SLionel Debieve /* FMC2_BCHDSR3 register */
102695f7df8SLionel Debieve #define FMC2_BCHDSR3_EBP5_MASK		GENMASK_32(12, 0)
103695f7df8SLionel Debieve #define FMC2_BCHDSR3_EBP6_MASK		GENMASK_32(28, 16)
104695f7df8SLionel Debieve #define FMC2_BCHDSR3_EBP6_SHIFT		16U
105695f7df8SLionel Debieve /* FMC2_BCHDSR4 register */
106695f7df8SLionel Debieve #define FMC2_BCHDSR4_EBP7_MASK		GENMASK_32(12, 0)
107695f7df8SLionel Debieve #define FMC2_BCHDSR4_EBP8_MASK		GENMASK_32(28, 16)
108695f7df8SLionel Debieve #define FMC2_BCHDSR4_EBP8_SHIFT		16U
109695f7df8SLionel Debieve 
110695f7df8SLionel Debieve /* Timings */
111695f7df8SLionel Debieve #define FMC2_THIZ			0x01U
112695f7df8SLionel Debieve #define FMC2_TIO			8000U
113695f7df8SLionel Debieve #define FMC2_TSYNC			3000U
114695f7df8SLionel Debieve #define FMC2_PCR_TIMING_MASK		GENMASK_32(3, 0)
115695f7df8SLionel Debieve #define FMC2_PMEM_PATT_TIMING_MASK	GENMASK_32(7, 0)
116695f7df8SLionel Debieve 
117695f7df8SLionel Debieve #define FMC2_BBM_LEN			2U
118695f7df8SLionel Debieve #define FMC2_MAX_ECC_BYTES		14U
119695f7df8SLionel Debieve #define TIMEOUT_US_10_MS		10000U
120695f7df8SLionel Debieve #define FMC2_PSEC_PER_MSEC		(1000UL * 1000UL * 1000UL)
121695f7df8SLionel Debieve 
122695f7df8SLionel Debieve enum stm32_fmc2_ecc {
123695f7df8SLionel Debieve 	FMC2_ECC_HAM = 1U,
124695f7df8SLionel Debieve 	FMC2_ECC_BCH4 = 4U,
125695f7df8SLionel Debieve 	FMC2_ECC_BCH8 = 8U
126695f7df8SLionel Debieve };
127695f7df8SLionel Debieve 
128695f7df8SLionel Debieve struct stm32_fmc2_cs_reg {
129695f7df8SLionel Debieve 	uintptr_t data_base;
130695f7df8SLionel Debieve 	uintptr_t cmd_base;
131695f7df8SLionel Debieve 	uintptr_t addr_base;
132695f7df8SLionel Debieve };
133695f7df8SLionel Debieve 
134695f7df8SLionel Debieve struct stm32_fmc2_nand_timings {
135695f7df8SLionel Debieve 	uint8_t tclr;
136695f7df8SLionel Debieve 	uint8_t tar;
137695f7df8SLionel Debieve 	uint8_t thiz;
138695f7df8SLionel Debieve 	uint8_t twait;
139695f7df8SLionel Debieve 	uint8_t thold_mem;
140695f7df8SLionel Debieve 	uint8_t tset_mem;
141695f7df8SLionel Debieve 	uint8_t thold_att;
142695f7df8SLionel Debieve 	uint8_t tset_att;
143695f7df8SLionel Debieve };
144695f7df8SLionel Debieve 
145695f7df8SLionel Debieve struct stm32_fmc2_nfc {
146695f7df8SLionel Debieve 	uintptr_t reg_base;
147695f7df8SLionel Debieve 	struct stm32_fmc2_cs_reg cs[MAX_CS];
148695f7df8SLionel Debieve 	unsigned long clock_id;
149695f7df8SLionel Debieve 	unsigned int reset_id;
150695f7df8SLionel Debieve 	uint8_t cs_sel;
151695f7df8SLionel Debieve };
152695f7df8SLionel Debieve 
153695f7df8SLionel Debieve static struct stm32_fmc2_nfc stm32_fmc2;
154695f7df8SLionel Debieve 
155695f7df8SLionel Debieve static uintptr_t fmc2_base(void)
156695f7df8SLionel Debieve {
157695f7df8SLionel Debieve 	return stm32_fmc2.reg_base;
158695f7df8SLionel Debieve }
159695f7df8SLionel Debieve 
160695f7df8SLionel Debieve static void stm32_fmc2_nand_setup_timing(void)
161695f7df8SLionel Debieve {
162695f7df8SLionel Debieve 	struct stm32_fmc2_nand_timings tims;
163695f7df8SLionel Debieve 	unsigned long hclk = stm32mp_clk_get_rate(stm32_fmc2.clock_id);
164695f7df8SLionel Debieve 	unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
165695f7df8SLionel Debieve 	unsigned long timing, tar, tclr, thiz, twait;
166695f7df8SLionel Debieve 	unsigned long tset_mem, tset_att, thold_mem, thold_att;
167695f7df8SLionel Debieve 	uint32_t pcr, pmem, patt;
168695f7df8SLionel Debieve 
169695f7df8SLionel Debieve 	tar = MAX(hclkp, NAND_TAR_MIN);
170695f7df8SLionel Debieve 	timing = div_round_up(tar, hclkp) - 1U;
171695f7df8SLionel Debieve 	tims.tar = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
172695f7df8SLionel Debieve 
173695f7df8SLionel Debieve 	tclr = MAX(hclkp, NAND_TCLR_MIN);
174695f7df8SLionel Debieve 	timing = div_round_up(tclr, hclkp) - 1U;
175695f7df8SLionel Debieve 	tims.tclr = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
176695f7df8SLionel Debieve 
177695f7df8SLionel Debieve 	tims.thiz = FMC2_THIZ;
178695f7df8SLionel Debieve 	thiz = (tims.thiz + 1U) * hclkp;
179695f7df8SLionel Debieve 
180695f7df8SLionel Debieve 	/*
181695f7df8SLionel Debieve 	 * tWAIT > tRP
182695f7df8SLionel Debieve 	 * tWAIT > tWP
183695f7df8SLionel Debieve 	 * tWAIT > tREA + tIO
184695f7df8SLionel Debieve 	 */
185695f7df8SLionel Debieve 	twait = MAX(hclkp, NAND_TRP_MIN);
186695f7df8SLionel Debieve 	twait = MAX(twait, NAND_TWP_MIN);
187695f7df8SLionel Debieve 	twait = MAX(twait, NAND_TREA_MAX + FMC2_TIO);
188695f7df8SLionel Debieve 	timing = div_round_up(twait, hclkp);
189695f7df8SLionel Debieve 	tims.twait = CLAMP(timing, 1UL,
190695f7df8SLionel Debieve 			   (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
191695f7df8SLionel Debieve 
192695f7df8SLionel Debieve 	/*
193695f7df8SLionel Debieve 	 * tSETUP_MEM > tCS - tWAIT
194695f7df8SLionel Debieve 	 * tSETUP_MEM > tALS - tWAIT
195695f7df8SLionel Debieve 	 * tSETUP_MEM > tDS - (tWAIT - tHIZ)
196695f7df8SLionel Debieve 	 */
197695f7df8SLionel Debieve 	tset_mem = hclkp;
198695f7df8SLionel Debieve 	if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
199695f7df8SLionel Debieve 		tset_mem = NAND_TCS_MIN - twait;
200695f7df8SLionel Debieve 	}
201695f7df8SLionel Debieve 	if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) {
202695f7df8SLionel Debieve 		tset_mem = NAND_TALS_MIN - twait;
203695f7df8SLionel Debieve 	}
204695f7df8SLionel Debieve 	if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
205695f7df8SLionel Debieve 	    (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
206695f7df8SLionel Debieve 		tset_mem = NAND_TDS_MIN - (twait - thiz);
207695f7df8SLionel Debieve 	}
208695f7df8SLionel Debieve 	timing = div_round_up(tset_mem, hclkp);
209695f7df8SLionel Debieve 	tims.tset_mem = CLAMP(timing, 1UL,
210695f7df8SLionel Debieve 			      (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
211695f7df8SLionel Debieve 
212695f7df8SLionel Debieve 	/*
213695f7df8SLionel Debieve 	 * tHOLD_MEM > tCH
214695f7df8SLionel Debieve 	 * tHOLD_MEM > tREH - tSETUP_MEM
215695f7df8SLionel Debieve 	 * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
216695f7df8SLionel Debieve 	 */
217695f7df8SLionel Debieve 	thold_mem = MAX(hclkp, NAND_TCH_MIN);
218695f7df8SLionel Debieve 	if ((tset_mem < NAND_TREH_MIN) &&
219695f7df8SLionel Debieve 	    (thold_mem < (NAND_TREH_MIN - tset_mem))) {
220695f7df8SLionel Debieve 		thold_mem = NAND_TREH_MIN - tset_mem;
221695f7df8SLionel Debieve 	}
222695f7df8SLionel Debieve 	if (((tset_mem + twait) < NAND_TRC_MIN) &&
223695f7df8SLionel Debieve 	    (thold_mem < (NAND_TRC_MIN - (tset_mem + twait)))) {
224695f7df8SLionel Debieve 		thold_mem = NAND_TRC_MIN  - (tset_mem + twait);
225695f7df8SLionel Debieve 	}
226695f7df8SLionel Debieve 	if (((tset_mem + twait) < NAND_TWC_MIN) &&
227695f7df8SLionel Debieve 	    (thold_mem < (NAND_TWC_MIN - (tset_mem + twait)))) {
228695f7df8SLionel Debieve 		thold_mem = NAND_TWC_MIN - (tset_mem + twait);
229695f7df8SLionel Debieve 	}
230695f7df8SLionel Debieve 	timing = div_round_up(thold_mem, hclkp);
231695f7df8SLionel Debieve 	tims.thold_mem = CLAMP(timing, 1UL,
232695f7df8SLionel Debieve 			       (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
233695f7df8SLionel Debieve 
234695f7df8SLionel Debieve 	/*
235695f7df8SLionel Debieve 	 * tSETUP_ATT > tCS - tWAIT
236695f7df8SLionel Debieve 	 * tSETUP_ATT > tCLS - tWAIT
237695f7df8SLionel Debieve 	 * tSETUP_ATT > tALS - tWAIT
238695f7df8SLionel Debieve 	 * tSETUP_ATT > tRHW - tHOLD_MEM
239695f7df8SLionel Debieve 	 * tSETUP_ATT > tDS - (tWAIT - tHIZ)
240695f7df8SLionel Debieve 	 */
241695f7df8SLionel Debieve 	tset_att = hclkp;
242695f7df8SLionel Debieve 	if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
243695f7df8SLionel Debieve 		tset_att = NAND_TCS_MIN - twait;
244695f7df8SLionel Debieve 	}
245695f7df8SLionel Debieve 	if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) {
246695f7df8SLionel Debieve 		tset_att = NAND_TCLS_MIN - twait;
247695f7df8SLionel Debieve 	}
248695f7df8SLionel Debieve 	if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) {
249695f7df8SLionel Debieve 		tset_att = NAND_TALS_MIN - twait;
250695f7df8SLionel Debieve 	}
251695f7df8SLionel Debieve 	if ((thold_mem < NAND_TRHW_MIN) &&
252695f7df8SLionel Debieve 	    (tset_att < (NAND_TRHW_MIN - thold_mem))) {
253695f7df8SLionel Debieve 		tset_att = NAND_TRHW_MIN - thold_mem;
254695f7df8SLionel Debieve 	}
255695f7df8SLionel Debieve 	if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
256695f7df8SLionel Debieve 	    (tset_att < (NAND_TDS_MIN - (twait - thiz)))) {
257695f7df8SLionel Debieve 		tset_att = NAND_TDS_MIN - (twait - thiz);
258695f7df8SLionel Debieve 	}
259695f7df8SLionel Debieve 	timing = div_round_up(tset_att, hclkp);
260695f7df8SLionel Debieve 	tims.tset_att = CLAMP(timing, 1UL,
261695f7df8SLionel Debieve 			      (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
262695f7df8SLionel Debieve 
263695f7df8SLionel Debieve 	/*
264695f7df8SLionel Debieve 	 * tHOLD_ATT > tALH
265695f7df8SLionel Debieve 	 * tHOLD_ATT > tCH
266695f7df8SLionel Debieve 	 * tHOLD_ATT > tCLH
267695f7df8SLionel Debieve 	 * tHOLD_ATT > tCOH
268695f7df8SLionel Debieve 	 * tHOLD_ATT > tDH
269695f7df8SLionel Debieve 	 * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
270695f7df8SLionel Debieve 	 * tHOLD_ATT > tADL - tSETUP_MEM
271695f7df8SLionel Debieve 	 * tHOLD_ATT > tWH - tSETUP_MEM
272695f7df8SLionel Debieve 	 * tHOLD_ATT > tWHR - tSETUP_MEM
273695f7df8SLionel Debieve 	 * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
274695f7df8SLionel Debieve 	 * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
275695f7df8SLionel Debieve 	 */
276695f7df8SLionel Debieve 	thold_att = MAX(hclkp, NAND_TALH_MIN);
277695f7df8SLionel Debieve 	thold_att = MAX(thold_att, NAND_TCH_MIN);
278695f7df8SLionel Debieve 	thold_att = MAX(thold_att, NAND_TCLH_MIN);
279695f7df8SLionel Debieve 	thold_att = MAX(thold_att, NAND_TCOH_MIN);
280695f7df8SLionel Debieve 	thold_att = MAX(thold_att, NAND_TDH_MIN);
281695f7df8SLionel Debieve 	if (((NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC) > tset_mem) &&
282695f7df8SLionel Debieve 	    (thold_att < (NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem))) {
283695f7df8SLionel Debieve 		thold_att = NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem;
284695f7df8SLionel Debieve 	}
285695f7df8SLionel Debieve 	if ((tset_mem < NAND_TADL_MIN) &&
286695f7df8SLionel Debieve 	    (thold_att < (NAND_TADL_MIN - tset_mem))) {
287695f7df8SLionel Debieve 		thold_att = NAND_TADL_MIN - tset_mem;
288695f7df8SLionel Debieve 	}
289695f7df8SLionel Debieve 	if ((tset_mem < NAND_TWH_MIN) &&
290695f7df8SLionel Debieve 	    (thold_att < (NAND_TWH_MIN - tset_mem))) {
291695f7df8SLionel Debieve 		thold_att = NAND_TWH_MIN - tset_mem;
292695f7df8SLionel Debieve 	}
293695f7df8SLionel Debieve 	if ((tset_mem < NAND_TWHR_MIN) &&
294695f7df8SLionel Debieve 	    (thold_att < (NAND_TWHR_MIN - tset_mem))) {
295695f7df8SLionel Debieve 		thold_att = NAND_TWHR_MIN - tset_mem;
296695f7df8SLionel Debieve 	}
297695f7df8SLionel Debieve 	if (((tset_att + twait) < NAND_TRC_MIN) &&
298695f7df8SLionel Debieve 	    (thold_att < (NAND_TRC_MIN - (tset_att + twait)))) {
299695f7df8SLionel Debieve 		thold_att = NAND_TRC_MIN - (tset_att + twait);
300695f7df8SLionel Debieve 	}
301695f7df8SLionel Debieve 	if (((tset_att + twait) < NAND_TWC_MIN) &&
302695f7df8SLionel Debieve 	    (thold_att < (NAND_TWC_MIN - (tset_att + twait)))) {
303695f7df8SLionel Debieve 		thold_att = NAND_TWC_MIN - (tset_att + twait);
304695f7df8SLionel Debieve 	}
305695f7df8SLionel Debieve 	timing = div_round_up(thold_att, hclkp);
306695f7df8SLionel Debieve 	tims.thold_att = CLAMP(timing, 1UL,
307695f7df8SLionel Debieve 			       (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
308695f7df8SLionel Debieve 
309695f7df8SLionel Debieve 	VERBOSE("NAND timings: %u - %u - %u - %u - %u - %u - %u - %u\n",
310695f7df8SLionel Debieve 		tims.tclr, tims.tar, tims.thiz, tims.twait,
311695f7df8SLionel Debieve 		tims.thold_mem, tims.tset_mem,
312695f7df8SLionel Debieve 		tims.thold_att, tims.tset_att);
313695f7df8SLionel Debieve 
314695f7df8SLionel Debieve 	/* Set tclr/tar timings */
315695f7df8SLionel Debieve 	pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
316695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_TCLR_MASK;
317695f7df8SLionel Debieve 	pcr |= FMC2_PCR_TCLR(tims.tclr);
318695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_TAR_MASK;
319695f7df8SLionel Debieve 	pcr |= FMC2_PCR_TAR(tims.tar);
320695f7df8SLionel Debieve 
321695f7df8SLionel Debieve 	/* Set tset/twait/thold/thiz timings in common bank */
322695f7df8SLionel Debieve 	pmem = FMC2_PMEM_MEMSET(tims.tset_mem);
323695f7df8SLionel Debieve 	pmem |= FMC2_PMEM_MEMWAIT(tims.twait);
324695f7df8SLionel Debieve 	pmem |=	FMC2_PMEM_MEMHOLD(tims.thold_mem);
325695f7df8SLionel Debieve 	pmem |= FMC2_PMEM_MEMHIZ(tims.thiz);
326695f7df8SLionel Debieve 
327695f7df8SLionel Debieve 	/* Set tset/twait/thold/thiz timings in attribute bank */
328695f7df8SLionel Debieve 	patt = FMC2_PATT_ATTSET(tims.tset_att);
329695f7df8SLionel Debieve 	patt |= FMC2_PATT_ATTWAIT(tims.twait);
330695f7df8SLionel Debieve 	patt |= FMC2_PATT_ATTHOLD(tims.thold_att);
331695f7df8SLionel Debieve 	patt |= FMC2_PATT_ATTHIZ(tims.thiz);
332695f7df8SLionel Debieve 
333695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
334695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PMEM, pmem);
335695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PATT, patt);
336695f7df8SLionel Debieve }
337695f7df8SLionel Debieve 
338695f7df8SLionel Debieve static void stm32_fmc2_set_buswidth_16(bool set)
339695f7df8SLionel Debieve {
340695f7df8SLionel Debieve 	mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_PWID_MASK,
341695f7df8SLionel Debieve 			   (set ? FMC2_PCR_PWID(FMC2_PCR_PWID_16) : 0U));
342695f7df8SLionel Debieve }
343695f7df8SLionel Debieve 
344695f7df8SLionel Debieve static void stm32_fmc2_set_ecc(bool enable)
345695f7df8SLionel Debieve {
346695f7df8SLionel Debieve 	mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_ECCEN,
347695f7df8SLionel Debieve 			   (enable ? FMC2_PCR_ECCEN : 0U));
348695f7df8SLionel Debieve }
349695f7df8SLionel Debieve 
350695f7df8SLionel Debieve static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
351695f7df8SLionel Debieve 				  uint8_t *ecc)
352695f7df8SLionel Debieve {
353695f7df8SLionel Debieve 	uint8_t xor_ecc_ones;
354695f7df8SLionel Debieve 	uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b;
355695f7df8SLionel Debieve 	union {
356695f7df8SLionel Debieve 		uint32_t val;
357695f7df8SLionel Debieve 		uint8_t  bytes[4];
358695f7df8SLionel Debieve 	} xor_ecc;
359695f7df8SLionel Debieve 
360695f7df8SLionel Debieve 	/* Page size--------ECC_Code Size
361695f7df8SLionel Debieve 	 * 256---------------22 bits LSB  (ECC_CODE & 0x003FFFFF)
362695f7df8SLionel Debieve 	 * 512---------------24 bits      (ECC_CODE & 0x00FFFFFF)
363695f7df8SLionel Debieve 	 * 1024--------------26 bits      (ECC_CODE & 0x03FFFFFF)
364695f7df8SLionel Debieve 	 * 2048--------------28 bits      (ECC_CODE & 0x0FFFFFFF)
365695f7df8SLionel Debieve 	 * 4096--------------30 bits      (ECC_CODE & 0x3FFFFFFF)
366695f7df8SLionel Debieve 	 * 8192--------------32 bits      (ECC_CODE & 0xFFFFFFFF)
367695f7df8SLionel Debieve 	 */
368695f7df8SLionel Debieve 
369695f7df8SLionel Debieve 	/* For Page size 512, ECC_Code size 24 bits */
370695f7df8SLionel Debieve 	xor_ecc_1b = ecc[0] ^ eccbuffer[0];
371695f7df8SLionel Debieve 	xor_ecc_2b = ecc[1] ^ eccbuffer[1];
372695f7df8SLionel Debieve 	xor_ecc_3b = ecc[2] ^ eccbuffer[2];
373695f7df8SLionel Debieve 
3749fe181c6SYann Gautier 	xor_ecc.val = 0U;
375695f7df8SLionel Debieve 	xor_ecc.bytes[2] = xor_ecc_3b;
376695f7df8SLionel Debieve 	xor_ecc.bytes[1] = xor_ecc_2b;
377695f7df8SLionel Debieve 	xor_ecc.bytes[0] = xor_ecc_1b;
378695f7df8SLionel Debieve 
379695f7df8SLionel Debieve 	if (xor_ecc.val == 0U) {
380695f7df8SLionel Debieve 		return 0; /* No Error */
381695f7df8SLionel Debieve 	}
382695f7df8SLionel Debieve 
383695f7df8SLionel Debieve 	xor_ecc_ones = __builtin_popcount(xor_ecc.val);
384695f7df8SLionel Debieve 	if (xor_ecc_ones < 23U) {
385695f7df8SLionel Debieve 		if (xor_ecc_ones == 12U) {
386695f7df8SLionel Debieve 			uint16_t bit_address, byte_address;
387695f7df8SLionel Debieve 
388695f7df8SLionel Debieve 			/* Correctable ERROR */
389695f7df8SLionel Debieve 			bit_address = ((xor_ecc_1b >> 1) & BIT(0)) |
390695f7df8SLionel Debieve 				      ((xor_ecc_1b >> 2) & BIT(1)) |
391695f7df8SLionel Debieve 				      ((xor_ecc_1b >> 3) & BIT(2));
392695f7df8SLionel Debieve 
393695f7df8SLionel Debieve 			byte_address = ((xor_ecc_1b >> 7) & BIT(0)) |
394695f7df8SLionel Debieve 				       ((xor_ecc_2b) & BIT(1)) |
395695f7df8SLionel Debieve 				       ((xor_ecc_2b >> 1) & BIT(2)) |
396695f7df8SLionel Debieve 				       ((xor_ecc_2b >> 2) & BIT(3)) |
397695f7df8SLionel Debieve 				       ((xor_ecc_2b >> 3) & BIT(4)) |
398695f7df8SLionel Debieve 				       ((xor_ecc_3b << 4) & BIT(5)) |
399695f7df8SLionel Debieve 				       ((xor_ecc_3b << 3) & BIT(6)) |
400695f7df8SLionel Debieve 				       ((xor_ecc_3b << 2) & BIT(7)) |
401695f7df8SLionel Debieve 				       ((xor_ecc_3b << 1) & BIT(8));
402695f7df8SLionel Debieve 
403695f7df8SLionel Debieve 			/* Correct bit error in the data */
404695f7df8SLionel Debieve 			buffer[byte_address] =
405695f7df8SLionel Debieve 				buffer[byte_address] ^ BIT(bit_address);
406695f7df8SLionel Debieve 			VERBOSE("Hamming: 1 ECC error corrected\n");
407695f7df8SLionel Debieve 
408695f7df8SLionel Debieve 			return 0;
409695f7df8SLionel Debieve 		}
410695f7df8SLionel Debieve 
411695f7df8SLionel Debieve 		/* Non Correctable ERROR */
412695f7df8SLionel Debieve 		ERROR("%s: Uncorrectable ECC Errors\n", __func__);
413695f7df8SLionel Debieve 		return -1;
414695f7df8SLionel Debieve 	}
415695f7df8SLionel Debieve 
416695f7df8SLionel Debieve 	/* ECC ERROR */
417695f7df8SLionel Debieve 	ERROR("%s: Hamming correction error\n", __func__);
418695f7df8SLionel Debieve 	return -1;
419695f7df8SLionel Debieve }
420695f7df8SLionel Debieve 
421695f7df8SLionel Debieve 
422695f7df8SLionel Debieve static int stm32_fmc2_ham_calculate(uint8_t *buffer, uint8_t *ecc)
423695f7df8SLionel Debieve {
424695f7df8SLionel Debieve 	uint32_t heccr;
425695f7df8SLionel Debieve 	uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
426695f7df8SLionel Debieve 
427695f7df8SLionel Debieve 	while ((mmio_read_32(fmc2_base() + FMC2_SR) & FMC2_SR_NWRF) == 0U) {
428695f7df8SLionel Debieve 		if (timeout_elapsed(timeout)) {
429695f7df8SLionel Debieve 			return -ETIMEDOUT;
430695f7df8SLionel Debieve 		}
431695f7df8SLionel Debieve 	}
432695f7df8SLionel Debieve 
433695f7df8SLionel Debieve 	heccr = mmio_read_32(fmc2_base() + FMC2_HECCR);
434695f7df8SLionel Debieve 
435695f7df8SLionel Debieve 	ecc[0] = heccr;
436695f7df8SLionel Debieve 	ecc[1] = heccr >> 8;
437695f7df8SLionel Debieve 	ecc[2] = heccr >> 16;
438695f7df8SLionel Debieve 
439695f7df8SLionel Debieve 	/* Disable ECC */
440695f7df8SLionel Debieve 	stm32_fmc2_set_ecc(false);
441695f7df8SLionel Debieve 
442695f7df8SLionel Debieve 	return 0;
443695f7df8SLionel Debieve }
444695f7df8SLionel Debieve 
445695f7df8SLionel Debieve static int stm32_fmc2_bch_correct(uint8_t *buffer, unsigned int eccsize)
446695f7df8SLionel Debieve {
447695f7df8SLionel Debieve 	uint32_t bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4;
448695f7df8SLionel Debieve 	uint16_t pos[8];
449695f7df8SLionel Debieve 	int i, den;
450695f7df8SLionel Debieve 	uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
451695f7df8SLionel Debieve 
452695f7df8SLionel Debieve 	while ((mmio_read_32(fmc2_base() + FMC2_BCHISR) &
453695f7df8SLionel Debieve 		FMC2_BCHISR_DERF) == 0U) {
454695f7df8SLionel Debieve 		if (timeout_elapsed(timeout)) {
455695f7df8SLionel Debieve 			return -ETIMEDOUT;
456695f7df8SLionel Debieve 		}
457695f7df8SLionel Debieve 	}
458695f7df8SLionel Debieve 
459695f7df8SLionel Debieve 	bchdsr0 = mmio_read_32(fmc2_base() + FMC2_BCHDSR0);
460695f7df8SLionel Debieve 	bchdsr1 = mmio_read_32(fmc2_base() + FMC2_BCHDSR1);
461695f7df8SLionel Debieve 	bchdsr2 = mmio_read_32(fmc2_base() + FMC2_BCHDSR2);
462695f7df8SLionel Debieve 	bchdsr3 = mmio_read_32(fmc2_base() + FMC2_BCHDSR3);
463695f7df8SLionel Debieve 	bchdsr4 = mmio_read_32(fmc2_base() + FMC2_BCHDSR4);
464695f7df8SLionel Debieve 
465695f7df8SLionel Debieve 	/* Disable ECC */
466695f7df8SLionel Debieve 	stm32_fmc2_set_ecc(false);
467695f7df8SLionel Debieve 
468695f7df8SLionel Debieve 	/* No error found */
469695f7df8SLionel Debieve 	if ((bchdsr0 & FMC2_BCHDSR0_DEF) == 0U) {
470695f7df8SLionel Debieve 		return 0;
471695f7df8SLionel Debieve 	}
472695f7df8SLionel Debieve 
473695f7df8SLionel Debieve 	/* Too many errors detected */
474695f7df8SLionel Debieve 	if ((bchdsr0 & FMC2_BCHDSR0_DUE) != 0U) {
475695f7df8SLionel Debieve 		return -EBADMSG;
476695f7df8SLionel Debieve 	}
477695f7df8SLionel Debieve 
478695f7df8SLionel Debieve 	pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK;
479695f7df8SLionel Debieve 	pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT;
480695f7df8SLionel Debieve 	pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK;
481695f7df8SLionel Debieve 	pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT;
482695f7df8SLionel Debieve 	pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK;
483695f7df8SLionel Debieve 	pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT;
484695f7df8SLionel Debieve 	pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK;
485695f7df8SLionel Debieve 	pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT;
486695f7df8SLionel Debieve 
487695f7df8SLionel Debieve 	den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT;
488695f7df8SLionel Debieve 	for (i = 0; i < den; i++) {
489695f7df8SLionel Debieve 		if (pos[i] < (eccsize * 8U)) {
490695f7df8SLionel Debieve 			uint8_t bitmask = BIT(pos[i] % 8U);
491695f7df8SLionel Debieve 			uint32_t offset = pos[i] / 8U;
492695f7df8SLionel Debieve 
493695f7df8SLionel Debieve 			*(buffer + offset) ^= bitmask;
494695f7df8SLionel Debieve 		}
495695f7df8SLionel Debieve 	}
496695f7df8SLionel Debieve 
497695f7df8SLionel Debieve 	return 0;
498695f7df8SLionel Debieve }
499695f7df8SLionel Debieve 
500695f7df8SLionel Debieve static void stm32_fmc2_hwctl(struct nand_device *nand)
501695f7df8SLionel Debieve {
502695f7df8SLionel Debieve 	stm32_fmc2_set_ecc(false);
503695f7df8SLionel Debieve 
504695f7df8SLionel Debieve 	if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
505695f7df8SLionel Debieve 		mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
506*44966000SLionel Debieve 		mmio_write_32(fmc2_base() + FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
507695f7df8SLionel Debieve 	}
508695f7df8SLionel Debieve 
509695f7df8SLionel Debieve 	stm32_fmc2_set_ecc(true);
510695f7df8SLionel Debieve }
511695f7df8SLionel Debieve 
512695f7df8SLionel Debieve static int stm32_fmc2_read_page(struct nand_device *nand,
513695f7df8SLionel Debieve 				unsigned int page, uintptr_t buffer)
514695f7df8SLionel Debieve {
515695f7df8SLionel Debieve 	unsigned int eccsize = nand->ecc.size;
516695f7df8SLionel Debieve 	unsigned int eccbytes = nand->ecc.bytes;
517695f7df8SLionel Debieve 	unsigned int eccsteps = nand->page_size / eccsize;
518695f7df8SLionel Debieve 	uint8_t ecc_corr[FMC2_MAX_ECC_BYTES];
519695f7df8SLionel Debieve 	uint8_t ecc_cal[FMC2_MAX_ECC_BYTES] = {0U};
520695f7df8SLionel Debieve 	uint8_t *p;
521695f7df8SLionel Debieve 	unsigned int i;
522695f7df8SLionel Debieve 	unsigned int s;
523695f7df8SLionel Debieve 	int ret;
524695f7df8SLionel Debieve 
525695f7df8SLionel Debieve 	VERBOSE(">%s page %i buffer %lx\n", __func__, page, buffer);
526695f7df8SLionel Debieve 
527695f7df8SLionel Debieve 	ret = nand_read_page_cmd(page, 0U, 0U, 0U);
528695f7df8SLionel Debieve 	if (ret != 0) {
529695f7df8SLionel Debieve 		return ret;
530695f7df8SLionel Debieve 	}
531695f7df8SLionel Debieve 
532695f7df8SLionel Debieve 	for (s = 0U, i = nand->page_size + FMC2_BBM_LEN, p = (uint8_t *)buffer;
533695f7df8SLionel Debieve 	     s < eccsteps;
534695f7df8SLionel Debieve 	     s++, i += eccbytes, p += eccsize) {
535695f7df8SLionel Debieve 		stm32_fmc2_hwctl(nand);
536695f7df8SLionel Debieve 
537695f7df8SLionel Debieve 		/* Read the NAND page sector (512 bytes) */
538695f7df8SLionel Debieve 		ret = nand_change_read_column_cmd(s * eccsize, (uintptr_t)p,
539695f7df8SLionel Debieve 						  eccsize);
540695f7df8SLionel Debieve 		if (ret != 0) {
541695f7df8SLionel Debieve 			return ret;
542695f7df8SLionel Debieve 		}
543695f7df8SLionel Debieve 
544695f7df8SLionel Debieve 		if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
545695f7df8SLionel Debieve 			ret = stm32_fmc2_ham_calculate(p, ecc_cal);
546695f7df8SLionel Debieve 			if (ret != 0) {
547695f7df8SLionel Debieve 				return ret;
548695f7df8SLionel Debieve 			}
549695f7df8SLionel Debieve 		}
550695f7df8SLionel Debieve 
551695f7df8SLionel Debieve 		/* Read the corresponding ECC bytes */
552695f7df8SLionel Debieve 		ret = nand_change_read_column_cmd(i, (uintptr_t)ecc_corr,
553695f7df8SLionel Debieve 						  eccbytes);
554695f7df8SLionel Debieve 		if (ret != 0) {
555695f7df8SLionel Debieve 			return ret;
556695f7df8SLionel Debieve 		}
557695f7df8SLionel Debieve 
558695f7df8SLionel Debieve 		/* Correct the data */
559695f7df8SLionel Debieve 		if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
560695f7df8SLionel Debieve 			ret = stm32_fmc2_ham_correct(p, ecc_corr, ecc_cal);
561695f7df8SLionel Debieve 		} else {
562695f7df8SLionel Debieve 			ret = stm32_fmc2_bch_correct(p, eccsize);
563695f7df8SLionel Debieve 		}
564695f7df8SLionel Debieve 
565695f7df8SLionel Debieve 		if (ret != 0) {
566695f7df8SLionel Debieve 			return ret;
567695f7df8SLionel Debieve 		}
568695f7df8SLionel Debieve 	}
569695f7df8SLionel Debieve 
570695f7df8SLionel Debieve 	return 0;
571695f7df8SLionel Debieve }
572695f7df8SLionel Debieve 
573695f7df8SLionel Debieve static void stm32_fmc2_read_data(struct nand_device *nand,
574695f7df8SLionel Debieve 				 uint8_t *buff, unsigned int length,
575695f7df8SLionel Debieve 				 bool use_bus8)
576695f7df8SLionel Debieve {
577695f7df8SLionel Debieve 	uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
578695f7df8SLionel Debieve 
579695f7df8SLionel Debieve 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
580695f7df8SLionel Debieve 		stm32_fmc2_set_buswidth_16(false);
581695f7df8SLionel Debieve 	}
582695f7df8SLionel Debieve 
583695f7df8SLionel Debieve 	if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
584695f7df8SLionel Debieve 		*buff = mmio_read_8(data_base);
585695f7df8SLionel Debieve 		buff += sizeof(uint8_t);
586695f7df8SLionel Debieve 		length -= sizeof(uint8_t);
587695f7df8SLionel Debieve 	}
588695f7df8SLionel Debieve 
589695f7df8SLionel Debieve 	if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
590695f7df8SLionel Debieve 	    (length >= sizeof(uint16_t))) {
591695f7df8SLionel Debieve 		*(uint16_t *)buff = mmio_read_16(data_base);
592695f7df8SLionel Debieve 		buff += sizeof(uint16_t);
593695f7df8SLionel Debieve 		length -= sizeof(uint16_t);
594695f7df8SLionel Debieve 	}
595695f7df8SLionel Debieve 
596695f7df8SLionel Debieve 	/* 32bit aligned */
597695f7df8SLionel Debieve 	while (length >= sizeof(uint32_t)) {
598695f7df8SLionel Debieve 		*(uint32_t *)buff = mmio_read_32(data_base);
599695f7df8SLionel Debieve 		buff += sizeof(uint32_t);
600695f7df8SLionel Debieve 		length -= sizeof(uint32_t);
601695f7df8SLionel Debieve 	}
602695f7df8SLionel Debieve 
603695f7df8SLionel Debieve 	/* Read remaining bytes */
604695f7df8SLionel Debieve 	if (length >= sizeof(uint16_t)) {
605695f7df8SLionel Debieve 		*(uint16_t *)buff = mmio_read_16(data_base);
606695f7df8SLionel Debieve 		buff += sizeof(uint16_t);
607695f7df8SLionel Debieve 		length -= sizeof(uint16_t);
608695f7df8SLionel Debieve 	}
609695f7df8SLionel Debieve 
610695f7df8SLionel Debieve 	if (length != 0U) {
611695f7df8SLionel Debieve 		*buff = mmio_read_8(data_base);
612695f7df8SLionel Debieve 	}
613695f7df8SLionel Debieve 
614695f7df8SLionel Debieve 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
615695f7df8SLionel Debieve 		/* Reconfigure bus width to 16-bit */
616695f7df8SLionel Debieve 		stm32_fmc2_set_buswidth_16(true);
617695f7df8SLionel Debieve 	}
618695f7df8SLionel Debieve }
619695f7df8SLionel Debieve 
620695f7df8SLionel Debieve static void stm32_fmc2_write_data(struct nand_device *nand,
621695f7df8SLionel Debieve 				  uint8_t *buff, unsigned int length,
622695f7df8SLionel Debieve 				  bool use_bus8)
623695f7df8SLionel Debieve {
624695f7df8SLionel Debieve 	uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
625695f7df8SLionel Debieve 
626695f7df8SLionel Debieve 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
627695f7df8SLionel Debieve 		/* Reconfigure bus width to 8-bit */
628695f7df8SLionel Debieve 		stm32_fmc2_set_buswidth_16(false);
629695f7df8SLionel Debieve 	}
630695f7df8SLionel Debieve 
631695f7df8SLionel Debieve 	if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
632695f7df8SLionel Debieve 		mmio_write_8(data_base, *buff);
633695f7df8SLionel Debieve 		buff += sizeof(uint8_t);
634695f7df8SLionel Debieve 		length -= sizeof(uint8_t);
635695f7df8SLionel Debieve 	}
636695f7df8SLionel Debieve 
637695f7df8SLionel Debieve 	if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
638695f7df8SLionel Debieve 	    (length >= sizeof(uint16_t))) {
639695f7df8SLionel Debieve 		mmio_write_16(data_base, *(uint16_t *)buff);
640695f7df8SLionel Debieve 		buff += sizeof(uint16_t);
641695f7df8SLionel Debieve 		length -= sizeof(uint16_t);
642695f7df8SLionel Debieve 	}
643695f7df8SLionel Debieve 
644695f7df8SLionel Debieve 	/* 32bits aligned */
645695f7df8SLionel Debieve 	while (length >= sizeof(uint32_t)) {
646695f7df8SLionel Debieve 		mmio_write_32(data_base, *(uint32_t *)buff);
647695f7df8SLionel Debieve 		buff += sizeof(uint32_t);
648695f7df8SLionel Debieve 		length -= sizeof(uint32_t);
649695f7df8SLionel Debieve 	}
650695f7df8SLionel Debieve 
651695f7df8SLionel Debieve 	/* Read remaining bytes */
652695f7df8SLionel Debieve 	if (length >= sizeof(uint16_t)) {
653695f7df8SLionel Debieve 		mmio_write_16(data_base, *(uint16_t *)buff);
654695f7df8SLionel Debieve 		buff += sizeof(uint16_t);
655695f7df8SLionel Debieve 		length -= sizeof(uint16_t);
656695f7df8SLionel Debieve 	}
657695f7df8SLionel Debieve 
658695f7df8SLionel Debieve 	if (length != 0U) {
659695f7df8SLionel Debieve 		mmio_write_8(data_base, *buff);
660695f7df8SLionel Debieve 	}
661695f7df8SLionel Debieve 
662695f7df8SLionel Debieve 	if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
663695f7df8SLionel Debieve 		/* Reconfigure bus width to 16-bit */
664695f7df8SLionel Debieve 		stm32_fmc2_set_buswidth_16(true);
665695f7df8SLionel Debieve 	}
666695f7df8SLionel Debieve }
667695f7df8SLionel Debieve 
668695f7df8SLionel Debieve static void stm32_fmc2_ctrl_init(void)
669695f7df8SLionel Debieve {
670695f7df8SLionel Debieve 	uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
671695f7df8SLionel Debieve 	uint32_t bcr1 = mmio_read_32(fmc2_base() + FMC2_BCR1);
672695f7df8SLionel Debieve 
673695f7df8SLionel Debieve 	/* Enable wait feature and NAND flash memory bank */
674695f7df8SLionel Debieve 	pcr |= FMC2_PCR_PWAITEN;
675695f7df8SLionel Debieve 	pcr |= FMC2_PCR_PBKEN;
676695f7df8SLionel Debieve 
677695f7df8SLionel Debieve 	/* Set buswidth to 8 bits mode for identification */
678695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_PWID_MASK;
679695f7df8SLionel Debieve 
680695f7df8SLionel Debieve 	/* ECC logic is disabled */
681695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_ECCEN;
682695f7df8SLionel Debieve 
683695f7df8SLionel Debieve 	/* Default mode */
684695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_ECCALG;
685695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_BCHECC;
686695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_WEN;
687695f7df8SLionel Debieve 
688695f7df8SLionel Debieve 	/* Set default ECC sector size */
689695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_ECCSS_MASK;
690695f7df8SLionel Debieve 	pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
691695f7df8SLionel Debieve 
692695f7df8SLionel Debieve 	/* Set default TCLR/TAR timings */
693695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_TCLR_MASK;
694695f7df8SLionel Debieve 	pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT);
695695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_TAR_MASK;
696695f7df8SLionel Debieve 	pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT);
697695f7df8SLionel Debieve 
698695f7df8SLionel Debieve 	/* Enable FMC2 controller */
699695f7df8SLionel Debieve 	bcr1 |= FMC2_BCR1_FMC2EN;
700695f7df8SLionel Debieve 
701695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_BCR1, bcr1);
702695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
703695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PMEM, FMC2_PMEM_DEFAULT);
704695f7df8SLionel Debieve 	mmio_write_32(fmc2_base() + FMC2_PATT, FMC2_PATT_DEFAULT);
705695f7df8SLionel Debieve }
706695f7df8SLionel Debieve 
707695f7df8SLionel Debieve static int stm32_fmc2_exec(struct nand_req *req)
708695f7df8SLionel Debieve {
709695f7df8SLionel Debieve 	int ret = 0;
710695f7df8SLionel Debieve 
711695f7df8SLionel Debieve 	switch (req->type & NAND_REQ_MASK) {
712695f7df8SLionel Debieve 	case NAND_REQ_CMD:
713695f7df8SLionel Debieve 		VERBOSE("Write CMD %x\n", (uint8_t)req->type);
714695f7df8SLionel Debieve 		mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].cmd_base,
715695f7df8SLionel Debieve 			     (uint8_t)req->type);
716695f7df8SLionel Debieve 		break;
717695f7df8SLionel Debieve 	case NAND_REQ_ADDR:
718695f7df8SLionel Debieve 		VERBOSE("Write ADDR %x\n", *(req->addr));
719695f7df8SLionel Debieve 		mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].addr_base,
720695f7df8SLionel Debieve 			     *(req->addr));
721695f7df8SLionel Debieve 		break;
722695f7df8SLionel Debieve 	case NAND_REQ_DATAIN:
723695f7df8SLionel Debieve 		VERBOSE("Read data\n");
724695f7df8SLionel Debieve 		stm32_fmc2_read_data(req->nand, req->addr, req->length,
725695f7df8SLionel Debieve 				     ((req->type & NAND_REQ_BUS_WIDTH_8) !=
726695f7df8SLionel Debieve 				      0U));
727695f7df8SLionel Debieve 		break;
728695f7df8SLionel Debieve 	case NAND_REQ_DATAOUT:
729695f7df8SLionel Debieve 		VERBOSE("Write data\n");
730695f7df8SLionel Debieve 		stm32_fmc2_write_data(req->nand, req->addr, req->length,
731695f7df8SLionel Debieve 				      ((req->type & NAND_REQ_BUS_WIDTH_8) !=
732695f7df8SLionel Debieve 				      0U));
733695f7df8SLionel Debieve 		break;
734695f7df8SLionel Debieve 	case NAND_REQ_WAIT:
735695f7df8SLionel Debieve 		VERBOSE("WAIT Ready\n");
736695f7df8SLionel Debieve 		ret = nand_wait_ready(req->delay_ms);
737695f7df8SLionel Debieve 		break;
738695f7df8SLionel Debieve 	default:
739695f7df8SLionel Debieve 		ret = -EINVAL;
740695f7df8SLionel Debieve 		break;
741695f7df8SLionel Debieve 	};
742695f7df8SLionel Debieve 
743695f7df8SLionel Debieve 	return ret;
744695f7df8SLionel Debieve }
745695f7df8SLionel Debieve 
746695f7df8SLionel Debieve static void stm32_fmc2_setup(struct nand_device *nand)
747695f7df8SLionel Debieve {
748695f7df8SLionel Debieve 	uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
749695f7df8SLionel Debieve 
750695f7df8SLionel Debieve 	/* Set buswidth */
751695f7df8SLionel Debieve 	pcr &= ~FMC2_PCR_PWID_MASK;
752695f7df8SLionel Debieve 	if (nand->buswidth == NAND_BUS_WIDTH_16) {
753695f7df8SLionel Debieve 		pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_16);
754695f7df8SLionel Debieve 	}
755695f7df8SLionel Debieve 
756695f7df8SLionel Debieve 	if (nand->ecc.mode == NAND_ECC_HW) {
757695f7df8SLionel Debieve 		nand->mtd_read_page = stm32_fmc2_read_page;
758695f7df8SLionel Debieve 
759695f7df8SLionel Debieve 		pcr &= ~FMC2_PCR_ECCALG;
760695f7df8SLionel Debieve 		pcr &= ~FMC2_PCR_BCHECC;
761695f7df8SLionel Debieve 
762695f7df8SLionel Debieve 		pcr &= ~FMC2_PCR_ECCSS_MASK;
763695f7df8SLionel Debieve 		pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
764695f7df8SLionel Debieve 
765695f7df8SLionel Debieve 		switch (nand->ecc.max_bit_corr) {
766695f7df8SLionel Debieve 		case FMC2_ECC_HAM:
767695f7df8SLionel Debieve 			nand->ecc.bytes = 3;
768695f7df8SLionel Debieve 			break;
769695f7df8SLionel Debieve 		case FMC2_ECC_BCH8:
770695f7df8SLionel Debieve 			pcr |= FMC2_PCR_ECCALG;
771695f7df8SLionel Debieve 			pcr |= FMC2_PCR_BCHECC;
772695f7df8SLionel Debieve 			nand->ecc.bytes = 13;
773695f7df8SLionel Debieve 			break;
774695f7df8SLionel Debieve 		default:
775695f7df8SLionel Debieve 			/* Use FMC2 ECC BCH4 */
776695f7df8SLionel Debieve 			pcr |= FMC2_PCR_ECCALG;
777695f7df8SLionel Debieve 			nand->ecc.bytes = 7;
778695f7df8SLionel Debieve 			break;
779695f7df8SLionel Debieve 		}
780695f7df8SLionel Debieve 
781695f7df8SLionel Debieve 		if ((nand->buswidth & NAND_BUS_WIDTH_16) != 0) {
782695f7df8SLionel Debieve 			nand->ecc.bytes++;
783695f7df8SLionel Debieve 		}
784695f7df8SLionel Debieve 	}
785695f7df8SLionel Debieve 
786695f7df8SLionel Debieve 	mmio_write_32(stm32_fmc2.reg_base + FMC2_PCR, pcr);
787695f7df8SLionel Debieve }
788695f7df8SLionel Debieve 
789695f7df8SLionel Debieve static const struct nand_ctrl_ops ctrl_ops = {
790695f7df8SLionel Debieve 	.setup = stm32_fmc2_setup,
791695f7df8SLionel Debieve 	.exec = stm32_fmc2_exec
792695f7df8SLionel Debieve };
793695f7df8SLionel Debieve 
794695f7df8SLionel Debieve int stm32_fmc2_init(void)
795695f7df8SLionel Debieve {
796695f7df8SLionel Debieve 	int fmc_node;
797695f7df8SLionel Debieve 	int fmc_subnode = 0;
798695f7df8SLionel Debieve 	int nchips = 0;
799695f7df8SLionel Debieve 	unsigned int i;
800695f7df8SLionel Debieve 	void *fdt = NULL;
801695f7df8SLionel Debieve 	const fdt32_t *cuint;
802695f7df8SLionel Debieve 	struct dt_node_info info;
80345c70e68SEtienne Carriere 	int ret;
804695f7df8SLionel Debieve 
805695f7df8SLionel Debieve 	if (fdt_get_address(&fdt) == 0) {
806695f7df8SLionel Debieve 		return -FDT_ERR_NOTFOUND;
807695f7df8SLionel Debieve 	}
808695f7df8SLionel Debieve 
809695f7df8SLionel Debieve 	fmc_node = dt_get_node(&info, -1, DT_FMC2_COMPAT);
810695f7df8SLionel Debieve 	if (fmc_node == -FDT_ERR_NOTFOUND) {
811695f7df8SLionel Debieve 		WARN("No FMC2 node found\n");
812695f7df8SLionel Debieve 		return fmc_node;
813695f7df8SLionel Debieve 	}
814695f7df8SLionel Debieve 
815695f7df8SLionel Debieve 	if (info.status == DT_DISABLED) {
816695f7df8SLionel Debieve 		return -FDT_ERR_NOTFOUND;
817695f7df8SLionel Debieve 	}
818695f7df8SLionel Debieve 
819695f7df8SLionel Debieve 	stm32_fmc2.reg_base = info.base;
820695f7df8SLionel Debieve 
821695f7df8SLionel Debieve 	if ((info.clock < 0) || (info.reset < 0)) {
822695f7df8SLionel Debieve 		return -FDT_ERR_BADVALUE;
823695f7df8SLionel Debieve 	}
824695f7df8SLionel Debieve 
825695f7df8SLionel Debieve 	stm32_fmc2.clock_id = (unsigned long)info.clock;
826695f7df8SLionel Debieve 	stm32_fmc2.reset_id = (unsigned int)info.reset;
827695f7df8SLionel Debieve 
828695f7df8SLionel Debieve 	cuint = fdt_getprop(fdt, fmc_node, "reg", NULL);
829695f7df8SLionel Debieve 	if (cuint == NULL) {
830695f7df8SLionel Debieve 		return -FDT_ERR_BADVALUE;
831695f7df8SLionel Debieve 	}
832695f7df8SLionel Debieve 
833695f7df8SLionel Debieve 	cuint += 2;
834695f7df8SLionel Debieve 
835695f7df8SLionel Debieve 	for (i = 0U; i < MAX_CS; i++) {
836695f7df8SLionel Debieve 		stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*cuint);
837695f7df8SLionel Debieve 		stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 2));
838695f7df8SLionel Debieve 		stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 4));
839695f7df8SLionel Debieve 		cuint += 6;
840695f7df8SLionel Debieve 	}
841695f7df8SLionel Debieve 
842695f7df8SLionel Debieve 	/* Pinctrl initialization */
843695f7df8SLionel Debieve 	if (dt_set_pinctrl_config(fmc_node) != 0) {
844695f7df8SLionel Debieve 		return -FDT_ERR_BADVALUE;
845695f7df8SLionel Debieve 	}
846695f7df8SLionel Debieve 
847695f7df8SLionel Debieve 	/* Parse flash nodes */
848695f7df8SLionel Debieve 	fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
849695f7df8SLionel Debieve 		nchips++;
850695f7df8SLionel Debieve 	}
851695f7df8SLionel Debieve 
852695f7df8SLionel Debieve 	if (nchips != 1) {
853695f7df8SLionel Debieve 		WARN("Only one SLC NAND device supported\n");
854695f7df8SLionel Debieve 		return -FDT_ERR_BADVALUE;
855695f7df8SLionel Debieve 	}
856695f7df8SLionel Debieve 
857695f7df8SLionel Debieve 	fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
858695f7df8SLionel Debieve 		/* Get chip select */
859695f7df8SLionel Debieve 		cuint = fdt_getprop(fdt, fmc_subnode, "reg", NULL);
860695f7df8SLionel Debieve 		if (cuint == NULL) {
861695f7df8SLionel Debieve 			WARN("Chip select not well defined\n");
862695f7df8SLionel Debieve 			return -FDT_ERR_BADVALUE;
863695f7df8SLionel Debieve 		}
864695f7df8SLionel Debieve 		stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
865695f7df8SLionel Debieve 		VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
866695f7df8SLionel Debieve 	}
867695f7df8SLionel Debieve 
868695f7df8SLionel Debieve 	/* Enable Clock */
869695f7df8SLionel Debieve 	stm32mp_clk_enable(stm32_fmc2.clock_id);
870695f7df8SLionel Debieve 
871695f7df8SLionel Debieve 	/* Reset IP */
87245c70e68SEtienne Carriere 	ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
87345c70e68SEtienne Carriere 	if (ret != 0) {
87445c70e68SEtienne Carriere 		panic();
87545c70e68SEtienne Carriere 	}
87645c70e68SEtienne Carriere 	ret = stm32mp_reset_deassert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
87745c70e68SEtienne Carriere 	if (ret != 0) {
87845c70e68SEtienne Carriere 		panic();
87945c70e68SEtienne Carriere 	}
880695f7df8SLionel Debieve 
881695f7df8SLionel Debieve 	/* Setup default IP registers */
882695f7df8SLionel Debieve 	stm32_fmc2_ctrl_init();
883695f7df8SLionel Debieve 
884695f7df8SLionel Debieve 	/* Setup default timings */
885695f7df8SLionel Debieve 	stm32_fmc2_nand_setup_timing();
886695f7df8SLionel Debieve 
887695f7df8SLionel Debieve 	/* Init NAND RAW framework */
888695f7df8SLionel Debieve 	nand_raw_ctrl_init(&ctrl_ops);
889695f7df8SLionel Debieve 
890695f7df8SLionel Debieve 	return 0;
891695f7df8SLionel Debieve }
892