aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/memory
diff options
context:
space:
mode:
authorIvan Khoronzhuk <ivan.khoronzhuk@ti.com>2014-02-24 12:26:11 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-28 19:47:21 -0500
commit5a7c81547c1db7563afc005a509d1ac38d9e0884 (patch)
tree0d1ae16ccd9e69f1faac6b2409b4a571100428d3 /drivers/memory
parent76ae0536ddc0aa576f2aac11f0f82d0fd60b522c (diff)
memory: ti-aemif: introduce AEMIF driver
Add new AEMIF driver for EMIF16 Texas Instruments controller. The EMIF16 module is intended to provide a glue-less interface to a variety of asynchronous memory devices like ASRA M, NOR and NAND memory. A total of 256M bytes of any of these memories can be accessed at any given time via 4 chip selects with 64M byte access per chip select. Synchronous memories such as DDR1 SD RAM, SDR SDRAM and Mobile SDR are not supported. This controller is used on SoCs like Davinci, Keysone2 Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/memory')
-rw-r--r--drivers/memory/Kconfig11
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/ti-aemif.c427
3 files changed, 439 insertions, 0 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index a3640fe9852f..c59e9c96e86d 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -7,6 +7,17 @@ menuconfig MEMORY
7 7
8if MEMORY 8if MEMORY
9 9
10config TI_AEMIF
11 tristate "Texas Instruments AEMIF driver"
12 depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
13 help
14 This driver is for the AEMIF module available in Texas Instruments
15 SoCs. AEMIF stands for Asynchronous External Memory Interface and
16 is intended to provide a glue-less interface to a variety of
17 asynchronuous memory devices like ASRAM, NOR and NAND memory. A total
18 of 256M bytes of any of these memories can be accessed at a given
19 time via four chip selects with 64M byte access per chip select.
20
10config TI_EMIF 21config TI_EMIF
11 tristate "Texas Instruments EMIF driver" 22 tristate "Texas Instruments EMIF driver"
12 depends on ARCH_OMAP2PLUS 23 depends on ARCH_OMAP2PLUS
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index f2bf25c801d0..71160a2b7313 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -5,6 +5,7 @@
5ifeq ($(CONFIG_DDR),y) 5ifeq ($(CONFIG_DDR),y)
6obj-$(CONFIG_OF) += of_memory.o 6obj-$(CONFIG_OF) += of_memory.o
7endif 7endif
8obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
8obj-$(CONFIG_TI_EMIF) += emif.o 9obj-$(CONFIG_TI_EMIF) += emif.o
9obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 10obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
10obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 11obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
new file mode 100644
index 000000000000..d3df7602f406
--- /dev/null
+++ b/drivers/memory/ti-aemif.c
@@ -0,0 +1,427 @@
1/*
2 * TI AEMIF driver
3 *
4 * Copyright (C) 2010 - 2013 Texas Instruments Incorporated. http://www.ti.com/
5 *
6 * Authors:
7 * Murali Karicheri <m-karicheri2@ti.com>
8 * Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/clk.h>
16#include <linux/err.h>
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_platform.h>
22#include <linux/platform_device.h>
23
24#define TA_SHIFT 2
25#define RHOLD_SHIFT 4
26#define RSTROBE_SHIFT 7
27#define RSETUP_SHIFT 13
28#define WHOLD_SHIFT 17
29#define WSTROBE_SHIFT 20
30#define WSETUP_SHIFT 26
31#define EW_SHIFT 30
32#define SS_SHIFT 31
33
34#define TA(x) ((x) << TA_SHIFT)
35#define RHOLD(x) ((x) << RHOLD_SHIFT)
36#define RSTROBE(x) ((x) << RSTROBE_SHIFT)
37#define RSETUP(x) ((x) << RSETUP_SHIFT)
38#define WHOLD(x) ((x) << WHOLD_SHIFT)
39#define WSTROBE(x) ((x) << WSTROBE_SHIFT)
40#define WSETUP(x) ((x) << WSETUP_SHIFT)
41#define EW(x) ((x) << EW_SHIFT)
42#define SS(x) ((x) << SS_SHIFT)
43
44#define ASIZE_MAX 0x1
45#define TA_MAX 0x3
46#define RHOLD_MAX 0x7
47#define RSTROBE_MAX 0x3f
48#define RSETUP_MAX 0xf
49#define WHOLD_MAX 0x7
50#define WSTROBE_MAX 0x3f
51#define WSETUP_MAX 0xf
52#define EW_MAX 0x1
53#define SS_MAX 0x1
54#define NUM_CS 4
55
56#define TA_VAL(x) (((x) & TA(TA_MAX)) >> TA_SHIFT)
57#define RHOLD_VAL(x) (((x) & RHOLD(RHOLD_MAX)) >> RHOLD_SHIFT)
58#define RSTROBE_VAL(x) (((x) & RSTROBE(RSTROBE_MAX)) >> RSTROBE_SHIFT)
59#define RSETUP_VAL(x) (((x) & RSETUP(RSETUP_MAX)) >> RSETUP_SHIFT)
60#define WHOLD_VAL(x) (((x) & WHOLD(WHOLD_MAX)) >> WHOLD_SHIFT)
61#define WSTROBE_VAL(x) (((x) & WSTROBE(WSTROBE_MAX)) >> WSTROBE_SHIFT)
62#define WSETUP_VAL(x) (((x) & WSETUP(WSETUP_MAX)) >> WSETUP_SHIFT)
63#define EW_VAL(x) (((x) & EW(EW_MAX)) >> EW_SHIFT)
64#define SS_VAL(x) (((x) & SS(SS_MAX)) >> SS_SHIFT)
65
66#define NRCSR_OFFSET 0x00
67#define AWCCR_OFFSET 0x04
68#define A1CR_OFFSET 0x10
69
70#define ACR_ASIZE_MASK 0x3
71#define ACR_EW_MASK BIT(30)
72#define ACR_SS_MASK BIT(31)
73#define ASIZE_16BIT 1
74
75#define CONFIG_MASK (TA(TA_MAX) | \
76 RHOLD(RHOLD_MAX) | \
77 RSTROBE(RSTROBE_MAX) | \
78 RSETUP(RSETUP_MAX) | \
79 WHOLD(WHOLD_MAX) | \
80 WSTROBE(WSTROBE_MAX) | \
81 WSETUP(WSETUP_MAX) | \
82 EW(EW_MAX) | SS(SS_MAX) | \
83 ASIZE_MAX)
84
85/**
86 * struct aemif_cs_data: structure to hold cs parameters
87 * @cs: chip-select number
88 * @wstrobe: write strobe width, ns
89 * @rstrobe: read strobe width, ns
90 * @wsetup: write setup width, ns
91 * @whold: write hold width, ns
92 * @rsetup: read setup width, ns
93 * @rhold: read hold width, ns
94 * @ta: minimum turn around time, ns
95 * @enable_ss: enable/disable select strobe mode
96 * @enable_ew: enable/disable extended wait mode
97 * @asize: width of the asynchronous device's data bus
98 */
99struct aemif_cs_data {
100 u8 cs;
101 u16 wstrobe;
102 u16 rstrobe;
103 u8 wsetup;
104 u8 whold;
105 u8 rsetup;
106 u8 rhold;
107 u8 ta;
108 u8 enable_ss;
109 u8 enable_ew;
110 u8 asize;
111};
112
113/**
114 * struct aemif_device: structure to hold device data
115 * @base: base address of AEMIF registers
116 * @clk: source clock
117 * @clk_rate: clock's rate in kHz
118 * @num_cs: number of assigned chip-selects
119 * @cs_offset: start number of cs nodes
120 * @cs_data: array of chip-select settings
121 */
122struct aemif_device {
123 void __iomem *base;
124 struct clk *clk;
125 unsigned long clk_rate;
126 u8 num_cs;
127 int cs_offset;
128 struct aemif_cs_data cs_data[NUM_CS];
129};
130
131/**
132 * aemif_calc_rate - calculate timing data.
133 * @pdev: platform device to calculate for
134 * @wanted: The cycle time needed in nanoseconds.
135 * @clk: The input clock rate in kHz.
136 * @max: The maximum divider value that can be programmed.
137 *
138 * On success, returns the calculated timing value minus 1 for easy
139 * programming into AEMIF timing registers, else negative errno.
140 */
141static int aemif_calc_rate(struct platform_device *pdev, int wanted,
142 unsigned long clk, int max)
143{
144 int result;
145
146 result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
147
148 dev_dbg(&pdev->dev, "%s: result %d from %ld, %d\n", __func__, result,
149 clk, wanted);
150
151 /* It is generally OK to have a more relaxed timing than requested... */
152 if (result < 0)
153 result = 0;
154
155 /* ... But configuring tighter timings is not an option. */
156 else if (result > max)
157 result = -EINVAL;
158
159 return result;
160}
161
162/**
163 * aemif_config_abus - configure async bus parameters
164 * @pdev: platform device to configure for
165 * @csnum: aemif chip select number
166 *
167 * This function programs the given timing values (in real clock) into the
168 * AEMIF registers taking the AEMIF clock into account.
169 *
170 * This function does not use any locking while programming the AEMIF
171 * because it is expected that there is only one user of a given
172 * chip-select.
173 *
174 * Returns 0 on success, else negative errno.
175 */
176static int aemif_config_abus(struct platform_device *pdev, int csnum)
177{
178 struct aemif_device *aemif = platform_get_drvdata(pdev);
179 struct aemif_cs_data *data = &aemif->cs_data[csnum];
180 int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
181 unsigned long clk_rate = aemif->clk_rate;
182 unsigned offset;
183 u32 set, val;
184
185 offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
186
187 ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
188 rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
189 rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
190 rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
191 whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
192 wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
193 wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
194
195 if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
196 whold < 0 || wstrobe < 0 || wsetup < 0) {
197 dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
198 __func__);
199 return -EINVAL;
200 }
201
202 set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
203 WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
204
205 set |= (data->asize & ACR_ASIZE_MASK);
206 if (data->enable_ew)
207 set |= ACR_EW_MASK;
208 if (data->enable_ss)
209 set |= ACR_SS_MASK;
210
211 val = readl(aemif->base + offset);
212 val &= ~CONFIG_MASK;
213 val |= set;
214 writel(val, aemif->base + offset);
215
216 return 0;
217}
218
219static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
220{
221 return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
222}
223
224/**
225 * aemif_get_hw_params - function to read hw register values
226 * @pdev: platform device to read for
227 * @csnum: aemif chip select number
228 *
229 * This function reads the defaults from the registers and update
230 * the timing values. Required for get/set commands and also for
231 * the case when driver needs to use defaults in hardware.
232 */
233static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
234{
235 struct aemif_device *aemif = platform_get_drvdata(pdev);
236 struct aemif_cs_data *data = &aemif->cs_data[csnum];
237 unsigned long clk_rate = aemif->clk_rate;
238 u32 val, offset;
239
240 offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
241 val = readl(aemif->base + offset);
242
243 data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
244 data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
245 data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
246 data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
247 data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
248 data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
249 data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
250 data->enable_ew = EW_VAL(val);
251 data->enable_ss = SS_VAL(val);
252 data->asize = val & ASIZE_MAX;
253}
254
255/**
256 * of_aemif_parse_abus_config - parse CS configuration from DT
257 * @pdev: platform device to parse for
258 * @np: device node ptr
259 *
260 * This function update the emif async bus configuration based on the values
261 * configured in a cs device binding node.
262 */
263static int of_aemif_parse_abus_config(struct platform_device *pdev,
264 struct device_node *np)
265{
266 struct aemif_device *aemif = platform_get_drvdata(pdev);
267 struct aemif_cs_data *data;
268 u32 cs;
269 u32 val;
270
271 if (of_property_read_u32(np, "ti,cs-chipselect", &cs)) {
272 dev_dbg(&pdev->dev, "cs property is required");
273 return -EINVAL;
274 }
275
276 if (cs - aemif->cs_offset >= NUM_CS || cs < aemif->cs_offset) {
277 dev_dbg(&pdev->dev, "cs number is incorrect %d", cs);
278 return -EINVAL;
279 }
280
281 if (aemif->num_cs >= NUM_CS) {
282 dev_dbg(&pdev->dev, "cs count is more than %d", NUM_CS);
283 return -EINVAL;
284 }
285
286 data = &aemif->cs_data[aemif->num_cs];
287 data->cs = cs;
288
289 /* read the current value in the hw register */
290 aemif_get_hw_params(pdev, aemif->num_cs++);
291
292 /* override the values from device node */
293 if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
294 data->ta = val;
295
296 if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
297 data->rhold = val;
298
299 if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
300 data->rstrobe = val;
301
302 if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
303 data->rsetup = val;
304
305 if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
306 data->whold = val;
307
308 if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
309 data->wstrobe = val;
310
311 if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
312 data->wsetup = val;
313
314 if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
315 if (val == 16)
316 data->asize = 1;
317 data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
318 data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
319 return 0;
320}
321
322static const struct of_device_id aemif_of_match[] = {
323 { .compatible = "ti,davinci-aemif", },
324 { .compatible = "ti,da850-aemif", },
325 {},
326};
327
328static int aemif_probe(struct platform_device *pdev)
329{
330 int i;
331 int ret = -ENODEV;
332 struct resource *res;
333 struct device *dev = &pdev->dev;
334 struct device_node *np = dev->of_node;
335 struct device_node *child_np;
336 struct aemif_device *aemif;
337
338 if (np == NULL)
339 return 0;
340
341 aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
342 if (!aemif)
343 return -ENOMEM;
344
345 platform_set_drvdata(pdev, aemif);
346
347 aemif->clk = devm_clk_get(dev, NULL);
348 if (IS_ERR(aemif->clk)) {
349 dev_err(dev, "cannot get clock 'aemif'\n");
350 return PTR_ERR(aemif->clk);
351 }
352
353 clk_prepare_enable(aemif->clk);
354 aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
355
356 if (of_device_is_compatible(np, "ti,da850-aemif"))
357 aemif->cs_offset = 2;
358
359 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
360 aemif->base = devm_ioremap_resource(dev, res);
361 if (IS_ERR(aemif->base)) {
362 ret = PTR_ERR(aemif->base);
363 goto error;
364 }
365
366 /*
367 * For every controller device node, there is a cs device node that
368 * describe the bus configuration parameters. This functions iterate
369 * over these nodes and update the cs data array.
370 */
371 for_each_available_child_of_node(np, child_np) {
372 ret = of_aemif_parse_abus_config(pdev, child_np);
373 if (ret < 0)
374 goto error;
375 }
376
377 for (i = 0; i < aemif->num_cs; i++) {
378 ret = aemif_config_abus(pdev, i);
379 if (ret < 0) {
380 dev_err(dev, "Error configuring chip select %d\n",
381 aemif->cs_data[i].cs);
382 goto error;
383 }
384 }
385
386 /*
387 * Create a child devices explicitly from here to
388 * guarantee that the child will be probed after the AEMIF timing
389 * parameters are set.
390 */
391 for_each_available_child_of_node(np, child_np) {
392 ret = of_platform_populate(child_np, NULL, NULL, dev);
393 if (ret < 0)
394 goto error;
395 }
396
397 return 0;
398error:
399 clk_disable_unprepare(aemif->clk);
400 return ret;
401}
402
403static int aemif_remove(struct platform_device *pdev)
404{
405 struct aemif_device *aemif = platform_get_drvdata(pdev);
406
407 clk_disable_unprepare(aemif->clk);
408 return 0;
409}
410
411static struct platform_driver aemif_driver = {
412 .probe = aemif_probe,
413 .remove = aemif_remove,
414 .driver = {
415 .name = KBUILD_MODNAME,
416 .owner = THIS_MODULE,
417 .of_match_table = of_match_ptr(aemif_of_match),
418 },
419};
420
421module_platform_driver(aemif_driver);
422
423MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
424MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
425MODULE_DESCRIPTION("Texas Instruments AEMIF driver");
426MODULE_LICENSE("GPL v2");
427MODULE_ALIAS("platform:" KBUILD_MODNAME);