1 /* $NetBSD: hpc.c,v 1.12 2002/11/09 18:54:27 thorpej 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 CFATTACH_DECL(hpc, sizeof(struct hpc_softc), 121 hpc_match, hpc_attach, NULL, NULL); 122 123 int 124 hpc_match(struct device *parent, struct cfdata *cf, void *aux) 125 { 126 struct gio_attach_args* ga = aux; 127 128 /* Make sure it's actually there and readable */ 129 if (badaddr((void*)MIPS_PHYS_TO_KSEG1(ga->ga_addr), sizeof(u_int32_t))) 130 return 0; 131 132 return 1; 133 } 134 135 void 136 hpc_attach(struct device *parent, struct device *self, void *aux) 137 { 138 struct hpc_softc *sc = (struct hpc_softc *)self; 139 struct gio_attach_args* ga = aux; 140 struct hpc_attach_args ha; 141 const struct hpc_device *hd; 142 int sysmask, hpctype; 143 144 switch (mach_type) { 145 case MACH_SGI_IP22: 146 hpctype = 3; 147 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 148 sysmask = HPCDEV_IP22; 149 else 150 sysmask = HPCDEV_IP24; 151 break; 152 153 default: 154 panic("hpc_attach: can't handle HPC on an IP%d", 155 mach_type); 156 }; 157 158 printf(": SGI HPC%d\n", hpctype); 159 160 sc->sc_ct = 1; 161 sc->sc_ch = ga->ga_ioh; 162 163 sc->sc_base = ga->ga_addr; 164 165 for (hd = hpc_devices; hd->hd_name != NULL; hd++) { 166 if (!(hd->hd_sysmask & sysmask)) 167 continue; 168 169 ha.ha_name = hd->hd_name; 170 ha.ha_devoff = hd->hd_devoff; 171 ha.ha_dmaoff = hd->hd_dmaoff; 172 ha.ha_irq = hd->hd_irq; 173 174 /* XXX This is disgusting. */ 175 ha.ha_st = 1; 176 ha.ha_sh = MIPS_PHYS_TO_KSEG1(sc->sc_base); 177 ha.ha_dmat = &sgimips_default_bus_dma_tag; 178 179 (void) config_found_sm(self, &ha, hpc_print, hpc_submatch); 180 } 181 182 /* 183 * XXX: Only attach the powerfail interrupt once, since the 184 * interrupt code doesn't let you share interrupt just yet. 185 * 186 * Since the powerfail interrupt is hardcoded to read from 187 * a specific register anyway (XXX#2!), we don't care when 188 * it gets attached, as long as it only happens once. 189 */ 190 if (!powerintr_established) { 191 cpu_intr_establish(9, IPL_NONE, hpc_power_intr, sc); 192 powerintr_established++; 193 } 194 } 195 196 int 197 hpc_submatch(struct device *parent, struct cfdata *cf, void *aux) 198 { 199 struct hpc_attach_args *ha = aux; 200 201 if (cf->cf_loc[HPCCF_OFFSET] != HPCCF_OFFSET_DEFAULT && 202 (bus_addr_t) cf->cf_loc[HPCCF_OFFSET] != ha->ha_devoff) 203 return (0); 204 205 return (config_match(parent, cf, aux)); 206 } 207 208 int 209 hpc_print(void *aux, const char *pnp) 210 { 211 struct hpc_attach_args *ha = aux; 212 213 if (pnp) 214 printf("%s at %s", ha->ha_name, pnp); 215 216 printf(" offset 0x%lx", ha->ha_devoff); 217 218 return (UNCONF); 219 } 220 221 int 222 hpc_power_intr(void *arg) 223 { 224 u_int32_t pwr_reg; 225 226 pwr_reg = *((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd9850)); 227 *((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd9850)) = pwr_reg; 228 229 printf("hpc_power_intr: panel reg = %08x\n", pwr_reg); 230 231 if (pwr_reg & 2) 232 cpu_reboot(RB_HALT, NULL); 233 234 return 1; 235 } 236