/** * 作用:读取分区相对偏移地址的标志值,主要是为NV模块用,查询此分区的偏移地址的标志位的值 * * 参数: * @partition_name ---分区名 * @partition_offset ---分区的相对偏移 * @flag ---把检测的分区的标志值存放在此flag中 * 描述:NV模块把一个分区的一个block的最后一页的OOB中存放特定标记值,读此标记值存放在flag中 */ u32 bsp_nand_read_flag_nv(const char *partition_name, u32 partition_offset, unsigned char *flag) { u32 flash_addr; u32 ret = NANDC_ERROR; static unsigned char *buffer = NULL; struct nand_spec spec; struct ST_PART_TBL * ptable = find_partition_by_name((char *)partition_name); /*参数不对*/ if(!ptable) { goto ERRO; } if(!flag) { NAND_TRACE(("argu error.\n")); goto ERRO; } /*得到此分区的nandflash的规格参数*/ ret = bsp_get_nand_info(&spec); if(ret) { goto ERRO; } /*没有内存时分配内存*/ if(!buffer) { buffer = (unsigned char *)himalloc(spec.pagesize + YAFFS_BYTES_PER_SPARE); if(!buffer) { NAND_TRACE(("get ram buffer failed!\n")); goto ERRO; } } memset(buffer, 0xFF, spec.pagesize + YAFFS_BYTES_PER_SPARE); flash_addr = ptable->offset + partition_offset; /*使能ECC功能的带OOB读数据功能*/ ret = nand_read_oob((flash_addr + spec.blocksize - spec.pagesize), (unsigned int)buffer, (spec.pagesize + YAFFS_BYTES_PER_SPARE),YAFFS_BYTES_PER_SPARE ,NULL); if(ret) { NAND_TRACE(("nand read oob failed!\n")); goto ERRO; } *flag = (*(buffer + spec.pagesize) == NV_WRITE_SUCCESS) ? NV_WRITE_SUCCESS : (~NV_WRITE_SUCCESS); return NANDC_OK; ERRO: return ret; }
/** * 作用:nandc模块按分区名的使能ECC功能的读数据操作,注意此函数的读操作不能读OOB数据 * * 参数: * @partition_name ---要读的分区名 * @partition_offset ---要读分区的相对偏移地址 * @ptr_ram_addr ---读到内存的地址 * @length ---读的数据长度 * @skip_len ---过滤的长度,当在读的过程中遇到坏块时跳过要读的块,此结构记录跳过的长度 * * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,把读到的数据存放在ptr_ram_addr中去 */ int bsp_nand_read(const char *partition_name, u32 partition_offset, void* ptr_ram_addr, u32 length, u32 *skip_len) { u32 flash_addr; u32 ret = NANDC_ERROR; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); if(!ptable) { goto ERRO; } /*通过分区名来转到Flash的地址*/ flash_addr = ptable->offset + partition_offset; /*要Flash的数据到内存中*/ return nand_read(flash_addr, (u32)ptr_ram_addr, length, skip_len); ERRO: return ret; }
/** * 作用:nandc模块按分区名和分区相对偏移来确定此块是不是坏块 * * 参数: * @partition_name ---查询数据块的分区名 * @partition_offset ---查询数据块的分区相对偏移地址 * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,再来判断此block是不是坏块 返回值: * 0表示此块是好块 * 1表示是坏块 * 其他的表示有错误 */ int bsp_nand_isbad(const char *partition_name, u32 partition_offset) { u32 flash_addr; u32 bad_flag; u32 ret = NANDC_ERROR; struct nandc_host * host = NULL; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); if(!ptable) { goto ERRO; } /*得到Flash地址*/ flash_addr = ptable->offset + partition_offset; host = nandc_nand_host; if(!host) { NAND_TRACE(("ERROR: function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*判断此block是否是坏块*/ ret = nand_isbad(flash_addr / host->nandchip->spec.blocksize, &bad_flag); if(ret == 1) { return -6; } else if(ret > 1) { return ret; } if(bad_flag == 1) /* bad block */ { return 1; } else /* good block */ { return 0; } ERRO: return ret; }
/** * 作用:nandc模块按分区名和分区相对偏移来使能ECC功能的写数据操作,注意此函数的写操作带OOB数据且在写的过程中会擦除nandflash * * 参数: * @partition_name ---要写数据的分区名 * @partition_offset ---要写数据的分区相对偏移地址 * @ptr_ram_addr ---要写数据的地址 * @length ---要写数据的长度 * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,再来写Flash操作 */ s32 bsp_nand_write(const char *partition_name, u32 partition_offset, void* ptr_ram_addr, u32 length) { u32 flash_addr, ret = NANDC_ERROR; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); if(!ptable) { goto ERRO; } /*得到要写Flash的地址*/ flash_addr = ptable->offset + partition_offset; /*在写的过程中会擦除nandflash,因此不需要调用者再来擦除一次*/ return nand_write(flash_addr, (u32)ptr_ram_addr, length, NULL); ERRO: return ret; }
/** * 作用:nandc模块按分区名和分区偏移地址来擦除flash操作 * * 参数: * @partition_name ---要擦除的分区名 * @partition_offset ---要擦除的相对偏移地址 * * * 描述:根据分区名和分区的偏移地址来确定Flash的地址,再来擦除一个block,注意是擦除一个block数据块 */ int bsp_nand_erase(const char *partition_name, u32 partition_offset) { u32 flash_addr; u32 block_id, bad_flag; u32 ret = NANDC_ERROR; struct nandc_host * host = NULL; struct ST_PART_TBL * ptable = find_partition_by_name(partition_name); /*参数不正确*/ if(!ptable) { goto ERRO; } /*得到flash的地址信息*/ flash_addr = ptable->offset + partition_offset; host = nandc_nand_host; if(!host) { NAND_TRACE(("ERROR: function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*得到块号并判断是否是坏块*/ block_id = flash_addr / host->nandchip->spec.blocksize; ret = nand_isbad(block_id, &bad_flag); if(ret) { NAND_TRACE(("ERROR: nand quary bad failed, function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } if(NANDC_BAD_BLOCK == bad_flag) { NAND_TRACE(("ERROR: try to erase a bad block, function %s, line %d\n", __FUNCTION__, __LINE__)); goto ERRO; } /*擦除flash操作*/ return nand_erase(block_id); ERRO: return ret; }
static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param) { struct mi_node* node = cmd_tree->node.kids; if(node != NULL){ ds_partition_t *partition = find_partition_by_name(&node->value); if (partition == NULL) return init_mi_tree(500, MI_SSTR(MI_UNK_PARTITION) ); if (ds_reload_db(partition) < 0) return init_mi_tree(500, MI_SSTR(MI_ERR_RELOAD)); else return init_mi_tree(200, MI_SSTR(MI_OK_S) ); } ds_partition_t *part_it; for (part_it = partitions; part_it; part_it = part_it->next) if (ds_reload_db(part_it)<0) return init_mi_tree(500, MI_SSTR(MI_ERR_RELOAD)); return init_mi_tree(200, MI_SSTR(MI_OK_S)); }
/**************************************************************** 函数功能: 在fastboot阶段获取分区大小 输入参数: partition_name-分区名称 输出参数: none 返回参数: 分区size 注意事项: 在fastboot阶段调用 ****************************************************************/ unsigned int bsp_get_part_cap( const char *partition_name ) { unsigned int ret_size = 0; struct ST_PART_TBL * ptable = ( void* )( 0 ); if ( ( void* )( 0 ) == partition_name ) { cprintf( "fastboot: nv dload partition_name is NULL!\n" ); goto ERRO; } ptable = find_partition_by_name(partition_name); if(!ptable) { cprintf( "fastboot: nv dload get ptable fail!\n" ); goto ERRO; } ret_size = ptable->capacity; cprintf( "fastboot: nv dload cap is 0x%x.\n", ret_size ); ERRO: return ret_size; }
/****************************************************************************************** * FUNC NAME: * @bsp_update_size_of_lastpart() - external API: * * PARAMETER: * @new_ptable - addr of new ptable * * RETURN: * null * * DESCRIPTION: * update the size of last partition to shared memory * 分区表最后一个分区将flash最后一块空间完全占有,从而导致静态编译的ptable.bin与软件实际使用的ptable不一样, * 升级分区表的时候就认为两个分区不一样,从而导致对yaffs分区的擦除。此处用实际使用的分区表最后一个分区大小 * 覆盖新ptable最后分区大小 * * CALL FUNC: * *****************************************************************************************/ void bsp_update_size_of_lastpart(struct ST_PART_TBL *new_ptable) { struct ST_PART_TBL * old_ptable = NULL; if(!new_ptable) { NAND_TRACE(("[%s]argu error\n", __FUNCTION__)); return; } /*根据分区名得到分区数据结构*/ while(0 != strcmp(PTABLE_END_STR, new_ptable->name)) { new_ptable++; } new_ptable--; old_ptable = find_partition_by_name(new_ptable->name); if(old_ptable) { new_ptable->capacity = old_ptable->capacity; } }
static int __init his_modem_probe(struct platform_device *pdev) { int ret = 0; #ifdef BSP_CONFIG_HI3630 u32 image_load_addr = 0; u32 image_length = 0; extern unsigned int is_load_modem(void); /* 如果是升级模式,则不激活modem */ if(!is_load_modem()) { hi_trace(HI_ERR, "upload or charge mode, will not start modem.\r\n"); return 0; } if (readl((void*)SHM_MEM_LOADM_ADDR) != LOAD_MODEM_OK_FLAG) { hi_trace(HI_ERR, "modem image not found\r\n"); return -1; } image_load_addr = readl((void*)SHM_MEM_LOADM_ADDR + 4); image_length = readl((void*)SHM_MEM_LOADM_ADDR + 8); g_ccore_entry = (u32)ioremap_nocache(image_load_addr, image_length); if(!g_ccore_entry) { hi_trace(HI_ERR, "ioremap failed. image size: 0x%X\r\n", image_length); return NAND_ERROR; } #else struct ST_PART_TBL * mc_part = NULL; hi_trace(HI_DEBUG, "his_modem_probe.\r\n"); mc_part = find_partition_by_name(PTABLE_VXWORKS_NM); if(NULL == mc_part) { hi_trace(HI_ERR, "load ccore image succeed\r\n"); return -EAGAIN; } if(NAND_OK == his_modem_load_vxworks(mc_part->name)) { hi_trace(HI_DEBUG, "load ccore image succeed\r\n"); } else { hi_trace(HI_ERR, "load ccore image failed\r\n"); return -EAGAIN; } ret = sysfs_create_group(&pdev->dev.kobj, &his_modem_group); if (0 != ret) { hi_trace(HI_ERR,"create his modem sys filesystem node failed.\n"); return -ENXIO; } #endif ret = his_modem_ipc_send(); if (ret) { hi_trace(HI_ERR, "load ccore image failed, ret=0x%x\r\n", ret); } else { hi_trace(HI_ERR, "load ccore image succeed\r\n"); } return ret; }
static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param) { str sp, partition_name; int ret; unsigned int group, state; struct mi_node* node; ds_partition_t *partition; node = cmd_tree->node.kids; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); sp = node->value; if(sp.len<=0 || !sp.s) { LM_ERR("bad state value\n"); return init_mi_tree( 500, MI_SSTR("Bad state value") ); } if(sp.s[0]=='0' || sp.s[0]=='I' || sp.s[0]=='i') state = 0; else if(sp.s[0]=='p' || sp.s[0]=='P' || sp.s[0]=='2') state = 2; else if(sp.s[0]=='a' || sp.s[0]=='A' || sp.s[0]=='1') state = 1; else return init_mi_tree( 500, MI_SSTR("Bad state value") ); node = node->next; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); sp = node->value; if(sp.s == NULL) { return init_mi_tree(500, MI_SSTR("group not found")); } if (split_partition_argument(&sp, &partition_name) != 0) { LM_ERR("bad group format\n"); return init_mi_tree(500, MI_SSTR("bad group format")); } partition = find_partition_by_name(&partition_name); if (partition == NULL) { LM_ERR("partition does not exist\n"); return init_mi_tree(404, MI_SSTR(MI_UNK_PARTITION) ); } if(str2int(&sp, &group)) { LM_ERR("bad group value\n"); return init_mi_tree( 500, MI_SSTR("bad group value")); } node= node->next; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); sp = node->value; if(sp.s == NULL) { return init_mi_tree(500, MI_SSTR("address not found")); } if (state==1) { /* set active */ ret = ds_set_state(group, &sp, DS_INACTIVE_DST|DS_PROBING_DST, 0, partition); } else if (state==2) { /* set probing */ ret = ds_set_state(group, &sp, DS_PROBING_DST, 1, partition); if (ret==0) ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 0, partition); } else { /* set inactive */ ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 1, partition); if (ret == 0) ret = ds_set_state(group, &sp, DS_PROBING_DST, 0, partition); } if(ret!=0) return init_mi_tree(404, MI_SSTR("destination not found")); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); }