eeprom.c revision 1.21.6.2 1 1.21.6.2 nathanw /* $NetBSD: eeprom.c,v 1.21.6.2 2002/10/18 02:40:19 nathanw Exp $ */
2 1.21.6.2 nathanw
3 1.21.6.2 nathanw /*-
4 1.21.6.2 nathanw * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 1.21.6.2 nathanw * All rights reserved.
6 1.21.6.2 nathanw *
7 1.21.6.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
8 1.21.6.2 nathanw * by Gordon W. Ross.
9 1.21.6.2 nathanw *
10 1.21.6.2 nathanw * Redistribution and use in source and binary forms, with or without
11 1.21.6.2 nathanw * modification, are permitted provided that the following conditions
12 1.21.6.2 nathanw * are met:
13 1.21.6.2 nathanw * 1. Redistributions of source code must retain the above copyright
14 1.21.6.2 nathanw * notice, this list of conditions and the following disclaimer.
15 1.21.6.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
16 1.21.6.2 nathanw * notice, this list of conditions and the following disclaimer in the
17 1.21.6.2 nathanw * documentation and/or other materials provided with the distribution.
18 1.21.6.2 nathanw * 3. All advertising materials mentioning features or use of this software
19 1.21.6.2 nathanw * must display the following acknowledgement:
20 1.21.6.2 nathanw * This product includes software developed by the NetBSD
21 1.21.6.2 nathanw * Foundation, Inc. and its contributors.
22 1.21.6.2 nathanw * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.21.6.2 nathanw * contributors may be used to endorse or promote products derived
24 1.21.6.2 nathanw * from this software without specific prior written permission.
25 1.21.6.2 nathanw *
26 1.21.6.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.21.6.2 nathanw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.21.6.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.21.6.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.21.6.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.21.6.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.21.6.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.21.6.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.21.6.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.21.6.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.21.6.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
37 1.21.6.2 nathanw */
38 1.21.6.2 nathanw
39 1.21.6.2 nathanw /*
40 1.21.6.2 nathanw * Access functions for the EEPROM (Electrically Eraseable PROM)
41 1.21.6.2 nathanw * The main reason for the existence of this module is to
42 1.21.6.2 nathanw * handle the painful task of updating the EEPROM contents.
43 1.21.6.2 nathanw * After a write, it must not be touched for 10 milliseconds.
44 1.21.6.2 nathanw * (See the Sun-3 Architecture Manual sec. 5.9)
45 1.21.6.2 nathanw */
46 1.21.6.2 nathanw
47 1.21.6.2 nathanw #include <sys/param.h>
48 1.21.6.2 nathanw #include <sys/systm.h>
49 1.21.6.2 nathanw #include <sys/device.h>
50 1.21.6.2 nathanw #include <sys/conf.h>
51 1.21.6.2 nathanw #include <sys/buf.h>
52 1.21.6.2 nathanw #include <sys/malloc.h>
53 1.21.6.2 nathanw #include <sys/proc.h>
54 1.21.6.2 nathanw #include <sys/kernel.h>
55 1.21.6.2 nathanw
56 1.21.6.2 nathanw #include <machine/autoconf.h>
57 1.21.6.2 nathanw #include <machine/idprom.h>
58 1.21.6.2 nathanw #include <machine/eeprom.h>
59 1.21.6.2 nathanw
60 1.21.6.2 nathanw #ifndef EEPROM_SIZE
61 1.21.6.2 nathanw #define EEPROM_SIZE 0x800
62 1.21.6.2 nathanw #endif
63 1.21.6.2 nathanw
64 1.21.6.2 nathanw struct eeprom *eeprom_copy; /* soft copy. */
65 1.21.6.2 nathanw
66 1.21.6.2 nathanw static int ee_update(int off, int cnt);
67 1.21.6.2 nathanw
68 1.21.6.2 nathanw static char *eeprom_va; /* mapping to actual device */
69 1.21.6.2 nathanw static int ee_size; /* size of usable part. */
70 1.21.6.2 nathanw
71 1.21.6.2 nathanw static int ee_busy, ee_want; /* serialization */
72 1.21.6.2 nathanw
73 1.21.6.2 nathanw static int eeprom_match __P((struct device *, struct cfdata *, void *));
74 1.21.6.2 nathanw static void eeprom_attach __P((struct device *, struct device *, void *));
75 1.21.6.2 nathanw
76 1.21.6.2 nathanw CFATTACH_DECL(eeprom, sizeof(struct device),
77 1.21.6.2 nathanw eeprom_match, eeprom_attach, NULL, NULL);
78 1.21.6.2 nathanw
79 1.21.6.2 nathanw static int
80 1.21.6.2 nathanw eeprom_match(parent, cf, args)
81 1.21.6.2 nathanw struct device *parent;
82 1.21.6.2 nathanw struct cfdata *cf;
83 1.21.6.2 nathanw void *args;
84 1.21.6.2 nathanw {
85 1.21.6.2 nathanw struct confargs *ca = args;
86 1.21.6.2 nathanw
87 1.21.6.2 nathanw /* This driver only supports one instance. */
88 1.21.6.2 nathanw if (eeprom_va != NULL)
89 1.21.6.2 nathanw return (0);
90 1.21.6.2 nathanw
91 1.21.6.2 nathanw if (bus_peek(ca->ca_bustype, ca->ca_paddr, 1) == -1)
92 1.21.6.2 nathanw return (0);
93 1.21.6.2 nathanw
94 1.21.6.2 nathanw return (1);
95 1.21.6.2 nathanw }
96 1.21.6.2 nathanw
97 1.21.6.2 nathanw static void
98 1.21.6.2 nathanw eeprom_attach(parent, self, args)
99 1.21.6.2 nathanw struct device *parent;
100 1.21.6.2 nathanw struct device *self;
101 1.21.6.2 nathanw void *args;
102 1.21.6.2 nathanw {
103 1.21.6.2 nathanw struct confargs *ca = args;
104 1.21.6.2 nathanw char *src, *dst, *lim;
105 1.21.6.2 nathanw
106 1.21.6.2 nathanw printf("\n");
107 1.21.6.2 nathanw #ifdef DIAGNOSTIC
108 1.21.6.2 nathanw if (sizeof(struct eeprom) != EEPROM_SIZE)
109 1.21.6.2 nathanw panic("eeprom struct wrong");
110 1.21.6.2 nathanw #endif
111 1.21.6.2 nathanw
112 1.21.6.2 nathanw ee_size = EEPROM_SIZE;
113 1.21.6.2 nathanw eeprom_va = bus_mapin(ca->ca_bustype, ca->ca_paddr, ee_size);
114 1.21.6.2 nathanw if (!eeprom_va)
115 1.21.6.2 nathanw panic("eeprom_attach");
116 1.21.6.2 nathanw
117 1.21.6.2 nathanw /* Keep a "soft" copy of the EEPROM to make access simpler. */
118 1.21.6.2 nathanw eeprom_copy = malloc(ee_size, M_DEVBUF, M_NOWAIT);
119 1.21.6.2 nathanw if (eeprom_copy == 0)
120 1.21.6.2 nathanw panic("eeprom_attach: malloc eeprom_copy");
121 1.21.6.2 nathanw
122 1.21.6.2 nathanw /*
123 1.21.6.2 nathanw * On the 3/80, do not touch the last 40 bytes!
124 1.21.6.2 nathanw * Writes there are ignored, reads show zero.
125 1.21.6.2 nathanw * Reduce ee_size and clear the last part of the
126 1.21.6.2 nathanw * soft copy. Note: ee_update obeys ee_size.
127 1.21.6.2 nathanw */
128 1.21.6.2 nathanw if (cpu_machine_id == SUN3X_MACH_80)
129 1.21.6.2 nathanw ee_size -= 40;
130 1.21.6.2 nathanw
131 1.21.6.2 nathanw /* Do only byte access in the EEPROM. */
132 1.21.6.2 nathanw src = eeprom_va;
133 1.21.6.2 nathanw dst = (char*) eeprom_copy;
134 1.21.6.2 nathanw lim = dst + ee_size;
135 1.21.6.2 nathanw
136 1.21.6.2 nathanw do *dst++ = *src++;
137 1.21.6.2 nathanw while (dst < lim);
138 1.21.6.2 nathanw
139 1.21.6.2 nathanw if (ee_size < EEPROM_SIZE) {
140 1.21.6.2 nathanw /* Clear out the last part. */
141 1.21.6.2 nathanw memset(dst, 0, (EEPROM_SIZE - ee_size));
142 1.21.6.2 nathanw }
143 1.21.6.2 nathanw }
144 1.21.6.2 nathanw
145 1.21.6.2 nathanw
146 1.21.6.2 nathanw /* Take the lock. */
147 1.21.6.2 nathanw static int
148 1.21.6.2 nathanw ee_take __P((void))
149 1.21.6.2 nathanw {
150 1.21.6.2 nathanw int error = 0;
151 1.21.6.2 nathanw while (ee_busy) {
152 1.21.6.2 nathanw ee_want = 1;
153 1.21.6.2 nathanw error = tsleep(&ee_busy, PZERO | PCATCH, "eeprom", 0);
154 1.21.6.2 nathanw ee_want = 0;
155 1.21.6.2 nathanw if (error) /* interrupted */
156 1.21.6.2 nathanw return error;
157 1.21.6.2 nathanw }
158 1.21.6.2 nathanw ee_busy = 1;
159 1.21.6.2 nathanw return error;
160 1.21.6.2 nathanw }
161 1.21.6.2 nathanw
162 1.21.6.2 nathanw /* Give the lock. */
163 1.21.6.2 nathanw static void
164 1.21.6.2 nathanw ee_give __P((void))
165 1.21.6.2 nathanw {
166 1.21.6.2 nathanw ee_busy = 0;
167 1.21.6.2 nathanw if (ee_want) {
168 1.21.6.2 nathanw ee_want = 0;
169 1.21.6.2 nathanw wakeup(&ee_busy);
170 1.21.6.2 nathanw }
171 1.21.6.2 nathanw }
172 1.21.6.2 nathanw
173 1.21.6.2 nathanw /*
174 1.21.6.2 nathanw * This is called by mem.c to handle /dev/eeprom
175 1.21.6.2 nathanw */
176 1.21.6.2 nathanw int
177 1.21.6.2 nathanw eeprom_uio(struct uio *uio)
178 1.21.6.2 nathanw {
179 1.21.6.2 nathanw int cnt, error;
180 1.21.6.2 nathanw int off; /* NOT off_t */
181 1.21.6.2 nathanw caddr_t va;
182 1.21.6.2 nathanw
183 1.21.6.2 nathanw if (eeprom_copy == NULL)
184 1.21.6.2 nathanw return (ENXIO);
185 1.21.6.2 nathanw
186 1.21.6.2 nathanw off = uio->uio_offset;
187 1.21.6.2 nathanw if ((off < 0) || (off > EEPROM_SIZE))
188 1.21.6.2 nathanw return (EFAULT);
189 1.21.6.2 nathanw
190 1.21.6.2 nathanw cnt = min(uio->uio_resid, (EEPROM_SIZE - off));
191 1.21.6.2 nathanw if (cnt == 0)
192 1.21.6.2 nathanw return (0); /* EOF */
193 1.21.6.2 nathanw
194 1.21.6.2 nathanw va = ((char*)eeprom_copy) + off;
195 1.21.6.2 nathanw error = uiomove(va, (int)cnt, uio);
196 1.21.6.2 nathanw
197 1.21.6.2 nathanw /* If we wrote the rambuf, update the H/W. */
198 1.21.6.2 nathanw if (!error && (uio->uio_rw != UIO_READ)) {
199 1.21.6.2 nathanw error = ee_take();
200 1.21.6.2 nathanw if (!error)
201 1.21.6.2 nathanw error = ee_update(off, cnt);
202 1.21.6.2 nathanw ee_give();
203 1.21.6.2 nathanw }
204 1.21.6.2 nathanw
205 1.21.6.2 nathanw return (error);
206 1.21.6.2 nathanw }
207 1.21.6.2 nathanw
208 1.21.6.2 nathanw /*
209 1.21.6.2 nathanw * Update the EEPROM from the soft copy.
210 1.21.6.2 nathanw * Other than the attach function, this is
211 1.21.6.2 nathanw * the ONLY place we touch the EEPROM H/W.
212 1.21.6.2 nathanw */
213 1.21.6.2 nathanw static int
214 1.21.6.2 nathanw ee_update(int off, int cnt)
215 1.21.6.2 nathanw {
216 1.21.6.2 nathanw volatile char *ep;
217 1.21.6.2 nathanw char *bp;
218 1.21.6.2 nathanw int errcnt;
219 1.21.6.2 nathanw
220 1.21.6.2 nathanw if (eeprom_va == NULL)
221 1.21.6.2 nathanw return (ENXIO);
222 1.21.6.2 nathanw
223 1.21.6.2 nathanw /*
224 1.21.6.2 nathanw * This check is NOT redundant with the one in
225 1.21.6.2 nathanw * eeprom_uio above if we are on a 3/80 where
226 1.21.6.2 nathanw * ee_size < EEPROM_SIZE
227 1.21.6.2 nathanw */
228 1.21.6.2 nathanw if (cnt > (ee_size - off))
229 1.21.6.2 nathanw cnt = (ee_size - off);
230 1.21.6.2 nathanw
231 1.21.6.2 nathanw bp = ((char*)eeprom_copy) + off;
232 1.21.6.2 nathanw ep = eeprom_va + off;
233 1.21.6.2 nathanw errcnt = 0;
234 1.21.6.2 nathanw
235 1.21.6.2 nathanw while (cnt > 0) {
236 1.21.6.2 nathanw /*
237 1.21.6.2 nathanw * DO NOT WRITE IT UNLESS WE HAVE TO because the
238 1.21.6.2 nathanw * EEPROM has a limited number of write cycles.
239 1.21.6.2 nathanw * After some number of writes it just fails!
240 1.21.6.2 nathanw */
241 1.21.6.2 nathanw if (*ep != *bp) {
242 1.21.6.2 nathanw *ep = *bp;
243 1.21.6.2 nathanw /*
244 1.21.6.2 nathanw * We have written the EEPROM, so now we must
245 1.21.6.2 nathanw * sleep for at least 10 milliseconds while
246 1.21.6.2 nathanw * holding the lock to prevent all access to
247 1.21.6.2 nathanw * the EEPROM while it recovers.
248 1.21.6.2 nathanw */
249 1.21.6.2 nathanw (void)tsleep(eeprom_va, PZERO-1, "eeprom", hz/50);
250 1.21.6.2 nathanw }
251 1.21.6.2 nathanw /* Make sure the write worked. */
252 1.21.6.2 nathanw if (*ep != *bp)
253 1.21.6.2 nathanw errcnt++;
254 1.21.6.2 nathanw ep++;
255 1.21.6.2 nathanw bp++;
256 1.21.6.2 nathanw cnt--;
257 1.21.6.2 nathanw }
258 1.21.6.2 nathanw return (errcnt ? EIO : 0);
259 1.21.6.2 nathanw }
260