xref: /netbsd-src/lib/libarch/alpha/alpha_pci_io.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: alpha_pci_io.c,v 1.1 2000/02/26 18:59:36 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Support for x86-style programmed I/O to PCI/EISA/ISA I/O space.  This
41  * is currently used to provide such support for XFree86.  In a perfect
42  * world, this would go away in favor of a real bus space mapping framework.
43  */
44 
45 #include <sys/param.h>
46 
47 #include <machine/bwx.h>
48 #include <machine/sysarch.h>
49 #include <machine/pio.h>
50 
51 #include <err.h>
52 #include <stdlib.h>
53 
54 struct alpha_bus_window *alpha_pci_io_windows;
55 int alpha_pci_io_window_count;
56 
57 __inline struct alpha_bus_window *alpha_pci_io_findwindow __P((bus_addr_t));
58 __inline u_int32_t *alpha_pci_io_swiz __P((bus_addr_t, int));
59 
60 u_int8_t	alpha_pci_io_swiz_inb __P((bus_addr_t));
61 u_int16_t	alpha_pci_io_swiz_inw __P((bus_addr_t));
62 u_int32_t	alpha_pci_io_swiz_inl __P((bus_addr_t));
63 void		alpha_pci_io_swiz_outb __P((bus_addr_t, u_int8_t));
64 void		alpha_pci_io_swiz_outw __P((bus_addr_t, u_int16_t));
65 void		alpha_pci_io_swiz_outl __P((bus_addr_t, u_int32_t));
66 
67 const struct alpha_pci_io_ops alpha_pci_io_swiz_ops = {
68 	alpha_pci_io_swiz_inb,
69 	alpha_pci_io_swiz_inw,
70 	alpha_pci_io_swiz_inl,
71 	alpha_pci_io_swiz_outb,
72 	alpha_pci_io_swiz_outw,
73 	alpha_pci_io_swiz_outl,
74 };
75 
76 u_int8_t	alpha_pci_io_bwx_inb __P((bus_addr_t));
77 u_int16_t	alpha_pci_io_bwx_inw __P((bus_addr_t));
78 u_int32_t	alpha_pci_io_bwx_inl __P((bus_addr_t));
79 void		alpha_pci_io_bwx_outb __P((bus_addr_t, u_int8_t));
80 void		alpha_pci_io_bwx_outw __P((bus_addr_t, u_int16_t));
81 void		alpha_pci_io_bwx_outl __P((bus_addr_t, u_int32_t));
82 
83 const struct alpha_pci_io_ops alpha_pci_io_bwx_ops = {
84 	alpha_pci_io_bwx_inb,
85 	alpha_pci_io_bwx_inw,
86 	alpha_pci_io_bwx_inl,
87 	alpha_pci_io_bwx_outb,
88 	alpha_pci_io_bwx_outw,
89 	alpha_pci_io_bwx_outl,
90 };
91 
92 const struct alpha_pci_io_ops *alpha_pci_io_switch;
93 
94 int
95 alpha_pci_io_enable(onoff)
96 	int onoff;
97 {
98 	struct alpha_bus_window *abw;
99 	int i, count;
100 
101 	if (onoff == 0 && alpha_pci_io_windows != NULL) {
102 		for (i = 0; i < alpha_pci_io_window_count; i++)
103 			alpha_bus_unmapwindow(&alpha_pci_io_windows[i]);
104 		free(alpha_pci_io_windows);
105 		alpha_pci_io_windows = NULL;
106 		alpha_pci_io_window_count = 0;
107 		alpha_pci_io_switch = NULL;
108 		return (0);
109 	} else if (onoff == 0)
110 		return (0);
111 	else if (alpha_pci_io_windows != NULL)
112 		return (0);
113 
114 	count = alpha_bus_getwindows(ALPHA_BUS_TYPE_PCI_IO, &abw);
115 	if (count <= 0)
116 		return (-1);
117 
118 	for (i = 0; i < count; i++) {
119 		if (alpha_bus_mapwindow(&abw[i]) == -1) {
120 			free(abw);
121 			return (-1);
122 		}
123 	}
124 
125 	alpha_pci_io_windows = abw;
126 	alpha_pci_io_window_count = count;
127 
128 	if (abw->abw_abst.abst_flags & ABST_BWX)
129 		alpha_pci_io_switch = &alpha_pci_io_bwx_ops;
130 	else
131 		alpha_pci_io_switch = &alpha_pci_io_swiz_ops;
132 
133 	return (0);
134 }
135 
136 __inline struct alpha_bus_window *
137 alpha_pci_io_findwindow(ioaddr)
138 	bus_addr_t ioaddr;
139 {
140 	struct alpha_bus_window *abw;
141 	int i;
142 
143 	/* XXX Cache the last hit? */
144 
145 	for (i = 0; i < alpha_pci_io_window_count; i++) {
146 		abw = &alpha_pci_io_windows[i];
147 		if (ioaddr >= abw->abw_abst.abst_bus_start &&
148 		    ioaddr <= abw->abw_abst.abst_bus_end)
149 			return (abw);
150 	}
151 
152 	warnx("alpha_pci_io_findwindow: no window for 0x%lx, ABORTING!",
153 	    (u_long) ioaddr);
154 	abort();
155 }
156 
157 __inline u_int32_t *
158 alpha_pci_io_swiz(ioaddr, size)
159 	bus_addr_t ioaddr;
160 	int size;
161 {
162 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
163 	u_int32_t *port;
164 
165 	port = (u_int32_t *) (abw->abw_addr +
166 	    (((ioaddr - abw->abw_abst.abst_bus_start) <<
167 	      abw->abw_abst.abst_addr_shift) |
168 	     (size << abw->abw_abst.abst_size_shift)));
169 
170 	return (port);
171 }
172 
173 u_int8_t
174 alpha_pci_io_swiz_inb(ioaddr)
175 	bus_addr_t ioaddr;
176 {
177 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 0);
178 	int offset = ioaddr & 3;
179 
180 	alpha_mb();
181 
182 	return ((*port >> (8 * offset)) & 0xff);
183 }
184 
185 u_int16_t
186 alpha_pci_io_swiz_inw(ioaddr)
187 	bus_addr_t ioaddr;
188 {
189 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 1);
190 	int offset = ioaddr & 3;
191 
192 	alpha_mb();
193 
194 	return ((*port >> (8 * offset)) & 0xffff);
195 }
196 
197 u_int32_t
198 alpha_pci_io_swiz_inl(ioaddr)
199 	bus_addr_t ioaddr;
200 {
201 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 3);
202 
203 	alpha_mb();
204 
205 	return (*port);
206 }
207 
208 void
209 alpha_pci_io_swiz_outb(ioaddr, val)
210 	bus_addr_t ioaddr;
211 	u_int8_t val;
212 {
213 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 0);
214 	int offset = ioaddr & 3;
215 	u_int32_t nval = val << (8 * offset);
216 
217 	*port = nval;
218 	alpha_mb();
219 }
220 
221 void
222 alpha_pci_io_swiz_outw(ioaddr, val)
223 	bus_addr_t ioaddr;
224 	u_int16_t val;
225 {
226 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 1);
227 	int offset = ioaddr & 3;
228 	u_int32_t nval = val << (8 * offset);
229 
230 	*port = nval;
231 	alpha_mb();
232 }
233 
234 void
235 alpha_pci_io_swiz_outl(ioaddr, val)
236 	bus_addr_t ioaddr;
237 	u_int32_t val;
238 {
239 	u_int32_t *port = alpha_pci_io_swiz(ioaddr, 3);
240 
241 	*port = val;
242 	alpha_mb();
243 }
244 
245 /*
246  * The following functions are used only on EV56 and greater CPUs,
247  * and the assembler requires going to EV56 mode in order to emit
248  * these instructions.
249  */
250 __asm(".arch ev56");
251 
252 u_int8_t
253 alpha_pci_io_bwx_inb(ioaddr)
254 	bus_addr_t ioaddr;
255 {
256 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
257 	u_int8_t *port = (u_int8_t *) (abw->abw_addr +
258 	    (ioaddr - abw->abw_abst.abst_bus_start));
259 
260 	alpha_mb();
261 
262 	return (alpha_ldbu(port));
263 }
264 
265 u_int16_t
266 alpha_pci_io_bwx_inw(ioaddr)
267 	bus_addr_t ioaddr;
268 {
269 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
270 	u_int16_t *port = (u_int16_t *) (abw->abw_addr +
271 	    (ioaddr - abw->abw_abst.abst_bus_start));
272 
273 	alpha_mb();
274 
275 	return (alpha_ldwu(port));
276 }
277 
278 u_int32_t
279 alpha_pci_io_bwx_inl(ioaddr)
280 	bus_addr_t ioaddr;
281 {
282 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
283 	u_int32_t *port = (u_int32_t *) (abw->abw_addr +
284 	    (ioaddr - abw->abw_abst.abst_bus_start));
285 
286 	alpha_mb();
287 
288 	return (*port);
289 }
290 
291 void
292 alpha_pci_io_bwx_outb(ioaddr, val)
293 	bus_addr_t ioaddr;
294 	u_int8_t val;
295 {
296 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
297 	u_int8_t *port = (u_int8_t *) (abw->abw_addr +
298 	    (ioaddr - abw->abw_abst.abst_bus_start));
299 
300 	alpha_stb(port, val);
301 	alpha_mb();
302 }
303 
304 void
305 alpha_pci_io_bwx_outw(ioaddr, val)
306 	bus_addr_t ioaddr;
307 	u_int16_t val;
308 {
309 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
310 	u_int16_t *port = (u_int16_t *) (abw->abw_addr +
311 	    (ioaddr - abw->abw_abst.abst_bus_start));
312 
313 	alpha_stw(port, val);
314 	alpha_mb();
315 }
316 
317 void
318 alpha_pci_io_bwx_outl(ioaddr, val)
319 	bus_addr_t ioaddr;
320 	u_int32_t val;
321 {
322 	struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr);
323 	u_int32_t *port = (u_int32_t *) (abw->abw_addr +
324 	    (ioaddr - abw->abw_abst.abst_bus_start));
325 
326 	*port = val;
327 	alpha_mb();
328 }
329