1 /* $NetBSD: athflash.c,v 1.2 2008/04/28 20:23:28 martin Exp $ */
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgements:
22 * This product includes software developed by the Urbana-Champaign
23 * Independent Media Center.
24 * This product includes software developed by Garrett D'Amore.
25 * 4. Urbana-Champaign Independent Media Center's name and Garrett
26 * D'Amore's name may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 * Copyright (c) 2002 The NetBSD Foundation, Inc.
45 * All rights reserved.
47 * This code is derived from software contributed to The NetBSD Foundation
48 * by Naoto Shimazaki of YOKOGAWA Electric Corporation.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 * notice, this list of conditions and the following disclaimer in the
57 * documentation and/or other materials provided with the distribution.
59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
75 * XXX This primitive flash driver does *not* support boot sectored devices,
76 * XXX and only supports a fairly limited set of devices, that we are likely to
77 * XXX to find in an AP30.
79 * XXX We also are only supporting flash widths of 16 _for the moment_, and
80 * XXX we are only supporting flash devices that use the AMD command sets.
81 * XXX All this should be reviewed and improved to be much more generic.
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: athflash.c,v 1.2 2008/04/28 20:23:28 martin Exp $");
87 #include <sys/param.h>
89 #include <sys/device.h>
90 #include <sys/kernel.h>
91 #include <sys/malloc.h>
93 #include <sys/systm.h>
95 #include <machine/bus.h>
97 #include <mips/atheros/include/arbusvar.h>
101 #define DPRINTF(x) if (flash_debug) printf x
107 struct device sc_dev
;
108 bus_space_tag_t sc_iot
;
109 bus_space_handle_t sc_ioh
;
111 size_t sc_sector_size
;
116 #define FLASH_ST_BUSY 0x1
118 static int flash_probe(struct device
*, struct cfdata
*, void *);
119 static void flash_attach(struct device
*, struct device
*, void *);
121 static int is_block_same(struct flash_softc
*, bus_size_t
, const void *);
122 static int toggle_bit_wait(struct flash_softc
*, bus_size_t
, int, int, int);
124 static int flash_sector_erase(struct flash_softc
*, bus_size_t
);
125 static int flash_sector_write(struct flash_softc
*, bus_size_t
);
127 extern struct cfdriver athflash_cd
;
129 CFATTACH_DECL(athflash
, sizeof(struct flash_softc
),
130 flash_probe
, flash_attach
, NULL
, NULL
);
132 dev_type_open(flashopen
);
133 dev_type_close(flashclose
);
134 dev_type_read(flashread
);
135 dev_type_write(flashwrite
);
137 const struct cdevsw athflash_cdevsw
= {
138 flashopen
, flashclose
, flashread
, flashwrite
, noioctl
,
139 nostop
, notty
, nopoll
, nommap
, nokqfilter
,
149 { 0x00bf, 0x2780, "SST 39VF400", 0x01000, 0x080000 }, /* 512KB */
150 { 0x00bf, 0x2782, "SST 39VF160", 0x01000, 0x200000 }, /* 2MB */
151 { 0xffff, 0xffff, NULL
, 0, 0 } /* end list */
155 flash_probe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
157 struct arbus_attach_args
*aa
= aux
;
158 bus_space_handle_t ioh
;
160 uint16_t venid
, devid
;
162 if (strcmp(aa
->aa_name
, cf
->cf_name
) != 0)
165 DPRINTF(("trying to map address %x\n", (unsigned)aa
->aa_addr
));
166 if (bus_space_map(aa
->aa_bst
, aa
->aa_addr
, aa
->aa_size
, 0, &ioh
))
169 /* issue JEDEC query */
170 DPRINTF(("issuing JEDEC query\n"));
171 bus_space_write_2(aa
->aa_bst
, ioh
, (0x5555 << 1), 0xAAAA);
172 bus_space_write_2(aa
->aa_bst
, ioh
, (0x2AAA << 1), 0x5555);
173 bus_space_write_2(aa
->aa_bst
, ioh
, (0x5555 << 1), 0x9090);
176 venid
= bus_space_read_2(aa
->aa_bst
, ioh
, 0);
177 devid
= bus_space_read_2(aa
->aa_bst
, ioh
, 2);
179 /* issue software exit */
180 bus_space_write_2(aa
->aa_bst
, ioh
, 0x0, 0xF0F0);
182 for (i
= 0; flash_ids
[i
].name
!= NULL
; i
++) {
183 if ((venid
== flash_ids
[i
].vendor_id
) &&
184 (devid
== flash_ids
[i
].device_id
)) {
190 bus_space_unmap(aa
->aa_bst
, ioh
, aa
->aa_size
);
195 flash_attach(struct device
*parent
, struct device
*self
, void *aux
)
197 struct flash_softc
*sc
= (void *) self
;
198 struct arbus_attach_args
*aa
= aux
;
200 bus_space_tag_t iot
= aa
->aa_bst
;
201 bus_space_handle_t ioh
;
202 uint16_t venid
, devid
;
204 if (bus_space_map(iot
, aa
->aa_addr
, aa
->aa_size
, 0, &ioh
)) {
205 printf(": can't map i/o space\n");
213 /* issue JEDEC query */
214 bus_space_write_2(aa
->aa_bst
, ioh
, (0x5555 << 1), 0xAAAA);
215 bus_space_write_2(aa
->aa_bst
, ioh
, (0x2AAA << 1), 0x5555);
216 bus_space_write_2(aa
->aa_bst
, ioh
, (0x5555 << 1), 0x9090);
219 venid
= bus_space_read_2(aa
->aa_bst
, ioh
, 0);
220 devid
= bus_space_read_2(aa
->aa_bst
, ioh
, 2);
222 /* issue software exit */
223 bus_space_write_2(aa
->aa_bst
, ioh
, 0x0, 0xF0F0);
225 for (i
= 0; flash_ids
[i
].name
!= NULL
; i
++) {
226 if ((venid
== flash_ids
[i
].vendor_id
) &&
227 (devid
== flash_ids
[i
].device_id
)) {
232 KASSERT(flash_ids
[i
].name
!= NULL
);
233 printf(": %s ", flash_ids
[i
].name
);
235 printf("(%d MB)", flash_ids
[i
].flash_size
>> 20);
237 printf("(%d KB)", flash_ids
[i
].flash_size
>> 10);
240 * determine size of the largest block
242 sc
->sc_size
= flash_ids
[i
].flash_size
;
243 sc
->sc_sector_size
= flash_ids
[i
].sector_size
;
245 if ((sc
->sc_buf
= malloc(sc
->sc_sector_size
, M_DEVBUF
, M_NOWAIT
))
247 printf(": can't alloc buffer space\n");
255 flashopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
257 struct flash_softc
*sc
;
259 sc
= device_lookup_private(&athflash_cd
, minor(dev
));
262 if (sc
->sc_status
& FLASH_ST_BUSY
)
264 sc
->sc_status
|= FLASH_ST_BUSY
;
269 flashclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
271 struct flash_softc
*sc
;
273 sc
= device_lookup_private(&athflash_cd
, minor(dev
));
274 sc
->sc_status
&= ~FLASH_ST_BUSY
;
279 flashread(dev_t dev
, struct uio
*uio
, int flag
)
281 struct flash_softc
*sc
;
283 bus_space_handle_t ioh
;
289 sc
= device_lookup_private(&athflash_cd
, minor(dev
));
293 off
= uio
->uio_offset
;
294 total
= min(sc
->sc_size
- off
, uio
->uio_resid
);
297 count
= min(sc
->sc_sector_size
, uio
->uio_resid
);
298 bus_space_read_region_1(iot
, ioh
, off
, sc
->sc_buf
, count
);
299 if ((error
= uiomove(sc
->sc_buf
, count
, uio
)) != 0)
309 flashwrite(dev_t dev
, struct uio
*uio
, int flag
)
311 struct flash_softc
*sc
;
313 bus_space_handle_t ioh
;
318 sc
= device_lookup_private(&athflash_cd
, minor(dev
));
320 if (sc
->sc_size
< uio
->uio_offset
+ uio
->uio_resid
)
322 if (uio
->uio_offset
% sc
->sc_sector_size
)
324 if (uio
->uio_resid
% sc
->sc_sector_size
)
330 for (off
= uio
->uio_offset
;
332 off
+= sc
->sc_sector_size
) {
333 error
= uiomove(sc
->sc_buf
, sc
->sc_sector_size
, uio
);
336 if (is_block_same(sc
, off
, sc
->sc_buf
))
338 if ((stat
= flash_sector_erase(sc
, off
)) != 0) {
339 printf("sector erase failed status = 0x%x\n", stat
);
342 if ((stat
= flash_sector_write(sc
, off
)) != 0) {
343 printf("sector write failed status = 0x%x\n", stat
);
351 is_block_same(struct flash_softc
*sc
, bus_size_t offset
, const void *bufp
)
353 bus_space_tag_t iot
= sc
->sc_iot
;
354 bus_space_handle_t ioh
= sc
->sc_ioh
;
355 const u_int8_t
*p
= bufp
;
356 int count
= sc
->sc_sector_size
;
358 while (count
-- > 0) {
359 if (bus_space_read_1(iot
, ioh
, offset
++) != *p
++)
366 toggle_bit_wait(struct flash_softc
*sc
, bus_size_t offset
,
367 int typtmo
, int maxtmo
, int spin
)
369 bus_space_tag_t iot
= sc
->sc_iot
;
370 bus_space_handle_t ioh
= sc
->sc_ioh
;
378 tsleep(sc
, PRIBIO
, "blockerase",
382 d1
= bus_space_read_1(iot
, ioh
, offset
);
383 d2
= bus_space_read_2(iot
, ioh
, offset
);
385 /* watch for the toggle bit to stop toggling */
386 if ((d1
& 0x40) == (d2
& 0x40)) {
396 flash_sector_erase(struct flash_softc
*sc
, bus_size_t offset
)
398 bus_space_tag_t iot
= sc
->sc_iot
;
399 bus_space_handle_t ioh
= sc
->sc_ioh
;
401 DPRINTF(("flash_sector_erase offset = %08lx\n", offset
));
403 bus_space_write_2(iot
, ioh
, (0x5555 << 1), 0xAAAA);
404 bus_space_write_2(iot
, ioh
, (0x2AAA << 1), 0x5555);
405 bus_space_write_2(iot
, ioh
, (0x5555 << 1), 0x8080);
406 bus_space_write_2(iot
, ioh
, (0x5555 << 1), 0xAAAA);
407 bus_space_write_2(iot
, ioh
, (0x2AAA << 1), 0x5555);
409 bus_space_write_2(iot
, ioh
, offset
, 0x3030);
412 * NB: with CFI, we could get more meaningful timeout data for
413 * now we just assign reasonable values - 10 msec typical, and
414 * up to 60 secs to erase the whole sector.
417 return toggle_bit_wait(sc
, offset
, 10000, 60000000, 0);
421 flash_sector_write(struct flash_softc
*sc
, bus_size_t offset
)
423 bus_space_tag_t iot
= sc
->sc_iot
;
424 bus_space_handle_t ioh
= sc
->sc_ioh
;
428 p
= (u_int16_t
*) sc
->sc_buf
;
429 fence
= offset
+ sc
->sc_sector_size
;
431 bus_space_write_2(iot
, ioh
, (0x5555 << 1), 0xAAAA);
432 bus_space_write_2(iot
, ioh
, (0x2AAA << 1), 0x5555);
433 bus_space_write_2(iot
, ioh
, (0xAAAA << 1), 0xA0A0);
435 bus_space_write_2(iot
, ioh
, offset
, *p
);
437 /* wait up to 1 msec, in 10 usec increments, no sleeping */
438 if (toggle_bit_wait(sc
, offset
, 10, 1000, 1) != 0)
442 } while (offset
< fence
);