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