Fix up mix of man(7)/mdoc(7).
[netbsd-mini2440.git] / sys / arch / arm / omap / omap_emifs.c
blob5031cba00b6a9ec2d7a2a1be5f331a826b190613
1 /* $NetBSD: omap_emifs.c,v 1.3 2008/11/21 17:13:07 matt Exp $ */
4 /*
5 * Autoconfiguration support for the Texas Instruments OMAP EMIFS bus.
6 * Based on arm/xscale/pxa2x0.c which in turn was derived
7 * from arm/sa11x0/sa11x0.c
9 * Copyright (c) 2002, 2005 Genetec Corporation. All rights reserved.
10 * Written by Hiroyuki Bessho for Genetec Corporation.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed for the NetBSD Project by
23 * Genetec Corporation.
24 * 4. The name of Genetec Corporation may not be used to endorse or
25 * promote products derived from this software without specific prior
26 * written permission.
28 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
40 * Copyright (c) 1997,1998, 2001, The NetBSD Foundation, Inc.
41 * All rights reserved.
43 * This code is derived from software contributed to The NetBSD Foundation
44 * by IWAMOTO Toshihiro, Ichiro FUKUHARA and Paul Kranenburg.
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65 * POSSIBILITY OF SUCH DAMAGE.
67 * Copyright (c) 1999
68 * Shin Takemura and PocketBSD Project. All rights reserved.
70 * Redistribution and use in source and binary forms, with or without
71 * modification, are permitted provided that the following conditions
72 * are met:
73 * 1. Redistributions of source code must retain the above copyright
74 * notice, this list of conditions and the following disclaimer.
75 * 2. Redistributions in binary form must reproduce the above copyright
76 * notice, this list of conditions and the following disclaimer in the
77 * documentation and/or other materials provided with the distribution.
78 * 3. All advertising materials mentioning features or use of this software
79 * must display the following acknowledgement:
80 * This product includes software developed by the PocketBSD project
81 * and its contributors.
82 * 4. Neither the name of the project nor the names of its contributors
83 * may be used to endorse or promote products derived from this software
84 * without specific prior written permission.
86 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
87 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
88 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
89 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
90 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
91 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
92 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
93 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
94 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
95 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
96 * SUCH DAMAGE.
99 #include <sys/cdefs.h>
100 __KERNEL_RCSID(0, "$NetBSD: omap_emifs.c,v 1.3 2008/11/21 17:13:07 matt Exp $");
102 #include "locators.h"
104 #include <sys/param.h>
105 #include <sys/systm.h>
106 #include <sys/device.h>
107 #include <sys/kernel.h>
108 #include <sys/reboot.h>
110 #include <machine/cpu.h>
111 #include <machine/bus.h>
113 #include <arm/cpufunc.h>
114 #include <arm/mainbus/mainbus.h>
115 #include <arm/omap/omap_reg.h>
116 #include <arm/omap/omap_emifs.h>
118 struct emifs_softc {
119 device_t sc_dev;
120 bus_dma_tag_t sc_dmac;
121 bus_space_tag_t sc_iot;
122 bus_space_handle_t sc_ioh;
125 enum which_clock { TC_CLK, REF_CLK };
126 enum which_reg { CCS, ACS };
127 typedef struct timing_parm_info {
128 const char *name; /* name of parm */
129 int cf_ndx; /* Index to get parm */
130 enum which_clock clk; /* TC_CLK or REF_CLK */
131 enum which_reg reg; /* CCS or ACS? */
132 u_int shift; /* Field's register position */
133 u_int adder; /* Number of cycles to add */
134 u_int max; /* Maximum field value */
135 } timing_parm_info;
137 /* prototypes */
138 static int emifs_match(device_t, cfdata_t, void *);
139 static void emifs_attach(device_t, device_t, void *);
140 static u_int emifs_cvt_nsec(const timing_parm_info *, u_int, int);
141 static void emifs_set_timing(struct emifs_softc *, cfdata_t );
142 static int emifs_search(device_t, cfdata_t,
143 const int *, void *);
144 static int emifs_print(void *, const char *);
146 #ifndef OMAP_TC_CLOCK_FREQ
147 #error Specify the TC clock frequency in Hz with the OMAP_TC_CLOCK_FREQ option.
148 #endif
150 /* Encapsulate the device knowledge within this source. */
151 /* Register offsets, values and information needed to set them. */
152 #define EMIFS_CCS(cs) (0x10+((cs)*4)) /* chip-select config */
153 #define EMIFS_ACS(cs) (0x50+((cs)*4)) /* advanced chip-select config */
154 #define EMIFS_ACS_BTMODE (1<<9)
155 #define EMIFS_SIZE 256 /* per TRM */
157 static const timing_parm_info timing_parms[] = {
158 { "rdwst", EMIFSCF_RDWST, REF_CLK, CCS, 4, 2, 0xF },
159 { "oesetup", EMIFSCF_OESETUP, REF_CLK, ACS, 0, 0, 0xF },
160 { "oehold", EMIFSCF_OEHOLD, REF_CLK, ACS, 4, 0, 0xF },
161 { "wrwst", EMIFSCF_WRWST, REF_CLK, CCS, 8, 1, 0xF },
162 { "welen", EMIFSCF_WELEN, REF_CLK, CCS, 12, 1, 0xF },
163 { "advhold", EMIFSCF_ADVHOLD, REF_CLK, ACS, 8, 1, 0x1 },
164 { "btwst", EMIFSCF_BTWST, TC_CLK, CCS, 23, 1, 0xF }
167 /* attach structures */
168 CFATTACH_DECL_NEW(emifs, sizeof(struct emifs_softc),
169 emifs_match, emifs_attach, NULL, NULL);
171 static int emifs_attached;
173 static int
174 emifs_match(device_t parent, cfdata_t match, void *aux)
176 if (emifs_attached)
177 return 0;
178 return 1;
181 static void
182 emifs_attach(device_t parent, device_t self, void *aux)
184 struct emifs_softc *sc = device_private(self);
185 struct mainbus_attach_args *mainbus = aux;
187 sc->sc_dev = self;
189 * mainbus->mb_iot always multiplies the offset by 4 and doesn't seem
190 * to be widely used, so I'm just going to use the omap bus.
192 if (mainbus->mb_iobase != -1) {
194 * The address is only needed for modifying the timings, so
195 * don't make it mandatory. We'll check to see if it was set
196 * when (and if) it is needed.
198 sc->sc_iot = &omap_bs_tag;
199 if (bus_space_map(sc->sc_iot,
200 mainbus->mb_iobase, EMIFS_SIZE,
201 0, &sc->sc_ioh))
202 panic("%s: Cannot map registers", device_xname(self));
203 } else
204 sc->sc_iot = NULL;
206 emifs_attached = 1;
208 #if NOMAPDMAC > 0
209 #error DMA not implemented
210 sc->sc_dmac = &omap_bus_dma_tag;
211 #else
212 sc->sc_dmac = NULL;
213 #endif
215 aprint_normal(": Extended Memory Interface Slow\n");
216 aprint_naive("\n");
219 * Attach all our devices
221 config_search_ia(emifs_search, self, "emifs", NULL);
224 static const u_int ns_per_sec = 1000000000;
226 static u_int
227 emifs_cvt_nsec(const timing_parm_info *tp, u_int source_freq, int nsec)
229 u_int desired_freq, clocks, rval;
232 * It is easier to work with a frequency in Hz, instead of a
233 * period in nanoseconds.
235 desired_freq = ns_per_sec / nsec;
238 * Then we can just divide the source frequency by the desired
239 * frequency to get the number of clocks. If it doesn't divide
240 * evenly, round up to make sure the period is long enough.
242 clocks = source_freq / desired_freq;
243 if ((clocks * desired_freq) != source_freq)
244 clocks++;
246 /* Adjust for the number of cycles that are added. */
247 rval = clocks - tp->adder;
249 /* Limit to maximum */
250 if (rval > tp->max) {
251 aprint_error("EMIFS: %s: %d ns is too large.\n",
252 tp->name, nsec);
253 rval = tp->max;
256 return rval;
259 static void
260 emifs_set_timing(struct emifs_softc *sc, cfdata_t cf)
262 static const u_int tc_freq = OMAP_TC_CLOCK_FREQ;
263 /* We force REF to be the same frequency as TC. */
264 static const u_int ref_freq = tc_freq;
266 int cs, i;
267 uint32_t ccs, acs;
270 * Ensure we have what everything we need to set the EMIFS bus
271 * timing parameters.
273 cs = cf->cf_loc[EMIFSCF_CS];
274 if (cs < 0 || cs > 3)
275 panic("cs parameter must be in the range of 0 to 3.");
276 if (sc->sc_iot == NULL)
277 panic("Parent emifs device must have base specified.");
279 ccs = 0;
280 acs = 0;
281 switch (cf->cf_loc[EMIFSCF_BTMODE]) {
282 case -1:
283 case 0:
284 break;
285 case 1:
286 acs = EMIFS_ACS_BTMODE;
287 break;
288 default:
289 panic("btmode must be 0, 1 or not given.");
292 aprint_verbose("EMIFS: TC_CK period: %u ns\n", ns_per_sec / tc_freq);
293 aprint_verbose("EMIFS: REF_CK period: %u ns\n", ns_per_sec / ref_freq);
295 for (i = 0; i < __arraycount(timing_parms); i++) {
296 const timing_parm_info *tp;
297 int nsec;
298 u_int source_freq, field_val;
300 tp = &timing_parms[i];
301 nsec = cf->cf_loc[tp->cf_ndx];
303 /* Blow up on completely wrong parameters. */
304 if (nsec < 0 || nsec > OMAP_TC_CLOCK_FREQ)
305 panic("Invalid %s period of %d nsec.", tp->name, nsec);
307 if (tp->clk == REF_CLK)
308 source_freq = ref_freq;
309 else
310 source_freq = tc_freq;
312 if (nsec == 0)
314 * Handle the zero case separately because: 1) it
315 * avoids a divide by zero case, 2) we already know
316 * the answer is zero, and 3) we know the field is
317 * already zeroed.
319 field_val = 0;
320 else {
321 field_val = emifs_cvt_nsec(tp, source_freq, nsec);
323 if (tp->reg == CCS)
324 ccs |= (field_val << tp->shift);
325 else
326 acs |= (field_val << tp->shift);
330 * Tell them what they got. The ">> 5"'s are to prevent
331 * overflow. We know ns_per_sec fits in a word, and we know
332 * that (field_val + tp->addr) is less than five bits. If we
333 * shift the numerator and denominator the same amount, we'll
334 * get the same answer, but without overflow.
336 aprint_verbose("EMIFS: %8s: Requested %4u ns. Got %4u ns.\n",
337 tp->name, nsec,
338 ((field_val + tp->adder) * (ns_per_sec >> 5)
339 / (source_freq >> 5)));
342 /* Now tell the hardware what we figured out. */
343 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMIFS_CCS(cs), ccs);
344 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMIFS_ACS(cs), acs);
347 static int
348 emifs_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
350 struct emifs_softc *sc = device_private(parent);
351 struct emifs_attach_args aa;
353 /* Set up the attach args. */
354 if (cf->cf_loc[EMIFSCF_NOBYTEACC] == 1) {
355 if (cf->cf_loc[EMIFSCF_MULT] == 1)
356 aa.emifs_iot = &nobyteacc_bs_tag;
357 else
358 panic("nobyteacc specified for device with non-byte multiplier\n");
359 } else {
360 switch (cf->cf_loc[EMIFSCF_MULT]) {
361 case 1:
362 aa.emifs_iot = &omap_bs_tag;
363 break;
364 case 2:
365 aa.emifs_iot = &omap_a2x_bs_tag;
366 break;
367 case 4:
368 aa.emifs_iot = &omap_a4x_bs_tag;
369 break;
370 default:
371 panic("Unsupported EMIFS multiplier.");
372 break;
376 aa.emifs_dmac = sc->sc_dmac;
377 aa.emifs_addr = cf->cf_loc[EMIFSCF_ADDR];
378 aa.emifs_size = cf->cf_loc[EMIFSCF_SIZE];
379 aa.emifs_intr = cf->cf_loc[EMIFSCF_INTR];
381 /* Chip-select specified? */
382 if (cf->cf_loc[EMIFSCF_CS] != -1)
383 emifs_set_timing(sc, cf);
385 if (config_match(parent, cf, &aa))
386 config_attach(parent, cf, &aa, emifs_print);
388 return 0;
391 static int
392 emifs_print(void *aux, const char *name)
394 struct emifs_attach_args *sa = (struct emifs_attach_args*)aux;
396 if (sa->emifs_addr != EMIFSCF_ADDR_DEFAULT) {
397 aprint_normal(" addr 0x%08lx", sa->emifs_addr);
398 if (sa->emifs_size > EMIFSCF_SIZE_DEFAULT)
399 aprint_normal("-0x%08lx", sa->emifs_addr + sa->emifs_size-1);
401 if (sa->emifs_intr != EMIFSCF_INTR_DEFAULT)
402 aprint_normal(" intr %d", sa->emifs_intr);
404 return (UNCONF);