initial commit
[freebsd-arm:freebsd-arm.git] / arm / xscale / ixp425 / ixp425_pci_space.c
1 /*      $NetBSD: ixp425_pci_space.c,v 1.6 2006/04/10 03:36:03 simonb Exp $ */
2
3 /*
4  * Copyright (c) 2003
5  *      Ichiro FUKUHARA <ichiro@ichiro.org>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Ichiro FUKUHARA.
19  * 4. The name of the company nor the name of the author may be used to
20  *    endorse or promote products derived from this software without specific
21  *    prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40  * bus_space PCI functions for ixp425
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/bus.h>
46 #include <sys/endian.h>
47
48 #include <machine/pcb.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_kern.h>
52 #include <vm/pmap.h>
53 #include <vm/vm_page.h>
54 #include <vm/vm_extern.h>
55
56 #include <machine/bus.h>
57
58 #include <arm/xscale/ixp425/ixp425reg.h>
59 #include <arm/xscale/ixp425/ixp425var.h>
60
61 /*
62  * Macros to read/write registers
63 */
64 #define CSR_READ_4(x)           *(volatile uint32_t *) \
65         (IXP425_PCI_CSR_BASE + (x))
66 #define CSR_WRITE_4(x, v)       *(volatile uint32_t *) \
67         (IXP425_PCI_CSR_BASE + (x)) = (v)
68
69 /* Proto types for all the bus_space structure functions */
70 bs_protos(ixp425_pci);
71 bs_protos(ixp425_pci_io);
72 bs_protos(ixp425_pci_mem);
73
74 /* special I/O functions */
75 static u_int8_t  _pci_io_bs_r_1(void *, bus_space_handle_t, bus_size_t);
76 static u_int16_t _pci_io_bs_r_2(void *, bus_space_handle_t, bus_size_t);
77 static u_int32_t _pci_io_bs_r_4(void *, bus_space_handle_t, bus_size_t);
78
79 static void _pci_io_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
80 static void _pci_io_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t);
81 static void _pci_io_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t);
82
83 #ifdef __ARMEB__
84 static u_int8_t  _pci_io_bs_r_1_s(void *, bus_space_handle_t, bus_size_t);
85 static u_int16_t _pci_io_bs_r_2_s(void *, bus_space_handle_t, bus_size_t);
86 static u_int32_t _pci_io_bs_r_4_s(void *, bus_space_handle_t, bus_size_t);
87
88 static void _pci_io_bs_w_1_s(void *, bus_space_handle_t, bus_size_t, u_int8_t);
89 static void _pci_io_bs_w_2_s(void *, bus_space_handle_t, bus_size_t, u_int16_t);
90 static void _pci_io_bs_w_4_s(void *, bus_space_handle_t, bus_size_t, u_int32_t);
91
92 static u_int8_t  _pci_mem_bs_r_1(void *, bus_space_handle_t, bus_size_t);
93 static u_int16_t _pci_mem_bs_r_2(void *, bus_space_handle_t, bus_size_t);
94 static u_int32_t _pci_mem_bs_r_4(void *, bus_space_handle_t, bus_size_t);
95
96 static void _pci_mem_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
97 static void _pci_mem_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t);
98 static void _pci_mem_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t);
99 #endif
100
101 struct bus_space ixp425_pci_io_bs_tag_template = {
102         /* mapping/unmapping */
103         .bs_map         = ixp425_pci_io_bs_map,
104         .bs_unmap       = ixp425_pci_io_bs_unmap,
105         .bs_subregion   = ixp425_pci_bs_subregion,
106
107         .bs_alloc       = ixp425_pci_io_bs_alloc,
108         .bs_free        = ixp425_pci_io_bs_free,
109
110         /* barrier */
111         .bs_barrier     = ixp425_pci_bs_barrier,
112
113         /*
114          * IXP425 processor does not have PCI I/O windows
115          */
116         /* read (single) */
117         .bs_r_1         = _pci_io_bs_r_1,
118         .bs_r_2         = _pci_io_bs_r_2,
119         .bs_r_4         = _pci_io_bs_r_4,
120
121         /* write (single) */
122         .bs_w_1         = _pci_io_bs_w_1,
123         .bs_w_2         = _pci_io_bs_w_2,
124         .bs_w_4         = _pci_io_bs_w_4,
125
126 #ifdef __ARMEB__
127         .bs_r_1_s       = _pci_io_bs_r_1_s,
128         .bs_r_2_s       = _pci_io_bs_r_2_s,
129         .bs_r_4_s       = _pci_io_bs_r_4_s,
130
131         .bs_w_1_s       = _pci_io_bs_w_1_s,
132         .bs_w_2_s       = _pci_io_bs_w_2_s,
133         .bs_w_4_s       = _pci_io_bs_w_4_s,
134 #else
135         .bs_r_1_s       = _pci_io_bs_r_1,
136         .bs_r_2_s       = _pci_io_bs_r_2,
137         .bs_r_4_s       = _pci_io_bs_r_4,
138
139         .bs_w_1_s       = _pci_io_bs_w_1,
140         .bs_w_2_s       = _pci_io_bs_w_2,
141         .bs_w_4_s       = _pci_io_bs_w_4,
142 #endif
143 };
144
145 void
146 ixp425_io_bs_init(bus_space_tag_t bs, void *cookie)
147 {
148         *bs = ixp425_pci_io_bs_tag_template;
149         bs->bs_cookie = cookie;
150 }
151
152 struct bus_space ixp425_pci_mem_bs_tag_template = {
153         /* mapping/unmapping */
154         .bs_map         = ixp425_pci_mem_bs_map,
155         .bs_unmap       = ixp425_pci_mem_bs_unmap,
156         .bs_subregion   = ixp425_pci_bs_subregion,
157
158         .bs_alloc       = ixp425_pci_mem_bs_alloc,
159         .bs_free        = ixp425_pci_mem_bs_free,
160
161         /* barrier */
162         .bs_barrier     = ixp425_pci_bs_barrier,
163
164 #ifdef __ARMEB__
165         /* read (single) */
166         .bs_r_1_s       = _pci_mem_bs_r_1,
167         .bs_r_2_s       = _pci_mem_bs_r_2,
168         .bs_r_4_s       = _pci_mem_bs_r_4,
169
170         .bs_r_1 =       ixp425_pci_mem_bs_r_1,
171         .bs_r_2 =       ixp425_pci_mem_bs_r_2,
172         .bs_r_4 =       ixp425_pci_mem_bs_r_4,
173
174         /* write (single) */
175         .bs_w_1_s       = _pci_mem_bs_w_1,
176         .bs_w_2_s       = _pci_mem_bs_w_2,
177         .bs_w_4_s       = _pci_mem_bs_w_4,
178
179         .bs_w_1 =        ixp425_pci_mem_bs_w_1,
180         .bs_w_2 =       ixp425_pci_mem_bs_w_2,
181         .bs_w_4 =       ixp425_pci_mem_bs_w_4,
182 #else
183         /* read (single) */
184         .bs_r_1         = ixp425_pci_mem_bs_r_1,
185         .bs_r_2         = ixp425_pci_mem_bs_r_2,
186         .bs_r_4         = ixp425_pci_mem_bs_r_4,
187         .bs_r_1_s       = ixp425_pci_mem_bs_r_1,
188         .bs_r_2_s       = ixp425_pci_mem_bs_r_2,
189         .bs_r_4_s       = ixp425_pci_mem_bs_r_4,
190
191         /* write (single) */
192         .bs_w_1         = ixp425_pci_mem_bs_w_1,
193         .bs_w_2         = ixp425_pci_mem_bs_w_2,
194         .bs_w_4         = ixp425_pci_mem_bs_w_4,
195         .bs_w_1_s       = ixp425_pci_mem_bs_w_1,
196         .bs_w_2_s       = ixp425_pci_mem_bs_w_2,
197         .bs_w_4_s       = ixp425_pci_mem_bs_w_4,
198 #endif
199 };
200
201 void
202 ixp425_mem_bs_init(bus_space_tag_t bs, void *cookie)
203 {
204         *bs = ixp425_pci_mem_bs_tag_template;
205         bs->bs_cookie = cookie;
206 }
207
208 /* common routine */
209 int
210 ixp425_pci_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
211         bus_size_t size, bus_space_handle_t *nbshp)
212 {
213         *nbshp = bsh + offset;
214         return (0);
215 }
216
217 void
218 ixp425_pci_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
219     bus_size_t len, int flags)
220 {
221         /* NULL */
222 }       
223
224 /* io bs */
225 int
226 ixp425_pci_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
227         int cacheable, bus_space_handle_t *bshp)
228 {
229         *bshp = bpa;
230         return (0);
231 }
232
233 void
234 ixp425_pci_io_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
235 {
236         /* Nothing to do. */
237 }
238
239 int
240 ixp425_pci_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
241         bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
242         bus_addr_t *bpap, bus_space_handle_t *bshp)
243 {
244         panic("ixp425_pci_io_bs_alloc(): not implemented\n");
245 }
246
247 void
248 ixp425_pci_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
249 {
250         panic("ixp425_pci_io_bs_free(): not implemented\n");
251 }
252
253 /* special I/O functions */
254 static __inline u_int32_t
255 _bs_r(void *v, bus_space_handle_t ioh, bus_size_t off, u_int32_t be)
256 {
257         u_int32_t data;
258
259         CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
260         CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_READ);
261         data = CSR_READ_4(PCI_NP_RDATA);
262         if (CSR_READ_4(PCI_ISR) & ISR_PFE)
263                 CSR_WRITE_4(PCI_ISR, ISR_PFE);
264
265         return data;
266 }
267
268 static u_int8_t
269 _pci_io_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off)
270 {
271         u_int32_t data, n, be;
272
273         n = (ioh + off) % 4;
274         be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
275         data = _bs_r(v, ioh, off, be);
276
277         return data >> (8 * n);
278 }
279
280 static u_int16_t
281 _pci_io_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off)
282 {
283         u_int32_t data, n, be;
284
285         n = (ioh + off) % 4;
286         be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
287         data = _bs_r(v, ioh, off, be);
288
289         return data >> (8 * n);
290 }
291
292 static u_int32_t
293 _pci_io_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off)
294 {
295         u_int32_t data;
296
297         data = _bs_r(v, ioh, off, 0);
298         return data;
299 }
300
301 #ifdef __ARMEB__
302 static u_int8_t
303 _pci_io_bs_r_1_s(void *v, bus_space_handle_t ioh, bus_size_t off)
304 {
305         u_int32_t data, n, be;
306
307         n = (ioh + off) % 4;
308         be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
309         data = _bs_r(v, ioh, off, be);
310
311         return data >> (8 * n);
312 }
313
314 static u_int16_t
315 _pci_io_bs_r_2_s(void *v, bus_space_handle_t ioh, bus_size_t off)
316 {
317         u_int32_t data, n, be;
318
319         n = (ioh + off) % 4;
320         be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
321         data = _bs_r(v, ioh, off, be);
322
323         return data >> (8 * n);
324 }
325
326 static u_int32_t
327 _pci_io_bs_r_4_s(void *v, bus_space_handle_t ioh, bus_size_t off)
328 {
329         u_int32_t data;
330
331         data = _bs_r(v, ioh, off, 0);
332         return le32toh(data);
333 }
334 #endif /* __ARMEB__ */
335
336 static __inline void
337 _bs_w(void *v, bus_space_handle_t ioh, bus_size_t off,
338         u_int32_t be, u_int32_t data)
339 {
340         CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
341         CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_WRITE);
342         CSR_WRITE_4(PCI_NP_WDATA, data);
343         if (CSR_READ_4(PCI_ISR) & ISR_PFE)
344                 CSR_WRITE_4(PCI_ISR, ISR_PFE);
345 }
346
347 static void
348 _pci_io_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off,
349         u_int8_t val)
350 {
351         u_int32_t data, n, be;
352
353         n = (ioh + off) % 4;
354         be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
355         data = val << (8 * n);
356         _bs_w(v, ioh, off, be, data);
357 }
358
359 static void
360 _pci_io_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off,
361         u_int16_t val)
362 {
363         u_int32_t data, n, be;
364
365         n = (ioh + off) % 4;
366         be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
367         data = val << (8 * n);
368         _bs_w(v, ioh, off, be, data);
369 }
370
371 static void
372 _pci_io_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off,
373         u_int32_t val)
374 {
375         _bs_w(v, ioh, off, 0, val);
376 }
377
378 #ifdef __ARMEB__
379 static void
380 _pci_io_bs_w_1_s(void *v, bus_space_handle_t ioh, bus_size_t off,
381         u_int8_t val)
382 {
383         u_int32_t data, n, be;
384
385         n = (ioh + off) % 4;
386         be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
387         data = val << (8 * n);
388         _bs_w(v, ioh, off, be, data);
389 }
390
391 static void
392 _pci_io_bs_w_2_s(void *v, bus_space_handle_t ioh, bus_size_t off,
393         u_int16_t val)
394 {
395         u_int32_t data, n, be;
396
397         n = (ioh + off) % 4;
398         be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
399         data = val << (8 * n);
400         _bs_w(v, ioh, off, be, data);
401 }
402
403 static void
404 _pci_io_bs_w_4_s(void *v, bus_space_handle_t ioh, bus_size_t off,
405         u_int32_t val)
406 {
407         _bs_w(v, ioh, off, 0, htole32(val));
408 }
409 #endif /* __ARMEB__ */
410
411 /* mem bs */
412 int
413 ixp425_pci_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
414               int cacheable, bus_space_handle_t *bshp)
415 {
416         vm_paddr_t pa, endpa;
417
418         pa = trunc_page(bpa);
419         endpa = round_page(bpa + size);
420
421         *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa);
422
423         return (0);
424 }
425
426 void
427 ixp425_pci_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
428 {
429         vm_offset_t va, endva;
430
431         va = trunc_page((vm_offset_t)t);
432         endva = va + round_page(size);
433
434         /* Free the kernel virtual mapping. */
435         kmem_free(kernel_map, va, endva - va);
436 }
437
438 int
439 ixp425_pci_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
440         bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
441         bus_addr_t *bpap, bus_space_handle_t *bshp)
442 {
443         panic("ixp425_mem_bs_alloc(): not implemented\n");
444 }
445
446 void    
447 ixp425_pci_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
448 {
449         panic("ixp425_mem_bs_free(): not implemented\n");
450 }
451
452 #ifdef __ARMEB__
453 static u_int8_t
454 _pci_mem_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off)
455 {
456         return ixp425_pci_mem_bs_r_1(v, ioh, off);
457 }
458
459 static u_int16_t
460 _pci_mem_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off)
461 {
462         return (ixp425_pci_mem_bs_r_2(v, ioh, off));
463 }
464
465 static u_int32_t
466 _pci_mem_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off)
467 {
468         u_int32_t data;
469
470         data = ixp425_pci_mem_bs_r_4(v, ioh, off);
471         return (le32toh(data));
472 }
473
474 static void
475 _pci_mem_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off,
476         u_int8_t val)
477 {
478         ixp425_pci_mem_bs_w_1(v, ioh, off, val);
479 }
480
481 static void
482 _pci_mem_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off,
483         u_int16_t val)
484 {
485         ixp425_pci_mem_bs_w_2(v, ioh, off, val);
486 }
487
488 static void
489 _pci_mem_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off,
490         u_int32_t val)
491 {
492         ixp425_pci_mem_bs_w_4(v, ioh, off, htole32(val));
493 }
494 #endif /* __ARMEB__ */
495
496 /* End of ixp425_pci_space.c */