aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Smith <alex.smith@imgtec.com>2015-03-09 10:29:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-26 18:51:36 -0400
commit911a88829725572820dad9a168e735c606a2fdcb (patch)
tree4ef6f905b90ac9746f4addc4e4335aa75e89014c
parentc0e6841653e9e96fea9e0f973a785bc66f45b532 (diff)
memory: jz4780-nemc: driver for the NEMC on JZ4780 SoCs
Add a driver for the NAND/External Memory Controller (NEMC) on JZ4780 and later SoCs. The primary function of this driver is to configure parameters, such as timings, for external memory devices using data supplied in the device tree. Devices connected to the NEMC are represented in the DT as children of the NEMC node, the driver uses optional properties specified in these child nodes to configure the parameters of each bank. Signed-off-by: Alex Smith <alex@alex-smith.me.uk> Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/memory/Kconfig9
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/jz4780-nemc.c391
-rw-r--r--include/linux/jz4780-nemc.h43
4 files changed, 444 insertions, 0 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 191383d8c94d..868036f70f8f 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -83,6 +83,15 @@ config FSL_IFC
83 bool 83 bool
84 depends on FSL_SOC 84 depends on FSL_SOC
85 85
86config JZ4780_NEMC
87 bool "Ingenic JZ4780 SoC NEMC driver"
88 default y
89 depends on MACH_JZ4780
90 help
91 This driver is for the NAND/External Memory Controller (NEMC) in
92 the Ingenic JZ4780. This controller is used to handle external
93 memory devices such as NAND and SRAM.
94
86source "drivers/memory/tegra/Kconfig" 95source "drivers/memory/tegra/Kconfig"
87 96
88endif 97endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 6b6548124473..b670441e3cdf 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
13obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 13obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
14obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 14obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
15obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o 15obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
16obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o
16 17
17obj-$(CONFIG_TEGRA_MC) += tegra/ 18obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c
new file mode 100644
index 000000000000..919d1925acb9
--- /dev/null
+++ b/drivers/memory/jz4780-nemc.c
@@ -0,0 +1,391 @@
1/*
2 * JZ4780 NAND/external memory controller (NEMC)
3 *
4 * Copyright (c) 2015 Imagination Technologies
5 * Author: Alex Smith <alex@alex-smith.me.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
10 */
11
12#include <linux/clk.h>
13#include <linux/init.h>
14#include <linux/math64.h>
15#include <linux/of.h>
16#include <linux/of_address.h>
17#include <linux/of_device.h>
18#include <linux/of_platform.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/spinlock.h>
22
23#include <linux/jz4780-nemc.h>
24
25#define NEMC_SMCRn(n) (0x14 + (((n) - 1) * 4))
26#define NEMC_NFCSR 0x50
27
28#define NEMC_SMCR_SMT BIT(0)
29#define NEMC_SMCR_BW_SHIFT 6
30#define NEMC_SMCR_BW_MASK (0x3 << NEMC_SMCR_BW_SHIFT)
31#define NEMC_SMCR_BW_8 (0 << 6)
32#define NEMC_SMCR_TAS_SHIFT 8
33#define NEMC_SMCR_TAS_MASK (0xf << NEMC_SMCR_TAS_SHIFT)
34#define NEMC_SMCR_TAH_SHIFT 12
35#define NEMC_SMCR_TAH_MASK (0xf << NEMC_SMCR_TAH_SHIFT)
36#define NEMC_SMCR_TBP_SHIFT 16
37#define NEMC_SMCR_TBP_MASK (0xf << NEMC_SMCR_TBP_SHIFT)
38#define NEMC_SMCR_TAW_SHIFT 20
39#define NEMC_SMCR_TAW_MASK (0xf << NEMC_SMCR_TAW_SHIFT)
40#define NEMC_SMCR_TSTRV_SHIFT 24
41#define NEMC_SMCR_TSTRV_MASK (0x3f << NEMC_SMCR_TSTRV_SHIFT)
42
43#define NEMC_NFCSR_NFEn(n) BIT(((n) - 1) << 1)
44#define NEMC_NFCSR_NFCEn(n) BIT((((n) - 1) << 1) + 1)
45#define NEMC_NFCSR_TNFEn(n) BIT(16 + (n) - 1)
46
47struct jz4780_nemc {
48 spinlock_t lock;
49 struct device *dev;
50 void __iomem *base;
51 struct clk *clk;
52 uint32_t clk_period;
53 unsigned long banks_present;
54};
55
56/**
57 * jz4780_nemc_num_banks() - count the number of banks referenced by a device
58 * @dev: device to count banks for, must be a child of the NEMC.
59 *
60 * Return: The number of unique NEMC banks referred to by the specified NEMC
61 * child device. Unique here means that a device that references the same bank
62 * multiple times in the its "reg" property will only count once.
63 */
64unsigned int jz4780_nemc_num_banks(struct device *dev)
65{
66 const __be32 *prop;
67 unsigned int bank, count = 0;
68 unsigned long referenced = 0;
69 int i = 0;
70
71 while ((prop = of_get_address(dev->of_node, i++, NULL, NULL))) {
72 bank = of_read_number(prop, 1);
73 if (!(referenced & BIT(bank))) {
74 referenced |= BIT(bank);
75 count++;
76 }
77 }
78
79 return count;
80}
81EXPORT_SYMBOL(jz4780_nemc_num_banks);
82
83/**
84 * jz4780_nemc_set_type() - set the type of device connected to a bank
85 * @dev: child device of the NEMC.
86 * @bank: bank number to configure.
87 * @type: type of device connected to the bank.
88 */
89void jz4780_nemc_set_type(struct device *dev, unsigned int bank,
90 enum jz4780_nemc_bank_type type)
91{
92 struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent);
93 uint32_t nfcsr;
94
95 nfcsr = readl(nemc->base + NEMC_NFCSR);
96
97 /* TODO: Support toggle NAND devices. */
98 switch (type) {
99 case JZ4780_NEMC_BANK_SRAM:
100 nfcsr &= ~(NEMC_NFCSR_TNFEn(bank) | NEMC_NFCSR_NFEn(bank));
101 break;
102 case JZ4780_NEMC_BANK_NAND:
103 nfcsr &= ~NEMC_NFCSR_TNFEn(bank);
104 nfcsr |= NEMC_NFCSR_NFEn(bank);
105 break;
106 }
107
108 writel(nfcsr, nemc->base + NEMC_NFCSR);
109}
110EXPORT_SYMBOL(jz4780_nemc_set_type);
111
112/**
113 * jz4780_nemc_assert() - (de-)assert a NAND device's chip enable pin
114 * @dev: child device of the NEMC.
115 * @bank: bank number of device.
116 * @assert: whether the chip enable pin should be asserted.
117 *
118 * (De-)asserts the chip enable pin for the NAND device connected to the
119 * specified bank.
120 */
121void jz4780_nemc_assert(struct device *dev, unsigned int bank, bool assert)
122{
123 struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent);
124 uint32_t nfcsr;
125
126 nfcsr = readl(nemc->base + NEMC_NFCSR);
127
128 if (assert)
129 nfcsr |= NEMC_NFCSR_NFCEn(bank);
130 else
131 nfcsr &= ~NEMC_NFCSR_NFCEn(bank);
132
133 writel(nfcsr, nemc->base + NEMC_NFCSR);
134}
135EXPORT_SYMBOL(jz4780_nemc_assert);
136
137static uint32_t jz4780_nemc_clk_period(struct jz4780_nemc *nemc)
138{
139 unsigned long rate;
140
141 rate = clk_get_rate(nemc->clk);
142 if (!rate)
143 return 0;
144
145 /* Return in picoseconds. */
146 return div64_ul(1000000000000ull, rate);
147}
148
149static uint32_t jz4780_nemc_ns_to_cycles(struct jz4780_nemc *nemc, uint32_t ns)
150{
151 return ((ns * 1000) + nemc->clk_period - 1) / nemc->clk_period;
152}
153
154static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
155 unsigned int bank,
156 struct device_node *node)
157{
158 uint32_t smcr, val, cycles;
159
160 /*
161 * Conversion of tBP and tAW cycle counts to values supported by the
162 * hardware (round up to the next supported value).
163 */
164 static const uint32_t convert_tBP_tAW[] = {
165 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
166
167 /* 11 - 12 -> 12 cycles */
168 11, 11,
169
170 /* 13 - 15 -> 15 cycles */
171 12, 12, 12,
172
173 /* 16 - 20 -> 20 cycles */
174 13, 13, 13, 13, 13,
175
176 /* 21 - 25 -> 25 cycles */
177 14, 14, 14, 14, 14,
178
179 /* 26 - 31 -> 31 cycles */
180 15, 15, 15, 15, 15, 15
181 };
182
183 smcr = readl(nemc->base + NEMC_SMCRn(bank));
184 smcr &= ~NEMC_SMCR_SMT;
185
186 if (!of_property_read_u32(node, "ingenic,nemc-bus-width", &val)) {
187 smcr &= ~NEMC_SMCR_BW_MASK;
188 switch (val) {
189 case 8:
190 smcr |= NEMC_SMCR_BW_8;
191 break;
192 default:
193 /*
194 * Earlier SoCs support a 16 bit bus width (the 4780
195 * does not), until those are properly supported, error.
196 */
197 dev_err(nemc->dev, "unsupported bus width: %u\n", val);
198 return false;
199 }
200 }
201
202 if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) {
203 smcr &= ~NEMC_SMCR_TAS_MASK;
204 cycles = jz4780_nemc_ns_to_cycles(nemc, val);
205 if (cycles > 15) {
206 dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n",
207 val, cycles);
208 return false;
209 }
210
211 smcr |= cycles << NEMC_SMCR_TAS_SHIFT;
212 }
213
214 if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) {
215 smcr &= ~NEMC_SMCR_TAH_MASK;
216 cycles = jz4780_nemc_ns_to_cycles(nemc, val);
217 if (cycles > 15) {
218 dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n",
219 val, cycles);
220 return false;
221 }
222
223 smcr |= cycles << NEMC_SMCR_TAH_SHIFT;
224 }
225
226 if (of_property_read_u32(node, "ingenic,nemc-tBP", &val) == 0) {
227 smcr &= ~NEMC_SMCR_TBP_MASK;
228 cycles = jz4780_nemc_ns_to_cycles(nemc, val);
229 if (cycles > 31) {
230 dev_err(nemc->dev, "tBP %u is too high (%u cycles)\n",
231 val, cycles);
232 return false;
233 }
234
235 smcr |= convert_tBP_tAW[cycles] << NEMC_SMCR_TBP_SHIFT;
236 }
237
238 if (of_property_read_u32(node, "ingenic,nemc-tAW", &val) == 0) {
239 smcr &= ~NEMC_SMCR_TAW_MASK;
240 cycles = jz4780_nemc_ns_to_cycles(nemc, val);
241 if (cycles > 31) {
242 dev_err(nemc->dev, "tAW %u is too high (%u cycles)\n",
243 val, cycles);
244 return false;
245 }
246
247 smcr |= convert_tBP_tAW[cycles] << NEMC_SMCR_TAW_SHIFT;
248 }
249
250 if (of_property_read_u32(node, "ingenic,nemc-tSTRV", &val) == 0) {
251 smcr &= ~NEMC_SMCR_TSTRV_MASK;
252 cycles = jz4780_nemc_ns_to_cycles(nemc, val);
253 if (cycles > 63) {
254 dev_err(nemc->dev, "tSTRV %u is too high (%u cycles)\n",
255 val, cycles);
256 return false;
257 }
258
259 smcr |= cycles << NEMC_SMCR_TSTRV_SHIFT;
260 }
261
262 writel(smcr, nemc->base + NEMC_SMCRn(bank));
263 return true;
264}
265
266static int jz4780_nemc_probe(struct platform_device *pdev)
267{
268 struct device *dev = &pdev->dev;
269 struct jz4780_nemc *nemc;
270 struct resource *res;
271 struct device_node *child;
272 const __be32 *prop;
273 unsigned int bank;
274 unsigned long referenced;
275 int i, ret;
276
277 nemc = devm_kzalloc(dev, sizeof(*nemc), GFP_KERNEL);
278 if (!nemc)
279 return -ENOMEM;
280
281 spin_lock_init(&nemc->lock);
282 nemc->dev = dev;
283
284 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
285 nemc->base = devm_ioremap_resource(dev, res);
286 if (IS_ERR(nemc->base)) {
287 dev_err(dev, "failed to get I/O memory\n");
288 return PTR_ERR(nemc->base);
289 }
290
291 writel(0, nemc->base + NEMC_NFCSR);
292
293 nemc->clk = devm_clk_get(dev, NULL);
294 if (IS_ERR(nemc->clk)) {
295 dev_err(dev, "failed to get clock\n");
296 return PTR_ERR(nemc->clk);
297 }
298
299 ret = clk_prepare_enable(nemc->clk);
300 if (ret) {
301 dev_err(dev, "failed to enable clock: %d\n", ret);
302 return ret;
303 }
304
305 nemc->clk_period = jz4780_nemc_clk_period(nemc);
306 if (!nemc->clk_period) {
307 dev_err(dev, "failed to calculate clock period\n");
308 clk_disable_unprepare(nemc->clk);
309 return -EINVAL;
310 }
311
312 /*
313 * Iterate over child devices, check that they do not conflict with
314 * each other, and register child devices for them. If a child device
315 * has invalid properties, it is ignored and no platform device is
316 * registered for it.
317 */
318 for_each_child_of_node(nemc->dev->of_node, child) {
319 referenced = 0;
320 i = 0;
321 while ((prop = of_get_address(child, i++, NULL, NULL))) {
322 bank = of_read_number(prop, 1);
323 if (bank < 1 || bank >= JZ4780_NEMC_NUM_BANKS) {
324 dev_err(nemc->dev,
325 "%s requests invalid bank %u\n",
326 child->full_name, bank);
327
328 /* Will continue the outer loop below. */
329 referenced = 0;
330 break;
331 }
332
333 referenced |= BIT(bank);
334 }
335
336 if (!referenced) {
337 dev_err(nemc->dev, "%s has no addresses\n",
338 child->full_name);
339 continue;
340 } else if (nemc->banks_present & referenced) {
341 dev_err(nemc->dev, "%s conflicts with another node\n",
342 child->full_name);
343 continue;
344 }
345
346 /* Configure bank parameters. */
347 for_each_set_bit(bank, &referenced, JZ4780_NEMC_NUM_BANKS) {
348 if (!jz4780_nemc_configure_bank(nemc, bank, child)) {
349 referenced = 0;
350 break;
351 }
352 }
353
354 if (referenced) {
355 if (of_platform_device_create(child, NULL, nemc->dev))
356 nemc->banks_present |= referenced;
357 }
358 }
359
360 platform_set_drvdata(pdev, nemc);
361 dev_info(dev, "JZ4780 NEMC initialised\n");
362 return 0;
363}
364
365static int jz4780_nemc_remove(struct platform_device *pdev)
366{
367 struct jz4780_nemc *nemc = platform_get_drvdata(pdev);
368
369 clk_disable_unprepare(nemc->clk);
370 return 0;
371}
372
373static const struct of_device_id jz4780_nemc_dt_match[] = {
374 { .compatible = "ingenic,jz4780-nemc" },
375 {},
376};
377
378static struct platform_driver jz4780_nemc_driver = {
379 .probe = jz4780_nemc_probe,
380 .remove = jz4780_nemc_remove,
381 .driver = {
382 .name = "jz4780-nemc",
383 .of_match_table = of_match_ptr(jz4780_nemc_dt_match),
384 },
385};
386
387static int __init jz4780_nemc_init(void)
388{
389 return platform_driver_register(&jz4780_nemc_driver);
390}
391subsys_initcall(jz4780_nemc_init);
diff --git a/include/linux/jz4780-nemc.h b/include/linux/jz4780-nemc.h
new file mode 100644
index 000000000000..e7f1cc7a2284
--- /dev/null
+++ b/include/linux/jz4780-nemc.h
@@ -0,0 +1,43 @@
1/*
2 * JZ4780 NAND/external memory controller (NEMC)
3 *
4 * Copyright (c) 2015 Imagination Technologies
5 * Author: Alex Smith <alex@alex-smith.me.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#ifndef __LINUX_JZ4780_NEMC_H__
14#define __LINUX_JZ4780_NEMC_H__
15
16#include <linux/types.h>
17
18struct device;
19
20/*
21 * Number of NEMC banks. Note that there are actually 6, but they are numbered
22 * from 1.
23 */
24#define JZ4780_NEMC_NUM_BANKS 7
25
26/**
27 * enum jz4780_nemc_bank_type - device types which can be connected to a bank
28 * @JZ4780_NEMC_BANK_SRAM: SRAM
29 * @JZ4780_NEMC_BANK_NAND: NAND
30 */
31enum jz4780_nemc_bank_type {
32 JZ4780_NEMC_BANK_SRAM,
33 JZ4780_NEMC_BANK_NAND,
34};
35
36extern unsigned int jz4780_nemc_num_banks(struct device *dev);
37
38extern void jz4780_nemc_set_type(struct device *dev, unsigned int bank,
39 enum jz4780_nemc_bank_type type);
40extern void jz4780_nemc_assert(struct device *dev, unsigned int bank,
41 bool assert);
42
43#endif /* __LINUX_JZ4780_NEMC_H__ */