1 /* $NetBSD: vme_pcc.c,v 1.26 2012/10/27 17:18:04 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 1996-2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Steve C. Woodford. 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 /* 33 * VME support specific to the Type 1 VMEchip found on the 34 * MVME-147. 35 * 36 * For a manual on the MVME-147, call: 408.991.8634. (Yes, this 37 * is the Sunnyvale sales office.) 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: vme_pcc.c,v 1.26 2012/10/27 17:18:04 chs Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/kernel.h> 45 #include <sys/systm.h> 46 #include <sys/device.h> 47 #include <sys/malloc.h> 48 #include <sys/kcore.h> 49 50 #include <machine/cpu.h> 51 #include <machine/bus.h> 52 53 #include <dev/vme/vmereg.h> 54 #include <dev/vme/vmevar.h> 55 56 #include <mvme68k/dev/pccreg.h> 57 #include <mvme68k/dev/pccvar.h> 58 59 #include <dev/mvme/mvmebus.h> 60 #include <mvme68k/dev/vme_pccreg.h> 61 #include <mvme68k/dev/vme_pccvar.h> 62 63 64 int vme_pcc_match(device_t, cfdata_t, void *); 65 void vme_pcc_attach(device_t, device_t, void *); 66 67 CFATTACH_DECL_NEW(vmepcc, sizeof(struct vme_pcc_softc), 68 vme_pcc_match, vme_pcc_attach, NULL, NULL); 69 70 extern struct cfdriver vmepcc_cd; 71 72 extern phys_ram_seg_t mem_clusters[]; 73 static int vme_pcc_attached; 74 75 void vme_pcc_intr_establish(void *, int, int, int, int, 76 int (*)(void *), void *, struct evcnt *); 77 void vme_pcc_intr_disestablish(void *, int, int, int, struct evcnt *); 78 79 80 static struct mvmebus_range vme_pcc_masters[] = { 81 {VME_AM_A24 | 82 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG | 83 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER, 84 VME_D32 | VME_D16 | VME_D8, 85 VME1_A24D32_LOC_START, 86 VME1_A24_MASK, 87 VME1_A24D32_START, 88 VME1_A24D32_END}, 89 90 {VME_AM_A32 | 91 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG | 92 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER, 93 VME_D32 | VME_D16 | VME_D8, 94 VME1_A32D32_LOC_START, 95 VME1_A32_MASK, 96 VME1_A32D32_START, 97 VME1_A32D32_END}, 98 99 {VME_AM_A24 | 100 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG | 101 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER, 102 VME_D16 | VME_D8, 103 VME1_A24D16_LOC_START, 104 VME1_A24_MASK, 105 VME1_A24D16_START, 106 VME1_A24D16_END}, 107 108 {VME_AM_A32 | 109 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG | 110 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER, 111 VME_D16 | VME_D8, 112 VME1_A32D16_LOC_START, 113 VME1_A32_MASK, 114 VME1_A32D16_START, 115 VME1_A32D16_END}, 116 117 {VME_AM_A16 | 118 MVMEBUS_AM_CAP_DATA | 119 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER, 120 VME_D16 | VME_D8, 121 VME1_A16D16_LOC_START, 122 VME1_A16_MASK, 123 VME1_A16D16_START, 124 VME1_A16D16_END} 125 }; 126 #define VME1_NMASTERS (sizeof(vme_pcc_masters)/sizeof(struct mvmebus_range)) 127 128 129 /* ARGSUSED */ 130 int 131 vme_pcc_match(device_t parent, cfdata_t cf, void *aux) 132 { 133 struct pcc_attach_args *pa; 134 135 pa = aux; 136 137 /* Only one VME chip, please. */ 138 if (vme_pcc_attached) 139 return (0); 140 141 if (strcmp(pa->pa_name, vmepcc_cd.cd_name)) 142 return (0); 143 144 return (1); 145 } 146 147 void 148 vme_pcc_attach(device_t parent, device_t self, void *aux) 149 { 150 struct pcc_attach_args *pa; 151 struct vme_pcc_softc *sc; 152 vme_am_t am; 153 uint8_t reg; 154 155 sc = device_private(self); 156 sc->sc_mvmebus.sc_dev = self; 157 pa = aux; 158 159 /* Map the VMEchip's registers */ 160 bus_space_map(pa->pa_bust, pa->pa_offset, VME1REG_SIZE, 0, 161 &sc->sc_bush); 162 163 /* Initialise stuff used by the mvme68k common VMEbus front-end */ 164 sc->sc_mvmebus.sc_bust = pa->pa_bust; 165 sc->sc_mvmebus.sc_dmat = pa->pa_dmat; 166 sc->sc_mvmebus.sc_chip = sc; 167 sc->sc_mvmebus.sc_nmasters = VME1_NMASTERS; 168 sc->sc_mvmebus.sc_masters = &vme_pcc_masters[0]; 169 sc->sc_mvmebus.sc_nslaves = VME1_NSLAVES; 170 sc->sc_mvmebus.sc_slaves = &sc->sc_slave[0]; 171 sc->sc_mvmebus.sc_intr_establish = vme_pcc_intr_establish; 172 sc->sc_mvmebus.sc_intr_disestablish = vme_pcc_intr_disestablish; 173 174 /* Initialize the chip. */ 175 reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL; 176 vme1_reg_write(sc, VME1REG_SCON, reg); 177 178 printf(": Type 1 VMEchip, scon jumper %s\n", 179 (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled"); 180 181 /* 182 * Adjust the start address of the first range in vme_pcc_masters[] 183 * according to how much onboard memory exists. Disable the first 184 * range if onboard memory >= 16Mb, and adjust the start of the 185 * second range (A32D32). 186 */ 187 vme_pcc_masters[0].vr_vmestart = (vme_addr_t) mem_clusters[0].size; 188 if (mem_clusters[0].size >= 0x01000000) { 189 vme_pcc_masters[0].vr_am = MVMEBUS_AM_DISABLED; 190 vme_pcc_masters[1].vr_vmestart += 191 (vme_addr_t) (mem_clusters[0].size - 0x01000000); 192 } 193 194 am = 0; 195 reg = vme1_reg_read(sc, VME1REG_SLADDRMOD); 196 if ((reg & VME1_SLMOD_DATA) != 0) 197 am |= MVMEBUS_AM_CAP_DATA; 198 if ((reg & VME1_SLMOD_PRGRM) != 0) 199 am |= MVMEBUS_AM_CAP_PROG; 200 if ((reg & VME1_SLMOD_SUPER) != 0) 201 am |= MVMEBUS_AM_CAP_SUPER; 202 if ((reg & VME1_SLMOD_USER) != 0) 203 am |= MVMEBUS_AM_CAP_USER; 204 if ((reg & VME1_SLMOD_BLOCK) != 0) 205 am |= MVMEBUS_AM_CAP_BLK; 206 207 #ifdef notyet 208 if ((reg & VME1_SLMOD_SHORT) != 0) { 209 sc->sc_slave[VME1_SLAVE_A16].vr_am = am | VME_AM_A16; 210 sc->sc_slave[VME1_SLAVE_A16].vr_mask = 0xffffu; 211 } else 212 #endif 213 sc->sc_slave[VME1_SLAVE_A16].vr_am = MVMEBUS_AM_DISABLED; 214 215 if (pcc_slave_base_addr < 0x01000000u && (reg & VME1_SLMOD_STND) != 0) { 216 sc->sc_slave[VME1_SLAVE_A24].vr_am = am | VME_AM_A24; 217 sc->sc_slave[VME1_SLAVE_A24].vr_datasize = VME_D32 | 218 VME_D16 | VME_D8; 219 sc->sc_slave[VME1_SLAVE_A24].vr_mask = 0xffffffu; 220 sc->sc_slave[VME1_SLAVE_A24].vr_locstart = 0; 221 sc->sc_slave[VME1_SLAVE_A24].vr_vmestart = pcc_slave_base_addr; 222 sc->sc_slave[VME1_SLAVE_A24].vr_vmeend = (pcc_slave_base_addr + 223 mem_clusters[0].size - 1) & 0x00ffffffu; 224 } else 225 sc->sc_slave[VME1_SLAVE_A24].vr_am = MVMEBUS_AM_DISABLED; 226 227 if ((reg & VME1_SLMOD_EXTED) != 0) { 228 sc->sc_slave[VME1_SLAVE_A32].vr_am = am | VME_AM_A32; 229 sc->sc_slave[VME1_SLAVE_A32].vr_datasize = VME_D32 | 230 VME_D16 | VME_D8; 231 sc->sc_slave[VME1_SLAVE_A32].vr_mask = 0xffffffffu; 232 sc->sc_slave[VME1_SLAVE_A32].vr_locstart = 0; 233 sc->sc_slave[VME1_SLAVE_A32].vr_vmestart = pcc_slave_base_addr; 234 sc->sc_slave[VME1_SLAVE_A32].vr_vmeend = 235 pcc_slave_base_addr + mem_clusters[0].size - 1; 236 } else 237 sc->sc_slave[VME1_SLAVE_A32].vr_am = MVMEBUS_AM_DISABLED; 238 239 vme_pcc_attached = 1; 240 241 mvmebus_attach(&sc->sc_mvmebus); 242 } 243 244 void 245 vme_pcc_intr_establish(void *csc, int prior, int level, int vector, int first, int (*func)(void *), void *arg, struct evcnt *evcnt) 246 { 247 struct vme_pcc_softc *sc = csc; 248 249 if (prior != level) 250 panic("vme_pcc_intr_establish: CPU priority != VMEbus irq level"); 251 252 isrlink_vectored(func, arg, prior, vector, evcnt); 253 254 if (first) { 255 evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR, 256 isrlink_evcnt(prior), device_xname(sc->sc_mvmebus.sc_dev), 257 mvmebus_irq_name[level]); 258 259 /* 260 * There had better not be another VMEbus master responding 261 * to this interrupt level... 262 */ 263 vme1_reg_write(sc, VME1REG_IRQEN, 264 vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level)); 265 } 266 } 267 268 void 269 vme_pcc_intr_disestablish(void *csc, int level, int vector, int last, struct evcnt *evcnt) 270 { 271 struct vme_pcc_softc *sc = csc; 272 273 isrunlink_vectored(vector); 274 275 if (last) { 276 vme1_reg_write(sc, VME1REG_IRQEN, 277 vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level)); 278 evcnt_detach(evcnt); 279 } 280 } 281