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