449 lines
11 KiB
C
Executable File
449 lines
11 KiB
C
Executable File
/*
|
|
* (C) Copyright 2019-2020
|
|
* Stelian Pop <junbao.zhang@molchip.com>
|
|
* Lead Tech Design <www.molchip.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <mach/hardware.h>
|
|
#include <mach/clk.h>
|
|
#include <mach/spl.h>
|
|
#include <mach/uart_drv.h>
|
|
#include <mach/uart.h>
|
|
#include <mach/spic.h>
|
|
#include <mach/norflash.h>
|
|
#include <mach/nandflash.h>
|
|
#include <mach/download.h>
|
|
#include <mach/board.h>
|
|
#include <mach/dma.h>
|
|
#include <mach/ddr.h>
|
|
#include <nand.h>
|
|
#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 <length){
|
|
length = mtd->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);
|
|
}
|
|
|
|
}
|
|
}
|
|
|