1 /* $NetBSD: omap_emifs.c,v 1.3 2008/11/21 17:13:07 matt Exp $ */
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
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
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
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.
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
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
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>
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 */
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.
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
;
174 emifs_match(device_t parent
, cfdata_t match
, void *aux
)
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
;
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
,
202 panic("%s: Cannot map registers", device_xname(self
));
209 #error DMA not implemented
210 sc
->sc_dmac
= &omap_bus_dma_tag
;
215 aprint_normal(": Extended Memory Interface Slow\n");
219 * Attach all our devices
221 config_search_ia(emifs_search
, self
, "emifs", NULL
);
224 static const u_int ns_per_sec
= 1000000000;
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
)
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",
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
;
270 * Ensure we have what everything we need to set the EMIFS bus
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.");
281 switch (cf
->cf_loc
[EMIFSCF_BTMODE
]) {
286 acs
= EMIFS_ACS_BTMODE
;
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
;
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
;
310 source_freq
= tc_freq
;
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
321 field_val
= emifs_cvt_nsec(tp
, source_freq
, nsec
);
324 ccs
|= (field_val
<< tp
->shift
);
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",
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
);
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
;
358 panic("nobyteacc specified for device with non-byte multiplier\n");
360 switch (cf
->cf_loc
[EMIFSCF_MULT
]) {
362 aa
.emifs_iot
= &omap_bs_tag
;
365 aa
.emifs_iot
= &omap_a2x_bs_tag
;
368 aa
.emifs_iot
= &omap_a4x_bs_tag
;
371 panic("Unsupported EMIFS multiplier.");
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
);
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
);