cfi.c revision 1.4
1/* $NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $ */ 2/*- 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Cliff Neighbors. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "opt_flash.h" 32#include "opt_nor.h" 33#include "opt_cfi.h" 34 35#include <sys/cdefs.h> 36__KERNEL_RCSID(0, "$NetBSD: cfi.c,v 1.4 2011/07/23 06:27:40 cliff Exp $"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/cdefs.h> 41#include <sys/device.h> 42#include <sys/endian.h> 43 44#include <sys/bus.h> 45 46#include <dev/nor/nor.h> 47#include <dev/nor/cfi.h> 48#include <dev/nor/cfi_0002.h> 49 50 51static bool cfi_chip_query(struct cfi * const); 52static int cfi_scan_media(device_t self, struct nor_chip *chip); 53static void cfi_init(device_t); 54static void cfi_select(device_t, bool); 55static void cfi_read_1(device_t, flash_off_t, uint8_t *); 56static void cfi_read_2(device_t, flash_off_t, uint16_t *); 57static void cfi_read_4(device_t, flash_off_t, uint32_t *); 58static void cfi_read_buf_1(device_t, flash_off_t, uint8_t *, size_t); 59static void cfi_read_buf_2(device_t, flash_off_t, uint16_t *, size_t); 60static void cfi_read_buf_4(device_t, flash_off_t, uint32_t *, size_t); 61static void cfi_write_1(device_t, flash_off_t, uint8_t); 62static void cfi_write_2(device_t, flash_off_t, uint16_t); 63static void cfi_write_4(device_t, flash_off_t, uint32_t); 64static void cfi_write_buf_1(device_t, flash_off_t, const uint8_t *, size_t); 65static void cfi_write_buf_2(device_t, flash_off_t, const uint16_t *, size_t); 66static void cfi_write_buf_4(device_t, flash_off_t, const uint32_t *, size_t); 67static void cfi_jedec_id_1(struct cfi * const ); 68static void cfi_jedec_id_2(struct cfi * const ); 69static void cfi_jedec_id_4(struct cfi * const ); 70static bool cfi_jedec_id(struct cfi * const); 71static bool cfi_emulate(struct cfi * const); 72static const struct cfi_jedec_tab * cfi_jedec_search(struct cfi *); 73static void cfi_jedec_fill(struct cfi * const, 74 const struct cfi_jedec_tab *); 75#if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY) 76static void cfi_hexdump(flash_off_t, void * const, u_int, u_int); 77#endif 78 79 80 81/* 82 * NOTE these opmode tables are informed by "Table 1. CFI Query Read" 83 * in Intel "Common Flash Interface (CFI) and Command Sets" 84 * Application Note 646, April 2000 85 * 86 * The byte ordering of the signature string here varies from that table 87 * because of discrepancy in observed behavior, for the case: 88 * - x16 device operating in 16-bit mode 89 * Similar discrepancy is expected (but not verified) for the case: 90 * - x32 device operating in 32-bit mode 91 * so the ordering is changed here for that case also. 92 * 93 * XXX down-sized, interleaved & multi-chip opmodes not yet supported 94 */ 95 96/* 1-byte access */ 97static const struct cfi_opmodes cfi_opmodes_1[] = { 98 { 0, 0, 0, 0x10, 3, "QRY", "x8 device operating in 8-bit mode" }, 99}; 100 101/* 2-byte access */ 102static const struct cfi_opmodes cfi_opmodes_2[] = { 103 { 1, 1, 0, 0x20, 6, "\0Q\0R\0Y", 104 "x16 device operating in 16-bit mode" }, 105}; 106 107/* 4-byte access */ 108static const struct cfi_opmodes cfi_opmodes_4[] = { 109 { 2, 2, 0, 0x40, 12, "\0\0\0Q\0\0\0R\0\0\0Y", 110 "x32 device operating in 32-bit mode" }, 111}; 112 113 114#define LOG2_64K 16 115#define LOG2_128K 17 116#define LOG2_256K 18 117#define LOG2_512K 19 118#define LOG2_1M 20 119#define LOG2_2M 21 120#define LOG2_4M 22 121#define LOG2_8M 23 122#define LOG2_16M 24 123#define LOG2_32M 25 124#define LOG2_64M 26 125#define LOG2_128M 27 126#define LOG2_256M 28 127#define LOG2_512M 29 128#define LOG2_1G 30 129#define LOG2_2G 31 130const struct cfi_jedec_tab cfi_jedec_tab[] = { 131 { 132 .jt_name = "Pm39LV512", 133 .jt_mid = 0x9d, 134 .jt_did = 0x1b, 135 .jt_id_pri = 0, /* XXX */ 136 .jt_id_alt = 0, /* XXX */ 137 .jt_device_size = LOG2_64K, 138 .jt_interface_code_desc = CFI_IFCODE_X8, 139 .jt_erase_blk_regions = 1, 140 .jt_erase_blk_info = { 141 { 4096/256, (64/4)-1 }, 142 }, 143 .jt_write_word_time_typ = 40, 144 .jt_write_nbyte_time_typ = 0, 145 .jt_erase_blk_time_typ = 55, 146 .jt_erase_chip_time_typ = 55, 147 .jt_write_word_time_max = 1, 148 .jt_write_nbyte_time_max = 0, 149 .jt_erase_blk_time_max = 1, 150 .jt_erase_chip_time_max = 1, 151 .jt_opmode = &cfi_opmodes_1[0], 152 }, 153 { 154 .jt_name = "Pm39LV010", 155 .jt_mid = 0x9d, 156 .jt_did = 0x1c, 157 .jt_id_pri = 0, /* XXX */ 158 .jt_id_alt = 0, /* XXX */ 159 .jt_device_size = LOG2_128K, 160 .jt_interface_code_desc = CFI_IFCODE_X8, 161 .jt_erase_blk_regions = 1, 162 .jt_erase_blk_info = { 163 { 4096/256, (128/4)-1 }, 164 }, 165 .jt_write_word_time_typ = 40, 166 .jt_write_nbyte_time_typ = 0, 167 .jt_erase_blk_time_typ = 55, 168 .jt_erase_chip_time_typ = 55, 169 .jt_write_word_time_max = 1, 170 .jt_write_nbyte_time_max = 0, 171 .jt_erase_blk_time_max = 1, 172 .jt_erase_chip_time_max = 1, 173 .jt_opmode = &cfi_opmodes_1[0], 174 }, 175}; 176 177 178const struct nor_interface nor_interface_cfi = { 179 .scan_media = cfi_scan_media, 180 .init = cfi_init, 181 .select = cfi_select, 182 .read_1 = cfi_read_1, 183 .read_2 = cfi_read_2, 184 .read_4 = cfi_read_4, 185 .read_buf_1 = cfi_read_buf_1, 186 .read_buf_2 = cfi_read_buf_2, 187 .read_buf_4 = cfi_read_buf_4, 188 .write_1 = cfi_write_1, 189 .write_2 = cfi_write_2, 190 .write_4 = cfi_write_4, 191 .write_buf_1 = cfi_write_buf_1, 192 .write_buf_2 = cfi_write_buf_2, 193 .write_buf_4 = cfi_write_buf_4, 194 .read_page = NULL, /* cmdset */ 195 .program_page = NULL, /* cmdset */ 196 .busy = NULL, 197 .private = NULL, 198 .access_width = -1, 199 .part_info = NULL, 200 .part_num = -1, 201}; 202 203 204/* only data[7..0] are used regardless of chip width */ 205#define cfi_unpack_1(n) ((n) & 0xff) 206 207/* construct (arbitrarily big endian) uint16_t */ 208#define cfi_unpack_2(b0, b1) \ 209 ((cfi_unpack_1(b1) << 8) | cfi_unpack_1(b0)) 210 211/* construct (arbitrarily) big endian uint32_t */ 212#define cfi_unpack_4(b0, b1, b2, b3) \ 213 ((cfi_unpack_1(b3) << 24) | \ 214 (cfi_unpack_1(b2) << 16) | \ 215 (cfi_unpack_1(b1) << 8) | \ 216 (cfi_unpack_1(b0))) 217 218#define cfi_unpack_qry(qryp, data) \ 219 do { \ 220 (qryp)->qry[0] = cfi_unpack_1(data[0x10]); \ 221 (qryp)->qry[1] = cfi_unpack_1(data[0x11]); \ 222 (qryp)->qry[2] = cfi_unpack_1(data[0x12]); \ 223 (qryp)->id_pri = be16toh(cfi_unpack_2(data[0x13], data[0x14])); \ 224 (qryp)->addr_pri = \ 225 be16toh(cfi_unpack_2(data[0x15], data[0x16])); \ 226 (qryp)->id_alt = be16toh(cfi_unpack_2(data[0x17], data[0x18])); \ 227 (qryp)->addr_alt = \ 228 be16toh(cfi_unpack_2(data[0x19], data[0x1a])); \ 229 (qryp)->vcc_min = cfi_unpack_1(data[0x1b]); \ 230 (qryp)->vcc_max = cfi_unpack_1(data[0x1c]); \ 231 (qryp)->vpp_min = cfi_unpack_1(data[0x1d]); \ 232 (qryp)->vpp_max = cfi_unpack_1(data[0x1e]); \ 233 (qryp)->write_word_time_typ = cfi_unpack_1(data[0x1f]); \ 234 (qryp)->write_nbyte_time_typ = cfi_unpack_1(data[0x20]); \ 235 (qryp)->erase_blk_time_typ = cfi_unpack_1(data[0x21]); \ 236 (qryp)->erase_chip_time_typ = cfi_unpack_1(data[0x22]); \ 237 (qryp)->write_word_time_max = cfi_unpack_1(data[0x23]); \ 238 (qryp)->write_nbyte_time_max = cfi_unpack_1(data[0x24]); \ 239 (qryp)->erase_blk_time_max = cfi_unpack_1(data[0x25]); \ 240 (qryp)->erase_chip_time_max = cfi_unpack_1(data[0x26]); \ 241 (qryp)->device_size = cfi_unpack_1(data[0x27]); \ 242 (qryp)->interface_code_desc = \ 243 be16toh(cfi_unpack_2(data[0x28], data[0x29])); \ 244 (qryp)->write_nbyte_size_max = \ 245 be16toh(cfi_unpack_2(data[0x2a], data[0x2b])); \ 246 (qryp)->erase_blk_regions = cfi_unpack_1(data[0x2c]); \ 247 u_int _i = 0x2d; \ 248 const u_int _n = (qryp)->erase_blk_regions; \ 249 KASSERT(_n <= 4); \ 250 for (u_int _r = 0; _r < _n; _r++, _i+=4) { \ 251 (qryp)->erase_blk_info[_r].y = \ 252 be32toh(cfi_unpack_2(data[_i+0], data[_i+1])); \ 253 (qryp)->erase_blk_info[_r].z = \ 254 be32toh(cfi_unpack_2(data[_i+2], data[_i+3])); \ 255 } \ 256 } while (0) 257 258#define cfi_unpack_pri_0002(qryp, data) \ 259 do { \ 260 (qryp)->pri.cmd_0002.pri[0] = cfi_unpack_1(data[0x00]); \ 261 (qryp)->pri.cmd_0002.pri[1] = cfi_unpack_1(data[0x01]); \ 262 (qryp)->pri.cmd_0002.pri[2] = cfi_unpack_1(data[0x02]); \ 263 (qryp)->pri.cmd_0002.version_maj = cfi_unpack_1(data[0x03]); \ 264 (qryp)->pri.cmd_0002.version_min = cfi_unpack_1(data[0x04]); \ 265 (qryp)->pri.cmd_0002.asupt = cfi_unpack_1(data[0x05]); \ 266 (qryp)->pri.cmd_0002.erase_susp = cfi_unpack_1(data[0x06]); \ 267 (qryp)->pri.cmd_0002.sector_prot = cfi_unpack_1(data[0x07]); \ 268 (qryp)->pri.cmd_0002.tmp_sector_unprot = \ 269 cfi_unpack_1(data[0x08]); \ 270 (qryp)->pri.cmd_0002.sector_prot_scheme = \ 271 cfi_unpack_1(data[0x09]); \ 272 (qryp)->pri.cmd_0002.simul_op = cfi_unpack_1(data[0x0a]); \ 273 (qryp)->pri.cmd_0002.burst_mode_type = cfi_unpack_1(data[0x0b]);\ 274 (qryp)->pri.cmd_0002.page_mode_type = cfi_unpack_1(data[0x0c]); \ 275 (qryp)->pri.cmd_0002.acc_min = cfi_unpack_1(data[0x0d]); \ 276 (qryp)->pri.cmd_0002.acc_max = cfi_unpack_1(data[0x0e]); \ 277 (qryp)->pri.cmd_0002.wp_prot = cfi_unpack_1(data[0x0f]); \ 278 /* XXX 1.3 stops here */ \ 279 (qryp)->pri.cmd_0002.prog_susp = cfi_unpack_1(data[0x10]); \ 280 (qryp)->pri.cmd_0002.unlock_bypass = cfi_unpack_1(data[0x11]); \ 281 (qryp)->pri.cmd_0002.sss_size = cfi_unpack_1(data[0x12]); \ 282 (qryp)->pri.cmd_0002.soft_feat = cfi_unpack_1(data[0x13]); \ 283 (qryp)->pri.cmd_0002.page_size = cfi_unpack_1(data[0x14]); \ 284 (qryp)->pri.cmd_0002.erase_susp_time_max = \ 285 cfi_unpack_1(data[0x15]); \ 286 (qryp)->pri.cmd_0002.prog_susp_time_max = \ 287 cfi_unpack_1(data[0x16]); \ 288 (qryp)->pri.cmd_0002.embhwrst_time_max = \ 289 cfi_unpack_1(data[0x38]); \ 290 (qryp)->pri.cmd_0002.hwrst_time_max = \ 291 cfi_unpack_1(data[0x39]); \ 292 } while (0) 293 294#define CFI_QRY_UNPACK_COMMON(cfi, data, type, found) \ 295 do { \ 296 struct cfi_query_data * const qryp = &cfi->cfi_qry_data; \ 297 \ 298 memset(qryp, 0, sizeof(*qryp)); \ 299 cfi_unpack_qry(qryp, data); \ 300 \ 301 switch (qryp->id_pri) { \ 302 case 0x0002: \ 303 if ((cfi_unpack_1(data[qryp->addr_pri + 0]) == 'P') && \ 304 (cfi_unpack_1(data[qryp->addr_pri + 1]) == 'R') && \ 305 (cfi_unpack_1(data[qryp->addr_pri + 2]) == 'I')) { \ 306 type *pri_data = &data[qryp->addr_pri]; \ 307 cfi_unpack_pri_0002(qryp, pri_data); \ 308 found = true; \ 309 break; \ 310 } \ 311 default: \ 312 printf("%s: unsupported id_pri=%#x\n", \ 313 __func__, qryp->id_pri); \ 314 break; /* unknown command set */ \ 315 } \ 316 } while (0) 317 318#ifdef CFI_DEBUG_QRY 319# define CFI_DUMP_QRY(off, p, sz, stride) \ 320 do { \ 321 printf("%s: QRY data\n", __func__); \ 322 cfi_hexdump(off, p, sz, stride); \ 323 } while (0) 324#else 325# define CFI_DUMP_QRY(off, p, sz, stride) 326#endif 327 328#ifdef CFI_DEBUG_JEDEC 329# define CFI_DUMP_JEDEC(off, p, sz, stride) \ 330 do { \ 331 printf("%s: JEDEC data\n", __func__); \ 332 cfi_hexdump(off, p, sz, stride); \ 333 } while (0) 334#else 335# define CFI_DUMP_JEDEC(off, p, sz, stride) 336#endif 337 338 339/* 340 * cfi_chip_query_opmode - determine operational mode based on QRY signature 341 */ 342static bool 343cfi_chip_query_opmode(struct cfi *cfi, uint8_t *data, 344 const struct cfi_opmodes *tab, u_int nentries) 345{ 346 for (u_int i=0; i < nentries; i++) { 347 if (memcmp(&data[tab[i].qsa], tab[i].sig, tab[i].len) == 0) { 348 cfi->cfi_opmode = &tab[i]; 349 return true; 350 } 351 } 352 return false; 353} 354 355static bool 356cfi_chip_query_1(struct cfi * const cfi) 357{ 358 uint8_t data[0x80]; 359 360 bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 361 __arraycount(data)); 362 363 CFI_DUMP_QRY(0, data, sizeof(data), 1); 364 365 bool found = cfi_chip_query_opmode(cfi, data, cfi_opmodes_1, 366 __arraycount(cfi_opmodes_1)); 367 368 if (found) { 369 CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t, found); 370 } 371 372 return found; 373} 374 375static bool 376cfi_chip_query_2(struct cfi * const cfi) 377{ 378 uint16_t data[0x80]; 379 380 bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 381 __arraycount(data)); 382 383 CFI_DUMP_QRY(0, data, sizeof(data), 2); 384 385 bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data, 386 cfi_opmodes_2, __arraycount(cfi_opmodes_2)); 387 388 if (found) { 389 CFI_QRY_UNPACK_COMMON(cfi, data, uint16_t, found); 390 } 391 392 return found; 393} 394 395static bool 396cfi_chip_query_4(struct cfi * const cfi) 397{ 398 uint32_t data[0x80]; 399 400 bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 401 __arraycount(data)); 402 403 CFI_DUMP_QRY(0, data, sizeof(data), 4); 404 405 bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data, 406 cfi_opmodes_4, __arraycount(cfi_opmodes_4)); 407 408 if (found) { 409 CFI_QRY_UNPACK_COMMON(cfi, data, uint32_t, found); 410 } 411 412 return found; 413} 414 415static bool 416cfi_chip_query_8(struct cfi * const cfi) 417{ 418#ifdef NOTYET 419 uint64_t data[0x80]; 420 421 bus_space_read_region_8(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 422 __arraycount(data)); 423 424 CFI_DUMP_QRY(0, data, sizeof(data), 8); 425 426 bool found = cfi_chip_query_opmode(cfi, (uint8_t *)data, 427 cfi_opmodes_8, __arraycount(cfi_opmodes_8)); 428 429 if (found) { 430 CFI_QRY_UNPACK_COMMON(cfi, data, uint64_t, found); 431 } 432 433 return found; 434#else 435 return false; 436#endif 437} 438 439/* 440 * cfi_chip_query - detect a CFI chip 441 * 442 * fill in the struct cfi as we discover what's there 443 */ 444static bool 445cfi_chip_query(struct cfi * const cfi) 446{ 447 bool found = false; 448 const bus_size_t cfi_query_offset[] = { 449 CFI_QUERY_MODE_ADDRESS, 450 CFI_QUERY_MODE_ALT_ADDRESS 451 }; 452 453 KASSERT(cfi != NULL); 454 KASSERT(cfi->cfi_bst != NULL); 455 456 for (int j=0; !found && j < __arraycount(cfi_query_offset); j++) { 457 458 cfi_reset_default(cfi); 459 cfi_cmd(cfi, cfi_query_offset[j], CFI_QUERY_DATA); 460 461 switch(cfi->cfi_portwidth) { 462 case 0: 463 found = cfi_chip_query_1(cfi); 464 break; 465 case 1: 466 found = cfi_chip_query_2(cfi); 467 break; 468 case 2: 469 found = cfi_chip_query_4(cfi); 470 break; 471 case 3: 472 found = cfi_chip_query_8(cfi); 473 break; 474 default: 475 panic("%s: bad portwidth %d\n", 476 __func__, cfi->cfi_portwidth); 477 } 478 } 479 480 if (found) 481 cfi->cfi_emulated = false; 482 483 return found; 484} 485 486/* 487 * cfi_probe - search for a CFI NOR trying various port & chip widths 488 * 489 * - gather CFI QRY and PRI data 490 * - gather JEDEC ID data 491 * - if cfi_chip_query() fails, emulate CFI using table data if possible, 492 * otherwise fail. 493 * 494 * NOTE: 495 * striped NOR chips design not supported yet, 496 * so force portwidth=chipwidth for now 497 * eventually permute portwidth seperately 498 */ 499bool 500cfi_probe(struct cfi * const cfi) 501{ 502 bool found; 503 504 KASSERT(cfi != NULL); 505 506 for (u_int cw = 0; cw < 3; cw++) { 507 cfi->cfi_portwidth = /* XXX */ 508 cfi->cfi_chipwidth = cw; 509 found = cfi_chip_query(cfi); 510 cfi_jedec_id(cfi); 511 if (! found) 512 found = cfi_emulate(cfi); 513 if (found) 514 break; 515 } 516 517 cfi_reset_default(cfi); /* exit QRY mode */ 518 return found; 519} 520 521bool 522cfi_identify(struct cfi * const cfi) 523{ 524 const bus_space_tag_t bst = cfi->cfi_bst; 525 const bus_space_handle_t bsh = cfi->cfi_bsh; 526 bool found; 527 528 KASSERT(cfi != NULL); 529 KASSERT(bst != NULL); 530 531 memset(cfi, 0, sizeof(struct cfi)); /* XXX clean slate */ 532 cfi->cfi_bst = bst; /* restore bus space */ 533 cfi->cfi_bsh = bsh; /* " " " */ 534 535 found = cfi_probe(cfi); 536 537 cfi_reset_default(cfi); /* exit QRY mode */ 538 539 return found; 540} 541 542static int 543cfi_scan_media(device_t self, struct nor_chip *chip) 544{ 545 struct nor_softc *sc = device_private(self); 546 KASSERT(sc != NULL); 547 KASSERT(sc->sc_nor_if != NULL); 548 struct cfi * const cfi = (struct cfi * const)sc->sc_nor_if->private; 549 KASSERT(cfi != NULL); 550 551 sc->sc_nor_if->access_width = cfi->cfi_portwidth; 552 553 chip->nc_manf_id = cfi->cfi_id_data.id_mid; 554 chip->nc_dev_id = cfi->cfi_id_data.id_did[0]; /* XXX 3 words */ 555 chip->nc_size = 1 << cfi->cfi_qry_data.device_size; 556 557 /* size of line for Read Buf command */ 558 chip->nc_line_size = 1 << cfi->cfi_qry_data.pri.cmd_0002.page_size; 559 560 /* 561 * size of erase block 562 * XXX depends on erase region 563 */ 564 chip->nc_num_luns = 1; 565 chip->nc_lun_blocks = cfi->cfi_qry_data.erase_blk_info[0].y + 1; 566 chip->nc_block_size = cfi->cfi_qry_data.erase_blk_info[0].z * 256; 567 568 switch (cfi->cfi_qry_data.id_pri) { 569 case 0x0002: 570 cfi_0002_init(sc, cfi, chip); 571 break; 572 default: 573 aprint_error_dev(self, "unsupported CFI cmdset %#04x\n", 574 cfi->cfi_qry_data.id_pri); 575 return -1; 576 } 577 578 return 0; 579} 580 581void 582cfi_init(device_t self) 583{ 584 /* nothing */ 585} 586 587static void 588cfi_select(device_t self, bool select) 589{ 590 /* nothing */ 591} 592 593static void 594cfi_read_1(device_t self, flash_off_t offset, uint8_t *datap) 595{ 596} 597 598static void 599cfi_read_2(device_t self, flash_off_t offset, uint16_t *datap) 600{ 601} 602 603static void 604cfi_read_4(device_t self, flash_off_t offset, uint32_t *datap) 605{ 606} 607 608static void 609cfi_read_buf_1(device_t self, flash_off_t offset, uint8_t *datap, size_t size) 610{ 611} 612 613static void 614cfi_read_buf_2(device_t self, flash_off_t offset, uint16_t *datap, size_t size) 615{ 616} 617 618static void 619cfi_read_buf_4(device_t self, flash_off_t offset, uint32_t *datap, size_t size) 620{ 621} 622 623static void 624cfi_write_1(device_t self, flash_off_t offset, uint8_t data) 625{ 626} 627 628static void 629cfi_write_2(device_t self, flash_off_t offset, uint16_t data) 630{ 631} 632 633static void 634cfi_write_4(device_t self, flash_off_t offset, uint32_t data) 635{ 636} 637 638static void 639cfi_write_buf_1(device_t self, flash_off_t offset, const uint8_t *datap, 640 size_t size) 641{ 642} 643 644static void 645cfi_write_buf_2(device_t self, flash_off_t offset, const uint16_t *datap, 646 size_t size) 647{ 648} 649 650static void 651cfi_write_buf_4(device_t self, flash_off_t offset, const uint32_t *datap, 652 size_t size) 653{ 654} 655 656void 657cfi_cmd(struct cfi * const cfi, bus_size_t off, uint32_t val) 658{ 659 const bus_space_tag_t bst = cfi->cfi_bst; 660 bus_space_handle_t bsh = cfi->cfi_bsh; 661 662 off <<= cfi->cfi_portwidth; 663 664 DPRINTF(("%s: %p %x %x %x\n", __func__, bst, bsh, off, val)); 665 666 switch(cfi->cfi_portwidth) { 667 case 0: 668 bus_space_write_1(bst, bsh, off, (uint8_t)val); 669 break; 670 case 1: 671 bus_space_write_2(bst, bsh, off, val); 672 break; 673 case 2: 674 bus_space_write_4(bst, bsh, off, (uint32_t)val); 675 break; 676#ifdef NOTYET 677 case 3: 678 bus_space_write_4(bst, bsh, off, (uint64_t)val); 679 break; 680#endif 681 default: 682 panic("%s: bad portwidth %d bytes\n", 683 __func__, 1 << cfi->cfi_portwidth); 684 } 685} 686 687/* 688 * cfi_reset_default - when we don't know which command will work, use both 689 */ 690void 691cfi_reset_default(struct cfi * const cfi) 692{ 693 cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA); 694 cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA); 695} 696 697/* 698 * cfi_reset_std - use standard reset command 699 */ 700void 701cfi_reset_std(struct cfi * const cfi) 702{ 703 cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_RESET_DATA); 704} 705 706/* 707 * cfi_reset_alt - use "alternate" reset command 708 */ 709void 710cfi_reset_alt(struct cfi * const cfi) 711{ 712 cfi_cmd(cfi, CFI_ADDRESS_ANY, CFI_ALT_RESET_DATA); 713} 714 715static void 716cfi_jedec_id_1(struct cfi * const cfi) 717{ 718 struct cfi_jedec_id_data *idp = &cfi->cfi_id_data; 719 uint8_t data[0x10]; 720 721 bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 722 __arraycount(data)); 723 724 CFI_DUMP_JEDEC(0, data, sizeof(data), 1); 725 726 idp->id_mid = (uint16_t)data[0]; 727 idp->id_did[0] = (uint16_t)data[1]; 728 idp->id_did[1] = (uint16_t)data[0xe]; 729 idp->id_did[2] = (uint16_t)data[0xf]; 730 idp->id_prot_state = (uint16_t)data[2]; 731 idp->id_indicators = (uint16_t)data[3]; 732 733 /* software bits, upper and lower */ 734 idp->id_swb_lo = data[0xc]; 735 idp->id_swb_hi = data[0xd]; 736 737} 738 739static void 740cfi_jedec_id_2(struct cfi * const cfi) 741{ 742 struct cfi_jedec_id_data *idp = &cfi->cfi_id_data; 743 uint16_t data[0x10]; 744 745 bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 746 __arraycount(data)); 747 748 CFI_DUMP_JEDEC(0, data, sizeof(data), 1); 749 750 idp->id_mid = data[0]; 751 idp->id_did[0] = data[1]; 752 idp->id_did[1] = data[0xe]; 753 idp->id_did[2] = data[0xf]; 754 idp->id_prot_state = data[2]; 755 idp->id_indicators = data[3]; 756 757 /* software bits, upper and lower 758 * - undefined on S29GL-P 759 * - defined on S29GL-S 760 */ 761 idp->id_swb_lo = data[0xc]; 762 idp->id_swb_hi = data[0xd]; 763 764} 765 766static void 767cfi_jedec_id_4(struct cfi * const cfi) 768{ 769 struct cfi_jedec_id_data *idp = &cfi->cfi_id_data; 770 uint32_t data[0x10]; 771 772 bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, 0, data, 773 __arraycount(data)); 774 775 CFI_DUMP_JEDEC(0, data, sizeof(data), 1); 776 777 idp->id_mid = data[0] & 0xffff; 778 idp->id_did[0] = data[1] & 0xffff; 779 idp->id_did[1] = data[0xe] & 0xffff; 780 idp->id_did[2] = data[0xf] & 0xffff; 781 idp->id_prot_state = data[2] & 0xffff; 782 idp->id_indicators = data[3] & 0xffff; 783 784 /* software bits, upper and lower 785 * - undefined on S29GL-P 786 * - defined on S29GL-S 787 */ 788 idp->id_swb_lo = data[0xc] & 0xffff; 789 idp->id_swb_hi = data[0xd] & 0xffff; 790 791} 792 793/* 794 * cfi_jedec_id - get JEDEC ID info 795 */ 796static bool 797cfi_jedec_id(struct cfi * const cfi) 798{ 799 800 DPRINTF(("%s\n", __func__)); 801 802 cfi_cmd(cfi, 0x555, 0xaa); 803 cfi_cmd(cfi, 0x2aa, 0x55); 804 cfi_cmd(cfi, 0x555, 0x90); 805 806 switch(cfi->cfi_portwidth) { 807 case 0: 808 cfi_jedec_id_1(cfi); 809 break; 810 case 1: 811 cfi_jedec_id_2(cfi); 812 break; 813 case 2: 814 cfi_jedec_id_4(cfi); 815 break; 816#ifdef NOTYET 817 case 3: 818 cfi_jedec_id_8(cfi); 819 break; 820#endif 821 default: 822 panic("%s: bad portwidth %d bytes\n", 823 __func__, 1 << cfi->cfi_portwidth); 824 } 825 826 return true; 827} 828 829static bool 830cfi_emulate(struct cfi * const cfi) 831{ 832 bool found = false; 833 const struct cfi_jedec_tab *jt = cfi_jedec_search(cfi); 834 if (jt != NULL) { 835 found = true; 836 cfi->cfi_emulated = true; 837 cfi_jedec_fill(cfi, jt); 838 } 839 return found; 840} 841 842/* 843 * cfi_jedec_search - search cfi_jedec_tab[] for entry matching given JEDEC IDs 844 */ 845static const struct cfi_jedec_tab * 846cfi_jedec_search(struct cfi *cfi) 847{ 848 struct cfi_jedec_id_data *idp = &cfi->cfi_id_data; 849 850 for (u_int i=0; i < __arraycount(cfi_jedec_tab); i++) { 851 const struct cfi_jedec_tab *jt = &cfi_jedec_tab[i]; 852 if ((jt->jt_mid == idp->id_mid) && 853 (jt->jt_did == idp->id_did[0])) { 854 return jt; 855 } 856 } 857 return NULL; 858} 859 860/* 861 * cfi_jedec_fill - fill in cfi with info from table entry 862 */ 863static void 864cfi_jedec_fill(struct cfi *cfi, const struct cfi_jedec_tab *jt) 865{ 866 cfi->cfi_name = jt->jt_name; 867 cfi->cfi_opmode = jt->jt_opmode; 868 memset(&cfi->cfi_qry_data, 0, sizeof(struct cfi_query_data)); 869 cfi->cfi_qry_data.id_pri = jt->jt_id_pri; 870 cfi->cfi_qry_data.id_alt = jt->jt_id_alt; 871 cfi->cfi_qry_data.interface_code_desc = jt->jt_interface_code_desc; 872 cfi->cfi_qry_data.write_word_time_typ = jt->jt_write_word_time_typ; 873 cfi->cfi_qry_data.write_nbyte_time_typ = jt->jt_write_nbyte_time_typ; 874 cfi->cfi_qry_data.erase_blk_time_typ = jt->jt_erase_blk_time_typ; 875 cfi->cfi_qry_data.erase_chip_time_typ = jt->jt_erase_chip_time_typ; 876 cfi->cfi_qry_data.write_word_time_max = jt->jt_write_word_time_max; 877 cfi->cfi_qry_data.write_nbyte_time_max = jt->jt_write_nbyte_time_max; 878 cfi->cfi_qry_data.erase_blk_time_max = jt->jt_erase_blk_time_max; 879 cfi->cfi_qry_data.erase_chip_time_max = jt->jt_erase_chip_time_max; 880 cfi->cfi_qry_data.device_size = jt->jt_device_size; 881 cfi->cfi_qry_data.interface_code_desc = jt->jt_interface_code_desc; 882 cfi->cfi_qry_data.write_nbyte_size_max = jt->jt_write_nbyte_size_max; 883 cfi->cfi_qry_data.erase_blk_regions = jt->jt_erase_blk_regions; 884 for (u_int i=0; i < 4; i++) 885 cfi->cfi_qry_data.erase_blk_info[i] = jt->jt_erase_blk_info[i]; 886} 887 888void 889cfi_print(device_t self, struct cfi * const cfi) 890{ 891 char pbuf[sizeof("XXXX MB")]; 892 struct cfi_query_data * const qryp = &cfi->cfi_qry_data; 893 894 format_bytes(pbuf, sizeof(pbuf), 1 << qryp->device_size); 895 if (cfi->cfi_emulated) { 896 aprint_normal_dev(self, "%s NOR flash %s %s\n", 897 cfi->cfi_name, pbuf, 898 cfi_interface_desc_str(qryp->interface_code_desc)); 899 } else { 900 aprint_normal_dev(self, "CFI NOR flash %s %s\n", pbuf, 901 cfi_interface_desc_str(qryp->interface_code_desc)); 902 } 903#ifdef NOR_VERBOSE 904 aprint_normal_dev(self, "manufacturer id %#x, device id %#x %#x %#x\n", 905 cfi->cfi_id_data.id_mid, 906 cfi->cfi_id_data.id_did[0], 907 cfi->cfi_id_data.id_did[1], 908 cfi->cfi_id_data.id_did[2]); 909 aprint_normal_dev(self, "%s\n", cfi->cfi_opmode->str); 910 aprint_normal_dev(self, "sw bits lo=%#x hi=%#x\n", 911 cfi->cfi_id_data.id_swb_lo, 912 cfi->cfi_id_data.id_swb_hi); 913 aprint_normal_dev(self, "max multibyte write size %d\n", 914 1 << qryp->write_nbyte_size_max); 915 aprint_normal_dev(self, "%d Erase Block Region(s)\n", 916 qryp->erase_blk_regions); 917 for (u_int r=0; r < qryp->erase_blk_regions; r++) { 918 size_t sz = qryp->erase_blk_info[r].z * 256; 919 format_bytes(pbuf, sizeof(pbuf), sz); 920 aprint_normal(" %d: %d blocks, size %s\n", r, 921 qryp->erase_blk_info[r].y + 1, pbuf); 922 } 923#endif 924 925 switch (cfi->cfi_qry_data.id_pri) { 926 case 0x0002: 927 cfi_0002_print(self, cfi); 928 break; 929 } 930} 931 932#if defined(CFI_DEBUG_JEDEC) || defined(CFI_DEBUG_QRY) 933void 934cfi_hexdump(flash_off_t offset, void * const v, u_int count, u_int stride) 935{ 936 uint8_t * const data = v; 937 for(int n=0; n < count; n+=16) { 938 int i; 939 printf("%08llx: ", (offset + n) / stride); 940 for(i=n; i < n+16; i++) 941 printf("%02x ", data[i]); 942 printf("\t"); 943 for(i=n; i < n+16; i++) { 944 u_int c = (int)data[i]; 945 if (c >= 0x20 && c < 0x7f) 946 printf("%c", c); 947 else 948 printf("%c", '.'); 949 } 950 printf("\n"); 951 } 952} 953#endif 954