/* * (C) Copyright 2019-2020 * Stelian Pop * Lead Tech Design * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../board/molchip/board/system.h" #ifdef CONFIG_SDL_MMC_SUPPORT #include "mach/sd_mmc.h" #endif #ifdef CONFIG_ARM64 void hang(void) { while(1); } #endif void s_init(void) { //timer clk init molchip_systimer_clk_enable(); //uart0 clk init molchip_uart_clk_enable(REG_UART0_BASE); //uart1 clk init molchip_uart_clk_enable(REG_UART1_BASE); //spic clk enable molchip_spic_clk_enable(); #ifndef CONFIG_TARGET_TS01 //dma clk enable molchip_dma_clk_enable(); #endif } /* This function prepares the hardware for * execution from system RAM (DRAM, DDR...) As system RAM may not * be available yet, , board_init_f() must use the current GD to * store any data which must be passed on to later stages. These * data include the relocation destination, the future stack, and * the future GD location. * * bss data not init */ void board_init_f(ulong dummy) { /* CPU/BUS CLK config if needed*/ /* hardware init */ //uart_hw_init(); board_spic_init(); } #ifdef CONFIG_SDL_MMC_SUPPORT u32 rd_buf = 0x70000000; void emmc_mini_init(void) { u32 i; int err = false; u32 rca = 1; u32 csd[4] = {0}; mmc_clk_set(); mmc_phy_init(); for (i = 0; i < ARRAY_SIZE(freqs); i++) { sdhci_init(0, freqs[i]); get_rom_version(); err = init_emmc(&rca, csd); if(err == true) break; } if(err == false) { printf("emmc init fail!!!\n"); } sdhci_set_ios(TRANS_DATA_FREQS); } int sdhci_all_data_tran_done(void) { u32 val; val = sdhci_readl(SDHCI_INT_STATUS); if(val & SDHCI_INT_ERROR){ return -1; } if (val & SDHCI_INT_RESPONSE) { if(val & SDHCI_INT_DATA_END) { sdhci_writel(val, SDHCI_INT_STATUS); return 0; } else { if(val & SDHCI_INT_DMA_END){ int start_addr; start_addr = sdhci_readl(SDHCI_ADMA_ADDRESS); sdhci_writel(SDHCI_INT_DMA_END, SDHCI_INT_STATUS); sdhci_writel(start_addr, SDHCI_ADMA_ADDRESS); } } } return 1; } int sdl_emmc_program_image( u32 dest, u32 len, u32 addr) { int err; u32 size; u8 boot_partition; u32 sector; struct mmc_command stop = {0}; boot_partition = ext_csd[EXT_CSD_PART_CONFIG]; boot_partition &= EXT_CSD_PART_CONFIG_BOOT_MASK; size = ALIGN(len, 512); sector = ALIGN(dest, 512)/512; boot_partition &= ~0x07; boot_partition |= 1; err = emmc_switch(EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, boot_partition); emmc_get_ext_csd((u8 **)ext_csd); err = emmc_blk_mq_issue_rw_rq(WRITE, addr, sector, size); while(0 != sdhci_all_data_tran_done()); stop.opcode = MMC_STOP_TRANSMISSION; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; err = mmc_start_request(&stop); boot_partition &= ~0x07; boot_partition |= 2; err = emmc_switch(EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, boot_partition); err = emmc_blk_mq_issue_rw_rq(WRITE, addr, sector, size); while(0 != sdhci_all_data_tran_done()); stop.opcode = MMC_STOP_TRANSMISSION; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; err = mmc_start_request(&stop); if(err == 1) return 0; return 0; } int sdl_emmc_program_user_part(u32 dest, u32 len, u32 addr) { int err; u8 boot_partition; u32 sector; u32 size; struct mmc_command stop = {0}; size = ALIGN(len, 512); sector = ALIGN(dest, 512)/512; boot_partition = ext_csd[EXT_CSD_PART_CONFIG]; boot_partition &= EXT_CSD_PART_CONFIG_BOOT_MASK; boot_partition &= ~0x07; err = emmc_switch(EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, boot_partition); emmc_get_ext_csd((u8 **)ext_csd); //while(sdhci_all_data_tran_done() != 0); err = emmc_blk_mq_issue_rw_rq(WRITE, addr, sector, size); while(sdhci_all_data_tran_done() != 0); stop.opcode = MMC_STOP_TRANSMISSION; stop.flags = MMC_RSP_R1B | MMC_CMD_AC; err = mmc_start_request(&stop); if(err == 1){ return 0; } return 0; } #endif #ifdef CONFIG_SDL_NAND_SUPPORT int spi_nand_program_image(u32 dest, u32 len, u8 *buf) { nand_erase_options_t opts; int ret; struct mtd_info *mtd; u32 actual; loff_t lim; struct spi_nand_info *nand_info; struct nand_chip *chip ; u32 length = (64<<11); u8 *buf_tmp; buf_tmp = buf + 0x1000000; mtd = get_nand_dev_by_index(0); chip = mtd_to_nand(mtd); if(len erasesize ; memset(buf_tmp, 0xff, length); memcpy(buf_tmp, buf, len); } else{ if(dest == 0){ length = mtd->erasesize + UBOOT_MAX_SIZE; memset(buf_tmp, 0xff, length); memcpy(buf_tmp, buf, (32<<10)); memcpy(buf_tmp + mtd->erasesize, buf+(32<<10), len-(32<<10)); } else{ memset(buf_tmp, 0xff, len); memcpy(buf_tmp, buf, len); length = len; } } if(dest == 0) { nand_info = (struct spi_nand_info *)(buf_tmp + NAND_INFO_OFFSET); memset(nand_info, 0,sizeof(struct spi_nand_info)); sfc_write_data((u8 *)buf_tmp, 512); sfc_all_clr(); sfc_data_length(512); sfc_spare_length(0); sfc_ecc_mode(ECC_24BIT); sfc_ecc_pos(0x0); sfc_ecc_enc_mode(true); sfc_access_start(); sfc_read_spare(nand_info->ecc,44,1); nand_info->main_size = 2048; if(mtd->writesize == 4096) nand_info->oob_size = mtd->oobsize/2; else nand_info->oob_size = mtd->oobsize; nand_info->sector_num = nand_info->main_size >> 10; nand_info->block_page = mtd->erasesize / mtd->writesize; if (chip->options & SPINAND_ECC_MODE_24_bit) { nand_info->ecc_mode = 1; nand_info->ecc_pos = nand_info->oob_size / nand_info->sector_num - 42; nand_info->spare_size = nand_info->ecc_pos; } else { nand_info->ecc_mode = 0; nand_info->ecc_pos = nand_info->oob_size / nand_info->sector_num - 14; nand_info->spare_size = nand_info->ecc_pos; } // memcpy(buf_tmp + mtd->erasesize, buf_tmp, (32<<10)); } lim = chip->chipsize; memset(&opts, 0, sizeof(opts)); opts.offset = dest; opts.length = length; opts.quiet = 1; ret = nand_erase_opts(mtd, &opts); if (ret){ return ret; } if((mtd->writesize == 4096) && (dest == 0)){ int temp_len = 32*1024; ret = nand_write_skip_bad(mtd, dest, (size_t *)&temp_len, &actual, lim, buf_tmp, WITH_WR_VERIFY); if(ret){ return ret; } temp_len = length - mtd->erasesize; ret = nand_write_skip_bad(mtd, dest+256*1024, (size_t *)&temp_len, &actual, lim, (buf_tmp + 256*1024) , WITH_WR_VERIFY); if(ret){ return ret; } } else{ ret = nand_write_skip_bad(mtd, dest, (size_t *)&length, &actual, lim, buf_tmp, WITH_WR_VERIFY); if(ret){ return ret; } } return 0; } #endif #if 1 static void boot_mode_pinmux_set(unsigned int boot_mode, unsigned int group_id) { switch (boot_mode) { case 1: *(volatile unsigned int*)0x10200110 = 0; /* EMMC D0 */ *(volatile unsigned int*)0x10200114 = 0; /* EMMC D1 */ *(volatile unsigned int*)0x10200118 = 0; /* EMMC D2 */ *(volatile unsigned int*)0x1020011C = 0; /* EMMC D3 */ *(volatile unsigned int*)0x10200130 = 0; /* EMMC CMD */ *(volatile unsigned int*)0x10200134 = 0; /* EMMC CLK */ *(volatile unsigned int*)0x10200138 = 0; /* EMMC RSTN */ if(group_id == 0) { *(volatile unsigned int*)0x1020013C = 0; /* EMMC DS */ *(volatile unsigned int*)0x10200120 = 0; /* EMMC D4 */ *(volatile unsigned int*)0x10200124 = 0; /* EMMC D5 */ *(volatile unsigned int*)0x10200128 = 0; /* EMMC D6 */ *(volatile unsigned int*)0x1020012C = 0; /* EMMC D7 */ } else { *(volatile unsigned int*)0x10200144 = 5; /* EMMC DS */ *(volatile unsigned int*)0x10200148 = 5; /* EMMC D4 */ *(volatile unsigned int*)0x1020014C = 5; /* EMMC D5 */ *(volatile unsigned int*)0x10200150 = 5; /* EMMC D6 */ *(volatile unsigned int*)0x10200154 = 5; /* EMMC D7 */ } break; case 5: *(volatile unsigned int*)0x10200140 = 0; /* SFC CLK */ *(volatile unsigned int*)0x10200144 = 0; /* SFC CS0N */ *(volatile unsigned int*)0x10200148 = 0; /* SFC MOSI IO0 */ *(volatile unsigned int*)0x1020014C = 0; /* SFC MISO IO1 */ *(volatile unsigned int*)0x10200150 = 0; /* SFC WP IO2 */ *(volatile unsigned int*)0x10200154 = 0; /* SFC HOLD IO3 */ *(volatile unsigned int*)0x10200158 = 0; /* SFC CS1N */ *(volatile unsigned int*)0x1c700014 = 0x10; /*sfc boa */ *(volatile unsigned int*)0x10300228 = 0x0; /*sfc boa */ break; default: break; } } #endif void board_init_r(gd_t *gd, ulong dest_addr) { u32 uart_port = 0; u32 nvm_mod; u32 idx; struct down_info *d_info; u32 ram_downaddr,nvm_downaddr,image_id; u32 i=0; int ret = 0; struct boot_image *images= (struct boot_image *)(CONFIG_SPL_TEXT_BASE - BOOT_INFO_OFFSET); nvm_mod = images->nvm_class; struct boot_image_info *info = (struct boot_image_info *)(&images->data[0]); timer_enable(); mem_malloc_init(AON_SHARE_SRAM, (64<<10)); gd->flags |= GD_FLG_FULL_MALLOC_INIT; #ifdef CONFIG_SDL_NAND_SUPPORT if(nvm_mod == BOOT_DEVICE_NAND) nand_init(); #endif #ifdef CONFIG_SDL_MMC_SUPPORT if(nvm_mod == BOOT_DEVICE_EMMC) emmc_mini_init(); #endif #ifdef CONFIG_TARGET_TS01 //store ddr parameter DRAM_param_store(nvm_mod); #endif boot_mode_pinmux_set(nvm_mod,0); uart_port = uart_identify(); uart_preboot(uart_port); while(1) { uart_boot(uart_port); d_info = get_cur_downinfo(); image_id = get_downmap_info(d_info,IMGID_CMD); idx = image_id - 1; switch(nvm_mod) { case BOOT_DEVICE_NAND: #ifdef CONFIG_SDL_NAND_SUPPORT ram_downaddr = get_downmap_info(d_info,IMGRAMADDR_CMD); nvm_downaddr = info[idx].nvm_base; ret = spi_nand_program_image(nvm_downaddr,d_info->total_len,(u8*)(unsigned long)ram_downaddr); //mark,just for debug *((volatile u32 *)(unsigned long)(0x47FFFF00+i * 4)) = d_info->imageid | (i<< 16); *((volatile u32 *)(unsigned long)(0x47FFFF20+i * 4)) = nvm_downaddr; *((volatile u32 *)(unsigned long)(0x47FFFF40+i * 4)) = d_info->total_len; *((volatile u32 *)(unsigned long)(0x47FFFF60+i * 4)) = ram_downaddr; i++; #endif break; case BOOT_DEVICE_NOR: ram_downaddr = get_downmap_info(d_info,IMGRAMADDR_CMD); nvm_downaddr = info[idx].nvm_base; ret = spi_nor_program_image(nvm_downaddr,d_info->total_len,(u8*)(unsigned long)ram_downaddr); //mark,just for debug *((volatile u32 *)(unsigned long)(0x47FFFF00+i * 4)) = d_info->imageid | (i<< 16); *((volatile u32 *)(unsigned long)(0x47FFFF20+i * 4)) = nvm_downaddr; *((volatile u32 *)(unsigned long)(0x47FFFF40+i * 4)) = d_info->total_len; *((volatile u32 *)(unsigned long)(0x47FFFF60+i * 4)) = ram_downaddr; i++; break; #ifdef CONFIG_SDL_MMC_SUPPORT case BOOT_DEVICE_EMMC: ram_downaddr = get_downmap_info(d_info,IMGRAMADDR_CMD); nvm_downaddr = info[idx].nvm_base; if(image_id == Kernel_IMG_ID || image_id == Uboot_IMG_ID) { ret = sdl_emmc_program_user_part( nvm_downaddr,d_info->total_len, ram_downaddr); } else { ret = sdl_emmc_program_image( nvm_downaddr,d_info->total_len, ram_downaddr); } break; #endif } if (ret == 0){ complete_info(INFO_OK, uart_port); } else{ complete_info(INFO_OTHER, uart_port); } } }