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