xref: /netbsd-src/sys/arch/hpcmips/stand/lcboot/i28f128.c (revision 95e1ffb15694e54f29f8baaa4232152b703c2a5a)
1 /* $NetBSD: i28f128.c,v 1.4 2005/12/11 12:17:34 christos Exp $ */
2 
3 /*
4  * Copyright (c) 2003 Naoto Shimazaki.
5  * All rights reserved.
6  *
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.
15  *
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.
27  */
28 
29 /*
30  * Flash Memory Writer
31  */
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: i28f128.c,v 1.4 2005/12/11 12:17:34 christos Exp $");
34 
35 #include <lib/libsa/stand.h>
36 
37 #include "extern.h"
38 
39 #include "i28f128reg.h"
40 
41 #define USE_TWIDDLE
42 
43 /*
44  * XXX
45  * this function is too much specific for the device.
46  */
47 int
i28f128_probe(void * base)48 i28f128_probe(void *base)
49 {
50 	static const u_int8_t	vendor_code[] = {
51 		0x89,	/* manufacturer code: 	intel */
52 		0x18,	/* device code:		28F128 */
53 	};
54 
55 	static const u_int8_t	idstr[] = {
56 		'Q', 'R', 'Y',
57 		0x01, 0x00,
58 		0x31, 0x00,
59 		0xff
60 	};
61 
62 	int	i;
63 
64 	/* start Common Flash Interface Query */
65 	REGWRITE_2(base, 0, 0x98);
66 
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;
71 	}
72 
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;
78 
79 	REGWRITE_2(base, 0, 0xff);
80 	return 0;
81 }
82 
83 static int
block_erase(void * addr)84 block_erase(void *addr)
85 {
86 	int	status;
87 
88 	REGWRITE_2(addr, 0, I28F128_BLK_ERASE_1ST);
89 	REGWRITE_2(addr, 0, I28F128_BLK_ERASE_2ND);
90 
91 	do {
92 		status = REGREAD_2(addr, 0);
93 	} while (!ISSET(status, I28F128_S_READY));
94 
95 	REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
96 	REGWRITE_2(addr, 0, I28F128_RESET);
97 
98 	return status & (I28F128_S_ERASE_SUSPEND
99 			 | I28F128_S_ERASE_ERROR
100 			 | I28F128_S_BLOCK_LOCKED);
101 }
102 
103 static int
word_program(void * addr,u_int16_t data)104 word_program(void *addr, u_int16_t data)
105 {
106 	int	status;
107 
108 	REGWRITE_2(addr, 0, I28F128_WORDBYTE_PROG);
109 	REGWRITE_2(addr, 0, data);
110 
111 	do {
112 		status = REGREAD_2(addr, 0);
113 	} while (!ISSET(status, I28F128_S_READY));
114 
115 	REGWRITE_2(addr, 0, I28F128_CLEAR_STATUS);
116 	REGWRITE_2(addr, 0, I28F128_RESET);
117 
118 	return status & (I28F128_S_PROG_ERROR
119 			 | I28F128_S_LOW_VOLTAGE
120 			 | I28F128_S_PROG_SUSPEND
121 			 | I28F128_S_BLOCK_LOCKED);
122 }
123 
124 static int
block_write(void * dst,const void * src)125 block_write(void *dst, const void *src)
126 {
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;
133 
134 	/* dst must be aligned to block boundary. */
135 	if (I28F128_BLOCK_MASK & (u_int32_t) dst)
136 		return -1;
137 
138 	if (memcmp(dst, src, I28F128_BLOCK_SIZE) == 0)
139 		return 0;
140 
141 	if ((status = block_erase(dst)) != 0)
142 		return status;
143 
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));
152 
153 		REGWRITE_2(dst, 0, wbuf_count - 1);
154 
155 		for (i = wbuf_count; i > 0; i--, p++, q++)
156 			REGWRITE_2(q, 0, *p);
157 
158 		REGWRITE_2(dst, 0, I28F128_WBUF_CONFIRM);
159 
160 		do {
161 			REGWRITE_2(dst, 0, I28F128_READ_STATUS);
162 			status = REGREAD_2(dst, 0);
163 		} while (!(status & I28F128_S_READY));
164 
165 	} while (p < fence);
166 
167 	REGWRITE_2(dst, 0, I28F128_CLEAR_STATUS);
168 	REGWRITE_2(dst, 0, I28F128_RESET);
169 
170 	return 0;
171 }
172 
173 int
i28f128_region_write(void * dst,const void * src,size_t len)174 i28f128_region_write(void *dst, const void *src, size_t len)
175 {
176 	int		status;
177 	const u_int16_t	*p = src;
178 	u_int16_t	*q = dst;
179 
180 	/* dst must be aligned to block boundary. */
181 	if (I28F128_BLOCK_MASK & (u_int32_t) dst)
182 		return -1;
183 
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;
191 	}
192 
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;
205 		}
206 		printf("w");
207 	}
208 
209 	putchar('\n');
210 	return 0;
211 }
212