1 /* $NetBSD: hpc.c,v 1.7 2002/03/13 13:12:27 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Soren S. Jorvang 5 * Copyright (c) 2001 Rafal K. Boni 6 * Copyright (c) 2001 Jason R. Thorpe 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the 20 * NetBSD Project. See http://www.netbsd.org/ for 21 * information about NetBSD. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/reboot.h> 41 42 #include <machine/machtype.h> 43 44 #include <sgimips/gio/gioreg.h> 45 #include <sgimips/gio/giovar.h> 46 47 #include <sgimips/hpc/hpcvar.h> 48 #include <sgimips/hpc/hpcreg.h> 49 #include <sgimips/hpc/iocreg.h> 50 51 #include "locators.h" 52 53 const struct hpc_device { 54 const char *hd_name; 55 bus_addr_t hd_devoff; 56 bus_addr_t hd_dmaoff; 57 int hd_irq; 58 int hd_sysmask; 59 #define HPCDEV_IP22 (1U << 0) /* Indigo2 */ 60 #define HPCDEV_IP24 (1U << 1) /* Indy */ 61 } hpc_devices[] = { 62 { "zsc", 63 /* XXX Magic numbers */ 64 HPC_PBUS_CH6_DEVREGS + 0x30, 0, 65 29, 66 HPCDEV_IP22 | HPCDEV_IP24 }, 67 68 { "sq", 69 HPC_ENET_DEVREGS, HPC_ENET_REGS, 70 3, 71 HPCDEV_IP22 | HPCDEV_IP24 }, 72 73 { "wdsc", 74 HPC_SCSI0_DEVREGS, HPC_SCSI0_REGS, 75 1, /* XXX 1 = IRQ_LOCAL0 + 1 */ 76 HPCDEV_IP22 | HPCDEV_IP24 }, 77 78 { "wdsc", 79 HPC_SCSI1_DEVREGS, HPC_SCSI1_REGS, 80 2, /* XXX 2 = IRQ_LOCAL0 + 2 */ 81 HPCDEV_IP22 }, 82 83 { "dsclock", 84 HPC_PBUS_BBRAM, 0, 85 -1, 86 HPCDEV_IP22 | HPCDEV_IP24 }, 87 88 { NULL, 89 0, 0, 90 0, 91 0 92 } 93 }; 94 95 struct hpc_softc { 96 struct device sc_dev; 97 98 bus_addr_t sc_base; 99 100 bus_space_tag_t sc_ct; 101 bus_space_handle_t sc_ch; 102 }; 103 104 extern int mach_type; /* IPxx type */ 105 extern int mach_subtype; /* subtype: eg., Guiness/Fullhouse for IP22 */ 106 extern int mach_boardrev; /* machine board revision, in case it matters */ 107 108 extern struct sgimips_bus_dma_tag sgimips_default_bus_dma_tag; 109 110 static int powerintr_established; 111 112 int hpc_match(struct device *, struct cfdata *, void *); 113 void hpc_attach(struct device *, struct device *, void *); 114 int hpc_print(void *, const char *); 115 116 int hpc_submatch(struct device *, struct cfdata *, void *); 117 118 int hpc_power_intr(void *); 119 120 struct cfattach hpc_ca = { 121 sizeof(struct hpc_softc), hpc_match, hpc_attach 122 }; 123 124 int 125 hpc_match(struct device *parent, struct cfdata *cf, void *aux) 126 { 127 struct gio_attach_args* ga = aux; 128 129 /* Make sure it's actually there and readable */ 130 if (badaddr((void*)MIPS_PHYS_TO_KSEG1(ga->ga_addr), sizeof(u_int32_t))) 131 return 0; 132 133 return 1; 134 } 135 136 void 137 hpc_attach(struct device *parent, struct device *self, void *aux) 138 { 139 struct hpc_softc *sc = (struct hpc_softc *)self; 140 struct gio_attach_args* ga = aux; 141 struct hpc_attach_args ha; 142 const struct hpc_device *hd; 143 int sysmask, hpctype; 144 145 switch (mach_type) { 146 case MACH_SGI_IP22: 147 hpctype = 3; 148 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 149 sysmask = HPCDEV_IP22; 150 else 151 sysmask = HPCDEV_IP24; 152 break; 153 154 default: 155 panic("hpc_attach: can't handle HPC on an IP%d\n", 156 mach_type); 157 }; 158 159 printf(": SGI HPC%d\n", hpctype); 160 161 sc->sc_ct = 1; 162 sc->sc_ch = ga->ga_ioh; 163 164 sc->sc_base = ga->ga_addr; 165 166 for (hd = hpc_devices; hd->hd_name != NULL; hd++) { 167 if (!(hd->hd_sysmask & sysmask)) 168 continue; 169 170 ha.ha_name = hd->hd_name; 171 ha.ha_devoff = hd->hd_devoff; 172 ha.ha_dmaoff = hd->hd_dmaoff; 173 ha.ha_irq = hd->hd_irq; 174 175 /* XXX This is disgusting. */ 176 ha.ha_st = 1; 177 ha.ha_sh = MIPS_PHYS_TO_KSEG1(sc->sc_base); 178 ha.ha_dmat = &sgimips_default_bus_dma_tag; 179 180 (void) config_found_sm(self, &ha, hpc_print, hpc_submatch); 181 } 182 183 /* 184 * XXX: Only attach the powerfail interrupt once, since the 185 * interrupt code doesn't let you share interrupt just yet. 186 * 187 * Since the powerfail interrupt is hardcoded to read from 188 * a specific register anyway (XXX#2!), we don't care when 189 * it gets attached, as long as it only happens once. 190 */ 191 if (!powerintr_established) { 192 cpu_intr_establish(9, IPL_NONE, hpc_power_intr, sc); 193 powerintr_established++; 194 } 195 } 196 197 int 198 hpc_submatch(struct device *parent, struct cfdata *cf, void *aux) 199 { 200 struct hpc_attach_args *ha = aux; 201 202 if (cf->cf_loc[HPCCF_OFFSET] != HPCCF_OFFSET_DEFAULT && 203 cf->cf_loc[HPCCF_OFFSET] != ha->ha_devoff) 204 return (0); 205 206 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 207 } 208 209 int 210 hpc_print(void *aux, const char *pnp) 211 { 212 struct hpc_attach_args *ha = aux; 213 214 if (pnp) 215 printf("%s at %s", ha->ha_name, pnp); 216 217 printf(" offset 0x%lx", ha->ha_devoff); 218 219 return (UNCONF); 220 } 221 222 int 223 hpc_power_intr(void *arg) 224 { 225 u_int32_t pwr_reg; 226 227 pwr_reg = *((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd9850)); 228 *((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd9850)) = pwr_reg; 229 230 printf("hpc_power_intr: panel reg = %08x\n", pwr_reg); 231 232 if (pwr_reg & 2) 233 cpu_reboot(RB_HALT, NULL); 234 235 return 1; 236 } 237