aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/aemif.c
diff options
context:
space:
mode:
authorSekhar Nori <nsekhar@ti.com>2010-08-09 06:16:35 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2010-09-24 10:40:26 -0400
commit8060ef4da9e73f461adf2ba1922ea5400a61cf98 (patch)
treec2b32a3ba886a40803aba15dd6f52852e912b846 /arch/arm/mach-davinci/aemif.c
parent13d36a923da6a1e0584e07d91320373c790c01c3 (diff)
davinci: add support for aemif timing configuration
This patch adds support to configure the AEMIF interface with supplied timing values. Since this capability is useful both from NOR and NAND flashes, it is provided as a new interface and in a file of its own. AEMIF timing configuration is required in cases: 1) Where the AEMIF clock rate can change at runtime (a side affect of cpu frequency change). 2) Where U-Boot does not support NAND/NOR but supports other media like SPI Flash or MMC/SD and thus does not care about setting up the AEMIF timing for kernel to use. 3) Where U-Boot just hasn't configured the timing values and cannot be upgraded because the box is already in the field. Since there is now a header file for AEMIF interface, the common (non-NAND specific) defines for AEMIF registers have been moved from nand.h into the newly created aemif.h Signed-off-by: Sekhar Nori <nsekhar@ti.com> Acked-by: Kevin Hilman <khilman@deeprootsystems.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-davinci/aemif.c')
-rw-r--r--arch/arm/mach-davinci/aemif.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c
new file mode 100644
index 000000000000..9c3f500fc12f
--- /dev/null
+++ b/arch/arm/mach-davinci/aemif.c
@@ -0,0 +1,133 @@
1/*
2 * AEMIF support for DaVinci SoCs
3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated. http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/io.h>
13#include <linux/err.h>
14#include <linux/clk.h>
15#include <linux/module.h>
16#include <linux/time.h>
17
18#include <mach/aemif.h>
19
20/* Timing value configuration */
21
22#define TA(x) ((x) << 2)
23#define RHOLD(x) ((x) << 4)
24#define RSTROBE(x) ((x) << 7)
25#define RSETUP(x) ((x) << 13)
26#define WHOLD(x) ((x) << 17)
27#define WSTROBE(x) ((x) << 20)
28#define WSETUP(x) ((x) << 26)
29
30#define TA_MAX 0x3
31#define RHOLD_MAX 0x7
32#define RSTROBE_MAX 0x3f
33#define RSETUP_MAX 0xf
34#define WHOLD_MAX 0x7
35#define WSTROBE_MAX 0x3f
36#define WSETUP_MAX 0xf
37
38#define TIMING_MASK (TA(TA_MAX) | \
39 RHOLD(RHOLD_MAX) | \
40 RSTROBE(RSTROBE_MAX) | \
41 RSETUP(RSETUP_MAX) | \
42 WHOLD(WHOLD_MAX) | \
43 WSTROBE(WSTROBE_MAX) | \
44 WSETUP(WSETUP_MAX))
45
46/*
47 * aemif_calc_rate - calculate timing data.
48 * @wanted: The cycle time needed in nanoseconds.
49 * @clk: The input clock rate in kHz.
50 * @max: The maximum divider value that can be programmed.
51 *
52 * On success, returns the calculated timing value minus 1 for easy
53 * programming into AEMIF timing registers, else negative errno.
54 */
55static int aemif_calc_rate(int wanted, unsigned long clk, int max)
56{
57 int result;
58
59 result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
60
61 pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
62
63 /* It is generally OK to have a more relaxed timing than requested... */
64 if (result < 0)
65 result = 0;
66
67 /* ... But configuring tighter timings is not an option. */
68 else if (result > max)
69 result = -EINVAL;
70
71 return result;
72}
73
74/**
75 * davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
76 * @t: timing values to be progammed
77 * @base: The virtual base address of the AEMIF interface
78 * @cs: chip-select to program the timing values for
79 *
80 * This function programs the given timing values (in real clock) into the
81 * AEMIF registers taking the AEMIF clock into account.
82 *
83 * This function does not use any locking while programming the AEMIF
84 * because it is expected that there is only one user of a given
85 * chip-select.
86 *
87 * Returns 0 on success, else negative errno.
88 */
89int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
90 void __iomem *base, unsigned cs)
91{
92 unsigned set, val;
93 unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
94 unsigned offset = A1CR_OFFSET + cs * 4;
95 struct clk *aemif_clk;
96 unsigned long clkrate;
97
98 if (!t)
99 return 0; /* Nothing to do */
100
101 aemif_clk = clk_get(NULL, "aemif");
102 if (IS_ERR(aemif_clk))
103 return PTR_ERR(aemif_clk);
104
105 clkrate = clk_get_rate(aemif_clk);
106
107 clkrate /= 1000; /* turn clock into kHz for ease of use */
108
109 ta = aemif_calc_rate(t->ta, clkrate, TA_MAX);
110 rhold = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
111 rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
112 rsetup = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
113 whold = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
114 wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
115 wsetup = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
116
117 if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
118 whold < 0 || wstrobe < 0 || wsetup < 0) {
119 pr_err("%s: cannot get suitable timings\n", __func__);
120 return -EINVAL;
121 }
122
123 set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
124 WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
125
126 val = __raw_readl(base + offset);
127 val &= ~TIMING_MASK;
128 val |= set;
129 __raw_writel(val, base + offset);
130
131 return 0;
132}
133EXPORT_SYMBOL(davinci_aemif_setup_timing);