Home | History | Annotate | Line # | Download | only in lcboot
      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
     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
     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
    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
    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
    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