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