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