[PATCH] arm,davinci: configure davinci aemif chipselects through OF
Heiko Schocher
hs at denx.de
Sun Dec 4 04:41:19 EST 2011
Signed-off-by: Heiko Schocher <hs at denx.de>
Cc: davinci-linux-open-source at linux.davincidsp.com
Cc: devicetree-discuss at lists.ozlabs.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: grant.likely at secretlab.ca
Cc: Sekhar Nori <nsekhar at ti.com>
Cc: Kevin Hilman <khilman at ti.com>
Cc: Wolfgang Denk <wd at denx.de>
---
.../devicetree/bindings/arm/davinci/aemif.txt | 85 ++++++++++++++++
arch/arm/mach-davinci/aemif.c | 105 +++++++++++++++++++-
arch/arm/mach-davinci/include/mach/aemif.h | 1 +
3 files changed, 190 insertions(+), 1 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/davinci/aemif.txt
diff --git a/Documentation/devicetree/bindings/arm/davinci/aemif.txt b/Documentation/devicetree/bindings/arm/davinci/aemif.txt
new file mode 100644
index 0000000..c9ed551
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/davinci/aemif.txt
@@ -0,0 +1,85 @@
+* Texas Instruments Davinci AEMIF
+
+This file provides information, what the device node for the
+davinci aemifa interface contain.
+
+Required properties:
+- compatible: "ti,davinci-emifa";
+- #address-cells : Should be either two or three. The first cell is the
+ chipselect number, and the remaining cells are the
+ offset into the chipselect.
+- #size-cells : Either one or two, depending on how large each chipselect
+ can be.
+- ranges : Each range corresponds to a single chipselect, and cover
+ the entire access window as configured.
+
+Optional properties:
+- none
+
+Optional subnodes:
+- Chipselect setup:
+ - Required properties:
+ - compatible: "ti,davinci-cs";
+ - #address-cells = <1>;
+ - #size-cells = <1>;
+
+ Timing setup, all timings in nanoseconds
+ - cs: chipselect (value 2,3,4 or 5)
+ - asize: Asynchronous Data Bus Width.
+ value:
+ 0: 8 bit
+ 1: 16 bit
+ - ta: Minimum Turn-Around time.
+ - rhold: Read hold width
+ - rstrobe: Read strobe width
+ - rsetup: Read setup width
+ - whold: Write hold width
+ - wstrobe: Write strobe width
+ - wsetup: Write setup width
+ - ew: Extend Wait bit
+ value:
+ 0: Extended wait cycles disabled.
+ 1: Extended wait cycles enabled.
+ -ss: Select Strobe bit.
+ value:
+ 0: Normal Mode enabled.
+ 1: Select Strobe Mode enabled.
+- CFI driver:
+ see: Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+
+Example (enbw_cmc board):
+ aemif at 60000000 {
+ compatible = "ti,davinci-emifa";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x68000000 0x80000>;
+ ranges = <2 0 0x60000000 0x02000000
+ 3 0 0x62000000 0x02000000
+ 4 0 0x64000000 0x02000000
+ 5 0 0x66000000 0x02000000>;
+ cs2 at 0x60000000 {
+ compatible = "ti,davinci-cs";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* all timings in nanoseconds */
+ cs = <2>;
+ asize = <1>;
+ ta = <0>;
+ rhold = <7>;
+ rstrobe = <42>;
+ rsetup = <14>;
+ whold = <7>;
+ wstrobe = <42>;
+ wsetup = <14>;
+ ew = <0>;
+ ss = <0>;
+ };
+ flash at 2,0 {
+ compatible = "cfi-flash";
+ reg = <2 0x0 0x400000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <2>;
+ device-width = <2>;
+ };
+ };
diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c
index 1ce70a9..12c559f 100644
--- a/arch/arm/mach-davinci/aemif.c
+++ b/arch/arm/mach-davinci/aemif.c
@@ -13,12 +13,14 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/time.h>
#include <mach/aemif.h>
/* Timing value configuration */
-
+#define ASIZE(x) (x)
#define TA(x) ((x) << 2)
#define RHOLD(x) ((x) << 4)
#define RSTROBE(x) ((x) << 7)
@@ -26,7 +28,10 @@
#define WHOLD(x) ((x) << 17)
#define WSTROBE(x) ((x) << 20)
#define WSETUP(x) ((x) << 26)
+#define EW(x) ((x) << 30)
+#define SS(x) ((x) << 31)
+#define ASIZE_MAX 0x1
#define TA_MAX 0x3
#define RHOLD_MAX 0x7
#define RSTROBE_MAX 0x3f
@@ -34,6 +39,8 @@
#define WHOLD_MAX 0x7
#define WSTROBE_MAX 0x3f
#define WSETUP_MAX 0xf
+#define EW_MAX 0x1
+#define SS_MAX 0x1
#define TIMING_MASK (TA(TA_MAX) | \
RHOLD(RHOLD_MAX) | \
@@ -131,3 +138,99 @@ int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
return 0;
}
EXPORT_SYMBOL(davinci_aemif_setup_timing);
+
+#if defined(CONFIG_OF)
+static int dv_get_value(struct device_node *np, const char *name)
+{
+ const u32 *data;
+ int len;
+
+ data = of_get_property(np, name, &len);
+ if (data)
+ return be32_to_cpu(readl(data));
+
+ return -EINVAL;
+}
+
+static int davinci_aemif_setup_timing_of_one(struct device_node *np,
+ void __iomem *base)
+{
+ unsigned val;
+ int asize, ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+ int ew, ss;
+ int cs;
+ unsigned offset;
+ struct clk *aemif_clk;
+ unsigned long clkrate;
+
+ aemif_clk = clk_get(NULL, "aemif");
+ if (IS_ERR(aemif_clk))
+ return PTR_ERR(aemif_clk);
+
+ clkrate = clk_get_rate(aemif_clk);
+
+ clkrate /= 1000; /* turn clock into kHz for ease of use */
+
+ cs = dv_get_value(np, "cs");
+ if (cs < 2)
+ return -EINVAL;
+
+ offset = A1CR_OFFSET + (cs - 2) * 4;
+ asize = dv_get_value(np, "asize");
+ ta = aemif_calc_rate(dv_get_value(np, "ta"), clkrate, TA_MAX);
+ rhold = aemif_calc_rate(dv_get_value(np, "rhold"), clkrate,
+ RHOLD_MAX);
+ rstrobe = aemif_calc_rate(dv_get_value(np, "rstrobe"), clkrate,
+ RSTROBE_MAX);
+ rsetup = aemif_calc_rate(dv_get_value(np, "rsetup"), clkrate,
+ RSETUP_MAX);
+ whold = aemif_calc_rate(dv_get_value(np, "whold"), clkrate,
+ WHOLD_MAX);
+ wstrobe = aemif_calc_rate(dv_get_value(np, "wstrobe"), clkrate,
+ WSTROBE_MAX);
+ wsetup = aemif_calc_rate(dv_get_value(np, "wsetup"), clkrate,
+ WSETUP_MAX);
+ ew = dv_get_value(np, "ew");
+ ss = dv_get_value(np, "ss");
+
+ if (asize < 0 || ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+ whold < 0 || wstrobe < 0 || wsetup < 0 || ew < 0 ||
+ ss < 0) {
+ pr_err("%s: cannot get suitable timings\n", __func__);
+ return -EINVAL;
+ }
+
+ val = ASIZE(asize) | TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) |
+ RSETUP(rsetup) | WHOLD(whold) | WSTROBE(wstrobe) |
+ WSETUP(wsetup) | EW(ew) | SS(ss);
+
+ __raw_writel(val, base + offset);
+
+ return 0;
+}
+
+int davinci_aemif_setup_timing_of(void)
+{
+ struct device_node *np = NULL;
+ void __iomem *base;
+
+ np = of_find_compatible_node(NULL, NULL, "ti,davinci-emifa");
+ if (!np) {
+ pr_warning("%s: ti,davinci-emifa not found\n", __func__);
+ return 0;
+ }
+
+ base = of_iomap(np, 0);
+ for_each_compatible_node(np, NULL, "ti,davinci-cs")
+ davinci_aemif_setup_timing_of_one(np, base);
+
+ iounmap(base);
+ return 0;
+}
+#else
+int davinci_aemif_setup_timing_of(void)
+{
+ return 0;
+}
+#endif
+EXPORT_SYMBOL(davinci_aemif_setup_timing_of);
diff --git a/arch/arm/mach-davinci/include/mach/aemif.h b/arch/arm/mach-davinci/include/mach/aemif.h
index 05b2934..1538565 100644
--- a/arch/arm/mach-davinci/include/mach/aemif.h
+++ b/arch/arm/mach-davinci/include/mach/aemif.h
@@ -33,4 +33,5 @@ struct davinci_aemif_timing {
int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
void __iomem *base, unsigned cs);
+int davinci_aemif_setup_timing_of(void);
#endif
--
1.7.6.4
More information about the linux-arm-kernel
mailing list