alpha_pci_io.c revision 1.1
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
54struct alpha_bus_window *alpha_pci_io_windows;
55int 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
60u_int8_t	alpha_pci_io_swiz_inb __P((bus_addr_t));
61u_int16_t	alpha_pci_io_swiz_inw __P((bus_addr_t));
62u_int32_t	alpha_pci_io_swiz_inl __P((bus_addr_t));
63void		alpha_pci_io_swiz_outb __P((bus_addr_t, u_int8_t));
64void		alpha_pci_io_swiz_outw __P((bus_addr_t, u_int16_t));
65void		alpha_pci_io_swiz_outl __P((bus_addr_t, u_int32_t));
66
67const 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
76u_int8_t	alpha_pci_io_bwx_inb __P((bus_addr_t));
77u_int16_t	alpha_pci_io_bwx_inw __P((bus_addr_t));
78u_int32_t	alpha_pci_io_bwx_inl __P((bus_addr_t));
79void		alpha_pci_io_bwx_outb __P((bus_addr_t, u_int8_t));
80void		alpha_pci_io_bwx_outw __P((bus_addr_t, u_int16_t));
81void		alpha_pci_io_bwx_outl __P((bus_addr_t, u_int32_t));
82
83const 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
92const struct alpha_pci_io_ops *alpha_pci_io_switch;
93
94int
95alpha_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 *
137alpha_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 *
158alpha_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
173u_int8_t
174alpha_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
185u_int16_t
186alpha_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
197u_int32_t
198alpha_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
208void
209alpha_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
221void
222alpha_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
234void
235alpha_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
252u_int8_t
253alpha_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
265u_int16_t
266alpha_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
278u_int32_t
279alpha_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
291void
292alpha_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
304void
305alpha_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
317void
318alpha_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