/* * hi3556av100.c * * The board init for hisilicon * * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "../../../lib/hw_dec/hw_decompress_v2.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) { /* Enable D-cache. I-cache is already enabled in start.S */ dcache_enable(); } #endif static int boot_media = BOOT_MEDIA_UNKNOWN; #if defined(CONFIG_SHOW_BOOT_PROGRESS) void show_boot_progress(int progress) { printf("Boot reached stage %d\n", progress); } #endif #define COMP_MODE_ENABLE ((unsigned int)0x0000EAEF) static inline void delay(unsigned long loops) { __asm__ volatile("1:\n" "subs %0, %1, #1\n" "bne 1b" : "=r"(loops) : "0"(loops)); } /* get uboot start media. */ int get_boot_media(void) { return boot_media; } int get_text_base(void) { return CONFIG_SYS_TEXT_BASE; } static void boot_flag_init(void) { unsigned int regval, boot_mode; /* get boot mode */ regval = __raw_readl(SYS_CTRL_REG_BASE + REG_SYSSTAT); boot_mode = get_sys_boot_mode(regval); switch (boot_mode) { /* [5:4] 00b - boot from spi device */ case BOOT_FROM_SPI: if (get_spi_device_type(regval)) boot_media = BOOT_MEDIA_NAND; else boot_media = BOOT_MEDIA_SPIFLASH; break; /* [5:4] 01b - boot from spi nand device */ case BOOT_FROM_SPI_NAND: boot_media = BOOT_MEDIA_NAND; break; /* [5:4] 01b - boot from Nand device */ case BOOT_FROM_NAND: boot_media = BOOT_MEDIA_NAND; break; /* [5:4] 10b - boot from emmc */ case BOOT_FROM_EMMC: boot_media = BOOT_MEDIA_EMMC; break; default: boot_media = BOOT_MEDIA_UNKNOWN; break; } } int board_early_init_f(void) { return 0; } #define UBOOT_DATA_ADDR 0x21000000ul #define UBOOT_DATA_SIZE 0x80000UL int data_to_spiflash(void) { static struct spi_flash *flash = NULL; void *buf = NULL; unsigned int val; /* 0:bus 0:cs 1000000:max_hz 0x3:spi_mode */ flash = spi_flash_probe(0, 0, 1000000, 0x3); if (!flash) { printf("Failed to initialize SPI flash\n"); return -1; /* -1:failed */ } /* erase the address range. */ printf("Spi flash erase...\n"); val = spi_flash_erase(flash, NUM_0, UBOOT_DATA_SIZE); if (val) { printf("SPI flash sector erase failed\n"); return 1; /* 1:failed */ } buf = map_physmem((unsigned long)UBOOT_DATA_ADDR, UBOOT_DATA_SIZE, MAP_WRBACK); if (!buf) { puts("Failed to map physical memory\n"); return 1; /* 1:failed */ } /* copy the data from RAM to FLASH */ printf("Spi flash write...\n"); val = flash->write(flash, NUM_0, UBOOT_DATA_SIZE, buf); if (val) { printf("SPI flash write failed, return %u\n", val); unmap_physmem(buf, UBOOT_DATA_SIZE); return 1; /* 1:failed */ } unmap_physmem(buf, UBOOT_DATA_SIZE); return 0; /* 0:success */ } int data_to_nandflash(void) { struct mtd_info *nand_flash = NULL; void *buf = NULL; size_t length = UBOOT_DATA_SIZE; unsigned int val; nand_flash = nand_info[0]; printf("Nand flash erase...\n"); val = nand_erase(nand_flash, 0, UBOOT_DATA_SIZE); if (val) { printf("Nand flash erase failed\n"); return 1; } buf = map_physmem((unsigned long)UBOOT_DATA_ADDR, UBOOT_DATA_SIZE, MAP_WRBACK); if (!buf) { puts("Failed to map physical memory\n"); return 1; } printf("Nand flash write...\n"); val = nand_write(nand_flash, 0, &length, buf); if (val) { printf("Nand flash write failed, return %u\n", val); unmap_physmem(buf, UBOOT_DATA_SIZE); return 1; } unmap_physmem(buf, UBOOT_DATA_SIZE); return 0; } int data_to_emmc(void) { struct mmc *mmc = find_mmc_device(0); void *buf = NULL; if (!mmc) return 1; (void)mmc_init(mmc); buf = map_physmem((unsigned long)UBOOT_DATA_ADDR, UBOOT_DATA_SIZE, MAP_WRBACK); if (!buf) { puts("Failed to map physical memory\n"); return 1; } printf("MMC write...\n"); blk_dwrite(mmc_get_blk_desc(mmc), 0, (UBOOT_DATA_SIZE >> NUM_9), buf); unmap_physmem(buf, UBOOT_DATA_SIZE); return 0; } int save_bootdata_to_flash(void) { unsigned int sd_update_flag = 0; int ret = 0; sd_update_flag = readl(REG_BASE_SCTL + REG_SC_GEN4); if (sd_update_flag == START_MAGIC) { #if defined(CONFIG_HIFMC) if (boot_media == BOOT_MEDIA_SPIFLASH) { ret = data_to_spiflash(); if (ret != 0) return ret; } if (boot_media == BOOT_MEDIA_NAND) { ret = data_to_nandflash(); if (ret != 0) return ret; } #endif #if defined(CONFIG_MMC) if (boot_media == BOOT_MEDIA_EMMC) { ret = data_to_emmc(); if (ret != 0) return ret; } #endif printf("update success!\n"); } return 0; } int auto_update_flag = 0; int bare_chip_program = 0; #define REG_BASE_GPIO4 0x045f4000 #define GPIO4_3_DATA_OFST 0x20 #define GPIO_DIR_OFST 0x400 #ifdef CONFIG_TARGET_HI3556AV100 /* * upgrade status register address */ #define UPGRADE_STATUS_REG_ADDR (0x04590048) typedef enum tagUPGRADE_STATUS_E { UPGRADE_STATUS_IDLE = 0, UPGRADE_STATUS_PROCESSING, UPGRADE_STATUS_FINISH, UPGRADE_STATUS_BUTT } upgrade_status_e; #endif int is_bare_program(void) { return 1; } #if (CONFIG_AUTO_UPDATE == 1) int is_auto_update(void) { #if (defined CONFIG_AUTO_SD_UPDATE) || (defined CONFIG_AUTO_USB_UPDATE) /* to add some judgement if neccessary */ unsigned int val[NUM_3]; #ifdef CONFIG_TARGET_HI3556AV100 unsigned int *puregval = (unsigned int *)UPGRADE_STATUS_REG_ADDR; if (((*puregval) & (UPGRADE_STATUS_PROCESSING)) != 0) return 1; /* update enable */ #endif writel(0, REG_BASE_GPIO4 + GPIO_DIR_OFST); val[NUM_0] = readl(REG_BASE_GPIO4 + GPIO4_3_DATA_OFST); if (val[NUM_0]) return 0; udelay(10000); /* delay 10000 us */ val[NUM_1] = readl(REG_BASE_GPIO4 + GPIO4_3_DATA_OFST); udelay(10000); /* delay 10000 us */ val[NUM_2] = readl(REG_BASE_GPIO4 + GPIO4_3_DATA_OFST); udelay(10000); /* delay 10000 us */ if (val[NUM_0] == val[NUM_1] && val[NUM_1] == val[NUM_2] && val[NUM_0] == NUM_0) return 1; /* update enable */ else return 0; #else return 0; #endif } #endif /* CONFIG_AUTO_UPDATE */ #ifdef CONFIG_TARGET_HI3556AV100 struct boot_medium_interface { char name[0x10]; /* 0x10:name len */ int (*init)(void); int (*read)(unsigned long offset, unsigned long len, void *buf); }; /* spi nand configure */ #if defined(CONFIG_HIFMC_SPI_NAND)|| defined(CONFIG_HIFMC_NAND) #define NAND_MAX_SIZE 0xFFFFFFFF static int nand_flash_read(unsigned long offset, unsigned long len, void *buf) { struct mtd_info *mtd = nand_info[NUM_0]; size_t rwsize = len; return nand_read_skip_bad(mtd, offset, &rwsize, NULL, NAND_MAX_SIZE, (unsigned char *)buf); } #endif #ifdef CONFIG_HIFMC_SPI_NOR /* spi nor configure */ struct spi_flash *spiflash; #include "spi_flash.h" static int spinor_flash_read(unsigned long offset, unsigned long len, void *buf) { /* 0,0,0,0:bus,cs,max_hz,spi_mode */ spiflash = spi_flash_probe(0, 0, 0, 0); if (!spiflash) printf("spiflash is null!\n"); spi_flash_read(spiflash, offset, len, buf); return 0; } #endif #ifdef CONFIG_MMC static int mmc_read_data(unsigned long offset, unsigned long len, void *buf) { unsigned long ret; struct mmc *mmc = find_mmc_device(0); if (!mmc) return 1; (void)mmc_init(mmc); ret = blk_dread(mmc_get_blk_desc(mmc), offset, len, buf); return ret; } #endif static struct boot_medium_interface boot_intf[NUM_1] = {0}; static struct boot_medium_interface *boot_intf_p; void boot_medium_init(void) { /* register boot media interface */ if (get_boot_media() == BOOT_MEDIA_SPIFLASH) { printf("boot_media spinor!\n"); boot_intf[NUM_0].init = NULL; #ifdef CONFIG_HIFMC_SPI_NOR boot_intf[NUM_0].read = spinor_flash_read; #endif strncpy(boot_intf[NUM_0].name, "spinor", sizeof(boot_intf[NUM_0].name)); } else if (get_boot_media() == BOOT_MEDIA_NAND) { printf("boot_media nand!\n"); boot_intf[NUM_0].init = NULL; #if defined(CONFIG_HIFMC_SPI_NAND)|| defined(CONFIG_HIFMC_NAND) boot_intf[NUM_0].read = nand_flash_read; #endif strncpy(boot_intf[NUM_0].name, "nand", sizeof(boot_intf[NUM_0].name)); } else if (get_boot_media() == BOOT_MEDIA_EMMC) { printf("boot_media emmc!\n"); boot_intf[NUM_0].init = NULL; #ifdef CONFIG_MMC boot_intf[NUM_0].read = mmc_read_data; #endif strncpy(boot_intf[NUM_0].name, "emmc", sizeof(boot_intf[NUM_0].name)); } else { printf("boot_media unkonw error !\n"); } boot_intf_p = &boot_intf[NUM_0]; /* boot media init */ if (boot_intf_p->init) boot_intf_p->init(); } #endif void select_upgrade_dev(void) { #ifdef CONFIG_EMMC unsigned int uval = readl(UPGRADE_STATUS_REG_ADDR); unsigned int stor_dev = 0; unsigned int stor_paration = 0; stor_dev = (uval >> 16) & 0x03; /* 16,0x03: store dev */ stor_paration = (uval >> 18) & 0x1f; /* 18,0x1f: store paration */ if (((uval) & (UPGRADE_STATUS_PROCESSING)) != NUM_0) { /* the upgrade startup by linux application */ if (stor_dev == NUM_0) { /* emmc */ target_dev = NUM_0; target_paratition = stor_paration; } else { /* sd */ target_dev = NUM_1; } } else { /* the upgrade startup by upgrade key on the board, os defaule upgrade style */ target_dev = NUM_1; } printf("update dev is %d: paratition is %d\n", target_dev, target_paratition); #endif return; } int misc_init_r(void) { #ifdef CONFIG_TARGET_HI3556AV100 boot_medium_init(); #endif #ifdef CONFIG_RANDOM_ETHADDR random_init_r(); #endif env_set("verify", "n"); /* bare chip program flag */ if (is_bare_program()) bare_chip_program = 1; else bare_chip_program = 0; #if (CONFIG_AUTO_UPDATE == 1) /* auto update flag */ if (is_auto_update()) auto_update_flag = 1; else auto_update_flag = 0; #ifdef CFG_MMU_HANDLEOK dcache_stop(); #endif #ifdef CFG_MMU_HANDLEOK dcache_start(); #endif #endif #if (CONFIG_AUTO_UPDATE == 1) if (auto_update_flag) { #ifdef CONFIG_TARGET_HI3556AV100 select_upgrade_dev(); int result = do_auto_update(); if (result == 0) { unsigned int uregval = readl(UPGRADE_STATUS_REG_ADDR); udelay(10000); /* delay 10000 us */ if ((uregval & UPGRADE_STATUS_PROCESSING) != NUM_0) { writel(UPGRADE_STATUS_FINISH, UPGRADE_STATUS_REG_ADDR); printf("upgrade status: finish\n"); } printf("update success\n"); do_reset(NULL, 0, 0, NULL); } #else do_auto_update(); #endif } #endif if (bare_chip_program && !auto_update_flag) save_bootdata_to_flash(); return 0; } int board_init(void) { DECLARE_GLOBAL_DATA_PTR; gd->bd->bi_arch_number = MACH_TYPE_HI3556AV100; gd->bd->bi_boot_params = CFG_BOOT_PARAMS; boot_flag_init(); return 0; } int dram_init(void) { DECLARE_GLOBAL_DATA_PTR; gd->ram_size = PHYS_SDRAM_1_SIZE; return 0; } void reset_cpu(ulong addr) { /* 0x12345678:writing any value will cause a reset. */ writel(0x12345678, REG_BASE_SCTL + REG_SC_SYSRES); while (1); } int timer_init(void) { /* * Under uboot, 0xffffffff is set to load register,] * timer_clk equals BUSCLK/2/256. * e.g. BUSCLK equals 50M, it will roll back after 0xffffffff/timer_clk * 43980s equals 12hours */ __raw_writel(0, CFG_TIMERBASE + REG_TIMER_CONTROL); __raw_writel(~0, CFG_TIMERBASE + REG_TIMER_RELOAD); /* 32 bit, periodic */ __raw_writel(CFG_TIMER_CTRL, CFG_TIMERBASE + REG_TIMER_CONTROL); __raw_writel(0, TIMER8_REG_BASE + REG_TIMER_CONTROL); __raw_writel(~0, TIMER8_REG_BASE + REG_TIMER_RELOAD); /* 32 bit, periodic */ __raw_writel(CFG_TIMER_CTRL, TIMER8_REG_BASE + REG_TIMER_CONTROL); return 0; } int board_eth_init(bd_t *bis) { int rc = 0; #ifdef CONFIG_HIGMACV300_ETH rc = higmac_initialize(bis); #endif return rc; } #ifdef CONFIG_GENERIC_MMC int board_mmc_init(bd_t *bis) { int ret = 0; #ifdef CONFIG_HISI_SDHCI #if !defined(CONFIG_HIFMC) || defined(CONFIG_AUTO_SD_UPDATE) int dev_num = 0; #endif #ifndef CONFIG_HIFMC ret = hisi_sdhci_add_port(0, EMMC_BASE_REG, MMC_TYPE_MMC); if (!ret) { ret = hisi_mmc_init(dev_num); if (ret) printf("No EMMC device found !\n"); } dev_num++; #endif #ifdef CONFIG_AUTO_SD_UPDATE if (is_auto_update()) { ret = hisi_sdhci_add_port(1, SDIO0_BASE_REG, MMC_TYPE_SD); if (ret) return ret; ret = hisi_mmc_init(dev_num); if (ret) printf("No SD device found !\n"); } #endif #endif return ret; } #endif #ifdef CONFIG_SECURE_SCHEME_ENABLE /* macros to get secure register's offset address */ #define sec_rgn_map_ofst(region_idx) (0x1100 + 0x10 * (region_idx)) #define sec_rgn_map_ext_ofst(region_idx) (0x1200 + 0x10 * (region_idx)) #define sec_rgn_attrib_ofst(region_idx) (0x1104 + 0x10 * (region_idx)) #define sec_mid_wr_ofst(region_idx) (0x1108 + 0x10 * (region_idx)) #define sec_mid_wr_ext_ofst(region_idx) (0x1204 + 0x10 * (region_idx)) #define sec_mid_rd_ofst(region_idx) (0x110c + 0x10 * (region_idx)) #define sec_mid_rd_ext_ofst(region_idx) (0x1208 + 0x10 * (region_idx)) #define SEC_BYPASS_OFST 0x1004 #define SEC_INT_EN_OFST 0x1020 /* macros for register value */ #define SECURITY_ENABLE 0xff #define SEC_INV_EN (0x1 << 4) #define SHARE_REGN_EN (0xf) #define SECUR_REGN_EN (0xc) #define NON_SEC_REGN_EN (0x3) #define A53CPU0_MID 0xf #define A53CPU1_MID 0x11 #define DSP_M0_MID 0x13 #define AVSP_M2_MID 0x18 #define DSP_M1_MID 0x1c #define MID_HIGH_START_BIT 0x20 #define FMC_MID 0x21 #define EMMC_MID 0x28 #define IPCM_REGN_WR_MID_MASK ((0x1 << A53CPU0_MID) | (0x1 << A53CPU1_MID)) #define IPCM_REGN_RD_MID_MASK IPCM_REGN_WR_MID_MASK #define DSP_REGN_WR_MID_MASK ((0x1 << A53CPU0_MID) | (0x1 << DSP_M0_MID) | \ (0x1 << AVSP_M2_MID) | (0x1 << DSP_M1_MID)) #define DSP_REGN_RD_MID_MASK DSP_REGN_WR_MID_MASK #define LITEOS_REGN_WR_MID_MASK (0x1 << A53CPU1_MID) #define LITEOS_REGN_RD_MID_MASK LITEOS_REGN_WR_MID_MASK #define LINUX_REGN_WR_MID_MASK ((0x1 << A53CPU0_MID)) #define LINUX_REGN_RD_MID_MASK LINUX_REGN_WR_MID_MASK #define LINUX_REGN_WR_MID_HIGH_MASK ((0x1 << (FMC_MID - MID_HIGH_START_BIT)) | \ (0x1 << (EMMC_MID - MID_HIGH_START_BIT))) #define LINUX_REGN_RD_MID_HIGH_MASK LINUX_REGN_WR_MID_HIGH_MASK #define REGN_CTRL_ENABLE (0x1 << 31) #define IPCM_REGN_HIGH_ADDR 0x2000 /* high 16 bit of address */ #define IPCM_REGN_SIZE 0x20 /* 0x20 * 64K Byte */ #define DSP_REGN_HIGH_ADDR 0x2020 /* high 16 bit of address */ #define DSP_REGN_SIZE 0x1e0 /* 0x1e0 * 64K Byte */ #define LITEOS_REGN_HIGH_ADDR 0x2200 /* high 16 bit of address */ #define LITEOS_REGN_SIZE 0x1000 /* 0x1000 * 64K Byte */ #define LINUX_REGN_HIGH_ADDR 0x3200 /* high 16 bit of address */ #define LINUX_REGN_SIZE 0x1000 /* 0x1000 * 64K Byte */ #define IPCM_DDR_REGN_IDX 1 #define DSP_DDR_REGN_IDX 2 #define LITEOS_DDR_REGN_IDX 3 #define LINUX_DDR_REGN_IDX 4 static void ipcm_tzasc_init(void) { /* Set the share access authority */ writel(SEC_INV_EN | SHARE_REGN_EN, DDRC0_REG_BASE + sec_rgn_attrib_ofst(IPCM_DDR_REGN_IDX)); /* Set the master id mask of write command */ writel(IPCM_REGN_WR_MID_MASK, DDRC0_REG_BASE + sec_mid_wr_ofst(IPCM_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_wr_ext_ofst(IPCM_DDR_REGN_IDX)); /* Set the master id mask of read command */ writel(IPCM_REGN_RD_MID_MASK, DDRC0_REG_BASE + sec_mid_rd_ofst(IPCM_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_rd_ext_ofst(IPCM_DDR_REGN_IDX)); /* Set the start address and enable bit */ writel(REGN_CTRL_ENABLE | IPCM_REGN_HIGH_ADDR, DDRC0_REG_BASE + sec_rgn_map_ofst(IPCM_DDR_REGN_IDX)); /* Set the size of ipcm ddr region */ writel(IPCM_REGN_SIZE, DDRC0_REG_BASE + sec_rgn_map_ext_ofst( IPCM_DDR_REGN_IDX)); } static void dsp_tzasc_init(void) { /* Set the share access authority */ writel(SEC_INV_EN | SHARE_REGN_EN, DDRC0_REG_BASE + sec_rgn_attrib_ofst(DSP_DDR_REGN_IDX)); /* Set the master id mask of write command */ writel(DSP_REGN_WR_MID_MASK, DDRC0_REG_BASE + sec_mid_wr_ofst(DSP_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_wr_ext_ofst(DSP_DDR_REGN_IDX)); /* Set the master id mask of read command */ writel(DSP_REGN_RD_MID_MASK, DDRC0_REG_BASE + sec_mid_rd_ofst(DSP_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_rd_ext_ofst(DSP_DDR_REGN_IDX)); /* Set the start address and enable bit */ writel(REGN_CTRL_ENABLE | DSP_REGN_HIGH_ADDR, DDRC0_REG_BASE + sec_rgn_map_ofst(DSP_DDR_REGN_IDX)); /* Set the size of dsp ddr region */ writel(DSP_REGN_SIZE, DDRC0_REG_BASE + sec_rgn_map_ext_ofst(DSP_DDR_REGN_IDX)); } static void liteos_tzasc_init(void) { /* Set the secure access authority */ writel(SEC_INV_EN | SECUR_REGN_EN, DDRC0_REG_BASE + sec_rgn_attrib_ofst(LITEOS_DDR_REGN_IDX)); /* Set the master id mask of write command */ writel(LITEOS_REGN_WR_MID_MASK, DDRC0_REG_BASE + sec_mid_wr_ofst(LITEOS_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_wr_ext_ofst(LITEOS_DDR_REGN_IDX)); /* Set the master id mask of read command */ writel(LITEOS_REGN_RD_MID_MASK, DDRC0_REG_BASE + sec_mid_rd_ofst(LITEOS_DDR_REGN_IDX)); writel(0, DDRC0_REG_BASE + sec_mid_rd_ext_ofst(LITEOS_DDR_REGN_IDX)); /* Set the start address and enable bit */ writel(REGN_CTRL_ENABLE | LITEOS_REGN_HIGH_ADDR, DDRC0_REG_BASE + sec_rgn_map_ofst(LITEOS_DDR_REGN_IDX)); /* Set the size of dsp ddr region */ writel(LITEOS_REGN_SIZE, DDRC0_REG_BASE + sec_rgn_map_ext_ofst(LITEOS_DDR_REGN_IDX)); } static void linux_tzasc_init(void) { /* Set the non-secure access authority */ writel(SEC_INV_EN | NON_SEC_REGN_EN, DDRC0_REG_BASE + sec_rgn_attrib_ofst(LINUX_DDR_REGN_IDX)); /* Set the master id mask of write command */ writel(LINUX_REGN_WR_MID_MASK, DDRC0_REG_BASE + sec_mid_wr_ofst(LINUX_DDR_REGN_IDX)); writel(LINUX_REGN_WR_MID_HIGH_MASK, DDRC0_REG_BASE + sec_mid_wr_ext_ofst(LINUX_DDR_REGN_IDX)); /* Set the master id mask of read command */ writel(LINUX_REGN_RD_MID_MASK, DDRC0_REG_BASE + sec_mid_rd_ofst(LINUX_DDR_REGN_IDX)); writel(LINUX_REGN_RD_MID_HIGH_MASK, DDRC0_REG_BASE + sec_mid_rd_ext_ofst(LINUX_DDR_REGN_IDX)); /* Set the start address and enable bit */ writel(REGN_CTRL_ENABLE | LINUX_REGN_HIGH_ADDR, DDRC0_REG_BASE + sec_rgn_map_ofst(LINUX_DDR_REGN_IDX)); /* Set the size of dsp ddr region */ writel(LINUX_REGN_SIZE, DDRC0_REG_BASE + sec_rgn_map_ext_ofst( LINUX_DDR_REGN_IDX)); } static int tzasc_init(void) { /* * Set IPCM ddr region attribution(0x20000000 ~ 0x20200000)*] * */ ipcm_tzasc_init(); /* * Set DSP ddr region attribution(0x20200000 ~ 0x22000000)*] * */ dsp_tzasc_init(); /* * Set Liteos ddr region attribution(0x22000000 ~ 0x10000000)*] * */ liteos_tzasc_init(); /* * Set Linux ddr region attribution(0x32000000 ~ 0x10000000)*] * */ linux_tzasc_init(); /* Disable interrupt */ writel(0, DDRC0_REG_BASE + SEC_INT_EN_OFST); /* Enable security */ writel(SECURITY_ENABLE, DDRC0_REG_BASE + SEC_BYPASS_OFST); return 0; } #endif #ifdef CONFIG_TARGET_HI3556AV100 #define PAGE_SIZE 4096 #define page_size_align(x) (((x)+(PAGE_SIZE)-1) / (PAGE_SIZE)*(PAGE_SIZE)) static int __run_a53cpu1(unsigned int addr) { unsigned int start_phys = 0; unsigned int crg_phys = 0x04510000; /* 0x04510000:crg base */ unsigned int regval; printf("## Starting A53 at 0x%08X ...\n", addr); /* 0xe51ff004 = "ldr pc, [pc, #-4]" */ writel(0xe51ff004, start_phys); /* 0x4:next addr value will be the "go_a53" addr */ writel(addr, (start_phys + 0x4)); asm("dsb"); asm("isb"); /* clear the slave cpu reset */ regval = readl(crg_phys + 0xcc); regval &= ~(0x1 << 5); /* 0x1,5:corel soft reset request */ regval &= ~(0x1 << 25); /* 0x1,25:cluster1 soft reset request */ writel(regval, (crg_phys + 0xcc)); return 0; } static int start_a53cpu1(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { int ret = 0; unsigned int addr; unsigned int srcaddr; unsigned int offset; unsigned int maxsize = 0; int size_compressed; int size_uncompressed = 0; if (argc == NUM_2) { addr = simple_strtoul(argv[NUM_1], NULL, 16); /* 16:base */ flush_dcache_all(); return __run_a53cpu1(addr); } if (argc != NUM_5) return CMD_RET_USAGE; #ifdef CONFIG_SECURE_SCHEME_ENABLE tzasc_init(); #endif addr = simple_strtoul(argv[NUM_1], NULL, 16); /* 16:base */ srcaddr = simple_strtoul(argv[NUM_2], NULL, 16); /* 16:base */ offset = simple_strtoul(argv[NUM_3], NULL, 16); /* 16:base */ maxsize = simple_strtoul(argv[NUM_4], NULL, 16); /* 16:base */ /* 0x80:Read A53bin size */ ret = boot_intf_p->read(offset, 0x80, (void *)srcaddr); flush_dcache_all(); /* read A53bin to DDR */ size_compressed = *(int *)(srcaddr + COMPRESSED_SIZE_OFFSET); if (page_size_align(size_compressed) > maxsize) { printf("->a53 Image size infor error !\n"); return 0; } boot_intf_p->read(offset, page_size_align(size_compressed), (void *)srcaddr); flush_dcache_all(); size_compressed = *(int *)(srcaddr + COMPRESSED_SIZE_OFFSET); size_uncompressed = *(int *)(srcaddr + UNCOMPRESSED_SIZE_OFFSET); hw_dec_init(); ret = hw_dec_decompress(NULL, (unsigned char *)(uintptr_t)addr, &size_uncompressed, NULL, ((unsigned char *)(uintptr_t)srcaddr + HIGZIP_HEAD_SIZE), size_compressed, NULL); if (ret) printf("->a53 decompress Fail!\n"); hw_dec_uinit(); return __run_a53cpu1(addr); } U_BOOT_CMD( go_a53cpu1, CONFIG_SYS_MAXARGS, 3, start_a53cpu1, "start a53-cpu1 at address 'addr'", "addr [arg ...]\n - start a53 application at address 'addr'\n" " passing 'arg' as arguments" ); #else static int start_a53cpu1(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { unsigned int addr; if (argc < NUM_2) return CMD_RET_USAGE; #ifdef CONFIG_SECURE_SCHEME_ENABLE tzasc_init(); #endif addr = simple_strtoul(argv[NUM_1], NULL, 16); /* 16:base */ printf("## Starting A53 at 0x%08X ...\n", addr); /* start up a53 */ { unsigned int start_phys = 0; unsigned int crg_phys = 0x04510000; /* 0x04510000:crg base */ unsigned int regval; /* 0xe51ff004 = "ldr pc, [pc, #-4]" */ writel(0xe51ff004, start_phys); /* 0x4:next addr value will be the "go_a53" addr */ writel(addr, (start_phys + 0x4)); asm("dsb"); asm("isb"); /* clear the slave cpu reset */ regval = readl(crg_phys + 0xcc); regval &= ~(0x1 << 5); /* 0x1,5:corel soft reset request */ regval &= ~(0x1 << 25); /* 0x1,25:cluster1 soft reset request */ writel(regval, (crg_phys + 0xcc)); } return 0; } U_BOOT_CMD( go_a53cpu1, CONFIG_SYS_MAXARGS, 1, start_a53cpu1, "start a53-cpu1 at address 'addr'", "addr [arg ...]\n - start a53 application at address 'addr'\n" " passing 'arg' as arguments" ); #endif