Home | History | Annotate | Line # | Download | only in lcboot
i28f128.c revision 1.2
      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