Home | History | Annotate | Line # | Download | only in lcboot
i28f128.c revision 1.1
      1 /* $NetBSD: i28f128.c,v 1.1 2003/05/01 07:02:01 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 
    140 	/* dst must be aligned to block boundary. */
    141 	if (I28F128_BLOCK_MASK & (u_int32_t) dst)
    142 		return -1;
    143 
    144 	if (memcmp(dst, src, I28F128_BLOCK_SIZE) == 0)
    145 		return 0;
    146 
    147 	if ((status = block_erase(dst)) != 0)
    148 		return status;
    149 
    150 	p = src;
    151 	q = dst;
    152 	fence = p + (I28F128_BLOCK_SIZE >> 1);
    153 	do {
    154 #ifdef USE_TWIDDLE
    155 		if (((u_int32_t) q % 4096) == 0)
    156 			twiddle();
    157 #endif
    158 		if ((status = word_program(q++, *p++)) != 0)
    159 			return status;
    160 	} while (p < fence);
    161 
    162 	return 0;
    163 }
    164 
    165 int
    166 i28f128_region_write(void *dst, const void *src, size_t len)
    167 {
    168 	int		status;
    169 	const u_int16_t	*p = src;
    170 	u_int16_t	*q = dst;
    171 
    172 	/* dst must be aligned to block boundary. */
    173 	if (I28F128_BLOCK_MASK & (u_int32_t) dst)
    174 		return -1;
    175 
    176 	while (len >= I28F128_BLOCK_SIZE) {
    177 		if ((status = block_write(q, p)) != 0)
    178 			return status;
    179 		putchar('b');
    180 		p += I28F128_BLOCK_SIZE >> 1;
    181 		q += I28F128_BLOCK_SIZE >> 1;
    182 		len -= I28F128_BLOCK_SIZE;
    183 	}
    184 
    185 	if (len > 0) {
    186 		if (memcmp(p, q, len) == 0)
    187 			return 0;
    188 		if ((status = block_erase(q)) != 0)
    189 			return status;
    190 		for (; len > 0; len -= 2) {
    191 #ifdef USE_TWIDDLE
    192 			if (((u_int32_t) q % 4096) == 0)
    193 				twiddle();
    194 #endif
    195 			if ((status = word_program(q++, *p++)) != 0)
    196 				return status;
    197 		}
    198 		printf("w");
    199 	}
    200 
    201 	putchar('\n');
    202 	return 0;
    203 }
    204