xref: /netbsd-src/sys/arch/sun3/dev/eeprom.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: eeprom.c,v 1.4 1994/12/12 18:59:04 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
50 
51 static int ee_update(caddr_t buf, int off, int cnt);
52 
53 static char *eeprom_va;
54 static int ee_busy, ee_want;
55 
56 int eeprom_match __P((struct device *, void *vcf, void *args));
57 void eeprom_attach __P((struct device *, struct device *, void *));
58 
59 struct cfdriver eepromcd = {
60 	NULL, "eeprom", eeprom_match, eeprom_attach,
61 	DV_DULL, sizeof(struct device), 0 };
62 
63 /* Called very earyl by internal_configure. */
64 void eeprom_init()
65 {
66 	eeprom_va = obio_find_mapping(OBIO_EEPROM, OBIO_EEPROM_SIZE);
67 }
68 
69 int eeprom_match(parent, vcf, args)
70     struct device *parent;
71     void *vcf, *args;
72 {
73     struct cfdata *cf = vcf;
74 	struct confargs *ca = args;
75 
76 	/* This driver only supports one unit. */
77 	if (cf->cf_unit != 0)
78 		return (0);
79 	if (eeprom_va == NULL)
80 		return (0);
81 	if (ca->ca_paddr == -1)
82 		ca->ca_paddr = OBIO_EEPROM;
83 	return (1);
84 }
85 
86 void eeprom_attach(parent, self, args)
87 	struct device *parent;
88 	struct device *self;
89 	void *args;
90 {
91 	struct confargs *ca = args;
92 
93 	printf("\n");
94 }
95 
96 
97 static int ee_take()	/* Take the lock. */
98 {
99 	int error = 0;
100 	while (ee_busy) {
101 		ee_want = 1;
102 		error = tsleep(&ee_busy, PZERO | PCATCH, "eeprom", 0);
103 		ee_want = 0;
104 		if (error)	/* interrupted */
105 			goto out;
106 	}
107 	ee_busy = 1;
108  out:
109 	return error;
110 }
111 
112 static void ee_give()	/* Give the lock. */
113 {
114 	ee_busy = 0;
115 	if (ee_want) {
116 		ee_want = 0;
117 		wakeup(&ee_busy);
118 	}
119 }
120 
121 int eeprom_uio(struct uio *uio)
122 {
123 	int error;
124 	int off;	/* NOT off_t */
125 	u_int cnt;
126 	caddr_t va;
127 	caddr_t buf = (caddr_t)0;
128 
129 	off = uio->uio_offset;
130 	if (off >= OBIO_EEPROM_SIZE)
131 		return (EFAULT);
132 
133 	cnt = uio->uio_resid;
134 	if (cnt > (OBIO_EEPROM_SIZE - off))
135 		cnt = (OBIO_EEPROM_SIZE - off);
136 
137 	if ((error = ee_take()) != 0)
138 		return (error);
139 
140 	if (eeprom_va == NULL) {
141 		error = ENXIO;
142 		goto out;
143 	}
144 
145 	va = eeprom_va;
146 	if (uio->uio_rw != UIO_READ) {
147 		/* Write requires a temporary buffer. */
148 		buf = malloc(OBIO_EEPROM_SIZE, M_DEVBUF, M_WAITOK);
149 		if (!buf) {
150 			error = EAGAIN;
151 			goto out;
152 		}
153 		va = buf;
154 	}
155 
156 	if ((error = uiomove(va + off, (int)cnt, uio)) != 0)
157 		goto out;
158 
159 	if (uio->uio_rw != UIO_READ)
160 		error = ee_update(buf, off, cnt);
161 
162  out:
163 	if (buf)
164 		free(buf, M_DEVBUF);
165 	ee_give();
166 	return (error);
167 }
168 
169 /*
170  * Update the EEPROM from the passed buf.
171  */
172 static int ee_update(char *buf, int off, int cnt)
173 {
174 	volatile char *ep;
175 	char *bp;
176 
177 	if (eeprom_va == NULL)
178 		return (ENXIO);
179 
180 	ep = eeprom_va + off;
181 	bp = buf + off;
182 
183 	while (cnt > 0) {
184 		/*
185 		 * DO NOT WRITE IT UNLESS WE HAVE TO because the
186 		 * EEPROM has a limited number of write cycles.
187 		 * After some number of writes it just fails!
188 		 */
189 		if (*ep != *bp) {
190 			*ep  = *bp;
191 			/*
192 			 * We have written the EEPROM, so now we must
193 			 * sleep for at least 10 milliseconds while
194 			 * holding the lock to prevent all access to
195 			 * the EEPROM while it recovers.
196 			 */
197 			(void)tsleep(eeprom_va, PZERO-1, "eeprom", HZ/50);
198 		}
199 		/* Make sure the write worked. */
200 		if (*ep != *bp)
201 			return (EIO);
202 		ep++;
203 		bp++;
204 		cnt--;
205 	}
206 }
207 
208 /*
209  * Read a byte out of the EEPROM.  This is called from
210  * things like the zs driver very early to find out
211  * which device should be used as the console.
212  */
213 int ee_get_byte(int off, int canwait)
214 {
215 	int c = -1;
216 	if ((off < 0) || (off >= OBIO_EEPROM_SIZE))
217 		goto out;
218 	if (eeprom_va == NULL)
219 		goto out;
220 
221 	if (canwait) {
222 		if (ee_take())
223 			goto out;
224 	} else {
225 		if (ee_busy)
226 			goto out;
227 	}
228 
229 	c = eeprom_va[off] & 0xFF;
230 
231 	if (canwait)
232 		ee_give();
233  out:
234 	return c;
235 }
236