tag 标签: uboot

相关帖子
相关博文
  • 热度 4
    2023-5-16 12:17
    579 次阅读|
    0 个评论
    itop4412 uboot-202301移植
    一、环境准备 下载官方uboot版本uboot-202301   下载地址https://ftp.denx.de/pub/u-boot/u-boot-2023.01.tar.bz2 交叉工具编译安装版本。安装后查看版本arm-none-linux-gnueabihf-gcc -v,如下图      安装openssl-1.1.1n,编译源码的过程中提示需安装,先前安装过低一点的版本也会报错,之后安装该版本后未再报错,安装方法请到网上搜索。 设备树编译工具安装    本次编译所用编译工具版本如下, 二、 硬件设备 所使用的硬件设备为北京讯为的iTop4412精英版,1G内存pop封装核心板。网上有很多iTop4412 uboot的移植资料,但由于pop版本和scp版本还是有所区别的,可能本次移植并不一定兼容scp的板子。 三、 参考资料   本文参考uboot-2017的移植,在别人对uboot-2017移植的基础上对uboot-202301进行移植。参考及学习的博客、文章如下: https://www.jianshu.com/p/5df61e55e96a https://www.tiandeng.xyz/posts/iTop4412-u-boot-%E7%A7%BB%E6%A4%8D/#3-添加板级配置文件 https://blog.csdn.net/lgc1990/article/details/109160426 https://chasinglulu.github.io/2019/08/29/%E5%9F%BA%E4%BA%8EExynos4412%E5%BC%80%E5%8F%91%E6%9D%BF%E7%9A%84uboot-2019-07%E7%A7%BB%E6%A4%8D/ https://www.cnblogs.com/pengdonglin137/p/5080645.html https://github.com/kuangfei2019/ITOP4412-POP-1G-uboot-2017 四、开始移植    本博客对照samsung的origen的移植文件进行修改,硬件外设对照iTop4412 精英版1G pop核心板开发板的设置。以下是对uboot-202301版本的移植过程。    1. 拷贝board/samsung/origen 目录的文件,目录名改为ex4412,目录下需修改的文件名如下 : $ tree board/samsung/ex4412 board/samsung/ex4412 ├── ex4412.c ├── Kconfig ├── MAINTAINERS ├── Makefile └── tools └── mkex4412spl.c    2.拷贝include/configs/origen.h,修改命名为ex4412.h    cp include/configs/origen.h include/configs/ex4412.h    3.拷贝arch/arm/dts/exynos4412-odroid.dts,修改文件名称为exynos4412-ex4412.dts    cp arch/arm/dts/exynos4412-odroid.dts arch/arm/dts/exynos4412-ex4412.dts    4. 拷贝arch/arm/mach-exynos/exynos4_setup.h,重命名为ex4412_setup.h   cp arch/arm/mach-exynos/exynos4_setup.h arch/arm/mach-exynos/ex4412_setup.h    5. 拷贝以下文件并重命名   cp configs/origen_defconfig configs/ex4412_defconfig    6 .新增文件   touch arch /arm /mach -exynos /board .c   其中board.c实现板子初始化点灯动作。    7.修改文件board/samsung/ex4412下的文件 ex4412.c   --- board/samsung/origen/origen.c 2023-01-10 00:07:33.000000000 +0800 +++ board/samsung/ex4412/ex4412.c 2023-04-28 17:27:21.000000000 +0800   @@ -12,6 +12,9 @@   #include   #include   +   +DECLARE_GLOBAL_DATA_PTR;   +   int exynos_init(void)   {   return 0; Kconfig   --- board/samsung/origen/Kconfig 2023-01-10 00:07:33.000000000 +0800 +++ board/samsung/ex4412/Kconfig 2023-04-15 10:38:39.000000000 +0800 @@ -1,12 +1,12 @@ -if TARGET_ORIGEN +if TARGET_EX4412 config SYS_BOARD - default "origen" + default "ex4412" config SYS_VENDOR default "samsung" config SYS_CONFIG_NAME - default "origen" + default "ex4412" endif Makefile  --- board/samsung/origen/Makefile 2023-01-10 00:07:33.000000000 +0800 +++ board/samsung/ex4412/Makefile 2023-04-26 16:43:42.000000000 +0800 @@ -6,7 +6,7 @@ # necessary to create built-in.o obj- := __dummy__.o -hostprogs-y := tools/mkorigenspl +hostprogs-y := tools/mkex4412spl always := $(hostprogs-y) # omit -O2 option to suppress @@ -14,7 +14,7 @@ # # TODO: # Fix the root cause in tools/mkorigenspl.c and delete the following work-around -$(obj)/tools/mkorigenspl: HOSTCFLAGS:=$(filter-out -O2,$(HOSTCFLAGS)) +$(obj)/tools/mkex4412spl: HOSTCFLAGS:=$(filter-out -O2,$(HOSTCFLAGS)) else -obj-y += origen.o +obj-y += ex4412.o endif MAINTAINERS --- board/samsung/origen/MAINTAINERS 2023-01-10 00:07:33.000000000 +0800 +++ board/samsung/ex4412/MAINTAINERS 2023-04-15 11:37:44.000000000 +0800 @@ -1,6 +1,6 @@ -ORIGEN BOARD +EX4412 BOARD M: Minkyu Kang S: Maintained -F: board/samsung/origen/ -F: include/configs/origen.h -F: configs/origen_defconfig +F: board/samsung/ex4412/ +F: include/configs/ex4412.h +F: configs/ex4412_defconfig 8. 在arch/arm/include/asm/mach-types.h文件末尾处新增machine-type 。文件中存在MACH_TYPE_EXYNOS4412,貌似也可以使用该ID,使用时需与ex4412.h里的引用一致,实际测试中,不论新增还是使用已有的,编译不受影响,存在即有其道理,只是暂时未知。       9.修改include /configs /ex4412 .h --- include/configs/origen.h 2023-01-10 00:07:33.000000000 +0800 +++ include/configs/ex4412.h 2023-05-11 10:51:17.000000000 +0800 @@ -5,24 +5,46 @@ * Configuration settings for the SAMSUNG ORIGEN (EXYNOS4210) board. */ -#ifndef __CONFIG_ORIGEN_H -#define __CONFIG_ORIGEN_H +#ifndef __CONFIG_EX4412_H +#define __CONFIG_EX4412_H #include +#define CONFIG_EXYNOS4412 1 +#define CONFIG_EX4412 1 +/* #define CONFIG_SYS_L2CACHE_OFF 1 */ +#define CONFIG_SPL_TEXT_BASE 0x02023400 +#define CONFIG_SYS_TEXT_BASE 0x43E00000 +#define COPY_BL2_FNPTR_ADDR 0x02020030 +#define CONFIG_DEFAULT_CONSOLE “console=ttySAC2,115200n8\0” + +#define CONFIG_DEBUG_UART_BASE 0x13820000 +#define CONFIG_DEBUG_UART_CLOCK 100000000 +#define CONFIG_SPL_SERIAL_SUPPORT 1 +#define CONFIG_SPL_GPIO_SUPPORT 1 + +#define CONFIG_CLK_1000_200_200 +/* #define CONFIG_SPL_BUILD run wrong*/ + +/* #define CONFIG_SYS_DRAM_TEST 1 */ /* ORIGEN has 4 bank of DRAM */ +#define CONFIG_NR_DRAM_BANKS 4 #define CONFIG_SYS_SDRAM_BASE 0x40000000 #define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE #define SDRAM_BANK_SIZE (256 << 20) /* 256 MB */ +#define CONFIG_SYS_MONITOR_BASE 0x00000000 + +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x6000000) + /* Power Down Modes */ #define S5P_CHECK_SLEEP 0x00000BAD #define S5P_CHECK_DIDLE 0xBAD00000 #define S5P_CHECK_LPA 0xABAD0000 /* MMC SPL */ -#define COPY_BL2_FNPTR_ADDR 0x02020030 - +#define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_EXTRA_ENV_SETTINGS \ "loadaddr=0x40007000\0" \ "rdaddr=0x48000000\0" \ @@ -40,8 +62,10 @@ /* MIU (Memory Interleaving Unit) */ #define CONFIG_MIU_2BIT_21_7_INTERLEAVED - #define RESERVE_BLOCK_SIZE (512) -#define BL1_SIZE (16 << 10) /*16 K reserved for BL1*/ +#define BL1_SIZE (8 << 10) /*16 K reserved for BL1*/ +#define BL2_SIZE (16 << 10) /* 512 KB */ + +/* #define SPI_FLASH_UBOOT_POS (SEC_FW_SIZE + BL1_SIZE) */ #endif /* __CONFIG_H */    10.修改arch/arm/dts/exynos4412-ex4412.dts --- arch/arm/dts/exynos4412-odroid.dts 2023-04-17 00:02:21.000000000 +0800 +++ arch/arm/dts/exynos4412-ex4412.dts 2023-04-29 22:14:35.000000000 +0800 @@ -10,17 +10,25 @@ #include "exynos4412.dtsi" / { - model = "Odroid based on Exynos4412"; - compatible = "samsung,odroid", "samsung,exynos4412"; + model = "EX4412 based on Exynos4412"; + compatible = "samsung,ex4412", "samsung,exynos4412"; aliases { - serial0 = "/serial@13800000"; - console = "/serial@13810000"; + serial2 = "/serial@13820000"; + console = "/serial@13820000"; mmc0 = &mshc_0; mmc2 = &sdhci2; }; + chosen { + stdout-path = "serial2:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = ; + }; - serial@13810000 { + serial@13820000 { status = "okay"; }; @@ -242,7 +250,7 @@ }; &mshc_0 { - samsung,bus-width = ; + samsung,bus-width = ; samsung,timing = ; samsung,removable = ; fifoth_val = ;    11.修改 arch/arm/mach-exynos/Kconfi g --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -77,6 +77,12 @@ config TARGET_ORIGEN select EXYNOS4210 select SUPPORT_SPL +config TARGET_EX4412 + bool "Exynos4412 Ex4412 board" + select EXYNOS4412 + select SUPPORT_SPL + + config TARGET_TRATS2 bool "Exynos4412 Trat2 board" @@ -232,6 +238,7 @@ source "board/samsung/smdkv310/Kconfig" source "board/samsung/trats/Kconfig" source "board/samsung/universal_c210/Kconfig" source "board/samsung/origen/Kconfig" +source "board/samsung/ex4412/Kconfig" source "board/samsung/trats2/Kconfig" source "board/samsung/odroid/Kconfig" source "board/samsung/arndale/Kconfig"    12.修改arch/arm/mach-exynos/Makefile --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -3,6 +3,7 @@ # Copyright (C) 2009 Samsung Electronics # Minkyu Kang +obj-y += board.o obj-y += soc.o obj-$(CONFIG_CPU_V7A) += clock.o pinmux.o power.o system.o obj-$(CONFIG_ARM64) += mmu-arm64.o @@ -12,7 +13,9 @@ obj-$(CONFIG_EXYNOS5420) += sec_boot.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_ARCH_EXYNOS5) += clock_init_exynos5.o obj-$(CONFIG_ARCH_EXYNOS5) += dmc_common.o dmc_init_ddr3.o -obj-$(CONFIG_EXYNOS4210)+= dmc_init_exynos4.o clock_init_exynos4.o +ifneq ($(filter y,$(CONFIG_EXYNOS4210)$(CONFIG_EX4412)),) +obj-y += dmc_init_exynos4.o clock_init_exynos4.o +endif obj-y += spl_boot.o tzpc.o obj-y += lowlevel_init.o endif 五、适配板子硬件的配置修改   前面已经对origen的配置做了拷贝,部分需针对iTop4412 1G pop精英版的板子做修改 1.对ex4412_defconfig的内容进行增减、修改 CONFIG_ARM=y # CONFIG_SKIP_LOWLEVEL_INIT=y #CONFIG_SPL_SKIP_LOWLEVEL_INIT=y CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y CONFIG_ARCH_EXYNOS=y CONFIG_SYS_TEXT_BASE=0x43E00000 CONFIG_SYS_MALLOC_LEN=0x5004000 CONFIG_SYS_MALLOC_F_LEN=0x400 CONFIG_ARCH_EXYNOS4=y CONFIG_EX4412=y CONFIG_TARGET_EX4412=y CONFIG_DEBUG_UART=y CONFIG_DEBUG_UART_S5P=y CONFIG_DEBUG_UART_BASE=0x13820000 CONFIG_DEBUG_UART_CLOCK=100000000 CONFIG_DISPLAY_CPUINFO=y CONFIG_DISPLAY_BOARDINFO=y CONFIG_BOOTDELAY=5 CONFIG_SYS_CONSOLE_IS_IN_ENV=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_ENV_SIZE=0x4000 CONFIG_ENV_OFFSET=0x4200 CONFIG_DEFAULT_DEVICE_TREE="exynos4412-ex4412" CONFIG_SPL_TEXT_BASE=0x02023400 CONFIG_SYS_PROMPT="EX4412 # " CONFIG_TEXT_BASE=0x43E00000 CONFIG_SD_BOOT=y CONFIG_IDENT_STRING=" for EX4412" CONFIG_SYS_MEM_TOP_HIDE=0x100000 CONFIG_SYS_LOAD_ADDR=0x43e00000 CONFIG_DISTRO_DEFAULTS=y CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x2040000 CONFIG_SYS_MONITOR_LEN=262144 CONFIG_BOOTCOMMAND="if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadbootenv; then echo Loaded environment from ${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;if run loadbootscript; then run bootscript; fi; fi;load mmc ${mmcdev} ${loadaddr} uImage; bootm ${loadaddr} " # CONFIG_SPL_FRAMEWORK is not set CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x3800 CONFIG_SYS_PBSIZE=1024 # CONFIG_CMD_XIMG is not set CONFIG_CMD_THOR_DOWNLOAD=y CONFIG_CMD_DFU=y CONFIG_CMD_GPT=y CONFIG_CMD_MMC=y CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_CMD_NET is not set CONFIG_CMD_CACHE=y # CONFIG_CMD_SLEEP is not set CONFIG_CMD_EXT4_WRITE=y CONFIG_OF_CONTROL=y CONFIG_ENV_OVERWRITE=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SPL=y CONFIG_SPL_GPIO_SUPPORT=y CONFIG_SPL_SERIAL_SUPPORT=y CONFIG_DFU_MMC=y CONFIG_SYS_DFU_DATA_BUF_SIZE=0x2000000 CONFIG_MMC_DW=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_SDMA=y CONFIG_MMC_SDHCI_S5P=y CONFIG_MTD=y CONFIG_USB=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="Samsung" CONFIG_USB_GADGET_VENDOR_NUM=0x04e8 CONFIG_USB_GADGET_PRODUCT_NUM=0x6601 CONFIG_USB_GADGET_DWC2_OTG=y CONFIG_USB_GADGET_DWC2_OTG_PHY=y CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_USB_FUNCTION_THOR=y    2 .修改arch/arm/mach-exynos/clock_init_exynos4.c,初始化时钟 diff --git a/arch/arm/mach-exynos/clock_init_exynos4.c b/arch/arm/mach-exynos/clock_init_exynos4.c index 584e4ba..bf85a3b 100644 --- a/arch/arm/mach-exynos/clock_init_exynos4.c +++ b/arch/arm/mach-exynos/clock_init_exynos4.c @@ -30,65 +30,559 @@ #include #include #include "common_setup.h" -#include "exynos4_setup.h" +#ifdef CONFIG_EX4412 +#include "ex4412_setup.h" +#else +#include "exynos4_setup.h" +#endif /* * system_clock_init: Initialize core clock and bus clock. * void system_clock_init(void) */ +/** + * freq (ARMCLK) = 1400 MHz at 1.3 V + * freq (ACLK_COREM0) = 350 MHz at 1.3V + * freq (ACLK_COREM1) = 188 MHz at 1.3 V + * freq (PERIPHCLK) = 1400 MHz at 1.3 V + * freq (ATCLK) = 214 MHz at 1.3 V + * freq (PCLK_DBG) = 107 MHz at 1.3 V + * freq (SCLK_DMC) = 400 MHz at 1.0 V + * freq (ACLK_DMCD) = 200 MHz at 1.0 V + * freq (ACLK_DMCP) = 100 MHz at 1.0 V + * freq (ACLK_ACP) = 200 MHz at 1.0 V + * freq (PCLK_ACP) = 100 MHz at 1.0 V + * freq (SCLK_C2C) = 400 MHz at 1.0 V + * freq (ACLK_C2C) = 200 MHz at 1.0 V + * freq (ACLK_GDL) = 200 MHz at 1.0 V + * freq (ACLK_GPL) = 100 MHz at 1.0 V + * freq (ACLK_GDR) = 200 MHz at 1.0 V + * freq (ACLK_GPR) = 100 MHz at 1.0 V + * freq (ACLK_400_MCUISP) = 400 MHz at 1.0 V + * freq (ACLK_200) = 160 MHz at 1.0 V + * freq (ACLK_100) = 100 MHz at 1.0 V + * freq (ACLK_160) = 160 MHz at 1.0 V + * freq (ACLK_133) = 133 MHz at 1.0 V + * freq (SCLK_ONENAND) = 160 MHz at 1.0 V + */ void system_clock_init(void) { - struct exynos4_clock *clk = - (struct exynos4_clock *)samsung_get_base_clock(); - src_cpu); - - sdelay(0x10000); - src_top0); src_top1); src_dmc); src_leftbus); src_rightbus); src_fsys); src_peril0); src_cam); src_mfc); src_g3d); src_lcd0); - - sdelay(0x10000); - div_cpu0); div_cpu1); div_dmc0); div_dmc1); div_leftbus); div_rightbus); div_top); div_fsys1); div_fsys2); div_fsys3); div_peril0); div_cam); div_mfc); div_g3d); div_lcd0); - - /* Set PLL locktime */ apll_lock); mpll_lock); epll_lock); vpll_lock); - apll_con1); apll_con0); mpll_con1); mpll_con0); epll_con1); epll_con0); vpll_con1); vpll_con0); - - sdelay(0x30000); + unsigned int set, clr, clr_src_cpu, clr_pll_con0, clr_src_dmc; + struct exynos4x12_clock *clk = (struct exynos4x12_clock *) + samsung_get_base_clock(); + +/************************************************************ + * Step 1: + * + * Set PDIV, MDIV, and SDIV values (Refer to (A, M, E, V) + * Change other PLL control values + ************************************************************/ + + /** + * Set dividers for MOUTcore = 1000 MHz + * + * DOUTcore = MOUTcore / (CORE_RATIO +1) = 1000 MHz (0) + * ACLK_COREM0 = ARMCLK / (COREM0_RATIO +1) = 250 MHz (3) + * ACLK_COREM1 = ARMCLK / (COREM1_RATIO +1) = 125 MHz (7) + * PERIPHCLK = DOUTcore / (PERIPH_RATIO + 1) = 1000 MHz (0) + * ATCLK = MOUTcore / (ATB_RATIO + 1) = 200 MHz (4) + * PCLK_DBG = ATCLK / (PCLK_DBG_RATIO + 1) = 100 MHz (1) + * SCLKapll = MOUTapll / (APLL_RATIO + 1) = 500 MHz (1) + * ARMCLK = DOUTcore / (CORE2_RATIO + 1) = 1000 MHz (0) + */ + + /** CLK_DIV_CPU0 */ + clr = CORE_RATIO(7) | COREM0_RATIO(7) | COREM1_RATIO(7) | + PERIPH_RATIO(7) | ATB_RATIO(7) | PCLK_DBG_RATIO(7) | + APLL_RATIO(7) | CORE2_RATIO(7); + set = CORE_RATIO(0) | COREM0_RATIO(3) | COREM1_RATIO(7) | + PERIPH_RATIO(0) | ATB_RATIO(4) | PCLK_DBG_RATIO(1) | + APLL_RATIO(1) | CORE2_RATIO(0); + div_cpu0, clr, set); + + /* Wait for divider ready status */ div_stat_cpu0) & DIV_STAT_CPU0_CHANGING) + continue; + + /** + * Set dividers for MOUThpm = 1000 MHz (MOUTapll) + * + * DOUTcopy = MOUThpm / (COPY_RATIO + 1) = 200 MHz (4) + * SCLK_HPM = DOUTcopy / (HPM_RATIO + 1) = 200 MHz (0) + * ACLK_CORES = ARMCLK / (CORES_RATIO + 1) = 1000 MHz (0) + */ + + /** CLK_DIV_CPU1 */ + clr = COPY_RATIO(7) | HPM_RATIO(7) | CORES_RATIO(7); + set = COPY_RATIO(4) | HPM_RATIO(0) | CORES_RATIO(0); + div_cpu1, clr, set); + + /* Wait for divider ready status */ div_stat_cpu1) & DIV_STAT_CPU1_CHANGING) + continue; + + /** + * MOUTdmc = 800 MHz + * MOUTdphy = 800 MHz + * + * ACLK_ACP = MOUTdmc / (ACP_RATIO + 1) = 200 MHz (3) + * PCLK_ACP = ACLK_ACP / (ACP_PCLK_RATIO + 1) = 100 MHz (1) + * SCLK_DPHY = MOUTdphy / (DPHY_RATIO + 1) = 400 MHz (1) + * SCLK_DMC = MOUTdmc / (DMC_RATIO + 1) = 400 MHz (1) + * ACLK_DMCD = SCLK_DMC / (DMCD_RATIO + 1) = 200 MHz (1) + * ACLK_DMCP = ACLK_DMCD / (DMCP_RATIO + 1) = 100 MHz (1) + */ + + /** CLK_DIV_DMC0 */ + clr = ACP_RATIO(7) | ACP_PCLK_RATIO(7) | DPHY_RATIO(7) | + DMC_RATIO(7) | DMCD_RATIO(7) | DMCP_RATIO(7); + set = ACP_RATIO(3) | ACP_PCLK_RATIO(1) | DPHY_RATIO(1) | + DMC_RATIO(1) | DMCD_RATIO(1) | DMCP_RATIO(1); + div_dmc0, clr, set); + + /* Wait for divider ready status */ div_stat_dmc0) & DIV_STAT_DMC0_CHANGING) + continue; + + /** + * For: + * MOUTg2d = 800 MHz + * MOUTc2c = 800 Mhz + * MOUTpwi = 24 MHz + * + * SCLK_G2D_ACP = MOUTg2d / (G2D_ACP_RATIO + 1) = 200 MHz (3) + * SCLK_C2C = MOUTc2c / (C2C_RATIO + 1) = 400 MHz (1) + * SCLK_PWI = MOUTpwi / (PWI_RATIO + 1) = 24 MHz (0) + * ACLK_C2C = SCLK_C2C / (C2C_ACLK_RATIO + 1) = 200 MHz (1) + * DVSEM_RATIO : It decides frequency for PWM frame time slot in DVS emulation mode. + * DPM_RATIO : It decides frequency of DPM channel clock. + */ + + /** CLK_DIV_DMC1 */ + clr = G2D_ACP_RATIO(15) | C2C_RATIO(7) | PWI_RATIO(15) | + C2C_ACLK_RATIO(7) | DVSEM_RATIO(127) | DPM_RATIO(127); + set = G2D_ACP_RATIO(3) | C2C_RATIO(1) | PWI_RATIO(0) | + C2C_ACLK_RATIO(1) | DVSEM_RATIO(1) | DPM_RATIO(1); + div_dmc1, clr, set); + + /* Wait for divider ready status */ div_stat_dmc1) & DIV_STAT_DMC1_CHANGING) + continue; + + /** + * MOUTmpll = 800 MHz + * MOUTvpll = 54 MHz + * + * ACLK_200 = MOUTACLK_200 / (ACLK_200_RATIO + 1) = 200 MHz (3) + * ACLK_100 = MOUTACLK_100 / (ACLK_100_RATIO + 1) = 100 MHz (7) + * ACLK_160 = MOUTACLK_160 / (ACLK_160_RATIO + 1) = 160 MHz (4) + * ACLK_133 = MOUTACLK_133 / (ACLK_133_RATIO + 1) = 133 MHz (5) + * ONENAND = MOUTONENAND_1 / (ONENAND_RATIO + 1) = 160 MHz (0) + * ACLK_266_GPS = MOUTACLK_266_GPS / (ACLK_266_GPS_RATIO + 1) = 266 MHz (2) + * ACLK_400_MCUISP = MOUTACLK_400_MCUISP / (ACLK_400_MCUISP_RATIO + 1) = 400 MHz (1) + */ + + /** CLK_DIV_TOP */ + clr = ACLK_200_RATIO(7) | ACLK_100_RATIO(15) | ACLK_160_RATIO(7) | + ACLK_133_RATIO(7) | ONENAND_RATIO(7) | ACLK_266_GPS_RATIO(7) | ACLK_400_MCUISP_RATIO(7); + set = ACLK_200_RATIO(3) | ACLK_100_RATIO(7) | ACLK_160_RATIO(4) | + ACLK_133_RATIO(5) | ONENAND_RATIO(0) | ACLK_266_GPS_RATIO(2) | ACLK_400_MCUISP_RATIO(1); + div_top, clr, set); + + /* Wait for divider ready status */ div_stat_top) & DIV_STAT_TOP_CHANGING) + continue; + + /** + * ACLK_GDL = MOUTGDL / (GDL_RATIO + 1) = 200 MHz (3) + * ACLK_GPL = MOUTGPL / (GPL_RATIO + 1) = 100 MHz (1) + */ + + /** CLK_DIV_LEFTBUS */ + clr = GDL_RATIO(7) | GPL_RATIO(7); + set = GDL_RATIO(3) | GPL_RATIO(1); + div_leftbus, clr, set); + + /* Wait for divider ready status */ div_stat_leftbus) & DIV_STAT_LEFTBUS_CHANGING) + continue; + + /** + * ACLK_GDR = MOUTGDR / (GDR_RATIO + 1) = 200 MHz (3) + * ACLK_GPR = MOUTGPR / (GPR_RATIO + 1) = 100 MHz (1) + */ + + /** CLK_DIV_RIGHTBUS */ + clr = GPR_RATIO(7) | GDR_RATIO(7); + set = GPR_RATIO(3) | GDR_RATIO(1); + div_rightbus, clr, set); + + /* Wait for divider ready status */ div_stat_rightbus) & DIV_STAT_RIGHTBUS_CHANGING) + continue; + + /** + * MOUTUART = 800 Mhz (MPLL) + * + * SCLK_UART0 = MOUTUART0 / (UART0_RATIO + 1) = 100 MHz (7) + * SCLK_UART1 = MOUTUART1 / (UART1_RATIO + 1) = 100 MHz (7) + * SCLK_UART2 = MOUTUART2 / (UART2_RATIO + 1) = 100 MHz (7) + * SCLK_UART3 = MOUTUART3 / (UART3_RATIO + 1) = 100 MHz (7) + * SCLK_UART4 = MOUTUART4 / (UART4_RATIO + 1) = 100 MHz (7) + */ + /** CLK_DIV_PERIL0 */ + clr = UART0_RATIO(15) | UART1_RATIO(15) | UART2_RATIO(15) | + UART3_RATIO(15) | UART4_RATIO(15); + set = UART0_RATIO(7) | UART1_RATIO(7) | UART2_RATIO(7) | + UART3_RATIO(7) | UART4_RATIO(7); + div_peril0, clr, set); + + /* Wait for divider ready status */ div_stat_peril0) & DIV_STAT_PERIL0_CHANGING) + continue; + /** + * For MOUTMMC0-3 = 800 MHz (MPLL) + * + * SCLK_MIPIHSI = MOUTMIPIHSI / (MIPIHSI_RATIO + 1) = 200 MHz (3) + */ + /* CLK_DIV_FSYS0 */ + clr = MIPIHSI_RATIO(15); + set = MIPIHSI_RATIO(3); + div_fsys0, clr, set); + + /* Wait for divider ready status */ div_stat_fsys0) & DIV_STAT_FSYS0_CHANGING) + continue; + + /** + * For MOUTMMC0-3 = 800 MHz (MPLL) + * + * DOUTMMC0 = MOUTMMC0 / (MMC0_RATIO + 1) = 100 MHz (7) + * SCLK_MMC0 = DOUTMMC0 / (MMC0_PRE_RATIO + 1) = 50 MHz (1) + * DOUTMMC1 = MOUTMMC1 / (MMC1_RATIO + 1) = 100 MHz (7) + * SCLK_MMC1 = DOUTMMC1 / (MMC1_PRE_RATIO + 1) = 50 MHz (1) + */ + /* CLK_DIV_FSYS1 */ + clr = MMC0_RATIO(15) | MMC0_PRE_RATIO(255) | MMC1_RATIO(15) | + MMC1_PRE_RATIO(255); + + set = MMC0_RATIO(7) | MMC0_PRE_RATIO(1) | MMC1_RATIO(7) | + MMC1_PRE_RATIO(1); + div_fsys1, clr, set); + + /* Wait for divider ready status */ div_stat_fsys1) & DIV_STAT_FSYS1_CHANGING) + continue; + + /** + * For MOUTmmc0-3 = 800 MHz (MPLL) + * + * DOUTmmc3 = MOUTmmc3 / (MMC2_RATIO + 1) = 100 MHz (7) + * sclk_mmc3 = DOUTmmc3 / (MMC2_PRE_RATIO + 1) = 50 MHz (1) + * DOUTmmc2 = MOUTmmc2 / (MMC3_RATIO + 1) = 100 MHz (7) + * sclk_mmc2 = DOUTmmc2 / (MMC3_PRE_RATIO + 1) = 50 MHz (1) + */ + /* CLK_DIV_FSYS2 */ + clr = MMC2_RATIO(15) | MMC2_PRE_RATIO(255) | MMC3_RATIO(15) | + MMC3_PRE_RATIO(255); + set = MMC2_RATIO(7) | MMC2_PRE_RATIO(1) | MMC3_RATIO(7) | + MMC3_PRE_RATIO(1); + div_fsys2, clr, set); + + /* Wait for divider ready status */ div_stat_fsys2) & DIV_STAT_FSYS2_CHANGING) + continue; + + /** + * For MOUTmmc4 = 800 MHz (MPLL) + * + * DOUTmmc4 = MOUTmmc4 / (MMC4_RATIO + 1) = 100 MHz (7) + * sclk_mmc4 = DOUTmmc4 / (MMC4_PRE_RATIO + 1) = 50 MHz (1) + */ + /* CLK_DIV_FSYS3 */ + clr = MMC4_RATIO(15) | MMC4_PRE_RATIO(255); + set = MMC4_RATIO(7) | MMC4_PRE_RATIO(1); + div_fsys3, clr, set); + + /* Wait for divider ready status */ div_stat_fsys3) & DIV_STAT_FSYS3_CHANGING) + continue; + +/************************************************************ + * Step 2: + * + * Set K, AFC, MRR, MFR values if necessary + * (Refer to (A, M, E, V)PLL_CON1 SFRs) + * Turn on a PLL (Refer to (A, M, E, V) PLL_CON0 SFRs) + ************************************************************/ + + /* Set APLL to 1000MHz */ + /** APLL_CON1 */ + clr = AFC(31) | LOCK_CON_DLY(31) | LOCK_CON_IN(3) | + LOCK_CON_OUT(3) |FEED_EN(1)| AFC_ENB(1) | + DCC_ENB(1) | BYPASS(1) |RESV0(1) | RESV1(1); + set = AFC(0) | LOCK_CON_DLY(8) | LOCK_CON_IN(3) | + LOCK_CON_OUT(0) |FEED_EN(0)| AFC_ENB(0) | + DCC_ENB(1) | BYPASS(0) |RESV0(0) | RESV1(0); + apll_con1, clr, set); + + /** APLL_CON0 */ + clr_pll_con0 = SDIV(7) | PDIV(63) | MDIV(1023) | FSEL(1) | PLL_ENABLE(1); + set = SDIV(0) | PDIV(3) | MDIV(125) | FSEL(0) | PLL_ENABLE(1); + apll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ apll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Set MPLL to 800MHz */ + /** MPLL_CON1 */ + clr = AFC(31) | LOCK_CON_DLY(31) | LOCK_CON_IN(3) | + LOCK_CON_OUT(3) |FEED_EN(1)| AFC_ENB(1) | + DCC_ENB(1) | BYPASS(1) |RESV0(1) | RESV1(1); + set = AFC(0) | LOCK_CON_DLY(8) | LOCK_CON_IN(3) | + LOCK_CON_OUT(0) |FEED_EN(0)| AFC_ENB(0) | + DCC_ENB(1) | BYPASS(0) |RESV0(0) | RESV1(0); + mpll_con1, clr, set); + + /** MPLL_CON0 */ + clr_pll_con0 = SDIV(7) | PDIV(63) | MDIV(1023) | FSEL(1) | PLL_ENABLE(1); + set = SDIV(0) | PDIV(3) | MDIV(100) | FSEL(0) | PLL_ENABLE(1); + mpll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ mpll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Set EPLL to 192MHz */ + /** EPLL_CON2 */ + clr = ICP_BOOST(7) | EV_FSEL(1) | FVCO_EN(1) | EV_BYPASS(1) | + SSCG_EN(1) | EV_AFC_ENB(1) | EV_DCC_ENB(1) | EXTAFC(1); + set = ICP_BOOST(0) | EV_FSEL(1) | FVCO_EN(1) | EV_BYPASS(1) | + SSCG_EN(0) | EV_AFC_ENB(0) | EV_DCC_ENB(1) | EXTAFC(0); + epll_con2, clr, set); + + /** EPLL_CON1 */ + /* there is null */ + + /** EPLL_CON0 */ + clr_pll_con0 = SDIV(7) | PDIV(63) | MDIV(1023) | FSEL(1) | PLL_ENABLE(1); + set = SDIV(2) | PDIV(2) | MDIV(64) | FSEL(0) | PLL_ENABLE(1); + epll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ epll_con0) & PLL_LOCKED_BIT)) + continue; + + /* Set VPLL to 54MHz */ + /** VPLL_CON2 */ + clr = ICP_BOOST(7) | EV_FSEL(1) | FVCO_EN(1) | EV_BYPASS(1) | + SSCG_EN(1) | EV_AFC_ENB(1) | EV_DCC_ENB(1) | EXTAFC(1); + set = ICP_BOOST(0) | EV_FSEL(1) | FVCO_EN(1) | EV_BYPASS(1) | + SSCG_EN(0) | EV_AFC_ENB(0) | EV_DCC_ENB(1) | EXTAFC(0); + vpll_con2, clr, set); + + /** VPLL_CON1 */ + /* there is null */ + + /** VPLL_CON0 */ + clr_pll_con0 = SDIV(7) | PDIV(63) | MDIV(1023) | FSEL(1) | PLL_ENABLE(1); + set = SDIV(3) | PDIV(3) | MDIV(54) | FSEL(0) | PLL_ENABLE(1); + vpll_con0, clr_pll_con0, set); + + /* Wait for PLL to be locked */ vpll_con0) & PLL_LOCKED_BIT)) + continue; + +/************************************************************ + *Step 3: + * + * Wait until the PLL is locked + ************************************************************/ + clr = PLL_LOCKTIME(65535); + + /** APLL LOCKTIME 1000MHz */ + set = PLL_LOCKTIME(PDIV(3) * 270); apll_lock, clr, set); + + /** MPLL LOCKTIME 800MHz */ + set = PLL_LOCKTIME(PDIV(3) * 270); mpll_lock, clr, set); + + /** EPLL LOCKTIME 192MHz */ + set = PLL_LOCKTIME(PDIV(2) * 270); epll_lock, clr, set); + + /** VPLL LOCKTIME 54MHz */ + set = PLL_LOCKTIME(PDIV(3) * 270); vpll_lock, clr, set); + +/************************************************************ + * Step 4: + * + * Select the PLL output clock instead of input reference clock, + * after PLL output clock is stabilized. + * (Refer to CLK_SRC_CPU SFR for APLL and MPLL, + * CLK_SRC_TOP0 for EPLL and VPLL) + * Once a PLL is turned on, do not turn it off. + ************************************************************/ + + /** + * before set system clocks,we switch system clocks src to FINpll + * + * Bit values: 0 ; 1 + * MUX_APLL_SEL: FIN_PLL ; MOUTAPLLFOUT + * MUX_CORE_SEL: MOUTAPLL ; SCLKMPLL + * MUX_HPM_SEL: MOUTAPLL ; SCLKMPLL + * MUX_MPLL_USER_SEL_C: FINPLL ; FOUTMPLL + */ + /** CLK_SRC_CPU */ + clr_src_cpu = MUX_APLL_SEL(1) | MUX_CORE_SEL(1) | + MUX_HPM_SEL(1) | MUX_MPLL_USER_SEL_C(1); + set = MUX_APLL_SEL(1) | MUX_CORE_SEL(0) | MUX_HPM_SEL(0) | + MUX_MPLL_USER_SEL_C(1); + src_cpu, clr_src_cpu, set); + + /* Wait for mux change */ mux_stat_cpu) & MUX_STAT_CPU_CHANGING) + continue; + + /** + * Set CMU_DMC default clocks src to APLL + * + * Bit values: 0 ; 1 + * MUX_C2C_SEL: SCLKMPLL ; SCLKAPLL + * MUX_DMC_BUS_SEL: SCLKMPLL ; SCLKAPLL + * MUX_DPHY_SEL: SCLKMPLL ; SCLKAPLL + * MUX_MPLL_SEL: FINPLL ; MOUT_MPLL_FOUT + * MUX_PWI_SEL: 0110 (MPLL); 0111 (EPLL); 1000 (VPLL); 0(XXTI) + * MUX_G2D_ACP0_SEL: SCLKMPLL ; SCLKAPLL + * MUX_G2D_ACP1_SEL: SCLKEPLL ; SCLKVPLL + * MUX_G2D_ACP_SEL: OUT_ACP0 ; OUT_ACP1 + */ + /** CLK_SRC_DMC */ + clr_src_dmc = MUX_C2C_SEL(1) | MUX_DMC_BUS_SEL(1) | + MUX_DPHY_SEL(1) | MUX_MPLL_SEL(1) | + MUX_PWI_SEL(15) | MUX_G2D_ACP0_SEL(1) | + MUX_G2D_ACP1_SEL(1) | MUX_G2D_ACP_SEL(1); + set = MUX_C2C_SEL(0) | MUX_DMC_BUS_SEL(0) | MUX_DPHY_SEL(0) | + MUX_MPLL_SEL(1) | MUX_PWI_SEL(0) | MUX_G2D_ACP0_SEL(0) | + MUX_G2D_ACP1_SEL(0) | MUX_G2D_ACP_SEL(0); + src_dmc, clr_src_dmc, set); + + /* Wait for mux change */ mux_stat_dmc) & MUX_STAT_DMC_CHANGING) + continue; + + /** + * Set CMU_TOP default clocks src to APLL + * + * Bit values: 0 ; 1 + * MUX_ONENAND_1_SEL MOUTONENAND ; SCLKVPLL + * MUX_EPLL_SEL FINPLL ; FOUTEPLL + * MUX_VPLL_SEL FINPLL ; FOUTEPLL + * MUX_ACLK_200_SEL SCLKMPLL ; SCLKAPLL + * MUX_ACLK_100_SEL SCLKMPLL ; SCLKAPLL + * MUX_ACLK_160_SEL SCLKMPLL ; SCLKAPLL + * MUX_ACLK_133_SEL SCLKMPLL ; SCLKAPLL + * MUX_ONENAND_SEL ACLK_133 ; ACLK_160 + */ + + /* CLK_SRC_TOP0 */ + clr = MUX_ONENAND_1_SEL(1) | MUX_EPLL_SEL(1) | MUX_VPLL_SEL(1) | + MUX_ACLK_200_SEL(1) | MUX_ACLK_100_SEL(1) | MUX_ACLK_160_SEL(1) | + MUX_ACLK_133_SEL(1) | MUX_ONENAND_SEL(1); + set = MUX_ONENAND_1_SEL(0) | MUX_EPLL_SEL(1) | MUX_VPLL_SEL(1) | + MUX_ACLK_200_SEL(0) | MUX_ACLK_100_SEL(0) | MUX_ACLK_160_SEL(0) | + MUX_ACLK_133_SEL(0) | MUX_ONENAND_SEL(1); + src_top0, clr, set); + + /* Wait for mux change */ mux_stat_top0) & MUX_STAT_TOP0_CHANGING) + continue; + + /** + * Bit values: 0 ; 1 + * MUX_ACLK_266_GPS_SEL SCLKMPLL_USER_T ; SCLKAPLL + * MUX_ACLK_400_MCUISP_SEL SCLKMPLL_USER_T ; SCLKAPLL + * MUX_MPLL_USER_SEL_T FINPLL ; SCLKMPLLL + * MUX_ACLK_266_GPS_SUB_SEL FINPLL ; DIVOUT_ACLK_266_GPS + * MUX_ACLK_200_SUB_SEL FINPLL ; DIVOUT_ACLK_200 + * MUX_ACLK_400_MCUISP_SUB_SEL FINPLL + */ + + /* CLK_SRC_TOP1 */ + clr = MUX_ACLK_266_GPS_SEL(1) | MUX_ACLK_400_MCUISP_SEL(1) | + MUX_MPLL_USER_SEL_T(1) | MUX_ACLK_266_GPS_SUB_SEL(1) | + MUX_ACLK_200_SUB_SEL(1) | MUX_ACLK_400_MCUISP_SUB_SEL(1); + set = MUX_ACLK_266_GPS_SEL(0) | MUX_ACLK_400_MCUISP_SEL(0) | + MUX_MPLL_USER_SEL_T(1) | MUX_ACLK_266_GPS_SUB_SEL(1) | + MUX_ACLK_200_SUB_SEL(1) | MUX_ACLK_400_MCUISP_SUB_SEL(1); + src_top1, clr, set); + + /* Wait for mux change */ mux_stat_top1) & MUX_STAT_TOP1_CHANGING) + continue; + + /* CLK_SRC_LEFTBUS */ + clr = MUX_GDL_SEL(1) | MUX_MPLL_USER_SEL_L(1); + set = MUX_GDL_SEL(0) | MUX_MPLL_USER_SEL_L(1); + src_leftbus, clr, set); + + /* Wait for mux change */ mux_stat_leftbus) & MUX_STAT_LEFTBUS_CHANGING) + continue; + + /* CLK_SRC_RIGHTBUS */ + clr = MUX_GDR_SEL(1) | MUX_MPLL_USER_SEL_R(1); + set = MUX_GDR_SEL(0) | MUX_MPLL_USER_SEL_R(1); + src_rightbus, clr, set); + + /* Wait for mux change */ mux_stat_rightbus) & MUX_STAT_RIGHTBUS_CHANGING) + continue; + + /** CLK_SRC_PERIL0 */ + clr = UART0_SEL(15) | UART1_SEL(15) | UART2_SEL(15) | + UART3_SEL(15) | UART4_SEL(15); + set = UART0_SEL(6) | UART1_SEL(6) | UART2_SEL(6) | + UART3_SEL(6) | UART4_SEL(6); + src_peril0, clr, set); + + /** CLK_SRC_FSYS */ + clr = MMC1_SEL(15) | MMC2_SEL(15) | MMC3_SEL(15) | + MMC4_SEL(15) | MIPIHSI_SEL(1); + set = MMC1_SEL(6) | MMC2_SEL(6) | MMC3_SEL(6) | + MMC4_SEL(6) | MIPIHSI_SEL(0); + src_fsys, clr, set); }    3.修改ex4412_setup.h   参照arch/arm/mach-exynos/exynos4_setup.h修改部分内容,由于对该部分不是很了解,在移植过程中遇到未能正确配置而导致写入内存的数据无法正确读取的情况。以下做记录,后续再查找相关文档分析学习。 diff --git a/arch/arm/mach-exynos/ex4412_setup.h b/arch/arm/mach-exynos/ex4412_setup.h new file mode 100644 index 0000000..65a205a --- /dev/null +++ b/arch/arm/mach-exynos/ex4412_setup.h @@ -0,0 +1,608 @@ +#ifndef _EX4412_SETUP_H +#define _EX4412_SETUP_H + +#include +#include + +#ifdef CONFIG_CLK_800_330_165 +#define DRAM_CLK_330 +#endif +#ifdef CONFIG_CLK_1000_200_200 +#define DRAM_CLK_200 +#endif +#ifdef CONFIG_CLK_1000_330_165 +#define DRAM_CLK_330 +#endif +#ifdef CONFIG_CLK_1000_400_200 +#define DRAM_CLK_400 +#endif + +/* this state is changing for register */ +#define MUX_STAT_CHANGING 0x100 +#define DIV_STAT_CHANGING 0x1 + +/* A/M/EV PLL_CON0 */ +#define SDIV(x) ((x) & 0x7) +#define PDIV(x) (((x) & 0x3f) << 8) +#define MDIV(x) (((x) & 0x3ff) << 16) +#define FSEL(x) (((x) & 0x1) << 27) +#define PLL_LOCKED_BIT (0x1 << 29) +#define PLL_ENABLE(x) (((x) & 0x1) << 31) + +/* A/M PLL_CON1 */ +#define AFC(x) ((x) & 0x1f) +#define LOCK_CON_DLY(x) (((x) & 0x1f) << 8) +#define LOCK_CON_IN(x) (((x) & 0x3) << 12) +#define LOCK_CON_OUT(x) (((x) & 0x3) << 14) +#define FEED_EN(x) (((x) & 0x1) << 16) +#define AFC_ENB(x) (((x) & 0x1) << 20) +#define DCC_ENB(x) (((x) & 0x1) << 21) +#define BYPASS(x) (((x) & 0x1) << 22) +#define RESV0(x) (((x) & 0x1) << 23) +#define RESV1(x) (((x) & 0x1) << 24) + +/* E/V PLL_CON1 */ +#define K(x) ((x) & 0xffff) +#define MFR(x) (((x) & 0xff) << 16) +#define MRR(x) (((x) & 0x1f) << 24) +#define SEL_PF(x) (((x) & 0x3) << 29) + +/* E/V PLL_CON2 */ +#define ICP_BOOST(x) ((x) & 0x3) +#define EV_FSEL(x) (((x) & 0x1) << 2) +#define FVCO_EN(x) (((x) & 0x1) << 3) +#define EV_BYPASS(x) (((x) & 0x1) << 4) +#define SSCG_EN(x) (((x) & 0x1) << 5) +#define EV_AFC_ENB(x) (((x) & 0x1) << 6) +#define EV_DCC_ENB(x) (((x) & 0x1) << 7) +#define EXTAFC(x) (((x) & 0x1f) << 8) + +/* CLK_SRC_CPU */ +#define MUX_APLL_SEL(x) ((x) & 0x1) +#define MUX_CORE_SEL(x) (((x) & 0x1) << 16) +#define MUX_HPM_SEL(x) (((x) & 0x1) << 20) +#define MUX_MPLL_USER_SEL_C(x) (((x) & 0x1) << 24) + +/* CLK_MUX_STAT_CPU */ +#define APLL_SEL(x) ((x) & 0x7) +#define CORE_SEL(x) (((x) & 0x7) << 16) +#define HPM_SEL(x) (((x) & 0x7) << 20) +#define MPLL_USER_SEL_C(x) (((x) & 0x7) << 24) +#define MUX_STAT_CPU_CHANGING (APLL_SEL(MUX_STAT_CHANGING) | \ + CORE_SEL(MUX_STAT_CHANGING) | \ + HPM_SEL(MUX_STAT_CHANGING) | \ + MPLL_USER_SEL_C(MUX_STAT_CHANGING)) + +/* A/M/E/V PLL_LOCK */ +#define PLL_LOCKTIME(x) ((x) & 0xffff) + +/* CLK_DIV_CPU0 */ +#define CORE_RATIO(x) ((x) & 0x7) +#define COREM0_RATIO(x) (((x) & 0x7) << 4) +#define COREM1_RATIO(x) (((x) & 0x7) << 8) +#define PERIPH_RATIO(x) (((x) & 0x7) << 12) +#define ATB_RATIO(x) (((x) & 0x7) << 16) +#define PCLK_DBG_RATIO(x) (((x) & 0x7) << 20) +#define APLL_RATIO(x) (((x) & 0x7) << 24) +#define CORE2_RATIO(x) (((x) & 0x7) << 28) + +/* CLK_DIV_CPU1 */ +#define COPY_RATIO(x) ((x) & 0x7) +#define HPM_RATIO(x) (((x) & 0x7) << 4) +#define CORES_RATIO(x) (((x) & 0x7) << 8) + +/* CLK_DIV_STAT_CPU0 */ +#define DIV_CORE(x) ((x) & 0x1) +#define DIV_COREM0(x) (((x) & 0x1) << 4) +#define DIV_COREM1(x) (((x) & 0x1) << 8) +#define DIV_PERIPH(x) (((x) & 0x1) << 12) +#define DIV_ATB(x) (((x) & 0x1) << 16) +#define DIV_PCLK_DBG(x) (((x) & 0x1) << 20) +#define DIV_APLL(x) (((x) & 0x1) << 24) +#define DIV_CORE2(x) (((x) & 0x1) << 28) + +#define DIV_STAT_CPU0_CHANGING (DIV_CORE(DIV_STAT_CHANGING) | \ + DIV_COREM0(DIV_STAT_CHANGING) | \ + DIV_COREM1(DIV_STAT_CHANGING) | \ + DIV_PERIPH(DIV_STAT_CHANGING) | \ + DIV_ATB(DIV_STAT_CHANGING) | \ + DIV_PCLK_DBG(DIV_STAT_CHANGING) | \ + DIV_APLL(DIV_STAT_CHANGING) | \ + DIV_CORE2(DIV_STAT_CHANGING)) + +/* CLK_DIV_STAT_CPU1 */ +#define DIV_COPY(x) ((x) & 0x1) +#define DIV_HPM(x) (((x) & 0x1) << 4) +#define DIV_CORES(x) (((x) & 0x1) << 8) + +#define DIV_STAT_CPU1_CHANGING (DIV_COPY(DIV_STAT_CHANGING) | \ + DIV_HPM(DIV_STAT_CHANGING) | \ + DIV_CORES(DIV_STAT_CHANGING)) + +/* CLK_SRC_DMC */ +#define MUX_C2C_SEL(x) ((x) & 0x1) +#define MUX_DMC_BUS_SEL(x) (((x) & 0x1) << 4) +#define MUX_DPHY_SEL(x) (((x) & 0x1) << 8) +#define MUX_MPLL_SEL(x) (((x) & 0x1) << 12) +#define MUX_PWI_SEL(x) (((x) & 0xf) << 16) +#define MUX_G2D_ACP0_SEL(x) (((x) & 0x1) << 20) +#define MUX_G2D_ACP1_SEL(x) (((x) & 0x1) << 24) +#define MUX_G2D_ACP_SEL(x) (((x) & 0x1) << 28) + +/* CLK_MUX_STAT_DMC */ +#define C2C_SEL(x) ((x) & 0x7) +#define DMC_BUS_SEL(x) (((x) & 0x7) << 4) +#define DPHY_SEL(x) (((x) & 0x7) << 8) +#define MPLL_SEL(x) (((x) & 0x7) << 12) +#define G2D_ACP0_SEL(x) (((x) & 0x7) << 20) +#define G2D_ACP1_SEL(x) (((x) & 0x7) << 24) +#define G2D_ACP_SEL(x) (((x) & 0x7) << 28) + +#define MUX_STAT_DMC_CHANGING (C2C_SEL(MUX_STAT_CHANGING) | \ + DMC_BUS_SEL(MUX_STAT_CHANGING) | \ + DPHY_SEL(MUX_STAT_CHANGING) | \ + MPLL_SEL(MUX_STAT_CHANGING) |\ + G2D_ACP0_SEL(MUX_STAT_CHANGING) | \ + G2D_ACP1_SEL(MUX_STAT_CHANGING) | \ + G2D_ACP_SEL(MUX_STAT_CHANGING)) + +/* CLK_DIV_DMC0 */ +#define ACP_RATIO(x) ((x) & 0x7) +#define ACP_PCLK_RATIO(x) (((x) & 0x7) << 4) +#define DPHY_RATIO(x) (((x) & 0x7) << 8) +#define DMC_RATIO(x) (((x) & 0x7) << 12) +#define DMCD_RATIO(x) (((x) & 0x7) << 16) +#define DMCP_RATIO(x) (((x) & 0x7) << 20) + +/* CLK_DIV_DMC1 */ +#define G2D_ACP_RATIO(x) ((x) & 0xf) +#define C2C_RATIO(x) (((x) & 0x7) << 4) +#define PWI_RATIO(x) (((x) & 0xf) << 8) +#define C2C_ACLK_RATIO(x) (((x) & 0x7) << 12) +#define DVSEM_RATIO(x) (((x) & 0x7f) << 16) +#define DPM_RATIO(x) (((x) & 0x7f) << 24) + +/* CLK_DIV_STAT_DMC0 */ +#define DIV_ACP(x) ((x) & 0x1) +#define DIV_ACP_PCLK(x) (((x) & 0x1) << 4) +#define DIV_DPHY(x) (((x) & 0x1) << 8) +#define DIV_DMC(x) (((x) & 0x1) << 12) +#define DIV_DMCD(x) (((x) & 0x1) << 16) +#define DIV_DMCP(x) (((x) & 0x1) << 20) + +#define DIV_STAT_DMC0_CHANGING (DIV_ACP(DIV_STAT_CHANGING) | \ + DIV_ACP_PCLK(DIV_STAT_CHANGING) | \ + DIV_DPHY(DIV_STAT_CHANGING) | \ + DIV_DMC(DIV_STAT_CHANGING) | \ + DIV_DMCD(DIV_STAT_CHANGING) | \ + DIV_DMCP(DIV_STAT_CHANGING)) + +/* CLK_DIV_STAT_DMC1 */ +#define DIV_G2D_ACP(x) ((x) & 0x1) +#define DIV_C2C(x) (((x) & 0x1) << 4) +#define DIV_PWI(x) (((x) & 0x1) << 8) +#define DIV_C2C_ACLK(x) (((x) & 0x1) << 12) +#define DIV_DVSEM(x) (((x) & 0x1) << 16) +#define DIV_DPM(x) (((x) & 0x1) << 24) + +#define DIV_STAT_DMC1_CHANGING (DIV_G2D_ACP(DIV_STAT_CHANGING) | \ + DIV_C2C(DIV_STAT_CHANGING) | \ + DIV_PWI(DIV_STAT_CHANGING) | \ + DIV_C2C_ACLK(DIV_STAT_CHANGING) | \ + DIV_DVSEM(DIV_STAT_CHANGING) | \ + DIV_DPM(DIV_STAT_CHANGING)) + +/* CLK_SRC_TOP0 */ +#define MUX_ONENAND_1_SEL(x) ((x) & 0x1) +#define MUX_EPLL_SEL(x) (((x) & 0x1) << 4) +#define MUX_VPLL_SEL(x) (((x) & 0x1) << 8) +#define MUX_ACLK_200_SEL(x) (((x) & 0x1) << 12) +#define MUX_ACLK_100_SEL(x) (((x) & 0x1) << 16) +#define MUX_ACLK_160_SEL(x) (((x) & 0x1) << 20) +#define MUX_ACLK_133_SEL(x) (((x) & 0x1) << 24) +#define MUX_ONENAND_SEL(x) (((x) & 0x1) << 28) + +/* CLK_MUX_STAT_TOP */ +#define ONENAND_1_SEL(x) ((x) & 0x3) +#define EPLL_SEL(x) (((x) & 0x3) << 4) +#define VPLL_SEL(x) (((x) & 0x3) << 8) +#define ACLK_200_SEL(x) (((x) & 0x3) << 12) +#define ACLK_100_SEL(x) (((x) & 0x3) << 16) +#define ACLK_160_SEL(x) (((x) & 0x3) << 20) +#define ACLK_133_SEL(x) (((x) & 0x3) << 24) +#define ONENAND_SEL(x) (((x) & 0x3) << 28) + +#define MUX_STAT_TOP0_CHANGING (ONENAND_1_SEL(MUX_STAT_CHANGING) | \ + EPLL_SEL(MUX_STAT_CHANGING) | \ + EPLL_SEL(MUX_STAT_CHANGING) | \ + VPLL_SEL(MUX_STAT_CHANGING) | \ + ACLK_200_SEL(MUX_STAT_CHANGING) | \ + ACLK_100_SEL(MUX_STAT_CHANGING) | \ + ACLK_160_SEL(MUX_STAT_CHANGING) | \ + ACLK_133_SEL(MUX_STAT_CHANGING) | \ + ONENAND_SEL(MUX_STAT_CHANGING)) + +/* CLK_SRC_TOP1 */ +#define MUX_ACLK_266_GPS_SEL(x) (((x) & 0x1) << 4) +#define MUX_ACLK_400_MCUISP_SEL(x) (((x) & 0x1) << 8) +#define MUX_MPLL_USER_SEL_T(x) (((x) & 0x1) << 12) +#define MUX_ACLK_266_GPS_SUB_SEL(x) (((x) & 0x1) << 16) +#define MUX_ACLK_200_SUB_SEL(x) (((x) & 0x1) << 20) +#define MUX_ACLK_400_MCUISP_SUB_SEL(x) (((x) & 0x1) << 24) + +/* CLK_MUX_STAT_TOP1 */ +#define ACLK_266_GPS_SEL(x) (((x) & 0x3) << 4) +#define ACLK_400_MCUISP_SEL(x) (((x) & 0x3) << 8) +#define MPLL_USER_SEL_T(x) (((x) & 0x3) << 12) +#define ACLK_266_GPS_SUB_SEL(x) (((x) & 0x3) << 16) +#define ACLK_200_SUB_SEL(x) (((x) & 0x3) << 20) +#define ACLK_400_MCUISP_SUB_SEL(x) (((x) & 0x3) << 24) + +#define MUX_STAT_TOP1_CHANGING (MUX_ACLK_266_GPS_SEL(MUX_STAT_CHANGING) | \ + ACLK_400_MCUISP_SEL(MUX_STAT_CHANGING) | \ + MPLL_USER_SEL_T(MUX_STAT_CHANGING) | \ + ACLK_266_GPS_SUB_SEL(MUX_STAT_CHANGING) | \ + ACLK_200_SUB_SEL(MUX_STAT_CHANGING) | \ + ACLK_400_MCUISP_SUB_SEL(MUX_STAT_CHANGING)) + +/* CLK_DIV_TOP */ +#define ACLK_200_RATIO(x) ((x) & 0x7) +#define ACLK_100_RATIO(x) (((x) & 0xf) << 4) +#define ACLK_160_RATIO(x) (((x) & 0x7) << 8) +#define ACLK_133_RATIO(x) (((x) & 0x7) << 12) +#define ONENAND_RATIO(x) (((x) & 0x7) << 16) +#define ACLK_266_GPS_RATIO(x) (((x) & 0x7) << 20) +#define ACLK_400_MCUISP_RATIO(x) (((x) & 0x7) << 24) + +#define DIV_STAT_TOP_CHANGING (ACLK_400_MCUISP_RATIO(DIV_STAT_CHANGING) | \ + ACLK_266_GPS_RATIO(DIV_STAT_CHANGING) | \ + ONENAND_RATIO(DIV_STAT_CHANGING) | \ + ACLK_133_RATIO(DIV_STAT_CHANGING) | \ + ACLK_160_RATIO(DIV_STAT_CHANGING) | \ + ACLK_100_RATIO(DIV_STAT_CHANGING) | \ + ACLK_200_RATIO(DIV_STAT_CHANGING)) + +/* CLK_SRC_LEFTBUS */ +#define MUX_GDL_SEL(x) ((x) & 0x1) +#define MUX_MPLL_USER_SEL_L(x) (((x) & 0x1) << 4) + +/* CLK_MUX_STAT_LEFTBUS */ +#define GDL_SEL(x) ((x) & 0x7) +#define MPLL_USER_SEL_L(x) (((x) & 0x7) << 4) + +#define MUX_STAT_LEFTBUS_CHANGING (GDL_SEL(MUX_STAT_CHANGING) | \ + MPLL_USER_SEL_L(MUX_STAT_CHANGING)) + +/* CLK_DIV_LEFTBUS */ +#define GDL_RATIO(x) ((x) & 0x7) +#define GPL_RATIO(x) (((x) & 0x7) << 4) + +/* CLK_DIV_STAT_LEFTBUS */ +#define DIV_GDL(x) ((x) & 0x1) +#define DIV_GPL(x) (((x) & 0x1) << 4) + +#define DIV_STAT_LEFTBUS_CHANGING (DIV_GDL(DIV_STAT_CHANGING) | \ + DIV_GPL(DIV_STAT_CHANGING)) + +/* CLK_SRC_RIGHTBUS */ +#define MUX_GDR_SEL(x) ((x) & 0x1) +#define MUX_MPLL_USER_SEL_R(x) (((x) & 0x1) << 4) + +/* CLK_MUX_STAT_RIGHTBUS */ +#define GDR_SEL(x) ((x) & 0x7) +#define MPLL_USER_SEL_R(x) (((x) & 0x7) << 4) + +#define MUX_STAT_RIGHTBUS_CHANGING (GDR_SEL(MUX_STAT_CHANGING) | \ + MPLL_USER_SEL_R(MUX_STAT_CHANGING)) + +/* CLK_DIV_RIGHTBUS */ +#define GPR_RATIO(x) ((x) & 0x7) +#define GDR_RATIO(x) (((x) & 0x7) << 4) + +/* CLK_DIV_STAT_RIGHTBUS */ +#define DIV_GDR(x) ((x) & 0x1) +#define DIV_GPR(x) ((x) & 0x1) + +#define DIV_STAT_RIGHTBUS_CHANGING (DIV_GDR(DIV_STAT_CHANGING) | \ + DIV_GPR(DIV_STAT_CHANGING)) + +/* CLK_SRC_PERIL0 */ +#define UART0_SEL(x) ((x) & 0xf) +#define UART1_SEL(x) (((x) & 0xf) << 4) +#define UART2_SEL(x) (((x) & 0xf) << 8) +#define UART3_SEL(x) (((x) & 0xf) << 12) +#define UART4_SEL(x) (((x) & 0xf) << 16) + +/* CLK_DIV_PERIL0 */ +#define UART0_RATIO(x) ((x) & 0xf) +#define UART1_RATIO(x) (((x) & 0xf) << 4) +#define UART2_RATIO(x) (((x) & 0xf) << 8) +#define UART3_RATIO(x) (((x) & 0xf) << 12) +#define UART4_RATIO(x) (((x) & 0xf) << 16) + +/* CLK_DIV_STAT_PERIL0 */ +#define DIV_UART0(x) ((x) & 0x1) +#define DIV_UART1(x) (((x) & 0x1) << 4) +#define DIV_UART2(x) (((x) & 0x1) << 8) +#define DIV_UART3(x) (((x) & 0x1) << 12) +#define DIV_UART4(x) (((x) & 0x1) << 16) + +#define DIV_STAT_PERIL0_CHANGING (DIV_UART4(DIV_STAT_CHANGING) | \ + DIV_UART3(DIV_STAT_CHANGING) | \ + DIV_UART2(DIV_STAT_CHANGING) | \ + DIV_UART1(DIV_STAT_CHANGING) | \ + DIV_UART0(DIV_STAT_CHANGING)) + +/* CLK_SRC_FSYS */ +#define MMC1_SEL(x) (((x) & 0xf) << 4) +#define MMC2_SEL(x) (((x) & 0xf) << 8) +#define MMC3_SEL(x) (((x) & 0xf) << 12) +#define MMC4_SEL(x) (((x) & 0xf) << 16) +#define MIPIHSI_SEL(x) (((x) & 0x1) << 24) + +/* CLK_DIV_FSYS0 */ +#define MIPIHSI_RATIO(x) (((x) & 0xf) << 20) + +/* CLK_DIV_STAT_FSYS0 */ +#define DIV_MIPIHSI(x) (((x) & 0x1) << 20) + +#define DIV_STAT_FSYS0_CHANGING (DIV_MIPIHSI(DIV_STAT_CHANGING)) + +/* CLK_DIV_FSYS1 */ +#define MMC0_RATIO(x) ((x) & 0xf) +#define MMC0_PRE_RATIO(x) (((x) & 0xff) << 8) +#define MMC1_RATIO(x) (((x) & 0xf) << 16) +#define MMC1_PRE_RATIO(x) (((x) & 0xff) << 24) + +/* CLK_DIV_STAT_FSYS1 */ +#define DIV_MMC0(x) ((x) & 1) +#define DIV_MMC0_PRE(x) (((x) & 1) << 8) +#define DIV_MMC1(x) (((x) & 1) << 16) +#define DIV_MMC1_PRE(x) (((x) & 1) << 24) + +#define DIV_STAT_FSYS1_CHANGING (DIV_MMC0(DIV_STAT_CHANGING) | \ + DIV_MMC0_PRE(DIV_STAT_CHANGING) | \ + DIV_MMC1(DIV_STAT_CHANGING) | \ + DIV_MMC1_PRE(DIV_STAT_CHANGING)) + +/* CLK_DIV_FSYS2 */ +#define MMC2_RATIO(x) ((x) & 0xf) +#define MMC2_PRE_RATIO(x) (((x) & 0xff) << 8) +#define MMC3_RATIO(x) (((x) & 0xf) << 16) +#define MMC3_PRE_RATIO(x) (((x) & 0xff) << 24) + +/* CLK_DIV_STAT_FSYS2 */ +#define DIV_MMC2(x) ((x) & 0x1) +#define DIV_MMC2_PRE(x) (((x) & 0x1) << 8) +#define DIV_MMC3(x) (((x) & 0x1) << 16) +#define DIV_MMC3_PRE(x) (((x) & 0x1) << 24) + +#define DIV_STAT_FSYS2_CHANGING (DIV_MMC2(DIV_STAT_CHANGING) | \ + DIV_MMC2_PRE(DIV_STAT_CHANGING) | \ + DIV_MMC3(DIV_STAT_CHANGING) | \ + DIV_MMC3_PRE(DIV_STAT_CHANGING)) + +/* CLK_DIV_FSYS3 */ +#define MMC4_RATIO(x) ((x) & 0x7) +#define MMC4_PRE_RATIO(x) (((x) & 0xff) << 8) + +/* CLK_DIV_STAT_FSYS3 */ +#define DIV_MMC4(x) ((x) & 0x1) +#define DIV_MMC4_PRE(x) (((x) & 0x1) << 8) + +#define DIV_STAT_FSYS3_CHANGING (DIV_MMC4(DIV_STAT_CHANGING) | \ + DIV_MMC4_PRE(DIV_STAT_CHANGING)) + +/* DMC */ +#ifdef CONFIG_CLK_800_330_165 +#define DRAM_CLK_330 +#endif +#ifdef CONFIG_CLK_1000_200_200 +#define DRAM_CLK_200 +#endif +#ifdef CONFIG_CLK_1000_330_165 +#define DRAM_CLK_330 +#endif +#ifdef CONFIG_CLK_1000_400_200 +#define DRAM_CLK_400 +#endif + +/* Bus Configuration Register Address */ +#define ASYNC_CONFIG 0x10010350 + +#define DIRECT_CMD_NOP 0x07000000 +#define DIRECT_CMD_ZQ 0x0a000000 +#define DIRECT_CMD_CHIP1_SHIFT (1 << 20) +#define MEM_TIMINGS_MSR_COUNT 4 +#define CTRL_START (1 << 0) +#define CTRL_DLL_ON (1 << 1) +#define AREF_EN (1 << 5) +#define DRV_TYPE (1 << 6) + +struct mem_timings { + unsigned direct_cmd_msr ; + unsigned timingref; + unsigned timingrow; + unsigned timingdata; + unsigned timingpower; + unsigned zqcontrol; + unsigned control0; + unsigned control1; + unsigned control2; + unsigned concontrol; + unsigned prechconfig; + unsigned memcontrol; + unsigned memconfig0; + unsigned memconfig1; + unsigned dll_resync; + unsigned dll_on; +}; + +/* MIU */ +/* MIU Config Register Offsets*/ +#define APB_SFR_INTERLEAVE_CONF_OFFSET 0x400 +#define APB_SFR_ARBRITATION_CONF_OFFSET 0xC00 +#define ABP_SFR_SLV_ADDRMAP_CONF_OFFSET 0x800 +#define ABP_SFR_INTERLEAVE_ADDRMAP_START_OFFSET 0x808 +#define ABP_SFR_INTERLEAVE_ADDRMAP_END_OFFSET 0x810 +#define ABP_SFR_SLV0_SINGLE_ADDRMAP_START_OFFSET 0x818 +#define ABP_SFR_SLV0_SINGLE_ADDRMAP_END_OFFSET 0x820 +#define ABP_SFR_SLV1_SINGLE_ADDRMAP_START_OFFSET 0x828 +#define ABP_SFR_SLV1_SINGLE_ADDRMAP_END_OFFSET 0x830 + +#if (defined CONFIG_ORIGEN) || (defined CONFIG_EX4412) +/* Interleave: 2Bit, Interleave_bit1: 0x15, Interleave_bit0: 0x7 */ +#define APB_SFR_INTERLEAVE_CONF_VAL 0x20001507 +#define APB_SFR_ARBRITATION_CONF_VAL 0x00000001 +#endif + +#define INTERLEAVE_ADDR_MAP_START_ADDR 0x40000000 +#define INTERLEAVE_ADDR_MAP_END_ADDR 0xbfffffff +#define INTERLEAVE_ADDR_MAP_EN 0x00000001 + +#ifdef CONFIG_MIU_1BIT_INTERLEAVED +/* Interleave_bit0: 0xC*/ +#define APB_SFR_INTERLEAVE_CONF_VAL 0x0000000c +#endif +#ifdef CONFIG_MIU_2BIT_INTERLEAVED +/* Interleave: 2Bit, Interleave_bit1: 0x15, Interleave_bit0: 0xc */ +#define APB_SFR_INTERLEAVE_CONF_VAL 0x2000150c +#endif +#define SLAVE0_SINGLE_ADDR_MAP_START_ADDR 0x40000000 +#define SLAVE0_SINGLE_ADDR_MAP_END_ADDR 0x7fffffff +#define SLAVE1_SINGLE_ADDR_MAP_START_ADDR 0x80000000 +#define SLAVE1_SINGLE_ADDR_MAP_END_ADDR 0xbfffffff +/* Enable SME0 and SME1*/ +#define APB_SFR_SLV_ADDR_MAP_CONF_VAL 0x00000006 + +#define FORCE_DLL_RESYNC 3 +#define DLL_CONTROL_ON 1 + +#define DIRECT_CMD1 0x00020000 +#define DIRECT_CMD2 0x00030000 +#define DIRECT_CMD3 0x00010002 +#define DIRECT_CMD4 0x00000328 + +#define CTRL_ZQ_MODE_NOTERM (0x1 << 0) +#define CTRL_ZQ_START (0x1 << 1) +#define CTRL_ZQ_DIV (0 << 4) +#define CTRL_ZQ_MODE_DDS (0x7 << 8) +#define CTRL_ZQ_MODE_TERM (0x2 << 11) +#define CTRL_ZQ_FORCE_IMPN (0x5 << 14) +#define CTRL_ZQ_FORCE_IMPP (0x6 << 17) +#define CTRL_DCC (0xE38 << 20) +/* +#define ZQ_CONTROL_VAL (CTRL_ZQ_MODE_NOTERM | CTRL_ZQ_START\ + | CTRL_ZQ_DIV | CTRL_ZQ_MODE_DDS\ + | CTRL_ZQ_MODE_TERM | CTRL_ZQ_FORCE_IMPN\ + | CTRL_ZQ_FORCE_IMPP | CTRL_DCC) +*/ +#define ZQ_CONTROL_VAL 0xe3855403 + +#define ASYNC (0 << 0) +#define CLK_RATIO (1 << 1) +#define DIV_PIPE (1 << 3) +#define AWR_ON (1 << 4) +#define AREF_DISABLE (0 << 5) +#define DRV_TYPE_DISABLE (0 << 6) +#define CHIP0_NOT_EMPTY (0 << 8) +#define CHIP1_NOT_EMPTY (0 << 9) +#define DQ_SWAP_DISABLE (0 << 10) +#define QOS_FAST_DISABLE (0 << 11) +#define RD_FETCH (0x3 << 12) +#define TIMEOUT_LEVEL0 (0xFFF << 16) +#define CONCONTROL_VAL (ASYNC | CLK_RATIO | DIV_PIPE | AWR_ON\ + | AREF_DISABLE | DRV_TYPE_DISABLE\ + | CHIP0_NOT_EMPTY | CHIP1_NOT_EMPTY\ + | DQ_SWAP_DISABLE | QOS_FAST_DISABLE\ + | RD_FETCH | TIMEOUT_LEVEL0) + +#define CLK_STOP_DISABLE (0 << 1) +#define DPWRDN_DISABLE (0 << 2) +#define DPWRDN_TYPE (0 << 3) +#define TP_DISABLE (0 << 4) +#define DSREF_DIABLE (0 << 5) +#define ADD_LAT_PALL (1 << 6) +#define MEM_TYPE_DDR3 (0x6 << 8) +#define MEM_WIDTH_32 (0x2 << 12) +#define NUM_CHIP_2 (0 << 16) +#define BL_8 (0x3 << 20) +/* +#define MEMCONTROL_VAL (CLK_STOP_DISABLE | DPWRDN_DISABLE\ + | DPWRDN_TYPE | TP_DISABLE | DSREF_DIABLE\ + | ADD_LAT_PALL | MEM_TYPE_DDR3 | MEM_WIDTH_32\ + | NUM_CHIP_2 | BL_8) +*/ +#define MEMCONTROL_VAL 0x00202500 + +#define CHIP_BANK_8 (0x3 << 0) +#define CHIP_ROW_14 (0x3 << 4) +#define CHIP_COL_10 (0x3 << 8) +#define CHIP_MAP_INTERLEAVED (1 << 12) +#define CHIP_MASK (0xC0 << 16) +#ifdef CONFIG_MIU_LINEAR +#define CHIP0_BASE (0x40 << 24) +#define CHIP1_BASE (0x60 << 24) +#else +#define CHIP0_BASE (0x40 << 24) +#define CHIP1_BASE (0x80 << 24) +#endif +/* +#define MEMCONFIG0_VAL (CHIP_BANK_8 | CHIP_ROW_14 | CHIP_COL_10\ + | CHIP_MAP_INTERLEAVED | CHIP_MASK | CHIP0_BASE) +*/ +#define MEMCONFIG1_VAL (CHIP_BANK_8 | CHIP_ROW_14 | CHIP_COL_10\ + | CHIP_MAP_INTERLEAVED | CHIP_MASK | CHIP1_BASE) + +#define MEMCONFIG0_VAL 0x40c01323 + +#define TP_CNT (0xff << 24) +#define PRECHCONFIG TP_CNT + +#define CTRL_OFF (0 << 0) +#define CTRL_DLL_OFF (0 << 1) +#define CTRL_HALF (0 << 2) +#define CTRL_DFDQS (1 << 3) +#define DQS_DELAY (0 << 4) +#define CTRL_START_POINT (0x10 << 8) +#define CTRL_INC (0x10 << 16) +#define CTRL_FORCE (0x71 << 24) +#define CONTROL0_VAL (CTRL_OFF | CTRL_DLL_OFF | CTRL_HALF\ + | CTRL_DFDQS | DQS_DELAY | CTRL_START_POINT\ + | CTRL_INC | CTRL_FORCE) + +#define CTRL_SHIFTC (0x6 << 0) +#define CTRL_REF (8 << 4) +#define CTRL_SHGATE (1 << 29) +#define TERM_READ_EN (1 << 30) +#define TERM_WRITE_EN (1 << 31) +#define CONTROL1_VAL (CTRL_SHIFTC | CTRL_REF | CTRL_SHGATE\ + | TERM_READ_EN | TERM_WRITE_EN) + +#define CONTROL2_VAL 0x00000000 + +#ifdef CONFIG_EX4412 +#define TIMINGREF_VAL 0x000000BB +#define TIMINGROW_VAL 0x4046654f +#define TIMINGDATA_VAL 0x46400506 +#define TIMINGPOWER_VAL 0x52000A3C +#else +#define TIMINGREF_VAL 0x000000BC +#ifdef DRAM_CLK_330 +#define TIMINGROW_VAL 0x3545548d +#define TIMINGDATA_VAL 0x45430506 +#define TIMINGPOWER_VAL 0x4439033c +#endif +#ifdef DRAM_CLK_400 +#define TIMINGROW_VAL 0x45430506 +#define TIMINGDATA_VAL 0x56500506 +#define TIMINGPOWER_VAL 0x5444033d +#endif +#endif + +#ifdef CONFIG_BOARD_TYPES +extern void sdelay(unsigned long); +#endif + + +#endif    4.修改初始化内存的dmc_init_exynos4.c文件 --- a/arch/arm/mach-exynos/dmc_init_exynos4.c +++ b/arch/arm/mach-exynos/dmc_init_exynos4.c @@ -25,8 +25,10 @@ #include #include +#include #include "common_setup.h" -#include "exynos4_setup.h" +/*#include "exynos4_setup.h" */ +#include "ex4412_setup.h" struct mem_timings mem = { .direct_cmd_msr = { @@ -48,6 +50,46 @@ struct mem_timings mem = { .dll_resync = FORCE_DLL_RESYNC, .dll_on = DLL_CONTROL_ON, }; + + +#ifdef CONFIG_EX4412 +/*简易测试tiny4412内存情况,如果读出的值正常,即初步判断内存初始化正常*/ +void tiny4412_mem_test(void) +{ +#ifdef CONFIG_DEBUG_UART + unsigned int i; + + printascii("Simple Memory test start...\r\n"); + printascii("write 0x12345678 ...\r\n"); + for (i = 0x40000000; + i < 0x80000000; i+=0x10000000) + { + writel(0x12345678, i); + printascii("addr:0x"); + printhex8(i); + printascii("--data:"); + printascii("0x"); + printhex8(readl(i)); + printascii("\r\n"); + } + printascii("write 0x89abcdef ...\r\n"); + for (i = 0x4FFFFFFC; + i <= 0x7FFFFFFC; i+=0x10000000) + { + writel(0x89ABCDEF, i); + printascii("addr:0x"); + printhex8(i); + printascii("--data:"); + printascii("0x"); + printhex8(readl(i)); + printascii("\r\n"); + } + printascii("Memory test end.\r\n\r\n"); +#endif + +} +#endif + static void phy_control_reset(int ctrl_no, struct exynos4_dmc *dmc) { if (ctrl_no) { @@ -80,89 +122,63 @@ static void dmc_config_mrs(struct exynos4_dmc *dmc, int chip) static void dmc_init(struct exynos4_dmc *dmc) { /* - * DLL Parameter Setting: - * Termination: Enable R/W - * Phase Delay for DQS Cleaning: 180' Shift - */ phycontrol1); - - /* * ZQ Calibration * Termination: Disable * Auto Calibration Start: Enable */ phyzqcontrol); - sdelay(0x100000); +// sdelay(0x100000); - /* - * Update DLL Information: - * Force DLL Resyncronization - */ - phy_control_reset(1, dmc); - phy_control_reset(0, dmc); phycontrol0); phycontrol0); phycontrol1); phycontrol0); phycontrol1); phycontrol1); phycontrol1); phycontrol1); - /* Set DLL Parameters */ phycontrol1); concontrol); - /* DLL Start */ phycontrol0); - phycontrol2); - - /* Set Clock Ratio of Bus clock to Memory Clock */ concontrol); - - /* - * Memor Burst length: 8 - * Number of chips: 2 - * Memory Bus width: 32 bit - * Memory Type: DDR3 - * Additional Latancy for PLL: 1 Cycle - */ memcontrol); memconfig0); memconfig1); ivcontrol); /* Config Precharge Policy */ prechconfig); /* * TimingAref, TimingRow, TimingData, TimingPower Setting: * Values as per Memory AC Parameters */ timingref); timingrow); timingdata); timingpower); timingref); timingrow); timingdata); timingpower); + sdelay(0x100000); /* Chip0: NOP Command: Assert and Hold CKE to high level */ directcmd); directcmd); sdelay(0x100000); - /* Chip0: EMRS2, EMRS3, EMRS, MRS Commands Using Direct Command */ - dmc_config_mrs(dmc, 0); directcmd); sdelay(0x100000); - /* Chip0: ZQINIT */ directcmd); directcmd); sdelay(0x100000); directcmd); - sdelay(0x100000); directcmd); +// sdelay(0x100000); - /* Chip1: EMRS2, EMRS3, EMRS, MRS Commands Using Direct Command */ - dmc_config_mrs(dmc, 1); - sdelay(0x100000); - /* Chip1: ZQINIT */ directcmd); - sdelay(0x100000); directcmd); +// sdelay(0x100000); - phy_control_reset(1, dmc); - sdelay(0x100000); directcmd); +// sdelay(0x100000); /* turn on DREX0, DREX1 */ concontrol); concontrol); } void mem_ctrl_init(int reset) @@ -175,13 +191,12 @@ void mem_ctrl_init(int reset) * 0: full_sync */ writel(1, ASYNC_CONFIG); -#ifdef CONFIG_TARGET_ORIGEN - /* Interleave: 2Bit, Interleave_bit1: 0x15, Interleave_bit0: 0x7 */ - writel(APB_SFR_INTERLEAVE_CONF_VAL, EXYNOS4_MIU_BASE + - APB_SFR_INTERLEAVE_CONF_OFFSET); - /* Update MIU Configuration */ - writel(APB_SFR_ARBRITATION_CONF_VAL, EXYNOS4_MIU_BASE + - APB_SFR_ARBRITATION_CONF_OFFSET); +#ifdef CONFIG_EX4412 + writel(0x13113113, 0x10030000 + 0x10500); + + writel(0x00117713, 0x10040500); + writel(0x00000000, 0x10020a00); + writel(0x00010905, 0x10040a00); #else writel(APB_SFR_INTERLEAVE_CONF_VAL, EXYNOS4_MIU_BASE + APB_SFR_INTERLEAVE_CONF_OFFSET);    5.修改clock.c   关于mmc和lcd部分,本文未实现这两个外设驱动功能,此处暂且先作修改,网文提到该文件错用struct exynos4_clock结构体,应该改为struct exynos4x12_clock,修改如下: --- a/arch/arm/mach-exynos/clock.c +++ b/arch/arm/mach-exynos/clock.c @@ -784,8 +784,13 @@ static unsigned long exynos4x12_get_uart_clk(int dev_index) static unsigned long exynos4_get_mmc_clk(int dev_index) { +#ifdef CONFIG_EX4412 + struct exynos4x12_clock *clk = + (struct exynos4x12_clock *)samsung_get_base_clock(); +#else struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); +#endif unsigned long uclk, sclk; unsigned int sel, ratio, pre_ratio; int shift = 0; @@ -834,8 +839,13 @@ static unsigned long exynos4_get_mmc_clk(int dev_index) /* exynos4: set the mmc clock */ static void exynos4_set_mmc_clk(int dev_index, unsigned int div) { +#ifdef CONFIG_EX4412 + struct exynos4x12_clock *clk = + (struct exynos4x12_clock *)samsung_get_base_clock(); +#else struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); +#endif unsigned int addr, clear_bit, set_bit; /* @@ -913,8 +923,13 @@ static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) /* get_lcd_clk: return lcd clock frequency */ static unsigned long exynos4_get_lcd_clk(void) { +#ifdef CONFIG_EX4412 + struct exynos4x12_clock *clk = + (struct exynos4x12_clock *)samsung_get_base_clock(); +#else struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); +#endif unsigned long pclk, sclk; unsigned int sel; unsigned int ratio; @@ -923,7 +938,11 @@ static unsigned long exynos4_get_lcd_clk(void) * CLK_SRC_LCD0 * FIMD0_SEL */ +#ifdef CONFIG_EX4412 src_lcd); +#else src_lcd0); +#endif sel = sel & 0xf; /* @@ -944,7 +963,11 @@ static unsigned long exynos4_get_lcd_clk(void) * CLK_DIV_LCD0 * FIMD0_RATIO */ +#ifdef CONFIG_EX4412 div_lcd); +#else div_lcd0); +#endif ratio = ratio & 0xf; pclk = sclk / (ratio + 1); @@ -1064,9 +1087,13 @@ static unsigned long exynos5800_get_lcd_clk(void) void exynos4_set_lcd_clk(void) { +#ifdef CONFIG_EX4412 + struct exynos4x12_clock *clk = + (struct exynos4x12_clock *)samsung_get_base_clock(); +#else struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); - +#endif /* * CLK_GATE_BLOCK * CLK_CAM @@ -1087,8 +1114,11 @@ void exynos4_set_lcd_clk(void) * MIPI0_SEL * set lcd0 src clock 0x6: SCLK_MPLL */ +#ifdef CONFIG_EX4412 src_lcd, 0xf, 0x6); +#else src_lcd0, 0xf, 0x6); - +#endif /* * CLK_GATE_IP_LCD0 * CLK_FIMD0 @@ -1099,8 +1129,11 @@ void exynos4_set_lcd_clk(void) * CLK_PPMULCD0 * Gating all clocks for FIMD0 */ +#ifdef CONFIG_EX4412 gate_ip_lcd, 1 << 0); +#else gate_ip_lcd0, 1 << 0); - +#endif /* * CLK_DIV_LCD0 * FIMD0_RATIO @@ -1111,7 +1144,11 @@ void exynos4_set_lcd_clk(void) * MIPI0_PRE_RATIO * set fimd ratio */ +#ifdef CONFIG_EX4412 div_lcd, 0xf, 0x1); +#else div_lcd0, 0xf, 0x1); +#endif } void exynos5_set_lcd_clk(void)    6.修改arch /arm /mach -exynos /lowlevel_init .c --- a/arch/arm/mach-exynos/lowlevel_init.c +++ b/arch/arm/mach-exynos/lowlevel_init.c @@ -39,6 +39,7 @@ #include "common_setup.h" #include "exynos5_setup.h" +extern void mem_init(void); /* These are the things we can do during low-level init */ enum { DO_WAKEUP = 1 << 0, @@ -170,10 +171,38 @@ static void secondary_cores_configure(void) dsb(); sev(); } - extern void relocate_wait_code(void); #endif - +/* +void test_uart() + { + unsigned int addr = 0x11400000; + writel(0x22222222,addr); + writel(0x222222,addr+0x20); + + addr = (unsigned int *)0x1003c250; + writel(0x666666,addr); + + addr = (unsigned int *)0x1003c250; + writel(0x777777,addr); + + addr = (unsigned int *)0x13820000; + #define ULCON_OFFSET 0x00 + #define UCON_OFFSET 0x04 + #define UFCON_OFFSET 0x08 + #define UBRDIV_OFFSET 0x28 + #define UDIVLOT_OFFSET 0x2c + #define UTXH_OFFSET 0x20 + writel(0x111, addr+UFCON_OFFSET); + writel(0x03, addr+ULCON_OFFSET); + writel(0x3c5, addr+UCON_OFFSET); + writel(0x35, addr+UBRDIV_OFFSET); + writel(0x3, addr+UDIVLOT_OFFSET); + writel(0x4f, addr+UTXH_OFFSET); + writel(0x4b, addr+UTXH_OFFSET); + return; + } +*/ int do_lowlevel_init(void) { uint32_t reset_status; @@ -200,7 +229,6 @@ int do_lowlevel_init(void) /* Reconfigure secondary cores */ secondary_cores_configure(); #endif - reset_status = get_reset_status(); switch (reset_status) { @@ -222,14 +250,16 @@ int do_lowlevel_init(void) if (actions & DO_CLOCKS) { system_clock_init(); #ifdef CONFIG_DEBUG_UART -#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL)) || \ - !defined(CONFIG_SPL_BUILD) - exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); +/*#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL)) || \ + !defined(CONFIG_SPL_BUILD) */ + exynos_pinmux_config(PERIPH_ID_UART2, PINMUX_FLAG_NONE); debug_uart_init(); -#endif +/*#endif */ + printascii("do_lowlevel_init ok\r\n"); #endif mem_ctrl_init(actions & DO_MEM_RESET); - tzpc_init(); + +/* tzpc_init(); */ } return actions & DO_WAKEUP;    7.修改电源配置 修改与板子exynos4412芯片适配的结构体exynos4x12_power,配置如下: diff --git a/arch/arm/mach-exynos/include/mach/power.h b/arch/arm/mach-exynos/include/mach/power.h index a3d8974..8b706ee 100644 --- a/arch/arm/mach-exynos/include/mach/power.h +++ b/arch/arm/mach-exynos/include/mach/power.h @@ -209,6 +209,214 @@ struct exynos4_power { unsigned int gps_alive_option; }; +struct exynos4x12_power { + unsigned int om_stat; + unsigned char res1 ; + unsigned int rtc_clko_sel; + unsigned int gnss_rtc_out_ctrl; + unsigned int lpi_denial_mask0; + unsigned int lpi_denial_mask1; + unsigned int lpi_denial_mask2; + unsigned int c2c_ctrl; + unsigned char res2 ; + unsigned int central_seq_config; + unsigned int res3; + unsigned int central_seq_option; + unsigned char res4 ; + unsigned int swreset; + unsigned int rst_stat; + unsigned int auto_wdt_reset_disable; + unsigned int mask_wdt_reset_request; + unsigned char res5 ; + unsigned int wakeup_stat; + unsigned int eint_wakeup_mask; + unsigned int wakeup_mask; + unsigned char res6 ; + unsigned int hdmi_phy_control; + unsigned int usbdevice_phy_control; + unsigned int hsic_1_phy_control; + unsigned int hsic_2_phy_control; + unsigned int mipi_phy0_control; + unsigned int mipi_phy1_control; + unsigned int adc_phy_control; + unsigned char res7 ; + unsigned int body_bias_con0; + unsigned int body_bias_con1; + unsigned int body_bias_con2; + unsigned int body_bias_con3; + unsigned char res8 ; + unsigned int inform0; + unsigned int inform1; + unsigned int inform2; + unsigned int inform3; + unsigned int inform4; + unsigned int inform5; + unsigned int inform6; + unsigned int inform7; + unsigned char res9 ; + unsigned int pmu_debug; + unsigned char res10 ; + unsigned int arm_core0_sys_pwr_reg; + unsigned char res11 ; + unsigned int arm_core1_sys_pwr_reg; + unsigned char res12 ; + unsigned int arm_common_sys_pwr_reg; + unsigned char res13 ; + unsigned int arm_cpu_l2_0_sys_pwr_reg; + unsigned int arm_cpu_l2_1_sys_pwr_reg; + unsigned char res14 ; + unsigned int cmu_aclkstop_sys_pwr_reg; + unsigned int cmu_sclkstop_sys_pwr_reg; + unsigned char res15 ; + unsigned int cmu_reset_sys_pwr_reg; + unsigned char res16 ; + unsigned int apll_sysclk_sys_pwr_reg; + unsigned int mpll_sysclk_sys_pwr_reg; + unsigned int vpll_sysclk_sys_pwr_reg; + unsigned int epll_sysclk_sys_pwr_reg; + unsigned char res17 ; + unsigned int cmu_clkstop_gps_alive_sys_pwr_reg; + unsigned int cmu_reset_gps_alive_sys_pwr_reg; + unsigned int cmu_clkstop_cam_sys_pwr_reg; + unsigned int cmu_clkstop_tv_sys_pwr_reg; + unsigned int cmu_clkstop_mfc_sys_pwr_reg; + unsigned int cmu_clkstop_g3d_sys_pwr_reg; + unsigned int cmu_clkstop_lcd0_sys_pwr_reg; + unsigned int cmu_clkstop_isp_sys_pwr_reg; + unsigned int cmu_clkstop_maudio_sys_pwr_reg; + unsigned int cmu_clkstop_gps_sys_pwr_reg; + unsigned int cmu_reset_cam_sys_pwr_reg; + unsigned int cmu_reset_tv_sys_pwr_reg; + unsigned int cmu_reset_mfc_sys_pwr_reg; + unsigned int cmu_reset_g3d_sys_pwr_reg; + unsigned int cmu_reset_lcd0_sys_pwr_reg; + unsigned int cmu_reset_isp_sys_pwr_reg; + unsigned int cmu_reset_maudio_sys_pwr_reg; + unsigned int cmu_reset_gps_sys_pwr_reg; + unsigned int top_bus_sys_pwr_reg; + unsigned int top_retention_sys_pwr_reg; + unsigned int top_pwr_sys_pwr_reg; + unsigned char res18 ; + unsigned int logic_reset_sys_pwr_reg; + unsigned char res19 ; + unsigned int onenandxl_mem_sys_pwr_reg; + unsigned int hsi_mem_sys_pwr_reg; + unsigned char res20 ; + unsigned int usbotg_mem_sys_pwr_reg; + unsigned int sdmmc_mem_sys_pwr_reg; + unsigned int cssys_mem_sys_pwr_reg; + unsigned int secss_mem_sys_pwr_reg; + unsigned int potator_mem_sys_pwr_reg; + unsigned char res21 ; + unsigned int pad_retention_dram_sys_pwr_reg; + unsigned int pad_retention_maudio_sys_pwr_reg; + unsigned char res22 ; + unsigned int pad_retention_gpio_sys_pwr_reg; + unsigned int pad_retention_uart_sys_pwr_reg; + unsigned int pad_retention_mmca_sys_pwr_reg; + unsigned int pad_retention_mmcb_sys_pwr_reg; + unsigned int pad_retention_ebia_sys_pwr_reg; + unsigned int pad_retention_ebib_sys_pwr_reg; + unsigned char res23 ; + unsigned int pad_isolation_sys_pwr_reg; + unsigned char res24 ; + unsigned int pad_alv_sel_sys_pwr_reg; + unsigned char res25 ; + unsigned int xusbxti_sys_pwr_reg; + unsigned int xxti_sys_pwr_reg; + unsigned char res26 ; + unsigned int ext_regulator_sys_pwr_reg; + unsigned char res27 ; + unsigned int gpio_mode_sys_pwr_reg; + unsigned char res28 ; + unsigned int gpio_mode_maudio_sys_pwr_reg; + unsigned char res29 ; + unsigned int cam_sys_pwr_reg; + unsigned int tv_sys_pwr_reg; + unsigned int mfc_sys_pwr_reg; + unsigned int g3d_sys_pwr_reg; + unsigned int lcd0_sys_pwr_reg; + unsigned int isp_sys_pwr_reg; + unsigned int maudio_sys_pwr_reg; + unsigned int gps_sys_pwr_reg; + unsigned int gps_alive_sys_pwr_reg; + unsigned char res30 ; + unsigned int arm_core0_configuration; + unsigned int arm_core0_status; + unsigned int arm_core0_option; + unsigned char res31 ; + unsigned int arm_core1_configuration; + unsigned int arm_core1_status; + unsigned int arm_core1_option; + unsigned char res32 ; + unsigned int arm_common_option; + unsigned char res33 ; + unsigned int arm_cpu_l2_0_configuration; + unsigned int arm_cpu_l2_0_status; + unsigned char res34 ; + unsigned int arm_cpu_l2_1_configuration; + unsigned int arm_cpu_l2_1_status; + unsigned char res35 ; + unsigned int pad_retention_maudio_option; + unsigned char res36 ; + unsigned int pad_retention_gpio_option; + unsigned char res37 ; + unsigned int pad_retention_uart_option; + unsigned char res38 ; + unsigned int pad_retention_mmca_option; + unsigned char res39 ; + unsigned int pad_retention_mmcb_option; + unsigned char res40 ; + unsigned int pad_retention_ebia_option; + unsigned char res41 ; + unsigned int pad_retention_ebib_option; + unsigned char res42 ; + unsigned int ps_hold_control; + unsigned char res43 ; + unsigned int xusbxti_configuration; + unsigned int xusbxti_status; + unsigned char res44 ; + unsigned int xusbxti_duration; + unsigned int xxti_configuration; + unsigned int xxti_status; + unsigned char res45 ; + unsigned int xxti_duration; + unsigned char res46 ; + unsigned int ext_regulator_duration; + unsigned char res47 ; + unsigned int cam_configuration; + unsigned int cam_status; + unsigned int cam_option; + unsigned char res48 ; + unsigned int tv_configuration; + unsigned int tv_status; + unsigned int tv_option; + unsigned char res49 ; + unsigned int mfc_configuration; + unsigned int mfc_status; + unsigned int mfc_option; + unsigned char res50 ; + unsigned int g3d_configuration; + unsigned int g3d_status; + unsigned int g3d_option; + unsigned char res51 ; + unsigned int lcd0_configuration; + unsigned int lcd0_status; + unsigned int lcd0_option; + unsigned char res52 ; + unsigned int isp_configuration; + unsigned int isp_status; + unsigned int isp_option; + unsigned char res53 ; + unsigned int gps_configuration; + unsigned int gps_status; + unsigned int gps_option; + unsigned char res54 ; + unsigned int gps_alive_configuration; + unsigned int gps_alive_status; + unsigned int gps_alive_option; +}; + struct exynos4412_power { unsigned char res1 ; unsigned int usbhost_phy_control; 修改power.c 当写有启动板子时有亮灯效果的程序时,通过锁电,让板子启动时不会只亮一下灯就熄灭,而是一直亮着,但实际测试时writel(0x3, (unsigned int *)0x11000c08);当把0x3改为别的数值时,灯也会是启动后一直亮着。 diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index f2a6c00..afccade 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -162,6 +162,28 @@ static void exynos5_set_ps_hold_ctrl(void) EXYNOS_PS_HOLD_CONTROL_DATA_HIGH); } +static void exynos4x12_set_ps_hold_ctrl(void) +{ + struct exynos4x12_power *power = + (struct exynos4x12_power *)samsung_get_base_power(); + + /* value: 1000000000B */ ps_hold_control, EXYNOS_PS_HOLD_CONTROL_DATA_HIGH); + /** + * GPX0PUD register + * + * 0x0 = Disables Pull-up/Pull-down + * 0x1 = Enables Pull-down + * 0x2 = Reserved + * 0x3 = Enables Pull-up + * Due to GPX0_2 attached to PMIC's ONO pin, + * make GPX0_2 pin PU for high level, + * but all other pin default state for low level + * otherwise, keep restarting 0x5575 + */ + writel(0x3, (unsigned int *)0x11000c08); +} + /* * Set ps_hold data driving value high * This enables the machine to stay powered on @@ -172,6 +194,12 @@ void set_ps_hold_ctrl(void) { if (cpu_is_exynos5()) exynos5_set_ps_hold_ctrl(); + #ifdef CONFIG_EX4412 + else if (cpu_is_exynos4()){ +/* if (proid_is_exynos4412()) */ + exynos4x12_set_ps_hold_ctrl(); + } + #endif } @@ -213,9 +241,13 @@ static uint32_t exynos5_get_reset_status(void) static uint32_t exynos4_get_reset_status(void) { +#ifdef CONFIG_EX4412 + struct exynos4x12_power *power = + (struct exynos4x12_power *)samsung_get_base_power(); +#else struct exynos4_power *power = (struct exynos4_power *)samsung_get_base_power(); - +#endif inform1; } 新增启动板子时亮灯程序arch/arm/mach-exynos/board.c,用以提示板子是否初始化成功 #include #include #include void s_init(void) { /* led test */ writel(0x10, 0x11000060); writel(0x2, 0x11000064); writel(0x1, 0x11000100); writel(0x1, 0x11000104); }    8.修改arch/arm/mach-exynos/spl_boot.c,拷贝uboot到dram。 diff --git a/arch/arm/mach-exynos/spl_boot.c b/arch/arm/mach-exynos/spl_boot.c index f518539..aa4e52a 100644 --- a/arch/arm/mach-exynos/spl_boot.c +++ b/arch/arm/mach-exynos/spl_boot.c @@ -18,11 +18,12 @@ #include #include #include +#include #include "common_setup.h" #include "clock_init.h" -#ifdef CONFIG_ARCH_EXYNOS5 +#ifdef CONFIG_ARCH_EXYNOS5 #define SECURE_BL1_ONLY /* Secure FW size configuration */ @@ -31,28 +32,41 @@ #else #define SEC_FW_SIZE 0 #endif - -/* Configuration of BL1, BL2, ENV Blocks on mmc */ -#define RES_BLOCK_SIZE (512) -#define BL1_SIZE (16 << 10) /*16 K reserved for BL1*/ -#define BL2_SIZE (512UL << 10UL) /* 512 KB */ - +#define CONFIG_SERIAL2 +#define CONFIG_SPL_BUILD +/* #define BL1_OFFSET (RES_BLOCK_SIZE + SEC_FW_SIZE) #define BL2_OFFSET (BL1_OFFSET + BL1_SIZE) +*/ /* U-Boot copy size from boot Media to DRAM.*/ +/* #define BL2_START_OFFSET (BL2_OFFSET/512) #define BL2_SIZE_BLOC_COUNT (BL2_SIZE/512) +*/ + +#define CONFIG_CLK_1000_400_200 + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_INIT_SP_ADDR 0x02040000 +#else +#define CONFIG_SYS_INIT_SP_ADDR 0x42E00000 +#endif -#define EXYNOS_COPY_SPI_FNPTR_ADDR 0x02020058 -#define SPI_FLASH_UBOOT_POS (SEC_FW_SIZE + BL1_SIZE) +/* #define EXYNOS_COPY_SPI_FNPTR_ADDR 0x02020058 */ #elif defined(CONFIG_ARCH_EXYNOS4) -#define COPY_BL2_SIZE 0x80000 -#define BL2_START_OFFSET ((CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)/512) +#define COPY_UBOOT_SIZE 0x80000 +#define UBOOT_START_OFFSET ((RESERVE_BLOCK_SIZE + BL1_SIZE + BL2_SIZE) /512) +#define UBOOT_SIZE_BLOC_COUNT (COPY_UBOOT_SIZE /512) + +#define COPY_BL2_SIZE 0x4000 +#define BL2_START_OFFSET ((RESERVE_BLOCK_SIZE + BL1_SIZE)/512) #define BL2_SIZE_BLOC_COUNT (COPY_BL2_SIZE/512) #endif DECLARE_GLOBAL_DATA_PTR; +gd_t gdata __attribute__ ((section(".data"))); + /* Index into irom ptr table */ enum index { @@ -255,15 +269,21 @@ void copy_uboot_to_ram(void) break; #endif case BOOT_MODE_SD: +#if defined(CONFIG_EX4412) + offset = UBOOT_START_OFFSET; + size = UBOOT_SIZE_BLOC_COUNT; +#else offset = BL2_START_OFFSET; size = BL2_SIZE_BLOC_COUNT; +#endif copy_bl2 = get_irom_func(MMC_INDEX); break; #ifdef CONFIG_SUPPORT_EMMC_BOOT case BOOT_MODE_EMMC: /* Set the FSYS1 clock divisor value for EMMC boot */ + #ifndef CONFIG_EX4412 emmc_boot_clk_div_set(); - + #endif copy_bl2_from_emmc = get_irom_func(EMMC44_INDEX); end_bootop_from_emmc = get_irom_func(EMMC44_END_INDEX); @@ -286,9 +306,31 @@ void copy_uboot_to_ram(void) default: break; } - - if (copy_bl2) +#ifdef CONFIG_TARGET_EX4412 + if (copy_bl2) { + /* + * Here I use iram 0x020250000-0x020260000 (64k) + * as an buffer, and copy u-boot from sd card to + * this buffer, then copy it to dram started + * from 0x43e00000. + * + */ + unsigned int i, count = 0; + unsigned char *buffer = (unsigned char *)0x02050000; + unsigned char *dst = (unsigned char *)CONFIG_TEXT_BASE; + unsigned int step = (0x10000 / 512); + + for (count = 0; count < size; count += step) { + /* copy u-boot from sdcard to iram firstly. */ + copy_bl2((u32)(offset + count), (u32)step, (u32)buffer); + for (i = 0; i < 0x10000; i++) { + *dst++ = buffer ; + } + } + } +#else copy_bl2(offset, size, CONFIG_TEXT_BASE); +#endif } void memzero(void *s, size_t n) @@ -316,6 +358,7 @@ static void setup_global_data(gd_t *gdp) have_console = 1; } +#include void board_init_f(unsigned long bootflag) { __aligned(8) gd_t local_gd; @@ -325,11 +368,17 @@ void board_init_f(unsigned long bootflag) if (do_lowlevel_init()) power_exit_wakeup(); +#ifdef CONFIG_DEBUG_UART +/* printascii("\r\nU-Boot SPL " PLAIN_VERSION " (" U_BOOT_DATE " - " U_BOOT_TIME ")\r\n"); */ +#endif copy_uboot_to_ram(); /* Jump to U-Boot image */ uboot = (void *)CONFIG_TEXT_BASE; + printascii("finish BL1 copying,Jump to U-Boot image\n\r"); +/* printhex8(uboot); */ + printascii("\n\r"); (*uboot)(); /* Never returns Here */ }    9.修改Makefile,执行CFGCHK u-boot.cfg时出错,屏蔽掉相关代码。 diff --git a/Makefile b/Makefile index 9a8a7c4..299f548 100644 --- a/Makefile +++ b/Makefile @@ -1073,9 +1073,9 @@ cmd_lzma = lzma -c -z -k -9 $ $@ cfg: u-boot.cfg -quiet_cmd_cfgcheck = CFGCHK $2 -cmd_cfgcheck = $(srctree)/scripts/check-config.sh $2 \ - $(srctree)/scripts/config_whitelist.txt $(srctree) +#quiet_cmd_cfgcheck = CFGCHK $2 +#cmd_cfgcheck = $(srctree)/scripts/check-config.sh $2 \ +# $(srctree)/scripts/config_whitelist.txt $(srctree) quiet_cmd_ofcheck = OFCHK $2 cmd_ofcheck = $(srctree)/scripts/check-of.sh $2 \    五、编译移植   1.编译   make distclean   make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- ex4412_defconfig   make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- -j4   编译报错   解决:make menuconfig打开配置 Enable SPL │ │ Support GPIO in SPL 和 Support serial 这里有些奇怪,虽然已经在config/ex4412_defconfig中配置以下内容,但不起作用 在make menuconfig配置后,重新编译,未报错误 Enable an early debug UART for debugging (0x13820000) Base address of UART(0x13820000) Base address of UART for SPL (100000000) UART input clock Low-level debugging functions 同时打开时会冲突报错,因此不打开该项配置。    2.使用mkbl2生成bl2.bin   ./mkbl2 spl/u-boot-spl.bin bl2.bin 14336    3.把BL1和BL2、uboot及all00_padding生成一个文件 u-boot-ex4412.bin    4、烧写,/dev/sdb为本人虚拟机识别到TF设备标识,以Ubuntu系统实际识别的TF卡设备标识为准。     dd if=/dev/zero of=/dev/sdb bs=512 seek=1 iflag=dsync oflag=dsync count=2048   dd iflag=dsync oflag=dsync if=u-boot-ex4412.bin of=/dev/sdb seek=1   以上编译、烧写过程,可整合到脚本里面实现,可后续优化,但由于本人TF卡有时识别异常,只能按部就班为稳妥。    六、成功运行 我的博客站点:https://www.cnblogs.com/fengconglin 我的csdn博客:https://blog.csdn.net/fengconglin 我的GitHub:https://github.com/WindThicket              
  • 热度 2
    2019-3-17 09:03
    3107 次阅读|
    1 个评论
    上一篇uboot主编译脚本分析的 编译选项参数 中提到了链接脚本这么个东西 我也是写到这里才开始了解链接脚本(Linker command scripts),之前只是大概知道有这么一个东西 先从参考资料中的内容开始说起,充当预备知识 总的来说,脚本定义了四个内存空间(memory regions)为vect、rom、ram and cache,五个段(output sections)为vect、text、bss、init、stack 从参考资料中的范例入手 下面是范例中提供的一个简单的链接脚本,简单而健全,先完整的贴上来,然后结合uboot的链接脚本慢慢介绍其中涉及到的OUTPUT_FORMAT、MEMORY等命令 /* 要链接的文件列表 (其他的可以在命令行上提供) */ INPUT(libc.a libg.a libgcc.a libc.a libgcc.a) /* 输出格式 (可以在命令行上被重写) */ OUTPUT_FORMAT("coff-sh") /* 输出文件名 (可以在命令行上被重写) */ OUTPUT_FILENAME("main.out") /* 我们的程序的入口点; 除了确保S7记录是正确的外,没有什么用处, 因为复位向量(reset vector)实际上 定义了大多数嵌入式系统中的“入口点” */ ENTRY(_start) /* 内存段的列表 */ MEMORY { vect : o = 0, l = 1k rom : o = 0x400, l = 127k ram : o = 0x400000, l = 128k cache : o = 0xfffff000, l = 4k } /* 组织每个模块中的内存段的方式 */ SECTIONS { /* 中断向量表 */ .vect : { __vect_start = .; *(.vect); __vect_end = .; vect /* 代码和常量 */ .text : { __text_start = .; *(.text) *(.strings) __text_end = .; rom /* 未初始化的数据 */ .bss : { __bss_start = . ; *(.bss) *(COMMON) __bss_end = . ; ram /* 已初始化的数据 */ .init : AT (__text_end) { __data_start = .; *(.data) __data_end = .; } ram /* 应用程序栈 */ .stack : { __stack_start = .; *(.stack) __stack_end = .; ram } OUTPUT_FORMAT命令 这条命令控制输出文件的的格式。 在x210的uboot脚本中,也是有这个命令 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 这条命令的使用方式为 OUTPUT_FORMAT(bfdname), OUTPUT_FORMAT(default, big, little) ,上面的例子是第一种使用方式,而uboot中的是第二种方式 MEMORY命令 链接器的默认配置允许分配所有可用内存,你可以使用MEMORY命令来覆盖它。 MEMORY { name : ORIGIN = origin, LENGTH = len ... } 我记得我以前使用stm32驱动显示器的时候遇到过sram不够用的情况,当时也是通过在链接脚本中添加一个段地址指向外部扩展的ddr,然后让显存地址指向这这个段解决的 SECTIONS命令 .text : { __text_start = .; *(.text) *(.strings) __text_end = .; rom 在例子中,定义了一个 .text 段,并将所有输入文件中的 .text and .strings 段放入这个段中 在我们的uboot链接脚本中,还出现了一些其他的东西 .text: { cpu/s5pc11x/start.o (.text) ... *(.text) } 从脚本中看出,链接不仅仅只是能直接 *(.text) 操作同一类的所有输入段,还能以文件定义的方式添加到输出文件的某个SECTIONS中,以文件定义的方式可以确定不同文件的链接顺序,以免产生依赖缺失的问题 AT指令 AT指令告诉链接器将一个节的数据加载到它所在的地址之外的其他位置。使用这个指令可以将需要使用的数据存储在ROM中,在使用前将数据从ROM中提前读取到RAM中。 objdump反汇编验证uboot链接脚本 本uboot链接脚本如下 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { ... .text : { cpu/s5pc11x/start.o (.text) ... *(.text) } ... } 对编译后生成的elf文件进行反汇编 greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ arm-linux-gnueabihf-objdump -f u-boot u-boot: file format elf32-littlearm architecture: arm, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0xc3e00010 前面两行就是 OUTPUT_FORMAT 和 OUTPUT_ARCH 对应内容 greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ arm-linux-gnueabihf-objdump -h u-boot u-boot: file format elf32-littlearm Sections: Idx Name Size VMA LMA File off Algn 0 .text 0002a0b0 c3e00000 c3e00000 00008000 2**5 CONTENTS, ALLOC, LOAD, READONLY, CODE ... 这里的 .text 地址也符合 主makefile 中定义的地址 参考资料 An Introduction to the GNU Compiler and Linker Red Hat Enterprise Linux 4 How to correctly use a simple linker script? Executable gets SIGKILL 个人博客
  • 热度 21
    2016-1-4 12:29
    1037 次阅读|
    0 个评论
    By Toradex Stefan Agner 有些应用对系统启动时间有着特殊的要求。在很多场合下,这些系统并不需要针对所有任务立即就位,但是针对某些关键任务(例如接收以太网命令或者显示用户界面)则必须能够应对。本文将提供一些方法和简单的步骤,以 Toradex 计算机模块为例去优化启动时间。 提示: 文中涉及到的部分方法需要重新编译 U-boot、内核以及文件系统。请参考Toradex 开发者中心网站 上的相关文章。 在开始动手优化之前, 我们需要一个合适的方法来测量启动时间。如果想要十分精准地测量启动时间,这甚至需要牵涉到硬件(例如 GPIO 和示波器)。在绝大多数场合下,通过监控系统串口控制台输出已经是相当准确了。Tim Bird 的 grabserial 是一个广泛使用的工具,可以用于查看串口控制台输出的时间信息。这个工具能够为收到的每一行信息添加上时间戳,如下面所示: ---------------------------------------------------------------------------- $ ./grabserial -d /dev/ttyUSB1 -t U-Boot 2015.04-00006-g6762920 (Oct 12 2015 - 15:35:50) CPU: Freescale Vybrid VF610 at 500 MHz Reset cause: POWER ON RESET DRAM:  256 MiB NAND:  512 MiB MMC:   FSL_SDHC: 0 ---------------------------------------------------------------------------- 第一列数字代表时间戳(从收到第一个字符算起),第二行代表的是收到当前一行和上一行信息之间的时间间隔。 该文章基本上适用于所有我们的模块产品。然而,这其中我所使用的方法和改进之处中确实有一些是针对基于 Freescale Vybrid 的 Colibri VF61 模块。 Linux 系统的启动,主要可以分为以下 3 个阶段,文章将逐一讨论。 Boot loader Linux kernel User space (init system)   Boot loader 实际上在 boot loader 启动之前,还有两个步骤:硬件初始化和 boot ROM。硬件初始化需要满足电源上电顺序以及总线和处理器芯片复位时序要求。这个阶段的耗时一般是固定的,在 10 ~ 200 ms。ARM 处理器从位于内部的 ROM 上启动固件。该固件从启动介质上加载 boot loader。该阶段的时间一般很短,取决于 boot loader 的大小。除了减小 boot loader 体积,很难做其他的优化。实际上能够做的优化和调整还是在 boot loader (U-Boot)。 目前Toradex发布Embedded Linux V2.5 Beta 1 版本,从第一个字符输出到内核启动的时间约为 1.85 秒。主要涉及以下过程: U-Boot 初始化(约 110ms,从接收到的第一个字符算起) Autoboot delay(1s) UBI 初始化和 UBIFS 挂载(约 300ms,得益于 Fastmap 功能,不使用该功能将耗时 1.6s) 内核加载(375ms) 加载和应用 device tree(约 35ms) 最后跳转至内核起始地址 --- Boot time to Kernel start: ~1850ms 首先最显著的优化就是降低 Autoboot delay 。这个值可以使用下面的命令设置为 0: ---------------------------------------------------------------------------- setenv bootdelay 0 saveenv ---------------------------------------------------------------------------- 这个也可以使用 CONFIG_BOOTDELAY 将其配置为默认值。在目前的发布版本中,如果将 bootdelay 设置为 0,那么将会没有办法直接进入 boot loader 的命令行模式。U-Boot 提供一个选项 CONFIG_ZERO_BOOTDELAY_CHECK,在 bootdelay 为 0 的情况下,用于检测一个字符。我们已经将其添加到下一个发布版本的默认配置中。 --- Boot time to Kernel start with this improvement: ~860ms 串口输出是同步发送的。这意味着 CPU 将等待,直到字符通过在串口线上发送完毕。因此,每一个输出的字符都将减慢 U-Boot 的启动。特别是 UBI 将会输出大量的信息,这是一个可以优化的地方。有一个配置符号 CONFIG_UBI_SILENCE_MSG 可以实现这个目的。 --- Boot time to Kernel start with this improvement: ~800ms 为了确保尽可能高效地使用硬件,需要深入了解硬件的功能以及目前实现的方法。目前还没有被使用的功能是 Level 2 Cache(仅 Colibri VF61)。在开启 Level 2 cache 后,启动时间可以提高 40 ms。 --- Boot time to Kernel start with this improvement: ~760ms 移除一些功能有助于减少分配时间和初始化这些功能的时间。例如可以移除显示支持 (DCU),EXT3 和 EXT4 支持以及 USB 外设驱动如 DFU 和 存储设备。这可以将 U-Boot 尺寸减小到 366 KB,同时节省 10 ms 时间。 --- Boot time to Kernel start with this improvement: ~750ms 根据显示的时间戳,绝大多数的时间被用于加载 UBI 和挂载 UBIFS 以及内核的加载(约 380ms)。显然内核大小和加载时间具有线性关系,因此,优化内核尺寸将可以进一步提高启动时间。   Kernel 为了只测量内核启动的时间,可以使用 grabserial 的匹配功能重置 boot loader 输出信息中的时间。 ---------------------------------------------------------------------------- ./grabserial -d /dev/ttyUSB1 -t -m "^Starting kernel.*" ---------------------------------------------------------------------------- 启动结束的时间多少有点难以确定,因为内核将会继续初始化硬件,即使文件系统已经挂载和第一个用户空间进程(init)开始运行(延时初始化)。 “Freeing unused kernel memory” 是 init 进程启动前发出的最后消息,因此将其标记为内核线性任务的结束(请查看 kernel_init in init/main.c)。我将会使用这个信息的时间戳来比较启动时间。我们模块上默认内核的压缩尺寸为 4316 KB,启动时间为 2.56 秒。 --- Kernel boot time to Init start: 2.56s 同 U-Boot 一样,Linux 内核也是同步地将信息发送到串口。具体的方法取决于所使用的串口,LPUART( Vybrid 的 console 驱动)会同步等待直到字符在串口上发送完毕。这个的优点在于,当内核崩溃的时候,那个时候的所有信息都是可见的。假如信息是异步输出,最后输出的信息将不 会指示内核所崩溃的地方。 内核中有一个参数,可以最大限度减少输出的信息:“Quiet”。然而,这也将屏蔽我们测试启动时间的字符信息(“Freeing unused kernel memory”)。最简单的方法输出这些信息是利用日志级别输出特定的信息。在 'mm/page_alloc.c' 中搜索 “Freeing %s memory”。我将使用 ‘pr_alert’ 输出信息。这个方法整整缩短了启动时间1.55 秒! --- Kernel boot time to Init start with this improvement: ~1.01s 进一步提高启动时间的另一个简单的方法是移除功能。Yocto 项目提供了一个方便的工具 ksize.py,这个需要在内核编译目录中运行。这个工具能够显示内核各个部分的大小。第一个表格显示了大致的概况(为了获得准确的概况, 编译之前使用 make clean)。 ---------------------------------------------------------------------------- Linux Kernel              total |       text       data        bss ------------------------------------------------------------------- vmlinux                 8305381 |    7882273     247732     175376 drivers/built-in.o      2010229 |    1881545     109796      18888 fs/built-in.o           1944926 |    1911100      19422      14404 net/built-in.o          1477404 |    1398316      44832      34256 kernel/built-in.o        628094 |     514935      17099      96060 sound/built-in.o         326322 |     316298       8248       1776 mm/built-in.o            288456 |     276492       8000       3964 lib/built-in.o           160209 |     157659        217       2333 block/built-in.o         137262 |     133614       2420       1228 crypto/built-in.o        104157 |     100063       4082         12 security/built-in.o       37391 |      36303        788        300 init/built-in.o           31064 |      16208      14772         84 ipc/built-in.o            29366 |      28640        722          4 usr/built-in.o              138 |        138          0          0 ------------------------------------------------------------------- sum                     7175018 |    6771311     230398     173309 delta                   1130363 |    1110962      17334       2067 ---------------------------------------------------------------------------- 可以被安全移除的一般是应用相关的功能。浏览各个第一层目录,有助于快速确定最可能移除的对象。为了文中的演示,我移除了部分文件系统(cifs, nfs, ext4, ntfs)、音频子系统、多媒体支持、USB 以及无线网络适配器支持。内核最后缩减到 3356 KB,比原来将近小了 1MB。这也减少了约 85ms 的内核加载时间。 --- Kernel boot time to Init start with this improvement: ~0.90s 另外一个提高启动时间的方法可以是使用不同的压缩算法,尽管目前我们内核配置中默认算法 LZO已经很高效了。   User Space 在 Linux 用户空间,初始化工作由 init 系统完成。 Toradex BSP 镜像使用 Ångströ标准启动 init 系统,其称为 Systemd。Systemd 目前已成成为桌面 Linux的标准 init 系统,具有丰富的功能,特别是为动态系统所设计。Systemd 同样会影响启动时间。多个守护进程可以用同时启动(利用现在的多核系统); socket activation支持延时加载服务,同时device activation支持按需启动服务。此外,集成的日志守护进程 journald 由于使用二进制日志文件和完善的日志文件管理可以节省空间。 根据实际应用,一个嵌入式系统可能是相当静态的。因此,并不需要 Systemd 的动态功能。不幸的是,Systemd 并不是一个很模块化的系统,各个模块之间由相互依赖关系。这使得精简 Systemd 变得困难。这一节将分文两部分,第一部分使用 Systemd 启动优化技术,第二部分会使用 System V 和其他技术。 在这两部分中,我们使用 “Freeing unused kernel memory” 作为测量基准时间。 ---------------------------------------------------------------------------- ./grabserial -d /dev/ttyUSB1 -t -m "^\ 0-9.]* Freeing unused kernel memory.*" ----------------------------------------------------------------------------   Systemd 在本文中,我们定义串口输出上的 login shell 作为关键任务。login shell 定义为 “Type=Idle”,根据定义它将在所有服务启动后立即运行。 为了启动一个没有界面或者基于 framebuffer 的应用,一般需要创建一个新的服务。Systemd 允许定义服务运行之前所需的条件(例如 Network 中 “Wants=network-online.target”)以及自动确保当所需的条件满足之后服务能够启动。然而,因为这些服务是同时启动的,所以 CPU 资源需要在它们之间共享。但是应用仍有可能在串口控制台可用之前就开始启动和运行。因此,下面的数字有可能更高。 --- User space boot time to Login without improvements: ~8.6s 内核参数中的 quiet,同样也适用于 Systemd。这个有助于减少 Systemd 的启动时间大约 1.6 秒。 --- User space boot time to Login with this improvement: ~6.5s Systemd 提供了 systemd-analyze 工具,当使用 “blame” 时,能够打印出各个服务以及其启动的时间。这个可以发现最消耗启动时间的服务。但是,其中的值可能具有迷惑性,因为测量的时间是实际流逝的时间。服务有可能处于睡眠状态,这时的 CPU 其实在处理其他任务。所以在列表顶部的服务不一定是最耗时的,特别是在单核心系统上。 服务可以使用 disable 命令来关闭。有些服务(特别是 Systemd 自身提供的)可能需要掩码才能关闭它们。另外有一些可能是系统运行所需的。因此,在关闭服务时需要特别小心,而且一次只能处理一个。在本文中,下面的服务已经被关闭: ---------------------------------------------------------------------------- systemctl disable usbg systemctl disable connman.service # replaced with networkd systemctl mask alsa-restore.service ---------------------------------------------------------------------------- --- User space boot time to Login with this improvement: ~6.1s Systemd 自带的系统日志守护进程为journald。这是一个不应该完全被禁用的组件之一。在启动的时候,日志守护进程需要管理和删除在磁盘上的旧文件,以及写入新文件。通过禁止将日志写入磁盘,可以提供启动时间,代价是日志文件将不会被保存。配置 /etc/systemd/journald.conf 中的 Storage=none,禁用日志保存。 --- User space boot time to Login with this improvement: ~5.6s   System V init 和其他方法 在很长一段时间内,Linux 也使用 SysV 作为标准的 init 系统。由于基于脚本模式,使得SysV是模块化的,并且可以相对容易进行精简,特别是针对不需要systemd的device activation或socket activation的相对静态的系统。此时,SysV 是另一个很好的选择。 在我另一篇博文《 The Yocto Project's Reference Distribution“Poky”on Toradex Hardware 》中提到的 Yocto 项目参考发布版本“Poky”就默认使用了 SysV。通过使用“minimal-console-image”和静态 IP 配置,Colibri VF61 上用户空间启动时间约为 2.3 s。 --- User space boot time to Shell with System V: ~2.3s meta-yocto 层同样提供“poky-tiny”,其使用 shell 脚本作为 init 系统。只要用 “poky-tiny” 替换Yocto标准发布版本并重新编译镜像,例如“console-image-minimal”。该版本原本用作 initramfs,然而,通过移除 conf/distro/poky-tiny.conf 文件中的 MACHINE_ESSENTIAL_EXTRA_RDEPENDS、IMAGE_FSTYPES 和 PREFERRED_PROVIDER_virtual/kernel,我们能够编译可用的 UBIFS 镜像。然后你需要创建新的distribution layer并复制配置文件,使得该版本拥有可烧写的root文件系统。这样之后,启动到 shell 的时间是相当快的(220ms),到可以执行简单命令的总体启动时间也要小于 2 秒。当然,这仅仅只提供了挂载 root file 系统、一些基本的虚拟文件支持和 shell 。根据你的项目所需功能的数量,可以以此作为一个优化的起点。 --- User space boot time to Shell with a Shell script only: ~0.2s   参考资料 http://free-electrons.com/doc/training/boot-time/boot-time-slides.pdf
  • 热度 16
    2016-1-4 11:31
    1102 次阅读|
    0 个评论
    By Toradex Stefan Agner 有些应用对系统启动时间有着特殊的要求。在很多场合下,这些系统并不需要针对所有任务立即就位,但是针对某些关键任务(例如接收以太网命令或者显示用户界面)则必须能够应对。本文将提供一些方法和简单的步骤,以 Toradex 计算机模块为例去优化启动时间。 提示: 文中涉及到的部分方法需要重新编译 U-boot、内核以及文件系统。请参考Toradex 开发者中心网站 上的相关文章。 在开始动手优化之前, 我们需要一个合适的方法来测量启动时间。如果想要十分精准地测量启动时间,这甚至需要牵涉到硬件(例如 GPIO 和示波器)。在绝大多数场合下,通过监控系统串口控制台输出已经是相当准确了。Tim Bird 的 grabserial 是一个广泛使用的工具,可以用于查看串口控制台输出的时间信息。这个工具能够为收到的每一行信息添加上时间戳,如下面所示: ---------------------------------------------------------------------------- $ ./grabserial -d /dev/ttyUSB1 -t U-Boot 2015.04-00006-g6762920 (Oct 12 2015 - 15:35:50) CPU: Freescale Vybrid VF610 at 500 MHz Reset cause: POWER ON RESET DRAM:  256 MiB NAND:  512 MiB MMC:   FSL_SDHC: 0 ---------------------------------------------------------------------------- 第一列数字代表时间戳(从收到第一个字符算起),第二行代表的是收到当前一行和上一行信息之间的时间间隔。 该文章基本上适用于所有我们的模块产品。然而,这其中我所使用的方法和改进之处中确实有一些是针对基于 Freescale Vybrid 的 Colibri VF61 模块。 Linux 系统的启动,主要可以分为以下 3 个阶段,文章将逐一讨论。 Boot loader Linux kernel User space (init system)   Boot loader 实际上在 boot loader 启动之前,还有两个步骤:硬件初始化和 boot ROM。硬件初始化需要满足电源上电顺序以及总线和处理器芯片复位时序要求。这个阶段的耗时一般是固定的,在 10 ~ 200 ms。ARM 处理器从位于内部的 ROM 上启动固件。该固件从启动介质上加载 boot loader。该阶段的时间一般很短,取决于 boot loader 的大小。除了减小 boot loader 体积,很难做其他的优化。实际上能够做的优化和调整还是在 boot loader (U-Boot)。 目前Toradex发布Embedded Linux V2.5 Beta 1 版本,从第一个字符输出到内核启动的时间约为 1.85 秒。主要涉及以下过程: U-Boot 初始化(约 110ms,从接收到的第一个字符算起) Autoboot delay(1s) UBI 初始化和 UBIFS 挂载(约 300ms,得益于 Fastmap 功能,不使用该功能将耗时 1.6s) 内核加载(375ms) 加载和应用 device tree(约 35ms) 最后跳转至内核起始地址 --- Boot time to Kernel start: ~1850ms 首先最显著的优化就是降低 Autoboot delay 。这个值可以使用下面的命令设置为 0: ---------------------------------------------------------------------------- setenv bootdelay 0 saveenv ---------------------------------------------------------------------------- 这个也可以使用 CONFIG_BOOTDELAY 将其配置为默认值。在目前的发布版本中,如果将 bootdelay 设置为 0,那么将会没有办法直接进入 boot loader 的命令行模式。U-Boot 提供一个选项 CONFIG_ZERO_BOOTDELAY_CHECK,在 bootdelay 为 0 的情况下,用于检测一个字符。我们已经将其添加到下一个发布版本的默认配置中。 --- Boot time to Kernel start with this improvement: ~860ms 串口输出是同步发送的。这意味着 CPU 将等待,直到字符通过在串口线上发送完毕。因此,每一个输出的字符都将减慢 U-Boot 的启动。特别是 UBI 将会输出大量的信息,这是一个可以优化的地方。有一个配置符号 CONFIG_UBI_SILENCE_MSG 可以实现这个目的。 --- Boot time to Kernel start with this improvement: ~800ms 为了确保尽可能高效地使用硬件,需要深入了解硬件的功能以及目前实现的方法。目前还没有被使用的功能是 Level 2 Cache(仅 Colibri VF61)。在开启 Level 2 cache 后,启动时间可以提高 40 ms。 --- Boot time to Kernel start with this improvement: ~760ms 移除一些功能有助于减少分配时间和初始化这些功能的时间。例如可以移除显示支持 (DCU),EXT3 和 EXT4 支持以及 USB 外设驱动如 DFU 和 存储设备。这可以将 U-Boot 尺寸减小到 366 KB,同时节省 10 ms 时间。 --- Boot time to Kernel start with this improvement: ~750ms 根据显示的时间戳,绝大多数的时间被用于加载 UBI 和挂载 UBIFS 以及内核的加载(约 380ms)。显然内核大小和加载时间具有线性关系,因此,优化内核尺寸将可以进一步提高启动时间。   Kernel 为了只测量内核启动的时间,可以使用 grabserial 的匹配功能重置 boot loader 输出信息中的时间。 ---------------------------------------------------------------------------- ./grabserial -d /dev/ttyUSB1 -t -m "^Starting kernel.*" ---------------------------------------------------------------------------- 启动结束的时间多少有点难以确定,因为内核将会继续初始化硬件,即使文件系统已经挂载和第一个用户空间进程(init)开始运行(延时初始化)。 “Freeing unused kernel memory” 是 init 进程启动前发出的最后消息,因此将其标记为内核线性任务的结束(请查看 kernel_init in init/main.c)。我将会使用这个信息的时间戳来比较启动时间。我们模块上默认内核的压缩尺寸为 4316 KB,启动时间为 2.56 秒。 --- Kernel boot time to Init start: 2.56s 同 U-Boot 一样,Linux 内核也是同步地将信息发送到串口。具体的方法取决于所使用的串口,LPUART( Vybrid 的 console 驱动)会同步等待直到字符在串口上发送完毕。这个的优点在于,当内核崩溃的时候,那个时候的所有信息都是可见的。假如信息是异步输出,最后输出的信息将不 会指示内核所崩溃的地方。 内核中有一个参数,可以最大限度减少输出的信息:“Quiet”。然而,这也将屏蔽我们测试启动时间的字符信息(“Freeing unused kernel memory”)。最简单的方法输出这些信息是利用日志级别输出特定的信息。在 'mm/page_alloc.c' 中搜索 “Freeing %s memory”。我将使用 ‘pr_alert’ 输出信息。这个方法整整缩短了启动时间1.55 秒! --- Kernel boot time to Init start with this improvement: ~1.01s 进一步提高启动时间的另一个简单的方法是移除功能。Yocto 项目提供了一个方便的工具 ksize.py,这个需要在内核编译目录中运行。这个工具能够显示内核各个部分的大小。第一个表格显示了大致的概况(为了获得准确的概况, 编译之前使用 make clean)。 ---------------------------------------------------------------------------- Linux Kernel              total |       text       data        bss ------------------------------------------------------------------- vmlinux                 8305381 |    7882273     247732     175376 drivers/built-in.o      2010229 |    1881545     109796      18888 fs/built-in.o           1944926 |    1911100      19422      14404 net/built-in.o          1477404 |    1398316      44832      34256 kernel/built-in.o        628094 |     514935      17099      96060 sound/built-in.o         326322 |     316298       8248       1776 mm/built-in.o            288456 |     276492       8000       3964 lib/built-in.o           160209 |     157659        217       2333 block/built-in.o         137262 |     133614       2420       1228 crypto/built-in.o        104157 |     100063       4082         12 security/built-in.o       37391 |      36303        788        300 init/built-in.o           31064 |      16208      14772         84 ipc/built-in.o            29366 |      28640        722          4 usr/built-in.o              138 |        138          0          0 ------------------------------------------------------------------- sum                     7175018 |    6771311     230398     173309 delta                   1130363 |    1110962      17334       2067 ---------------------------------------------------------------------------- 可以被安全移除的一般是应用相关的功能。浏览各个第一层目录,有助于快速确定最可能移除的对象。为了文中的演示,我移除了部分文件系统(cifs, nfs, ext4, ntfs)、音频子系统、多媒体支持、USB 以及无线网络适配器支持。内核最后缩减到 3356 KB,比原来将近小了 1MB。这也减少了约 85ms 的内核加载时间。 --- Kernel boot time to Init start with this improvement: ~0.90s 另外一个提高启动时间的方法可以是使用不同的压缩算法,尽管目前我们内核配置中默认算法 LZO已经很高效了。   User Space 在 Linux 用户空间,初始化工作由 init 系统完成。 Toradex BSP 镜像使用 Ångströ标准启动 init 系统,其称为 Systemd。Systemd 目前已成成为桌面 Linux的标准 init 系统,具有丰富的功能,特别是为动态系统所设计。Systemd 同样会影响启动时间。多个守护进程可以用同时启动(利用现在的多核系统); socket activation支持延时加载服务,同时device activation支持按需启动服务。此外,集成的日志守护进程 journald 由于使用二进制日志文件和完善的日志文件管理可以节省空间。 根据实际应用,一个嵌入式系统可能是相当静态的。因此,并不需要 Systemd 的动态功能。不幸的是,Systemd 并不是一个很模块化的系统,各个模块之间由相互依赖关系。这使得精简 Systemd 变得困难。这一节将分文两部分,第一部分使用 Systemd 启动优化技术,第二部分会使用 System V 和其他技术。 在这两部分中,我们使用 “Freeing unused kernel memory” 作为测量基准时间。 ---------------------------------------------------------------------------- ./grabserial -d /dev/ttyUSB1 -t -m "^\ 0-9.]* Freeing unused kernel memory.*" ----------------------------------------------------------------------------   Systemd 在本文中,我们定义串口输出上的 login shell 作为关键任务。login shell 定义为 “Type=Idle”,根据定义它将在所有服务启动后立即运行。 为了启动一个没有界面或者基于 framebuffer 的应用,一般需要创建一个新的服务。Systemd 允许定义服务运行之前所需的条件(例如 Network 中 “Wants=network-online.target”)以及自动确保当所需的条件满足之后服务能够启动。然而,因为这些服务是同时启动的,所以 CPU 资源需要在它们之间共享。但是应用仍有可能在串口控制台可用之前就开始启动和运行。因此,下面的数字有可能更高。 --- User space boot time to Login without improvements: ~8.6s 内核参数中的 quiet,同样也适用于 Systemd。这个有助于减少 Systemd 的启动时间大约 1.6 秒。 --- User space boot time to Login with this improvement: ~6.5s Systemd 提供了 systemd-analyze 工具,当使用 “blame” 时,能够打印出各个服务以及其启动的时间。这个可以发现最消耗启动时间的服务。但是,其中的值可能具有迷惑性,因为测量的时间是实际流逝的时间。服务有可能处于睡眠状态,这时的 CPU 其实在处理其他任务。所以在列表顶部的服务不一定是最耗时的,特别是在单核心系统上。 服务可以使用 disable 命令来关闭。有些服务(特别是 Systemd 自身提供的)可能需要掩码才能关闭它们。另外有一些可能是系统运行所需的。因此,在关闭服务时需要特别小心,而且一次只能处理一个。在本文中,下面的服务已经被关闭: ---------------------------------------------------------------------------- systemctl disable usbg systemctl disable connman.service # replaced with networkd systemctl mask alsa-restore.service ---------------------------------------------------------------------------- --- User space boot time to Login with this improvement: ~6.1s Systemd 自带的系统日志守护进程为journald。这是一个不应该完全被禁用的组件之一。在启动的时候,日志守护进程需要管理和删除在磁盘上的旧文件,以及写入新文件。通过禁止将日志写入磁盘,可以提供启动时间,代价是日志文件将不会被保存。配置 /etc/systemd/journald.conf 中的 Storage=none,禁用日志保存。 --- User space boot time to Login with this improvement: ~5.6s   System V init 和其他方法 在很长一段时间内,Linux 也使用 SysV 作为标准的 init 系统。由于基于脚本模式,使得SysV是模块化的,并且可以相对容易进行精简,特别是针对不需要systemd的device activation或socket activation的相对静态的系统。此时,SysV 是另一个很好的选择。 在我另一篇博文《 The Yocto Project's Reference Distribution“Poky”on Toradex Hardware 》中提到的 Yocto 项目参考发布版本“Poky”就默认使用了 SysV。通过使用“minimal-console-image”和静态 IP 配置,Colibri VF61 上用户空间启动时间约为 2.3 s。 --- User space boot time to Shell with System V: ~2.3s meta-yocto 层同样提供“poky-tiny”,其使用 shell 脚本作为 init 系统。只要用 “poky-tiny” 替换Yocto标准发布版本并重新编译镜像,例如“console-image-minimal”。该版本原本用作 initramfs,然而,通过移除 conf/distro/poky-tiny.conf 文件中的 MACHINE_ESSENTIAL_EXTRA_RDEPENDS、IMAGE_FSTYPES 和 PREFERRED_PROVIDER_virtual/kernel,我们能够编译可用的 UBIFS 镜像。然后你需要创建新的distribution layer并复制配置文件,使得该版本拥有可烧写的root文件系统。这样之后,启动到 shell 的时间是相当快的(220ms),到可以执行简单命令的总体启动时间也要小于 2 秒。当然,这仅仅只提供了挂载 root file 系统、一些基本的虚拟文件支持和 shell 。根据你的项目所需功能的数量,可以以此作为一个优化的起点。 --- User space boot time to Shell with a Shell script only: ~0.2s   参考资料 http://free-electrons.com/doc/training/boot-time/boot-time-slides.pdf
  • 热度 26
    2015-9-4 10:12
    3879 次阅读|
    0 个评论
    主要说明在 uboot 下实现对 SD 卡的识别、挂载和使用的命令操作。 实验环境 Atmel 公司的 SAM5D3X_plained ,原装系统 uboot 版本为 U-Boot 2015.01-linux4sam_4.7 ; SD 卡需要是 fat32 文件系统。 实验步骤: SD 卡的操作流程与 USB 设备的操作流程相似,熟悉 USB 操作后,对 SD 卡很容易就可以使用。 1.   使用 help mmc 命令查看 uboot 支持的 SD 卡相关命令; 2.   由于实际应用中并不会使用全部命令,我们仅仅考虑如何读取 SD 卡中的文件。 U-Boot help mmc mmc - MMC sub system   Usage: mmc info - display info of the current MMC device mmc read addr blk# cnt mmc write addr blk# cnt mmc erase blk# cnt mmc rescan mmc part - lists available partition on current mmc device mmc dev - show or set current mmc device mmc list - lists available devices mmc setdsr value - set DSR register value   U-Boot mmc info Device: mci Manufacturer ID: 27 ... U-Boot mmc list mci: 0 U-Boot mmc part Partition Map for MMC device 0  --   Partition Type: DOS Part    Start Sector    Num Sectors     UUID            Type   1     63              144522          00000000-01     0c Boot   2     160650          3743145         00000000-02     83 U-Boot fatls mmc 0:2 ** Unrecognized filesystem type ** U-Boot fatls mmc 0:1 ... 5 file(s), 0 dir(s) U-Boot 对比 uboot 下对 U 盘的操作,两者思想是一致的,只是 SD 不需要 scan 和 stop 操作。
相关资源
  • 所需E币: 0
    时间: 2023-11-10 15:44
    大小: 1001KB
    上传者: Argent
    第4讲Uboot源码目录分析
  • 所需E币: 0
    时间: 2023-11-10 15:43
    大小: 1006KB
    上传者: Argent
    第3讲Uboot命令使用
  • 所需E币: 0
    时间: 2023-11-10 15:43
    大小: 1018KB
    上传者: Argent
    第2讲正点原子官方Uboot编译与体验
  • 所需E币: 0
    时间: 2023-11-10 15:48
    大小: 1016KB
    上传者: Argent
    第16讲Uboot移植实验(NAND版本)-补录
  • 所需E币: 0
    时间: 2023-11-10 15:45
    大小: 1011KB
    上传者: Argent
    第8讲Uboot图形化界面配置
  • 所需E币: 0
    时间: 2023-11-10 15:45
    大小: 1016KB
    上传者: Argent
    第7讲Uboot移植实验
  • 所需E币: 0
    时间: 2023-11-10 15:45
    大小: 1013.5KB
    上传者: Argent
    第6讲Uboot启动流程详解
  • 所需E币: 0
    时间: 2023-11-10 15:45
    大小: 1006KB
    上传者: Argent
    第5讲Uboot顶层Makefile分析
  • 所需E币: 2
    时间: 2023-5-15 19:01
    大小: 2.16MB
    上传者: 舒凤志
    第1章start.S详解第2章start.S的总结第3章相关知识点详解
  • 所需E币: 1
    时间: 2023-4-24 00:13
    大小: 522.96KB
    上传者: Power_RISC
    Uboot启动过程详解.pdf
  • 所需E币: 3
    时间: 2022-12-16 01:20
    大小: 1.7MB
    上传者: fzyiye
    ARM体系结构——ARM79出品-u-boot移植手册
  • 所需E币: 1
    时间: 2021-9-27 14:33
    大小: 724.46KB
    上传者: Argent
    电子产品日新月异,不管是硬件工程师还是软件工程师,基本的模电、数电、微机原理、信号处理等知识是必备的条件,从二极管到三极管,从单片机到多核MCU,3G网络到5G产品的普及,不管电子产品的集成度怎么高,其产品还是少不了电阻电容电感,每个元器件在电路中必然有其作用,有兴趣了解的网友,下载学习学习吧。
  • 所需E币: 1
    时间: 2021-9-27 14:33
    大小: 748.91KB
    上传者: Argent
    电子产品日新月异,不管是硬件工程师还是软件工程师,基本的模电、数电、微机原理、信号处理等知识是必备的条件,从二极管到三极管,从单片机到多核MCU,3G网络到5G产品的普及,不管电子产品的集成度怎么高,其产品还是少不了电阻电容电感,每个元器件在电路中必然有其作用,有兴趣了解的网友,下载学习学习吧。
  • 所需E币: 5
    时间: 2021-10-5 11:12
    大小: 9.72MB
    上传者: zendy_731593397
    DasU-Boot 是一个主要用于嵌入式系统的引导加载程序,可以支持多种不同的计算机系统结构,包括PPC、ARM、AVR32、MIPS、x86、68k、Nios与MicroBlaze。这也是一套在GNU通用公共许可证之下发布的自由软件。DasU-Boot可以在x86计算机上建构,但这部x86计算机必须安装有可支持特定平台结构的交互发展GNU工具链,例如crosstool、EmbeddedLinuxDevelopmentKit(ELDK)或OSELAS.Toolchain
  • 所需E币: 2
    时间: 2021-4-19 18:01
    大小: 153.87KB
    上传者: czdian2005
    第2天(U-Boot移植)-每日必修实验.pdf
  • 所需E币: 0
    时间: 2021-3-25 18:06
    大小: 701.61KB
    上传者: Argent
    全志方案在消费类电子占有很大的市场,随着产品的不断升级优化,全志方案不仅仅在安卓平板,视频监控、广告应用等领域崭露头角,本人收集些有关全志方案的开发资料,希望对正在使用全志方案的网友有所帮助。
  • 所需E币: 0
    时间: 2021-3-25 23:18
    大小: 630.98KB
    上传者: Argent
    全志方案在消费类电子占有很大的市场,随着产品的不断升级优化,全志方案不仅仅在安卓平板,视频监控、广告应用等领域崭露头角,本人收集些有关全志方案的开发资料,希望对正在使用全志方案的网友有所帮助。
  • 所需E币: 1
    时间: 2020-9-3 12:50
    大小: 164.64KB
    上传者: symic
    U-BOOT的启动流程及移植
  • 所需E币: 5
    时间: 2020-8-31 12:50
    大小: 333.3KB
    上传者: 东亚安防
    Hi3510HiBoot与标准U-boot差异说明
  • 所需E币: 3
    时间: 2019-12-26 00:22
    大小: 46.28KB
    上传者: wsu_w_hotmail.com
    44b0uboot移植程序……