1 /* $NetBSD: eeprom.c,v 1.11 1996/10/30 00:24:32 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 /* Validate the given address. */ 90 if (ca->ca_paddr != OBIO_EEPROM) 91 return (0); 92 93 if (eeprom_va == NULL) 94 return (0); 95 96 return (1); 97 } 98 99 static void 100 eeprom_attach(parent, self, args) 101 struct device *parent; 102 struct device *self; 103 void *args; 104 { 105 struct confargs *ca = args; 106 107 printf("\n"); 108 } 109 110 111 static int ee_take() /* Take the lock. */ 112 { 113 int error = 0; 114 while (ee_busy) { 115 ee_want = 1; 116 error = tsleep(&ee_busy, PZERO | PCATCH, "eeprom", 0); 117 ee_want = 0; 118 if (error) /* interrupted */ 119 goto out; 120 } 121 ee_busy = 1; 122 out: 123 return error; 124 } 125 126 static void ee_give() /* Give the lock. */ 127 { 128 ee_busy = 0; 129 if (ee_want) { 130 ee_want = 0; 131 wakeup(&ee_busy); 132 } 133 } 134 135 int eeprom_uio(struct uio *uio) 136 { 137 int error; 138 int off; /* NOT off_t */ 139 u_int cnt; 140 caddr_t va; 141 caddr_t buf = (caddr_t)0; 142 143 off = uio->uio_offset; 144 if (off >= OBIO_EEPROM_SIZE) 145 return (EFAULT); 146 147 cnt = uio->uio_resid; 148 if (cnt > (OBIO_EEPROM_SIZE - off)) 149 cnt = (OBIO_EEPROM_SIZE - off); 150 151 if ((error = ee_take()) != 0) 152 return (error); 153 154 if (eeprom_va == NULL) { 155 error = ENXIO; 156 goto out; 157 } 158 159 va = eeprom_va; 160 if (uio->uio_rw != UIO_READ) { 161 /* Write requires a temporary buffer. */ 162 buf = malloc(OBIO_EEPROM_SIZE, M_DEVBUF, M_WAITOK); 163 if (!buf) { 164 error = EAGAIN; 165 goto out; 166 } 167 va = buf; 168 } 169 170 if ((error = uiomove(va + off, (int)cnt, uio)) != 0) 171 goto out; 172 173 if (uio->uio_rw != UIO_READ) 174 error = ee_update(buf, off, cnt); 175 176 out: 177 if (buf) 178 free(buf, M_DEVBUF); 179 ee_give(); 180 return (error); 181 } 182 183 /* 184 * Update the EEPROM from the passed buf. 185 */ 186 static int ee_update(char *buf, int off, int cnt) 187 { 188 volatile char *ep; 189 char *bp; 190 191 if (eeprom_va == NULL) 192 return (ENXIO); 193 194 ep = eeprom_va + off; 195 bp = buf + off; 196 197 while (cnt > 0) { 198 /* 199 * DO NOT WRITE IT UNLESS WE HAVE TO because the 200 * EEPROM has a limited number of write cycles. 201 * After some number of writes it just fails! 202 */ 203 if (*ep != *bp) { 204 *ep = *bp; 205 /* 206 * We have written the EEPROM, so now we must 207 * sleep for at least 10 milliseconds while 208 * holding the lock to prevent all access to 209 * the EEPROM while it recovers. 210 */ 211 (void)tsleep(eeprom_va, PZERO-1, "eeprom", HZ/50); 212 } 213 /* Make sure the write worked. */ 214 if (*ep != *bp) 215 return (EIO); 216 ep++; 217 bp++; 218 cnt--; 219 } 220 return(0); 221 } 222 223 /* 224 * Read a byte out of the EEPROM. This is called from 225 * things like the zs driver very early to find out 226 * which device should be used as the console. 227 */ 228 int ee_get_byte(int off, int canwait) 229 { 230 int c = -1; 231 if ((off < 0) || (off >= OBIO_EEPROM_SIZE)) 232 goto out; 233 if (eeprom_va == NULL) 234 goto out; 235 236 if (canwait) { 237 if (ee_take()) 238 goto out; 239 } else { 240 if (ee_busy) 241 goto out; 242 } 243 244 c = eeprom_va[off] & 0xFF; 245 246 if (canwait) 247 ee_give(); 248 out: 249 return c; 250 } 251