1 /* $NetBSD: alpha_pci_io.c,v 1.4 2007/03/05 03:05:16 mrg Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Support for x86-style programmed I/O to PCI/EISA/ISA I/O space. This
34 * is currently used to provide such support for XFree86. In a perfect
35 * world, this would go away in favor of a real bus space mapping framework.
38 #include <sys/param.h>
40 #include <machine/bwx.h>
41 #include <machine/sysarch.h>
42 #include <machine/pio.h>
47 struct alpha_bus_window
*alpha_pci_io_windows
;
48 int alpha_pci_io_window_count
;
50 uint8_t alpha_pci_io_swiz_inb(bus_addr_t
);
51 uint16_t alpha_pci_io_swiz_inw(bus_addr_t
);
52 uint32_t alpha_pci_io_swiz_inl(bus_addr_t
);
53 void alpha_pci_io_swiz_outb(bus_addr_t
, uint8_t);
54 void alpha_pci_io_swiz_outw(bus_addr_t
, uint16_t);
55 void alpha_pci_io_swiz_outl(bus_addr_t
, uint32_t);
57 const struct alpha_pci_io_ops alpha_pci_io_swiz_ops
= {
58 alpha_pci_io_swiz_inb
,
59 alpha_pci_io_swiz_inw
,
60 alpha_pci_io_swiz_inl
,
61 alpha_pci_io_swiz_outb
,
62 alpha_pci_io_swiz_outw
,
63 alpha_pci_io_swiz_outl
,
66 uint8_t alpha_pci_io_bwx_inb(bus_addr_t
);
67 uint16_t alpha_pci_io_bwx_inw(bus_addr_t
);
68 uint32_t alpha_pci_io_bwx_inl(bus_addr_t
);
69 void alpha_pci_io_bwx_outb(bus_addr_t
, uint8_t);
70 void alpha_pci_io_bwx_outw(bus_addr_t
, uint16_t);
71 void alpha_pci_io_bwx_outl(bus_addr_t
, uint32_t);
73 const struct alpha_pci_io_ops alpha_pci_io_bwx_ops
= {
77 alpha_pci_io_bwx_outb
,
78 alpha_pci_io_bwx_outw
,
79 alpha_pci_io_bwx_outl
,
82 const struct alpha_pci_io_ops
*alpha_pci_io_switch
;
85 alpha_pci_io_enable(int onoff
)
87 struct alpha_bus_window
*abw
;
90 if (onoff
== 0 && alpha_pci_io_windows
!= NULL
) {
91 for (i
= 0; i
< alpha_pci_io_window_count
; i
++)
92 alpha_bus_unmapwindow(&alpha_pci_io_windows
[i
]);
93 free(alpha_pci_io_windows
);
94 alpha_pci_io_windows
= NULL
;
95 alpha_pci_io_window_count
= 0;
96 alpha_pci_io_switch
= NULL
;
98 } else if (onoff
== 0)
100 else if (alpha_pci_io_windows
!= NULL
)
103 count
= alpha_bus_getwindows(ALPHA_BUS_TYPE_PCI_IO
, &abw
);
107 for (i
= 0; i
< count
; i
++) {
108 if (alpha_bus_mapwindow(&abw
[i
]) == -1) {
114 alpha_pci_io_windows
= abw
;
115 alpha_pci_io_window_count
= count
;
117 if (abw
->abw_abst
.abst_flags
& ABST_BWX
)
118 alpha_pci_io_switch
= &alpha_pci_io_bwx_ops
;
120 alpha_pci_io_switch
= &alpha_pci_io_swiz_ops
;
125 static inline struct alpha_bus_window
*
126 alpha_pci_io_findwindow(bus_addr_t ioaddr
)
128 struct alpha_bus_window
*abw
;
131 /* XXX Cache the last hit? */
133 for (i
= 0; i
< alpha_pci_io_window_count
; i
++) {
134 abw
= &alpha_pci_io_windows
[i
];
135 if (ioaddr
>= abw
->abw_abst
.abst_bus_start
&&
136 ioaddr
<= abw
->abw_abst
.abst_bus_end
)
140 warnx("alpha_pci_io_findwindow: no window for 0x%lx, ABORTING!",
146 static inline uint32_t *
147 alpha_pci_io_swiz(bus_addr_t ioaddr
, int size
)
149 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
153 port
= (uint32_t *) ((char *)abw
->abw_addr
+
154 (((ioaddr
- abw
->abw_abst
.abst_bus_start
) <<
155 abw
->abw_abst
.abst_addr_shift
) |
156 (size
<< abw
->abw_abst
.abst_size_shift
)));
162 alpha_pci_io_swiz_inb(bus_addr_t ioaddr
)
164 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 0);
165 bus_addr_t offset
= ioaddr
& 3;
169 return ((*port
>> (8 * offset
)) & 0xff);
173 alpha_pci_io_swiz_inw(bus_addr_t ioaddr
)
175 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 1);
176 bus_addr_t offset
= ioaddr
& 3;
180 return ((*port
>> (8 * offset
)) & 0xffff);
184 alpha_pci_io_swiz_inl(bus_addr_t ioaddr
)
186 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 3);
194 alpha_pci_io_swiz_outb(bus_addr_t ioaddr
, uint8_t val
)
196 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 0);
197 bus_addr_t offset
= ioaddr
& 3;
198 uint32_t nval
= ((uint32_t)val
) << (8 * offset
);
205 alpha_pci_io_swiz_outw(bus_addr_t ioaddr
, uint16_t val
)
207 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 1);
208 bus_addr_t offset
= ioaddr
& 3;
209 uint32_t nval
= ((uint32_t)val
) << (8 * offset
);
216 alpha_pci_io_swiz_outl(bus_addr_t ioaddr
, uint32_t val
)
218 uint32_t *port
= alpha_pci_io_swiz(ioaddr
, 3);
225 * The following functions are used only on EV56 and greater CPUs,
226 * and the assembler requires going to EV56 mode in order to emit
227 * these instructions.
232 alpha_pci_io_bwx_inb(bus_addr_t ioaddr
)
234 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
235 uint8_t *port
= (uint8_t *) ((char *)abw
->abw_addr
+
236 (ioaddr
- abw
->abw_abst
.abst_bus_start
));
240 return (alpha_ldbu(port
));
244 alpha_pci_io_bwx_inw(bus_addr_t ioaddr
)
246 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
248 uint16_t *port
= (uint16_t *) ((char *)abw
->abw_addr
+
249 (ioaddr
- abw
->abw_abst
.abst_bus_start
));
253 return (alpha_ldwu(port
));
257 alpha_pci_io_bwx_inl(bus_addr_t ioaddr
)
259 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
261 uint32_t *port
= (uint32_t *) ((char *)abw
->abw_addr
+
262 (ioaddr
- abw
->abw_abst
.abst_bus_start
));
270 alpha_pci_io_bwx_outb(bus_addr_t ioaddr
, uint8_t val
)
272 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
273 uint8_t *port
= (uint8_t *) ((char *)abw
->abw_addr
+
274 (ioaddr
- abw
->abw_abst
.abst_bus_start
));
276 alpha_stb(port
, val
);
281 alpha_pci_io_bwx_outw(bus_addr_t ioaddr
, uint16_t val
)
283 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
285 uint16_t *port
= (uint16_t *) ((char *)abw
->abw_addr
+
286 (ioaddr
- abw
->abw_abst
.abst_bus_start
));
288 alpha_stw(port
, val
);
293 alpha_pci_io_bwx_outl(bus_addr_t ioaddr
, uint32_t val
)
295 struct alpha_bus_window
*abw
= alpha_pci_io_findwindow(ioaddr
);
297 uint32_t *port
= (uint32_t *) ((char *)abw
->abw_addr
+
298 (ioaddr
- abw
->abw_abst
.abst_bus_start
));