1 /* $NetBSD: i28f128.c,v 1.2.2.3 2004/09/21 13:16:12 skrll Exp $ */
4 * Copyright (c) 2003 Naoto Shimazaki.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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>
39 #include "i28f128reg.h"
45 * this function is too much specific for the device.
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
[] = {
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
])
73 /* read manufacturer code and device code */
74 if (REGREAD_2(base
, 0x00) != vendor_code
[0])
76 if (REGREAD_2(base
, 0x02) != vendor_code
[1])
79 REGWRITE_2(base
, 0, 0xff);
84 block_erase(void *addr
)
88 REGWRITE_2(addr
, 0, I28F128_BLK_ERASE_1ST
);
89 REGWRITE_2(addr
, 0, I28F128_BLK_ERASE_2ND
);
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
);
104 word_program(void *addr
, u_int16_t data
)
108 REGWRITE_2(addr
, 0, I28F128_WORDBYTE_PROG
);
109 REGWRITE_2(addr
, 0, data
);
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
);
125 block_write(void *dst
, const void *src
)
130 const u_int16_t
*fence
;
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
)
138 if (memcmp(dst
, src
, I28F128_BLOCK_SIZE
) == 0)
141 if ((status
= block_erase(dst
)) != 0)
146 fence
= p
+ (I28F128_BLOCK_SIZE
>> 1);
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
);
161 REGWRITE_2(dst
, 0, I28F128_READ_STATUS
);
162 status
= REGREAD_2(dst
, 0);
163 } while (!(status
& I28F128_S_READY
));
167 REGWRITE_2(dst
, 0, I28F128_CLEAR_STATUS
);
168 REGWRITE_2(dst
, 0, I28F128_RESET
);
174 i28f128_region_write(void *dst
, const void *src
, size_t len
)
177 const u_int16_t
*p
= src
;
180 /* dst must be aligned to block boundary. */
181 if (I28F128_BLOCK_MASK
& (u_int32_t
) dst
)
184 while (len
>= I28F128_BLOCK_SIZE
) {
185 if ((status
= block_write(q
, p
)) != 0)
188 p
+= I28F128_BLOCK_SIZE
>> 1;
189 q
+= I28F128_BLOCK_SIZE
>> 1;
190 len
-= I28F128_BLOCK_SIZE
;
194 if (memcmp(p
, q
, len
) == 0)
196 if ((status
= block_erase(q
)) != 0)
198 for (; len
> 0; len
-= 2) {
200 if (((u_int32_t
) q
% 4096) == 0)
203 if ((status
= word_program(q
++, *p
++)) != 0)