1/* $NetBSD: i28f128.c,v 1.2.2.3 2004/09/21 13:16:12 skrll 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.2.2.3 2004/09/21 13:16:12 skrll 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 */ 47int 48i28f128_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 83static int 84block_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 103static int 104word_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 124static int 125block_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 173int 174i28f128_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