241 lines
6.2 KiB
C
241 lines
6.2 KiB
C
#include <libfdt.h>
|
||
#include <common.h>
|
||
#include <boot_param.h>
|
||
|
||
#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;
|
||
}
|
||
|