/* SPDX-License-Identifier: GPL-2.0 */ #define _NCFB8_C_ #include "../../nfd/nand_osal_for_linux.h" /*#include "../nand_boot.h"*/ #include "../nand-partition3/sunxi_nand_boot.h" #include "../nand_physic_interface.h" #include "rawnand_chip.h" #include "controller/ndfc_ops.h" #include "controller/ndfc_timings.h" #include "rawnand.h" #include "rawnand_base.h" #include "rawnand_debug.h" #include "rawnand_ids.h" #include "rawnand_readretry.h" #include "../version.h" #include "rawnand_boot.h" /*#include */ /*int small_nand_seed; //small nand random seed flag*/ static __u32 SECURE_FLAG; u32 _cal_sum(u32 *mem_base, u32 size) { u32 count, sum; u32 *buf; count = size >> 2; sum = 0; buf = (__u32 *)mem_base; do { sum += *buf++; sum += *buf++; sum += *buf++; sum += *buf++; } while ((count -= 4) > (4 - 1)); while (count-- > 0) sum += *buf++; return sum; } __s32 check_sum(__u32 *mem_base, __u32 size) { __u32 *buf; __u32 count; __u32 src_sum; __u32 sum; boot_file_head_t *bfh; bfh = (boot_file_head_t *)mem_base; /* generate check sum, * get check_sum field from the head of boot0 */ src_sum = bfh->check_sum; /*replace the check_sum field of the boot0 head with STAMP_VALUE*/ bfh->check_sum = STAMP_VALUE; /*unit, 4byte*/ count = size >> 2; sum = 0; buf = (__u32 *)mem_base; do { sum += *buf++; // calculate check sum sum += *buf++; sum += *buf++; sum += *buf++; } while ((count -= 4) > (4 - 1)); while (count-- > 0) sum += *buf++; /*restore the check_sum field of the boot0 head*/ bfh->check_sum = src_sum; //msg("sum:0x%x - src_sum:0x%x\n", sum, src_sum); if (sum == src_sum) return 0; // ok else return 1; // err } int _generate_page_map_tab(__u32 nand_page_size, __u32 copy_cnt, __u32 page_cnt, __u32 *page_addr, __u32 *page_map_tab_addr, __u32 *tab_size) { s32 i, j; u32 max_page_cnt; u32 checksum = 0; u8 *magic = (u8 *)NDFC_PAGE_TAB_MAGIC; u32 *pdst = (u32 *)page_map_tab_addr; boot_file_head_t *bfh = (boot_file_head_t *)page_map_tab_addr; u32 page_tab_size = 0; u32 nand_page_cnt; u32 c, p; if (copy_cnt == 1) { if (nand_page_size != 1024) { RAWNAND_ERR("_cal_page_map_tab, wrong @nand_page_size, %u\n", nand_page_size); return -1; } max_page_cnt = (1024 - NDFC_PAGE_TAB_HEAD_SIZE) / 4; if (page_cnt > max_page_cnt) { RAWNAND_ERR("_cal_page_map_tab, wrong @page_cnt, %u\n", page_cnt); return -1; } // clear to 0x00 for (i = 0; i < 1024 / 4; i++) *(pdst + i) = 0x0; // set page address for (j = 0, i = NDFC_PAGE_TAB_HEAD_SIZE / 4; j < page_cnt; i++, j++) *(pdst + i) = page_addr[j]; // set page table information bfh->platform[0] = page_cnt; //entry_cnt bfh->platform[1] = 1; //entry_cell_cnt bfh->platform[2] = 4; //entry_cell_size, byte bfh->platform[3] = nand_page_size / 512; // set magic //msg("page map table magic: "); for (i = 0; i < sizeof(bfh->magic); i++) { bfh->magic[i] = *(magic + i); //msg("%c", bfh->magic[i]); } //msg("\n"); // set stamp value bfh->check_sum = STAMP_VALUE; // cal checksum checksum = _cal_sum((u32 *)page_map_tab_addr, 1024); bfh->check_sum = checksum; // check if (check_sum((__u32 *)page_map_tab_addr, 1024)) { RAWNAND_ERR("_cal_page_map_tab, checksum error!\n"); return -1; } *tab_size = 1024; } else { page_tab_size = NDFC_PAGE_TAB_HEAD_SIZE + copy_cnt * page_cnt * 4; if (page_tab_size % nand_page_size) nand_page_cnt = page_tab_size / nand_page_size + 1; else nand_page_cnt = page_tab_size / nand_page_size; page_tab_size = nand_page_cnt * nand_page_size; /* clear page table memory spare */ for (i = 0; i < page_tab_size / 4; i++) *(pdst + i) = 0x0; /* set header */ bfh->length = page_tab_size; bfh->platform[0] = page_cnt; //entry_cnt bfh->platform[1] = copy_cnt; //entry_cell_cnt bfh->platform[2] = 4; //entry_cell_size, byte bfh->platform[3] = nand_page_size / 512; //RAWNAND_DBG("length: 0x%x, page_cnt: %d, copy: %d, cell_size: %d Byte\n",bfh->length, bfh->platform[0], bfh->platform[1], bfh->platform[2]); /* fill page address */ for (p = 0; p < page_cnt; p++) { for (c = 0; c < copy_cnt; c++) { i = NDFC_PAGE_TAB_HEAD_SIZE / 4 + p * copy_cnt + c; j = c * page_cnt + p; //j = c*(page_cnt+4) + p; *(pdst + i) = page_addr[j]; } } /* set magic */ //msg("page map table magic: "); for (i = 0; i < sizeof(bfh->magic); i++) { bfh->magic[i] = *(magic + i); //msg("%c", bfh->magic[i]); } //msg("\n"); /* set stamp value */ bfh->check_sum = STAMP_VALUE; /* cal checksum */ checksum = _cal_sum((u32 *)page_map_tab_addr, page_tab_size); bfh->check_sum = checksum; //msg("bfh->check_sum: 0x%x\n", bfh->check_sum); /* check */ if (check_sum((__u32 *)page_map_tab_addr, page_tab_size)) { RAWNAND_ERR("_cal_page_map_tab, checksum error!\n"); return -1; } *tab_size = page_tab_size; } return 0; } int _get_read_retry_table(struct nand_chip_info *nci, u8 *rr_tab) { // boot_file_head_t rr_tab_head={0}; u32 checksum = 0; // u8 *magic = NDFC_RR_TAB_MAGIC; u8 *dummy_magic = (u8 *)NDFC_DMY_TAB_MAGIC; u8 *pdst = (u8 *)rr_tab; boot_file_head_t *bfh = (boot_file_head_t *)rr_tab; __u32 table_size = sizeof(boot_file_head_t); int i; //get read retry cmd data /* clear page table memory spare */ for (i = 0; i < table_size; i++) *(pdst + i) = 0x0; /* set header */ bfh->length = table_size; bfh->platform[3] = nci->sector_cnt_per_page; RAWNAND_DBG("length: 0x%x\n", bfh->length); /* set magic */ RAWNAND_DBG("rr table magic: "); { for (i = 0; i < sizeof(bfh->magic); i++) { bfh->magic[i] = *(dummy_magic + i); RAWNAND_DBG("%c", bfh->magic[i]); } RAWNAND_DBG("\n"); } /* set stamp value */ bfh->check_sum = STAMP_VALUE; /* cal checksum */ checksum = _cal_sum((u32 *)rr_tab, table_size); bfh->check_sum = checksum; RAWNAND_DBG("bfh->check_sum: 0x%x\n", bfh->check_sum); /* check */ if (check_sum((u32 *)rr_tab, table_size)) { RAWNAND_ERR("_cal_rr_tab, checksum error!\n"); return -1; } return 0; } int generic_write_boot0_one_pagetab_4k(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, k, j, count, block; __u8 oob_buf[64]; __u32 tab_size, data_size_per_page; __u32 pages_per_block, copies_per_block; __u32 page_addr; __u32 *pos_data = NULL, *tab = NULL, *rr_tab = NULL; int ret; struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; #if 0 /*A50 FPGA LDPC encode have bug, must to use SDR interface By zzm*/ if (nci->support_toggle_only) { ret = before_update_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("before_update nctri nand interface fail!\n"); return ret; } } else { ret = update_boot0_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("update boot0 nctri nand interface fail!\n"); return ret; } } #endif /*For A50, LDPC*/ /*nci->nctri->channel_sel = 1;*/ /*For R100, BCH*/ //nci->nctri->channel_sel = 0; ndfc_encode_select(nci->nctri); RAWNAND_DBG("burn_boot0_lsb_pagetab_4k mode!\n"); pos_data = (__u32 *)nand_malloc(128 * 4 * BOOT0_MAX_COPY_CNT); if (!pos_data) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for pos_data failed.\n"); goto error; } tab = (__u32 *)nand_malloc(8 * 1024); if (!tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for tab failed.\n"); goto error; } rr_tab = (__u32 *)nand_malloc(8 * 1024); if (!rr_tab) { RAWNAND_ERR(" malloc for rr tab failed.\n"); goto error; } for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } data_size_per_page = 4096; pages_per_block = nci->page_cnt_per_blk; copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY; count = 0; for (i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + aw_nand_info.boot->uboot_start_block); i++) { for (j = 0; j < copies_per_block; j++) { for (k = 8; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { page_addr = i * pages_per_block + j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; if (nci->is_lsb_page((page_addr % pages_per_block))) { *((__u32 *)pos_data + count) = page_addr; count++; if (((count % (len / data_size_per_page)) == 0) && (count != 0)) break; } } } } _generate_page_map_tab(data_size_per_page, copies_per_block * aw_nand_info.boot->uboot_start_block, len / data_size_per_page, pos_data, tab, &tab_size); // get read retry table _get_read_retry_table(nci, (u8 *)rr_tab); block = NAND_BOOT0_BLK_START + counter; RAWNAND_DBG("pagetab boot0 %x \n", block); lnpo.chip = 0; lnpo.block = block; lnpo.page = 0; nand_wait_all_rb_ready(); ret = nci->nand_physic_erase_block(&lnpo); if (ret) { RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block); //return ret; } for (j = 0; j < copies_per_block; j++) { count = 0; for (k = 0; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { lnpo.chip = 0; lnpo.block = block; lnpo.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; lnpo.sdata = oob_buf; lnpo.slen = 64; if (nci->is_lsb_page(lnpo.page)) { if (k < 4) lnpo.mdata = (__u8 *)rr_tab; else if (k < 8) { lnpo.mdata = (__u8 *)tab; } else { lnpo.mdata = (__u8 *)(buf + count * data_size_per_page); count++; } nand_wait_all_rb_ready(); if (nci->nand_write_boot0_page(nci, &lnpo) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } if (count == (len + data_size_per_page - 1) / data_size_per_page) { count = 0; } } } } //nci->nctri->channel_sel = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return 0; error: if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return -1; } int generic_write_boot0_one_1k_mode(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, j; __u8 oob_buf[64]; __u32 pages_per_block = 0, blocks_per_copy = 0, start_block, count = 0; int ret; struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; ndfc_encode_default(nci->nctri); RAWNAND_DBG("burn_boot0_1k mode!\n"); for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } pages_per_block = nci->page_cnt_per_blk; blocks_per_copy = NAND_BOOT0_PAGE_CNT_PER_COPY / pages_per_block; if (NAND_BOOT0_PAGE_CNT_PER_COPY % pages_per_block) blocks_per_copy++; start_block = blocks_per_copy * counter; if ((start_block + blocks_per_copy) > aw_nand_info.boot->uboot_start_block) { return 0; } RAWNAND_DBG("boot0 count %d!\n", counter); count = 0; for (i = start_block; i < (start_block + blocks_per_copy); i++) { lnpo.chip = 0; lnpo.block = i; lnpo.page = 0; nand_wait_all_rb_ready(); ret = nci->nand_physic_erase_block(&lnpo); if (ret) { RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block); //return ret; } for (j = 0; j < pages_per_block; j++) { lnpo.page = j; lnpo.sdata = oob_buf; lnpo.slen = 64; nci->nctri->random_factor = count; nci->nctri->random_factor |= SMALL_CAPACITY_NAND; lnpo.mdata = (__u8 *)(buf + 1024 * count); nand_wait_all_rb_ready(); if (nci->nand_write_boot0_page(nci, &lnpo) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } count++; if (count == len / 1024) { count = 0; } } } nci->nctri->random_factor = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); return 0; error: return -1; } int generic_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { struct nand_chip_info *nci; __u32 pagesize = 0; __u32 pagesperblock = 0; nci = g_nctri->nci; pagesize = nci->sector_cnt_per_page << 9; pagesperblock = nci->page_cnt_per_blk; RAWNAND_DBG("m0 write boot0 one \n"); if ((pagesize >= 8192) && (pagesperblock >= 128)) return generic_write_boot0_one_pagetab_4k(buf, len, counter); else return generic_write_boot0_one_1k_mode(buf, len, counter); return -1; } s32 generic_read_boot0_page_cfg_mode(struct nand_chip_info *nci, struct _nand_physic_op_par *npo, struct boot_ndfc_cfg cfg) { struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq; u32 row_addr = 0, col_addr = 0, blk_mask, config = 0, i; u32 def_spare[32]; s32 ecc_sta = 0, ret = 0; uchar spare[64]; //u32 ecc_mode_temp,page_size_temp,page_size_set; u32 ecc_mode_temp, bitmap = 0; u32 ecc_block_valid, ecc_block_lose; unsigned char *buff = NULL; /*For A50, Buffer Must 32 Bytes align*/ buff = nand_malloc(cfg.page_size_kb << 10); memcpy(buff, npo->mdata, (cfg.page_size_kb << 10)); ecc_block_lose = get_data_block_cnt_for_boot0_ecccode(nci, cfg.ecc_mode); ecc_block_valid = nci->sector_cnt_per_page / 2 - ecc_block_lose; bitmap = ((u32)1 << (ecc_block_valid - 1)) | (((u32)1 << (ecc_block_valid - 1)) - 1); blk_mask = (0x0000FFFF >> (16 - (cfg.page_size_kb << 10) / 2048)); //wait nand ready before read nand_read_chip_status_ready(nci); ecc_mode_temp = ndfc_get_ecc_mode(nci->nctri); nand_enable_chip(nci); ndfc_clean_cmd_seq(cmd_seq); //set ecc and randomizer if (nci->nctri->channel_sel == 0) { /*BCH*/ ndfc_channel_select(nci->nctri, 0); ndfc_set_ecc_mode(nci->nctri, cfg.ecc_mode); ndfc_enable_ecc(nci->nctri, 1, 1); if (nci->nctri->random_factor & SMALL_CAPACITY_NAND) { ndfc_set_rand_seed(nci->nctri, (nci->nctri->random_factor & RANDOM_VALID_BITS)); } else { ndfc_set_rand_seed(nci->nctri, npo->page); } ndfc_enable_randomize(nci->nctri); } else { /*LDPC*/ ndfc_channel_select(nci->nctri, 1); ndfc_enable_decode(nci->nctri); ndfc_enable_ldpc_ecc(nci->nctri, 1); ndfc_enable_randomize(nci->nctri); ndfc_set_new_rand_seed(nci->nctri, npo->page); } //command set_default_batch_read_cmd_seq(cmd_seq); if (cfg.sequence_mode == 1) cmd_seq->ecc_layout = cfg.sequence_mode; //address row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page); if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) { cmd_seq->nctri_cmd[0].cmd_acnt = 4; fill_cmd_addr(col_addr, 2, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr); } else { cmd_seq->nctri_cmd[0].cmd_acnt = 5; fill_cmd_addr(col_addr, 2, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr); } nci->nctri->random_addr_num = nci->random_addr_num; //data cmd_seq->nctri_cmd[0].cmd_trans_data_nand_bus = 1; if (npo->mdata != NULL) { cmd_seq->nctri_cmd[0].cmd_swap_data = 1; cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 1; } else { //don't swap main data with host memory cmd_seq->nctri_cmd[0].cmd_swap_data = 0; cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 0; } cmd_seq->nctri_cmd[0].cmd_direction = 0; //read cmd_seq->nctri_cmd[0].cmd_mdata_addr = buff; if (nci->nctri->channel_sel == 0) { cmd_seq->nctri_cmd[0].cmd_data_block_mask = bitmap; cmd_seq->nctri_cmd[0].cmd_mdata_len = ecc_block_valid << 10; } else { cmd_seq->nctri_cmd[0].cmd_data_block_mask = blk_mask; cmd_seq->nctri_cmd[0].cmd_mdata_len = cfg.page_size_kb << 10; } // RAWNAND_DBG("before send cmd: %d 0x%x 0x%x\n", nci->randomizer, *(nci->nctri->nreg.reg_ecc_ctl), *(nci->nctri->nreg.reg_ecc_sta)); memset(def_spare, 0x99, 128); ndfc_set_spare_data(nci->nctri, (u8 *)def_spare, nci->sdata_bytes_per_page); ndfc_set_user_data_len_cfg_4bytesper1k(nci->nctri, nci->sdata_bytes_per_page); ndfc_set_user_data_len(nci->nctri); if (nci->nctri->channel_sel == 1) { for (i = 0; i < (cfg.page_size_kb / 2) * 4; i += 4) { config |= NDFC_DATA_LEN_DATA_BLOCK << i; } *nci->nctri->nreg.reg_user_data_len_base = config; } ret = batch_cmd_io_send(nci->nctri, cmd_seq); if (ret) { RAWNAND_ERR("m8 read page start, batch cmd io send error!\n"); nand_disable_chip(nci); return ret; } ret = _batch_cmd_io_wait(nci->nctri, cmd_seq); if (ret) { RAWNAND_ERR("m8 read page end, batch cmd io wait error!\n"); goto ERROR; } //check ecc ecc_sta = ndfc_check_ecc(nci->nctri, cfg.page_size_kb); //get spare data ndfc_get_spare_data(nci->nctri, (u8 *)spare, npo->slen); if (npo->slen != 0) { memcpy(npo->sdata, spare, npo->slen); } //don't update ecc status and spare data for boot operation //ret = ndfc_update_ecc_sta_and_spare_data(npo, ecc_sta, spare); ret = ecc_sta; ERROR: ndfc_set_ecc_mode(nci->nctri, ecc_mode_temp); //*(nci->nctri->nreg.reg_ctl) = ((*(nci->nctri->nreg.reg_ctl)) & (~NDFC_PAGE_SIZE)) | ((page_size_temp & 0xf) << 8); // ndfc_set_page_size(nci->nctri,page_size_temp); //disable ecc mode & randomize ndfc_disable_ecc(nci->nctri); ndfc_disable_randomize(nci->nctri); nand_disable_chip(nci); memcpy(npo->mdata, buff, (cfg.page_size_kb << 10)); nand_free(buff); return ret; //ecc status } /***************************************************************************** *Name : *Description : *Parameter : *Return : 0:ok -1:fail *Note : *****************************************************************************/ #define NDFC_VERSION_1 (1) #define NDFC_VERSION_2 (2) int generic_read_boot0_page(struct nand_chip_info *nci, struct _nand_physic_op_par *npo) { struct boot_ndfc_cfg cfg; // struct _nand_physic_op_par lnpo = *npo; if (nci->nctri->channel_sel == 0) //BCH cfg.page_size_kb = ((nci->sector_cnt_per_page) / 2) - 1; else //LDPC cfg.page_size_kb = ((nci->sector_cnt_per_page) / 2) - 2; cfg.ecc_mode = nci->nctri->max_ecc_level; cfg.sequence_mode = 1; return generic_read_boot0_page_cfg_mode(nci, npo, cfg); } s32 generic_write_boot0_page_cfg_mode(struct nand_chip_info *nci, struct _nand_physic_op_par *npo, struct boot_ndfc_cfg cfg) { uchar spare[64]; struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq; u32 row_addr = 0, col_addr = 0, blk_mask, config = 0, i; s32 ret = 0; u32 ecc_mode_temp = 0; u32 ecc_block_valid, ecc_block_lose, bitmap = 0; unsigned char *buff = NULL; if (npo->mdata == NULL) { RAWNAND_ERR("m8 write page start, input parameter error!\n"); return ERR_NO_87; } /*For A50, Buffer Must 32 Bytes align*/ buff = nand_malloc(cfg.page_size_kb << 10); memcpy(buff, npo->mdata, (cfg.page_size_kb << 10)); ecc_block_lose = get_data_block_cnt_for_boot0_ecccode(nci, cfg.ecc_mode); ecc_block_valid = nci->sector_cnt_per_page / 2 - ecc_block_lose; bitmap = ((u32)1 << (ecc_block_valid - 1)) | (((u32)1 << (ecc_block_valid - 1)) - 1); blk_mask = (0x0000FFFF >> (16 - (cfg.page_size_kb << 10) / 2048)); //wait nand ready before write nand_read_chip_status_ready(nci); //get spare data memset(spare, 0xff, 64); if (npo->slen != 0) { memcpy(spare, npo->sdata, npo->slen); } nand_enable_chip(nci); ndfc_clean_cmd_seq(cmd_seq); ndfc_set_spare_data(nci->nctri, (u8 *)spare, nci->sdata_bytes_per_page); ecc_mode_temp = ndfc_get_ecc_mode(nci->nctri); //set ecc and randomizer if (nci->nctri->channel_sel == 0) { /*BCH*/ ndfc_enable_randomize(nci->nctri); if (nci->nctri->random_factor & SMALL_CAPACITY_NAND) { ndfc_set_rand_seed(nci->nctri, (nci->nctri->random_factor & RANDOM_VALID_BITS)); } else { ndfc_set_rand_seed(nci->nctri, npo->page); } ndfc_channel_select(nci->nctri, 0); ndfc_set_ecc_mode(nci->nctri, cfg.ecc_mode); ndfc_enable_ecc(nci->nctri, 1, 1); } else { /*LDPC*/ ndfc_enable_randomize(nci->nctri); ndfc_set_new_rand_seed(nci->nctri, npo->page); ndfc_channel_select(nci->nctri, 1); ndfc_enable_encode(nci->nctri); ndfc_enable_ldpc_ecc(nci->nctri, 1); } nci->nctri->current_op_type = 1; nci->nctri->random_addr_num = nci->random_addr_num; nci->nctri->random_cmd2_send_flag = nci->random_cmd2_send_flag; if (nci->random_cmd2_send_flag) { nci->nctri->random_cmd2 = get_random_cmd2(npo); } //command set_default_batch_write_cmd_seq(cmd_seq, CMD_WRITE_PAGE_CMD1, CMD_WRITE_PAGE_CMD2); if (cfg.sequence_mode == 1) { cmd_seq->ecc_layout = cfg.sequence_mode; } //address row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page); if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) { cmd_seq->nctri_cmd[0].cmd_acnt = 4; fill_cmd_addr(col_addr, 2, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr); } else { cmd_seq->nctri_cmd[0].cmd_acnt = 5; fill_cmd_addr(col_addr, 2, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr); } //data cmd_seq->nctri_cmd[0].cmd_trans_data_nand_bus = 1; cmd_seq->nctri_cmd[0].cmd_swap_data = 1; cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 1; cmd_seq->nctri_cmd[0].cmd_direction = 1; //write cmd_seq->nctri_cmd[0].cmd_mdata_addr = buff; if (nci->nctri->channel_sel == 0) { cmd_seq->nctri_cmd[0].cmd_data_block_mask = bitmap; cmd_seq->nctri_cmd[0].cmd_mdata_len = (ecc_block_valid << 10); } else { cmd_seq->nctri_cmd[0].cmd_data_block_mask = blk_mask; cmd_seq->nctri_cmd[0].cmd_mdata_len = cfg.page_size_kb << 10; } ndfc_set_user_data_len_cfg_4bytesper1k(nci->nctri, nci->sdata_bytes_per_page); ndfc_set_user_data_len(nci->nctri); if (nci->nctri->channel_sel == 1) { for (i = 0; i < (cfg.page_size_kb / 2) * 4; i += 4) { config |= NDFC_DATA_LEN_DATA_BLOCK << i; } *nci->nctri->nreg.reg_user_data_len_base = config; } ret = batch_cmd_io_send(nci->nctri, cmd_seq); if (ret) { RAWNAND_ERR("m8 read page start, batch cmd io send error!\n"); nand_disable_chip(nci); return ret; } ret = _batch_cmd_io_wait(nci->nctri, cmd_seq); if (ret) { RAWNAND_ERR("m8 read page end, batch cmd io wait error!\n"); } ndfc_set_ecc_mode(nci->nctri, ecc_mode_temp); ndfc_disable_ecc(nci->nctri); ndfc_disable_randomize(nci->nctri); nci->nctri->current_op_type = 0; nci->nctri->random_cmd2_send_flag = 0; nand_disable_chip(nci); nand_free(buff); return ret; } /***************************************************************************** *Name : *Description : *Parameter : *Return : 0:ok -1:fail *Note : *****************************************************************************/ int generic_write_boot0_page(struct nand_chip_info *nci, struct _nand_physic_op_par *npo) { struct boot_ndfc_cfg cfg; // truct _nand_physic_op_par lnpo = *npo; if (nci->nctri->channel_sel == 0) //BCH cfg.page_size_kb = ((nci->sector_cnt_per_page) / 2) - 1; else //LDPC cfg.page_size_kb = ((nci->sector_cnt_per_page) / 2) - 2; cfg.ecc_mode = nci->nctri->max_ecc_level; cfg.sequence_mode = 1; return generic_write_boot0_page_cfg_mode(nci, npo, cfg); } int generic_read_boot0_one_pagetab_4k(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 j, k, m, err_flag, count, block; __u8 oob_buf[64]; __u32 data_size_per_page; __u32 pages_per_block, copies_per_block; unsigned char *ptr; struct _nand_physic_op_par lnpo; struct nand_chip_info *nci; nci = g_nctri->nci; /*For A50, LDPC*/ /*nci->nctri->channel_sel = 1;*/ /*For R100, BCH*/ // nci->nctri->channel_sel = 0; ndfc_encode_select(nci->nctri); data_size_per_page = 4096; pages_per_block = nci->page_cnt_per_blk; copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY; block = NAND_BOOT0_BLK_START + counter; ptr = nand_get_temp_buf(data_size_per_page); RAWNAND_DBG("read blk %x \n", block); for (j = 0; j < copies_per_block; j++) { err_flag = 0; count = 0; for (k = 8; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { lnpo.chip = 0; lnpo.block = block; lnpo.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; lnpo.sdata = oob_buf; lnpo.slen = 64; for (m = 0; m < 64; m++) oob_buf[m] = 0x55; if (nci->is_lsb_page(lnpo.page)) { lnpo.mdata = ptr; nand_wait_all_rb_ready(); SECURE_FLAG = 1; if (nci->nand_read_boot0_page(nci, &lnpo) < 0) { RAWNAND_ERR("Warning. Fail in read page %d in block %d.\n", lnpo.page, lnpo.block); err_flag = 1; break; } if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); err_flag = 1; break; } memcpy(buf + count * data_size_per_page, ptr, data_size_per_page); count++; if (count == (len / data_size_per_page)) break; } } if (err_flag == 0) break; } // nci->nctri->channel_sel = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); nand_wait_all_rb_ready(); nand_free_temp_buf(ptr); if (err_flag == 1) return -1; return 0; } int generic_read_boot0_one_1k_mode(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, j; __u8 oob_buf[64]; __u32 pages_per_block, blocks_per_copy, start_block, count; __u32 flag; unsigned char *ptr = NULL; struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; RAWNAND_DBG("read_boot0_1k mode!\n"); for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } pages_per_block = nci->page_cnt_per_blk; blocks_per_copy = NAND_BOOT0_PAGE_CNT_PER_COPY_4 / pages_per_block; if (NAND_BOOT0_PAGE_CNT_PER_COPY_4 % pages_per_block) blocks_per_copy++; start_block = blocks_per_copy * counter; if ((start_block + blocks_per_copy) > aw_nand_info.boot->uboot_start_block) { return 0; } RAWNAND_DBG("boot0 count %d!\n", counter); ptr = nand_get_temp_buf(1024); if (ptr == NULL) RAWNAND_ERR("%s %d ptr get buf fail\n", __func__, __LINE__); count = 0; flag = 0; for (i = start_block; i < (start_block + blocks_per_copy); i++) { lnpo.chip = 0; lnpo.block = i; lnpo.page = 0; nand_wait_all_rb_ready(); for (j = 0; j < pages_per_block; j++) { lnpo.page = j; lnpo.sdata = oob_buf; lnpo.slen = 64; lnpo.mdata = ptr; nci->nctri->random_factor = count; nci->nctri->random_factor |= SMALL_CAPACITY_NAND; nand_wait_all_rb_ready(); if (nci->nand_read_boot0_page(nci, &lnpo) < 0) { RAWNAND_ERR("Warning. Fail in read page %d in block %d.\n", lnpo.page, lnpo.block); goto error; } if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } memcpy(buf + count * 1024, ptr, 1024); count++; if (count == (len / 1024)) { flag = 1; break; } } if (flag == 1) break; } nand_free_temp_buf(ptr); nci->nctri->random_factor = 0; return 0; error: nand_free_temp_buf(ptr); return -1; } int generic_read_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { struct nand_chip_info *nci; __u32 pagesize = 0; __u32 pagesperblock = 0; nci = g_nctri->nci; pagesize = nci->sector_cnt_per_page << 9; pagesperblock = nci->page_cnt_per_blk; RAWNAND_DBG("m0 read boot0 one \n"); if ((pagesize >= 8192) && (pagesperblock >= 128)) return generic_read_boot0_one_pagetab_4k(buf, len, counter); else return generic_read_boot0_one_1k_mode(buf, len, counter); return -1; } int hynix16nm_4G_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, k, j, count, block; __u8 oob_buf[64]; __u32 tab_size, data_size_per_page; __u32 pages_per_block, copies_per_block; __u32 page_addr; __u32 *pos_data = NULL, *tab = NULL, *rr_tab = NULL; __u8 *data_FF_buf = NULL; int ret; // struct boot_ndfc_cfg cfg; struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; #if 1 /*A50 FPGA LDPC encode have bug, must to use SDR interface By zzm*/ if (nci->support_toggle_only) { ret = before_update_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("before_update nctri nand interface fail!\n"); return ret; } } else { ret = update_boot0_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("update boot0 nctri nand interface fail!\n"); return ret; } } #endif /*For A50, LDPC*/ /*nci->nctri->channel_sel = 1;*/ /*For R100, BCH*/ //nci->nctri->channel_sel = 0; ndfc_encode_select(nci->nctri); RAWNAND_DBG("burn_boot0_lsb_FF_pagetab secure mode!\n"); pos_data = (__u32 *)nand_malloc(128 * 4 * BOOT0_MAX_COPY_CNT); if (!pos_data) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for pos_data failed.\n"); goto error; } tab = (__u32 *)nand_malloc(8 * 1024); if (!tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for tab failed.\n"); goto error; } rr_tab = (__u32 *)nand_malloc(8 * 1024); if (!rr_tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for rr_tab failed.\n"); goto error; } data_FF_buf = nand_malloc(20 * 1024); if (data_FF_buf == NULL) { RAWNAND_ERR("data_FF_buf malloc error!"); goto error; } for (i = 0; i < (16384 + 1664); i++) *((__u8 *)data_FF_buf + i) = 0xFF; for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } data_size_per_page = 4096; pages_per_block = nci->page_cnt_per_blk; copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY; count = 0; for (i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + aw_nand_info.boot->uboot_start_block); i++) { for (j = 0; j < copies_per_block; j++) { for (k = 8; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { page_addr = i * pages_per_block + j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; if (nci->is_lsb_page((page_addr % pages_per_block))) { *((__u32 *)pos_data + count) = page_addr; count++; if (((count % (len / data_size_per_page)) == 0) && (count != 0)) break; } } } } _generate_page_map_tab(data_size_per_page, copies_per_block * aw_nand_info.boot->uboot_start_block, len / data_size_per_page, pos_data, tab, &tab_size); // get read retry table _get_read_retry_table(nci, (u8 *)rr_tab); block = NAND_BOOT0_BLK_START + counter; RAWNAND_DBG("pagetab boot0 %x \n", block); lnpo.chip = 0; lnpo.block = block; lnpo.page = 0; nand_wait_all_rb_ready(); ret = nci->nand_physic_erase_block(&lnpo); if (ret) { RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block); //return ret; } for (j = 0; j < copies_per_block; j++) { count = 0; for (k = 0; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { lnpo.chip = 0; lnpo.block = block; lnpo.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; lnpo.sdata = oob_buf; lnpo.slen = 64; if (nci->is_lsb_page(lnpo.page)) { if (k < 4) lnpo.mdata = (__u8 *)rr_tab; else if (k < 8) lnpo.mdata = (__u8 *)tab; else { if (count < len / data_size_per_page) lnpo.mdata = (__u8 *)(buf + count * data_size_per_page); else lnpo.mdata = (__u8 *)buf; count++; } nand_wait_all_rb_ready(); if (nci->nand_write_boot0_page(nci, &lnpo) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } } else { lnpo.mdata = (__u8 *)data_FF_buf; nand_wait_all_rb_ready(); if (hynix16nm_write_page_FF(&lnpo, (nci->sector_cnt_per_page / 2)) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } } } } //nci->nctri->channel_sel = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); if (data_FF_buf) nand_free(data_FF_buf); return 0; error: if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); if (data_FF_buf) nand_free(data_FF_buf); return -1; } /** * nand flash controller different, write boot0 way is different */ /* *struct boot0_df_cfg_mode boot0_cfg_df = { *#if defined(CONFIG_ARCH_SUN8IW18) * .generic_read_boot0_page_cfg_mode = generic_read_boot0_page_cfg_mode, * .generic_write_boot0_page_cfg_mode = generic_write_boot0_page_cfg_mode, *#else [>CONFIG_ARCH_SUN50IW9<] * .generic_read_boot0_page_cfg_mode = generic_read_boot0_page_cfg_mode_v1px, * .generic_write_boot0_page_cfg_mode = generic_write_boot0_page_cfg_mode_v1px, *#endif *}; */ int hynix20nm_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, k, j, count, block, chip_no; __u8 oob_buf[64]; __u32 tab_size, data_size_per_page; __u32 pages_per_block, copies_per_block; __u32 page_addr; __u32 *pos_data = NULL, *tab = NULL, *rr_tab = NULL; /*__u8 *data_FF_buf=NULL;*/ int ret; /*struct boot_ndfc_cfg cfg;*/ struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; #if 0 /*A50 FPGA LDPC encode have bug, must to use SDR interface By zzm*/ if (nci->support_toggle_only) { ret = before_update_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("before_update nctri nand interface fail!\n"); return ret; } } else { ret = update_boot0_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("update boot0 nctri nand interface fail!\n"); return ret; } } #endif /*For A50, LDPC*/ /*nci->nctri->channel_sel = 1;*/ /*For R100, BCH*/ //nci->nctri->channel_sel = 0; ndfc_encode_select(nci->nctri); RAWNAND_DBG("burn_boot0_lsb_enable_pagetab mode!\n"); pos_data = (__u32 *)nand_malloc(128 * 4 * BOOT0_MAX_COPY_CNT); if (!pos_data) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for pos_data failed.\n"); goto error; } tab = (__u32 *)nand_malloc(8 * 1024); if (!tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for tab failed.\n"); goto error; } rr_tab = (__u32 *)nand_malloc(8 * 1024); if (!rr_tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for rr_tab failed.\n"); goto error; } #if 0 data_FF_buf = nand_malloc(18048); if (data_FF_buf == NULL) { nand_malloc("data_FF_buf malloc error!"); goto error; } for (i = 0; i < (16384 + 1664); i++) *((__u8 *)data_FF_buf + i) = 0xFF; #endif for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } // lsb enable RAWNAND_DBG("lsb enalbe \n"); RAWNAND_DBG("read retry mode: 0x%x\n", hynix20nm_read_retry_mode); chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix20nm_lsb_init(nci); hynix20nm_lsb_enable(nci); nci->nctri_chip_no = chip_no; data_size_per_page = 4096; pages_per_block = nci->page_cnt_per_blk; copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY; count = 0; for (i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + aw_nand_info.boot->uboot_start_block); i++) { for (j = 0; j < copies_per_block; j++) { for (k = 8; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { page_addr = i * pages_per_block + j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; if (nci->is_lsb_page((page_addr % pages_per_block))) { *((__u32 *)pos_data + count) = page_addr; count++; if (((count % (len / data_size_per_page)) == 0) && (count != 0)) break; } } } } _generate_page_map_tab(data_size_per_page, copies_per_block * aw_nand_info.boot->uboot_start_block, len / data_size_per_page, pos_data, tab, &tab_size); // get read retry table _get_read_retry_table(nci, (u8 *)rr_tab); block = NAND_BOOT0_BLK_START + counter; RAWNAND_DBG("pagetab boot0 %x \n", block); lnpo.chip = 0; lnpo.block = block; lnpo.page = 0; nand_wait_all_rb_ready(); ret = nci->nand_physic_erase_block(&lnpo); if (ret) { RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block); //return ret; } for (j = 0; j < copies_per_block; j++) { count = 0; for (k = 0; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { lnpo.chip = 0; lnpo.block = block; lnpo.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; lnpo.sdata = oob_buf; lnpo.slen = 64; if (nci->is_lsb_page(lnpo.page)) { if (k < 4) lnpo.mdata = (__u8 *)rr_tab; else if (k < 8) lnpo.mdata = (__u8 *)tab; else { if (count < len / data_size_per_page) lnpo.mdata = (__u8 *)(buf + count * data_size_per_page); else lnpo.mdata = (__u8 *)buf; count++; } nand_wait_all_rb_ready(); if (nci->nand_write_boot0_page(nci, &lnpo) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } } } } chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix20nm_lsb_disable(nci); hynix20nm_lsb_exit(nci); nci->nctri_chip_no = chip_no; RAWNAND_DBG("lsb disalbe \n"); // nci->nctri->channel_sel = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return 0; error: chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix20nm_lsb_disable(nci); hynix20nm_lsb_exit(nci); nci->nctri_chip_no = chip_no; RAWNAND_DBG("lsb disalbe \n"); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return -1; } int hynix26nm_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { __u32 i, k, j, count, block, chip_no; __u8 oob_buf[64]; __u32 tab_size, data_size_per_page; __u32 pages_per_block, copies_per_block; __u32 page_addr; __u32 *pos_data = NULL, *tab = NULL, *rr_tab = NULL; // __u8 *data_FF_buf=NULL; int ret; // struct boot_ndfc_cfg cfg; struct nand_chip_info *nci; struct _nand_physic_op_par lnpo; nci = g_nctri->nci; #if 0 /*A50 FPGA LDPC encode have bug, must to use SDR interface By zzm*/ if (nci->support_toggle_only) { ret = before_update_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("before_update nctri nand interface fail!\n"); return ret; } } else { ret = update_boot0_nctri_interface(nci->nctri); if (ret) { RAWNAND_ERR("update boot0 nctri nand interface fail!\n"); return ret; } } #endif /*For A50, LDPC*/ /*nci->nctri->channel_sel = 1;*/ /*For R100, BCH*/ //nci->nctri->channel_sel = 0; ndfc_encode_select(nci->nctri); RAWNAND_DBG("burn_boot0_lsb_enable_pagetab mode!\n"); pos_data = (__u32 *)nand_malloc(128 * 4 * BOOT0_MAX_COPY_CNT); if (!pos_data) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for pos_data failed.\n"); goto error; } tab = (__u32 *)nand_malloc(8 * 1024); if (!tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for tab failed.\n"); goto error; } rr_tab = (__u32 *)nand_malloc(8 * 1024); if (!rr_tab) { RAWNAND_ERR("burn_boot0_lsb_FF_mode, malloc for rr_tab failed.\n"); goto error; } #if 0 data_FF_buf = nand_malloc(18048); if (data_FF_buf == NULL) { nand_malloc("data_FF_buf malloc error!"); goto error; } for (i = 0; i < (16384 + 1664); i++) *((__u8 *)data_FF_buf + i) = 0xFF; #endif for (i = 0; i < 64; i++) oob_buf[i] = 0xff; /* get nand driver version */ nand_get_version(oob_buf); if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) { RAWNAND_ERR("get flash driver version error!"); goto error; } // lsb enable RAWNAND_DBG("lsb enalbe \n"); RAWNAND_DBG("read retry mode: 0x%x\n", hynix20nm_read_retry_mode); chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix26nm_lsb_init(nci); hynix26nm_lsb_enable(nci); nci->nctri_chip_no = chip_no; data_size_per_page = 4096; pages_per_block = nci->page_cnt_per_blk; copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY; count = 0; for (i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + aw_nand_info.boot->uboot_start_block); i++) { for (j = 0; j < copies_per_block; j++) { for (k = 8; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { page_addr = i * pages_per_block + j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; if (nci->is_lsb_page((page_addr % pages_per_block))) { *((__u32 *)pos_data + count) = page_addr; count++; if (((count % (len / data_size_per_page)) == 0) && (count != 0)) break; } } } } _generate_page_map_tab(data_size_per_page, copies_per_block * aw_nand_info.boot->uboot_start_block, len / data_size_per_page, pos_data, tab, &tab_size); // get read retry table _get_read_retry_table(nci, (u8 *)rr_tab); block = NAND_BOOT0_BLK_START + counter; RAWNAND_DBG("pagetab boot0 %x \n", block); lnpo.chip = 0; lnpo.block = block; lnpo.page = 0; nand_wait_all_rb_ready(); ret = nci->nand_physic_erase_block(&lnpo); if (ret) { RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block); //return ret; } for (j = 0; j < copies_per_block; j++) { count = 0; for (k = 0; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++) { lnpo.chip = 0; lnpo.block = block; lnpo.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k; lnpo.sdata = oob_buf; lnpo.slen = 64; if (nci->is_lsb_page(lnpo.page)) { if (k < 4) lnpo.mdata = (__u8 *)rr_tab; else if (k < 8) lnpo.mdata = (__u8 *)tab; else { if (count < len / data_size_per_page) lnpo.mdata = (__u8 *)(buf + count * data_size_per_page); else lnpo.mdata = (__u8 *)buf; count++; } nand_wait_all_rb_ready(); if (nci->nand_write_boot0_page(nci, &lnpo) != 0) { RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block); } } } } chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix26nm_lsb_disable(nci); hynix26nm_lsb_exit(nci); nci->nctri_chip_no = chip_no; RAWNAND_DBG("lsb disalbe \n"); //nci->nctri->channel_sel = 0; ndfc_encode_default(nci->nctri); ndfc_channel_select(nci->nctri, 0); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return 0; error: chip_no = nci->nctri_chip_no; nci->nctri_chip_no = 0; hynix26nm_lsb_disable(nci); hynix26nm_lsb_exit(nci); nci->nctri_chip_no = chip_no; RAWNAND_DBG("lsb disalbe \n"); if (pos_data) nand_free(pos_data); if (tab) nand_free(tab); if (rr_tab) nand_free(rr_tab); /* *if(data_FF_buf) * nand_free(data_FF_buf); */ return -1; } /***************************************************************************** *Name : *Description : *Parameter : *Return : 0:ok -1:fail *Note : *****************************************************************************/ int rawnand_write_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { int ret; ret = g_nsi->nci->nand_write_boot0_one(buf, len, counter); return ret; } /***************************************************************************** *Name : *Description : *Parameter : *Return : 0:ok -1:fail *Note : *****************************************************************************/ int rawnand_read_boot0_one(unsigned char *buf, unsigned int len, unsigned int counter) { int ret; ret = g_nsi->nci->nand_read_boot0_one(buf, len, counter); return ret; } /** * different platform boot0 size is different ,so one copy size is different * */ /* *struct boot0_copy_df boot0_copy_df = { *#if defined(CONFIG_ARCH_SUN8IW18) * .ndfc_blks_per_boot0_copy = ndfc_blks_per_boot0_copy_v2px, *#else * .ndfc_blks_per_boot0_copy = ndfc_blks_per_boot0_copy_v1px, *#endif *}; */ void selected_write_boot0_one(enum rq_write_boot0_type rq) { switch (rq) { case NAND_WRITE_BOOT0_GENERIC: rawnand_boot0_ops.write_boot0_one = generic_write_boot0_one; break; case NAND_WRITE_BOOT0_HYNIX_16NM_4G: rawnand_boot0_ops.write_boot0_one = hynix16nm_4G_write_boot0_one; break; case NAND_WRITE_BOOT0_HYNIX_20NM: rawnand_boot0_ops.write_boot0_one = hynix20nm_write_boot0_one; break; case NAND_WRITE_BOOT0_HYNIX_26NM: rawnand_boot0_ops.write_boot0_one = hynix26nm_write_boot0_one; break; default: rawnand_boot0_ops.write_boot0_one = generic_write_boot0_one; break; }; } write_boot0_one_t write_boot0_one[] = { generic_write_boot0_one, hynix16nm_4G_write_boot0_one, hynix20nm_write_boot0_one, hynix26nm_write_boot0_one, }; struct rawnand_boot0_ops_t rawnand_boot0_ops = { .write_boot0_page = generic_write_boot0_page, .read_boot0_page = generic_read_boot0_page, .write_boot0_one = NULL, .read_boot0_one = generic_read_boot0_one, };