empb.c revision 1.3 1 /* $NetBSD: empb.c,v 1.3 2012/06/01 09:41:35 rkujawa Exp $ */
2
3 /*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Radoslaw Kujawa.
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 *
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
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
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
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
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /* Elbox Mediator PCI bridge driver. Currently supports Mediator 1200 models.*/
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/extent.h>
42 #include <sys/kmem.h>
43
44 #include <uvm/uvm_extern.h>
45
46 #include <machine/bus.h>
47 #include <machine/cpu.h>
48
49 #include <amiga/dev/zbusvar.h>
50 #include <amiga/pci/empbreg.h>
51 #include <amiga/pci/empbvar.h>
52 #include <amiga/pci/emmemvar.h>
53
54 #include <dev/pci/pciconf.h>
55
56 #include "opt_pci.h"
57
58 #define EMPB_DEBUG 1
59
60 #define PCI_CONF_LOCK(s) (s) = splhigh()
61 #define PCI_CONF_UNLOCK(s) splx((s))
62
63 #define WINDOW_LOCK(s) (s) = splhigh()
64 #define WINDOW_UNLOCK(s) splx((s))
65
66 static int empb_match(struct device *, struct cfdata *, void *);
67 static void empb_attach(struct device *, struct device *, void *);
68
69 static void empb_callback(device_t self);
70
71 static void empb_find_mem(struct empb_softc *sc);
72 static void empb_switch_bridge(struct empb_softc *sc, uint8_t mode);
73
74 pcireg_t empb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int);
75 void empb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
76 int empb_pci_bus_maxdevs(pci_chipset_tag_t pc, int busno);
77 void empb_pci_attach_hook(struct device *parent,
78 struct device *self, struct pcibus_attach_args *pba);
79 pcitag_t empb_pci_make_tag(pci_chipset_tag_t pc, int bus, int device,
80 int function);
81 void empb_pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag,
82 int *bp, int *dp, int *fp);
83 int empb_pci_intr_map(const struct pci_attach_args *pa,
84 pci_intr_handle_t *ihp);
85 const struct evcnt * empb_pci_intr_evcnt(pci_chipset_tag_t pc,
86 pci_intr_handle_t ih);
87
88 CFATTACH_DECL_NEW(empb, sizeof(struct empb_softc),
89 empb_match, empb_attach, NULL, NULL);
90
91 static int
92 empb_match(device_t parent, cfdata_t cf, void *aux)
93 {
94 struct zbus_args *zap;
95
96 zap = aux;
97
98 if (zap->manid != ZORRO_MANID_ELBOX)
99 return 0;
100
101 switch (zap->prodid) {
102 case ZORRO_PRODID_MED1K2:
103 case ZORRO_PRODID_MED1K2SX:
104 case ZORRO_PRODID_MED1K2LT2:
105 case ZORRO_PRODID_MED1K2LT4:
106 case ZORRO_PRODID_MED1K2TX:
107 return 1;
108 }
109
110 return 0;
111 }
112
113
114 static void
115 empb_attach(device_t parent, device_t self, void *aux)
116 {
117 struct empb_softc *sc;
118 struct zbus_args *zap;
119
120 volatile char *ba;
121
122 zap = aux;
123 sc = device_private(self);
124 sc->sc_dev = self;
125 ba = zap->va;
126
127 switch (zap->prodid) {
128 case ZORRO_PRODID_MED1K2:
129 aprint_normal(": ELBOX Mediator PCI 1200\n");
130 break;
131 case ZORRO_PRODID_MED1K2SX:
132 aprint_normal(": ELBOX Mediator PCI 1200 SX\n");
133 break;
134 case ZORRO_PRODID_MED1K2LT2:
135 aprint_normal(": ELBOX Mediator PCI 1200 LT2\n");
136 break;
137 case ZORRO_PRODID_MED1K2LT4:
138 aprint_normal(": ELBOX Mediator PCI 1200 LT4\n");
139 break;
140 case ZORRO_PRODID_MED1K2TX:
141 aprint_normal(": ELBOX Mediator PCI 1200 TX\n");
142 break;
143 default:
144 aprint_normal(": ELBOX Mediator PCI (unknown)\n");
145 break;
146 }
147
148 /* Setup bus space mappings. */
149 sc->pci_confio_area.base = (bus_addr_t) ba + EMPB_BRIDGE_OFF;
150 sc->pci_confio_area.absm = &amiga_bus_stride_1swap;
151
152 sc->setup_area.base = (bus_addr_t) ba + EMPB_SETUP_OFF;
153 sc->setup_area.absm = &amiga_bus_stride_1;
154
155 /*
156 * Defer everything until later, we need to wait for possible
157 * emmem attachments.
158 */
159
160 config_defer(self, empb_callback);
161 }
162
163 static void
164 empb_callback(device_t self) {
165
166 struct empb_softc *sc;
167 pci_chipset_tag_t pc;
168 struct pcibus_attach_args pba;
169
170 sc = device_private(self);
171 pc = &sc->apc;
172
173 #ifdef EMPB_DEBUG
174 aprint_normal("empb: mapped setup %x->%x, conf/io %x->%x\n",
175 kvtop((void*) sc->setup_area.base), sc->setup_area.base,
176 kvtop((void*) sc->pci_confio_area.base), sc->pci_confio_area.base);
177 #endif
178
179 sc->pci_confio_t = &(sc->pci_confio_area);
180
181 if (bus_space_map(sc->pci_confio_t, 0, EMPB_BRIDGE_SIZE, 0,
182 &sc->pci_confio_h))
183 aprint_error_dev(self,
184 "couldn't map PCI configuration & I/O space\n");
185
186 sc->apc.pci_conf_datat = sc->pci_confio_t;
187 sc->apc.pci_conf_datah = sc->pci_confio_h;
188
189 sc->setup_area_t = &(sc->setup_area);
190
191 if (bus_space_map(sc->setup_area_t, 0, EMPB_SETUP_SIZE, 0,
192 &sc->setup_area_h))
193 aprint_error_dev(self,
194 "couldn't map Mediator setup space\n");
195
196 empb_find_mem(sc);
197 if (sc->pci_mem_win_size == 0)
198 aprint_error_dev(self,
199 "couldn't find memory space, check your WINDOW jumper\n");
200
201 /* just a test */
202 empb_switch_window(sc, 0x80000000);
203 empb_switch_window(sc, 0x82F00000);
204 empb_switch_window(sc, 0x82000000);
205
206 /* Initialize the PCI chipset tag. */
207 sc->apc.pc_conf_v = (void*) pc;
208 sc->apc.pc_bus_maxdevs = empb_pci_bus_maxdevs;
209 sc->apc.pc_make_tag = amiga_pci_make_tag;
210 sc->apc.pc_decompose_tag = amiga_pci_decompose_tag;
211 sc->apc.pc_conf_read = empb_pci_conf_read;
212 sc->apc.pc_conf_write = empb_pci_conf_write;
213 sc->apc.pc_attach_hook = empb_pci_attach_hook;
214
215 sc->apc.pc_intr_map = empb_pci_intr_map;
216 sc->apc.pc_intr_string = amiga_pci_intr_string;
217 sc->apc.pc_intr_establish = amiga_pci_intr_establish;
218 sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish;
219
220 sc->apc.pc_conf_hook = amiga_pci_conf_hook;
221 sc->apc.pc_conf_interrupt = amiga_pci_conf_interrupt;
222
223 sc->apc.cookie = sc;
224
225 pba.pba_iot = &(sc->pci_confio_area);
226 pba.pba_dmat = NULL;
227 pba.pba_dmat64 = NULL;
228 pba.pba_pc = pc;
229 pba.pba_flags = PCI_FLAGS_IO_OKAY;
230
231 if(sc->pci_mem_win_size > 0) {
232 pba.pba_memt = &(sc->pci_mem_win);
233 pba.pba_flags |= PCI_FLAGS_MEM_OKAY;
234 } else
235 pba.pba_memt = NULL;
236
237 pba.pba_bus = 0;
238 pba.pba_bridgetag = NULL;
239
240 config_found_ia(self, "pcibus", &pba, pcibusprint);
241 }
242
243 /*
244 * Switch between configuration space and I/O space.
245 */
246 static void
247 empb_switch_bridge(struct empb_softc *sc, uint8_t mode)
248 {
249 bus_space_write_1(sc->setup_area_t, sc->setup_area_h,
250 EMPB_SETUP_BRIDGE_OFF, mode);
251 }
252
253
254 /*
255 * Try to find a (optional) memory window board.
256 */
257 static void
258 empb_find_mem(struct empb_softc *sc)
259 {
260 device_t memdev;
261 struct emmem_softc *mem_sc;
262
263 memdev = device_find_by_xname("emmem0");
264 sc->pci_mem_win_size = 0;
265
266 if(memdev == NULL) {
267 return;
268 }
269
270 mem_sc = device_private(memdev);
271
272 sc->pci_mem_win.base = (bus_addr_t) mem_sc->sc_base;
273 sc->pci_mem_win.absm = &amiga_bus_stride_1;
274
275 sc->pci_mem_win_size = mem_sc->sc_size;
276
277 if(sc->pci_mem_win_size == 8*1024*1024)
278 sc->pci_mem_win_mask = EMPB_WINDOW_MASK_8M;
279 else if(sc->pci_mem_win_size == 4*1024*1024)
280 sc->pci_mem_win_mask = EMPB_WINDOW_MASK_4M;
281 else /* disable anyway */
282 sc->pci_mem_win_size = 0;
283
284 #ifdef EMPB_DEBUG
285 aprint_normal("empb: found %x b window at %p, switch mask %x\n",
286 sc->pci_mem_win_size, (void*) sc->pci_mem_win.base,
287 sc->pci_mem_win_mask);
288 #endif /* EMPB_DEBUG */
289
290 }
291
292 /*
293 * Switch memory window position.
294 */
295 void
296 empb_switch_window(struct empb_softc *sc, bus_addr_t address)
297 {
298 int s;
299 uint16_t win_reg;
300
301 WINDOW_LOCK(s);
302
303 win_reg = bswap16((address >> EMPB_WINDOW_SHIFT)
304 & sc->pci_mem_win_mask);
305
306 #ifdef EMPB_DEBUG
307 aprint_normal("empb: access to %p window switch to %x (@%p)\n",
308 (void*) address, win_reg, (void*) sc->setup_area_h);
309 #endif /* EMPB_DEBUG */
310
311 bus_space_write_2(sc->setup_area_t, sc->setup_area_h,
312 EMPB_SETUP_WINDOW_OFF, win_reg);
313
314 /* store window pos, like: sc->pci_mem_win_pos = win_reg ? */
315
316 win_reg = bus_space_read_2(sc->setup_area_t, sc->setup_area_h,
317 EMPB_SETUP_WINDOW_OFF);
318
319 WINDOW_UNLOCK(s);
320
321 #ifdef EMPB_DEBUG
322 aprint_normal("empb: window reg now %x\n", win_reg);
323 #endif /* EMPB_DEBUG */
324 }
325
326
327 pcireg_t
328 empb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
329 {
330 uint32_t data;
331 uint32_t bus, dev, func;
332 struct empb_softc *sc;
333 int s;
334
335 sc = pc->cookie;
336
337 pci_decompose_tag(pc, tag, &bus, &dev, &func);
338
339 PCI_CONF_LOCK(s);
340
341 empb_switch_bridge(sc, BRIDGE_CONF);
342
343 data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah,
344 EMPB_CONF_DEV_STRIDE*dev + EMPB_CONF_FUNC_STRIDE*func + reg);
345 #ifdef EMPB_DEBUG_CONF
346 aprint_normal("empb conf read va: %lx, bus: %d, dev: %d, "
347 "func: %d, reg: %d -r-> data %x\n",
348 pc->pci_conf_datah, bus, dev, func, reg, data);
349 #endif /* EMPB_DEBUG_CONF */
350
351 empb_switch_bridge(sc, BRIDGE_IO);
352
353 PCI_CONF_UNLOCK(s);
354
355 return data;
356 }
357
358 void
359 empb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val)
360 {
361 uint32_t bus, dev, func;
362 struct empb_softc *sc;
363 int s;
364
365 sc = pc->cookie;
366
367 pci_decompose_tag(pc, tag, &bus, &dev, &func);
368
369 PCI_CONF_LOCK(s);
370
371 empb_switch_bridge(sc, BRIDGE_CONF);
372
373 bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah,
374 EMPB_CONF_DEV_STRIDE*dev + EMPB_CONF_FUNC_STRIDE*func + reg, val);
375 #ifdef EMPB_DEBUG_CONF
376 aprint_normal("empb conf write va: %lx, bus: %d, dev: %d, "
377 "func: %d, reg: %d -w-> data %x\n",
378 pc->pci_conf_datah, bus, dev, func, reg, val);
379 #endif /* EMPB_DEBUG_CONF */
380 empb_switch_bridge(sc, BRIDGE_IO);
381
382 PCI_CONF_UNLOCK(s);
383 }
384
385 int
386 empb_pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
387 {
388 return 6; /* no Mediator with more than 6 slots? */
389 }
390
391 void
392 empb_pci_attach_hook(struct device *parent, struct device *self,
393 struct pcibus_attach_args *pba)
394 {
395 }
396
397 int
398 empb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
399 {
400 /* TODO: add sanity checking */
401
402 *ihp = EMPB_INT;
403 return 0;
404 }
405
406 const struct evcnt *
407 empb_pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
408 {
409 /* TODO: implement */
410 return NULL;
411 }
412
413