1 /* $NetBSD: eeprom.c,v 1.8 1996/03/26 15:16:06 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Gordon W. Ross 5 * 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 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Access functions for the EEPROM (Electrically Eraseable PROM) 32 * The main reason for the existence of this module is to 33 * handle the painful task of updating the EEPROM contents. 34 * After a write, it must not be touched for 10 milliseconds. 35 * (See the Sun-3 Architecture Manual sec. 5.9) 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/conf.h> 42 #include <sys/buf.h> 43 #include <sys/malloc.h> 44 45 #include <machine/autoconf.h> 46 #include <machine/obio.h> 47 #include <machine/eeprom.h> 48 49 #define HZ 100 /* XXX */ 50 51 int ee_console; /* for convenience of drivers */ 52 53 static int ee_update(caddr_t buf, int off, int cnt); 54 55 static char *eeprom_va; 56 static int ee_busy, ee_want; 57 58 static int eeprom_match __P((struct device *, void *vcf, void *args)); 59 static void eeprom_attach __P((struct device *, struct device *, void *)); 60 61 struct cfattach eeprom_ca = { 62 sizeof(struct device), eeprom_match, eeprom_attach 63 }; 64 65 struct cfdriver eeprom_cd = { 66 NULL, "eeprom", DV_DULL 67 }; 68 69 /* Called very early by internal_configure. */ 70 void eeprom_init() 71 { 72 eeprom_va = obio_find_mapping(OBIO_EEPROM, OBIO_EEPROM_SIZE); 73 ee_console = ((struct eeprom *)eeprom_va)->eeConsole; 74 } 75 76 static int 77 eeprom_match(parent, vcf, args) 78 struct device *parent; 79 void *vcf, *args; 80 { 81 struct cfdata *cf = vcf; 82 struct confargs *ca = args; 83 int pa; 84 85 /* This driver only supports one unit. */ 86 if (cf->cf_unit != 0) 87 return (0); 88 89 if ((pa = cf->cf_paddr) == -1) { 90 /* Use our default PA. */ 91 pa = OBIO_EEPROM; 92 } else { 93 /* Validate the given PA. */ 94 if (pa != OBIO_EEPROM) 95 return (0); 96 } 97 if (pa != ca->ca_paddr) 98 return (0); 99 100 if (eeprom_va == NULL) 101 return (0); 102 103 return (1); 104 } 105 106 static void 107 eeprom_attach(parent, self, args) 108 struct device *parent; 109 struct device *self; 110 void *args; 111 { 112 struct confargs *ca = args; 113 114 printf("\n"); 115 } 116 117 118 static int ee_take() /* Take the lock. */ 119 { 120 int error = 0; 121 while (ee_busy) { 122 ee_want = 1; 123 error = tsleep(&ee_busy, PZERO | PCATCH, "eeprom", 0); 124 ee_want = 0; 125 if (error) /* interrupted */ 126 goto out; 127 } 128 ee_busy = 1; 129 out: 130 return error; 131 } 132 133 static void ee_give() /* Give the lock. */ 134 { 135 ee_busy = 0; 136 if (ee_want) { 137 ee_want = 0; 138 wakeup(&ee_busy); 139 } 140 } 141 142 int eeprom_uio(struct uio *uio) 143 { 144 int error; 145 int off; /* NOT off_t */ 146 u_int cnt; 147 caddr_t va; 148 caddr_t buf = (caddr_t)0; 149 150 off = uio->uio_offset; 151 if (off >= OBIO_EEPROM_SIZE) 152 return (EFAULT); 153 154 cnt = uio->uio_resid; 155 if (cnt > (OBIO_EEPROM_SIZE - off)) 156 cnt = (OBIO_EEPROM_SIZE - off); 157 158 if ((error = ee_take()) != 0) 159 return (error); 160 161 if (eeprom_va == NULL) { 162 error = ENXIO; 163 goto out; 164 } 165 166 va = eeprom_va; 167 if (uio->uio_rw != UIO_READ) { 168 /* Write requires a temporary buffer. */ 169 buf = malloc(OBIO_EEPROM_SIZE, M_DEVBUF, M_WAITOK); 170 if (!buf) { 171 error = EAGAIN; 172 goto out; 173 } 174 va = buf; 175 } 176 177 if ((error = uiomove(va + off, (int)cnt, uio)) != 0) 178 goto out; 179 180 if (uio->uio_rw != UIO_READ) 181 error = ee_update(buf, off, cnt); 182 183 out: 184 if (buf) 185 free(buf, M_DEVBUF); 186 ee_give(); 187 return (error); 188 } 189 190 /* 191 * Update the EEPROM from the passed buf. 192 */ 193 static int ee_update(char *buf, int off, int cnt) 194 { 195 volatile char *ep; 196 char *bp; 197 198 if (eeprom_va == NULL) 199 return (ENXIO); 200 201 ep = eeprom_va + off; 202 bp = buf + off; 203 204 while (cnt > 0) { 205 /* 206 * DO NOT WRITE IT UNLESS WE HAVE TO because the 207 * EEPROM has a limited number of write cycles. 208 * After some number of writes it just fails! 209 */ 210 if (*ep != *bp) { 211 *ep = *bp; 212 /* 213 * We have written the EEPROM, so now we must 214 * sleep for at least 10 milliseconds while 215 * holding the lock to prevent all access to 216 * the EEPROM while it recovers. 217 */ 218 (void)tsleep(eeprom_va, PZERO-1, "eeprom", HZ/50); 219 } 220 /* Make sure the write worked. */ 221 if (*ep != *bp) 222 return (EIO); 223 ep++; 224 bp++; 225 cnt--; 226 } 227 return(0); 228 } 229 230 /* 231 * Read a byte out of the EEPROM. This is called from 232 * things like the zs driver very early to find out 233 * which device should be used as the console. 234 */ 235 int ee_get_byte(int off, int canwait) 236 { 237 int c = -1; 238 if ((off < 0) || (off >= OBIO_EEPROM_SIZE)) 239 goto out; 240 if (eeprom_va == NULL) 241 goto out; 242 243 if (canwait) { 244 if (ee_take()) 245 goto out; 246 } else { 247 if (ee_busy) 248 goto out; 249 } 250 251 c = eeprom_va[off] & 0xFF; 252 253 if (canwait) 254 ee_give(); 255 out: 256 return c; 257 } 258