Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / hpcmips / stand / lcboot / i28f128.c
blob50d63119d88ec07a4e7426039a4f604b4710faca
1 /* $NetBSD: i28f128.c,v 1.2.2.3 2004/09/21 13:16:12 skrll Exp $ */
3 /*
4 * Copyright (c) 2003 Naoto Shimazaki.
5 * All rights reserved.
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.
16 * THIS SOFTWARE IS PROVIDED BY NAOTO SHIMAZAKI AND CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE NAOTO OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
30 * Flash Memory Writer
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: i28f128.c,v 1.2.2.3 2004/09/21 13:16:12 skrll Exp $");
35 #include <lib/libsa/stand.h>
37 #include "extern.h"
39 #include "i28f128reg.h"
41 #define USE_TWIDDLE
44 * XXX
45 * this function is too much specific for the device.
47 int
48 i28f128_probe(void *base)
50 static const u_int8_t vendor_code[] = {
51 0x89, /* manufacturer code: intel */
52 0x18, /* device code: 28F128 */
55 static const u_int8_t idstr[] = {
56 'Q', 'R', 'Y',
57 0x01, 0x00,
58 0x31, 0x00,
59 0xff
62 int i;
64 /* start Common Flash Interface Query */
65 REGWRITE_2(base, 0, 0x98);
67 /* read CFI Query ID string */
68 for (i = 0; idstr[i] != 0xff; i++) {
69 if (REGREAD_2(base, (0x10 + i) << 1) != idstr[i])
70 return 1;
73 /* read manufacturer code and device code */
74 if (REGREAD_2(base, 0x00) != vendor_code[0])
75 return 1;
76 if (REGREAD_2(base, 0x02) != vendor_code[1])
77 return 1;
79 REGWRITE_2(base, 0, 0xff);
80 return 0;
83 static int
84 block_erase(void *addr)
86 int status;
88 REGWRITE_2(addr, 0, I28F128_BLK_ERASE_1ST);
89 REGWRITE_2(addr, 0, I28F128_BLK_ERASE_2ND);
91 do {
92 status = REGREAD_2(addr, 0);
93 } while (!ISSET(status, I28F128_S_READY));
95 REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
96 REGWRITE_2(addr, 0, I28F128_RESET);
98 return status & (I28F128_S_ERASE_SUSPEND
99 | I28F128_S_ERASE_ERROR
100 | I28F128_S_BLOCK_LOCKED);
103 static int
104 word_program(void *addr, u_int16_t data)
106 int status;
108 REGWRITE_2(addr, 0, I28F128_WORDBYTE_PROG);
109 REGWRITE_2(addr, 0, data);
111 do {
112 status = REGREAD_2(addr, 0);
113 } while (!ISSET(status, I28F128_S_READY));
115 REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
116 REGWRITE_2(addr, 0, I28F128_RESET);
118 return status & (I28F128_S_PROG_ERROR
119 | I28F128_S_LOW_VOLTAGE
120 | I28F128_S_PROG_SUSPEND
121 | I28F128_S_BLOCK_LOCKED);
124 static int
125 block_write(void *dst, const void *src)
127 int status;
128 const u_int16_t *p;
129 u_int16_t *q;
130 const u_int16_t *fence;
131 int i;
132 const int wbuf_count = I28F128_WBUF_SIZE >> 1;
134 /* dst must be aligned to block boundary. */
135 if (I28F128_BLOCK_MASK & (u_int32_t) dst)
136 return -1;
138 if (memcmp(dst, src, I28F128_BLOCK_SIZE) == 0)
139 return 0;
141 if ((status = block_erase(dst)) != 0)
142 return status;
144 p = src;
145 q = dst;
146 fence = p + (I28F128_BLOCK_SIZE >> 1);
147 do {
148 do {
149 REGWRITE_2(dst, 0, I28F128_WRITE_BUFFER);
150 status = REGREAD_2(dst, 0);
151 } while (!ISSET(status, I28F128_XS_BUF_AVAIL));
153 REGWRITE_2(dst, 0, wbuf_count - 1);
155 for (i = wbuf_count; i > 0; i--, p++, q++)
156 REGWRITE_2(q, 0, *p);
158 REGWRITE_2(dst, 0, I28F128_WBUF_CONFIRM);
160 do {
161 REGWRITE_2(dst, 0, I28F128_READ_STATUS);
162 status = REGREAD_2(dst, 0);
163 } while (!(status & I28F128_S_READY));
165 } while (p < fence);
167 REGWRITE_2(dst, 0, I28F128_CLEAR_STATUS);
168 REGWRITE_2(dst, 0, I28F128_RESET);
170 return 0;
174 i28f128_region_write(void *dst, const void *src, size_t len)
176 int status;
177 const u_int16_t *p = src;
178 u_int16_t *q = dst;
180 /* dst must be aligned to block boundary. */
181 if (I28F128_BLOCK_MASK & (u_int32_t) dst)
182 return -1;
184 while (len >= I28F128_BLOCK_SIZE) {
185 if ((status = block_write(q, p)) != 0)
186 return status;
187 putchar('b');
188 p += I28F128_BLOCK_SIZE >> 1;
189 q += I28F128_BLOCK_SIZE >> 1;
190 len -= I28F128_BLOCK_SIZE;
193 if (len > 0) {
194 if (memcmp(p, q, len) == 0)
195 return 0;
196 if ((status = block_erase(q)) != 0)
197 return status;
198 for (; len > 0; len -= 2) {
199 #ifdef USE_TWIDDLE
200 if (((u_int32_t) q % 4096) == 0)
201 twiddle();
202 #endif
203 if ((status = word_program(q++, *p++)) != 0)
204 return status;
206 printf("w");
209 putchar('\n');
210 return 0;