vlpci.c revision 1.1 1 1.1 jakllsch /* $NetBSD: vlpci.c,v 1.1 2017/02/17 18:07:51 jakllsch Exp $ */
2 1.1 jakllsch
3 1.1 jakllsch /*
4 1.1 jakllsch * Copyright (c) 2017 Jonathan A. Kollasch
5 1.1 jakllsch * All rights reserved.
6 1.1 jakllsch *
7 1.1 jakllsch * Redistribution and use in source and binary forms, with or without
8 1.1 jakllsch * modification, are permitted provided that the following conditions
9 1.1 jakllsch * are met:
10 1.1 jakllsch * 1. Redistributions of source code must retain the above copyright
11 1.1 jakllsch * notice, this list of conditions and the following disclaimer.
12 1.1 jakllsch * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jakllsch * notice, this list of conditions and the following disclaimer in the
14 1.1 jakllsch * documentation and/or other materials provided with the distribution.
15 1.1 jakllsch *
16 1.1 jakllsch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 1.1 jakllsch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 jakllsch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 jakllsch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 1.1 jakllsch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 1.1 jakllsch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 1.1 jakllsch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 1.1 jakllsch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 1.1 jakllsch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 1.1 jakllsch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 1.1 jakllsch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.1 jakllsch */
28 1.1 jakllsch
29 1.1 jakllsch #include <sys/cdefs.h>
30 1.1 jakllsch __KERNEL_RCSID(0, "$NetBSD: vlpci.c,v 1.1 2017/02/17 18:07:51 jakllsch Exp $");
31 1.1 jakllsch
32 1.1 jakllsch #include "opt_pci.h"
33 1.1 jakllsch #include "pci.h"
34 1.1 jakllsch
35 1.1 jakllsch #include <sys/param.h>
36 1.1 jakllsch #include <sys/bus.h>
37 1.1 jakllsch #include <sys/device.h>
38 1.1 jakllsch #include <sys/extent.h>
39 1.1 jakllsch #include <sys/mutex.h>
40 1.1 jakllsch
41 1.1 jakllsch #include <dev/isa/isavar.h>
42 1.1 jakllsch
43 1.1 jakllsch #include <dev/ofw/openfirm.h>
44 1.1 jakllsch
45 1.1 jakllsch #include <dev/pci/pcivar.h>
46 1.1 jakllsch #include <dev/pci/pciconf.h>
47 1.1 jakllsch #include <arm/pci_machdep.h>
48 1.1 jakllsch
49 1.1 jakllsch static int vlpci_match(device_t, struct cfdata *, void *);
50 1.1 jakllsch static void vlpci_attach(device_t, device_t, void *);
51 1.1 jakllsch
52 1.1 jakllsch static void vlpci_pc_attach_hook(device_t, device_t,
53 1.1 jakllsch struct pcibus_attach_args *);
54 1.1 jakllsch static int vlpci_pc_bus_maxdevs(void *, int);
55 1.1 jakllsch static pcitag_t vlpci_pc_make_tag(void *, int, int, int);
56 1.1 jakllsch static void vlpci_pc_decompose_tag(void *, pcitag_t, int *, int *, int *);
57 1.1 jakllsch static pcireg_t vlpci_pc_conf_read(void *, pcitag_t, int);
58 1.1 jakllsch static void vlpci_pc_conf_write(void *, pcitag_t, int, pcireg_t);
59 1.1 jakllsch #ifdef __HAVE_PCI_CONF_HOOK
60 1.1 jakllsch static int vlpci_pc_conf_hook(void *, int, int, int, pcireg_t);
61 1.1 jakllsch #endif
62 1.1 jakllsch static void vlpci_pc_conf_interrupt(void *, int, int, int, int, int *);
63 1.1 jakllsch
64 1.1 jakllsch struct vlpci_softc {
65 1.1 jakllsch device_t sc_dev;
66 1.1 jakllsch kmutex_t sc_lock;
67 1.1 jakllsch bus_space_handle_t sc_conf_ioh;
68 1.1 jakllsch bus_space_handle_t sc_reg_ioh;
69 1.1 jakllsch struct arm32_pci_chipset sc_pc;
70 1.1 jakllsch };
71 1.1 jakllsch
72 1.1 jakllsch CFATTACH_DECL_NEW(vlpci, sizeof(struct vlpci_softc),
73 1.1 jakllsch vlpci_match, vlpci_attach, NULL, NULL);
74 1.1 jakllsch
75 1.1 jakllsch static const char * const compat_strings[] = { "via,vt82c505", NULL };
76 1.1 jakllsch
77 1.1 jakllsch static void
78 1.1 jakllsch regwrite_1(struct vlpci_softc * const sc, uint8_t off, uint8_t val)
79 1.1 jakllsch {
80 1.1 jakllsch mutex_spin_enter(&sc->sc_lock);
81 1.1 jakllsch bus_space_write_1(&isa_io_bs_tag, sc->sc_reg_ioh, 0, off);
82 1.1 jakllsch bus_space_write_1(&isa_io_bs_tag, sc->sc_reg_ioh, 1, val);
83 1.1 jakllsch mutex_spin_exit(&sc->sc_lock);
84 1.1 jakllsch }
85 1.1 jakllsch
86 1.1 jakllsch static int
87 1.1 jakllsch vlpci_match(device_t parent, struct cfdata *match, void *aux)
88 1.1 jakllsch {
89 1.1 jakllsch struct ofbus_attach_args * const oba = aux;
90 1.1 jakllsch
91 1.1 jakllsch if (of_compatible(oba->oba_phandle, compat_strings) < 0)
92 1.1 jakllsch return 0;
93 1.1 jakllsch
94 1.1 jakllsch return 1;
95 1.1 jakllsch }
96 1.1 jakllsch
97 1.1 jakllsch static void
98 1.1 jakllsch vlpci_attach(device_t parent, device_t self, void *aux)
99 1.1 jakllsch {
100 1.1 jakllsch struct vlpci_softc * const sc = device_private(self);
101 1.1 jakllsch pci_chipset_tag_t const pc = &sc->sc_pc;
102 1.1 jakllsch struct pcibus_attach_args pba;
103 1.1 jakllsch
104 1.1 jakllsch aprint_normal("\n");
105 1.1 jakllsch
106 1.1 jakllsch sc->sc_dev = self;
107 1.1 jakllsch mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
108 1.1 jakllsch memset(&pba, 0, sizeof(pba));
109 1.1 jakllsch
110 1.1 jakllsch if (bus_space_map(&isa_io_bs_tag, 0xa8, 0x2,
111 1.1 jakllsch 0, &sc->sc_reg_ioh) != 0) {
112 1.1 jakllsch aprint_error_dev(self, "failed to map 0xa8-9\n");
113 1.1 jakllsch return;
114 1.1 jakllsch }
115 1.1 jakllsch if (bus_space_map(&isa_io_bs_tag, 0xcf8, 0x8,
116 1.1 jakllsch 0, &sc->sc_conf_ioh) != 0) {
117 1.1 jakllsch aprint_error_dev(self, "failed to map 0xcf8-f\n");
118 1.1 jakllsch return;
119 1.1 jakllsch }
120 1.1 jakllsch
121 1.1 jakllsch /* Enable VLB/PCI bridge */
122 1.1 jakllsch regwrite_1(sc, 0x96, 0x18); /* Undocumented by VIA */
123 1.1 jakllsch regwrite_1(sc, 0x93, 0xd0);
124 1.1 jakllsch
125 1.1 jakllsch pc->pc_conf_v = sc;
126 1.1 jakllsch pc->pc_attach_hook = vlpci_pc_attach_hook;
127 1.1 jakllsch pc->pc_bus_maxdevs = vlpci_pc_bus_maxdevs;
128 1.1 jakllsch pc->pc_make_tag = vlpci_pc_make_tag;
129 1.1 jakllsch pc->pc_decompose_tag = vlpci_pc_decompose_tag;
130 1.1 jakllsch pc->pc_conf_read = vlpci_pc_conf_read;
131 1.1 jakllsch pc->pc_conf_write = vlpci_pc_conf_write;
132 1.1 jakllsch #ifdef __HAVE_PCI_CONF_HOOK
133 1.1 jakllsch pc->pc_conf_hook = vlpci_pc_conf_hook;
134 1.1 jakllsch #endif
135 1.1 jakllsch pc->pc_conf_interrupt = vlpci_pc_conf_interrupt;
136 1.1 jakllsch
137 1.1 jakllsch pc->pc_intr_v = sc;
138 1.1 jakllsch
139 1.1 jakllsch pba.pba_flags = PCI_FLAGS_IO_OKAY; /* XXX test this, implement more */
140 1.1 jakllsch pba.pba_pc = &sc->sc_pc;
141 1.1 jakllsch pba.pba_bus = 0;
142 1.1 jakllsch
143 1.1 jakllsch config_found_ia(self, "pcibus", &pba, pcibusprint);
144 1.1 jakllsch }
145 1.1 jakllsch
146 1.1 jakllsch static void
147 1.1 jakllsch vlpci_pc_attach_hook(device_t parent, device_t self,
148 1.1 jakllsch struct pcibus_attach_args *pba)
149 1.1 jakllsch {
150 1.1 jakllsch }
151 1.1 jakllsch
152 1.1 jakllsch static int
153 1.1 jakllsch vlpci_pc_bus_maxdevs(void *v, int busno)
154 1.1 jakllsch {
155 1.1 jakllsch return busno == 0 ? 32 : 0;
156 1.1 jakllsch }
157 1.1 jakllsch
158 1.1 jakllsch static pcitag_t
159 1.1 jakllsch vlpci_pc_make_tag(void *v, int b, int d, int f)
160 1.1 jakllsch {
161 1.1 jakllsch return (b << 16) | (d << 11) | (f << 8);
162 1.1 jakllsch }
163 1.1 jakllsch
164 1.1 jakllsch static void
165 1.1 jakllsch vlpci_pc_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
166 1.1 jakllsch {
167 1.1 jakllsch if (bp)
168 1.1 jakllsch *bp = (tag >> 16) & 0xff;
169 1.1 jakllsch if (dp)
170 1.1 jakllsch *dp = (tag >> 11) & 0x1f;
171 1.1 jakllsch if (fp)
172 1.1 jakllsch *fp = (tag >> 8) & 0x7;
173 1.1 jakllsch }
174 1.1 jakllsch
175 1.1 jakllsch static pcireg_t
176 1.1 jakllsch vlpci_pc_conf_read(void *v, pcitag_t tag, int offset)
177 1.1 jakllsch {
178 1.1 jakllsch struct vlpci_softc * const sc = v;
179 1.1 jakllsch pcireg_t ret;
180 1.1 jakllsch
181 1.1 jakllsch KASSERT((offset & 3) == 0);
182 1.1 jakllsch KASSERT(offset < 0x100);
183 1.1 jakllsch
184 1.1 jakllsch mutex_spin_enter(&sc->sc_lock);
185 1.1 jakllsch bus_space_write_4(&isa_io_bs_tag, sc->sc_conf_ioh, 0,
186 1.1 jakllsch 0x80000000UL|tag|offset);
187 1.1 jakllsch ret = bus_space_read_4(&isa_io_bs_tag, sc->sc_conf_ioh, 4);
188 1.1 jakllsch mutex_spin_exit(&sc->sc_lock);
189 1.1 jakllsch
190 1.1 jakllsch #if 0
191 1.1 jakllsch device_printf(sc->sc_dev, "%s tag %x offset %x ret %x\n",
192 1.1 jakllsch __func__, (unsigned int)tag, offset, ret);
193 1.1 jakllsch #endif
194 1.1 jakllsch
195 1.1 jakllsch return ret;
196 1.1 jakllsch }
197 1.1 jakllsch
198 1.1 jakllsch static void
199 1.1 jakllsch vlpci_pc_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
200 1.1 jakllsch {
201 1.1 jakllsch struct vlpci_softc * const sc = v;
202 1.1 jakllsch
203 1.1 jakllsch KASSERT((offset & 3) == 0);
204 1.1 jakllsch KASSERT(offset < 0x100);
205 1.1 jakllsch
206 1.1 jakllsch #if 0
207 1.1 jakllsch device_printf(sc->sc_dev, "%s tag %x offset %x val %x\n",
208 1.1 jakllsch __func__, (unsigned int)tag, offset, val);
209 1.1 jakllsch #endif
210 1.1 jakllsch
211 1.1 jakllsch mutex_spin_enter(&sc->sc_lock);
212 1.1 jakllsch bus_space_write_4(&isa_io_bs_tag, sc->sc_conf_ioh, 0,
213 1.1 jakllsch 0x80000000UL|tag|offset);
214 1.1 jakllsch bus_space_write_4(&isa_io_bs_tag, sc->sc_conf_ioh, 4, val);
215 1.1 jakllsch mutex_spin_exit(&sc->sc_lock);
216 1.1 jakllsch }
217 1.1 jakllsch
218 1.1 jakllsch #ifdef __HAVE_PCI_CONF_HOOK
219 1.1 jakllsch static int
220 1.1 jakllsch vlpci_pc_conf_hook(void *v, int b, int d, int f, pcireg_t id)
221 1.1 jakllsch {
222 1.1 jakllsch return PCI_CONF_DEFAULT & ~PCI_CONF_ENABLE_BM;
223 1.1 jakllsch }
224 1.1 jakllsch #endif
225 1.1 jakllsch
226 1.1 jakllsch static void
227 1.1 jakllsch vlpci_pc_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz,
228 1.1 jakllsch int *ilinep)
229 1.1 jakllsch {
230 1.1 jakllsch *ilinep = 0xff; /* XXX */
231 1.1 jakllsch }
232