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