| @@ -1,619 +1,619 @@ | | | @@ -1,619 +1,619 @@ |
1 | /* $NetBSD: p5pb.c,v 1.7 2012/01/24 00:20:45 rkujawa Exp $ */ | | 1 | /* $NetBSD: p5pb.c,v 1.8 2012/01/29 15:32:52 para Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2011, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2011, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Radoslaw Kujawa. | | 8 | * by Radoslaw Kujawa. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 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 | | 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 | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/types.h> | | 32 | #include <sys/types.h> |
33 | #include <sys/param.h> | | 33 | #include <sys/param.h> |
34 | #include <sys/time.h> | | 34 | #include <sys/time.h> |
35 | #include <sys/systm.h> | | 35 | #include <sys/systm.h> |
36 | #include <sys/errno.h> | | 36 | #include <sys/errno.h> |
37 | #include <sys/device.h> | | 37 | #include <sys/device.h> |
38 | #include <sys/malloc.h> | | 38 | #include <sys/malloc.h> |
39 | #include <sys/kmem.h> | | 39 | #include <sys/kmem.h> |
40 | #include <sys/extent.h> | | 40 | #include <sys/extent.h> |
41 | | | 41 | |
42 | #include <uvm/uvm_extern.h> | | 42 | #include <uvm/uvm_extern.h> |
43 | | | 43 | |
44 | #include <machine/bus.h> | | 44 | #include <machine/bus.h> |
45 | #include <machine/cpu.h> | | 45 | #include <machine/cpu.h> |
46 | | | 46 | |
47 | #include <m68k/bus_dma.h> | | 47 | #include <m68k/bus_dma.h> |
48 | #include <amiga/dev/zbusvar.h> | | 48 | #include <amiga/dev/zbusvar.h> |
49 | #include <amiga/dev/p5busvar.h> | | 49 | #include <amiga/dev/p5busvar.h> |
50 | #include <amiga/pci/p5pbreg.h> | | 50 | #include <amiga/pci/p5pbreg.h> |
51 | #include <amiga/pci/p5pbvar.h> | | 51 | #include <amiga/pci/p5pbvar.h> |
52 | #include <amiga/pci/p5membarvar.h> | | 52 | #include <amiga/pci/p5membarvar.h> |
53 | | | 53 | |
54 | #include <dev/pci/pcivar.h> | | 54 | #include <dev/pci/pcivar.h> |
55 | #include <dev/pci/pcireg.h> | | 55 | #include <dev/pci/pcireg.h> |
56 | #include <dev/pci/pcidevs.h> | | 56 | #include <dev/pci/pcidevs.h> |
57 | #ifdef PCI_NETBSD_CONFIGURE | | 57 | #ifdef PCI_NETBSD_CONFIGURE |
58 | #include <dev/pci/pciconf.h> | | 58 | #include <dev/pci/pciconf.h> |
59 | #endif /* PCI_NETBSD_CONFIGURE */ | | 59 | #endif /* PCI_NETBSD_CONFIGURE */ |
60 | | | 60 | |
61 | #include "opt_p5pb.h" | | 61 | #include "opt_p5pb.h" |
62 | #include "opt_pci.h" | | 62 | #include "opt_pci.h" |
63 | | | 63 | |
64 | /* Initial CVPPC/BVPPC resolution as configured by the firmware */ | | 64 | /* Initial CVPPC/BVPPC resolution as configured by the firmware */ |
65 | #define P5GFX_WIDTH 640 | | 65 | #define P5GFX_WIDTH 640 |
66 | #define P5GFX_HEIGHT 480 | | 66 | #define P5GFX_HEIGHT 480 |
67 | #define P5GFX_DEPTH 8 | | 67 | #define P5GFX_DEPTH 8 |
68 | #define P5GFX_LINEBYTES 640 | | 68 | #define P5GFX_LINEBYTES 640 |
69 | | | 69 | |
70 | static int p5pb_match(struct device *, struct cfdata *, void *); | | 70 | static int p5pb_match(struct device *, struct cfdata *, void *); |
71 | static void p5pb_attach(struct device *, struct device *, void *); | | 71 | static void p5pb_attach(struct device *, struct device *, void *); |
72 | void p5pb_set_props(struct p5pb_softc *sc); | | 72 | void p5pb_set_props(struct p5pb_softc *sc); |
73 | pcireg_t p5pb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int); | | 73 | pcireg_t p5pb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int); |
74 | void p5pb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); | | 74 | void p5pb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); |
75 | int p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno); | | 75 | int p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno); |
76 | int p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno); | | 76 | int p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno); |
77 | int p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno); | | 77 | int p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno); |
78 | int p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, | | 78 | int p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, |
79 | int func, pcireg_t id); | | 79 | int func, pcireg_t id); |
80 | void p5pb_pci_attach_hook (struct device *parent, | | 80 | void p5pb_pci_attach_hook (struct device *parent, |
81 | struct device *self, struct pcibus_attach_args *pba); | | 81 | struct device *self, struct pcibus_attach_args *pba); |
82 | pcitag_t p5pb_pci_make_tag(pci_chipset_tag_t pc, int bus, int device, | | 82 | pcitag_t p5pb_pci_make_tag(pci_chipset_tag_t pc, int bus, int device, |
83 | int function); | | 83 | int function); |
84 | void p5pb_pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, | | 84 | void p5pb_pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, |
85 | int *bp, int *dp, int *fp); | | 85 | int *bp, int *dp, int *fp); |
86 | int p5pb_pci_intr_map(const struct pci_attach_args *pa, | | 86 | int p5pb_pci_intr_map(const struct pci_attach_args *pa, |
87 | pci_intr_handle_t *ihp); | | 87 | pci_intr_handle_t *ihp); |
88 | bool p5pb_bus_map_memio(struct p5pb_softc *sc); | | 88 | bool p5pb_bus_map_memio(struct p5pb_softc *sc); |
89 | bool p5pb_bus_map_conf(struct p5pb_softc *sc); | | 89 | bool p5pb_bus_map_conf(struct p5pb_softc *sc); |
90 | uint8_t p5pb_find_resources(struct p5pb_softc *sc); | | 90 | uint8_t p5pb_find_resources(struct p5pb_softc *sc); |
91 | static bool p5pb_identify_bridge(struct p5pb_softc *sc); | | 91 | static bool p5pb_identify_bridge(struct p5pb_softc *sc); |
92 | void p5pb_membar_grex(struct p5pb_softc *sc); | | 92 | void p5pb_membar_grex(struct p5pb_softc *sc); |
93 | static bool p5pb_cvppc_probe(struct p5pb_softc *sc); | | 93 | static bool p5pb_cvppc_probe(struct p5pb_softc *sc); |
94 | #ifdef PCI_NETBSD_CONFIGURE | | 94 | #ifdef PCI_NETBSD_CONFIGURE |
95 | bool p5pb_bus_reconfigure(struct p5pb_softc *sc); | | 95 | bool p5pb_bus_reconfigure(struct p5pb_softc *sc); |
96 | #endif /* PCI_NETBSD_CONFIGURE */ | | 96 | #endif /* PCI_NETBSD_CONFIGURE */ |
97 | #ifdef P5PB_DEBUG | | 97 | #ifdef P5PB_DEBUG |
98 | void p5pb_usable_ranges(struct p5pb_softc *sc); | | 98 | void p5pb_usable_ranges(struct p5pb_softc *sc); |
99 | void p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, | | 99 | void p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, |
100 | bus_addr_t base, size_t len); | | 100 | bus_addr_t base, size_t len); |
101 | void p5pb_conf_search(struct p5pb_softc *sc, uint16_t val); | | 101 | void p5pb_conf_search(struct p5pb_softc *sc, uint16_t val); |
102 | #endif /* P5PB_DEBUG */ | | 102 | #endif /* P5PB_DEBUG */ |
103 | | | 103 | |
104 | CFATTACH_DECL_NEW(p5pb, sizeof(struct p5pb_softc), | | 104 | CFATTACH_DECL_NEW(p5pb, sizeof(struct p5pb_softc), |
105 | p5pb_match, p5pb_attach, NULL, NULL); | | 105 | p5pb_match, p5pb_attach, NULL, NULL); |
106 | | | 106 | |
107 | static int | | 107 | static int |
108 | p5pb_match(device_t parent, cfdata_t cf, void *aux) | | 108 | p5pb_match(device_t parent, cfdata_t cf, void *aux) |
109 | { | | 109 | { |
110 | struct p5bus_attach_args *p5baa; | | 110 | struct p5bus_attach_args *p5baa; |
111 | | | 111 | |
112 | p5baa = (struct p5bus_attach_args *) aux; | | 112 | p5baa = (struct p5bus_attach_args *) aux; |
113 | | | 113 | |
114 | if (strcmp(p5baa->p5baa_name, "p5pb") == 0) | | 114 | if (strcmp(p5baa->p5baa_name, "p5pb") == 0) |
115 | return 1; | | 115 | return 1; |
116 | | | 116 | |
117 | return 0; | | 117 | return 0; |
118 | } | | 118 | } |
119 | | | 119 | |
120 | static void | | 120 | static void |
121 | p5pb_attach(device_t parent, device_t self, void *aux) | | 121 | p5pb_attach(device_t parent, device_t self, void *aux) |
122 | { | | 122 | { |
123 | struct p5pb_softc *sc; | | 123 | struct p5pb_softc *sc; |
124 | struct pcibus_attach_args pba; | | 124 | struct pcibus_attach_args pba; |
125 | | | 125 | |
126 | sc = device_private(self); | | 126 | sc = device_private(self); |
127 | sc->sc_dev = self; | | 127 | sc->sc_dev = self; |
128 | sc->p5baa = (struct p5bus_attach_args *) aux; | | 128 | sc->p5baa = (struct p5bus_attach_args *) aux; |
129 | | | 129 | |
130 | pci_chipset_tag_t pc = &sc->apc; | | 130 | pci_chipset_tag_t pc = &sc->apc; |
131 | | | 131 | |
132 | if (!p5pb_bus_map_conf(sc)) { | | 132 | if (!p5pb_bus_map_conf(sc)) { |
133 | aprint_error_dev(self, | | 133 | aprint_error_dev(self, |
134 | "couldn't map PCI configuration space\n"); | | 134 | "couldn't map PCI configuration space\n"); |
135 | return; | | 135 | return; |
136 | } | | 136 | } |
137 | | | 137 | |
138 | if (!p5pb_identify_bridge(sc)) { | | 138 | if (!p5pb_identify_bridge(sc)) { |
139 | return; | | 139 | return; |
140 | } | | 140 | } |
141 | | | 141 | |
142 | if (sc->bridge_type == P5PB_BRIDGE_CVPPC) { | | 142 | if (sc->bridge_type == P5PB_BRIDGE_CVPPC) { |
143 | sc->pci_mem_lowest = P5BUS_PCI_MEM_BASE; | | 143 | sc->pci_mem_lowest = P5BUS_PCI_MEM_BASE; |
144 | sc->pci_mem_highest = P5BUS_PCI_MEM_BASE + P5BUS_PCI_MEM_SIZE; | | 144 | sc->pci_mem_highest = P5BUS_PCI_MEM_BASE + P5BUS_PCI_MEM_SIZE; |
145 | } else { | | 145 | } else { |
146 | p5pb_membar_grex(sc); | | 146 | p5pb_membar_grex(sc); |
147 | } | | 147 | } |
148 | | | 148 | |
149 | if (!p5pb_bus_map_memio(sc)) { | | 149 | if (!p5pb_bus_map_memio(sc)) { |
150 | aprint_error_dev(self, | | 150 | aprint_error_dev(self, |
151 | "couldn't map PCI I/O and memory space\n"); | | 151 | "couldn't map PCI I/O and memory space\n"); |
152 | return; | | 152 | return; |
153 | } | | 153 | } |
154 | | | 154 | |
155 | #ifdef P5PB_DEBUG | | 155 | #ifdef P5PB_DEBUG |
156 | aprint_normal("p5pb: map conf %x -> %x, io %x -> %x, mem %x -> %x\n", | | 156 | aprint_normal("p5pb: map conf %x -> %x, io %x -> %x, mem %x -> %x\n", |
157 | kvtop((void*) sc->pci_conf_area.base), sc->pci_conf_area.base, | | 157 | kvtop((void*) sc->pci_conf_area.base), sc->pci_conf_area.base, |
158 | kvtop((void*) sc->pci_io_area.base), sc->pci_io_area.base, | | 158 | kvtop((void*) sc->pci_io_area.base), sc->pci_io_area.base, |
159 | kvtop((void*) sc->pci_mem_area.base), sc->pci_mem_area.base ); | | 159 | kvtop((void*) sc->pci_mem_area.base), sc->pci_mem_area.base ); |
160 | #endif | | 160 | #endif |
161 | | | 161 | |
162 | /* Initialize the PCI chipset tag. */ | | 162 | /* Initialize the PCI chipset tag. */ |
163 | | | 163 | |
164 | if (sc->bridge_type == P5PB_BRIDGE_GREX1200) | | 164 | if (sc->bridge_type == P5PB_BRIDGE_GREX1200) |
165 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex1200; | | 165 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex1200; |
166 | else if (sc->bridge_type == P5PB_BRIDGE_GREX4000) | | 166 | else if (sc->bridge_type == P5PB_BRIDGE_GREX4000) |
167 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex4000; | | 167 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex4000; |
168 | else | | 168 | else |
169 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_cvppc; | | 169 | sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_cvppc; |
170 | | | 170 | |
171 | sc->apc.pc_conf_v = (void*) pc; | | 171 | sc->apc.pc_conf_v = (void*) pc; |
172 | sc->apc.pc_make_tag = amiga_pci_make_tag; | | 172 | sc->apc.pc_make_tag = amiga_pci_make_tag; |
173 | sc->apc.pc_decompose_tag = amiga_pci_decompose_tag; | | 173 | sc->apc.pc_decompose_tag = amiga_pci_decompose_tag; |
174 | sc->apc.pc_conf_read = p5pb_pci_conf_read; | | 174 | sc->apc.pc_conf_read = p5pb_pci_conf_read; |
175 | sc->apc.pc_conf_write = p5pb_pci_conf_write; | | 175 | sc->apc.pc_conf_write = p5pb_pci_conf_write; |
176 | sc->apc.pc_conf_hook = p5pb_pci_conf_hook; | | 176 | sc->apc.pc_conf_hook = p5pb_pci_conf_hook; |
177 | sc->apc.pc_conf_interrupt = amiga_pci_conf_interrupt; | | 177 | sc->apc.pc_conf_interrupt = amiga_pci_conf_interrupt; |
178 | sc->apc.pc_attach_hook = p5pb_pci_attach_hook; | | 178 | sc->apc.pc_attach_hook = p5pb_pci_attach_hook; |
179 | | | 179 | |
180 | sc->apc.pc_intr_map = p5pb_pci_intr_map; | | 180 | sc->apc.pc_intr_map = p5pb_pci_intr_map; |
181 | sc->apc.pc_intr_string = amiga_pci_intr_string; | | 181 | sc->apc.pc_intr_string = amiga_pci_intr_string; |
182 | sc->apc.pc_intr_establish = amiga_pci_intr_establish; | | 182 | sc->apc.pc_intr_establish = amiga_pci_intr_establish; |
183 | sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish; | | 183 | sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish; |
184 | | | 184 | |
185 | #ifdef PCI_NETBSD_CONFIGURE | | 185 | #ifdef PCI_NETBSD_CONFIGURE |
186 | /* Never reconfigure the bus on CVPPC/BVPPC, avoid the fb breakage. */ | | 186 | /* Never reconfigure the bus on CVPPC/BVPPC, avoid the fb breakage. */ |
187 | if (sc->bridge_type != P5PB_BRIDGE_CVPPC) { | | 187 | if (sc->bridge_type != P5PB_BRIDGE_CVPPC) { |
188 | p5pb_bus_reconfigure(sc); | | 188 | p5pb_bus_reconfigure(sc); |
189 | } | | 189 | } |
190 | #endif /* PCI_NETBSD_CONFIGURE */ | | 190 | #endif /* PCI_NETBSD_CONFIGURE */ |
191 | | | 191 | |
192 | /* Initialize the bus attachment structure. */ | | 192 | /* Initialize the bus attachment structure. */ |
193 | | | 193 | |
194 | pba.pba_iot = &(sc->pci_io_area); | | 194 | pba.pba_iot = &(sc->pci_io_area); |
195 | pba.pba_memt = &(sc->pci_mem_area); | | 195 | pba.pba_memt = &(sc->pci_mem_area); |
196 | pba.pba_dmat = NULL; | | 196 | pba.pba_dmat = NULL; |
197 | pba.pba_dmat64 = NULL; | | 197 | pba.pba_dmat64 = NULL; |
198 | pba.pba_pc = pc; | | 198 | pba.pba_pc = pc; |
199 | pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY; | | 199 | pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY; |
200 | pba.pba_bus = 0; | | 200 | pba.pba_bus = 0; |
201 | pba.pba_bridgetag = NULL; | | 201 | pba.pba_bridgetag = NULL; |
202 | | | 202 | |
203 | p5pb_set_props(sc); | | 203 | p5pb_set_props(sc); |
204 | | | 204 | |
205 | config_found_ia(self, "pcibus", &pba, pcibusprint); | | 205 | config_found_ia(self, "pcibus", &pba, pcibusprint); |
206 | } | | 206 | } |
207 | | | 207 | |
208 | /* | | 208 | /* |
209 | * Try to detect what kind of bridge are we dealing with. | | 209 | * Try to detect what kind of bridge are we dealing with. |
210 | */ | | 210 | */ |
211 | static bool | | 211 | static bool |
212 | p5pb_identify_bridge(struct p5pb_softc *sc) | | 212 | p5pb_identify_bridge(struct p5pb_softc *sc) |
213 | { | | 213 | { |
214 | int pcires_count; /* Number of AutoConfig(TM) PCI resources */ | | 214 | int pcires_count; /* Number of AutoConfig(TM) PCI resources */ |
215 | | | 215 | |
216 | pcires_count = p5pb_find_resources(sc); | | 216 | pcires_count = p5pb_find_resources(sc); |
217 | | | 217 | |
218 | switch (pcires_count) { | | 218 | switch (pcires_count) { |
219 | case 0: | | 219 | case 0: |
220 | /* | | 220 | /* |
221 | * Zero AutoConfig(TM) PCI resources, means that there's nothing | | 221 | * Zero AutoConfig(TM) PCI resources, means that there's nothing |
222 | * OR there's a CVPPC/BVPPC with a pre-44.69 firmware. | | 222 | * OR there's a CVPPC/BVPPC with a pre-44.69 firmware. |
223 | */ | | 223 | */ |
224 | if (p5pb_cvppc_probe(sc)) { | | 224 | if (p5pb_cvppc_probe(sc)) { |
225 | sc->bridge_type = P5PB_BRIDGE_CVPPC; | | 225 | sc->bridge_type = P5PB_BRIDGE_CVPPC; |
226 | aprint_normal(": Phase5 CVPPC/BVPPC PCI bridge\n"); | | 226 | aprint_normal(": Phase5 CVPPC/BVPPC PCI bridge\n"); |
227 | } else { | | 227 | } else { |
228 | aprint_normal(": no PCI bridges detected\n"); | | 228 | aprint_normal(": no PCI bridges detected\n"); |
229 | return false; | | 229 | return false; |
230 | } | | 230 | } |
231 | break; | | 231 | break; |
232 | case 6: | | 232 | case 6: |
233 | /* | | 233 | /* |
234 | * We have a slight possibility, that there's a CVPPC/BVPPC with | | 234 | * We have a slight possibility, that there's a CVPPC/BVPPC with |
235 | * the new firmware. So check for it first. | | 235 | * the new firmware. So check for it first. |
236 | */ | | 236 | */ |
237 | if (p5pb_cvppc_probe(sc)) { | | 237 | if (p5pb_cvppc_probe(sc)) { |
238 | /* New firmware, treat as one-slot GREX. */ | | 238 | /* New firmware, treat as one-slot GREX. */ |
239 | sc->bridge_type = P5PB_BRIDGE_CVPPC; | | 239 | sc->bridge_type = P5PB_BRIDGE_CVPPC; |
240 | aprint_normal( | | 240 | aprint_normal( |
241 | ": Phase5 CVPPC/BVPPC PCI bridge (44.69/44.71)\n"); | | 241 | ": Phase5 CVPPC/BVPPC PCI bridge (44.69/44.71)\n"); |
242 | break; | | 242 | break; |
243 | } | | 243 | } |
244 | default: | | 244 | default: |
245 | /* We have a G-REX surely. */ | | 245 | /* We have a G-REX surely. */ |
246 | | | 246 | |
247 | if (sc->p5baa->p5baa_cardtype == P5_CARDTYPE_CS) { | | 247 | if (sc->p5baa->p5baa_cardtype == P5_CARDTYPE_CS) { |
248 | sc->bridge_type = P5PB_BRIDGE_GREX4000; | | 248 | sc->bridge_type = P5PB_BRIDGE_GREX4000; |
249 | aprint_normal(": DCE G-REX 4000 PCI bridge\n"); | | 249 | aprint_normal(": DCE G-REX 4000 PCI bridge\n"); |
250 | } else { | | 250 | } else { |
251 | sc->bridge_type = P5PB_BRIDGE_GREX1200; | | 251 | sc->bridge_type = P5PB_BRIDGE_GREX1200; |
252 | aprint_normal(": DCE G-REX 1200 PCI bridge\n"); | | 252 | aprint_normal(": DCE G-REX 1200 PCI bridge\n"); |
253 | } | | 253 | } |
254 | break; | | 254 | break; |
255 | } | | 255 | } |
256 | return true; | | 256 | return true; |
257 | } | | 257 | } |
258 | | | 258 | |
259 | /* | | 259 | /* |
260 | * Find AutoConfig(TM) resuorces (for boards running G-REX firmware). Return the | | 260 | * Find AutoConfig(TM) resuorces (for boards running G-REX firmware). Return the |
261 | * total number of found resources. | | 261 | * total number of found resources. |
262 | */ | | 262 | */ |
263 | uint8_t | | 263 | uint8_t |
264 | p5pb_find_resources(struct p5pb_softc *sc) | | 264 | p5pb_find_resources(struct p5pb_softc *sc) |
265 | { | | 265 | { |
266 | uint8_t i, rv; | | 266 | uint8_t i, rv; |
267 | struct p5pb_autoconf_entry *auto_entry; | | 267 | struct p5pb_autoconf_entry *auto_entry; |
268 | struct p5membar_softc *membar_sc; | | 268 | struct p5membar_softc *membar_sc; |
269 | device_t p5membar_dev; | | 269 | device_t p5membar_dev; |
270 | | | 270 | |
271 | rv = 0; | | 271 | rv = 0; |
272 | | | 272 | |
273 | TAILQ_INIT(&sc->auto_bars); | | 273 | TAILQ_INIT(&sc->auto_bars); |
274 | | | 274 | |
275 | /* 255 should be enough for everybody */ | | 275 | /* 255 should be enough for everybody */ |
276 | for(i = 0; i < 255; i++) { | | 276 | for(i = 0; i < 255; i++) { |
277 | | | 277 | |
278 | if ((p5membar_dev = | | 278 | if ((p5membar_dev = |
279 | device_find_by_driver_unit("p5membar", i)) != NULL) { | | 279 | device_find_by_driver_unit("p5membar", i)) != NULL) { |
280 | | | 280 | |
281 | rv++; | | 281 | rv++; |
282 | | | 282 | |
283 | membar_sc = device_private(p5membar_dev); | | 283 | membar_sc = device_private(p5membar_dev); |
284 | if (membar_sc->sc_type == P5MEMBAR_TYPE_INTERNAL) | | 284 | if (membar_sc->sc_type == P5MEMBAR_TYPE_INTERNAL) |
285 | continue; | | 285 | continue; |
286 | | | 286 | |
287 | auto_entry = | | 287 | auto_entry = |
288 | kmem_alloc(sizeof(struct p5pb_autoconf_entry), | | 288 | kmem_alloc(sizeof(struct p5pb_autoconf_entry), |
289 | KM_SLEEP); | | 289 | KM_SLEEP); |
290 | | | 290 | |
291 | auto_entry->base = membar_sc->sc_base; | | 291 | auto_entry->base = membar_sc->sc_base; |
292 | auto_entry->size = membar_sc->sc_size; | | 292 | auto_entry->size = membar_sc->sc_size; |
293 | | | 293 | |
294 | TAILQ_INSERT_TAIL(&sc->auto_bars, auto_entry, entries); | | 294 | TAILQ_INSERT_TAIL(&sc->auto_bars, auto_entry, entries); |
295 | } | | 295 | } |
296 | } | | 296 | } |
297 | return rv; | | 297 | return rv; |
298 | } | | 298 | } |
299 | | | 299 | |
300 | /* | | 300 | /* |
301 | * Set properties needed to support fb driver. These are read later during | | 301 | * Set properties needed to support fb driver. These are read later during |
302 | * autoconfg in device_register(). Needed for CVPPC/BVPPC and Voodoo in G-REX. | | 302 | * autoconfg in device_register(). Needed for CVPPC/BVPPC and Voodoo in G-REX. |
303 | */ | | 303 | */ |
304 | void | | 304 | void |
305 | p5pb_set_props(struct p5pb_softc *sc) | | 305 | p5pb_set_props(struct p5pb_softc *sc) |
306 | { | | 306 | { |
307 | prop_dictionary_t dict; | | 307 | prop_dictionary_t dict; |
308 | device_t dev; | | 308 | device_t dev; |
309 | | | 309 | |
310 | dev = sc->sc_dev; | | 310 | dev = sc->sc_dev; |
311 | dict = device_properties(dev); | | 311 | dict = device_properties(dev); |
312 | | | 312 | |
313 | prop_dictionary_set_uint32(dict, "width", P5GFX_WIDTH); | | 313 | prop_dictionary_set_uint32(dict, "width", P5GFX_WIDTH); |
314 | prop_dictionary_set_uint32(dict, "height", P5GFX_HEIGHT); | | 314 | prop_dictionary_set_uint32(dict, "height", P5GFX_HEIGHT); |
315 | prop_dictionary_set_uint8(dict, "depth", P5GFX_DEPTH); | | 315 | prop_dictionary_set_uint8(dict, "depth", P5GFX_DEPTH); |
316 | | | 316 | |
317 | /* genfb needs additional properties, like virtual, physical address */ | | 317 | /* genfb needs additional properties, like virtual, physical address */ |
318 | #if (NGENFB > 0) | | 318 | #if (NGENFB > 0) |
319 | /* XXX: currently genfb is supported only on CVPPC/BVPPC */ | | 319 | /* XXX: currently genfb is supported only on CVPPC/BVPPC */ |
320 | prop_dictionary_set_uint16(dict, "linebytes", P5GFX_LINEBYTES); | | 320 | prop_dictionary_set_uint16(dict, "linebytes", P5GFX_LINEBYTES); |
321 | prop_dictionary_set_uint64(dict, "virtual_address", | | 321 | prop_dictionary_set_uint64(dict, "virtual_address", |
322 | sc->pci_mem_area.base); | | 322 | sc->pci_mem_area.base); |
323 | prop_dictionary_set_uint64(dict, "address", | | 323 | prop_dictionary_set_uint64(dict, "address", |
324 | kvtop((void*) sc->pci_mem_area.base)); | | 324 | kvtop((void*) sc->pci_mem_area.base)); |
325 | #endif | | 325 | #endif |
326 | | | 326 | |
327 | #ifdef P5PB_CONSOLE | | 327 | #ifdef P5PB_CONSOLE |
328 | prop_dictionary_set_bool(dict, "is_console", true); | | 328 | prop_dictionary_set_bool(dict, "is_console", true); |
329 | #else | | 329 | #else |
330 | prop_dictionary_set_bool(dict, "is_console", false); | | 330 | prop_dictionary_set_bool(dict, "is_console", false); |
331 | #endif | | 331 | #endif |
332 | | | 332 | |
333 | } | | 333 | } |
334 | | | 334 | |
335 | pcireg_t | | 335 | pcireg_t |
336 | p5pb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) | | 336 | p5pb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) |
337 | { | | 337 | { |
338 | uint32_t data; | | 338 | uint32_t data; |
339 | uint32_t bus, dev, func; | | 339 | uint32_t bus, dev, func; |
340 | | | 340 | |
341 | pci_decompose_tag(pc, tag, &bus, &dev, &func); | | 341 | pci_decompose_tag(pc, tag, &bus, &dev, &func); |
342 | | | 342 | |
343 | data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah, | | 343 | data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah, |
344 | + reg + (dev * OFF_PCI_DEVICE)); | | 344 | + reg + (dev * OFF_PCI_DEVICE)); |
345 | #ifdef P5PB_DEBUG_CONF | | 345 | #ifdef P5PB_DEBUG_CONF |
346 | aprint_normal("p5pb conf read va: %lx, bus: %d, dev: %d, " | | 346 | aprint_normal("p5pb conf read va: %lx, bus: %d, dev: %d, " |
347 | "func: %d, reg: %d -r-> data %x\n", | | 347 | "func: %d, reg: %d -r-> data %x\n", |
348 | pc->pci_conf_datah, bus, dev, func, reg, data); | | 348 | pc->pci_conf_datah, bus, dev, func, reg, data); |
349 | #endif | | 349 | #endif |
350 | return data; | | 350 | return data; |
351 | } | | 351 | } |
352 | | | 352 | |
353 | void | | 353 | void |
354 | p5pb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val) | | 354 | p5pb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val) |
355 | { | | 355 | { |
356 | uint32_t bus, dev, func; | | 356 | uint32_t bus, dev, func; |
357 | | | 357 | |
358 | pci_decompose_tag(pc, tag, &bus, &dev, &func); | | 358 | pci_decompose_tag(pc, tag, &bus, &dev, &func); |
359 | | | 359 | |
360 | bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah, | | 360 | bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah, |
361 | + reg + (dev * OFF_PCI_DEVICE), val); | | 361 | + reg + (dev * OFF_PCI_DEVICE), val); |
362 | #ifdef P5PB_DEBUG_CONF | | 362 | #ifdef P5PB_DEBUG_CONF |
363 | aprint_normal("p5pb conf write va: %lx, bus: %d, dev: %d, " | | 363 | aprint_normal("p5pb conf write va: %lx, bus: %d, dev: %d, " |
364 | "func: %d, reg: %d -w-> data %x\n", | | 364 | "func: %d, reg: %d -w-> data %x\n", |
365 | pc->pci_conf_datah, bus, dev, func, reg, val); | | 365 | pc->pci_conf_datah, bus, dev, func, reg, val); |
366 | #endif | | 366 | #endif |
367 | | | 367 | |
368 | } | | 368 | } |
369 | | | 369 | |
370 | int | | 370 | int |
371 | p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno) | | 371 | p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno) |
372 | { | | 372 | { |
373 | /* CVPPC/BVPPC has only 1 "slot". */ | | 373 | /* CVPPC/BVPPC has only 1 "slot". */ |
374 | return 1; | | 374 | return 1; |
375 | } | | 375 | } |
376 | | | 376 | |
377 | int | | 377 | int |
378 | p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno) | | 378 | p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno) |
379 | { | | 379 | { |
380 | /* G-REX 4000 has 4, G-REX 4000T has 3 slots? */ | | 380 | /* G-REX 4000 has 4, G-REX 4000T has 3 slots? */ |
381 | return 1; /* XXX: 4 not yet! */ | | 381 | return 1; /* XXX: 4 not yet! */ |
382 | } | | 382 | } |
383 | | | 383 | |
384 | int | | 384 | int |
385 | p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno) | | 385 | p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno) |
386 | { | | 386 | { |
387 | /* G-REX 1200 has 5 slots. */ | | 387 | /* G-REX 1200 has 5 slots. */ |
388 | return 1; /* XXX: 5 not yet! */ | | 388 | return 1; /* XXX: 5 not yet! */ |
389 | } | | 389 | } |
390 | | | 390 | |
391 | void | | 391 | void |
392 | p5pb_pci_attach_hook(struct device *parent, struct device *self, | | 392 | p5pb_pci_attach_hook(struct device *parent, struct device *self, |
393 | struct pcibus_attach_args *pba) | | 393 | struct pcibus_attach_args *pba) |
394 | { | | 394 | { |
395 | } | | 395 | } |
396 | | | 396 | |
397 | int | | 397 | int |
398 | p5pb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) | | 398 | p5pb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) |
399 | { | | 399 | { |
400 | /* TODO: add sanity checking */ | | 400 | /* TODO: add sanity checking */ |
401 | | | 401 | |
402 | *ihp = 2; | | 402 | *ihp = 2; |
403 | return 0; | | 403 | return 0; |
404 | } | | 404 | } |
405 | | | 405 | |
406 | /* Probe for CVPPC/BVPPC. */ | | 406 | /* Probe for CVPPC/BVPPC. */ |
407 | static bool | | 407 | static bool |
408 | p5pb_cvppc_probe(struct p5pb_softc *sc) | | 408 | p5pb_cvppc_probe(struct p5pb_softc *sc) |
409 | { | | 409 | { |
410 | bus_space_handle_t probe_h; | | 410 | bus_space_handle_t probe_h; |
411 | uint16_t prodid, manid; | | 411 | uint16_t prodid, manid; |
412 | void* data; | | 412 | void* data; |
413 | bool rv; | | 413 | bool rv; |
414 | | | 414 | |
415 | manid = 0; prodid = 0; | | 415 | manid = 0; prodid = 0; |
416 | rv = false; | | 416 | rv = false; |
417 | | | 417 | |
418 | if (bus_space_map(sc->apc.pci_conf_datat, 0, 4, 0, &probe_h)) | | 418 | if (bus_space_map(sc->apc.pci_conf_datat, 0, 4, 0, &probe_h)) |
419 | return rv; | | 419 | return rv; |
420 | | | 420 | |
421 | data = bus_space_vaddr(sc->apc.pci_conf_datat, probe_h); | | 421 | data = bus_space_vaddr(sc->apc.pci_conf_datat, probe_h); |
422 | | | 422 | |
423 | if (badaddr((void *)__UNVOLATILE((uint32_t) data))) { | | 423 | if (badaddr((void *)__UNVOLATILE((uint32_t) data))) { |
424 | #ifdef P5PB_DEBUG_PROBE | | 424 | #ifdef P5PB_DEBUG_PROBE |
425 | aprint_normal("p5pb: CVPPC configuration space not usable!\n"); | | 425 | aprint_normal("p5pb: CVPPC configuration space not usable!\n"); |
426 | #endif /* P5PB_DEBUG_PROBE */ | | 426 | #endif /* P5PB_DEBUG_PROBE */ |
427 | } else { | | 427 | } else { |
428 | prodid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 0); | | 428 | prodid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 0); |
429 | manid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 2); | | 429 | manid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 2); |
430 | | | 430 | |
431 | if ((prodid == P5PB_PM2_PRODUCT_ID) && | | 431 | if ((prodid == P5PB_PM2_PRODUCT_ID) && |
432 | (manid == P5PB_PM2_VENDOR_ID)) | | 432 | (manid == P5PB_PM2_VENDOR_ID)) |
433 | rv = true; | | 433 | rv = true; |
434 | } | | 434 | } |
435 | | | 435 | |
436 | #ifdef P5PB_DEBUG_PROBE | | 436 | #ifdef P5PB_DEBUG_PROBE |
437 | aprint_normal("p5pb: CVPPC probe for PCI ID: %x, %x returns %d\n", | | 437 | aprint_normal("p5pb: CVPPC probe for PCI ID: %x, %x returns %d\n", |
438 | manid, prodid, (int) rv); | | 438 | manid, prodid, (int) rv); |
439 | #endif /* P5PB_DEBUG_PROBE */ | | 439 | #endif /* P5PB_DEBUG_PROBE */ |
440 | | | 440 | |
441 | bus_space_unmap(sc->apc.pci_conf_datat, probe_h, 4); | | 441 | bus_space_unmap(sc->apc.pci_conf_datat, probe_h, 4); |
442 | return rv; | | 442 | return rv; |
443 | } | | 443 | } |
444 | | | 444 | |
445 | #ifdef PCI_NETBSD_CONFIGURE | | 445 | #ifdef PCI_NETBSD_CONFIGURE |
446 | /* Reconfigure the bus. */ | | 446 | /* Reconfigure the bus. */ |
447 | bool | | 447 | bool |
448 | p5pb_bus_reconfigure(struct p5pb_softc *sc) | | 448 | p5pb_bus_reconfigure(struct p5pb_softc *sc) |
449 | { | | 449 | { |
450 | struct extent *ioext, *memext; | | 450 | struct extent *ioext, *memext; |
451 | pci_chipset_tag_t pc; | | 451 | pci_chipset_tag_t pc; |
452 | | | 452 | |
453 | pc = &sc->apc; | | 453 | pc = &sc->apc; |
454 | | | 454 | |
455 | ioext = extent_create("p5pbio", 0, P5BUS_PCI_IO_SIZE, M_DEVBUF, NULL, 0, | | 455 | ioext = extent_create("p5pbio", 0, P5BUS_PCI_IO_SIZE, NULL, 0, |
456 | EX_NOWAIT); | | 456 | EX_NOWAIT); |
457 | | | 457 | |
458 | memext = extent_create("p5pbmem", sc->pci_mem_lowest, | | 458 | memext = extent_create("p5pbmem", sc->pci_mem_lowest, |
459 | sc->pci_mem_highest, M_DEVBUF, NULL, 0, EX_NOWAIT); | | 459 | sc->pci_mem_highest, NULL, 0, EX_NOWAIT); |
460 | | | 460 | |
461 | if ( (!ioext) || (!memext) ) | | 461 | if ( (!ioext) || (!memext) ) |
462 | return false; | | 462 | return false; |
463 | | | 463 | |
464 | #ifdef P5PB_DEBUG | | 464 | #ifdef P5PB_DEBUG |
465 | aprint_normal("p5pb: reconfiguring the bus!\n"); | | 465 | aprint_normal("p5pb: reconfiguring the bus!\n"); |
466 | #endif /* P5PB_DEBUG */ | | 466 | #endif /* P5PB_DEBUG */ |
467 | pci_configure_bus(pc, ioext, memext, NULL, 0, CACHELINE_SIZE); | | 467 | pci_configure_bus(pc, ioext, memext, NULL, 0, CACHELINE_SIZE); |
468 | | | 468 | |
469 | extent_destroy(ioext); | | 469 | extent_destroy(ioext); |
470 | extent_destroy(memext); | | 470 | extent_destroy(memext); |
471 | | | 471 | |
472 | return true; /* TODO: better error handling */ | | 472 | return true; /* TODO: better error handling */ |
473 | } | | 473 | } |
474 | #endif /* PCI_NETBSD_CONFIGURE */ | | 474 | #endif /* PCI_NETBSD_CONFIGURE */ |
475 | | | 475 | |
476 | /* Determine the PCI memory space (done G-REX-style). */ | | 476 | /* Determine the PCI memory space (done G-REX-style). */ |
477 | void | | 477 | void |
478 | p5pb_membar_grex(struct p5pb_softc *sc) | | 478 | p5pb_membar_grex(struct p5pb_softc *sc) |
479 | { | | 479 | { |
480 | struct p5pb_autoconf_entry *membar_entry; | | 480 | struct p5pb_autoconf_entry *membar_entry; |
481 | uint32_t bar_address; | | 481 | uint32_t bar_address; |
482 | | | 482 | |
483 | sc->pci_mem_lowest = 0xFFFFFFFF; | | 483 | sc->pci_mem_lowest = 0xFFFFFFFF; |
484 | sc->pci_mem_highest = 0; | | 484 | sc->pci_mem_highest = 0; |
485 | | | 485 | |
486 | /* Iterate over membar entries to find lowest and highest address. */ | | 486 | /* Iterate over membar entries to find lowest and highest address. */ |
487 | TAILQ_FOREACH(membar_entry, &sc->auto_bars, entries) { | | 487 | TAILQ_FOREACH(membar_entry, &sc->auto_bars, entries) { |
488 | | | 488 | |
489 | bar_address = (uint32_t) membar_entry->base; | | 489 | bar_address = (uint32_t) membar_entry->base; |
490 | if ((bar_address + membar_entry->size) > sc->pci_mem_highest) | | 490 | if ((bar_address + membar_entry->size) > sc->pci_mem_highest) |
491 | sc->pci_mem_highest = bar_address + membar_entry->size; | | 491 | sc->pci_mem_highest = bar_address + membar_entry->size; |
492 | if (bar_address < sc->pci_mem_lowest) | | 492 | if (bar_address < sc->pci_mem_lowest) |
493 | sc->pci_mem_lowest = bar_address; | | 493 | sc->pci_mem_lowest = bar_address; |
494 | | | 494 | |
495 | #ifdef P5PB_DEBUG_BAR | | 495 | #ifdef P5PB_DEBUG_BAR |
496 | aprint_normal("p5pb: %d kB mem BAR at %p, hi = %x, lo = %x\n", | | 496 | aprint_normal("p5pb: %d kB mem BAR at %p, hi = %x, lo = %x\n", |
497 | membar_entry->size / 1024, membar_entry->base, | | 497 | membar_entry->size / 1024, membar_entry->base, |
498 | sc->pci_mem_highest, sc->pci_mem_lowest); | | 498 | sc->pci_mem_highest, sc->pci_mem_lowest); |
499 | #endif /* P5PB_DEBUG_BAR */ | | 499 | #endif /* P5PB_DEBUG_BAR */ |
500 | } | | 500 | } |
501 | | | 501 | |
502 | aprint_normal("p5pb: %d kB PCI memory space (%8p to %8p)\n", | | 502 | aprint_normal("p5pb: %d kB PCI memory space (%8p to %8p)\n", |
503 | (sc->pci_mem_highest - sc->pci_mem_lowest) / 1024, | | 503 | (sc->pci_mem_highest - sc->pci_mem_lowest) / 1024, |
504 | (void*) sc->pci_mem_lowest, (void*) sc->pci_mem_highest); | | 504 | (void*) sc->pci_mem_lowest, (void*) sc->pci_mem_highest); |
505 | | | 505 | |
506 | } | | 506 | } |
507 | | | 507 | |
508 | bool | | 508 | bool |
509 | p5pb_bus_map_conf(struct p5pb_softc *sc) | | 509 | p5pb_bus_map_conf(struct p5pb_softc *sc) |
510 | { | | 510 | { |
511 | sc->pci_conf_area.base = (bus_addr_t) zbusmap( | | 511 | sc->pci_conf_area.base = (bus_addr_t) zbusmap( |
512 | (void *) P5BUS_PCI_CONF_BASE, P5BUS_PCI_CONF_SIZE); | | 512 | (void *) P5BUS_PCI_CONF_BASE, P5BUS_PCI_CONF_SIZE); |
513 | sc->pci_conf_area.absm = &amiga_bus_stride_1; | | 513 | sc->pci_conf_area.absm = &amiga_bus_stride_1; |
514 | | | 514 | |
515 | sc->apc.pci_conf_datat = &(sc->pci_conf_area); | | 515 | sc->apc.pci_conf_datat = &(sc->pci_conf_area); |
516 | | | 516 | |
517 | if (bus_space_map(sc->apc.pci_conf_datat, OFF_PCI_CONF_DATA, | | 517 | if (bus_space_map(sc->apc.pci_conf_datat, OFF_PCI_CONF_DATA, |
518 | 256, 0, &sc->apc.pci_conf_datah)) | | 518 | 256, 0, &sc->apc.pci_conf_datah)) |
519 | return false; | | 519 | return false; |
520 | | | 520 | |
521 | return true; | | 521 | return true; |
522 | } | | 522 | } |
523 | | | 523 | |
524 | /* Map I/O and memory space. */ | | 524 | /* Map I/O and memory space. */ |
525 | bool | | 525 | bool |
526 | p5pb_bus_map_memio(struct p5pb_softc *sc) | | 526 | p5pb_bus_map_memio(struct p5pb_softc *sc) |
527 | { | | 527 | { |
528 | sc->pci_io_area.base = (bus_addr_t) zbusmap( | | 528 | sc->pci_io_area.base = (bus_addr_t) zbusmap( |
529 | (void *) P5BUS_PCI_IO_BASE, P5BUS_PCI_IO_SIZE); | | 529 | (void *) P5BUS_PCI_IO_BASE, P5BUS_PCI_IO_SIZE); |
530 | sc->pci_io_area.absm = &amiga_bus_stride_1swap; | | 530 | sc->pci_io_area.absm = &amiga_bus_stride_1swap; |
531 | | | 531 | |
532 | sc->pci_mem_area.base = (bus_addr_t) zbusmap( | | 532 | sc->pci_mem_area.base = (bus_addr_t) zbusmap( |
533 | (void *) sc->pci_mem_lowest, | | 533 | (void *) sc->pci_mem_lowest, |
534 | sc->pci_mem_highest - sc->pci_mem_lowest); | | 534 | sc->pci_mem_highest - sc->pci_mem_lowest); |
535 | sc->pci_mem_area.absm = &amiga_bus_stride_1swap_abs; | | 535 | sc->pci_mem_area.absm = &amiga_bus_stride_1swap_abs; |
536 | | | 536 | |
537 | return true; | | 537 | return true; |
538 | } | | 538 | } |
539 | | | 539 | |
540 | int | | 540 | int |
541 | p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, | | 541 | p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, |
542 | int func, pcireg_t id) | | 542 | int func, pcireg_t id) |
543 | { | | 543 | { |
544 | /* XXX: What should we do on CVPPC/BVPPC? It breaks genfb. */ | | 544 | /* XXX: What should we do on CVPPC/BVPPC? It breaks genfb. */ |
545 | | | 545 | |
546 | return PCI_CONF_DEFAULT; | | 546 | return PCI_CONF_DEFAULT; |
547 | } | | 547 | } |
548 | | | 548 | |
549 | #ifdef P5PB_DEBUG | | 549 | #ifdef P5PB_DEBUG |
550 | /* Check which config and I/O ranges are usable. */ | | 550 | /* Check which config and I/O ranges are usable. */ |
551 | void | | 551 | void |
552 | p5pb_usable_ranges(struct p5pb_softc *sc) | | 552 | p5pb_usable_ranges(struct p5pb_softc *sc) |
553 | { | | 553 | { |
554 | p5pb_badaddr_range(sc, &(sc->pci_conf_area), 0, P5BUS_PCI_CONF_SIZE); | | 554 | p5pb_badaddr_range(sc, &(sc->pci_conf_area), 0, P5BUS_PCI_CONF_SIZE); |
555 | p5pb_badaddr_range(sc, &(sc->pci_io_area), 0, P5BUS_PCI_IO_SIZE); | | 555 | p5pb_badaddr_range(sc, &(sc->pci_io_area), 0, P5BUS_PCI_IO_SIZE); |
556 | } | | 556 | } |
557 | | | 557 | |
558 | void | | 558 | void |
559 | p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, bus_addr_t base, | | 559 | p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, bus_addr_t base, |
560 | size_t len) | | 560 | size_t len) |
561 | { | | 561 | { |
562 | int i, state, prev_state; | | 562 | int i, state, prev_state; |
563 | bus_space_handle_t bush; | | 563 | bus_space_handle_t bush; |
564 | volatile void *data; | | 564 | volatile void *data; |
565 | | | 565 | |
566 | state = -1; | | 566 | state = -1; |
567 | prev_state = -1; | | 567 | prev_state = -1; |
568 | | | 568 | |
569 | bus_space_map(bust, base, len, 0, &bush); | | 569 | bus_space_map(bust, base, len, 0, &bush); |
570 | | | 570 | |
571 | aprint_normal("p5pb: badaddr range check from %x (%x) to %x (%x)\n", | | 571 | aprint_normal("p5pb: badaddr range check from %x (%x) to %x (%x)\n", |
572 | (bus_addr_t) bush, /* start VA */ | | 572 | (bus_addr_t) bush, /* start VA */ |
573 | (bus_addr_t) kvtop((void*) bush), /* start PA */ | | 573 | (bus_addr_t) kvtop((void*) bush), /* start PA */ |
574 | (bus_addr_t) bush + len, /* end VA */ | | 574 | (bus_addr_t) bush + len, /* end VA */ |
575 | (bus_addr_t) kvtop((void*) (bush + len)));/* end PA */ | | 575 | (bus_addr_t) kvtop((void*) (bush + len)));/* end PA */ |
576 | | | 576 | |
577 | data = bus_space_vaddr(bust, bush); | | 577 | data = bus_space_vaddr(bust, bush); |
578 | | | 578 | |
579 | for(i = 0; i < len; i++) { | | 579 | for(i = 0; i < len; i++) { |
580 | state = badaddr((void *)__UNVOLATILE(((uint32_t) data + i))); | | 580 | state = badaddr((void *)__UNVOLATILE(((uint32_t) data + i))); |
581 | if(state != prev_state) { | | 581 | if(state != prev_state) { |
582 | aprint_normal("p5pb: badaddr %p (%x) : %d\n", | | 582 | aprint_normal("p5pb: badaddr %p (%x) : %d\n", |
583 | (void*) ((uint32_t) data + i), | | 583 | (void*) ((uint32_t) data + i), |
584 | (bus_addr_t) kvtop((void*) ((uint32_t) data + i)), | | 584 | (bus_addr_t) kvtop((void*) ((uint32_t) data + i)), |
585 | state); | | 585 | state); |
586 | prev_state = state; | | 586 | prev_state = state; |
587 | } | | 587 | } |
588 | | | 588 | |
589 | } | | 589 | } |
590 | | | 590 | |
591 | bus_space_unmap(bust, bush, len); | | 591 | bus_space_unmap(bust, bush, len); |
592 | } | | 592 | } |
593 | | | 593 | |
594 | /* Search for 16-bit value in the configuration space. */ | | 594 | /* Search for 16-bit value in the configuration space. */ |
595 | void | | 595 | void |
596 | p5pb_conf_search(struct p5pb_softc *sc, uint16_t val) | | 596 | p5pb_conf_search(struct p5pb_softc *sc, uint16_t val) |
597 | { | | 597 | { |
598 | int i, state; | | 598 | int i, state; |
599 | uint16_t readv; | | 599 | uint16_t readv; |
600 | void *va; | | 600 | void *va; |
601 | | | 601 | |
602 | va = bus_space_vaddr(sc->apc.pci_conf_datat, sc->apc.pci_conf_datah); | | 602 | va = bus_space_vaddr(sc->apc.pci_conf_datat, sc->apc.pci_conf_datah); |
603 | | | 603 | |
604 | for (i = 0; i < P5BUS_PCI_CONF_SIZE; i++) { | | 604 | for (i = 0; i < P5BUS_PCI_CONF_SIZE; i++) { |
605 | state = badaddr((void *)__UNVOLATILE(((uint32_t) va + i))); | | 605 | state = badaddr((void *)__UNVOLATILE(((uint32_t) va + i))); |
606 | if(state == 0) { | | 606 | if(state == 0) { |
607 | readv = bus_space_read_2(sc->apc.pci_conf_datat, | | 607 | readv = bus_space_read_2(sc->apc.pci_conf_datat, |
608 | sc->apc.pci_conf_datah, i); | | 608 | sc->apc.pci_conf_datah, i); |
609 | if(readv == val) | | 609 | if(readv == val) |
610 | aprint_normal("p5pb: found val %x @ %x (%x)\n", | | 610 | aprint_normal("p5pb: found val %x @ %x (%x)\n", |
611 | readv, (uint32_t) sc->apc.pci_conf_datah | | 611 | readv, (uint32_t) sc->apc.pci_conf_datah |
612 | + i, (bus_addr_t) kvtop((void*) | | 612 | + i, (bus_addr_t) kvtop((void*) |
613 | ((uint32_t) sc->apc.pci_conf_datah + i))); | | 613 | ((uint32_t) sc->apc.pci_conf_datah + i))); |
614 | } | | 614 | } |
615 | } | | 615 | } |
616 | } | | 616 | } |
617 | | | 617 | |
618 | #endif /* P5PB_DEBUG */ | | 618 | #endif /* P5PB_DEBUG */ |
619 | | | 619 | |