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