1 /* $NetBSD: universe_pci.c,v 1.1 2000/02/25 18:22:39 drochner Exp $ */ 2 3 /* 4 * Copyright (c) 1999 5 * Matthias Drochner. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Common functions for PCI-VME-interfaces using the 31 * Newbridge/Tundra Universe II chip (CA91C142). 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 38 #include <dev/pci/pcireg.h> 39 #include <dev/pci/pcivar.h> 40 /*#include <dev/pci/pcidevs.h>*/ 41 42 #include <machine/bus.h> 43 44 #include <dev/vme/vmereg.h> 45 #include <dev/vme/vmevar.h> 46 47 #include <dev/ic/universereg.h> 48 #include <dev/pci/universe_pci_var.h> 49 50 int univ_pci_intr __P((void *)); 51 52 #define read_csr_4(d, reg) \ 53 bus_space_read_4(d->csrt, d->csrh, offsetof(struct universereg, reg)) 54 #define write_csr_4(d, reg, val) \ 55 bus_space_write_4(d->csrt, d->csrh, offsetof(struct universereg, reg), val) 56 57 #define _pso(i) offsetof(struct universereg, __CONCAT(pcislv, i)) 58 static int pcislvoffsets[8] = { 59 _pso(0), _pso(1), _pso(2), _pso(3), 60 _pso(4), _pso(5), _pso(6), _pso(7) 61 }; 62 #undef _pso 63 64 #define read_pcislv(d, idx, reg) \ 65 bus_space_read_4(d->csrt, d->csrh, \ 66 pcislvoffsets[idx] + offsetof(struct universe_pcislvimg, reg)) 67 #define write_pcislv(d, idx, reg, val) \ 68 bus_space_write_4(d->csrt, d->csrh, \ 69 pcislvoffsets[idx] + offsetof(struct universe_pcislvimg, reg), val) 70 71 int 72 univ_pci_attach(d, pa) 73 struct univ_pci_data *d; 74 struct pci_attach_args *pa; 75 { 76 pci_chipset_tag_t pc = pa->pa_pc; 77 pci_intr_handle_t ih; 78 const char *intrstr = NULL; 79 u_int32_t reg; 80 81 d->pc = pc; 82 83 if (pci_mapreg_map(pa, 0x10, 84 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 85 0, &d->csrt, &d->csrh, NULL, NULL) && 86 pci_mapreg_map(pa, 0x14, 87 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 88 0, &d->csrt, &d->csrh, NULL, NULL) && 89 pci_mapreg_map(pa, 0x10, 90 PCI_MAPREG_TYPE_IO, 91 0, &d->csrt, &d->csrh, NULL, NULL) && 92 pci_mapreg_map(pa, 0x14, 93 PCI_MAPREG_TYPE_IO, 94 0, &d->csrt, &d->csrh, NULL, NULL)) 95 return (-1); 96 97 reg = read_csr_4(d, misc_ctl); 98 printf("univ_pci_attach: misc_ctl=%x\n", reg); 99 100 /* enable DMA */ 101 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 102 pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | 103 PCI_COMMAND_MASTER_ENABLE); 104 105 /* Map and establish the interrupt. */ 106 if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, 107 pa->pa_intrline, &ih)) { 108 printf("univ_pci_attach: couldn't map interrupt\n"); 109 return (-1); 110 } 111 intrstr = pci_intr_string(pc, ih); 112 /* 113 * Use a low interrupt level (the lowest?). 114 * We will raise before calling a subdevice's handler. 115 */ 116 d->ih = pci_intr_establish(pc, ih, IPL_BIO, univ_pci_intr, d); 117 if (d->ih == NULL) { 118 printf("univ_pci_attach: couldn't establish interrupt"); 119 if (intrstr != NULL) 120 printf(" at %s", intrstr); 121 printf("\n"); 122 return (-1); 123 } 124 printf("univ_pci: interrupting at %s\n", intrstr); 125 126 return (0); 127 } 128 129 int 130 univ_pci_mapvme(d, wnd, vmebase, len, am, datawidth, pcibase) 131 struct univ_pci_data *d; 132 int wnd; 133 vme_addr_t vmebase; 134 u_int32_t len; 135 vme_am_t am; 136 vme_datasize_t datawidth; 137 u_int32_t pcibase; 138 { 139 u_int32_t ctl = 0x80000000; 140 141 switch (am & VME_AM_ADRSIZEMASK) { 142 case VME_AM_A32: 143 ctl |= 0x00020000; 144 break; 145 case VME_AM_A24: 146 ctl |= 0x00010000; 147 break; 148 case VME_AM_A16: 149 break; 150 default: 151 return (EINVAL); 152 } 153 if (am & VME_AM_SUPER) 154 ctl |= 0x00001000; 155 if ((am & VME_AM_MODEMASK) == VME_AM_PRG) 156 ctl |= 0x00004000; 157 if (datawidth & VME_D32) 158 ctl |= 0x00800000; 159 else if (datawidth & VME_D16) 160 ctl |= 0x00400000; 161 else if (!(datawidth & VME_D8)) 162 return (EINVAL); 163 164 #ifdef UNIV_DEBUG 165 printf("univ_pci_mapvme: wnd %d, map %x-%x to %x, ctl=%x\n", 166 wnd, pcibase, pcibase + len, vmebase, ctl); 167 #endif 168 169 write_pcislv(d, wnd, lsi_bs, pcibase); 170 write_pcislv(d, wnd, lsi_bd, pcibase + len); 171 write_pcislv(d, wnd, lsi_to, vmebase - pcibase); 172 write_pcislv(d, wnd, lsi_ctl, ctl); 173 return (0); 174 } 175 176 void 177 univ_pci_unmapvme(d, wnd) 178 struct univ_pci_data *d; 179 int wnd; 180 { 181 #ifdef UNIV_DEBUG 182 printf("univ_pci_unmapvme: wnd %d\n", wnd); 183 #endif 184 write_pcislv(d, wnd, lsi_ctl, 0); 185 } 186 187 int 188 univ_pci_intr(v) 189 void *v; 190 { 191 struct univ_pci_data *d = v; 192 u_int32_t intcsr; 193 194 intcsr = read_csr_4(d, lint_stat) & 0xffffff; 195 196 if (!intcsr) 197 return (0); 198 199 /* ack everything */ 200 write_csr_4(d, lint_stat, intcsr); 201 202 printf("univ_pci_intr: lint_stat=%x\n", intcsr); 203 204 return (1); 205 } 206