1 /* $NetBSD: nsclpcsio_isa.c,v 1.5 2002/10/22 16:18:26 drochner Exp $ */ 2 3 /* 4 * Copyright (c) 2002 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 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: nsclpcsio_isa.c,v 1.5 2002/10/22 16:18:26 drochner Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <machine/bus.h> 36 37 #include <dev/isa/isareg.h> 38 #include <dev/isa/isavar.h> 39 #include <dev/sysmon/sysmonvar.h> 40 41 static int nsclpcsio_isa_match __P((struct device *, struct cfdata *, void *)); 42 static void nsclpcsio_isa_attach __P((struct device *, struct device *, 43 void *)); 44 45 struct nsclpcsio_softc { 46 struct device sc_dev; 47 bus_space_tag_t sc_iot, sc_tms_iot; 48 bus_space_handle_t sc_ioh, sc_tms_ioh; 49 50 struct envsys_tre_data sc_data[3]; 51 struct envsys_basic_info sc_info[3]; 52 struct sysmon_envsys sc_sysmon; 53 }; 54 55 CFATTACH_DECL(nsclpcsio_isa, sizeof(struct nsclpcsio_softc), 56 nsclpcsio_isa_match, nsclpcsio_isa_attach, NULL, NULL); 57 58 static const struct envsys_range tms_ranges[] = { 59 { 0, 2, ENVSYS_STEMP }, 60 }; 61 62 static u_int8_t nsread(bus_space_tag_t, bus_space_handle_t, int); 63 static void nswrite(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); 64 static int nscheck(bus_space_tag_t, int); 65 66 static void tms_update(struct nsclpcsio_softc *, int); 67 static int tms_gtredata(struct sysmon_envsys *, struct envsys_tre_data *); 68 static int tms_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 69 70 static u_int8_t 71 nsread(iot, ioh, idx) 72 bus_space_tag_t iot; 73 bus_space_handle_t ioh; 74 int idx; 75 { 76 77 bus_space_write_1(iot, ioh, 0, idx); 78 return (bus_space_read_1(iot, ioh, 1)); 79 } 80 81 static void 82 nswrite(iot, ioh, idx, data) 83 bus_space_tag_t iot; 84 bus_space_handle_t ioh; 85 int idx; 86 u_int8_t data; 87 { 88 89 bus_space_write_1(iot, ioh, 0, idx); 90 bus_space_write_1(iot, ioh, 1, data); 91 } 92 93 static int 94 nscheck(iot, base) 95 bus_space_tag_t iot; 96 int base; 97 { 98 bus_space_handle_t ioh; 99 int rv = 0; 100 101 if (bus_space_map(iot, base, 2, 0, &ioh)) 102 return (0); 103 104 /* XXX this is for PC87366 only for now */ 105 if (nsread(iot, ioh, 0x20) == 0xe9) 106 rv = 1; 107 108 bus_space_unmap(iot, ioh, 2); 109 return (rv); 110 } 111 112 static int 113 nsclpcsio_isa_match(parent, match, aux) 114 struct device *parent; 115 struct cfdata *match; 116 void *aux; 117 { 118 struct isa_attach_args *ia = aux; 119 int iobase; 120 121 if (ISA_DIRECT_CONFIG(ia)) 122 return (0); 123 124 if (ia->ia_nio > 0 && ia->ia_io[0].ir_addr != ISACF_PORT_DEFAULT) { 125 /* XXX check for legal iobase ??? */ 126 if (nscheck(ia->ia_iot, ia->ia_io[0].ir_addr)) { 127 iobase = ia->ia_io[0].ir_addr; 128 goto found; 129 } 130 return (0); 131 } 132 133 /* PC87366 has two possible locations depending on wiring */ 134 if (nscheck(ia->ia_iot, 0x2e)) { 135 iobase = 0x2e; 136 goto found; 137 } 138 if (nscheck(ia->ia_iot, 0x4e)) { 139 iobase = 0x4e; 140 goto found; 141 } 142 return (0); 143 144 found: 145 ia->ia_nio = 1; 146 ia->ia_io[0].ir_addr = iobase; 147 ia->ia_io[0].ir_size = 2; 148 ia->ia_niomem = 0; 149 ia->ia_nirq = 0; 150 ia->ia_ndrq = 0; 151 return (1); 152 } 153 154 static void 155 nsclpcsio_isa_attach(parent, self, aux) 156 struct device *parent, *self; 157 void *aux; 158 { 159 struct nsclpcsio_softc *sc = (void *)self; 160 struct isa_attach_args *ia = aux; 161 bus_space_tag_t iot; 162 bus_space_handle_t ioh; 163 u_int8_t val; 164 int tms_iobase; 165 int i; 166 167 sc->sc_iot = iot = ia->ia_iot; 168 if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh)) { 169 printf(": can't map i/o space\n"); 170 return; 171 } 172 sc->sc_ioh = ioh; 173 printf(": NSC PC87366 rev. %d\n", nsread(iot, ioh, 0x27)); 174 175 nswrite(iot, ioh, 0x07, 0x0e); /* select tms */ 176 177 val = nsread(iot, ioh, 0x30); /* control register */ 178 if (!(val & 1)) { 179 printf("%s: TMS disabled\n", sc->sc_dev.dv_xname); 180 return; 181 } 182 183 tms_iobase = (nsread(iot, ioh, 0x60) << 8) | nsread(iot, ioh, 0x61); 184 sc->sc_tms_iot = iot; 185 if (bus_space_map(iot, tms_iobase, 16, 0, &sc->sc_tms_ioh)) { 186 printf("%s: can't map TMS i/o space\n", sc->sc_dev.dv_xname); 187 return; 188 } 189 printf("%s: TMS at 0x%x\n", sc->sc_dev.dv_xname, tms_iobase); 190 191 if (bus_space_read_1(sc->sc_tms_iot, sc->sc_tms_ioh, 0x08) & 1) { 192 printf("%s: TMS in standby mode\n", sc->sc_dev.dv_xname); 193 /* XXX awake it ??? */ 194 return; 195 } 196 197 /* Initialize sensor meta data */ 198 for (i = 0; i < 3; i++) { 199 sc->sc_data[i].sensor = sc->sc_info[i].sensor = i; 200 sc->sc_data[i].units = sc->sc_info[i].units = ENVSYS_STEMP; 201 } 202 strcpy(sc->sc_info[0].desc, "TSENS1"); 203 strcpy(sc->sc_info[1].desc, "TSENS2"); 204 strcpy(sc->sc_info[2].desc, "TNSC"); 205 206 /* Get initial set of sensor values. */ 207 for (i = 0; i < 3; i++) 208 tms_update(sc, i); 209 210 /* 211 * Hook into the System Monitor. 212 */ 213 sc->sc_sysmon.sme_ranges = tms_ranges; 214 sc->sc_sysmon.sme_sensor_info = sc->sc_info; 215 sc->sc_sysmon.sme_sensor_data = sc->sc_data; 216 sc->sc_sysmon.sme_cookie = sc; 217 218 sc->sc_sysmon.sme_gtredata = tms_gtredata; 219 sc->sc_sysmon.sme_streinfo = tms_streinfo; 220 221 sc->sc_sysmon.sme_nsensors = 3; 222 sc->sc_sysmon.sme_envsys_version = 1000; 223 224 if (sysmon_envsys_register(&sc->sc_sysmon)) 225 printf("%s: unable to register with sysmon\n", 226 sc->sc_dev.dv_xname); 227 } 228 229 static void 230 tms_update(sc, chan) 231 struct nsclpcsio_softc *sc; 232 int chan; 233 { 234 bus_space_tag_t iot = sc->sc_tms_iot; 235 bus_space_handle_t ioh = sc->sc_tms_ioh; 236 u_int8_t status; 237 int8_t temp, ctemp; /* signed!! */ 238 239 bus_space_write_1(iot, ioh, 0x09, chan); /* select */ 240 241 status = bus_space_read_1(iot, ioh, 0x0a); /* config/status */ 242 if (status & 0x01) { 243 /* enabled */ 244 sc->sc_info[chan].validflags = ENVSYS_FVALID; 245 }else { 246 sc->sc_info[chan].validflags = 0; 247 return; 248 } 249 250 /* 251 * If the channel is enabled, it is considered valid. 252 * An "open circuit" might be temporary. 253 */ 254 sc->sc_data[chan].validflags = ENVSYS_FVALID; 255 if (status & 0x40) { 256 /* 257 * open circuit 258 * XXX should have a warning for it 259 */ 260 sc->sc_data[chan].warnflags = ENVSYS_WARN_OK; /* XXX */ 261 return; 262 } 263 264 /* get current temperature in signed degree celsius */ 265 temp = bus_space_read_1(iot, ioh, 0x0b); 266 sc->sc_data[chan].cur.data_us = (int)temp * 1000000 + 273150000; 267 sc->sc_data[chan].validflags |= ENVSYS_FCURVALID; 268 269 if (status & 0x0e) { /* any temperature warning? */ 270 /* 271 * XXX the chip documentation is a bit fuzzy - it doesn't state 272 * that the hardware OTS output depends on the "overtemp" 273 * warning bit. 274 * It seems the output gets cleared if the warning bit is reset. 275 * This sucks. 276 * The hardware might do something useful with output pins, eg 277 * throttling the CPU, so we must do the comparision in 278 * software, and only reset the bits if the reason is gone. 279 */ 280 if (status & 0x02) { /* low limit */ 281 sc->sc_data[chan].warnflags = ENVSYS_WARN_UNDER; 282 /* read low limit */ 283 ctemp = bus_space_read_1(iot, ioh, 0x0d); 284 if (temp <= ctemp) /* still valid, don't reset */ 285 status &= ~0x02; 286 } 287 if (status & 0x04) { /* high limit */ 288 sc->sc_data[chan].warnflags = ENVSYS_WARN_OVER; 289 /* read high limit */ 290 ctemp = bus_space_read_1(iot, ioh, 0x0c); 291 if (temp >= ctemp) /* still valid, don't reset */ 292 status &= ~0x04; 293 } 294 if (status & 0x08) { /* overtemperature */ 295 sc->sc_data[chan].warnflags = ENVSYS_WARN_CRITOVER; 296 /* read overtemperature limit */ 297 ctemp = bus_space_read_1(iot, ioh, 0x0e); 298 if (temp >= ctemp) /* still valid, don't reset */ 299 status &= ~0x08; 300 } 301 302 /* clear outdated warnings */ 303 if (status & 0x0e) 304 bus_space_write_1(iot, ioh, 0x0a, status); 305 } 306 } 307 308 static int 309 tms_gtredata(sme, data) 310 struct sysmon_envsys *sme; 311 struct envsys_tre_data *data; 312 { 313 struct nsclpcsio_softc *sc = sme->sme_cookie; 314 315 tms_update(sc, data->sensor); 316 317 *data = sc->sc_data[data->sensor]; 318 return (0); 319 } 320 321 static int 322 tms_streinfo(sme, info) 323 struct sysmon_envsys *sme; 324 struct envsys_basic_info *info; 325 { 326 #if 0 327 struct nsclpcsio_softc *sc = sme->sme_cookie; 328 #endif 329 /* XXX Not implemented */ 330 info->validflags = 0; 331 332 return (0); 333 } 334