xref: /netbsd-src/sys/arch/sun3/dev/eeprom.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
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