Signed-off-by: Heiko Schocher <h...@denx.de> Cc: davinci-linux-open-source@linux.davincidsp.com Cc: devicetree-disc...@lists.ozlabs.org Cc: linux-arm-ker...@lists.infradead.org Cc: grant.lik...@secretlab.ca Cc: Sekhar Nori <nsek...@ti.com> Cc: Kevin Hilman <khil...@ti.com> Cc: Wolfgang Denk <w...@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@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@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@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 _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source