i28f128.c revision 1.2.2.2 1 1.2.2.1 skrll /* $NetBSD: i28f128.c,v 1.2.2.2 2004/09/18 14:34:58 skrll Exp $ */
2 1.1 igy
3 1.1 igy /*
4 1.2.2.1 skrll * Copyright (c) 2003 Naoto Shimazaki.
5 1.1 igy * All rights reserved.
6 1.1 igy *
7 1.1 igy * Redistribution and use in source and binary forms, with or without
8 1.1 igy * modification, are permitted provided that the following conditions
9 1.1 igy * are met:
10 1.1 igy * 1. Redistributions of source code must retain the above copyright
11 1.1 igy * notice, this list of conditions and the following disclaimer.
12 1.1 igy * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 igy * notice, this list of conditions and the following disclaimer in the
14 1.1 igy * documentation and/or other materials provided with the distribution.
15 1.1 igy *
16 1.2.2.1 skrll * THIS SOFTWARE IS PROVIDED BY NAOTO SHIMAZAKI AND CONTRIBUTORS ``AS IS''
17 1.2.2.1 skrll * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 1.2.2.1 skrll * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.2.2.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE NAOTO OR CONTRIBUTORS BE
20 1.2.2.1 skrll * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 igy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 igy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 igy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 igy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.2.2.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 1.2.2.1 skrll * THE POSSIBILITY OF SUCH DAMAGE.
27 1.1 igy */
28 1.1 igy
29 1.1 igy /*
30 1.1 igy * Flash Memory Writer
31 1.1 igy */
32 1.2.2.1 skrll #include <sys/cdefs.h>
33 1.2.2.1 skrll __KERNEL_RCSID(0, "$NetBSD: i28f128.c,v 1.2.2.2 2004/09/18 14:34:58 skrll Exp $");
34 1.1 igy
35 1.1 igy #include <lib/libsa/stand.h>
36 1.1 igy
37 1.1 igy #include "extern.h"
38 1.1 igy
39 1.1 igy #include "i28f128reg.h"
40 1.1 igy
41 1.1 igy #define USE_TWIDDLE
42 1.1 igy
43 1.1 igy /*
44 1.1 igy * XXX
45 1.1 igy * this function is too much specific for the device.
46 1.1 igy */
47 1.1 igy int
48 1.1 igy i28f128_probe(void *base)
49 1.1 igy {
50 1.1 igy static const u_int8_t vendor_code[] = {
51 1.1 igy 0x89, /* manufacturer code: intel */
52 1.1 igy 0x18, /* device code: 28F128 */
53 1.1 igy };
54 1.1 igy
55 1.1 igy static const u_int8_t idstr[] = {
56 1.1 igy 'Q', 'R', 'Y',
57 1.1 igy 0x01, 0x00,
58 1.1 igy 0x31, 0x00,
59 1.1 igy 0xff
60 1.1 igy };
61 1.1 igy
62 1.1 igy int i;
63 1.1 igy
64 1.1 igy /* start Common Flash Interface Query */
65 1.1 igy REGWRITE_2(base, 0, 0x98);
66 1.1 igy
67 1.1 igy /* read CFI Query ID string */
68 1.1 igy for (i = 0; idstr[i] != 0xff; i++) {
69 1.1 igy if (REGREAD_2(base, (0x10 + i) << 1) != idstr[i])
70 1.1 igy return 1;
71 1.1 igy }
72 1.1 igy
73 1.1 igy /* read manufacturer code and device code */
74 1.1 igy if (REGREAD_2(base, 0x00) != vendor_code[0])
75 1.1 igy return 1;
76 1.1 igy if (REGREAD_2(base, 0x02) != vendor_code[1])
77 1.1 igy return 1;
78 1.1 igy
79 1.1 igy REGWRITE_2(base, 0, 0xff);
80 1.1 igy return 0;
81 1.1 igy }
82 1.1 igy
83 1.1 igy static int
84 1.1 igy block_erase(void *addr)
85 1.1 igy {
86 1.1 igy int status;
87 1.1 igy
88 1.1 igy REGWRITE_2(addr, 0, I28F128_BLK_ERASE_1ST);
89 1.1 igy REGWRITE_2(addr, 0, I28F128_BLK_ERASE_2ND);
90 1.1 igy
91 1.1 igy do {
92 1.1 igy status = REGREAD_2(addr, 0);
93 1.1 igy } while (!ISSET(status, I28F128_S_READY));
94 1.1 igy
95 1.1 igy REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
96 1.1 igy REGWRITE_2(addr, 0, I28F128_RESET);
97 1.1 igy
98 1.1 igy return status & (I28F128_S_ERASE_SUSPEND
99 1.1 igy | I28F128_S_ERASE_ERROR
100 1.1 igy | I28F128_S_BLOCK_LOCKED);
101 1.1 igy }
102 1.1 igy
103 1.1 igy static int
104 1.1 igy word_program(void *addr, u_int16_t data)
105 1.1 igy {
106 1.1 igy int status;
107 1.1 igy
108 1.1 igy REGWRITE_2(addr, 0, I28F128_WORDBYTE_PROG);
109 1.1 igy REGWRITE_2(addr, 0, data);
110 1.1 igy
111 1.1 igy do {
112 1.1 igy status = REGREAD_2(addr, 0);
113 1.1 igy } while (!ISSET(status, I28F128_S_READY));
114 1.1 igy
115 1.1 igy REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
116 1.1 igy REGWRITE_2(addr, 0, I28F128_RESET);
117 1.1 igy
118 1.1 igy return status & (I28F128_S_PROG_ERROR
119 1.1 igy | I28F128_S_LOW_VOLTAGE
120 1.1 igy | I28F128_S_PROG_SUSPEND
121 1.1 igy | I28F128_S_BLOCK_LOCKED);
122 1.1 igy }
123 1.1 igy
124 1.1 igy static int
125 1.1 igy block_write(void *dst, const void *src)
126 1.1 igy {
127 1.1 igy int status;
128 1.1 igy const u_int16_t *p;
129 1.1 igy u_int16_t *q;
130 1.1 igy const u_int16_t *fence;
131 1.2 igy int i;
132 1.2 igy const int wbuf_count = I28F128_WBUF_SIZE >> 1;
133 1.1 igy
134 1.1 igy /* dst must be aligned to block boundary. */
135 1.1 igy if (I28F128_BLOCK_MASK & (u_int32_t) dst)
136 1.1 igy return -1;
137 1.1 igy
138 1.1 igy if (memcmp(dst, src, I28F128_BLOCK_SIZE) == 0)
139 1.1 igy return 0;
140 1.1 igy
141 1.1 igy if ((status = block_erase(dst)) != 0)
142 1.1 igy return status;
143 1.1 igy
144 1.1 igy p = src;
145 1.1 igy q = dst;
146 1.1 igy fence = p + (I28F128_BLOCK_SIZE >> 1);
147 1.1 igy do {
148 1.2 igy do {
149 1.2 igy REGWRITE_2(dst, 0, I28F128_WRITE_BUFFER);
150 1.2 igy status = REGREAD_2(dst, 0);
151 1.2 igy } while (!ISSET(status, I28F128_XS_BUF_AVAIL));
152 1.2 igy
153 1.2 igy REGWRITE_2(dst, 0, wbuf_count - 1);
154 1.2 igy
155 1.2 igy for (i = wbuf_count; i > 0; i--, p++, q++)
156 1.2 igy REGWRITE_2(q, 0, *p);
157 1.2 igy
158 1.2 igy REGWRITE_2(dst, 0, I28F128_WBUF_CONFIRM);
159 1.2 igy
160 1.2 igy do {
161 1.2 igy REGWRITE_2(dst, 0, I28F128_READ_STATUS);
162 1.2 igy status = REGREAD_2(dst, 0);
163 1.2 igy } while (!(status & I28F128_S_READY));
164 1.2 igy
165 1.1 igy } while (p < fence);
166 1.2 igy
167 1.2 igy REGWRITE_2(dst, 0, I28F128_CLEAR_STATUS);
168 1.2 igy REGWRITE_2(dst, 0, I28F128_RESET);
169 1.1 igy
170 1.1 igy return 0;
171 1.1 igy }
172 1.1 igy
173 1.1 igy int
174 1.1 igy i28f128_region_write(void *dst, const void *src, size_t len)
175 1.1 igy {
176 1.1 igy int status;
177 1.1 igy const u_int16_t *p = src;
178 1.1 igy u_int16_t *q = dst;
179 1.1 igy
180 1.1 igy /* dst must be aligned to block boundary. */
181 1.1 igy if (I28F128_BLOCK_MASK & (u_int32_t) dst)
182 1.1 igy return -1;
183 1.1 igy
184 1.1 igy while (len >= I28F128_BLOCK_SIZE) {
185 1.1 igy if ((status = block_write(q, p)) != 0)
186 1.1 igy return status;
187 1.1 igy putchar('b');
188 1.1 igy p += I28F128_BLOCK_SIZE >> 1;
189 1.1 igy q += I28F128_BLOCK_SIZE >> 1;
190 1.1 igy len -= I28F128_BLOCK_SIZE;
191 1.1 igy }
192 1.1 igy
193 1.1 igy if (len > 0) {
194 1.1 igy if (memcmp(p, q, len) == 0)
195 1.1 igy return 0;
196 1.1 igy if ((status = block_erase(q)) != 0)
197 1.1 igy return status;
198 1.1 igy for (; len > 0; len -= 2) {
199 1.1 igy #ifdef USE_TWIDDLE
200 1.1 igy if (((u_int32_t) q % 4096) == 0)
201 1.1 igy twiddle();
202 1.1 igy #endif
203 1.1 igy if ((status = word_program(q++, *p++)) != 0)
204 1.1 igy return status;
205 1.1 igy }
206 1.1 igy printf("w");
207 1.1 igy }
208 1.1 igy
209 1.1 igy putchar('\n');
210 1.1 igy return 0;
211 1.1 igy }
212