1 /* $NetBSD: vme_pcc.c,v 1.25 2009/03/16 23:11:13 dsl 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.25 2009/03/16 23:11:13 dsl 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(struct device *, struct cfdata *, void *); 65 void vme_pcc_attach(struct device *, struct device *, void *); 66 67 CFATTACH_DECL(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(struct device *parent, struct cfdata *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(struct device *parent, struct device *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 = (struct vme_pcc_softc *) self; 156 pa = aux; 157 158 /* Map the VMEchip's registers */ 159 bus_space_map(pa->pa_bust, pa->pa_offset, VME1REG_SIZE, 0, 160 &sc->sc_bush); 161 162 /* Initialise stuff used by the mvme68k common VMEbus front-end */ 163 sc->sc_mvmebus.sc_bust = pa->pa_bust; 164 sc->sc_mvmebus.sc_dmat = pa->pa_dmat; 165 sc->sc_mvmebus.sc_chip = sc; 166 sc->sc_mvmebus.sc_nmasters = VME1_NMASTERS; 167 sc->sc_mvmebus.sc_masters = &vme_pcc_masters[0]; 168 sc->sc_mvmebus.sc_nslaves = VME1_NSLAVES; 169 sc->sc_mvmebus.sc_slaves = &sc->sc_slave[0]; 170 sc->sc_mvmebus.sc_intr_establish = vme_pcc_intr_establish; 171 sc->sc_mvmebus.sc_intr_disestablish = vme_pcc_intr_disestablish; 172 173 /* Initialize the chip. */ 174 reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL; 175 vme1_reg_write(sc, VME1REG_SCON, reg); 176 177 printf(": Type 1 VMEchip, scon jumper %s\n", 178 (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled"); 179 180 /* 181 * Adjust the start address of the first range in vme_pcc_masters[] 182 * according to how much onboard memory exists. Disable the first 183 * range if onboard memory >= 16Mb, and adjust the start of the 184 * second range (A32D32). 185 */ 186 vme_pcc_masters[0].vr_vmestart = (vme_addr_t) mem_clusters[0].size; 187 if (mem_clusters[0].size >= 0x01000000) { 188 vme_pcc_masters[0].vr_am = MVMEBUS_AM_DISABLED; 189 vme_pcc_masters[1].vr_vmestart += 190 (vme_addr_t) (mem_clusters[0].size - 0x01000000); 191 } 192 193 am = 0; 194 reg = vme1_reg_read(sc, VME1REG_SLADDRMOD); 195 if ((reg & VME1_SLMOD_DATA) != 0) 196 am |= MVMEBUS_AM_CAP_DATA; 197 if ((reg & VME1_SLMOD_PRGRM) != 0) 198 am |= MVMEBUS_AM_CAP_PROG; 199 if ((reg & VME1_SLMOD_SUPER) != 0) 200 am |= MVMEBUS_AM_CAP_SUPER; 201 if ((reg & VME1_SLMOD_USER) != 0) 202 am |= MVMEBUS_AM_CAP_USER; 203 if ((reg & VME1_SLMOD_BLOCK) != 0) 204 am |= MVMEBUS_AM_CAP_BLK; 205 206 #ifdef notyet 207 if ((reg & VME1_SLMOD_SHORT) != 0) { 208 sc->sc_slave[VME1_SLAVE_A16].vr_am = am | VME_AM_A16; 209 sc->sc_slave[VME1_SLAVE_A16].vr_mask = 0xffffu; 210 } else 211 #endif 212 sc->sc_slave[VME1_SLAVE_A16].vr_am = MVMEBUS_AM_DISABLED; 213 214 if (pcc_slave_base_addr < 0x01000000u && (reg & VME1_SLMOD_STND) != 0) { 215 sc->sc_slave[VME1_SLAVE_A24].vr_am = am | VME_AM_A24; 216 sc->sc_slave[VME1_SLAVE_A24].vr_datasize = VME_D32 | 217 VME_D16 | VME_D8; 218 sc->sc_slave[VME1_SLAVE_A24].vr_mask = 0xffffffu; 219 sc->sc_slave[VME1_SLAVE_A24].vr_locstart = 0; 220 sc->sc_slave[VME1_SLAVE_A24].vr_vmestart = pcc_slave_base_addr; 221 sc->sc_slave[VME1_SLAVE_A24].vr_vmeend = (pcc_slave_base_addr + 222 mem_clusters[0].size - 1) & 0x00ffffffu; 223 } else 224 sc->sc_slave[VME1_SLAVE_A24].vr_am = MVMEBUS_AM_DISABLED; 225 226 if ((reg & VME1_SLMOD_EXTED) != 0) { 227 sc->sc_slave[VME1_SLAVE_A32].vr_am = am | VME_AM_A32; 228 sc->sc_slave[VME1_SLAVE_A32].vr_datasize = VME_D32 | 229 VME_D16 | VME_D8; 230 sc->sc_slave[VME1_SLAVE_A32].vr_mask = 0xffffffffu; 231 sc->sc_slave[VME1_SLAVE_A32].vr_locstart = 0; 232 sc->sc_slave[VME1_SLAVE_A32].vr_vmestart = pcc_slave_base_addr; 233 sc->sc_slave[VME1_SLAVE_A32].vr_vmeend = 234 pcc_slave_base_addr + mem_clusters[0].size - 1; 235 } else 236 sc->sc_slave[VME1_SLAVE_A32].vr_am = MVMEBUS_AM_DISABLED; 237 238 vme_pcc_attached = 1; 239 240 mvmebus_attach(&sc->sc_mvmebus); 241 } 242 243 void 244 vme_pcc_intr_establish(void *csc, int prior, int level, int vector, int first, int (*func)(void *), void *arg, struct evcnt *evcnt) 245 { 246 struct vme_pcc_softc *sc = csc; 247 248 if (prior != level) 249 panic("vme_pcc_intr_establish: CPU priority != VMEbus irq level"); 250 251 isrlink_vectored(func, arg, prior, vector, evcnt); 252 253 if (first) { 254 evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR, 255 isrlink_evcnt(prior), sc->sc_mvmebus.sc_dev.dv_xname, 256 mvmebus_irq_name[level]); 257 258 /* 259 * There had better not be another VMEbus master responding 260 * to this interrupt level... 261 */ 262 vme1_reg_write(sc, VME1REG_IRQEN, 263 vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level)); 264 } 265 } 266 267 void 268 vme_pcc_intr_disestablish(void *csc, int level, int vector, int last, struct evcnt *evcnt) 269 { 270 struct vme_pcc_softc *sc = csc; 271 272 isrunlink_vectored(vector); 273 274 if (last) { 275 vme1_reg_write(sc, VME1REG_IRQEN, 276 vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level)); 277 evcnt_detach(evcnt); 278 } 279 } 280