#include #include #include #define FDT_DEBUG 0 #if FDT_DEBUG #define FDT_DBG(fmt, arg...) printf("%s()%d - " fmt, __func__, __LINE__, ##arg) #define FDT_ERR(fmt, arg...) printf("%s()%d - " fmt, __func__, __LINE__, ##arg) #else #define FDT_DBG(fmt, arg...) #define FDT_ERR(fmt, arg...) printf("%s()%d - " fmt, __func__, __LINE__, ##arg) #endif #ifdef CFG_SUNXI_SDMMC extern void mmc_update_config_for_sdly(void); #endif #ifndef CFG_SUNXI_ENV #define ROOTFS_NAME "rootfs@" #define ROOTFS_BACKUP_NAME "rootfs_backup@" #define BLOCK_ROOTFS_NUM "root=/dev/" /* During the first mass production, * this area of ​​the nor scheme is erased to 1, * and the mmc scheme is erased to 0 * */ #ifdef CFG_SUNXI_SPINOR #define USE_BACKUP_BIT_IS_ZERO 0x00 #elif CFG_SUNXI_SDMMC #define USE_BACKUP_BIT_IS_ZERO 0xFF #else #define USE_BACKUP_BIT_IS_ZERO 0x00 #endif //#define USE_BACKUP_IS_ZERO 0 #define KERNEL_AND_ROOTFS_MASK 0x01 #define ROOTFS_SWITCH_MASK 0x02 #define KERNEL_SWITCH_MASK 0x01 /* switch_flag default -- 0xff, * value : 1 -- system 0 -- system_backup * bit 1~7: reserve * bit 0 : rootfs and kernel */ char get_switch_flag(void) { #ifdef CFG_BOOT0_LOAD_ISPPARM char switch_flag = read_switch_flag_from_kernel(); #else char switch_flag = 0xff; #endif switch_flag = (switch_flag && KERNEL_AND_ROOTFS_MASK)^USE_BACKUP_BIT_IS_ZERO; FDT_DBG("switch_flag = 0x%x\n", switch_flag); return switch_flag; } /* switch_flag default -- 0xff, * value : 1 -- system 0 -- system_backup * bit 3~7: reserve * bit 2 :extend partition,/usr directory,boot0 not use,system use * bit 1 : rootfs: 1:system 0:system_backup * bit 0 : kernel, 1:system 0:system_backup */ char get_switch_kernel_flag(void) { #ifdef CFG_BOOT0_LOAD_ISPPARM char switch_flag = read_switch_flag_from_kernel(); #else char switch_flag = 0xff; #endif switch_flag = (switch_flag & KERNEL_SWITCH_MASK)^USE_BACKUP_BIT_IS_ZERO; printf("switch_kernel_flag = 0x%x\n", switch_flag); return switch_flag; } /* switch_flag default -- 0xff, * value : 1 -- system 0 -- system_backup * bit 3~7: reserve * bit 2 :extend partition,/usr directory,boot0 not use,system use * bit 1 : rootfs: 1:system 0:system_backup * bit 0 : kernel, 1:system 0:system_backup */ #ifndef CFG_SUNXI_NO_UPDATE_FDT_CHOSEN char get_switch_rootfs_flag(void) { #ifdef CFG_BOOT0_LOAD_ISPPARM char switch_flag = read_switch_flag_from_kernel(); #else char switch_flag = 0xff; #endif switch_flag = (switch_flag & ROOTFS_SWITCH_MASK)^USE_BACKUP_BIT_IS_ZERO; printf("switch_rootfs_flag = 0x%x\n", switch_flag); return switch_flag; } static void sunxi_switch_rootfs(char *rootfs_name) { u32 bootargs_node; int len = 0; int err; char *bootargs_str = NULL; char cmdline[512] = { 0 }; char temp_blocknum[32] = { 0 }; bootargs_node = fdt_path_offset(working_fdt, "/chosen"); bootargs_str = (void *)fdt_getprop(working_fdt, bootargs_node, "bootargs", &len); if (!bootargs_str) { FDT_ERR("bootargs_str is NULL!!!\n"); } char *rootfs_start = strstr(bootargs_str, rootfs_name); if (!rootfs_start) { FDT_ERR("cont find rootfs partition!!!\n"); } /* The last partition of the sunxi platform is udisk */ char *rootfs_end = strchr(rootfs_start, ':'); if (!rootfs_end) { FDT_DBG("error:cant find rootfs end\n"); } char *spacer_symbol = strchr(rootfs_start, '@'); memcpy(temp_blocknum, spacer_symbol + 1, rootfs_end - spacer_symbol -1); FDT_DBG("temp_blocknum : %s\n", temp_blocknum); char *blck_root_start = strstr(bootargs_str, BLOCK_ROOTFS_NUM); if (!blck_root_start) { FDT_ERR("cont find rootfs partition!!!\n"); } char *blck_root_end = strchr(blck_root_start, ' '); if (!blck_root_end) { blck_root_end = bootargs_str + strlen(bootargs_str) - 1; FDT_DBG("error:cant find rootfs end\n"); } strncat(cmdline, bootargs_str, blck_root_start - bootargs_str); strncat(cmdline, BLOCK_ROOTFS_NUM, sizeof(BLOCK_ROOTFS_NUM)); strncat(cmdline, temp_blocknum, sizeof(temp_blocknum)); strncat(cmdline, blck_root_end, bootargs_str + strlen(bootargs_str) - blck_root_end); FDT_DBG("cmdline:%s\nstrlen(cmdline = %d)\n", cmdline, strlen(cmdline)); err = fdt_setprop(working_fdt, bootargs_node, "bootargs", cmdline, strlen(cmdline) + 1); if (err < 0) { printf("libfdt fdt_setprop(): %s\n", fdt_strerror(err)); return; } return; } static void sunxi_update_chosen(void) { if (get_switch_rootfs_flag()) { sunxi_switch_rootfs(ROOTFS_NAME); } else { sunxi_switch_rootfs(ROOTFS_BACKUP_NAME); } } #endif //CFG_SUNXI_NO_UPDATE_FDT_CHOSEN #endif //CFG_SUNXI_GPT __weak void mmc_update_config_for_sdly(void) { } #ifdef CFG_SUNXI_BOOT_PARAM extern int sprintf(char *buf, const char *fmt, ...); int update_fdt_dram_para_from_bootpara(void *dtb_base) { /*fix dram para*/ int i, nodeoffset = 0; char dram_str[16] = { 0 }; uint32_t *dram_para = NULL; typedef_sunxi_boot_param *sunxi_boot_param = sunxi_bootparam_get_buf(); nodeoffset = fdt_path_offset(dtb_base, "/dram"); if (nodeoffset < 0) { FDT_ERR("## error: %s : %s\n", __func__, fdt_strerror(nodeoffset)); return -1; } dram_para = (uint32_t *)sunxi_boot_param->ddr_info; memset(dram_str, 0, sizeof(dram_str)); for (i = MAX_DRAMPARA_SIZE - 1; i >= 0; i--) { sprintf(dram_str, "dram_para[%02d]", i); fdt_setprop_u32(dtb_base, nodeoffset, dram_str, dram_para[i]); } return 0; } #endif int sunxi_update_fdt_para_for_kernel(void) { #ifdef CFG_USE_DCACHE dcache_enable(); #endif int err = fdt_check_header(working_fdt); if (err < 0) { printf("fdt_chosen: %s\n", fdt_strerror(err)); return err; } #ifndef CFG_SUNXI_NO_UPDATE_FDT_CHOSEN sunxi_update_chosen(); #endif #ifdef CFG_SUNXI_BOOT_PARAM update_fdt_dram_para_from_bootpara(working_fdt); #endif #ifdef CFG_SUNXI_SDMMC mmc_update_config_for_sdly(); #endif #ifdef CFG_USE_DCACHE dcache_disable(); #endif printf("update dts\n"); return 0; } int fdt_enable_node(char *name, int onoff) { int nodeoffset = 0; int ret = 0; nodeoffset = fdt_path_offset(working_fdt, name); ret = fdt_set_node_status(working_fdt, nodeoffset, onoff ? FDT_STATUS_OKAY : FDT_STATUS_DISABLED, 0); if (ret < 0) { printf("disable nand error: %s\n", fdt_strerror(ret)); } return ret; }