• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <linux/platform_data/mtd-davinci-aemif.h>
19 #include <linux/platform_data/mtd-davinci.h>
20 
21 /* Timing value configuration */
22 
23 #define TA(x)		((x) << 2)
24 #define RHOLD(x)	((x) << 4)
25 #define RSTROBE(x)	((x) << 7)
26 #define RSETUP(x)	((x) << 13)
27 #define WHOLD(x)	((x) << 17)
28 #define WSTROBE(x)	((x) << 20)
29 #define WSETUP(x)	((x) << 26)
30 
31 #define TA_MAX		0x3
32 #define RHOLD_MAX	0x7
33 #define RSTROBE_MAX	0x3f
34 #define RSETUP_MAX	0xf
35 #define WHOLD_MAX	0x7
36 #define WSTROBE_MAX	0x3f
37 #define WSETUP_MAX	0xf
38 
39 #define TIMING_MASK	(TA(TA_MAX) | \
40 				RHOLD(RHOLD_MAX) | \
41 				RSTROBE(RSTROBE_MAX) |	\
42 				RSETUP(RSETUP_MAX) | \
43 				WHOLD(WHOLD_MAX) | \
44 				WSTROBE(WSTROBE_MAX) | \
45 				WSETUP(WSETUP_MAX))
46 
davinci_aemif_readl(void __iomem * base,int offset)47 static inline unsigned int davinci_aemif_readl(void __iomem *base, int offset)
48 {
49 	return readl_relaxed(base + offset);
50 }
51 
davinci_aemif_writel(void __iomem * base,int offset,unsigned long value)52 static inline void davinci_aemif_writel(void __iomem *base,
53 					int offset, unsigned long value)
54 {
55 	writel_relaxed(value, base + offset);
56 }
57 
58 /*
59  * aemif_calc_rate - calculate timing data.
60  * @wanted: The cycle time needed in nanoseconds.
61  * @clk: The input clock rate in kHz.
62  * @max: The maximum divider value that can be programmed.
63  *
64  * On success, returns the calculated timing value minus 1 for easy
65  * programming into AEMIF timing registers, else negative errno.
66  */
aemif_calc_rate(int wanted,unsigned long clk,int max)67 static int aemif_calc_rate(int wanted, unsigned long clk, int max)
68 {
69 	int result;
70 
71 	result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
72 
73 	pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
74 
75 	/* It is generally OK to have a more relaxed timing than requested... */
76 	if (result < 0)
77 		result = 0;
78 
79 	/* ... But configuring tighter timings is not an option. */
80 	else if (result > max)
81 		result = -EINVAL;
82 
83 	return result;
84 }
85 
86 /**
87  * davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
88  * @t: timing values to be progammed
89  * @base: The virtual base address of the AEMIF interface
90  * @cs: chip-select to program the timing values for
91  * @clkrate: the AEMIF clkrate
92  *
93  * This function programs the given timing values (in real clock) into the
94  * AEMIF registers taking the AEMIF clock into account.
95  *
96  * This function does not use any locking while programming the AEMIF
97  * because it is expected that there is only one user of a given
98  * chip-select.
99  *
100  * Returns 0 on success, else negative errno.
101  */
davinci_aemif_setup_timing(struct davinci_aemif_timing * t,void __iomem * base,unsigned cs,unsigned long clkrate)102 static int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
103 					void __iomem *base, unsigned cs,
104 					unsigned long clkrate)
105 {
106 	unsigned set, val;
107 	int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
108 	unsigned offset = A1CR_OFFSET + cs * 4;
109 
110 	if (!t)
111 		return 0;	/* Nothing to do */
112 
113 	clkrate /= 1000;	/* turn clock into kHz for ease of use */
114 
115 	ta	= aemif_calc_rate(t->ta, clkrate, TA_MAX);
116 	rhold	= aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
117 	rstrobe	= aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
118 	rsetup	= aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
119 	whold	= aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
120 	wstrobe	= aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
121 	wsetup	= aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
122 
123 	if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
124 			whold < 0 || wstrobe < 0 || wsetup < 0) {
125 		pr_err("%s: cannot get suitable timings\n", __func__);
126 		return -EINVAL;
127 	}
128 
129 	set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
130 		WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
131 
132 	val = __raw_readl(base + offset);
133 	val &= ~TIMING_MASK;
134 	val |= set;
135 	__raw_writel(val, base + offset);
136 
137 	return 0;
138 }
139 
140 /**
141  * davinci_aemif_setup - setup AEMIF interface by davinci_nand_pdata
142  * @pdev - link to platform device to setup settings for
143  *
144  * This function does not use any locking while programming the AEMIF
145  * because it is expected that there is only one user of a given
146  * chip-select.
147  *
148  * Returns 0 on success, else negative errno.
149  */
davinci_aemif_setup(struct platform_device * pdev)150 int davinci_aemif_setup(struct platform_device *pdev)
151 {
152 	struct davinci_nand_pdata *pdata = dev_get_platdata(&pdev->dev);
153 	uint32_t val;
154 	unsigned long clkrate;
155 	struct resource	*res;
156 	void __iomem *base;
157 	struct clk *clk;
158 	int ret = 0;
159 
160 	clk = clk_get(&pdev->dev, "aemif");
161 	if (IS_ERR(clk)) {
162 		ret = PTR_ERR(clk);
163 		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
164 		return ret;
165 	}
166 
167 	ret = clk_prepare_enable(clk);
168 	if (ret < 0) {
169 		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
170 			ret);
171 		goto err_put;
172 	}
173 
174 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
175 	if (!res) {
176 		dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n");
177 		ret = -ENOMEM;
178 		goto err;
179 	}
180 
181 	base = ioremap(res->start, resource_size(res));
182 	if (!base) {
183 		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res);
184 		ret = -ENOMEM;
185 		goto err;
186 	}
187 
188 	/*
189 	 * Setup Async configuration register in case we did not boot
190 	 * from NAND and so bootloader did not bother to set it up.
191 	 */
192 	val = davinci_aemif_readl(base, A1CR_OFFSET + pdev->id * 4);
193 	/*
194 	 * Extended Wait is not valid and Select Strobe mode is not
195 	 * used
196 	 */
197 	val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK);
198 	if (pdata->options & NAND_BUSWIDTH_16)
199 		val |= 0x1;
200 
201 	davinci_aemif_writel(base, A1CR_OFFSET + pdev->id * 4, val);
202 
203 	clkrate = clk_get_rate(clk);
204 
205 	if (pdata->timing)
206 		ret = davinci_aemif_setup_timing(pdata->timing, base, pdev->id,
207 						 clkrate);
208 
209 	if (ret < 0)
210 		dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
211 
212 	iounmap(base);
213 err:
214 	clk_disable_unprepare(clk);
215 err_put:
216 	clk_put(clk);
217 	return ret;
218 }
219