xref: /openbmc/linux/drivers/memory/pl353-smc.c (revision fee10bd2)
1fee10bd2SNaga Sureshkumar Relli // SPDX-License-Identifier: GPL-2.0
2fee10bd2SNaga Sureshkumar Relli /*
3fee10bd2SNaga Sureshkumar Relli  * ARM PL353 SMC driver
4fee10bd2SNaga Sureshkumar Relli  *
5fee10bd2SNaga Sureshkumar Relli  * Copyright (C) 2012 - 2018 Xilinx, Inc
6fee10bd2SNaga Sureshkumar Relli  * Author: Punnaiah Choudary Kalluri <punnaiah@xilinx.com>
7fee10bd2SNaga Sureshkumar Relli  * Author: Naga Sureshkumar Relli <nagasure@xilinx.com>
8fee10bd2SNaga Sureshkumar Relli  */
9fee10bd2SNaga Sureshkumar Relli 
10fee10bd2SNaga Sureshkumar Relli #include <linux/clk.h>
11fee10bd2SNaga Sureshkumar Relli #include <linux/io.h>
12fee10bd2SNaga Sureshkumar Relli #include <linux/kernel.h>
13fee10bd2SNaga Sureshkumar Relli #include <linux/module.h>
14fee10bd2SNaga Sureshkumar Relli #include <linux/of_platform.h>
15fee10bd2SNaga Sureshkumar Relli #include <linux/platform_device.h>
16fee10bd2SNaga Sureshkumar Relli #include <linux/slab.h>
17fee10bd2SNaga Sureshkumar Relli #include <linux/pl353-smc.h>
18fee10bd2SNaga Sureshkumar Relli #include <linux/amba/bus.h>
19fee10bd2SNaga Sureshkumar Relli 
20fee10bd2SNaga Sureshkumar Relli /* Register definitions */
21fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_MEMC_STATUS_OFFS	0	/* Controller status reg, RO */
22fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_OFFS		0xC	/* Clear config reg, WO */
23fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_DIRECT_CMD_OFFS	0x10	/* Direct command reg, WO */
24fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_OFFS	0x14	/* Set cycles register, WO */
25fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_OPMODE_OFFS	0x18	/* Set opmode register, WO */
26fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_STATUS_OFFS	0x400	/* ECC status register */
27fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_OFFS	0x404	/* ECC mem config reg */
28fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCMD1_OFFS	0x408	/* ECC mem cmd1 reg */
29fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCMD2_OFFS	0x40C	/* ECC mem cmd2 reg */
30fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_VALUE0_OFFS	0x418	/* ECC value 0 reg */
31fee10bd2SNaga Sureshkumar Relli 
32fee10bd2SNaga Sureshkumar Relli /* Controller status register specific constants */
33fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT	6
34fee10bd2SNaga Sureshkumar Relli 
35fee10bd2SNaga Sureshkumar Relli /* Clear configuration register specific constants */
36fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_INT_CLR_1	0x10
37fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_ECC_INT_DIS_1	0x40
38fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_INT_DIS_1	0x2
39fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_DEFAULT_MASK	(PL353_SMC_CFG_CLR_INT_CLR_1 | \
40fee10bd2SNaga Sureshkumar Relli 					 PL353_SMC_CFG_CLR_ECC_INT_DIS_1 | \
41fee10bd2SNaga Sureshkumar Relli 					 PL353_SMC_CFG_CLR_INT_DIS_1)
42fee10bd2SNaga Sureshkumar Relli 
43fee10bd2SNaga Sureshkumar Relli /* Set cycles register specific constants */
44fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T0_MASK	0xF
45fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T0_SHIFT	0
46fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T1_MASK	0xF
47fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T1_SHIFT	4
48fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T2_MASK	0x7
49fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T2_SHIFT	8
50fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T3_MASK	0x7
51fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T3_SHIFT	11
52fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T4_MASK	0x7
53fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T4_SHIFT	14
54fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T5_MASK	0x7
55fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T5_SHIFT	17
56fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T6_MASK	0xF
57fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T6_SHIFT	20
58fee10bd2SNaga Sureshkumar Relli 
59fee10bd2SNaga Sureshkumar Relli /* ECC status register specific constants */
60fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_STATUS_BUSY	BIT(6)
61fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_REG_SIZE_OFFS	4
62fee10bd2SNaga Sureshkumar Relli 
63fee10bd2SNaga Sureshkumar Relli /* ECC memory config register specific constants */
64fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_MODE_MASK	0xC
65fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_MODE_SHIFT	2
66fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK	0xC
67fee10bd2SNaga Sureshkumar Relli 
68fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_DC_UPT_NAND_REGS	((4 << 23) |	/* CS: NAND chip */ \
69fee10bd2SNaga Sureshkumar Relli 				 (2 << 21))	/* UpdateRegs operation */
70fee10bd2SNaga Sureshkumar Relli 
71fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_CMD1	((0x80)       |	/* Write command */ \
72fee10bd2SNaga Sureshkumar Relli 				 (0 << 8)     |	/* Read command */ \
73fee10bd2SNaga Sureshkumar Relli 				 (0x30 << 16) |	/* Read End command */ \
74fee10bd2SNaga Sureshkumar Relli 				 (1 << 24))	/* Read End command calid */
75fee10bd2SNaga Sureshkumar Relli 
76fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_CMD2	((0x85)	      |	/* Write col change cmd */ \
77fee10bd2SNaga Sureshkumar Relli 				 (5 << 8)     |	/* Read col change cmd */ \
78fee10bd2SNaga Sureshkumar Relli 				 (0xE0 << 16) |	/* Read col change end cmd */ \
79fee10bd2SNaga Sureshkumar Relli 				 (1 << 24)) /* Read col change end cmd valid */
80fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_BUSY_TIMEOUT	(1 * HZ)
81fee10bd2SNaga Sureshkumar Relli /**
82fee10bd2SNaga Sureshkumar Relli  * struct pl353_smc_data - Private smc driver structure
83fee10bd2SNaga Sureshkumar Relli  * @memclk:		Pointer to the peripheral clock
84fee10bd2SNaga Sureshkumar Relli  * @aclk:		Pointer to the APER clock
85fee10bd2SNaga Sureshkumar Relli  */
86fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data {
87fee10bd2SNaga Sureshkumar Relli 	struct clk		*memclk;
88fee10bd2SNaga Sureshkumar Relli 	struct clk		*aclk;
89fee10bd2SNaga Sureshkumar Relli };
90fee10bd2SNaga Sureshkumar Relli 
91fee10bd2SNaga Sureshkumar Relli /* SMC virtual register base */
92fee10bd2SNaga Sureshkumar Relli static void __iomem *pl353_smc_base;
93fee10bd2SNaga Sureshkumar Relli 
94fee10bd2SNaga Sureshkumar Relli /**
95fee10bd2SNaga Sureshkumar Relli  * pl353_smc_set_buswidth - Set memory buswidth
96fee10bd2SNaga Sureshkumar Relli  * @bw: Memory buswidth (8 | 16)
97fee10bd2SNaga Sureshkumar Relli  * Return: 0 on success or negative errno.
98fee10bd2SNaga Sureshkumar Relli  */
99fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_buswidth(unsigned int bw)
100fee10bd2SNaga Sureshkumar Relli {
101fee10bd2SNaga Sureshkumar Relli 	if (bw != PL353_SMC_MEM_WIDTH_8  && bw != PL353_SMC_MEM_WIDTH_16)
102fee10bd2SNaga Sureshkumar Relli 		return -EINVAL;
103fee10bd2SNaga Sureshkumar Relli 
104fee10bd2SNaga Sureshkumar Relli 	writel(bw, pl353_smc_base + PL353_SMC_SET_OPMODE_OFFS);
105fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
106fee10bd2SNaga Sureshkumar Relli 	       PL353_SMC_DIRECT_CMD_OFFS);
107fee10bd2SNaga Sureshkumar Relli 
108fee10bd2SNaga Sureshkumar Relli 	return 0;
109fee10bd2SNaga Sureshkumar Relli }
110fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_buswidth);
111fee10bd2SNaga Sureshkumar Relli 
112fee10bd2SNaga Sureshkumar Relli /**
113fee10bd2SNaga Sureshkumar Relli  * pl353_smc_set_cycles - Set memory timing parameters
114fee10bd2SNaga Sureshkumar Relli  * @timings: NAND controller timing parameters
115fee10bd2SNaga Sureshkumar Relli  *
116fee10bd2SNaga Sureshkumar Relli  * Sets NAND chip specific timing parameters.
117fee10bd2SNaga Sureshkumar Relli  */
118fee10bd2SNaga Sureshkumar Relli void pl353_smc_set_cycles(u32 timings[])
119fee10bd2SNaga Sureshkumar Relli {
120fee10bd2SNaga Sureshkumar Relli 	/*
121fee10bd2SNaga Sureshkumar Relli 	 * Set write pulse timing. This one is easy to extract:
122fee10bd2SNaga Sureshkumar Relli 	 *
123fee10bd2SNaga Sureshkumar Relli 	 * NWE_PULSE = tWP
124fee10bd2SNaga Sureshkumar Relli 	 */
125fee10bd2SNaga Sureshkumar Relli 	timings[0] &= PL353_SMC_SET_CYCLES_T0_MASK;
126fee10bd2SNaga Sureshkumar Relli 	timings[1] = (timings[1] & PL353_SMC_SET_CYCLES_T1_MASK) <<
127fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T1_SHIFT;
128fee10bd2SNaga Sureshkumar Relli 	timings[2] = (timings[2]  & PL353_SMC_SET_CYCLES_T2_MASK) <<
129fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T2_SHIFT;
130fee10bd2SNaga Sureshkumar Relli 	timings[3] = (timings[3]  & PL353_SMC_SET_CYCLES_T3_MASK) <<
131fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T3_SHIFT;
132fee10bd2SNaga Sureshkumar Relli 	timings[4] = (timings[4] & PL353_SMC_SET_CYCLES_T4_MASK) <<
133fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T4_SHIFT;
134fee10bd2SNaga Sureshkumar Relli 	timings[5]  = (timings[5]  & PL353_SMC_SET_CYCLES_T5_MASK) <<
135fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T5_SHIFT;
136fee10bd2SNaga Sureshkumar Relli 	timings[6]  = (timings[6]  & PL353_SMC_SET_CYCLES_T6_MASK) <<
137fee10bd2SNaga Sureshkumar Relli 			PL353_SMC_SET_CYCLES_T6_SHIFT;
138fee10bd2SNaga Sureshkumar Relli 	timings[0] |= timings[1] | timings[2] | timings[3] |
139fee10bd2SNaga Sureshkumar Relli 			timings[4] | timings[5] | timings[6];
140fee10bd2SNaga Sureshkumar Relli 
141fee10bd2SNaga Sureshkumar Relli 	writel(timings[0], pl353_smc_base + PL353_SMC_SET_CYCLES_OFFS);
142fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
143fee10bd2SNaga Sureshkumar Relli 	       PL353_SMC_DIRECT_CMD_OFFS);
144fee10bd2SNaga Sureshkumar Relli }
145fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_cycles);
146fee10bd2SNaga Sureshkumar Relli 
147fee10bd2SNaga Sureshkumar Relli /**
148fee10bd2SNaga Sureshkumar Relli  * pl353_smc_ecc_is_busy - Read ecc busy flag
149fee10bd2SNaga Sureshkumar Relli  * Return: the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle
150fee10bd2SNaga Sureshkumar Relli  */
151fee10bd2SNaga Sureshkumar Relli bool pl353_smc_ecc_is_busy(void)
152fee10bd2SNaga Sureshkumar Relli {
153fee10bd2SNaga Sureshkumar Relli 	return ((readl(pl353_smc_base + PL353_SMC_ECC_STATUS_OFFS) &
154fee10bd2SNaga Sureshkumar Relli 		  PL353_SMC_ECC_STATUS_BUSY) == PL353_SMC_ECC_STATUS_BUSY);
155fee10bd2SNaga Sureshkumar Relli }
156fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_ecc_is_busy);
157fee10bd2SNaga Sureshkumar Relli 
158fee10bd2SNaga Sureshkumar Relli /**
159fee10bd2SNaga Sureshkumar Relli  * pl353_smc_get_ecc_val - Read ecc_valueN registers
160fee10bd2SNaga Sureshkumar Relli  * @ecc_reg: Index of the ecc_value reg (0..3)
161fee10bd2SNaga Sureshkumar Relli  * Return: the content of the requested ecc_value register.
162fee10bd2SNaga Sureshkumar Relli  *
163fee10bd2SNaga Sureshkumar Relli  * There are four valid ecc_value registers. The argument is truncated to stay
164fee10bd2SNaga Sureshkumar Relli  * within this valid boundary.
165fee10bd2SNaga Sureshkumar Relli  */
166fee10bd2SNaga Sureshkumar Relli u32 pl353_smc_get_ecc_val(int ecc_reg)
167fee10bd2SNaga Sureshkumar Relli {
168fee10bd2SNaga Sureshkumar Relli 	u32 addr, reg;
169fee10bd2SNaga Sureshkumar Relli 
170fee10bd2SNaga Sureshkumar Relli 	addr = PL353_SMC_ECC_VALUE0_OFFS +
171fee10bd2SNaga Sureshkumar Relli 		(ecc_reg * PL353_SMC_ECC_REG_SIZE_OFFS);
172fee10bd2SNaga Sureshkumar Relli 	reg = readl(pl353_smc_base + addr);
173fee10bd2SNaga Sureshkumar Relli 
174fee10bd2SNaga Sureshkumar Relli 	return reg;
175fee10bd2SNaga Sureshkumar Relli }
176fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_get_ecc_val);
177fee10bd2SNaga Sureshkumar Relli 
178fee10bd2SNaga Sureshkumar Relli /**
179fee10bd2SNaga Sureshkumar Relli  * pl353_smc_get_nand_int_status_raw - Get NAND interrupt status bit
180fee10bd2SNaga Sureshkumar Relli  * Return: the raw_int_status1 bit from the memc_status register
181fee10bd2SNaga Sureshkumar Relli  */
182fee10bd2SNaga Sureshkumar Relli int pl353_smc_get_nand_int_status_raw(void)
183fee10bd2SNaga Sureshkumar Relli {
184fee10bd2SNaga Sureshkumar Relli 	u32 reg;
185fee10bd2SNaga Sureshkumar Relli 
186fee10bd2SNaga Sureshkumar Relli 	reg = readl(pl353_smc_base + PL353_SMC_MEMC_STATUS_OFFS);
187fee10bd2SNaga Sureshkumar Relli 	reg >>= PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT;
188fee10bd2SNaga Sureshkumar Relli 	reg &= 1;
189fee10bd2SNaga Sureshkumar Relli 
190fee10bd2SNaga Sureshkumar Relli 	return reg;
191fee10bd2SNaga Sureshkumar Relli }
192fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_get_nand_int_status_raw);
193fee10bd2SNaga Sureshkumar Relli 
194fee10bd2SNaga Sureshkumar Relli /**
195fee10bd2SNaga Sureshkumar Relli  * pl353_smc_clr_nand_int - Clear NAND interrupt
196fee10bd2SNaga Sureshkumar Relli  */
197fee10bd2SNaga Sureshkumar Relli void pl353_smc_clr_nand_int(void)
198fee10bd2SNaga Sureshkumar Relli {
199fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_CFG_CLR_INT_CLR_1,
200fee10bd2SNaga Sureshkumar Relli 	       pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
201fee10bd2SNaga Sureshkumar Relli }
202fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_clr_nand_int);
203fee10bd2SNaga Sureshkumar Relli 
204fee10bd2SNaga Sureshkumar Relli /**
205fee10bd2SNaga Sureshkumar Relli  * pl353_smc_set_ecc_mode - Set SMC ECC mode
206fee10bd2SNaga Sureshkumar Relli  * @mode: ECC mode (BYPASS, APB, MEM)
207fee10bd2SNaga Sureshkumar Relli  * Return: 0 on success or negative errno.
208fee10bd2SNaga Sureshkumar Relli  */
209fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_ecc_mode(enum pl353_smc_ecc_mode mode)
210fee10bd2SNaga Sureshkumar Relli {
211fee10bd2SNaga Sureshkumar Relli 	u32 reg;
212fee10bd2SNaga Sureshkumar Relli 	int ret = 0;
213fee10bd2SNaga Sureshkumar Relli 
214fee10bd2SNaga Sureshkumar Relli 	switch (mode) {
215fee10bd2SNaga Sureshkumar Relli 	case PL353_SMC_ECCMODE_BYPASS:
216fee10bd2SNaga Sureshkumar Relli 	case PL353_SMC_ECCMODE_APB:
217fee10bd2SNaga Sureshkumar Relli 	case PL353_SMC_ECCMODE_MEM:
218fee10bd2SNaga Sureshkumar Relli 
219fee10bd2SNaga Sureshkumar Relli 		reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
220fee10bd2SNaga Sureshkumar Relli 		reg &= ~PL353_SMC_ECC_MEMCFG_MODE_MASK;
221fee10bd2SNaga Sureshkumar Relli 		reg |= mode << PL353_SMC_ECC_MEMCFG_MODE_SHIFT;
222fee10bd2SNaga Sureshkumar Relli 		writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
223fee10bd2SNaga Sureshkumar Relli 
224fee10bd2SNaga Sureshkumar Relli 		break;
225fee10bd2SNaga Sureshkumar Relli 	default:
226fee10bd2SNaga Sureshkumar Relli 		ret = -EINVAL;
227fee10bd2SNaga Sureshkumar Relli 	}
228fee10bd2SNaga Sureshkumar Relli 
229fee10bd2SNaga Sureshkumar Relli 	return ret;
230fee10bd2SNaga Sureshkumar Relli }
231fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_mode);
232fee10bd2SNaga Sureshkumar Relli 
233fee10bd2SNaga Sureshkumar Relli /**
234fee10bd2SNaga Sureshkumar Relli  * pl353_smc_set_ecc_pg_size - Set SMC ECC page size
235fee10bd2SNaga Sureshkumar Relli  * @pg_sz: ECC page size
236fee10bd2SNaga Sureshkumar Relli  * Return: 0 on success or negative errno.
237fee10bd2SNaga Sureshkumar Relli  */
238fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_ecc_pg_size(unsigned int pg_sz)
239fee10bd2SNaga Sureshkumar Relli {
240fee10bd2SNaga Sureshkumar Relli 	u32 reg, sz;
241fee10bd2SNaga Sureshkumar Relli 
242fee10bd2SNaga Sureshkumar Relli 	switch (pg_sz) {
243fee10bd2SNaga Sureshkumar Relli 	case 0:
244fee10bd2SNaga Sureshkumar Relli 		sz = 0;
245fee10bd2SNaga Sureshkumar Relli 		break;
246fee10bd2SNaga Sureshkumar Relli 	case SZ_512:
247fee10bd2SNaga Sureshkumar Relli 		sz = 1;
248fee10bd2SNaga Sureshkumar Relli 		break;
249fee10bd2SNaga Sureshkumar Relli 	case SZ_1K:
250fee10bd2SNaga Sureshkumar Relli 		sz = 2;
251fee10bd2SNaga Sureshkumar Relli 		break;
252fee10bd2SNaga Sureshkumar Relli 	case SZ_2K:
253fee10bd2SNaga Sureshkumar Relli 		sz = 3;
254fee10bd2SNaga Sureshkumar Relli 		break;
255fee10bd2SNaga Sureshkumar Relli 	default:
256fee10bd2SNaga Sureshkumar Relli 		return -EINVAL;
257fee10bd2SNaga Sureshkumar Relli 	}
258fee10bd2SNaga Sureshkumar Relli 
259fee10bd2SNaga Sureshkumar Relli 	reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
260fee10bd2SNaga Sureshkumar Relli 	reg &= ~PL353_SMC_ECC_MEMCFG_PGSIZE_MASK;
261fee10bd2SNaga Sureshkumar Relli 	reg |= sz;
262fee10bd2SNaga Sureshkumar Relli 	writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
263fee10bd2SNaga Sureshkumar Relli 
264fee10bd2SNaga Sureshkumar Relli 	return 0;
265fee10bd2SNaga Sureshkumar Relli }
266fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_pg_size);
267fee10bd2SNaga Sureshkumar Relli 
268fee10bd2SNaga Sureshkumar Relli static int __maybe_unused pl353_smc_suspend(struct device *dev)
269fee10bd2SNaga Sureshkumar Relli {
270fee10bd2SNaga Sureshkumar Relli 	struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
271fee10bd2SNaga Sureshkumar Relli 
272fee10bd2SNaga Sureshkumar Relli 	clk_disable(pl353_smc->memclk);
273fee10bd2SNaga Sureshkumar Relli 	clk_disable(pl353_smc->aclk);
274fee10bd2SNaga Sureshkumar Relli 
275fee10bd2SNaga Sureshkumar Relli 	return 0;
276fee10bd2SNaga Sureshkumar Relli }
277fee10bd2SNaga Sureshkumar Relli 
278fee10bd2SNaga Sureshkumar Relli static int __maybe_unused pl353_smc_resume(struct device *dev)
279fee10bd2SNaga Sureshkumar Relli {
280fee10bd2SNaga Sureshkumar Relli 	int ret;
281fee10bd2SNaga Sureshkumar Relli 	struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
282fee10bd2SNaga Sureshkumar Relli 
283fee10bd2SNaga Sureshkumar Relli 	ret = clk_enable(pl353_smc->aclk);
284fee10bd2SNaga Sureshkumar Relli 	if (ret) {
285fee10bd2SNaga Sureshkumar Relli 		dev_err(dev, "Cannot enable axi domain clock.\n");
286fee10bd2SNaga Sureshkumar Relli 		return ret;
287fee10bd2SNaga Sureshkumar Relli 	}
288fee10bd2SNaga Sureshkumar Relli 
289fee10bd2SNaga Sureshkumar Relli 	ret = clk_enable(pl353_smc->memclk);
290fee10bd2SNaga Sureshkumar Relli 	if (ret) {
291fee10bd2SNaga Sureshkumar Relli 		dev_err(dev, "Cannot enable memory clock.\n");
292fee10bd2SNaga Sureshkumar Relli 		clk_disable(pl353_smc->aclk);
293fee10bd2SNaga Sureshkumar Relli 		return ret;
294fee10bd2SNaga Sureshkumar Relli 	}
295fee10bd2SNaga Sureshkumar Relli 
296fee10bd2SNaga Sureshkumar Relli 	return ret;
297fee10bd2SNaga Sureshkumar Relli }
298fee10bd2SNaga Sureshkumar Relli 
299fee10bd2SNaga Sureshkumar Relli static struct amba_driver pl353_smc_driver;
300fee10bd2SNaga Sureshkumar Relli 
301fee10bd2SNaga Sureshkumar Relli static SIMPLE_DEV_PM_OPS(pl353_smc_dev_pm_ops, pl353_smc_suspend,
302fee10bd2SNaga Sureshkumar Relli 			 pl353_smc_resume);
303fee10bd2SNaga Sureshkumar Relli 
304fee10bd2SNaga Sureshkumar Relli /**
305fee10bd2SNaga Sureshkumar Relli  * pl353_smc_init_nand_interface - Initialize the NAND interface
306fee10bd2SNaga Sureshkumar Relli  * @adev: Pointer to the amba_device struct
307fee10bd2SNaga Sureshkumar Relli  * @nand_node: Pointer to the pl353_nand device_node struct
308fee10bd2SNaga Sureshkumar Relli  */
309fee10bd2SNaga Sureshkumar Relli static void pl353_smc_init_nand_interface(struct amba_device *adev,
310fee10bd2SNaga Sureshkumar Relli 					  struct device_node *nand_node)
311fee10bd2SNaga Sureshkumar Relli {
312fee10bd2SNaga Sureshkumar Relli 	unsigned long timeout;
313fee10bd2SNaga Sureshkumar Relli 
314fee10bd2SNaga Sureshkumar Relli 	pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_8);
315fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_CFG_CLR_INT_CLR_1,
316fee10bd2SNaga Sureshkumar Relli 	       pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
317fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
318fee10bd2SNaga Sureshkumar Relli 	       PL353_SMC_DIRECT_CMD_OFFS);
319fee10bd2SNaga Sureshkumar Relli 
320fee10bd2SNaga Sureshkumar Relli 	timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT;
321fee10bd2SNaga Sureshkumar Relli 	/* Wait till the ECC operation is complete */
322fee10bd2SNaga Sureshkumar Relli 	do {
323fee10bd2SNaga Sureshkumar Relli 		if (pl353_smc_ecc_is_busy())
324fee10bd2SNaga Sureshkumar Relli 			cpu_relax();
325fee10bd2SNaga Sureshkumar Relli 		else
326fee10bd2SNaga Sureshkumar Relli 			break;
327fee10bd2SNaga Sureshkumar Relli 	} while (!time_after_eq(jiffies, timeout));
328fee10bd2SNaga Sureshkumar Relli 
329fee10bd2SNaga Sureshkumar Relli 	if (time_after_eq(jiffies, timeout))
330fee10bd2SNaga Sureshkumar Relli 		return;
331fee10bd2SNaga Sureshkumar Relli 
332fee10bd2SNaga Sureshkumar Relli 	writel(PL353_NAND_ECC_CMD1,
333fee10bd2SNaga Sureshkumar Relli 	       pl353_smc_base + PL353_SMC_ECC_MEMCMD1_OFFS);
334fee10bd2SNaga Sureshkumar Relli 	writel(PL353_NAND_ECC_CMD2,
335fee10bd2SNaga Sureshkumar Relli 	       pl353_smc_base + PL353_SMC_ECC_MEMCMD2_OFFS);
336fee10bd2SNaga Sureshkumar Relli }
337fee10bd2SNaga Sureshkumar Relli 
338fee10bd2SNaga Sureshkumar Relli static const struct of_device_id pl353_smc_supported_children[] = {
339fee10bd2SNaga Sureshkumar Relli 	{
340fee10bd2SNaga Sureshkumar Relli 		.compatible = "cfi-flash"
341fee10bd2SNaga Sureshkumar Relli 	},
342fee10bd2SNaga Sureshkumar Relli 	{
343fee10bd2SNaga Sureshkumar Relli 		.compatible = "arm,pl353-nand-r2p1",
344fee10bd2SNaga Sureshkumar Relli 		.data = pl353_smc_init_nand_interface
345fee10bd2SNaga Sureshkumar Relli 	},
346fee10bd2SNaga Sureshkumar Relli 	{}
347fee10bd2SNaga Sureshkumar Relli };
348fee10bd2SNaga Sureshkumar Relli 
349fee10bd2SNaga Sureshkumar Relli static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
350fee10bd2SNaga Sureshkumar Relli {
351fee10bd2SNaga Sureshkumar Relli 	struct pl353_smc_data *pl353_smc;
352fee10bd2SNaga Sureshkumar Relli 	struct device_node *child;
353fee10bd2SNaga Sureshkumar Relli 	struct resource *res;
354fee10bd2SNaga Sureshkumar Relli 	int err;
355fee10bd2SNaga Sureshkumar Relli 	struct device_node *of_node = adev->dev.of_node;
356fee10bd2SNaga Sureshkumar Relli 	static void (*init)(struct amba_device *adev,
357fee10bd2SNaga Sureshkumar Relli 			    struct device_node *nand_node);
358fee10bd2SNaga Sureshkumar Relli 	const struct of_device_id *match = NULL;
359fee10bd2SNaga Sureshkumar Relli 
360fee10bd2SNaga Sureshkumar Relli 	pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL);
361fee10bd2SNaga Sureshkumar Relli 	if (!pl353_smc)
362fee10bd2SNaga Sureshkumar Relli 		return -ENOMEM;
363fee10bd2SNaga Sureshkumar Relli 
364fee10bd2SNaga Sureshkumar Relli 	/* Get the NAND controller virtual address */
365fee10bd2SNaga Sureshkumar Relli 	res = &adev->res;
366fee10bd2SNaga Sureshkumar Relli 	pl353_smc_base = devm_ioremap_resource(&adev->dev, res);
367fee10bd2SNaga Sureshkumar Relli 	if (IS_ERR(pl353_smc_base))
368fee10bd2SNaga Sureshkumar Relli 		return PTR_ERR(pl353_smc_base);
369fee10bd2SNaga Sureshkumar Relli 
370fee10bd2SNaga Sureshkumar Relli 	pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk");
371fee10bd2SNaga Sureshkumar Relli 	if (IS_ERR(pl353_smc->aclk)) {
372fee10bd2SNaga Sureshkumar Relli 		dev_err(&adev->dev, "aclk clock not found.\n");
373fee10bd2SNaga Sureshkumar Relli 		return PTR_ERR(pl353_smc->aclk);
374fee10bd2SNaga Sureshkumar Relli 	}
375fee10bd2SNaga Sureshkumar Relli 
376fee10bd2SNaga Sureshkumar Relli 	pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk");
377fee10bd2SNaga Sureshkumar Relli 	if (IS_ERR(pl353_smc->memclk)) {
378fee10bd2SNaga Sureshkumar Relli 		dev_err(&adev->dev, "memclk clock not found.\n");
379fee10bd2SNaga Sureshkumar Relli 		return PTR_ERR(pl353_smc->memclk);
380fee10bd2SNaga Sureshkumar Relli 	}
381fee10bd2SNaga Sureshkumar Relli 
382fee10bd2SNaga Sureshkumar Relli 	err = clk_prepare_enable(pl353_smc->aclk);
383fee10bd2SNaga Sureshkumar Relli 	if (err) {
384fee10bd2SNaga Sureshkumar Relli 		dev_err(&adev->dev, "Unable to enable AXI clock.\n");
385fee10bd2SNaga Sureshkumar Relli 		return err;
386fee10bd2SNaga Sureshkumar Relli 	}
387fee10bd2SNaga Sureshkumar Relli 
388fee10bd2SNaga Sureshkumar Relli 	err = clk_prepare_enable(pl353_smc->memclk);
389fee10bd2SNaga Sureshkumar Relli 	if (err) {
390fee10bd2SNaga Sureshkumar Relli 		dev_err(&adev->dev, "Unable to enable memory clock.\n");
391fee10bd2SNaga Sureshkumar Relli 		goto out_clk_dis_aper;
392fee10bd2SNaga Sureshkumar Relli 	}
393fee10bd2SNaga Sureshkumar Relli 
394fee10bd2SNaga Sureshkumar Relli 	amba_set_drvdata(adev, pl353_smc);
395fee10bd2SNaga Sureshkumar Relli 
396fee10bd2SNaga Sureshkumar Relli 	/* clear interrupts */
397fee10bd2SNaga Sureshkumar Relli 	writel(PL353_SMC_CFG_CLR_DEFAULT_MASK,
398fee10bd2SNaga Sureshkumar Relli 	       pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
399fee10bd2SNaga Sureshkumar Relli 
400fee10bd2SNaga Sureshkumar Relli 	/* Find compatible children. Only a single child is supported */
401fee10bd2SNaga Sureshkumar Relli 	for_each_available_child_of_node(of_node, child) {
402fee10bd2SNaga Sureshkumar Relli 		match = of_match_node(pl353_smc_supported_children, child);
403fee10bd2SNaga Sureshkumar Relli 		if (!match) {
404fee10bd2SNaga Sureshkumar Relli 			dev_warn(&adev->dev, "unsupported child node\n");
405fee10bd2SNaga Sureshkumar Relli 			continue;
406fee10bd2SNaga Sureshkumar Relli 		}
407fee10bd2SNaga Sureshkumar Relli 		break;
408fee10bd2SNaga Sureshkumar Relli 	}
409fee10bd2SNaga Sureshkumar Relli 	if (!match) {
410fee10bd2SNaga Sureshkumar Relli 		dev_err(&adev->dev, "no matching children\n");
411fee10bd2SNaga Sureshkumar Relli 		goto out_clk_disable;
412fee10bd2SNaga Sureshkumar Relli 	}
413fee10bd2SNaga Sureshkumar Relli 
414fee10bd2SNaga Sureshkumar Relli 	init = match->data;
415fee10bd2SNaga Sureshkumar Relli 	if (init)
416fee10bd2SNaga Sureshkumar Relli 		init(adev, child);
417fee10bd2SNaga Sureshkumar Relli 	of_platform_device_create(child, NULL, &adev->dev);
418fee10bd2SNaga Sureshkumar Relli 
419fee10bd2SNaga Sureshkumar Relli 	return 0;
420fee10bd2SNaga Sureshkumar Relli 
421fee10bd2SNaga Sureshkumar Relli out_clk_disable:
422fee10bd2SNaga Sureshkumar Relli 	clk_disable_unprepare(pl353_smc->memclk);
423fee10bd2SNaga Sureshkumar Relli out_clk_dis_aper:
424fee10bd2SNaga Sureshkumar Relli 	clk_disable_unprepare(pl353_smc->aclk);
425fee10bd2SNaga Sureshkumar Relli 
426fee10bd2SNaga Sureshkumar Relli 	return err;
427fee10bd2SNaga Sureshkumar Relli }
428fee10bd2SNaga Sureshkumar Relli 
429fee10bd2SNaga Sureshkumar Relli static int pl353_smc_remove(struct amba_device *adev)
430fee10bd2SNaga Sureshkumar Relli {
431fee10bd2SNaga Sureshkumar Relli 	struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev);
432fee10bd2SNaga Sureshkumar Relli 
433fee10bd2SNaga Sureshkumar Relli 	clk_disable_unprepare(pl353_smc->memclk);
434fee10bd2SNaga Sureshkumar Relli 	clk_disable_unprepare(pl353_smc->aclk);
435fee10bd2SNaga Sureshkumar Relli 
436fee10bd2SNaga Sureshkumar Relli 	return 0;
437fee10bd2SNaga Sureshkumar Relli }
438fee10bd2SNaga Sureshkumar Relli 
439fee10bd2SNaga Sureshkumar Relli static const struct amba_id pl353_ids[] = {
440fee10bd2SNaga Sureshkumar Relli 	{
441fee10bd2SNaga Sureshkumar Relli 	.id = 0x00041353,
442fee10bd2SNaga Sureshkumar Relli 	.mask = 0x000fffff,
443fee10bd2SNaga Sureshkumar Relli 	},
444fee10bd2SNaga Sureshkumar Relli 	{ 0, 0 },
445fee10bd2SNaga Sureshkumar Relli };
446fee10bd2SNaga Sureshkumar Relli MODULE_DEVICE_TABLE(amba, pl353_ids);
447fee10bd2SNaga Sureshkumar Relli 
448fee10bd2SNaga Sureshkumar Relli static struct amba_driver pl353_smc_driver = {
449fee10bd2SNaga Sureshkumar Relli 	.drv = {
450fee10bd2SNaga Sureshkumar Relli 		.owner = THIS_MODULE,
451fee10bd2SNaga Sureshkumar Relli 		.name = "pl353-smc",
452fee10bd2SNaga Sureshkumar Relli 		.pm = &pl353_smc_dev_pm_ops,
453fee10bd2SNaga Sureshkumar Relli 	},
454fee10bd2SNaga Sureshkumar Relli 	.id_table = pl353_ids,
455fee10bd2SNaga Sureshkumar Relli 	.probe = pl353_smc_probe,
456fee10bd2SNaga Sureshkumar Relli 	.remove = pl353_smc_remove,
457fee10bd2SNaga Sureshkumar Relli };
458fee10bd2SNaga Sureshkumar Relli 
459fee10bd2SNaga Sureshkumar Relli module_amba_driver(pl353_smc_driver);
460fee10bd2SNaga Sureshkumar Relli 
461fee10bd2SNaga Sureshkumar Relli MODULE_AUTHOR("Xilinx, Inc.");
462fee10bd2SNaga Sureshkumar Relli MODULE_DESCRIPTION("ARM PL353 SMC Driver");
463fee10bd2SNaga Sureshkumar Relli MODULE_LICENSE("GPL");
464