int32_t nand_secure_read(struct amlnand_chip * aml_chip, char *buf,int len) { //struct amlnand_chip * aml_chip = provider->priv; //secure_t *secure_ptr = NULL; unsigned char *secure_ptr = NULL; int error = 0; if(len > CONFIG_SECURE_SIZE) { aml_nand_msg("key data len too much,%s\n",__func__); return -EFAULT; } secure_ptr = kzalloc(CONFIG_SECURE_SIZE, GFP_KERNEL); if(secure_ptr == NULL) return -ENOMEM; memset(secure_ptr,0,CONFIG_SECURE_SIZE); error = amlnand_read_info_by_name(aml_chip, (unsigned char *)(&aml_chip->nand_secure),secure_ptr,(unsigned char *)SECURE_INFO_HEAD_MAGIC, CONFIG_SECURE_SIZE); if (error) { aml_nand_msg("read key error,%s\n",__func__); error = -EFAULT; goto exit; } //memcpy(buf, secure_ptr->data, len); memcpy(buf, secure_ptr, len); exit: kfree(secure_ptr); return error; }
int aml_nand_update_secure(struct amlnand_chip * aml_chip, char *secure_ptr) { int ret = 0; char malloc_flag = 0; unsigned char *secure_buf = NULL; if(secure_buf == NULL){ secure_buf = kzalloc(CONFIG_SECURE_SIZE, GFP_KERNEL); if(secure_buf == NULL) return -ENOMEM; memset(secure_buf,0,CONFIG_SECURE_SIZE); ret = amlnand_read_info_by_name(aml_chip, (unsigned char *)(&aml_chip->nand_secure),secure_buf,(unsigned char *)SECURE_INFO_HEAD_MAGIC, CONFIG_SECURE_SIZE); if (ret) { aml_nand_msg("read key error,%s\n",__func__); ret = -EFAULT; goto exit; } }else{ secure_buf = (unsigned char *)secure_ptr; } ret = amlnand_save_info_by_name(aml_chip, (unsigned char *)(&aml_chip->nand_secure), secure_buf, (unsigned char *)SECURE_INFO_HEAD_MAGIC, CONFIG_SECURE_SIZE); if(ret < 0){ aml_nand_msg("aml_nand_update_secure : update secure failed"); } exit: if(malloc_flag && (secure_buf)){ kfree(secure_buf); secure_buf = NULL; } return 0; }
/***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ static void part_resume(struct ntd_info *ntd) { struct amlnand_phydev *phy; /* int ret = 0; */ phy = ntd->priv; if (phy == NULL) { aml_nand_msg("%s : get phy dev failed", __func__); return; } phy->resume(phy); aml_nand_msg("part_resume %s", phy->name); return; }
int32_t nand_secure_write(struct amlnand_chip * aml_chip, char *buf,int len) { secure_t *secure_ptr = NULL; int error = 0; if(len > CONFIG_SECURE_SIZE) { aml_nand_msg("key data len too much,%s\n",__func__); return -EFAULT; } secure_ptr = kzalloc(CONFIG_SECURE_SIZE, GFP_KERNEL); if(secure_ptr == NULL) return -ENOMEM; memset(secure_ptr,0,CONFIG_SECURE_SIZE); memcpy(secure_ptr->data + 0, buf, len); amlnand_get_device(aml_chip, CHIP_WRITING); error = amlnand_save_info_by_name(aml_chip, (unsigned char *)&(aml_chip->nand_secure),(unsigned char *)secure_ptr,SECURE_INFO_HEAD_MAGIC, CONFIG_SECURE_SIZE); if (error) { printk("save key error,%s\n",__func__); error = -EFAULT; goto exit; } exit: amlnand_release_device(aml_chip); kfree(secure_ptr); return error; }
static int controller_queue_rb_irq(struct hw_controller *controller, unsigned char chipnr) { int ret = 0, timeout = 0; if (chipnr != NAND_CHIP_UNDEFINE)/* skip dma operation */ controller->select_chip(controller, chipnr); reinit_completion(&rb_complete); controller_open_interrupt(controller); NFC_SEND_CMD_IDLE(controller, NAND_TWB_TIME_CYCLE); controller->cmd_ctrl(controller, NAND_CMD_STATUS, NAND_CTRL_CLE); NFC_SEND_CMD_IDLE(controller, NAND_TWB_TIME_CYCLE); /* */ smp_rmb(); /* */ smp_wmb(); NFC_SEND_CMD_RB_IRQ(controller, 18); /* NFC_SEND_CMD_IDLE(controller, NAND_TWB_TIME_CYCLE); */ timeout = wait_for_completion_timeout(&rb_complete, 800); if (timeout == 0) { aml_nand_msg("***[nand] rb irq timeout"); ret = -NAND_BUSY_FAILURE; } controller_close_interrupt(controller); return ret; }
int roomboot_nand_write(struct amlnand_phydev *phydev) { struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv; struct nand_flash * flash = &aml_chip->flash; struct phydev_ops *devops = &(phydev->ops); struct hw_controller *controller = &(aml_chip->controller); struct chip_operation *operation = &(aml_chip->operation); struct chip_ops_para *ops_para = &(aml_chip->ops_para); uint64_t offset , write_len, addr; unsigned char * buffer; int pages_per_blk = 0, ret = 0; int oob_set = 0; offset = devops->addr; write_len = devops->len; buffer = devops->datbuf; if (offset != 0){ aml_nand_msg("Wrong addr begin"); return -1; } if(write_len < phydev->erasesize){ write_len = phydev->erasesize; } if((flash->new_type) &&((flash->new_type < 10) || (flash->new_type == SANDISK_19NM))){ write_len = phydev->erasesize >> 1; }
static int controller_queue_rb_irq(struct hw_controller *controller, unsigned char chipnr) { int ret = 0, timeout = 0; if(chipnr != NAND_CHIP_UNDEFINE){ //skip dma operation controller->select_chip(controller, chipnr); } init_completion(&controller_rb_completion); controller_open_interrupt(); NFC_SEND_CMD_IDLE(controller->chip_selected, NAND_TWB_TIME_CYCLE); controller->cmd_ctrl(controller, NAND_CMD_STATUS, NAND_CTRL_CLE); NFC_SEND_CMD_IDLE(controller->chip_selected, NAND_TWB_TIME_CYCLE); smp_rmb(); smp_wmb(); NFC_SEND_CMD_RB_IRQ(18); //NFC_SEND_CMD_IDLE(controller->chip_selected, NAND_TWB_TIME_CYCLE); timeout = wait_for_completion_timeout(&controller_rb_completion, 200); if(timeout == 0){ aml_nand_msg("***nand irq timeout here"); ret = -NAND_BUSY_FAILURE; } controller_close_interrupt(); return ret; }
static int controller_select_chip(struct hw_controller *controller, unsigned char chipnr) { int ret = 0; switch (chipnr) { case 0: case 1: case 2: case 3: controller->chip_selected = controller->ce_enable[chipnr]; controller->rb_received = controller->rb_enable[chipnr]; #ifdef AML_NAND_UBOOT for (i=0; i < controller->chip_num; i++) { pinmux_select_chip(controller->ce_enable[i], controller->rb_enable[i], ((controller->option & NAND_CTRL_NONE_RB) == 0)); } #endif NFC_SEND_CMD_IDLE(controller->chip_selected, 0); break; default: BUG(); controller->chip_selected = CE_NOT_SEL; ret = -NAND_SELECT_CHIP_FAILURE; aml_nand_msg("failed"); break; } return ret; }
int amlnf_env_read(unsigned char *buf,int len) { unsigned char *env_buf = NULL; //int ret=0, i=0; int ret=0; aml_nand_msg("uboot env amlnf_env_read : ####"); if(aml_chip_env == NULL){ return 0; } if(len > CONFIG_ENV_SIZE) { aml_nand_msg("uboot env data len too much,%s",__func__); return -EFAULT; } if(aml_chip_env->uboot_env.arg_valid == 0){ memset(buf,0x0,len); return 0; } env_buf = aml_nand_malloc(CONFIG_ENV_SIZE); if (env_buf == NULL){ aml_nand_msg("nand malloc for uboot env failed"); ret = -1; goto exit_err; } memset(env_buf,0,CONFIG_ENV_SIZE); ret = amlnand_read_info_by_name(aml_chip_env, (unsigned char *)&(aml_chip_env->uboot_env),env_buf,(unsigned char *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand uboot env error,%s",__func__); ret = -EFAULT; goto exit_err; } memcpy(buf,env_buf, len); exit_err: if(env_buf){ kfree(env_buf); env_buf= NULL; } return ret; }
static int controller_hwecc_correct(struct hw_controller *controller, unsigned int size, unsigned char *oob_buf) { unsigned int ecc_step_num, cur_ecc, usr_info; unsigned int info_times_int_len = PER_INFO_BYTE/sizeof(unsigned int); struct amlnand_chip *aml_chip = controller->aml_chip; int max_ecc = 0; int user_offset = 0; unsigned int tmp_value; if (controller->oob_mod == 1) user_offset = 4; if (size % controller->ecc_unit) { aml_nand_msg("err para size for ecc correct %x,and ecc_unit:%x", size, controller->ecc_unit); return -NAND_ARGUMENT_FAILURE; } controller->ecc_cnt_cur = 0; for (ecc_step_num = 0; ecc_step_num < (size / controller->ecc_unit); ecc_step_num++) { /* check if there have uncorrectable sector */ tmp_value = ecc_step_num*info_times_int_len + user_offset; usr_info = (*(u32 *)(&(controller->user_buf[tmp_value]))); cur_ecc = NAND_ECC_CNT(usr_info); /* aml_nand_dbg("uncorrected for cur_ecc:%d, usr_buf[%d]:%x", cur_ecc, ecc_step_num, usr_info); */ if (cur_ecc == 0x3f) { controller->zero_cnt = NAND_ZERO_CNT(usr_info); if (max_ecc < controller->zero_cnt) max_ecc = controller->zero_cnt; /* aml_nand_dbg("uncorrected for ecc_step_num:%d, zero_cnt:%d", ecc_step_num, controller->zero_cnt); */ return NAND_ECC_FAILURE; } else { controller->ecc_cnt_cur = (controller->ecc_cnt_cur > cur_ecc) ? controller->ecc_cnt_cur : cur_ecc; if (max_ecc < controller->ecc_cnt_cur) max_ecc = controller->ecc_cnt_cur; } } aml_chip->max_ecc_per_page = max_ecc; return 0; }
/***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ static int part_suspend(struct ntd_info *ntd) { struct amlnand_phydev *phy; int ret = 0; phy = ntd->priv; if (phy == NULL) { aml_nand_msg("%s : get phy dev failed", __func__); return 0; } ret = phy->suspend(phy); if (ret) aml_nand_msg("part_suspend %s failed!!!", phy->name); aml_nand_msg("part_suspend %s", phy->name); return ret; }
int secure_storage_nand_write(char *buf,unsigned int len) { struct amlnand_chip *aml_chip = aml_chip_secure; int ret = 0; ret = nand_secure_write(aml_chip,buf,len); if(ret < 0){ aml_nand_msg("secure storage nand write failed\n"); } return ret; }
int aml_key_init(struct amlnand_chip *aml_chip) { int ret = 0; meson_key *key_ptr = NULL; aml_keybox_provider_t *provider; key_ptr = aml_nand_malloc(CONFIG_KEYSIZE); if (key_ptr == NULL){ aml_nand_msg("nand malloc for key_ptr failed"); ret = -1; goto exit_error0; } memset(key_ptr,0x0,CONFIG_KEYSIZE); aml_nand_dbg("nand key: nand_key_probe. "); ret = amlnand_info_init(aml_chip, (unsigned char *)&(aml_chip->nand_key),(unsigned char *)key_ptr,(unsigned char *)KEY_INFO_HEAD_MAGIC, CONFIG_KEYSIZE); if(ret < 0){ aml_nand_msg("invalid nand key\n"); } aml_chip_key = aml_chip; nand_provider.priv=aml_chip_key; provider = aml_keybox_provider_get(nand_provider.name); if(provider){ return ret; } ret = aml_keybox_provider_register(&nand_provider); if(ret){ BUG(); } exit_error0: if(key_ptr){ aml_nand_free(key_ptr); key_ptr =NULL; } return ret; }
int aml_secure_init(struct amlnand_chip *aml_chip) { int ret = 0; unsigned char *secure_ptr = NULL; secure_ptr = aml_nand_malloc(CONFIG_SECURE_SIZE); if (secure_ptr == NULL){ aml_nand_msg("nand malloc for secure_ptr failed"); ret = -1; goto exit_error0; } memset(secure_ptr,0x0,CONFIG_SECURE_SIZE); aml_nand_dbg("nand secure: nand_secure_probe. "); ret = amlnand_info_init(aml_chip, (unsigned char *)(&aml_chip->nand_secure),secure_ptr,(unsigned char *)SECURE_INFO_HEAD_MAGIC, CONFIG_SECURE_SIZE); if(ret < 0){ aml_nand_msg("invalid nand secure_ptr\n"); ret = -1; goto exit_error0; } #if 0 aml_nand_msg("nand secure debug :: save secure again !!!!"); ret = amlnand_save_info_by_name( aml_chip,&(aml_chip->nand_secure),secure_ptr, SECURE_INFO_HEAD_MAGIC,CONFIG_SECURE_SIZE); if(ret < 0){ aml_nand_msg("nand save default secure_ptr failed aigain!!"); } #endif aml_chip_secure = aml_chip; exit_error0: if(secure_ptr){ aml_nand_free(secure_ptr); secure_ptr =NULL; } return ret; }
int aml_nand_update_key(struct amlnand_chip * aml_chip, char *key_ptr) { int ret = 0; int malloc_flag = 0; char *key_buf = NULL; if(key_buf == NULL){ key_buf = kzalloc(CONFIG_KEYSIZE, GFP_KERNEL); malloc_flag = 1; if(key_buf == NULL) return -ENOMEM; memset(key_buf,0,CONFIG_KEYSIZE); ret = amlnand_read_info_by_name(aml_chip, (unsigned char *)&(aml_chip->nand_key),(unsigned char *)key_buf,(unsigned char *)KEY_INFO_HEAD_MAGIC, CONFIG_KEYSIZE); if (ret) { aml_nand_msg("read key error,%s\n",__func__); ret = -EFAULT; goto exit; } }else{ key_buf = key_ptr; } aml_nand_msg("aml_chip->nand_key : arg_type%d valid %d,update_flag %d,valid_blk_addr %d,valid_page_addr %d",aml_chip->nand_key.arg_type,aml_chip->nand_key.arg_valid,\ aml_chip->nand_key.update_flag,aml_chip->nand_key.valid_blk_addr,aml_chip->nand_key.valid_page_addr); ret = amlnand_save_info_by_name( aml_chip,(unsigned char *)&(aml_chip->nand_key),(unsigned char *)key_buf, (unsigned char *)KEY_INFO_HEAD_MAGIC,CONFIG_KEYSIZE); if(ret < 0){ aml_nand_msg("aml_nand_update_key : save key info failed"); } exit: if(malloc_flag &&(key_buf)){ kfree(key_buf); key_buf = NULL; } return 0; }
int aml_nand_update_ubootenv(struct amlnand_chip * aml_chip, char *env_ptr) { int ret = 0; char malloc_flag = 0; char *env_buf = NULL; if(env_buf == NULL){ env_buf = kzalloc(CONFIG_ENV_SIZE, GFP_KERNEL); malloc_flag = 1; if(env_buf == NULL) return -ENOMEM; memset(env_buf,0,CONFIG_ENV_SIZE); ret = amlnand_read_info_by_name(aml_chip, (unsigned char *)&(aml_chip->uboot_env),(unsigned char *)env_buf,(unsigned char *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("read ubootenv error,%s\n",__func__); ret = -EFAULT; goto exit; } }else{ env_buf = env_ptr; } ret = amlnand_save_info_by_name(aml_chip, (unsigned char *)&(aml_chip->uboot_env),(unsigned char *)env_buf,(unsigned char *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if(ret < 0){ aml_nand_msg("aml_nand_update_secure : update secure failed"); } exit: if(malloc_flag &&(env_buf)){ kfree(env_buf); env_buf = NULL; } return 0; }
int aml_ubootenv_init(struct amlnand_chip *aml_chip) { int ret = 0; unsigned char * env_buf = NULL; aml_chip_env = aml_chip; env_buf = aml_nand_malloc(CONFIG_ENV_SIZE); if (env_buf == NULL){ aml_nand_msg("nand malloc for secure_ptr failed"); ret = -1; goto exit_err; } memset(env_buf,0x0,CONFIG_ENV_SIZE); ret = amlnand_info_init(aml_chip, (unsigned char *)&(aml_chip->uboot_env),env_buf,(unsigned char *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if(ret < 0){ aml_nand_msg("aml_ubootenv_init failed\n"); ret = -1; goto exit_err; } /*if(aml_chip->uboot_env.arg_valid == 0){ memset(env_buf,0x0,CONFIG_ENV_SIZE); ret = amlnf_env_save(env_buf,CONFIG_ENV_SIZE); if(ret){ aml_nand_msg("amlnf_env_save: save env failed"); } }*/ exit_err: if(env_buf){ kfree(env_buf); env_buf = NULL; } return ret; }
static int controller_dma_timer_handle(struct hw_controller *controller) { struct amlnand_chip *aml_chip = controller->aml_chip; struct nand_flash *flash = &(aml_chip->flash); int timeout, time_start; time_start = (flash->pagesize + flash->oobsize)*50+5000; init_completion(&controller_dma_completion); hrtimer_start(&controller->timer,ktime_set(0, time_start), HRTIMER_MODE_REL); timeout = wait_for_completion_timeout(&controller_dma_completion, 50); //max 500mS if(timeout == 0){ aml_nand_msg("dma time out"); return -NAND_BUSY_FAILURE; } return 0; }
int amlnand_get_partition_table(void) { int ret=0; if(part_table == NULL){ aml_nand_msg("part_table from ACS is NULL, do not init nand"); return -NAND_FAILED; } amlnand_config = aml_nand_malloc(MAX_NAND_PART_NUM * sizeof(struct amlnf_partition)); if(!amlnand_config){ aml_nand_dbg("amlnand_config: malloc failed!"); ret = -NAND_MALLOC_FAILURE; } //show_partition_table(); memcpy(amlnand_config, part_table, (MAX_NAND_PART_NUM * sizeof(struct amlnf_partition))); return ret; }
static int controller_select_chip(struct hw_controller *controller, unsigned char chipnr) { int ret = 0; switch (chipnr) { case 0: case 1: case 2: case 3: controller->chip_selected = controller->ce_enable[chipnr]; controller->rb_received = controller->rb_enable[chipnr]; NFC_SEND_CMD_IDLE(controller, 0); break; default: BUG(); controller->chip_selected = CE_NOT_SEL; ret = -NAND_SELECT_CHIP_FAILURE; aml_nand_msg("failed"); break; } return ret; }
/***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ static int part_flush(struct ntd_info *ntd) { aml_nand_msg("part_flush"); return 0; }
/***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ void print_ntd(struct ntd_info *ntd) { aml_nand_msg("ntd->name %s", ntd->name); aml_nand_msg("ntd->offset %llx", ntd->offset); aml_nand_msg("ntd->flags %lx", ntd->flags); aml_nand_msg("ntd->size %llx", ntd->size); aml_nand_msg("ntd->blocksize %ld", ntd->blocksize); aml_nand_msg("ntd->pagesize %ld", ntd->pagesize); aml_nand_msg("ntd->oobsize %ld", ntd->oobsize); aml_nand_msg("ntd->blocksize_shift %ld", ntd->blocksize_shift); aml_nand_msg("ntd->pagesize_shift %ld", ntd->pagesize_shift); aml_nand_msg("ntd->blocksize_mask %ld", ntd->blocksize_mask); aml_nand_msg("ntd->pagesize_mask %ld", ntd->pagesize_mask); aml_nand_msg("ntd->index %ld", ntd->index); }
/***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ static struct ntd_info *allocate_partition(struct amlnand_phydev *master) { struct ntd_info *slave; char *name; uint block = 0; uint block_num = 0; /* allocate the partition structure */ slave = kzalloc(sizeof(*slave), GFP_KERNEL); /* name = kstrdup(part->name, GFP_KERNEL); */ name = kstrdup(master->name, GFP_KERNEL); if (!name || !slave) { aml_nand_msg("\"%s\":mem alloc err while creating partitions", master->name); kfree(name); kfree(slave); return ERR_PTR(-ENOMEM); } /* set up the NTD object for this partition */ slave->flags = master->flags; slave->blocksize = master->erasesize; slave->pagesize = master->writesize; slave->oobsize = master->oobavail; slave->name = name; slave->blocksize_shift = ffs(slave->blocksize) - 1; slave->pagesize_shift = ffs(slave->pagesize) - 1; slave->parts = (struct ntd_partition *)master->partitions; slave->nr_partitions = master->nr_partitions; /* slave->owner = master->owner; */ /* slave->dev.parent = master->dev.parent; */ /* printk("-------------------------------slave->dev.parentr %d\n", slave->dev.parent); */ slave->read_page_with_oob = read_page_with_oob; slave->write_page_with_oob = write_page_with_oob; slave->read_only_oob = read_only_oob; slave->block_isbad = part_block_isbad; slave->block_markbad = part_block_markbad; slave->suspend = part_suspend; slave->resume = part_resume; slave->flush = part_flush; slave->get_device = NULL; slave->put_device = NULL; slave->erase = part_erase; slave->priv = master; slave->offset = master->offset; slave->size = master->size; if ((slave->flags & NTD_WRITEABLE) && ntd_mod_by_eb(slave->offset, slave)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ slave->flags &= ~NTD_WRITEABLE; aml_nand_msg("ntd:part \"%s\" doesn't start on blk boundary", slave->name); aml_nand_msg("force read-only"); } if ((slave->flags & NTD_WRITEABLE) && ntd_mod_by_eb(slave->size, slave)) { slave->flags &= ~NTD_WRITEABLE; aml_nand_msg("ntd:part \"%s\" doesn't end on block", slave->name); aml_nand_msg("force read-only"); } /* print_ntd(slave); */ block_num = (uint)(slave->size >> slave->blocksize_shift); do { if (slave->block_isbad(slave, block)) slave->badblocks++; block++; block_num--; } while (block_num != 0); /* out_register: */ return slave; }
static int write_uboot(struct amlnand_phydev *phydev) { struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv; struct nand_flash *flash = &(aml_chip->flash); struct phydev_ops *devops = &(phydev->ops); struct hw_controller *controller = &(aml_chip->controller); struct chip_operation *operation = &(aml_chip->operation); struct chip_ops_para *ops_para = &(aml_chip->ops_para); struct en_slc_info *slc_info = &(controller->slc_info); unsigned char *fill_buf; unsigned char *oob_buf, *page0_buf, tmp_bch_mode, tmp_user_mode, tmp_ecc_limit, tmp_ecc_max,tmp_rand; unsigned configure_data, pages_per_blk, oobsize, page_size, tmp_size,priv_lsb,ops_tem; unsigned short tmp_ecc_unit, tmp_ecc_bytes, tmp_ecc_steps; uint64_t addr, writelen = 0, len = 0; int chip_num=1, nand_read_info, new_nand_type, i, ret = 0; unsigned char *tmp_buf; if((devops->addr + devops->len) > phydev->size){ aml_nand_msg("writeboot:out of space and addr:%llx len:%llx phydev->offset:%llx phydev->size:%llx",\ devops->addr, devops->len, phydev->offset, phydev->size); return -NAND_ARGUMENT_FAILURE; } if((devops->len == 0) && (devops->ooblen == 0)){ aml_nand_msg("len equal zero here"); return NAND_SUCCESS; } if(devops->addr != 0){ aml_nand_msg("addr do not equal zero here for uboot write"); return NAND_SUCCESS; } tmp_ecc_unit = controller->ecc_unit; tmp_ecc_bytes = controller->ecc_bytes; tmp_bch_mode = controller->bch_mode; tmp_user_mode = controller->user_mode; tmp_ecc_limit = controller->ecc_cnt_limit; tmp_ecc_max = controller->ecc_max; tmp_ecc_steps = controller->ecc_steps; tmp_rand = controller->ran_mode; if (controller->bch_mode == NAND_ECC_BCH_SHORT){ page_size = (flash->pagesize / 512) * NAND_ECC_UNIT_SHORT; } oobsize = controller->ecc_steps*controller->user_mode; tmp_size = phydev->writesize; //phydev->writesize = page_size; //amlnand_get_device(aml_chip, CHIP_WRITING); oob_buf = aml_nand_malloc(oobsize); if(oob_buf == NULL){ aml_nand_msg("malloc failed and oobavail:%d", phydev->oobavail); ret = -NAND_MALLOC_FAILURE; goto error_exit; } memset(oob_buf,0x0,oobsize); page0_buf = aml_nand_malloc(flash->pagesize); if(page0_buf == NULL){ aml_nand_msg("malloc failed and oobavail:%d", flash->pagesize); ret = -NAND_MALLOC_FAILURE; goto error_exit; } memset(page0_buf,0x0,flash->pagesize); len = devops->len; for (i=0; i<oobsize; i+=2){ oob_buf[i] = 0x55; oob_buf[i+1] = 0xaa; } fill_buf = aml_nand_malloc(flash->pagesize); if(fill_buf == NULL){ aml_nand_msg("malloc failed and oobavail:%d", flash->pagesize); ret = -NAND_MALLOC_FAILURE; goto error_exit; } memset(fill_buf,0xff,(flash->pagesize + flash->oobsize)); //clear ops_para here memset(ops_para, 0, sizeof(struct chip_ops_para)); addr = phydev->offset + devops->addr; ops_para->option = phydev->option; ops_para->data_buf = devops->datbuf; ops_para->oob_buf = oob_buf; if((flash->new_type) &&((flash->new_type < 10) || (flash->new_type == SANDISK_19NM))) ops_para->option |= DEV_SLC_MODE; configure_data = NFC_CMD_N2M(controller->ran_mode, controller->bch_mode, 0, (controller->ecc_unit >> 3), controller->ecc_steps); //configure_data = NFC_CMD_N2M(controller->ran_mode, NAND_ECC_BCH60_1K, 1, (controller->ecc_unit >> 3), controller->ecc_steps); pages_per_blk = flash->blocksize / flash->pagesize; aml_nand_msg("configure_data:%x, pages_per_blk:%x", configure_data, pages_per_blk); nand_boot_info_prepare(phydev,page0_buf); unsigned char * lazy_buf = devops->datbuf; for(i=0; i<BOOT_COPY_NUM; i++){ writelen = 0; addr = 0; addr += flash->pagesize*(BOOT_PAGES_PER_COPY*i); ops_para->data_buf = lazy_buf; devops->datbuf = lazy_buf; while(1){ if(((((unsigned)addr / flash->pagesize)) % BOOT_PAGES_PER_COPY) == 0){ uboot_set_ran_mode(phydev); ops_para->data_buf = page0_buf; page_size = (flash->pagesize / 512) * NAND_ECC_UNIT_SHORT; phydev->writesize = page_size; #if 1 controller->ecc_unit = NAND_ECC_UNIT_SHORT; controller->ecc_bytes = NAND_BCH60_1K_ECC_SIZE; controller->bch_mode = NAND_ECC_BCH_SHORT; controller->user_mode = 2; controller->ecc_cnt_limit = 55; controller->ecc_max = 60; controller->ecc_steps = (flash->pagesize+flash->oobsize)/512; #endif } ops_para->page_addr = ((unsigned)addr / flash->pagesize);// /controller->chip_num; ops_tem = ops_para->page_addr ; if((ops_para->option & DEV_SLC_MODE)) { if((flash->new_type > 0) && (flash->new_type < 10)) ops_para->page_addr = (ops_para->page_addr & (~(pages_per_blk -1))) |(slc_info->pagelist[ops_para->page_addr % 256]); if (flash->new_type == SANDISK_19NM) ops_para->page_addr = (ops_para->page_addr & (~(pages_per_blk -1))) |((ops_para->page_addr % pages_per_blk) << 1); } #if 1 if(flash->new_type ==HYNIX_1YNM_8GB) { if((ops_tem % 256)>1) { priv_lsb = (ops_tem & (~(pages_per_blk -1))) |(slc_info->pagelist[(ops_tem % 256)-1]); ops_tem = ops_para->page_addr ; while(ops_tem > (priv_lsb+1)) { ops_para->data_buf = fill_buf; controller->bch_mode =NAND_ECC_NONE; ops_para->page_addr = priv_lsb+1; operation->write_page(aml_chip); priv_lsb++; } ops_para->page_addr = ops_tem; ops_para->data_buf = devops->datbuf; controller->ecc_unit = tmp_ecc_unit; controller->ecc_bytes = tmp_ecc_bytes; controller->bch_mode =tmp_bch_mode; controller->user_mode =tmp_user_mode; controller->ecc_cnt_limit =tmp_ecc_limit; controller->ecc_max =tmp_ecc_max; controller->ecc_steps = tmp_ecc_steps; phydev->writesize = tmp_size; controller->ran_mode = tmp_rand; } } #endif if(((((unsigned)addr / flash->pagesize)) % BOOT_PAGES_PER_COPY) != 0) ops_para->data_buf = devops->datbuf; ret = operation->write_page(aml_chip); if(ret<0){ aml_nand_msg("fail page_addr:%d", ops_para->page_addr); break; } if((((unsigned)addr / flash->pagesize) % BOOT_PAGES_PER_COPY) == 0){ controller->ran_mode = 1; addr += flash->pagesize; ops_para->data_buf = devops->datbuf; #if 1 controller->ecc_unit = tmp_ecc_unit; controller->ecc_bytes = tmp_ecc_bytes; controller->bch_mode =tmp_bch_mode; controller->user_mode =tmp_user_mode; controller->ecc_cnt_limit =tmp_ecc_limit; controller->ecc_max =tmp_ecc_max; controller->ecc_steps = tmp_ecc_steps; phydev->writesize = tmp_size; #endif continue; } addr += flash->pagesize; devops->datbuf += phydev->writesize; writelen += phydev->writesize; if((writelen >= UBOOT_WRITE_SIZE)&&(writelen < phydev->erasesize)){ devops->datbuf = fill_buf; } if((writelen >= (len-flash->pagesize))||((unsigned)addr%flash->blocksize ==0)){ break; } } } devops->retlen = writelen; error_exit: //amlnand_release_device(aml_chip); controller->ran_mode = 1; controller->ecc_unit = tmp_ecc_unit; controller->ecc_bytes = tmp_ecc_bytes; controller->bch_mode =tmp_bch_mode; controller->user_mode =tmp_user_mode; controller->ecc_cnt_limit =tmp_ecc_limit; controller->ecc_max =tmp_ecc_max; controller->ecc_steps = tmp_ecc_steps; phydev->writesize = tmp_size; if(fill_buf){ kfree(fill_buf); fill_buf =NULL; } if(page0_buf){ kfree(page0_buf); page0_buf =NULL; } return ret; }
static int read_uboot(struct amlnand_phydev *phydev) { struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv; struct nand_flash *flash = &(aml_chip->flash); struct phydev_ops *devops = &(phydev->ops); struct hw_controller *controller = &(aml_chip->controller); struct chip_operation *operation = &(aml_chip->operation); struct chip_ops_para *ops_para = &(aml_chip->ops_para); struct en_slc_info *slc_info = &(controller->slc_info); unsigned configure_data, pages_per_blk, configure_data_w, pages_per_blk_w, page_size, tmp_size; unsigned char tmp_bch_mode, tmp_user_mode, tmp_ecc_limit, tmp_ecc_max; unsigned short tmp_ecc_unit, tmp_ecc_bytes, tmp_ecc_steps; uint64_t addr, readlen = 0, len = 0; int ret = 0; if((devops->addr + devops->len) > phydev->size){ aml_nand_msg("read uboot:out of space and addr:%llx len:%llx phydev->offset:%llx phydev->size:%llx",\ devops->addr, devops->len, phydev->offset, phydev->size); return -NAND_ARGUMENT_FAILURE; } if((devops->len == 0) && (devops->ooblen == 0)){ aml_nand_msg("len equal zero here"); return NAND_SUCCESS; } tmp_ecc_unit = controller->ecc_unit; tmp_ecc_bytes = controller->ecc_bytes; tmp_bch_mode = controller->bch_mode; tmp_user_mode = controller->user_mode; tmp_ecc_limit = controller->ecc_cnt_limit; tmp_ecc_max = controller->ecc_max; tmp_ecc_steps = controller->ecc_steps; if (controller->bch_mode == NAND_ECC_BCH_SHORT){ page_size = (flash->pagesize / 512) * NAND_ECC_UNIT_SHORT; } tmp_size = phydev->writesize; //phydev->writesize = page_size; //amlnand_get_device(aml_chip, CHIP_READING); //clear ops_para here memset(ops_para, 0, sizeof(struct chip_ops_para)); if(devops->len == 0){ len = phydev->writesize; ops_para->ooblen = devops->ooblen; } else{ len = devops->len; ops_para->ooblen = devops->ooblen; } addr = phydev->offset + devops->addr; ops_para->data_buf = devops->datbuf; ops_para->option = phydev->option; ops_para->oob_buf = devops->oobbuf; if(devops->mode == NAND_SOFT_ECC){ ops_para->option |= DEV_ECC_SOFT_MODE; } if((flash->new_type) &&((flash->new_type < 10) || (flash->new_type == SANDISK_19NM))) ops_para->option |= DEV_SLC_MODE; pages_per_blk = flash->blocksize / flash->pagesize; configure_data = NFC_CMD_N2M(controller->ran_mode, controller->bch_mode, 0, (controller->ecc_unit >> 3), controller->ecc_steps); while(1){ if ((((unsigned)addr / flash->pagesize )%BOOT_PAGES_PER_COPY) == 0){ uboot_set_ran_mode(phydev); page_size = (flash->pagesize / 512) * NAND_ECC_UNIT_SHORT; phydev->writesize = page_size; #if 1 controller->ecc_unit = NAND_ECC_UNIT_SHORT; controller->ecc_bytes = NAND_BCH60_1K_ECC_SIZE; controller->bch_mode = NAND_ECC_BCH_SHORT; controller->user_mode = 2; controller->ecc_cnt_limit = 55; controller->ecc_max = 60; controller->ecc_steps = (flash->pagesize+flash->oobsize)/512; #endif }else{ controller->ran_mode = 1; } ops_para->page_addr = ((unsigned)addr / flash->pagesize);// /controller->chip_num; if((ops_para->option & DEV_SLC_MODE)) { if((flash->new_type > 0) && (flash->new_type <10)) ops_para->page_addr = (ops_para->page_addr & (~(pages_per_blk -1))) |(slc_info->pagelist[ops_para->page_addr % 256]); if (flash->new_type == SANDISK_19NM) ops_para->page_addr = (ops_para->page_addr & (~(pages_per_blk -1))) |((ops_para->page_addr % pages_per_blk) << 1); } ret = operation->read_page(aml_chip); if((ops_para->ecc_err) || (ret<0)){ aml_nand_msg("fail page_addr:%d", ops_para->page_addr); break; } //check info page if((!strncmp((char*)phydev->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME))) && (((((unsigned)addr / flash->pagesize ))%BOOT_PAGES_PER_COPY) == 0)){ controller->ran_mode = 1; // 1 memcpy((unsigned char *)(&configure_data_w), ops_para->data_buf, sizeof(int)); memcpy((unsigned char *)(&pages_per_blk_w), ops_para->data_buf+4, sizeof(int)); aml_nand_msg("configure_data:%x, pages_per_blk:%x", configure_data, pages_per_blk); /*if ((pages_per_blk_w != pages_per_blk) || (configure_data_w != configure_data)){ aml_nand_msg("nand boot check data failed, and configure_data_w:0x%x, pages_per_blk_w:0x%x",\ configure_data_w, pages_per_blk_w); }*/ addr += flash->pagesize; #if 1 controller->ecc_unit = tmp_ecc_unit; controller->ecc_bytes = tmp_ecc_bytes; controller->bch_mode =tmp_bch_mode; controller->user_mode =tmp_user_mode; controller->ecc_cnt_limit =tmp_ecc_limit; controller->ecc_max =tmp_ecc_max; controller->ecc_steps = tmp_ecc_steps; phydev->writesize = tmp_size; #endif continue; } addr += flash->pagesize; ops_para->data_buf += phydev->writesize; readlen += phydev->writesize; if(readlen >= len){ break; } } devops->retlen = readlen; //amlnand_release_device(aml_chip); if(!ret){ if(ops_para->ecc_err){ ret = NAND_ECC_FAILURE; } /*else if(ops_para->bit_flip){ ret = NAND_BITFLIP_FAILURE; }*/ } controller->ran_mode = 1; controller->ecc_unit = tmp_ecc_unit; controller->ecc_bytes = tmp_ecc_bytes; controller->bch_mode =tmp_bch_mode; controller->user_mode =tmp_user_mode; controller->ecc_cnt_limit =tmp_ecc_limit; controller->ecc_max =tmp_ecc_max; controller->ecc_steps = tmp_ecc_steps; phydev->writesize = tmp_size; return ret; }