diff --git a/build_gnu/Makefile b/build_gnu/Makefile
index 4133e82..b7a8b24 100644
--- a/build_gnu/Makefile
+++ b/build_gnu/Makefile
@@ -4,16 +4,16 @@ CC = $(PREFIX)gcc
AS = $(PREFIX)as
LD = $(PREFIX)ld
OBJCOPY = $(PREFIX)objcopy
-RM = del
+RM = rm
INCLUDES = -I../include -I../ftl_$(FTL) -I../sata -I../target_spw
CFLAGS = -mcpu=arm7tdmi-s -mthumb-interwork -ffreestanding -nostdlib -std=c99 -O2 -g -DPROGRAM_MAIN_FW -Wall
ASFLAGS = -R -mcpu=arm7tdmi-s
LDFLAGS = -static -nostartfiles -ffreestanding -T ld_script -Wl,-O1,-Map=list.txt
LIBS = -lgcc
-VPATH = ../ftl_$(FTL);../sata;..;../target_spw
+VPATH = ../ftl_$(FTL):../sata:..:../target_spw
-SRCS = ftl.c sata_identify.c sata_cmd.c sata_isr.c sata_main.c sata_table.c initialize.c mem_util.c flash.c flash_wrapper.c misc.c uart.c
+SRCS = ftl.c sata_identify.c sata_cmd.c sata_isr.c sata_main.c sata_table.c initialize.c mem_util.c flash.c flash_wrapper.c misc.c uart.c syscalls.c
INITSRC = ../target_spw/init_gnu.s
OBJS = $(SRCS:.c=.o) init.o
DEPS = $(SRCS:.c=.d)
diff --git a/include/jasmine.h b/include/jasmine.h
index 0e2a82d..d3516c4 100644
--- a/include/jasmine.h
+++ b/include/jasmine.h
@@ -27,7 +27,7 @@
#define OPTION_2_PLANE 1 // 1 = 2-plane mode, 0 = 1-plane mode
#define OPTION_ENABLE_ASSERT 0 // 1 = enable ASSERT() for debugging, 0 = disable ASSERT()
#define OPTION_FTL_TEST 0 // 1 = FTL test without SATA communication, 0 = normal
-#define OPTION_UART_DEBUG 0 // 1 = enable UART message output, 0 = disable
+#define OPTION_UART_DEBUG 1 // 1 = enable UART message output, 0 = disable
#define OPTION_SLOW_SATA 0 // 1 = SATA 1.5Gbps, 0 = 3Gbps
#define OPTION_SUPPORT_NCQ 0 // 1 = support SATA NCQ (=FPDMA) for AHCI hosts, 0 = support only DMA mode
#define OPTION_REDUCED_CAPACITY 0 // reduce the number of blocks per bank for testing purpose
diff --git a/installer/Makefile b/installer/Makefile
new file mode 100644
index 0000000..2cfad13
--- /dev/null
+++ b/installer/Makefile
@@ -0,0 +1,5 @@
+installer: installer-linux.c
+ gcc -Wall -W -I../include -I../ftl_tutorial -I../target_spw $< -o $@
+
+clean:
+ rm -rf installer
diff --git a/installer/installer-linux.c b/installer/installer-linux.c
new file mode 100644
index 0000000..316a5c6
--- /dev/null
+++ b/installer/installer-linux.c
@@ -0,0 +1,1676 @@
+// Copyright 2011 INDILINX Co., Ltd.
+//
+// This file is part of Jasmine.
+//
+// Jasmine is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Jasmine is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Jasmine. See the file COPYING.
+// If not, see .
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "jasmine.h"
+#include "rom.h"
+#include "ata_7.h"
+
+#define PAUSE { printf("press any key to continue"); getchar(); printf("\n"); fflush(stdin); fflush(stdout); }
+
+#define FW_BUF_BYTES (96 * 1024)
+
+#define BLANK_CHK_BYTES 16
+
+#define SCAN_LIST_NOT_LOADED 0
+#define SCAN_LIST_OLD 1
+#define SCAN_LIST_NEW 2
+
+#define ERR_CORRUPT (OK + 3)
+#define ERR_BLANK (OK + 4)
+
+#define PGSIZE 4096
+
+typedef int HANDLE;
+
+typedef struct
+{
+ factory_cmd_t fac;
+
+ UINT8 pad[BYTES_PER_SECTOR - sizeof(factory_cmd_t)];
+ scan_list_t scan_list[NUM_BANKS_MAX];
+ UINT8 firmware_image_buf[FW_BUF_BYTES];
+ UINT32 firmware_image_bytes;
+ int handle; // device handle
+ BOOL32 up; // whether initialized
+ UINT32 total_bad_vblks;
+ BOOL8 scan_list_loaded;
+} installer_context_t;
+
+factory_cmd_t* fac;
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#define ASSERT(X) \
+{ \
+ if (!(X)) \
+ { \
+ printf("\ndebug assertion failure\n%s : %d\n", \
+ __FILE__, __LINE__); \
+ fflush(NULL); \
+ getchar(); \
+ exit(0); \
+ } \
+}
+
+#define ERR_EXIT \
+{ \
+ printf("error at %s %u\n", __FILE__, __LINE__); \
+ getchar(); \
+ exit(1); \
+}
+
+void enable_factory_mode(UINT32);
+UINT32 detect_sdram_size();
+UINT32 check_flash_id(UINT16* const id);
+BOOL32 open_target_drv();
+void reset_banks();
+void reset_fctrl(BOOL32 big_ecc);
+BOOL32 init();
+void scan_bad_blks();
+void install();
+BOOL32 erase_flash(UINT32 start_pblk_offset, UINT32 end_pblk_offset);
+BOOL32 load_scan_list_from_nand();
+UINT32 bank_read(UINT32 rbank, UINT32 row, UINT32 num_bytes, UINT8* buf);
+UINT8* get_bsp_intr();
+void print_bank_number(UINT32 rbank);
+void print_scan_list(FILE* file);
+void send_to_dev(void* const buf, UINT32 const sect_cnt);
+void recv_from_dev(void* const buf, UINT32 const lba, UINT32 const sect_cnt);
+void save_scan();
+BOOL32 load_scan_list_from_file();
+void ftl_install_mapping_table(); // FTL should provide the function that creates initial mapping table.
+
+UINT8 GETCH(char* msg, char* list);
+
+enum { FLASH_ID_OK, FLASH_ID_VOID, FLASH_ID_ERROR };
+
+
+const UINT8 c_bank_map[NUM_BANKS] = BANK_MAP;
+
+installer_context_t* hc;
+
+UINT8 GETCH(char* msg, char* list)
+{
+ UINT32 i;
+
+ if (msg)
+ printf("%s", msg);
+
+ while (1)
+ {
+ char ch = (char) getchar();
+
+ if (ch >= 'A' && ch <= 'Z')
+ {
+ ch -= 'A' - 'a';
+ }
+
+ if (list == NULL)
+ return (UINT8) ch;
+ else
+ {
+ for (i = 0; i < strlen(list); i++)
+ {
+ if (list[i] == ch)
+ {
+ printf("%c\n", ch);
+ fflush(stdin);
+ fflush(stdout);
+ return (UINT8) ch;
+ }
+ }
+ }
+ }
+}
+
+void recv_from_dev(void* const buf, UINT32 const lba, UINT32 const sect_cnt)
+{
+ ssize_t rv;
+ UINT8* buf_ptr = (UINT8*) buf;
+ UINT32 remain = sect_cnt;
+
+ if (((uintptr_t) buf & (BYTES_PER_SECTOR-1)) != 0)
+ {
+ printf("ERROR: buffer address is not aligned\n");
+ ERR_EXIT;
+ }
+
+ lseek(hc->handle, lba * BYTES_PER_SECTOR, SEEK_SET);
+
+ while (remain != 0)
+ {
+ UINT32 num_sectors = MIN(remain, 256);
+ ssize_t nbytes = num_sectors * BYTES_PER_SECTOR;
+
+ if ((rv = read(hc->handle, buf_ptr, nbytes)) != nbytes)
+ {
+ printf("\nERROR: no response from drive\t\t\n");
+ ERR_EXIT;
+ }
+
+ buf_ptr += nbytes;
+ remain -= num_sectors;
+ }
+}
+
+#define MAX_SECTORS 256
+
+void send_to_dev(void* const buf, UINT32 const sect_cnt)
+{
+ ssize_t rv;
+ void* aligned_buf = memalign(PGSIZE, MAX_SECTORS * BYTES_PER_SECTOR);
+
+ if (buf != NULL)
+ {
+ UINT8* buf_ptr = (UINT8*) buf;
+ UINT32 remain = sect_cnt;
+
+ if (sect_cnt == 0)
+ {
+ ERR_EXIT;
+ }
+
+ if (ROM_DRAM_BUF_LBA + sect_cnt >= DRAM_SIZE)
+ {
+ printf("ERROR: sect_cnt is too large\n");
+ ERR_EXIT;
+ }
+
+ lseek(hc->handle, ROM_DRAM_BUF_LBA * BYTES_PER_SECTOR, SEEK_SET);
+
+ while (remain != 0)
+ {
+ UINT32 num_sectors = MIN(remain, MAX_SECTORS);
+ ssize_t nbytes = num_sectors * BYTES_PER_SECTOR;
+
+ memcpy(aligned_buf, buf_ptr, nbytes);
+ if ((rv = write(hc->handle, aligned_buf, nbytes)) != nbytes)
+ {
+ printf("ERROR: no response from drive\t\t\n");
+ ERR_EXIT;
+ }
+
+ buf_ptr += nbytes;
+ remain -= num_sectors;
+ }
+ }
+
+ srand((UINT32) time(NULL));
+
+ fac->key_1 = rand();
+ fac->key_2 = 0 - fac->key_1;
+
+ lseek(hc->handle, 0, SEEK_SET);
+
+ memcpy(aligned_buf, &hc->fac, BYTES_PER_SECTOR);
+ if ((rv = write(hc->handle, aligned_buf, BYTES_PER_SECTOR)) != BYTES_PER_SECTOR)
+ {
+ printf("ERROR: no response from drive\t\t\n");
+ ERR_EXIT;
+ }
+}
+
+void print_bank_number(UINT32 rbank)
+{
+ rbank = rbank;
+ printf("bank %u=%c%u\t\n", rbank, rbank % NUM_CHNLS_MAX + 'A', rbank / NUM_CHNLS_MAX);
+}
+
+UINT32 check_flash_id(UINT16* const id)
+{
+ UINT32 maker_code = 0;
+ UINT32 id_data;
+ UINT32 i;
+ UINT32 same_count;
+
+ id_data = 0;
+ same_count = 0;
+
+ for (i = 0; i < 5; i++)
+ {
+ UINT32 high = id[i] & 0xFF;
+ UINT32 low = (id[i] >> 8) & 0xFF;
+
+ if (high != low)
+ {
+ return FLASH_ID_ERROR; // different ID output from high chip and from low chip
+ }
+
+ if (id[i] == id[0])
+ {
+ same_count++;
+ }
+
+ if (i == 0)
+ {
+ maker_code = low;
+ }
+ else
+ {
+ id_data = id_data | (low << (8*(i - 1)));
+ }
+ }
+
+ if (same_count == 5)
+ {
+ return FLASH_ID_VOID; // chip does not exist
+ }
+
+ if (maker_code != NAND_SPEC_MF)
+ {
+ return FLASH_ID_ERROR;
+ }
+ else if ((id_data & NAND_SPEC_ID_MASK) != NAND_SPEC_ID)
+ {
+ return FLASH_ID_ERROR;
+ }
+ else
+ {
+ return FLASH_ID_OK;
+ }
+}
+
+BOOL32 init()
+{
+ UINT32 i;
+ UINT8* buf;
+ UINT32 rbank;
+ UINT32 bank_bmp;
+
+ if (hc->handle == -1)
+ {
+ printf("ERROR: target device not opened\n");
+ return FAIL;
+ }
+
+ buf = (UINT8*) memalign(PGSIZE, BYTES_PER_SECTOR);
+
+ reset_fctrl(FALSE);
+ reset_banks();
+
+ bank_bmp = 0;
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ // flash -> SRAM buffer
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_READ_ID;
+ fac->rbank = rbank;
+ fac->option = 0;
+ fac->dma_addr = INVALID32;
+ fac->dma_cnt = 16;
+ fac->col = 0;
+ fac->row_l = 0;
+ fac->row_h = 0;
+ fac->wait = TRUE;
+ fac->clear = TRUE;
+ send_to_dev(NULL, 0);
+
+ // SRAM buffer -> DRAM_BASE
+ fac->cmd = ROM_CMD_MU_CMD;
+ fac->subcmd = MU_CMD_COPY;
+ fac->mu_src_addr = INVALID32;
+ fac->mu_dst_addr = DRAM_BASE;
+ fac->mu_size = 16;
+ send_to_dev(NULL, 0);
+
+ // DRAM_BASE -> host
+ recv_from_dev(buf, 0, 1);
+
+ printf("bank %02u(%c%u) low:", rbank, rbank % NUM_CHNLS_MAX + 'A', rbank / NUM_CHNLS_MAX);
+
+ for (i = 0; i < 5; i++)
+ printf(" %02X", buf[i*2]);
+
+ printf(" high:");
+
+ for (i = 0; i < 5; i++)
+ printf(" %02X", buf[i*2 + 1]);
+
+ printf("\n");
+
+ if (check_flash_id((UINT16*) buf) == FLASH_ID_OK)
+ {
+ bank_bmp |= (1 << rbank);
+ }
+ }
+
+ printf("bank_bmp = %08X\n", bank_bmp);
+
+ free(buf);
+
+ hc->up = FALSE;
+
+ if (bank_bmp == BANK_BMP)
+ {
+ hc->up = TRUE;
+ }
+ else if ((bank_bmp & BANK_BMP) == BANK_BMP)
+ {
+ printf("WARNING: Flash configuration mismatch. The firmware was built for %08X.\n", BANK_BMP);
+
+ if (GETCH("Proceed anyway?", "yn") == 'y')
+ {
+ hc->up = TRUE;
+ }
+ }
+ else
+ {
+ printf("ERROR: Flash configuration mismatch. The firmware was built for %08X.\n", BANK_BMP);
+ }
+
+ return hc->up ? OK : FAIL;
+}
+
+void enable_factory_mode(UINT32 sdram_size)
+{
+ UINT32 sum, i;
+ factory_cmd_t* fac = &hc->fac;
+ UINT32* const buf = (UINT32*) fac;
+
+ for (i = 0; i < BYTES_PER_SECTOR / sizeof(UINT32); i++)
+ {
+ buf[i] = 0;
+ }
+
+ fac->sdram_signature_1 = 0x0c23bb10;
+ fac->sdram_signature_2_ptr = (BYTES_PER_SECTOR - 1) / sizeof(UINT32);
+ *(buf + fac->sdram_signature_2_ptr) = SDRAM_PARAM_SIGNATURE - fac->sdram_signature_1;
+
+ fac->cmd = ROM_CMD_FACTORY_MODE;
+
+ if(sdram_size == SDRAM_16MB)
+ fac->sdram.init = SDRAM_PARAM_75_16_INIT ;
+ else if(sdram_size == SDRAM_32MB)
+ fac->sdram.init = SDRAM_PARAM_75_32_INIT ;
+ else if(sdram_size == SDRAM_64MB)
+ fac->sdram.init = SDRAM_PARAM_75_64_INIT ;
+ else
+ fac->sdram.init = SDRAM_PARAM_ROM_CODE_INIT ;
+
+ fac->sdram.refresh = SDRAM_PARAM_ROM_CODE_REFRESH;
+ fac->sdram.timing = SDRAM_PARAM_ROM_CODE_TIMING;
+ fac->sdram.mrs = SDRAM_PARAM_ROM_CODE_MRS;
+ fac->sdram.bytes = DRAM_SIZE;
+
+ fac->key_1 = 0;
+ fac->key_2 = 0;
+ fac->last_member = 0;
+ sum = 0;
+
+ for (i = 0; i < BYTES_PER_SECTOR / sizeof(UINT32); i++)
+ {
+ sum += buf[i];
+ }
+
+ fac->last_member = FACTORY_CMD_SIGNATURE - sum;
+
+ send_to_dev(NULL, 0);
+
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = PHY_DEBUG;
+ fac->mem_val = 0x40000139;
+ send_to_dev(NULL, 0);
+
+ usleep(600 * 1000); /* 600 ms */
+
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = PHY_DEBUG;
+ fac->mem_val = 0x400A040E;
+ send_to_dev(NULL, 0);
+
+ usleep(600 * 1000); /* 600 ms */
+}
+
+
+#define SDRAM_SIZE_TEST_16_VAL 0x16161616
+#define SDRAM_SIZE_TEST_32_VAL 0x32323232
+#define SDRAM_SIZE_TEST_BASE 0x40000800
+#define SDRAM_SIZE_16_TEST_BASE 0x40000C00
+#define SDRAM_SIZE_32_TEST_BASE 0x42000800
+
+UINT32 detect_sdram_size(void)
+{
+ UINT8* buf = (UINT8*) memalign(PGSIZE, 64 * 1024 * 1024);
+ UINT32 read_value;
+ UINT32 sdram_size = INVALID32;
+
+ if (buf == NULL)
+ {
+ printf("ERROR: memory allocation failure\n");
+ ERR_EXIT
+ }
+
+ /////////////////////////////////////////
+ // Detect 16MB Memory
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = SDRAM_SIZE_TEST_BASE;
+ fac->mem_val = 0x0;
+ send_to_dev(NULL, 0);
+
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = SDRAM_SIZE_16_TEST_BASE;
+ fac->mem_val = SDRAM_SIZE_TEST_16_VAL;
+ send_to_dev(NULL, 0);
+
+ // Check if above write operation affects test base address
+ fac->cmd = ROM_CMD_READ_MEM;
+ fac->mem_addr = SDRAM_SIZE_TEST_BASE;
+ send_to_dev(NULL, 0);
+ recv_from_dev(buf, 0, 1);
+ read_value = *(UINT32 *)buf;
+
+ if(SDRAM_SIZE_TEST_16_VAL == read_value)
+ {
+ sdram_size = SDRAM_16MB;
+ goto detect_end;
+ }
+
+ /////////////////////////////////////////
+ // Detect 32MB Memory
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = SDRAM_SIZE_TEST_BASE;
+ fac->mem_val = 0x0;
+ send_to_dev(NULL, 0);
+
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = SDRAM_SIZE_32_TEST_BASE;
+ fac->mem_val = SDRAM_SIZE_TEST_32_VAL;
+ send_to_dev(NULL, 0);
+
+ // At first, read back written data
+ fac->cmd = ROM_CMD_READ_MEM;
+ fac->mem_addr = SDRAM_SIZE_32_TEST_BASE;
+ send_to_dev(NULL, 0);
+ recv_from_dev(buf, 0, 1);
+ read_value = *(UINT32 *)buf;
+
+ if(SDRAM_SIZE_TEST_32_VAL != read_value)
+ {
+ sdram_size = SDRAM_32MB;
+ goto detect_end;
+ }
+
+ // Check if above write operation affects test base address
+ fac->cmd = ROM_CMD_READ_MEM;
+ fac->mem_addr = SDRAM_SIZE_TEST_BASE;
+ send_to_dev(NULL, 0);
+ recv_from_dev(buf, 0, 1);
+ read_value = *(UINT32 *)buf;
+
+ if(SDRAM_SIZE_TEST_32_VAL == read_value)
+ {
+ sdram_size = SDRAM_32MB;
+ goto detect_end;
+ }
+
+ sdram_size = SDRAM_64MB;
+
+detect_end:
+
+ free(buf);
+
+ return sdram_size;
+}
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVICE_ID "YATAPDONG"
+#define HDIO_GET_IDENTITY 0x030d
+#define HDIO_GETGEO 0x0301
+
+/* lifted from util-linux */
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders; /* truncated */
+ unsigned long start;
+};
+
+int is_whole_disk_fd(int fd)
+{
+ struct hd_geometry geometry;
+ int i = 0;
+
+ if (fd != -1)
+ i = ioctl(fd, HDIO_GETGEO, &geometry);
+ if (i == 0)
+ return geometry.start == 0;
+ return 0;
+}
+
+int is_whole_disk(const char *name)
+{
+ int fd = -1, res = 0;
+ fd = open(name, O_RDONLY);
+ if (fd != -1)
+ res = is_whole_disk_fd(fd);
+
+ if (fd != -1)
+ close(fd);
+ return res;
+}
+
+int is_jasmine(const char *name)
+{
+ uint16_t id[256];
+ int fd;
+
+ if ((fd = open(name, O_RDONLY|O_NONBLOCK)) < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (ioctl(fd, HDIO_GET_IDENTITY, id) < 0) {
+ perror("ioctl");
+ exit(1);
+ }
+
+ close(fd);
+ return strncmp((char *)&id[27], DEVICE_ID, strlen(DEVICE_ID)) == 0;
+}
+
+BOOL32 open_target_drv()
+{
+ FILE *procpt;
+ char line[128], ptname[128], devname[256];
+ int ma, mi;
+ unsigned long long sz;
+
+ procpt = fopen(PROC_PARTITIONS, "r");
+ if (procpt == NULL) {
+ fprintf(stderr, "cannot open %s\n", PROC_PARTITIONS);
+ exit(1);
+ }
+
+ /* lifted from hdparm.c */
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf (line, " %d %d %llu %128[^\n ]",
+ &ma, &mi, &sz, ptname) != 4)
+ continue;
+ snprintf(devname, sizeof(devname), "/dev/%s", ptname);
+ if (is_whole_disk(devname) && is_jasmine(devname)) {
+ if ((hc->handle = open(devname, O_RDWR|O_DIRECT|O_SYNC)) < 0) {
+ fprintf(stderr, "failed to open jasmine device");
+ exit(1);
+ }
+ }
+ }
+ fclose(procpt);
+
+ if (hc->handle == -1) {
+ fprintf(stderr, "ERROR: Jasmine not found\n");
+ exit(1);
+ }
+
+ UINT32 sdram_size;
+ printf("enabling factory mode...");
+
+ enable_factory_mode(SDRAM_64MB);
+ sdram_size = detect_sdram_size();
+ printf("\ndetected SDRAM size = %d MB\n", (SDRAM_16MB == sdram_size) ? 16 : ((SDRAM_32MB == sdram_size) ? 32 : 64) );
+
+ if (((DRAM_SIZE == 65075200) && (sdram_size != SDRAM_64MB)) ||
+ ((DRAM_SIZE == 32537600) && (sdram_size != SDRAM_32MB)) ||
+ ((DRAM_SIZE == 16268800) && (sdram_size != SDRAM_16MB)))
+ {
+ printf("ERROR: firmware built for %d MB\n", (DRAM_SIZE == 16268800) ? 16 : ((DRAM_SIZE == 32537600) ? 32 : 64));
+ ERR_EXIT;
+ }
+
+ enable_factory_mode(sdram_size);
+
+ return OK;
+}
+
+void reset_fctrl(BOOL32 strong_ecc)
+{
+ UINT32 nand_cfg_1, nand_cfg_2, ecc_size;
+
+ if (strong_ecc)
+ {
+ ecc_size = 2;
+ }
+ else
+ {
+ #if SPARE_PER_PHYPAGE / SECTORS_PER_PHYPAGE >= 28
+ // RS : 12 symbol correction per sector
+ // BCH : 16 bit correction per sector
+ ecc_size = 2;
+
+ #elif SPARE_PER_PHYPAGE / SECTORS_PER_PHYPAGE >= 23
+ // RS : 12 symbol correction per sector
+ // BCH : 12 bit correction per sector
+ ecc_size = 1;
+
+ #elif SPARE_PER_PHYPAGE / SECTORS_PER_PHYPAGE >= 16
+ // RS : 6 symbol correction per sector
+ // BCH : 8 bit correction per sector
+ ecc_size = 0;
+
+ #else
+ #error("ECC configuration error");
+ #endif
+ }
+
+ nand_cfg_2 = PG_SIZE(SECTORS_PER_PHYPAGE >> 3)
+ | BLK_SIZE(PAGES_PER_VBLK >> 7)
+ | CHK_CMD(NAND_SPEC_MF == NAND_SPEC_TOSHIBA && OPTION_2_PLANE)
+ | CHK_CODE(0xC0)
+ | CHK_MASK(0xC1)
+ | BCH((NAND_SPEC_CELL == NAND_SPEC_CELL_MLC) || strong_ecc)
+ | ECC_SIZE(ecc_size);
+
+ #if FLASH_TYPE == H27UCG8UDMYR || FLASH_TYPE == H27UBG8T2MYR || FLASH_TYPE == H27UDG8VEMYR || \
+ FLASH_TYPE == H27UCG8VFATR || FLASH_TYPE == H27UBG8U5ATR || FLASH_TYPE == H27UBG8T2ATR || \
+ FLASH_TYPE == K9GAG08U0D || FLASH_TYPE == K9LBG08U0D || FLASH_TYPE == K9HCG08U1D || \
+ FLASH_TYPE == K9GBG08U0M || FLASH_TYPE == K9PFG08U5M
+ nand_cfg_1 = 0x18; // 4Xnm process with LGA TYPE
+ #elif NAND_SPEC_MF == NAND_SPEC_SAMSUNG || NAND_SPEC_MF == NAND_SPEC_HYNIX
+ {
+ #if NAND_SPEC_DIE == NAND_SPEC_DIE_2 && NAND_SPEC_PLANE == NAND_SPEC_PLANE_2 && OPTION_2_PLANE
+ {
+ #if ROWS_PER_BANK == 262144
+ nand_cfg_1 = 0x10 | (1 << 12); // A30
+
+ #elif ROWS_PER_BANK == 524288
+ nand_cfg_1 = 0x10 | (2 << 12); // A31
+
+ #elif ROWS_PER_BANK == 1048576
+ nand_cfg_1 = 0x10 | (3 << 12); // A32
+
+ #elif ROWS_PER_BANK == 2097152
+ nand_cfg_1 = 0x10 | (4 << 12); // A33
+
+ #elif ROWS_PER_BANK == 4194304
+ nand_cfg_1 = 0x10 | (5 << 12); // A34
+
+ #else
+ #error("invalid configuration for 2-plane operation in DDP");
+ #endif
+ }
+ #else
+ nand_cfg_1 = 0x10;
+ #endif
+ }
+ #elif NAND_SPEC_MF == NAND_SPEC_MICRON || NAND_SPEC_MF == NAND_SPEC_INTEL
+ #if NAND_SPEC_READ == NAND_SPEC_READ_CYCLE_2
+ nand_cfg_1 = 0x21; // Micron 2-plane with ONFI
+ #else
+ nand_cfg_1 = 0x11; // Micron 2-plane
+ #endif
+ #elif NAND_SPEC_MF == NAND_SPEC_TOSHIBA
+ #if NAND_SPEC_PLANE == NAND_SPEC_PLANE_2
+ nand_cfg_1 = 0x12 | 0x08; // Toshiba 4Xnm process
+ #else
+ nand_cfg_1 = 0x12; // Toshiba copyback
+ #endif
+ #else
+ nand_cfg_1 = 0x10;
+ #endif
+
+ fac->cmd = ROM_CMD_RESET_FLASH;
+ fac->nand_cfg_2 = nand_cfg_2;
+ fac->time_cycle = FLASH_PARAM_TIMECYCLE_SAFE;
+ fac->nand_cfg_1 = nand_cfg_1;
+
+ send_to_dev(NULL, 0);
+
+ fac->cmd = ROM_CMD_WRITE_MEM;
+ fac->mem_addr = SATA_BUF_PAGE_SIZE;
+ fac->mem_val = BYTES_PER_PAGE;
+ send_to_dev(NULL, 0);
+}
+
+void reset_banks()
+{
+ UINT32 rbank;
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_GENERIC;
+ fac->rbank = rbank;
+ fac->col = 0xFF;
+ fac->option = 0;
+ fac->wait = TRUE;
+ fac->clear = TRUE;
+
+ send_to_dev(NULL, 0);
+ }
+
+ usleep(100 * 1000); /* 100ms */
+}
+
+void print_scan_list(FILE* file)
+{
+ UINT32 i, num_bad_pblks, num_bad_pblks_h, num_bad_pblks_l, rbank, num_total_entries;
+
+ num_total_entries = 0;
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ num_total_entries += hc->scan_list[rbank].num_entries;
+ }
+
+ fprintf(file, "list of initial bad blocks :\n");
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ num_bad_pblks = hc->scan_list[rbank].num_entries;
+
+ num_bad_pblks_l = 0;
+
+ for (i = 0; i < num_bad_pblks; i++)
+ {
+ if ((hc->scan_list[rbank].list[i] & 0x8000) == 0)
+ num_bad_pblks_l++;
+ }
+
+ fprintf(file, "\nbank %u(%c%u) L: %u of %u (%.2f%%)\n", rbank, rbank % NUM_CHNLS_MAX + 'A', rbank / NUM_CHNLS_MAX,
+ num_bad_pblks_l, PBLKS_PER_BANK, (double) num_bad_pblks_l / PBLKS_PER_BANK * 100);
+
+ for (i = 0; i < num_bad_pblks; i++)
+ {
+ if ((hc->scan_list[rbank].list[i] & 0x8000) == 0)
+ fprintf(file, "%u ", hc->scan_list[rbank].list[i]);
+ }
+
+ num_bad_pblks_h = 0;
+
+ for (i = 0; i < num_bad_pblks; i++)
+ {
+ if (hc->scan_list[rbank].list[i] & 0x8000)
+ num_bad_pblks_h++;
+ }
+
+ fprintf(file, "\nbank %u(%c%u) H: %u of %u (%.2f%%)\n", rbank, rbank % NUM_CHNLS_MAX + 'A', rbank / NUM_CHNLS_MAX,
+ num_bad_pblks_h, PBLKS_PER_BANK, (double) num_bad_pblks_h / PBLKS_PER_BANK * 100);
+
+ for (i = 0; i < num_bad_pblks; i++)
+ {
+ if (hc->scan_list[rbank].list[i] & 0x8000)
+ fprintf(file, "%u ", hc->scan_list[rbank].list[i] & (~0x8000));
+ }
+
+ if (num_bad_pblks_l + num_bad_pblks_h != num_bad_pblks)
+ {
+ GETCH("\nWARNING: scan list seems to be corrupt for this bank\n", NULL);
+ }
+ }
+
+ fprintf(file, "\n");
+}
+
+void scan_bad_blks(void)
+{
+ UINT32 total_bad_blk_entries;
+ UINT32* input;
+ UINT32* buf;
+ UINT32 total_bad_blks;
+
+ if (hc->up == FALSE)
+ {
+ printf("ERROR: not initialized\n");
+ return;
+ }
+
+ buf = (UINT32*) memalign(PGSIZE, ROM_SCAN_BUF_SIZE);
+ input = buf;
+
+ fac->start_blk = 1;
+ fac->blks_per_bank = PBLKS_PER_BANK;
+
+ fac->shift_rpb = ffs(PAGES_PER_VBLK) - 1;
+
+ fac->cmd = ROM_CMD_SCAN;
+ fac->col = BYTES_PER_PHYPAGE; // the offset of the first byte of the spare area
+ fac->dma_cnt = 4; // number of bytes to inspect
+ fac->rows_per_blk = PAGES_PER_VBLK;
+ fac->bank_bmp = BANK_BMP;
+
+ send_to_dev(NULL, 0);
+
+ usleep(1000 * 1000);
+
+ recv_from_dev(buf, ROM_DRAM_BUF_LBA, ROM_SCAN_BUF_SIZE / BYTES_PER_SECTOR);
+
+ // The output from the ROM code (scan result) is going to be converted into scan list.
+
+ total_bad_blk_entries = *input++; // bad block #k in high chip and bad block #k in low chip are counted as one
+ total_bad_blks = *input++; // bad block #k in high chip and bad block #k in low chip are counted as two
+
+ printf("total number of bad blocks reported = %u\n", total_bad_blks);
+
+ if (total_bad_blks > (ROM_SCAN_BUF_SIZE / sizeof(UINT32) - 2))
+ {
+ printf("ERROR: Too many bad blocks. Device-side buffer can hold %lu entries.\n",
+ ROM_SCAN_BUF_SIZE / sizeof(UINT32) - 2);
+
+ ERR_EXIT;
+ }
+
+ while (total_bad_blk_entries-- != 0)
+ {
+ UINT32 list_entry = *input++;
+ UINT32 rbank = (list_entry >> 24) & 0x3F;
+ UINT32 blk = list_entry & 0x00FFFFFF;
+
+ if ((list_entry & 0xC0000000) == 0)
+ {
+ printf("ERROR: scan result has error\n");
+ ERR_EXIT;
+ }
+ else
+ {
+ if (list_entry & 0x80000000)
+ {
+ UINT32 num_entries = hc->scan_list[rbank].num_entries++;
+ hc->scan_list[rbank].list[num_entries] = ((UINT16) blk) | 0x8000;
+ }
+
+ if (list_entry & 0x40000000)
+ {
+ UINT32 num_entries = hc->scan_list[rbank].num_entries++;
+ hc->scan_list[rbank].list[num_entries] = (UINT16) blk;
+ }
+ }
+ }
+
+ if (*input != 0xFFFFFFFF)
+ {
+ // This should not be the case, because the ROM code always puts 0xFFFFFFFF at the end of scan result.
+
+ printf("ERROR: termination mark not found from list end\n");
+ ERR_EXIT;
+ }
+
+ hc->scan_list_loaded = TRUE;
+
+ free(buf);
+}
+
+BOOL32 erase_flash(UINT32 start_pblk_offset, UINT32 end_pblk_offset)
+{
+ UINT32 pblk_offset;
+ UINT32 rbank;
+
+ if (end_pblk_offset == (UINT32) -1)
+ end_pblk_offset = PBLKS_PER_BANK;
+
+ for (pblk_offset = start_pblk_offset; pblk_offset <= end_pblk_offset; pblk_offset++)
+ {
+ BOOL8 erased[NUM_BANKS_MAX];
+
+ fac->clear = TRUE;
+
+ printf("erasing block %u\r", pblk_offset);
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ UINT32 i;
+ BOOL32 bad_h, bad_l;
+
+ erased[rbank] = FALSE;
+
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_ERASE;
+ fac->rbank = rbank;
+ fac->option = 0;
+ fac->col = 0;
+ fac->wait = FALSE;
+ fac->row_l = pblk_offset * PAGES_PER_VBLK;
+ fac->row_h = pblk_offset * PAGES_PER_VBLK;
+
+ bad_h = bad_l = FALSE;
+
+ for (i = 0; i < hc->scan_list[rbank].num_entries; i++)
+ {
+ UINT16 bad_pblk_offset = hc->scan_list[rbank].list[i] & (~0x8000);
+ UINT16 high_chip_flag = hc->scan_list[rbank].list[i] & 0x8000;
+
+ if (pblk_offset == bad_pblk_offset)
+ {
+ if (high_chip_flag)
+ bad_h = TRUE;
+ else
+ bad_l = TRUE;
+ }
+ }
+
+ if (bad_h && bad_l)
+ {
+ // If both of high chip and low chip have bad blocks at the same block address,
+ // we erase nothing at this iteration.
+
+ continue;
+ }
+
+ // If either one of high chip or low chip has a bad block, we do not erase it.
+ fac->option = (bad_h * 0x20) | (bad_l * 0x10);
+
+ send_to_dev(NULL, 0);
+
+ fac->clear = FALSE;
+
+ erased[rbank] = TRUE;
+ }
+ }
+
+ fac->cmd = ROM_CMD_FLASH_FINISH;
+ send_to_dev(NULL, 0);
+
+ printf("\t\t\t\t\n");
+
+ return OK;
+}
+
+void save_scan()
+{
+ UINT32 rbank;
+ FILE* file;
+ char directory[100];
+ char file_name[150];
+
+ if (hc->scan_list_loaded == FALSE)
+ {
+ printf("ERROR: have nothing to save\n");
+ return;
+ }
+
+ printf("new directory = ");
+ scanf("%s", directory);
+
+ if (mkdir(directory, 0755) == -1)
+ {
+ printf("ERROR: directory creation failed\n");
+ return;
+ }
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ UINT32 temp;
+ UINT32 size;
+
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ sprintf(file_name, "%s/scan_%u.bin", directory, rbank);
+
+ file = fopen(file_name, "w+b");
+
+ if (file == NULL)
+ {
+ ERR_EXIT;
+ }
+
+ size = SCAN_LIST_SIZE;
+ temp = fwrite((void*) (hc->scan_list + rbank), 1, size, file);
+
+ if (temp != size)
+ {
+ ERR_EXIT;
+ }
+
+ fclose(file);
+ }
+
+ sprintf(file_name, "%s\\scan.txt", directory);
+
+ file = fopen(file_name, "w+t");
+
+ if (file == NULL)
+ {
+ ERR_EXIT;
+ }
+
+ print_scan_list(file);
+
+ fclose(file);
+}
+
+BOOL32 load_scan_list_from_file()
+{
+ UINT32 rbank;
+ FILE* file;
+ char directory[100];
+ char file_name[150];
+
+ printf("directory = ");
+ scanf("%s", directory);
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ sprintf(file_name, "%s/scan_%u.bin", directory, rbank);
+
+ file = fopen(file_name, "rb");
+
+ if (file == NULL)
+ {
+ printf("ERROR: cannot open file %s\n", file_name);
+ return FAIL;
+ }
+
+ fread((void*) (hc->scan_list + rbank), 1, SCAN_LIST_SIZE, file);
+
+ fclose(file);
+
+ hc->scan_list_loaded = TRUE;
+ }
+
+ print_scan_list(stdout);
+
+ return OK;
+}
+
+BOOL32 load_scan_list_from_nand(void)
+{
+ UINT32 rbank, page_read_result, result;
+ UINT32* buf;
+
+ if (hc->up == FALSE)
+ {
+ printf("ERROR: not initialized\n");
+ return FAIL;
+ }
+
+ result = OK;
+ buf = (UINT32*) memalign(PGSIZE, BYTES_PER_SMALL_PAGE);
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ page_read_result = bank_read(rbank, SCAN_LIST_PAGE_OFFSET, SCAN_LIST_SIZE, (UINT8*) buf);
+
+ if (page_read_result == OK)
+ {
+ printf("scan list found on ");
+ print_bank_number(rbank);
+
+ memcpy(hc->scan_list + rbank, buf, SCAN_LIST_SIZE);
+ }
+ else if (page_read_result == ERR_CORRUPT)
+ {
+ printf("ERROR: corrupted scan list (or unknown type of data) on ");
+ print_bank_number(rbank);
+
+ result = FAIL;
+ }
+ else
+ {
+ printf("ERROR: cannot find scan list on ");
+ print_bank_number(rbank);
+ result = FAIL;
+ }
+ }
+
+ free(buf);
+
+ if (result == OK)
+ {
+ hc->scan_list_loaded = TRUE;
+ }
+
+ return result;
+}
+
+UINT32 bank_read(UINT32 rbank, UINT32 row, UINT32 num_bytes, UINT8* buf)
+{
+ if (hc->up == FALSE)
+ {
+ printf("ERROR: not initialized\n");
+ return FAIL;
+ }
+
+ if (rbank == INVALID32)
+ {
+ printf("bank = ");
+ scanf("%u", &rbank);
+
+ printf("row (real) = ");
+ scanf("%u", &row);
+
+ printf("bytes = ");
+ scanf("%u", &num_bytes);
+ }
+
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ {
+ printf("ERROR: specified bank does not exist\n");
+ print_bank_number(rbank);
+ return FAIL;
+ }
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_COL_ROW_READ_OUT;
+ fac->rbank = rbank;
+ fac->option = FO_E;
+ fac->dma_addr = ROM_DRAM_BUF_ADDR;
+ fac->dma_cnt = num_bytes;
+ fac->col = 0;
+ fac->row_l = row;
+ fac->row_h = row;
+ fac->wait = TRUE;
+ fac->clear = TRUE;
+ send_to_dev(NULL, 0);
+
+ UINT8* bsp_intr = get_bsp_intr();
+
+ recv_from_dev(buf, ROM_DRAM_BUF_LBA, num_bytes / BYTES_PER_SECTOR);
+
+ if (bsp_intr[rbank] & FIRQ_DATA_CORRUPT)
+ {
+ return ERR_CORRUPT;
+ }
+ else if (bsp_intr[rbank] & FIRQ_ALL_FF)
+ {
+ return ERR_BLANK;
+ }
+ else
+ {
+ return OK;
+ }
+}
+
+UINT8* get_bsp_intr()
+{
+ static UINT32 bsp_intr[8];
+ UINT32 i;
+ UINT32* buf = (UINT32*) memalign(PGSIZE, BYTES_PER_SECTOR);
+
+ for (i = 0; i < NUM_BANKS_MAX; i += 4)
+ {
+ fac->cmd = ROM_CMD_READ_MEM;
+ fac->mem_addr = BSP_INTR_BASE + i;
+ send_to_dev(NULL, 0);
+ recv_from_dev(buf, 0, 1);
+ bsp_intr[i / 4] = *buf;
+ }
+
+ free(buf);
+
+ return (UINT8*) bsp_intr;
+}
+
+static BOOL32 write_to_flash(void* buf, UINT32 rbank, UINT32 page_addr, UINT32 num_bytes)
+{
+ void* read_buf;
+ BOOL32 result = OK;
+ UINT32 num_sectors;
+
+ num_sectors = num_bytes / BYTES_PER_SECTOR;
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_COL_ROW_IN_PROG;
+ fac->rbank = rbank;
+ fac->option = FO_E | FO_B_W_DRDY;
+ fac->dma_addr = ROM_DRAM_BUF_ADDR;
+ fac->dma_cnt = num_bytes;
+ fac->col = 0;
+ fac->row_l = page_addr;
+ fac->row_h = page_addr;
+ fac->wait = TRUE;
+ fac->clear = TRUE;
+
+ send_to_dev(buf, num_sectors);
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_COL_ROW_READ_OUT;
+ fac->rbank = rbank;
+ fac->option = FO_E;
+ fac->dma_addr = ROM_DRAM_BUF_ADDR;
+ fac->dma_cnt = num_bytes;
+ fac->col = 0;
+ fac->row_l = page_addr;
+ fac->row_h = page_addr;
+ fac->wait = TRUE;
+ fac->clear = TRUE;
+
+ send_to_dev(NULL, 0);
+
+ read_buf = memalign(PGSIZE, num_bytes);
+ recv_from_dev(read_buf, ROM_DRAM_BUF_LBA, num_sectors);
+
+ if (memcmp(read_buf, buf, num_bytes) != 0)
+ {
+ FILE* file;
+ char file_name[20];
+
+ printf("\nERROR: data corruption. see good.bin and bad.bin\n");
+ print_bank_number(rbank);
+
+ file = fopen("good.bin", "w+b");
+ fwrite(buf, 1, num_bytes, file);
+ fclose(file);
+
+ sprintf(file_name, "bad%u.bin", rbank);
+ file = fopen(file_name, "w+b");
+ fwrite(read_buf, 1, num_bytes, file);
+ fclose(file);
+
+ result = FAIL;
+ }
+
+ free(read_buf);
+
+ return result;
+}
+
+static BOOL32 install_block_zero(void)
+{
+ UINT32 num_fw_pages, page_offset = NULL, rbank;
+ UINT32* buf;
+ UINT32* read_buf;
+ BOOL32 result;
+ UINT32 const total_bytes = NUM_BANKS_MAX * BYTES_PER_SMALL_PAGE;
+
+ result = OK;
+
+ // STEP 1 - write the scan list into page_offset #0 of block #0 of each bank
+
+ reset_fctrl(FALSE); // scan list is written in normal ECC mode
+
+ read_buf = (UINT32*) memalign(PGSIZE, total_bytes);
+
+ fac->cmd = ROM_CMD_DO_NOTHING;
+ send_to_dev((void*) hc->scan_list, NUM_BANKS_MAX * SECTORS_PER_SMALL_PAGE);
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_COL_ROW_IN_PROG;
+ fac->rbank = rbank;
+ fac->dma_addr = ROM_DRAM_BUF_ADDR + rbank * BYTES_PER_SMALL_PAGE;
+ fac->option = FO_E | FO_B_W_DRDY;
+ fac->dma_cnt = BYTES_PER_SMALL_PAGE;
+ fac->col = 0;
+ fac->row_l = SCAN_LIST_PAGE_OFFSET;
+ fac->row_h = SCAN_LIST_PAGE_OFFSET;
+ fac->wait = FALSE;
+ fac->clear = TRUE;
+ send_to_dev(NULL, 0);
+ }
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ fac->cmd = ROM_CMD_FLASH_CMD;
+ fac->subcmd = FC_COL_ROW_READ_OUT;
+ fac->rbank = rbank;
+ fac->dma_addr = ROM_DRAM_BUF_ADDR + rbank * BYTES_PER_SMALL_PAGE;
+ fac->option = FO_E;
+ fac->dma_cnt = BYTES_PER_SMALL_PAGE;
+ fac->col = 0;
+ fac->row_l = SCAN_LIST_PAGE_OFFSET;
+ fac->row_h = SCAN_LIST_PAGE_OFFSET;
+ fac->wait = FALSE;
+ fac->clear = TRUE;
+ send_to_dev(NULL, 0);
+ }
+
+ fac->cmd = ROM_CMD_FLASH_FINISH;
+ send_to_dev(NULL, 0);
+
+ recv_from_dev(read_buf, ROM_DRAM_BUF_LBA, NUM_BANKS_MAX * SECTORS_PER_SMALL_PAGE);
+
+ if (memcmp(read_buf, (void*) hc->scan_list, total_bytes))
+ {
+ FILE* file;
+
+ printf("\nERROR: data corruption. see good.bin and bad.bin\n");
+
+ file = fopen("good.bin", "w+b");
+ fwrite((void*) hc->scan_list, 1, total_bytes, file);
+ fclose(file);
+
+ file = fopen("bad.bin", "w+b");
+ fwrite(read_buf, 1, total_bytes, file);
+ fclose(file);
+
+ result = FAIL;
+ }
+
+ free(read_buf);
+
+ if (result == FAIL)
+ {
+ return FAIL;
+ }
+
+ // STEP 2 - dummy pages filled with 0xFF
+
+ buf = (UINT32*)memalign(PGSIZE, BYTES_PER_SECTOR);
+ memset(buf, 0xFF, BYTES_PER_SECTOR);
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ for (page_offset = SCAN_LIST_PAGE_OFFSET + 1; page_offset < STAMP_PAGE_OFFSET; page_offset++)
+ {
+ if (write_to_flash(buf, rbank, page_offset, BYTES_PER_SECTOR) == FAIL)
+ {
+ return FAIL;
+ }
+ }
+ }
+
+ // STEP 3 - size information of firmware binary image
+ // This information is used by ROM code while loading the image.
+
+ reset_fctrl(TRUE); // use BCH (16bit/512byte)
+
+ memset(buf, 0, BYTES_PER_SECTOR);
+
+ buf[0] = 0xC0C2E003; // magic number
+ buf[1] = hc->firmware_image_bytes; // size of the image
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ if (write_to_flash(buf, rbank, STAMP_PAGE_OFFSET, BYTES_PER_SECTOR) == FAIL)
+ {
+ result = FAIL;
+ }
+ }
+
+ free(buf);
+
+ if (result == FAIL)
+ {
+ return FAIL;
+ }
+
+ // STEP 4 - firmware binary image
+ //
+ // Due to the way ROM code was implemented, the following three restrictions apply to firmware image:
+ // 1. The image should be written with 16bit/512byte BCH.
+ // 2. The image should start from page_offset #5 of block #0.
+ // 3. Only the first 2KB of each page can be used for storing the image.
+
+ num_fw_pages = (hc->firmware_image_bytes + BYTES_PER_FW_PAGE - 1) / BYTES_PER_FW_PAGE;
+
+ for (rbank = 0; rbank < NUM_BANKS_MAX; rbank++)
+ {
+ if ((BANK_BMP & (1 << rbank)) == 0)
+ continue;
+
+ buf = (UINT32*) hc->firmware_image_buf;
+
+ for (page_offset = FW_PAGE_OFFSET; page_offset < FW_PAGE_OFFSET + num_fw_pages; page_offset++)
+ {
+ if (write_to_flash(buf, rbank, page_offset, BYTES_PER_FW_PAGE) == FAIL)
+ {
+ return FAIL;
+ }
+
+ buf += BYTES_PER_FW_PAGE / sizeof(UINT32);
+ }
+ }
+
+ printf("firmware image written to pages %u through %u\n", FW_PAGE_OFFSET, page_offset - 1);
+
+ reset_fctrl(FALSE);
+
+ return OK;
+}
+
+static BOOL32 load_firmware_image(void)
+{
+ FILE* file;
+ UINT32 num_bytes;
+
+ file = fopen("firmware.bin", "rb");
+
+ if (file == NULL)
+ {
+ printf("ERROR: cannot open firmware.bin for reading\n");
+ return FAIL;
+ }
+
+ num_bytes = fread(hc->firmware_image_buf, 1, FW_BUF_BYTES, file);
+
+ fclose(file);
+
+ if (num_bytes == 0)
+ {
+ printf("ERROR: cannot read firmware.bin\n");
+ return FAIL;
+ }
+
+ if (num_bytes == FW_BUF_BYTES)
+ {
+ printf("ERROR: firmware image too large\n");
+ return FAIL;
+ }
+
+ hc->firmware_image_bytes = num_bytes;
+
+ return OK;
+}
+
+void install(void)
+{
+ if (hc->up == FALSE)
+ {
+ printf("ERROR: target device not initialized\n");
+ return;
+ }
+
+ if (hc->scan_list_loaded == FALSE)
+ {
+ printf("ERROR: scan list not loaded.\n");
+ return;
+ }
+
+ if (load_firmware_image() == FAIL)
+ return;
+
+ if (erase_flash(0, 0) == FAIL)
+ return;
+
+ if (install_block_zero() == FAIL)
+ return;
+
+ //ftl_install_mapping_table();
+
+ fac->cmd = ROM_CMD_RESET;
+ send_to_dev(NULL, 0);
+
+ GETCH("firmware installation complete", NULL);
+
+ exit(0);
+}
+
+enum
+{
+ MENU_INIT = 1,
+ MENU_LOAD_SCAN_DEV,
+ MENU_INSTALL,
+ MENU_SCAN,
+ MENU_ERASE_ALL,
+ MENU_SAVE_SCAN,
+ MENU_LOAD_SCAN,
+ MENU_EXIT,
+ NUM_FAC_MENU_ITEMS
+};
+
+static UINT32 print_menu()
+{
+ char* menu_text[NUM_FAC_MENU_ITEMS];
+
+ memset(menu_text, NULL, NUM_FAC_MENU_ITEMS);
+
+ menu_text[MENU_INIT] = "initialize";
+ menu_text[MENU_SCAN] = "scan init bad blks";
+ menu_text[MENU_LOAD_SCAN_DEV] = "read scan list from flash block 0";
+ menu_text[MENU_ERASE_ALL] = "erase flash all";
+ menu_text[MENU_INSTALL] = "install FW";
+ menu_text[MENU_SAVE_SCAN] = "save scan list to file";
+ menu_text[MENU_LOAD_SCAN] = "read scan list from file";
+ menu_text[MENU_EXIT] = "exit";
+
+ UINT32 i;
+ UINT32 menu_sel;
+
+ fflush(stdin);
+
+ printf("\n");
+
+ for (i = 0; i < NUM_FAC_MENU_ITEMS; i++)
+ {
+ if (menu_text[i] != NULL)
+ {
+ printf("%2u %s\n", i, menu_text[i]);
+ }
+ }
+
+ do
+ {
+ printf("\nselect :");
+ scanf("%u", &menu_sel);
+ }
+ while (menu_sel >= NUM_FAC_MENU_ITEMS);
+
+ printf("%s\n\n", menu_text[menu_sel]);
+
+ return menu_sel;
+}
+
+int main() {
+ hc = malloc(sizeof(installer_context_t));
+ fac = &(hc->fac);
+
+ ASSERT(sizeof(factory_cmd_t) <= BYTES_PER_SECTOR);
+
+ hc->handle = -1;
+ hc->up = FALSE;
+ hc->scan_list_loaded = FALSE;
+
+ memset(hc->scan_list, 0, sizeof(hc->scan_list));
+
+ if (open_target_drv() == FAIL)
+ {
+ return 1;
+ }
+
+ while (1)
+ {
+ UINT32 menu_sel;
+
+ menu_sel = print_menu();
+
+ if (menu_sel == MENU_EXIT)
+ break;
+
+ switch (menu_sel)
+ {
+ case MENU_INIT:
+ init();
+ break;
+
+ case MENU_SCAN:
+ scan_bad_blks();
+ break;
+
+ case MENU_LOAD_SCAN_DEV:
+ load_scan_list_from_nand();
+ break;
+
+ case MENU_ERASE_ALL:
+
+ if (hc->scan_list_loaded)
+ {
+ if (GETCH("WARNING: All the blocks will be erased.\nScan list will also be lost.\nContinue?", "yn") == 'y')
+ {
+ erase_flash(0, (UINT32)-1);
+ }
+ }
+ else
+ {
+ if (GETCH("WARNING: All the blocks will be erased.\nBecause you have not read a scan list,\ninitial bad blocks will also be erased.\nContinue?", "yn") == 'y')
+ {
+ erase_flash(0, (UINT32)-1);
+ }
+ }
+ break;
+
+ case MENU_INSTALL:
+ install();
+ break;
+
+ case MENU_SAVE_SCAN:
+ save_scan();
+ break;
+
+ case MENU_LOAD_SCAN:
+ load_scan_list_from_file();
+ break;
+
+ }
+ }
+
+ if (hc->handle != -1)
+ {
+ close(hc->handle);
+ }
+
+ free(hc);
+
+ return 0;
+}
+
diff --git a/target_spw/syscalls.c b/target_spw/syscalls.c
new file mode 100644
index 0000000..a9326b0
--- /dev/null
+++ b/target_spw/syscalls.c
@@ -0,0 +1,15 @@
+int _close(int file) {
+ return -1;
+}
+
+int _lseek(int file, int ptr, int dir) {
+ return 0;
+}
+
+int _write(int file, char *ptr, int len) {
+ return 0;
+}
+
+int _read(int file, char *ptr, int len) {
+ return 0;
+}