/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_board_run_fel(void) { #if defined(CONFIG_SUN6I) || defined(CONFIG_ARCH_SUN8IW3P1)|| defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN7I) *((volatile unsigned int *)(SUNXI_RUN_EFEX_ADDR)) = SUNXI_RUN_EFEX_FLAG; #elif defined(CONFIG_ARCH_SUN9IW1P1) volatile unsigned int *rtc_addr = (volatile unsigned int *)(0x08001400 + 0x1f0); do { *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); *rtc_addr = (1<<31) | (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); __usdelay(10); *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); } while((*rtc_addr & 0xff) != SUNXI_RUN_EFEX_FLAG); #elif defined(CONFIG_ARCH_SUN8IW6P1) volatile unsigned int *rtc_addr = (volatile unsigned int *)(0x01f01400 + 0x1f0); do { *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); *rtc_addr = (1<<31) | (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); __usdelay(10); *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); } while((*rtc_addr & 0xff) != SUNXI_RUN_EFEX_FLAG); #endif printf("set next system status\n"); axp_set_next_poweron_status(PMU_PRE_SYS_MODE); board_display_set_exit_mode(0); #ifdef CONFIG_SUNXI_DISPLAY drv_disp_exit(); #endif printf("sunxi_board_close_source\n"); sunxi_board_close_source(); sunxi_flush_allcaches(); #if defined(CONFIG_ARCH_SUN5I) printf("jump to fel_base\n"); jump_to(FEL_BASE); #else printf("reset cpu\n"); reset_cpu(0); #endif return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_board_run_fel_eraly(void) { #if defined(CONFIG_SUN6I) || defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1)|| defined(CONFIG_ARCH_SUN7I) *((volatile unsigned int *)(SUNXI_RUN_EFEX_ADDR)) = SUNXI_RUN_EFEX_FLAG; #elif defined(CONFIG_ARCH_SUN9IW1P1) volatile unsigned int *rtc_addr = (volatile unsigned int *)(0x08001400 + 0x1f0); do { *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); *rtc_addr = (1<<31) | (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); __usdelay(10); *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); } while((*rtc_addr & 0xff) != SUNXI_RUN_EFEX_FLAG); #elif defined(CONFIG_ARCH_SUN8IW6P1) volatile unsigned int *rtc_addr = (volatile unsigned int *)(0x01f01400 + 0x1f0); do { *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); *rtc_addr = (1<<31) | (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); __usdelay(10); *rtc_addr = (1<<16) | (SUNXI_RUN_EFEX_FLAG<<8); } while((*rtc_addr & 0xff) != SUNXI_RUN_EFEX_FLAG); #endif printf("set next system status\n"); axp_set_next_poweron_status(PMU_PRE_SYS_MODE); timer_exit(); sunxi_key_exit(); #ifdef CONFIG_SUN6I p2wi_exit(); #endif sunxi_dma_exit(); #if defined(CONFIG_ARCH_SUN5I) printf("jump to fel_base\n"); jump_to(FEL_BASE); #else printf("reset cpu\n"); #if defined(CONFIG_ARCH_SUN9IW1P1) *( volatile unsigned int *)(0x008000e0) = 0x16aa0000; #endif reset_cpu(0); #endif return 0; }
void hdmi_delay_us(unsigned long us) { #if defined(__LINUX_PLAT__) udelay(us); #elif defined(__UBOOT_OSAL__) __usdelay(us); #endif return ; }
void restore_cpu_source_ctrl(void) { u32 reg_val; reg_val = smc_readl(CCM_CPU_SOURCECTRL); reg_val |= 1; smc_writel(reg_val, CCM_CPU_SOURCECTRL); __usdelay(1000); dmb(); isb(); }
void modify_cpu_source_ctrl(void) { u32 reg_val; reg_val = smc_readl(CCM_CPU_SOURCECTRL); reg_val &= ~1; smc_writel(reg_val, CCM_CPU_SOURCECTRL); __usdelay(10); dmb(); isb(); }
/******************************************************************************* *函数名称: set_pll *函数原型:void set_pll( void ) *函数功能: 调整CPU频率 *入口参数: void *返 回 值: void *备 注: *******************************************************************************/ void set_pll( void ) { unsigned int reg_val; unsigned int i; //设置时钟为默认408M //切换到24M reg_val = readl(CCM_CPU_L2_AXI_CTRL); reg_val &= ~(0x01 << 16); reg_val |= (0x01 << 16); reg_val |= (0x01 << 0); writel(reg_val, CCM_CPU_L2_AXI_CTRL); //延时,等待时钟稳定 for(i=0; i<0x400; i++); //回写PLL1 reg_val = (0x01<<12)|(0x01<<31); writel(reg_val, CCM_PLL1_CPUX_CTRL); //延时,等待时钟稳定 #ifndef CONFIG_FPGA do { reg_val = readl(CCM_PLL1_CPUX_CTRL); } while(!(reg_val & (0x1 << 28))); #endif //修改AXI,AHB,APB分频 clk_set_divd(); //dma reset writel(readl(CCM_AHB1_RESET_CTRL) | (1 << 6), CCM_AHB1_RESET_CTRL); for(i=0;i<100;i++); //gating clock for dma pass writel(readl(CCM_AHB1_GATE0_CTRL) | (1 << 6), CCM_AHB1_GATE0_CTRL); writel(7, (0x01c20000+0x20)); //打开MBUS,clk src is pll6 writel(0x80000000, CCM_MBUS_RESET_CTRL); //Assert mbus domain writel(0x81000002, CCM_MBUS_SCLK_CTRL0); //dram>600M, so mbus from 300M->400M //使能PLL6 writel(readl(CCM_PLL6_MOD_CTRL) | (1U << 31), CCM_PLL6_MOD_CTRL); //切换时钟到COREPLL上 reg_val = readl(CCM_CPU_L2_AXI_CTRL); reg_val &= ~(0x03 << 16); reg_val |= (0x02 << 16); writel(reg_val, CCM_CPU_L2_AXI_CTRL); __usdelay(1000); CP15DMB; CP15ISB; //打开GPIO writel(readl(CCM_APB1_GATE0_CTRL) | (1 << 5), CCM_APB1_GATE0_CTRL); writel(readl(SUNXI_RPRCM_BASE + 0x28) | 0x01, SUNXI_RPRCM_BASE + 0x28); return ; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ void sunxi_clear_fel_flag(void) { volatile uint reg_val; do { smc_writel((1<<16), SUNXI_RPRCM_BASE + 0x1f0); smc_writel((1<<16) | (1U<<31), SUNXI_RPRCM_BASE + 0x1f0); __usdelay(10); CP15ISB; CP15DMB; smc_writel((1<<16), SUNXI_RPRCM_BASE + 0x1f0); reg_val = smc_readl(SUNXI_RPRCM_BASE + 0x1f0); } while((reg_val & 0xff) != 0); }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ void rtc_region_clear_fel_flag(void) { volatile uint reg_val; do { writel(1<<16, RPCM_R_PIO_HOLD_CTRL_REG); writel((1<<16) | (1U<<31), RPCM_R_PIO_HOLD_CTRL_REG); __usdelay(10); CP15ISB; CP15DMB; writel(1<<16, RPCM_R_PIO_HOLD_CTRL_REG); reg_val = readl(RPCM_R_PIO_HOLD_CTRL_REG); } while((reg_val & 0xff) != 0); }
/* ********************************************************************************************************************** * i2c_init * * Description: * * Arguments : * * Returns : none * * Notes : none * ********************************************************************************************************************** */ void i2c_init(int bus_id, int speed, int slaveaddr) { int i, clk_n, clk_m; int reg_value = 0; char twi_para[16] = {0}; uint twi_host = 0; struct sunxi_twi_reg *i2c = NULL; if(bus_id < SUNXI_TWI_COUNT) { twi_host = SUNXI_TWI0_BASE + SUNXI_TWI_OFFSET * bus_id; } else { printf("i2c bus id %d is error\n", bus_id); return ; } i2c = (struct sunxi_twi_reg *)twi_host; sprintf(twi_para, "twi%d", bus_id); #if defined(CONFIG_ARCH_SUN9IW1P1) //reset apb1 twi[bus_id] reg_value = *((unsigned int *)CCM_APB1_RST_REG0); reg_value |= (0x01 << bus_id); *((unsigned int *)CCM_APB1_RST_REG0) = reg_value; __msdelay(1); //set apb1 twi[bus_id] gating reg_value = *((unsigned int *)CCM_APB1_GATE0_CTRL); reg_value |= (0x01 << bus_id); *((unsigned int *)CCM_APB1_GATE0_CTRL) = reg_value; #else #if defined(CONFIG_ARCH_SUN8IW6P1) reg_value = *((unsigned int *)CCMU_BUS_SOFT_RST_REG4); reg_value |= (0x01 << bus_id); *((unsigned int *)CCMU_BUS_SOFT_RST_REG4) = reg_value; __msdelay(1); reg_value = *((unsigned int *)CCMU_BUS_CLK_GATING_REG3); reg_value |= (0x01 << bus_id); *((unsigned int *)CCMU_BUS_CLK_GATING_REG3) = reg_value ; #else struct sunxi_ccm_reg *ccm_reg = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; #if !defined(CONFIG_ARCH_SUN5I)||!defined(CONFIG_ARCH_SUN7I) /* reset i2c clock */ /* reset apb2 twi0*/ reg_value = *((unsigned int *)0x01c202d8); reg_value |= 0x01; *((unsigned int *)0x01c202d8) = reg_value; __msdelay(1); #endif ccm_reg->apb1_gate &= ~1; __msdelay(1); ccm_reg->apb1_gate |= 1; #endif #endif /* set i2c gpio */ //gpio_request_early((void *)uboot_spare_head.boot_data.twi_gpio, 2, 1); gpio_request_simple(twi_para, NULL); /* reset i2c control */ i = 0xffff; i2c->srst = 1; while((i2c->srst) && (i)) { i --; } if((i2c->lcr & 0x30) != 0x30 ) { /* toggle I2CSCL until bus idle */ i2c->lcr = 0x05; __usdelay(500); i = 10; while ((i > 0) && ((i2c->lcr & 0x02) != 2)) { i2c->lcr |= 0x08; __usdelay(1000); i2c->lcr &= ~0x08; __usdelay(1000); i--; } i2c->lcr = 0x0; __usdelay(500); } if(speed < 100) { speed = 100; } else if(speed > 400) { speed = 400; } clk_n = 1; clk_m = (24000/10)/((2^clk_n) * speed) - 1; i2c->clk = (clk_m<<3) | clk_n; i2c->ctl = 0x40; i2c->eft = 0; return ; }
/******************************************************************************* *函数名称: set_pll *函数原型:void set_pll( void ) *函数功能: 调整CPU频率 *入口参数: void *返 回 值: void *备 注: *******************************************************************************/ void set_pll( void ) { __u32 reg_val; //select C0_CPUX clock src: OSC24M,AXI divide ratio is 2 //cpu/axi clock ratio writel((1<<16 | 1<<0), CCMU_CPUX_AXI_CFG_REG); //set PLL_C0CPUX, the default clk is 408M ,PLL_OUTPUT= 24M*N/P reg_val = 0x82001100; writel(reg_val, CCMU_PLL_C0CPUX_CTRL_REG); //wait pll1 stable #ifndef CONFIG_SUNXI_FPGA do { reg_val = readl(CCMU_PLL_STB_STATUS_REG); } while(!(reg_val & 0x1)); #endif //set PLL_C1CPUX, the default clk is 408M ,PLL_OUTPUT= 24M*N/P reg_val = 0x82001100; writel(reg_val, CCMU_PLL_C1CPUX_CTRL_REG); //wait pll1 stable #ifndef CONFIG_SUNXI_FPGA do { reg_val = readl(CCMU_PLL_STB_STATUS_REG); } while(!(reg_val & 0x2)); #endif //enable pll_hsic, default is 480M writel(0x42800, CCMU_PLL_HSIC_CTRL_REG); //set default value writel(readl(CCMU_PLL_HSIC_CTRL_REG) | (1U << 31), CCMU_PLL_HSIC_CTRL_REG); #ifndef CONFIG_SUNXI_FPGA do { reg_val = readl(CCMU_PLL_STB_STATUS_REG); } while(!(reg_val & (1<<8))); #endif //cci400 clk src is pll_hsic: (2<<24) , div is 1:(0<<0) CP15DMB; CP15ISB; reg_val = readl(CCMU_CCI400_CFG_REG); if(!(reg_val & (0x3<<24))) //src is osc24M { writel(0x0, CCMU_CCI400_CFG_REG); __usdelay(50); } writel((2<<24 | 0<<0), CCMU_CCI400_CFG_REG); __usdelay(100); CP15DMB; CP15ISB; //change ahb src before set pll6 writel((0x01 << 12) | (readl(CCMU_AHB1_APB1_CFG_REG)&(~(0x3<<12))), CCMU_AHB1_APB1_CFG_REG); //enable PLL6 writel( (0x32<<8) | (1U << 31), CCMU_PLL_PERIPH_CTRL_REG); __usdelay(10); #ifndef CONFIG_SUNXI_FPGA do { reg_val = readl(CCMU_PLL_STB_STATUS_REG); } while(!(reg_val & (1<<6))); #endif //set AHB1/APB1 clock divide ratio //ahb1 clock src is PLL6, (0x02 << 12) //apb1 clk src is ahb1 clk src, divide ratio is 2 (1<<8) //ahb1 pre divide ratio is 2: 0:1 , 1:2, 2:3, 3:4 (2<<6) //PLL6:AHB1:APB1 = 600M:200M:100M , writel((0x02 << 12) | (1<<8) | (2<<6) | (1<<4), CCMU_AHB1_APB1_CFG_REG); //set and change cpu clk src to pll1, PLL1:AXI0 = 408M:204M reg_val = readl(CCMU_CPUX_AXI_CFG_REG); reg_val &= ~(3 << 0); reg_val |= (1 << 0); //axi0 clk src is C0_CPUX , divide ratio is 2 reg_val |= (1 << 12); //C0_CPUX clk src is PLL_C0CPUX writel(reg_val, CCMU_CPUX_AXI_CFG_REG); //set C1_CPUX clk src is PLL_C1CPUX reg_val = readl(CCMU_CPUX_AXI_CFG_REG); reg_val &= ~(3<<16); reg_val |= 1<<16; //axi1 clk src is C1_CPUX , divide ratio is 2 reg_val |= 1<<28; //C1_CPUX clk src is PLL_C1CPUX writel(reg_val, CCMU_CPUX_AXI_CFG_REG); __usdelay(1000); //----DMA function-------- //dma reset writel(readl(CCMU_BUS_SOFT_RST_REG0) | (1 << 6), CCMU_BUS_SOFT_RST_REG0); __usdelay(20); //gating clock for dma pass writel(readl(CCMU_BUS_CLK_GATING_REG0) | (1 << 6), CCMU_BUS_CLK_GATING_REG0); //auto gating disable writel(7, (SUNXI_DMA_BASE+0x20)); //reset mbus domain writel(0x80000000, CCMU_MBUS_RST_REG); //open MBUS,clk src is pll6 , pll6/(m+1) = 300M writel(0x81000002, CCMU_MBUS_CLK_REG); //open TIMESTAMP ,aw1673_cpux_cfg.pdf descript this register writel(1, 0x01720000); return ; }
void __udelay(unsigned long usec) { __usdelay(usec); }
/* ********************************************************************************************************************** * i2c_init * * Description: * * Arguments : * * Returns : none * * Notes : none * ********************************************************************************************************************** */ void i2c_init(int speed, int slaveaddr) { int i, clk_n, clk_m; int i2c_nodeoffset; /*set gpio and clock*/ #ifndef CONFIG_CPUS_I2C i2c_nodeoffset = fdt_path_offset(working_fdt,"/soc/twi_para"); if(i2c_nodeoffset < 0) { printf("axp: get node[%s] error\n",PMU_SCRIPT_NAME); return ; } //if(script_parser_fetch(PMU_SCRIPT_NAME, "pmu_pwron_vol", &vol_value, 1)) if(fdt_getprop_u32(working_fdt,i2c_nodeoffset,"twi_port", (uint32_t*)&bus_num)<0) { printf("can not get i2c bus num \n"); } if(bus_num > SUNXI_I2C_CONTROLLER) { printf("can not support i2c bus num %d \n",bus_num); return ; } set_i2c_clock(); if(0 != fdt_set_all_pin_by_offset(i2c_nodeoffset,"pinctrl-0")) { printf("set pin for i2c bus num %d error\n",bus_num); return ; } i2c = (struct sunxi_twi_reg *)(SUNXI_TWI0_BASE + (bus_num * TWI_CONTROL_OFFSET)); #else set_cpus_i2c_clock(); fdt_set_all_pin("/soc/s_twi0","pinctrl-0"); #endif /* reset i2c control */ i = 0xffff; i2c->srst = 1; while((i2c->srst) && (i)) { i --; } if((i2c->lcr & 0x30) != 0x30 ) { /* toggle I2CSCL until bus idle */ i2c->lcr = 0x05; __usdelay(500); i = 10; while ((i > 0) && ((i2c->lcr & 0x02) != 2)) { i2c->lcr |= 0x08; __usdelay(1000); i2c->lcr &= ~0x08; __usdelay(1000); i--; } i2c->lcr = 0x0; __usdelay(500); } if(speed < 100) { speed = 100; } else if(speed > 400) { speed = 400; } clk_n = 1; clk_m = (24000/10)/((2^clk_n) * speed) - 1; i2c->clk = (clk_m<<3) | clk_n; i2c->ctl = 0x40; i2c->eft = 0; return ; }