/**
******************************************************************************
* @file bootmain.c
* @author StarFive Technology
* @version V1.0
* @date 07/29/2020
* @brief
******************************************************************************
* @copy
*
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
*
© COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd.
*/
#include "sys.h"
#include "spi_flash.h"
#include "spi.h"
#include "timer.h"
#include "encoding.h"
#include "gpt.h"
#include "clkgen_ctrl_macro.h"
#include "syscon_sysmain_ctrl_macro.h"
#include "rstgen_ctrl_macro.h"
#include "crc32.h"
extern void boot_sdio_init(void);
extern int boot_load_gpt_partition(void* dst, const gpt_guid* partition_type_guid);
extern const gpt_guid gpt_guid_sifive_uboot;
extern const gpt_guid gpt_guid_sifive_kernel;
extern unsigned int receive_count;
typedef void ( *STARTRUNNING )( unsigned int par1 );
/*
To run a procedure from the address:start
start: start address of runing in armmode, not do address align checking
*/
void start2run32(unsigned int start)
{
(( STARTRUNNING )(start))(0);
}
#define SPIBOOT_LOAD_ADDR_OFFSET 252
/*read data from flash to the destination address
*
*spi_flash: flash device informations
*des_addr: store the data read from flash
*page_offset:Offset of data stored in flash
*mode:flash work mode
*/
static int load_data(struct spi_flash* spi_flash,void *des_addr,unsigned int page_offset,int mode)
{
u8 dataBuf[260];
u32 startPage,endPage;
u32 pageSize;
u32 fileSize;
u8 *addr;
int ret;
int i;
u32 offset;
pageSize = spi_flash->page_size;
addr = (u8 *)des_addr;
offset = page_offset*pageSize;
/*read first page,get the file size*/
ret = spi_flash->read(spi_flash,offset,pageSize,dataBuf,mode);
if(ret != 0)
{
printk("read fail#\r\n");
return -1;
}
/*calculate file size*/
fileSize = (dataBuf[3] << 24) | (dataBuf[2] << 16) | (dataBuf[1] << 8) | (dataBuf[0]) ;
if(fileSize == 0)
return -1;
endPage = ((fileSize + 255) >> 8);//page align
/*copy the first page data*/
sys_memcpy(addr, &dataBuf[4], SPIBOOT_LOAD_ADDR_OFFSET);
//copy data from flash to des_addr, with crc check
#if 1
uint32_t crc_org = 0, crc_ddr = 0;
uint32_t n_bytes_left = fileSize - SPIBOOT_LOAD_ADDR_OFFSET;
uint32_t once = 0;
crc32(dataBuf+4, SPIBOOT_LOAD_ADDR_OFFSET, &crc_org);
crc32(addr, SPIBOOT_LOAD_ADDR_OFFSET, &crc_ddr);
offset += pageSize;
addr += SPIBOOT_LOAD_ADDR_OFFSET;
/*read Remaining pages data*/
while (n_bytes_left) {
once = n_bytes_left > pageSize ? pageSize : n_bytes_left;
ret = spi_flash->read(spi_flash, offset, once, dataBuf, mode);
if(ret != 0)
{
printk("read 0x%x fail##\r\n", offset);
return -1;
}
sys_memcpy(addr, dataBuf, once);
crc32(dataBuf, once, &crc_org);
crc32(addr, once, &crc_ddr);
offset += once;
addr += once;
n_bytes_left -= once;
}
printk("crc flash: %08x, crc ddr: %08x\n", crc_org, crc_ddr);
if (crc_org != crc_ddr) {
printk("ERROR: crc check FAILED\n");
while (1) {
__asm__ ("wfi");
}
} else {
printk("crc check PASSED\n");
}
#else
offset += pageSize;
addr += SPIBOOT_LOAD_ADDR_OFFSET;
for(i=1; i<=endPage; i++)
{
ret = spi_flash->read(spi_flash,offset,pageSize, addr, mode);
if(ret != 0)
{
printk("read fail##\r\n");
return -1;
}
offset += pageSize;
addr +=pageSize;
}
#endif
return 0;
}
int updata_flash(struct spi_flash* spi_flash,u32 flash_addr,u32 flash_size_limit, u32 load_addr,unsigned char mode)
{
int ret = 0;
u32 offset = 0;
int erase_block = 0;
unsigned int page_count = 0;
unsigned int index = 0;
unsigned int blockSize,pageSize;
u8 *data;
printk("send file by xmodem\r\n");
blockSize = spi_flash->block_size;
pageSize = spi_flash->page_size;
ret = xmodemReceive((unsigned char *)load_addr,0);
if(ret <= 0)
return -1;
if ((u32)ret > flash_size_limit) {
printk("error: size %d exceeds the limit %d\n", ret, flash_size_limit);
return -1;
}
erase_block = (ret + blockSize - 1) / blockSize;
page_count = (ret + pageSize - 1) / pageSize;
/*erase flash*/
offset = flash_addr;
for(index=0; indexerase(spi_flash, offset, blockSize, 64);
if(ret < 0)
{
printk("erases block %d fail\r\n",offset);
return -1;
}
offset +=blockSize;
}
/*write data*/
offset = flash_addr;
data = (u8 *)load_addr;
for(index=0; indexwrite(spi_flash, offset,pageSize, data, mode);
printk(".");
if(index%64 == 0)
printk("\n");
if(ret < 0)
{
printk("write page %d fail\r\n",offset);
return -1;
}
offset +=pageSize;
data += pageSize;
}
return 0;
}
static int updata_flash_code(struct spi_flash* spi_flash,unsigned int updata_num,unsigned char mode)
{
int ret = 0;
switch (updata_num){
case 0:
ret = updata_flash(spi_flash,FLASH_SECONDBOOT_START_ADDR,FLASH_SECONDBOOT_SIZE_LIMIT,DEFAULT_SECONDBOOT_LOAD_ADDR,mode);
break;
case 1:
ret = updata_flash(spi_flash,FLASH_DDRINIT_START_ADDR,FLASH_DDRINIT_SIZE_LIMIT,DEFAULT_DDRINIT_LOAD_ADDR,mode);
break;
case 2:
ret = updata_flash(spi_flash,FLASH_UBOOT_START_ADDR,FLASH_UBOOT_SIZE_LIMIT,DEFAULT_UBOOT_LOAD_ADDR,mode);
break;
default:
break;
}
return ret;
}
void boot_from_chiplink(void)
{
int bootdelay = 3;
int abort = 0;
char str[6];
char *tmp;
int ret=0;
s32 usel;
unsigned long ts;
struct spi_flash* spi_flash;
unsigned char mode = 1;// or 4
while ((bootdelay > 0) && (!abort)) {
--bootdelay;
/* delay 1000 ms */
ts = get_timer(0);
do {
if (serial_tstc()) { /* we got a key press */
abort = 1; /* don't auto boot */
bootdelay = 0; /* no more delay */
serial_getc(); /* consume input */
break;
}
mdelay(100);
} while (!abort && get_timer(ts) < 1000);
printk("\b\b\b%d ", bootdelay);
}
if(1 == abort)
{
cadence_qspi_init(0, mode);
spi_flash = spi_flash_probe(0, 0, 31250000, 0, (u32)SPI_DATAMODE_8);
printk("***************************************************\r\n");
printk("***************VIC DDR INIT BOOT ********************\r\n");
printk("***************************************************\r\n");
again:
tmp = str;
printk("0:updata second boot\r\n");
printk("1:updata ddr init boot\r\n");
printk("2:updata uboot\r\n");
printk("3:quit\r\n");
printk("Select the function to test : ");
serial_gets(str);
if(str[0] == 0)
goto again;
while(*tmp == 4){tmp++;} /*skip EOT*/
usel = atoi(tmp);
if(usel > 3)
{
printk("error select,try again\r\n");
goto again;
}
/*quit*/
if(usel == 3)
return;
printk("usel:%d\n",usel);
ret = updata_flash_code(spi_flash,usel,mode);
if(ret < 0)
printk("updata fail\r\n");
else
printk("updata success\r\n");
goto again;
}
}
void boot_from_uart(void)
{
sys_cmd_proc();
}
void boot_from_sdio(void)
{
boot_sdio_init();
/*load uboot bin file from sd card*/
boot_load_gpt_partition((void *)DEFAULT_UBOOT_ADDR,&gpt_guid_sifive_uboot);
/*load kernel bin file from sd card*/
// boot_load_gpt_partition((void *)DEFAULT_KERNEL_ADDR,&gpt_guid_sifive_kernel);
}
void boot_from_spi(int mode)
{
struct spi_flash* spi_flash;
int ret;
u32 *addr;
u32 val;
cadence_qspi_init(0, mode);
spi_flash = spi_flash_probe(0, 0, 31250000, 0, (u32)SPI_DATAMODE_8);
/*load uboot*/
load_data(spi_flash,DEFAULT_UBOOT_ADDR,DEFAULT_UBOOT_OFFSET,mode);
}
static int init_ddr(void)
{
int fail_flag = 0;
uint32_t tmp;
uint32_t OMC_APB_BASE_ADDR, OMC_SECURE_APB_BASE_ADDR, PHY_APB_BASE_ADDR;
uint64_t mem_addr;
uint32_t wdata;
int i = 0;
u32 count = 0;
uint64_t base_addr = U74_SYS_PORT_DDRC_BASE_ADDR;
///printf_led("Main start");
//Set PLL to 15750M
//_ASSERT_RESET_rstgen_rstn_ddrphy_apb_ //reset ddrphy,unvalid
_SWITCH_CLOCK_clk_dla_root_SOURCE_clk_osc_sys_;
//SCFG_PLL [31:24] [23:16] [15:8] [7:4] [3] [2] [1] [0]
// OD BWADJ CLKFDIV CLKR bypass infb pd rst
#if defined(DDR_2133)
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x292905);//set reset
udelay(10); //wait(500*(1/25M))
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x0292904);//clear reset
udelay(10); //wait(500*(1/25M))
#elif defined(DDR_2800)
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x373705);//set reset
udelay(10); //wait(500*(1/25M))
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x0373704);//clear reset
udelay(10); //wait(500*(1/25M))
#elif defined(DDR_3200)
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x3f3f05);//set reset
udelay(10); //wait(500*(1/25M))
MA_OUTW(syscon_sysmain_ctrl_SCFG_pll1_REG_ADDR,0x03f3f04);//clear reset
udelay(10); //wait(500*(1/25M))
#endif
_SWITCH_CLOCK_clk_dla_root_SOURCE_clk_pll1_out_;
//_CLEAR_RESET_rstgen_rstn_ddrphy_apb_ //clear reset of ddrphy,unvalid
//ddrc_clock=400M test
//_SWITCH_CLOCK_clk_ddrc0_SOURCE_clk_ddrpll_div4_;
//_SWITCH_CLOCK_clk_ddrc1_SOURCE_clk_ddrpll_div4_;
//ddrc_clock=800M
//_SWITCH_CLOCK_clk_ddrc0_SOURCE_clk_ddrpll_div2_;
//_SWITCH_CLOCK_clk_ddrc1_SOURCE_clk_ddrpll_div2_;
//12.5M
_SWITCH_CLOCK_clk_ddrc0_SOURCE_clk_ddrosc_div2_;
_SWITCH_CLOCK_clk_ddrc1_SOURCE_clk_ddrosc_div2_;
_ENABLE_CLOCK_clk_ddrc0_;
_ENABLE_CLOCK_clk_ddrc1_;
#if 0
_ENABLE_CLOCK_clk_ddrphy_apb_ ;
_CLEAR_RESET_rstgen_rstn_ddrphy_apb_ ;
_ENABLE_CLOCK_clk_dla_bus_ ;
_ENABLE_CLOCK_clk_dla_axi_ ;
_ENABLE_CLOCK_clk_dlanoc_axi_ ;
_ENABLE_CLOCK_clk_dla_apb_ ;
_ENABLE_CLOCK_clk_dlaslv_axi_ ;
_CLEAR_RESET_rstgen_rstn_dla_axi_ ;
_CLEAR_RESET_rstgen_rstn_dlanoc_axi_ ;
_CLEAR_RESET_rstgen_rstn_dla_apb_ ;
_CLEAR_RESET_rstgen_rstn_dlaslv_axi_ ;
#endif
//---- config ddrphy0/omc0 ----
for(int ddr_num=0; ddr_num<2; ddr_num++) {
if(ddr_num == 0) {
OMC_APB_BASE_ADDR = OMC_CFG0_BASE_ADDR;
OMC_SECURE_APB_BASE_ADDR = OMC_CFG0_BASE_ADDR+0x1000;
PHY_APB_BASE_ADDR = DDRPHY0_CSR_BASE_ADDR;
} else {
OMC_APB_BASE_ADDR = OMC_CFG1_BASE_ADDR;
OMC_SECURE_APB_BASE_ADDR = OMC_CFG1_BASE_ADDR+0x1000;
PHY_APB_BASE_ADDR = DDRPHY1_CSR_BASE_ADDR;
}
//reg_wr_test;
//`ifdef G_OPENEDGE_DDRPHY
// `include "noc/continue_wr/orbit_cfg/orbit_boot.c"
//`else
#if 0
#include "./ddrphy_cfg/regconfig.h.sim_PI.C"
#include "./ddrphy_cfg/regconfig.h.sim_PHY.C"
#else
regconfig_h_sim_pi(OMC_APB_BASE_ADDR, OMC_SECURE_APB_BASE_ADDR, PHY_APB_BASE_ADDR);
regconfig_h_sim_phy(OMC_APB_BASE_ADDR, OMC_SECURE_APB_BASE_ADDR, PHY_APB_BASE_ADDR);
#endif
//#include "./ddrc_cfg/lpddr4_1600_cl28_bl16/orbit_boot_8gx16.v"
regconfig_pi_start(OMC_APB_BASE_ADDR, OMC_SECURE_APB_BASE_ADDR, PHY_APB_BASE_ADDR, ddr_num);
if(ddr_num == 0) //ddrc_clock=12.5M
{
_SWITCH_CLOCK_clk_ddrc0_SOURCE_clk_ddrosc_div2_;
//_SWITCH_CLOCK_clk_ddrc0_SOURCE_clk_ddrpll_div4_;
}
else
{
_SWITCH_CLOCK_clk_ddrc1_SOURCE_clk_ddrosc_div2_;
}
udelay(300);
apb_write(PHY_APB_BASE_ADDR + (0 +0 << 2), 0x01);//release dll_rst_n
udelay(300);
orbit_boot(OMC_APB_BASE_ADDR, OMC_SECURE_APB_BASE_ADDR, PHY_APB_BASE_ADDR, ddr_num);
//`endif
}
#if 1
//while(1)
{
for(i = 0; i < 0x80000; i++)
{
writel(0xa5a5a5a5, 0x1000000000 + i *4);
tmp = readl(0x1000000000 + i *4);
if(tmp != 0xa5a5a5a5)
{
printk("error addr %d = 0x%x\n", i *4, tmp);
fail_flag = -1;
}
writel(0x5a5a5a5a, 0x1000000000 + i *4);
tmp = readl(0x1000000000 + i *4);
if(tmp != 0x5a5a5a5a)
{
printk("error addr %d = 0x%x\n", i *4, tmp);
fail_flag = -1;
}
writel(0x00000000, 0x1000000000 + i *4);
tmp = readl(0x1000000000 + i *4);
if(tmp != 0x00000000)
{
printk("error addr %d = 0x%x\n", i *4, tmp);
fail_flag = -1;
}
writel(0xffffffff, 0x1000000000 + i *4);
tmp = readl(0x1000000000 + i *4);
if(tmp != 0xffffffff)
{
printk("error addr %d = 0x%x\n", i *4, tmp);
fail_flag = -1;
}
if((i% 262144) == 0)
{
count++;
printk("ddr 0x%x, %dM test\r\n",(i * 4), count);
}
}
}
#endif
}
/*only hartid 0 call this function*/
void BootMain(void)
{
int boot_mode = 0;
int ret=0;
// gpio_init();
uart_init(3);
ret = init_ddr();
if(ret == 0)
{
_SET_SYSCON_REG_register68_SCFG_disable_u74_memaxi_remap(1);
#if defined(DDR_2133)
printk("DDR clk 2133M,Version: %s\r\n",VERSION);
#elif defined(DDR_2800)
printk("DDR clk 2800M,Version: %s\r\n",VERSION);
#elif defined(DDR_3200)
printk("DDR clk 3200M,Version: %s\r\n",VERSION);
#endif
}
else
printk("End init lpddr4, test ddr fail\r\n");
#if (UBOOT_EXEC_AT_NBDLA_2M == 1)
printk("init nbdla 2M ram\r\n");
_SET_SYSCON_REG_register16_SCFG_nbdla_clkgating_en(1);
_ENABLE_CLOCK_clk_dla_axi_;
_ENABLE_CLOCK_clk_dlanoc_axi_;
_ENABLE_CLOCK_clk_dla_apb_;
_ENABLE_CLOCK_clk_dlaslv_axi_;
_CLEAR_RESET_rstgen_rstn_dla_axi_;
_CLEAR_RESET_rstgen_rstn_dlanoc_axi_;
_CLEAR_RESET_rstgen_rstn_dla_apb_;
_CLEAR_RESET_rstgen_rstn_dlaslv_axi_;
#endif /* UBOOT_EXEC_AT_NBDLA_2M */
boot_from_chiplink();
boot_mode = get_boot_mode();
switch(boot_mode){
case 0:
boot_from_spi(1);
break;
case 1:
boot_from_spi(4);
break;
case 2:
boot_from_sdio();
break;
case 4:
boot_from_uart();
break;
case 6:
boot_from_chiplink();
break;
default:
break;
}
printk("\nbootloader.\n");
writel(0x1, 0x2000004);
}