1*23e63c4bSthorpej /* $NetBSD: p5pb.c,v 1.21 2023/12/20 00:40:42 thorpej Exp $ */
2f02273fbSrkujawa
3f02273fbSrkujawa /*-
41502adf2Srkujawa * Copyright (c) 2011, 2012 The NetBSD Foundation, Inc.
5f02273fbSrkujawa * All rights reserved.
6f02273fbSrkujawa *
7f02273fbSrkujawa * This code is derived from software contributed to The NetBSD Foundation
8f02273fbSrkujawa * by Radoslaw Kujawa.
9f02273fbSrkujawa *
10f02273fbSrkujawa * Redistribution and use in source and binary forms, with or without
11f02273fbSrkujawa * modification, are permitted provided that the following conditions
12f02273fbSrkujawa * are met:
13f02273fbSrkujawa * 1. Redistributions of source code must retain the above copyright
14f02273fbSrkujawa * notice, this list of conditions and the following disclaimer.
15f02273fbSrkujawa * 2. Redistributions in binary form must reproduce the above copyright
16f02273fbSrkujawa * notice, this list of conditions and the following disclaimer in the
17f02273fbSrkujawa * documentation and/or other materials provided with the distribution.
18f02273fbSrkujawa *
19f02273fbSrkujawa * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f02273fbSrkujawa * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f02273fbSrkujawa * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f02273fbSrkujawa * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f02273fbSrkujawa * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f02273fbSrkujawa * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f02273fbSrkujawa * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f02273fbSrkujawa * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f02273fbSrkujawa * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f02273fbSrkujawa * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f02273fbSrkujawa * POSSIBILITY OF SUCH DAMAGE.
30f02273fbSrkujawa */
31f02273fbSrkujawa
32f02273fbSrkujawa #include <sys/types.h>
33f02273fbSrkujawa #include <sys/param.h>
34f02273fbSrkujawa #include <sys/time.h>
35f02273fbSrkujawa #include <sys/systm.h>
36f02273fbSrkujawa #include <sys/errno.h>
37f02273fbSrkujawa #include <sys/device.h>
38363ad7afSrkujawa #include <sys/kmem.h>
39f02273fbSrkujawa
40f02273fbSrkujawa #include <uvm/uvm_extern.h>
41f02273fbSrkujawa
4268f1c0c4Srkujawa #define _M68K_BUS_DMA_PRIVATE
43f02273fbSrkujawa #include <machine/bus.h>
44f02273fbSrkujawa #include <machine/cpu.h>
45f02273fbSrkujawa
46f02273fbSrkujawa #include <m68k/bus_dma.h>
47f02273fbSrkujawa #include <amiga/dev/zbusvar.h>
48363ad7afSrkujawa #include <amiga/dev/p5busvar.h>
49f02273fbSrkujawa #include <amiga/pci/p5pbreg.h>
501190cfb4Srkujawa #include <amiga/pci/p5pbvar.h>
51363ad7afSrkujawa #include <amiga/pci/p5membarvar.h>
52f02273fbSrkujawa
53f02273fbSrkujawa #include <dev/pci/pcivar.h>
54f02273fbSrkujawa #include <dev/pci/pcireg.h>
55f02273fbSrkujawa #include <dev/pci/pcidevs.h>
561502adf2Srkujawa #ifdef PCI_NETBSD_CONFIGURE
57f02273fbSrkujawa #include <dev/pci/pciconf.h>
581502adf2Srkujawa #endif /* PCI_NETBSD_CONFIGURE */
591502adf2Srkujawa
601502adf2Srkujawa #include "opt_p5pb.h"
611502adf2Srkujawa #include "opt_pci.h"
62bac2deebSphx #include "genfb.h"
63f02273fbSrkujawa
641190cfb4Srkujawa /* Initial CVPPC/BVPPC resolution as configured by the firmware */
65f02273fbSrkujawa #define P5GFX_WIDTH 640
66f02273fbSrkujawa #define P5GFX_HEIGHT 480
67f02273fbSrkujawa #define P5GFX_DEPTH 8
68f02273fbSrkujawa #define P5GFX_LINEBYTES 640
69f02273fbSrkujawa
7068f1c0c4Srkujawa struct m68k_bus_dma_tag p5pb_bus_dma_tag = {
7168f1c0c4Srkujawa 0,
7268f1c0c4Srkujawa 0,
7368f1c0c4Srkujawa _bus_dmamap_create,
7468f1c0c4Srkujawa _bus_dmamap_destroy,
7568f1c0c4Srkujawa _bus_dmamap_load_direct,
7668f1c0c4Srkujawa _bus_dmamap_load_mbuf_direct,
7768f1c0c4Srkujawa _bus_dmamap_load_uio_direct,
7868f1c0c4Srkujawa _bus_dmamap_load_raw_direct,
7968f1c0c4Srkujawa _bus_dmamap_unload,
802acf4370Srkujawa _bus_dmamap_sync,
812acf4370Srkujawa _bus_dmamem_alloc,
822acf4370Srkujawa _bus_dmamem_free,
832acf4370Srkujawa _bus_dmamem_map,
842acf4370Srkujawa _bus_dmamem_unmap,
852acf4370Srkujawa _bus_dmamem_mmap
8668f1c0c4Srkujawa };
8768f1c0c4Srkujawa
88cbab9cadSchs static int p5pb_match(device_t, cfdata_t, void *);
89cbab9cadSchs static void p5pb_attach(device_t, device_t, void *);
90cbab9cadSchs void p5pb_set_props(struct p5pb_softc *);
91f02273fbSrkujawa pcireg_t p5pb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int);
92f02273fbSrkujawa void p5pb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
93cbab9cadSchs int p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t, int);
94cbab9cadSchs int p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t, int);
95cbab9cadSchs int p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t, int);
96cbab9cadSchs int p5pb_pci_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t);
97cbab9cadSchs void p5pb_pci_attach_hook (device_t, device_t,
98cbab9cadSchs struct pcibus_attach_args *);
99cbab9cadSchs pcitag_t p5pb_pci_make_tag(pci_chipset_tag_t, int, int, int);
100cbab9cadSchs void p5pb_pci_decompose_tag(pci_chipset_tag_t, pcitag_t,
101cbab9cadSchs int *, int *, int *);
102cbab9cadSchs int p5pb_pci_intr_map(const struct pci_attach_args *,
103cbab9cadSchs pci_intr_handle_t *);
104cbab9cadSchs bool p5pb_bus_map_memio(struct p5pb_softc *);
105cbab9cadSchs bool p5pb_bus_map_conf(struct p5pb_softc *);
106cbab9cadSchs uint8_t p5pb_find_resources(struct p5pb_softc *);
107cbab9cadSchs static bool p5pb_identify_bridge(struct p5pb_softc *);
108cbab9cadSchs void p5pb_membar_grex(struct p5pb_softc *);
109cbab9cadSchs static bool p5pb_cvppc_probe(struct p5pb_softc *);
1101502adf2Srkujawa #ifdef PCI_NETBSD_CONFIGURE
111cbab9cadSchs bool p5pb_bus_reconfigure(struct p5pb_softc *);
1121502adf2Srkujawa #endif /* PCI_NETBSD_CONFIGURE */
1131502adf2Srkujawa #ifdef P5PB_DEBUG
114cbab9cadSchs void p5pb_usable_ranges(struct p5pb_softc *);
115cbab9cadSchs void p5pb_badaddr_range(struct p5pb_softc *, bus_space_tag_t,
116cbab9cadSchs bus_addr_t, size_t);
117cbab9cadSchs void p5pb_conf_search(struct p5pb_softc *, uint16_t);
1181502adf2Srkujawa #endif /* P5PB_DEBUG */
119f02273fbSrkujawa
120f02273fbSrkujawa CFATTACH_DECL_NEW(p5pb, sizeof(struct p5pb_softc),
121f02273fbSrkujawa p5pb_match, p5pb_attach, NULL, NULL);
122f02273fbSrkujawa
123f02273fbSrkujawa static int
p5pb_match(device_t parent,cfdata_t cf,void * aux)124f02273fbSrkujawa p5pb_match(device_t parent, cfdata_t cf, void *aux)
125f02273fbSrkujawa {
126363ad7afSrkujawa struct p5bus_attach_args *p5baa;
127f02273fbSrkujawa
128363ad7afSrkujawa p5baa = (struct p5bus_attach_args *) aux;
129f02273fbSrkujawa
130363ad7afSrkujawa if (strcmp(p5baa->p5baa_name, "p5pb") == 0)
131363ad7afSrkujawa return 1;
132363ad7afSrkujawa
133f02273fbSrkujawa return 0;
134f02273fbSrkujawa }
135f02273fbSrkujawa
136f02273fbSrkujawa static void
p5pb_attach(device_t parent,device_t self,void * aux)137f02273fbSrkujawa p5pb_attach(device_t parent, device_t self, void *aux)
138f02273fbSrkujawa {
1391190cfb4Srkujawa struct p5pb_softc *sc;
140f02273fbSrkujawa struct pcibus_attach_args pba;
141f02273fbSrkujawa
1421190cfb4Srkujawa sc = device_private(self);
143f02273fbSrkujawa sc->sc_dev = self;
1441502adf2Srkujawa sc->p5baa = (struct p5bus_attach_args *) aux;
145f02273fbSrkujawa
1461502adf2Srkujawa pci_chipset_tag_t pc = &sc->apc;
1471502adf2Srkujawa
1481502adf2Srkujawa if (!p5pb_bus_map_conf(sc)) {
1491502adf2Srkujawa aprint_error_dev(self,
1501502adf2Srkujawa "couldn't map PCI configuration space\n");
1511502adf2Srkujawa return;
1521502adf2Srkujawa }
1531502adf2Srkujawa
1541502adf2Srkujawa if (!p5pb_identify_bridge(sc)) {
1551502adf2Srkujawa return;
1561502adf2Srkujawa }
1571502adf2Srkujawa
1581502adf2Srkujawa if (sc->bridge_type == P5PB_BRIDGE_CVPPC) {
1591502adf2Srkujawa sc->pci_mem_lowest = P5BUS_PCI_MEM_BASE;
1601502adf2Srkujawa sc->pci_mem_highest = P5BUS_PCI_MEM_BASE + P5BUS_PCI_MEM_SIZE;
1611190cfb4Srkujawa } else {
1621502adf2Srkujawa p5pb_membar_grex(sc);
163363ad7afSrkujawa }
164363ad7afSrkujawa
1651502adf2Srkujawa if (!p5pb_bus_map_memio(sc)) {
166363ad7afSrkujawa aprint_error_dev(self,
1671502adf2Srkujawa "couldn't map PCI I/O and memory space\n");
1681190cfb4Srkujawa return;
1691190cfb4Srkujawa }
1700d5229b8Srkujawa
171f02273fbSrkujawa #ifdef P5PB_DEBUG
1721502adf2Srkujawa aprint_normal("p5pb: map conf %x -> %x, io %x -> %x, mem %x -> %x\n",
1731502adf2Srkujawa kvtop((void*) sc->pci_conf_area.base), sc->pci_conf_area.base,
1741502adf2Srkujawa kvtop((void*) sc->pci_io_area.base), sc->pci_io_area.base,
1751502adf2Srkujawa kvtop((void*) sc->pci_mem_area.base), sc->pci_mem_area.base );
176f02273fbSrkujawa #endif
177f02273fbSrkujawa
178f02273fbSrkujawa /* Initialize the PCI chipset tag. */
1791502adf2Srkujawa
1801502adf2Srkujawa if (sc->bridge_type == P5PB_BRIDGE_GREX1200)
1811502adf2Srkujawa sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex1200;
1821502adf2Srkujawa else if (sc->bridge_type == P5PB_BRIDGE_GREX4000)
1831502adf2Srkujawa sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex4000;
1841502adf2Srkujawa else
1851502adf2Srkujawa sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_cvppc;
1861502adf2Srkujawa
187f02273fbSrkujawa sc->apc.pc_conf_v = (void*) pc;
1880d5229b8Srkujawa sc->apc.pc_make_tag = amiga_pci_make_tag;
1890d5229b8Srkujawa sc->apc.pc_decompose_tag = amiga_pci_decompose_tag;
190f02273fbSrkujawa sc->apc.pc_conf_read = p5pb_pci_conf_read;
191f02273fbSrkujawa sc->apc.pc_conf_write = p5pb_pci_conf_write;
1921502adf2Srkujawa sc->apc.pc_conf_hook = p5pb_pci_conf_hook;
1931502adf2Srkujawa sc->apc.pc_conf_interrupt = amiga_pci_conf_interrupt;
194f02273fbSrkujawa sc->apc.pc_attach_hook = p5pb_pci_attach_hook;
195f02273fbSrkujawa
1960d5229b8Srkujawa sc->apc.pc_intr_map = p5pb_pci_intr_map;
1970d5229b8Srkujawa sc->apc.pc_intr_string = amiga_pci_intr_string;
1980d5229b8Srkujawa sc->apc.pc_intr_establish = amiga_pci_intr_establish;
1990d5229b8Srkujawa sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish;
2000d5229b8Srkujawa
2011502adf2Srkujawa #ifdef PCI_NETBSD_CONFIGURE
2025bf221d4Srkujawa /* Never reconfigure the bus on CVPPC/BVPPC, avoid the fb breakage. */
2035bf221d4Srkujawa if (sc->bridge_type != P5PB_BRIDGE_CVPPC) {
2041502adf2Srkujawa p5pb_bus_reconfigure(sc);
2055bf221d4Srkujawa }
2061502adf2Srkujawa #endif /* PCI_NETBSD_CONFIGURE */
2071502adf2Srkujawa
2081502adf2Srkujawa /* Initialize the bus attachment structure. */
2091502adf2Srkujawa
2100d5229b8Srkujawa pba.pba_iot = &(sc->pci_io_area);
211f02273fbSrkujawa pba.pba_memt = &(sc->pci_mem_area);
21268f1c0c4Srkujawa pba.pba_dmat = &p5pb_bus_dma_tag;
213f02273fbSrkujawa pba.pba_dmat64 = NULL;
214f02273fbSrkujawa pba.pba_pc = pc;
2150d5229b8Srkujawa pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY;
216f02273fbSrkujawa pba.pba_bus = 0;
217f02273fbSrkujawa pba.pba_bridgetag = NULL;
218f02273fbSrkujawa
219f02273fbSrkujawa p5pb_set_props(sc);
220f02273fbSrkujawa
221c7fb772bSthorpej config_found(self, &pba, pcibusprint, CFARGS_NONE);
222f02273fbSrkujawa }
223f02273fbSrkujawa
224f02273fbSrkujawa /*
2251502adf2Srkujawa * Try to detect what kind of bridge are we dealing with.
2261502adf2Srkujawa */
2271502adf2Srkujawa static bool
p5pb_identify_bridge(struct p5pb_softc * sc)2281502adf2Srkujawa p5pb_identify_bridge(struct p5pb_softc *sc)
2291502adf2Srkujawa {
2301502adf2Srkujawa int pcires_count; /* Number of AutoConfig(TM) PCI resources */
2311502adf2Srkujawa
2321502adf2Srkujawa pcires_count = p5pb_find_resources(sc);
2331502adf2Srkujawa
2341502adf2Srkujawa switch (pcires_count) {
2351502adf2Srkujawa case 0:
2361502adf2Srkujawa /*
2371502adf2Srkujawa * Zero AutoConfig(TM) PCI resources, means that there's nothing
2381502adf2Srkujawa * OR there's a CVPPC/BVPPC with a pre-44.69 firmware.
2391502adf2Srkujawa */
2401502adf2Srkujawa if (p5pb_cvppc_probe(sc)) {
2411502adf2Srkujawa sc->bridge_type = P5PB_BRIDGE_CVPPC;
2421502adf2Srkujawa aprint_normal(": Phase5 CVPPC/BVPPC PCI bridge\n");
2431502adf2Srkujawa } else {
2441502adf2Srkujawa aprint_normal(": no PCI bridges detected\n");
2451502adf2Srkujawa return false;
2461502adf2Srkujawa }
2471502adf2Srkujawa break;
2481502adf2Srkujawa case 6:
2491502adf2Srkujawa /*
2501502adf2Srkujawa * We have a slight possibility, that there's a CVPPC/BVPPC with
2511502adf2Srkujawa * the new firmware. So check for it first.
2521502adf2Srkujawa */
2531502adf2Srkujawa if (p5pb_cvppc_probe(sc)) {
2541502adf2Srkujawa /* New firmware, treat as one-slot GREX. */
2551502adf2Srkujawa sc->bridge_type = P5PB_BRIDGE_CVPPC;
2561502adf2Srkujawa aprint_normal(
2571502adf2Srkujawa ": Phase5 CVPPC/BVPPC PCI bridge (44.69/44.71)\n");
2581502adf2Srkujawa break;
2591502adf2Srkujawa }
2601502adf2Srkujawa default:
2611502adf2Srkujawa /* We have a G-REX surely. */
2621502adf2Srkujawa
2631502adf2Srkujawa if (sc->p5baa->p5baa_cardtype == P5_CARDTYPE_CS) {
2641502adf2Srkujawa sc->bridge_type = P5PB_BRIDGE_GREX4000;
2651502adf2Srkujawa aprint_normal(": DCE G-REX 4000 PCI bridge\n");
2661502adf2Srkujawa } else {
2671502adf2Srkujawa sc->bridge_type = P5PB_BRIDGE_GREX1200;
2681502adf2Srkujawa aprint_normal(": DCE G-REX 1200 PCI bridge\n");
2691502adf2Srkujawa }
2701502adf2Srkujawa break;
2711502adf2Srkujawa }
2721502adf2Srkujawa return true;
2731502adf2Srkujawa }
2741502adf2Srkujawa
2751502adf2Srkujawa /*
2761502adf2Srkujawa * Find AutoConfig(TM) resuorces (for boards running G-REX firmware). Return the
277363ad7afSrkujawa * total number of found resources.
278363ad7afSrkujawa */
279363ad7afSrkujawa uint8_t
p5pb_find_resources(struct p5pb_softc * sc)280363ad7afSrkujawa p5pb_find_resources(struct p5pb_softc *sc)
281363ad7afSrkujawa {
282363ad7afSrkujawa uint8_t i, rv;
283363ad7afSrkujawa struct p5pb_autoconf_entry *auto_entry;
284363ad7afSrkujawa struct p5membar_softc *membar_sc;
285363ad7afSrkujawa device_t p5membar_dev;
286363ad7afSrkujawa
287363ad7afSrkujawa rv = 0;
288363ad7afSrkujawa
289363ad7afSrkujawa TAILQ_INIT(&sc->auto_bars);
290363ad7afSrkujawa
291363ad7afSrkujawa /* 255 should be enough for everybody */
292363ad7afSrkujawa for(i = 0; i < 255; i++) {
293363ad7afSrkujawa
294363ad7afSrkujawa if ((p5membar_dev =
295363ad7afSrkujawa device_find_by_driver_unit("p5membar", i)) != NULL) {
296363ad7afSrkujawa
297363ad7afSrkujawa rv++;
298363ad7afSrkujawa
299363ad7afSrkujawa membar_sc = device_private(p5membar_dev);
300363ad7afSrkujawa if (membar_sc->sc_type == P5MEMBAR_TYPE_INTERNAL)
301363ad7afSrkujawa continue;
302363ad7afSrkujawa
303363ad7afSrkujawa auto_entry =
304363ad7afSrkujawa kmem_alloc(sizeof(struct p5pb_autoconf_entry),
305363ad7afSrkujawa KM_SLEEP);
306363ad7afSrkujawa
307363ad7afSrkujawa auto_entry->base = membar_sc->sc_base;
308363ad7afSrkujawa auto_entry->size = membar_sc->sc_size;
309363ad7afSrkujawa
310363ad7afSrkujawa TAILQ_INSERT_TAIL(&sc->auto_bars, auto_entry, entries);
311363ad7afSrkujawa }
312363ad7afSrkujawa }
313363ad7afSrkujawa return rv;
314363ad7afSrkujawa }
315363ad7afSrkujawa
316363ad7afSrkujawa /*
317f02273fbSrkujawa * Set properties needed to support fb driver. These are read later during
3183d8ca501Srkujawa * autoconfg in device_register(). Needed for CVPPC/BVPPC.
319f02273fbSrkujawa */
320f02273fbSrkujawa void
p5pb_set_props(struct p5pb_softc * sc)321f02273fbSrkujawa p5pb_set_props(struct p5pb_softc *sc)
322f02273fbSrkujawa {
323889cc98cSchristos #if NGENFB > 0
324f02273fbSrkujawa prop_dictionary_t dict;
325f02273fbSrkujawa device_t dev;
326f02273fbSrkujawa
327f02273fbSrkujawa dev = sc->sc_dev;
328f02273fbSrkujawa dict = device_properties(dev);
329f02273fbSrkujawa
3305bf221d4Srkujawa /* genfb needs additional properties, like virtual, physical address */
3315bf221d4Srkujawa /* XXX: currently genfb is supported only on CVPPC/BVPPC */
332f02273fbSrkujawa prop_dictionary_set_uint64(dict, "virtual_address",
333f02273fbSrkujawa sc->pci_mem_area.base);
3345bf221d4Srkujawa prop_dictionary_set_uint64(dict, "address",
3355bf221d4Srkujawa kvtop((void*) sc->pci_mem_area.base));
336f02273fbSrkujawa #endif
337f02273fbSrkujawa }
338f02273fbSrkujawa
339f02273fbSrkujawa pcireg_t
p5pb_pci_conf_read(pci_chipset_tag_t pc,pcitag_t tag,int reg)340f02273fbSrkujawa p5pb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
341f02273fbSrkujawa {
342f02273fbSrkujawa uint32_t data;
343f02273fbSrkujawa uint32_t bus, dev, func;
34468f1c0c4Srkujawa uint32_t offset;
345f02273fbSrkujawa
346605f564fSmsaitoh if ((unsigned int)reg >= PCI_CONF_SIZE)
347605f564fSmsaitoh return 0xFFFFFFFF;
348605f564fSmsaitoh
349f02273fbSrkujawa pci_decompose_tag(pc, tag, &bus, &dev, &func);
350f02273fbSrkujawa
35168f1c0c4Srkujawa offset = (OFF_PCI_DEVICE << dev) + reg;
35268f1c0c4Srkujawa
35368f1c0c4Srkujawa if(func == 0) /* ugly, ugly hack */
35468f1c0c4Srkujawa offset += 0;
35568f1c0c4Srkujawa else if(func == 1)
35668f1c0c4Srkujawa offset += OFF_PCI_FUNCTION;
35768f1c0c4Srkujawa else
35868f1c0c4Srkujawa return 0xFFFFFFFF;
35968f1c0c4Srkujawa
36068f1c0c4Srkujawa if(badaddr((void *)__UNVOLATILE(((uint32_t)
36168f1c0c4Srkujawa bus_space_vaddr(pc->pci_conf_datat, pc->pci_conf_datah)
36268f1c0c4Srkujawa + offset))))
36368f1c0c4Srkujawa return 0xFFFFFFFF;
36468f1c0c4Srkujawa
3650d5229b8Srkujawa data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah,
36668f1c0c4Srkujawa offset);
3671502adf2Srkujawa #ifdef P5PB_DEBUG_CONF
368f02273fbSrkujawa aprint_normal("p5pb conf read va: %lx, bus: %d, dev: %d, "
369f02273fbSrkujawa "func: %d, reg: %d -r-> data %x\n",
3700d5229b8Srkujawa pc->pci_conf_datah, bus, dev, func, reg, data);
371f02273fbSrkujawa #endif
372f02273fbSrkujawa return data;
373f02273fbSrkujawa }
374f02273fbSrkujawa
375f02273fbSrkujawa void
p5pb_pci_conf_write(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t val)376f02273fbSrkujawa p5pb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val)
377f02273fbSrkujawa {
378f02273fbSrkujawa uint32_t bus, dev, func;
37968f1c0c4Srkujawa uint32_t offset;
380f02273fbSrkujawa
381605f564fSmsaitoh if ((unsigned int)reg >= PCI_CONF_SIZE)
382605f564fSmsaitoh return;
383605f564fSmsaitoh
384f02273fbSrkujawa pci_decompose_tag(pc, tag, &bus, &dev, &func);
385f02273fbSrkujawa
38668f1c0c4Srkujawa offset = (OFF_PCI_DEVICE << dev) + reg;
38768f1c0c4Srkujawa
38868f1c0c4Srkujawa if(func == 0) /* ugly, ugly hack */
38968f1c0c4Srkujawa offset += 0;
39068f1c0c4Srkujawa else if(func == 1)
39168f1c0c4Srkujawa offset += OFF_PCI_FUNCTION;
39268f1c0c4Srkujawa else
39368f1c0c4Srkujawa return;
39468f1c0c4Srkujawa
39568f1c0c4Srkujawa if(badaddr((void *)__UNVOLATILE(((uint32_t)
39668f1c0c4Srkujawa bus_space_vaddr(pc->pci_conf_datat, pc->pci_conf_datah)
39768f1c0c4Srkujawa + offset))))
39868f1c0c4Srkujawa return;
39968f1c0c4Srkujawa
4000d5229b8Srkujawa bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah,
40168f1c0c4Srkujawa offset, val);
4021502adf2Srkujawa #ifdef P5PB_DEBUG_CONF
403f02273fbSrkujawa aprint_normal("p5pb conf write va: %lx, bus: %d, dev: %d, "
404f02273fbSrkujawa "func: %d, reg: %d -w-> data %x\n",
4050d5229b8Srkujawa pc->pci_conf_datah, bus, dev, func, reg, val);
406f02273fbSrkujawa #endif
407f02273fbSrkujawa
408f02273fbSrkujawa }
409f02273fbSrkujawa
410f02273fbSrkujawa int
p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc,int busno)4111502adf2Srkujawa p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno)
412f02273fbSrkujawa {
4131502adf2Srkujawa /* CVPPC/BVPPC has only 1 "slot". */
414f02273fbSrkujawa return 1;
415f02273fbSrkujawa }
416f02273fbSrkujawa
4171502adf2Srkujawa int
p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc,int busno)4181502adf2Srkujawa p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno)
4191502adf2Srkujawa {
4205bf221d4Srkujawa /* G-REX 4000 has 4, G-REX 4000T has 3 slots? */
42168f1c0c4Srkujawa return 4;
4221502adf2Srkujawa }
4231502adf2Srkujawa
4241502adf2Srkujawa int
p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc,int busno)4251502adf2Srkujawa p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno)
4261502adf2Srkujawa {
4271502adf2Srkujawa /* G-REX 1200 has 5 slots. */
42868f1c0c4Srkujawa return 4; /* XXX: 5 not yet! */
4291502adf2Srkujawa }
4301502adf2Srkujawa
431f02273fbSrkujawa void
p5pb_pci_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)432cbab9cadSchs p5pb_pci_attach_hook(device_t parent, device_t self,
433f02273fbSrkujawa struct pcibus_attach_args *pba)
434f02273fbSrkujawa {
435f02273fbSrkujawa }
436f02273fbSrkujawa
4370d5229b8Srkujawa int
p5pb_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)4380d5229b8Srkujawa p5pb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
4390d5229b8Srkujawa {
4400d5229b8Srkujawa /* TODO: add sanity checking */
4410d5229b8Srkujawa
4420d5229b8Srkujawa *ihp = 2;
4430d5229b8Srkujawa return 0;
4440d5229b8Srkujawa }
4450d5229b8Srkujawa
4461502adf2Srkujawa /* Probe for CVPPC/BVPPC. */
4471502adf2Srkujawa static bool
p5pb_cvppc_probe(struct p5pb_softc * sc)4481502adf2Srkujawa p5pb_cvppc_probe(struct p5pb_softc *sc)
4491502adf2Srkujawa {
4501502adf2Srkujawa bus_space_handle_t probe_h;
4511502adf2Srkujawa uint16_t prodid, manid;
4521502adf2Srkujawa void* data;
4531502adf2Srkujawa bool rv;
4541502adf2Srkujawa
4551502adf2Srkujawa manid = 0; prodid = 0;
4561502adf2Srkujawa rv = false;
4571502adf2Srkujawa
4581502adf2Srkujawa if (bus_space_map(sc->apc.pci_conf_datat, 0, 4, 0, &probe_h))
4591502adf2Srkujawa return rv;
4601502adf2Srkujawa
4611502adf2Srkujawa data = bus_space_vaddr(sc->apc.pci_conf_datat, probe_h);
4621502adf2Srkujawa
4631502adf2Srkujawa if (badaddr((void *)__UNVOLATILE((uint32_t) data))) {
4641502adf2Srkujawa #ifdef P5PB_DEBUG_PROBE
4651502adf2Srkujawa aprint_normal("p5pb: CVPPC configuration space not usable!\n");
4661502adf2Srkujawa #endif /* P5PB_DEBUG_PROBE */
4671502adf2Srkujawa } else {
4681502adf2Srkujawa prodid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 0);
4691502adf2Srkujawa manid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 2);
4701502adf2Srkujawa
4711502adf2Srkujawa if ((prodid == P5PB_PM2_PRODUCT_ID) &&
4721502adf2Srkujawa (manid == P5PB_PM2_VENDOR_ID))
4731502adf2Srkujawa rv = true;
4741502adf2Srkujawa }
4751502adf2Srkujawa
4761502adf2Srkujawa #ifdef P5PB_DEBUG_PROBE
4771502adf2Srkujawa aprint_normal("p5pb: CVPPC probe for PCI ID: %x, %x returns %d\n",
4781502adf2Srkujawa manid, prodid, (int) rv);
4791502adf2Srkujawa #endif /* P5PB_DEBUG_PROBE */
4801502adf2Srkujawa
4811502adf2Srkujawa bus_space_unmap(sc->apc.pci_conf_datat, probe_h, 4);
4821502adf2Srkujawa return rv;
4831502adf2Srkujawa }
4841502adf2Srkujawa
4851502adf2Srkujawa #ifdef PCI_NETBSD_CONFIGURE
4861502adf2Srkujawa /* Reconfigure the bus. */
487363ad7afSrkujawa bool
p5pb_bus_reconfigure(struct p5pb_softc * sc)4881502adf2Srkujawa p5pb_bus_reconfigure(struct p5pb_softc *sc)
4891502adf2Srkujawa {
4901502adf2Srkujawa pci_chipset_tag_t pc;
4911502adf2Srkujawa
4921502adf2Srkujawa pc = &sc->apc;
4931502adf2Srkujawa
494ca8ce3aeSthorpej struct pciconf_resources *pcires = pciconf_resource_init();
4951502adf2Srkujawa
496ca8ce3aeSthorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_IO,
497ca8ce3aeSthorpej 0, P5BUS_PCI_IO_SIZE);
498ca8ce3aeSthorpej pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM,
499ca8ce3aeSthorpej sc->pci_mem_lowest, sc->pci_mem_highest - sc->pci_mem_lowest);
5001502adf2Srkujawa
5011502adf2Srkujawa #ifdef P5PB_DEBUG
5021502adf2Srkujawa aprint_normal("p5pb: reconfiguring the bus!\n");
5031502adf2Srkujawa #endif /* P5PB_DEBUG */
504ca8ce3aeSthorpej pci_configure_bus(pc, pcires, 0, CACHELINE_SIZE);
5051502adf2Srkujawa
506ca8ce3aeSthorpej pciconf_resource_fini(pcires);
5071502adf2Srkujawa
5081502adf2Srkujawa return true; /* TODO: better error handling */
5091502adf2Srkujawa }
5101502adf2Srkujawa #endif /* PCI_NETBSD_CONFIGURE */
5111502adf2Srkujawa
5121502adf2Srkujawa /* Determine the PCI memory space (done G-REX-style). */
5131502adf2Srkujawa void
p5pb_membar_grex(struct p5pb_softc * sc)5141502adf2Srkujawa p5pb_membar_grex(struct p5pb_softc *sc)
515363ad7afSrkujawa {
516363ad7afSrkujawa struct p5pb_autoconf_entry *membar_entry;
5171502adf2Srkujawa uint32_t bar_address;
518363ad7afSrkujawa
5191502adf2Srkujawa sc->pci_mem_lowest = 0xFFFFFFFF;
5201502adf2Srkujawa sc->pci_mem_highest = 0;
521363ad7afSrkujawa
5221502adf2Srkujawa /* Iterate over membar entries to find lowest and highest address. */
523363ad7afSrkujawa TAILQ_FOREACH(membar_entry, &sc->auto_bars, entries) {
524363ad7afSrkujawa
5251502adf2Srkujawa bar_address = (uint32_t) membar_entry->base;
5261502adf2Srkujawa if ((bar_address + membar_entry->size) > sc->pci_mem_highest)
5271502adf2Srkujawa sc->pci_mem_highest = bar_address + membar_entry->size;
5281502adf2Srkujawa if (bar_address < sc->pci_mem_lowest)
5291502adf2Srkujawa sc->pci_mem_lowest = bar_address;
530363ad7afSrkujawa
5311502adf2Srkujawa #ifdef P5PB_DEBUG_BAR
5321502adf2Srkujawa aprint_normal("p5pb: %d kB mem BAR at %p, hi = %x, lo = %x\n",
5331502adf2Srkujawa membar_entry->size / 1024, membar_entry->base,
5341502adf2Srkujawa sc->pci_mem_highest, sc->pci_mem_lowest);
5351502adf2Srkujawa #endif /* P5PB_DEBUG_BAR */
536363ad7afSrkujawa }
537363ad7afSrkujawa
5381502adf2Srkujawa aprint_normal("p5pb: %d kB PCI memory space (%8p to %8p)\n",
5391502adf2Srkujawa (sc->pci_mem_highest - sc->pci_mem_lowest) / 1024,
5401502adf2Srkujawa (void*) sc->pci_mem_lowest, (void*) sc->pci_mem_highest);
541363ad7afSrkujawa
542363ad7afSrkujawa }
543363ad7afSrkujawa
544363ad7afSrkujawa bool
p5pb_bus_map_conf(struct p5pb_softc * sc)5451502adf2Srkujawa p5pb_bus_map_conf(struct p5pb_softc *sc)
5461190cfb4Srkujawa {
5471190cfb4Srkujawa sc->pci_conf_area.base = (bus_addr_t) zbusmap(
5481190cfb4Srkujawa (void *) P5BUS_PCI_CONF_BASE, P5BUS_PCI_CONF_SIZE);
5491190cfb4Srkujawa sc->pci_conf_area.absm = &amiga_bus_stride_1;
5501190cfb4Srkujawa
5511190cfb4Srkujawa sc->apc.pci_conf_datat = &(sc->pci_conf_area);
5521190cfb4Srkujawa
5531190cfb4Srkujawa if (bus_space_map(sc->apc.pci_conf_datat, OFF_PCI_CONF_DATA,
55468f1c0c4Srkujawa P5BUS_PCI_CONF_SIZE, 0, &sc->apc.pci_conf_datah))
5551190cfb4Srkujawa return false;
5561190cfb4Srkujawa
5571190cfb4Srkujawa return true;
5581190cfb4Srkujawa }
5591190cfb4Srkujawa
5601502adf2Srkujawa /* Map I/O and memory space. */
5611190cfb4Srkujawa bool
p5pb_bus_map_memio(struct p5pb_softc * sc)5621502adf2Srkujawa p5pb_bus_map_memio(struct p5pb_softc *sc)
563363ad7afSrkujawa {
5641502adf2Srkujawa sc->pci_io_area.base = (bus_addr_t) zbusmap(
5651502adf2Srkujawa (void *) P5BUS_PCI_IO_BASE, P5BUS_PCI_IO_SIZE);
5661502adf2Srkujawa sc->pci_io_area.absm = &amiga_bus_stride_1swap;
5671502adf2Srkujawa
568363ad7afSrkujawa sc->pci_mem_area.base = (bus_addr_t) zbusmap(
5691502adf2Srkujawa (void *) sc->pci_mem_lowest,
5701502adf2Srkujawa sc->pci_mem_highest - sc->pci_mem_lowest);
571363ad7afSrkujawa sc->pci_mem_area.absm = &amiga_bus_stride_1swap_abs;
5721190cfb4Srkujawa
5731190cfb4Srkujawa return true;
5741190cfb4Srkujawa }
5751190cfb4Srkujawa
5761502adf2Srkujawa int
p5pb_pci_conf_hook(pci_chipset_tag_t pct,int bus,int dev,int func,pcireg_t id)5771502adf2Srkujawa p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev,
5781502adf2Srkujawa int func, pcireg_t id)
5791502adf2Srkujawa {
5801502adf2Srkujawa /* XXX: What should we do on CVPPC/BVPPC? It breaks genfb. */
5811502adf2Srkujawa
5821502adf2Srkujawa return PCI_CONF_DEFAULT;
5831502adf2Srkujawa }
5841502adf2Srkujawa
5851502adf2Srkujawa #ifdef P5PB_DEBUG
5861502adf2Srkujawa /* Check which config and I/O ranges are usable. */
5871502adf2Srkujawa void
p5pb_usable_ranges(struct p5pb_softc * sc)5881502adf2Srkujawa p5pb_usable_ranges(struct p5pb_softc *sc)
5891502adf2Srkujawa {
5901502adf2Srkujawa p5pb_badaddr_range(sc, &(sc->pci_conf_area), 0, P5BUS_PCI_CONF_SIZE);
5911502adf2Srkujawa p5pb_badaddr_range(sc, &(sc->pci_io_area), 0, P5BUS_PCI_IO_SIZE);
5921502adf2Srkujawa }
5931502adf2Srkujawa
5941502adf2Srkujawa void
p5pb_badaddr_range(struct p5pb_softc * sc,bus_space_tag_t bust,bus_addr_t base,size_t len)5951502adf2Srkujawa p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, bus_addr_t base,
5961502adf2Srkujawa size_t len)
5971502adf2Srkujawa {
5981502adf2Srkujawa int i, state, prev_state;
5991502adf2Srkujawa bus_space_handle_t bush;
6001502adf2Srkujawa volatile void *data;
6011502adf2Srkujawa
6021502adf2Srkujawa state = -1;
6031502adf2Srkujawa prev_state = -1;
6041502adf2Srkujawa
6051502adf2Srkujawa bus_space_map(bust, base, len, 0, &bush);
6061502adf2Srkujawa
6071502adf2Srkujawa aprint_normal("p5pb: badaddr range check from %x (%x) to %x (%x)\n",
6081502adf2Srkujawa (bus_addr_t) bush, /* start VA */
6091502adf2Srkujawa (bus_addr_t) kvtop((void*) bush), /* start PA */
6101502adf2Srkujawa (bus_addr_t) bush + len, /* end VA */
6111502adf2Srkujawa (bus_addr_t) kvtop((void*) (bush + len)));/* end PA */
6121502adf2Srkujawa
6131502adf2Srkujawa data = bus_space_vaddr(bust, bush);
6141502adf2Srkujawa
6151502adf2Srkujawa for(i = 0; i < len; i++) {
6161502adf2Srkujawa state = badaddr((void *)__UNVOLATILE(((uint32_t) data + i)));
6171502adf2Srkujawa if(state != prev_state) {
6181502adf2Srkujawa aprint_normal("p5pb: badaddr %p (%x) : %d\n",
6191502adf2Srkujawa (void*) ((uint32_t) data + i),
6201502adf2Srkujawa (bus_addr_t) kvtop((void*) ((uint32_t) data + i)),
6211502adf2Srkujawa state);
6221502adf2Srkujawa prev_state = state;
6231502adf2Srkujawa }
6241502adf2Srkujawa
6251502adf2Srkujawa }
6261502adf2Srkujawa
6271502adf2Srkujawa bus_space_unmap(bust, bush, len);
6281502adf2Srkujawa }
6291502adf2Srkujawa
6301502adf2Srkujawa /* Search for 16-bit value in the configuration space. */
6311502adf2Srkujawa void
p5pb_conf_search(struct p5pb_softc * sc,uint16_t val)6321502adf2Srkujawa p5pb_conf_search(struct p5pb_softc *sc, uint16_t val)
6331502adf2Srkujawa {
6341502adf2Srkujawa int i, state;
6351502adf2Srkujawa uint16_t readv;
6361502adf2Srkujawa void *va;
6371502adf2Srkujawa
6381502adf2Srkujawa va = bus_space_vaddr(sc->apc.pci_conf_datat, sc->apc.pci_conf_datah);
6391502adf2Srkujawa
6401502adf2Srkujawa for (i = 0; i < P5BUS_PCI_CONF_SIZE; i++) {
6411502adf2Srkujawa state = badaddr((void *)__UNVOLATILE(((uint32_t) va + i)));
6421502adf2Srkujawa if(state == 0) {
6431502adf2Srkujawa readv = bus_space_read_2(sc->apc.pci_conf_datat,
6441502adf2Srkujawa sc->apc.pci_conf_datah, i);
6451502adf2Srkujawa if(readv == val)
6461502adf2Srkujawa aprint_normal("p5pb: found val %x @ %x (%x)\n",
6471502adf2Srkujawa readv, (uint32_t) sc->apc.pci_conf_datah
6481502adf2Srkujawa + i, (bus_addr_t) kvtop((void*)
6491502adf2Srkujawa ((uint32_t) sc->apc.pci_conf_datah + i)));
6501502adf2Srkujawa }
6511502adf2Srkujawa }
6521502adf2Srkujawa }
6531502adf2Srkujawa
6541502adf2Srkujawa #endif /* P5PB_DEBUG */
6551502adf2Srkujawa
6563d8ca501Srkujawa #ifdef P5PB_CONSOLE
6573d8ca501Srkujawa void
p5pb_device_register(device_t dev,void * aux)6583d8ca501Srkujawa p5pb_device_register(device_t dev, void *aux)
6593d8ca501Srkujawa {
66016740355Sandvar prop_dictionary_t dict;
6613d8ca501Srkujawa struct pci_attach_args *pa = aux;
6623d8ca501Srkujawa
6633d8ca501Srkujawa if (device_parent(dev) && device_is_a(device_parent(dev), "pci")) {
6643d8ca501Srkujawa
6653d8ca501Srkujawa dict = device_properties(dev);
6663d8ca501Srkujawa
6673d8ca501Srkujawa if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) {
6683d8ca501Srkujawa
6693d8ca501Srkujawa /* Handle the CVPPC/BVPPC card... */
6703d8ca501Srkujawa if ( ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI)
6713d8ca501Srkujawa && (PCI_PRODUCT(pa->pa_id) ==
6723d8ca501Srkujawa PCI_PRODUCT_TI_TVP4020) ) ||
6733d8ca501Srkujawa /* ...and 3Dfx Voodoo 3 in G-REX. */
6743d8ca501Srkujawa ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DFX)
6753d8ca501Srkujawa && (PCI_PRODUCT(pa->pa_id) ==
6763d8ca501Srkujawa PCI_PRODUCT_3DFX_VOODOO3) )) {
6773d8ca501Srkujawa
6783d8ca501Srkujawa prop_dictionary_set_uint32(dict, "width",
6793d8ca501Srkujawa P5GFX_WIDTH);
6803d8ca501Srkujawa
6813d8ca501Srkujawa prop_dictionary_set_uint32(dict, "height",
6823d8ca501Srkujawa P5GFX_HEIGHT);
6833d8ca501Srkujawa
6843d8ca501Srkujawa prop_dictionary_set_uint32(dict, "depth",
6853d8ca501Srkujawa P5GFX_DEPTH);
6863d8ca501Srkujawa
687bac2deebSphx #if NGENFB > 0
68816740355Sandvar prop_dictionary_t parent_dict;
68916740355Sandvar
69016740355Sandvar parent_dict = device_properties(
69116740355Sandvar device_parent(device_parent(dev)));
69216740355Sandvar
6933d8ca501Srkujawa prop_dictionary_set_uint32(dict, "linebytes",
6943d8ca501Srkujawa P5GFX_LINEBYTES);
6953d8ca501Srkujawa
6963d8ca501Srkujawa prop_dictionary_set(dict, "address",
6973d8ca501Srkujawa prop_dictionary_get(parent_dict,
6983d8ca501Srkujawa "address"));
6993d8ca501Srkujawa prop_dictionary_set(dict, "virtual_address",
7003d8ca501Srkujawa prop_dictionary_get(parent_dict,
7013d8ca501Srkujawa "virtual_address"));
7023d8ca501Srkujawa #endif
7033d8ca501Srkujawa prop_dictionary_set_bool(dict, "is_console",
7043d8ca501Srkujawa true);
7053d8ca501Srkujawa }
7063d8ca501Srkujawa }
7073d8ca501Srkujawa }
7083d8ca501Srkujawa }
7093d8ca501Srkujawa #endif /* P5PB_CONSOLE */
710