diff options
294 files changed, 17304 insertions, 2040 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf index d88af5712..35167e120 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -18,3 +18,6 @@  # Not Linux, so we don't recommend usleep_range() over udelay()  --ignore USLEEP_RANGE + +# Ignore networking block comment style +--ignore NETWORKING_BLOCK_COMMENT_STYLE @@ -24,7 +24,7 @@  VERSION = 2013  PATCHLEVEL = 07  SUBLEVEL = -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2  ifneq "$(SUBLEVEL)" ""  U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)  else @@ -247,6 +247,7 @@ OBJS := $(addprefix $(obj),$(OBJS))  HAVE_VENDOR_COMMON_LIB = $(if $(wildcard board/$(VENDOR)/common/Makefile),y,n)  LIBS-y += lib/libgeneric.o +LIBS-y += lib/rsa/librsa.o  LIBS-y += lib/lzma/liblzma.o  LIBS-y += lib/lzo/liblzo.o  LIBS-y += lib/zlib/libz.o @@ -743,6 +744,13 @@ tools: $(VERSION_FILE) $(TIMESTAMP_FILE)  	$(MAKE) -C $@ all  endif	# config.mk +# ARM relocations should all be R_ARM_RELATIVE. +checkarmreloc: $(obj)u-boot +	@if test "R_ARM_RELATIVE" != \ +		"`readelf -r $< | cut -d ' ' -f 4 | grep R_ARM | sort -u`"; \ +		then echo "$< contains relocations other than \ +		R_ARM_RELATIVE"; false; fi +  $(VERSION_FILE):  		@mkdir -p $(dir $(VERSION_FILE))  		@( localvers='$(shell $(TOPDIR)/tools/setlocalversion $(TOPDIR))' ; \ @@ -824,7 +832,8 @@ clean:  	       $(obj)tools/mk{smdk5250,}spl				  \  	       $(obj)tools/mxsboot					  \  	       $(obj)tools/ncb		   $(obj)tools/ubsha1		  \ -	       $(obj)tools/kernel-doc/docproc +	       $(obj)tools/kernel-doc/docproc				  \ +	       $(obj)tools/proftool  	@rm -f $(obj)board/cray/L1/{bootscript.c,bootscript.image}	  \  	       $(obj)board/matrix_vision/*/bootscript.img		  \  	       $(obj)board/voiceblue/eeprom 				  \ @@ -413,11 +413,22 @@ The following options need to be configured:  		See Freescale App Note 4493 for more information about  		this erratum. +		CONFIG_A003399_NOR_WORKAROUND +		Enables a workaround for IFC erratum A003399. It is only +		requred during NOR boot. +  		CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY  		This is the value to write into CCSR offset 0x18600  		according to the A004510 workaround. +		CONFIG_SYS_FSL_DSP_M2_RAM_ADDR +		This value denotes start offset of M2 memory +		which is directly connected to the DSP core. + +		CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT +		This value denotes start offset of DSP CCSR space. +  - Generic CPU options:  		CONFIG_SYS_BIG_ENDIAN, CONFIG_SYS_LITTLE_ENDIAN @@ -843,7 +854,7 @@ The following options need to be configured:  		CONFIG_CMD_FDOS		* Dos diskette Support  		CONFIG_CMD_FLASH	  flinfo, erase, protect  		CONFIG_CMD_FPGA		  FPGA device initialization support -		CONFIG_CMD_FUSE		  Device fuse support +		CONFIG_CMD_FUSE		* Device fuse support  		CONFIG_CMD_GETTIME	* Get time since boot  		CONFIG_CMD_GO		* the 'go' command (exec code)  		CONFIG_CMD_GREPENV	* search environment @@ -853,7 +864,7 @@ The following options need to be configured:  		CONFIG_CMD_IDE		* IDE harddisk support  		CONFIG_CMD_IMI		  iminfo  		CONFIG_CMD_IMLS		  List all images found in NOR flash -		CONFIG_CMD_IMLS_NAND	  List all images found in NAND flash +		CONFIG_CMD_IMLS_NAND	* List all images found in NAND flash  		CONFIG_CMD_IMMAP	* IMMR dump support  		CONFIG_CMD_IMPORTENV	* import an environment  		CONFIG_CMD_INI		* import data from an ini file into the env @@ -861,23 +872,24 @@ The following options need to be configured:  		CONFIG_CMD_ITEST	  Integer/string test of 2 values  		CONFIG_CMD_JFFS2	* JFFS2 Support  		CONFIG_CMD_KGDB		* kgdb -		CONFIG_CMD_LDRINFO	  ldrinfo (display Blackfin loader) +		CONFIG_CMD_LDRINFO	* ldrinfo (display Blackfin loader)  		CONFIG_CMD_LINK_LOCAL	* link-local IP address auto-configuration  					  (169.254.*.*)  		CONFIG_CMD_LOADB	  loadb  		CONFIG_CMD_LOADS	  loads -		CONFIG_CMD_MD5SUM	  print md5 message digest +		CONFIG_CMD_MD5SUM	* print md5 message digest  					  (requires CONFIG_CMD_MEMORY and CONFIG_MD5)  		CONFIG_CMD_MEMINFO	* Display detailed memory information  		CONFIG_CMD_MEMORY	  md, mm, nm, mw, cp, cmp, crc, base,  					  loop, loopw -		CONFIG_CMD_MEMTEST	  mtest +		CONFIG_CMD_MEMTEST	* mtest  		CONFIG_CMD_MISC		  Misc functions like sleep etc  		CONFIG_CMD_MMC		* MMC memory mapped support  		CONFIG_CMD_MII		* MII utility commands  		CONFIG_CMD_MTDPARTS	* MTD partition support  		CONFIG_CMD_NAND		* NAND support  		CONFIG_CMD_NET		  bootp, tftpboot, rarpboot +		CONFIG_CMD_NFS		  NFS support  		CONFIG_CMD_PCA953X	* PCA953x I2C gpio commands  		CONFIG_CMD_PCA953X_INFO * PCA953x I2C gpio info command  		CONFIG_CMD_PCI		* pciinfo @@ -896,7 +908,7 @@ The following options need to be configured:  		CONFIG_CMD_SETGETDCR	  Support for DCR Register access  					  (4xx only)  		CONFIG_CMD_SF		* Read/write/erase SPI NOR flash -		CONFIG_CMD_SHA1SUM	  print sha1 memory digest +		CONFIG_CMD_SHA1SUM	* print sha1 memory digest  					  (requires CONFIG_CMD_MEMORY)  		CONFIG_CMD_SOFTSWITCH	* Soft switch setting command for BF60x  		CONFIG_CMD_SOURCE	  "source" command Support @@ -908,6 +920,7 @@ The following options need to be configured:  		CONFIG_CMD_USB		* USB support  		CONFIG_CMD_CDP		* Cisco Discover Protocol support  		CONFIG_CMD_MFSL		* Microblaze FSL support +		CONFIG_CMD_XIMG		  Load part of Multi Image  		EXAMPLE: If you want all functions except of network @@ -1432,6 +1445,11 @@ CBFS (Coreboot Filesystem) support  		Export function i8042_kbd_init, i8042_tstc and i8042_getc  		for cfb_console. Supports cursor blinking. +		CONFIG_CROS_EC_KEYB +		Enables a Chrome OS keyboard using the CROS_EC interface. +		This uses CROS_EC to communicate with a second microcontroller +		which provides key scans on request. +  - Video support:  		CONFIG_VIDEO @@ -2509,6 +2527,11 @@ CBFS (Coreboot Filesystem) support  		Define this option to include a destructive SPI flash  		test ('sf test'). +		CONFIG_SPI_FLASH_BAR		Ban/Extended Addr Reg + +		Define this option to use the Bank addr/Extended addr +		support on SPI flashes which has size > 16Mbytes. +  - SystemACE Support:  		CONFIG_SYSTEMACE @@ -2560,6 +2583,16 @@ CBFS (Coreboot Filesystem) support  		Note: There is also a sha1sum command, which should perhaps  		be deprecated in favour of 'hash sha1'. +- Signing support: +		CONFIG_RSA + +		This enables the RSA algorithm used for FIT image verification +		in U-Boot. See doc/uImage/signature for more information. + +		The signing part is build into mkimage regardless of this +		option. + +  - Show boot progress:  		CONFIG_SHOW_BOOT_PROGRESS @@ -2784,6 +2817,11 @@ FIT uImage format:  		most specific compatibility entry of U-Boot's fdt's root node.  		The order of entries in the configuration's fdt is ignored. +		CONFIG_FIT_SIGNATURE +		This option enables signature verification of FIT uImages, +		using a hash signed and verified using RSA. See +		doc/uImage.FIT/signature.txt for more details. +  - Standalone program support:  		CONFIG_STANDALONE_LOAD_ADDR @@ -3022,6 +3060,14 @@ FIT uImage format:  		CONFIG_SPL_LIBGENERIC_SUPPORT  		Support for lib/libgeneric.o in SPL binary +		CONFIG_SPL_ENV_SUPPORT +		Support for the environment operating in SPL binary + +		CONFIG_SPL_NET_SUPPORT +		Support for the net/libnet.o in SPL binary. +		It conflicts with SPL env from storage medium specified by +		CONFIG_ENV_IS_xxx but CONFIG_ENV_IS_NOWHERE +  		CONFIG_SPL_PAD_TO  		Image offset to which the SPL should be padded before appending  		the SPL payload. By default, this is defined as @@ -3964,6 +4010,9 @@ Low Level (hardware related) configuration options:  - CONFIG_SRIO2:  		Board has SRIO 2 port available +- CONFIG_SRIO_PCIE_BOOT_MASTER +		Board can support master function for Boot from SRIO and PCIE +  - CONFIG_SYS_SRIOn_MEM_VIRT:  		Virtual Address of SRIO port 'n' memory region @@ -4074,6 +4123,11 @@ Low Level (hardware related) configuration options:  		that is executed before the actual U-Boot. E.g. when  		compiling a NAND SPL. +- CONFIG_SYS_MPC85XX_NO_RESETVEC +		Only for 85xx systems. If this variable is specified, the section +		.resetvec is not kept and the section .bootpg is placed in the +		previous 4k of the .text section. +  - CONFIG_ARCH_MAP_SYSMEM  		Generally U-Boot (and in particular the md command) uses  		effective address. It is therefore not necessary to regard diff --git a/arch/arm/config.mk b/arch/arm/config.mk index dc6416078..e80e1ed1a 100644 --- a/arch/arm/config.mk +++ b/arch/arm/config.mk @@ -109,3 +109,8 @@ ifeq ($(GAS_BUG_12532),y)  PLATFORM_RELFLAGS += -fno-optimize-sibling-calls  endif  endif + +# check that only R_ARM_RELATIVE relocations are generated +ifneq ($(CONFIG_SPL_BUILD),y) +ALL-y	+= checkarmreloc +endif diff --git a/arch/arm/cpu/arm920t/ep93xx/u-boot.lds b/arch/arm/cpu/arm920t/ep93xx/u-boot.lds index cf55bf7d4..367c805e3 100644 --- a/arch/arm/cpu/arm920t/ep93xx/u-boot.lds +++ b/arch/arm/cpu/arm920t/ep93xx/u-boot.lds @@ -31,6 +31,7 @@ SECTIONS  	. = ALIGN(4);  	.text      :  	{ +		*(.__image_copy_start)  	  arch/arm/cpu/arm920t/start.o	(.text*)  		/* the EP93xx expects to find the pattern 'CRUS' at 0x1000 */  	  . = 0x1000; @@ -56,7 +57,10 @@ SECTIONS  	. = ALIGN(4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	}  	__bss_start = .;  	.bss : { *(.bss*) } diff --git a/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds index 673c725ab..f4e7525f1 100644 --- a/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds +++ b/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds @@ -57,11 +57,6 @@ SECTIONS  		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} -  	.bss : {  		. = ALIGN(4);  		__bss_start = .; diff --git a/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds index 967a135b3..446d09501 100644 --- a/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds +++ b/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds @@ -57,11 +57,6 @@ SECTIONS  		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} -  	.bss : {  		. = ALIGN(4);  		__bss_start = .; diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c index 885fb2d20..b935a29a3 100644 --- a/arch/arm/cpu/armv7/am33xx/board.c +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -149,3 +149,43 @@ int arch_misc_init(void)  #endif  	return 0;  } + +#ifdef CONFIG_SPL_BUILD +void rtc32k_enable(void) +{ +	struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; + +	/* +	 * Unlock the RTC's registers.  For more details please see the +	 * RTC_SS section of the TRM.  In order to unlock we need to +	 * write these specific values (keys) in this order. +	 */ +	writel(0x83e70b13, &rtc->kick0r); +	writel(0x95a4f1e0, &rtc->kick1r); + +	/* Enable the RTC 32K OSC by setting bits 3 and 6. */ +	writel((1 << 3) | (1 << 6), &rtc->osc); +} + +#define UART_RESET		(0x1 << 1) +#define UART_CLK_RUNNING_MASK	0x1 +#define UART_SMART_IDLE_EN	(0x1 << 0x3) + +void uart_soft_reset(void) +{ +	struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE; +	u32 regval; + +	regval = readl(&uart_base->uartsyscfg); +	regval |= UART_RESET; +	writel(regval, &uart_base->uartsyscfg); +	while ((readl(&uart_base->uartsyssts) & +		UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK) +		; + +	/* Disable smart idle */ +	regval = readl(&uart_base->uartsyscfg); +	regval |= UART_SMART_IDLE_EN; +	writel(regval, &uart_base->uartsyscfg); +} +#endif diff --git a/arch/arm/cpu/armv7/am33xx/clock_am33xx.c b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c index a1efc7520..9c4d0b439 100644 --- a/arch/arm/cpu/armv7/am33xx/clock_am33xx.c +++ b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c @@ -246,7 +246,7 @@ static void enable_per_clocks(void)  		;  } -static void mpu_pll_config(void) +void mpu_pll_config_val(int mpull_m)  {  	u32 clkmode, clksel, div_m2; @@ -260,7 +260,7 @@ static void mpu_pll_config(void)  		;  	clksel = clksel & (~CLK_SEL_MASK); -	clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N); +	clksel = clksel | ((mpull_m << CLK_SEL_SHIFT) | MPUPLL_N);  	writel(clksel, &cmwkup->clkseldpllmpu);  	div_m2 = div_m2 & ~CLK_DIV_MASK; @@ -274,6 +274,11 @@ static void mpu_pll_config(void)  		;  } +static void mpu_pll_config(void) +{ +	mpu_pll_config_val(CONFIG_SYS_MPUCLK); +} +  static void core_pll_config(void)  {  	u32 clkmode, clksel, div_m4, div_m5, div_m6; diff --git a/arch/arm/cpu/armv7/exynos/Makefile b/arch/arm/cpu/armv7/exynos/Makefile index 9119961d9..b2f9152e1 100644 --- a/arch/arm/cpu/armv7/exynos/Makefile +++ b/arch/arm/cpu/armv7/exynos/Makefile @@ -22,7 +22,7 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(SOC).o -COBJS	+= clock.o power.o soc.o system.o pinmux.o +COBJS	+= clock.o power.o soc.o system.o pinmux.o tzpc.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 223660aab..e1c42462e 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -116,10 +116,8 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  		/* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */  		fout = (m + k / 1024) * (freq / (p * (1 << s)));  	} else { -		if (s < 1) -			s = 1; -		/* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */ -		fout = m * (freq / (p * (1 << (s - 1)))); +		/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */ +		fout = m * (freq / (p * (1 << s)));  	}  	return fout; @@ -613,7 +611,7 @@ static unsigned long exynos4_get_mmc_clk(int dev_index)  		(struct exynos4_clock *)samsung_get_base_clock();  	unsigned long uclk, sclk;  	unsigned int sel, ratio, pre_ratio; -	int shift; +	int shift = 0;  	sel = readl(&clk->src_fsys);  	sel = (sel >> (dev_index << 2)) & 0xf; @@ -662,7 +660,7 @@ static unsigned long exynos5_get_mmc_clk(int dev_index)  		(struct exynos5_clock *)samsung_get_base_clock();  	unsigned long uclk, sclk;  	unsigned int sel, ratio, pre_ratio; -	int shift; +	int shift = 0;  	sel = readl(&clk->src_fsys);  	sel = (sel >> (dev_index << 2)) & 0xf; diff --git a/board/samsung/smdk5250/tzpc_init.c b/arch/arm/cpu/armv7/exynos/tzpc.c index c833541fd..f5e8e9c47 100644 --- a/board/samsung/smdk5250/tzpc_init.c +++ b/arch/arm/cpu/armv7/exynos/tzpc.c @@ -22,27 +22,36 @@   * MA 02111-1307 USA   */ +#include <common.h>  #include <asm/arch/tzpc.h> -#include"setup.h" +#include <asm/io.h>  /* Setting TZPC[TrustZone Protection Controller] */  void tzpc_init(void)  {  	struct exynos_tzpc *tzpc; -	unsigned int addr; +	unsigned int addr, start = 0, end = 0; -	for (addr = TZPC0_BASE; addr <= TZPC9_BASE; addr += TZPC_BASE_OFFSET) { +	start = samsung_get_base_tzpc(); + +	if (cpu_is_exynos5()) +		end = start + ((EXYNOS5_NR_TZPC_BANKS - 1) * TZPC_BASE_OFFSET); +	else if (cpu_is_exynos4()) +		end = start + ((EXYNOS4_NR_TZPC_BANKS - 1) * TZPC_BASE_OFFSET); + +	for (addr = start; addr <= end; addr += TZPC_BASE_OFFSET) {  		tzpc = (struct exynos_tzpc *)addr; -		if (addr == TZPC0_BASE) +		if (addr == start)  			writel(R0SIZE, &tzpc->r0size);  		writel(DECPROTXSET, &tzpc->decprot0set);  		writel(DECPROTXSET, &tzpc->decprot1set); -		if (addr != TZPC9_BASE) { -			writel(DECPROTXSET, &tzpc->decprot2set); -			writel(DECPROTXSET, &tzpc->decprot3set); -		} +		if (cpu_is_exynos5() && (addr == end)) +			break; + +		writel(DECPROTXSET, &tzpc->decprot2set); +		writel(DECPROTXSET, &tzpc->decprot3set);  	}  } diff --git a/arch/arm/cpu/armv7/s5p-common/Makefile b/arch/arm/cpu/armv7/s5p-common/Makefile index 17053995b..0c38bd0d2 100644 --- a/arch/arm/cpu/armv7/s5p-common/Makefile +++ b/arch/arm/cpu/armv7/s5p-common/Makefile @@ -26,9 +26,11 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)libs5p-common.o  COBJS-y		+= cpu_info.o +ifndef CONFIG_SPL_BUILD  COBJS-y		+= timer.o  COBJS-y		+= sromc.o  COBJS-$(CONFIG_PWM)	+= pwm.o +endif  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS-y) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index 4adfaae65..637593c33 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -95,7 +95,7 @@ unsigned long get_timer(unsigned long base)  	return time_ms - base;  } -unsigned long timer_get_us(void) +unsigned long __attribute__((no_instrument_function)) timer_get_us(void)  {  	static unsigned long base_time_us; diff --git a/arch/arm/cpu/ixp/u-boot.lds b/arch/arm/cpu/ixp/u-boot.lds index 553589ca6..54bafda32 100644 --- a/arch/arm/cpu/ixp/u-boot.lds +++ b/arch/arm/cpu/ixp/u-boot.lds @@ -31,6 +31,7 @@ SECTIONS  	. = ALIGN(4);  	.text :  	{ +		*(.__image_copy_start)  		arch/arm/cpu/ixp/start.o(.text*)  		*(.text*)  	} @@ -54,17 +55,23 @@ SECTIONS  	. = ALIGN(4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -88,6 +95,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds index 1408f03b2..b6ed25f7d 100644 --- a/arch/arm/cpu/u-boot-spl.lds +++ b/arch/arm/cpu/u-boot-spl.lds @@ -58,11 +58,6 @@ SECTIONS  		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} -  	_end = .;  	.bss __rel_dyn_start (OVERLAY) : { @@ -72,6 +67,7 @@ SECTIONS  		__bss_end = .;  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds index d9bbee3b2..3037885b1 100644 --- a/arch/arm/cpu/u-boot.lds +++ b/arch/arm/cpu/u-boot.lds @@ -33,7 +33,7 @@ SECTIONS  	. = ALIGN(4);  	.text :  	{ -		__image_copy_start = .; +		*(.__image_copy_start)  		CPUDIR/start.o (.text*)  		*(.text*)  	} @@ -57,17 +57,23 @@ SECTIONS  	. = ALIGN(4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -101,6 +107,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index df4b231cf..2d6dfff59 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -169,4 +169,39 @@  		#address-cells = <1>;  		#size-cells = <1>;  	}; + +	mmc@12200000 { +		#address-cells = <1>; +		#size-cells = <0>; +		compatible = "samsung,exynos5250-dwmmc"; +		reg = <0x12200000 0x1000>; +		interrupts = <0 75 0>; +	}; + +	mmc@12210000 { +		#address-cells = <1>; +		#size-cells = <0>; +		compatible = "samsung,exynos5250-dwmmc"; +		reg = <0x12210000 0x1000>; +		interrupts = <0 76 0>; +	}; + +	mmc@12220000 { +		#address-cells = <1>; +		#size-cells = <0>; +		compatible = "samsung,exynos5250-dwmmc"; +		reg = <0x12220000 0x1000>; +		interrupts = <0 77 0>; +	}; + +	mmc@12230000 { +		#address-cells = <1>; +		#size-cells = <0>; +		compatible = "samsung,exynos5250-dwmmc"; +		reg = <0x12230000 0x1000>; +		interrupts = <0 78 0>; +	}; + +	gpio: gpio { +	};  }; diff --git a/arch/arm/include/asm/arch-am33xx/sys_proto.h b/arch/arm/include/asm/arch-am33xx/sys_proto.h index fedc67403..307ac2824 100644 --- a/arch/arm/include/asm/arch-am33xx/sys_proto.h +++ b/arch/arm/include/asm/arch-am33xx/sys_proto.h @@ -32,6 +32,7 @@ extern struct ctrl_stat *cstat;  u32 get_device_type(void);  void save_omap_boot_params(void);  void setup_clocks_for_console(void); +void mpu_pll_config_val(int mpull_m);  void ddr_pll_config(unsigned int ddrpll_M);  void sdelay(unsigned long); @@ -41,4 +42,7 @@ void gpmc_init(void);  void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base,  			u32 size);  void omap_nand_switch_ecc(uint32_t, uint32_t); + +void rtc32k_enable(void); +void uart_soft_reset(void);  #endif diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index f76e4897e..1ff7642d0 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -38,6 +38,7 @@  #define EXYNOS4_CLOCK_BASE		0x10030000  #define EXYNOS4_SYSTIMER_BASE		0x10050000  #define EXYNOS4_WATCHDOG_BASE		0x10060000 +#define EXYNOS4_TZPC_BASE		0x10110000  #define EXYNOS4_MIU_BASE		0x10600000  #define EXYNOS4_DMC0_BASE		0x10400000  #define EXYNOS4_DMC1_BASE		0x10410000 @@ -74,6 +75,7 @@  #define EXYNOS4X12_CLOCK_BASE		0x10030000  #define EXYNOS4X12_SYSTIMER_BASE	0x10050000  #define EXYNOS4X12_WATCHDOG_BASE	0x10060000 +#define EXYNOS4X12_TZPC_BASE		0x10110000  #define EXYNOS4X12_DMC0_BASE		0x10600000  #define EXYNOS4X12_DMC1_BASE		0x10610000  #define EXYNOS4X12_GPIO_PART4_BASE	0x106E0000 @@ -107,6 +109,7 @@  #define EXYNOS5_POWER_BASE		0x10040000  #define EXYNOS5_SWRESET			0x10040400  #define EXYNOS5_SYSREG_BASE		0x10050000 +#define EXYNOS5_TZPC_BASE		0x10100000  #define EXYNOS5_WATCHDOG_BASE		0x101D0000  #define EXYNOS5_ACE_SFR_BASE            0x10830000  #define EXYNOS5_DMC_PHY0_BASE		0x10C00000 @@ -175,7 +178,7 @@ static inline char *s5p_get_cpu_name(void)  }  #define IS_SAMSUNG_TYPE(type, id)			\ -static inline int cpu_is_##type(void)			\ +static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \  {							\  	return (s5p_cpu_id >> 12) == id;		\  } @@ -184,7 +187,8 @@ IS_SAMSUNG_TYPE(exynos4, 0x4)  IS_SAMSUNG_TYPE(exynos5, 0x5)  #define IS_EXYNOS_TYPE(type, id)			\ -static inline int proid_is_##type(void)			\ +static inline int __attribute__((no_instrument_function)) \ +	proid_is_##type(void)				\  {							\  	return s5p_cpu_id == id;			\  } @@ -194,9 +198,10 @@ IS_EXYNOS_TYPE(exynos4412, 0x4412)  IS_EXYNOS_TYPE(exynos5250, 0x5250)  #define SAMSUNG_BASE(device, base)				\ -static inline unsigned int samsung_get_base_##device(void)	\ +static inline unsigned int __attribute__((no_instrument_function)) \ +	samsung_get_base_##device(void) \  {								\ -	if (cpu_is_exynos4()) {					\ +	if (cpu_is_exynos4()) {				\  		if (proid_is_exynos4412())			\  			return EXYNOS4X12_##base;		\  		return EXYNOS4_##base;				\ @@ -233,6 +238,7 @@ SAMSUNG_BASE(watchdog, WATCHDOG_BASE)  SAMSUNG_BASE(power, POWER_BASE)  SAMSUNG_BASE(spi, SPI_BASE)  SAMSUNG_BASE(spi_isp, SPI_ISP_BASE) +SAMSUNG_BASE(tzpc, TZPC_BASE)  #endif  #endif	/* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/dwmmc.h b/arch/arm/include/asm/arch-exynos/dwmmc.h index 8acdf9b72..3b147b86e 100644 --- a/arch/arm/include/asm/arch-exynos/dwmmc.h +++ b/arch/arm/include/asm/arch-exynos/dwmmc.h @@ -27,10 +27,7 @@  #define DWMCI_SET_DRV_CLK(x)	((x) << 16)  #define DWMCI_SET_DIV_RATIO(x)	((x) << 24) -int exynos_dwmci_init(u32 regbase, int bus_width, int index); - -static inline unsigned int exynos_dwmmc_init(int index, int bus_width) -{ -	unsigned int base = samsung_get_base_mmc() + (0x10000 * index); -	return exynos_dwmci_init(base, bus_width, index); -} +#ifdef CONFIG_OF_CONTROL +int exynos_dwmmc_init(const void *blob); +#endif +int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel); diff --git a/arch/arm/include/asm/arch-exynos/tmu.h b/arch/arm/include/asm/arch-exynos/tmu.h index 7e0158efb..cad35694f 100644 --- a/arch/arm/include/asm/arch-exynos/tmu.h +++ b/arch/arm/include/asm/arch-exynos/tmu.h @@ -21,38 +21,30 @@  #define __ASM_ARCH_TMU_H  struct exynos5_tmu_reg { -	unsigned triminfo; -	unsigned rsvd1; -	unsigned rsvd2; -	unsigned rsvd3; -	unsigned rsvd4; -	unsigned triminfo_control; -	unsigned rsvd5; -	unsigned rsvd6; -	unsigned tmu_control; -	unsigned rsvd7; -	unsigned tmu_status; -	unsigned sampling_internal; -	unsigned counter_value0; -	unsigned counter_value1; -	unsigned rsvd8; -	unsigned rsvd9; -	unsigned current_temp; -	unsigned rsvd10; -	unsigned rsvd11; -	unsigned rsvd12; -	unsigned threshold_temp_rise; -	unsigned threshold_temp_fall; -	unsigned rsvd13; -	unsigned rsvd14; -	unsigned past_temp3_0; -	unsigned past_temp7_4; -	unsigned past_temp11_8; -	unsigned past_temp15_12; -	unsigned inten; -	unsigned intstat; -	unsigned intclear; -	unsigned rsvd15; -	unsigned emul_con; +	u32 triminfo; +	u32 rsvd1[4]; +	u32 triminfo_control; +	u32 rsvd5[2]; +	u32 tmu_control; +	u32 rsvd7; +	u32 tmu_status; +	u32 sampling_internal; +	u32 counter_value0; +	u32 counter_value1; +	u32 rsvd8[2]; +	u32 current_temp; +	u32 rsvd10[3]; +	u32 threshold_temp_rise; +	u32 threshold_temp_fall; +	u32 rsvd13[2]; +	u32 past_temp3_0; +	u32 past_temp7_4; +	u32 past_temp11_8; +	u32 past_temp15_12; +	u32 inten; +	u32 intstat; +	u32 intclear; +	u32 rsvd15; +	u32 emul_con;  };  #endif /* __ASM_ARCH_TMU_H */ diff --git a/arch/arm/include/asm/arch-exynos/tzpc.h b/arch/arm/include/asm/arch-exynos/tzpc.h index c5eb4b1cc..4d9c3a32f 100644 --- a/arch/arm/include/asm/arch-exynos/tzpc.h +++ b/arch/arm/include/asm/arch-exynos/tzpc.h @@ -47,6 +47,26 @@ struct exynos_tzpc {  	unsigned int pcellid2;  	unsigned int pcellid3;  }; + +#define EXYNOS4_NR_TZPC_BANKS		6 +#define EXYNOS5_NR_TZPC_BANKS		10 + +/* TZPC : Register Offsets */ +#define TZPC_BASE_OFFSET		0x10000 + +/* + * TZPC Register Value : + * R0SIZE: 0x0 : Size of secured ram + */ +#define R0SIZE			0x0 + +/* + * TZPC Decode Protection Register Value : + * DECPROTXSET: 0xFF : Set Decode region to non-secure + */ +#define DECPROTXSET		0xFF +void tzpc_init(void); +  #endif  #endif diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 8ad9f66a5..9ecafb272 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -43,7 +43,7 @@ SOBJS-y += relocate.o  ifndef CONFIG_SYS_GENERIC_BOARD  COBJS-y	+= board.o  endif -COBJS-y += bss.o +COBJS-y += sections.o  COBJS-y	+= bootm.o  COBJS-$(CONFIG_OF_LIBFDT) += bootm-fdt.o diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 1b6e0ace4..b22fbc998 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -68,12 +68,19 @@ void arch_lmb_reserve(struct lmb *lmb)  		    gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);  } -static void announce_and_cleanup(void) +/** + * announce_and_cleanup() - Print message and prepare for kernel boot + * + * @fake: non-zero to do everything except actually boot + */ +static void announce_and_cleanup(int fake)  { -	printf("\nStarting kernel ...\n\n"); +	printf("\nStarting kernel ...%s\n\n", fake ? +		"(fake run for tracing)" : "");  	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");  #ifdef CONFIG_BOOTSTAGE_FDT -	bootstage_fdt_add_report(); +	if (flag == BOOTM_STATE_OS_FAKE_GO) +		bootstage_fdt_add_report();  #endif  #ifdef CONFIG_BOOTSTAGE_REPORT  	bootstage_report(); @@ -225,12 +232,13 @@ static void boot_prep_linux(bootm_headers_t *images)  }  /* Subcommand: GO */ -static void boot_jump_linux(bootm_headers_t *images) +static void boot_jump_linux(bootm_headers_t *images, int flag)  {  	unsigned long machid = gd->bd->bi_arch_number;  	char *s;  	void (*kernel_entry)(int zero, int arch, uint params);  	unsigned long r2; +	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);  	kernel_entry = (void (*)(int, int, uint))images->ep; @@ -243,14 +251,15 @@ static void boot_jump_linux(bootm_headers_t *images)  	debug("## Transferring control to Linux (at address %08lx)" \  		"...\n", (ulong) kernel_entry);  	bootstage_mark(BOOTSTAGE_ID_RUN_OS); -	announce_and_cleanup(); +	announce_and_cleanup(fake);  	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)  		r2 = (unsigned long)images->ft_addr;  	else  		r2 = gd->bd->bi_boot_params; -	kernel_entry(0, machid, r2); +	if (!fake) +		kernel_entry(0, machid, r2);  }  /* Main Entry point for arm bootm implementation @@ -270,13 +279,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)  		return 0;  	} -	if (flag & BOOTM_STATE_OS_GO) { -		boot_jump_linux(images); +	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { +		boot_jump_linux(images, flag);  		return 0;  	}  	boot_prep_linux(images); -	boot_jump_linux(images); +	boot_jump_linux(images, flag);  	return 0;  } diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S index 4446da94c..949b9e802 100644 --- a/arch/arm/lib/relocate.S +++ b/arch/arm/lib/relocate.S @@ -37,56 +37,34 @@   */  ENTRY(relocate_code) -	mov	r6, r0	/* save addr of destination */ - -	ldr	r0, =_start		/* r0 <- SRC &_start */ -	subs	r9, r6, r0		/* r9 <- relocation offset */ +	ldr	r1, =__image_copy_start	/* r1 <- SRC &__image_copy_start */ +	subs	r9, r0, r1		/* r9 <- relocation offset */  	beq	relocate_done		/* skip relocation */ -	mov	r1, r6			/* r1 <- scratch for copy loop */ -	adr	r7, relocate_code	/* r7 <- SRC &relocate_code */ -	ldr	r3, _image_copy_end_ofs	/* r3 <- __image_copy_end local ofs */ -	add	r2, r7, r3		/* r2 <- SRC &__image_copy_end */ +	ldr	r2, =__image_copy_end	/* r2 <- SRC &__image_copy_end */  copy_loop: -	ldmia	r0!, {r10-r11}		/* copy from source address [r0]    */ -	stmia	r1!, {r10-r11}		/* copy to   target address [r1]    */ -	cmp	r0, r2			/* until source end address [r2]    */ +	ldmia	r1!, {r10-r11}		/* copy from source address [r1]    */ +	stmia	r0!, {r10-r11}		/* copy to   target address [r0]    */ +	cmp	r1, r2			/* until source end address [r2]    */  	blo	copy_loop  	/*  	 * fix .rel.dyn relocations  	 */ -	ldr	r10, _dynsym_start_ofs	/* r10 <- __dynsym_start local ofs */ -	add	r10, r10, r7		/* r10 <- SRC &__dynsym_start */ -	ldr	r2, _rel_dyn_start_ofs	/* r2 <- __rel_dyn_start local ofs */ -	add	r2, r2, r7		/* r2 <- SRC &__rel_dyn_start */ -	ldr	r3, _rel_dyn_end_ofs	/* r3 <- __rel_dyn_end local ofs */ -	add	r3, r3, r7		/* r3 <- SRC &__rel_dyn_end */ +	ldr	r2, =__rel_dyn_start	/* r2 <- SRC &__rel_dyn_start */ +	ldr	r3, =__rel_dyn_end	/* r3 <- SRC &__rel_dyn_end */  fixloop: -	ldr	r0, [r2]		/* r0 <- SRC location to fix up */ -	add	r0, r0, r9		/* r0 <- DST location to fix up */ -	ldr	r1, [r2, #4] -	and	r7, r1, #0xff -	cmp	r7, #23			/* relative fixup? */ -	beq	fixrel -	cmp	r7, #2			/* absolute fixup? */ -	beq	fixabs -	/* ignore unknown type of fixup */ -	b	fixnext -fixabs: -	/* absolute fix: set location to (offset) symbol value */ -	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */ -	add	r1, r10, r1		/* r1 <- address of symbol in table */ -	ldr	r1, [r1, #4]		/* r1 <- symbol value */ -	add	r1, r1, r9		/* r1 <- relocated sym addr */ -	b	fixnext -fixrel: +	ldmia	r2!, {r0-r1}		/* (r0,r1) <- (SRC location,fixup) */ +	and	r1, r1, #0xff +	cmp	r1, #23			/* relative fixup? */ +	bne	fixnext +  	/* relative fix: increase location by offset */ +	add	r0, r0, r9  	ldr	r1, [r0]  	add	r1, r1, r9 -fixnext:  	str	r1, [r0] -	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */ +fixnext:  	cmp	r2, r3  	blo	fixloop @@ -100,13 +78,4 @@ relocate_done:          bx        lr  #endif -_image_copy_end_ofs: -	.word __image_copy_end - relocate_code -_rel_dyn_start_ofs: -	.word __rel_dyn_start - relocate_code -_rel_dyn_end_ofs: -	.word __rel_dyn_end - relocate_code -_dynsym_start_ofs: -	.word __dynsym_start - relocate_code -  ENDPROC(relocate_code) diff --git a/arch/arm/lib/bss.c b/arch/arm/lib/sections.c index 99eda5913..5921dd8d6 100644 --- a/arch/arm/lib/bss.c +++ b/arch/arm/lib/sections.c @@ -35,5 +35,9 @@   * aliasing warnings.   */ -char __bss_start[0] __attribute__((used, section(".__bss_start"))); -char __bss_end[0] __attribute__((used, section(".__bss_end"))); +char __bss_start[0] __attribute__((section(".__bss_start"))); +char __bss_end[0] __attribute__((section(".__bss_end"))); +char __image_copy_start[0] __attribute__((section(".__image_copy_start"))); +char __image_copy_end[0] __attribute__((section(".__image_copy_end"))); +char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start"))); +char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end"))); diff --git a/arch/m68k/cpu/mcf5445x/speed.c b/arch/m68k/cpu/mcf5445x/speed.c index aa73e1f02..0276d4d82 100644 --- a/arch/m68k/cpu/mcf5445x/speed.c +++ b/arch/m68k/cpu/mcf5445x/speed.c @@ -122,17 +122,17 @@ void setup_5441x_clocks(void)  	vco =  ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) *  		CONFIG_SYS_INPUT_CLKSRC; -	gd->vco_clk = vco; +	gd->arch.vco_clk = vco; -	gd->inp_clk = CONFIG_SYS_INPUT_CLKSRC;	/* Input clock */ +	gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC;	/* Input clock */  	pdr = in_be32(&pll->pdr);  	temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1;  	gd->cpu_clk = vco / temp;	/* cpu clock */ -	gd->flb_clk = vco / temp;	/* FlexBus clock */ -	gd->flb_clk >>= 1; +	gd->arch.flb_clk = vco / temp;	/* FlexBus clock */ +	gd->arch.flb_clk >>= 1;  	if (in_be16(ccm->misccr2) & 2)		/* fsys/4 */ -		gd->flb_clk >>= 1; +		gd->arch.flb_clk >>= 1;  	temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1;  	gd->bus_clk = vco / temp;	/* bus clock */ diff --git a/arch/m68k/include/asm/m5235.h b/arch/m68k/include/asm/m5235.h index 71a40d33d..a573f1cf0 100644 --- a/arch/m68k/include/asm/m5235.h +++ b/arch/m68k/include/asm/m5235.h @@ -134,7 +134,7 @@  #define SDRAMC_DCR_RC(x)		(((x)&0xFF)<<8)  /* Bit definitions and macros for SDRAMC_DARCn */ -#define SDRAMC_DARCn_BA(x)		(((x)&0xFFFC)<<18) +#define SDRAMC_DARCn_BA(x)		((x)&0xFFFC0000)  #define SDRAMC_DARCn_RE			(0x00008000)  #define SDRAMC_DARCn_CASL_MASK		(0x00003000)  #define SDRAMC_DARCn_CASL_C0		(0x00000000) diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index b2e306836..efc9fccc1 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -403,14 +403,14 @@ void board_init_r (gd_t *id, ulong dest_addr)  	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */ -	debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr); -  	WATCHDOG_RESET ();  	gd->reloc_off =  dest_addr - CONFIG_SYS_MONITOR_BASE;  	serial_initialize(); +	debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); +  	monitor_flash_len = (ulong)&__init_end - dest_addr;  #if defined(CONFIG_NEEDS_MANUAL_RELOC) diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index 384270900..b328f9497 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -62,8 +62,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],  	bootstage_mark(BOOTSTAGE_ID_RUN_OS); -	if (!of_flat_tree && argc > 3) -		of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); +	if (!of_flat_tree && argc > 1) +		of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);  	/* fixup the initrd now that we know where it should be */  	if (images->rd_start && images->rd_end && of_flat_tree) diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c index f32be5210..114e146d9 100644 --- a/arch/nios2/lib/bootm.c +++ b/arch/nios2/lib/bootm.c @@ -40,8 +40,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima  	if (images->ft_len)  		of_flat_tree = images->ft_addr;  #endif -	if (!of_flat_tree && argc > 3) -		of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); +	if (!of_flat_tree && argc > 1) +		of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);  	if (of_flat_tree)  		initrd_end = (ulong)of_flat_tree; diff --git a/arch/openrisc/lib/bootm.c b/arch/openrisc/lib/bootm.c index 2c5d9aea9..7f716b859 100644 --- a/arch/openrisc/lib/bootm.c +++ b/arch/openrisc/lib/bootm.c @@ -63,8 +63,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],  	show_boot_progress(15); -	if (!of_flat_tree && argc > 3) -		of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); +	if (!of_flat_tree && argc > 1) +		of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16);  #ifdef DEBUG  	printf("## Transferring control to Linux (at address 0x%08lx) " \  				"ramdisk 0x%08lx, FDT 0x%08lx...\n", diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile index 2318064a4..4669883a3 100644 --- a/arch/powerpc/cpu/mpc85xx/Makefile +++ b/arch/powerpc/cpu/mpc85xx/Makefile @@ -73,6 +73,7 @@ COBJS-$(CONFIG_P1014)	+= ddr-gen3.o  COBJS-$(CONFIG_P1020)	+= ddr-gen3.o  COBJS-$(CONFIG_P1021)	+= ddr-gen3.o  COBJS-$(CONFIG_P1022)	+= ddr-gen3.o +COBJS-$(CONFIG_P1023)	+= ddr-gen3.o  COBJS-$(CONFIG_P1024)	+= ddr-gen3.o  COBJS-$(CONFIG_P1025)	+= ddr-gen3.o  COBJS-$(CONFIG_P2010)	+= ddr-gen3.o diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c index 422782ca8..a7ed87769 100644 --- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c +++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -258,6 +258,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  #ifdef CONFIG_SYS_FSL_ERRATUM_USB14  	puts("Work-around for Erratum USB14 enabled\n");  #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006593 +	puts("Work-around for Erratum A006593 enabled\n"); +#endif  	return 0;  } diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 6ce483e17..fbee75390 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -121,16 +121,16 @@ int checkcpu (void)  	switch(ver) {  	case PVR_VER_E500_V1:  	case PVR_VER_E500_V2: -		puts("E500"); +		puts("e500");  		break;  	case PVR_VER_E500MC: -		puts("E500MC"); +		puts("e500mc");  		break;  	case PVR_VER_E5500: -		puts("E5500"); +		puts("e5500");  		break;  	case PVR_VER_E6500: -		puts("E6500"); +		puts("e6500");  		break;  	default:  		puts("Unknown"); @@ -341,7 +341,7 @@ phys_size_t initdram(int board_type)  #if defined(CONFIG_SPD_EEPROM) || defined(CONFIG_DDR_SPD)  	return fsl_ddr_sdram_size();  #else -	return CONFIG_SYS_SDRAM_SIZE * 1024 * 1024; +	return (phys_size_t)CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;  #endif  }  #else /* CONFIG_SYS_RAMBOOT */ diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index 4067f0537..3c8f59cdb 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -172,6 +172,9 @@ static void enable_cpc(void)  #ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A003  		setbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_DATA_ECC_SCRUB_DIS);  #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006593 +		setbits_be32(&cpc->cpchdbcr0, 1 << (31 - 21)); +#endif  		out_be32(&cpc->cpccsr0, CPC_CSR0_CE | CPC_CSR0_PE);  		/* Read back to sync write */ @@ -564,7 +567,7 @@ skip_l2:  #ifdef CONFIG_SYS_SRIO  	srio_init(); -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER  +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  	char *s = getenv("bootmaster");  	if (s) {  		if (!strcmp(s, "SRIO1")) { diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c index 234fde484..837c034be 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c @@ -25,7 +25,7 @@  DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND  void setup_ifc(void)  {  	struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR; @@ -99,7 +99,7 @@ void cpu_init_early_f(void)  #ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549  	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);  #endif -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND  	ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;  	u32  *dst, *src;  	void (*setup_ifc_sram)(void); @@ -138,7 +138,7 @@ void cpu_init_early_f(void)   * Work Around for IFC Erratum A003399, issue will hit only when execution   * from NOR Flash   */ -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND  #define SRAM_BASE_ADDR	(0x00000000)  	/* TLB for SRAM */  	mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9); @@ -180,5 +180,9 @@ void cpu_init_early_f(void)  	invalidate_tlb(1); +#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB) && !defined(CONFIG_SPL_BUILD) && !defined(CONFIG_NAND_SPL) +	disable_tlb(CONFIG_SYS_PPC_E500_DEBUG_TLB); +#endif +  	init_tlbs();  } diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c index 288f7b286..bb95f3d50 100644 --- a/arch/powerpc/cpu/mpc85xx/fdt.c +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -663,7 +663,7 @@ void ft_cpu_setup(void *blob, bd_t *bd)  #ifdef CONFIG_FSL_CORENET  	do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-1.0",  		"clock-frequency", CONFIG_SYS_CLK_FREQ, 1); -	do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-2", +	do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-2.0",  		"clock-frequency", CONFIG_SYS_CLK_FREQ, 1);  	do_fixup_by_compat_u32(blob, "fsl,mpic",  		"clock-frequency", get_bus_freq(0)/2, 1); diff --git a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c index 6dadeb8ca..ec96e81ed 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c @@ -228,7 +228,7 @@ void fsl_serdes_init(void)  		break;  	} -	if (srds1_io_sel > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds1_io_sel >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[SRDS1_IO_SEL] = %d\n", srds1_io_sel);  		return;  	} @@ -237,7 +237,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds2_io_sel > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds2_io_sel >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[SRDS2_IO_SEL] = %d\n", srds2_io_sel);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c index 7c490972a..3483366e6 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c @@ -68,7 +68,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} @@ -77,7 +77,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c index 76288cd56..c9eea15d3 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c @@ -53,7 +53,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL] = %x\n", srds1_cfg); -	if (srds1_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds1_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL] = %d\n", srds1_cfg);  		return ;  	} diff --git a/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c index 258263739..49a029062 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c @@ -53,7 +53,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c index f480c2609..7af6aff25 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c @@ -62,7 +62,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c index 2ff5d9a06..fcccb52b6 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c @@ -57,7 +57,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p1010_serdes.c b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c index e8a0387ca..1f7dba0d6 100644 --- a/arch/powerpc/cpu/mpc85xx/p1010_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c @@ -54,7 +54,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} @@ -63,7 +63,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p1021_serdes.c b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c index 1849c1642..d6d2696e0 100644 --- a/arch/powerpc/cpu/mpc85xx/p1021_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c @@ -73,7 +73,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p1022_serdes.c b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c index e4c9c2210..ed4992053 100644 --- a/arch/powerpc/cpu/mpc85xx/p1022_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c @@ -93,7 +93,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} @@ -102,7 +102,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p1023_serdes.c b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c index c8ab5d6f3..0b4ae90c2 100644 --- a/arch/powerpc/cpu/mpc85xx/p1023_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c @@ -41,7 +41,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p2020_serdes.c b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c index 389ff6bd2..01af33370 100644 --- a/arch/powerpc/cpu/mpc85xx/p2020_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c @@ -61,7 +61,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc85xx/p2041_serdes.c b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c index eec4ffe51..87335c944 100644 --- a/arch/powerpc/cpu/mpc85xx/p2041_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c @@ -90,7 +90,7 @@ int is_serdes_prtcl_valid(u32 prtcl)  	u32 svr = get_svr();  	u32 ver = SVR_SOC_VER(svr); -	if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))  		return 0;  	/* P2040[e] does not support XAUI */ diff --git a/arch/powerpc/cpu/mpc85xx/p3041_serdes.c b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c index fba9ff245..a36dcd542 100644 --- a/arch/powerpc/cpu/mpc85xx/p3041_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c @@ -139,7 +139,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane)  int is_serdes_prtcl_valid(u32 prtcl) {  	int i; -	if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))  		return 0;  	for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p4080_serdes.c b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c index 87bd79529..94ec44503 100644 --- a/arch/powerpc/cpu/mpc85xx/p4080_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c @@ -86,7 +86,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane)  int is_serdes_prtcl_valid(u32 prtcl) {  	int i; -	if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))  		return 0;  	for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p5020_serdes.c b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c index fba9ff245..a36dcd542 100644 --- a/arch/powerpc/cpu/mpc85xx/p5020_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c @@ -139,7 +139,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane)  int is_serdes_prtcl_valid(u32 prtcl) {  	int i; -	if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))  		return 0;  	for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p5040_serdes.c b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c index 890b88e4e..d646e8561 100644 --- a/arch/powerpc/cpu/mpc85xx/p5040_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c @@ -105,7 +105,7 @@ int is_serdes_prtcl_valid(u32 prtcl)  {  	int i; -	if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))  		return 0;  	for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S index 4f0480b76..2657982a4 100644 --- a/arch/powerpc/cpu/mpc85xx/start.S +++ b/arch/powerpc/cpu/mpc85xx/start.S @@ -1795,7 +1795,7 @@ clear_bss:  	stw	r0,0(r3)  	addi	r3,r3,4  	cmplw	0,r3,r4 -	bne	5b +	blt	5b  6:  	mr	r3,r9		/* Init Data pointer		*/ diff --git a/arch/powerpc/cpu/mpc85xx/t1040_serdes.c b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c index 8261e0347..19add9f96 100644 --- a/arch/powerpc/cpu/mpc85xx/t1040_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c @@ -81,7 +81,7 @@ int is_serdes_prtcl_valid(int serdes, u32 prtcl)  {  	int i; -	if (prtcl > (ARRAY_SIZE(serdes_cfg_tbl[serdes]))) +	if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl[serdes]))  		return 0;  	for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds index f2b7bffda..20284ed5a 100644 --- a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds +++ b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds @@ -26,6 +26,13 @@  #include "config.h"	/* CONFIG_BOARDDIR */  OUTPUT_ARCH(powerpc) +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC +PHDRS +{ +	text PT_LOAD; +	bss PT_LOAD; +} +#endif  SECTIONS  {  	. = CONFIG_SPL_TEXT_BASE; @@ -60,7 +67,7 @@ SECTIONS  #if defined(CONFIG_FSL_IFC) /* Restrict bootpg at 4K boundry for IFC */  	.bootpg ADDR(.text) + 0x1000 :  	{ -		start.o	(.bootpg) +		arch/powerpc/cpu/mpc85xx/start.o (.bootpg)  	}  #define RESET_VECTOR_OFFSET 0x1ffc /* IFC has 8K sram */  #elif defined(CONFIG_FSL_ELBC) @@ -68,9 +75,16 @@ SECTIONS  #else  #error unknown NAND controller  #endif +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC +	.bootpg ADDR(.text) - 0x1000 : +	{ +		KEEP(*(.bootpg)) +	} :text = 0xffff +#else  	.resetvec ADDR(.text) + RESET_VECTOR_OFFSET : {  		KEEP(*(.resetvec))  	} = 0xffff +#endif  	/*  	 * Make sure that the bss segment isn't linked at 0x0, otherwise its @@ -78,10 +92,12 @@ SECTIONS  	 */  	. |= 0x10; +	. = ALIGN(4);  	__bss_start = .;  	.bss : {  		*(.sbss*)  		*(.bss*)  	} +	. = ALIGN(4);  	__bss_end = .;  } diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds index 0503dce5a..2643563d4 100644 --- a/arch/powerpc/cpu/mpc85xx/u-boot.lds +++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds @@ -95,6 +95,13 @@ SECTIONS    . = ALIGN(256);    __init_end = .; +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC +  .bootpg ADDR(.text) - 0x1000 : +  { +    KEEP(arch/powerpc/cpu/mpc85xx/start.o (.bootpg)) +  } :text = 0xffff +  . = ADDR(.text) + 0x80000; +#else    .bootpg RESET_VECTOR_ADDRESS - 0xffc :    {      arch/powerpc/cpu/mpc85xx/start.o	(.bootpg) @@ -117,6 +124,7 @@ SECTIONS  #if (RESET_VECTOR_ADDRESS == 0xfffffffc)    . |= 0x10;  #endif +#endif    __bss_start = .;    .bss (NOLOAD)       : diff --git a/arch/powerpc/cpu/mpc86xx/cpu.c b/arch/powerpc/cpu/mpc86xx/cpu.c index c553415b5..5ed3eb24f 100644 --- a/arch/powerpc/cpu/mpc86xx/cpu.c +++ b/arch/powerpc/cpu/mpc86xx/cpu.c @@ -78,7 +78,7 @@ checkcpu(void)  	major = PVR_E600_MAJ(pvr);  	minor = PVR_E600_MIN(pvr); -	printf("E600 Core %d", (msscr0 & 0x20) ? 1 : 0 ); +	printf("e600 Core %d", (msscr0 & 0x20) ? 1 : 0);  	if (gur->pordevsr & MPC86xx_PORDEVSR_CORE1TE)  		puts("\n    Core1Translation Enabled");  	debug(" (MSSCR0=%x, PORDEVSR=%x)", msscr0, gur->pordevsr); diff --git a/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c index 0dc1975bf..0342e3465 100644 --- a/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c +++ b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c @@ -64,7 +64,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} @@ -73,7 +73,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c index 3ae9069f1..21c5ddbfa 100644 --- a/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c +++ b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c @@ -73,7 +73,7 @@ void fsl_serdes_init(void)  	debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); -	if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} @@ -82,7 +82,7 @@ void fsl_serdes_init(void)  		serdes1_prtcl_map |= (1 << lane_prtcl);  	} -	if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { +	if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {  		printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);  		return;  	} diff --git a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c index 56b319f5d..4e8a4415f 100644 --- a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c +++ b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c @@ -26,7 +26,7 @@ void print_ifc_regs(void)  	int i, j;  	printf("IFC Controller Registers\n"); -	for (i = 0; i < FSL_IFC_BANK_COUNT; i++) { +	for (i = 0; i < CONFIG_SYS_FSL_IFC_BANK_COUNT; i++) {  		printf("CSPR%d:0x%08X\tAMASK%d:0x%08X\tCSOR%d:0x%08X\n",  			i, get_ifc_cspr(i), i, get_ifc_amask(i),  			i, get_ifc_csor(i)); @@ -43,7 +43,7 @@ void init_early_memctl_regs(void)  	set_ifc_ftim(IFC_CS0, IFC_FTIM2, CONFIG_SYS_CS0_FTIM2);  	set_ifc_ftim(IFC_CS0, IFC_FTIM3, CONFIG_SYS_CS0_FTIM3); -#if !defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) || defined(CONFIG_SYS_RAMBOOT) +#ifndef CONFIG_A003399_NOR_WORKAROUND  #ifdef CONFIG_SYS_CSPR0_EXT  	set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT);  #endif @@ -94,4 +94,60 @@ void init_early_memctl_regs(void)  	set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3);  	set_ifc_csor(IFC_CS3, CONFIG_SYS_CSOR3);  #endif + +#ifdef CONFIG_SYS_CSPR4_EXT +	set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT); +#endif +#if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4) +	set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0); +	set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1); +	set_ifc_ftim(IFC_CS4, IFC_FTIM2, CONFIG_SYS_CS4_FTIM2); +	set_ifc_ftim(IFC_CS4, IFC_FTIM3, CONFIG_SYS_CS4_FTIM3); + +	set_ifc_cspr(IFC_CS4, CONFIG_SYS_CSPR4); +	set_ifc_amask(IFC_CS4, CONFIG_SYS_AMASK4); +	set_ifc_csor(IFC_CS4, CONFIG_SYS_CSOR4); +#endif + +#ifdef CONFIG_SYS_CSPR5_EXT +	set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT); +#endif +#if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5) +	set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0); +	set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1); +	set_ifc_ftim(IFC_CS5, IFC_FTIM2, CONFIG_SYS_CS5_FTIM2); +	set_ifc_ftim(IFC_CS5, IFC_FTIM3, CONFIG_SYS_CS5_FTIM3); + +	set_ifc_cspr(IFC_CS5, CONFIG_SYS_CSPR5); +	set_ifc_amask(IFC_CS5, CONFIG_SYS_AMASK5); +	set_ifc_csor(IFC_CS5, CONFIG_SYS_CSOR5); +#endif + +#ifdef CONFIG_SYS_CSPR6_EXT +	set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT); +#endif +#if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6) +	set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0); +	set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1); +	set_ifc_ftim(IFC_CS6, IFC_FTIM2, CONFIG_SYS_CS6_FTIM2); +	set_ifc_ftim(IFC_CS6, IFC_FTIM3, CONFIG_SYS_CS6_FTIM3); + +	set_ifc_cspr(IFC_CS6, CONFIG_SYS_CSPR6); +	set_ifc_amask(IFC_CS6, CONFIG_SYS_AMASK6); +	set_ifc_csor(IFC_CS6, CONFIG_SYS_CSOR6); +#endif + +#ifdef CONFIG_SYS_CSPR7_EXT +	set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT); +#endif +#if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7) +	set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0); +	set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1); +	set_ifc_ftim(IFC_CS7, IFC_FTIM2, CONFIG_SYS_CS7_FTIM2); +	set_ifc_ftim(IFC_CS7, IFC_FTIM3, CONFIG_SYS_CS7_FTIM3); + +	set_ifc_cspr(IFC_CS7, CONFIG_SYS_CSPR7); +	set_ifc_amask(IFC_CS7, CONFIG_SYS_AMASK7); +	set_ifc_csor(IFC_CS7, CONFIG_SYS_CSOR7); +#endif  } diff --git a/arch/powerpc/cpu/mpc8xxx/srio.c b/arch/powerpc/cpu/mpc8xxx/srio.c index 6e6f7dcc3..90d1065de 100644 --- a/arch/powerpc/cpu/mpc8xxx/srio.c +++ b/arch/powerpc/cpu/mpc8xxx/srio.c @@ -24,7 +24,7 @@  #include <asm/fsl_srio.h>  #include <asm/errno.h> -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  #define SRIO_PORT_ACCEPT_ALL 0x10000001  #define SRIO_IB_ATMU_AR 0x80f55000  #define SRIO_OB_ATMU_AR_MAINT 0x80077000 @@ -299,7 +299,7 @@ void srio_init(void)  	}  } -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  void srio_boot_master(int port)  {  	struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR; diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h index 1009a31b3..1d46b1423 100644 --- a/arch/powerpc/include/asm/config_mpc85xx.h +++ b/arch/powerpc/include/asm/config_mpc85xx.h @@ -139,6 +139,7 @@  #define CONFIG_SYS_FSL_SEC_COMPAT	4  #define CONFIG_SYS_FSL_ERRATUM_ESDHC111  #define CONFIG_NUM_DDR_CONTROLLERS	1 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT	4  #define CONFIG_SYS_CCSRBAR_DEFAULT	0xff700000  #define CONFIG_SYS_FSL_PCIE_COMPAT	"fsl,qoriq-pcie-v2.2"  #define CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY @@ -337,7 +338,6 @@  #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER  #define CONFIG_SYS_FSL_SRIO_MAX_PORTS	2  #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM	9  #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM	5 @@ -371,7 +371,6 @@  #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER  #define CONFIG_SYS_FSL_SRIO_MAX_PORTS	2  #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM	9  #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM	5 @@ -413,7 +412,6 @@  #define CONFIG_SYS_P4080_ERRATUM_SERDES_A005  #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER  #define CONFIG_SYS_FSL_SRIO_MAX_PORTS	2  #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM	9  #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM	5 @@ -449,7 +447,6 @@  #define CONFIG_SYS_FSL_ERRATUM_USB14  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003  #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER  #define CONFIG_SYS_FSL_SRIO_MAX_PORTS	2  #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM	9  #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM	5 @@ -494,6 +491,9 @@  #define CONFIG_TSECV2  #define CONFIG_SYS_FSL_SEC_COMPAT	4  #define CONFIG_NUM_DDR_CONTROLLERS	1 +#define CONFIG_SYS_FSL_DSP_M2_RAM_ADDR	0xb0000000 +#define CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT	0xff600000 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT	3  #define CONFIG_SYS_CCSRBAR_DEFAULT	0xff700000  #define CONFIG_NAND_FSL_IFC  #define CONFIG_SYS_FSL_ERRATUM_ESDHC111 @@ -506,6 +506,7 @@  #define CONFIG_TSECV2  #define CONFIG_SYS_FSL_SEC_COMPAT	4  #define CONFIG_NUM_DDR_CONTROLLERS	2 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT	3  #define CONFIG_SYS_CCSRBAR_DEFAULT	0xff700000  #define CONFIG_NAND_FSL_IFC  #define CONFIG_SYS_FSL_ERRATUM_ESDHC111 @@ -541,6 +542,7 @@  #define CONFIG_SYS_FSL_SEC_COMPAT	4  #define CONFIG_SYS_NUM_FMAN		2  #define CONFIG_SYS_FSL_DDR_VER		FSL_DDR_VER_4_7 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT	8  #define CONFIG_SYS_FMAN_V3  #define CONFIG_SYS_FM_MURAM_SIZE	0x60000  #define CONFIG_SYS_FSL_TBCLK_DIV	16 @@ -553,6 +555,7 @@  #define CONFIG_SYS_FSL_ERRATUM_A004468  #define CONFIG_SYS_FSL_ERRATUM_A_004934  #define CONFIG_SYS_FSL_ERRATUM_A005871 +#define CONFIG_SYS_FSL_ERRATUM_A006593  #define CONFIG_SYS_CCSRBAR_DEFAULT	0xfe000000  #define CONFIG_SYS_FSL_PCI_VER_3_X @@ -566,6 +569,7 @@  #define CONFIG_SYS_FSL_SEC_COMPAT	4  #define CONFIG_SYS_NUM_FMAN		1  #define CONFIG_SYS_FSL_DDR_VER		FSL_DDR_VER_4_7 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT	4  #define CONFIG_SYS_FMAN_V3  #define CONFIG_SYS_FM_MURAM_SIZE	0x60000  #define CONFIG_SYS_FSL_TBCLK_DIV	16 @@ -573,6 +577,7 @@  #define CONFIG_SYS_FSL_USB1_PHY_ENABLE  #define CONFIG_SYS_FSL_ERRATUM_A_004934  #define CONFIG_SYS_FSL_ERRATUM_A005871 +#define CONFIG_SYS_FSL_ERRATUM_A006593  #define CONFIG_SYS_CCSRBAR_DEFAULT	0xfe000000  #ifdef CONFIG_PPC_B4860 diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h index ba41b73cc..3baf4ccba 100644 --- a/arch/powerpc/include/asm/fsl_ifc.h +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -21,6 +21,7 @@  #ifndef __ASM_PPC_FSL_IFC_H  #define __ASM_PPC_FSL_IFC_H +#ifdef CONFIG_FSL_IFC  #include <config.h>  #include <common.h> @@ -798,13 +799,15 @@ extern void init_early_memctl_regs(void);  #define set_ifc_ftim(i, j, v) \  			(out_be32(&(IFC_BASE_ADDR)->ftim_cs[i].ftim[j], v)) -#define FSL_IFC_BANK_COUNT	4 -  enum ifc_chip_sel {  	IFC_CS0,  	IFC_CS1,  	IFC_CS2,  	IFC_CS3, +	IFC_CS4, +	IFC_CS5, +	IFC_CS6, +	IFC_CS7,  };  enum ifc_ftims { @@ -907,6 +910,49 @@ struct fsl_ifc_gpcm {  	u32 res4[0x1F3];  }; +#ifdef CONFIG_SYS_FSL_IFC_BANK_COUNT +#if (CONFIG_SYS_FSL_IFC_BANK_COUNT <= 8) +#define IFC_CSPR_REG_LEN	148 +#define IFC_AMASK_REG_LEN	144 +#define IFC_CSOR_REG_LEN	144 +#define IFC_FTIM_REG_LEN	576 + +#define IFC_CSPR_USED_LEN	sizeof(struct fsl_ifc_cspr) * \ +					CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_AMASK_USED_LEN	sizeof(struct fsl_ifc_amask) * \ +					CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_CSOR_USED_LEN	sizeof(struct fsl_ifc_csor) * \ +					CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_FTIM_USED_LEN	sizeof(struct fsl_ifc_ftim) * \ +					CONFIG_SYS_FSL_IFC_BANK_COUNT +#else +#error IFC BANK count not vaild +#endif +#else +#error IFC BANK count not defined +#endif + +struct fsl_ifc_cspr { +	u32 cspr_ext; +	u32 cspr; +	u32 res; +}; + +struct fsl_ifc_amask { +	u32 amask; +	u32 res[0x2]; +}; + +struct fsl_ifc_csor { +	u32 csor; +	u32 csor_ext; +	u32 res; +}; + +struct fsl_ifc_ftim { +	u32 ftim[4]; +	u32 res[0x8]; +};  /*   * IFC Controller Registers @@ -914,44 +960,30 @@ struct fsl_ifc_gpcm {  struct fsl_ifc {  	u32 ifc_rev;  	u32 res1[0x2]; -	struct { -		u32 cspr_ext; -		u32 cspr; -		u32 res2; -	} cspr_cs[FSL_IFC_BANK_COUNT]; -	u32 res3[0x19]; -	struct { -		u32 amask; -		u32 res4[0x2]; -	} amask_cs[FSL_IFC_BANK_COUNT]; -	u32 res5[0x17]; -	struct { -		u32 csor_ext; -		u32 csor; -		u32 res6; -	} csor_cs[FSL_IFC_BANK_COUNT]; -	u32 res7[0x19]; -	struct { -		u32 ftim[4]; -		u32 res8[0x8]; -	} ftim_cs[FSL_IFC_BANK_COUNT]; -	u32 res9[0x60]; +	struct fsl_ifc_cspr cspr_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; +	u8 res2[IFC_CSPR_REG_LEN - IFC_CSPR_USED_LEN]; +	struct fsl_ifc_amask amask_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; +	u8 res3[IFC_AMASK_REG_LEN - IFC_AMASK_USED_LEN]; +	struct fsl_ifc_csor csor_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; +	u8 res4[IFC_CSOR_REG_LEN - IFC_CSOR_USED_LEN]; +	struct fsl_ifc_ftim ftim_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; +	u8 res5[IFC_FTIM_REG_LEN - IFC_FTIM_USED_LEN];  	u32 rb_stat; -	u32 res10[0x2]; +	u32 res6[0x2];  	u32 ifc_gcr; -	u32 res11[0x2]; +	u32 res7[0x2];  	u32 cm_evter_stat; -	u32 res12[0x2]; +	u32 res8[0x2];  	u32 cm_evter_en; -	u32 res13[0x2]; +	u32 res9[0x2];  	u32 cm_evter_intr_en; -	u32 res14[0x2]; +	u32 res10[0x2];  	u32 cm_erattr0;  	u32 cm_erattr1; -	u32 res15[0x2]; +	u32 res11[0x2];  	u32 ifc_ccr;  	u32 ifc_csr; -	u32 res16[0x2EB]; +	u32 res12[0x2EB];  	struct fsl_ifc_nand ifc_nand;  	struct fsl_ifc_nor ifc_nor;  	struct fsl_ifc_gpcm ifc_gpcm; @@ -961,6 +993,7 @@ struct fsl_ifc {  #undef CSPR_MSEL_NOR  #define CSPR_MSEL_NOR	CSPR_MSEL_GPCM  #endif +#endif /* CONFIG_FSL_IFC */  #endif /* __ASSEMBLY__ */  #endif /* __ASM_PPC_FSL_IFC_H */ diff --git a/arch/powerpc/include/asm/fsl_law.h b/arch/powerpc/include/asm/fsl_law.h index 90b264d35..bea163676 100644 --- a/arch/powerpc/include/asm/fsl_law.h +++ b/arch/powerpc/include/asm/fsl_law.h @@ -82,11 +82,16 @@ enum law_trgt_if {  #ifndef CONFIG_MPC8641  	LAW_TRGT_IF_PCIE_1 = 0x02,  #endif +#if defined(CONFIG_BSC9131) +	LAW_TRGT_IF_OCN_DSP = 0x03, +#else  #if !defined(CONFIG_MPC8572) && !defined(CONFIG_P2020)  	LAW_TRGT_IF_PCIE_3 = 0x03,  #endif +#endif  	LAW_TRGT_IF_LBC = 0x04,  	LAW_TRGT_IF_CCSR = 0x08, +	LAW_TRGT_IF_DSP_CCSR = 0x09,  	LAW_TRGT_IF_DDR_INTRLV = 0x0b,  	LAW_TRGT_IF_RIO = 0x0c,  	LAW_TRGT_IF_RIO_2 = 0x0d, diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h index 4052037f5..db70d048f 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -1839,11 +1839,13 @@ typedef struct ccsr_gur {  #define FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT	11  #define FSL_CORENET2_RCWSR4_SRDS4_PRTCL		0x000000f8  #define FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT	3 +#define FSL_CORENET_RCWSR6_BOOT_LOC	0x0f800000  #elif defined(CONFIG_PPC_B4860) || defined(CONFIG_PPC_B4420)  #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL	0xfe000000  #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT	25  #define FSL_CORENET2_RCWSR4_SRDS2_PRTCL	0x00ff0000  #define FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT	16 +#define FSL_CORENET_RCWSR6_BOOT_LOC	0x0f800000  #elif defined(CONFIG_PPC_T1040)  #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL	0xff000000  #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT	24 @@ -2160,7 +2162,7 @@ typedef struct ccsr_gur {  	u32	porbmsr;	/* POR boot mode status */  #define MPC85xx_PORBMSR_HA		0x00070000  #define MPC85xx_PORBMSR_HA_SHIFT	16 -#define MPC85XX_PORBMSR_ROMLOC_SHIFT	24 +#define MPC85xx_PORBMSR_ROMLOC_SHIFT	24  #define PORBMSR_ROMLOC_SPI	0x6  #define PORBMSR_ROMLOC_SDHC	0x7  #define PORBMSR_ROMLOC_NAND_2K	0x9 diff --git a/arch/powerpc/lib/bootm.c b/arch/powerpc/lib/bootm.c index dd6c98cdb..d4ad323fe 100644 --- a/arch/powerpc/lib/bootm.c +++ b/arch/powerpc/lib/bootm.c @@ -256,11 +256,6 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima  		return 0;  	} -	if (flag & BOOTM_STATE_OS_GO) { -		boot_jump_linux(images); -		return 0; -	} -  	boot_prep_linux(images);  	ret = boot_body_linux(images);  	if (ret) diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index dd8d495e3..e9385de2a 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -37,7 +37,7 @@ void __udelay(unsigned long usec)  	os_usleep(usec);  } -unsigned long timer_get_us(void) +unsigned long __attribute__((no_instrument_function)) timer_get_us(void)  {  	return os_get_nsec() / 1000;  } diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index d07540776..541e450bf 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -152,7 +152,7 @@ void os_usleep(unsigned long usec)  	usleep(usec);  } -u64 os_get_nsec(void) +u64 __attribute__((no_instrument_function)) os_get_nsec(void)  {  #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK)  	struct timespec tp; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4fdb08090..9a2056a70 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -40,7 +40,7 @@ struct arch_global_data {  #include <asm-generic/global_data.h>  #ifndef __ASSEMBLY__ -static inline gd_t *get_fs_gd_ptr(void) +static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)  {  	gd_t *gd_ptr; diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 6030633d1..b459a63ee 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -85,7 +85,8 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)  #define EAX_EDX_RET(val, low, high)	"=A" (val)  #endif -static inline unsigned long long native_read_msr(unsigned int msr) +static inline __attribute__((no_instrument_function)) +	unsigned long long native_read_msr(unsigned int msr)  {  	DECLARE_ARGS(val, low, high); diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 22e093427..709dc8400 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -64,7 +64,7 @@ void	board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));  void	board_init_f_r(void) __attribute__ ((noreturn));  /* Read the time stamp counter */ -static inline uint64_t rdtsc(void) +static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)  {  	uint32_t high, low;  	__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 2520228b4..0d3250cfa 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -63,6 +63,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],  		}  #if defined(CONFIG_FIT)  	} else if (images->fit_uname_os) { +		int ret; +  		ret = fit_image_get_data(images->fit_hdr_os,  					images->fit_noffset_os, &data, &len);  		if (ret) { diff --git a/arch/x86/lib/gcc.c b/arch/x86/lib/gcc.c index 4043431ec..497ad75b7 100644 --- a/arch/x86/lib/gcc.c +++ b/arch/x86/lib/gcc.c @@ -28,7 +28,9 @@  #define WRAP_LIBGCC_CALL(type, name) \  	type __normal_##name(type a, type b) __attribute__((regparm(0))); \  	type __wrap_##name(type a, type b); \ -	type __wrap_##name(type a, type b) { return __normal_##name(a, b); } +	type __attribute__((no_instrument_function)) \ +		__wrap_##name(type a, type b) \ +		 { return __normal_##name(a, b); }  WRAP_LIBGCC_CALL(long long, __divdi3)  WRAP_LIBGCC_CALL(unsigned long long, __udivdi3) diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c index c509801f9..06889737d 100644 --- a/arch/x86/lib/tsc_timer.c +++ b/arch/x86/lib/tsc_timer.c @@ -37,7 +37,7 @@ void timer_set_base(u64 base)   * restart. This yields a free running counter guaranteed to take almost 6   * years to wrap around even at 100GHz clock rate.   */ -u64 get_ticks(void) +u64 __attribute__((no_instrument_function)) get_ticks(void)  {  	u64 now_tick = rdtsc(); @@ -50,7 +50,7 @@ u64 get_ticks(void)  #define PLATFORM_INFO_MSR 0xce  /* Get the speed of the TSC timer in MHz */ -unsigned long get_tbclk_mhz(void) +unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)  {  	u32 ratio;  	u64 platform_info = native_read_msr(PLATFORM_INFO_MSR); @@ -75,7 +75,7 @@ ulong get_timer(ulong base)  	return get_ms_timer() - base;  } -ulong timer_get_us(void) +ulong __attribute__((no_instrument_function)) timer_get_us(void)  {  	return get_ticks() / get_tbclk_mhz();  } diff --git a/board/LaCie/common/cpld-gpio-bus.c b/board/LaCie/common/cpld-gpio-bus.c new file mode 100644 index 000000000..fb9bf8d5d --- /dev/null +++ b/board/LaCie/common/cpld-gpio-bus.c @@ -0,0 +1,50 @@ +/* + * cpld-gpio-bus.c: provides support for the CPLD GPIO bus found on some LaCie + * boards (as the 2Big/5Big Network v2 and the 2Big NAS). This parallel GPIO + * bus exposes two registers (address and data). Each of this register is made + * up of several dedicated GPIOs. An extra GPIO is used to notify the CPLD that + * the registers have been updated. + * + * Mostly this bus is used to configure the LEDs on LaCie boards. + * + * Copyright (C) 2013 Simon Guinot <simon.guinot@sequanux.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <asm/arch/gpio.h> +#include "cpld-gpio-bus.h" + +static void cpld_gpio_bus_set_addr(struct cpld_gpio_bus *bus, unsigned addr) +{ +	int pin; + +	for (pin = 0; pin < bus->num_addr; pin++) +		kw_gpio_set_value(bus->addr[pin], (addr >> pin) & 1); +} + +static void cpld_gpio_bus_set_data(struct cpld_gpio_bus *bus, unsigned data) +{ +	int pin; + +	for (pin = 0; pin < bus->num_data; pin++) +		kw_gpio_set_value(bus->data[pin], (data >> pin) & 1); +} + +static void cpld_gpio_bus_enable_select(struct cpld_gpio_bus *bus) +{ +	/* The transfer is enabled on the raising edge. */ +	kw_gpio_set_value(bus->enable, 0); +	kw_gpio_set_value(bus->enable, 1); +} + +void cpld_gpio_bus_write(struct cpld_gpio_bus *bus, +			 unsigned addr, unsigned value) +{ +	cpld_gpio_bus_set_addr(bus, addr); +	cpld_gpio_bus_set_data(bus, value); +	cpld_gpio_bus_enable_select(bus); +} diff --git a/board/LaCie/common/cpld-gpio-bus.h b/board/LaCie/common/cpld-gpio-bus.h new file mode 100644 index 000000000..e9e9b9604 --- /dev/null +++ b/board/LaCie/common/cpld-gpio-bus.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Simon Guinot <simon.guinot@sequanux.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _LACIE_CPLD_GPI0_BUS_H +#define _LACIE_CPLD_GPI0_BUS_H + +struct cpld_gpio_bus { +	unsigned *addr; +	unsigned num_addr; +	unsigned *data; +	unsigned num_data; +	unsigned enable; +}; + +void cpld_gpio_bus_write(struct cpld_gpio_bus *cpld_gpio_bus, +			 unsigned addr, unsigned value); + +#endif /* _LACIE_CPLD_GPI0_BUS_H */ diff --git a/board/LaCie/net2big_v2/Makefile b/board/LaCie/net2big_v2/Makefile index fbae48ef2..9a6dfb619 100644 --- a/board/LaCie/net2big_v2/Makefile +++ b/board/LaCie/net2big_v2/Makefile @@ -28,6 +28,9 @@ endif  LIB	= $(obj)lib$(BOARD).o  COBJS	:= $(BOARD).o ../common/common.o +ifneq ($(and $(CONFIG_KIRKWOOD_GPIO),$(CONFIG_NET2BIG_V2)),) +COBJS	+= ../common/cpld-gpio-bus.o +endif  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS)) diff --git a/board/LaCie/net2big_v2/net2big_v2.c b/board/LaCie/net2big_v2/net2big_v2.c index e524f3511..b133f7cb3 100644 --- a/board/LaCie/net2big_v2/net2big_v2.c +++ b/board/LaCie/net2big_v2/net2big_v2.c @@ -22,6 +22,7 @@  #include <common.h>  #include <command.h> +#include <i2c.h>  #include <asm/arch/cpu.h>  #include <asm/arch/kirkwood.h>  #include <asm/arch/mpp.h> @@ -29,6 +30,7 @@  #include "net2big_v2.h"  #include "../common/common.h" +#include "../common/cpld-gpio-bus.h"  DECLARE_GLOBAL_DATA_PTR; @@ -60,18 +62,18 @@ int board_early_init_f(void)  		MPP24_GPIO,		/* USB mode select */  		MPP26_GPIO,		/* USB device vbus */  		MPP28_GPIO,		/* USB enable host vbus */ -		MPP29_GPIO,		/* GPIO extension ALE */ +		MPP29_GPIO,		/* CPLD GPIO bus ALE */  		MPP34_GPIO,		/* Rear Push button 0=on 1=off */  		MPP35_GPIO,		/* Inhibit switch power-off */  		MPP36_GPIO,		/* SATA HDD1 presence */  		MPP37_GPIO,		/* SATA HDD2 presence */  		MPP40_GPIO,		/* eSATA presence */ -		MPP44_GPIO,		/* GPIO extension (data 0) */ -		MPP45_GPIO,		/* GPIO extension (data 1) */ -		MPP46_GPIO,		/* GPIO extension (data 2) */ -		MPP47_GPIO,		/* GPIO extension (addr 0) */ -		MPP48_GPIO,		/* GPIO extension (addr 1) */ -		MPP49_GPIO,		/* GPIO extension (addr 2) */ +		MPP44_GPIO,		/* CPLD GPIO bus (data 0) */ +		MPP45_GPIO,		/* CPLD GPIO bus (data 1) */ +		MPP46_GPIO,		/* CPLD GPIO bus (data 2) */ +		MPP47_GPIO,		/* CPLD GPIO bus (addr 0) */ +		MPP48_GPIO,		/* CPLD GPIO bus (addr 1) */ +		MPP49_GPIO,		/* CPLD GPIO bus (addr 2) */  		0  	}; @@ -92,8 +94,142 @@ int board_init(void)  }  #if defined(CONFIG_MISC_INIT_R) + +#if defined(CONFIG_CMD_I2C) && defined(CONFIG_SYS_I2C_G762_ADDR) +/* + * Start I2C fan (GMT G762 controller) + */ +static void init_fan(void) +{ +	u8 data; + +	i2c_set_bus_num(0); + +	/* Enable open-loop and PWM modes */ +	data = 0x20; +	if (i2c_write(CONFIG_SYS_I2C_G762_ADDR, +		      G762_REG_FAN_CMD1, 1, &data, 1) != 0) +		goto err; +	data = 0; +	if (i2c_write(CONFIG_SYS_I2C_G762_ADDR, +		      G762_REG_SET_CNT, 1, &data, 1) != 0) +		goto err; +	/* +	 * RPM to PWM (set_out register) fan speed conversion array: +	 * 0    0x00 +	 * 1500	0x04 +	 * 2800	0x08 +	 * 3400	0x0C +	 * 3700	0x10 +	 * 4400	0x20 +	 * 4700	0x30 +	 * 4800	0x50 +	 * 5200	0x80 +	 * 5400	0xC0 +	 * 5500	0xFF +	 * +	 * Start fan at low speed (2800 RPM): +	 */ +	data = 0x08; +	if (i2c_write(CONFIG_SYS_I2C_G762_ADDR, +		      G762_REG_SET_OUT, 1, &data, 1) != 0) +		goto err; + +	return; +err: +	printf("Error: failed to start I2C fan @%02x\n", +	       CONFIG_SYS_I2C_G762_ADDR); +} +#else +static void init_fan(void) {} +#endif /* CONFIG_CMD_I2C && CONFIG_SYS_I2C_G762_ADDR */ + +#if defined(CONFIG_NET2BIG_V2) && defined(CONFIG_KIRKWOOD_GPIO) +/* + * CPLD GPIO bus: + * + * - address register : bit [0-2] -> GPIO [47-49] + * - data register    : bit [0-2] -> GPIO [44-46] + * - enable register  : GPIO 29 + */ +static unsigned cpld_gpio_bus_addr[] = { 47, 48, 49 }; +static unsigned cpld_gpio_bus_data[] = { 44, 45, 46 }; + +static struct cpld_gpio_bus cpld_gpio_bus = { +	.addr		= cpld_gpio_bus_addr, +	.num_addr	= ARRAY_SIZE(cpld_gpio_bus_addr), +	.data		= cpld_gpio_bus_data, +	.num_data	= ARRAY_SIZE(cpld_gpio_bus_data), +	.enable		= 29, +}; + +/* + * LEDs configuration: + * + * The LEDs are controlled by a CPLD and can be configured through + * the CPLD GPIO bus. + * + * Address register selection: + * + * addr | register + * ---------------------------- + *   0  | front LED + *   1  | front LED brightness + *   2  | SATA LED brightness + *   3  | SATA0 LED + *   4  | SATA1 LED + *   5  | SATA2 LED + *   6  | SATA3 LED + *   7  | SATA4 LED + * + * Data register configuration: + * + * data | LED brightness + * ------------------------------------------------- + *   0  | min (off) + *   -  | - + *   7  | max + * + * data | front LED mode + * ------------------------------------------------- + *   0  | fix off + *   1  | fix blue on + *   2  | fix red on + *   3  | blink blue on=1 sec and blue off=1 sec + *   4  | blink red on=1 sec and red off=1 sec + *   5  | blink blue on=2.5 sec and red on=0.5 sec + *   6  | blink blue on=1 sec and red on=1 sec + *   7  | blink blue on=0.5 sec and blue off=2.5 sec + * + * data | SATA LED mode + * ------------------------------------------------- + *   0  | fix off + *   1  | SATA activity blink + *   2  | fix red on + *   3  | blink blue on=1 sec and blue off=1 sec + *   4  | blink red on=1 sec and red off=1 sec + *   5  | blink blue on=2.5 sec and red on=0.5 sec + *   6  | blink blue on=1 sec and red on=1 sec + *   7  | fix blue on + */ +static void init_leds(void) +{ +	/* Enable the front blue LED */ +	cpld_gpio_bus_write(&cpld_gpio_bus, 0, 1); +	cpld_gpio_bus_write(&cpld_gpio_bus, 1, 3); + +	/* Configure SATA LEDs to blink in relation with the SATA activity */ +	cpld_gpio_bus_write(&cpld_gpio_bus, 3, 1); +	cpld_gpio_bus_write(&cpld_gpio_bus, 4, 1); +	cpld_gpio_bus_write(&cpld_gpio_bus, 2, 3); +} +#else +static void init_leds(void) {} +#endif /* CONFIG_NET2BIG_V2 && CONFIG_KIRKWOOD_GPIO */ +  int misc_init_r(void)  { +	init_fan();  #if defined(CONFIG_CMD_I2C) && defined(CONFIG_SYS_I2C_EEPROM_ADDR)  	if (!getenv("ethaddr")) {  		uchar mac[6]; @@ -101,9 +237,11 @@ int misc_init_r(void)  			eth_setenv_enetaddr("ethaddr", mac);  	}  #endif +	init_leds(); +  	return 0;  } -#endif +#endif /* CONFIG_MISC_INIT_R */  #if defined(CONFIG_CMD_NET) && defined(CONFIG_RESET_PHY_R)  /* Configure and initialize PHY */ diff --git a/board/LaCie/net2big_v2/net2big_v2.h b/board/LaCie/net2big_v2/net2big_v2.h index f9778f4f0..83537d6b9 100644 --- a/board/LaCie/net2big_v2/net2big_v2.h +++ b/board/LaCie/net2big_v2/net2big_v2.h @@ -32,4 +32,9 @@  /* Buttons */  #define NET2BIG_V2_GPIO_PUSH_BUTTON	34 +/* GMT G762 registers (I2C fan controller) */ +#define G762_REG_SET_CNT		0x00 +#define G762_REG_SET_OUT		0x03 +#define G762_REG_FAN_CMD1		0x04 +  #endif /* NET2BIG_V2_H */ diff --git a/board/actux1/u-boot.lds b/board/actux1/u-boot.lds index ef4a25bc3..74aec5fbc 100644 --- a/board/actux1/u-boot.lds +++ b/board/actux1/u-boot.lds @@ -30,6 +30,7 @@ SECTIONS  	. = ALIGN (4);  	.text : { +		*(.__image_copy_start)  		arch/arm/cpu/ixp/start.o(.text*)  		net/libnet.o(.text*)  		board/actux1/libactux1.o(.text*) @@ -62,17 +63,23 @@ SECTIONS  	. = ALIGN (4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -96,6 +103,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/board/actux2/u-boot.lds b/board/actux2/u-boot.lds index 00ad8b71c..c276501bd 100644 --- a/board/actux2/u-boot.lds +++ b/board/actux2/u-boot.lds @@ -30,6 +30,7 @@ SECTIONS  	. = ALIGN (4);  	.text : { +		*(.__image_copy_start)  		arch/arm/cpu/ixp/start.o(.text*)  		net/libnet.o(.text*)  		board/actux2/libactux2.o(.text*) @@ -62,17 +63,23 @@ SECTIONS  	. = ALIGN (4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -96,6 +103,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/board/actux3/u-boot.lds b/board/actux3/u-boot.lds index 44b990ee7..5610644d7 100644 --- a/board/actux3/u-boot.lds +++ b/board/actux3/u-boot.lds @@ -30,6 +30,7 @@ SECTIONS  	. = ALIGN (4);  	.text : { +		*(.__image_copy_start)  		arch/arm/cpu/ixp/start.o(.text*)  		net/libnet.o(.text*)  		board/actux3/libactux3.o(.text*) @@ -62,17 +63,23 @@ SECTIONS  	. = ALIGN (4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -96,6 +103,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/board/ait/cam_enc_4xx/u-boot-spl.lds b/board/ait/cam_enc_4xx/u-boot-spl.lds index 1daa1b3b9..39726854c 100644 --- a/board/ait/cam_enc_4xx/u-boot-spl.lds +++ b/board/ait/cam_enc_4xx/u-boot-spl.lds @@ -54,11 +54,6 @@ SECTIONS  		__rel_dyn_end = .;  	} >.sram -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} >.sram -  	.bss :  	{  		. = ALIGN(4); diff --git a/board/atmel/at91sam9n12ek/at91sam9n12ek.c b/board/atmel/at91sam9n12ek/at91sam9n12ek.c index 8752794c8..3013a42a2 100644 --- a/board/atmel/at91sam9n12ek/at91sam9n12ek.c +++ b/board/atmel/at91sam9n12ek/at91sam9n12ek.c @@ -33,6 +33,7 @@  #include <lcd.h>  #include <atmel_hlcdc.h>  #include <atmel_mci.h> +#include <netdev.h>  #ifdef CONFIG_LCD_INFO  #include <nand.h> @@ -190,6 +191,30 @@ int board_mmc_init(bd_t *bd)  }  #endif +#ifdef CONFIG_KS8851_MLL +void at91sam9n12ek_ks8851_hw_init(void) +{ +	struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; + +	writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) | +	       AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0), +	       &smc->cs[2].setup); +	writel(AT91_SMC_PULSE_NWE(7) | AT91_SMC_PULSE_NCS_WR(7) | +	       AT91_SMC_PULSE_NRD(7) | AT91_SMC_PULSE_NCS_RD(7), +	       &smc->cs[2].pulse); +	writel(AT91_SMC_CYCLE_NWE(9) | AT91_SMC_CYCLE_NRD(9), +	       &smc->cs[2].cycle); +	writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE | +	       AT91_SMC_MODE_EXNW_DISABLE | +	       AT91_SMC_MODE_BAT | AT91_SMC_MODE_DBW_16 | +	       AT91_SMC_MODE_TDF_CYCLE(1), +	       &smc->cs[2].mode); + +	/* Configure NCS2 PIN */ +	at91_set_b_periph(AT91_PIO_PORTD, 19, 0); +} +#endif +  int board_early_init_f(void)  {  	/* Enable clocks for all PIOs */ @@ -217,9 +242,20 @@ int board_init(void)  	at91_lcd_hw_init();  #endif +#ifdef CONFIG_KS8851_MLL +	at91sam9n12ek_ks8851_hw_init(); +#endif +  	return 0;  } +#ifdef CONFIG_KS8851_MLL +int board_eth_init(bd_t *bis) +{ +	return ks8851_mll_initialize(0, CONFIG_KS8851_MLL_BASEADDR); +} +#endif +  int dram_init(void)  {  	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, diff --git a/board/davinci/da8xxevm/u-boot-spl-da850evm.lds b/board/davinci/da8xxevm/u-boot-spl-da850evm.lds index b1b870181..6fa450909 100644 --- a/board/davinci/da8xxevm/u-boot-spl-da850evm.lds +++ b/board/davinci/da8xxevm/u-boot-spl-da850evm.lds @@ -55,11 +55,6 @@ SECTIONS  		__rel_dyn_end = .;  	} >.sram -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} >.sram -  	.bss :  	{  		. = ALIGN(4); diff --git a/board/davinci/da8xxevm/u-boot-spl-hawk.lds b/board/davinci/da8xxevm/u-boot-spl-hawk.lds index 596a9e08e..b452f2078 100644 --- a/board/davinci/da8xxevm/u-boot-spl-hawk.lds +++ b/board/davinci/da8xxevm/u-boot-spl-hawk.lds @@ -61,7 +61,6 @@ SECTIONS  	__image_copy_end = .;  	__rel_dyn_start = .;  	__rel_dyn_end = .; -	__dynsym_start = .;  	__got_start = .;  	. = ALIGN(4); diff --git a/board/dvlhost/u-boot.lds b/board/dvlhost/u-boot.lds index 6d4b1875c..f35911232 100644 --- a/board/dvlhost/u-boot.lds +++ b/board/dvlhost/u-boot.lds @@ -30,6 +30,7 @@ SECTIONS  	. = ALIGN (4);  	.text : { +		*(.__image_copy_start)  		arch/arm/cpu/ixp/start.o(.text*)  		net/libnet.o(.text*)  		board/dvlhost/libdvlhost.o(.text*) @@ -62,17 +63,23 @@ SECTIONS  	. = ALIGN (4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -96,6 +103,7 @@ SECTIONS  		KEEP(*(.__bss_end));  	} +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynamic*) }  	/DISCARD/ : { *(.plt*) } diff --git a/board/eltec/elppc/misc.c b/board/eltec/elppc/misc.c index 89f1b1d35..4c3656e24 100644 --- a/board/eltec/elppc/misc.c +++ b/board/eltec/elppc/misc.c @@ -207,9 +207,14 @@ int misc_init_r (void)  		buf[4] = eerev.etheraddr[5];  		buf[5] = eerev.etheraddr[4]; -		*(unsigned short *) &buf[20] = 0x48B2; -		*(unsigned short *) &buf[22] = 0x0004; -		*(unsigned short *) &buf[24] = 0x1433; +		buf[20] = 0x48; +		buf[21] = 0xB2; + +		buf[22] = 0x00; +		buf[23] = 0x04; + +		buf[24] = 0x14; +		buf[25] = 0x33;  		printf ("\nSRom:  Writing i82559 info ........ ");  		if (eepro100_srom_store ((unsigned short *) buf) == -1) diff --git a/board/freescale/b4860qds/tlb.c b/board/freescale/b4860qds/tlb.c index 29cc41bfa..1416f98dc 100644 --- a/board/freescale/b4860qds/tlb.c +++ b/board/freescale/b4860qds/tlb.c @@ -52,6 +52,15 @@ struct fsl_e_tlb_entry tlb_table[] = {  	SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 0, BOOKE_PAGESZ_1M, 1), +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +	/* +	 * SRIO_PCIE_BOOT-SLAVE. When slave boot, the address of the +	 * space is at 0xfff00000, it covered the 0xfffff000. +	 */ +	SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR, +		      CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, +		      0, 0, BOOKE_PAGESZ_1M, 1),  #else  	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000,  		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, @@ -137,6 +146,16 @@ struct fsl_e_tlb_entry tlb_table[] = {  		MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  		      0, 16, BOOKE_PAGESZ_256M, 1),  #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +	/* +	 * SRIO_PCIE_BOOT-SLAVE. 1M space from 0xffe00000 for +	 * fetching ucode and ENV from master +	 */ +	SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR, +		      CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_G, +		      0, 17, BOOKE_PAGESZ_1M, 1), +#endif  };  int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/bsc9131rdb/Makefile b/board/freescale/bsc9131rdb/Makefile index 6f4cb268f..2e829ad2e 100644 --- a/board/freescale/bsc9131rdb/Makefile +++ b/board/freescale/bsc9131rdb/Makefile @@ -24,12 +24,28 @@ include $(TOPDIR)/config.mk  LIB    = $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y	+= spl_minimal.o tlb.o law.o + +else +  COBJS-y        += $(BOARD).o  COBJS-y        += ddr.o  COBJS-y        += law.o  COBJS-y        += tlb.o  #COBJS-y		+= bsc9131rdb_mux.o +endif +  SRCS   := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS   := $(addprefix $(obj),$(COBJS-y))  SOBJS  := $(addprefix $(obj),$(SOBJS)) diff --git a/board/freescale/bsc9131rdb/README b/board/freescale/bsc9131rdb/README index 065faa378..4902b98ba 100644 --- a/board/freescale/bsc9131rdb/README +++ b/board/freescale/bsc9131rdb/README @@ -89,10 +89,14 @@ NAND boot  Building U-boot  --------------  To build the u-boot for BSC9131RDB: -1. NAND Flash +1. NAND Flash with sysclk 66MHz(J16 on RDB closed, default)  	make BSC9131RDB_NAND -2. SPI Flash +2. NAND Flash with sysclk 100MHz(J16 on RDB open) +	make BSC9131RDB_NAND_SYSCLK100 +3. SPI Flash with sysclk 66MHz(J16 on RDB closed, default)  	make BSC9131RDB_SPIFLASH +4. SPI Flash with sysclk 100MHz(J16 on RDB open) +	make BSC9131RDB_SPIFLASH_SYSCLK100  Memory map  ----------- @@ -107,6 +111,16 @@ Memory map   0xFF70_0000	0xFF7F_FFFF	PA CCSR			1M   0xFF80_0000	0xFFFF_FFFF	Boot Page & NAND Buffer 8M +DDR Memory map +--------------- + 0x0000_0000	0x36FF_FFFF	Memory passed onto Linux + 0x3700_0000	0x37FF_FFFF	PowerPC-DSP shared control area + 0x3800_0000	0x4FFF_FFFF	DSP Private area + + Out of 880M, passed onto Linux, 1hugetlb page of 256M is reserved for + data communcation between PowerPC and DSP core. + Rest is PowerPC private area. +  Flashing Images  ---------------  To place a new u-boot image in the NAND flash and then boot diff --git a/board/freescale/bsc9131rdb/law.c b/board/freescale/bsc9131rdb/law.c index 201c14707..0432780f9 100644 --- a/board/freescale/bsc9131rdb/law.c +++ b/board/freescale/bsc9131rdb/law.c @@ -26,6 +26,10 @@  struct law_entry law_table[] = {  	SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_IFC), +	SET_LAW(CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS, LAW_SIZE_1M, +		LAW_TRGT_IF_DSP_CCSR), +	SET_LAW(CONFIG_SYS_FSL_DSP_M2_RAM_ADDR, LAW_SIZE_16M, +		LAW_TRGT_IF_OCN_DSP),  };  int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/bsc9131rdb/spl_minimal.c b/board/freescale/bsc9131rdb/spl_minimal.c new file mode 100644 index 000000000..301115e5e --- /dev/null +++ b/board/freescale/bsc9131rdb/spl_minimal.c @@ -0,0 +1,118 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <ns16550.h> +#include <asm/io.h> +#include <nand.h> +#include <linux/compiler.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Fixed sdram init -- doesn't use serial presence detect. + */ +static void sdram_init(void) +{ +	ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; + +	__raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); +	__raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); +#if CONFIG_CHIP_SELECTS_PER_CTRL > 1 +	__raw_writel(CONFIG_SYS_DDR_CS1_BNDS, &ddr->cs1_bnds); +	__raw_writel(CONFIG_SYS_DDR_CS1_CONFIG, &ddr->cs1_config); +#endif +	__raw_writel(CONFIG_SYS_DDR_TIMING_3_800, &ddr->timing_cfg_3); +	__raw_writel(CONFIG_SYS_DDR_TIMING_0_800, &ddr->timing_cfg_0); +	__raw_writel(CONFIG_SYS_DDR_TIMING_1_800, &ddr->timing_cfg_1); +	__raw_writel(CONFIG_SYS_DDR_TIMING_2_800, &ddr->timing_cfg_2); + +	__raw_writel(CONFIG_SYS_DDR_CONTROL_2, &ddr->sdram_cfg_2); +	__raw_writel(CONFIG_SYS_DDR_MODE_1_800, &ddr->sdram_mode); +	__raw_writel(CONFIG_SYS_DDR_MODE_2_800, &ddr->sdram_mode_2); + +	__raw_writel(CONFIG_SYS_DDR_INTERVAL_800, &ddr->sdram_interval); +	__raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); +	__raw_writel(CONFIG_SYS_DDR_CLK_CTRL_800, &ddr->sdram_clk_cntl); + +	__raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_800, &ddr->ddr_wrlvl_cntl); +	__raw_writel(CONFIG_SYS_DDR_TIMING_4, &ddr->timing_cfg_4); +	__raw_writel(CONFIG_SYS_DDR_TIMING_5, &ddr->timing_cfg_5); +	__raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); + +	/* Set, but do not enable the memory */ +	__raw_writel(CONFIG_SYS_DDR_CONTROL & ~SDRAM_CFG_MEM_EN, &ddr->sdram_cfg); + +	asm volatile("sync;isync"); +	udelay(500); + +	/* Let the controller go */ +	out_be32(&ddr->sdram_cfg, in_be32(&ddr->sdram_cfg) | SDRAM_CFG_MEM_EN); + +	set_next_law(CONFIG_SYS_NAND_DDR_LAW, LAW_SIZE_1G, LAW_TRGT_IF_DDR_1); +} + +void board_init_f(ulong bootflag) +{ +	u32 plat_ratio; +	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + +	/* initialize selected port with appropriate baud rate */ +	plat_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_PLAT_RATIO; +	plat_ratio >>= 1; +	gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; + +	NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1, +		     gd->bus_clk / 16 / CONFIG_BAUDRATE); + +	puts("\nNAND boot... "); + +	/* Initialize the DDR3 */ +	sdram_init(); + +	/* copy code to RAM and jump to it - this should not return */ +	/* NOTE - code has to be copied out of NAND buffer before +	 * other blocks can be read. +	 */ +	relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); +} + +void board_init_r(gd_t *gd, ulong dest_addr) +{ +	nand_boot(); +} + +void putc(char c) +{ +	if (c == '\n') +		NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, '\r'); + +	NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, c); +} + +void puts(const char *str) +{ +	while (*str) +		putc(*str++); +} diff --git a/board/freescale/bsc9131rdb/tlb.c b/board/freescale/bsc9131rdb/tlb.c index 5b68f4af3..c05a556a3 100644 --- a/board/freescale/bsc9131rdb/tlb.c +++ b/board/freescale/bsc9131rdb/tlb.c @@ -44,15 +44,26 @@ struct fsl_e_tlb_entry tlb_table[] = {  	/* TLB 1 */  	/* *I*** - Covers boot page */  	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, -			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, -			0, 0, BOOKE_PAGESZ_4K, 1), +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL +	SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 10, BOOKE_PAGESZ_4K, 1), +#endif  	/* *I*G* - CCSRBAR (PA) */  	SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 1, BOOKE_PAGESZ_1M, 1), -#if defined(CONFIG_SYS_RAMBOOT) +	/* CCSRBAR (DSP) */ +	SET_TLB_ENTRY(1, CONFIG_SYS_FSL_DSP_CCSRBAR, +		      CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 2, BOOKE_PAGESZ_1M, 1), + +#if  defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL)  	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE,  			MAS3_SX|MAS3_SW|MAS3_SR, 0,  			0, 8, BOOKE_PAGESZ_1G, 1), diff --git a/board/freescale/bsc9132qds/Makefile b/board/freescale/bsc9132qds/Makefile index 267400bec..72b19174b 100644 --- a/board/freescale/bsc9132qds/Makefile +++ b/board/freescale/bsc9132qds/Makefile @@ -24,11 +24,28 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y	+= spl_minimal.o tlb.o law.o + +else + +  COBJS-y	+= $(BOARD).o  COBJS-y	+= ddr.o  COBJS-y	+= law.o  COBJS-y	+= tlb.o +endif +  SRCS	:= $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS-y))  SOBJS	:= $(addprefix $(obj),$(SOBJS)) diff --git a/board/freescale/bsc9132qds/bsc9132qds.c b/board/freescale/bsc9132qds/bsc9132qds.c index 6e1b55816..ddc9d0a16 100644 --- a/board/freescale/bsc9132qds/bsc9132qds.c +++ b/board/freescale/bsc9132qds/bsc9132qds.c @@ -258,7 +258,7 @@ int misc_init_r(void)  	u8 val;  	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);  	u32 porbmsr = in_be32(&gur->porbmsr); -	u32 romloc = (porbmsr >> MPC85XX_PORBMSR_ROMLOC_SHIFT) & 0xf; +	u32 romloc = (porbmsr >> MPC85xx_PORBMSR_ROMLOC_SHIFT) & 0xf;  	/*Configure 1588 clock-in source from RF Card*/  	val = QIXIS_READ_I2C(brdcfg[5]); @@ -360,7 +360,7 @@ void ft_board_setup(void *blob, bd_t *bd)  	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);  	u32 porbmsr = in_be32(&gur->porbmsr); -	u32 romloc = (porbmsr >> MPC85XX_PORBMSR_ROMLOC_SHIFT) & 0xf; +	u32 romloc = (porbmsr >> MPC85xx_PORBMSR_ROMLOC_SHIFT) & 0xf;  	if (!(hwconfig("uart2") && hwconfig("usb1"))) {  		/* If uart2 is there in hwconfig remove usb node from diff --git a/board/freescale/bsc9132qds/law.c b/board/freescale/bsc9132qds/law.c index dc2365851..b4bce99d3 100644 --- a/board/freescale/bsc9132qds/law.c +++ b/board/freescale/bsc9132qds/law.c @@ -25,11 +25,13 @@  #include <asm/mmu.h>  struct law_entry law_table[] = { -#ifndef CONFIG_SYS_NO_FLASH  	SET_LAW(CONFIG_SYS_FLASH_BASE_PHYS, LAW_SIZE_128M, LAW_TRGT_IF_IFC), -#endif +#ifdef CONFIG_SYS_NAND_BASE_PHYS  	SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_IFC), +#endif +#ifdef CONFIG_SYS_FPGA_BASE_PHYS  	SET_LAW(CONFIG_SYS_FPGA_BASE_PHYS, LAW_SIZE_128K, LAW_TRGT_IF_IFC), +#endif  };  int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/bsc9132qds/spl_minimal.c b/board/freescale/bsc9132qds/spl_minimal.c new file mode 100644 index 000000000..62dee52b1 --- /dev/null +++ b/board/freescale/bsc9132qds/spl_minimal.c @@ -0,0 +1,130 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <ns16550.h> +#include <asm/io.h> +#include <nand.h> +#include <linux/compiler.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void sdram_init(void) +{ +	ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; +#if CONFIG_DDR_CLK_FREQ == 100000000 +	__raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); +	__raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); +	__raw_writel(CONFIG_SYS_DDR_CONTROL_800 | SDRAM_CFG_32_BE, &ddr->sdram_cfg); +	__raw_writel(CONFIG_SYS_DDR_CONTROL_2_800, &ddr->sdram_cfg_2); +	__raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); + +	__raw_writel(CONFIG_SYS_DDR_TIMING_3_800, &ddr->timing_cfg_3); +	__raw_writel(CONFIG_SYS_DDR_TIMING_0_800, &ddr->timing_cfg_0); +	__raw_writel(CONFIG_SYS_DDR_TIMING_1_800, &ddr->timing_cfg_1); +	__raw_writel(CONFIG_SYS_DDR_TIMING_2_800, &ddr->timing_cfg_2); +	__raw_writel(CONFIG_SYS_DDR_MODE_1_800, &ddr->sdram_mode); +	__raw_writel(CONFIG_SYS_DDR_MODE_2_800, &ddr->sdram_mode_2); +	__raw_writel(CONFIG_SYS_DDR_INTERVAL_800, &ddr->sdram_interval); +	__raw_writel(CONFIG_SYS_DDR_CLK_CTRL_800, &ddr->sdram_clk_cntl); +	__raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_800, &ddr->ddr_wrlvl_cntl); + +	__raw_writel(CONFIG_SYS_DDR_TIMING_4_800, &ddr->timing_cfg_4); +	__raw_writel(CONFIG_SYS_DDR_TIMING_5_800, &ddr->timing_cfg_5); +	__raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); +#elif CONFIG_DDR_CLK_FREQ == 133000000 +	__raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); +	__raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); +	__raw_writel(CONFIG_SYS_DDR_CONTROL_1333 | SDRAM_CFG_32_BE, &ddr->sdram_cfg); +	__raw_writel(CONFIG_SYS_DDR_CONTROL_2_1333, &ddr->sdram_cfg_2); +	__raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); + +	__raw_writel(CONFIG_SYS_DDR_TIMING_3_1333, &ddr->timing_cfg_3); +	__raw_writel(CONFIG_SYS_DDR_TIMING_0_1333, &ddr->timing_cfg_0); +	__raw_writel(CONFIG_SYS_DDR_TIMING_1_1333, &ddr->timing_cfg_1); +	__raw_writel(CONFIG_SYS_DDR_TIMING_2_1333, &ddr->timing_cfg_2); +	__raw_writel(CONFIG_SYS_DDR_MODE_1_1333, &ddr->sdram_mode); +	__raw_writel(CONFIG_SYS_DDR_MODE_2_1333, &ddr->sdram_mode_2); +	__raw_writel(CONFIG_SYS_DDR_INTERVAL_1333, &ddr->sdram_interval); +	__raw_writel(CONFIG_SYS_DDR_CLK_CTRL_1333, &ddr->sdram_clk_cntl); +	__raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_1333, &ddr->ddr_wrlvl_cntl); + +	__raw_writel(CONFIG_SYS_DDR_TIMING_4_1333, &ddr->timing_cfg_4); +	__raw_writel(CONFIG_SYS_DDR_TIMING_5_1333, &ddr->timing_cfg_5); +	__raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); +#else +	puts("Not a valid DDR Freq Found! Please Reset\n"); +#endif +	asm volatile("sync;isync"); +	udelay(500); + +	/* Let the controller go */ +	out_be32(&ddr->sdram_cfg, in_be32(&ddr->sdram_cfg) | SDRAM_CFG_MEM_EN); + +	set_next_law(CONFIG_SYS_NAND_DDR_LAW, LAW_SIZE_1G, LAW_TRGT_IF_DDR_1); +} + +void board_init_f(ulong bootflag) +{ +	u32 plat_ratio; +	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + +	/* initialize selected port with appropriate baud rate */ +	plat_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_PLAT_RATIO; +	plat_ratio >>= 1; +	gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; + +	NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1, +		     gd->bus_clk / 16 / CONFIG_BAUDRATE); + +	puts("\nNAND boot... "); + +	/* Initialize the DDR3 */ +	sdram_init(); + +	/* copy code to RAM and jump to it - this should not return */ +	/* NOTE - code has to be copied out of NAND buffer before +	 * other blocks can be read. +	 */ +	relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); +} + +void board_init_r(gd_t *gd, ulong dest_addr) +{ +	nand_boot(); +} + +void putc(char c) +{ +	if (c == '\n') +		NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, '\r'); + +	NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, c); +} + +void puts(const char *str) +{ +	while (*str) +		putc(*str++); +} diff --git a/board/freescale/bsc9132qds/tlb.c b/board/freescale/bsc9132qds/tlb.c index 0e4545fb1..0ec9a851a 100644 --- a/board/freescale/bsc9132qds/tlb.c +++ b/board/freescale/bsc9132qds/tlb.c @@ -44,14 +44,20 @@ struct fsl_e_tlb_entry tlb_table[] = {  	/* TLB 1 */  	/* *I*** - Covers boot page */  	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, -			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, -			0, 0, BOOKE_PAGESZ_4K, 1), +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL +	SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 10, BOOKE_PAGESZ_4K, 1), +#endif  	/* *I*G* - CCSRBAR (PA) */  	SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 1, BOOKE_PAGESZ_1M, 1), +#ifndef CONFIG_SPL_BUILD  	SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS,  			MAS3_SX|MAS3_SR, MAS2_W|MAS2_G,  			0, 3, BOOKE_PAGESZ_64M, 1), @@ -61,12 +67,6 @@ struct fsl_e_tlb_entry tlb_table[] = {  			MAS3_SX|MAS3_SR, MAS2_W|MAS2_G,  			0, 4, BOOKE_PAGESZ_64M, 1), -#if defined(CONFIG_SYS_RAMBOOT) -	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, -			MAS3_SX|MAS3_SW|MAS3_SR, 0, -			0, 8, BOOKE_PAGESZ_1G, 1), -#endif -  #ifdef CONFIG_PCI  	/* *I*G* - PCI */  	SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_MEM_VIRT, CONFIG_SYS_PCIE1_MEM_PHYS, @@ -78,15 +78,26 @@ struct fsl_e_tlb_entry tlb_table[] = {  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 7, BOOKE_PAGESZ_64K, 1),  #endif +#endif + +#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL) +	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 8, BOOKE_PAGESZ_1G, 1), +#endif +#ifdef CONFIG_SYS_FPGA_BASE  		/* *I*G - Board FPGA  */  	SET_TLB_ENTRY(1, CONFIG_SYS_FPGA_BASE, CONFIG_SYS_FPGA_BASE_PHYS,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 9, BOOKE_PAGESZ_256K, 1), +#endif +#ifdef CONFIG_SYS_NAND_BASE_PHYS  	SET_TLB_ENTRY(1, CONFIG_SYS_NAND_BASE, CONFIG_SYS_NAND_BASE_PHYS,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 5, BOOKE_PAGESZ_1M, 1), +#endif  };  int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile index 72bb56cac..37236d072 100644 --- a/board/freescale/common/Makefile +++ b/board/freescale/common/Makefile @@ -29,6 +29,15 @@ endif  LIB	= $(obj)libfreescale.o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifndef MINIMAL  COBJS-$(CONFIG_FSL_CADMUS)	+= cadmus.o  COBJS-$(CONFIG_FSL_VIA)		+= cds_via.o  COBJS-$(CONFIG_FMAN_ENET)	+= fman.o @@ -68,6 +77,7 @@ SUBLIB-$(CONFIG_P3041DS)	+= p_corenet/libp_corenet.o  SUBLIB-$(CONFIG_P4080DS)	+= p_corenet/libp_corenet.o  SUBLIB-$(CONFIG_P5020DS)	+= p_corenet/libp_corenet.o  SUBLIB-$(CONFIG_P5040DS)	+= p_corenet/libp_corenet.o +endif  SRCS	:= $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS-y)) diff --git a/board/freescale/common/pixis.c b/board/freescale/common/pixis.c index 8d07061c3..fbb709de1 100644 --- a/board/freescale/common/pixis.c +++ b/board/freescale/common/pixis.c @@ -480,6 +480,7 @@ static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const ar  	    ||	unknown_param) {  #ifdef CONFIG_SYS_LONGHELP  		puts(cmdtp->help); +		putc('\n');  #endif  		return 1;  	} @@ -512,6 +513,7 @@ static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const ar  		      && set_px_mpxpll(mpxpll))) {  #ifdef CONFIG_SYS_LONGHELP  			puts(cmdtp->help); +			putc('\n');  #endif  			return 1;  		} diff --git a/board/freescale/mx31ads/u-boot.lds b/board/freescale/mx31ads/u-boot.lds index 496996000..963d29f2d 100644 --- a/board/freescale/mx31ads/u-boot.lds +++ b/board/freescale/mx31ads/u-boot.lds @@ -34,6 +34,7 @@ SECTIONS  	. = ALIGN(4);  	.text	   :  	{ +		*(.__image_copy_start)  	  /* WARNING - the following is hand-optimized to fit within	*/  	  /* the sector layout of our flash chips!	XXX FIXME XXX	*/ @@ -65,17 +66,23 @@ SECTIONS  	. = ALIGN(4); -	__image_copy_end = .; +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	}  	.rel.dyn : { -		__rel_dyn_start = .;  		*(.rel*) -		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end)  	}  	_end = .; @@ -100,6 +107,7 @@ SECTIONS  	}  	/DISCARD/ : { *(.bss*) } +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynsym*) }  	/DISCARD/ : { *(.dynamic*) } diff --git a/board/freescale/p1010rdb/Makefile b/board/freescale/p1010rdb/Makefile index 4c705b627..e6563be09 100644 --- a/board/freescale/p1010rdb/Makefile +++ b/board/freescale/p1010rdb/Makefile @@ -24,11 +24,27 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y	+= spl_minimal.o tlb.o law.o + +else +  COBJS-y	+= $(BOARD).o  COBJS-y	+= ddr.o  COBJS-y	+= law.o  COBJS-y	+= tlb.o +endif +  SRCS	:= $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS-y))  SOBJS	:= $(addprefix $(obj),$(SOBJS)) diff --git a/nand_spl/board/freescale/p1010rdb/nand_boot.c b/board/freescale/p1010rdb/spl_minimal.c index 3c7bc2bc6..c909e0ee3 100644 --- a/nand_spl/board/freescale/p1010rdb/nand_boot.c +++ b/board/freescale/p1010rdb/spl_minimal.c @@ -31,11 +31,18 @@  DECLARE_GLOBAL_DATA_PTR; -unsigned long ddr_freq_mhz;  void sdram_init(void)  {  	ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; +	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; +	u32 ddr_ratio; +	unsigned long ddr_freq_mhz; + +	ddr_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO; +	ddr_ratio = ddr_ratio >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; +	ddr_freq_mhz = (CONFIG_SYS_CLK_FREQ * ddr_ratio) / 0x1000000; +  	/* mask off E bit */  	u32 svr = SVR_SOC_VER(mfspr(SPRN_SVR)); @@ -81,6 +88,7 @@ void sdram_init(void)  		__raw_writel((CONFIG_SYS_DDR_CS0_BNDS >> 1) & 0x0fff0fff, &ddr->cs0_bnds);  	} +	asm volatile("sync;isync");  	udelay(500);  	/* Let the controller go */ @@ -91,7 +99,7 @@ void sdram_init(void)  void board_init_f(ulong bootflag)  { -	u32 plat_ratio, ddr_ratio; +	u32 plat_ratio;  	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;  	/* initialize selected port with appropriate baud rate */ @@ -99,10 +107,6 @@ void board_init_f(ulong bootflag)  	plat_ratio >>= 1;  	gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; -	ddr_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO; -	ddr_ratio = ddr_ratio >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; -	ddr_freq_mhz = (CONFIG_SYS_CLK_FREQ * ddr_ratio) / 0x1000000; -  	NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1,  			gd->bus_clk / 16 / CONFIG_BAUDRATE); @@ -115,8 +119,8 @@ void board_init_f(ulong bootflag)  	/* NOTE - code has to be copied out of NAND buffer before  	 * other blocks can be read.  	 */ -	relocate_code(CONFIG_SYS_NAND_U_BOOT_RELOC_SP, 0, -			CONFIG_SYS_NAND_U_BOOT_RELOC); + +	relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE);  }  void board_init_r(gd_t *gd, ulong dest_addr) diff --git a/board/freescale/p1010rdb/tlb.c b/board/freescale/p1010rdb/tlb.c index 4256bf4e5..078717a5b 100644 --- a/board/freescale/p1010rdb/tlb.c +++ b/board/freescale/p1010rdb/tlb.c @@ -44,15 +44,20 @@ struct fsl_e_tlb_entry tlb_table[] = {  	/* TLB 1 */  	/* *I*** - Covers boot page */  	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, -			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, -			0, 0, BOOKE_PAGESZ_4K, 1), +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL +	SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 10, BOOKE_PAGESZ_4K, 1), +#endif  	/* *I*G* - CCSRBAR */  	SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS,  			MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 1, BOOKE_PAGESZ_1M, 1), -#ifndef CONFIG_NAND_SPL +#ifndef CONFIG_SPL_BUILD  #ifndef CONFIG_SDCARD  	SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS,  			MAS3_SX|MAS3_SR, MAS2_W|MAS2_G, @@ -88,7 +93,7 @@ struct fsl_e_tlb_entry tlb_table[] = {  			0, 7, BOOKE_PAGESZ_1M, 1),  #endif -#if defined(CONFIG_SYS_RAMBOOT) +#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL)  	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE,  			MAS3_SX|MAS3_SW|MAS3_SR, 0,  			0, 8, BOOKE_PAGESZ_1G, 1) diff --git a/board/freescale/p1023rdb/Makefile b/board/freescale/p1023rdb/Makefile new file mode 100644 index 000000000..45c4f8b7c --- /dev/null +++ b/board/freescale/p1023rdb/Makefile @@ -0,0 +1,33 @@ +# +# Copyright 2013 Freescale Semiconductor, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(BOARD).o + +COBJS-y	+= $(BOARD).o +COBJS-y	+= ddr.o +COBJS-y	+= law.o +COBJS-y	+= tlb.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS-y)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) $(SOBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/freescale/p1023rdb/ddr.c b/board/freescale/p1023rdb/ddr.c new file mode 100644 index 000000000..7ed275ade --- /dev/null +++ b/board/freescale/p1023rdb/ddr.c @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/mmu.h> +#include <asm/immap_85xx.h> +#include <asm/processor.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include <asm/io.h> +#include <asm/fsl_law.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* CONFIG_SYS_DDR_RAW_TIMING */ +/* + * Hynix H5TQ1G83TFR-H9C + */ +dimm_params_t ddr_raw_timing = { +	.n_ranks = 1, +	.rank_density = 536870912u, +	.capacity = 536870912u, +	.primary_sdram_width = 32, +	.ec_sdram_width = 0, +	.registered_dimm = 0, +	.mirrored_dimm = 0, +	.n_row_addr = 14, +	.n_col_addr = 10, +	.n_banks_per_sdram_device = 8, +	.edc_config = 0, +	.burst_lengths_bitmask = 0x0c, + +	.tCKmin_X_ps = 1875, +	.caslat_X = 0x1e << 4,	/* 5,6,7,8 */ +	.tAA_ps = 13125, +	.tWR_ps = 18000, +	.tRCD_ps = 13125, +	.tRRD_ps = 7500, +	.tRP_ps = 13125, +	.tRAS_ps = 37500, +	.tRC_ps = 50625, +	.tRFC_ps = 160000, +	.tWTR_ps = 7500, +	.tRTP_ps = 7500, +	.refresh_rate_ps = 7800000, +	.tFAW_ps = 37500, +}; + +int fsl_ddr_get_dimm_params(dimm_params_t *pdimm, +		unsigned int controller_number, +		unsigned int dimm_number) +{ +	const char dimm_model[] = "Fixed DDR on board"; + +	if ((controller_number == 0) && (dimm_number == 0)) { +		memcpy(pdimm, &ddr_raw_timing, sizeof(dimm_params_t)); +		memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); +		memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1); +	} + +	return 0; +} + +void fsl_ddr_board_options(memctl_options_t *popts, +				dimm_params_t *pdimm, +				unsigned int ctrl_num) +{ +	int i; +	popts->clk_adjust = 6; +	popts->cpo_override = 0x1f; +	popts->write_data_delay = 2; +	popts->half_strength_driver_enable = 1; +	/* Write leveling override */ +	popts->wrlvl_en = 1; +	popts->wrlvl_override = 1; +	popts->wrlvl_sample = 0xf; +	popts->wrlvl_start = 0x8; +	popts->trwt_override = 1; +	popts->trwt = 0; + +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { +		popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER; +		popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS; +	} +} + diff --git a/board/freescale/p1023rdb/law.c b/board/freescale/p1023rdb/law.c new file mode 100644 index 000000000..331662cfc --- /dev/null +++ b/board/freescale/p1023rdb/law.c @@ -0,0 +1,34 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/fsl_law.h> +#include <asm/mmu.h> + +struct law_entry law_table[] = { +	SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_LBC), +	SET_LAW(CONFIG_SYS_QMAN_MEM_PHYS, LAW_SIZE_4M, +		LAW_TRGT_IF_DPAA_SWP_SRAM), +	SET_LAW(CONFIG_SYS_FLASH_BASE_PHYS, LAW_SIZE_256M, LAW_TRGT_IF_LBC), +}; + +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/p1023rdb/p1023rdb.c b/board/freescale/p1023rdb/p1023rdb.c new file mode 100644 index 000000000..918398bd8 --- /dev/null +++ b/board/freescale/p1023rdb/p1023rdb.c @@ -0,0 +1,161 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Authors:  Roy Zang <tie-fei.zang@freescale.com> + *           Chunhe Lan <Chunhe.Lan@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/io.h> +#include <asm/cache.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#include <asm/immap_85xx.h> +#include <asm/fsl_pci.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_portals.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <netdev.h> +#include <malloc.h> +#include <fm_eth.h> +#include <fsl_mdio.h> +#include <miiphy.h> +#include <phy.h> +#include <asm/fsl_dtsec.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_early_init_f(void) +{ +	fsl_lbc_t *lbc = LBC_BASE_ADDR; + +	/* Set ABSWP to implement conversion of addresses in the LBC */ +	setbits_be32(&lbc->lbcr, CONFIG_SYS_LBC_LBCR); + +	return 0; +} + +int checkboard(void) +{ +	printf("Board: P1023 RDB\n"); + +	return 0; +} + +#ifdef CONFIG_PCI +void pci_init_board(void) +{ +	fsl_pcie_init_board(0); +} +#endif + +int board_early_init_r(void) +{ +	const unsigned int flashbase = CONFIG_SYS_FLASH_BASE; +	const u8 flash_esel = find_tlb_idx((void *)flashbase, 1); + +	/* +	 * Remap Boot flash + PROMJET region to caching-inhibited +	 * so that flash can be erased properly. +	 */ + +	/* Flush d-cache and invalidate i-cache of any FLASH data */ +	flush_dcache(); +	invalidate_icache(); + +	/* invalidate existing TLB entry for flash + promjet */ +	disable_tlb(flash_esel); + +	set_tlb(1, flashbase, CONFIG_SYS_FLASH_BASE_PHYS, +		MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		0, flash_esel, BOOKE_PAGESZ_256M, 1); + +	setup_portals(); + +	return 0; +} + +unsigned long get_board_sys_clk(ulong dummy) +{ +	return gd->bus_clk; +} + +unsigned long get_board_ddr_clk(ulong dummy) +{ +	return gd->mem_clk; +} + +int board_eth_init(bd_t *bis) +{ +	ccsr_gur_t *gur = (ccsr_gur_t *)CONFIG_SYS_MPC85xx_GUTS_ADDR; +	struct fsl_pq_mdio_info dtsec_mdio_info; + +	/* +	 * Need to set dTSEC 1 pin multiplexing to TSEC. The default setting +	 * is not correct. +	 */ +	setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_TSEC1_1); + +	dtsec_mdio_info.regs = +		(struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR; +	dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; + +	/* Register the 1G MDIO bus */ +	fsl_pq_mdio_init(bis, &dtsec_mdio_info); + +	fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR); +	fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR); + +	fm_info_set_mdio(FM1_DTSEC1, +			 miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); +	fm_info_set_mdio(FM1_DTSEC2, +			 miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); + +#ifdef CONFIG_FMAN_ENET +	cpu_eth_init(bis); +#endif + +	return pci_eth_init(bis); +} + +#if defined(CONFIG_OF_BOARD_SETUP) +void ft_board_setup(void *blob, bd_t *bd) +{ +	phys_addr_t base; +	phys_size_t size; + +	ft_cpu_setup(blob, bd); + +	base = getenv_bootm_low(); +	size = getenv_bootm_size(); + +	fdt_fixup_memory(blob, (u64)base, (u64)size); + +#ifdef CONFIG_HAS_FSL_DR_USB +	fdt_fixup_dr_usb(blob, bd); +#endif + +	fdt_fixup_fman_ethernet(blob); +} +#endif diff --git a/board/freescale/p1023rdb/tlb.c b/board/freescale/p1023rdb/tlb.c new file mode 100644 index 000000000..3417c0f01 --- /dev/null +++ b/board/freescale/p1023rdb/tlb.c @@ -0,0 +1,115 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { +	/* TLB 0 - for temp stack in cache */ +	SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR, CONFIG_SYS_INIT_RAM_ADDR, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 4 * 1024, +		      CONFIG_SYS_INIT_RAM_ADDR + 4 * 1024, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 8 * 1024, +		      CONFIG_SYS_INIT_RAM_ADDR + 8 * 1024, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 12 * 1024, +		      CONFIG_SYS_INIT_RAM_ADDR + 12 * 1024, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 0, BOOKE_PAGESZ_4K, 0), + +	/* TLB 1 */ +	/* *I*** - Covers boot page */ +	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I, +		      0, 0, BOOKE_PAGESZ_4K, 1), + +	/* *I*G* - CCSRBAR */ +	SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 1, BOOKE_PAGESZ_4M, 1), + +	/* W**G* - Flash, localbus */ +	/* This will be changed to *I*G* after relocation to RAM. */ +	SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, +		      0, 2, BOOKE_PAGESZ_256M, 1), + +	/* *I*G* - PCI */ +	SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT, CONFIG_SYS_PCIE3_MEM_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 3, BOOKE_PAGESZ_1G, 1), + +	/* *I*G* - PCI */ +	SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT + 0x40000000, +		      CONFIG_SYS_PCIE3_MEM_PHYS + 0x40000000, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 4, BOOKE_PAGESZ_256M, 1), + +	SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT + 0x50000000, +		      CONFIG_SYS_PCIE3_MEM_PHYS + 0x50000000, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 5, BOOKE_PAGESZ_256M, 1), + +	/* *I*G* - PCI I/O */ +	SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_IO_VIRT, CONFIG_SYS_PCIE3_IO_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 6, BOOKE_PAGESZ_256K, 1), + +	/* Bman/Qman */ +	SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE, CONFIG_SYS_BMAN_MEM_PHYS, +		      MAS3_SW|MAS3_SR, 0, +		      0, 7, BOOKE_PAGESZ_1M, 1), +	SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE + 0x00100000, +		      CONFIG_SYS_BMAN_MEM_PHYS + 0x00100000, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 8, BOOKE_PAGESZ_1M, 1), +	SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE, CONFIG_SYS_QMAN_MEM_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_M, +		      0, 9, BOOKE_PAGESZ_1M, 1), +	SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE + 0x00100000, +		      CONFIG_SYS_QMAN_MEM_PHYS + 0x00100000, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 10, BOOKE_PAGESZ_1M, 1), + +	SET_TLB_ENTRY(1, CONFIG_SYS_NAND_BASE, CONFIG_SYS_NAND_BASE_PHYS, +		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, +		      0, 11, BOOKE_PAGESZ_16K, 1), + +#ifdef CONFIG_SYS_RAMBOOT +	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, +		      CONFIG_SYS_DDR_SDRAM_BASE, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 12, BOOKE_PAGESZ_256M, 1), + +	SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE + 0x10000000, +		      CONFIG_SYS_DDR_SDRAM_BASE + 0x10000000, +		      MAS3_SX|MAS3_SW|MAS3_SR, 0, +		      0, 13, BOOKE_PAGESZ_256M, 1), +#endif +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/t4qds/tlb.c b/board/freescale/t4qds/tlb.c index 92c01cf95..a138d5a9e 100644 --- a/board/freescale/t4qds/tlb.c +++ b/board/freescale/t4qds/tlb.c @@ -55,6 +55,15 @@ struct fsl_e_tlb_entry tlb_table[] = {  	SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR,  			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  			0, 0, BOOKE_PAGESZ_1M, 1), +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +	/* +	 * SRIO_PCIE_BOOT-SLAVE. When slave boot, the address of the +	 * space is at 0xfff00000, it covered the 0xfffff000. +	 */ +	SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR, +		      CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, +		      0, 0, BOOKE_PAGESZ_1M, 1),  #else  	SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000,  		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, @@ -130,6 +139,16 @@ struct fsl_e_tlb_entry tlb_table[] = {  	SET_TLB_ENTRY(1, QIXIS_BASE, QIXIS_BASE_PHYS,  		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  		      0, 17, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +	/* +	 * SRIO_PCIE_BOOT-SLAVE. 1M space from 0xffe00000 for +	 * fetching ucode and ENV from master +	 */ +	SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR, +		      CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, +		      MAS3_SX|MAS3_SW|MAS3_SR, MAS2_G, +		      0, 18, BOOKE_PAGESZ_1M, 1), +#endif  }; diff --git a/board/ifm/ac14xx/ac14xx.c b/board/ifm/ac14xx/ac14xx.c index 74425912d..dc2aff099 100644 --- a/board/ifm/ac14xx/ac14xx.c +++ b/board/ifm/ac14xx/ac14xx.c @@ -23,6 +23,10 @@  #include <i2c.h>  #endif +static int eeprom_diag; +static int mac_diag; +static int gpio_diag; +  DECLARE_GLOBAL_DATA_PTR;  static void gpio_configure(void) @@ -37,7 +41,7 @@ static void gpio_configure(void)  	/*  	 * out_be32(&gpioregs->gpdir, 0xC2293020); -	 * workaround for a hardware affect: configure direction in pieces, +	 * workaround for a hardware effect: configure direction in pieces,  	 * setting all outputs at once drops the reset line too low and  	 * makes us lose the MII connection (breaks ethernet for us)  	 */ @@ -126,8 +130,6 @@ static u32 gpio_querykbd(void)  /* excerpt from the recovery's hw_info.h */ -static int eeprom_diag = 1; -  struct __attribute__ ((__packed__)) eeprom_layout {  	char	magic[3];	/** 'ifm' */  	u8	len[2];		/** content length without magic/len fields */ @@ -209,6 +211,7 @@ static int read_eeprom(void)  int mac_read_from_eeprom(void)  {  	const u8 *mac; +	const char *mac_txt;  	if (read_eeprom()) {  		printf("I2C EEPROM read failed.\n"); @@ -230,8 +233,13 @@ int mac_read_from_eeprom(void)  	if (mac && is_valid_ether_addr(mac)) {  		eth_setenv_enetaddr("ethaddr", mac); -		printf("DIAG: %s() MAC value [%s]\n", -			__func__, getenv("ethaddr")); +		if (mac_diag) { +			mac_txt = getenv("ethaddr"); +			if (mac_txt) +				printf("DIAG: MAC value [%s]\n", mac_txt); +			else +				printf("DIAG: failed to setup MAC env\n"); +		}  	}  	return 0; @@ -326,42 +334,38 @@ int misc_init_r(void)  	gpio_configure();  	/* -	 * check the GPIO keyboard, -	 * enforced start of the recovery when +	 * enforce the start of the recovery system when  	 * - the appropriate keys were pressed -	 * - a previous installation was aborted or has failed  	 * - "some" external software told us to +	 * - a previous installation was aborted or has failed  	 */  	want_recovery = 0;  	keys = gpio_querykbd(); -	printf("GPIO keyboard status [0x%08X]\n", keys); -	/* XXX insist in the _exact_ combination? */ +	if (gpio_diag) +		printf("GPIO keyboard status [0x%02X]\n", keys);  	if ((keys & GPIOKEY_BITS_RECOVERY) == GPIOKEY_BITS_RECOVERY) { -		printf("GPIO keyboard requested RECOVERY\n"); -		/* XXX TODO -		 * refine the logic to detect the first keypress, and -		 * wait to recheck IF it was the recovery combination? -		 */ +		printf("detected recovery request (keyboard)\n");  		want_recovery = 1;  	} -	s = getenv("install_in_progress"); +	s = getenv("want_recovery");  	if ((s != NULL) && (*s != '\0')) { -		printf("previous installation aborted, running RECOVERY\n"); +		printf("detected recovery request (environment)\n");  		want_recovery = 1;  	} -	s = getenv("install_failed"); +	s = getenv("install_in_progress");  	if ((s != NULL) && (*s != '\0')) { -		printf("previous installation FAILED, running RECOVERY\n"); +		printf("previous installation has not completed\n");  		want_recovery = 1;  	} -	s = getenv("want_recovery"); +	s = getenv("install_failed");  	if ((s != NULL) && (*s != '\0')) { -		printf("running RECOVERY according to the request\n"); +		printf("previous installation has failed\n");  		want_recovery = 1;  	} - -	if (want_recovery) +	if (want_recovery) { +		printf("enforced start of the recovery system\n");  		setenv("bootcmd", "run recovery"); +	}  	/*  	 * boot the recovery system without waiting; boot the diff --git a/board/isee/igep0033/board.c b/board/isee/igep0033/board.c index 826ceadd8..ea3bea50f 100644 --- a/board/isee/igep0033/board.c +++ b/board/isee/igep0033/board.c @@ -36,37 +36,13 @@  DECLARE_GLOBAL_DATA_PTR;  static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; -#ifdef CONFIG_SPL_BUILD -static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE; -#endif  /* MII mode defines */  #define RMII_MODE_ENABLE	0x4D  static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; -/* UART Defines */  #ifdef CONFIG_SPL_BUILD -#define UART_RESET		(0x1 << 1) -#define UART_CLK_RUNNING_MASK	0x1 -#define UART_SMART_IDLE_EN	(0x1 << 0x3) - -static void rtc32k_enable(void) -{ -	struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; - -	/* -	 * Unlock the RTC's registers.  For more details please see the -	 * RTC_SS section of the TRM.  In order to unlock we need to -	 * write these specific values (keys) in this order. -	 */ -	writel(0x83e70b13, &rtc->kick0r); -	writel(0x95a4f1e0, &rtc->kick1r); - -	/* Enable the RTC 32K OSC by setting bits 3 and 6. */ -	writel((1 << 3) | (1 << 6), &rtc->osc); -} -  static const struct ddr_data ddr3_data = {  	.datardsratio0 = K4B2G1646EBIH9_RD_DQS,  	.datawdsratio0 = K4B2G1646EBIH9_WR_DQS, @@ -131,23 +107,9 @@ void s_init(void)  	/* Enable RTC32K clock */  	rtc32k_enable(); -	/* UART softreset */ -	u32 regval; -  	enable_uart0_pin_mux(); -	regval = readl(&uart_base->uartsyscfg); -	regval |= UART_RESET; -	writel(regval, &uart_base->uartsyscfg); -	while ((readl(&uart_base->uartsyssts) & -		UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK) -		; - -	/* Disable smart idle */ -	regval = readl(&uart_base->uartsyscfg); -	regval |= UART_SMART_IDLE_EN; -	writel(regval, &uart_base->uartsyscfg); - +	uart_soft_reset();  	gd = &gdata;  	preloader_console_init(); diff --git a/board/phytec/pcm051/board.c b/board/phytec/pcm051/board.c index 93c611dfc..0cca8d75b 100644 --- a/board/phytec/pcm051/board.c +++ b/board/phytec/pcm051/board.c @@ -39,9 +39,6 @@  DECLARE_GLOBAL_DATA_PTR;  static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; -#ifdef CONFIG_SPL_BUILD -static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE; -#endif  /* MII mode defines */  #define MII_MODE_ENABLE		0x0 @@ -50,31 +47,11 @@ static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE;  static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; -/* UART defines */  #ifdef CONFIG_SPL_BUILD -#define UART_RESET		(0x1 << 1) -#define UART_CLK_RUNNING_MASK	0x1 -#define UART_SMART_IDLE_EN	(0x1 << 0x3)  /* DDR RAM defines */  #define DDR_CLK_MHZ		303 /* DDR_DPLL_MULT value */ -static void rtc32k_enable(void) -{ -	struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; - -	/* -	 * Unlock the RTC's registers.  For more details please see the -	 * RTC_SS section of the TRM.  In order to unlock we need to -	 * write these specific values (keys) in this order. -	 */ -	writel(0x83e70b13, &rtc->kick0r); -	writel(0x95a4f1e0, &rtc->kick1r); - -	/* Enable the RTC 32K OSC by setting bits 3 and 6. */ -	writel((1 << 3) | (1 << 6), &rtc->osc); -} -  static const struct ddr_data ddr3_data = {  	.datardsratio0 = MT41J256M8HX15E_RD_DQS,  	.datawdsratio0 = MT41J256M8HX15E_WR_DQS, @@ -141,22 +118,8 @@ void s_init(void)  	/* Enable RTC32K clock */  	rtc32k_enable(); -	/* UART softreset */ -	u32 regval; -  	enable_uart0_pin_mux(); - -	regval = readl(&uart_base->uartsyscfg); -	regval |= UART_RESET; -	writel(regval, &uart_base->uartsyscfg); -	while ((readl(&uart_base->uartsyssts) &	UART_CLK_RUNNING_MASK) -		!= UART_CLK_RUNNING_MASK) -		; - -	/* Disable smart idle */ -	regval = readl(&uart_base->uartsyscfg); -	regval |= UART_SMART_IDLE_EN; -	writel(regval, &uart_base->uartsyscfg); +	uart_soft_reset();  	gd = &gdata; diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 8da973b30..93375a64b 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -30,6 +30,10 @@  		spi2 = "/spi@12d40000";  		spi3 = "/spi@131a0000";  		spi4 = "/spi@131b0000"; +		mmc0 = "/mmc@12200000"; +		mmc1 = "/mmc@12210000"; +		mmc2 = "/mmc@12220000"; +		mmc3 = "/mmc@12230000";  	};  	sromc@12250000 { @@ -119,4 +123,24 @@  		samsung,ycbcr-coeff = <0>;  		samsung,color-depth = <1>;  	}; + +	mmc@12200000 { +		samsung,bus-width = <8>; +		samsung,timing = <1 3 3>; +		samsung,removable = <0>; +	}; + +	mmc@12210000 { +		status = "disabled"; +	}; + +	mmc@12220000 { +		samsung,bus-width = <4>; +		samsung,timing = <1 2 3>; +		samsung,removable = <1>; +	}; + +	mmc@12230000 { +		status = "disabled"; +	};  }; diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts index 24658c198..d2ccc6675 100644 --- a/board/samsung/dts/exynos5250-snow.dts +++ b/board/samsung/dts/exynos5250-snow.dts @@ -32,6 +32,33 @@  		spi4 = "/spi@131b0000";  	}; +	i2c4: i2c@12ca0000 { +		cros-ec@1e { +			reg = <0x1e>; +			compatible = "google,cros-ec"; +			i2c-max-frequency = <100000>; +			ec-interrupt = <&gpio 782 1>; +		}; + +		power-regulator@48 { +			compatible = "ti,tps65090"; +			reg = <0x48>; +		}; +	}; + +	spi@131b0000 { +		spi-max-frequency = <1000000>; +		spi-deactivate-delay = <100>; +		cros-ec@0 { +			reg = <0>; +			compatible = "google,cros-ec"; +			spi-max-frequency = <5000000>; +			ec-interrupt = <&gpio 782 1>; +			optimise-flash-write; +			status = "disabled"; +		}; +	}; +  	sound@12d60000 {  		samsung,i2s-epll-clock-frequency = <192000000>;  		samsung,i2s-sampling-rate = <48000>; @@ -69,4 +96,58 @@  		samsung,dc-value	= <25>;  	}; +	cros-ec-keyb { +		compatible = "google,cros-ec-keyb"; +		google,key-rows = <8>; +		google,key-columns = <13>; +		google,repeat-delay-ms = <240>; +		google,repeat-rate-ms = <30>; +		google,ghost-filter; +		/* +		 * Keymap entries take the form of 0xRRCCKKKK where +		 * RR=Row CC=Column KKKK=Key Code +		 * The values below are for a US keyboard layout and +		 * are taken from the Linux driver. Note that the +		 * 102ND key is not used for US keyboards. +		 */ +		linux,keymap = < +			/* CAPSLCK F1         B          F10     */ +			0x0001003a 0x0002003b 0x00030030 0x00040044 +			/* N       =          R_ALT      ESC     */ +			0x00060031 0x0008000d 0x000a0064 0x01010001 +			/* F4      G          F7         H       */ +			0x0102003e 0x01030022 0x01040041 0x01060023 +			/* '       F9         BKSPACE    L_CTRL  */ +			0x01080028 0x01090043 0x010b000e 0x0200001d +			/* TAB     F3         T          F6      */ +			0x0201000f 0x0202003d 0x02030014 0x02040040 +			/* ]       Y          102ND      [       */ +			0x0205001b 0x02060015 0x02070056 0x0208001a +			/* F8      GRAVE      F2         5       */ +			0x02090042 0x03010029 0x0302003c 0x03030006 +			/* F5      6          -          \       */ +			0x0304003f 0x03060007 0x0308000c 0x030b002b +			/* R_CTRL  A          D          F       */ +			0x04000061 0x0401001e 0x04020020 0x04030021 +			/* S       K          J          ;       */ +			0x0404001f 0x04050025 0x04060024 0x04080027 +			/* L       ENTER      Z          C       */ +			0x04090026 0x040b001c 0x0501002c 0x0502002e +			/* V       X          ,          M       */ +			0x0503002f 0x0504002d 0x05050033 0x05060032 +			/* L_SHIFT /          .          SPACE   */ +			0x0507002a 0x05080035 0x05090034 0x050B0039 +			/* 1       3          4          2       */ +			0x06010002 0x06020004 0x06030005 0x06040003 +			/* 8       7          0          9       */ +			0x06050009 0x06060008 0x0608000b 0x0609000a +			/* L_ALT   DOWN       RIGHT      Q       */ +			0x060a0038 0x060b006c 0x060c006a 0x07010010 +			/* E       R          W          I       */ +			0x07020012 0x07030013 0x07040011 0x07050017 +			/* U       R_SHIFT    P          O       */ +			0x07060016 0x07070036 0x07080019 0x07090018 +			/* UP      LEFT    */ +			0x070b0067 0x070c0069>; +	};  }; diff --git a/board/samsung/origen/lowlevel_init.S b/board/samsung/origen/lowlevel_init.S index 9daa0da61..be9d41826 100644 --- a/board/samsung/origen/lowlevel_init.S +++ b/board/samsung/origen/lowlevel_init.S @@ -87,12 +87,14 @@ lowlevel_init:  1:  	/* for UART */  	bl uart_asm_init +	bl arch_cpu_init  	bl tzpc_init  	pop	{pc}  wakeup_reset:  	bl system_clock_init  	bl mem_ctrl_asm_init +	bl arch_cpu_init  	bl tzpc_init  exit_wakeup: @@ -353,45 +355,3 @@ uart_asm_init:  	nop  	nop -/* Setting TZPC[TrustZone Protection Controller] */ -tzpc_init: -	ldr	r0, =TZPC0_BASE -	mov	r1, #R0SIZE -	str	r1, [r0] -	mov	r1, #DECPROTXSET -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	ldr	r0, =TZPC1_BASE -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	ldr	r0, =TZPC2_BASE -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	ldr	r0, =TZPC3_BASE -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	ldr	r0, =TZPC4_BASE -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	ldr	r0, =TZPC5_BASE -	str	r1, [r0, #TZPC_DECPROT0SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT1SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT2SET_OFFSET] -	str	r1, [r0, #TZPC_DECPROT3SET_OFFSET] - -	mov	pc, lr diff --git a/board/samsung/origen/origen_setup.h b/board/samsung/origen/origen_setup.h index 930b94850..926a4ccc2 100644 --- a/board/samsung/origen/origen_setup.h +++ b/board/samsung/origen/origen_setup.h @@ -121,19 +121,6 @@  #define UBRDIV_OFFSET		0x28  #define UFRACVAL_OFFSET		0x2C -/* TZPC : Register Offsets */ -#define TZPC0_BASE		0x10110000 -#define TZPC1_BASE		0x10120000 -#define TZPC2_BASE		0x10130000 -#define TZPC3_BASE		0x10140000 -#define TZPC4_BASE		0x10150000 -#define TZPC5_BASE		0x10160000 - -#define TZPC_DECPROT0SET_OFFSET	0x804 -#define TZPC_DECPROT1SET_OFFSET	0x810 -#define TZPC_DECPROT2SET_OFFSET	0x81C -#define TZPC_DECPROT3SET_OFFSET	0x828 -  /* CLK_SRC_CPU */  #define MUX_HPM_SEL_MOUTAPLL		0x0  #define MUX_HPM_SEL_SCLKMPLL		0x1 @@ -617,16 +604,4 @@   * UBRFRACVAL = ((((800MHz*10/(115200*16) -10))%10)*16/10)   */  #define UFRACVAL_VAL		0x4 - -/* - * TZPC Register Value : - * R0SIZE: 0x0 : Size of secured ram - */ -#define R0SIZE			0x0 - -/* - * TZPC Decode Protection Register Value : - * DECPROTXSET: 0xFF : Set Decode region to non-secure - */ -#define DECPROTXSET		0xFF  #endif diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index 47c6a5a46..f2c32ee4c 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -28,12 +28,15 @@ SOBJS	:= lowlevel_init.o  COBJS	:= clock_init.o  COBJS	+= dmc_common.o dmc_init_ddr3.o -COBJS	+= tzpc_init.o  COBJS	+= smdk5250_spl.o  ifndef CONFIG_SPL_BUILD +ifdef CONFIG_OF_CONTROL +COBJS	+= exynos5-dt.o +else  COBJS	+= smdk5250.o  endif +endif  ifdef CONFIG_SPL_BUILD  COBJS	+= spl_boot.o diff --git a/board/samsung/smdk5250/clock_init.c b/board/samsung/smdk5250/clock_init.c index 5b9e82fdf..b288e66f0 100644 --- a/board/samsung/smdk5250/clock_init.c +++ b/board/samsung/smdk5250/clock_init.c @@ -28,10 +28,14 @@  #include <asm/arch/clk.h>  #include <asm/arch/clock.h>  #include <asm/arch/spl.h> +#include <asm/arch/dwmmc.h>  #include "clock_init.h"  #include "setup.h" +#define FSYS1_MMC0_DIV_MASK	0xff0f +#define FSYS1_MMC0_DIV_VAL	0x0701 +  DECLARE_GLOBAL_DATA_PTR;  struct arm_clk_ratios arm_clk_ratios[] = { @@ -664,3 +668,17 @@ void clock_init_dp_clock(void)  	/* We run DP at 267 Mhz */  	setbits_le32(&clk->div_disp1_0, CLK_DIV_DISP1_0_FIMD1);  } + +/* + * Set clock divisor value for booting from EMMC. + * Set DWMMC channel-0 clk div to operate mmc0 device at 50MHz. + */ +void emmc_boot_clk_div_set(void) +{ +	struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; +	unsigned int div_mmc; + +	div_mmc = readl((unsigned int) &clk->div_fsys1) & ~FSYS1_MMC0_DIV_MASK; +	div_mmc |= FSYS1_MMC0_DIV_VAL; +	writel(div_mmc, (unsigned int) &clk->div_fsys1); +} diff --git a/board/samsung/smdk5250/clock_init.h b/board/samsung/smdk5250/clock_init.h index f751bcb65..20a1d47e0 100644 --- a/board/samsung/smdk5250/clock_init.h +++ b/board/samsung/smdk5250/clock_init.h @@ -146,4 +146,9 @@ struct mem_timings *clock_get_mem_timings(void);   * Initialize clock for the device   */  void system_clock_init(void); + +/* + * Set clock divisor value for booting from EMMC. + */ +void emmc_boot_clk_div_set(void);  #endif diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c new file mode 100644 index 000000000..aacf43eaa --- /dev/null +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <cros_ec.h> +#include <fdtdec.h> +#include <asm/io.h> +#include <errno.h> +#include <i2c.h> +#include <netdev.h> +#include <spi.h> +#include <asm/arch/cpu.h> +#include <asm/arch/dwmmc.h> +#include <asm/arch/gpio.h> +#include <asm/arch/mmc.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/power.h> +#include <asm/arch/sromc.h> +#include <power/pmic.h> +#include <power/max77686_pmic.h> +#include <tmu.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined CONFIG_EXYNOS_TMU +/* + * Boot Time Thermal Analysis for SoC temperature threshold breach + */ +static void boot_temp_check(void) +{ +	int temp; + +	switch (tmu_monitor(&temp)) { +	/* Status TRIPPED ans WARNING means corresponding threshold breach */ +	case TMU_STATUS_TRIPPED: +		puts("EXYNOS_TMU: TRIPPING! Device power going down ...\n"); +		set_ps_hold_ctrl(); +		hang(); +		break; +	case TMU_STATUS_WARNING: +		puts("EXYNOS_TMU: WARNING! Temperature very high\n"); +		break; +	/* +	 * TMU_STATUS_INIT means something is wrong with temperature sensing +	 * and TMU status was changed back from NORMAL to INIT. +	 */ +	case TMU_STATUS_INIT: +	default: +		debug("EXYNOS_TMU: Unknown TMU state\n"); +	} +} +#endif + +struct local_info { +	struct cros_ec_dev *cros_ec_dev;	/* Pointer to cros_ec device */ +	int cros_ec_err;			/* Error for cros_ec, 0 if ok */ +}; + +static struct local_info local; + +#ifdef CONFIG_USB_EHCI_EXYNOS +int board_usb_vbus_init(void) +{ +	struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) +						samsung_get_base_gpio_part1(); + +	/* Enable VBUS power switch */ +	s5p_gpio_direction_output(&gpio1->x2, 6, 1); + +	/* VBUS turn ON time */ +	mdelay(3); + +	return 0; +} +#endif + +#ifdef CONFIG_SOUND_MAX98095 +static void  board_enable_audio_codec(void) +{ +	struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) +						samsung_get_base_gpio_part1(); + +	/* Enable MAX98095 Codec */ +	s5p_gpio_direction_output(&gpio1->x1, 7, 1); +	s5p_gpio_set_pull(&gpio1->x1, 7, GPIO_PULL_NONE); +} +#endif + +struct cros_ec_dev *board_get_cros_ec_dev(void) +{ +	return local.cros_ec_dev; +} + +static int board_init_cros_ec_devices(const void *blob) +{ +	local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev); +	if (local.cros_ec_err) +		return -1;  /* Will report in board_late_init() */ + +	return 0; +} + +int board_init(void) +{ +	gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); + +#if defined CONFIG_EXYNOS_TMU +	if (tmu_init(gd->fdt_blob) != TMU_STATUS_NORMAL) { +		debug("%s: Failed to init TMU\n", __func__); +		return -1; +	} +	boot_temp_check(); +#endif + +#ifdef CONFIG_EXYNOS_SPI +	spi_init(); +#endif + +	if (board_init_cros_ec_devices(gd->fdt_blob)) +		return -1; + +#ifdef CONFIG_USB_EHCI_EXYNOS +	board_usb_vbus_init(); +#endif +#ifdef CONFIG_SOUND_MAX98095 +	board_enable_audio_codec(); +#endif +	return 0; +} + +int dram_init(void) +{ +	int i; +	u32 addr; + +	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { +		addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); +		gd->ram_size += get_ram_size((long *)addr, SDRAM_BANK_SIZE); +	} +	return 0; +} + +#if defined(CONFIG_POWER) +static int pmic_reg_update(struct pmic *p, int reg, uint regval) +{ +	u32 val; +	int ret = 0; + +	ret = pmic_reg_read(p, reg, &val); +	if (ret) { +		debug("%s: PMIC %d register read failed\n", __func__, reg); +		return -1; +	} +	val |= regval; +	ret = pmic_reg_write(p, reg, val); +	if (ret) { +		debug("%s: PMIC %d register write failed\n", __func__, reg); +		return -1; +	} +	return 0; +} + +int power_init_board(void) +{ +	struct pmic *p; + +	set_ps_hold_ctrl(); + +	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + +	if (pmic_init(I2C_PMIC)) +		return -1; + +	p = pmic_get("MAX77686_PMIC"); +	if (!p) +		return -ENODEV; + +	if (pmic_probe(p)) +		return -1; + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN)) +		return -1; + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT, +			    MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V)) +		return -1; + +	/* VDD_MIF */ +	if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT, +			   MAX77686_BUCK1OUT_1V)) { +		debug("%s: PMIC %d register write failed\n", __func__, +		      MAX77686_REG_PMIC_BUCK1OUT); +		return -1; +	} + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL, +			    MAX77686_BUCK1CTRL_EN)) +		return -1; + +	/* VDD_ARM */ +	if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1, +			   MAX77686_BUCK2DVS1_1_3V)) { +		debug("%s: PMIC %d register write failed\n", __func__, +		      MAX77686_REG_PMIC_BUCK2DVS1); +		return -1; +	} + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1, +			    MAX77686_BUCK2CTRL_ON)) +		return -1; + +	/* VDD_INT */ +	if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1, +			   MAX77686_BUCK3DVS1_1_0125V)) { +		debug("%s: PMIC %d register write failed\n", __func__, +		      MAX77686_REG_PMIC_BUCK3DVS1); +		return -1; +	} + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL, +			    MAX77686_BUCK3CTRL_ON)) +		return -1; + +	/* VDD_G3D */ +	if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1, +			   MAX77686_BUCK4DVS1_1_2V)) { +		debug("%s: PMIC %d register write failed\n", __func__, +		      MAX77686_REG_PMIC_BUCK4DVS1); +		return -1; +	} + +	if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1, +			    MAX77686_BUCK3CTRL_ON)) +		return -1; + +	/* VDD_LDO2 */ +	if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1, +			    MAX77686_LD02CTRL1_1_5V | EN_LDO)) +		return -1; + +	/* VDD_LDO3 */ +	if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1, +			    MAX77686_LD03CTRL1_1_8V | EN_LDO)) +		return -1; + +	/* VDD_LDO5 */ +	if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1, +			    MAX77686_LD05CTRL1_1_8V | EN_LDO)) +		return -1; + +	/* VDD_LDO10 */ +	if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1, +			    MAX77686_LD10CTRL1_1_8V | EN_LDO)) +		return -1; + +	return 0; +} +#endif + +void dram_init_banksize(void) +{ +	int i; +	u32 addr, size; + +	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { +		addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); +		size = get_ram_size((long *)addr, SDRAM_BANK_SIZE); + +		gd->bd->bi_dram[i].start = addr; +		gd->bd->bi_dram[i].size = size; +	} +} + +static int decode_sromc(const void *blob, struct fdt_sromc *config) +{ +	int err; +	int node; + +	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_SROMC); +	if (node < 0) { +		debug("Could not find SROMC node\n"); +		return node; +	} + +	config->bank = fdtdec_get_int(blob, node, "bank", 0); +	config->width = fdtdec_get_int(blob, node, "width", 2); + +	err = fdtdec_get_int_array(blob, node, "srom-timing", config->timing, +			FDT_SROM_TIMING_COUNT); +	if (err < 0) { +		debug("Could not decode SROMC configuration Error: %s\n", +		      fdt_strerror(err)); +		return -FDT_ERR_NOTFOUND; +	} +	return 0; +} + +int board_eth_init(bd_t *bis) +{ +#ifdef CONFIG_SMC911X +	u32 smc_bw_conf, smc_bc_conf; +	struct fdt_sromc config; +	fdt_addr_t base_addr; +	int node; + +	node = decode_sromc(gd->fdt_blob, &config); +	if (node < 0) { +		debug("%s: Could not find sromc configuration\n", __func__); +		return 0; +	} +	node = fdtdec_next_compatible(gd->fdt_blob, node, COMPAT_SMSC_LAN9215); +	if (node < 0) { +		debug("%s: Could not find lan9215 configuration\n", __func__); +		return 0; +	} + +	/* We now have a node, so any problems from now on are errors */ +	base_addr = fdtdec_get_addr(gd->fdt_blob, node, "reg"); +	if (base_addr == FDT_ADDR_T_NONE) { +		debug("%s: Could not find lan9215 address\n", __func__); +		return -1; +	} + +	/* Ethernet needs data bus width of 16 bits */ +	if (config.width != 2) { +		debug("%s: Unsupported bus width %d\n", __func__, +		      config.width); +		return -1; +	} +	smc_bw_conf = SROMC_DATA16_WIDTH(config.bank) +			| SROMC_BYTE_ENABLE(config.bank); + +	smc_bc_conf = SROMC_BC_TACS(config.timing[FDT_SROM_TACS])   | +			SROMC_BC_TCOS(config.timing[FDT_SROM_TCOS]) | +			SROMC_BC_TACC(config.timing[FDT_SROM_TACC]) | +			SROMC_BC_TCOH(config.timing[FDT_SROM_TCOH]) | +			SROMC_BC_TAH(config.timing[FDT_SROM_TAH])   | +			SROMC_BC_TACP(config.timing[FDT_SROM_TACP]) | +			SROMC_BC_PMC(config.timing[FDT_SROM_PMC]); + +	/* Select and configure the SROMC bank */ +	exynos_pinmux_config(PERIPH_ID_SROMC, config.bank); +	s5p_config_sromc(config.bank, smc_bw_conf, smc_bc_conf); +	return smc911x_initialize(0, base_addr); +#endif +	return 0; +} + +#ifdef CONFIG_DISPLAY_BOARDINFO +int checkboard(void) +{ +	const char *board_name; + +	board_name = fdt_getprop(gd->fdt_blob, 0, "model", NULL); +	if (board_name == NULL) +		printf("\nUnknown Board\n"); +	else +		printf("\nBoard: %s\n", board_name); + +	return 0; +} +#endif + +#ifdef CONFIG_GENERIC_MMC +int board_mmc_init(bd_t *bis) +{ +	int ret; +	/* dwmmc initializattion for available channels */ +	ret = exynos_dwmmc_init(gd->fdt_blob); +	if (ret) +		debug("dwmmc init failed\n"); + +	return ret; +} +#endif + +static int board_uart_init(void) +{ +	int err, uart_id, ret = 0; + +	for (uart_id = PERIPH_ID_UART0; uart_id <= PERIPH_ID_UART3; uart_id++) { +		err = exynos_pinmux_config(uart_id, PINMUX_FLAG_NONE); +		if (err) { +			debug("UART%d not configured\n", +			      (uart_id - PERIPH_ID_UART0)); +			ret |= err; +		} +	} +	return ret; +} + +#ifdef CONFIG_BOARD_EARLY_INIT_F +int board_early_init_f(void) +{ +	int err; +	err = board_uart_init(); +	if (err) { +		debug("UART init failed\n"); +		return err; +	} +#ifdef CONFIG_SYS_I2C_INIT_BOARD +	board_i2c_init(gd->fdt_blob); +#endif +	return err; +} +#endif + +#ifdef CONFIG_LCD +void exynos_cfg_lcd_gpio(void) +{ +	struct exynos5_gpio_part1 *gpio1 = +		(struct exynos5_gpio_part1 *)samsung_get_base_gpio_part1(); + +	/* For Backlight */ +	s5p_gpio_cfg_pin(&gpio1->b2, 0, GPIO_OUTPUT); +	s5p_gpio_set_value(&gpio1->b2, 0, 1); + +	/* LCD power on */ +	s5p_gpio_cfg_pin(&gpio1->x1, 5, GPIO_OUTPUT); +	s5p_gpio_set_value(&gpio1->x1, 5, 1); + +	/* Set Hotplug detect for DP */ +	s5p_gpio_cfg_pin(&gpio1->x0, 7, GPIO_FUNC(0x3)); +} + +void exynos_set_dp_phy(unsigned int onoff) +{ +	set_dp_phy_ctrl(onoff); +} +#endif + +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ +	stdio_print_current_devices(); + +	if (local.cros_ec_err) { +		/* Force console on */ +		gd->flags &= ~GD_FLG_SILENT; + +		printf("cros-ec communications failure %d\n", +		       local.cros_ec_err); +		puts("\nPlease reset with Power+Refresh\n\n"); +		panic("Cannot init cros-ec device"); +		return -1; +	} +	return 0; +} +#endif diff --git a/board/samsung/smdk5250/lowlevel_init.S b/board/samsung/smdk5250/lowlevel_init.S index bc6cb6f73..edc565ef7 100644 --- a/board/samsung/smdk5250/lowlevel_init.S +++ b/board/samsung/smdk5250/lowlevel_init.S @@ -75,12 +75,14 @@ lowlevel_init:  	bl	mem_ctrl_init  1: +	bl	arch_cpu_init  	bl	tzpc_init  	ldmia	r13!, {ip,pc}  wakeup_reset:  	bl	system_clock_init  	bl	mem_ctrl_init +	bl	arch_cpu_init  	bl	tzpc_init  exit_wakeup: diff --git a/board/samsung/smdk5250/setup.h b/board/samsung/smdk5250/setup.h index 34d8bc31f..eb91d1310 100644 --- a/board/samsung/smdk5250/setup.h +++ b/board/samsung/smdk5250/setup.h @@ -28,18 +28,6 @@  #include <config.h>  #include <asm/arch/dmc.h> -/* TZPC : Register Offsets */ -#define TZPC0_BASE		0x10100000 -#define TZPC1_BASE		0x10110000 -#define TZPC2_BASE		0x10120000 -#define TZPC3_BASE		0x10130000 -#define TZPC4_BASE		0x10140000 -#define TZPC5_BASE		0x10150000 -#define TZPC6_BASE		0x10160000 -#define TZPC7_BASE		0x10170000 -#define TZPC8_BASE		0x10180000 -#define TZPC9_BASE		0x10190000 -  /* APLL_CON1	*/  #define APLL_CON1_VAL	(0x00203800) @@ -458,18 +446,6 @@  /* CLK_GATE_IP_DISP1 */  #define CLK_GATE_DP1_ALLOW	(1 << 4) -/* - * TZPC Register Value : - * R0SIZE: 0x0 : Size of secured ram - */ -#define R0SIZE			0x0 - -/* - * TZPC Decode Protection Register Value : - * DECPROTXSET: 0xFF : Set Decode region to non-secure - */ -#define DECPROTXSET		0xFF -  #define DDR3PHY_CTRL_PHY_RESET	(1 << 0)  #define DDR3PHY_CTRL_PHY_RESET_OFF	(0 << 0) @@ -590,5 +566,4 @@ void update_reset_dll(struct exynos5_dmc *, enum ddr_mode);  void sdelay(unsigned long);  void mem_ctrl_init(void);  void system_clock_init(void); -void tzpc_init(void);  #endif diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 8b09e1de4..276fd4132 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -29,6 +29,7 @@  #include <netdev.h>  #include <spi.h>  #include <asm/arch/cpu.h> +#include <asm/arch/dwmmc.h>  #include <asm/arch/gpio.h>  #include <asm/arch/mmc.h>  #include <asm/arch/pinmux.h> @@ -37,39 +38,9 @@  #include <asm/arch/dp_info.h>  #include <power/pmic.h>  #include <power/max77686_pmic.h> -#include <tmu.h>  DECLARE_GLOBAL_DATA_PTR; -#if defined CONFIG_EXYNOS_TMU -/* - * Boot Time Thermal Analysis for SoC temperature threshold breach - */ -static void boot_temp_check(void) -{ -	int temp; - -	switch (tmu_monitor(&temp)) { -	/* Status TRIPPED ans WARNING means corresponding threshold breach */ -	case TMU_STATUS_TRIPPED: -		puts("EXYNOS_TMU: TRIPPING! Device power going down ...\n"); -		set_ps_hold_ctrl(); -		hang(); -		break; -	case TMU_STATUS_WARNING: -		puts("EXYNOS_TMU: WARNING! Temperature very high\n"); -		break; -	/* -	 * TMU_STATUS_INIT means something is wrong with temperature sensing -	 * and TMU status was changed back from NORMAL to INIT. -	 */ -	case TMU_STATUS_INIT: -	default: -		debug("EXYNOS_TMU: Unknown TMU state\n"); -	} -} -#endif -  #ifdef CONFIG_USB_EHCI_EXYNOS  int board_usb_vbus_init(void)  { @@ -102,14 +73,6 @@ int board_init(void)  {  	gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); -#if defined CONFIG_EXYNOS_TMU -	if (tmu_init(gd->fdt_blob) != TMU_STATUS_NORMAL) { -		debug("%s: Failed to init TMU\n", __func__); -		return -1; -	} -	boot_temp_check(); -#endif -  #ifdef CONFIG_EXYNOS_SPI  	spi_init();  #endif @@ -124,14 +87,13 @@ int board_init(void)  int dram_init(void)  { -	gd->ram_size	= get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_2, PHYS_SDRAM_2_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_3, PHYS_SDRAM_3_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_4, PHYS_SDRAM_4_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_5, PHYS_SDRAM_7_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_6, PHYS_SDRAM_7_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_7, PHYS_SDRAM_7_SIZE) -			+ get_ram_size((long *)PHYS_SDRAM_8, PHYS_SDRAM_8_SIZE); +	int i; +	u32 addr; + +	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { +		addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); +		gd->ram_size += get_ram_size((long *)addr, SDRAM_BANK_SIZE); +	}  	return 0;  } @@ -254,57 +216,15 @@ int power_init_board(void)  void dram_init_banksize(void)  { -	gd->bd->bi_dram[0].start = PHYS_SDRAM_1; -	gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1, -							PHYS_SDRAM_1_SIZE); -	gd->bd->bi_dram[1].start = PHYS_SDRAM_2; -	gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2, -							PHYS_SDRAM_2_SIZE); -	gd->bd->bi_dram[2].start = PHYS_SDRAM_3; -	gd->bd->bi_dram[2].size = get_ram_size((long *)PHYS_SDRAM_3, -							PHYS_SDRAM_3_SIZE); -	gd->bd->bi_dram[3].start = PHYS_SDRAM_4; -	gd->bd->bi_dram[3].size = get_ram_size((long *)PHYS_SDRAM_4, -							PHYS_SDRAM_4_SIZE); -	gd->bd->bi_dram[4].start = PHYS_SDRAM_5; -	gd->bd->bi_dram[4].size = get_ram_size((long *)PHYS_SDRAM_5, -							PHYS_SDRAM_5_SIZE); -	gd->bd->bi_dram[5].start = PHYS_SDRAM_6; -	gd->bd->bi_dram[5].size = get_ram_size((long *)PHYS_SDRAM_6, -							PHYS_SDRAM_6_SIZE); -	gd->bd->bi_dram[6].start = PHYS_SDRAM_7; -	gd->bd->bi_dram[6].size = get_ram_size((long *)PHYS_SDRAM_7, -							PHYS_SDRAM_7_SIZE); -	gd->bd->bi_dram[7].start = PHYS_SDRAM_8; -	gd->bd->bi_dram[7].size = get_ram_size((long *)PHYS_SDRAM_8, -							PHYS_SDRAM_8_SIZE); -} - -#ifdef CONFIG_OF_CONTROL -static int decode_sromc(const void *blob, struct fdt_sromc *config) -{ -	int err; -	int node; - -	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_SROMC); -	if (node < 0) { -		debug("Could not find SROMC node\n"); -		return node; -	} - -	config->bank = fdtdec_get_int(blob, node, "bank", 0); -	config->width = fdtdec_get_int(blob, node, "width", 2); - -	err = fdtdec_get_int_array(blob, node, "srom-timing", config->timing, -			FDT_SROM_TIMING_COUNT); -	if (err < 0) { -		debug("Could not decode SROMC configuration\n"); -		return -FDT_ERR_NOTFOUND; +	int i; +	u32 addr, size; +	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { +		addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); +		size = get_ram_size((long *)addr, SDRAM_BANK_SIZE); +		gd->bd->bi_dram[i].start = addr; +		gd->bd->bi_dram[i].size = size;  	} - -	return 0;  } -#endif  int board_eth_init(bd_t *bis)  { @@ -313,27 +233,6 @@ int board_eth_init(bd_t *bis)  	struct fdt_sromc config;  	fdt_addr_t base_addr; -#ifdef CONFIG_OF_CONTROL -	int node; - -	node = decode_sromc(gd->fdt_blob, &config); -	if (node < 0) { -		debug("%s: Could not find sromc configuration\n", __func__); -		return 0; -	} -	node = fdtdec_next_compatible(gd->fdt_blob, node, COMPAT_SMSC_LAN9215); -	if (node < 0) { -		debug("%s: Could not find lan9215 configuration\n", __func__); -		return 0; -	} - -	/* We now have a node, so any problems from now on are errors */ -	base_addr = fdtdec_get_addr(gd->fdt_blob, node, "reg"); -	if (base_addr == FDT_ADDR_T_NONE) { -		debug("%s: Could not find lan9215 address\n", __func__); -		return -1; -	} -#else  	/* Non-FDT configuration - bank number and timing parameters*/  	config.bank = CONFIG_ENV_SROM_BANK;  	config.width = 2; @@ -346,7 +245,6 @@ int board_eth_init(bd_t *bis)  	config.timing[FDT_SROM_TACP] = 0x09;  	config.timing[FDT_SROM_PMC] = 0x01;  	base_addr = CONFIG_SMC911X_BASE; -#endif  	/* Ethernet needs data bus width of 16 bits */  	if (config.width != 2) { @@ -376,17 +274,7 @@ int board_eth_init(bd_t *bis)  #ifdef CONFIG_DISPLAY_BOARDINFO  int checkboard(void)  { -#ifdef CONFIG_OF_CONTROL -	const char *board_name; - -	board_name = fdt_getprop(gd->fdt_blob, 0, "model", NULL); -	if (board_name == NULL) -		printf("\nUnknown Board\n"); -	else -		printf("\nBoard: %s\n", board_name); -#else  	printf("\nBoard: SMDK5250\n"); -#endif  	return 0;  }  #endif @@ -394,48 +282,54 @@ int checkboard(void)  #ifdef CONFIG_GENERIC_MMC  int board_mmc_init(bd_t *bis)  { -	int err; +	int err, ret = 0, index, bus_width; +	u32 base;  	err = exynos_pinmux_config(PERIPH_ID_SDMMC0, PINMUX_FLAG_8BIT_MODE); -	if (err) { +	if (err)  		debug("SDMMC0 not configured\n"); -		return err; -	} +	ret |= err; -	err = s5p_mmc_init(0, 8); -	return err; +	/*EMMC: dwmmc Channel-0 with 8 bit bus width */ +	index = 0; +	base =  samsung_get_base_mmc() + (0x10000 * index); +	bus_width = 8; +	err = exynos_dwmci_add_port(index, base, bus_width, (u32)NULL); +	if (err) +		debug("dwmmc Channel-0 init failed\n"); +	ret |= err; + +	err = exynos_pinmux_config(PERIPH_ID_SDMMC2, PINMUX_FLAG_NONE); +	if (err) +		debug("SDMMC2 not configured\n"); +	ret |= err; + +	/*SD: dwmmc Channel-2 with 4 bit bus width */ +	index = 2; +	base = samsung_get_base_mmc() + (0x10000 * index); +	bus_width = 4; +	err = exynos_dwmci_add_port(index, base, bus_width, (u32)NULL); +	if (err) +		debug("dwmmc Channel-2 init failed\n"); +	ret |= err; + +	return ret;  }  #endif  static int board_uart_init(void)  { -	int err; +	int err, uart_id, ret = 0; -	err = exynos_pinmux_config(PERIPH_ID_UART0, PINMUX_FLAG_NONE); -	if (err) { -		debug("UART0 not configured\n"); -		return err; +	for (uart_id = PERIPH_ID_UART0; uart_id <= PERIPH_ID_UART3; uart_id++) { +		err = exynos_pinmux_config(uart_id, PINMUX_FLAG_NONE); +		if (err) { +			debug("UART%d not configured\n", +			      (uart_id - PERIPH_ID_UART0)); +			ret |= err; +		}  	} - -	err = exynos_pinmux_config(PERIPH_ID_UART1, PINMUX_FLAG_NONE); -	if (err) { -		debug("UART1 not configured\n"); -		return err; -	} - -	err = exynos_pinmux_config(PERIPH_ID_UART2, PINMUX_FLAG_NONE); -	if (err) { -		debug("UART2 not configured\n"); -		return err; -	} - -	err = exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); -	if (err) { -		debug("UART3 not configured\n"); -		return err; -	} - -	return 0; +	return ret;  }  #ifdef CONFIG_BOARD_EARLY_INIT_F @@ -448,7 +342,7 @@ int board_early_init_f(void)  		return err;  	}  #ifdef CONFIG_SYS_I2C_INIT_BOARD -	board_i2c_init(gd->fdt_blob); +	board_i2c_init(NULL);  #endif  	return err;  } @@ -477,7 +371,6 @@ void exynos_set_dp_phy(unsigned int onoff)  	set_dp_phy_ctrl(onoff);  } -#ifndef CONFIG_OF_CONTROL  vidinfo_t panel_info = {  	.vl_freq	= 60,  	.vl_col		= 2560, @@ -543,13 +436,9 @@ static struct exynos_dp_platform_data dp_platform_data = {  	.edp_dev_info	= &edp_info,  }; -#endif  void init_panel_info(vidinfo_t *vid)  { -#ifndef CONFIG_OF_CONTROL -	vid->rgb_mode   = MODE_RGB_P, - +	vid->rgb_mode   = MODE_RGB_P;  	exynos_set_dp_platform_data(&dp_platform_data); -#endif  }  #endif diff --git a/board/samsung/smdk5250/spl_boot.c b/board/samsung/smdk5250/spl_boot.c index c0bcf460f..98f2286f9 100644 --- a/board/samsung/smdk5250/spl_boot.c +++ b/board/samsung/smdk5250/spl_boot.c @@ -23,16 +23,44 @@  #include<common.h>  #include<config.h> +#include <asm/arch-exynos/dmc.h> +#include <asm/arch/clock.h> +#include <asm/arch/clk.h> + +#include "clock_init.h" + +/* Index into irom ptr table */ +enum index { +	MMC_INDEX, +	EMMC44_INDEX, +	EMMC44_END_INDEX, +	SPI_INDEX, +	USB_INDEX, +}; + +/* IROM Function Pointers Table */ +u32 irom_ptr_table[] = { +	[MMC_INDEX] = 0x02020030,	/* iROM Function Pointer-SDMMC boot */ +	[EMMC44_INDEX] = 0x02020044,	/* iROM Function Pointer-EMMC4.4 boot*/ +	[EMMC44_END_INDEX] = 0x02020048,/* iROM Function Pointer +						-EMMC4.4 end boot operation */ +	[SPI_INDEX] = 0x02020058,	/* iROM Function Pointer-SPI boot */ +	[USB_INDEX] = 0x02020070,	/* iROM Function Pointer-USB boot*/ +	}; +  enum boot_mode {  	BOOT_MODE_MMC = 4,  	BOOT_MODE_SERIAL = 20, +	BOOT_MODE_EMMC = 8,     /* EMMC4.4 */  	/* Boot based on Operating Mode pin settings */  	BOOT_MODE_OM = 32,  	BOOT_MODE_USB,	/* Boot using USB download */  }; -	typedef u32 (*spi_copy_func_t)(u32 offset, u32 nblock, u32 dst); -	typedef u32 (*usb_copy_func_t)(void); +void *get_irom_func(int index) +{ +	return (void *)*(u32 *)irom_ptr_table[index]; +}  /*   * Set/clear program flow prediction and return the previous state. @@ -55,13 +83,15 @@ static int config_branch_prediction(int set_cr_z)  */  void copy_uboot_to_ram(void)  { -	spi_copy_func_t spi_copy; -	usb_copy_func_t usb_copy; -  	int is_cr_z_set;  	unsigned int sec_boot_check;  	enum boot_mode bootmode = BOOT_MODE_OM; -	u32 (*copy_bl2)(u32, u32, u32); + +	u32 (*spi_copy)(u32 offset, u32 nblock, u32 dst); +	u32 (*copy_bl2)(u32 offset, u32 nblock, u32 dst); +	u32 (*copy_bl2_from_emmc)(u32 nblock, u32 dst); +	void (*end_bootop_from_emmc)(void); +	u32 (*usb_copy)(void);  	/* Read iRAM location to check for secondary USB boot mode */  	sec_boot_check = readl(EXYNOS_IRAM_SECONDARY_BASE); @@ -73,14 +103,24 @@ void copy_uboot_to_ram(void)  	switch (bootmode) {  	case BOOT_MODE_SERIAL: -		spi_copy = *(spi_copy_func_t *)EXYNOS_COPY_SPI_FNPTR_ADDR; +		spi_copy = get_irom_func(SPI_INDEX);  		spi_copy(SPI_FLASH_UBOOT_POS, CONFIG_BL2_SIZE, -						CONFIG_SYS_TEXT_BASE); +			 CONFIG_SYS_TEXT_BASE);  		break;  	case BOOT_MODE_MMC: -		copy_bl2 = (void *) *(u32 *)COPY_BL2_FNPTR_ADDR; +		copy_bl2 = get_irom_func(MMC_INDEX);  		copy_bl2(BL2_START_OFFSET, BL2_SIZE_BLOC_COUNT, -						CONFIG_SYS_TEXT_BASE); +			 CONFIG_SYS_TEXT_BASE); +		break; +	case BOOT_MODE_EMMC: +		/* Set the FSYS1 clock divisor value for EMMC boot */ +		emmc_boot_clk_div_set(); + +		copy_bl2_from_emmc = get_irom_func(EMMC44_INDEX); +		end_bootop_from_emmc = get_irom_func(EMMC44_END_INDEX); + +		copy_bl2_from_emmc(BL2_SIZE_BLOC_COUNT, CONFIG_SYS_TEXT_BASE); +		end_bootop_from_emmc();  		break;  	case BOOT_MODE_USB:  		/* @@ -88,8 +128,7 @@ void copy_uboot_to_ram(void)  		 * before copy from USB device to RAM  		 */  		is_cr_z_set = config_branch_prediction(0); -		usb_copy = *(usb_copy_func_t *) -				EXYNOS_COPY_USB_FNPTR_ADDR; +		usb_copy = get_irom_func(USB_INDEX);  		usb_copy();  		config_branch_prediction(is_cr_z_set);  		break; @@ -117,5 +156,4 @@ void board_init_r(gd_t *id, ulong dest_addr)  	while (1)  		;  } -  void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {} diff --git a/board/samsung/smdkv310/lowlevel_init.S b/board/samsung/smdkv310/lowlevel_init.S index 7a1ea98ae..31e0e2eda 100644 --- a/board/samsung/smdkv310/lowlevel_init.S +++ b/board/samsung/smdkv310/lowlevel_init.S @@ -85,12 +85,14 @@ lowlevel_init:  1:  	/* for UART */  	bl uart_asm_init +	bl arch_cpu_init  	bl tzpc_init  	pop	{pc}  wakeup_reset:  	bl system_clock_init  	bl mem_ctrl_asm_init +	bl arch_cpu_init  	bl tzpc_init  exit_wakeup: @@ -410,61 +412,3 @@ uart_asm_init:  	nop  	nop  	nop - -/* Setting TZPC[TrustZone Protection Controller] */ -tzpc_init: -	ldr	r0, =0x10110000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	ldr	r0, =0x10120000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	ldr	r0, =0x10130000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	ldr	r0, =0x10140000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	ldr	r0, =0x10150000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	ldr	r0, =0x10160000 -	mov	r1, #0x0 -	str	r1, [r0] -	mov	r1, #0xff -	str	r1, [r0, #0x0804] -	str	r1, [r0, #0x0810] -	str	r1, [r0, #0x081C] -	str	r1, [r0, #0x0828] - -	mov	pc, lr diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index 638cc4d68..fdbe26cde 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -38,9 +38,6 @@  DECLARE_GLOBAL_DATA_PTR;  static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; -#ifdef CONFIG_SPL_BUILD -static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE; -#endif  /* MII mode defines */  #define MII_MODE_ENABLE		0x0 @@ -126,28 +123,7 @@ static int read_eeprom(void)  	return 0;  } -/* UART Defines */  #ifdef CONFIG_SPL_BUILD -#define UART_RESET		(0x1 << 1) -#define UART_CLK_RUNNING_MASK	0x1 -#define UART_SMART_IDLE_EN	(0x1 << 0x3) - -static void rtc32k_enable(void) -{ -	struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; - -	/* -	 * Unlock the RTC's registers.  For more details please see the -	 * RTC_SS section of the TRM.  In order to unlock we need to -	 * write these specific values (keys) in this order. -	 */ -	writel(0x83e70b13, &rtc->kick0r); -	writel(0x95a4f1e0, &rtc->kick1r); - -	/* Enable the RTC 32K OSC by setting bits 3 and 6. */ -	writel((1 << 3) | (1 << 6), &rtc->osc); -} -  static const struct ddr_data ddr2_data = {  	.datardsratio0 = ((MT47H128M16RT25E_RD_DQS<<30) |  			  (MT47H128M16RT25E_RD_DQS<<20) | @@ -339,9 +315,6 @@ void s_init(void)  	/* Enable RTC32K clock */  	rtc32k_enable(); -	/* UART softreset */ -	u32 regVal; -  #ifdef CONFIG_SERIAL1  	enable_uart0_pin_mux();  #endif /* CONFIG_SERIAL1 */ @@ -361,17 +334,7 @@ void s_init(void)  	enable_uart5_pin_mux();  #endif /* CONFIG_SERIAL6 */ -	regVal = readl(&uart_base->uartsyscfg); -	regVal |= UART_RESET; -	writel(regVal, &uart_base->uartsyscfg); -	while ((readl(&uart_base->uartsyssts) & -		UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK) -		; - -	/* Disable smart idle */ -	regVal = readl(&uart_base->uartsyscfg); -	regVal |= UART_SMART_IDLE_EN; -	writel(regVal, &uart_base->uartsyscfg); +	uart_soft_reset();  	gd = &gdata; diff --git a/board/ti/panda/panda.c b/board/ti/panda/panda.c index 90ae29e7c..1da5b359c 100644 --- a/board/ti/panda/panda.c +++ b/board/ti/panda/panda.c @@ -37,6 +37,11 @@  #endif  #define PANDA_ULPI_PHY_TYPE_GPIO       182 +#define PANDA_BOARD_ID_1_GPIO          101 +#define PANDA_ES_BOARD_ID_1_GPIO        48 +#define PANDA_BOARD_ID_2_GPIO          171 +#define PANDA_ES_BOARD_ID_3_GPIO         3 +#define PANDA_ES_BOARD_ID_4_GPIO         2  DECLARE_GLOBAL_DATA_PTR; @@ -66,6 +71,73 @@ int board_eth_init(bd_t *bis)  	return 0;  } +/* +* Routine: get_board_revision +* Description: Detect if we are running on a panda revision A1-A6, +*              or an ES panda board. This can be done by reading +*              the level of GPIOs and checking the processor revisions. +*              This should result in: +*			Panda 4430: +*              GPIO171, GPIO101, GPIO182: 0 1 1 => A1-A5 +*              GPIO171, GPIO101, GPIO182: 1 0 1 => A6 +*			Panda ES: +*              GPIO2, GPIO3, GPIO171, GPIO48, GPIO182: 0 0 0 1 1 => B1/B2 +*              GPIO2, GPIO3, GPIO171, GPIO48, GPIO182: 0 0 1 1 1 => B3 +*/ +int get_board_revision(void) +{ +	int board_id0, board_id1, board_id2; +	int board_id3, board_id4; +	int board_id; + +	int processor_rev = omap_revision(); + +	/* Setup the mux for the common board ID pins (gpio 171 and 182) */ +	writew((IEN | M3), (*ctrl)->control_padconf_core_base + UNIPRO_TX0); +	writew((IEN | M3), (*ctrl)->control_padconf_core_base + FREF_CLK2_OUT); + +	board_id0 = gpio_get_value(PANDA_ULPI_PHY_TYPE_GPIO); +	board_id2 = gpio_get_value(PANDA_BOARD_ID_2_GPIO); + +	if ((processor_rev >= OMAP4460_ES1_0 && +	     processor_rev <= OMAP4460_ES1_1)) { +		/* +		 * Setup the mux for the ES specific board ID pins (gpio 101, +		 * 2 and 3. +		 */ +		writew((IEN | M3), (*ctrl)->control_padconf_core_base + +				GPMC_A24); +		writew((IEN | M3), (*ctrl)->control_padconf_core_base + +				UNIPRO_RY0); +		writew((IEN | M3), (*ctrl)->control_padconf_core_base + +				UNIPRO_RX1); + +		board_id1 = gpio_get_value(PANDA_ES_BOARD_ID_1_GPIO); +		board_id3 = gpio_get_value(PANDA_ES_BOARD_ID_3_GPIO); +		board_id4 = gpio_get_value(PANDA_ES_BOARD_ID_4_GPIO); + +#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +		setenv("board_name", strcat(CONFIG_SYS_BOARD, "-es")); +#endif +		board_id = ((board_id4 << 4) | (board_id3 << 3) | +			(board_id2 << 2) | (board_id1 << 1) | (board_id0)); +	} else { +		/* Setup the mux for the Ax specific board ID pins (gpio 101) */ +		writew((IEN | M3), (*ctrl)->control_padconf_core_base + +				FREF_CLK2_OUT); + +		board_id1 = gpio_get_value(PANDA_BOARD_ID_1_GPIO); +		board_id = ((board_id2 << 2) | (board_id1 << 1) | (board_id0)); + +#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +		if ((board_id >= 0x3) && (processor_rev == OMAP4430_ES2_3)) +			setenv("board_name", strcat(CONFIG_SYS_BOARD, "-a4")); +#endif +	} + +	return board_id; +} +  /**   * @brief misc_init_r - Configure Panda board specific configurations   * such as power configurations, ethernet initialization as phase2 of @@ -82,11 +154,7 @@ int misc_init_r(void)  	if (omap_revision() == OMAP4430_ES1_0)  		return 0; -#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG -	if (omap_revision() >= OMAP4460_ES1_0 || -		omap_revision() <= OMAP4460_ES1_1) -		setenv("board_name", strcat(CONFIG_SYS_BOARD, "-es")); -#endif +	get_board_revision();  	gpio_direction_input(PANDA_ULPI_PHY_TYPE_GPIO);  	phy_type = gpio_get_value(PANDA_ULPI_PHY_TYPE_GPIO); @@ -106,7 +174,7 @@ int misc_init_r(void)  		auxclk |= AUXCLK_ENABLE_MASK;  		writel(auxclk, &scrm->auxclk3); -       } else { +	} else {  		/* ULPI PHY supplied by auxclk1 derived from PER dpll */  		debug("ULPI PHY supplied by auxclk1\n"); @@ -151,9 +219,9 @@ void set_muxconf_regs_essential(void)  	if (omap_revision() >= OMAP4460_ES1_0)  		do_set_mux((*ctrl)->control_padconf_wkup_base, -				 wkup_padconf_array_essential_4460, -				 sizeof(wkup_padconf_array_essential_4460) / -				 sizeof(struct pad_conf_entry)); +			   wkup_padconf_array_essential_4460, +			   sizeof(wkup_padconf_array_essential_4460) / +			   sizeof(struct pad_conf_entry));  }  void set_muxconf_regs_non_essential(void) @@ -165,14 +233,14 @@ void set_muxconf_regs_non_essential(void)  	if (omap_revision() < OMAP4460_ES1_0)  		do_set_mux((*ctrl)->control_padconf_core_base, -				core_padconf_array_non_essential_4430, -				sizeof(core_padconf_array_non_essential_4430) / -				sizeof(struct pad_conf_entry)); +			   core_padconf_array_non_essential_4430, +			   sizeof(core_padconf_array_non_essential_4430) / +			   sizeof(struct pad_conf_entry));  	else  		do_set_mux((*ctrl)->control_padconf_core_base, -				core_padconf_array_non_essential_4460, -				sizeof(core_padconf_array_non_essential_4460) / -				sizeof(struct pad_conf_entry)); +			   core_padconf_array_non_essential_4460, +			   sizeof(core_padconf_array_non_essential_4460) / +			   sizeof(struct pad_conf_entry));  	do_set_mux((*ctrl)->control_padconf_wkup_base,  		   wkup_padconf_array_non_essential, @@ -181,9 +249,9 @@ void set_muxconf_regs_non_essential(void)  	if (omap_revision() < OMAP4460_ES1_0)  		do_set_mux((*ctrl)->control_padconf_wkup_base, -				wkup_padconf_array_non_essential_4430, -				sizeof(wkup_padconf_array_non_essential_4430) / -				sizeof(struct pad_conf_entry)); +			   wkup_padconf_array_non_essential_4430, +			   sizeof(wkup_padconf_array_non_essential_4430) / +			   sizeof(struct pad_conf_entry));  }  #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_GENERIC_MMC) diff --git a/board/ti/ti814x/evm.c b/board/ti/ti814x/evm.c index 4759b167a..6ad3dd8fc 100644 --- a/board/ti/ti814x/evm.c +++ b/board/ti/ti814x/evm.c @@ -37,49 +37,16 @@ DECLARE_GLOBAL_DATA_PTR;  #ifdef CONFIG_SPL_BUILD  static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; -static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE;  #endif  static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;  /* UART Defines */  #ifdef CONFIG_SPL_BUILD -#define UART_RESET		(0x1 << 1) -#define UART_CLK_RUNNING_MASK	0x1 -#define UART_SMART_IDLE_EN	(0x1 << 0x3) - -static void rtc32k_enable(void) -{ -	struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; - -	/* -	 * Unlock the RTC's registers.  For more details please see the -	 * RTC_SS section of the TRM.  In order to unlock we need to -	 * write these specific values (keys) in this order. -	 */ -	writel(0x83e70b13, &rtc->kick0r); -	writel(0x95a4f1e0, &rtc->kick1r); - -	/* Enable the RTC 32K OSC by setting bits 3 and 6. */ -	writel((1 << 3) | (1 << 6), &rtc->osc); -} -  static void uart_enable(void)  { -	u32 regVal; -  	/* UART softreset */ -	regVal = readl(&uart_base->uartsyscfg); -	regVal |= UART_RESET; -	writel(regVal, &uart_base->uartsyscfg); -	while ((readl(&uart_base->uartsyssts) & -		UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK) -		; - -	/* Disable smart idle */ -	regVal = readl(&uart_base->uartsyscfg); -	regVal |= UART_SMART_IDLE_EN; -	writel(regVal, &uart_base->uartsyscfg); +	uart_soft_reset();  }  static void wdt_disable(void) diff --git a/board/vpac270/u-boot-spl.lds b/board/vpac270/u-boot-spl.lds index 61d1154af..1a3ef9285 100644 --- a/board/vpac270/u-boot-spl.lds +++ b/board/vpac270/u-boot-spl.lds @@ -67,11 +67,6 @@ SECTIONS  		__rel_dyn_end = .;  	} -	.dynsym : { -		__dynsym_start = .; -		*(.dynsym) -	} -  	. = ALIGN(0x800);  	_end = .; @@ -84,6 +79,7 @@ SECTIONS  	}  	/DISCARD/ : { *(.bss*) } +	/DISCARD/ : { *(.dynsym) }  	/DISCARD/ : { *(.dynstr*) }  	/DISCARD/ : { *(.dynsym*) }  	/DISCARD/ : { *(.dynamic*) } diff --git a/boards.cfg b/boards.cfg index 1e598cb7e..c0c428262 100644 --- a/boards.cfg +++ b/boards.cfg @@ -831,6 +831,7 @@ P1022DS_36BIT_SPIFLASH       powerpc     mpc85xx     p1022ds             freesca  P1022DS_SDCARD               powerpc     mpc85xx     p1022ds             freescale	-	    P1022DS:SDCARD  P1022DS_36BIT_SDCARD         powerpc     mpc85xx     p1022ds             freescale	-	    P1022DS:36BIT,SDCARD  P1022DS_36BIT                powerpc     mpc85xx     p1022ds             freescale      -           P1022DS:36BIT +P1023RDB                     powerpc     mpc85xx     p1023rdb            freescale      -           P1023RDB  P1023RDS                     powerpc     mpc85xx     p1023rds            freescale      -           P1023RDS  P1023RDS_NAND                powerpc     mpc85xx     p1023rds            freescale      -           P1023RDS:NAND  P1024RDB                     powerpc     mpc85xx     p1_p2_rdb_pc        freescale      -           p1_p2_rdb_pc:P1024RDB @@ -900,8 +901,13 @@ P5040DS_NAND		     powerpc     mpc85xx     corenet_ds          freescale      -  P5040DS_SDCARD		     powerpc     mpc85xx     corenet_ds          freescale      -           P5040DS:RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000  P5040DS_SPIFLASH	     powerpc     mpc85xx     corenet_ds          freescale      -           P5040DS:RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000  BSC9131RDB_SPIFLASH          powerpc     mpc85xx     bsc9131rdb          freescale      -           BSC9131RDB:BSC9131RDB,SPIFLASH +BSC9131RDB_SPIFLASH_SYSCLK100 powerpc     mpc85xx     bsc9131rdb          freescale      -           BSC9131RDB:BSC9131RDB,SPIFLASH,SYS_CLK_100 +BSC9131RDB_NAND              powerpc     mpc85xx     bsc9131rdb          freescale      -           BSC9131RDB:BSC9131RDB,NAND +BSC9131RDB_NAND_SYSCLK100    powerpc     mpc85xx     bsc9131rdb          freescale      -           BSC9131RDB:BSC9131RDB,NAND,SYS_CLK_100  BSC9132QDS_NOR_DDRCLK100     powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,SYS_CLK_100_DDR_100  BSC9132QDS_NOR_DDRCLK133     powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,SYS_CLK_100_DDR_133 +BSC9132QDS_NAND_DDRCLK100    powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,NAND,SYS_CLK_100_DDR_100 +BSC9132QDS_NAND_DDRCLK133    powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,NAND,SYS_CLK_100_DDR_133  BSC9132QDS_SDCARD_DDRCLK100  powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,SDCARD,SYS_CLK_100_DDR_100  BSC9132QDS_SDCARD_DDRCLK133  powerpc     mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,SDCARD,SYS_CLK_100_DDR_133  BSC9132QDS_SPIFLASH_DDRCLK100 powerpc    mpc85xx     bsc9132qds          freescale      -           BSC9132QDS:BSC9132QDS,SPIFLASH,SYS_CLK_100_DDR_100 @@ -912,12 +918,14 @@ stxssa_4M                    powerpc     mpc85xx     stxssa              stx  T4240QDS                     powerpc     mpc85xx     t4qds               freescale      -           T4240QDS:PPC_T4240  T4240QDS_SDCARD              powerpc     mpc85xx     t4qds               freescale	-           T4240QDS:PPC_T4240,RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000  T4240QDS_SPIFLASH            powerpc     mpc85xx     t4qds               freescale	-           T4240QDS:PPC_T4240,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 +T4240QDS_SRIO_PCIE_BOOT	     powerpc     mpc85xx     t4qds               freescale      -           T4240QDS:PPC_T4240,SRIO_PCIE_BOOT_SLAVE,SYS_TEXT_BASE=0xFFF80000  T4160QDS                     powerpc     mpc85xx     t4qds               freescale      -           T4240QDS:PPC_T4160  T4160QDS_SDCARD              powerpc     mpc85xx     t4qds               freescale	-           T4240QDS:PPC_T4160,RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000  T4160QDS_SPIFLASH            powerpc     mpc85xx     t4qds               freescale	-           T4240QDS:PPC_T4160,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000  B4860QDS                     powerpc     mpc85xx     b4860qds            freescale      -           B4860QDS:PPC_B4860  B4860QDS_NAND		     powerpc     mpc85xx     b4860qds            freescale      -           B4860QDS:PPC_B4860,RAMBOOT_PBL,NAND,SYS_TEXT_BASE=0xFFF80000  B4860QDS_SPIFLASH            powerpc     mpc85xx     b4860qds            freescale	-           B4860QDS:PPC_B4860,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 +B4860QDS_SRIO_PCIE_BOOT	     powerpc     mpc85xx     b4860qds            freescale      -           B4860QDS:PPC_B4860,SRIO_PCIE_BOOT_SLAVE,SYS_TEXT_BASE=0xFFF80000  B4420QDS                     powerpc     mpc85xx     b4860qds            freescale	-	    B4860QDS:PPC_B4420  B4420QDS_NAND		     powerpc     mpc85xx     b4860qds            freescale      -           B4860QDS:PPC_B4420,RAMBOOT_PBL,NAND,SYS_TEXT_BASE=0xFFF80000  B4420QDS_SPIFLASH            powerpc     mpc85xx     b4860qds            freescale	-           B4860QDS:PPC_B4420,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 diff --git a/common/Makefile b/common/Makefile index 3ba431626..48791b7ff 100644 --- a/common/Makefile +++ b/common/Makefile @@ -44,13 +44,11 @@ COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o  COBJS-y += cmd_boot.o  COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o  COBJS-y += cmd_help.o -COBJS-y += cmd_nvedit.o  COBJS-y += cmd_version.o  # environment  COBJS-y += env_attr.o  COBJS-y += env_callback.o -COBJS-y += env_common.o  COBJS-y += env_flags.o  COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o  COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o @@ -171,6 +169,7 @@ COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o  COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o  COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o  COBJS-$(CONFIG_CMD_TIME) += cmd_time.o +COBJS-$(CONFIG_CMD_TRACE) += cmd_trace.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o  COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o  COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o @@ -191,14 +190,6 @@ COBJS-$(CONFIG_CMD_ZIP) += cmd_zip.o  COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o  # others -ifdef CONFIG_DDR_SPD -SPD := y -endif -ifdef CONFIG_SPD_EEPROM -SPD := y -endif -COBJS-$(SPD) += ddr_spd.o -COBJS-$(CONFIG_HWCONFIG) += hwconfig.o  COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o  COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o  COBJS-y += flash.o @@ -216,24 +207,43 @@ COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o  endif  ifdef CONFIG_SPL_BUILD -COBJS-y += cmd_nvedit.o -COBJS-y += env_common.o  COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o  COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o +# environment +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_flags.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_callback.o +ifneq ($(CONFIG_SPL_NET_SUPPORT),y) +COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o +COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o +COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o +COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o +COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o +else +COBJS-y += env_nowhere.o +endif  endif +# core command +COBJS-y += cmd_nvedit.o +#environment +COBJS-y += env_common.o +#others +ifdef CONFIG_DDR_SPD +SPD := y +endif +ifdef CONFIG_SPD_EEPROM +SPD := y +endif +COBJS-$(SPD) += ddr_spd.o +COBJS-$(CONFIG_HWCONFIG) += hwconfig.o  COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o  COBJS-y += console.o  COBJS-y += dlmalloc.o  COBJS-y += image.o  COBJS-$(CONFIG_OF_LIBFDT) += image-fdt.o  COBJS-$(CONFIG_FIT) += image-fit.o +COBJS-$(CONFIG_FIT_SIGNATURE) += image-sig.o  COBJS-y += memsize.o  COBJS-y += stdio.o diff --git a/common/board_f.c b/common/board_f.c index 8efdb6365..ab4242a77 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -53,6 +53,7 @@  #include <os.h>  #include <post.h>  #include <spi.h> +#include <trace.h>  #include <watchdog.h>  #include <asm/errno.h>  #include <asm/io.h> @@ -500,6 +501,18 @@ static int reserve_lcd(void)  }  #endif /* CONFIG_LCD */ +static int reserve_trace(void) +{ +#ifdef CONFIG_TRACE +	gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE; +	gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE); +	debug("Reserving %dk for trace data at: %08lx\n", +	      CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr); +#endif + +	return 0; +} +  #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \  		&& !defined(CONFIG_ARM) && !defined(CONFIG_X86)  static int reserve_video(void) @@ -818,8 +831,9 @@ static init_fnc_t init_sequence_f[] = {  #ifdef CONFIG_SANDBOX  	setup_ram_buf,  #endif -	setup_fdt,  	setup_mon_len, +	setup_fdt, +	trace_early_init,  #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)  	/* TODO: can this go into arch_cpu_init()? */  	probecpu, @@ -963,6 +977,7 @@ static init_fnc_t init_sequence_f[] = {  #ifdef CONFIG_LCD  	reserve_lcd,  #endif +	reserve_trace,  	/* TODO: Why the dependency on CONFIG_8xx? */  #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \  		&& !defined(CONFIG_ARM) && !defined(CONFIG_X86) diff --git a/common/board_r.c b/common/board_r.c index f5649c95f..f7a036e32 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -58,6 +58,7 @@  #include <serial.h>  #include <spi.h>  #include <stdio_dev.h> +#include <trace.h>  #include <watchdog.h>  #ifdef CONFIG_ADDR_MAP  #include <asm/mmu.h> @@ -106,6 +107,15 @@ static int initr_secondary_cpu(void)  	return 0;  } +static int initr_trace(void) +{ +#ifdef CONFIG_TRACE +	trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE); +#endif + +	return 0; +} +  static int initr_reloc(void)  {  	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */ @@ -711,6 +721,7 @@ static int run_main_loop(void)   * TODO: perhaps reset the watchdog in the initcall function after each call?   */  init_fnc_t init_sequence_r[] = { +	initr_trace,  	initr_reloc,  	/* TODO: could x86/PPC have this also perhaps? */  #ifdef CONFIG_ARM diff --git a/common/bootstage.c b/common/bootstage.c index c5c69961a..94a32a997 100644 --- a/common/bootstage.c +++ b/common/bootstage.c @@ -49,6 +49,7 @@ static int next_id = BOOTSTAGE_ID_USER;  enum {  	BOOTSTAGE_VERSION	= 0,  	BOOTSTAGE_MAGIC		= 0xb00757a3, +	BOOTSTAGE_DIGITS	= 9,  };  struct bootstage_hdr { @@ -165,21 +166,6 @@ uint32_t bootstage_accum(enum bootstage_id id)  	return duration;  } -static void print_time(unsigned long us_time) -{ -	char str[15], *s; -	int grab = 3; - -	/* We don't seem to have %'d in U-Boot */ -	sprintf(str, "%12lu", us_time); -	for (s = str + 3; *s; s += grab) { -		if (s != str + 3) -			putc(s[-1] != ' ' ? ',' : ' '); -		printf("%.*s", grab, s); -		grab = 3; -	} -} -  /**   * Get a record name as a printable string   * @@ -208,10 +194,10 @@ static uint32_t print_time_record(enum bootstage_id id,  	if (prev == -1U) {  		printf("%11s", ""); -		print_time(rec->time_us); +		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);  	} else { -		print_time(rec->time_us); -		print_time(rec->time_us - prev); +		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); +		print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);  	}  	printf("  %s\n", get_record_name(buf, sizeof(buf), rec)); @@ -445,9 +431,9 @@ int bootstage_unstash(void *base, int size)  	}  	if (hdr->count * sizeof(*rec) > hdr->size) { -		debug("%s: Bootstage has %d records needing %d bytes, but " +		debug("%s: Bootstage has %d records needing %lu bytes, but "  			"only %d bytes is available\n", __func__, hdr->count, -		      hdr->count * sizeof(*rec), hdr->size); +		      (ulong)hdr->count * sizeof(*rec), hdr->size);  		return -1;  	} diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 05130b693..02a5013c0 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -104,9 +104,18 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,   *  - verified image architecture (PPC) and type (KERNEL or MULTI),   *  - loaded (first part of) image to header load address,   *  - disabled interrupts. + * + * @flag: Flags indicating what to do (BOOTM_STATE_...) + * @argc: Number of arguments. Note that the arguments are shifted down + *	 so that 0 is the first argument not processed by U-Boot, and + *	 argc is adjusted accordingly. This avoids confusion as to how + *	 many arguments are available for the OS. + * @images: Pointers to os/initrd/fdt + * @return 1 on error. On success the OS boots so this function does + * not return.   */  typedef int boot_os_fn(int flag, int argc, char * const argv[], -			bootm_headers_t *images); /* pointers to os/initrd/fdt */ +			bootm_headers_t *images);  #ifdef CONFIG_BOOTM_LINUX  extern boot_os_fn do_bootm_linux; @@ -199,15 +208,21 @@ static inline void boot_start_lmb(bootm_headers_t *images) { }  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	const void *os_hdr; -	int ret; -  	memset((void *)&images, 0, sizeof(images));  	images.verify = getenv_yesno("verify");  	boot_start_lmb(&images);  	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); +	images.state = BOOTM_STATE_START; + +	return 0; +} + +static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, +			 char * const argv[]) +{ +	const void *os_hdr;  	/* get kernel image header, start address and length */  	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, @@ -270,6 +285,8 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  		images.ep = image_get_ep(&images.legacy_hdr_os_copy);  #if defined(CONFIG_FIT)  	} else if (images.fit_uname_os) { +		int ret; +  		ret = fit_image_get_entry(images.fit_hdr_os,  					  images.fit_noffset_os, &images.ep);  		if (ret) { @@ -287,6 +304,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  		images.ep += images.os.load;  	} +	images.os.start = (ulong)os_hdr; + +	return 0; +} + +static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, +			    char * const argv[]) +{ +	int ret; +  	if (((images.os.type == IH_TYPE_KERNEL) ||  	     (images.os.type == IH_TYPE_KERNEL_NOLOAD) ||  	     (images.os.type == IH_TYPE_MULTI)) && @@ -312,17 +339,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  #endif  	} -	images.os.start = (ulong)os_hdr; -	images.state = BOOTM_STATE_START; -  	return 0;  }  #define BOOTM_ERR_RESET		-1  #define BOOTM_ERR_OVERLAP	-2  #define BOOTM_ERR_UNIMPLEMENTED	-3 -static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) +static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end, +		int boot_progress)  { +	image_info_t os = images->os;  	uint8_t comp = os.comp;  	ulong load = os.load;  	ulong blob_start = os.start; @@ -440,13 +466,23 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)  		debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,  			*load_end); -		return BOOTM_ERR_OVERLAP; +		/* Check what type of image this is. */ +		if (images->legacy_hdr_valid) { +			if (image_get_type(&images->legacy_hdr_os_copy) +					== IH_TYPE_MULTI) +				puts("WARNING: legacy format multi component image overwritten\n"); +			return BOOTM_ERR_OVERLAP; +		} else { +			puts("ERROR: new format image overwritten - must RESET the board to recover\n"); +			bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); +			return BOOTM_ERR_RESET; +		}  	}  	return 0;  } -static int bootm_start_standalone(ulong iflag, int argc, char * const argv[]) +static int bootm_start_standalone(int argc, char * const argv[])  {  	char  *s;  	int   (*appl)(int, char * const []); @@ -457,7 +493,7 @@ static int bootm_start_standalone(ulong iflag, int argc, char * const argv[])  		return 0;  	}  	appl = (int (*)(int, char * const []))(ulong)ntohl(images.ep); -	(*appl)(argc-1, &argv[1]); +	(*appl)(argc, argv);  	return 0;  } @@ -475,110 +511,227 @@ static cmd_tbl_t cmd_bootm_sub[] = {  	U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),  	U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),  	U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), +	U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),  	U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),  }; -static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, -			char * const argv[]) +static int boot_selected_os(int argc, char * const argv[], int state, +		bootm_headers_t *images, boot_os_fn *boot_fn) +{ +	if (images->os.type == IH_TYPE_STANDALONE) { +		/* This may return when 'autostart' is 'no' */ +		bootm_start_standalone(argc, argv); +		return 0; +	} +#ifdef CONFIG_SILENT_CONSOLE +	if (images->os.os == IH_OS_LINUX) +		fixup_silent_linux(); +#endif +	arch_preboot_os(); +	boot_fn(state, argc, argv, images); +	if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ +		return 0; +	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); +#ifdef DEBUG +	puts("\n## Control returned to monitor - resetting...\n"); +#endif +	return BOOTM_ERR_RESET; +} + +/** + * Execute selected states of the bootm command. + * + * Note the arguments to this state must be the first argument, Any 'bootm' + * or sub-command arguments must have already been taken. + * + * Note that if states contains more than one flag it MUST contain + * BOOTM_STATE_START, since this handles and consumes the command line args. + * + * Also note that aside from boot_os_fn functions and bootm_load_os no other + * functions we store the return value of in 'ret' may use a negative return + * value, without special handling. + * + * @param cmdtp		Pointer to bootm command table entry + * @param flag		Command flags (CMD_FLAG_...) + * @param argc		Number of subcommand arguments (0 = no arguments) + * @param argv		Arguments + * @param states	Mask containing states to run (BOOTM_STATE_...) + * @param images	Image header information + * @param boot_progress 1 to show boot progress, 0 to not do this + * @return 0 if ok, something else on error. Some errors will cause this + *	function to perform a reboot! If states contains BOOTM_STATE_OS_GO + *	then the intent is to boot an OS, so this function will not return + *	unless the image type is standalone. + */ +static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, +		char * const argv[], int states, bootm_headers_t *images, +		int boot_progress)  { -	int ret = 0; -	long state; -	cmd_tbl_t *c;  	boot_os_fn *boot_fn; +	ulong iflag = 0; +	int ret = 0; -	c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); +	images->state |= states; -	if (c) { -		state = (long)c->cmd; +	/* +	 * Work through the states and see how far we get. We stop on +	 * any error. +	 */ +	if (states & BOOTM_STATE_START) +		ret = bootm_start(cmdtp, flag, argc, argv); -		/* treat start special since it resets the state machine */ -		if (state == BOOTM_STATE_START) { -			argc--; -			argv++; -			return bootm_start(cmdtp, flag, argc, argv); -		} -	} else { -		/* Unrecognized command */ -		return CMD_RET_USAGE; -	} +	if (!ret && (states & BOOTM_STATE_FINDOS)) +		ret = bootm_find_os(cmdtp, flag, argc, argv); -	if (images.state < BOOTM_STATE_START || -	    images.state >= state) { -		printf("Trying to execute a command out of order\n"); -		return CMD_RET_USAGE; +	if (!ret && (states & BOOTM_STATE_FINDOTHER)) { +		ret = bootm_find_other(cmdtp, flag, argc, argv); +		argc = 0;	/* consume the args */  	} -	images.state |= state; -	boot_fn = boot_os[images.os.os]; +	/* +	 * We have reached the point of no return: we are going to +	 * overwrite all exception vector code, so we cannot easily +	 * recover from any failures any more... +	 */ +	iflag = disable_interrupts(); +#ifdef CONFIG_NETCONSOLE +	/* Stop the ethernet stack if NetConsole could have left it up */ +	eth_halt(); +#endif -	switch (state) { +#if defined(CONFIG_CMD_USB) +	/* +	 * turn off USB to prevent the host controller from writing to the +	 * SDRAM while Linux is booting. This could happen (at least for OHCI +	 * controller), because the HCCA (Host Controller Communication Area) +	 * lies within the SDRAM and the host controller writes continously to +	 * this area (as busmaster!). The HccaFrameNumber is for example +	 * updated every 1 ms within the HCCA structure in SDRAM! For more +	 * details see the OpenHCI specification. +	 */ +	usb_stop(); +#endif + +	/* Load the OS */ +	if (!ret && (states & BOOTM_STATE_LOADOS)) {  		ulong load_end; -		case BOOTM_STATE_START: -			/* should never occur */ -			break; -		case BOOTM_STATE_LOADOS: -			ret = bootm_load_os(images.os, &load_end, 0); -			if (ret) -				return ret; -			lmb_reserve(&images.lmb, images.os.load, -					(load_end - images.os.load)); -			break; -#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH -		case BOOTM_STATE_RAMDISK: -		{ -			ulong rd_len = images.rd_end - images.rd_start; +		ret = bootm_load_os(images, &load_end, 0); +		if (ret && ret != BOOTM_ERR_OVERLAP) +			goto err; + +		if (ret == 0) +			lmb_reserve(&images->lmb, images->os.load, +				    (load_end - images->os.load)); +		else if (ret == BOOTM_ERR_OVERLAP) +			ret = 0; +	} -			ret = boot_ramdisk_high(&images.lmb, images.rd_start, -				rd_len, &images.initrd_start, &images.initrd_end); -			if (ret) -				return ret; +	/* Relocate the ramdisk */ +#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH +	if (!ret && (states & BOOTM_STATE_RAMDISK)) { +		ulong rd_len = images->rd_end - images->rd_start; -			setenv_hex("initrd_start", images.initrd_start); -			setenv_hex("initrd_end", images.initrd_end); +		ret = boot_ramdisk_high(&images->lmb, images->rd_start, +			rd_len, &images->initrd_start, &images->initrd_end); +		if (!ret) { +			setenv_hex("initrd_start", images->initrd_start); +			setenv_hex("initrd_end", images->initrd_end);  		} -			break; +	}  #endif  #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) -		case BOOTM_STATE_FDT: -		{ -			boot_fdt_add_mem_rsv_regions(&images.lmb, -						     images.ft_addr); -			ret = boot_relocate_fdt(&images.lmb, -				&images.ft_addr, &images.ft_len); -			break; -		} +	if (!ret && (states & BOOTM_STATE_FDT)) { +		boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); +		ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, +					&images->ft_len); +	}  #endif -		case BOOTM_STATE_OS_CMDLINE: -			ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images); -			if (ret) -				printf("cmdline subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_BD_T: -			ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images); -			if (ret) -				printf("bdt subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_PREP: -			ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images); -			if (ret) -				printf("prep subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_GO: -			disable_interrupts(); -#ifdef CONFIG_NETCONSOLE -			/* -			 * Stop the ethernet stack if NetConsole could have -			 * left it up -			 */ -			eth_halt(); + +	/* From now on, we need the OS boot function */ +	if (ret) +		return ret; +	boot_fn = boot_os[images->os.os]; +	if (boot_fn == NULL) { +		if (iflag) +			enable_interrupts(); +		printf("ERROR: booting os '%s' (%d) is not supported\n", +		       genimg_get_os_name(images->os.os), images->os.os); +		bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); +		return 1; +	} + +	/* Call various other states that are not generally used */ +	if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) +		ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); +	if (!ret && (states & BOOTM_STATE_OS_BD_T)) +		ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); +	if (!ret && (states & BOOTM_STATE_OS_PREP)) +		ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); + +#ifdef CONFIG_TRACE +	/* Pretend to run the OS, then run a user command */ +	if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { +		char *cmd_list = getenv("fakegocmd"); + +		ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, +				images, boot_fn); +		if (!ret && cmd_list) +			ret = run_command_list(cmd_list, -1, flag); +	}  #endif -			arch_preboot_os(); -			boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images); -			break; +	/* Now run the OS! We hope this doesn't return */ +	if (!ret && (states & BOOTM_STATE_OS_GO)) { +		ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, +				images, boot_fn); +		if (ret) +			goto err;  	}  	return ret; + +	/* Deal with any fallout */ +err: +	if (iflag) +		enable_interrupts(); + +	if (ret == BOOTM_ERR_UNIMPLEMENTED) +		bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); +	else if (ret == BOOTM_ERR_RESET) +		do_reset(cmdtp, flag, argc, argv); +	else +		puts("subcommand not supported\n"); + +	return ret; +} + +static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, +			char * const argv[]) +{ +	int ret = 0; +	long state; +	cmd_tbl_t *c; + +	c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); +	argc--; argv++; + +	if (c) { +		state = (long)c->cmd; +		if (state == BOOTM_STATE_START) +			state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER; +	} else { +		/* Unrecognized command */ +		return CMD_RET_USAGE; +	} + +	if (state != BOOTM_STATE_START && images.state >= state) { +		printf("Trying to execute a command out of order\n"); +		return CMD_RET_USAGE; +	} + +	ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0); + +	return ret;  }  /*******************************************************************/ @@ -587,10 +740,6 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,  int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	ulong		iflag; -	ulong		load_end = 0; -	int		ret; -	boot_os_fn	*boot_fn;  #ifdef CONFIG_NEEDS_MANUAL_RELOC  	static int relocated = 0; @@ -611,11 +760,12 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  #endif  	/* determine if we have a sub command */ -	if (argc > 1) { +	argc--; argv++; +	if (argc > 0) {  		char *endp; -		simple_strtoul(argv[1], &endp, 16); -		/* endp pointing to NULL means that argv[1] was just a +		simple_strtoul(argv[0], &endp, 16); +		/* endp pointing to NULL means that argv[0] was just a  		 * valid number, pass it along to the normal bootm processing  		 *  		 * If endp is ':' or '#' assume a FIT identifier so pass @@ -627,101 +777,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  			return do_bootm_subcommand(cmdtp, flag, argc, argv);  	} -	if (bootm_start(cmdtp, flag, argc, argv)) -		return 1; - -	/* -	 * We have reached the point of no return: we are going to -	 * overwrite all exception vector code, so we cannot easily -	 * recover from any failures any more... -	 */ -	iflag = disable_interrupts(); - -#ifdef CONFIG_NETCONSOLE -	/* Stop the ethernet stack if NetConsole could have left it up */ -	eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) -	/* -	 * turn off USB to prevent the host controller from writing to the -	 * SDRAM while Linux is booting. This could happen (at least for OHCI -	 * controller), because the HCCA (Host Controller Communication Area) -	 * lies within the SDRAM and the host controller writes continously to -	 * this area (as busmaster!). The HccaFrameNumber is for example -	 * updated every 1 ms within the HCCA structure in SDRAM! For more -	 * details see the OpenHCI specification. -	 */ -	usb_stop(); -#endif - -	ret = bootm_load_os(images.os, &load_end, 1); - -	if (ret < 0) { -		if (ret == BOOTM_ERR_RESET) -			do_reset(cmdtp, flag, argc, argv); -		if (ret == BOOTM_ERR_OVERLAP) { -			if (images.legacy_hdr_valid) { -				image_header_t *hdr; -				hdr = &images.legacy_hdr_os_copy; -				if (image_get_type(hdr) == IH_TYPE_MULTI) -					puts("WARNING: legacy format multi " -						"component image " -						"overwritten\n"); -			} else { -				puts("ERROR: new format image overwritten - " -					"must RESET the board to recover\n"); -				bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); -				do_reset(cmdtp, flag, argc, argv); -			} -		} -		if (ret == BOOTM_ERR_UNIMPLEMENTED) { -			if (iflag) -				enable_interrupts(); -			bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); -			return 1; -		} -	} - -	lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load)); - -	if (images.os.type == IH_TYPE_STANDALONE) { -		if (iflag) -			enable_interrupts(); -		/* This may return when 'autostart' is 'no' */ -		bootm_start_standalone(iflag, argc, argv); -		return 0; -	} - -	bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS); - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) -	if (images.os.os == IH_OS_LINUX) -		fixup_silent_linux(); -#endif - -	boot_fn = boot_os[images.os.os]; - -	if (boot_fn == NULL) { -		if (iflag) -			enable_interrupts(); -		printf("ERROR: booting os '%s' (%d) is not supported\n", -			genimg_get_os_name(images.os.os), images.os.os); -		bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); -		return 1; -	} - -	arch_preboot_os(); - -	boot_fn(0, argc, argv, &images); - -	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); -#ifdef DEBUG -	puts("\n## Control returned to monitor - resetting...\n"); -#endif -	do_reset(cmdtp, flag, argc, argv); - -	return 1; +	return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | +		BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | +		BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP | +		BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1);  }  int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) @@ -816,22 +875,22 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,  #endif  	/* find out kernel image address */ -	if (argc < 2) { +	if (argc < 1) {  		img_addr = load_addr;  		debug("*  kernel: default image load address = 0x%08lx\n",  				load_addr);  #if defined(CONFIG_FIT) -	} else if (fit_parse_conf(argv[1], load_addr, &img_addr, +	} else if (fit_parse_conf(argv[0], load_addr, &img_addr,  							&fit_uname_config)) {  		debug("*  kernel: config '%s' from image at 0x%08lx\n",  				fit_uname_config, img_addr); -	} else if (fit_parse_subimage(argv[1], load_addr, &img_addr, +	} else if (fit_parse_subimage(argv[0], load_addr, &img_addr,  							&fit_uname_kernel)) {  		debug("*  kernel: subimage '%s' from image at 0x%08lx\n",  				fit_uname_kernel, img_addr);  #endif  	} else { -		img_addr = simple_strtoul(argv[1], NULL, 16); +		img_addr = simple_strtoul(argv[0], NULL, 16);  		debug("*  kernel: cmdline image address = 0x%08lx\n", img_addr);  	} @@ -1346,6 +1405,19 @@ static void fixup_silent_linux(void)  }  #endif /* CONFIG_SILENT_CONSOLE */ +#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9) +static void copy_args(char *dest, int argc, char * const argv[], char delim) +{ +	int i; + +	for (i = 0; i < argc; i++) { +		if (i > 0) +			*dest++ = delim; +		strcpy(dest, argv[i]); +		dest += strlen(argv[i]); +	} +} +#endif  /*******************************************************************/  /* OS booting routines */ @@ -1401,20 +1473,14 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[],  	consdev = "scc3";  #endif -	if (argc > 2) { +	if (argc > 0) {  		ulong len;  		int   i; -		for (i = 2, len = 0; i < argc; i += 1) +		for (i = 0, len = 0; i < argc; i += 1)  			len += strlen(argv[i]) + 1;  		cmdline = malloc(len); - -		for (i = 2, len = 0; i < argc; i += 1) { -			if (i > 2) -				cmdline[len++] = ' '; -			strcpy(&cmdline[len], argv[i]); -			len += strlen(argv[i]); -		} +		copy_args(cmdline, argc, argv, ' ');  	} else if ((cmdline = getenv("bootargs")) == NULL) {  		cmdline = "";  	} @@ -1533,6 +1599,7 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],  			   bootm_headers_t *images)  {  	void (*entry_point)(void); +	char *s;  	if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))  		return 1; @@ -1544,6 +1611,20 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],  	}  #endif +	/* See README.plan9 */ +	s = getenv("confaddr"); +	if (s != NULL) { +		char *confaddr = (char *)simple_strtoul(s, NULL, 16); + +		if (argc > 0) { +			copy_args(confaddr, argc, argv, '\n'); +		} else { +			s = getenv("bootargs"); +			if (s != NULL) +				strcpy(confaddr, s); +		} +	} +  	entry_point = (void (*)(void))images->ep;  	printf("## Transferring control to Plan 9 (at address %08lx) ...\n", @@ -1663,9 +1744,8 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,  	int ret;  	void *zi_start, *zi_end; -	memset(images, 0, sizeof(bootm_headers_t)); - -	boot_start_lmb(images); +	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, +			      images, 1);  	/* Setup Linux kernel zImage entry point */  	if (argc < 2) { @@ -1684,73 +1764,25 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,  	lmb_reserve(&images->lmb, images->ep, zi_end - zi_start); -	/* Find ramdisk */ -	ret = boot_get_ramdisk(argc, argv, images, IH_INITRD_ARCH, -			&images->rd_start, &images->rd_end); -	if (ret) { -		puts("Ramdisk image is corrupt or invalid\n"); -		return 1; -	} - -#if defined(CONFIG_OF_LIBFDT) -	/* find flattened device tree */ -	ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images, -			   &images->ft_addr, &images->ft_len); -	if (ret) { -		puts("Could not find a valid device tree\n"); -		return 1; -	} - -	set_working_fdt_addr(images->ft_addr); -#endif +	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER, +			      images, 1); -	return 0; +	return ret;  } -static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	bootm_headers_t	images; +	int ret;  	if (bootz_start(cmdtp, flag, argc, argv, &images))  		return 1; -	/* -	 * We have reached the point of no return: we are going to -	 * overwrite all exception vector code, so we cannot easily -	 * recover from any failures any more... -	 */ -	disable_interrupts(); +	ret = do_bootm_states(cmdtp, flag, argc, argv, +			      BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, +			      &images, 1); -#ifdef CONFIG_NETCONSOLE -	/* Stop the ethernet stack if NetConsole could have left it up */ -	eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) -	/* -	 * turn off USB to prevent the host controller from writing to the -	 * SDRAM while Linux is booting. This could happen (at least for OHCI -	 * controller), because the HCCA (Host Controller Communication Area) -	 * lies within the SDRAM and the host controller writes continously to -	 * this area (as busmaster!). The HccaFrameNumber is for example -	 * updated every 1 ms within the HCCA structure in SDRAM! For more -	 * details see the OpenHCI specification. -	 */ -	usb_stop(); -#endif - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) -	fixup_silent_linux(); -#endif -	arch_preboot_os(); - -	do_bootm_linux(0, argc, argv, &images); -#ifdef DEBUG -	puts("\n## Control returned to monitor - resetting...\n"); -#endif -	do_reset(cmdtp, flag, argc, argv); - -	return 1; +	return ret;  }  #ifdef CONFIG_SYS_LONGHELP diff --git a/common/cmd_ide.c b/common/cmd_ide.c index 78b4aa70b..59e95dfa1 100644 --- a/common/cmd_ide.c +++ b/common/cmd_ide.c @@ -830,7 +830,7 @@ static void ide_ident(block_dev_desc_t *dev_desc)  /* ------------------------------------------------------------------------- */ -ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer)  {  	ulong n = 0;  	unsigned char c; @@ -844,7 +844,7 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)  		lba48 = 1;  	}  #endif -	debug("ide_read dev %d start %lX, blocks " LBAF " buffer at %lX\n", +	debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",  	      device, blknr, blkcnt, (ulong) buffer);  	ide_led(DEVICE_LED(device), 1);	/* LED on       */ @@ -934,8 +934,8 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)  		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=  		    ATA_STAT_DRQ) { -			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", -				device, blknr, c); +			printf("Error (no IRQ) dev %d blk " LBAF ": status " +			       "%#02x\n", device, blknr, c);  			break;  		} @@ -954,7 +954,7 @@ IDE_READ_E:  /* ------------------------------------------------------------------------- */ -ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) +ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer)  {  	ulong n = 0;  	unsigned char c; @@ -1022,8 +1022,8 @@ ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer)  		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=  		    ATA_STAT_DRQ) { -			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", -				device, blknr, c); +			printf("Error (no IRQ) dev %d blk " LBAF ": status " +				"%#02x\n", device, blknr, c);  			goto WR_OUT;  		} diff --git a/common/cmd_mem.c b/common/cmd_mem.c index 6df00b15d..77eafa0b8 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -551,6 +551,8 @@ static int do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc,  			*cp++;  	}  	unmap_sysmem(buf); + +	return 0;  }  #ifdef CONFIG_LOOPW diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 7d824690b..5f1ed430e 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -147,6 +147,36 @@ U_BOOT_CMD(  	"- display info of the current MMC device"  ); +#ifdef CONFIG_SUPPORT_EMMC_BOOT +static int boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ +	int err; +	err = mmc_boot_part_access(mmc, ack, part_num, access); + +	if ((err == 0) && (access != 0)) { +		printf("\t\t\t!!!Notice!!!\n"); + +		printf("!You must close EMMC boot Partition"); +		printf("after all images are written\n"); + +		printf("!EMMC boot partition has continuity"); +		printf("at image writing time.\n"); + +		printf("!So, do not close the boot partition"); +		printf("before all images are written.\n"); +		return 0; +	} else if ((err == 0) && (access == 0)) +		return 0; +	else if ((err != 0) && (access != 0)) { +		printf("EMMC boot partition-%d OPEN Failed.\n", part_num); +		return 1; +	} else { +		printf("EMMC boot partition-%d CLOSE Failed.\n", part_num); +		return 1; +	} +} +#endif +  static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	enum mmc_state state; @@ -258,8 +288,74 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  				curr_device, mmc->part_num);  		return 0; -	} +#ifdef CONFIG_SUPPORT_EMMC_BOOT +	} else if ((strcmp(argv[1], "open") == 0) || +			(strcmp(argv[1], "close") == 0)) { +		int dev; +		struct mmc *mmc; +		u8 part_num, access = 0; + +		if (argc == 4) { +			dev = simple_strtoul(argv[2], NULL, 10); +			part_num = simple_strtoul(argv[3], NULL, 10); +		} else { +			return CMD_RET_USAGE; +		} + +		mmc = find_mmc_device(dev); +		if (!mmc) { +			printf("no mmc device at slot %x\n", dev); +			return 1; +		} +		if (IS_SD(mmc)) { +			printf("SD device cannot be opened/closed\n"); +			return 1; +		} + +		if ((part_num <= 0) || (part_num > MMC_NUM_BOOT_PARTITION)) { +			printf("Invalid boot partition number:\n"); +			printf("Boot partition number cannot be <= 0\n"); +			printf("EMMC44 supports only 2 boot partitions\n"); +			return 1; +		} + +		if (strcmp(argv[1], "open") == 0) +			access = part_num; /* enable R/W access to boot part*/ +		else +			access = 0; /* No access to boot partition */ + +		/* acknowledge to be sent during boot operation */ +		return boot_part_access(mmc, 1, part_num, access); + +	} else if (strcmp(argv[1], "bootpart") == 0) { +		int dev; +		dev = simple_strtoul(argv[2], NULL, 10); + +		u32 bootsize = simple_strtoul(argv[3], NULL, 10); +		u32 rpmbsize = simple_strtoul(argv[4], NULL, 10); +		struct mmc *mmc = find_mmc_device(dev); +		if (!mmc) { +			printf("no mmc device at slot %x\n", dev); +			return 1; +		} + +		if (IS_SD(mmc)) { +			printf("It is not a EMMC device\n"); +			return 1; +		} + +		if (0 == mmc_boot_partition_size_change(mmc, +							bootsize, rpmbsize)) { +			printf("EMMC boot partition Size %d MB\n", bootsize); +			printf("EMMC RPMB partition Size %d MB\n", rpmbsize); +			return 0; +		} else { +			printf("EMMC boot partition Size change Failed.\n"); +			return 1; +		} +#endif /* CONFIG_SUPPORT_EMMC_BOOT */ +	}  	state = MMC_INVALID;  	if (argc == 5 && strcmp(argv[1], "read") == 0)  		state = MMC_READ; @@ -334,5 +430,14 @@ U_BOOT_CMD(  	"mmc rescan\n"  	"mmc part - lists available partition on current mmc device\n"  	"mmc dev [dev] [part] - show or set current mmc device [partition]\n" -	"mmc list - lists available devices"); +	"mmc list - lists available devices\n" +#ifdef CONFIG_SUPPORT_EMMC_BOOT +	"mmc open <dev> <boot_partition>\n" +	" - Enable boot_part for booting and enable R/W access of boot_part\n" +	"mmc close <dev> <boot_partition>\n" +	" - Enable boot_part for booting and disable access to boot_part\n" +	"mmc bootpart <device num> <boot part size MB> <RPMB part size MB>\n" +	" - change sizes of boot and RPMB partions of specified device\n"  #endif +	); +#endif /* !CONFIG_GENERIC_MMC */ diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 2dbd49cbd..1fb75d8ae 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -26,12 +26,21 @@  #define MAX_TFTP_PATH_LEN 127 +const char *pxe_default_paths[] = { +#ifdef CONFIG_SYS_SOC +	"default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC, +#endif +	"default-" CONFIG_SYS_ARCH, +	"default", +	NULL +}; +  /*   * Like getenv, but prints an error if envvar isn't defined in the   * environment.  It always returns what getenv does, so it can be used in   * place of getenv without changing error handling otherwise.   */ -static char *from_env(char *envvar) +static char *from_env(const char *envvar)  {  	char *ret; @@ -55,37 +64,21 @@ static char *from_env(char *envvar)   */  static int format_mac_pxe(char *outbuf, size_t outbuf_len)  { -	size_t ethaddr_len; -	char *p, *ethaddr; - -	ethaddr = from_env("ethaddr"); +	uchar ethaddr[6]; -	if (!ethaddr) -		return -ENOENT; - -	ethaddr_len = strlen(ethaddr); - -	/* -	 * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at -	 * the end. -	 */ -	if (outbuf_len < ethaddr_len + 4) { -		printf("outbuf is too small (%d < %d)\n", -				outbuf_len, ethaddr_len + 4); +	if (outbuf_len < 21) { +		printf("outbuf is too small (%d < 21)\n", outbuf_len);  		return -EINVAL;  	} -	strcpy(outbuf, "01-"); - -	for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { -		if (*ethaddr == ':') -			*p = '-'; -		else -			*p = tolower(*ethaddr); -	} +	if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(), +					  ethaddr)) +		return -ENOENT; -	*p = '\0'; +	sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x", +		ethaddr[0], ethaddr[1], ethaddr[2], +		ethaddr[3], ethaddr[4], ethaddr[5]);  	return 1;  } @@ -131,14 +124,14 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path,  	return 1;  } -static int (*do_getfile)(char *file_path, char *file_addr); +static int (*do_getfile)(const char *file_path, char *file_addr); -static int do_get_tftp(char *file_path, char *file_addr) +static int do_get_tftp(const char *file_path, char *file_addr)  {  	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};  	tftp_argv[1] = file_addr; -	tftp_argv[2] = file_path; +	tftp_argv[2] = (void *)file_path;  	if (do_tftpb(NULL, 0, 3, tftp_argv))  		return -ENOENT; @@ -148,12 +141,12 @@ static int do_get_tftp(char *file_path, char *file_addr)  static char *fs_argv[5]; -static int do_get_ext2(char *file_path, char *file_addr) +static int do_get_ext2(const char *file_path, char *file_addr)  {  #ifdef CONFIG_CMD_EXT2  	fs_argv[0] = "ext2load";  	fs_argv[3] = file_addr; -	fs_argv[4] = file_path; +	fs_argv[4] = (void *)file_path;  	if (!do_ext2load(NULL, 0, 5, fs_argv))  		return 1; @@ -161,12 +154,12 @@ static int do_get_ext2(char *file_path, char *file_addr)  	return -ENOENT;  } -static int do_get_fat(char *file_path, char *file_addr) +static int do_get_fat(const char *file_path, char *file_addr)  {  #ifdef CONFIG_CMD_FAT  	fs_argv[0] = "fatload";  	fs_argv[3] = file_addr; -	fs_argv[4] = file_path; +	fs_argv[4] = (void *)file_path;  	if (!do_fat_fsload(NULL, 0, 5, fs_argv))  		return 1; @@ -182,7 +175,7 @@ static int do_get_fat(char *file_path, char *file_addr)   *   * Returns 1 for success, or < 0 on error.   */ -static int get_relfile(char *file_path, void *file_addr) +static int get_relfile(const char *file_path, void *file_addr)  {  	size_t path_len;  	char relfile[MAX_TFTP_PATH_LEN+1]; @@ -221,7 +214,7 @@ static int get_relfile(char *file_path, void *file_addr)   *   * Returns 1 on success, or < 0 for error.   */ -static int get_pxe_file(char *file_path, void *file_addr) +static int get_pxe_file(const char *file_path, void *file_addr)  {  	unsigned long config_file_size;  	char *tftp_filesize; @@ -258,7 +251,7 @@ static int get_pxe_file(char *file_path, void *file_addr)   *   * Returns 1 on success or < 0 on error.   */ -static int get_pxelinux_path(char *file, void *pxefile_addr_r) +static int get_pxelinux_path(const char *file, void *pxefile_addr_r)  {  	size_t base_len = strlen(PXELINUX_DIR);  	char path[MAX_TFTP_PATH_LEN+1]; @@ -355,7 +348,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	char *pxefile_addr_str;  	unsigned long pxefile_addr_r; -	int err; +	int err, i = 0;  	do_getfile = do_get_tftp; @@ -376,16 +369,23 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	 * Keep trying paths until we successfully get a file we're looking  	 * for.  	 */ -	if (pxe_uuid_path((void *)pxefile_addr_r) > 0 -		|| pxe_mac_path((void *)pxefile_addr_r) > 0 -		|| pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 -		|| get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { - +	if (pxe_uuid_path((void *)pxefile_addr_r) > 0 || +	    pxe_mac_path((void *)pxefile_addr_r) > 0 || +	    pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {  		printf("Config file found\n");  		return 0;  	} +	while (pxe_default_paths[i]) { +		if (get_pxelinux_path(pxe_default_paths[i], +				      (void *)pxefile_addr_r) > 0) { +			printf("Config file found\n"); +			return 0; +		} +		i++; +	} +  	printf("Config file not found\n");  	return 1; @@ -398,7 +398,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])   *   * Returns 1 on success or < 0 on error.   */ -static int get_relfile_envaddr(char *file_path, char *envaddr_name) +static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)  {  	unsigned long file_addr;  	char *envaddr; @@ -445,14 +445,17 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name)   * list - lets these form a list, which a pxe_menu struct will hold.   */  struct pxe_label { +	char num[4];  	char *name;  	char *menu;  	char *kernel;  	char *append;  	char *initrd;  	char *fdt; +	int ipappend;  	int attempted;  	int localboot; +	int localboot_val;  	struct list_head list;  }; @@ -533,21 +536,9 @@ static void label_destroy(struct pxe_label *label)  static void label_print(void *data)  {  	struct pxe_label *label = data; -	const char *c = label->menu ? label->menu : label->kernel; - -	printf("%s:\t%s\n", label->name, c); - -	if (label->kernel) -		printf("\t\tkernel: %s\n", label->kernel); - -	if (label->append) -		printf("\t\tappend: %s\n", label->append); +	const char *c = label->menu ? label->menu : label->name; -	if (label->initrd) -		printf("\t\tinitrd: %s\n", label->initrd); - -	if (label->fdt) -		printf("\tfdt: %s\n", label->fdt); +	printf("%s:\t%s\n", label->num, c);  }  /* @@ -591,34 +582,43 @@ static int label_localboot(struct pxe_label *label)   * If the label specifies an 'append' line, its contents will overwrite that   * of the 'bootargs' environment variable.   */ -static void label_boot(struct pxe_label *label) +static int label_boot(struct pxe_label *label)  {  	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; +	char initrd_str[22]; +	char mac_str[29] = ""; +	char ip_str[68] = ""; +	char *bootargs;  	int bootm_argc = 3; +	int len = 0;  	label_print(label);  	label->attempted = 1;  	if (label->localboot) { -		label_localboot(label); -		return; +		if (label->localboot_val >= 0) +			label_localboot(label); +		return 0;  	}  	if (label->kernel == NULL) {  		printf("No kernel given, skipping %s\n",  				label->name); -		return; +		return 1;  	}  	if (label->initrd) {  		if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {  			printf("Skipping %s for failure retrieving initrd\n",  					label->name); -			return; +			return 1;  		} -		bootm_argv[2] = getenv("ramdisk_addr_r"); +		bootm_argv[2] = initrd_str; +		strcpy(bootm_argv[2], getenv("ramdisk_addr_r")); +		strcat(bootm_argv[2], ":"); +		strcat(bootm_argv[2], getenv("filesize"));  	} else {  		bootm_argv[2] = "-";  	} @@ -626,11 +626,43 @@ static void label_boot(struct pxe_label *label)  	if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {  		printf("Skipping %s for failure retrieving kernel\n",  				label->name); -		return; +		return 1; +	} + +	if (label->ipappend & 0x1) { +		sprintf(ip_str, " ip=%s:%s:%s:%s", +			getenv("ipaddr"), getenv("serverip"), +			getenv("gatewayip"), getenv("netmask")); +		len += strlen(ip_str); +	} + +	if (label->ipappend & 0x2) { +		int err; +		strcpy(mac_str, " BOOTIF="); +		err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); +		if (err < 0) +			mac_str[0] = '\0'; +		len += strlen(mac_str);  	}  	if (label->append) -		setenv("bootargs", label->append); +		len += strlen(label->append); + +	if (len) { +		bootargs = malloc(len + 1); +		if (!bootargs) +			return 1; +		bootargs[0] = '\0'; +		if (label->append) +			strcpy(bootargs, label->append); +		strcat(bootargs, ip_str); +		strcat(bootargs, mac_str); + +		setenv("bootargs", bootargs); +		printf("append: %s\n", bootargs); + +		free(bootargs); +	}  	bootm_argv[1] = getenv("kernel_addr_r"); @@ -654,7 +686,7 @@ static void label_boot(struct pxe_label *label)  		if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {  			printf("Skipping %s for failure retrieving fdt\n",  					label->name); -			return; +			return 1;  		}  	} else  		bootm_argv[3] = getenv("fdt_addr"); @@ -663,6 +695,12 @@ static void label_boot(struct pxe_label *label)  		bootm_argc = 4;  	do_bootm(NULL, 0, bootm_argc, bootm_argv); + +#ifdef CONFIG_CMD_BOOTZ +	/* Try booting a zImage if do_bootm returns */ +	do_bootz(NULL, 0, bootm_argc, bootm_argv); +#endif +	return 1;  }  /* @@ -685,6 +723,8 @@ enum token_type {  	T_PROMPT,  	T_INCLUDE,  	T_FDT, +	T_ONTIMEOUT, +	T_IPAPPEND,  	T_INVALID  }; @@ -713,6 +753,8 @@ static const struct token keywords[] = {  	{"initrd", T_INITRD},  	{"include", T_INCLUDE},  	{"fdt", T_FDT}, +	{"ontimeout", T_ONTIMEOUT,}, +	{"ipappend", T_IPAPPEND,},  	{NULL, T_INVALID}  }; @@ -903,7 +945,6 @@ static int parse_integer(char **c, int *dst)  {  	struct token t;  	char *s = *c; -	unsigned long temp;  	get_token(c, &t, L_SLITERAL); @@ -912,12 +953,7 @@ static int parse_integer(char **c, int *dst)  		return -EINVAL;  	} -	if (strict_strtoul(t.val, 10, &temp) < 0) { -		printf("Expected unsigned integer: %s\n", t.val); -		return -EINVAL; -	} - -	*dst = (int)temp; +	*dst = simple_strtol(t.val, NULL, 10);  	free(t.val); @@ -1016,10 +1052,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg,  	switch (t.type) {  	case T_DEFAULT: -		if (cfg->default_label) -			free(cfg->default_label); - -		cfg->default_label = strdup(label->name); +		if (!cfg->default_label) +			cfg->default_label = strdup(label->name);  		if (!cfg->default_label)  			return -ENOMEM; @@ -1108,7 +1142,12 @@ static int parse_label(char **c, struct pxe_menu *cfg)  			break;  		case T_LOCALBOOT: -			err = parse_integer(c, &label->localboot); +			label->localboot = 1; +			err = parse_integer(c, &label->localboot_val); +			break; + +		case T_IPAPPEND: +			err = parse_integer(c, &label->ipappend);  			break;  		case T_EOL: @@ -1164,6 +1203,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  		err = 0;  		switch (t.type) {  		case T_MENU: +			cfg->prompt = 1;  			err = parse_menu(&p, cfg, b, nest_level);  			break; @@ -1176,6 +1216,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  			break;  		case T_DEFAULT: +		case T_ONTIMEOUT:  			err = parse_sliteral(&p, &label_name);  			if (label_name) { @@ -1193,7 +1234,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  			break;  		case T_PROMPT: -			err = parse_integer(&p, &cfg->prompt); +			eol_or_eof(&p);  			break;  		case T_EOL: @@ -1276,6 +1317,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)  	struct list_head *pos;  	struct menu *m;  	int err; +	int i = 1; +	char *default_num = NULL;  	/*  	 * Create a menu and add items for all the labels. @@ -1289,18 +1332,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)  	list_for_each(pos, &cfg->labels) {  		label = list_entry(pos, struct pxe_label, list); -		if (menu_item_add(m, label->name, label) != 1) { +		sprintf(label->num, "%d", i++); +		if (menu_item_add(m, label->num, label) != 1) {  			menu_destroy(m);  			return NULL;  		} +		if (cfg->default_label && +		    (strcmp(label->name, cfg->default_label) == 0)) +			default_num = label->num; +  	}  	/*  	 * After we've created items for each label in the menu, set the  	 * menu's default label if one was specified.  	 */ -	if (cfg->default_label) { -		err = menu_default_set(m, cfg->default_label); +	if (default_num) { +		err = menu_default_set(m, default_num);  		if (err != 1) {  			if (err != -ENOENT) {  				menu_destroy(m); @@ -1367,10 +1415,13 @@ static void handle_pxe_menu(struct pxe_menu *cfg)  	 * we give up.  	 */ -	if (err == 1) -		label_boot(choice); -	else if (err != -ENOENT) +	if (err == 1) { +		err = label_boot(choice); +		if (!err) +			return; +	} else if (err != -ENOENT) {  		return; +	}  	boot_unattempted_labels(cfg);  } diff --git a/common/cmd_trace.c b/common/cmd_trace.c new file mode 100644 index 000000000..ec3137a8a --- /dev/null +++ b/common/cmd_trace.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <trace.h> +#include <asm/io.h> + +static int get_args(int argc, char * const argv[], char **buff, +		    size_t *buff_ptr, size_t *buff_size) +{ +	if (argc < 2) +		return -1; +	if (argc < 4) { +		*buff_size = getenv_ulong("profsize", 16, 0); +		*buff = map_sysmem(getenv_ulong("profbase", 16, 0), +				   *buff_size); +		*buff_ptr = getenv_ulong("profoffset", 16, 0); +	} else { +		*buff_size = simple_strtoul(argv[3], NULL, 16); +		*buff = map_sysmem(simple_strtoul(argv[2], NULL, 16), +				   *buff_size); +		*buff_ptr = 0; +	}; +	return 0; +} + +static int create_func_list(int argc, char * const argv[]) +{ +	size_t buff_size, avail, buff_ptr, used; +	unsigned int needed; +	char *buff; +	int err; + +	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) +		return -1; + +	avail = buff_size - buff_ptr; +	err = trace_list_functions(buff + buff_ptr, avail, &needed); +	if (err) +		printf("Error: truncated (%#x bytes needed)\n", needed); +	used = min(avail, needed); +	printf("Function trace dumped to %08lx, size %#zx\n", +	       (ulong)map_to_sysmem(buff + buff_ptr), used); +	setenv_hex("profbase", map_to_sysmem(buff)); +	setenv_hex("profsize", buff_size); +	setenv_hex("profoffset", buff_ptr + used); + +	return 0; +} + +static int create_call_list(int argc, char * const argv[]) +{ +	size_t buff_size, avail, buff_ptr, used; +	unsigned int needed; +	char *buff; +	int err; + +	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) +		return -1; + +	avail = buff_size - buff_ptr; +	err = trace_list_calls(buff + buff_ptr, avail, &needed); +	if (err) +		printf("Error: truncated (%#x bytes needed)\n", needed); +	used = min(avail, needed); +	printf("Call list dumped to %08lx, size %#zx\n", +	       (ulong)map_to_sysmem(buff + buff_ptr), used); + +	setenv_hex("profbase", map_to_sysmem(buff)); +	setenv_hex("profsize", buff_size); +	setenv_hex("profoffset", buff_ptr + used); + +	return 0; +} + +int do_trace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	const char *cmd = argc < 2 ? NULL : argv[1]; + +	if (!cmd) +		return cmd_usage(cmdtp); +	switch (*cmd) { +	case 'p': +		trace_set_enabled(0); +		break; +	case 'c': +		if (create_call_list(argc, argv)) +			return cmd_usage(cmdtp); +		break; +	case 'r': +		trace_set_enabled(1); +		break; +	case 'f': +		if (create_func_list(argc, argv)) +			return cmd_usage(cmdtp); +		break; +	case 's': +		trace_print_stats(); +		break; +	default: +		return CMD_RET_USAGE; +	} + +	return 0; +} + +U_BOOT_CMD( +	trace,	4,	1,	do_trace, +	"trace utility commands", +	"stats                        - display tracing statistics\n" +	"trace pause                        - pause tracing\n" +	"trace resume                       - resume tracing\n" +	"trace funclist [<addr> <size>]     - dump function list into buffer\n" +	"trace calls  [<addr> <size>]       " +		"- dump function call trace into buffer" +); diff --git a/common/image-fdt.c b/common/image-fdt.c index 0d421d92f..d99f444de 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -248,13 +248,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,  	ulong		default_addr;  	int		fdt_noffset;  #endif +	const char *select = NULL;  	*of_flat_tree = NULL;  	*of_size = 0; -	if (argc > 3 || genimg_has_config(images)) { +	if (argc > 2) +		select = argv[2]; +	if (select || genimg_has_config(images)) {  #if defined(CONFIG_FIT) -		if (argc > 3) { +		if (select) {  			/*  			 * If the FDT blob comes from the FIT image and the  			 * FIT image address is omitted in the command line @@ -268,18 +271,18 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,  			else  				default_addr = load_addr; -			if (fit_parse_conf(argv[3], default_addr, +			if (fit_parse_conf(select, default_addr,  					   &fdt_addr, &fit_uname_config)) {  				debug("*  fdt: config '%s' from image at 0x%08lx\n",  				      fit_uname_config, fdt_addr); -			} else if (fit_parse_subimage(argv[3], default_addr, +			} else if (fit_parse_subimage(select, default_addr,  				   &fdt_addr, &fit_uname_fdt)) {  				debug("*  fdt: subimage '%s' from image at 0x%08lx\n",  				      fit_uname_fdt, fdt_addr);  			} else  #endif  			{ -				fdt_addr = simple_strtoul(argv[3], NULL, 16); +				fdt_addr = simple_strtoul(select, NULL, 16);  				debug("*  fdt: cmdline image address = 0x%08lx\n",  				      fdt_addr);  			} diff --git a/common/image-fit.c b/common/image-fit.c index f40f1603f..b75e119d9 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -234,42 +234,45 @@ void fit_print_contents(const void *fit)   * @fit: pointer to the FIT format image header   * @noffset: offset of the hash node   * @p: pointer to prefix string + * @type: Type of information to print ("hash" or "sign")   *   * fit_image_print_data() lists properies for the processed hash node   * + * This function avoid using puts() since it prints a newline on the host + * but does not in U-Boot. + *   * returns:   *     no returned results   */ -static void fit_image_print_data(const void *fit, int noffset, const char *p) +static void fit_image_print_data(const void *fit, int noffset, const char *p, +				 const char *type)  { -	char *algo; +	const char *keyname;  	uint8_t *value;  	int value_len; -	int i, ret; - -	/* -	 * Check subnode name, must be equal to "hash". -	 * Multiple hash nodes require unique unit node -	 * names, e.g. hash@1, hash@2, etc. -	 */ -	if (strncmp(fit_get_name(fit, noffset, NULL), -		    FIT_HASH_NODENAME, -		    strlen(FIT_HASH_NODENAME)) != 0) -		return; +	char *algo; +	int required; +	int ret, i; -	debug("%s  Hash node:    '%s'\n", p, +	debug("%s  %s node:    '%s'\n", p, type,  	      fit_get_name(fit, noffset, NULL)); - -	printf("%s  Hash algo:    ", p); +	printf("%s  %s algo:    ", p, type);  	if (fit_image_hash_get_algo(fit, noffset, &algo)) {  		printf("invalid/unsupported\n");  		return;  	} -	printf("%s\n", algo); +	printf("%s", algo); +	keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); +	required = fdt_getprop(fit, noffset, "required", NULL) != NULL; +	if (keyname) +		printf(":%s", keyname); +	if (required) +		printf(" (required)"); +	printf("\n");  	ret = fit_image_hash_get_value(fit, noffset, &value,  					&value_len); -	printf("%s  Hash value:   ", p); +	printf("%s  %s value:   ", p, type);  	if (ret) {  		printf("unavailable\n");  	} else { @@ -278,7 +281,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p)  		printf("\n");  	} -	debug("%s  Hash len:     %d\n", p, value_len); +	debug("%s  %s len:     %d\n", p, type, value_len); + +	/* Signatures have a time stamp */ +	if (IMAGE_ENABLE_TIMESTAMP && keyname) { +		time_t timestamp; + +		printf("%s  Timestamp:    ", p); +		if (fit_get_timestamp(fit, noffset, ×tamp)) +			printf("unavailable\n"); +		else +			genimg_print_time(timestamp); +	}  }  /** @@ -303,8 +317,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset,  	 * names, e.g. hash@1, hash@2, signature@1, signature@2, etc.  	 */  	name = fit_get_name(fit, noffset, NULL); -	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) -		fit_image_print_data(fit, noffset, p); +	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { +		fit_image_print_data(fit, noffset, p, "Hash"); +	} else if (!strncmp(name, FIT_SIG_NODENAME, +				strlen(FIT_SIG_NODENAME))) { +		fit_image_print_data(fit, noffset, p, "Sign"); +	}  }  /** @@ -944,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset)  {  	const void	*data;  	size_t		size; -	int		noffset; +	int		noffset = 0;  	char		*err_msg = ""; +	int verify_all = 1; +	int ret;  	/* Get image data and data length */  	if (fit_image_get_data(fit, image_noffset, &data, &size)) {  		err_msg = "Can't get image data/size"; -		return 0; +		goto error; +	} + +	/* Verify all required signatures */ +	if (IMAGE_ENABLE_VERIFY && +	    fit_image_verify_required_sigs(fit, image_noffset, data, size, +					   gd_fdt_blob(), &verify_all)) { +		err_msg = "Unable to verify required signature"; +		goto error;  	}  	/* Process all hash subnodes of the component image node */ @@ -970,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset)  						 &err_msg))  				goto error;  			puts("+ "); +		} else if (IMAGE_ENABLE_VERIFY && verify_all && +				!strncmp(name, FIT_SIG_NODENAME, +					strlen(FIT_SIG_NODENAME))) { +			ret = fit_image_check_sig(fit, noffset, data, +							size, -1, &err_msg); +			if (ret) +				puts("- "); +			else +				puts("+ ");  		}  	} diff --git a/common/image-sig.c b/common/image-sig.c new file mode 100644 index 000000000..5d907cfc4 --- /dev/null +++ b/common/image-sig.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifdef USE_HOSTCC +#include "mkimage.h" +#include <time.h> +#else +#include <common.h> +#include <malloc.h> +DECLARE_GLOBAL_DATA_PTR; +#endif /* !USE_HOSTCC*/ +#include <image.h> +#include <rsa.h> + +#define IMAGE_MAX_HASHED_NODES		100 + +struct image_sig_algo image_sig_algos[] = { +	{ +		"sha1,rsa2048", +		rsa_sign, +		rsa_add_verify_data, +		rsa_verify, +	} +}; + +struct image_sig_algo *image_get_sig_algo(const char *name) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) { +		if (!strcmp(image_sig_algos[i].name, name)) +			return &image_sig_algos[i]; +	} + +	return NULL; +} + +/** + * fit_region_make_list() - Make a list of image regions + * + * Given a list of fdt_regions, create a list of image_regions. This is a + * simple conversion routine since the FDT and image code use different + * structures. + * + * @fit: FIT image + * @fdt_regions: Pointer to FDT regions + * @count: Number of FDT regions + * @region: Pointer to image regions, which must hold @count records. If + * region is NULL, then (except for an SPL build) the array will be + * allocated. + * @return: Pointer to image regions + */ +struct image_region *fit_region_make_list(const void *fit, +		struct fdt_region *fdt_regions, int count, +		struct image_region *region) +{ +	int i; + +	debug("Hash regions:\n"); +	debug("%10s %10s\n", "Offset", "Size"); + +	/* +	 * Use malloc() except in SPL (to save code size). In SPL the caller +	 * must allocate the array. +	 */ +#ifndef CONFIG_SPL_BUILD +	if (!region) +		region = calloc(sizeof(*region), count); +#endif +	if (!region) +		return NULL; +	for (i = 0; i < count; i++) { +		debug("%10x %10x\n", fdt_regions[i].offset, +		      fdt_regions[i].size); +		region[i].data = fit + fdt_regions[i].offset; +		region[i].size = fdt_regions[i].size; +	} + +	return region; +} + +static int fit_image_setup_verify(struct image_sign_info *info, +		const void *fit, int noffset, int required_keynode, +		char **err_msgp) +{ +	char *algo_name; + +	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { +		*err_msgp = "Can't get hash algo property"; +		return -1; +	} +	memset(info, '\0', sizeof(*info)); +	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); +	info->fit = (void *)fit; +	info->node_offset = noffset; +	info->algo = image_get_sig_algo(algo_name); +	info->fdt_blob = gd_fdt_blob(); +	info->required_keynode = required_keynode; +	printf("%s:%s", algo_name, info->keyname); + +	if (!info->algo) { +		*err_msgp = "Unknown signature algorithm"; +		return -1; +	} + +	return 0; +} + +int fit_image_check_sig(const void *fit, int noffset, const void *data, +		size_t size, int required_keynode, char **err_msgp) +{ +	struct image_sign_info info; +	struct image_region region; +	uint8_t *fit_value; +	int fit_value_len; + +	*err_msgp = NULL; +	if (fit_image_setup_verify(&info, fit, noffset, required_keynode, +				   err_msgp)) +		return -1; + +	if (fit_image_hash_get_value(fit, noffset, &fit_value, +				     &fit_value_len)) { +		*err_msgp = "Can't get hash value property"; +		return -1; +	} + +	region.data = data; +	region.size = size; + +	if (info.algo->verify(&info, ®ion, 1, fit_value, fit_value_len)) { +		*err_msgp = "Verification failed"; +		return -1; +	} + +	return 0; +} + +static int fit_image_verify_sig(const void *fit, int image_noffset, +		const char *data, size_t size, const void *sig_blob, +		int sig_offset) +{ +	int noffset; +	char *err_msg = ""; +	int verified = 0; +	int ret; + +	/* Process all hash subnodes of the component image node */ +	for (noffset = fdt_first_subnode(fit, image_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		const char *name = fit_get_name(fit, noffset, NULL); + +		if (!strncmp(name, FIT_SIG_NODENAME, +			     strlen(FIT_SIG_NODENAME))) { +			ret = fit_image_check_sig(fit, noffset, data, +							size, -1, &err_msg); +			if (ret) { +				puts("- "); +			} else { +				puts("+ "); +				verified = 1; +				break; +			} +		} +	} + +	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { +		err_msg = "Corrupted or truncated tree"; +		goto error; +	} + +	return verified ? 0 : -EPERM; + +error: +	printf(" error!\n%s for '%s' hash node in '%s' image node\n", +	       err_msg, fit_get_name(fit, noffset, NULL), +	       fit_get_name(fit, image_noffset, NULL)); +	return -1; +} + +int fit_image_verify_required_sigs(const void *fit, int image_noffset, +		const char *data, size_t size, const void *sig_blob, +		int *no_sigsp) +{ +	int verify_count = 0; +	int noffset; +	int sig_node; + +	/* Work out what we need to verify */ +	*no_sigsp = 1; +	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); +	if (sig_node < 0) { +		debug("%s: No signature node found: %s\n", __func__, +		      fdt_strerror(sig_node)); +		return 0; +	} + +	for (noffset = fdt_first_subnode(sig_blob, sig_node); +	     noffset >= 0; +	     noffset = fdt_next_subnode(sig_blob, noffset)) { +		const char *required; +		int ret; + +		required = fdt_getprop(sig_blob, noffset, "required", NULL); +		if (!required || strcmp(required, "image")) +			continue; +		ret = fit_image_verify_sig(fit, image_noffset, data, size, +					sig_blob, noffset); +		if (ret) { +			printf("Failed to verify required signature '%s'\n", +			       fit_get_name(sig_blob, noffset, NULL)); +			return ret; +		} +		verify_count++; +	} + +	if (verify_count) +		*no_sigsp = 0; + +	return 0; +} + +int fit_config_check_sig(const void *fit, int noffset, int required_keynode, +			 char **err_msgp) +{ +	char * const exc_prop[] = {"data"}; +	const char *prop, *end, *name; +	struct image_sign_info info; +	const uint32_t *strings; +	uint8_t *fit_value; +	int fit_value_len; +	int max_regions; +	int i, prop_len; +	char path[200]; +	int count; + +	debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(), +	      fit_get_name(fit, noffset, NULL), +	      fit_get_name(gd_fdt_blob(), required_keynode, NULL)); +	*err_msgp = NULL; +	if (fit_image_setup_verify(&info, fit, noffset, required_keynode, +				   err_msgp)) +		return -1; + +	if (fit_image_hash_get_value(fit, noffset, &fit_value, +				     &fit_value_len)) { +		*err_msgp = "Can't get hash value property"; +		return -1; +	} + +	/* Count the number of strings in the property */ +	prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len); +	end = prop ? prop + prop_len : prop; +	for (name = prop, count = 0; name < end; name++) +		if (!*name) +			count++; +	if (!count) { +		*err_msgp = "Can't get hashed-nodes property"; +		return -1; +	} + +	/* Add a sanity check here since we are using the stack */ +	if (count > IMAGE_MAX_HASHED_NODES) { +		*err_msgp = "Number of hashed nodes exceeds maximum"; +		return -1; +	} + +	/* Create a list of node names from those strings */ +	char *node_inc[count]; + +	debug("Hash nodes (%d):\n", count); +	for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { +		debug("   '%s'\n", name); +		node_inc[i] = (char *)name; +	} + +	/* +	 * Each node can generate one region for each sub-node. Allow for +	 * 7 sub-nodes (hash@1, signature@1, etc.) and some extra. +	 */ +	max_regions = 20 + count * 7; +	struct fdt_region fdt_regions[max_regions]; + +	/* Get a list of regions to hash */ +	count = fdt_find_regions(fit, node_inc, count, +			exc_prop, ARRAY_SIZE(exc_prop), +			fdt_regions, max_regions - 1, +			path, sizeof(path), 0); +	if (count < 0) { +		*err_msgp = "Failed to hash configuration"; +		return -1; +	} +	if (count == 0) { +		*err_msgp = "No data to hash"; +		return -1; +	} +	if (count >= max_regions - 1) { +		*err_msgp = "Too many hash regions"; +		return -1; +	} + +	/* Add the strings */ +	strings = fdt_getprop(fit, noffset, "hashed-strings", NULL); +	if (strings) { +		fdt_regions[count].offset = fdt_off_dt_strings(fit) + +				fdt32_to_cpu(strings[0]); +		fdt_regions[count].size = fdt32_to_cpu(strings[1]); +		count++; +	} + +	/* Allocate the region list on the stack */ +	struct image_region region[count]; + +	fit_region_make_list(fit, fdt_regions, count, region); +	if (info.algo->verify(&info, region, count, fit_value, +			      fit_value_len)) { +		*err_msgp = "Verification failed"; +		return -1; +	} + +	return 0; +} + +static int fit_config_verify_sig(const void *fit, int conf_noffset, +		const void *sig_blob, int sig_offset) +{ +	int noffset; +	char *err_msg = ""; +	int verified = 0; +	int ret; + +	/* Process all hash subnodes of the component conf node */ +	for (noffset = fdt_first_subnode(fit, conf_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		const char *name = fit_get_name(fit, noffset, NULL); + +		if (!strncmp(name, FIT_SIG_NODENAME, +			     strlen(FIT_SIG_NODENAME))) { +			ret = fit_config_check_sig(fit, noffset, sig_offset, +						   &err_msg); +			if (ret) { +				puts("- "); +			} else { +				puts("+ "); +				verified = 1; +				break; +			} +		} +	} + +	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { +		err_msg = "Corrupted or truncated tree"; +		goto error; +	} + +	return verified ? 0 : -EPERM; + +error: +	printf(" error!\n%s for '%s' hash node in '%s' config node\n", +	       err_msg, fit_get_name(fit, noffset, NULL), +	       fit_get_name(fit, conf_noffset, NULL)); +	return -1; +} + +int fit_config_verify_required_sigs(const void *fit, int conf_noffset, +		const void *sig_blob) +{ +	int noffset; +	int sig_node; + +	/* Work out what we need to verify */ +	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); +	if (sig_node < 0) { +		debug("%s: No signature node found: %s\n", __func__, +		      fdt_strerror(sig_node)); +		return 0; +	} + +	for (noffset = fdt_first_subnode(sig_blob, sig_node); +	     noffset >= 0; +	     noffset = fdt_next_subnode(sig_blob, noffset)) { +		const char *required; +		int ret; + +		required = fdt_getprop(sig_blob, noffset, "required", NULL); +		if (!required || strcmp(required, "conf")) +			continue; +		ret = fit_config_verify_sig(fit, conf_noffset, sig_blob, +					    noffset); +		if (ret) { +			printf("Failed to verify required signature '%s'\n", +			       fit_get_name(sig_blob, noffset, NULL)); +			return ret; +		} +	} + +	return 0; +} + +int fit_config_verify(const void *fit, int conf_noffset) +{ +	return !fit_config_verify_required_sigs(fit, conf_noffset, +						gd_fdt_blob()); +} diff --git a/common/image.c b/common/image.c index f863502ab..1be384f26 100644 --- a/common/image.c +++ b/common/image.c @@ -816,20 +816,23 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  	ulong		default_addr;  	int		rd_noffset;  #endif +	const char *select = NULL;  	*rd_start = 0;  	*rd_end = 0; +	if (argc >= 2) +		select = argv[1];  	/*  	 * Look for a '-' which indicates to ignore the  	 * ramdisk argument  	 */ -	if ((argc >= 3) && (strcmp(argv[2], "-") ==  0)) { +	if (select && strcmp(select, "-") ==  0) {  		debug("## Skipping init Ramdisk\n");  		rd_len = rd_data = 0; -	} else if (argc >= 3 || genimg_has_config(images)) { +	} else if (select || genimg_has_config(images)) {  #if defined(CONFIG_FIT) -		if (argc >= 3) { +		if (select) {  			/*  			 * If the init ramdisk comes from the FIT image and  			 * the FIT image address is omitted in the command @@ -841,12 +844,12 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  			else  				default_addr = load_addr; -			if (fit_parse_conf(argv[2], default_addr, -						&rd_addr, &fit_uname_config)) { +			if (fit_parse_conf(select, default_addr, +					   &rd_addr, &fit_uname_config)) {  				debug("*  ramdisk: config '%s' from image at "  						"0x%08lx\n",  						fit_uname_config, rd_addr); -			} else if (fit_parse_subimage(argv[2], default_addr, +			} else if (fit_parse_subimage(select, default_addr,  						&rd_addr, &fit_uname_ramdisk)) {  				debug("*  ramdisk: subimage '%s' from image at "  						"0x%08lx\n", @@ -854,7 +857,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  			} else  #endif  			{ -				rd_addr = simple_strtoul(argv[2], NULL, 16); +				rd_addr = simple_strtoul(select, NULL, 16);  				debug("*  ramdisk: cmdline image address = "  						"0x%08lx\n",  						rd_addr); @@ -918,7 +921,10 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  #endif  		default:  #ifdef CONFIG_SUPPORT_RAW_INITRD -			if (argc >= 3 && (end = strchr(argv[2], ':'))) { +			end = NULL; +			if (select) +				end = strchr(select, ':'); +			if (end) {  				rd_len = simple_strtoul(++end, NULL, 16);  				rd_data = rd_addr;  			} else diff --git a/common/usb_storage.c b/common/usb_storage.c index 457970f77..4599d03c3 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -170,9 +170,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *us,  		      block_dev_desc_t *dev_desc);  int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,  		      struct us_data *ss); -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr,  			    lbaint_t blkcnt, void *buffer); -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr,  			     lbaint_t blkcnt, const void *buffer);  struct usb_device * usb_get_dev_index(int index);  void uhci_show_temp_int_td(void); @@ -1054,7 +1054,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,  }  #endif /* CONFIG_USB_BIN_FIXUP */ -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr,  			    lbaint_t blkcnt, void *buffer)  {  	lbaint_t start, blks; @@ -1127,7 +1127,7 @@ retry_it:  	return blkcnt;  } -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr,  				lbaint_t blkcnt, const void *buffer)  {  	lbaint_t start, blks; @@ -210,6 +210,11 @@ CPPFLAGS += -ffunction-sections -fdata-sections  LDFLAGS_FINAL += --gc-sections  endif +# TODO(sjg@chromium.org): Is this correct on Mac OS? +ifdef CONFIG_FIT_SIGNATURE +HOSTLIBS	+= -lssl -lcrypto +endif +  ifneq ($(CONFIG_SYS_TEXT_BASE),)  CPPFLAGS += -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE)  endif @@ -268,6 +273,16 @@ CFLAGS += $(CFLAGS_WARN)  CFLAGS_STACK := $(call cc-option,-fstack-usage)  CFLAGS += $(CFLAGS_STACK) +BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%)) + +ifeq ($(findstring examples/,$(BCURDIR)),) +ifeq ($(CONFIG_SPL_BUILD),) +ifdef FTRACE +CFLAGS += -finstrument-functions -DFTRACE +endif +endif +endif +  # $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g<format>  # option to the assembler.  AFLAGS_DEBUG := @@ -330,7 +345,6 @@ export	CONFIG_SYS_TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS  #########################################################################  # Allow boards to use custom optimize flags on a per dir/file basis -BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%))  ALL_AFLAGS = $(AFLAGS) $(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR))  ALL_CFLAGS = $(CFLAGS) $(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR))  EXTRA_CPPFLAGS = $(CPPFLAGS_$(BCURDIR)/$(@F)) $(CPPFLAGS_$(BCURDIR)) diff --git a/doc/README.plan9 b/doc/README.plan9 new file mode 100644 index 000000000..2d3d0e0cf --- /dev/null +++ b/doc/README.plan9 @@ -0,0 +1,18 @@ +Plan 9 from Bell Labs kernel images require additional setup to pass +configuration information to the kernel.  An environment variable named +confaddr must be defined with the same value as CONFADDR (see mem.h). +Use of this facility is optional, but should be preferable to manual +configuration. + +When booting an image, arguments supplied to the bootm command will be +copied to CONFADDR.  If no arguments are specified, the contents of the +bootargs environment variable will be copied. + +If no command line arguments or bootargs are defined, CONFADDR is left +uninitialized to permit manual configuration.  For example, PC-style +configuration could be simulated by issuing a fatload in bootcmd: + +  # setenv bootcmd fatload mmc 0 $confaddr plan9.ini; ...; bootm + +Steven Stallion +June 2013 diff --git a/doc/README.srio-pcie-boot-corenet b/doc/README.srio-pcie-boot-corenet index cd7e7ee9b..2b1f76b8d 100644 --- a/doc/README.srio-pcie-boot-corenet +++ b/doc/README.srio-pcie-boot-corenet @@ -21,13 +21,13 @@ Environment of the SRIO or PCIE boot:  	e) Slave's RCW should configure the SerDes for SRIO or PCIE boot port, set  	   the boot location to SRIO or PCIE, and holdoff all the cores. -	----------        -----------             ----------- -	|		  |       |         |             |         | -	|		  |       |         |             |         | +	-----------       -----------             ----------- +	|         |       |         |             |         | +	|         |       |         |             |         |  	| NorFlash|<----->| Master  |SRIO or PCIE |  Slave  |<---->[EEPROM] -	|		  |       |         |<===========>|         | -	|		  |       |         |             |         | -	----------        -----------             ----------- +	|         |       |         |<===========>|         | +	|         |       |         |             |         | +	-----------       -----------             -----------  The example based on P4080DS platform:  	Two P4080DS platforms can be used to implement the boot from SRIO or PCIE. @@ -87,26 +87,32 @@ How to use this feature:  	   Please refer to the examples given above.  	2. U-Boot image's compilation. -		For master, U-Boot image should be generated normally. +	   For master, U-Boot image should be generated normally. -		For example, master U-Boot image used on P4080DS should be compiled with +	   For example, master U-Boot image used on P4080DS should be compiled with  				make P4080DS_config. -		For slave, U-Boot image should be generated specifically by +	   For slave, U-Boot image should be generated specifically by  				make xxxx_SRIO_PCIE_BOOT_config. -		For example, slave U-Boot image used on P4080DS should be compiled with +	   For example, slave U-Boot image used on P4080DS should be compiled with  				make P4080DS_SRIO_PCIE_BOOT_config.  	3. Necessary modifications based on a specific environment. -		For a specific environment, the addresses of the slave's U-Boot image, -		UCode, ENV stored in master's NorFlash, and any other configurations -		can be modified in the file: -					include/configs/corenet_ds.h. +	   For a specific environment, the addresses of the slave's U-Boot image, +	   UCode, ENV stored in master's NorFlash, and any other configurations +	   can be modified in the file: +				include/configs/corenet_ds.h.  	4. Set and save the environment variable "bootmaster" with "SRIO1", "SRIO2"  	   or "PCIE1", "PCIE2", "PCIE3" for master, and then restart it in order to  	   perform the role as a master for boot from SRIO or PCIE. + +NOTE: When the Slave's ENV parameters are stored in Master's NorFlash, +      it can fetch them through PCIE or SRIO interface. But the ENV +      parameters can not be modified by "saveenv" or other commands under +      the Slave's u-boot environment, because the Slave can not erase, +      write Master's NorFlash by PCIE or SRIO link. diff --git a/doc/README.trace b/doc/README.trace new file mode 100644 index 000000000..b535c0656 --- /dev/null +++ b/doc/README.trace @@ -0,0 +1,361 @@ +# +# Copyright (c) 2013 The Chromium OS Authors. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundatio; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +Tracing in U-Boot +================= + +U-Boot supports a simple tracing feature which allows a record of excecution +to be collected and sent to a host machine for analysis. At present the +main use for this is to profile boot time. + + +Overview +-------- + +The trace feature uses GCC's instrument-functions feature to trace all +function entry/exit points. These are then recorded in a memory buffer. +The memory buffer can be saved to the host over a network link using +tftpput or by writing to an attached memory device such as MMC. + +On the host, the file is first converted with a tool called 'proftool', +which extracts useful information from it. The resulting trace output +resembles that emitted by Linux's ftrace feature, so can be visually +displayed by pytimechart. + + +Quick-start using Sandbox +------------------------- + +Sandbox is a build of U-Boot that can run under Linux so it is a convenient +way of trying out tracing before you use it on your actual board. To do +this, follow these steps: + +Add the following to include/configs/sandbox.h (if not already there) + +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE		(16 << 20) +#define CONFIG_TRACE_EARLY_SIZE		(8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR		0x00100000 + +Build sandbox U-Boot with tracing enabled: + +$ make FTRACE=1 O=sandbox sandbox_config +$ make FTRACE=1 O=sandbox + +Run sandbox, wait for a bit of trace information to appear, and then capture +a trace: + +$ ./sandbox/u-boot + + +U-Boot 2013.04-rc2-00100-ga72fcef (Apr 17 2013 - 19:25:24) + +DRAM:  128 MiB +trace: enabled +Using default environment + +In:    serial +Out:   serial +Err:   serial +=>trace stats +        671,406 function sites +         69,712 function calls +              0 untracked function calls +         73,373 traced function calls +             16 maximum observed call depth +             15 call depth limit +         66,491 calls not traced due to depth +=>trace stats +        671,406 function sites +      1,279,450 function calls +              0 untracked function calls +        950,490 traced function calls (333217 dropped due to overflow) +             16 maximum observed call depth +             15 call depth limit +      1,275,767 calls not traced due to depth +=>trace calls 0 e00000 +Call list dumped to 00000000, size 0xae0a40 +=>print +baudrate=115200 +profbase=0 +profoffset=ae0a40 +profsize=e00000 +stderr=serial +stdin=serial +stdout=serial + +Environment size: 117/8188 bytes +=>sb save host 0 trace 0 ${profoffset} +11405888 bytes written in 10 ms (1.1 GiB/s) +=>reset + + +Then run proftool to convert the trace information to ftrace format. + +$ ./sandbox/tools/proftool -m sandbox/System.map -p trace dump-ftrace >trace.txt + +Finally run pytimechart to display it: + +$ pytimechart trace.txt + +Using this tool you can zoom and pan across the trace, with the function +calls on the left and little marks representing the start and end of each +function. + + +CONFIG Options +-------------- + +- CONFIG_TRACE +		Enables the trace feature in U-Boot. + +- CONFIG_CMD_TRACE +		Enables the trace command. + +- CONFIG_TRACE_BUFFER_SIZE +		Size of trace buffer to allocate for U-Boot. This buffer is +		used after relocation, as a place to put function tracing +		information. The address of the buffer is determined by +		the relocation code. + +- CONFIG_TRACE_EARLY +		Define this to start tracing early, before relocation. + +- CONFIG_TRACE_EARLY_SIZE +		Size of 'early' trace buffer. Before U-Boot has relocated +		it doesn't have a proper trace buffer. On many boards +		you can define an area of memory to use for the trace +		buffer until the 'real' trace buffer is available after +		relocation. The contents of this buffer are then copied to +		the real buffer. + +- CONFIG_TRACE_EARLY_ADDR +		Address of early trace buffer + + +Building U-Boot with Tracing Enabled +------------------------------------ + +Pass 'FTRACE=1' to the U-Boot Makefile to actually instrument the code. +This is kept as a separate option so that it is easy to enable/disable +instrumenting from the command line instead of having to change board +config files. + + +Collecting Trace Data +--------------------- + +When you run U-Boot on your board it will collect trace data up to the +limit of the trace buffer size you have specified. Once that is exhausted +no more data will be collected. + +Collecting trace data has an affect on execution time/performance. You +will notice this particularly with trvial functions - the overhead of +recording their execution may even exceed their normal execution time. +In practice this doesn't matter much so long as you are aware of the +effect. Once you have done your optimisations, turn off tracing before +doing end-to-end timing. + +The best time to start tracing is right at the beginning of U-Boot. The +best time to stop tracing is right at the end. In practice it is hard +to achieve these ideals. + +This implementation enables tracing early in board_init_f(). This means +that it captures most of the board init process, missing only the +early architecture-specific init. However, it also misses the entire +SPL stage if there is one. + +U-Boot typically ends with a 'bootm' command which loads and runs an +OS. There is useful trace data in the execution of that bootm +command. Therefore this implementation provides a way to collect trace +data after bootm has finished processing, but just before it jumps to +the OS. In practical terms, U-Boot runs the 'fakegocmd' environment +variable at this point. This variable should have a short script which +collects the trace data and writes it somewhere. + +Trace data collection relies on a microsecond timer, accesed through +timer_get_us(). So the first think you should do is make sure that +this produces sensible results for your board. Suitable sources for +this timer include high resolution timers, PWMs or profile timers if +available. Most modern SOCs have a suitable timer for this. Make sure +that you mark this timer (and anything it calls) with +__attribute__((no_instrument_function)) so that the trace library can +use it without causing an infinite loop. + + +Commands +-------- + +The trace command has variable sub-commands: + +- stats +		Display tracing statistics + +- pause +		Pause tracing + +- resume +		Resume tracing + +- funclist [<addr> <size>] +		Dump a list of functions into the buffer + +- calls  [<addr> <size>] +		Dump function call trace into buffer + +If the address and size are not given, these are obtained from environment +variables (see below). In any case the environment variables are updated +after the command runs. + + +Environment Variables +--------------------- + +The following are used: + +- profbase +		Base address of trace output buffer + +- profoffset +		Offset of first unwritten byte in trace output buffer + +- profsize +		Size of trace output buffer + +All of these are set by the 'trace calls' command. + +These variables keep track of the amount of data written to the trace +output buffer by the 'trace' command. The trace commands which write data +to the output buffer can use these to specify the buffer to write to, and +update profoffset each time. This allows successive commands to append data +to the same buffer, for example: + +	trace funclist 10000 e00000 +	trace calls + +(the latter command appends more data to the buffer). + + +- fakegocmd +		Specifies commands to run just before booting the OS. This +		is a useful time to write the trace data to the host for +		processing. + + +Writing Out Trace Data +---------------------- + +Once the trace data is in an output buffer in memory there are various ways +to transmit it to the host. Notably you can use tftput to send the data +over a network link: + +fakegocmd=trace pause; usb start; set autoload n; bootp; +	trace calls 10000000 1000000; +	tftpput ${profbase} ${profoffset} 192.168.1.4:/tftpboot/calls + +This starts up USB (to talk to an attached USB Ethernet dongle), writes +a trace log to address 10000000 and sends it to a host machine using +TFTP. After this, U-Boot will boot the OS normally, albeit a little +later. + + +Converting Trace Output Data +---------------------------- + +The trace output data is kept in a binary format which is not documented +here. To convert it into something useful, you can use proftool. + +This tool must be given the U-Boot map file and the trace data received +from running that U-Boot. It produces a text output file. + +Options +	-m <map_file> +		Specify U-Boot map file + +	-p <trace_file> +		Specifiy profile/trace file + +Commands: + +- dump-ftrace +	Write a text dump of the file in Linux ftrace format to stdout + + +Viewing the Trace Data +---------------------- + +You can use pytimechart for this (sudo apt-get pytimechart might work on +your Debian-style machine, and use your favourite search engine to obtain +documentation). It expects the file to have a .txt extension. The program +has terse user interface but is very convenient for viewing U-Boot +profile information. + + +Workflow Suggestions +-------------------- + +The following suggestions may be helpful if you are trying to reduce boot +time: + +1. Enable CONFIG_BOOTSTAGE and CONFIG_BOOTSTAGE_REPORT. This should get +you are helpful overall snapshot of the boot time. + +2. Build U-Boot with tracing and run it. Note the difference in boot time +(it is common for tracing to add 10% to the time) + +3. Collect the trace information as descibed above. Use this to find where +all the time is being spent. + +4. Take a look at that code and see if you can optimise it. Perhaps it is +possible to speed up the initialisation of a device, or remove an unused +feature. + +5. Rebuild, run and collect again. Compare your results. + +6. Keep going until you run out of steam, or your boot is fast enough. + + +Configuring Trace +----------------- + +There are a few parameters in the code that you may want to consider. +There is a function call depth limit (set to 15 by default). When the +stack depth goes above this then no tracing information is recorded. +The maximum depth reached is recorded and displayed by the 'trace stats' +command. + + +Future Work +----------- + +Tracing could be a little tidier in some areas, for example providing +run-time configuration options for trace. + +Some other features that might be useful: + +- Trace filter to select which functions are recorded +- Sample-based profiling using a timer interrupt +- Better control over trace depth +- Compression of trace information + + +Simon Glass <sjg@chromium.org> +April 2013 diff --git a/doc/device-tree-bindings/exynos/dwmmc.txt b/doc/device-tree-bindings/exynos/dwmmc.txt new file mode 100644 index 000000000..566da3b63 --- /dev/null +++ b/doc/device-tree-bindings/exynos/dwmmc.txt @@ -0,0 +1,54 @@ +* Exynos 5250 DWC_mobile_storage + +The Exynos 5250 provides DWC_mobile_storage interface which supports +. Embedded Multimedia Cards (EMMC-version 4.5) +. Secure Digital memory (SD mem-version 2.0) +. Secure Digital I/O (SDIO-version 3.0) +. Consumer Electronics Advanced Transport Architecture (CE-ATA-version 1.1) + +The Exynos 5250 DWC_mobile_storage provides four channels. +SOC specific and Board specific properties are channel specific. + +Required SoC Specific Properties: + +- compatible: should be +	- samsung,exynos5250-dwmmc: for exynos5250 platforms + +- reg: physical base address of the controller and length of memory mapped +	region. + +- interrupts: The interrupt number to the cpu. + +Required Board Specific Properties: + +- #address-cells: should be 1. +- #size-cells: should be 0. +- samsung,bus-width: The width of the bus used to interface the devices +	supported by DWC_mobile_storage (SD-MMC/EMMC/SDIO). +	. Typically the bus width is 4 or 8. +- samsung,timing: The timing values to be written into the +	Drv/sample clock selection register of corresponding channel. +	. It is comprised of 3 values corresponding to the 3 fileds +	  'SelClk_sample', 'SelClk_drv' and 'DIVRATIO' of CLKSEL register. +	. SelClk_sample: Select sample clock among 8 shifted clocks. +	. SelClk_drv: Select drv clock among 8 shifted clocks. +	. DIVRATIO: Clock Divide ratio select. +	. The above 3 values are used by the clock phase shifter. + +Example: + +mmc@12200000 { +	samsung,bus-width = <8>; +	samsung,timing = <1 3 3>; +	samsung,removable = <1>; +} +In the above example, +	. The bus width is 8 +	. Timing is comprised of 3 values as explained below +		1 - SelClk_sample +		3 - SelClk_drv +		3 - DIVRATIO +	. The 'removable' flag indicates whether the the particilar device +	  cannot be removed (always present) or it is a removable device. +		1 - Indicates that the device is removable. +		0 - Indicates that the device cannot be removed. diff --git a/doc/device-tree-bindings/input/cros-ec-keyb.txt b/doc/device-tree-bindings/input/cros-ec-keyb.txt new file mode 100644 index 000000000..311827607 --- /dev/null +++ b/doc/device-tree-bindings/input/cros-ec-keyb.txt @@ -0,0 +1,79 @@ +CROS_EC Keyboard + +The CROS_EC (Matrix Keyboard Protocol) allows communcation with a secondary +micro used for keyboard, and possible other features. + +The CROS_EC keyboard uses this protocol to receive key scans and produce input +in U-Boot. + +Required properties : +- compatible : "google,cros-ec-keyb" +- google,key-rows : Number of key rows +- google,key-columns : Number of key columns + +Optional properties, in addition to those specified by the shared +matrix-keyboard bindings: + +- linux,fn-keymap: a second keymap, same specification as the +  matrix-keyboard-controller spec but to be used when the KEY_FN modifier +  key is pressed. +- google,repeat-delay-ms : delay in milliseconds before repeat starts +- google,repeat-rate-ms : delay between each subsequent key press +- google,ghost-filter : enable ghost filtering for this device + +Example, taken from daisy: + +cros-ec-keyb { +	compatible = "google,cros-ec-keyb"; +	google,key-rows = <8>; +	google,key-columns = <13>; +	google,ghost-filter; +	google,repeat-delay-ms = <240>; +	google,repeat-rate-ms = <30>; +	/* +		* Keymap entries take the form of 0xRRCCKKKK where +		* RR=Row CC=Column KKKK=Key Code +		* The values below are for a US keyboard layout and +		* are taken from the Linux driver. Note that the +		* 102ND key is not used for US keyboards. +		*/ +	linux,keymap = < +		/* CAPSLCK F1         B          F10     */ +		0x0001003a 0x0002003c 0x00030030 0x00040044 +		/* N       =          R_ALT      ESC     */ +		0x00060031 0x0008000d 0x000a0064 0x01010001 +		/* F4      G          F7         H       */ +		0x0102003e 0x01030022 0x01040041 0x01060023 +		/* '       F9         BKSPACE    L_CTRL  */ +		0x01080028 0x01090043 0x010b000e 0x0200001d +		/* TAB     F3         T          F6      */ +		0x0201000f 0x0202003d 0x02030014 0x02040040 +		/* ]       Y          102ND      [       */ +		0x0205001b 0x02060015 0x02070056 0x0208001a +		/* F8      GRAVE      F2         5       */ +		0x02090042 0x03010029 0x0302003c 0x03030006 +		/* F5      6          -          \       */ +		0x0304003f 0x03060007 0x0308000c 0x030b002b +		/* R_CTRL  A          D          F       */ +		0x04000061 0x0401001e 0x04020020 0x04030021 +		/* S       K          J          ;       */ +		0x0404001f 0x04050025 0x04060024 0x04080027 +		/* L       ENTER      Z          C       */ +		0x04090026 0x040b001c 0x0501002c 0x0502002e +		/* V       X          ,          M       */ +		0x0503002f 0x0504002d 0x05050033 0x05060032 +		/* L_SHIFT /          .          SPACE   */ +		0x0507002a 0x05080035 0x05090034 0x050B0039 +		/* 1       3          4          2       */ +		0x06010002 0x06020004 0x06030005 0x06040003 +		/* 8       7          0          9       */ +		0x06050009 0x06060008 0x0608000b 0x0609000a +		/* L_ALT   DOWN       RIGHT      Q       */ +		0x060a0038 0x060b006c 0x060c006a 0x07010010 +		/* E       R          W          I       */ +		0x07020012 0x07030013 0x07040011 0x07050017 +		/* U       R_SHIFT    P          O       */ +		0x07060016 0x07070036 0x07080019 0x07090018 +		/* UP      LEFT    */ +		0x070b0067 0x070c0069>; +}; diff --git a/doc/device-tree-bindings/misc/cros-ec.txt b/doc/device-tree-bindings/misc/cros-ec.txt new file mode 100644 index 000000000..07ea7cdea --- /dev/null +++ b/doc/device-tree-bindings/misc/cros-ec.txt @@ -0,0 +1,38 @@ +Chrome OS CROS_EC Binding +====================== + +The device tree node which describes the operation of the CROS_EC interface +is as follows: + +Required properties : +- compatible = "google,cros-ec" + +Optional properties : +- spi-max-frequency : Sets the maximum frequency (in Hz) for SPI bus +   operation +- i2c-max-frequency : Sets the maximum frequency (in Hz) for I2C bus +   operation +- ec-interrupt : Selects the EC interrupt, defined as a GPIO according +   to the platform +- optimise-flash-write : Boolean property - if present then flash blocks +   containing all 0xff will not be written, since we assume that the EC +   uses that pattern for erased blocks + +The CROS_EC node should appear as a subnode of the interrupt that connects it +to the EC (e.g. i2c, spi, lpc). The reg property (as usual) will indicate +the unit address on that bus. + + +Example +======= + +	spi@131b0000 { +		cros-ec@0 { +			reg = <0>; +			compatible = "google,cros-ec"; +			spi-max-frequency = <5000000>; +			ec-interrupt = <&gpio 174 1>; +			optimise-flash-write; +			status = "disabled"; +		}; +	}; diff --git a/doc/mkimage.1 b/doc/mkimage.1 index 39652c82d..14374da88 100644 --- a/doc/mkimage.1 +++ b/doc/mkimage.1 @@ -4,7 +4,17 @@  mkimage \- Generate image for U-Boot  .SH SYNOPSIS  .B mkimage -.RB [\fIoptions\fP] +.RB "\-l [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " \-F [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " (legacy mode)" +  .SH "DESCRIPTION"  The  .B mkimage @@ -26,7 +36,8 @@ etc.  The new  .I FIT (Flattened Image Tree) format  allows for more flexibility in handling images of various types and also -enhances integrity protection of images with stronger checksums. +enhances integrity protection of images with stronger checksums. It also +supports verified boot.  .SH "OPTIONS" @@ -67,6 +78,10 @@ Set load address with a hex number.  Set entry point with a hex number.  .TP +.BI "\-l" +List the contents of an image. + +.TP  .BI "\-n [" "image name" "]"  Set image name to 'image name'. @@ -82,6 +97,12 @@ Set XIP (execute in place) flag.  .B Create FIT image:  .TP +.BI "\-c [" "comment" "]" +Specifies a comment to be added when signing. This is typically a useful +message which describes how the image was signed or some other useful +information. + +.TP  .BI "\-D [" "dtc options" "]"  Provide special options to the device tree compiler that is used to  create the image. @@ -91,6 +112,33 @@ create the image.  Image tree source file that describes the structure and contents of the  FIT image. +.TP +.BI "\-F" +Indicates that an existing FIT image should be modified. No dtc +compilation is performed and the -f flag should not be given. +This can be used to sign images with additional keys after initial image +creation. + +.TP +.BI "\-k [" "key_directory" "]" +Specifies the directory containing keys to use for signing. This directory +should contain a private key file <name>.key for use with signing and a +certificate <name>.crt (containing the public key) for use with verification. + +.TP +.BI "\-K [" "key_destination" "]" +Specifies a compiled device tree binary file (typically .dtb) to write +public key information into. When a private key is used to sign an image, +the corresponding public key is written into this file for for run-time +verification. Typically the file here is the device tree binary used by +CONFIG_OF_CONTROL in U-Boot. + +.TP +.BI "\-r +Specifies that keys used to sign the FIT are required. This means that they +must be verified for the image to boot. Without this option, the verification +will be optional (useful for testing but not for release). +  .SH EXAMPLES  List image information: @@ -109,10 +157,29 @@ Create FIT image with compressed PowerPC Linux kernel:  .nf  .B mkimage -f kernel.its kernel.itb  .fi +.P +Create FIT image with compressed kernel and sign it with keys in the +/public/signing-keys directory. Add corresponding public keys into u-boot.dtb, +skipping those for which keys cannot be found. Also add a comment. +.nf +.B mkimage -f kernel.its -k /public/signing-keys -K u-boot.dtb \\\\ +-c "Kernel 3.8 image for production devices" kernel.itb +.fi + +.P +Update an existing FIT image, signing it with additional keys. +Add corresponding public keys into u-boot.dtb. This will resign all images +with keys that are available in the new directory. Images that request signing +with unavailable keys are skipped. +.nf +.B mkimage -F -k /secret/signing-keys -K u-boot.dtb \\\\ +-c "Kernel 3.8 image for production devices" kernel.itb +.fi  .SH HOMEPAGE  http://www.denx.de/wiki/U-Boot/WebHome  .PP  .SH AUTHOR  This manual page was written by Nobuhiro Iwamatsu <iwamatsu@nigauri.org> -and Wolfgang Denk <wd@denx.de> +and Wolfgang Denk <wd@denx.de>. It was updated for image signing by +Simon Glass <sjg@chromium.org>. diff --git a/doc/uImage.FIT/sign-configs.its b/doc/uImage.FIT/sign-configs.its new file mode 100644 index 000000000..3c17f040d --- /dev/null +++ b/doc/uImage.FIT/sign-configs.its @@ -0,0 +1,45 @@ +/dts-v1/; + +/ { +	description = "Chrome OS kernel image with one or more FDT blobs"; +	#address-cells = <1>; + +	images { +		kernel@1 { +			data = /incbin/("test-kernel.bin"); +			type = "kernel_noload"; +			arch = "sandbox"; +			os = "linux"; +			compression = "lzo"; +			load = <0x4>; +			entry = <0x8>; +			kernel-version = <1>; +			hash@1 { +				algo = "sha1"; +			}; +		}; +		fdt@1 { +			description = "snow"; +			data = /incbin/("sandbox-kernel.dtb"); +			type = "flat_dt"; +			arch = "sandbox"; +			compression = "none"; +			fdt-version = <1>; +			hash@1 { +				algo = "sha1"; +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +				sign-images = "fdt", "kernel"; +			}; +		}; +	}; +}; diff --git a/doc/uImage.FIT/sign-images.its b/doc/uImage.FIT/sign-images.its new file mode 100644 index 000000000..f69326a39 --- /dev/null +++ b/doc/uImage.FIT/sign-images.its @@ -0,0 +1,42 @@ +/dts-v1/; + +/ { +	description = "Chrome OS kernel image with one or more FDT blobs"; +	#address-cells = <1>; + +	images { +		kernel@1 { +			data = /incbin/("test-kernel.bin"); +			type = "kernel_noload"; +			arch = "sandbox"; +			os = "linux"; +			compression = "none"; +			load = <0x4>; +			entry = <0x8>; +			kernel-version = <1>; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +			}; +		}; +		fdt@1 { +			description = "snow"; +			data = /incbin/("sandbox-kernel.dtb"); +			type = "flat_dt"; +			arch = "sandbox"; +			compression = "none"; +			fdt-version = <1>; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +		}; +	}; +}; diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt new file mode 100644 index 000000000..bc9f3fa6e --- /dev/null +++ b/doc/uImage.FIT/signature.txt @@ -0,0 +1,382 @@ +U-Boot FIT Signature Verification +================================= + +Introduction +------------ +FIT supports hashing of images so that these hashes can be checked on +loading. This protects against corruption of the image. However it does not +prevent the substitution of one image for another. + +The signature feature allows the hash to be signed with a private key such +that it can be verified using a public key later. Provided that the private +key is kept secret and the public key is stored in a non-volatile place, +any image can be verified in this way. + +See verified-boot.txt for more general information on verified boot. + + +Concepts +-------- +Some familiarity with public key cryptography is assumed in this section. + +The procedure for signing is as follows: + +   - hash an image in the FIT +   - sign the hash with a private key to produce a signature +   - store the resulting signature in the FIT + +The procedure for verification is: + +   - read the FIT +   - obtain the public key +   - extract the signature from the FIT +   - hash the image from the FIT +   - verify (with the public key) that the extracted signature matches the +       hash + +The signing is generally performed by mkimage, as part of making a firmware +image for the device. The verification is normally done in U-Boot on the +device. + + +Algorithms +---------- +In principle any suitable algorithm can be used to sign and verify a hash. +At present only one class of algorithms is supported: SHA1 hashing with RSA. +This works by hashing the image to produce a 20-byte hash. + +While it is acceptable to bring in large cryptographic libraries such as +openssl on the host side (e.g. mkimage), it is not desirable for U-Boot. +For the run-time verification side, it is important to keep code and data +size as small as possible. + +For this reason the RSA image verification uses pre-processed public keys +which can be used with a very small amount of code - just some extraction +of data from the FDT and exponentiation mod n. Code size impact is a little +under 5KB on Tegra Seaboard, for example. + +It is relatively straightforward to add new algorithms if required. If +another RSA variant is needed, then it can be added to the table in +image-sig.c. If another algorithm is needed (such as DSA) then it can be +placed alongside rsa.c, and its functions added to the table in image-sig.c +also. + + +Creating an RSA key and certificate +----------------------------------- +To create a new public key, size 2048 bits: + +$ openssl genrsa -F4 -out keys/dev.key 2048 + +To create a certificate for this: + +$ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt + +If you like you can look at the public key also: + +$ openssl rsa -in keys/dev.key -pubout + + +Device Tree Bindings +-------------------- +The following properties are required in the FIT's signature node(s) to +allow thes signer to operate. These should be added to the .its file. +Signature nodes sit at the same level as hash nodes and are called +signature@1, signature@2, etc. + +- algo: Algorithm name (e.g. "sha1,rs2048") + +- key-name-hint: Name of key to use for signing. The keys will normally be in +a single directory (parameter -k to mkimage). For a given key <name>, its +private key is stored in <name>.key and the certificate is stored in +<name>.crt. + +When the image is signed, the following properties are added (mandatory): + +- value: The signature data (e.g. 256 bytes for 2048-bit RSA) + +When the image is signed, the following properties are optional: + +- timestamp: Time when image was signed (standard Unix time_t format) + +- signer-name: Name of the signer (e.g. "mkimage") + +- signer-version: Version string of the signer (e.g. "2013.01") + +- comment: Additional information about the signer or image + +For config bindings (see Signed Configurations below), the following +additional properties are optional: + +- sign-images: A list of images to sign, each being a property of the conf +node that contains then. The default is "kernel,fdt" which means that these +two images will be looked up in the config and signed if present. + +For config bindings, these properties are added by the signer: + +- hashed-nodes: A list of nodes which were hashed by the signer. Each is +	a string - the full path to node. A typical value might be: + +	hashed-nodes = "/", "/configurations/conf@1", "/images/kernel@1", +		"/images/kernel@1/hash@1", "/images/fdt@1", +		"/images/fdt@1/hash@1"; + +- hashed-strings: The start and size of the string region of the FIT that +	was hashed + +Example: See sign-images.its for an example image tree source file and +sign-configs.its for config signing. + + +Public Key Storage +------------------ +In order to verify an image that has been signed with a public key we need to +have a trusted public key. This cannot be stored in the signed image, since +it would be easy to alter. For this implementation we choose to store the +public key in U-Boot's control FDT (using CONFIG_OF_CONTROL). + +Public keys should be stored as sub-nodes in a /signature node. Required +properties are: + +- algo: Algorithm name (e.g. "sha1,rs2048") + +Optional properties are: + +- key-name-hint: Name of key used for signing. This is only a hint since it +is possible for the name to be changed. Verification can proceed by checking +all available signing keys until one matches. + +- required: If present this indicates that the key must be verified for the +image / configuration to be considered valid. Only required keys are +normally verified by the FIT image booting algorithm. Valid values are +"image" to force verification of all images, and "conf" to force verfication +of the selected configuration (which then relies on hashes in the images to +verify those). + +Each signing algorithm has its own additional properties. + +For RSA the following are mandatory: + +- rsa,num-bits: Number of key bits (e.g. 2048) +- rsa,modulus: Modulus (N) as a big-endian multi-word integer +- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer +- rsa,n0-inverse: -1 / modulus[0] mod 2^32 + + +Signed Configurations +--------------------- +While signing images is useful, it does not provide complete protection +against several types of attack. For example, it it possible to create a +FIT with the same signed images, but with the configuration changed such +that a different one is selected (mix and match attack). It is also possible +to substitute a signed image from an older FIT version into a newer FIT +(roll-back attack). + +As an example, consider this FIT: + +/ { +	images { +		kernel@1 { +			data = <data for kernel1> +			signature@1 { +				algo = "sha1,rsa2048"; +				value = <...kernel signature 1...> +			}; +		}; +		kernel@2 { +			data = <data for kernel2> +			signature@1 { +				algo = "sha1,rsa2048"; +				value = <...kernel signature 2...> +			}; +		}; +		fdt@1 { +			data = <data for fdt1>; +			signature@1 { +				algo = "sha1,rsa2048"; +				vaue = <...fdt signature 1...> +			}; +		}; +		fdt@2 { +			data = <data for fdt2>; +			signature@1 { +				algo = "sha1,rsa2048"; +				vaue = <...fdt signature 2...> +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +		}; +		conf@1 { +			kernel = "kernel@2"; +			fdt = "fdt@2"; +		}; +	}; +}; + +Since both kernels are signed it is easy for an attacker to add a new +configuration 3 with kernel 1 and fdt 2: + +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +		}; +		conf@1 { +			kernel = "kernel@2"; +			fdt = "fdt@2"; +		}; +		conf@3 { +			kernel = "kernel@1"; +			fdt = "fdt@2"; +		}; +	}; + +With signed images, nothing protects against this. Whether it gains an +advantage for the attacker is debatable, but it is not secure. + +To solved this problem, we support signed configurations. In this case it +is the configurations that are signed, not the image. Each image has its +own hash, and we include the hash in the configuration signature. + +So the above example is adjusted to look like this: + +/ { +	images { +		kernel@1 { +			data = <data for kernel1> +			hash@1 { +				algo = "sha1"; +				value = <...kernel hash 1...> +			}; +		}; +		kernel@2 { +			data = <data for kernel2> +			hash@1 { +				algo = "sha1"; +				value = <...kernel hash 2...> +			}; +		}; +		fdt@1 { +			data = <data for fdt1>; +			hash@1 { +				algo = "sha1"; +				value = <...fdt hash 1...> +			}; +		}; +		fdt@2 { +			data = <data for fdt2>; +			hash@1 { +				algo = "sha1"; +				value = <...fdt hash 2...> +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +			signature@1 { +				algo = "sha1,rsa2048"; +				value = <...conf 1 signature...>; +			}; +		}; +		conf@2 { +			kernel = "kernel@2"; +			fdt = "fdt@2"; +			signature@1 { +				algo = "sha1,rsa2048"; +				value = <...conf 1 signature...>; +			}; +		}; +	}; +}; + + +You can see that we have added hashes for all images (since they are no +longer signed), and a signature to each configuration. In the above example, +mkimage will sign configurations/conf@1, the kernel and fdt that are +pointed to by the configuration (/images/kernel@1, /images/kernel@1/hash@1, +/images/fdt@1, /images/fdt@1/hash@1) and the root structure of the image +(so that it isn't possible to add or remove root nodes). The signature is +written into /configurations/conf@1/signature@1/value. It can easily be +verified later even if the FIT has been signed with other keys in the +meantime. + + +Verification +------------ +FITs are verified when loaded. After the configuration is selected a list +of required images is produced. If there are 'required' public keys, then +each image must be verified against those keys. This means that every image +that might be used by the target needs to be signed with 'required' keys. + +This happens automatically as part of a bootm command when FITs are used. + + +Enabling FIT Verification +------------------------- +In addition to the options to enable FIT itself, the following CONFIGs must +be enabled: + +CONFIG_FIT_SIGNATURE - enable signing and verfication in FITs +CONFIG_RSA - enable RSA algorithm for signing + + +Testing +------- +An easy way to test signing and verfication is to use the test script +provided in test/vboot/vboot_test.sh. This uses sandbox (a special version +of U-Boot which runs under Linux) to show the operation of a 'bootm' +command loading and verifying images. + +A sample run is show below: + +$ make O=sandbox sandbox_config +$ make O=sandbox +$ O=sandbox ./test/vboot/vboot_test.sh +Simple Verified Boot Test +========================= + +Please see doc/uImage.FIT/verified-boot.txt for more information + +Build keys +Build FIT with signed images +Test Verified Boot Run: unsigned signatures:: OK +Sign images +Test Verified Boot Run: signed images: OK +Build FIT with signed configuration +Test Verified Boot Run: unsigned config: OK +Sign images +Test Verified Boot Run: signed config: OK + +Test passed + + +Future Work +----------- +- Roll-back protection using a TPM is done using the tpm command. This can +be scripted, but we might consider a default way of doing this, built into +bootm. + + +Possible Future Work +-------------------- +- Add support for other RSA/SHA variants, such as rsa4096,sha512. +- Other algorithms besides RSA +- More sandbox tests for failure modes +- Passwords for keys/certificates +- Perhaps implement OAEP +- Enhance bootm to permit scripted signature verification (so that a script +can verify an image but not actually boot it) + + +Simon Glass +sjg@chromium.org +1-1-13 diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt new file mode 100644 index 000000000..3c83fbc2c --- /dev/null +++ b/doc/uImage.FIT/verified-boot.txt @@ -0,0 +1,104 @@ +U-Boot Verified Boot +==================== + +Introduction +------------ +Verified boot here means the verification of all software loaded into a +machine during the boot process to ensure that it is authorised and correct +for that machine. + +Verified boot extends from the moment of system reset to as far as you wish +into the boot process. An example might be loading U-Boot from read-only +memory, then loading a signed kernel, then using the kernel's dm-verity +driver to mount a signed root filesystem. + +A key point is that it is possible to field-upgrade the software on machines +which use verified boot. Since the machine will only run software that has +been correctly signed, it is safe to read software from an updatable medium. +It is also possible to add a secondary signed firmware image, in read-write +memory, so that firmware can easily be upgraded in a secure manner. + + +Signing +------- +Verified boot uses cryptographic algorithms to 'sign' software images. +Images are signed using a private key known only to the signer, but can +be verified using a public key. As its name suggests the public key can be +made available without risk to the verification process. The private and +public keys are mathematically related. For more information on how this +works look up "public key cryptography" and "RSA" (a particular algorithm). + +The signing and verification process looks something like this: + + +      Signing                                      Verification +      =======                                      ============ + + +--------------+                   * + | RSA key pair |                   *             +---------------+ + | .key  .crt   |                   *             | Public key in | + +--------------+       +------> public key ----->| trusted place | +       |                |           *             +---------------+ +       |                |           *                    | +       v                |           *                    v +   +---------+          |           *              +--------------+ +   |         |----------+           *              |              | +   | signer  |                      *              |    U-Boot    | +   |         |----------+           *              |  signature   |--> yes/no +   +---------+          |           *              | verification | +      ^                 |           *              |              | +      |                 |           *              +--------------+ +      |                 |           *                    ^ + +----------+           |           *                    | + | Software |           +----> signed image -------------+ + |  image   |                       * + +----------+                       * + + +The signature algorithm relies only on the public key to do its work. Using +this key it checks the signature that it finds in the image. If it verifies +then we know that the image is OK. + +The public key from the signer allows us to verify and therefore trust +software from updatable memory. + +It is critical that the public key be secure and cannot be tampered with. +It can be stored in read-only memory, or perhaps protected by other on-chip +crypto provided by some modern SOCs. If the public key can ben changed, then +the verification is worthless. + + +Chaining Images +--------------- +The above method works for a signer providing images to a run-time U-Boot. +It is also possible to extend this scheme to a second level, like this: + +1. Master private key is used by the signer to sign a first-stage image. +2. Master public key is placed in read-only memory. +2. Secondary private key is created and used to sign second-stage images. +3. Secondary public key is placed in first stage images +4. We use the master public key to verify the first-stage image. We then +use the secondary public key in the first-stage image to verify the second- +state image. +5. This chaining process can go on indefinitely. It is recommended to use a +different key at each stage, so that a compromise in one place will not +affect the whole change. + + +Flattened Image Tree (FIT) +-------------------------- +The FIT format is alreay widely used in U-Boot. It is a flattened device +tree (FDT) in a particular format, with images contained within. FITs +include hashes to verify images, so it is relatively straightforward to +add signatures as well. + +The public key can be stored in U-Boot's CONFIG_OF_CONTROL device tree in +a standard place. Then when a FIT it loaded it can be verified using that +public key. Multiple keys and multiple signatures are supported. + +See signature.txt for more information. + + +Simon Glass +sjg@chromium.org +1-1-13 diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index f3adf6485..bb8e644cd 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -133,8 +133,7 @@ int dtt_init_one(int sensor)  	/*  	 * Setup PWM Lookup-Table  	 */ -	for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry); -	     i++) { +	for (i = 0; i < ARRAY_SIZE(pwm_lookup); i++) {  		int address = DTT_PWM_LOOKUP_BASE + 2 * i;  		val = pwm_lookup[i].temp;  		if (is_lm64(sensor)) diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 0805e8667..4331190de 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -27,6 +27,7 @@ LIB	:= $(obj)libinput.o  COBJS-$(CONFIG_I8042_KBD) += i8042.o  COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o +COBJS-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o  ifdef CONFIG_PS2KBD  COBJS-y += keyboard.o pc_keyb.o  COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c new file mode 100644 index 000000000..c19730822 --- /dev/null +++ b/drivers/input/cros_ec_keyb.c @@ -0,0 +1,261 @@ +/* + * Chromium OS Matrix Keyboard + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <cros_ec.h> +#include <fdtdec.h> +#include <input.h> +#include <key_matrix.h> +#include <stdio_dev.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { +	KBC_MAX_KEYS		= 8,	/* Maximum keys held down at once */ +}; + +static struct keyb { +	struct cros_ec_dev *dev;		/* The CROS_EC device */ +	struct input_config input;	/* The input layer */ +	struct key_matrix matrix;	/* The key matrix layer */ +	int key_rows;			/* Number of keyboard rows */ +	int key_cols;			/* Number of keyboard columns */ +	unsigned int repeat_delay_ms;	/* Time before autorepeat starts */ +	unsigned int repeat_rate_ms;	/* Autorepeat rate in ms */ +	int ghost_filter;		/* 1 to enable ghost filter, else 0 */ +	int inited;			/* 1 if keyboard is ready */ +} config; + + +/** + * Check the keyboard controller and return a list of key matrix positions + * for which a key is pressed + * + * @param config	Keyboard config + * @param keys		List of keys that we have detected + * @param max_count	Maximum number of keys to return + * @return number of pressed keys, 0 for none + */ +static int check_for_keys(struct keyb *config, +			   struct key_matrix_key *keys, int max_count) +{ +	struct key_matrix_key *key; +	struct mbkp_keyscan scan; +	unsigned int row, col, bit, data; +	int num_keys; + +	if (cros_ec_scan_keyboard(config->dev, &scan)) { +		debug("%s: keyboard scan failed\n", __func__); +		return -1; +	} + +	for (col = num_keys = bit = 0; col < config->matrix.num_cols; +			col++) { +		for (row = 0; row < config->matrix.num_rows; row++) { +			unsigned int mask = 1 << (bit & 7); + +			data = scan.data[bit / 8]; +			if ((data & mask) && num_keys < max_count) { +				key = keys + num_keys++; +				key->row = row; +				key->col = col; +				key->valid = 1; +			} +			bit++; +		} +	} + +	return num_keys; +} + +/** + * Test if keys are available to be read + * + * @return 0 if no keys available, 1 if keys are available + */ +static int kbd_tstc(void) +{ +	/* Just get input to do this for us */ +	return config.inited ? input_tstc(&config.input) : 0; +} + +/** + * Read a key + * + * @return ASCII key code, or 0 if no key, or -1 if error + */ +static int kbd_getc(void) +{ +	/* Just get input to do this for us */ +	return config.inited ? input_getc(&config.input) : 0; +} + +/** + * Check the keyboard, and send any keys that are pressed. + * + * This is called by input_tstc() and input_getc() when they need more + * characters + * + * @param input		Input configuration + * @return 1, to indicate that we have something to look at + */ +int cros_ec_kbc_check(struct input_config *input) +{ +	static struct key_matrix_key last_keys[KBC_MAX_KEYS]; +	static int last_num_keys; +	struct key_matrix_key keys[KBC_MAX_KEYS]; +	int keycodes[KBC_MAX_KEYS]; +	int num_keys, num_keycodes; +	int irq_pending, sent; + +	/* +	 * Loop until the EC has no more keyscan records, or we have +	 * received at least one character. This means we know that tstc() +	 * will always return non-zero if keys have been pressed. +	 * +	 * Without this loop, a key release (which generates no new ascii +	 * characters) will cause us to exit this function, and just tstc() +	 * may return 0 before all keys have been read from the EC. +	 */ +	do { +		irq_pending = cros_ec_interrupt_pending(config.dev); +		if (irq_pending) { +			num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS); +			last_num_keys = num_keys; +			memcpy(last_keys, keys, sizeof(keys)); +		} else { +			/* +			 * EC doesn't want to be asked, so use keys from last +			 * time. +			 */ +			num_keys = last_num_keys; +			memcpy(keys, last_keys, sizeof(keys)); +		} + +		if (num_keys < 0) +			return -1; +		num_keycodes = key_matrix_decode(&config.matrix, keys, +				num_keys, keycodes, KBC_MAX_KEYS); +		sent = input_send_keycodes(input, keycodes, num_keycodes); +	} while (irq_pending && !sent); + +	return 1; +} + +/** + * Decode MBKP keyboard details from the device tree + * + * @param blob		Device tree blob + * @param node		Node to decode from + * @param config	Configuration data read from fdt + * @return 0 if ok, -1 on error + */ +static int cros_ec_keyb_decode_fdt(const void *blob, int node, +				struct keyb *config) +{ +	/* +	 * Get keyboard rows and columns - at present we are limited to +	 * 8 columns by the protocol (one byte per row scan) +	 */ +	config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0); +	config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", 0); +	if (!config->key_rows || !config->key_cols || +			config->key_rows * config->key_cols / 8 +				> CROS_EC_KEYSCAN_COLS) { +		debug("%s: Invalid key matrix size %d x %d\n", __func__, +		      config->key_rows, config->key_cols); +		return -1; +	} +	config->repeat_delay_ms = fdtdec_get_int(blob, node, +						 "google,repeat-delay-ms", 0); +	config->repeat_rate_ms = fdtdec_get_int(blob, node, +						"google,repeat-rate-ms", 0); +	config->ghost_filter = fdtdec_get_bool(blob, node, +					       "google,ghost-filter"); +	return 0; +} + +/** + * Set up the keyboard. This is called by the stdio device handler. + * + * We want to do this init when the keyboard is actually used rather than + * at start-up, since keyboard input may not currently be selected. + * + * @return 0 if ok, -1 on error + */ +static int cros_ec_init_keyboard(void) +{ +	const void *blob = gd->fdt_blob; +	int node; + +	config.dev = board_get_cros_ec_dev(); +	if (!config.dev) { +		debug("%s: no cros_ec device: cannot init keyboard\n", +		      __func__); +		return -1; +	} +	node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB); +	if (node < 0) { +		debug("%s: Node not found\n", __func__); +		return -1; +	} +	if (cros_ec_keyb_decode_fdt(blob, node, &config)) +		return -1; +	input_set_delays(&config.input, config.repeat_delay_ms, +			 config.repeat_rate_ms); +	if (key_matrix_init(&config.matrix, config.key_rows, +			config.key_cols, config.ghost_filter)) { +		debug("%s: cannot init key matrix\n", __func__); +		return -1; +	} +	if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) { +		debug("%s: Could not decode key matrix from fdt\n", __func__); +		return -1; +	} +	config.inited = 1; +	debug("%s: Matrix keyboard %dx%d ready\n", __func__, config.key_rows, +	      config.key_cols); + +	return 0; +} + +int drv_keyboard_init(void) +{ +	struct stdio_dev dev; + +	if (input_init(&config.input, 0)) { +		debug("%s: Cannot set up input\n", __func__); +		return -1; +	} +	config.input.read_keys = cros_ec_kbc_check; + +	memset(&dev, '\0', sizeof(dev)); +	strcpy(dev.name, "cros-ec-keyb"); +	dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; +	dev.getc = kbd_getc; +	dev.tstc = kbd_tstc; +	dev.start = cros_ec_init_keyboard; + +	/* Register the device. cros_ec_init_keyboard() will be called soon */ +	return input_stdio_register(&dev); +} diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5d869b47a..5fbff8ab6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,6 +28,10 @@ LIB	:= $(obj)libmisc.o  COBJS-$(CONFIG_ALI152X) += ali512x.o  COBJS-$(CONFIG_DS4510)  += ds4510.o  COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o +COBJS-$(CONFIG_CROS_EC) += cros_ec.o +COBJS-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o +COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o +COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o  COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o  COBJS-$(CONFIG_GPIO_LED) += gpio_led.o  COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c new file mode 100644 index 000000000..6e774d921 --- /dev/null +++ b/drivers/misc/cros_ec.c @@ -0,0 +1,1304 @@ +/* + * Chromium OS cros_ec driver + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <command.h> +#include <i2c.h> +#include <cros_ec.h> +#include <fdtdec.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <asm-generic/gpio.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...)	debug(fmt, #b) +#else +#define debug_trace(fmt, b...) +#endif + +enum { +	/* Timeout waiting for a flash erase command to complete */ +	CROS_EC_CMD_TIMEOUT_MS	= 5000, +	/* Timeout waiting for a synchronous hash to be recomputed */ +	CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, +}; + +static struct cros_ec_dev static_dev, *last_dev; + +DECLARE_GLOBAL_DATA_PTR; + +/* Note: depends on enum ec_current_image */ +static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"}; + +void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len) +{ +#ifdef DEBUG +	int i; + +	printf("%s: ", name); +	if (cmd != -1) +		printf("cmd=%#x: ", cmd); +	for (i = 0; i < len; i++) +		printf("%02x ", data[i]); +	printf("\n"); +#endif +} + +/* + * Calculate a simple 8-bit checksum of a data block + * + * @param data	Data block to checksum + * @param size	Size of data block in bytes + * @return checksum value (0 to 255) + */ +int cros_ec_calc_checksum(const uint8_t *data, int size) +{ +	int csum, i; + +	for (i = csum = 0; i < size; i++) +		csum += data[i]; +	return csum & 0xff; +} + +static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +			const void *dout, int dout_len, +			uint8_t **dinp, int din_len) +{ +	int ret; + +	switch (dev->interface) { +#ifdef CONFIG_CROS_EC_SPI +	case CROS_EC_IF_SPI: +		ret = cros_ec_spi_command(dev, cmd, cmd_version, +					(const uint8_t *)dout, dout_len, +					dinp, din_len); +		break; +#endif +#ifdef CONFIG_CROS_EC_I2C +	case CROS_EC_IF_I2C: +		ret = cros_ec_i2c_command(dev, cmd, cmd_version, +					(const uint8_t *)dout, dout_len, +					dinp, din_len); +		break; +#endif +#ifdef CONFIG_CROS_EC_LPC +	case CROS_EC_IF_LPC: +		ret = cros_ec_lpc_command(dev, cmd, cmd_version, +					(const uint8_t *)dout, dout_len, +					dinp, din_len); +		break; +#endif +	case CROS_EC_IF_NONE: +	default: +		ret = -1; +	} + +	return ret; +} + +/** + * Send a command to the CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS-EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout          Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param dinp          Response data (may be NULL If din_len=0). + *			If not NULL, it will be updated to point to the data + *			and will always be double word aligned (64-bits) + * @param din_len       Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd, +		int cmd_version, const void *dout, int dout_len, uint8_t **dinp, +		int din_len) +{ +	uint8_t *din; +	int len; + +	if (cmd_version != 0 && !dev->cmd_version_is_supported) { +		debug("%s: Command version >0 unsupported\n", __func__); +		return -1; +	} +	len = send_command(dev, cmd, cmd_version, dout, dout_len, +				&din, din_len); + +	/* If the command doesn't complete, wait a while */ +	if (len == -EC_RES_IN_PROGRESS) { +		struct ec_response_get_comms_status *resp; +		ulong start; + +		/* Wait for command to complete */ +		start = get_timer(0); +		do { +			int ret; + +			mdelay(50);	/* Insert some reasonable delay */ +			ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0, +					NULL, 0, +					(uint8_t **)&resp, sizeof(*resp)); +			if (ret < 0) +				return ret; + +			if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) { +				debug("%s: Command %#02x timeout\n", +				      __func__, cmd); +				return -EC_RES_TIMEOUT; +			} +		} while (resp->flags & EC_COMMS_STATUS_PROCESSING); + +		/* OK it completed, so read the status response */ +		/* not sure why it was 0 for the last argument */ +		len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0, +				NULL, 0, &din, din_len); +	} + +	debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp); +	if (dinp) { +		/* If we have any data to return, it must be 64bit-aligned */ +		assert(len <= 0 || !((uintptr_t)din & 7)); +		*dinp = din; +	} + +	return len; +} + +/** + * Send a command to the CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS-EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout          Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param din           Response data (may be NULL If din_len=0). + *			It not NULL, it is a place for ec_command() to copy the + *      data to. + * @param din_len       Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		      const void *dout, int dout_len, +		      void *din, int din_len) +{ +	uint8_t *in_buffer; +	int len; + +	assert((din_len == 0) || din); +	len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len, +			&in_buffer, din_len); +	if (len > 0) { +		/* +		 * If we were asked to put it somewhere, do so, otherwise just +		 * disregard the result. +		 */ +		if (din && in_buffer) { +			assert(len <= din_len); +			memmove(din, in_buffer, len); +		} +	} +	return len; +} + +int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan) +{ +	if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan, +		       sizeof(scan->data)) < sizeof(scan->data)) +		return -1; + +	return 0; +} + +int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen) +{ +	struct ec_response_get_version *r; + +	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, +			(uint8_t **)&r, sizeof(*r)) < sizeof(*r)) +		return -1; + +	if (maxlen > sizeof(r->version_string_ro)) +		maxlen = sizeof(r->version_string_ro); + +	switch (r->current_image) { +	case EC_IMAGE_RO: +		memcpy(id, r->version_string_ro, maxlen); +		break; +	case EC_IMAGE_RW: +		memcpy(id, r->version_string_rw, maxlen); +		break; +	default: +		return -1; +	} + +	id[maxlen - 1] = '\0'; +	return 0; +} + +int cros_ec_read_version(struct cros_ec_dev *dev, +		       struct ec_response_get_version **versionp) +{ +	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, +			(uint8_t **)versionp, sizeof(**versionp)) +			< sizeof(**versionp)) +		return -1; + +	return 0; +} + +int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp) +{ +	if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0, +			(uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0) +		return -1; + +	return 0; +} + +int cros_ec_read_current_image(struct cros_ec_dev *dev, +		enum ec_current_image *image) +{ +	struct ec_response_get_version *r; + +	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, +			(uint8_t **)&r, sizeof(*r)) < sizeof(*r)) +		return -1; + +	*image = r->current_image; +	return 0; +} + +static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev, +				  struct ec_response_vboot_hash *hash) +{ +	struct ec_params_vboot_hash p; +	ulong start; + +	start = get_timer(0); +	while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) { +		mdelay(50);	/* Insert some reasonable delay */ + +		p.cmd = EC_VBOOT_HASH_GET; +		if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), +		       hash, sizeof(*hash)) < 0) +			return -1; + +		if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) { +			debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__); +			return -EC_RES_TIMEOUT; +		} +	} +	return 0; +} + + +int cros_ec_read_hash(struct cros_ec_dev *dev, +		struct ec_response_vboot_hash *hash) +{ +	struct ec_params_vboot_hash p; +	int rv; + +	p.cmd = EC_VBOOT_HASH_GET; +	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), +		       hash, sizeof(*hash)) < 0) +		return -1; + +	/* If the EC is busy calculating the hash, fidget until it's done. */ +	rv = cros_ec_wait_on_hash_done(dev, hash); +	if (rv) +		return rv; + +	/* If the hash is valid, we're done. Otherwise, we have to kick it off +	 * again and wait for it to complete. Note that we explicitly assume +	 * that hashing zero bytes is always wrong, even though that would +	 * produce a valid hash value. */ +	if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size) +		return 0; + +	debug("%s: No valid hash (status=%d size=%d). Compute one...\n", +	      __func__, hash->status, hash->size); + +	p.cmd = EC_VBOOT_HASH_RECALC; +	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; +	p.nonce_size = 0; +	p.offset = EC_VBOOT_HASH_OFFSET_RW; + +	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), +		       hash, sizeof(*hash)) < 0) +		return -1; + +	rv = cros_ec_wait_on_hash_done(dev, hash); +	if (rv) +		return rv; + +	debug("%s: hash done\n", __func__); + +	return 0; +} + +static int cros_ec_invalidate_hash(struct cros_ec_dev *dev) +{ +	struct ec_params_vboot_hash p; +	struct ec_response_vboot_hash *hash; + +	/* We don't have an explict command for the EC to discard its current +	 * hash value, so we'll just tell it to calculate one that we know is +	 * wrong (we claim that hashing zero bytes is always invalid). +	 */ +	p.cmd = EC_VBOOT_HASH_RECALC; +	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; +	p.nonce_size = 0; +	p.offset = 0; +	p.size = 0; + +	debug("%s:\n", __func__); + +	if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), +		       (uint8_t **)&hash, sizeof(*hash)) < 0) +		return -1; + +	/* No need to wait for it to finish */ +	return 0; +} + +int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd, +		uint8_t flags) +{ +	struct ec_params_reboot_ec p; + +	p.cmd = cmd; +	p.flags = flags; + +	if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0) +			< 0) +		return -1; + +	if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) { +		/* +		 * EC reboot will take place immediately so delay to allow it +		 * to complete.  Note that some reboot types (EC_REBOOT_COLD) +		 * will reboot the AP as well, in which case we won't actually +		 * get to this point. +		 */ +		/* +		 * TODO(rspangler@chromium.org): Would be nice if we had a +		 * better way to determine when the reboot is complete.  Could +		 * we poll a memory-mapped LPC value? +		 */ +		udelay(50000); +	} + +	return 0; +} + +int cros_ec_interrupt_pending(struct cros_ec_dev *dev) +{ +	/* no interrupt support : always poll */ +	if (!fdt_gpio_isvalid(&dev->ec_int)) +		return 1; + +	return !gpio_get_value(dev->ec_int.gpio); +} + +int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info) +{ +	if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info, +			sizeof(*info)) < sizeof(*info)) +		return -1; + +	return 0; +} + +int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr) +{ +	struct ec_response_host_event_mask *resp; + +	/* +	 * Use the B copy of the event flags, because the main copy is already +	 * used by ACPI/SMI. +	 */ +	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0, +		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) +		return -1; + +	if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID)) +		return -1; + +	*events_ptr = resp->mask; +	return 0; +} + +int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events) +{ +	struct ec_params_host_event_mask params; + +	params.mask = events; + +	/* +	 * Use the B copy of the event flags, so it affects the data returned +	 * by cros_ec_get_host_events(). +	 */ +	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0, +		       ¶ms, sizeof(params), NULL, 0) < 0) +		return -1; + +	return 0; +} + +int cros_ec_flash_protect(struct cros_ec_dev *dev, +		       uint32_t set_mask, uint32_t set_flags, +		       struct ec_response_flash_protect *resp) +{ +	struct ec_params_flash_protect params; + +	params.mask = set_mask; +	params.flags = set_flags; + +	if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT, +		       ¶ms, sizeof(params), +		       resp, sizeof(*resp)) < sizeof(*resp)) +		return -1; + +	return 0; +} + +static int cros_ec_check_version(struct cros_ec_dev *dev) +{ +	struct ec_params_hello req; +	struct ec_response_hello *resp; + +#ifdef CONFIG_CROS_EC_LPC +	/* LPC has its own way of doing this */ +	if (dev->interface == CROS_EC_IF_LPC) +		return cros_ec_lpc_check_version(dev); +#endif + +	/* +	 * TODO(sjg@chromium.org). +	 * There is a strange oddity here with the EC. We could just ignore +	 * the response, i.e. pass the last two parameters as NULL and 0. +	 * In this case we won't read back very many bytes from the EC. +	 * On the I2C bus the EC gets upset about this and will try to send +	 * the bytes anyway. This means that we will have to wait for that +	 * to complete before continuing with a new EC command. +	 * +	 * This problem is probably unique to the I2C bus. +	 * +	 * So for now, just read all the data anyway. +	 */ +	dev->cmd_version_is_supported = 1; +	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), +		       (uint8_t **)&resp, sizeof(*resp)) > 0) { +		/* It appears to understand new version commands */ +		dev->cmd_version_is_supported = 1; +	} else { +		dev->cmd_version_is_supported = 0; +		if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, +			      sizeof(req), (uint8_t **)&resp, +			      sizeof(*resp)) < 0) { +			debug("%s: Failed both old and new command style\n", +				__func__); +			return -1; +		} +	} + +	return 0; +} + +int cros_ec_test(struct cros_ec_dev *dev) +{ +	struct ec_params_hello req; +	struct ec_response_hello *resp; + +	req.in_data = 0x12345678; +	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), +		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) { +		printf("ec_command_inptr() returned error\n"); +		return -1; +	} +	if (resp->out_data != req.in_data + 0x01020304) { +		printf("Received invalid handshake %x\n", resp->out_data); +		return -1; +	} + +	return 0; +} + +int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region, +		      uint32_t *offset, uint32_t *size) +{ +	struct ec_params_flash_region_info p; +	struct ec_response_flash_region_info *r; +	int ret; + +	p.region = region; +	ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO, +			 EC_VER_FLASH_REGION_INFO, +			 &p, sizeof(p), (uint8_t **)&r, sizeof(*r)); +	if (ret != sizeof(*r)) +		return -1; + +	if (offset) +		*offset = r->offset; +	if (size) +		*size = r->size; + +	return 0; +} + +int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size) +{ +	struct ec_params_flash_erase p; + +	p.offset = offset; +	p.size = size; +	return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p), +			NULL, 0); +} + +/** + * Write a single block to the flash + * + * Write a block of data to the EC flash. The size must not exceed the flash + * write block size which you can obtain from cros_ec_flash_write_burst_size(). + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to write for a particular region. + * + * Attempting to write to the region where the EC is currently running from + * will result in an error. + * + * @param dev		CROS-EC device + * @param data		Pointer to data buffer to write + * @param offset	Offset within flash to write to. + * @param size		Number of bytes to write + * @return 0 if ok, -1 on error + */ +static int cros_ec_flash_write_block(struct cros_ec_dev *dev, +		const uint8_t *data, uint32_t offset, uint32_t size) +{ +	struct ec_params_flash_write p; + +	p.offset = offset; +	p.size = size; +	assert(data && p.size <= sizeof(p.data)); +	memcpy(p.data, data, p.size); + +	return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0, +			  &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1; +} + +/** + * Return optimal flash write burst size + */ +static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev) +{ +	struct ec_params_flash_write p; +	return sizeof(p.data); +} + +/** + * Check if a block of data is erased (all 0xff) + * + * This function is useful when dealing with flash, for checking whether a + * data block is erased and thus does not need to be programmed. + * + * @param data		Pointer to data to check (must be word-aligned) + * @param size		Number of bytes to check (must be word-aligned) + * @return 0 if erased, non-zero if any word is not erased + */ +static int cros_ec_data_is_erased(const uint32_t *data, int size) +{ +	assert(!(size & 3)); +	size /= sizeof(uint32_t); +	for (; size > 0; size -= 4, data++) +		if (*data != -1U) +			return 0; + +	return 1; +} + +int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, +		     uint32_t offset, uint32_t size) +{ +	uint32_t burst = cros_ec_flash_write_burst_size(dev); +	uint32_t end, off; +	int ret; + +	/* +	 * TODO: round up to the nearest multiple of write size.  Can get away +	 * without that on link right now because its write size is 4 bytes. +	 */ +	end = offset + size; +	for (off = offset; off < end; off += burst, data += burst) { +		uint32_t todo; + +		/* If the data is empty, there is no point in programming it */ +		todo = min(end - off, burst); +		if (dev->optimise_flash_write && +				cros_ec_data_is_erased((uint32_t *)data, todo)) +			continue; + +		ret = cros_ec_flash_write_block(dev, data, off, todo); +		if (ret) +			return ret; +	} + +	return 0; +} + +/** + * Read a single block from the flash + * + * Read a block of data from the EC flash. The size must not exceed the flash + * write block size which you can obtain from cros_ec_flash_write_burst_size(). + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to read for a particular region. + * + * @param dev		CROS-EC device + * @param data		Pointer to data buffer to read into + * @param offset	Offset within flash to read from + * @param size		Number of bytes to read + * @return 0 if ok, -1 on error + */ +static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data, +				 uint32_t offset, uint32_t size) +{ +	struct ec_params_flash_read p; + +	p.offset = offset; +	p.size = size; + +	return ec_command(dev, EC_CMD_FLASH_READ, 0, +			  &p, sizeof(p), data, size) >= 0 ? 0 : -1; +} + +int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, +		    uint32_t size) +{ +	uint32_t burst = cros_ec_flash_write_burst_size(dev); +	uint32_t end, off; +	int ret; + +	end = offset + size; +	for (off = offset; off < end; off += burst, data += burst) { +		ret = cros_ec_flash_read_block(dev, data, off, +					    min(end - off, burst)); +		if (ret) +			return ret; +	} + +	return 0; +} + +int cros_ec_flash_update_rw(struct cros_ec_dev *dev, +			 const uint8_t *image, int image_size) +{ +	uint32_t rw_offset, rw_size; +	int ret; + +	if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size)) +		return -1; +	if (image_size > rw_size) +		return -1; + +	/* Invalidate the existing hash, just in case the AP reboots +	 * unexpectedly during the update. If that happened, the EC RW firmware +	 * would be invalid, but the EC would still have the original hash. +	 */ +	ret = cros_ec_invalidate_hash(dev); +	if (ret) +		return ret; + +	/* +	 * Erase the entire RW section, so that the EC doesn't see any garbage +	 * past the new image if it's smaller than the current image. +	 * +	 * TODO: could optimize this to erase just the current image, since +	 * presumably everything past that is 0xff's.  But would still need to +	 * round up to the nearest multiple of erase size. +	 */ +	ret = cros_ec_flash_erase(dev, rw_offset, rw_size); +	if (ret) +		return ret; + +	/* Write the image */ +	ret = cros_ec_flash_write(dev, image, rw_offset, image_size); +	if (ret) +		return ret; + +	return 0; +} + +int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block) +{ +	struct ec_params_vbnvcontext p; +	int len; + +	p.op = EC_VBNV_CONTEXT_OP_READ; + +	len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, +			&p, sizeof(p), block, EC_VBNV_BLOCK_SIZE); +	if (len < EC_VBNV_BLOCK_SIZE) +		return -1; + +	return 0; +} + +int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block) +{ +	struct ec_params_vbnvcontext p; +	int len; + +	p.op = EC_VBNV_CONTEXT_OP_WRITE; +	memcpy(p.block, block, sizeof(p.block)); + +	len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, +			&p, sizeof(p), NULL, 0); +	if (len < 0) +		return -1; + +	return 0; +} + +int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state) +{ +	struct ec_params_ldo_set params; + +	params.index = index; +	params.state = state; + +	if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0, +		       ¶ms, sizeof(params), +		       NULL, 0)) +		return -1; + +	return 0; +} + +int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state) +{ +	struct ec_params_ldo_get params; +	struct ec_response_ldo_get *resp; + +	params.index = index; + +	if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0, +		       ¶ms, sizeof(params), +		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) +		return -1; + +	*state = resp->state; + +	return 0; +} + +/** + * Decode MBKP details from the device tree and allocate a suitable device. + * + * @param blob		Device tree blob + * @param node		Node to decode from + * @param devp		Returns a pointer to the new allocated device + * @return 0 if ok, -1 on error + */ +static int cros_ec_decode_fdt(const void *blob, int node, +		struct cros_ec_dev **devp) +{ +	enum fdt_compat_id compat; +	struct cros_ec_dev *dev; +	int parent; + +	/* See what type of parent we are inside (this is expensive) */ +	parent = fdt_parent_offset(blob, node); +	if (parent < 0) { +		debug("%s: Cannot find node parent\n", __func__); +		return -1; +	} + +	dev = &static_dev; +	dev->node = node; +	dev->parent_node = parent; + +	compat = fdtdec_lookup(blob, parent); +	switch (compat) { +#ifdef CONFIG_CROS_EC_SPI +	case COMPAT_SAMSUNG_EXYNOS_SPI: +		dev->interface = CROS_EC_IF_SPI; +		if (cros_ec_spi_decode_fdt(dev, blob)) +			return -1; +		break; +#endif +#ifdef CONFIG_CROS_EC_I2C +	case COMPAT_SAMSUNG_S3C2440_I2C: +		dev->interface = CROS_EC_IF_I2C; +		if (cros_ec_i2c_decode_fdt(dev, blob)) +			return -1; +		break; +#endif +#ifdef CONFIG_CROS_EC_LPC +	case COMPAT_INTEL_LPC: +		dev->interface = CROS_EC_IF_LPC; +		break; +#endif +	default: +		debug("%s: Unknown compat id %d\n", __func__, compat); +		return -1; +	} + +	fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int); +	dev->optimise_flash_write = fdtdec_get_bool(blob, node, +						    "optimise-flash-write"); +	*devp = dev; + +	return 0; +} + +int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) +{ +	char id[MSG_BYTES]; +	struct cros_ec_dev *dev; +	int node = 0; + +	*cros_ecp = NULL; +	do { +		node = fdtdec_next_compatible(blob, node, +					      COMPAT_GOOGLE_CROS_EC); +		if (node < 0) { +			debug("%s: Node not found\n", __func__); +			return 0; +		} +	} while (!fdtdec_get_is_enabled(blob, node)); + +	if (cros_ec_decode_fdt(blob, node, &dev)) { +		debug("%s: Failed to decode device.\n", __func__); +		return -CROS_EC_ERR_FDT_DECODE; +	} + +	switch (dev->interface) { +#ifdef CONFIG_CROS_EC_SPI +	case CROS_EC_IF_SPI: +		if (cros_ec_spi_init(dev, blob)) { +			debug("%s: Could not setup SPI interface\n", __func__); +			return -CROS_EC_ERR_DEV_INIT; +		} +		break; +#endif +#ifdef CONFIG_CROS_EC_I2C +	case CROS_EC_IF_I2C: +		if (cros_ec_i2c_init(dev, blob)) +			return -CROS_EC_ERR_DEV_INIT; +		break; +#endif +#ifdef CONFIG_CROS_EC_LPC +	case CROS_EC_IF_LPC: +		if (cros_ec_lpc_init(dev, blob)) +			return -CROS_EC_ERR_DEV_INIT; +		break; +#endif +	case CROS_EC_IF_NONE: +	default: +		return 0; +	} + +	/* we will poll the EC interrupt line */ +	fdtdec_setup_gpio(&dev->ec_int); +	if (fdt_gpio_isvalid(&dev->ec_int)) +		gpio_direction_input(dev->ec_int.gpio); + +	if (cros_ec_check_version(dev)) { +		debug("%s: Could not detect CROS-EC version\n", __func__); +		return -CROS_EC_ERR_CHECK_VERSION; +	} + +	if (cros_ec_read_id(dev, id, sizeof(id))) { +		debug("%s: Could not read KBC ID\n", __func__); +		return -CROS_EC_ERR_READ_ID; +	} + +	/* Remember this device for use by the cros_ec command */ +	last_dev = *cros_ecp = dev; +	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id); + +	return 0; +} + +#ifdef CONFIG_CMD_CROS_EC +int cros_ec_decode_region(int argc, char * const argv[]) +{ +	if (argc > 0) { +		if (0 == strcmp(*argv, "rw")) +			return EC_FLASH_REGION_RW; +		else if (0 == strcmp(*argv, "ro")) +			return EC_FLASH_REGION_RO; + +		debug("%s: Invalid region '%s'\n", __func__, *argv); +	} else { +		debug("%s: Missing region parameter\n", __func__); +	} + +	return -1; +} + +/** + * Perform a flash read or write command + * + * @param dev		CROS-EC device to read/write + * @param is_write	1 do to a write, 0 to do a read + * @param argc		Number of arguments + * @param argv		Arguments (2 is region, 3 is address) + * @return 0 for ok, 1 for a usage error or -ve for ec command error + *	(negative EC_RES_...) + */ +static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc, +			 char * const argv[]) +{ +	uint32_t offset, size = -1U, region_size; +	unsigned long addr; +	char *endp; +	int region; +	int ret; + +	region = cros_ec_decode_region(argc - 2, argv + 2); +	if (region == -1) +		return 1; +	if (argc < 4) +		return 1; +	addr = simple_strtoul(argv[3], &endp, 16); +	if (*argv[3] == 0 || *endp != 0) +		return 1; +	if (argc > 4) { +		size = simple_strtoul(argv[4], &endp, 16); +		if (*argv[4] == 0 || *endp != 0) +			return 1; +	} + +	ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size); +	if (ret) { +		debug("%s: Could not read region info\n", __func__); +		return ret; +	} +	if (size == -1U) +		size = region_size; + +	ret = is_write ? +		cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) : +		cros_ec_flash_read(dev, (uint8_t *)addr, offset, size); +	if (ret) { +		debug("%s: Could not %s region\n", __func__, +		      is_write ? "write" : "read"); +		return ret; +	} + +	return 0; +} + +static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	struct cros_ec_dev *dev = last_dev; +	const char *cmd; +	int ret = 0; + +	if (argc < 2) +		return CMD_RET_USAGE; + +	cmd = argv[1]; +	if (0 == strcmp("init", cmd)) { +		ret = cros_ec_init(gd->fdt_blob, &dev); +		if (ret) { +			printf("Could not init cros_ec device (err %d)\n", ret); +			return 1; +		} +		return 0; +	} + +	/* Just use the last allocated device; there should be only one */ +	if (!last_dev) { +		printf("No CROS-EC device available\n"); +		return 1; +	} +	if (0 == strcmp("id", cmd)) { +		char id[MSG_BYTES]; + +		if (cros_ec_read_id(dev, id, sizeof(id))) { +			debug("%s: Could not read KBC ID\n", __func__); +			return 1; +		} +		printf("%s\n", id); +	} else if (0 == strcmp("info", cmd)) { +		struct ec_response_cros_ec_info info; + +		if (cros_ec_info(dev, &info)) { +			debug("%s: Could not read KBC info\n", __func__); +			return 1; +		} +		printf("rows     = %u\n", info.rows); +		printf("cols     = %u\n", info.cols); +		printf("switches = %#x\n", info.switches); +	} else if (0 == strcmp("curimage", cmd)) { +		enum ec_current_image image; + +		if (cros_ec_read_current_image(dev, &image)) { +			debug("%s: Could not read KBC image\n", __func__); +			return 1; +		} +		printf("%d\n", image); +	} else if (0 == strcmp("hash", cmd)) { +		struct ec_response_vboot_hash hash; +		int i; + +		if (cros_ec_read_hash(dev, &hash)) { +			debug("%s: Could not read KBC hash\n", __func__); +			return 1; +		} + +		if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256) +			printf("type:    SHA-256\n"); +		else +			printf("type:    %d\n", hash.hash_type); + +		printf("offset:  0x%08x\n", hash.offset); +		printf("size:    0x%08x\n", hash.size); + +		printf("digest:  "); +		for (i = 0; i < hash.digest_size; i++) +			printf("%02x", hash.hash_digest[i]); +		printf("\n"); +	} else if (0 == strcmp("reboot", cmd)) { +		int region; +		enum ec_reboot_cmd cmd; + +		if (argc >= 3 && !strcmp(argv[2], "cold")) +			cmd = EC_REBOOT_COLD; +		else { +			region = cros_ec_decode_region(argc - 2, argv + 2); +			if (region == EC_FLASH_REGION_RO) +				cmd = EC_REBOOT_JUMP_RO; +			else if (region == EC_FLASH_REGION_RW) +				cmd = EC_REBOOT_JUMP_RW; +			else +				return CMD_RET_USAGE; +		} + +		if (cros_ec_reboot(dev, cmd, 0)) { +			debug("%s: Could not reboot KBC\n", __func__); +			return 1; +		} +	} else if (0 == strcmp("events", cmd)) { +		uint32_t events; + +		if (cros_ec_get_host_events(dev, &events)) { +			debug("%s: Could not read host events\n", __func__); +			return 1; +		} +		printf("0x%08x\n", events); +	} else if (0 == strcmp("clrevents", cmd)) { +		uint32_t events = 0x7fffffff; + +		if (argc >= 3) +			events = simple_strtol(argv[2], NULL, 0); + +		if (cros_ec_clear_host_events(dev, events)) { +			debug("%s: Could not clear host events\n", __func__); +			return 1; +		} +	} else if (0 == strcmp("read", cmd)) { +		ret = do_read_write(dev, 0, argc, argv); +		if (ret > 0) +			return CMD_RET_USAGE; +	} else if (0 == strcmp("write", cmd)) { +		ret = do_read_write(dev, 1, argc, argv); +		if (ret > 0) +			return CMD_RET_USAGE; +	} else if (0 == strcmp("erase", cmd)) { +		int region = cros_ec_decode_region(argc - 2, argv + 2); +		uint32_t offset, size; + +		if (region == -1) +			return CMD_RET_USAGE; +		if (cros_ec_flash_offset(dev, region, &offset, &size)) { +			debug("%s: Could not read region info\n", __func__); +			ret = -1; +		} else { +			ret = cros_ec_flash_erase(dev, offset, size); +			if (ret) { +				debug("%s: Could not erase region\n", +				      __func__); +			} +		} +	} else if (0 == strcmp("regioninfo", cmd)) { +		int region = cros_ec_decode_region(argc - 2, argv + 2); +		uint32_t offset, size; + +		if (region == -1) +			return CMD_RET_USAGE; +		ret = cros_ec_flash_offset(dev, region, &offset, &size); +		if (ret) { +			debug("%s: Could not read region info\n", __func__); +		} else { +			printf("Region: %s\n", region == EC_FLASH_REGION_RO ? +					"RO" : "RW"); +			printf("Offset: %x\n", offset); +			printf("Size:   %x\n", size); +		} +	} else if (0 == strcmp("vbnvcontext", cmd)) { +		uint8_t block[EC_VBNV_BLOCK_SIZE]; +		char buf[3]; +		int i, len; +		unsigned long result; + +		if (argc <= 2) { +			ret = cros_ec_read_vbnvcontext(dev, block); +			if (!ret) { +				printf("vbnv_block: "); +				for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) +					printf("%02x", block[i]); +				putc('\n'); +			} +		} else { +			/* +			 * TODO(clchiou): Move this to a utility function as +			 * cmd_spi might want to call it. +			 */ +			memset(block, 0, EC_VBNV_BLOCK_SIZE); +			len = strlen(argv[2]); +			buf[2] = '\0'; +			for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) { +				if (i * 2 >= len) +					break; +				buf[0] = argv[2][i * 2]; +				if (i * 2 + 1 >= len) +					buf[1] = '0'; +				else +					buf[1] = argv[2][i * 2 + 1]; +				strict_strtoul(buf, 16, &result); +				block[i] = result; +			} +			ret = cros_ec_write_vbnvcontext(dev, block); +		} +		if (ret) { +			debug("%s: Could not %s VbNvContext\n", __func__, +					argc <= 2 ?  "read" : "write"); +		} +	} else if (0 == strcmp("test", cmd)) { +		int result = cros_ec_test(dev); + +		if (result) +			printf("Test failed with error %d\n", result); +		else +			puts("Test passed\n"); +	} else if (0 == strcmp("version", cmd)) { +		struct ec_response_get_version *p; +		char *build_string; + +		ret = cros_ec_read_version(dev, &p); +		if (!ret) { +			/* Print versions */ +			printf("RO version:    %1.*s\n", +			       sizeof(p->version_string_ro), +			       p->version_string_ro); +			printf("RW version:    %1.*s\n", +			       sizeof(p->version_string_rw), +			       p->version_string_rw); +			printf("Firmware copy: %s\n", +				(p->current_image < +					ARRAY_SIZE(ec_current_image_name) ? +				ec_current_image_name[p->current_image] : +				"?")); +			ret = cros_ec_read_build_info(dev, &build_string); +			if (!ret) +				printf("Build info:    %s\n", build_string); +		} +	} else if (0 == strcmp("ldo", cmd)) { +		uint8_t index, state; +		char *endp; + +		if (argc < 3) +			return CMD_RET_USAGE; +		index = simple_strtoul(argv[2], &endp, 10); +		if (*argv[2] == 0 || *endp != 0) +			return CMD_RET_USAGE; +		if (argc > 3) { +			state = simple_strtoul(argv[3], &endp, 10); +			if (*argv[3] == 0 || *endp != 0) +				return CMD_RET_USAGE; +			ret = cros_ec_set_ldo(dev, index, state); +		} else { +			ret = cros_ec_get_ldo(dev, index, &state); +			if (!ret) { +				printf("LDO%d: %s\n", index, +					state == EC_LDO_STATE_ON ? +					"on" : "off"); +			} +		} + +		if (ret) { +			debug("%s: Could not access LDO%d\n", __func__, index); +			return ret; +		} +	} else { +		return CMD_RET_USAGE; +	} + +	if (ret < 0) { +		printf("Error: CROS-EC command failed (error %d)\n", ret); +		ret = 1; +	} + +	return ret; +} + +U_BOOT_CMD( +	crosec,	5,	1,	do_cros_ec, +	"CROS-EC utility command", +	"init                Re-init CROS-EC (done on startup automatically)\n" +	"crosec id                  Read CROS-EC ID\n" +	"crosec info                Read CROS-EC info\n" +	"crosec curimage            Read CROS-EC current image\n" +	"crosec hash                Read CROS-EC hash\n" +	"crosec reboot [rw | ro | cold]  Reboot CROS-EC\n" +	"crosec events              Read CROS-EC host events\n" +	"crosec clrevents [mask]    Clear CROS-EC host events\n" +	"crosec regioninfo <ro|rw>  Read image info\n" +	"crosec erase <ro|rw>       Erase EC image\n" +	"crosec read <ro|rw> <addr> [<size>]   Read EC image\n" +	"crosec write <ro|rw> <addr> [<size>]  Write EC image\n" +	"crosec vbnvcontext [hexstring]        Read [write] VbNvContext from EC\n" +	"crosec ldo <idx> [<state>] Switch/Read LDO state\n" +	"crosec test                run tests on cros_ec\n" +	"crosec version             Read CROS-EC version" +); +#endif diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c new file mode 100644 index 000000000..b0060ac19 --- /dev/null +++ b/drivers/misc/cros_ec_i2c.c @@ -0,0 +1,199 @@ +/* + * Chromium OS cros_ec driver - I2C interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <i2c.h> +#include <cros_ec.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...)	debug(fmt, #b) +#else +#define debug_trace(fmt, b...) +#endif + +int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len) +{ +	int old_bus = 0; +	/* version8, cmd8, arglen8, out8[dout_len], csum8 */ +	int out_bytes = dout_len + 4; +	/* response8, arglen8, in8[din_len], checksum8 */ +	int in_bytes = din_len + 3; +	uint8_t *ptr; +	/* Receive input data, so that args will be dword aligned */ +	uint8_t *in_ptr; +	int ret; + +	old_bus = i2c_get_bus_num(); + +	/* +	 * Sanity-check I/O sizes given transaction overhead in internal +	 * buffers. +	 */ +	if (out_bytes > sizeof(dev->dout)) { +		debug("%s: Cannot send %d bytes\n", __func__, dout_len); +		return -1; +	} +	if (in_bytes > sizeof(dev->din)) { +		debug("%s: Cannot receive %d bytes\n", __func__, din_len); +		return -1; +	} +	assert(dout_len >= 0); +	assert(dinp); + +	/* +	 * Copy command and data into output buffer so we can do a single I2C +	 * burst transaction. +	 */ +	ptr = dev->dout; + +	/* +	 * in_ptr starts of pointing to a dword-aligned input data buffer. +	 * We decrement it back by the number of header bytes we expect to +	 * receive, so that the first parameter of the resulting input data +	 * will be dword aligned. +	 */ +	in_ptr = dev->din + sizeof(int64_t); +	if (!dev->cmd_version_is_supported) { +		/* Send an old-style command */ +		*ptr++ = cmd; +		out_bytes = dout_len + 1; +		in_bytes = din_len + 2; +		in_ptr--;	/* Expect just a status byte */ +	} else { +		*ptr++ = EC_CMD_VERSION0 + cmd_version; +		*ptr++ = cmd; +		*ptr++ = dout_len; +		in_ptr -= 2;	/* Expect status, length bytes */ +	} +	memcpy(ptr, dout, dout_len); +	ptr += dout_len; + +	if (dev->cmd_version_is_supported) +		*ptr++ = (uint8_t) +			 cros_ec_calc_checksum(dev->dout, dout_len + 3); + +	/* Set to the proper i2c bus */ +	if (i2c_set_bus_num(dev->bus_num)) { +		debug("%s: Cannot change to I2C bus %d\n", __func__, +			dev->bus_num); +		return -1; +	} + +	/* Send output data */ +	cros_ec_dump_data("out", -1, dev->dout, out_bytes); +	ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes); +	if (ret) { +		debug("%s: Cannot complete I2C write to 0x%x\n", +			__func__, dev->addr); +		ret = -1; +	} + +	if (!ret) { +		ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes); +		if (ret) { +			debug("%s: Cannot complete I2C read from 0x%x\n", +				__func__, dev->addr); +			ret = -1; +		} +	} + +	/* Return to original bus number */ +	i2c_set_bus_num(old_bus); +	if (ret) +		return ret; + +	if (*in_ptr != EC_RES_SUCCESS) { +		debug("%s: Received bad result code %d\n", __func__, *in_ptr); +		return -(int)*in_ptr; +	} + +	if (dev->cmd_version_is_supported) { +		int len, csum; + +		len = in_ptr[1]; +		if (len + 3 > sizeof(dev->din)) { +			debug("%s: Received length %#02x too large\n", +			      __func__, len); +			return -1; +		} +		csum = cros_ec_calc_checksum(in_ptr, 2 + len); +		if (csum != in_ptr[2 + len]) { +			debug("%s: Invalid checksum rx %#02x, calced %#02x\n", +			      __func__, in_ptr[2 + din_len], csum); +			return -1; +		} +		din_len = min(din_len, len); +		cros_ec_dump_data("in", -1, in_ptr, din_len + 3); +	} else { +		cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes); +	} + +	/* Return pointer to dword-aligned input data, if any */ +	*dinp = dev->din + sizeof(int64_t); + +	return din_len; +} + +int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ +	/* Decode interface-specific FDT params */ +	dev->max_frequency = fdtdec_get_int(blob, dev->node, +					    "i2c-max-frequency", 100000); +	dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node); +	if (dev->bus_num == -1) { +		debug("%s: Failed to read bus number\n", __func__); +		return -1; +	} +	dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1); +	if (dev->addr == -1) { +		debug("%s: Failed to read device address\n", __func__); +		return -1; +	} + +	return 0; +} + +/** + * Initialize I2C protocol. + * + * @param dev		CROS_EC device + * @param blob		Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob) +{ +	i2c_init(dev->max_frequency, dev->addr); + +	dev->cmd_version_is_supported = 0; + +	return 0; +} diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c new file mode 100644 index 000000000..cf0435b8d --- /dev/null +++ b/drivers/misc/cros_ec_lpc.c @@ -0,0 +1,283 @@ +/* + * Chromium OS cros_ec driver - LPC interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <command.h> +#include <cros_ec.h> +#include <asm/io.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...)	debug(fmt, ##b) +#else +#define debug_trace(fmt, b...) +#endif + +static int wait_for_sync(struct cros_ec_dev *dev) +{ +	unsigned long start; + +	start = get_timer(0); +	while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) { +		if (get_timer(start) > 1000) { +			debug("%s: Timeout waiting for CROS_EC sync\n", +			      __func__); +			return -1; +		} +	} + +	return 0; +} + +/** + * Send a command to a LPC CROS_EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS_EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout          Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param dinp          Place to put pointer to response data + * @param din_len       Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int old_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len) +{ +	int ret, i; + +	if (dout_len > EC_OLD_PARAM_SIZE) { +		debug("%s: Cannot send %d bytes\n", __func__, dout_len); +		return -1; +	} + +	if (din_len > EC_OLD_PARAM_SIZE) { +		debug("%s: Cannot receive %d bytes\n", __func__, din_len); +		return -1; +	} + +	if (wait_for_sync(dev)) { +		debug("%s: Timeout waiting ready\n", __func__); +		return -1; +	} + +	debug_trace("cmd: %02x, ", cmd); +	for (i = 0; i < dout_len; i++) { +		debug_trace("%02x ", dout[i]); +		outb(dout[i], EC_LPC_ADDR_OLD_PARAM + i); +	} +	outb(cmd, EC_LPC_ADDR_HOST_CMD); +	debug_trace("\n"); + +	if (wait_for_sync(dev)) { +		debug("%s: Timeout waiting ready\n", __func__); +		return -1; +	} + +	ret = inb(EC_LPC_ADDR_HOST_DATA); +	if (ret) { +		debug("%s: CROS_EC result code %d\n", __func__, ret); +		return -ret; +	} + +	debug_trace("resp: %02x, ", ret); +	for (i = 0; i < din_len; i++) { +		dev->din[i] = inb(EC_LPC_ADDR_OLD_PARAM + i); +		debug_trace("%02x ", dev->din[i]); +	} +	debug_trace("\n"); +	*dinp = dev->din; + +	return din_len; +} + +int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len) +{ +	const int cmd_addr = EC_LPC_ADDR_HOST_CMD; +	const int data_addr = EC_LPC_ADDR_HOST_DATA; +	const int args_addr = EC_LPC_ADDR_HOST_ARGS; +	const int param_addr = EC_LPC_ADDR_HOST_PARAM; + +	struct ec_lpc_host_args args; +	uint8_t *d; +	int csum; +	int i; + +	/* Fall back to old-style command interface if args aren't supported */ +	if (!dev->cmd_version_is_supported) +		return old_lpc_command(dev, cmd, dout, dout_len, dinp, +				       din_len); + +	if (dout_len > EC_HOST_PARAM_SIZE) { +		debug("%s: Cannot send %d bytes\n", __func__, dout_len); +		return -1; +	} + +	/* Fill in args */ +	args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; +	args.command_version = cmd_version; +	args.data_size = dout_len; + +	/* Calculate checksum */ +	csum = cmd + args.flags + args.command_version + args.data_size; +	for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) +		csum += *d; + +	args.checksum = (uint8_t)csum; + +	if (wait_for_sync(dev)) { +		debug("%s: Timeout waiting ready\n", __func__); +		return -1; +	} + +	/* Write args */ +	for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) +		outb(*d, args_addr + i); + +	/* Write data, if any */ +	debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version); +	for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) { +		outb(*d, param_addr + i); +		debug_trace("%02x ", *d); +	} + +	outb(cmd, cmd_addr); +	debug_trace("\n"); + +	if (wait_for_sync(dev)) { +		debug("%s: Timeout waiting for response\n", __func__); +		return -1; +	} + +	/* Check result */ +	i = inb(data_addr); +	if (i) { +		debug("%s: CROS_EC result code %d\n", __func__, i); +		return -i; +	} + +	/* Read back args */ +	for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) +		*d = inb(args_addr + i); + +	/* +	 * If EC didn't modify args flags, then somehow we sent a new-style +	 * command to an old EC, which means it would have read its params +	 * from the wrong place. +	 */ +	if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) { +		debug("%s: CROS_EC protocol mismatch\n", __func__); +		return -EC_RES_INVALID_RESPONSE; +	} + +	if (args.data_size > din_len) { +		debug("%s: CROS_EC returned too much data %d > %d\n", +		      __func__, args.data_size, din_len); +		return -EC_RES_INVALID_RESPONSE; +	} + +	/* Read data, if any */ +	for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) { +		*d = inb(param_addr + i); +		debug_trace("%02x ", *d); +	} +	debug_trace("\n"); + +	/* Verify checksum */ +	csum = cmd + args.flags + args.command_version + args.data_size; +	for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) +		csum += *d; + +	if (args.checksum != (uint8_t)csum) { +		debug("%s: CROS_EC response has invalid checksum\n", __func__); +		return -EC_RES_INVALID_CHECKSUM; +	} +	*dinp = dev->din; + +	/* Return actual amount of data received */ +	return args.data_size; +} + +/** + * Initialize LPC protocol. + * + * @param dev		CROS_EC device + * @param blob		Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob) +{ +	int byte, i; + +	/* See if we can find an EC at the other end */ +	byte = 0xff; +	byte &= inb(EC_LPC_ADDR_HOST_CMD); +	byte &= inb(EC_LPC_ADDR_HOST_DATA); +	for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++) +		byte &= inb(EC_LPC_ADDR_HOST_PARAM + i); +	if (byte == 0xff) { +		debug("%s: CROS_EC device not found on LPC bus\n", +			__func__); +		return -1; +	} + +	return 0; +} + +/* + * Test if LPC command args are supported. + * + * The cheapest way to do this is by looking for the memory-mapped + * flag.  This is faster than sending a new-style 'hello' command and + * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag + * in args when it responds. + */ +int cros_ec_lpc_check_version(struct cros_ec_dev *dev) +{ +	if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' && +			inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) +				== 'C' && +			(inb(EC_LPC_ADDR_MEMMAP + +				EC_MEMMAP_HOST_CMD_FLAGS) & +				EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) { +		dev->cmd_version_is_supported = 1; +	} else { +		/* We are going to use the old IO ports */ +		dev->cmd_version_is_supported = 0; +	} +	debug("lpc: version %s\n", dev->cmd_version_is_supported ? +			"new" : "old"); + +	return 0; +} diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c new file mode 100644 index 000000000..e15c83341 --- /dev/null +++ b/drivers/misc/cros_ec_spi.c @@ -0,0 +1,161 @@ +/* + * Chromium OS cros_ec driver - SPI interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <cros_ec.h> +#include <spi.h> + +/** + * Send a command to a LPC CROS_EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS_EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout		Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param dinp		Returns pointer to response data. This will be + *			untouched unless we return a value > 0. + * @param din_len	Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len) +{ +	int in_bytes = din_len + 4;	/* status, length, checksum, trailer */ +	uint8_t *out; +	uint8_t *p; +	int csum, len; +	int rv; + +	/* +	 * Sanity-check input size to make sure it plus transaction overhead +	 * fits in the internal device buffer. +	 */ +	if (in_bytes > sizeof(dev->din)) { +		debug("%s: Cannot receive %d bytes\n", __func__, din_len); +		return -1; +	} + +	/* We represent message length as a byte */ +	if (dout_len > 0xff) { +		debug("%s: Cannot send %d bytes\n", __func__, dout_len); +		return -1; +	} + +	/* +	 * Clear input buffer so we don't get false hits for MSG_HEADER +	 */ +	memset(dev->din, '\0', in_bytes); + +	if (spi_claim_bus(dev->spi)) { +		debug("%s: Cannot claim SPI bus\n", __func__); +		return -1; +	} + +	out = dev->dout; +	out[0] = cmd_version; +	out[1] = cmd; +	out[2] = (uint8_t)dout_len; +	memcpy(out + 3, dout, dout_len); +	csum = cros_ec_calc_checksum(out, 3) +	       + cros_ec_calc_checksum(dout, dout_len); +	out[3 + dout_len] = (uint8_t)csum; + +	/* +	 * Send output data and receive input data starting such that the +	 * message body will be dword aligned. +	 */ +	p = dev->din + sizeof(int64_t) - 2; +	len = dout_len + 4; +	cros_ec_dump_data("out", cmd, out, len); +	rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p, +		      SPI_XFER_BEGIN | SPI_XFER_END); + +	spi_release_bus(dev->spi); + +	if (rv) { +		debug("%s: Cannot complete SPI transfer\n", __func__); +		return -1; +	} + +	len = min(p[1], din_len); +	cros_ec_dump_data("in", -1, p, len + 3); + +	/* Response code is first byte of message */ +	if (p[0] != EC_RES_SUCCESS) { +		printf("%s: Returned status %d\n", __func__, p[0]); +		return -(int)(p[0]); +	} + +	/* Check checksum */ +	csum = cros_ec_calc_checksum(p, len + 2); +	if (csum != p[len + 2]) { +		debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__, +		      p[2 + len], csum); +		return -1; +	} + +	/* Anything else is the response data */ +	*dinp = p + 2; + +	return len; +} + +int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ +	/* Decode interface-specific FDT params */ +	dev->max_frequency = fdtdec_get_int(blob, dev->node, +					    "spi-max-frequency", 500000); +	dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0); + +	return 0; +} + +/** + * Initialize SPI protocol. + * + * @param dev		CROS_EC device + * @param blob		Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob) +{ +	dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, +				       dev->cs, dev->max_frequency, 0); +	if (!dev->spi) { +		debug("%s: Could not setup SPI slave\n", __func__); +		return -1; +	} + +	return 0; +} diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 4070d4ea5..5da20eda5 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -129,13 +129,13 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  	unsigned int timeout = 100000;  	u32 retry = 10000;  	u32 mask, ctrl; +	ulong start = get_timer(0);  	while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { -		if (timeout == 0) { +		if (get_timer(start) > timeout) {  			printf("Timeout on data busy\n");  			return TIMEOUT;  		} -		timeout--;  	}  	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); @@ -143,7 +143,6 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  	if (data)  		dwmci_prepare_data(host, data); -  	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);  	if (data) @@ -231,9 +230,8 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)  	int timeout = 10000;  	unsigned long sclk; -	if (freq == host->clock) +	if ((freq == host->clock) || (freq == 0))  		return 0; -  	/*  	 * If host->mmc_clk didn't define,  	 * then assume that host->bus_hz is source clock value. @@ -314,7 +312,7 @@ static void dwmci_set_ios(struct mmc *mmc)  static int dwmci_init(struct mmc *mmc)  {  	struct dwmci_host *host = (struct dwmci_host *)mmc->priv; -	u32 fifo_size, fifoth_val; +	u32 fifo_size;  	dwmci_writel(host, DWMCI_PWREN, 1); @@ -323,6 +321,9 @@ static int dwmci_init(struct mmc *mmc)  		return -1;  	} +	/* Enumerate at 400KHz */ +	dwmci_setup_bus(host, mmc->f_min); +  	dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF);  	dwmci_writel(host, DWMCI_INTMASK, 0); @@ -331,13 +332,13 @@ static int dwmci_init(struct mmc *mmc)  	dwmci_writel(host, DWMCI_IDINTEN, 0);  	dwmci_writel(host, DWMCI_BMOD, 1); -	fifo_size = dwmci_readl(host, DWMCI_FIFOTH); -	if (host->fifoth_val) -		fifoth_val = host->fifoth_val; -	else -		fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | -			TX_WMARK(fifo_size/2); -	dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); +	if (!host->fifoth_val) { +		fifo_size = dwmci_readl(host, DWMCI_FIFOTH); +		fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; +		host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) | +			TX_WMARK(fifo_size / 2); +	} +	dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val);  	dwmci_writel(host, DWMCI_CLKENA, 0);  	dwmci_writel(host, DWMCI_CLKSRC, 0); diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 72a31b73f..4238dd933 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -19,39 +19,146 @@   */  #include <common.h> -#include <malloc.h>  #include <dwmmc.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <malloc.h>  #include <asm/arch/dwmmc.h>  #include <asm/arch/clk.h> +#include <asm/arch/pinmux.h> -static char *EXYNOS_NAME = "EXYNOS DWMMC"; +#define	DWMMC_MAX_CH_NUM		4 +#define	DWMMC_MAX_FREQ			52000000 +#define	DWMMC_MIN_FREQ			400000 +#define	DWMMC_MMC0_CLKSEL_VAL		0x03030001 +#define	DWMMC_MMC2_CLKSEL_VAL		0x03020001 +/* + * Function used as callback function to initialise the + * CLKSEL register for every mmc channel. + */  static void exynos_dwmci_clksel(struct dwmci_host *host)  { -	u32 val; -	val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) | -		DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(0); +	dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val); +} -	dwmci_writel(host, DWMCI_CLKSEL, val); +unsigned int exynos_dwmci_get_clk(int dev_index) +{ +	return get_mmc_clk(dev_index);  } -int exynos_dwmci_init(u32 regbase, int bus_width, int index) +/* + * This function adds the mmc channel to be registered with mmc core. + * index -	mmc channel number. + * regbase -	register base address of mmc channel specified in 'index'. + * bus_width -	operating bus width of mmc channel specified in 'index'. + * clksel -	value to be written into CLKSEL register in case of FDT. + *		NULL in case od non-FDT. + */ +int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)  {  	struct dwmci_host *host = NULL; +	unsigned int div; +	unsigned long freq, sclk;  	host = malloc(sizeof(struct dwmci_host));  	if (!host) {  		printf("dwmci_host malloc fail!\n");  		return 1;  	} +	/* request mmc clock vlaue of 52MHz.  */ +	freq = 52000000; +	sclk = get_mmc_clk(index); +	div = DIV_ROUND_UP(sclk, freq); +	/* set the clock divisor for mmc */ +	set_mmc_clk(index, div); -	host->name = EXYNOS_NAME; +	host->name = "EXYNOS DWMMC";  	host->ioaddr = (void *)regbase;  	host->buswidth = bus_width; + +	if (clksel) { +		host->clksel_val = clksel; +	} else { +		if (0 == index) +			host->clksel_val = DWMMC_MMC0_CLKSEL_VAL; +		if (2 == index) +			host->clksel_val = DWMMC_MMC2_CLKSEL_VAL; +	} +  	host->clksel = exynos_dwmci_clksel;  	host->dev_index = index; +	host->mmc_clk = exynos_dwmci_get_clk; +	/* Add the mmc channel to be registered with mmc core */ +	if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) { +		debug("dwmmc%d registration failed\n", index); +		return -1; +	} +	return 0; +} + +#ifdef CONFIG_OF_CONTROL +int exynos_dwmmc_init(const void *blob) +{ +	int index, bus_width; +	int node_list[DWMMC_MAX_CH_NUM]; +	int err = 0, dev_id, flag, count, i; +	u32 clksel_val, base, timing[3]; + +	count = fdtdec_find_aliases_for_id(blob, "mmc", +				COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list, +				DWMMC_MAX_CH_NUM); + +	for (i = 0; i < count; i++) { +		int node = node_list[i]; + +		if (node <= 0) +			continue; -	add_dwmci(host, 52000000, 400000); +		/* Extract device id for each mmc channel */ +		dev_id = pinmux_decode_periph_id(blob, node); +		/* Get the bus width from the device node */ +		bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); +		if (bus_width <= 0) { +			debug("DWMMC: Can't get bus-width\n"); +			return -1; +		} +		if (8 == bus_width) +			flag = PINMUX_FLAG_8BIT_MODE; +		else +			flag = PINMUX_FLAG_NONE; + +		/* config pinmux for each mmc channel */ +		err = exynos_pinmux_config(dev_id, flag); +		if (err) { +			debug("DWMMC not configured\n"); +			return err; +		} + +		index = dev_id - PERIPH_ID_SDMMC0; + +		/* Get the base address from the device node */ +		base = fdtdec_get_addr(blob, node, "reg"); +		if (!base) { +			debug("DWMMC: Can't get base address\n"); +			return -1; +		} +		/* Extract the timing info from the node */ +		err = fdtdec_get_int_array(blob, node, "samsung,timing", +					timing, 3); +		if (err) { +			debug("Can't get sdr-timings for divider\n"); +			return -1; +		} + +		clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | +				DWMCI_SET_DRV_CLK(timing[1]) | +				DWMCI_SET_DIV_RATIO(timing[2])); +		/* Initialise each mmc channel */ +		err = exynos_dwmci_add_port(index, base, bus_width, clksel_val); +		if (err) +			debug("dwmmc Channel-%d init failed\n", index); +	}  	return 0;  } - +#endif diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e6a296a57..73f719579 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -254,7 +254,7 @@ err_out:  }  static unsigned long -mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) +mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)  {  	int err = 0;  	struct mmc *mmc = find_mmc_device(dev_num); @@ -266,7 +266,8 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)  	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))  		printf("\n\nCaution! Your devices Erase group is 0x%x\n" -			"The erase range would be change to 0x%lx~0x%lx\n\n", +		       "The erase range would be change to " +		       "0x" LBAF "~0x" LBAF "\n\n",  		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),  		       ((start + blkcnt + mmc->erase_grp_size)  		       & ~(mmc->erase_grp_size - 1)) - 1); @@ -289,14 +290,14 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)  }  static ulong -mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) +mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)  {  	struct mmc_cmd cmd;  	struct mmc_data data;  	int timeout = 1000;  	if ((start + blkcnt) > mmc->block_dev.lba) { -		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", +		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",  			start + blkcnt, mmc->block_dev.lba);  		return 0;  	} @@ -346,7 +347,7 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  }  static ulong -mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) +mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)  {  	lbaint_t cur, blocks_todo = blkcnt; @@ -369,7 +370,7 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)  	return blkcnt;  } -static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, +static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,  			   lbaint_t blkcnt)  {  	struct mmc_cmd cmd; @@ -408,7 +409,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start,  	return blkcnt;  } -static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) +static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)  {  	lbaint_t cur, blocks_todo = blkcnt; @@ -420,7 +421,7 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)  		return 0;  	if ((start + blkcnt) > mmc->block_dev.lba) { -		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", +		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",  			start + blkcnt, mmc->block_dev.lba);  		return 0;  	} @@ -1503,3 +1504,137 @@ int mmc_initialize(bd_t *bis)  	do_preinit();  	return 0;  } + +#ifdef CONFIG_SUPPORT_EMMC_BOOT +/* + * This function changes the size of boot partition and the size of rpmb + * partition present on EMMC devices. + * + * Input Parameters: + * struct *mmc: pointer for the mmc device strcuture + * bootsize: size of boot partition + * rpmbsize: size of rpmb partition + * + * Returns 0 on success. + */ + +int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, +				unsigned long rpmbsize) +{ +	int err; +	struct mmc_cmd cmd; + +	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = MMC_CMD62_ARG1; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error1 = %d\n", err); +		return err; +	} + +	/* Boot partition changing mode */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = MMC_CMD62_ARG2; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error2 = %d\n", err); +		return err; +	} +	/* boot partition size is multiple of 128KB */ +	bootsize = (bootsize * 1024) / 128; + +	/* Arg: boot partition size */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = bootsize; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error3 = %d\n", err); +		return err; +	} +	/* RPMB partition size is multiple of 128KB */ +	rpmbsize = (rpmbsize * 1024) / 128; +	/* Arg: RPMB partition size */ +	cmd.cmdidx = MMC_CMD_RES_MAN; +	cmd.resp_type = MMC_RSP_R1b; +	cmd.cmdarg = rpmbsize; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		debug("mmc_boot_partition_size_change: Error4 = %d\n", err); +		return err; +	} +	return 0; +} + +/* + * This function shall form and send the commands to open / close the + * boot partition specified by user. + * + * Input Parameters: + * ack: 0x0 - No boot acknowledge sent (default) + *	0x1 - Boot acknowledge sent during boot operation + * part_num: User selects boot data that will be sent to master + *	0x0 - Device not boot enabled (default) + *	0x1 - Boot partition 1 enabled for boot + *	0x2 - Boot partition 2 enabled for boot + * access: User selects partitions to access + *	0x0 : No access to boot partition (default) + *	0x1 : R/W boot partition 1 + *	0x2 : R/W boot partition 2 + *	0x3 : R/W Replay Protected Memory Block (RPMB) + * + * Returns 0 on success. + */ +int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ +	int err; +	struct mmc_cmd cmd; + +	/* Boot ack enable, boot partition enable , boot partition access */ +	cmd.cmdidx = MMC_CMD_SWITCH; +	cmd.resp_type = MMC_RSP_R1b; + +	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +			(EXT_CSD_PART_CONF << 16) | +			((EXT_CSD_BOOT_ACK(ack) | +			EXT_CSD_BOOT_PART_NUM(part_num) | +			EXT_CSD_PARTITION_ACCESS(access)) << 8); + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) { +		if (access) { +			debug("mmc boot partition#%d open fail:Error1 = %d\n", +			      part_num, err); +		} else { +			debug("mmc boot partition#%d close fail:Error = %d\n", +			      part_num, err); +		} +		return err; +	} + +	if (access) { +		/* 4bit transfer mode at booting time. */ +		cmd.cmdidx = MMC_CMD_SWITCH; +		cmd.resp_type = MMC_RSP_R1b; + +		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +				(EXT_CSD_BOOT_BUS_WIDTH << 16) | +				((1 << 0) << 8); + +		err = mmc_send_cmd(mmc, &cmd, NULL); +		if (err) { +			debug("mmc boot partition#%d open fail:Error2 = %d\n", +			      part_num, err); +			return err; +		} +	} +	return 0; +} +#endif diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 25f875202..25a571075 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1797,7 +1797,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)  			};  			int i; -			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { +			for (i = 0; i < ARRAY_SIZE(modes); i++) {  				info->vendor = modes[i];  				info->start[0] =  					(ulong)map_physmem(base, @@ -1883,8 +1883,7 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)  	/* Issue FLASH reset command */  	flash_cmd_reset(info); -	for (cfi_offset=0; -	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); +	for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi);  	     cfi_offset++) {  		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],  				 FLASH_CMD_CFI); @@ -2336,7 +2335,7 @@ void flash_protect_default(void)  #endif  #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) -	for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { +	for (i = 0; i < ARRAY_SIZE(apl); i++) {  		debug("autoprotecting from %08lx to %08lx\n",  		      apl[i].start, apl[i].start + apl[i].size - 1);  		flash_protect(FLAG_PROTECT_SET, diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 882170491..bb81e8411 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -83,6 +83,7 @@ COBJS-$(CONFIG_NAND_DOCG4) += docg4.o  else  # minimal SPL drivers  COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o +COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o  COBJS-$(CONFIG_NAND_MXC) += mxc_nand_spl.o  endif # drivers diff --git a/nand_spl/nand_boot_fsl_ifc.c b/drivers/mtd/nand/fsl_ifc_spl.c index 44972c5c0..8537c4c6f 100644 --- a/nand_spl/nand_boot_fsl_ifc.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -1,5 +1,5 @@  /* - * NAND boot for FSL Integrated Flash Controller, NAND Flash Control Machine + * NAND boot for Freescale Integrated Flash Controller, NAND FCM   *   * Copyright 2011 Freescale Semiconductor, Inc.   * Author: Dipen Dudhat <dipen.dudhat@freescale.com> @@ -46,9 +46,9 @@ static inline int check_read_ecc(uchar *buf, u32 *eccstat,  				 unsigned int bufnum, int page_size)  {  	u32 reg = eccstat[bufnum / 4]; -	int errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; +	int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; -	if (errors == 15) { /* uncorrectable */ +	if (errors == 0xf) { /* uncorrectable */  		/* Blank pages fail hw ECC checks */  		if (is_blank(buf, page_size))  			return 1; @@ -123,30 +123,17 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)  	csor = CONFIG_SYS_NAND_CSOR;  	cspr = CONFIG_SYS_NAND_CSPR; -	if (!(csor & CSOR_NAND_ECC_DEC_EN)) { -		/* soft ECC in SPL is unimplemented */ -		puts("WARNING: soft ECC not checked in SPL\n"); -	} else { -		u32 hwcsor; - -		/* make sure board is configured with ECC on boot */ -		hwcsor = in_be32(&ifc->csor_cs[0].csor); -		if (!(hwcsor & CSOR_NAND_ECC_DEC_EN)) -			puts("WARNING: ECC not checked in SPL, " -				"check board cfg\n"); -	} -  	port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8;  	if (csor & CSOR_NAND_PGS_4K) {  		page_size = 4096; -		bufnum_mask = 1; +		bufnum_mask = 0x1;  	} else if (csor & CSOR_NAND_PGS_2K) {  		page_size = 2048; -		bufnum_mask = 3; +		bufnum_mask = 0x3;  	} else {  		page_size = 512; -		bufnum_mask = 15; +		bufnum_mask = 0xf;  		if (port_size == 8)  			bad_marker = 5; @@ -174,8 +161,8 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)  		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);  		out_be32(&ifc->ifc_nand.nand_fcr0, -			(NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | -			(NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); +			 (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | +			 (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));  	} else {  		out_be32(&ifc->ifc_nand.nand_fir0,  			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | @@ -185,7 +172,7 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)  		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);  		out_be32(&ifc->ifc_nand.nand_fcr0, -			NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); +			 NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);  	}  	/* Program FBCR = 0 for full page read */ @@ -206,7 +193,7 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)  			out_be32(&ifc->ifc_nand.col0, 0);  			/* start read */  			out_be32(&ifc->ifc_nand.nandseq_strt, -				IFC_NAND_SEQ_STRT_FIR_STRT); +				 IFC_NAND_SEQ_STRT_FIR_STRT);  			/* wait for read to complete */  			nand_wait(&buf[sram_addr], bufnum, page_size); @@ -241,7 +228,6 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)  void nand_boot(void)  {  	__attribute__((noreturn)) void (*uboot)(void); -  	/*  	 * Load U-Boot image from NAND into RAM  	 */ @@ -257,15 +243,16 @@ void nand_boot(void)  		  (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);  #endif  #endif -  	/*  	 * Jump to U-Boot image  	 */ +#ifdef CONFIG_SPL_FLUSH_IMAGE  	/*  	 * Clean d-cache and invalidate i-cache, to  	 * make sure that no stale data is executed.  	 */  	flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif  	uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;  	uboot();  } diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 90f83924e..ecbb2108f 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -32,6 +32,7 @@ endif  COBJS-$(CONFIG_SPI_FLASH)	+= spi_flash.o  COBJS-$(CONFIG_SPI_FLASH_ATMEL)	+= atmel.o  COBJS-$(CONFIG_SPI_FLASH_EON)	+= eon.o +COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE)	+= gigadevice.o  COBJS-$(CONFIG_SPI_FLASH_MACRONIX)	+= macronix.o  COBJS-$(CONFIG_SPI_FLASH_SPANSION)	+= spansion.o  COBJS-$(CONFIG_SPI_FLASH_SST)	+= sst.o diff --git a/drivers/mtd/spi/gigadevice.c b/drivers/mtd/spi/gigadevice.c new file mode 100644 index 000000000..b5e1ebedf --- /dev/null +++ b/drivers/mtd/spi/gigadevice.c @@ -0,0 +1,81 @@ +/* + * Gigadevice SPI flash driver + * Copyright 2013, Samsung Electronics Co., Ltd. + * Author: Banajit Goswami <banajit.g@samsung.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +struct gigadevice_spi_flash_params { +	uint16_t	id; +	uint16_t	nr_blocks; +	const char	*name; +}; + +static const struct gigadevice_spi_flash_params gigadevice_spi_flash_table[] = { +	{ +		.id			= 0x6016, +		.nr_blocks		= 64, +		.name			= "GD25LQ", +	}, +	{ +		.id			= 0x4017, +		.nr_blocks		= 128, +		.name			= "GD25Q64B", +	}, +}; + +struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode) +{ +	const struct gigadevice_spi_flash_params *params; +	struct spi_flash *flash; +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(gigadevice_spi_flash_table); i++) { +		params = &gigadevice_spi_flash_table[i]; +		if (params->id == ((idcode[1] << 8) | idcode[2])) +			break; +	} + +	if (i == ARRAY_SIZE(gigadevice_spi_flash_table)) { +		debug("SF: Unsupported Gigadevice ID %02x%02x\n", +				idcode[1], idcode[2]); +		return NULL; +	} + +	flash = spi_flash_alloc_base(spi, params->name); +	if (!flash) { +		debug("SF: Failed to allocate memory\n"); +		return NULL; +	} +	/* page_size */ +	flash->page_size = 256; +	/* sector_size = page_size * pages_per_sector */ +	flash->sector_size = flash->page_size * 16; +	/* size = sector_size * sector_per_block * number of blocks */ +	flash->size = flash->sector_size * 16 * params->nr_blocks; + +	return flash; +} diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index b3ef90f13..3ec2151b3 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -101,7 +101,7 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = {  		.idcode2 = 0x4d01,  		.pages_per_sector = 256,  		.nr_sectors = 256, -		.name = "S25FL129P_64K/S25FL128S", +		.name = "S25FL129P_64K/S25FL128S_64K",  	},  	{  		.idcode1 = 0x0219, @@ -110,6 +110,13 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = {  		.nr_sectors = 512,  		.name = "S25FL256S_64K",  	}, +	{ +		.idcode1 = 0x0220, +		.idcode2 = 0x4d01, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "S25FL512S_64K", +	},  };  struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 0e38f5948..6a6fe37e0 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -68,17 +68,60 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,  	return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);  } -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, -		size_t len, const void *buf) +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)  { -	unsigned long page_addr, byte_addr, page_size; -	size_t chunk_len, actual; +	struct spi_slave *spi = flash->spi; +	unsigned long timebase;  	int ret; -	u8 cmd[4]; +	u8 status; +	u8 check_status = 0x0; +	u8 poll_bit = STATUS_WIP; +	u8 cmd = flash->poll_cmd; -	page_size = flash->page_size; -	page_addr = offset / page_size; -	byte_addr = offset % page_size; +	if (cmd == CMD_FLAG_STATUS) { +		poll_bit = STATUS_PEC; +		check_status = poll_bit; +	} + +	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); +	if (ret) { +		debug("SF: fail to read %s status register\n", +			cmd == CMD_READ_STATUS ? "read" : "flag"); +		return ret; +	} + +	timebase = get_timer(0); +	do { +		WATCHDOG_RESET(); + +		ret = spi_xfer(spi, 8, NULL, &status, 0); +		if (ret) +			return -1; + +		if ((status & poll_bit) == check_status) +			break; + +	} while (get_timer(timebase) < timeout); + +	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + +	if ((status & poll_bit) == check_status) +		return 0; + +	/* Timed out */ +	debug("SF: time out!\n"); +	return -1; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, +		size_t cmd_len, const void *buf, size_t buf_len) +{ +	struct spi_slave *spi = flash->spi; +	unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; +	int ret; + +	if (buf == NULL) +		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;  	ret = spi_claim_bus(flash->spi);  	if (ret) { @@ -86,45 +129,122 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,  		return ret;  	} +	ret = spi_flash_cmd_write_enable(flash); +	if (ret < 0) { +		debug("SF: enabling write failed\n"); +		return ret; +	} + +	ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); +	if (ret < 0) { +		debug("SF: write cmd failed\n"); +		return ret; +	} + +	ret = spi_flash_cmd_wait_ready(flash, timeout); +	if (ret < 0) { +		debug("SF: write %s timed out\n", +			timeout == SPI_FLASH_PROG_TIMEOUT ? +			"program" : "page erase"); +		return ret; +	} + +	spi_release_bus(spi); + +	return ret; +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +{ +	u32 erase_size; +	u8 cmd[4]; +	int ret = -1; + +	erase_size = flash->sector_size; +	if (offset % erase_size || len % erase_size) { +		debug("SF: Erase offset/length not multiple of erase size\n"); +		return -1; +	} + +	if (erase_size == 4096) +		cmd[0] = CMD_ERASE_4K; +	else +		cmd[0] = CMD_ERASE_64K; + +	while (len) { +#ifdef CONFIG_SPI_FLASH_BAR +		u8 bank_sel; + +		bank_sel = offset / SPI_FLASH_16MB_BOUN; + +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		spi_flash_addr(offset, cmd); + +		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], +		      cmd[2], cmd[3], offset); + +		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); +		if (ret < 0) { +			debug("SF: erase failed\n"); +			break; +		} + +		offset += erase_size; +		len -= erase_size; +	} + +	return ret; +} + +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, +		size_t len, const void *buf) +{ +	unsigned long byte_addr, page_size; +	size_t chunk_len, actual; +	u8 cmd[4]; +	int ret = -1; + +	page_size = flash->page_size; +  	cmd[0] = CMD_PAGE_PROGRAM;  	for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR +		u8 bank_sel; + +		bank_sel = offset / SPI_FLASH_16MB_BOUN; + +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		byte_addr = offset % page_size;  		chunk_len = min(len - actual, page_size - byte_addr);  		if (flash->spi->max_write_size)  			chunk_len = min(chunk_len, flash->spi->max_write_size); -		cmd[1] = page_addr >> 8; -		cmd[2] = page_addr; -		cmd[3] = byte_addr; +		spi_flash_addr(offset, cmd);  		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",  		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); -		ret = spi_flash_cmd_write_enable(flash); -		if (ret < 0) { -			debug("SF: enabling write failed\n"); -			break; -		} - -		ret = spi_flash_cmd_write(flash->spi, cmd, 4, -					  buf + actual, chunk_len); +		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), +					buf + actual, chunk_len);  		if (ret < 0) {  			debug("SF: write failed\n");  			break;  		} -		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -		if (ret) -			break; - -		byte_addr += chunk_len; -		if (byte_addr == page_size) { -			page_addr++; -			byte_addr = 0; -		} +		offset += chunk_len;  	} -	spi_release_bus(flash->spi);  	return ret;  } @@ -134,8 +254,18 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  	struct spi_slave *spi = flash->spi;  	int ret; -	spi_claim_bus(spi); +	ret = spi_claim_bus(flash->spi); +	if (ret) { +		debug("SF: unable to claim SPI bus\n"); +		return ret; +	} +  	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); +	if (ret < 0) { +		debug("SF: read cmd failed\n"); +		return ret; +	} +  	spi_release_bus(spi);  	return ret; @@ -144,7 +274,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,  		size_t len, void *data)  { -	u8 cmd[5]; +	u8 cmd[5], bank_sel = 0; +	u32 remain_len, read_len; +	int ret = -1;  	/* Handle memory-mapped SPI */  	if (flash->memory_map) { @@ -153,130 +285,114 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,  	}  	cmd[0] = CMD_READ_ARRAY_FAST; -	spi_flash_addr(offset, cmd);  	cmd[4] = 0x00; -	return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); -} - -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, -			   u8 cmd, u8 poll_bit) -{ -	struct spi_slave *spi = flash->spi; -	unsigned long timebase; -	int ret; -	u8 status; - -	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); -	if (ret) { -		debug("SF: Failed to send command %02x: %d\n", cmd, ret); -		return ret; -	} +	while (len) { +#ifdef CONFIG_SPI_FLASH_BAR +		bank_sel = offset / SPI_FLASH_16MB_BOUN; -	timebase = get_timer(0); -	do { -		WATCHDOG_RESET(); +		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); +		if (ret) { +			debug("SF: fail to set bank%d\n", bank_sel); +			return ret; +		} +#endif +		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); +		if (len < remain_len) +			read_len = len; +		else +			read_len = remain_len; -		ret = spi_xfer(spi, 8, NULL, &status, 0); -		if (ret) -			return -1; +		spi_flash_addr(offset, cmd); -		if ((status & poll_bit) == 0) +		ret = spi_flash_read_common(flash, cmd, sizeof(cmd), +							data, read_len); +		if (ret < 0) { +			debug("SF: read failed\n");  			break; +		} -	} while (get_timer(timebase) < timeout); - -	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - -	if ((status & poll_bit) == 0) -		return 0; - -	/* Timed out */ -	debug("SF: time out!\n"); -	return -1; -} +		offset += read_len; +		len -= read_len; +		data += read_len; +	} -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ -	return spi_flash_cmd_poll_bit(flash, timeout, -		CMD_READ_STATUS, STATUS_WIP); +	return ret;  } -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)  { -	u32 end, erase_size; +	u8 cmd;  	int ret; -	u8 cmd[4]; - -	erase_size = flash->sector_size; -	if (offset % erase_size || len % erase_size) { -		debug("SF: Erase offset/length not multiple of erase size\n"); -		return -1; -	} -	ret = spi_claim_bus(flash->spi); -	if (ret) { -		debug("SF: Unable to claim SPI bus\n"); +	cmd = CMD_WRITE_STATUS; +	ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); +	if (ret < 0) { +		debug("SF: fail to write status register\n");  		return ret;  	} -	if (erase_size == 4096) -		cmd[0] = CMD_ERASE_4K; -	else -		cmd[0] = CMD_ERASE_64K; -	end = offset + len; - -	while (offset < end) { -		spi_flash_addr(offset, cmd); -		offset += erase_size; - -		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], -		      cmd[2], cmd[3], offset); - -		ret = spi_flash_cmd_write_enable(flash); -		if (ret) -			goto out; - -		ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); -		if (ret) -			goto out; - -		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); -		if (ret) -			goto out; -	} - - out: -	spi_release_bus(flash->spi); -	return ret; +	return 0;  } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)  {  	u8 cmd;  	int ret; -	ret = spi_flash_cmd_write_enable(flash); +	if (flash->bank_curr == bank_sel) { +		debug("SF: not require to enable bank%d\n", bank_sel); +		return 0; +	} + +	cmd = flash->bank_write_cmd; +	ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1);  	if (ret < 0) { -		debug("SF: enabling write failed\n"); +		debug("SF: fail to write bank register\n");  		return ret;  	} +	flash->bank_curr = bank_sel; -	cmd = CMD_WRITE_STATUS; -	ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); -	if (ret) { -		debug("SF: fail to write status register\n"); -		return ret; +	return 0; +} + +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) +{ +	u8 cmd; +	u8 curr_bank = 0; + +	/* discover bank cmds */ +	switch (idcode0) { +	case SPI_FLASH_SPANSION_IDCODE0: +		flash->bank_read_cmd = CMD_BANKADDR_BRRD; +		flash->bank_write_cmd = CMD_BANKADDR_BRWR; +		break; +	case SPI_FLASH_STMICRO_IDCODE0: +	case SPI_FLASH_WINBOND_IDCODE0: +		flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; +		flash->bank_write_cmd = CMD_EXTNADDR_WREAR; +		break; +	default: +		printf("SF: Unsupported bank commands %02x\n", idcode0); +		return -1;  	} -	ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -	if (ret < 0) { -		debug("SF: write status register timed out\n"); -		return ret; +	/* read the bank reg - on which bank the flash is in currently */ +	cmd = flash->bank_read_cmd; +	if (flash->size > SPI_FLASH_16MB_BOUN) { +		if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { +			debug("SF: fail to read bank addr register\n"); +			return -1; +		} +		flash->bank_curr = curr_bank; +	} else { +		flash->bank_curr = curr_bank;  	}  	return 0;  } +#endif  #ifdef CONFIG_OF_CONTROL  int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) @@ -342,6 +458,9 @@ static const struct {  #ifdef CONFIG_SPI_FLASH_EON  	{ 0, 0x1c, spi_flash_probe_eon, },  #endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE +	{ 0, 0xc8, spi_flash_probe_gigadevice, }, +#endif  #ifdef CONFIG_SPI_FLASH_MACRONIX  	{ 0, 0xc2, spi_flash_probe_macronix, },  #endif @@ -422,6 +541,13 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,  		goto err_manufacturer_probe;  	} +#ifdef CONFIG_SPI_FLASH_BAR +	/* Configure the BAR - disover bank cmds and read current bank  */ +	ret = spi_flash_bank_config(flash, *idp); +	if (ret < 0) +		goto err_manufacturer_probe; +#endif +  #ifdef CONFIG_OF_CONTROL  	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {  		debug("SF: FDT decode error\n"); @@ -434,6 +560,12 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,  	if (flash->memory_map)  		printf(", mapped at %p", flash->memory_map);  	puts("\n"); +#ifndef CONFIG_SPI_FLASH_BAR +	if (flash->size > SPI_FLASH_16MB_BOUN) { +		puts("SF: Warning - Only lower 16MiB accessible,"); +		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); +	} +#endif  	spi_release_bus(spi); @@ -464,6 +596,7 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,  	/* Set up some basic fields - caller will sort out sizes */  	flash->spi = spi;  	flash->name = name; +	flash->poll_cmd = CMD_READ_STATUS;  	flash->read = spi_flash_cmd_read_fast;  	flash->write = spi_flash_cmd_write_multi; diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 141cfa8b2..af1afa96c 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -22,14 +22,31 @@  #define CMD_PAGE_PROGRAM		0x02  #define CMD_WRITE_DISABLE		0x04  #define CMD_READ_STATUS			0x05 +#define CMD_FLAG_STATUS			0x70  #define CMD_WRITE_ENABLE		0x06  #define CMD_ERASE_4K			0x20  #define CMD_ERASE_32K			0x52  #define CMD_ERASE_64K			0xd8  #define CMD_ERASE_CHIP			0xc7 +#define SPI_FLASH_16MB_BOUN		0x1000000 + +/* Manufacture ID's */ +#define SPI_FLASH_SPANSION_IDCODE0	0x01 +#define SPI_FLASH_STMICRO_IDCODE0	0x20 +#define SPI_FLASH_WINBOND_IDCODE0	0xef + +#ifdef CONFIG_SPI_FLASH_BAR +/* Bank addr access commands */ +# define CMD_BANKADDR_BRWR		0x17 +# define CMD_BANKADDR_BRRD		0x16 +# define CMD_EXTNADDR_WREAR		0xC5 +# define CMD_EXTNADDR_RDEAR		0xC8 +#endif +  /* Common status */  #define STATUS_WIP			0x01 +#define STATUS_PEC			0x80  /* Send a single-byte command to the device and read the response */  int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); @@ -77,16 +94,30 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)  /* Program the status register. */  int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); +#ifdef CONFIG_SPI_FLASH_BAR +/* Program the bank address register */ +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel); + +/* Configure the BAR - discover the bank cmds */ +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0); +#endif +  /*   * Same as spi_flash_cmd_read() except it also claims/releases the SPI   * bus. Used as common part of the ->read() operation.   */  int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,  		size_t cmd_len, void *data, size_t data_len); - -/* Send a command to the device and wait for some bit to clear itself. */ -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, -			   u8 cmd, u8 poll_bit); +/* + * Used for spi_flash write operation + * - SPI claim + * - spi_flash_cmd_write_enable + * - spi_flash_cmd_write + * - spi_flash_cmd_wait_ready + * - SPI release + */ +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, +		size_t cmd_len, const void *buf, size_t buf_len);  /*   * Send the read status command to the device and wait for the wip @@ -106,3 +137,4 @@ struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode);  struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode);  struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode);  struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 2a9972bd4..7e41ee132 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -140,6 +140,30 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {  		.nr_sectors = 512,  		.name = "N25Q256A",  	}, +	{ +		.id = 0xba20, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "N25Q512", +	}, +	{ +		.id = 0xbb20, +		.pages_per_sector = 256, +		.nr_sectors = 1024, +		.name = "N25Q512A", +	}, +	{ +		.id = 0xba21, +		.pages_per_sector = 256, +		.nr_sectors = 2048, +		.name = "N25Q1024", +	}, +	{ +		.id = 0xbb21, +		.pages_per_sector = 256, +		.nr_sectors = 2048, +		.name = "N25Q1024A", +	},  };  struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) @@ -186,5 +210,9 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)  	flash->sector_size = 256 * params->pages_per_sector;  	flash->size = flash->sector_size * params->nr_sectors; +	/* for >= 512MiB flashes, use flag status instead of read_status */ +	if (flash->size >= 0x4000000) +		flash->poll_cmd = CMD_FLAG_STATUS; +  	return flash;  } diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 845780849..c399bf14d 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -55,27 +55,27 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {  	{  		.id			= 0x4014,  		.nr_blocks		= 16, -		.name			= "W25Q80BL", +		.name			= "W25Q80BL/W25Q80BV",  	},  	{  		.id			= 0x4015,  		.nr_blocks		= 32, -		.name			= "W25Q16", +		.name			= "W25Q16CL/W25Q16DV",  	},  	{  		.id			= 0x4016,  		.nr_blocks		= 64, -		.name			= "W25Q32", +		.name			= "W25Q32BV/W25Q32FV_SPI",  	},  	{  		.id			= 0x4017,  		.nr_blocks		= 128, -		.name			= "W25Q64", +		.name			= "W25Q64CV/W25Q64FV_SPI",  	},  	{  		.id			= 0x4018,  		.nr_blocks		= 256, -		.name			= "W25Q128", +		.name			= "W25Q128BV/W25Q128FV_SPI",  	},  	{  		.id			= 0x4019, @@ -88,14 +88,24 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {  		.name			= "W25Q80BW",  	},  	{ +		.id			= 0x6015, +		.nr_blocks		= 32, +		.name			= "W25Q16DW", +	}, +	{  		.id			= 0x6016,  		.nr_blocks		= 64, -		.name			= "W25Q32DW", +		.name			= "W25Q32DW/W25Q32FV_QPI",  	},  	{  		.id			= 0x6017,  		.nr_blocks		= 128, -		.name			= "W25Q64DW", +		.name			= "W25Q64DW/W25Q64FV_QPI", +	}, +	{ +		.id			= 0x6018, +		.nr_blocks		= 256, +		.name			= "W25Q128FW/W25Q128FV_QPI",  	},  }; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 786a6567a..9cf2983d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -46,10 +46,12 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o  COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o  COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o  COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o +COBJS-$(CONFIG_FTMAC110) += ftmac110.o  COBJS-$(CONFIG_FTMAC100) += ftmac100.o  COBJS-$(CONFIG_GRETH) += greth.o  COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o  COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o +COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o  COBJS-$(CONFIG_LAN91C96) += lan91c96.o  COBJS-$(CONFIG_MACB) += macb.o  COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o @@ -68,6 +70,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o  COBJS-$(CONFIG_SH_ETHER) += sh_eth.o  COBJS-$(CONFIG_SMC91111) += smc91111.o  COBJS-$(CONFIG_SMC911X) += smc911x.o +COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o  COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o  COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o  COBJS-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o diff --git a/drivers/net/designware.c b/drivers/net/designware.c index bf21a08bd..46f6601fa 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -113,7 +113,9 @@ static int mac_reset(struct eth_device *dev)  	int timeout = CONFIG_MACRESET_TIMEOUT;  	writel(DMAMAC_SRST, &dma_p->busmode); -	writel(MII_PORTSELECT, &mac_p->conf); + +	if (priv->interface != PHY_INTERFACE_MODE_RGMII) +		writel(MII_PORTSELECT, &mac_p->conf);  	start = get_timer(0);  	while (get_timer(start) < timeout) { diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 69ba57d3d..2dbb328b8 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,11 +27,13 @@  #include <malloc.h>  #include <net.h>  #include <asm/io.h> +#include <asm/dma-mapping.h>  #include <linux/mii.h>  #include "ftgmac100.h"  #define ETH_ZLEN	60 +#define CFG_XBUF_SIZE	1536  /* RBSR - hw default init value is also 0x640 */  #define RBSR_DEFAULT_VALUE	0x640 @@ -40,8 +42,10 @@  #define PKTBUFSTX	4	/* must be power of 2 */  struct ftgmac100_data { -	struct ftgmac100_txdes txdes[PKTBUFSTX]; -	struct ftgmac100_rxdes rxdes[PKTBUFSRX]; +	ulong txdes_dma; +	struct ftgmac100_txdes *txdes; +	ulong rxdes_dma; +	struct ftgmac100_rxdes *rxdes;  	int tx_index;  	int rx_index;  	int phy_addr; @@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)  {  	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;  	struct ftgmac100_data *priv = dev->priv; -	struct ftgmac100_txdes *txdes = priv->txdes; -	struct ftgmac100_rxdes *rxdes = priv->rxdes; +	struct ftgmac100_txdes *txdes; +	struct ftgmac100_rxdes *rxdes;  	unsigned int maccr; +	void *buf;  	int i;  	debug("%s()\n", __func__); +	if (!priv->txdes) { +		txdes = dma_alloc_coherent( +			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma); +		if (!txdes) +			panic("ftgmac100: out of memory\n"); +		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX); +		priv->txdes = txdes; +	} +	txdes = priv->txdes; + +	if (!priv->rxdes) { +		rxdes = dma_alloc_coherent( +			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma); +		if (!rxdes) +			panic("ftgmac100: out of memory\n"); +		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX); +		priv->rxdes = rxdes; +	} +	rxdes = priv->rxdes; +  	/* set the ethernet address */  	ftgmac100_set_mac_from_env(dev); @@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)  	for (i = 0; i < PKTBUFSTX; i++) {  		/* TXBUF_BADR */ -		txdes[i].txdes3 = 0; +		if (!txdes[i].txdes2) { +			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); +			if (!buf) +				panic("ftgmac100: out of memory\n"); +			txdes[i].txdes3 = virt_to_phys(buf); +			txdes[i].txdes2 = (uint)buf; +		}  		txdes[i].txdes1 = 0;  	}  	for (i = 0; i < PKTBUFSRX; i++) {  		/* RXBUF_BADR */ -		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i]; +		if (!rxdes[i].rxdes2) { +			buf = NetRxPackets[i]; +			rxdes[i].rxdes3 = virt_to_phys(buf); +			rxdes[i].rxdes2 = (uint)buf; +		}  		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;  	}  	/* transmit ring */ -	writel((unsigned int)txdes, &ftgmac100->txr_badr); +	writel(priv->txdes_dma, &ftgmac100->txr_badr);  	/* receive ring */ -	writel((unsigned int)rxdes, &ftgmac100->rxr_badr); +	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);  	/* poll receive descriptor automatically */  	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc); @@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)  	debug("%s(): RX buffer %d, %x received\n",  	       __func__, priv->rx_index, rxlen); +	/* invalidate d-cache */ +	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE); +  	/* pass the packet up to the protocol layers. */ -	NetReceive((void *)curr_des->rxdes3, rxlen); +	NetReceive((void *)curr_des->rxdes2, rxlen);  	/* release buffer to DMA */  	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; @@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)  	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;  	struct ftgmac100_data *priv = dev->priv;  	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; -	int start;  	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {  		debug("%s(): no TX descriptor available\n", __func__); @@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)  	length = (length < ETH_ZLEN) ? ETH_ZLEN : length; -	/* initiate a transmit sequence */ -	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */ +	memcpy((void *)curr_des->txdes2, (void *)packet, length); +	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);  	/* only one descriptor on TXBUF */  	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; @@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)  	/* start transmit */  	writel(1, &ftgmac100->txpd); -	/* wait for transfer to succeed */ -	start = get_timer(0); -	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { -		if (get_timer(0) >= 5) { -			debug("%s(): timed out\n", __func__); -			return -1; -		} -	} -  	debug("%s(): packet sent\n", __func__);  	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX; diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c new file mode 100644 index 000000000..579dcc72f --- /dev/null +++ b/drivers/net/ftmac110.c @@ -0,0 +1,473 @@ +/* + * Faraday 10/100Mbps Ethernet Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/dma-mapping.h> + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#include <miiphy.h> +#endif + +#include "ftmac110.h" + +#define CFG_RXDES_NUM   8 +#define CFG_TXDES_NUM   2 +#define CFG_XBUF_SIZE   1536 + +#define CFG_MDIORD_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */ +#define CFG_MDIOWR_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */ +#define CFG_LINKUP_TIMEOUT  (CONFIG_SYS_HZ << 2) /* 4 sec */ + +/* + * FTMAC110 DMA design issue + * + * Its DMA engine has a weird restriction that its Rx DMA engine + * accepts only 16-bits aligned address, 32-bits aligned is not + * acceptable. However this restriction does not apply to Tx DMA. + * + * Conclusion: + * (1) Tx DMA Buffer Address: + *     1 bytes aligned: Invalid + *     2 bytes aligned: O.K + *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible) + * (2) Rx DMA Buffer Address: + *     1 bytes aligned: Invalid + *     2 bytes aligned: O.K + *     4 bytes aligned: Invalid + */ + +struct ftmac110_chip { +	void __iomem *regs; +	uint32_t imr; +	uint32_t maccr; +	uint32_t lnkup; +	uint32_t phy_addr; + +	struct ftmac110_rxd *rxd; +	ulong                rxd_dma; +	uint32_t             rxd_idx; + +	struct ftmac110_txd *txd; +	ulong                txd_dma; +	uint32_t             txd_idx; +}; + +static int ftmac110_reset(struct eth_device *dev); + +static uint16_t mdio_read(struct eth_device *dev, +	uint8_t phyaddr, uint8_t phyreg) +{ +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_regs __iomem *regs = chip->regs; +	uint32_t tmp, ts; +	uint16_t ret = 0xffff; + +	tmp = PHYCR_READ +		| (phyaddr << PHYCR_ADDR_SHIFT) +		| (phyreg  << PHYCR_REG_SHIFT); + +	writel(tmp, ®s->phycr); + +	for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) { +		tmp = readl(®s->phycr); +		if (tmp & PHYCR_READ) +			continue; +		break; +	} + +	if (tmp & PHYCR_READ) +		printf("ftmac110: mdio read timeout\n"); +	else +		ret = (uint16_t)(tmp & 0xffff); + +	return ret; +} + +static void mdio_write(struct eth_device *dev, +	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata) +{ +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_regs __iomem *regs = chip->regs; +	uint32_t tmp, ts; + +	tmp = PHYCR_WRITE +		| (phyaddr << PHYCR_ADDR_SHIFT) +		| (phyreg  << PHYCR_REG_SHIFT); + +	writel(phydata, ®s->phydr); +	writel(tmp, ®s->phycr); + +	for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) { +		if (readl(®s->phycr) & PHYCR_WRITE) +			continue; +		break; +	} + +	if (readl(®s->phycr) & PHYCR_WRITE) +		printf("ftmac110: mdio write timeout\n"); +} + +static uint32_t ftmac110_phyqry(struct eth_device *dev) +{ +	ulong ts; +	uint32_t maccr; +	uint16_t pa, tmp, bmsr, bmcr; +	struct ftmac110_chip *chip = dev->priv; + +	/* Default = 100Mbps Full */ +	maccr = MACCR_100M | MACCR_FD; + +	/* 1. find the phy device  */ +	for (pa = 0; pa < 32; ++pa) { +		tmp = mdio_read(dev, pa, MII_PHYSID1); +		if (tmp == 0xFFFF || tmp == 0x0000) +			continue; +		chip->phy_addr = pa; +		break; +	} +	if (pa >= 32) { +		puts("ftmac110: phy device not found!\n"); +		goto exit; +	} + +	/* 2. wait until link-up & auto-negotiation complete */ +	chip->lnkup = 0; +	bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR); +	ts = get_timer(0); +	do { +		bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR); +		chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0; +		if (!chip->lnkup) +			continue; +		if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE)) +			break; +	} while (get_timer(ts) < CFG_LINKUP_TIMEOUT); +	if (!chip->lnkup) { +		puts("ftmac110: link down\n"); +		goto exit; +	} +	if (!(bmcr & BMCR_ANENABLE)) +		puts("ftmac110: auto negotiation disabled\n"); +	else if (!(bmsr & BMSR_ANEGCOMPLETE)) +		puts("ftmac110: auto negotiation timeout\n"); + +	/* 3. derive MACCR */ +	if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) { +		tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE); +		tmp &= mdio_read(dev, chip->phy_addr, MII_LPA); +		if (tmp & LPA_100FULL)      /* 100Mbps full-duplex */ +			maccr = MACCR_100M | MACCR_FD; +		else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */ +			maccr = MACCR_100M; +		else if (tmp & LPA_10FULL)  /* 10Mbps full-duplex */ +			maccr = MACCR_FD; +		else if (tmp & LPA_10HALF)  /* 10Mbps half-duplex */ +			maccr = 0; +	} else { +		if (bmcr & BMCR_SPEED100) +			maccr = MACCR_100M; +		else +			maccr = 0; +		if (bmcr & BMCR_FULLDPLX) +			maccr |= MACCR_FD; +	} + +exit: +	printf("ftmac110: %d Mbps, %s\n", +	       (maccr & MACCR_100M) ? 100 : 10, +	       (maccr & MACCR_FD) ? "Full" : "half"); +	return maccr; +} + +static int ftmac110_reset(struct eth_device *dev) +{ +	uint8_t *a; +	uint32_t i, maccr; +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_regs __iomem *regs = chip->regs; + +	/* 1. MAC reset */ +	writel(MACCR_RESET, ®s->maccr); +	for (i = get_timer(0); get_timer(i) < 1000; ) { +		if (readl(®s->maccr) & MACCR_RESET) +			continue; +		break; +	} +	if (readl(®s->maccr) & MACCR_RESET) { +		printf("ftmac110: reset failed\n"); +		return -ENXIO; +	} + +	/* 1-1. Init tx ring */ +	for (i = 0; i < CFG_TXDES_NUM; ++i) { +		/* owned by SW */ +		chip->txd[i].ct[0] = 0; +	} +	chip->txd_idx = 0; + +	/* 1-2. Init rx ring */ +	for (i = 0; i < CFG_RXDES_NUM; ++i) { +		/* owned by HW */ +		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); +	} +	chip->rxd_idx = 0; + +	/* 2. PHY status query */ +	maccr = ftmac110_phyqry(dev); + +	/* 3. Fix up the MACCR value */ +	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT +		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN; + +	/* 4. MAC address setup */ +	a = dev->enetaddr; +	writel(a[1] | (a[0] << 8), ®s->mac[0]); +	writel(a[5] | (a[4] << 8) | (a[3] << 16) +		| (a[2] << 24), ®s->mac[1]); + +	/* 5. MAC registers setup */ +	writel(chip->rxd_dma, ®s->rxba); +	writel(chip->txd_dma, ®s->txba); +	/* interrupt at each tx/rx */ +	writel(ITC_DEFAULT, ®s->itc); +	/* no tx pool, rx poll = 1 normal cycle */ +	writel(APTC_DEFAULT, ®s->aptc); +	/* rx threshold = [6/8 fifo, 2/8 fifo] */ +	writel(DBLAC_DEFAULT, ®s->dblac); +	/* disable & clear all interrupt status */ +	chip->imr = 0; +	writel(ISR_ALL, ®s->isr); +	writel(chip->imr, ®s->imr); +	/* enable mac */ +	writel(chip->maccr, ®s->maccr); + +	return 0; +} + +static int ftmac110_probe(struct eth_device *dev, bd_t *bis) +{ +	debug("ftmac110: probe\n"); + +	if (ftmac110_reset(dev)) +		return -1; + +	return 0; +} + +static void ftmac110_halt(struct eth_device *dev) +{ +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_regs __iomem *regs = chip->regs; + +	writel(0, ®s->imr); +	writel(0, ®s->maccr); + +	debug("ftmac110: halt\n"); +} + +static int ftmac110_send(struct eth_device *dev, void *pkt, int len) +{ +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_regs __iomem *regs = chip->regs; +	struct ftmac110_txd *des; + +	if (!chip->lnkup) +		return 0; + +	if (len <= 0 || len > CFG_XBUF_SIZE) { +		printf("ftmac110: bad tx pkt len(%d)\n", len); +		return 0; +	} + +	len = max(60, len); + +	des = &chip->txd[chip->txd_idx]; +	if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) { +		/* kick-off Tx DMA */ +		writel(0xffffffff, ®s->txpd); +		printf("ftmac110: out of txd\n"); +		return 0; +	} + +	memcpy(des->vbuf, (void *)pkt, len); +	dma_map_single(des->vbuf, len, DMA_TO_DEVICE); + +	/* update len, fts and lts */ +	des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END); +	des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len) +		| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS); + +	/* set owner bit and clear others */ +	des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER); + +	/* kick-off Tx DMA */ +	writel(0xffffffff, ®s->txpd); + +	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM; + +	return len; +} + +static int ftmac110_recv(struct eth_device *dev) +{ +	struct ftmac110_chip *chip = dev->priv; +	struct ftmac110_rxd *des; +	uint32_t ct0, len, rlen = 0; +	uint8_t *buf; + +	if (!chip->lnkup) +		return 0; + +	do { +		des = &chip->rxd[chip->rxd_idx]; +		ct0 = le32_to_cpu(des->ct[0]); +		if (ct0 & FTMAC110_RXCT0_OWNER) +			break; + +		len = FTMAC110_RXCT0_LEN(ct0); +		buf = des->vbuf; + +		if (ct0 & FTMAC110_RXCT0_ERRMASK) { +			printf("ftmac110: rx error\n"); +		} else { +			dma_map_single(buf, len, DMA_FROM_DEVICE); +			NetReceive(buf, len); +			rlen += len; +		} + +		/* owned by hardware */ +		des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); + +		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM; +	} while (0); + +	return rlen; +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + +static int ftmac110_mdio_read( +	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value) +{ +	int ret = 0; +	struct eth_device *dev; + +	dev = eth_get_dev_by_name(devname); +	if (dev == NULL) { +		printf("%s: no such device\n", devname); +		ret = -1; +	} else { +		*value = mdio_read(dev, addr, reg); +	} + +	return ret; +} + +static int ftmac110_mdio_write( +	const char *devname, uint8_t addr, uint8_t reg, uint16_t value) +{ +	int ret = 0; +	struct eth_device *dev; + +	dev = eth_get_dev_by_name(devname); +	if (dev == NULL) { +		printf("%s: no such device\n", devname); +		ret = -1; +	} else { +		mdio_write(dev, addr, reg, value); +	} + +	return ret; +} + +#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */ + +int ftmac110_initialize(bd_t *bis) +{ +	int i, card_nr = 0; +	struct eth_device *dev; +	struct ftmac110_chip *chip; + +	dev = malloc(sizeof(*dev) + sizeof(*chip)); +	if (dev == NULL) { +		panic("ftmac110: out of memory 1\n"); +		return -1; +	} +	chip = (struct ftmac110_chip *)(dev + 1); +	memset(dev, 0, sizeof(*dev) + sizeof(*chip)); + +	sprintf(dev->name, "FTMAC110#%d", card_nr); + +	dev->iobase = CONFIG_FTMAC110_BASE; +	chip->regs = (void __iomem *)dev->iobase; +	dev->priv = chip; +	dev->init = ftmac110_probe; +	dev->halt = ftmac110_halt; +	dev->send = ftmac110_send; +	dev->recv = ftmac110_recv; + +	if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr)) +		eth_random_enetaddr(dev->enetaddr); + +	/* allocate tx descriptors (it must be 16 bytes aligned) */ +	chip->txd = dma_alloc_coherent( +		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma); +	if (!chip->txd) +		panic("ftmac110: out of memory 3\n"); +	memset(chip->txd, 0, +	       sizeof(struct ftmac110_txd) * CFG_TXDES_NUM); +	for (i = 0; i < CFG_TXDES_NUM; ++i) { +		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); +		if (!va) +			panic("ftmac110: out of memory 4\n"); +		chip->txd[i].vbuf  = va; +		chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va)); +		chip->txd[i].ct[1] = 0; +		chip->txd[i].ct[0] = 0; /* owned by SW */ +	} +	chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END); +	chip->txd_idx = 0; + +	/* allocate rx descriptors (it must be 16 bytes aligned) */ +	chip->rxd = dma_alloc_coherent( +		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma); +	if (!chip->rxd) +		panic("ftmac110: out of memory 4\n"); +	memset((void *)chip->rxd, 0, +	       sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM); +	for (i = 0; i < CFG_RXDES_NUM; ++i) { +		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2); +		if (!va) +			panic("ftmac110: out of memory 5\n"); +		/* it needs to be exactly 2 bytes aligned */ +		va = ((uint8_t *)va + 2); +		chip->rxd[i].vbuf  = va; +		chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va)); +		chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE); +		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); +	} +	chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END); +	chip->rxd_idx = 0; + +	eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write); +#endif + +	card_nr++; + +	return card_nr; +} diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h new file mode 100644 index 000000000..5b2d23b0d --- /dev/null +++ b/drivers/net/ftmac110.h @@ -0,0 +1,177 @@ +/* + * Faraday 10/100Mbps Ethernet Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef _FTMAC110_H +#define _FTMAC110_H + +struct ftmac110_regs { +	uint32_t isr;    /* 0x00: Interrups Status Register */ +	uint32_t imr;    /* 0x04: Interrupt Mask Register */ +	uint32_t mac[2]; /* 0x08: MAC Address */ +	uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */ +	uint32_t txpd;   /* 0x18: Tx Poll Demand Register */ +	uint32_t rxpd;   /* 0x1c: Rx Poll Demand Register */ +	uint32_t txba;   /* 0x20: Tx Ring Base Address Register */ +	uint32_t rxba;   /* 0x24: Rx Ring Base Address Register */ +	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */ +	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */ +	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */ +	uint32_t revr;   /* 0x34: Revision Register */ +	uint32_t fear;   /* 0x38: Feature Register */ +	uint32_t rsvd[19]; +	uint32_t maccr;  /* 0x88: MAC Control Register */ +	uint32_t macsr;  /* 0x8C: MAC Status Register */ +	uint32_t phycr;  /* 0x90: PHY Control Register */ +	uint32_t phydr;  /* 0x94: PHY Data Register */ +	uint32_t fcr;    /* 0x98: Flow Control Register */ +	uint32_t bpr;    /* 0x9C: Back Pressure Register */ +}; + +/* + * Interrupt status/mask register(ISR/IMR) bits + */ +#define ISR_ALL          0x3ff +#define ISR_PHYSTCHG     (1 << 9) /* phy status change */ +#define ISR_AHBERR       (1 << 8) /* bus error */ +#define ISR_RXLOST       (1 << 7) /* rx lost */ +#define ISR_RXFIFO       (1 << 6) /* rx to fifo */ +#define ISR_TXLOST       (1 << 5) /* tx lost */ +#define ISR_TXOK         (1 << 4) /* tx to ethernet */ +#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */ +#define ISR_TXFIFO       (1 << 2) /* tx to fifo */ +#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */ +#define ISR_RXOK         (1 << 0) /* rx to buffer */ + +/* + * MACCR control bits + */ +#define MACCR_100M       (1 << 18) /* 100Mbps mode */ +#define MACCR_RXBCST     (1 << 17) /* rx broadcast packet */ +#define MACCR_RXMCST     (1 << 16) /* rx multicast packet */ +#define MACCR_FD         (1 << 15) /* full duplex */ +#define MACCR_CRCAPD     (1 << 14) /* tx crc append */ +#define MACCR_RXALL      (1 << 12) /* rx all packets */ +#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */ +#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */ +#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast hash table */ +#define MACCR_RXEN       (1 << 8)  /* rx enable */ +#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */ +#define MACCR_TXEN       (1 << 5)  /* tx enable */ +#define MACCR_CRCDIS     (1 << 4)  /* tx packet even it's crc error */ +#define MACCR_LOOPBACK   (1 << 3)  /* loop-back */ +#define MACCR_RESET      (1 << 2)  /* reset */ +#define MACCR_RXDMAEN    (1 << 1)  /* rx dma enable */ +#define MACCR_TXDMAEN    (1 << 0)  /* tx dma enable */ + +/* + * PHYCR control bits + */ +#define PHYCR_READ       (1 << 26) +#define PHYCR_WRITE      (1 << 27) +#define PHYCR_REG_SHIFT  21 +#define PHYCR_ADDR_SHIFT 16 + +/* + * ITC control bits + */ + +/* Tx Cycle Length */ +#define ITC_TX_CYCLONG   (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define ITC_TX_CYCNORM   (0 << 15) /* 100Mbps=5.12us;  10Mbps=51.2us */ +/* Tx Threshold: Aggregate n interrupts as 1 interrupt */ +#define ITC_TX_THR(n)    (((n) & 0x7) << 12) +/* Tx Interrupt Timeout = n * Tx Cycle */ +#define ITC_TX_ITMO(n)   (((n) & 0xf) << 8) +/* Rx Cycle Length */ +#define ITC_RX_CYCLONG   (1 << 7)  /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define ITC_RX_CYCNORM   (0 << 7)  /* 100Mbps=5.12us;  10Mbps=51.2us */ +/* Rx Threshold: Aggregate n interrupts as 1 interrupt */ +#define ITC_RX_THR(n)    (((n) & 0x7) << 4) +/* Rx Interrupt Timeout = n * Rx Cycle */ +#define ITC_RX_ITMO(n)   (((n) & 0xf) << 0) + +#define ITC_DEFAULT \ +	(ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0)) + +/* + * APTC contrl bits + */ + +/* Tx Cycle Length */ +#define APTC_TX_CYCLONG  (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define APTC_TX_CYCNORM  (0 << 12) /* 100Mbps=5.12us;  10Mbps=51.2us */ +/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */ +#define APTC_TX_PTMO(n)  (((n) & 0xf) << 8) +/* Rx Cycle Length */ +#define APTC_RX_CYCLONG  (1 << 4)  /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define APTC_RX_CYCNORM  (0 << 4)  /* 100Mbps=5.12us;  10Mbps=51.2us */ +/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */ +#define APTC_RX_PTMO(n)  (((n) & 0xf) << 0) + +#define APTC_DEFAULT     (APTC_TX_PTMO(0) | APTC_RX_PTMO(1)) + +/* + * DBLAC contrl bits + */ +#define DBLAC_BURST_MAX_ANY  (0 << 14) /* un-limited */ +#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */ +#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */ +#define DBLAC_RXTHR_EN       (1 << 9)  /* enable rx threshold arbitration */ +#define DBLAC_RXTHR_HIGH(n)  (((n) & 0x7) << 6) /* upper bound = n/8 fifo */ +#define DBLAC_RXTHR_LOW(n)   (((n) & 0x7) << 3) /* lower bound = n/8 fifo */ +#define DBLAC_BURST_CAP16    (1 << 2)  /* support burst 16 */ +#define DBLAC_BURST_CAP8     (1 << 1)  /* support burst 8 */ +#define DBLAC_BURST_CAP4     (1 << 0)  /* support burst 4 */ + +#define DBLAC_DEFAULT \ +	(DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2)) + +/* + * descriptor structure + */ +struct ftmac110_rxd { +	uint32_t ct[2]; +	uint32_t buf; +	void    *vbuf; /* reserved */ +}; + +#define FTMAC110_RXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */ +#define FTMAC110_RXCT0_FRS         BIT_MASK(29) /* first pkt desc */ +#define FTMAC110_RXCT0_LRS         BIT_MASK(28) /* last pkt desc */ +#define FTMAC110_RXCT0_ODDNB       BIT_MASK(22) /* odd nibble */ +#define FTMAC110_RXCT0_RUNT        BIT_MASK(21) /* runt pkt */ +#define FTMAC110_RXCT0_FTL         BIT_MASK(20) /* frame too long */ +#define FTMAC110_RXCT0_CRC         BIT_MASK(19) /* pkt crc error */ +#define FTMAC110_RXCT0_ERR         BIT_MASK(18) /* bus error */ +#define FTMAC110_RXCT0_ERRMASK     (0x1f << 18) /* all errors */ +#define FTMAC110_RXCT0_BCST        BIT_MASK(17) /* Bcst pkt */ +#define FTMAC110_RXCT0_MCST        BIT_MASK(16) /* Mcst pkt */ +#define FTMAC110_RXCT0_LEN(x)      ((x) & 0x7ff) + +#define FTMAC110_RXCT1_END         BIT_MASK(31) +#define FTMAC110_RXCT1_BUFSZ(x)    ((x) & 0x7ff) + +struct ftmac110_txd { +	uint32_t ct[2]; +	uint32_t buf; +	void    *vbuf; /* reserved */ +}; + +#define FTMAC110_TXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */ +#define FTMAC110_TXCT0_COL         0x00000003   /* collision */ + +#define FTMAC110_TXCT1_END         BIT_MASK(31) /* end of ring */ +#define FTMAC110_TXCT1_TXIC        BIT_MASK(30) /* tx done interrupt */ +#define FTMAC110_TXCT1_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */ +#define FTMAC110_TXCT1_FTS         BIT_MASK(28) /* first pkt desc */ +#define FTMAC110_TXCT1_LTS         BIT_MASK(27) /* last pkt desc */ +#define FTMAC110_TXCT1_LEN(x)      ((x) & 0x7ff) + +#endif  /* FTMAC110_H */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c new file mode 100644 index 000000000..b02d59a1b --- /dev/null +++ b/drivers/net/ks8851_mll.c @@ -0,0 +1,645 @@ +/* + * Micrel KS8851_MLL 16bit Network driver + * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/io.h> +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> + +#include "ks8851_mll.h" + +#define DRIVERNAME			"ks8851_mll" + +#define MAX_RECV_FRAMES			32 +#define MAX_BUF_SIZE			2048 +#define TX_BUF_SIZE			2000 +#define RX_BUF_SIZE			2000 + +static const struct chip_id chip_ids[] =  { +	{CIDER_ID, "KSZ8851"}, +	{0, NULL}, +}; + +/* + * union ks_tx_hdr - tx header data + * @txb: The header as bytes + * @txw: The header as 16bit, little-endian words + * + * A dual representation of the tx header data to allow + * access to individual bytes, and to allow 16bit accesses + * with 16bit alignment. + */ +union ks_tx_hdr { +	u8      txb[4]; +	__le16  txw[2]; +}; + +/* + * struct ks_net - KS8851 driver private data + * @net_device	: The network device we're bound to + * @txh		: temporaly buffer to save status/length. + * @frame_head_info	: frame header information for multi-pkt rx. + * @statelock	: Lock on this structure for tx list. + * @msg_enable	: The message flags controlling driver output (see ethtool). + * @frame_cnt	: number of frames received. + * @bus_width	: i/o bus width. + * @irq		: irq number assigned to this device. + * @rc_rxqcr	: Cached copy of KS_RXQCR. + * @rc_txcr	: Cached copy of KS_TXCR. + * @rc_ier	: Cached copy of KS_IER. + * @sharedbus	: Multipex(addr and data bus) mode indicator. + * @cmd_reg_cache	: command register cached. + * @cmd_reg_cache_int	: command register cached. Used in the irq handler. + * @promiscuous	: promiscuous mode indicator. + * @all_mcast	: mutlicast indicator. + * @mcast_lst_size	: size of multicast list. + * @mcast_lst		: multicast list. + * @mcast_bits		: multicast enabed. + * @mac_addr		: MAC address assigned to this device. + * @fid			: frame id. + * @extra_byte		: number of extra byte prepended rx pkt. + * @enabled		: indicator this device works. + */ + +/* Receive multiplex framer header info */ +struct type_frame_head { +	u16	sts;         /* Frame status */ +	u16	len;         /* Byte count */ +} fr_h_i[MAX_RECV_FRAMES]; + +struct ks_net { +	struct net_device	*netdev; +	union ks_tx_hdr		txh; +	struct type_frame_head	*frame_head_info; +	u32			msg_enable; +	u32			frame_cnt; +	int			bus_width; +	int			irq; +	u16			rc_rxqcr; +	u16			rc_txcr; +	u16			rc_ier; +	u16			sharedbus; +	u16			cmd_reg_cache; +	u16			cmd_reg_cache_int; +	u16			promiscuous; +	u16			all_mcast; +	u16			mcast_lst_size; +	u8			mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN]; +	u8			mcast_bits[HW_MCAST_SIZE]; +	u8			mac_addr[6]; +	u8                      fid; +	u8			extra_byte; +	u8			enabled; +} ks_str, *ks; + +#define BE3             0x8000      /* Byte Enable 3 */ +#define BE2             0x4000      /* Byte Enable 2 */ +#define BE1             0x2000      /* Byte Enable 1 */ +#define BE0             0x1000      /* Byte Enable 0 */ + +static u8 ks_rdreg8(struct eth_device *dev, u16 offset) +{ +	u8 shift_bit = offset & 0x03; +	u8 shift_data = (offset & 1) << 3; + +	writew(offset | (BE0 << shift_bit), dev->iobase + 2); + +	return (u8)(readw(dev->iobase) >> shift_data); +} + +static u16 ks_rdreg16(struct eth_device *dev, u16 offset) +{ +	writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); + +	return readw(dev->iobase); +} + +static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val) +{ +	u8 shift_bit = (offset & 0x03); +	u16 value_write = (u16)(val << ((offset & 1) << 3)); + +	writew(offset | (BE0 << shift_bit), dev->iobase + 2); +	writew(value_write, dev->iobase); +} + +static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val) +{ +	writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); +	writew(val, dev->iobase); +} + +/* + * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode + * enabled. + * @ks: The chip state + * @wptr: buffer address to save data + * @len: length in byte to read + */ +static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len) +{ +	len >>= 1; + +	while (len--) +		*wptr++ = readw(dev->iobase); +} + +/* + * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled. + * @ks: The chip information + * @wptr: buffer address + * @len: length in byte to write + */ +static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len) +{ +	len >>= 1; + +	while (len--) +		writew(*wptr++, dev->iobase); +} + +static void ks_enable_int(struct eth_device *dev) +{ +	ks_wrreg16(dev, KS_IER, ks->rc_ier); +} + +static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode) +{ +	unsigned pmecr; + +	ks_rdreg16(dev, KS_GRR); +	pmecr = ks_rdreg16(dev, KS_PMECR); +	pmecr &= ~PMECR_PM_MASK; +	pmecr |= pwrmode; + +	ks_wrreg16(dev, KS_PMECR, pmecr); +} + +/* + * ks_read_config - read chip configuration of bus width. + * @ks: The chip information + */ +static void ks_read_config(struct eth_device *dev) +{ +	u16 reg_data = 0; + +	/* Regardless of bus width, 8 bit read should always work. */ +	reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF; +	reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8; + +	/* addr/data bus are multiplexed */ +	ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED; + +	/* +	 * There are garbage data when reading data from QMU, +	 * depending on bus-width. +	 */ +	if (reg_data & CCR_8BIT) { +		ks->bus_width = ENUM_BUS_8BIT; +		ks->extra_byte = 1; +	} else if (reg_data & CCR_16BIT) { +		ks->bus_width = ENUM_BUS_16BIT; +		ks->extra_byte = 2; +	} else { +		ks->bus_width = ENUM_BUS_32BIT; +		ks->extra_byte = 4; +	} +} + +/* + * ks_soft_reset - issue one of the soft reset to the device + * @ks: The device state. + * @op: The bit(s) to set in the GRR + * + * Issue the relevant soft-reset command to the device's GRR register + * specified by @op. + * + * Note, the delays are in there as a caution to ensure that the reset + * has time to take effect and then complete. Since the datasheet does + * not currently specify the exact sequence, we have chosen something + * that seems to work with our device. + */ +static void ks_soft_reset(struct eth_device *dev, unsigned op) +{ +	/* Disable interrupt first */ +	ks_wrreg16(dev, KS_IER, 0x0000); +	ks_wrreg16(dev, KS_GRR, op); +	mdelay(10);	/* wait a short time to effect reset */ +	ks_wrreg16(dev, KS_GRR, 0); +	mdelay(1);	/* wait for condition to clear */ +} + +void ks_enable_qmu(struct eth_device *dev) +{ +	u16 w; + +	w = ks_rdreg16(dev, KS_TXCR); + +	/* Enables QMU Transmit (TXCR). */ +	ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE); + +	/* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */ +	w = ks_rdreg16(dev, KS_RXQCR); +	ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE); + +	/* Enables QMU Receive (RXCR1). */ +	w = ks_rdreg16(dev, KS_RXCR1); +	ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE); +} + +static void ks_disable_qmu(struct eth_device *dev) +{ +	u16 w; + +	w = ks_rdreg16(dev, KS_TXCR); + +	/* Disables QMU Transmit (TXCR). */ +	w &= ~TXCR_TXE; +	ks_wrreg16(dev, KS_TXCR, w); + +	/* Disables QMU Receive (RXCR1). */ +	w = ks_rdreg16(dev, KS_RXCR1); +	w &= ~RXCR1_RXE; +	ks_wrreg16(dev, KS_RXCR1, w); +} + +static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) +{ +	u32 r = ks->extra_byte & 0x1; +	u32 w = ks->extra_byte - r; + +	/* 1. set sudo DMA mode */ +	ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); +	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + +	/* +	 * 2. read prepend data +	 * +	 * read 4 + extra bytes and discard them. +	 * extra bytes for dummy, 2 for status, 2 for len +	 */ + +	if (r) +		ks_rdreg8(dev, 0); + +	ks_inblk(dev, buf, w + 2 + 2); + +	/* 3. read pkt data */ +	ks_inblk(dev, buf, ALIGN(len, 4)); + +	/* 4. reset sudo DMA Mode */ +	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); +} + +static void ks_rcv(struct eth_device *dev, uchar **pv_data) +{ +	struct type_frame_head *frame_hdr = ks->frame_head_info; +	int i; + +	ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; + +	/* read all header information */ +	for (i = 0; i < ks->frame_cnt; i++) { +		/* Checking Received packet status */ +		frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR); +		/* Get packet len from hardware */ +		frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR); +		frame_hdr++; +	} + +	frame_hdr = ks->frame_head_info; +	while (ks->frame_cnt--) { +		if ((frame_hdr->sts & RXFSHR_RXFV) && +		    (frame_hdr->len < RX_BUF_SIZE) && +		    frame_hdr->len) { +			/* read data block including CRC 4 bytes */ +			ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len); + +			/* NetRxPackets buffer size is ok (*pv_data pointer) */ +			NetReceive(*pv_data, frame_hdr->len); +			pv_data++; +		} else { +			ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF)); +			printf(DRIVERNAME ": bad packet\n"); +		} +		frame_hdr++; +	} +} + +/* + * ks_read_selftest - read the selftest memory info. + * @ks: The device state + * + * Read and check the TX/RX memory selftest information. + */ +static int ks_read_selftest(struct eth_device *dev) +{ +	u16 both_done = MBIR_TXMBF | MBIR_RXMBF; +	u16 mbir; +	int ret = 0; + +	mbir = ks_rdreg16(dev, KS_MBIR); + +	if ((mbir & both_done) != both_done) { +		printf(DRIVERNAME ": Memory selftest not finished\n"); +		return 0; +	} + +	if (mbir & MBIR_TXMBFA) { +		printf(DRIVERNAME ": TX memory selftest fails\n"); +		ret |= 1; +	} + +	if (mbir & MBIR_RXMBFA) { +		printf(DRIVERNAME ": RX memory selftest fails\n"); +		ret |= 2; +	} + +	debug(DRIVERNAME ": the selftest passes\n"); + +	return ret; +} + +static void ks_setup(struct eth_device *dev) +{ +	u16 w; + +	/* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */ +	ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); + +	/* Setup Receive Frame Data Pointer Auto-Increment */ +	ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); + +	/* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */ +	ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); + +	/* Setup RxQ Command Control (RXQCR) */ +	ks->rc_rxqcr = RXQCR_CMD_CNTL; +	ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr); + +	/* +	 * set the force mode to half duplex, default is full duplex +	 * because if the auto-negotiation fails, most switch uses +	 * half-duplex. +	 */ +	w = ks_rdreg16(dev, KS_P1MBCR); +	w &= ~P1MBCR_FORCE_FDX; +	ks_wrreg16(dev, KS_P1MBCR, w); + +	w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP; +	ks_wrreg16(dev, KS_TXCR, w); + +	w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC; + +	/* Normal mode */ +	w |= RXCR1_RXPAFMA; + +	ks_wrreg16(dev, KS_RXCR1, w); +} + +static void ks_setup_int(struct eth_device *dev) +{ +	ks->rc_ier = 0x00; + +	/* Clear the interrupts status of the hardware. */ +	ks_wrreg16(dev, KS_ISR, 0xffff); + +	/* Enables the interrupts of the hardware. */ +	ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI); +} + +static int ks8851_mll_detect_chip(struct eth_device *dev) +{ +	unsigned short val, i; + +	ks_read_config(dev); + +	val = ks_rdreg16(dev, KS_CIDER); + +	if (val == 0xffff) { +		/* Special case -- no chip present */ +		printf(DRIVERNAME ":  is chip mounted ?\n"); +		return -1; +	} else if ((val & 0xfff0) != CIDER_ID) { +		printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val); +		return -1; +	} + +	debug("Read back KS8851 id 0x%x\n", val); + +	/* only one entry in the table */ +	val &= 0xfff0; +	for (i = 0; chip_ids[i].id != 0; i++) { +		if (chip_ids[i].id == val) +			break; +	} +	if (!chip_ids[i].id) { +		printf(DRIVERNAME ": Unknown chip ID %04x\n", val); +		return -1; +	} + +	dev->priv = (void *)&chip_ids[i]; + +	return 0; +} + +static void ks8851_mll_reset(struct eth_device *dev) +{ +	/* wake up powermode to normal mode */ +	ks_set_powermode(dev, PMECR_PM_NORMAL); +	mdelay(1);	/* wait for normal mode to take effect */ + +	/* Disable interrupt and reset */ +	ks_soft_reset(dev, GRR_GSR); + +	/* turn off the IRQs and ack any outstanding */ +	ks_wrreg16(dev, KS_IER, 0x0000); +	ks_wrreg16(dev, KS_ISR, 0xffff); + +	/* shutdown RX/TX QMU */ +	ks_disable_qmu(dev); +} + +static void ks8851_mll_phy_configure(struct eth_device *dev) +{ +	u16 data; + +	ks_setup(dev); +	ks_setup_int(dev); + +	/* Probing the phy */ +	data = ks_rdreg16(dev, KS_OBCR); +	ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA); + +	debug(DRIVERNAME ": phy initialized\n"); +} + +static void ks8851_mll_enable(struct eth_device *dev) +{ +	ks_wrreg16(dev, KS_ISR, 0xffff); +	ks_enable_int(dev); +	ks_enable_qmu(dev); +} + +static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) +{ +	struct chip_id *id = dev->priv; + +	debug(DRIVERNAME ": detected %s controller\n", id->name); + +	if (ks_read_selftest(dev)) { +		printf(DRIVERNAME ": Selftest failed\n"); +		return -1; +	} + +	ks8851_mll_reset(dev); + +	/* Configure the PHY, initialize the link state */ +	ks8851_mll_phy_configure(dev); + +	/* static allocation of private informations */ +	ks->frame_head_info = fr_h_i; + +	/* Turn on Tx + Rx */ +	ks8851_mll_enable(dev); + +	return 0; +} + +static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) +{ +	/* start header at txb[0] to align txw entries */ +	ks->txh.txw[0] = 0; +	ks->txh.txw[1] = cpu_to_le16(len); + +	/* 1. set sudo-DMA mode */ +	ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); +	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); +	/* 2. write status/lenth info */ +	ks_outblk(dev, ks->txh.txw, 4); +	/* 3. write pkt data */ +	ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); +	/* 4. reset sudo-DMA mode */ +	ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); +	/* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ +	ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE); +	/* 6. wait until TXQCR_METFE is auto-cleared */ +	do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE); +} + +static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) +{ +	u8 *data = (u8 *)packet; +	u16 tmplen = (u16)length; +	u16 retv; + +	/* +	 * Extra space are required: +	 * 4 byte for alignment, 4 for status/length, 4 for CRC +	 */ +	retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff; +	if (retv >= tmplen + 12) { +		ks_write_qmu(dev, data, tmplen); +		return 0; +	} else { +		printf(DRIVERNAME ": failed to send packet: No buffer\n"); +		return -1; +	} +} + +static void ks8851_mll_halt(struct eth_device *dev) +{ +	ks8851_mll_reset(dev); +} + +/* + * Maximum receive ring size; that is, the number of packets + * we can buffer before overflow happens. Basically, this just + * needs to be enough to prevent a packet being discarded while + * we are processing the previous one. + */ +static int ks8851_mll_recv(struct eth_device *dev) +{ +	u16 status; + +	status = ks_rdreg16(dev, KS_ISR); + +	ks_wrreg16(dev, KS_ISR, status); + +	if ((status & IRQ_RXI)) +		ks_rcv(dev, (uchar **)NetRxPackets); + +	if ((status & IRQ_LDI)) { +		u16 pmecr = ks_rdreg16(dev, KS_PMECR); +		pmecr &= ~PMECR_WKEVT_MASK; +		ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK); +	} + +	return 0; +} + +static int ks8851_mll_write_hwaddr(struct eth_device *dev) +{ +	u16 addrl, addrm, addrh; + +	addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1]; +	addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3]; +	addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5]; + +	ks_wrreg16(dev, KS_MARH, addrh); +	ks_wrreg16(dev, KS_MARM, addrm); +	ks_wrreg16(dev, KS_MARL, addrl); + +	return 0; +} + +int ks8851_mll_initialize(u8 dev_num, int base_addr) +{ +	struct eth_device *dev; + +	dev = malloc(sizeof(*dev)); +	if (!dev) { +		printf("Error: Failed to allocate memory\n"); +		return -1; +	} +	memset(dev, 0, sizeof(*dev)); + +	dev->iobase = base_addr; + +	ks = &ks_str; + +	/* Try to detect chip. Will fail if not present. */ +	if (ks8851_mll_detect_chip(dev)) { +		free(dev); +		return -1; +	} + +	dev->init = ks8851_mll_init; +	dev->halt = ks8851_mll_halt; +	dev->send = ks8851_mll_send; +	dev->recv = ks8851_mll_recv; +	dev->write_hwaddr = ks8851_mll_write_hwaddr; +	sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); + +	eth_register(dev); + +	return 0; +} diff --git a/drivers/net/ks8851_mll.h b/drivers/net/ks8851_mll.h new file mode 100644 index 000000000..7f90ae4e5 --- /dev/null +++ b/drivers/net/ks8851_mll.h @@ -0,0 +1,357 @@ +/* + * drivers/net/ks8851_mll.c + * + * Supports: + * KS8851 16bit MLL chip from Micrel Inc. + * + * Copyright (c) 2009 Micrel Inc. + * + * modified by + * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _KS8851_MLL_H_ +#define _KS8851_MLL_H_ + +#include <linux/types.h> + +#define KS_CCR				0x08 +#define CCR_EEPROM			(1 << 9) +#define CCR_SPI				(1 << 8) +#define CCR_8BIT			(1 << 7) +#define CCR_16BIT			(1 << 6) +#define CCR_32BIT			(1 << 5) +#define CCR_SHARED			(1 << 4) +#define CCR_32PIN			(1 << 0) + +/* MAC address registers */ +#define KS_MARL				0x10 +#define KS_MARM				0x12 +#define KS_MARH				0x14 + +#define KS_OBCR				0x20 +#define OBCR_ODS_16MA			(1 << 6) + +#define KS_EEPCR			0x22 +#define EEPCR_EESA			(1 << 4) +#define EEPCR_EESB			(1 << 3) +#define EEPCR_EEDO			(1 << 2) +#define EEPCR_EESCK			(1 << 1) +#define EEPCR_EECS			(1 << 0) + +#define KS_MBIR				0x24 +#define MBIR_TXMBF			(1 << 12) +#define MBIR_TXMBFA			(1 << 11) +#define MBIR_RXMBF			(1 << 4) +#define MBIR_RXMBFA			(1 << 3) + +#define KS_GRR				0x26 +#define GRR_QMU				(1 << 1) +#define GRR_GSR				(1 << 0) + +#define KS_WFCR				0x2A +#define WFCR_MPRXE			(1 << 7) +#define WFCR_WF3E			(1 << 3) +#define WFCR_WF2E			(1 << 2) +#define WFCR_WF1E			(1 << 1) +#define WFCR_WF0E			(1 << 0) + +#define KS_WF0CRC0			0x30 +#define KS_WF0CRC1			0x32 +#define KS_WF0BM0			0x34 +#define KS_WF0BM1			0x36 +#define KS_WF0BM2			0x38 +#define KS_WF0BM3			0x3A + +#define KS_WF1CRC0			0x40 +#define KS_WF1CRC1			0x42 +#define KS_WF1BM0			0x44 +#define KS_WF1BM1			0x46 +#define KS_WF1BM2			0x48 +#define KS_WF1BM3			0x4A + +#define KS_WF2CRC0			0x50 +#define KS_WF2CRC1			0x52 +#define KS_WF2BM0			0x54 +#define KS_WF2BM1			0x56 +#define KS_WF2BM2			0x58 +#define KS_WF2BM3			0x5A + +#define KS_WF3CRC0			0x60 +#define KS_WF3CRC1			0x62 +#define KS_WF3BM0			0x64 +#define KS_WF3BM1			0x66 +#define KS_WF3BM2			0x68 +#define KS_WF3BM3			0x6A + +#define KS_TXCR				0x70 +#define TXCR_TCGICMP			(1 << 8) +#define TXCR_TCGUDP			(1 << 7) +#define TXCR_TCGTCP			(1 << 6) +#define TXCR_TCGIP			(1 << 5) +#define TXCR_FTXQ			(1 << 4) +#define TXCR_TXFCE			(1 << 3) +#define TXCR_TXPE			(1 << 2) +#define TXCR_TXCRC			(1 << 1) +#define TXCR_TXE			(1 << 0) + +#define KS_TXSR				0x72 +#define TXSR_TXLC			(1 << 13) +#define TXSR_TXMC			(1 << 12) +#define TXSR_TXFID_MASK			(0x3f << 0) +#define TXSR_TXFID_SHIFT		(0) +#define TXSR_TXFID_GET(_v)		(((_v) >> 0) & 0x3f) + + +#define KS_RXCR1			0x74 +#define RXCR1_FRXQ			(1 << 15) +#define RXCR1_RXUDPFCC			(1 << 14) +#define RXCR1_RXTCPFCC			(1 << 13) +#define RXCR1_RXIPFCC			(1 << 12) +#define RXCR1_RXPAFMA			(1 << 11) +#define RXCR1_RXFCE			(1 << 10) +#define RXCR1_RXEFE			(1 << 9) +#define RXCR1_RXMAFMA			(1 << 8) +#define RXCR1_RXBE			(1 << 7) +#define RXCR1_RXME			(1 << 6) +#define RXCR1_RXUE			(1 << 5) +#define RXCR1_RXAE			(1 << 4) +#define RXCR1_RXINVF			(1 << 1) +#define RXCR1_RXE			(1 << 0) +#define RXCR1_FILTER_MASK		(RXCR1_RXINVF | RXCR1_RXAE | \ +					 RXCR1_RXMAFMA | RXCR1_RXPAFMA) + +#define KS_RXCR2			0x76 +#define RXCR2_SRDBL_MASK		(0x7 << 5) +#define RXCR2_SRDBL_SHIFT		(5) +#define RXCR2_SRDBL_4B			(0x0 << 5) +#define RXCR2_SRDBL_8B			(0x1 << 5) +#define RXCR2_SRDBL_16B			(0x2 << 5) +#define RXCR2_SRDBL_32B			(0x3 << 5) +/* #define RXCR2_SRDBL_FRAME		(0x4 << 5) */ +#define RXCR2_IUFFP			(1 << 4) +#define RXCR2_RXIUFCEZ			(1 << 3) +#define RXCR2_UDPLFE			(1 << 2) +#define RXCR2_RXICMPFCC			(1 << 1) +#define RXCR2_RXSAF			(1 << 0) + +#define KS_TXMIR			0x78 + +#define KS_RXFHSR			0x7C +#define RXFSHR_RXFV			(1 << 15) +#define RXFSHR_RXICMPFCS		(1 << 13) +#define RXFSHR_RXIPFCS			(1 << 12) +#define RXFSHR_RXTCPFCS			(1 << 11) +#define RXFSHR_RXUDPFCS			(1 << 10) +#define RXFSHR_RXBF			(1 << 7) +#define RXFSHR_RXMF			(1 << 6) +#define RXFSHR_RXUF			(1 << 5) +#define RXFSHR_RXMR			(1 << 4) +#define RXFSHR_RXFT			(1 << 3) +#define RXFSHR_RXFTL			(1 << 2) +#define RXFSHR_RXRF			(1 << 1) +#define RXFSHR_RXCE			(1 << 0) +#define RXFSHR_ERR			(RXFSHR_RXCE | RXFSHR_RXRF |\ +					RXFSHR_RXFTL | RXFSHR_RXMR |\ +					RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\ +					RXFSHR_RXTCPFCS) +#define KS_RXFHBCR			0x7E +#define RXFHBCR_CNT_MASK		0x0FFF + +#define KS_TXQCR			0x80 +#define TXQCR_AETFE			(1 << 2) +#define TXQCR_TXQMAM			(1 << 1) +#define TXQCR_METFE			(1 << 0) + +#define KS_RXQCR			0x82 +#define RXQCR_RXDTTS			(1 << 12) +#define RXQCR_RXDBCTS			(1 << 11) +#define RXQCR_RXFCTS			(1 << 10) +#define RXQCR_RXIPHTOE			(1 << 9) +#define RXQCR_RXDTTE			(1 << 7) +#define RXQCR_RXDBCTE			(1 << 6) +#define RXQCR_RXFCTE			(1 << 5) +#define RXQCR_ADRFE			(1 << 4) +#define RXQCR_SDA			(1 << 3) +#define RXQCR_RRXEF			(1 << 0) +#define RXQCR_CMD_CNTL			(RXQCR_RXFCTE|RXQCR_ADRFE) + +#define KS_TXFDPR			0x84 +#define TXFDPR_TXFPAI			(1 << 14) +#define TXFDPR_TXFP_MASK		(0x7ff << 0) +#define TXFDPR_TXFP_SHIFT		(0) + +#define KS_RXFDPR			0x86 +#define RXFDPR_RXFPAI			(1 << 14) + +#define KS_RXDTTR			0x8C +#define KS_RXDBCTR			0x8E + +#define KS_IER				0x90 +#define KS_ISR				0x92 +#define IRQ_LCI				(1 << 15) +#define IRQ_TXI				(1 << 14) +#define IRQ_RXI				(1 << 13) +#define IRQ_RXOI			(1 << 11) +#define IRQ_TXPSI			(1 << 9) +#define IRQ_RXPSI			(1 << 8) +#define IRQ_TXSAI			(1 << 6) +#define IRQ_RXWFDI			(1 << 5) +#define IRQ_RXMPDI			(1 << 4) +#define IRQ_LDI				(1 << 3) +#define IRQ_EDI				(1 << 2) +#define IRQ_SPIBEI			(1 << 1) +#define IRQ_DEDI			(1 << 0) + +#define KS_RXFCTR			0x9C +#define RXFCTR_THRESHOLD_MASK		0x00FF + +#define KS_RXFC				0x9D +#define RXFCTR_RXFC_MASK		(0xff << 8) +#define RXFCTR_RXFC_SHIFT		(8) +#define RXFCTR_RXFC_GET(_v)		(((_v) >> 8) & 0xff) +#define RXFCTR_RXFCT_MASK		(0xff << 0) +#define RXFCTR_RXFCT_SHIFT		(0) + +#define KS_TXNTFSR			0x9E + +#define KS_MAHTR0			0xA0 +#define KS_MAHTR1			0xA2 +#define KS_MAHTR2			0xA4 +#define KS_MAHTR3			0xA6 + +#define KS_FCLWR			0xB0 +#define KS_FCHWR			0xB2 +#define KS_FCOWR			0xB4 + +#define KS_CIDER			0xC0 +#define CIDER_ID			0x8870 +#define CIDER_REV_MASK			(0x7 << 1) +#define CIDER_REV_SHIFT			(1) +#define CIDER_REV_GET(_v)		(((_v) >> 1) & 0x7) + +#define KS_CGCR				0xC6 +#define KS_IACR				0xC8 +#define IACR_RDEN			(1 << 12) +#define IACR_TSEL_MASK			(0x3 << 10) +#define IACR_TSEL_SHIFT			(10) +#define IACR_TSEL_MIB			(0x3 << 10) +#define IACR_ADDR_MASK			(0x1f << 0) +#define IACR_ADDR_SHIFT			(0) + +#define KS_IADLR			0xD0 +#define KS_IAHDR			0xD2 + +#define KS_PMECR			0xD4 +#define PMECR_PME_DELAY			(1 << 14) +#define PMECR_PME_POL			(1 << 12) +#define PMECR_WOL_WAKEUP		(1 << 11) +#define PMECR_WOL_MAGICPKT		(1 << 10) +#define PMECR_WOL_LINKUP		(1 << 9) +#define PMECR_WOL_ENERGY		(1 << 8) +#define PMECR_AUTO_WAKE_EN		(1 << 7) +#define PMECR_WAKEUP_NORMAL		(1 << 6) +#define PMECR_WKEVT_MASK		(0xf << 2) +#define PMECR_WKEVT_SHIFT		(2) +#define PMECR_WKEVT_GET(_v)		(((_v) >> 2) & 0xf) +#define PMECR_WKEVT_ENERGY		(0x1 << 2) +#define PMECR_WKEVT_LINK		(0x2 << 2) +#define PMECR_WKEVT_MAGICPKT		(0x4 << 2) +#define PMECR_WKEVT_FRAME		(0x8 << 2) +#define PMECR_PM_MASK			(0x3 << 0) +#define PMECR_PM_SHIFT			(0) +#define PMECR_PM_NORMAL			(0x0 << 0) +#define PMECR_PM_ENERGY			(0x1 << 0) +#define PMECR_PM_SOFTDOWN		(0x2 << 0) +#define PMECR_PM_POWERSAVE		(0x3 << 0) + +/* Standard MII PHY data */ +#define KS_P1MBCR			0xE4 +#define P1MBCR_FORCE_FDX		(1 << 8) + +#define KS_P1MBSR			0xE6 +#define P1MBSR_AN_COMPLETE		(1 << 5) +#define P1MBSR_AN_CAPABLE		(1 << 3) +#define P1MBSR_LINK_UP			(1 << 2) + +#define KS_PHY1ILR			0xE8 +#define KS_PHY1IHR			0xEA +#define KS_P1ANAR			0xEC +#define KS_P1ANLPR			0xEE + +#define KS_P1SCLMD			0xF4 +#define P1SCLMD_LEDOFF			(1 << 15) +#define P1SCLMD_TXIDS			(1 << 14) +#define P1SCLMD_RESTARTAN		(1 << 13) +#define P1SCLMD_DISAUTOMDIX		(1 << 10) +#define P1SCLMD_FORCEMDIX		(1 << 9) +#define P1SCLMD_AUTONEGEN		(1 << 7) +#define P1SCLMD_FORCE100		(1 << 6) +#define P1SCLMD_FORCEFDX		(1 << 5) +#define P1SCLMD_ADV_FLOW		(1 << 4) +#define P1SCLMD_ADV_100BT_FDX		(1 << 3) +#define P1SCLMD_ADV_100BT_HDX		(1 << 2) +#define P1SCLMD_ADV_10BT_FDX		(1 << 1) +#define P1SCLMD_ADV_10BT_HDX		(1 << 0) + +#define KS_P1CR				0xF6 +#define P1CR_HP_MDIX			(1 << 15) +#define P1CR_REV_POL			(1 << 13) +#define P1CR_OP_100M			(1 << 10) +#define P1CR_OP_FDX			(1 << 9) +#define P1CR_OP_MDI			(1 << 7) +#define P1CR_AN_DONE			(1 << 6) +#define P1CR_LINK_GOOD			(1 << 5) +#define P1CR_PNTR_FLOW			(1 << 4) +#define P1CR_PNTR_100BT_FDX		(1 << 3) +#define P1CR_PNTR_100BT_HDX		(1 << 2) +#define P1CR_PNTR_10BT_FDX		(1 << 1) +#define P1CR_PNTR_10BT_HDX		(1 << 0) + +/* TX Frame control */ +#define TXFR_TXIC			(1 << 15) +#define TXFR_TXFID_MASK			(0x3f << 0) +#define TXFR_TXFID_SHIFT		(0) + +#define KS_P1SR				0xF8 +#define P1SR_HP_MDIX			(1 << 15) +#define P1SR_REV_POL			(1 << 13) +#define P1SR_OP_100M			(1 << 10) +#define P1SR_OP_FDX			(1 << 9) +#define P1SR_OP_MDI			(1 << 7) +#define P1SR_AN_DONE			(1 << 6) +#define P1SR_LINK_GOOD			(1 << 5) +#define P1SR_PNTR_FLOW			(1 << 4) +#define P1SR_PNTR_100BT_FDX		(1 << 3) +#define P1SR_PNTR_100BT_HDX		(1 << 2) +#define P1SR_PNTR_10BT_FDX		(1 << 1) +#define P1SR_PNTR_10BT_HDX		(1 << 0) + +#define ENUM_BUS_NONE			0 +#define ENUM_BUS_8BIT			1 +#define ENUM_BUS_16BIT			2 +#define ENUM_BUS_32BIT			3 + +#define MAX_MCAST_LST			32 +#define HW_MCAST_SIZE			8 +#define MAC_ADDR_LEN			6 + +/* Chip ID values */ +struct chip_id { +	u16 id; +	char *name; +}; + +#endif diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 8bacbda71..b7802a2fe 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -103,9 +103,15 @@ struct macb_device {  	const struct device	*dev;  	struct eth_device	netdev;  	unsigned short		phy_addr; +	struct mii_dev		*bus;  };  #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) +static int macb_is_gem(struct macb_device *macb) +{ +	return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; +} +  static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)  {  	unsigned long netctl; @@ -163,7 +169,12 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)  	return MACB_BFEXT(DATA, frame);  } -#if defined(CONFIG_CMD_MII) +void __weak arch_get_mdio_control(const char *name) +{ +	return; +} + +#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)  int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)  { @@ -173,6 +184,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)  	if ( macb->phy_addr != phy_adr )  		return -1; +	arch_get_mdio_control(devname);  	*value = macb_mdio_read(macb, reg);  	return 0; @@ -186,6 +198,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)  	if ( macb->phy_addr != phy_adr )  		return -1; +	arch_get_mdio_control(devname);  	macb_mdio_write(macb, reg, value);  	return 0; @@ -372,11 +385,15 @@ static int macb_phy_find(struct macb_device *macb)  static int macb_phy_init(struct macb_device *macb)  {  	struct eth_device *netdev = &macb->netdev; +#ifdef CONFIG_PHYLIB +	struct phy_device *phydev; +#endif  	u32 ncfgr;  	u16 phy_id, status, adv, lpa;  	int media, speed, duplex;  	int i; +	arch_get_mdio_control(netdev->name);  #ifdef CONFIG_MACB_SEARCH_PHY  	/* Auto-detect phy_addr */  	if (!macb_phy_find(macb)) { @@ -391,6 +408,13 @@ static int macb_phy_init(struct macb_device *macb)  		return 0;  	} +#ifdef CONFIG_PHYLIB +	phydev->bus = macb->bus; +	phydev->dev = netdev; +	phydev->addr = macb->phy_addr; +	phy_config(phydev); +#endif +  	status = macb_mdio_read(macb, MII_BMSR);  	if (!(status & BMSR_LSTATUS)) {  		/* Try to re-negotiate if we don't have link already. */ @@ -408,28 +432,64 @@ static int macb_phy_init(struct macb_device *macb)  		printf("%s: link down (status: 0x%04x)\n",  		       netdev->name, status);  		return 0; -	} else { -		adv = macb_mdio_read(macb, MII_ADVERTISE); -		lpa = macb_mdio_read(macb, MII_LPA); -		media = mii_nway_result(lpa & adv); -		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) -			 ? 1 : 0); -		duplex = (media & ADVERTISE_FULL) ? 1 : 0; -		printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", -		       netdev->name, -		       speed ? "100" : "10", -		       duplex ? "full" : "half", -		       lpa); +	} -		ncfgr = macb_readl(macb, NCFGR); -		ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); -		if (speed) -			ncfgr |= MACB_BIT(SPD); -		if (duplex) -			ncfgr |= MACB_BIT(FD); -		macb_writel(macb, NCFGR, ncfgr); -		return 1; +	/* First check for GMAC */ +	if (macb_is_gem(macb)) { +		lpa = macb_mdio_read(macb, MII_STAT1000); +		if (lpa & (1 << 11)) { +			speed = 1000; +			duplex = 1; +		} else { +		       if (lpa & (1 << 10)) { +				speed = 1000; +				duplex = 1; +			} else { +				speed = 0; +			} +		} + +		if (speed == 1000) { +			printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n", +			       netdev->name, +			       speed, +			       duplex ? "full" : "half", +			       lpa); + +			ncfgr = macb_readl(macb, NCFGR); +			ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD)); +			if (speed) +				ncfgr |= GEM_BIT(GBE); +			if (duplex) +				ncfgr |= MACB_BIT(FD); +			macb_writel(macb, NCFGR, ncfgr); + +			return 1; +		}  	} + +	/* fall back for EMAC checking */ +	adv = macb_mdio_read(macb, MII_ADVERTISE); +	lpa = macb_mdio_read(macb, MII_LPA); +	media = mii_nway_result(lpa & adv); +	speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) +		 ? 1 : 0); +	duplex = (media & ADVERTISE_FULL) ? 1 : 0; +	printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", +	       netdev->name, +	       speed ? "100" : "10", +	       duplex ? "full" : "half", +	       lpa); + +	ncfgr = macb_readl(macb, NCFGR); +	ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); +	if (speed) +		ncfgr |= MACB_BIT(SPD); +	if (duplex) +		ncfgr |= MACB_BIT(FD); +	macb_writel(macb, NCFGR, ncfgr); + +	return 1;  }  static int macb_init(struct eth_device *netdev, bd_t *bd) @@ -464,26 +524,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)  	macb_writel(macb, RBQP, macb->rx_ring_dma);  	macb_writel(macb, TBQP, macb->tx_ring_dma); +	if (macb_is_gem(macb)) { +#ifdef CONFIG_RGMII +		gem_writel(macb, UR, GEM_BIT(RGMII)); +#else +		gem_writel(macb, UR, 0); +#endif +	} else {  	/* choose RMII or MII mode. This depends on the board */  #ifdef CONFIG_RMII -#if	defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ -	defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \ -	defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ -	defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) +#ifdef CONFIG_AT91FAMILY  	macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));  #else  	macb_writel(macb, USRIO, 0);  #endif  #else -#if	defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ -	defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \ -	defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ -	defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) +#ifdef CONFIG_AT91FAMILY  	macb_writel(macb, USRIO, MACB_BIT(CLKEN));  #else  	macb_writel(macb, USRIO, MACB_BIT(MII));  #endif  #endif /* CONFIG_RMII */ +	}  	if (!macb_phy_init(macb))  		return -1; @@ -527,11 +589,48 @@ static int macb_write_hwaddr(struct eth_device *dev)  	return 0;  } +static u32 macb_mdc_clk_div(int id, struct macb_device *macb) +{ +	u32 config; +	unsigned long macb_hz = get_macb_pclk_rate(id); + +	if (macb_hz < 20000000) +		config = MACB_BF(CLK, MACB_CLK_DIV8); +	else if (macb_hz < 40000000) +		config = MACB_BF(CLK, MACB_CLK_DIV16); +	else if (macb_hz < 80000000) +		config = MACB_BF(CLK, MACB_CLK_DIV32); +	else +		config = MACB_BF(CLK, MACB_CLK_DIV64); + +	return config; +} + +static u32 gem_mdc_clk_div(int id, struct macb_device *macb) +{ +	u32 config; +	unsigned long macb_hz = get_macb_pclk_rate(id); + +	if (macb_hz < 20000000) +		config = GEM_BF(CLK, GEM_CLK_DIV8); +	else if (macb_hz < 40000000) +		config = GEM_BF(CLK, GEM_CLK_DIV16); +	else if (macb_hz < 80000000) +		config = GEM_BF(CLK, GEM_CLK_DIV32); +	else if (macb_hz < 120000000) +		config = GEM_BF(CLK, GEM_CLK_DIV48); +	else if (macb_hz < 160000000) +		config = GEM_BF(CLK, GEM_CLK_DIV64); +	else +		config = GEM_BF(CLK, GEM_CLK_DIV96); + +	return config; +} +  int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)  {  	struct macb_device *macb;  	struct eth_device *netdev; -	unsigned long macb_hz;  	u32 ncfgr;  	macb = malloc(sizeof(struct macb_device)); @@ -555,7 +654,11 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)  	macb->regs = regs;  	macb->phy_addr = phy_addr; -	sprintf(netdev->name, "macb%d", id); +	if (macb_is_gem(macb)) +		sprintf(netdev->name, "gmac%d", id); +	else +		sprintf(netdev->name, "macb%d", id); +  	netdev->init = macb_init;  	netdev->halt = macb_halt;  	netdev->send = macb_send; @@ -566,22 +669,20 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)  	 * Do some basic initialization so that we at least can talk  	 * to the PHY  	 */ -	macb_hz = get_macb_pclk_rate(id); -	if (macb_hz < 20000000) -		ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); -	else if (macb_hz < 40000000) -		ncfgr = MACB_BF(CLK, MACB_CLK_DIV16); -	else if (macb_hz < 80000000) -		ncfgr = MACB_BF(CLK, MACB_CLK_DIV32); -	else -		ncfgr = MACB_BF(CLK, MACB_CLK_DIV64); +	if (macb_is_gem(macb)) { +		ncfgr = gem_mdc_clk_div(id, macb); +		ncfgr |= GEM_BF(DBW, 1); +	} else { +		ncfgr = macb_mdc_clk_div(id, macb); +	}  	macb_writel(macb, NCFGR, ncfgr);  	eth_register(netdev); -#if defined(CONFIG_CMD_MII) +#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)  	miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write); +	macb->bus = miiphy_get_dev_by_name(netdev->name);  #endif  	return 0;  } diff --git a/drivers/net/macb.h b/drivers/net/macb.h index f92a20c70..68eef00c0 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -26,6 +26,7 @@  #define MACB_NCR				0x0000  #define MACB_NCFGR				0x0004  #define MACB_NSR				0x0008 +#define GEM_UR					0x000c  #define MACB_TSR				0x0014  #define MACB_RBQP				0x0018  #define MACB_TBQP				0x001c @@ -71,6 +72,7 @@  #define MACB_TPQ				0x00bc  #define MACB_USRIO				0x00c0  #define MACB_WOL				0x00c4 +#define MACB_MID				0x00fc  /* Bitfields in NCR */  #define MACB_LB_OFFSET				0 @@ -138,6 +140,13 @@  #define MACB_IRXFCS_OFFSET			19  #define MACB_IRXFCS_SIZE			1 +#define GEM_GBE_OFFSET				10 +#define GEM_GBE_SIZE				1 +#define GEM_CLK_OFFSET				18 +#define GEM_CLK_SIZE				3 +#define GEM_DBW_OFFSET				21 +#define GEM_DBW_SIZE				2 +  /* Bitfields in NSR */  #define MACB_NSR_LINK_OFFSET			0  #define MACB_NSR_LINK_SIZE			1 @@ -146,6 +155,10 @@  #define MACB_IDLE_OFFSET			2  #define MACB_IDLE_SIZE				1 +/* Bitfields in UR */ +#define GEM_RGMII_OFFSET			0 +#define GEM_RGMII_SIZE				1 +  /* Bitfields in TSR */  #define MACB_UBR_OFFSET				0  #define MACB_UBR_SIZE				1 @@ -240,12 +253,25 @@  #define MACB_WOL_MTI_OFFSET			19  #define MACB_WOL_MTI_SIZE			1 +/* Bitfields in MID */ +#define MACB_IDNUM_OFFSET			16 +#define MACB_IDNUM_SIZE				16 + +/* Bitfields in DCFG1 */  /* Constants for CLK */  #define MACB_CLK_DIV8				0  #define MACB_CLK_DIV16				1  #define MACB_CLK_DIV32				2  #define MACB_CLK_DIV64				3 +/* GEM specific constants for CLK */ +#define GEM_CLK_DIV8				0 +#define GEM_CLK_DIV16				1 +#define GEM_CLK_DIV32				2 +#define GEM_CLK_DIV48				3 +#define GEM_CLK_DIV64				4 +#define GEM_CLK_DIV96				5 +  /* Constants for MAN register */  #define MACB_MAN_SOF				1  #define MACB_MAN_WRITE				1 @@ -255,21 +281,38 @@  /* Bit manipulation macros */  #define MACB_BIT(name)					\  	(1 << MACB_##name##_OFFSET) -#define MACB_BF(name,value)				\ +#define MACB_BF(name, value)				\  	(((value) & ((1 << MACB_##name##_SIZE) - 1))	\  	 << MACB_##name##_OFFSET) -#define MACB_BFEXT(name,value)\ +#define MACB_BFEXT(name, value)\  	(((value) >> MACB_##name##_OFFSET)		\  	 & ((1 << MACB_##name##_SIZE) - 1)) -#define MACB_BFINS(name,value,old)			\ +#define MACB_BFINS(name, value, old)			\  	(((old) & ~(((1 << MACB_##name##_SIZE) - 1)	\  		    << MACB_##name##_OFFSET))		\ -	 | MACB_BF(name,value)) +	 | MACB_BF(name, value)) + +#define GEM_BIT(name)					\ +	(1 << GEM_##name##_OFFSET) +#define GEM_BF(name, value)				\ +	(((value) & ((1 << GEM_##name##_SIZE) - 1))	\ +	 << GEM_##name##_OFFSET) +#define GEM_BFEXT(name, value)\ +	(((value) >> GEM_##name##_OFFSET)		\ +	 & ((1 << GEM_##name##_SIZE) - 1)) +#define GEM_BFINS(name, value, old)			\ +	(((old) & ~(((1 << GEM_##name##_SIZE) - 1)	\ +		    << GEM_##name##_OFFSET))		\ +	 | GEM_BF(name, value))  /* Register access macros */ -#define macb_readl(port,reg)				\ +#define macb_readl(port, reg)				\  	readl((port)->regs + MACB_##reg) -#define macb_writel(port,reg,value)			\ +#define macb_writel(port, reg, value)			\  	writel((value), (port)->regs + MACB_##reg) +#define gem_readl(port, reg)				\ +	readl((port)->regs + GEM_##reg) +#define gem_writel(port, reg, value)			\ +	writel((value), (port)->regs + GEM_##reg)  #endif /* __DRIVERS_MACB_H__ */ diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 47bf27c8b..319fe8aba 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -43,6 +43,8 @@  #include <asm/arch/kirkwood.h>  #elif defined(CONFIG_ORION5X)  #include <asm/arch/orion5x.h> +#elif defined(CONFIG_DOVE) +#include <asm/arch/dove.h>  #endif  #include "mvgbe.h" @@ -52,7 +54,7 @@ DECLARE_GLOBAL_DATA_PTR;  #define MV_PHY_ADR_REQUEST 0xee  #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi) -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)  /*   * smi_reg_read - miiphy_read callback function.   * @@ -184,6 +186,25 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)  }  #endif +#if defined(CONFIG_PHYLIB) +int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, +		   int reg_addr) +{ +	u16 data; +	int ret; +	ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data); +	if (ret) +		return ret; +	return data; +} + +int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr, +		    int reg_addr, u16 data) +{ +	return smi_reg_write(bus->name, phy_addr, reg_addr, data); +} +#endif +  /* Stop and checks all queues */  static void stop_queue(u32 * qreg)  { @@ -467,8 +488,9 @@ static int mvgbe_init(struct eth_device *dev)  	/* Enable port Rx. */  	MVGBE_REG_WR(regs->rqc, (1 << RXUQ)); -#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \ -	 && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN) +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \ +	!defined(CONFIG_PHYLIB) && \ +	defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)  	/* Wait up to 5s for the link status */  	for (i = 0; i < 5; i++) {  		u16 phyadr; @@ -647,6 +669,45 @@ static int mvgbe_recv(struct eth_device *dev)  	return 0;  } +#if defined(CONFIG_PHYLIB) +int mvgbe_phylib_init(struct eth_device *dev, int phyid) +{ +	struct mii_dev *bus; +	struct phy_device *phydev; +	int ret; + +	bus = mdio_alloc(); +	if (!bus) { +		printf("mdio_alloc failed\n"); +		return -ENOMEM; +	} +	bus->read = mvgbe_phy_read; +	bus->write = mvgbe_phy_write; +	sprintf(bus->name, dev->name); + +	ret = mdio_register(bus); +	if (ret) { +		printf("mdio_register failed\n"); +		free(bus); +		return -ENOMEM; +	} + +	/* Set phy address of the port */ +	mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid); + +	phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII); +	if (!phydev) { +		printf("phy_connect failed\n"); +		return -ENODEV; +	} + +	phy_config(phydev); +	phy_startup(phydev); + +	return 0; +} +#endif +  int mvgbe_initialize(bd_t *bis)  {  	struct mvgbe_device *dmvgbe; @@ -729,7 +790,9 @@ error1:  		eth_register(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#if defined(CONFIG_PHYLIB) +		mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum); +#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)  		miiphy_register(dev->name, smi_reg_read, smi_reg_write);  		/* Set phy address of the port */  		miiphy_write(dev->name, MV_PHY_ADR_REQUEST, diff --git a/drivers/net/mvgbe.h b/drivers/net/mvgbe.h index d8a5429de..7f5d98ff5 100644 --- a/drivers/net/mvgbe.h +++ b/drivers/net/mvgbe.h @@ -308,10 +308,17 @@  #define EBAR_TARGET_GUNIT			0x00000007  /* Window attrib */ +#if defined(CONFIG_DOVE) +#define EBAR_DRAM_CS0				0x00000000 +#define EBAR_DRAM_CS1				0x00000000 +#define EBAR_DRAM_CS2				0x00000000 +#define EBAR_DRAM_CS3				0x00000000 +#else  #define EBAR_DRAM_CS0				0x00000E00  #define EBAR_DRAM_CS1				0x00000D00  #define EBAR_DRAM_CS2				0x00000B00  #define EBAR_DRAM_CS3				0x00000700 +#endif  /* DRAM Target interface */  #define EBAR_DRAM_NO_CACHE_COHERENCY		0x00000000 diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index af5f4b848..695873eaa 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,6 +35,7 @@ COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o  COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o  COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o  COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o +COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o  COBJS-$(CONFIG_PHY_LXT) += lxt.o  COBJS-$(CONFIG_PHY_MARVELL) += marvell.o  COBJS-$(CONFIG_PHY_MICREL) += micrel.o diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 9b3808bfa..09d487971 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -16,7 +16,7 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston,   * MA 02111-1307 USA   * - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011, 2013 Freescale Semiconductor, Inc.   * author Andy Fleming   *   */ @@ -30,6 +30,27 @@ static int ar8021_config(struct phy_device *phydev)  	return 0;  } +static int ar8035_config(struct phy_device *phydev) +{ +	int regval; + +	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007); +	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); +	phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); +	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); +	phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); + +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); +	regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); +	phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100)); + +	genphy_config_aneg(phydev); + +	phy_reset(phydev); + +	return 0; +} +  static struct phy_driver AR8021_driver =  {  	.name = "AR8021",  	.uid = 0x4dd040, @@ -40,9 +61,31 @@ static struct phy_driver AR8021_driver =  {  	.shutdown = genphy_shutdown,  }; +static struct phy_driver AR8031_driver =  { +	.name = "AR8031", +	.uid = 0x4dd074, +	.mask = 0xfffff0, +	.features = PHY_GBIT_FEATURES, +	.config = genphy_config, +	.startup = genphy_startup, +	.shutdown = genphy_shutdown, +}; + +static struct phy_driver AR8035_driver =  { +	.name = "AR8035", +	.uid = 0x4dd072, +	.mask = 0x4fffff, +	.features = PHY_GBIT_FEATURES, +	.config = ar8035_config, +	.startup = genphy_startup, +	.shutdown = genphy_shutdown, +}; +  int phy_atheros_init(void)  {  	phy_register(&AR8021_driver); +	phy_register(&AR8031_driver); +	phy_register(&AR8035_driver);  	return 0;  } diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c new file mode 100644 index 000000000..dd5c59259 --- /dev/null +++ b/drivers/net/phy/icplus.c @@ -0,0 +1,94 @@ +/* + * ICPlus PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + */ +#include <phy.h> + +/* IP101A/G - IP1001 */ +#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */ +#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */ +#define IP1001_PHASE_SEL_MASK           3       /* IP1001 RX/TXPHASE_SEL */ +#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */ +#define IP101A_G_APS_ON                 2       /* IP101A/G APS Mode bit */ +#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */ +#define IP101A_G_IRQ_PIN_USED           (1<<15) /* INTR pin used */ +#define IP101A_G_IRQ_DEFAULT            IP101A_G_IRQ_PIN_USED + +static int ip1001_config(struct phy_device *phydev) +{ +	int c; + +	/* Enable Auto Power Saving mode */ +	c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2); +	if (c < 0) +		return c; +	c |= IP1001_APS_ON; +	c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c); +	if (c < 0) +		return c; + +	/* INTR pin used: speed/link/duplex will cause an interrupt */ +	c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS, +		      IP101A_G_IRQ_DEFAULT); +	if (c < 0) +		return c; + +	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { +		/* +		 * Additional delay (2ns) used to adjust RX clock phase +		 * at RGMII interface +		 */ +		c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS); +		if (c < 0) +			return c; + +		c |= IP1001_PHASE_SEL_MASK; +		c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS, +			      c); +		if (c < 0) +			return c; +	} + +	return 0; +} + +static int ip1001_startup(struct phy_device *phydev) +{ +	genphy_update_link(phydev); +	genphy_parse_link(phydev); + +	return 0; +} +static struct phy_driver IP1001_driver = { +	.name = "ICPlus IP1001", +	.uid = 0x02430d90, +	.mask = 0x0ffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &ip1001_config, +	.startup = &ip1001_startup, +	.shutdown = &genphy_shutdown, +}; + +int phy_icplus_init(void) +{ +	phy_register(&IP1001_driver); + +	return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 46801c791..8397e32e1 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -89,6 +89,12 @@  #define MIIM_88E1149_PHY_PAGE	29 +/* 88E1310 PHY defines */ +#define MIIM_88E1310_PHY_LED_CTRL	16 +#define MIIM_88E1310_PHY_IRQ_EN		18 +#define MIIM_88E1310_PHY_RGMII_CTRL	21 +#define MIIM_88E1310_PHY_PAGE		22 +  /* Marvell 88E1011S */  static int m88e1011s_config(struct phy_device *phydev)  { @@ -394,6 +400,37 @@ static int m88e1149_config(struct phy_device *phydev)  	return 0;  } +/* Marvell 88E1310 */ +static int m88e1310_config(struct phy_device *phydev) +{ +	u16 reg; + +	/* LED link and activity */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); +	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); +	reg = (reg & ~0xf) | 0x1; +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); + +	/* Set LED2/INT to INT mode, low active */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); +	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); +	reg = (reg & 0x77ff) | 0x0880; +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); + +	/* Set RGMII delay */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); +	reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); +	reg |= 0x0030; +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); + +	/* Ensure to return to page 0 */ +	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); + +	genphy_config_aneg(phydev); +	phy_reset(phydev); + +	return 0; +}  static struct phy_driver M88E1011S_driver = {  	.name = "Marvell 88E1011S", @@ -475,8 +512,19 @@ static struct phy_driver M88E1518_driver = {  	.shutdown = &genphy_shutdown,  }; +static struct phy_driver M88E1310_driver = { +	.name = "Marvell 88E1310", +	.uid = 0x01410e90, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1310_config, +	.startup = &m88e1011s_startup, +	.shutdown = &genphy_shutdown, +}; +  int phy_marvell_init(void)  { +	phy_register(&M88E1310_driver);  	phy_register(&M88E1149S_driver);  	phy_register(&M88E1145_driver);  	phy_register(&M88E1121R_driver); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 30f326489..aa9cbcfff 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -18,6 +18,7 @@   *   * Copyright 2010-2011 Freescale Semiconductor, Inc.   * author Andy Fleming + * (C) 2012 NetModule AG, David Andrey, added KSZ9031   *   */  #include <config.h> @@ -52,16 +53,46 @@ static struct phy_driver KS8721_driver = {  };  #endif + +/** + * KSZ9021 - KSZ9031 common + */ + +#define MII_KSZ90xx_PHY_CTL		0x1f +#define MIIM_KSZ90xx_PHYCTL_1000	(1 << 6) +#define MIIM_KSZ90xx_PHYCTL_100		(1 << 5) +#define MIIM_KSZ90xx_PHYCTL_10		(1 << 4) +#define MIIM_KSZ90xx_PHYCTL_DUPLEX	(1 << 3) + +static int ksz90xx_startup(struct phy_device *phydev) +{ +	unsigned phy_ctl; +	genphy_update_link(phydev); +	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL); + +	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX) +		phydev->duplex = DUPLEX_FULL; +	else +		phydev->duplex = DUPLEX_HALF; + +	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000) +		phydev->speed = SPEED_1000; +	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100) +		phydev->speed = SPEED_100; +	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10) +		phydev->speed = SPEED_10; +	return 0; +}  #ifdef CONFIG_PHY_MICREL_KSZ9021 -/* ksz9021 PHY Registers */ + +/* + * KSZ9021 + */ + +/* PHY Registers */  #define MII_KSZ9021_EXTENDED_CTRL	0x0b  #define MII_KSZ9021_EXTENDED_DATAW	0x0c  #define MII_KSZ9021_EXTENDED_DATAR	0x0d -#define MII_KSZ9021_PHY_CTL		0x1f -#define MIIM_KSZ9021_PHYCTL_1000	(1 << 6) -#define MIIM_KSZ9021_PHYCTL_100		(1 << 5) -#define MIIM_KSZ9021_PHYCTL_10		(1 << 4) -#define MIIM_KSZ9021_PHYCTL_DUPLEX	(1 << 3)  #define CTRL1000_PREFER_MASTER		(1 << 10)  #define CTRL1000_CONFIG_MASTER		(1 << 11) @@ -106,37 +137,64 @@ static int ksz9021_config(struct phy_device *phydev)  	return 0;  } -static int ksz9021_startup(struct phy_device *phydev) -{ -	unsigned phy_ctl; -	genphy_update_link(phydev); -	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL); - -	if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX) -		phydev->duplex = DUPLEX_FULL; -	else -		phydev->duplex = DUPLEX_HALF; - -	if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000) -		phydev->speed = SPEED_1000; -	else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100) -		phydev->speed = SPEED_100; -	else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10) -		phydev->speed = SPEED_10; -	return 0; -} -  static struct phy_driver ksz9021_driver = {  	.name = "Micrel ksz9021",  	.uid  = 0x221610,  	.mask = 0xfffff0,  	.features = PHY_GBIT_FEATURES,  	.config = &ksz9021_config, -	.startup = &ksz9021_startup, +	.startup = &ksz90xx_startup,  	.shutdown = &genphy_shutdown,  };  #endif +/** + * KSZ9031 + */ +/* PHY Registers */ +#define MII_KSZ9031_MMD_ACCES_CTRL	0x0d +#define MII_KSZ9031_MMD_REG_DATA	0x0e + +/* Accessors to extended registers*/ +int ksz9031_phy_extended_write(struct phy_device *phydev, +			       int devaddr, int regnum, u16 mode, u16 val) +{ +	/*select register addr for mmd*/ +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr); +	/*select register for mmd*/ +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_REG_DATA, regnum); +	/*setup mode*/ +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr)); +	/*write the value*/ +	return	phy_write(phydev, MDIO_DEVAD_NONE, +		MII_KSZ9031_MMD_REG_DATA, val); +} + +int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, +			      int regnum, u16 mode) +{ +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr); +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_REG_DATA, regnum); +	phy_write(phydev, MDIO_DEVAD_NONE, +		  MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode)); +	return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA); +} + +static struct phy_driver ksz9031_driver = { +	.name = "Micrel ksz9031", +	.uid  = 0x221620, +	.mask = 0xfffffe, +	.features = PHY_GBIT_FEATURES, +	.config   = &genphy_config, +	.startup  = &ksz90xx_startup, +	.shutdown = &genphy_shutdown, +}; +  int phy_micrel_init(void)  {  	phy_register(&KSZ804_driver); @@ -145,5 +203,6 @@ int phy_micrel_init(void)  #else  	phy_register(&KS8721_driver);  #endif +	phy_register(&ksz9031_driver);  	return 0;  } diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c index ea60ac1b0..6dc7ed505 100644 --- a/drivers/net/phy/natsemi.c +++ b/drivers/net/phy/natsemi.c @@ -22,6 +22,42 @@   */  #include <phy.h> +/* NatSemi DP83630 */ + +#define DP83630_PHY_PAGESEL_REG		0x13 +#define DP83630_PHY_PTP_COC_REG		0x14 +#define DP83630_PHY_PTP_CLKOUT_EN	(1<<15) +#define DP83630_PHY_RBR_REG		0x17 + +static int dp83630_config(struct phy_device *phydev) +{ +	int ptp_coc_reg; + +	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); +	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6); +	ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE, +			       DP83630_PHY_PTP_COC_REG); +	ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN; +	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG, +		  ptp_coc_reg); +	phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0); + +	genphy_config_aneg(phydev); + +	return 0; +} + +static struct phy_driver DP83630_driver = { +	.name = "NatSemi DP83630", +	.uid = 0x20005ce1, +	.mask = 0xfffffff0, +	.features = PHY_BASIC_FEATURES, +	.config = &dp83630_config, +	.startup = &genphy_startup, +	.shutdown = &genphy_shutdown, +}; + +  /* DP83865 Link and Auto-Neg Status Register */  #define MIIM_DP83865_LANR      0x11  #define MIIM_DP83865_SPD_MASK  0x0018 @@ -90,6 +126,7 @@ static struct phy_driver DP83865_driver = {  int phy_natsemi_init(void)  { +	phy_register(&DP83630_driver);  	phy_register(&DP83865_driver);  	return 0; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f8c548147..7c0eaec51 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -75,6 +75,10 @@ static int genphy_config_advert(struct phy_device *phydev)  		adv |= ADVERTISE_PAUSE_CAP;  	if (advertise & ADVERTISED_Asym_Pause)  		adv |= ADVERTISE_PAUSE_ASYM; +	if (advertise & ADVERTISED_1000baseX_Half) +		adv |= ADVERTISE_1000XHALF; +	if (advertise & ADVERTISED_1000baseX_Full) +		adv |= ADVERTISE_1000XFULL;  	if (adv != oldadv) {  		err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); @@ -280,7 +284,7 @@ int genphy_update_link(struct phy_device *phydev)   *   * Stolen from Linux's mii.c and phy_device.c   */ -static int genphy_parse_link(struct phy_device *phydev) +int genphy_parse_link(struct phy_device *phydev)  {  	int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); @@ -288,6 +292,7 @@ static int genphy_parse_link(struct phy_device *phydev)  	if (mii_reg & BMSR_ANEGCAPABLE) {  		u32 lpa = 0;  		u32 gblpa = 0; +		u32 estatus = 0;  		/* Check for gigabit capability */  		if (mii_reg & BMSR_ERCAP) { @@ -327,6 +332,18 @@ static int genphy_parse_link(struct phy_device *phydev)  		} else if (lpa & LPA_10FULL)  			phydev->duplex = DUPLEX_FULL; + +		if (mii_reg & BMSR_ESTATEN) +			estatus = phy_read(phydev, MDIO_DEVAD_NONE, +					   MII_ESTATUS); + +		if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF | +				ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { +			phydev->speed = SPEED_1000; +			if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL)) +				phydev->duplex = DUPLEX_FULL; +		} +  	} else {  		u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); @@ -384,6 +401,10 @@ int genphy_config(struct phy_device *phydev)  			features |= SUPPORTED_1000baseT_Full;  		if (val & ESTATUS_1000_THALF)  			features |= SUPPORTED_1000baseT_Half; +		if (val & ESTATUS_1000_XFULL) +			features |= SUPPORTED_1000baseX_Full; +		if (val & ESTATUS_1000_XHALF) +			features |= SUPPORTED_1000baseX_Full;  	}  	phydev->supported = features; @@ -433,6 +454,9 @@ int phy_init(void)  #ifdef CONFIG_PHY_ET1011C  	phy_et1011c_init();  #endif +#ifdef CONFIG_PHY_ICPLUS +	phy_icplus_init(); +#endif  #ifdef CONFIG_PHY_LXT  	phy_lxt_init();  #endif diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c new file mode 100644 index 000000000..1db3529c2 --- /dev/null +++ b/drivers/net/sunxi_wemac.c @@ -0,0 +1,533 @@ +/* + * sunxi_wemac.c -- Allwinner A10 ethernet driver + * + * (C) Copyright 2012, Stefan Roese <sr@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> +#include <linux/err.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> + +/* EMAC register  */ +struct wemac_regs { +	u32 ctl;	/* 0x00 */ +	u32 tx_mode;	/* 0x04 */ +	u32 tx_flow;	/* 0x08 */ +	u32 tx_ctl0;	/* 0x0c */ +	u32 tx_ctl1;	/* 0x10 */ +	u32 tx_ins;	/* 0x14 */ +	u32 tx_pl0;	/* 0x18 */ +	u32 tx_pl1;	/* 0x1c */ +	u32 tx_sta;	/* 0x20 */ +	u32 tx_io_data;	/* 0x24 */ +	u32 tx_io_data1; /* 0x28 */ +	u32 tx_tsvl0;	/* 0x2c */ +	u32 tx_tsvh0;	/* 0x30 */ +	u32 tx_tsvl1;	/* 0x34 */ +	u32 tx_tsvh1;	/* 0x38 */ +	u32 rx_ctl;	/* 0x3c */ +	u32 rx_hash0;	/* 0x40 */ +	u32 rx_hash1;	/* 0x44 */ +	u32 rx_sta;	/* 0x48 */ +	u32 rx_io_data;	/* 0x4c */ +	u32 rx_fbc;	/* 0x50 */ +	u32 int_ctl;	/* 0x54 */ +	u32 int_sta;	/* 0x58 */ +	u32 mac_ctl0;	/* 0x5c */ +	u32 mac_ctl1;	/* 0x60 */ +	u32 mac_ipgt;	/* 0x64 */ +	u32 mac_ipgr;	/* 0x68 */ +	u32 mac_clrt;	/* 0x6c */ +	u32 mac_maxf;	/* 0x70 */ +	u32 mac_supp;	/* 0x74 */ +	u32 mac_test;	/* 0x78 */ +	u32 mac_mcfg;	/* 0x7c */ +	u32 mac_mcmd;	/* 0x80 */ +	u32 mac_madr;	/* 0x84 */ +	u32 mac_mwtd;	/* 0x88 */ +	u32 mac_mrdd;	/* 0x8c */ +	u32 mac_mind;	/* 0x90 */ +	u32 mac_ssrr;	/* 0x94 */ +	u32 mac_a0;	/* 0x98 */ +	u32 mac_a1;	/* 0x9c */ +}; + +/* SRAMC register  */ +struct sunxi_sramc_regs { +	u32 ctrl0; +	u32 ctrl1; +}; + +/* 0: Disable       1: Aborted frame enable(default) */ +#define EMAC_TX_AB_M		(0x1 << 0) +/* 0: CPU           1: DMA(default) */ +#define EMAC_TX_TM		(0x1 << 1) + +#define EMAC_TX_SETUP		(0) + +/* 0: DRQ asserted  1: DRQ automatically(default) */ +#define EMAC_RX_DRQ_MODE	(0x1 << 1) +/* 0: CPU           1: DMA(default) */ +#define EMAC_RX_TM		(0x1 << 2) +/* 0: Normal(default)        1: Pass all Frames */ +#define EMAC_RX_PA		(0x1 << 4) +/* 0: Normal(default)        1: Pass Control Frames */ +#define EMAC_RX_PCF		(0x1 << 5) +/* 0: Normal(default)        1: Pass Frames with CRC Error */ +#define EMAC_RX_PCRCE		(0x1 << 6) +/* 0: Normal(default)        1: Pass Frames with Length Error */ +#define EMAC_RX_PLE		(0x1 << 7) +/* 0: Normal                 1: Pass Frames length out of range(default) */ +#define EMAC_RX_POR		(0x1 << 8) +/* 0: Not accept             1: Accept unicast Packets(default) */ +#define EMAC_RX_UCAD		(0x1 << 16) +/* 0: Normal(default)        1: DA Filtering */ +#define EMAC_RX_DAF		(0x1 << 17) +/* 0: Not accept             1: Accept multicast Packets(default) */ +#define EMAC_RX_MCO		(0x1 << 20) +/* 0: Disable(default)       1: Enable Hash filter */ +#define EMAC_RX_MHF		(0x1 << 21) +/* 0: Not accept             1: Accept Broadcast Packets(default) */ +#define EMAC_RX_BCO		(0x1 << 22) +/* 0: Disable(default)       1: Enable SA Filtering */ +#define EMAC_RX_SAF		(0x1 << 24) +/* 0: Normal(default)        1: Inverse Filtering */ +#define EMAC_RX_SAIF		(0x1 << 25) + +#define EMAC_RX_SETUP		(EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \ +				 EMAC_RX_MCO | EMAC_RX_BCO) + +/* 0: Disable                1: Enable Receive Flow Control(default) */ +#define EMAC_MAC_CTL0_RFC	(0x1 << 2) +/* 0: Disable                1: Enable Transmit Flow Control(default) */ +#define EMAC_MAC_CTL0_TFC	(0x1 << 3) + +#define EMAC_MAC_CTL0_SETUP	(EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC) + +/* 0: Disable                1: Enable MAC Frame Length Checking(default) */ +#define EMAC_MAC_CTL1_FLC	(0x1 << 1) +/* 0: Disable(default)       1: Enable Huge Frame */ +#define EMAC_MAC_CTL1_HF	(0x1 << 2) +/* 0: Disable(default)       1: Enable MAC Delayed CRC */ +#define EMAC_MAC_CTL1_DCRC	(0x1 << 3) +/* 0: Disable                1: Enable MAC CRC(default) */ +#define EMAC_MAC_CTL1_CRC	(0x1 << 4) +/* 0: Disable                1: Enable MAC PAD Short frames(default) */ +#define EMAC_MAC_CTL1_PC	(0x1 << 5) +/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */ +#define EMAC_MAC_CTL1_VC	(0x1 << 6) +/* 0: Disable(default)       1: Enable MAC auto detect Short frames */ +#define EMAC_MAC_CTL1_ADP	(0x1 << 7) +/* 0: Disable(default)       1: Enable */ +#define EMAC_MAC_CTL1_PRE	(0x1 << 8) +/* 0: Disable(default)       1: Enable */ +#define EMAC_MAC_CTL1_LPE	(0x1 << 9) +/* 0: Disable(default)       1: Enable no back off */ +#define EMAC_MAC_CTL1_NB	(0x1 << 12) +/* 0: Disable(default)       1: Enable */ +#define EMAC_MAC_CTL1_BNB	(0x1 << 13) +/* 0: Disable(default)       1: Enable */ +#define EMAC_MAC_CTL1_ED	(0x1 << 14) + +#define EMAC_MAC_CTL1_SETUP	(EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \ +				 EMAC_MAC_CTL1_PC) + +#define EMAC_MAC_IPGT		0x15 + +#define EMAC_MAC_NBTB_IPG1	0xC +#define EMAC_MAC_NBTB_IPG2	0x12 + +#define EMAC_MAC_CW		0x37 +#define EMAC_MAC_RM		0xF + +#define EMAC_MAC_MFL		0x0600 + +/* Receive status */ +#define EMAC_CRCERR		(1 << 4) +#define EMAC_LENERR		(3 << 5) + +#define DMA_CPU_TRRESHOLD	2000 + +struct wemac_eth_dev { +	u32 speed; +	u32 duplex; +	u32 phy_configured; +	int link_printed; +}; + +struct wemac_rxhdr { +	s16 rx_len; +	u16 rx_status; +}; + +static void wemac_inblk_32bit(void *reg, void *data, int count) +{ +	int cnt = (count + 3) >> 2; + +	if (cnt) { +		u32 *buf = data; + +		do { +			u32 x = readl(reg); +			*buf++ = x; +		} while (--cnt); +	} +} + +static void wemac_outblk_32bit(void *reg, void *data, int count) +{ +	int cnt = (count + 3) >> 2; + +	if (cnt) { +		const u32 *buf = data; + +		do { +			writel(*buf++, reg); +		} while (--cnt); +	} +} + +/* + * Read a word from phyxcer + */ +static int wemac_phy_read(const char *devname, unsigned char addr, +			  unsigned char reg, unsigned short *value) +{ +	struct eth_device *dev = eth_get_dev_by_name(devname); +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + +	/* issue the phy address and reg */ +	writel(addr << 8 | reg, ®s->mac_madr); + +	/* pull up the phy io line */ +	writel(0x1, ®s->mac_mcmd); + +	/* Wait read complete */ +	mdelay(1); + +	/* push down the phy io line */ +	writel(0x0, ®s->mac_mcmd); + +	/* and write data */ +	*value = readl(®s->mac_mrdd); + +	return 0; +} + +/* + * Write a word to phyxcer + */ +static int wemac_phy_write(const char *devname, unsigned char addr, +			   unsigned char reg, unsigned short value) +{ +	struct eth_device *dev = eth_get_dev_by_name(devname); +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + +	/* issue the phy address and reg */ +	writel(addr << 8 | reg, ®s->mac_madr); + +	/* pull up the phy io line */ +	writel(0x1, ®s->mac_mcmd); + +	/* Wait write complete */ +	mdelay(1); + +	/* push down the phy io line */ +	writel(0x0, ®s->mac_mcmd); + +	/* and write data */ +	writel(value, ®s->mac_mwtd); + +	return 0; +} + +static void emac_setup(struct eth_device *dev) +{ +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; +	u32 reg_val; +	u16 phy_val; +	u32 duplex_flag; + +	/* Set up TX */ +	writel(EMAC_TX_SETUP, ®s->tx_mode); + +	/* Set up RX */ +	writel(EMAC_RX_SETUP, ®s->rx_ctl); + +	/* Set MAC */ +	/* Set MAC CTL0 */ +	writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0); + +	/* Set MAC CTL1 */ +	wemac_phy_read(dev->name, 1, 0, &phy_val); +	debug("PHY SETUP, reg 0 value: %x\n", phy_val); +	duplex_flag = !!(phy_val & (1 << 8)); + +	reg_val = 0; +	if (duplex_flag) +		reg_val = (0x1 << 0); +	writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1); + +	/* Set up IPGT */ +	writel(EMAC_MAC_IPGT, ®s->mac_ipgt); + +	/* Set up IPGR */ +	writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr); + +	/* Set up Collison window */ +	writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt); + +	/* Set up Max Frame Length */ +	writel(EMAC_MAC_MFL, ®s->mac_maxf); +} + +static void wemac_reset(struct eth_device *dev) +{ +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + +	debug("resetting device\n"); + +	/* RESET device */ +	writel(0, ®s->ctl); +	udelay(200); + +	writel(1, ®s->ctl); +	udelay(200); +} + +static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd) +{ +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; +	struct wemac_eth_dev *priv = dev->priv; +	u16 phy_reg; + +	/* Init EMAC */ + +	/* Flush RX FIFO */ +	setbits_le32(®s->rx_ctl, 0x8); +	udelay(1); + +	/* Init MAC */ + +	/* Soft reset MAC */ +	clrbits_le32(®s->mac_ctl0, 1 << 15); + +	/* Set MII clock */ +	clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); + +	/* Clear RX counter */ +	writel(0x0, ®s->rx_fbc); +	udelay(1); + +	/* Set up EMAC */ +	emac_setup(dev); + +	writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | +	       dev->enetaddr[2], ®s->mac_a1); +	writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | +	       dev->enetaddr[5], ®s->mac_a0); + +	mdelay(1); + +	wemac_reset(dev); + +	/* PHY POWER UP */ +	wemac_phy_read(dev->name, 1, 0, &phy_reg); +	wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11))); +	mdelay(1); + +	wemac_phy_read(dev->name, 1, 0, &phy_reg); + +	priv->speed = miiphy_speed(dev->name, 0); +	priv->duplex = miiphy_duplex(dev->name, 0); + +	/* Print link status only once */ +	if (!priv->link_printed) { +		printf("ENET Speed is %d Mbps - %s duplex connection\n", +		       priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); +		priv->link_printed = 1; +	} + +	/* Set EMAC SPEED depend on PHY */ +	clrsetbits_le32(®s->mac_supp, 1 << 8, +			((phy_reg & (1 << 13)) >> 13) << 8); + +	/* Set duplex depend on phy */ +	clrsetbits_le32(®s->mac_ctl1, 1 << 0, +			((phy_reg & (1 << 8)) >> 8) << 0); + +	/* Enable RX/TX */ +	setbits_le32(®s->ctl, 0x7); + +	return 0; +} + +static void sunxi_wemac_eth_halt(struct eth_device *dev) +{ +	/* Nothing to do here */ +} + +static int sunxi_wemac_eth_recv(struct eth_device *dev) +{ +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; +	struct wemac_rxhdr rxhdr; +	u32 rxcount; +	u32 reg_val; +	int rx_len; +	int rx_status; +	int good_packet; + +	/* Check packet ready or not */ + +	/* +	 * Race warning: The first packet might arrive with +	 * the interrupts disabled, but the second will fix +	 */ +	rxcount = readl(®s->rx_fbc); +	if (!rxcount) { +		/* Had one stuck? */ +		rxcount = readl(®s->rx_fbc); +		if (!rxcount) +			return 0; +	} + +	reg_val = readl(®s->rx_io_data); +	if (reg_val != 0x0143414d) { +		/* Disable RX */ +		clrbits_le32(®s->ctl, 1 << 2); + +		/* Flush RX FIFO */ +		setbits_le32(®s->rx_ctl, 1 << 3); +		while (readl(®s->rx_ctl) & (1 << 3)) +			; + +		/* Enable RX */ +		setbits_le32(®s->ctl, 1 << 2); + +		return 0; +	} + +	/* +	 * A packet ready now +	 * Get status/length +	 */ +	good_packet = 1; + +	wemac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr)); + +	rx_len = rxhdr.rx_len; +	rx_status = rxhdr.rx_status; + +	/* Packet Status check */ +	if (rx_len < 0x40) { +		good_packet = 0; +		debug("RX: Bad Packet (runt)\n"); +	} + +	/* rx_status is identical to RSR register. */ +	if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) { +		good_packet = 0; +		if (rx_status & EMAC_CRCERR) +			printf("crc error\n"); +		if (rx_status & EMAC_LENERR) +			printf("length error\n"); +	} + +	/* Move data from WEMAC */ +	if (good_packet) { +		if (rx_len > DMA_CPU_TRRESHOLD) { +			printf("Received packet is too big (len=%d)\n", rx_len); +		} else { +			wemac_inblk_32bit((void *)®s->rx_io_data, +					  NetRxPackets[0], rx_len); + +			/* Pass to upper layer */ +			NetReceive(NetRxPackets[0], rx_len); +			return rx_len; +		} +	} + +	return 0; +} + +static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len) +{ +	struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + +	/* Select channel 0 */ +	writel(0, ®s->tx_ins); + +	/* Write packet */ +	wemac_outblk_32bit((void *)®s->tx_io_data, packet, len); + +	/* Set TX len */ +	writel(len, ®s->tx_pl0); + +	/* Start translate from fifo to phy */ +	setbits_le32(®s->tx_ctl0, 1); + +	return 0; +} + +int sunxi_wemac_initialize(void) +{ +	struct sunxi_ccm_reg *const ccm = +		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE; +	struct sunxi_sramc_regs *sram = +		(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; +	struct eth_device *dev; +	struct wemac_eth_dev *priv; +	int pin; + +	dev = malloc(sizeof(*dev)); +	if (dev == NULL) +		return -ENOMEM; + +	priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev)); +	if (!priv) { +		free(dev); +		return -ENOMEM; +	} + +	memset(dev, 0, sizeof(*dev)); +	memset(priv, 0, sizeof(struct wemac_eth_dev)); + +	/* Map SRAM to EMAC */ +	setbits_le32(&sram->ctrl1, 0x5 << 2); + +	/* Configure pin mux settings for MII Ethernet */ +	for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) +		sunxi_gpio_set_cfgpin(pin, 2); + +	/* Set up clock gating */ +	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC); + +	dev->iobase = SUNXI_EMAC_BASE; +	dev->priv = priv; +	dev->init = sunxi_wemac_eth_init; +	dev->halt = sunxi_wemac_eth_halt; +	dev->send = sunxi_wemac_eth_send; +	dev->recv = sunxi_wemac_eth_recv; +	strcpy(dev->name, "wemac"); + +	eth_register(dev); + +	miiphy_register(dev->name, wemac_phy_read, wemac_phy_write); + +	return 0; +} diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c index 77ac1f7c7..621c89912 100644 --- a/drivers/pci/fsl_pci_init.c +++ b/drivers/pci/fsl_pci_init.c @@ -211,7 +211,7 @@ static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,  	return 1;  } -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  static void fsl_pcie_boot_master(pit_t *pi)  {  	/* configure inbound window for slave's u-boot image */ @@ -388,7 +388,7 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)  	/* see if we are a PCIe or PCI controller */  	pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  	/* boot from PCIE --master */  	char *s = getenv("bootmaster");  	char pcie[6]; @@ -624,7 +624,7 @@ int fsl_pci_init_port(struct fsl_pci_info *pci_info,  	if (fsl_is_pci_agent(hose)) {  		fsl_pci_config_unlock(hose);  		hose->last_busno = hose->first_busno; -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER  	} else {  		/* boot from PCIE --master releases slave's core 0 */  		char *s = getenv("bootmaster"); diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c index d4b3e65a3..9a093a5bd 100644 --- a/drivers/power/exynos-tmu.c +++ b/drivers/power/exynos-tmu.c @@ -50,15 +50,15 @@  /* Tmeperature threshold values for various thermal events */  struct temperature_params {  	/* minimum value in temperature code range */ -	unsigned int min_val; +	unsigned min_val;  	/* maximum value in temperature code range */ -	unsigned int max_val; +	unsigned max_val;  	/* temperature threshold to start warning */ -	unsigned int start_warning; +	unsigned start_warning;  	/* temperature threshold CPU tripping */ -	unsigned int start_tripping; +	unsigned start_tripping;  	/* temperature threshold for HW tripping */ -	unsigned int hardware_tripping; +	unsigned hardware_tripping;  };  /* Pre-defined values and thresholds for calibration of current temperature */ @@ -66,25 +66,27 @@ struct tmu_data {  	/* pre-defined temperature thresholds */  	struct temperature_params ts;  	/* pre-defined efuse range minimum value */ -	unsigned int efuse_min_value; +	unsigned efuse_min_value;  	/* pre-defined efuse value for temperature calibration */ -	unsigned int efuse_value; +	unsigned efuse_value;  	/* pre-defined efuse range maximum value */ -	unsigned int efuse_max_value; +	unsigned efuse_max_value;  	/* current temperature sensing slope */ -	unsigned int slope; +	unsigned slope;  };  /* TMU device specific details and status */  struct tmu_info {  	/* base Address for the TMU */ -	unsigned tmu_base; +	struct exynos5_tmu_reg *tmu_base; +	/* mux Address for the TMU */ +	int tmu_mux;  	/* pre-defined values for calibration and thresholds */  	struct tmu_data data;  	/* value required for triminfo_25 calibration */ -	unsigned int te1; +	unsigned te1;  	/* value required for triminfo_85 calibration */ -	unsigned int te2; +	unsigned te2;  	/* Value for measured data calibration */  	int dc_value;  	/* enum value indicating status of the TMU */ @@ -103,17 +105,24 @@ static struct tmu_info gbl_info;   */  static int get_cur_temp(struct tmu_info *info)  { -	int cur_temp; -	struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base; +	struct exynos5_tmu_reg *reg = info->tmu_base; +	ulong start; +	int cur_temp = 0;  	/*  	 * Temperature code range between min 25 and max 125.  	 * May run more than once for first call as initial sensing  	 * has not yet happened.  	 */ -	do { -		cur_temp = readl(®->current_temp) & 0xff; -	} while (cur_temp == 0 && info->tmu_state == TMU_STATUS_NORMAL); +	if (info->tmu_state == TMU_STATUS_NORMAL) { +		start = get_timer(0); +		do { +			cur_temp = readl(®->current_temp) & 0xff; +		} while ((cur_temp == 0) || (get_timer(start) > 100)); +	} + +	if (cur_temp == 0) +		return cur_temp;  	/* Calibrate current temperature */  	cur_temp = cur_temp - info->te1 + info->dc_value; @@ -137,23 +146,29 @@ enum tmu_status_t tmu_monitor(int *temp)  	/* Read current temperature of the SOC */  	cur_temp = get_cur_temp(&gbl_info); + +	if (!cur_temp) +		goto out; +  	*temp = cur_temp;  	/* Temperature code lies between min 25 and max 125 */ -	if (cur_temp >= data->ts.start_tripping && -			cur_temp <= data->ts.max_val) { +	if ((cur_temp >= data->ts.start_tripping) && +	    (cur_temp <= data->ts.max_val))  		return TMU_STATUS_TRIPPED; -	} else if (cur_temp >= data->ts.start_warning) { + +	if (cur_temp >= data->ts.start_warning)  		return TMU_STATUS_WARNING; -	} else if (cur_temp < data->ts.start_warning && -			cur_temp >= data->ts.min_val) { + +	if ((cur_temp < data->ts.start_warning) && +	    (cur_temp >= data->ts.min_val))  		return TMU_STATUS_NORMAL; -	} else { -		/* Temperature code does not lie between min 25 and max 125 */ -		gbl_info.tmu_state = TMU_STATUS_INIT; -		debug("EXYNOS_TMU: Thermal reading failed\n"); -		return TMU_STATUS_INIT; -	} + + out: +	/* Temperature code does not lie between min 25 and max 125 */ +	gbl_info.tmu_state = TMU_STATUS_INIT; +	debug("EXYNOS_TMU: Thermal reading failed\n"); +	return TMU_STATUS_INIT;  }  /* @@ -166,6 +181,7 @@ enum tmu_status_t tmu_monitor(int *temp)  static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)  {  #ifdef CONFIG_OF_CONTROL +	fdt_addr_t addr;  	int node;  	int error = 0; @@ -183,46 +199,58 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)  	 * miscalculation of register values in tmu_setup_parameters  	 * may result in misleading current temperature.  	 */ -	info->tmu_base = fdtdec_get_addr(blob, node, "reg"); -	if (info->tmu_base == FDT_ADDR_T_NONE) { +	addr = fdtdec_get_addr(blob, node, "reg"); +	if (addr == FDT_ADDR_T_NONE) {  		debug("%s: Missing tmu-base\n", __func__);  		return -1;  	} +	info->tmu_base = (struct exynos5_tmu_reg *)addr; + +	/* Optional field. */ +	info->tmu_mux = fdtdec_get_int(blob, +				node, "samsung,mux", -1); +	/* Take default value as per the user manual b(110) */ +	if (info->tmu_mux == -1) +		info->tmu_mux = 0x6; +  	info->data.ts.min_val = fdtdec_get_int(blob,  				node, "samsung,min-temp", -1); -	error |= info->data.ts.min_val; +	error |= (info->data.ts.min_val == -1);  	info->data.ts.max_val = fdtdec_get_int(blob,  				node, "samsung,max-temp", -1); -	error |= info->data.ts.max_val; +	error |= (info->data.ts.max_val == -1);  	info->data.ts.start_warning = fdtdec_get_int(blob,  				node, "samsung,start-warning", -1); -	error |= info->data.ts.start_warning; +	error |= (info->data.ts.start_warning == -1);  	info->data.ts.start_tripping = fdtdec_get_int(blob,  				node, "samsung,start-tripping", -1); -	error |= info->data.ts.start_tripping; +	error |= (info->data.ts.start_tripping == -1);  	info->data.ts.hardware_tripping = fdtdec_get_int(blob,  				node, "samsung,hw-tripping", -1); -	error |= info->data.ts.hardware_tripping; +	error |= (info->data.ts.hardware_tripping == -1);  	info->data.efuse_min_value = fdtdec_get_int(blob,  				node, "samsung,efuse-min-value", -1); -	error |= info->data.efuse_min_value; +	error |= (info->data.efuse_min_value == -1);  	info->data.efuse_value = fdtdec_get_int(blob,  				node, "samsung,efuse-value", -1); -	error |= info->data.efuse_value; +	error |= (info->data.efuse_value == -1);  	info->data.efuse_max_value = fdtdec_get_int(blob,  				node, "samsung,efuse-max-value", -1); -	error |= info->data.efuse_max_value; +	error |= (info->data.efuse_max_value == -1);  	info->data.slope = fdtdec_get_int(blob,  				node, "samsung,slope", -1); -	error |= info->data.slope; +	error |= (info->data.slope == -1);  	info->dc_value = fdtdec_get_int(blob,  				node, "samsung,dc-value", -1); -	error |= info->dc_value; +	error |= (info->dc_value == -1); -	if (error == -1) { +	if (error) {  		debug("fail to get tmu node properties\n");  		return -1;  	} +#else +	/* Non DT support may never be added. Just in case  */ +	return -1;  #endif  	return 0; @@ -236,12 +264,12 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)   */  static void tmu_setup_parameters(struct tmu_info *info)  { -	unsigned int te_code, con; -	unsigned int warning_code, trip_code, hwtrip_code; -	unsigned int cooling_temp; -	unsigned int rising_value; +	unsigned te_code, con; +	unsigned warning_code, trip_code, hwtrip_code; +	unsigned cooling_temp; +	unsigned rising_value;  	struct tmu_data *data = &info->data; -	struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base; +	struct exynos5_tmu_reg *reg = info->tmu_base;  	/* Must reload for reading efuse value from triminfo register */  	writel(TRIMINFO_RELOAD, ®->triminfo_control); @@ -288,7 +316,7 @@ static void tmu_setup_parameters(struct tmu_info *info)  	/* TMU core enable */  	con = readl(®->tmu_control); -	con |= THERM_TRIP_EN | CORE_EN; +	con |= THERM_TRIP_EN | CORE_EN | (info->tmu_mux << 20);  	writel(con, ®->tmu_control); @@ -314,6 +342,5 @@ int tmu_init(const void *blob)  	tmu_setup_parameters(&gbl_info);  	gbl_info.tmu_state = TMU_STATUS_NORMAL;  ret: -  	return gbl_info.tmu_state;  } diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index daa80038a..a19cec5ac 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -37,7 +37,6 @@ static struct serial_device *serial_current;   * Table with supported baudrates (defined in config_xyz.h)   */  static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; -#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))  /**   * serial_null() - Void registration routine of a serial driver @@ -74,11 +73,11 @@ static int on_baudrate(const char *name, const char *value, enum env_op op,  		if (gd->baudrate == baudrate)  			return 0; -		for (i = 0; i < N_BAUDRATES; ++i) { +		for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {  			if (baudrate == baudrate_table[i])  				break;  		} -		if (i == N_BAUDRATES) { +		if (i == ARRAY_SIZE(baudrate_table)) {  			if ((flags & H_FORCE) == 0)  				printf("## Baudrate %d bps not supported\n",  					baudrate); diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 3c41242a8..e65125ccd 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -30,6 +30,10 @@  DECLARE_GLOBAL_DATA_PTR; +#define RX_FIFO_COUNT_MASK	0xff +#define RX_FIFO_FULL_MASK	(1 << 8) +#define TX_FIFO_FULL_MASK	(1 << 24) +  static inline struct s5p_uart *s5p_get_base_uart(int dev_index)  {  	u32 offset = dev_index * sizeof(struct s5p_uart); @@ -87,8 +91,8 @@ int serial_init_dev(const int dev_index)  {  	struct s5p_uart *const uart = s5p_get_base_uart(dev_index); -	/* reset and enable FIFOs, set triggers to the maximum */ -	writel(0, &uart->ufcon); +	/* enable FIFOs */ +	writel(0x1, &uart->ufcon);  	writel(0, &uart->umcon);  	/* 8N1 */  	writel(0x3, &uart->ulcon); @@ -130,7 +134,8 @@ int serial_getc_dev(const int dev_index)  	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);  	/* wait for character to arrive */ -	while (!(readl(&uart->utrstat) & 0x1)) { +	while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | +					 RX_FIFO_FULL_MASK))) {  		if (serial_err_check(dev_index, 0))  			return 0;  	} @@ -146,7 +151,7 @@ void serial_putc_dev(const char c, const int dev_index)  	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);  	/* wait for room in the tx FIFO */ -	while (!(readl(&uart->utrstat) & 0x2)) { +	while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {  		if (serial_err_check(dev_index, 1))  			return;  	} diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c index a37ac4e52..06bcf91a4 100644 --- a/drivers/spi/cf_qspi.c +++ b/drivers/spi/cf_qspi.c @@ -171,7 +171,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  	volatile qspi_t *qspi = dev->regs;  	u8 *txbuf = (u8 *)dout;  	u8 *rxbuf = (u8 *)din; -	u32 count = ((bitlen / 8) + (bitlen % 8 ? 1 : 0)); +	u32 count = DIV_ROUND_UP(bitlen, 8);  	u32 n, i = 0;  	/* Sanitize arguments */ diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 01378d098..7a25a35aa 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -465,6 +465,28 @@ static int process_nodes(const void *blob, int node_list[], int count)  }  #endif +/** + * Set up a new SPI slave for an fdt node + * + * @param blob		Device tree blob + * @param node		SPI peripheral node to use + * @return 0 if ok, -1 on error + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, +		unsigned int cs, unsigned int max_hz, unsigned int mode) +{ +	struct spi_bus *bus; +	unsigned int i; + +	for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) { +		if (bus->node == node) +			return spi_setup_slave(i, cs, max_hz, mode); +	} + +	debug("%s: Failed to find bus node %d\n", __func__, node); +	return NULL; +} +  /* Sadly there is no error return from this function */  void spi_init(void)  { diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 5bed85878..2ea322833 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -224,7 +224,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  	const u8 *dout, u8 *din, unsigned long flags)  {  	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); -	int nbytes = (bitlen + 7) / 8; +	int nbytes = DIV_ROUND_UP(bitlen, 8);  	u32 data, cnt, i;  	struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; @@ -294,7 +294,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  	/* Transfer completed, clear any pending request */  	reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); -	nbytes = (bitlen + 7) / 8; +	nbytes = DIV_ROUND_UP(bitlen, 8);  	cnt = nbytes % 32; @@ -330,7 +330,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  		void *din, unsigned long flags)  { -	int n_bytes = (bitlen + 7) / 8; +	int n_bytes = DIV_ROUND_UP(bitlen, 8);  	int n_bits;  	int ret;  	u32 blk_size; diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 60e03a4bf..7bb91e5ab 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -1105,8 +1105,7 @@ int usb_lowlevel_init(int index, void **controller)  	/* Configure all the endpoint FIFO's and start usb controller */  	musbr = musb_cfg.regs; -	musb_configure_ep(&epinfo[0], -			sizeof(epinfo) / sizeof(struct musb_epinfo)); +	musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));  	musb_start();  	/* diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c index e0b4217dc..e8a2ce041 100644 --- a/drivers/usb/musb/musb_udc.c +++ b/drivers/usb/musb/musb_udc.c @@ -894,8 +894,7 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,  			epinfo[id * 2].epsize = endpoint->rcv_packetSize;  		} -		musb_configure_ep(&epinfo[0], -				  sizeof(epinfo) / sizeof(struct musb_epinfo)); +		musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));  	} else {  		if (debug_level > 0)  			serial_printf("ERROR : %s endpoint request %d " diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c index ed0823bf9..c3606d5b0 100644 --- a/drivers/video/exynos_fb.c +++ b/drivers/video/exynos_fb.c @@ -319,10 +319,10 @@ void lcd_ctrl_init(void *lcdbase)  #ifdef CONFIG_OF_CONTROL  	if (exynos_fimd_parse_dt(gd->fdt_blob))  		debug("Can't get proper panel info\n"); -#endif +#else  	/* initialize parameters which is specific to panel. */  	init_panel_info(&panel_info); - +#endif  	panel_width = panel_info.vl_width;  	panel_height = panel_info.vl_height; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 3e9ca1182..8cfc3fa77 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -82,6 +82,9 @@ typedef struct global_data {  	unsigned long fdt_size;	/* Space reserved for relocated FDT */  	void **jt;		/* jump table */  	char env_buf[32];	/* buffer for getenv() before reloc. */ +#ifdef CONFIG_TRACE +	void		*trace_buff;	/* The trace buffer */ +#endif  	struct arch_global_data arch;	/* architecture-specific data */  } gd_t;  #endif diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 4b3984454..3e32eee92 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -90,9 +90,6 @@ extern void _start(void);  extern ulong _rel_dyn_start_ofs;  extern ulong _rel_dyn_end_ofs; -/* Start/end of the relocation symbol table, as an offset from _start */ -extern ulong _dynsym_start_ofs; -  /* End of the region to be relocated, as an offset form _start */  extern ulong _image_copy_end_ofs; diff --git a/include/command.h b/include/command.h index 65692fd2a..9e05ddc13 100644 --- a/include/command.h +++ b/include/command.h @@ -110,6 +110,8 @@ static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)  }  #endif +extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +  extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,  			   char *const argv[]); diff --git a/include/common.h b/include/common.h index 126891d65..e5220cf67 100644 --- a/include/common.h +++ b/include/common.h @@ -750,6 +750,10 @@ void	irq_install_handler(int, interrupt_handler_t *, void *);  void	irq_free_handler   (int);  void	reset_timer	   (void);  ulong	get_timer	   (ulong base); + +/* Return value of monotonic microsecond timer */ +unsigned long timer_get_us(void); +  void	enable_interrupts  (void);  int	disable_interrupts (void); diff --git a/include/configs/B4860QDS.h b/include/configs/B4860QDS.h index c15bbd856..a823f9f3a 100644 --- a/include/configs/B4860QDS.h +++ b/include/configs/B4860QDS.h @@ -34,6 +34,15 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0xfffffffc  #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +/* Set 1M boot space */ +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR (CONFIG_SYS_TEXT_BASE & 0xfff00000) +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS \ +		(0x300000000ull | CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR) +#define CONFIG_RESET_VECTOR_ADDRESS 0xfffffffc +#define CONFIG_SYS_NO_FLASH +#endif +  /* High Level Configuration Options */  #define CONFIG_BOOKE  #define CONFIG_E500			/* BOOKE e500 family */ @@ -63,6 +72,7 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #endif  #define CONFIG_FSL_LAW			/* Use common FSL init code */ @@ -84,14 +94,15 @@  #define CONFIG_ENV_OVERWRITE  #ifdef CONFIG_SYS_NO_FLASH +#if !defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) && !defined(CONFIG_RAMBOOT_PBL)  #define CONFIG_ENV_IS_NOWHERE +#endif  #else  #define CONFIG_FLASH_CFI_DRIVER  #define CONFIG_SYS_FLASH_CFI  #define CONFIG_SYS_FLASH_USE_BUFFER_WRITE  #endif -#ifndef CONFIG_SYS_NO_FLASH  #if defined(CONFIG_SPIFLASH)  #define CONFIG_SYS_EXTRA_ENV_RELOC  #define CONFIG_ENV_IS_IN_SPI_FLASH @@ -113,16 +124,18 @@  #define CONFIG_ENV_IS_IN_NAND  #define CONFIG_ENV_SIZE			CONFIG_SYS_NAND_BLOCK_SIZE  #define CONFIG_ENV_OFFSET		(5 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +#define CONFIG_ENV_IS_IN_REMOTE +#define CONFIG_ENV_ADDR		0xffe20000 +#define CONFIG_ENV_SIZE		0x2000 +#elif defined(CONFIG_ENV_IS_NOWHERE) +#define CONFIG_ENV_SIZE		0x2000  #else  #define CONFIG_ENV_IS_IN_FLASH  #define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE)  #define CONFIG_ENV_SIZE		0x2000  #define CONFIG_ENV_SECT_SIZE	0x20000 /* 128K (one sector) */  #endif -#else /* CONFIG_SYS_NO_FLASH */ -#define CONFIG_ENV_SIZE                0x2000 -#define CONFIG_ENV_SECT_SIZE   0x20000 /* 128K (one sector) */ -#endif  #ifndef __ASSEMBLY__  unsigned long get_board_sys_clk(void); @@ -223,7 +236,7 @@ unsigned long get_board_ddr_clk(void);  /* NOR Flash Timing Params */  #define CONFIG_SYS_NOR_CSOR	CSOR_NOR_ADM_SHIFT(4)  #define CONFIG_SYS_NOR_FTIM0	(FTIM0_NOR_TACSE(0x01) | \ -				FTIM0_NOR_TEADC(0x01) | \ +				FTIM0_NOR_TEADC(0x04) | \  				FTIM0_NOR_TEAHC(0x20))  #define CONFIG_SYS_NOR_FTIM1	(FTIM1_NOR_TACO(0x35) | \  				FTIM1_NOR_TRAD_NOR(0x1A) |\ @@ -600,6 +613,16 @@ unsigned long get_board_ddr_clk(void);  #elif defined(CONFIG_NAND)  #define CONFIG_SYS_QE_FMAN_FW_IN_NAND  #define CONFIG_SYS_QE_FMAN_FW_ADDR	(6 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +/* + * Slave has no ucode locally, it can fetch this from remote. When implementing + * in two corenet boards, slave's ucode could be stored in master's memory + * space, the address can be mapped from slave TLB->slave LAW-> + * slave SRIO or PCIE outbound window->master inbound window-> + * master LAW->the ucode address in master's memory space. + */ +#define CONFIG_SYS_QE_FMAN_FW_IN_REMOTE +#define CONFIG_SYS_QE_FMAN_FW_ADDR	0xFFE00000  #else  #define CONFIG_SYS_QE_FMAN_FW_IN_NOR  #define CONFIG_SYS_QE_FMAN_FW_ADDR		0xEFF40000 diff --git a/include/configs/BSC9131RDB.h b/include/configs/BSC9131RDB.h index fd076e09a..b5911c694 100644 --- a/include/configs/BSC9131RDB.h +++ b/include/configs/BSC9131RDB.h @@ -40,10 +40,34 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0x1107fffc  #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE    /* start of monitor */ +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET		"u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE		0x00201000 +#define CONFIG_SPL_TEXT_BASE		0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE		8192 +#define CONFIG_SPL_RELOC_TEXT_BASE	0x00100000 +#define CONFIG_SPL_RELOC_STACK		0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE	((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST	(0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START	0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS	0 +#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds" +#endif + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE	/* start of monitor */  #endif +  /* High Level Configuration Options */  #define CONFIG_BOOKE			/* BOOKE */  #define CONFIG_E500			/* BOOKE e500 family */ @@ -55,7 +79,11 @@  #define CONFIG_ENV_OVERWRITE  #define CONFIG_DDR_CLK_FREQ	66666666 /* DDRCLK on 9131 RDB */ +#if defined(CONFIG_SYS_CLK_100) +#define CONFIG_SYS_CLK_FREQ    100000000 /* SYSCLK for 9131 RDB */ +#else  #define CONFIG_SYS_CLK_FREQ	66666666 /* SYSCLK for 9131 RDB */ +#endif  #define CONFIG_HWCONFIG  /* @@ -125,16 +153,21 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_IMMR		CONFIG_SYS_CCSRBAR	/* PQII uses */  							/* CONFIG_SYS_IMMR */ +/* DSP CCSRBAR */ +#define CONFIG_SYS_FSL_DSP_CCSRBAR	CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT +#define CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS	CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT  /*   * Memory map   *   * 0x0000_0000	0x3FFF_FFFF	DDR			1G cacheable   * 0x8800_0000	0x8810_0000	IFC internal SRAM		1M + * 0xB000_0000	0xB0FF_FFFF	DSP core M2 memory	16M   * 0xC100_0000	0xC13F_FFFF	MAPLE-2F		4M   * 0xC1F0_0000	0xC1F3_FFFF	PA L2 SRAM Region 0	256K   * 0xC1F8_0000	0xC1F9_FFFF	PA L2 SRAM Region 1	128K   * 0xFED0_0000	0xFED0_3FFF	SEC Secured RAM		16K + * 0xFF60_0000	0xFF6F_FFFF	DSP CCSR		1M   * 0xFF70_0000	0xFF7F_FFFF	PA CCSR			1M   * 0xFF80_0000	0xFFFF_FFFF	Boot Page & NAND flash buffer	8M   * @@ -214,6 +247,9 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_NS16550_SERIAL  #define CONFIG_SYS_NS16550_REG_SIZE	1  #define CONFIG_SYS_NS16550_CLK		get_bus_freq(0) +#ifdef CONFIG_SPL_BUILD +#define CONFIG_NS16550_MIN_FUNCTIONS +#endif  #define CONFIG_SYS_CONSOLE_IS_IN_ENV	/* determine from environment */ @@ -295,7 +331,6 @@ extern unsigned long get_sdram_size(void);  /*   * Environment   */ -#if defined(CONFIG_SYS_RAMBOOT)  #if defined(CONFIG_RAMBOOT_SPIFLASH)  #define CONFIG_ENV_IS_IN_SPI_FLASH  #define CONFIG_ENV_SPI_BUS	0 @@ -305,15 +340,16 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_ENV_OFFSET	0x100000	/* 1MB */  #define CONFIG_ENV_SECT_SIZE	0x10000  #define CONFIG_ENV_SIZE		0x2000 -#else -#define CONFIG_ENV_IS_NOWHERE		/* Store ENV in memory only */ -#define CONFIG_ENV_ADDR			(CONFIG_SYS_MONITOR_BASE - 0x1000) -#define CONFIG_ENV_SIZE			0x2000 -#endif -#else -#define CONFIG_ENV_IS_NOWHERE	1	/* Store ENV in memory only */ +#elif defined(CONFIG_NAND) +#define CONFIG_ENV_IS_IN_NAND +#define CONFIG_SYS_EXTRA_ENV_RELOC +#define CONFIG_ENV_SIZE		CONFIG_SYS_NAND_BLOCK_SIZE +#define CONFIG_ENV_OFFSET	((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE) +#define CONFIG_ENV_RANGE	(3 * CONFIG_ENV_SIZE) +#elif defined(CONFIG_SYS_RAMBOOT) +#define CONFIG_ENV_IS_NOWHERE	/* Store ENV in memory only */  #define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE - 0x1000) -#define CONFIG_ENV_SIZE		0x400 +#define CONFIG_ENV_SIZE		0x2000  #endif  #define CONFIG_LOADS_ECHO		/* echo on for serial download */ @@ -406,7 +442,9 @@ extern unsigned long get_sdram_size(void);  	"fdtfile=bsc9131rdb.dtb\0"		\  	"bdev=sda1\0"	\  	"hwconfig=usb1:dr_mode=host,phy_type=ulpi\0"	\ -	"othbootargs=ramdisk_size=600000 \0" \ +	"bootm_size=0x37000000\0"	\ +	"othbootargs=ramdisk_size=600000 " \ +	"default_hugepagesz=256m hugepagesz=256m hugepages=1\0" \  	"usbext2boot=setenv bootargs root=/dev/ram rw "	\  	"console=$consoledev,$baudrate $othbootargs; "	\  	"usb start;"			\ diff --git a/include/configs/BSC9132QDS.h b/include/configs/BSC9132QDS.h index 9d15d0eb8..3aa44435a 100644 --- a/include/configs/BSC9132QDS.h +++ b/include/configs/BSC9132QDS.h @@ -49,6 +49,27 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0x1107fffc  #endif +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET		"u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE		0x00201000 +#define CONFIG_SPL_TEXT_BASE		0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE		8192 +#define CONFIG_SPL_RELOC_TEXT_BASE	0x00100000 +#define CONFIG_SPL_RELOC_STACK		0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE	((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST	(0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START	0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS	0 +#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds" +#endif +  #ifndef CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_TEXT_BASE		0x8ff80000  #endif @@ -57,11 +78,12 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0x8ffffffc  #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE    /* start of monitor */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE	/* start of monitor */  #endif -  /* High Level Configuration Options */  #define CONFIG_BOOKE			/* BOOKE */  #define CONFIG_E500			/* BOOKE e500 family */ @@ -222,6 +244,10 @@ combinations. this should be removed later   * IFC Definitions   */  /* NOR Flash on IFC */ + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_NO_FLASH +#endif  #define CONFIG_SYS_FLASH_BASE		0x88000000  #define CONFIG_SYS_MAX_FLASH_SECT	1024	/* Max number of sector: 32M */ @@ -302,7 +328,9 @@ combinations. this should be removed later  #define CONFIG_SYS_NAND_BLOCK_SIZE	(128 * 1024) +#ifndef CONFIG_SPL_BUILD  #define CONFIG_FSL_QIXIS +#endif  #ifdef CONFIG_FSL_QIXIS  #define CONFIG_SYS_FPGA_BASE	0xffb00000  #define CONFIG_SYS_I2C_FPGA_ADDR	0x66 @@ -338,6 +366,22 @@ combinations. this should be removed later  #endif  /* Set up IFC registers for boot location NOR/NAND */ +#if defined(CONFIG_NAND) +#define CONFIG_SYS_CSPR0		CONFIG_SYS_NAND_CSPR +#define CONFIG_SYS_AMASK0		CONFIG_SYS_NAND_AMASK +#define CONFIG_SYS_CSOR0		CONFIG_SYS_NAND_CSOR +#define CONFIG_SYS_CS0_FTIM0		CONFIG_SYS_NAND_FTIM0 +#define CONFIG_SYS_CS0_FTIM1		CONFIG_SYS_NAND_FTIM1 +#define CONFIG_SYS_CS0_FTIM2		CONFIG_SYS_NAND_FTIM2 +#define CONFIG_SYS_CS0_FTIM3		CONFIG_SYS_NAND_FTIM3 +#define CONFIG_SYS_CSPR1		CONFIG_SYS_NOR_CSPR +#define CONFIG_SYS_AMASK1		CONFIG_SYS_NOR_AMASK +#define CONFIG_SYS_CSOR1		CONFIG_SYS_NOR_CSOR +#define CONFIG_SYS_CS1_FTIM0		CONFIG_SYS_NOR_FTIM0 +#define CONFIG_SYS_CS1_FTIM1		CONFIG_SYS_NOR_FTIM1 +#define CONFIG_SYS_CS1_FTIM2		CONFIG_SYS_NOR_FTIM2 +#define CONFIG_SYS_CS1_FTIM3		CONFIG_SYS_NOR_FTIM3 +#else  #define CONFIG_SYS_CSPR0		CONFIG_SYS_NOR_CSPR  #define CONFIG_SYS_AMASK0		CONFIG_SYS_NOR_AMASK  #define CONFIG_SYS_CSOR0		CONFIG_SYS_NOR_CSOR @@ -352,6 +396,7 @@ combinations. this should be removed later  #define CONFIG_SYS_CS1_FTIM1		CONFIG_SYS_NAND_FTIM1  #define CONFIG_SYS_CS1_FTIM2		CONFIG_SYS_NAND_FTIM2  #define CONFIG_SYS_CS1_FTIM3		CONFIG_SYS_NAND_FTIM3 +#endif  #define CONFIG_BOARD_EARLY_INIT_F	/* Call board_pre_init */  #define CONFIG_BOARD_EARLY_INIT_R @@ -374,6 +419,9 @@ combinations. this should be removed later  #define CONFIG_SYS_NS16550_SERIAL  #define CONFIG_SYS_NS16550_REG_SIZE	1  #define CONFIG_SYS_NS16550_CLK		get_bus_freq(0) +#ifdef CONFIG_SPL_BUILD +#define CONFIG_NS16550_MIN_FUNCTIONS +#endif  #define CONFIG_SERIAL_MULTI	1 /* Enable both serial ports */  #define CONFIG_SYS_CONSOLE_IS_IN_ENV	/* determine from environment */ @@ -503,7 +551,6 @@ combinations. this should be removed later  /*   * Environment   */ -#if defined(CONFIG_SYS_RAMBOOT)  #if defined(CONFIG_RAMBOOT_SDCARD)  #define CONFIG_ENV_IS_IN_MMC  #define CONFIG_SYS_MMC_ENV_DEV		0 @@ -517,11 +564,15 @@ combinations. this should be removed later  #define CONFIG_ENV_OFFSET	0x100000	/* 1MB */  #define CONFIG_ENV_SECT_SIZE	0x10000  #define CONFIG_ENV_SIZE		0x2000 -#else +#elif defined(CONFIG_NAND) +#define CONFIG_ENV_IS_IN_NAND +#define CONFIG_ENV_SIZE		CONFIG_SYS_NAND_BLOCK_SIZE +#define CONFIG_ENV_OFFSET	((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE) +#define CONFIG_ENV_RANGE	(3 * CONFIG_ENV_SIZE) +#elif defined(CONFIG_SYS_RAMBOOT)  #define CONFIG_ENV_IS_NOWHERE		/* Store ENV in memory only */  #define CONFIG_ENV_ADDR			(CONFIG_SYS_MONITOR_BASE - 0x1000)  #define CONFIG_ENV_SIZE			0x2000 -#endif  #else  #define CONFIG_ENV_IS_IN_FLASH  #if CONFIG_SYS_MONITOR_BASE > 0xfff80000 diff --git a/include/configs/P1010RDB.h b/include/configs/P1010RDB.h index 518559790..7b28a27bc 100644 --- a/include/configs/P1010RDB.h +++ b/include/configs/P1010RDB.h @@ -31,10 +31,10 @@  #define CONFIG_PHYS_64BIT  #endif -#ifdef CONFIG_P1010RDB  #define CONFIG_P1010 +#define CONFIG_E500			/* BOOKE e500 family */ +#include <asm/config_mpc85xx.h>  #define CONFIG_NAND_FSL_IFC -#endif  #ifdef CONFIG_SDCARD  #define CONFIG_RAMBOOT_SDCARD @@ -48,15 +48,25 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0x1107fffc  #endif -#ifdef CONFIG_NAND	/* NAND Boot */ -#define CONFIG_RAMBOOT_NAND -#define CONFIG_NAND_U_BOOT -#define CONFIG_SYS_TEXT_BASE_SPL	0xff800000 -#ifdef CONFIG_NAND_SPL -#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE_SPL -#else -#define CONFIG_SYS_TEXT_BASE		0x11001000 -#endif /* CONFIG_NAND_SPL */ +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET		"u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE		0x00201000 +#define CONFIG_SPL_TEXT_BASE		0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE		8192 +#define CONFIG_SPL_RELOC_TEXT_BASE	0x00100000 +#define CONFIG_SPL_RELOC_STACK		0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE	((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST	(0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START	0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS	0 +#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"  #endif @@ -74,8 +84,10 @@  #define CONFIG_RESET_VECTOR_ADDRESS	0xeffffffc  #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE    /* start of monitor */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE	/* start of monitor */  #endif  /* High Level Configuration Options */ @@ -242,7 +254,7 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_CCSRBAR_PHYS_LOW		CONFIG_SYS_CCSRBAR  /* Don't relocate CCSRBAR while in NAND_SPL */ -#ifdef CONFIG_NAND_SPL +#ifdef CONFIG_SPL_BUILD  #define CONFIG_SYS_CCSR_DO_NOT_RELOCATE  #endif @@ -268,6 +280,10 @@ extern unsigned long get_sdram_size(void);   * IFC Definitions   */  /* NOR Flash on IFC */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_NO_FLASH +#endif +  #define CONFIG_SYS_FLASH_BASE		0xee000000  #define CONFIG_SYS_MAX_FLASH_SECT	256	/* 32M */ @@ -353,7 +369,7 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_NAND_DDR_LAW		11  /* Set up IFC registers for boot location NOR/NAND */ -#if defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SECBOOT) +#if defined(CONFIG_NAND) || defined(CONFIG_NAND_SECBOOT)  #define CONFIG_SYS_CSPR0		CONFIG_SYS_NAND_CSPR  #define CONFIG_SYS_AMASK0		CONFIG_SYS_NAND_AMASK  #define CONFIG_SYS_CSOR0		CONFIG_SYS_NAND_CSOR @@ -385,15 +401,6 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_CS1_FTIM3		CONFIG_SYS_NAND_FTIM3  #endif -/* NAND boot: 8K NAND loader config */ -#define CONFIG_SYS_NAND_SPL_SIZE	0x2000 -#define CONFIG_SYS_NAND_U_BOOT_SIZE	(512 << 10) -#define CONFIG_SYS_NAND_U_BOOT_DST	(0x11000000 - CONFIG_SYS_NAND_SPL_SIZE) -#define CONFIG_SYS_NAND_U_BOOT_START	0x11000000 -#define CONFIG_SYS_NAND_U_BOOT_OFFS	(0) -#define CONFIG_SYS_NAND_U_BOOT_RELOC	0x10000 -#define CONFIG_SYS_NAND_U_BOOT_RELOC_SP	(CONFIG_SYS_NAND_U_BOOT_RELOC + 0x10000) -  /* CPLD on IFC */  #define CONFIG_SYS_CPLD_BASE		0xffb00000 @@ -421,14 +428,20 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_CS3_FTIM3		0x0  #endif	/* CONFIG_SDCARD */ -#if defined(CONFIG_RAMBOOT_SDCARD) || defined(CONFIG_RAMBOOT_SPIFLASH) || \ -    defined(CONFIG_RAMBOOT_NAND) +#if defined(CONFIG_RAMBOOT_SDCARD) || defined(CONFIG_RAMBOOT_SPIFLASH)  #define CONFIG_SYS_RAMBOOT  #define CONFIG_SYS_EXTRA_ENV_RELOC  #else  #undef CONFIG_SYS_RAMBOOT  #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_IFC_A003399 +#if !defined(CONFIG_SPL) && !defined(CONFIG_SYS_RAMBOOT)\ +	&& !defined(CONFIG_SECURE_BOOT) +#define CONFIG_A003399_NOR_WORKAROUND +#endif +#endif +  #define CONFIG_BOARD_EARLY_INIT_F	/* Call board_pre_init */  #define CONFIG_BOARD_EARLY_INIT_R @@ -450,7 +463,7 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_SYS_NS16550_SERIAL  #define CONFIG_SYS_NS16550_REG_SIZE	1  #define CONFIG_SYS_NS16550_CLK		get_bus_freq(0) -#ifdef CONFIG_NAND_SPL +#ifdef CONFIG_SPL_BUILD  #define CONFIG_NS16550_MIN_FUNCTIONS  #endif @@ -505,7 +518,7 @@ extern unsigned long get_sdram_size(void);   * SPI interface will not be available in case of NAND boot SPI CS0 will be   * used for SLIC   */ -#if !defined(CONFIG_NAND_U_BOOT) || !defined(CONFIG_NAND_SECBOOT) +#if !defined(CONFIG_NAND) || !defined(CONFIG_NAND_SECBOOT)  /* eSPI - Enhanced SPI */  #define CONFIG_FSL_ESPI  #define CONFIG_SPI_FLASH @@ -600,7 +613,6 @@ extern unsigned long get_sdram_size(void);  /*   * Environment   */ -#if defined(CONFIG_SYS_RAMBOOT)  #if defined(CONFIG_RAMBOOT_SDCARD)  #define CONFIG_ENV_IS_IN_MMC  #define CONFIG_FSL_FIXED_MMC_LOCATION @@ -615,16 +627,15 @@ extern unsigned long get_sdram_size(void);  #define CONFIG_ENV_OFFSET	0x100000	/* 1MB */  #define CONFIG_ENV_SECT_SIZE	0x10000  #define CONFIG_ENV_SIZE		0x2000 -#elif defined(CONFIG_NAND_U_BOOT) +#elif defined(CONFIG_NAND)  #define CONFIG_ENV_IS_IN_NAND  #define CONFIG_ENV_SIZE		CONFIG_SYS_NAND_BLOCK_SIZE -#define CONFIG_ENV_OFFSET	CONFIG_SYS_NAND_U_BOOT_SIZE +#define CONFIG_ENV_OFFSET	((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE)  #define CONFIG_ENV_RANGE	(3 * CONFIG_ENV_SIZE) -#else +#elif defined(CONFIG_SYS_RAMBOOT)  #define CONFIG_ENV_IS_NOWHERE		/* Store ENV in memory only */  #define CONFIG_ENV_ADDR			(CONFIG_SYS_MONITOR_BASE - 0x1000)  #define CONFIG_ENV_SIZE			0x2000 -#endif  #else  #define CONFIG_ENV_IS_IN_FLASH  #if CONFIG_SYS_MONITOR_BASE > 0xfff80000 diff --git a/include/configs/P1023RDB.h b/include/configs/P1023RDB.h new file mode 100644 index 000000000..fee8040e2 --- /dev/null +++ b/include/configs/P1023RDB.h @@ -0,0 +1,401 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Authors:  Roy Zang <tie-fei.zang@freescale.com> + *	     Chunhe Lan <Chunhe.Lan@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifndef CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_TEXT_BASE	0xeff80000 +#endif + +#ifndef CONFIG_SYS_MONITOR_BASE +#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE	/* start of monitor */ +#endif + +#ifndef CONFIG_RESET_VECTOR_ADDRESS +#define CONFIG_RESET_VECTOR_ADDRESS	0xeffffffc +#endif + +/* High Level Configuration Options */ +#define CONFIG_BOOKE		/* BOOKE */ +#define CONFIG_E500		/* BOOKE e500 family */ +#define CONFIG_MPC85xx +#define CONFIG_P1023 +#define CONFIG_MP		/* support multiple processors */ + +#define CONFIG_FSL_ELBC		/* Has Enhanced localbus controller */ +#define CONFIG_PCI		/* Enable PCI/PCIE */ +#define CONFIG_PCI_INDIRECT_BRIDGE     /* indirect PCI bridge support */ +#define CONFIG_PCIE1		/* PCIE controler 1 (slot 1) */ +#define CONFIG_PCIE2		/* PCIE controler 2 (slot 2) */ +#define CONFIG_PCIE3		/* PCIE controler 3 (slot 3) */ +#define CONFIG_FSL_PCI_INIT	/* Use common FSL init code */ +#define CONFIG_FSL_PCIE_RESET	/* need PCIe reset errata */ +#define CONFIG_SYS_PCI_64BIT	/* enable 64-bit PCI resources */ +#define CONFIG_FSL_LAW		/* Use common FSL init code */ + +#ifndef __ASSEMBLY__ +extern unsigned long get_clock_freq(void); +#endif + +#define CONFIG_SYS_CLK_FREQ	66666666 +#define CONFIG_DDR_CLK_FREQ	CONFIG_SYS_CLK_FREQ + +/* + * These can be toggled for performance analysis, otherwise use default. + */ +#define CONFIG_L2_CACHE			/* toggle L2 cache */ +#define CONFIG_BTB			/* toggle branch predition */ +#define CONFIG_HWCONFIG + +#define CONFIG_ENABLE_36BIT_PHYS + +#define CONFIG_SYS_MEMTEST_START	0x01000000	/* memtest works on */ +#define CONFIG_SYS_MEMTEST_END		0x02000000 + +#define CONFIG_PANIC_HANG	/* do not reset board on panic */ + +/* Implement conversion of addresses in the LBC */ +#define CONFIG_SYS_LBC_LBCR		0x00000000 +#define CONFIG_SYS_LBC_LCRR		LCRR_CLKDIV_8 + +/* DDR Setup */ +#define CONFIG_VERY_BIG_RAM +#define CONFIG_SYS_DDR_SDRAM_BASE	0x00000000 +#define CONFIG_SYS_SDRAM_BASE		CONFIG_SYS_DDR_SDRAM_BASE + +#define CONFIG_DIMM_SLOTS_PER_CTLR	1 +#define CONFIG_CHIP_SELECTS_PER_CTRL	1 + +#define CONFIG_DDR_SPD +#define CONFIG_FSL_DDR3 +#define CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SYS_SDRAM_SIZE		512u	/* DDR is 512M */ +#define CONFIG_SYS_SPD_BUS_NUM          0 +#define SPD_EEPROM_ADDRESS              0x50 +#define CONFIG_SYS_DDR_RAW_TIMING + +/* + * Memory map + * + * 0x0000_0000	0x1fff_ffff	DDR			512M cacheable + * 0x8000_0000	0xbfff_ffff	PCI Express Mem		1G non-cacheable + * 0xc000_0000	0xdfff_ffff	PCI			512M non-cacheable + * 0xe100_0000	0xe3ff_ffff	PCI IO range		4M non-cacheable + * 0xff00_0000	0xff3f_ffff	DPAA_QBMAN		4M cacheable + * 0xff60_0000	0xff7f_ffff	CCSR			2M non-cacheable + * 0xffd0_0000	0xffd0_3fff	L1 for stack		16K cacheable TLB0 + * + * Localbus non-cacheable + * + * 0xec00_0000	0xefff_ffff	NOR flash		64M non-cacheable + * 0xffa0_0000	0xffaf_ffff	NAND			1M non-cacheable + */ + +/* + * Local Bus Definitions + */ +#define CONFIG_SYS_FLASH_BASE		0xec000000 /* start of FLASH 64M */ +#define CONFIG_SYS_FLASH_BASE_PHYS	CONFIG_SYS_FLASH_BASE + +#define CONFIG_FLASH_BR_PRELIM  (BR_PHYS_ADDR(CONFIG_SYS_FLASH_BASE_PHYS) \ +				| BR_PS_16 | BR_V) +#define CONFIG_FLASH_OR_PRELIM	0xfc000ff7 + +#define CONFIG_FLASH_CFI_DRIVER +#define CONFIG_SYS_FLASH_CFI +#define CONFIG_SYS_FLASH_EMPTY_INFO +#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* number of banks */ +#define CONFIG_SYS_MAX_FLASH_SECT	512	/* sectors per device */ +#define CONFIG_SYS_FLASH_ERASE_TOUT	60000	/* Flash Erase Timeout (ms) */ +#define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* Flash Write Timeout (ms) */ + +#define CONFIG_BOARD_EARLY_INIT_F	/* call board_early_init_f function */ +#define CONFIG_BOARD_EARLY_INIT_R	/* call board_early_init_r function */ + +#define CONFIG_SYS_INIT_RAM_LOCK +#define CONFIG_SYS_INIT_RAM_ADDR	0xffd00000	/* Initial L1 address */ +#define CONFIG_SYS_INIT_RAM_SIZE	0x00004000/* Size of used area in RAM */ +#define CONFIG_SYS_GBL_DATA_OFFSET	(CONFIG_SYS_INIT_RAM_SIZE - \ +					GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_INIT_SP_OFFSET	CONFIG_SYS_GBL_DATA_OFFSET + +#define CONFIG_SYS_MONITOR_LEN	(512 * 1024)	  /* Reserve 512 kB for Mon */ +#define CONFIG_SYS_MALLOC_LEN	(6 * 1024 * 1024) /* Reserved for malloc */ + +#define CONFIG_SYS_NAND_BASE		0xffa00000 +#define CONFIG_SYS_NAND_BASE_PHYS	CONFIG_SYS_NAND_BASE + +#define CONFIG_SYS_NAND_BASE_LIST	{ CONFIG_SYS_NAND_BASE } +#define CONFIG_SYS_MAX_NAND_DEVICE	1 +#define CONFIG_MTD_NAND_VERIFY_WRITE +#define CONFIG_CMD_NAND +#define CONFIG_NAND_FSL_ELBC +#define CONFIG_SYS_NAND_BLOCK_SIZE	(128 * 1024) + +/* NAND flash config */ +#define CONFIG_SYS_NAND_BR_PRELIM  (BR_PHYS_ADDR(CONFIG_SYS_NAND_BASE_PHYS) \ +				| (2<<BR_DECC_SHIFT)	/* Use HW ECC */ \ +				| BR_PS_8		/* Port Size = 8bit */ \ +				| BR_MS_FCM		/* MSEL = FCM */ \ +				| BR_V)			/* valid */ +#define CONFIG_SYS_NAND_OR_PRELIM  (OR_AM_256KB		/* length 256K */ \ +				| OR_FCM_PGS \ +				| OR_FCM_CSCT \ +				| OR_FCM_CST \ +				| OR_FCM_CHT \ +				| OR_FCM_SCY_1 \ +				| OR_FCM_TRLX \ +				| OR_FCM_EHTR) + +#define CONFIG_SYS_BR0_PRELIM	CONFIG_FLASH_BR_PRELIM	/* NOR Base Address */ +#define CONFIG_SYS_OR0_PRELIM	CONFIG_FLASH_OR_PRELIM	/* NOR Options */ +#define CONFIG_SYS_BR1_PRELIM	CONFIG_SYS_NAND_BR_PRELIM +#define CONFIG_SYS_OR1_PRELIM	CONFIG_SYS_NAND_OR_PRELIM /* NAND Options */ + +/* Serial Port */ +#define CONFIG_CONS_INDEX		1 +#undef	CONFIG_SERIAL_SOFTWARE_FIFO +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE	1 +#define CONFIG_SYS_NS16550_CLK		get_bus_freq(0) + +#define CONFIG_SYS_BAUDRATE_TABLE	\ +	{300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200} + +#define CONFIG_SYS_NS16550_COM1	(CONFIG_SYS_CCSRBAR + 0x4500) +#define CONFIG_SYS_NS16550_COM2	(CONFIG_SYS_CCSRBAR + 0x4600) + +/* Use the HUSH parser */ +#define CONFIG_SYS_HUSH_PARSER + +/* + * Pass open firmware flat tree + */ +#define CONFIG_OF_LIBFDT +#define CONFIG_OF_BOARD_SETUP +#define CONFIG_OF_STDOUT_VIA_ALIAS + +/* new uImage format support */ +#define CONFIG_FIT +#define CONFIG_FIT_VERBOSE	/* enable fit_format_{error,warning}() */ + +/* I2C */ +#define CONFIG_FSL_I2C		/* Use FSL common I2C driver */ +#define CONFIG_HARD_I2C		/* I2C with hardware support */ +#define CONFIG_I2C_MULTI_BUS +#define CONFIG_SYS_I2C_SPEED	400000	/* I2C speed and slave address */ +#define CONFIG_SYS_I2C_SLAVE		0x7F +#define CONFIG_SYS_I2C_OFFSET		0x3000 +#define CONFIG_SYS_I2C2_OFFSET		0x3100 + +/* + * I2C2 EEPROM + */ +#define CONFIG_ID_EEPROM +#ifdef CONFIG_ID_EEPROM +#define CONFIG_SYS_I2C_EEPROM_NXID +#endif +#define CONFIG_SYS_I2C_EEPROM_ADDR		0x50 +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1 +#define CONFIG_SYS_EEPROM_BUS_NUM		0 + +#define CONFIG_CMD_I2C + +/* + * General PCI + * Memory space is mapped 1-1, but I/O space must start from 0. + */ + +/* controller 3, Slot 1, tgtid 3, Base address b000 */ +#define CONFIG_SYS_PCIE3_NAME		"Slot 3" +#define CONFIG_SYS_PCIE3_MEM_VIRT	0x80000000 +#define CONFIG_SYS_PCIE3_MEM_BUS	0x80000000 +#define CONFIG_SYS_PCIE3_MEM_PHYS	0x80000000 +#define CONFIG_SYS_PCIE3_MEM_SIZE	0x20000000	/* 512M */ +#define CONFIG_SYS_PCIE3_IO_VIRT	0xffc00000 +#define CONFIG_SYS_PCIE3_IO_BUS		0x00000000 +#define CONFIG_SYS_PCIE3_IO_PHYS	0xffc00000 +#define CONFIG_SYS_PCIE3_IO_SIZE	0x00010000	/* 64k */ + +/* controller 2, direct to uli, tgtid 2, Base address 9000 */ +#define CONFIG_SYS_PCIE2_NAME		"Slot 2" +#define CONFIG_SYS_PCIE2_MEM_VIRT	0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_BUS	0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_PHYS	0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_SIZE	0x20000000	/* 512M */ +#define CONFIG_SYS_PCIE2_IO_VIRT	0xffc10000 +#define CONFIG_SYS_PCIE2_IO_BUS		0x00000000 +#define CONFIG_SYS_PCIE2_IO_PHYS	0xffc10000 +#define CONFIG_SYS_PCIE2_IO_SIZE	0x00010000	/* 64k */ + +/* controller 1, Slot 2, tgtid 1, Base address a000 */ +#define CONFIG_SYS_PCIE1_NAME		"Slot 1" +#define CONFIG_SYS_PCIE1_MEM_VIRT	0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_BUS	0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_PHYS	0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_SIZE	0x20000000	/* 512M */ +#define CONFIG_SYS_PCIE1_IO_VIRT	0xffc20000 +#define CONFIG_SYS_PCIE1_IO_BUS		0x00000000 +#define CONFIG_SYS_PCIE1_IO_PHYS	0xffc20000 +#define CONFIG_SYS_PCIE1_IO_SIZE	0x00010000	/* 64k */ + +#if defined(CONFIG_PCI) +#define CONFIG_E1000		/* Defind e1000 pci Ethernet card */ +#define CONFIG_PCI_PNP		/* do pci plug-and-play */ +#define CONFIG_PCI_SCAN_SHOW	/* show pci devices on startup */ +#endif	/* CONFIG_PCI */ + +/* + * Environment + */ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_ENV_IS_IN_FLASH +#if CONFIG_SYS_MONITOR_BASE > 0xfff80000 +#define CONFIG_ENV_ADDR		0xfff80000 +#else +#define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE) +#endif +#define CONFIG_ENV_SIZE		0x2000 +#define CONFIG_ENV_SECT_SIZE	0x20000 /* 128K (one sector) */ + +#define CONFIG_LOADS_ECHO		/* echo on for serial download */ +#define CONFIG_SYS_LOADS_BAUD_CHANGE	/* allow baudrate change */ + +/* + * Command line configuration. + */ +#include <config_cmd_default.h> + +#define CONFIG_CMD_IRQ +#define CONFIG_CMD_PING +#define CONFIG_CMD_MII +#define CONFIG_CMD_SETEXPR +#define CONFIG_CMD_REGINFO + +#if defined(CONFIG_PCI) +#define CONFIG_CMD_PCI +#define CONFIG_CMD_NET +#endif + +/* + * USB + */ +#define CONFIG_HAS_FSL_DR_USB +#ifdef CONFIG_HAS_FSL_DR_USB +#define CONFIG_USB_EHCI + +#ifdef CONFIG_USB_EHCI +#define CONFIG_CMD_USB +#define CONFIG_EHCI_HCD_INIT_AFTER_RESET +#define CONFIG_USB_EHCI_FSL +#define CONFIG_USB_STORAGE +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_FAT +#define CONFIG_DOS_PARTITION +#endif +#endif + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP			/* undef to save memory	*/ +#define CONFIG_CMDLINE_EDITING		/* Command-line editing */ +#define CONFIG_SYS_LOAD_ADDR	0x2000000	/* default load address */ +#define CONFIG_SYS_PROMPT	"=> "		/* Monitor Command Prompt */ +#if defined(CONFIG_CMD_KGDB) +#define CONFIG_SYS_CBSIZE	1024		/* Console I/O Buffer Size */ +#else +#define CONFIG_SYS_CBSIZE	256		/* Console I/O Buffer Size */ +#endif +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT)+16) +#define CONFIG_SYS_MAXARGS	16		/* max number of command args */ +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE	CONFIG_SYS_CBSIZE +#define CONFIG_SYS_HZ	1000		/* decrementer freq: 1ms ticks */ + +/* + * For booting Linux, the board info and command line data + * have to be in the first 64 MB of memory, since this is + * the maximum mapped by the Linux kernel during initialization. + */ +#define CONFIG_SYS_BOOTMAPSZ	(64 << 20)   /* Initial Memory map for Linux*/ +#define CONFIG_SYS_BOOTM_LEN	(64 << 20)   /* Increase max gunzip size */ + +/* + * Environment Configuration + */ +#define CONFIG_BOOTFILE		"uImage" +#define CONFIG_UBOOTPATH	(u-boot.bin) /* U-Boot image on TFTP server */ + +/* default location for tftp and bootm */ +#define CONFIG_LOADADDR		1000000 + +#define CONFIG_BOOTDELAY -1	/* -1 disables auto-boot */ + +#define CONFIG_BAUDRATE	115200 + +/* Qman/Bman */ +#define CONFIG_SYS_DPAA_QBMAN		/* support Q/Bman */ +#define CONFIG_SYS_QMAN_MEM_BASE	0xff000000 +#define CONFIG_SYS_QMAN_MEM_PHYS	CONFIG_SYS_QMAN_MEM_BASE +#define CONFIG_SYS_QMAN_MEM_SIZE	0x00200000 +#define CONFIG_SYS_BMAN_MEM_BASE	0xff200000 +#define CONFIG_SYS_BMAN_MEM_PHYS	CONFIG_SYS_BMAN_MEM_BASE +#define CONFIG_SYS_BMAN_MEM_SIZE	0x00200000 + +/* For FM */ +#define CONFIG_SYS_DPAA_FMAN +#define CONFIG_PHY_GIGE		/* Include GbE speed/duplex detection */ + +#ifdef CONFIG_SYS_DPAA_FMAN +#define CONFIG_FMAN_ENET +#define CONFIG_PHY_ATHEROS +#endif + +/* Default address of microcode for the Linux Fman driver */ +/* QE microcode/firmware address */ +#define CONFIG_SYS_QE_FMAN_FW_IN_NOR +#define CONFIG_SYS_QE_FMAN_FW_ADDR	0xeff40000 +#define CONFIG_SYS_QE_FMAN_FW_LENGTH	0x10000 +#define CONFIG_SYS_FDT_PAD		(0x3000 + CONFIG_SYS_QE_FMAN_FW_LENGTH) + +#ifdef CONFIG_FMAN_ENET +#define CONFIG_SYS_FM1_DTSEC1_PHY_ADDR	0x1 +#define CONFIG_SYS_FM1_DTSEC2_PHY_ADDR	0x2 + +#define CONFIG_SYS_TBIPA_VALUE	8 +#define CONFIG_MII		/* MII PHY management */ +#define CONFIG_ETHPRIME		"FM1@DTSEC1" +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS	\ +	"hwconfig=usb1:dr_mode=host,phy_type=ulpi\0" + +#endif	/* __CONFIG_H */ diff --git a/include/configs/P2041RDB.h b/include/configs/P2041RDB.h index 9cd3a7cb3..4ea871736 100644 --- a/include/configs/P2041RDB.h +++ b/include/configs/P2041RDB.h @@ -77,6 +77,7 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #define CONFIG_SYS_DPAA_RMAN		/* RMan */  #define CONFIG_FSL_LAW			/* Use common FSL init code */ diff --git a/include/configs/P3041DS.h b/include/configs/P3041DS.h index ce8f9b0b2..dd2b9c34e 100644 --- a/include/configs/P3041DS.h +++ b/include/configs/P3041DS.h @@ -40,7 +40,7 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #define CONFIG_ICS307_REFCLK_HZ		25000000  /* ICS307 ref clk freq */  #include "corenet_ds.h" diff --git a/include/configs/P4080DS.h b/include/configs/P4080DS.h index 53979dddf..48acee499 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -36,7 +36,7 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #define CONFIG_ICS307_REFCLK_HZ		33333000  /* ICS307 ref clk freq */  #include "corenet_ds.h" diff --git a/include/configs/P5020DS.h b/include/configs/P5020DS.h index 778230d33..d1e27c42d 100644 --- a/include/configs/P5020DS.h +++ b/include/configs/P5020DS.h @@ -41,7 +41,7 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #define CONFIG_ICS307_REFCLK_HZ		25000000  /* ICS307 ref clk freq */  #include "corenet_ds.h" diff --git a/include/configs/a3m071.h b/include/configs/a3m071.h index e9af82566..8f29229cd 100644 --- a/include/configs/a3m071.h +++ b/include/configs/a3m071.h @@ -426,6 +426,7 @@  #define CONFIG_SPL_BSS_MAX_SIZE		(64 << 10)  #define CONFIG_SPL_OS_BOOT +#define CONFIG_SPL_ENV_SUPPORT  /* Place patched DT blob (fdt) at this address */  #define CONFIG_SYS_SPL_ARGS_ADDR	0x01800000 diff --git a/include/configs/ac14xx.h b/include/configs/ac14xx.h index 7cb10fb01..381bcdda0 100644 --- a/include/configs/ac14xx.h +++ b/include/configs/ac14xx.h @@ -72,7 +72,7 @@  #define CONFIG_SYS_MAX_RAM_SIZE		0x20000000  /* - * DDR Controller Configuration XXX TODO + * DDR Controller Configuration   *   * SYS_CFG:   *	[31:31]	MDDRC Soft Reset:	Diabled @@ -265,7 +265,6 @@  /*   * CS related parameters - * TODO document these   */  /* CS0 Flash */  #define CONFIG_SYS_CS0_CFG		0x00031110 @@ -331,8 +330,6 @@  #endif  #define CONFIG_BAUDRATE			115200	/* ... at 115200 bps */ -#define CONFIG_SYS_BAUDRATE_TABLE  \ -	{300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 115200}  #define CONSOLE_FIFO_TX_SIZE		FIFOC_PSC3_TX_SIZE  #define CONSOLE_FIFO_TX_ADDR		FIFOC_PSC3_TX_ADDR @@ -497,30 +494,26 @@  #define CONFIG_ENV_OVERWRITE  #define CONFIG_TIMESTAMP -#define CONFIG_HOSTNAME		ac14xx -#define CONFIG_BOOTFILE		"ac14xx/uImage" -#define CONFIG_ROOTPATH		"/opt/eldk/ppc_6xx" -  /* default load addr for tftp and bootm */  #define CONFIG_LOADADDR		400000  #define CONFIG_BOOTDELAY	2	/* -1 disables auto-boot */ -/* XXX TODO need to specify the builtin environment */ +/* the builtin environment and standard greeting */  #define CONFIG_PREBOOT	"echo;"	\  	"echo Type \\\"run flash_nfs\\\" to mount root filesystem over NFS;" \  	"echo"  #define CONFIG_EXTRA_ENV_SETTINGS_DEVEL					\ -	"muster_nr=00\0"						\ +	"muster_nr=-00\0"						\  	"fromram=run ramargs addip addtty; "				\ -		"tftp ${fdt_addr_r} k6m2/ac14xx.dtb-${muster_nr}; "	\ -		"tftp ${kernel_addr_r} k6m2/uImage-${muster_nr}; "	\ -		"tftp ${ramdisk_addr_r} k6m2/uFS-${muster_nr}; "	\ +		"tftp ${fdt_addr_r} ac14xx/ac14xx.dtb${muster_nr}; "	\ +		"tftp ${kernel_addr_r} ac14xx/uImage${muster_nr}; "	\ +		"tftp ${ramdisk_addr_r} ac14xx/uFS${muster_nr}; "	\  		"bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}\0" \  	"fromnfs=run nfsargs addip addtty; "				\ -		"tftp ${fdt_addr_r} k6m2/ac14xx.dtb-${muster_nr}; "	\ -		"tftp ${kernel_addr_r} k6m2/uImage-${muster_nr}; "	\ +		"tftp ${fdt_addr_r} ac14xx/ac14xx.dtb${muster_nr}; "	\ +		"tftp ${kernel_addr_r} ac14xx/uImage${muster_nr}; "	\  		"bootm ${kernel_addr_r} - ${fdt_addr_r}\0"		\  	"fromflash=run nfsargs addip addtty; "				\  		"bootm fc020000 - fc000000\0"				\ @@ -548,12 +541,11 @@  	"u-boot=ac14xx/u-boot.bin\0"					\  	"bootfile=ac14xx/uImage\0"					\  	"fdtfile=ac14xx/ac14xx.dtb\0"					\ -	"rootpath=/opt/eldk/ppc_6xx\n"					\  	"netdev=eth0\0"							\  	"consdev=ttyPSC0\0"						\  	"hostname=ac14xx\0"						\  	"nfsargs=setenv bootargs root=/dev/nfs rw "			\ -		"nfsroot=${serverip}:${rootpath}-${muster_nr}\0"	\ +		"nfsroot=${serverip}:${rootpath}${muster_nr}\0"	\  	"ramargs=setenv bootargs root=/dev/ram rw\0"			\  	"addip=setenv bootargs ${bootargs} "				\  		"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}"	\ @@ -583,6 +575,8 @@  #define CONFIG_BOOTCOMMAND	"run production" +#define CONFIG_ARP_TIMEOUT	200UL +  #define CONFIG_FIT		1  #define CONFIG_OF_LIBFDT	1  #define CONFIG_OF_BOARD_SETUP	1 diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 737e19ee6..c5a6d4b31 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -60,7 +60,7 @@  	"rdaddr=0x81000000\0" \  	"bootdir=/boot\0" \  	"bootfile=uImage\0" \ -	"fdtfile=\0" \ +	"fdtfile=undefined\0" \  	"console=ttyO0,115200n8\0" \  	"optargs=\0" \  	"mtdids=" MTDIDS_DEFAULT "\0" \ @@ -145,8 +145,9 @@  		"if test $board_name = A33515BB; then " \  			"setenv fdtfile am335x-evm.dtb; fi; " \  		"if test $board_name = A335X_SK; then " \ -			"setenv fdtfile am335x-evmsk.dtb; fi\0" \ - +			"setenv fdtfile am335x-evmsk.dtb; fi; " \ +		"if test $fdtfile = undefined; then " \ +			"echo WARNING: Could not determine device tree to use; fi; \0"  #endif  #define CONFIG_BOOTCOMMAND \ @@ -355,6 +356,7 @@  #define CONFIG_SPL_GPIO_SUPPORT  #define CONFIG_SPL_YMODEM_SUPPORT  #define CONFIG_SPL_NET_SUPPORT +#define CONFIG_SPL_ENV_SUPPORT  #define CONFIG_SPL_NET_VCI_STRING	"AM335x U-Boot SPL"  #define CONFIG_SPL_ETH_SUPPORT  #define CONFIG_SPL_SPI_SUPPORT diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h index 8d2673dac..b4b1c3196 100644 --- a/include/configs/at91sam9n12ek.h +++ b/include/configs/at91sam9n12ek.h @@ -167,6 +167,10 @@  #define CONFIG_DOS_PARTITION  #endif +/* Ethernet */ +#define CONFIG_KS8851_MLL +#define CONFIG_KS8851_MLL_BASEADDR	0x30000000 /* use NCS2 */ +  #define CONFIG_SYS_LOAD_ADDR		0x22000000 /* load address */  #define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h index 2fefdc80d..288ef8df7 100644 --- a/include/configs/coreboot.h +++ b/include/configs/coreboot.h @@ -168,6 +168,13 @@   */  #include <config_cmd_default.h> +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE	(16 << 20) +#define CONFIG_TRACE_EARLY_SIZE		(8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR		0x01400000 +  #define CONFIG_CMD_BDI  #define CONFIG_CMD_BOOTD  #define CONFIG_CMD_CONSOLE diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index 0eea28c80..c11f00553 100644 --- a/include/configs/dra7xx_evm.h +++ b/include/configs/dra7xx_evm.h @@ -41,4 +41,7 @@  #define CONFIG_BAUDRATE			115200  #define CONFIG_SYS_OMAP_ABE_SYSCK + +#define CONSOLEDEV		"ttyO0" +  #endif /* __CONFIG_DRA7XX_EVM_H */ diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index 41d6cf9d1..e2a096b64 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -43,6 +43,14 @@  #define CONFIG_OF_CONTROL  #define CONFIG_OF_SEPARATE +/* Allow tracing to be enabled */ +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE	(16 << 20) +#define CONFIG_TRACE_EARLY_SIZE		(8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR		0x50000000 +  /* Keep L2 Cache Disabled */  #define CONFIG_SYS_DCACHE_OFF @@ -82,24 +90,34 @@  #define CONFIG_BAUDRATE			115200  #define EXYNOS5_DEFAULT_UART_OFFSET	0x010000 +/* Enable keyboard */ +#define CONFIG_CROS_EC		/* CROS_EC protocol */ +#define CONFIG_CROS_EC_SPI		/* Support CROS_EC over SPI */ +#define CONFIG_CROS_EC_I2C		/* Support CROS_EC over I2C */ +#define CONFIG_CROS_EC_KEYB	/* CROS_EC keyboard input */ +#define CONFIG_CMD_CROS_EC +#define CONFIG_KEYBOARD +  /* Console configuration */  #define CONFIG_CONSOLE_MUX  #define CONFIG_SYS_CONSOLE_IS_IN_ENV  #define EXYNOS_DEVICE_SETTINGS \ -		"stdin=serial\0" \ +		"stdin=serial,cros-ec-keyb\0" \  		"stdout=serial,lcd\0" \  		"stderr=serial,lcd\0"  #define CONFIG_EXTRA_ENV_SETTINGS \  	EXYNOS_DEVICE_SETTINGS -#define TZPC_BASE_OFFSET		0x10000 -  /* SD/MMC configuration */  #define CONFIG_GENERIC_MMC  #define CONFIG_MMC  #define CONFIG_SDHCI  #define CONFIG_S5P_SDHCI +#define CONFIG_DWMMC +#define CONFIG_EXYNOS_DWMMC +#define CONFIG_SUPPORT_EMMC_BOOT +  #define CONFIG_BOARD_EARLY_INIT_F @@ -232,6 +250,10 @@  #define SPI_FLASH_UBOOT_POS		(CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE)  #define CONFIG_DOS_PARTITION +#define CONFIG_EFI_PARTITION +#define CONFIG_CMD_PART +#define CONFIG_PARTITION_UUIDS +  #define CONFIG_IRAM_STACK	0x02050000 @@ -262,6 +284,7 @@  #define CONFIG_CMD_SF  #define CONFIG_CMD_SPI  #define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SPI_FLASH_GIGADEVICE  #define CONFIG_SF_DEFAULT_MODE		SPI_MODE_0  #define CONFIG_SF_DEFAULT_SPEED		50000000  #define EXYNOS5_SPI_NUM_CONTROLLERS	5 diff --git a/include/configs/lacie_kw.h b/include/configs/lacie_kw.h index 09b5798d5..e2b3b2118 100644 --- a/include/configs/lacie_kw.h +++ b/include/configs/lacie_kw.h @@ -120,10 +120,14 @@  #endif  /* + * Enable platform initialisation via misc_init_r() function + */ +#define CONFIG_MISC_INIT_R + +/*   * Ethernet Driver configuration   */  #ifdef CONFIG_CMD_NET -#define CONFIG_MISC_INIT_R /* Call misc_init_r() to initialize MAC address */  #define CONFIG_MVGBE_PORTS		{1, 0} /* enable port 0 only */  #define CONFIG_NETCONSOLE  #endif @@ -153,6 +157,9 @@  #define CONFIG_SYS_I2C_EEPROM_ADDR		0x50  #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4 /* 16-byte page size */  #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1 /* 8-bit device address */ +#if defined(CONFIG_NET2BIG_V2) +#define CONFIG_SYS_I2C_G762_ADDR		0x3e +#endif  #endif /* CONFIG_CMD_I2C */  /* diff --git a/include/configs/omap4_common.h b/include/configs/omap4_common.h index 3e5d36b21..2fa4382c3 100644 --- a/include/configs/omap4_common.h +++ b/include/configs/omap4_common.h @@ -150,6 +150,7 @@  	"console=ttyO2,115200n8\0" \  	"fdt_high=0xffffffff\0" \  	"fdtaddr=0x80f80000\0" \ +	"fdtfile=undefined\0" \  	"bootpart=0:2\0" \  	"bootdir=/boot\0" \  	"bootfile=zImage\0" \ @@ -177,8 +178,12 @@  			"setenv fdtfile omap4-sdp.dtb; fi; " \  		"if test $board_name = panda; then " \  			"setenv fdtfile omap4-panda.dtb; fi;" \ +		"if test $board_name = panda-a4; then " \ +			"setenv fdtfile omap4-panda-a4.dtb; fi;" \  		"if test $board_name = panda-es; then " \ -			"setenv fdtfile omap4-panda-es.dtb; fi; \0" \ +			"setenv fdtfile omap4-panda-es.dtb; fi;" \ +		"if test $fdtfile = undefined; then " \ +			"echo WARNING: Could not determine device tree to use; fi; \0" \  	"loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}\0" \  #define CONFIG_BOOTCOMMAND \ diff --git a/include/configs/omap5_common.h b/include/configs/omap5_common.h index ddf2ad4fc..b87ee4228 100644 --- a/include/configs/omap5_common.h +++ b/include/configs/omap5_common.h @@ -136,9 +136,10 @@  #define CONFIG_EXTRA_ENV_SETTINGS \  	"loadaddr=0x82000000\0" \ -	"console=ttyO2,115200n8\0" \ +	"console=" CONSOLEDEV ",115200n8\0" \  	"fdt_high=0xffffffff\0" \  	"fdtaddr=0x80f80000\0" \ +	"fdtfile=undefined\0" \  	"bootpart=0:2\0" \  	"bootdir=/boot\0" \  	"bootfile=zImage\0" \ @@ -166,7 +167,11 @@  		"bootz ${loadaddr} - ${fdtaddr}\0" \  	"findfdt="\  		"if test $board_name = omap5_uevm; then " \ -			"setenv fdtfile omap5-uevm.dtb; fi;\0 " \ +			"setenv fdtfile omap5-uevm.dtb; fi; " \ +		"if test $board_name = dra7xx; then " \ +			"setenv fdtfile dra7-evm.dtb; fi;" \ +		"if test $fdtfile = undefined; then " \ +			"echo WARNING: Could not determine device tree to use; fi; \0" \  	"loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile};\0" \  #define CONFIG_BOOTCOMMAND \ diff --git a/include/configs/omap5_uevm.h b/include/configs/omap5_uevm.h index dea05bc91..46dacc207 100644 --- a/include/configs/omap5_uevm.h +++ b/include/configs/omap5_uevm.h @@ -53,7 +53,9 @@  #define CONFIG_PARTITION_UUIDS  #define CONFIG_CMD_PART -#define CONFIG_SYS_PROMPT		"OMAP5430 EVM # " +#define CONFIG_SYS_PROMPT		"OMAP5432 uEVM # " + +#define CONSOLEDEV		"ttyO2"  #define CONFIG_OMAP_PLATFORM_RESET_TIME_MAX_USEC	16296  #endif /* __CONFIG_OMAP5_EVM_H */ diff --git a/include/configs/origen.h b/include/configs/origen.h index ff2b24d97..e179911d0 100644 --- a/include/configs/origen.h +++ b/include/configs/origen.h @@ -96,6 +96,8 @@  #define CONFIG_SPL  #define COPY_BL2_FNPTR_ADDR	0x02020030 +#define CONFIG_SPL_TEXT_BASE	0x02021410 +  #define CONFIG_BOOTCOMMAND	"fatload mmc 0 40007000 uImage; bootm 40007000"  /* Miscellaneous configurable options */ diff --git a/include/configs/pcm051.h b/include/configs/pcm051.h index 2ecd1050c..9b16c4782 100644 --- a/include/configs/pcm051.h +++ b/include/configs/pcm051.h @@ -231,6 +231,7 @@  #define CONFIG_SPL_GPIO_SUPPORT  #define CONFIG_SPL_YMODEM_SUPPORT  #define CONFIG_SPL_NET_SUPPORT +#define CONFIG_SPL_ENV_SUPPORT  #define CONFIG_SPL_NET_VCI_STRING	"pcm051 U-Boot SPL"  #define CONFIG_SPL_ETH_SUPPORT  #define CONFIG_SPL_SPI_SUPPORT diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 788207d00..98dd08330 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -22,6 +22,19 @@  #ifndef __CONFIG_H  #define __CONFIG_H +#ifdef FTRACE +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE	(16 << 20) +#define CONFIG_TRACE_EARLY_SIZE		(8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR		0x00100000 + +#endif + +#define CONFIG_BOOTSTAGE +#define CONFIG_BOOTSTAGE_REPORT +  /* Number of bits in a C 'long' on this architecture */  #define CONFIG_SANDBOX_BITS_PER_LONG	64 @@ -30,6 +43,8 @@  #define CONFIG_OF_LIBFDT  #define CONFIG_LMB  #define CONFIG_FIT +#define CONFIG_FIT_SIGNATURE +#define CONFIG_RSA  #define CONFIG_CMD_FDT  #define CONFIG_FS_FAT diff --git a/include/configs/smdkv310.h b/include/configs/smdkv310.h index b796b46a7..5e430660f 100644 --- a/include/configs/smdkv310.h +++ b/include/configs/smdkv310.h @@ -95,6 +95,8 @@  #define CONFIG_SPL  #define COPY_BL2_FNPTR_ADDR	0x00002488 +#define CONFIG_SPL_TEXT_BASE	0x02021410 +  #define CONFIG_BOOTCOMMAND	"fatload mmc 0 40007000 uImage; bootm 40007000"  /* Miscellaneous configurable options */ diff --git a/include/configs/t4qds.h b/include/configs/t4qds.h index aa90249f0..92b2179ca 100644 --- a/include/configs/t4qds.h +++ b/include/configs/t4qds.h @@ -33,6 +33,15 @@  #define CONFIG_PBLRCW_CONFIG $(SRCTREE)/board/freescale/t4qds/t4_rcw.cfg  #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +/* Set 1M boot space */ +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR (CONFIG_SYS_TEXT_BASE & 0xfff00000) +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS \ +		(0x300000000ull | CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR) +#define CONFIG_RESET_VECTOR_ADDRESS 0xfffffffc +#define CONFIG_SYS_NO_FLASH +#endif +  #define CONFIG_CMD_REGINFO  /* High Level Configuration Options */ @@ -65,20 +74,22 @@  #define CONFIG_SYS_SRIO  #define CONFIG_SRIO1			/* SRIO port 1 */  #define CONFIG_SRIO2			/* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER  #define CONFIG_FSL_LAW			/* Use common FSL init code */  #define CONFIG_ENV_OVERWRITE  #ifdef CONFIG_SYS_NO_FLASH +#if !defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) && !defined(CONFIG_RAMBOOT_PBL)  #define CONFIG_ENV_IS_NOWHERE +#endif  #else  #define CONFIG_FLASH_CFI_DRIVER  #define CONFIG_SYS_FLASH_CFI  #define CONFIG_SYS_FLASH_USE_BUFFER_WRITE  #endif -#ifndef CONFIG_SYS_NO_FLASH  #if defined(CONFIG_SPIFLASH)  #define CONFIG_SYS_EXTRA_ENV_RELOC  #define CONFIG_ENV_IS_IN_SPI_FLASH @@ -100,18 +111,18 @@  #define CONFIG_ENV_IS_IN_NAND  #define CONFIG_ENV_SIZE			CONFIG_SYS_NAND_BLOCK_SIZE  #define CONFIG_ENV_OFFSET		(5 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +#define CONFIG_ENV_IS_IN_REMOTE +#define CONFIG_ENV_ADDR		0xffe20000 +#define CONFIG_ENV_SIZE		0x2000 +#elif defined(CONFIG_ENV_IS_NOWHERE) +#define CONFIG_ENV_SIZE		0x2000  #else  #define CONFIG_ENV_IS_IN_FLASH  #define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE)  #define CONFIG_ENV_SIZE		0x2000  #define CONFIG_ENV_SECT_SIZE	0x20000 /* 128K (one sector) */  #endif -#else /* CONFIG_SYS_NO_FLASH */ -#define CONFIG_ENV_SIZE                0x2000 -#define CONFIG_ENV_SECT_SIZE   0x20000 /* 128K (one sector) */ -#endif - -  #define CONFIG_SYS_CLK_FREQ	get_board_sys_clk()  #define CONFIG_DDR_CLK_FREQ	get_board_ddr_clk() @@ -633,6 +644,16 @@ unsigned long get_board_ddr_clk(void);  #elif defined(CONFIG_NAND)  #define CONFIG_SYS_QE_FMAN_FW_IN_NAND  #define CONFIG_SYS_QE_FMAN_FW_ADDR	(6 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +/* + * Slave has no ucode locally, it can fetch this from remote. When implementing + * in two corenet boards, slave's ucode could be stored in master's memory + * space, the address can be mapped from slave TLB->slave LAW-> + * slave SRIO or PCIE outbound window->master inbound window-> + * master LAW->the ucode address in master's memory space. + */ +#define CONFIG_SYS_QE_FMAN_FW_IN_REMOTE +#define CONFIG_SYS_QE_FMAN_FW_ADDR	0xFFE00000  #else  #define CONFIG_SYS_QE_FMAN_FW_IN_NOR  #define CONFIG_SYS_QE_FMAN_FW_ADDR		0xEFF40000 diff --git a/include/configs/trats.h b/include/configs/trats.h index fd58558be..c70838b91 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -146,7 +146,8 @@  #define CONFIG_DFU_ALT \  	"u-boot mmc 80 400;" \ -	"uImage ext4 0 2\0" \ +	"uImage ext4 0 2;" \ +	"exynos4210-trats.dtb ext4 0 2\0"  #define CONFIG_ENV_OVERWRITE  #define CONFIG_SYS_CONSOLE_INFO_QUIET @@ -154,7 +155,7 @@  #define CONFIG_EXTRA_ENV_SETTINGS \  	"bootk=" \ -		"run loaduimage; bootm 0x40007FC0\0" \ +		"run loaddtb; run loaduimage; bootm 0x40007FC0 - ${fdtaddr}\0" \  	"updatemmc=" \  		"mmc boot 0 1 1 1; mmc write 0 0x42008000 0 0x200;" \  		"mmc boot 0 1 1 0\0" \ @@ -177,7 +178,7 @@  	"mmcboot=" \  		"setenv bootargs root=/dev/mmcblk${mmcdev}p${mmcrootpart} " \  		"${lpj} rootwait ${console} ${meminfo} ${opts} ${lcdinfo}; " \ -		"run loaduimage; bootm 0x40007FC0\0" \ +		"run loaddtb; run loaduimage; bootm 0x40007FC0 - ${fdtaddr}\0" \  	"bootchart=setenv opts init=/sbin/bootchartd; run bootcmd\0" \  	"boottrace=setenv opts initcall_debug; run bootcmd\0" \  	"mmcoops=mmc read 0 0x40000000 0x40 8; md 0x40000000 0x400\0" \ @@ -188,6 +189,8 @@  	"nfsroot=/nfsroot/arm\0" \  	"bootblock=" CONFIG_BOOTBLOCK "\0" \  	"loaduimage=ext4load mmc ${mmcdev}:${mmcbootpart} 0x40007FC0 uImage\0" \ +	"loaddtb=ext4load mmc ${mmcdev}:${mmcbootpart} ${fdtaddr}" \ +		"${fdtfile}\0" \  	"mmcdev=0\0" \  	"mmcbootpart=2\0" \  	"mmcrootpart=5\0" \ @@ -212,7 +215,10 @@  		   " /${splfile} ${spl_imgaddr} ${spl_imgsize};" \  		   "setenv spl_imgsize;" \  		   "setenv spl_imgaddr;" \ -		   "setenv spl_addr_tmp;\0" +		   "setenv spl_addr_tmp;\0" \ +	"fdtaddr=40800000\0" \ +	"fdtfile=exynos4210-trats.dtb\0" +  /* Miscellaneous configurable options */  #define CONFIG_SYS_LONGHELP		/* undef to save memory */ @@ -322,4 +328,7 @@  #define CONFIG_USB_GADGET_MASS_STORAGE  #endif +/* Pass open firmware flat tree */ +#define CONFIG_OF_LIBFDT    1 +  #endif	/* __CONFIG_H */ diff --git a/include/cros_ec.h b/include/cros_ec.h new file mode 100644 index 000000000..335d5b4e6 --- /dev/null +++ b/include/cros_ec.h @@ -0,0 +1,449 @@ +/* + * Chromium OS cros_ec driver + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CROS_EC_H +#define _CROS_EC_H + +#include <linux/compiler.h> +#include <ec_commands.h> +#include <fdtdec.h> +#include <cros_ec_message.h> + +/* Which interface is the device on? */ +enum cros_ec_interface_t { +	CROS_EC_IF_NONE, +	CROS_EC_IF_SPI, +	CROS_EC_IF_I2C, +	CROS_EC_IF_LPC,	/* Intel Low Pin Count interface */ +}; + +/* Our configuration information */ +struct cros_ec_dev { +	enum cros_ec_interface_t interface; +	struct spi_slave *spi;		/* Our SPI slave, if using SPI */ +	int node;                       /* Our node */ +	int parent_node;		/* Our parent node (interface) */ +	unsigned int cs;		/* Our chip select */ +	unsigned int addr;		/* Device address (for I2C) */ +	unsigned int bus_num;		/* Bus number (for I2C) */ +	unsigned int max_frequency;	/* Maximum interface frequency */ +	struct fdt_gpio_state ec_int;	/* GPIO used as EC interrupt line */ +	int cmd_version_is_supported;   /* Device supports command versions */ +	int optimise_flash_write;	/* Don't write erased flash blocks */ + +	/* +	 * These two buffers will always be dword-aligned and include enough +	 * space for up to 7 word-alignment bytes also, so we can ensure that +	 * the body of the message is always dword-aligned (64-bit). +	 * +	 * We use this alignment to keep ARM and x86 happy. Probably word +	 * alignment would be OK, there might be a small performance advantage +	 * to using dword. +	 */ +	uint8_t din[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))] +		__aligned(sizeof(int64_t)); +	uint8_t dout[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))] +		__aligned(sizeof(int64_t)); +}; + +/* + * Hard-code the number of columns we happen to know we have right now.  It + * would be more correct to call cros_ec_info() at startup and determine the + * actual number of keyboard cols from there. + */ +#define CROS_EC_KEYSCAN_COLS 13 + +/* Information returned by a key scan */ +struct mbkp_keyscan { +	uint8_t data[CROS_EC_KEYSCAN_COLS]; +}; + +/** + * Read the ID of the CROS-EC device + * + * The ID is a string identifying the CROS-EC device. + * + * @param dev		CROS-EC device + * @param id		Place to put the ID + * @param maxlen	Maximum length of the ID field + * @return 0 if ok, -1 on error + */ +int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen); + +/** + * Read a keyboard scan from the CROS-EC device + * + * Send a message requesting a keyboard scan and return the result + * + * @param dev		CROS-EC device + * @param scan		Place to put the scan results + * @return 0 if ok, -1 on error + */ +int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan); + +/** + * Read which image is currently running on the CROS-EC device. + * + * @param dev		CROS-EC device + * @param image		Destination for image identifier + * @return 0 if ok, <0 on error + */ +int cros_ec_read_current_image(struct cros_ec_dev *dev, +		enum ec_current_image *image); + +/** + * Read the hash of the CROS-EC device firmware. + * + * @param dev		CROS-EC device + * @param hash		Destination for hash information + * @return 0 if ok, <0 on error + */ +int cros_ec_read_hash(struct cros_ec_dev *dev, +		struct ec_response_vboot_hash *hash); + +/** + * Send a reboot command to the CROS-EC device. + * + * Note that some reboot commands (such as EC_REBOOT_COLD) also reboot the AP. + * + * @param dev		CROS-EC device + * @param cmd		Reboot command + * @param flags         Flags for reboot command (EC_REBOOT_FLAG_*) + * @return 0 if ok, <0 on error + */ +int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd, +		uint8_t flags); + +/** + * Check if the CROS-EC device has an interrupt pending. + * + * Read the status of the external interrupt connected to the CROS-EC device. + * If no external interrupt is configured, this always returns 1. + * + * @param dev		CROS-EC device + * @return 0 if no interrupt is pending + */ +int cros_ec_interrupt_pending(struct cros_ec_dev *dev); + +enum { +	CROS_EC_OK, +	CROS_EC_ERR = 1, +	CROS_EC_ERR_FDT_DECODE, +	CROS_EC_ERR_CHECK_VERSION, +	CROS_EC_ERR_READ_ID, +	CROS_EC_ERR_DEV_INIT, +}; + +/** + * Set up the Chromium OS matrix keyboard protocol + * + * @param blob		Device tree blob containing setup information + * @param cros_ecp        Returns pointer to the cros_ec device, or NULL if none + * @return 0 if we got an cros_ec device and all is well (or no cros_ec is + *	expected), -ve if we should have an cros_ec device but failed to find + *	one, or init failed (-CROS_EC_ERR_...). + */ +int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp); + +/** + * Read information about the keyboard matrix + * + * @param dev		CROS-EC device + * @param info		Place to put the info structure + */ +int cros_ec_info(struct cros_ec_dev *dev, +		struct ec_response_cros_ec_info *info); + +/** + * Read the host event flags + * + * @param dev		CROS-EC device + * @param events_ptr	Destination for event flags.  Not changed on error. + * @return 0 if ok, <0 on error + */ +int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr); + +/** + * Clear the specified host event flags + * + * @param dev		CROS-EC device + * @param events	Event flags to clear + * @return 0 if ok, <0 on error + */ +int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events); + +/** + * Get/set flash protection + * + * @param dev		CROS-EC device + * @param set_mask	Mask of flags to set; if 0, just retrieves existing + *                      protection state without changing it. + * @param set_flags	New flag values; only bits in set_mask are applied; + *                      ignored if set_mask=0. + * @param prot          Destination for updated protection state from EC. + * @return 0 if ok, <0 on error + */ +int cros_ec_flash_protect(struct cros_ec_dev *dev, +		       uint32_t set_mask, uint32_t set_flags, +		       struct ec_response_flash_protect *resp); + + +/** + * Run internal tests on the cros_ec interface. + * + * @param dev		CROS-EC device + * @return 0 if ok, <0 if the test failed + */ +int cros_ec_test(struct cros_ec_dev *dev); + +/** + * Update the EC RW copy. + * + * @param dev		CROS-EC device + * @param image		the content to write + * @param imafge_size	content length + * @return 0 if ok, <0 if the test failed + */ +int cros_ec_flash_update_rw(struct cros_ec_dev *dev, +			 const uint8_t  *image, int image_size); + +/** + * Return a pointer to the board's CROS-EC device + * + * This should be implemented by board files. + * + * @return pointer to CROS-EC device, or NULL if none is available + */ +struct cros_ec_dev *board_get_cros_ec_dev(void); + + +/* Internal interfaces */ +int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob); +int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob); +int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob); + +/** + * Read information from the fdt for the i2c cros_ec interface + * + * @param dev		CROS-EC device + * @param blob		Device tree blob + * @return 0 if ok, -1 if we failed to read all required information + */ +int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob); + +/** + * Read information from the fdt for the spi cros_ec interface + * + * @param dev		CROS-EC device + * @param blob		Device tree blob + * @return 0 if ok, -1 if we failed to read all required information + */ +int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob); + +/** + * Check whether the LPC interface supports new-style commands. + * + * LPC has its own way of doing this, which involves checking LPC values + * visible to the host. Do this, and update dev->cmd_version_is_supported + * accordingly. + * + * @param dev		CROS-EC device to check + */ +int cros_ec_lpc_check_version(struct cros_ec_dev *dev); + +/** + * Send a command to an I2C CROS-EC device and return the reply. + * + * This rather complicated function deals with sending both old-style and + * new-style commands. The old ones have just a command byte and arguments. + * The new ones have version, command, arg-len, [args], chksum so are 3 bytes + * longer. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS-EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout          Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param dinp          Returns pointer to response data + * @param din_len       Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len); + +/** + * Send a command to a LPC CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev		CROS-EC device + * @param cmd		Command to send (EC_CMD_...) + * @param cmd_version	Version of command to send (EC_VER_...) + * @param dout          Output data (may be NULL If dout_len=0) + * @param dout_len      Size of output data in bytes + * @param dinp          Returns pointer to response data + * @param din_len       Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len); + +int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +		     const uint8_t *dout, int dout_len, +		     uint8_t **dinp, int din_len); + +/** + * Dump a block of data for a command. + * + * @param name	Name for data (e.g. 'in', 'out') + * @param cmd	Command number associated with data, or -1 for none + * @param data	Data block to dump + * @param len	Length of data block to dump + */ +void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len); + +/** + * Calculate a simple 8-bit checksum of a data block + * + * @param data	Data block to checksum + * @param size	Size of data block in bytes + * @return checksum value (0 to 255) + */ +int cros_ec_calc_checksum(const uint8_t *data, int size); + +/** + * Decode a flash region parameter + * + * @param argc	Number of params remaining + * @param argv	List of remaining parameters + * @return flash region (EC_FLASH_REGION_...) or -1 on error + */ +int cros_ec_decode_region(int argc, char * const argv[]); + +int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, +		uint32_t size); + +/** + * Read data from the flash + * + * Read an arbitrary amount of data from the EC flash, by repeatedly reading + * small blocks. + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to read for a particular region. + * + * @param dev		CROS-EC device + * @param data		Pointer to data buffer to read into + * @param offset	Offset within flash to read from + * @param size		Number of bytes to read + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, +		    uint32_t size); + +/** + * Write data to the flash + * + * Write an arbitrary amount of data to the EC flash, by repeatedly writing + * small blocks. + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to write for a particular region. + * + * Attempting to write to the region where the EC is currently running from + * will result in an error. + * + * @param dev		CROS-EC device + * @param data		Pointer to data buffer to write + * @param offset	Offset within flash to write to. + * @param size		Number of bytes to write + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, +		     uint32_t offset, uint32_t size); + +/** + * Obtain position and size of a flash region + * + * @param dev		CROS-EC device + * @param region	Flash region to query + * @param offset	Returns offset of flash region in EC flash + * @param size		Returns size of flash region + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region, +		      uint32_t *offset, uint32_t *size); + +/** + * Read/write VbNvContext from/to a CROS-EC device. + * + * @param dev		CROS-EC device + * @param block		Buffer of VbNvContext to be read/write + * @return 0 if ok, -1 on error + */ +int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block); +int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block); + +/** + * Read the version information for the EC images + * + * @param dev		CROS-EC device + * @param versionp	This is set to point to the version information + * @return 0 if ok, -1 on error + */ +int cros_ec_read_version(struct cros_ec_dev *dev, +		       struct ec_response_get_version **versionp); + +/** + * Read the build information for the EC + * + * @param dev		CROS-EC device + * @param versionp	This is set to point to the build string + * @return 0 if ok, -1 on error + */ +int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp); + +/** + * Switch on/off a LDO / FET. + * + * @param dev		CROS-EC device + * @param index		index of the LDO/FET to switch + * @param state		new state of the LDO/FET : EC_LDO_STATE_ON|OFF + * @return 0 if ok, -1 on error + */ +int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state); + +/** + * Read back a LDO / FET current state. + * + * @param dev		CROS-EC device + * @param index		index of the LDO/FET to switch + * @param state		current state of the LDO/FET : EC_LDO_STATE_ON|OFF + * @return 0 if ok, -1 on error + */ +int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state); +#endif diff --git a/include/cros_ec_message.h b/include/cros_ec_message.h new file mode 100644 index 000000000..a2421c7ba --- /dev/null +++ b/include/cros_ec_message.h @@ -0,0 +1,44 @@ +/* + * Chromium OS Matrix Keyboard Message Protocol definitions + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CROS_MESSAGE_H +#define _CROS_MESSAGE_H + +/* + * Command interface between EC and AP, for LPC, I2C and SPI interfaces. + * + * This is copied from the Chromium OS Open Source Embedded Controller code. + */ +enum { +	/* The header byte, which follows the preamble */ +	MSG_HEADER	= 0xec, + +	MSG_HEADER_BYTES	= 3, +	MSG_TRAILER_BYTES	= 2, +	MSG_PROTO_BYTES		= MSG_HEADER_BYTES + MSG_TRAILER_BYTES, + +	/* Max length of messages */ +	MSG_BYTES		= EC_HOST_PARAM_SIZE + MSG_PROTO_BYTES, +}; + +#endif diff --git a/include/dwmmc.h b/include/dwmmc.h index c8b1d408e..e142f3ec4 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -123,6 +123,8 @@  #define MSIZE(x)		((x) << 28)  #define RX_WMARK(x)		((x) << 16)  #define TX_WMARK(x)		(x) +#define RX_WMARK_SHIFT		16 +#define RX_WMARK_MASK		(0xfff << RX_WMARK_SHIFT)  #define DWMCI_IDMAC_OWN		(1 << 31)  #define DWMCI_IDMAC_CH		(1 << 4) @@ -144,6 +146,7 @@ struct dwmci_host {  	unsigned int bus_hz;  	int dev_index;  	int buswidth; +	u32 clksel_val;  	u32 fifoth_val;  	struct mmc *mmc; diff --git a/include/ec_commands.h b/include/ec_commands.h new file mode 100644 index 000000000..12811cc07 --- /dev/null +++ b/include/ec_commands.h @@ -0,0 +1,1440 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Host communication command constants for Chrome EC */ + +#ifndef __CROS_EC_COMMANDS_H +#define __CROS_EC_COMMANDS_H + +/* + * Protocol overview + * + * request:  CMD [ P0 P1 P2 ... Pn S ] + * response: ERR [ P0 P1 P2 ... Pn S ] + * + * where the bytes are defined as follow : + *      - CMD is the command code. (defined by EC_CMD_ constants) + *      - ERR is the error code. (defined by EC_RES_ constants) + *      - Px is the optional payload. + *        it is not sent if the error code is not success. + *        (defined by ec_params_ and ec_response_ structures) + *      - S is the checksum which is the sum of all payload bytes. + * + * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD + * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM. + * On I2C, all bytes are sent serially in the same message. + */ + +/* Current version of this protocol */ +#define EC_PROTO_VERSION          0x00000002 + +/* Command version mask */ +#define EC_VER_MASK(version) (1UL << (version)) + +/* I/O addresses for ACPI commands */ +#define EC_LPC_ADDR_ACPI_DATA  0x62 +#define EC_LPC_ADDR_ACPI_CMD   0x66 + +/* I/O addresses for host command */ +#define EC_LPC_ADDR_HOST_DATA  0x200 +#define EC_LPC_ADDR_HOST_CMD   0x204 + +/* I/O addresses for host command args and params */ +#define EC_LPC_ADDR_HOST_ARGS  0x800 +#define EC_LPC_ADDR_HOST_PARAM 0x804 +#define EC_HOST_PARAM_SIZE     0x0fc  /* Size of param area in bytes */ + +/* I/O addresses for host command params, old interface */ +#define EC_LPC_ADDR_OLD_PARAM  0x880 +#define EC_OLD_PARAM_SIZE      0x080  /* Size of param area in bytes */ + +/* EC command register bit functions */ +#define EC_LPC_CMDR_DATA	(1 << 0)  /* Data ready for host to read */ +#define EC_LPC_CMDR_PENDING	(1 << 1)  /* Write pending to EC */ +#define EC_LPC_CMDR_BUSY	(1 << 2)  /* EC is busy processing a command */ +#define EC_LPC_CMDR_CMD		(1 << 3)  /* Last host write was a command */ +#define EC_LPC_CMDR_ACPI_BRST	(1 << 4)  /* Burst mode (not used) */ +#define EC_LPC_CMDR_SCI		(1 << 5)  /* SCI event is pending */ +#define EC_LPC_CMDR_SMI		(1 << 6)  /* SMI event is pending */ + +#define EC_LPC_ADDR_MEMMAP       0x900 +#define EC_MEMMAP_SIZE         255 /* ACPI IO buffer max is 255 bytes */ +#define EC_MEMMAP_TEXT_MAX     8   /* Size of a string in the memory map */ + +/* The offset address of each type of data in mapped memory. */ +#define EC_MEMMAP_TEMP_SENSOR      0x00 /* Temp sensors */ +#define EC_MEMMAP_FAN              0x10 /* Fan speeds */ +#define EC_MEMMAP_TEMP_SENSOR_B    0x18 /* Temp sensors (second set) */ +#define EC_MEMMAP_ID               0x20 /* 'E' 'C' */ +#define EC_MEMMAP_ID_VERSION       0x22 /* Version of data in 0x20 - 0x2f */ +#define EC_MEMMAP_THERMAL_VERSION  0x23 /* Version of data in 0x00 - 0x1f */ +#define EC_MEMMAP_BATTERY_VERSION  0x24 /* Version of data in 0x40 - 0x7f */ +#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */ +#define EC_MEMMAP_EVENTS_VERSION   0x26 /* Version of data in 0x34 - 0x3f */ +#define EC_MEMMAP_HOST_CMD_FLAGS   0x27 /* Host command interface flags */ +#define EC_MEMMAP_SWITCHES         0x30 +#define EC_MEMMAP_HOST_EVENTS      0x34 +#define EC_MEMMAP_BATT_VOLT        0x40 /* Battery Present Voltage */ +#define EC_MEMMAP_BATT_RATE        0x44 /* Battery Present Rate */ +#define EC_MEMMAP_BATT_CAP         0x48 /* Battery Remaining Capacity */ +#define EC_MEMMAP_BATT_FLAG        0x4c /* Battery State, defined below */ +#define EC_MEMMAP_BATT_DCAP        0x50 /* Battery Design Capacity */ +#define EC_MEMMAP_BATT_DVLT        0x54 /* Battery Design Voltage */ +#define EC_MEMMAP_BATT_LFCC        0x58 /* Battery Last Full Charge Capacity */ +#define EC_MEMMAP_BATT_CCNT        0x5c /* Battery Cycle Count */ +#define EC_MEMMAP_BATT_MFGR        0x60 /* Battery Manufacturer String */ +#define EC_MEMMAP_BATT_MODEL       0x68 /* Battery Model Number String */ +#define EC_MEMMAP_BATT_SERIAL      0x70 /* Battery Serial Number String */ +#define EC_MEMMAP_BATT_TYPE        0x78 /* Battery Type String */ + +/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */ +#define EC_TEMP_SENSOR_ENTRIES     16 +/* + * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B. + * + * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2. + */ +#define EC_TEMP_SENSOR_B_ENTRIES      8 +#define EC_TEMP_SENSOR_NOT_PRESENT    0xff +#define EC_TEMP_SENSOR_ERROR          0xfe +#define EC_TEMP_SENSOR_NOT_POWERED    0xfd +#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc +/* + * The offset of temperature value stored in mapped memory.  This allows + * reporting a temperature range of 200K to 454K = -73C to 181C. + */ +#define EC_TEMP_SENSOR_OFFSET      200 + +#define EC_FAN_SPEED_ENTRIES       4       /* Number of fans at EC_MEMMAP_FAN */ +#define EC_FAN_SPEED_NOT_PRESENT   0xffff  /* Entry not present */ +#define EC_FAN_SPEED_STALLED       0xfffe  /* Fan stalled */ + +/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */ +#define EC_BATT_FLAG_AC_PRESENT   0x01 +#define EC_BATT_FLAG_BATT_PRESENT 0x02 +#define EC_BATT_FLAG_DISCHARGING  0x04 +#define EC_BATT_FLAG_CHARGING     0x08 +#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10 + +/* Switch flags at EC_MEMMAP_SWITCHES */ +#define EC_SWITCH_LID_OPEN               0x01 +#define EC_SWITCH_POWER_BUTTON_PRESSED   0x02 +#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04 +/* Recovery requested via keyboard */ +#define EC_SWITCH_KEYBOARD_RECOVERY      0x08 +/* Recovery requested via dedicated signal (from servo board) */ +#define EC_SWITCH_DEDICATED_RECOVERY     0x10 +/* Was fake developer mode switch; now unused.  Remove in next refactor. */ +#define EC_SWITCH_IGNORE0                0x20 + +/* Host command interface flags */ +/* Host command interface supports LPC args (LPC interface only) */ +#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED  0x01 + +/* Wireless switch flags */ +#define EC_WIRELESS_SWITCH_WLAN      0x01 +#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 + +/* + * This header file is used in coreboot both in C and ACPI code.  The ACPI code + * is pre-processed to handle constants but the ASL compiler is unable to + * handle actual C code so keep it separate. + */ +#ifndef __ACPI__ + +/* + * Define __packed if someone hasn't beat us to it.  Linux kernel style + * checking prefers __packed over __attribute__((packed)). + */ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +/* LPC command status byte masks */ +/* EC has written a byte in the data register and host hasn't read it yet */ +#define EC_LPC_STATUS_TO_HOST     0x01 +/* Host has written a command/data byte and the EC hasn't read it yet */ +#define EC_LPC_STATUS_FROM_HOST   0x02 +/* EC is processing a command */ +#define EC_LPC_STATUS_PROCESSING  0x04 +/* Last write to EC was a command, not data */ +#define EC_LPC_STATUS_LAST_CMD    0x08 +/* EC is in burst mode.  Unsupported by Chrome EC, so this bit is never set */ +#define EC_LPC_STATUS_BURST_MODE  0x10 +/* SCI event is pending (requesting SCI query) */ +#define EC_LPC_STATUS_SCI_PENDING 0x20 +/* SMI event is pending (requesting SMI query) */ +#define EC_LPC_STATUS_SMI_PENDING 0x40 +/* (reserved) */ +#define EC_LPC_STATUS_RESERVED    0x80 + +/* + * EC is busy.  This covers both the EC processing a command, and the host has + * written a new command but the EC hasn't picked it up yet. + */ +#define EC_LPC_STATUS_BUSY_MASK \ +	(EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING) + +/* Host command response codes */ +enum ec_status { +	EC_RES_SUCCESS = 0, +	EC_RES_INVALID_COMMAND = 1, +	EC_RES_ERROR = 2, +	EC_RES_INVALID_PARAM = 3, +	EC_RES_ACCESS_DENIED = 4, +	EC_RES_INVALID_RESPONSE = 5, +	EC_RES_INVALID_VERSION = 6, +	EC_RES_INVALID_CHECKSUM = 7, +	EC_RES_IN_PROGRESS = 8,		/* Accepted, command in progress */ +	EC_RES_UNAVAILABLE = 9,		/* No response available */ +	EC_RES_TIMEOUT = 10,		/* We got a timeout */ +	EC_RES_OVERFLOW = 11,		/* Table / data overflow */ +}; + +/* + * Host event codes.  Note these are 1-based, not 0-based, because ACPI query + * EC command uses code 0 to mean "no event pending".  We explicitly specify + * each value in the enum listing so they won't change if we delete/insert an + * item or rearrange the list (it needs to be stable across platforms, not + * just within a single compiled instance). + */ +enum host_event_code { +	EC_HOST_EVENT_LID_CLOSED = 1, +	EC_HOST_EVENT_LID_OPEN = 2, +	EC_HOST_EVENT_POWER_BUTTON = 3, +	EC_HOST_EVENT_AC_CONNECTED = 4, +	EC_HOST_EVENT_AC_DISCONNECTED = 5, +	EC_HOST_EVENT_BATTERY_LOW = 6, +	EC_HOST_EVENT_BATTERY_CRITICAL = 7, +	EC_HOST_EVENT_BATTERY = 8, +	EC_HOST_EVENT_THERMAL_THRESHOLD = 9, +	EC_HOST_EVENT_THERMAL_OVERLOAD = 10, +	EC_HOST_EVENT_THERMAL = 11, +	EC_HOST_EVENT_USB_CHARGER = 12, +	EC_HOST_EVENT_KEY_PRESSED = 13, +	/* +	 * EC has finished initializing the host interface.  The host can check +	 * for this event following sending a EC_CMD_REBOOT_EC command to +	 * determine when the EC is ready to accept subsequent commands. +	 */ +	EC_HOST_EVENT_INTERFACE_READY = 14, +	/* Keyboard recovery combo has been pressed */ +	EC_HOST_EVENT_KEYBOARD_RECOVERY = 15, + +	/* Shutdown due to thermal overload */ +	EC_HOST_EVENT_THERMAL_SHUTDOWN = 16, +	/* Shutdown due to battery level too low */ +	EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, + +	/* +	 * The high bit of the event mask is not used as a host event code.  If +	 * it reads back as set, then the entire event mask should be +	 * considered invalid by the host.  This can happen when reading the +	 * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is +	 * not initialized on the EC, or improperly configured on the host. +	 */ +	EC_HOST_EVENT_INVALID = 32 +}; +/* Host event mask */ +#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1)) + +/* Arguments at EC_LPC_ADDR_HOST_ARGS */ +struct ec_lpc_host_args { +	uint8_t flags; +	uint8_t command_version; +	uint8_t data_size; +	/* +	 * Checksum; sum of command + flags + command_version + data_size + +	 * all params/response data bytes. +	 */ +	uint8_t checksum; +} __packed; + +/* Flags for ec_lpc_host_args.flags */ +/* + * Args are from host.  Data area at EC_LPC_ADDR_HOST_PARAM contains command + * params. + * + * If EC gets a command and this flag is not set, this is an old-style command. + * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with + * unknown length.  EC must respond with an old-style response (that is, + * withouth setting EC_HOST_ARGS_FLAG_TO_HOST). + */ +#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01 +/* + * Args are from EC.  Data area at EC_LPC_ADDR_HOST_PARAM contains response. + * + * If EC responds to a command and this flag is not set, this is an old-style + * response.  Command version is 0 and response data from EC is at + * EC_LPC_ADDR_OLD_PARAM with unknown length. + */ +#define EC_HOST_ARGS_FLAG_TO_HOST   0x02 + +/* + * Notes on commands: + * + * Each command is an 8-byte command value.  Commands which take params or + * return response data specify structs for that data.  If no struct is + * specified, the command does not input or output data, respectively. + * Parameter/response length is implicit in the structs.  Some underlying + * communication protocols (I2C, SPI) may add length or checksum headers, but + * those are implementation-dependent and not defined here. + */ + +/*****************************************************************************/ +/* General / test commands */ + +/* + * Get protocol version, used to deal with non-backward compatible protocol + * changes. + */ +#define EC_CMD_PROTO_VERSION 0x00 + +struct ec_response_proto_version { +	uint32_t version; +} __packed; + +/* + * Hello.  This is a simple command to test the EC is responsive to + * commands. + */ +#define EC_CMD_HELLO 0x01 + +struct ec_params_hello { +	uint32_t in_data;  /* Pass anything here */ +} __packed; + +struct ec_response_hello { +	uint32_t out_data;  /* Output will be in_data + 0x01020304 */ +} __packed; + +/* Get version number */ +#define EC_CMD_GET_VERSION 0x02 + +enum ec_current_image { +	EC_IMAGE_UNKNOWN = 0, +	EC_IMAGE_RO, +	EC_IMAGE_RW +}; + +struct ec_response_get_version { +	/* Null-terminated version strings for RO, RW */ +	char version_string_ro[32]; +	char version_string_rw[32]; +	char reserved[32];       /* Was previously RW-B string */ +	uint32_t current_image;  /* One of ec_current_image */ +} __packed; + +/* Read test */ +#define EC_CMD_READ_TEST 0x03 + +struct ec_params_read_test { +	uint32_t offset;   /* Starting value for read buffer */ +	uint32_t size;     /* Size to read in bytes */ +} __packed; + +struct ec_response_read_test { +	uint32_t data[32]; +} __packed; + +/* + * Get build information + * + * Response is null-terminated string. + */ +#define EC_CMD_GET_BUILD_INFO 0x04 + +/* Get chip info */ +#define EC_CMD_GET_CHIP_INFO 0x05 + +struct ec_response_get_chip_info { +	/* Null-terminated strings */ +	char vendor[32]; +	char name[32]; +	char revision[32];  /* Mask version */ +} __packed; + +/* Get board HW version */ +#define EC_CMD_GET_BOARD_VERSION 0x06 + +struct ec_response_board_version { +	uint16_t board_version;  /* A monotonously incrementing number. */ +} __packed; + +/* + * Read memory-mapped data. + * + * This is an alternate interface to memory-mapped data for bus protocols + * which don't support direct-mapped memory - I2C, SPI, etc. + * + * Response is params.size bytes of data. + */ +#define EC_CMD_READ_MEMMAP 0x07 + +struct ec_params_read_memmap { +	uint8_t offset;   /* Offset in memmap (EC_MEMMAP_*) */ +	uint8_t size;     /* Size to read in bytes */ +} __packed; + +/* Read versions supported for a command */ +#define EC_CMD_GET_CMD_VERSIONS 0x08 + +struct ec_params_get_cmd_versions { +	uint8_t cmd;      /* Command to check */ +} __packed; + +struct ec_response_get_cmd_versions { +	/* +	 * Mask of supported versions; use EC_VER_MASK() to compare with a +	 * desired version. +	 */ +	uint32_t version_mask; +} __packed; + +/* + * Check EC communcations status (busy). This is needed on i2c/spi but not + * on lpc since it has its own out-of-band busy indicator. + * + * lpc must read the status from the command register. Attempting this on + * lpc will overwrite the args/parameter space and corrupt its data. + */ +#define EC_CMD_GET_COMMS_STATUS		0x09 + +/* Avoid using ec_status which is for return values */ +enum ec_comms_status { +	EC_COMMS_STATUS_PROCESSING	= 1 << 0,	/* Processing cmd */ +}; + +struct ec_response_get_comms_status { +	uint32_t flags;		/* Mask of enum ec_comms_status */ +} __packed; + + +/*****************************************************************************/ +/* Flash commands */ + +/* Get flash info */ +#define EC_CMD_FLASH_INFO 0x10 + +struct ec_response_flash_info { +	/* Usable flash size, in bytes */ +	uint32_t flash_size; +	/* +	 * Write block size.  Write offset and size must be a multiple +	 * of this. +	 */ +	uint32_t write_block_size; +	/* +	 * Erase block size.  Erase offset and size must be a multiple +	 * of this. +	 */ +	uint32_t erase_block_size; +	/* +	 * Protection block size.  Protection offset and size must be a +	 * multiple of this. +	 */ +	uint32_t protect_block_size; +} __packed; + +/* + * Read flash + * + * Response is params.size bytes of data. + */ +#define EC_CMD_FLASH_READ 0x11 + +struct ec_params_flash_read { +	uint32_t offset;   /* Byte offset to read */ +	uint32_t size;     /* Size to read in bytes */ +} __packed; + +/* Write flash */ +#define EC_CMD_FLASH_WRITE 0x12 + +struct ec_params_flash_write { +	uint32_t offset;   /* Byte offset to write */ +	uint32_t size;     /* Size to write in bytes */ +	/* +	 * Data to write.  Could really use EC_PARAM_SIZE - 8, but tidiest to +	 * use a power of 2 so writes stay aligned. +	 */ +	uint8_t data[64]; +} __packed; + +/* Erase flash */ +#define EC_CMD_FLASH_ERASE 0x13 + +struct ec_params_flash_erase { +	uint32_t offset;   /* Byte offset to erase */ +	uint32_t size;     /* Size to erase in bytes */ +} __packed; + +/* + * Get/set flash protection. + * + * If mask!=0, sets/clear the requested bits of flags.  Depending on the + * firmware write protect GPIO, not all flags will take effect immediately; + * some flags require a subsequent hard reset to take effect.  Check the + * returned flags bits to see what actually happened. + * + * If mask=0, simply returns the current flags state. + */ +#define EC_CMD_FLASH_PROTECT 0x15 +#define EC_VER_FLASH_PROTECT 1  /* Command version 1 */ + +/* Flags for flash protection */ +/* RO flash code protected when the EC boots */ +#define EC_FLASH_PROTECT_RO_AT_BOOT         (1 << 0) +/* + * RO flash code protected now.  If this bit is set, at-boot status cannot + * be changed. + */ +#define EC_FLASH_PROTECT_RO_NOW             (1 << 1) +/* Entire flash code protected now, until reboot. */ +#define EC_FLASH_PROTECT_ALL_NOW            (1 << 2) +/* Flash write protect GPIO is asserted now */ +#define EC_FLASH_PROTECT_GPIO_ASSERTED      (1 << 3) +/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */ +#define EC_FLASH_PROTECT_ERROR_STUCK        (1 << 4) +/* + * Error - flash protection is in inconsistent state.  At least one bank of + * flash which should be protected is not protected.  Usually fixed by + * re-requesting the desired flags, or by a hard reset if that fails. + */ +#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5) +/* Entile flash code protected when the EC boots */ +#define EC_FLASH_PROTECT_ALL_AT_BOOT        (1 << 6) + +struct ec_params_flash_protect { +	uint32_t mask;   /* Bits in flags to apply */ +	uint32_t flags;  /* New flags to apply */ +} __packed; + +struct ec_response_flash_protect { +	/* Current value of flash protect flags */ +	uint32_t flags; +	/* +	 * Flags which are valid on this platform.  This allows the caller +	 * to distinguish between flags which aren't set vs. flags which can't +	 * be set on this platform. +	 */ +	uint32_t valid_flags; +	/* Flags which can be changed given the current protection state */ +	uint32_t writable_flags; +} __packed; + +/* + * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash + * write protect.  These commands may be reused with version > 0. + */ + +/* Get the region offset/size */ +#define EC_CMD_FLASH_REGION_INFO 0x16 +#define EC_VER_FLASH_REGION_INFO 1 + +enum ec_flash_region { +	/* Region which holds read-only EC image */ +	EC_FLASH_REGION_RO, +	/* Region which holds rewritable EC image */ +	EC_FLASH_REGION_RW, +	/* +	 * Region which should be write-protected in the factory (a superset of +	 * EC_FLASH_REGION_RO) +	 */ +	EC_FLASH_REGION_WP_RO, +}; + +struct ec_params_flash_region_info { +	uint32_t region;  /* enum ec_flash_region */ +} __packed; + +struct ec_response_flash_region_info { +	uint32_t offset; +	uint32_t size; +} __packed; + +/* Read/write VbNvContext */ +#define EC_CMD_VBNV_CONTEXT 0x17 +#define EC_VER_VBNV_CONTEXT 1 +#define EC_VBNV_BLOCK_SIZE 16 + +enum ec_vbnvcontext_op { +	EC_VBNV_CONTEXT_OP_READ, +	EC_VBNV_CONTEXT_OP_WRITE, +}; + +struct ec_params_vbnvcontext { +	uint32_t op; +	uint8_t block[EC_VBNV_BLOCK_SIZE]; +} __packed; + +struct ec_response_vbnvcontext { +	uint8_t block[EC_VBNV_BLOCK_SIZE]; +} __packed; + +/*****************************************************************************/ +/* PWM commands */ + +/* Get fan target RPM */ +#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20 + +struct ec_response_pwm_get_fan_rpm { +	uint32_t rpm; +} __packed; + +/* Set target fan RPM */ +#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21 + +struct ec_params_pwm_set_fan_target_rpm { +	uint32_t rpm; +} __packed; + +/* Get keyboard backlight */ +#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22 + +struct ec_response_pwm_get_keyboard_backlight { +	uint8_t percent; +	uint8_t enabled; +} __packed; + +/* Set keyboard backlight */ +#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23 + +struct ec_params_pwm_set_keyboard_backlight { +	uint8_t percent; +} __packed; + +/* Set target fan PWM duty cycle */ +#define EC_CMD_PWM_SET_FAN_DUTY 0x24 + +struct ec_params_pwm_set_fan_duty { +	uint32_t percent; +} __packed; + +/*****************************************************************************/ +/* + * Lightbar commands. This looks worse than it is. Since we only use one HOST + * command to say "talk to the lightbar", we put the "and tell it to do X" part + * into a subcommand. We'll make separate structs for subcommands with + * different input args, so that we know how much to expect. + */ +#define EC_CMD_LIGHTBAR_CMD 0x28 + +struct rgb_s { +	uint8_t r, g, b; +}; + +#define LB_BATTERY_LEVELS 4 +/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a + * host command, but the alignment is the same regardless. Keep it that way. + */ +struct lightbar_params { +	/* Timing */ +	int google_ramp_up; +	int google_ramp_down; +	int s3s0_ramp_up; +	int s0_tick_delay[2];			/* AC=0/1 */ +	int s0a_tick_delay[2];			/* AC=0/1 */ +	int s0s3_ramp_down; +	int s3_sleep_for; +	int s3_ramp_up; +	int s3_ramp_down; + +	/* Oscillation */ +	uint8_t new_s0; +	uint8_t osc_min[2];			/* AC=0/1 */ +	uint8_t osc_max[2];			/* AC=0/1 */ +	uint8_t w_ofs[2];			/* AC=0/1 */ + +	/* Brightness limits based on the backlight and AC. */ +	uint8_t bright_bl_off_fixed[2];		/* AC=0/1 */ +	uint8_t bright_bl_on_min[2];		/* AC=0/1 */ +	uint8_t bright_bl_on_max[2];		/* AC=0/1 */ + +	/* Battery level thresholds */ +	uint8_t battery_threshold[LB_BATTERY_LEVELS - 1]; + +	/* Map [AC][battery_level] to color index */ +	uint8_t s0_idx[2][LB_BATTERY_LEVELS];	/* AP is running */ +	uint8_t s3_idx[2][LB_BATTERY_LEVELS];	/* AP is sleeping */ + +	/* Color palette */ +	struct rgb_s color[8];			/* 0-3 are Google colors */ +} __packed; + +struct ec_params_lightbar { +	uint8_t cmd;		      /* Command (see enum lightbar_command) */ +	union { +		struct { +			/* no args */ +		} dump, off, on, init, get_seq, get_params; + +		struct num { +			uint8_t num; +		} brightness, seq, demo; + +		struct reg { +			uint8_t ctrl, reg, value; +		} reg; + +		struct rgb { +			uint8_t led, red, green, blue; +		} rgb; + +		struct lightbar_params set_params; +	}; +} __packed; + +struct ec_response_lightbar { +	union { +		struct dump { +			struct { +				uint8_t reg; +				uint8_t ic0; +				uint8_t ic1; +			} vals[23]; +		} dump; + +		struct get_seq { +			uint8_t num; +		} get_seq; + +		struct lightbar_params get_params; + +		struct { +			/* no return params */ +		} off, on, init, brightness, seq, reg, rgb, demo, set_params; +	}; +} __packed; + +/* Lightbar commands */ +enum lightbar_command { +	LIGHTBAR_CMD_DUMP = 0, +	LIGHTBAR_CMD_OFF = 1, +	LIGHTBAR_CMD_ON = 2, +	LIGHTBAR_CMD_INIT = 3, +	LIGHTBAR_CMD_BRIGHTNESS = 4, +	LIGHTBAR_CMD_SEQ = 5, +	LIGHTBAR_CMD_REG = 6, +	LIGHTBAR_CMD_RGB = 7, +	LIGHTBAR_CMD_GET_SEQ = 8, +	LIGHTBAR_CMD_DEMO = 9, +	LIGHTBAR_CMD_GET_PARAMS = 10, +	LIGHTBAR_CMD_SET_PARAMS = 11, +	LIGHTBAR_NUM_CMDS +}; + +/*****************************************************************************/ +/* Verified boot commands */ + +/* + * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be + * reused for other purposes with version > 0. + */ + +/* Verified boot hash command */ +#define EC_CMD_VBOOT_HASH 0x2A + +struct ec_params_vboot_hash { +	uint8_t cmd;             /* enum ec_vboot_hash_cmd */ +	uint8_t hash_type;       /* enum ec_vboot_hash_type */ +	uint8_t nonce_size;      /* Nonce size; may be 0 */ +	uint8_t reserved0;       /* Reserved; set 0 */ +	uint32_t offset;         /* Offset in flash to hash */ +	uint32_t size;           /* Number of bytes to hash */ +	uint8_t nonce_data[64];  /* Nonce data; ignored if nonce_size=0 */ +} __packed; + +struct ec_response_vboot_hash { +	uint8_t status;          /* enum ec_vboot_hash_status */ +	uint8_t hash_type;       /* enum ec_vboot_hash_type */ +	uint8_t digest_size;     /* Size of hash digest in bytes */ +	uint8_t reserved0;       /* Ignore; will be 0 */ +	uint32_t offset;         /* Offset in flash which was hashed */ +	uint32_t size;           /* Number of bytes hashed */ +	uint8_t hash_digest[64]; /* Hash digest data */ +} __packed; + +enum ec_vboot_hash_cmd { +	EC_VBOOT_HASH_GET = 0,       /* Get current hash status */ +	EC_VBOOT_HASH_ABORT = 1,     /* Abort calculating current hash */ +	EC_VBOOT_HASH_START = 2,     /* Start computing a new hash */ +	EC_VBOOT_HASH_RECALC = 3,    /* Synchronously compute a new hash */ +}; + +enum ec_vboot_hash_type { +	EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */ +}; + +enum ec_vboot_hash_status { +	EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */ +	EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */ +	EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */ +}; + +/* + * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC. + * If one of these is specified, the EC will automatically update offset and + * size to the correct values for the specified image (RO or RW). + */ +#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe +#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd + +/*****************************************************************************/ +/* USB charging control commands */ + +/* Set USB port charging mode */ +#define EC_CMD_USB_CHARGE_SET_MODE 0x30 + +struct ec_params_usb_charge_set_mode { +	uint8_t usb_port_id; +	uint8_t mode; +} __packed; + +/*****************************************************************************/ +/* Persistent storage for host */ + +/* Maximum bytes that can be read/written in a single command */ +#define EC_PSTORE_SIZE_MAX 64 + +/* Get persistent storage info */ +#define EC_CMD_PSTORE_INFO 0x40 + +struct ec_response_pstore_info { +	/* Persistent storage size, in bytes */ +	uint32_t pstore_size; +	/* Access size; read/write offset and size must be a multiple of this */ +	uint32_t access_size; +} __packed; + +/* + * Read persistent storage + * + * Response is params.size bytes of data. + */ +#define EC_CMD_PSTORE_READ 0x41 + +struct ec_params_pstore_read { +	uint32_t offset;   /* Byte offset to read */ +	uint32_t size;     /* Size to read in bytes */ +} __packed; + +/* Write persistent storage */ +#define EC_CMD_PSTORE_WRITE 0x42 + +struct ec_params_pstore_write { +	uint32_t offset;   /* Byte offset to write */ +	uint32_t size;     /* Size to write in bytes */ +	uint8_t data[EC_PSTORE_SIZE_MAX]; +} __packed; + +/*****************************************************************************/ +/* Real-time clock */ + +/* RTC params and response structures */ +struct ec_params_rtc { +	uint32_t time; +} __packed; + +struct ec_response_rtc { +	uint32_t time; +} __packed; + +/* These use ec_response_rtc */ +#define EC_CMD_RTC_GET_VALUE 0x44 +#define EC_CMD_RTC_GET_ALARM 0x45 + +/* These all use ec_params_rtc */ +#define EC_CMD_RTC_SET_VALUE 0x46 +#define EC_CMD_RTC_SET_ALARM 0x47 + +/*****************************************************************************/ +/* Port80 log access */ + +/* Get last port80 code from previous boot */ +#define EC_CMD_PORT80_LAST_BOOT 0x48 + +struct ec_response_port80_last_boot { +	uint16_t code; +} __packed; + +/*****************************************************************************/ +/* Thermal engine commands */ + +/* Set thershold value */ +#define EC_CMD_THERMAL_SET_THRESHOLD 0x50 + +struct ec_params_thermal_set_threshold { +	uint8_t sensor_type; +	uint8_t threshold_id; +	uint16_t value; +} __packed; + +/* Get threshold value */ +#define EC_CMD_THERMAL_GET_THRESHOLD 0x51 + +struct ec_params_thermal_get_threshold { +	uint8_t sensor_type; +	uint8_t threshold_id; +} __packed; + +struct ec_response_thermal_get_threshold { +	uint16_t value; +} __packed; + +/* Toggle automatic fan control */ +#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52 + +/* Get TMP006 calibration data */ +#define EC_CMD_TMP006_GET_CALIBRATION 0x53 + +struct ec_params_tmp006_get_calibration { +	uint8_t index; +} __packed; + +struct ec_response_tmp006_get_calibration { +	float s0; +	float b0; +	float b1; +	float b2; +} __packed; + +/* Set TMP006 calibration data */ +#define EC_CMD_TMP006_SET_CALIBRATION 0x54 + +struct ec_params_tmp006_set_calibration { +	uint8_t index; +	uint8_t reserved[3];  /* Reserved; set 0 */ +	float s0; +	float b0; +	float b1; +	float b2; +} __packed; + +/*****************************************************************************/ +/* CROS_EC - Matrix KeyBoard Protocol */ + +/* + * Read key state + * + * Returns raw data for keyboard cols; see ec_response_cros_ec_info.cols for + * expected response size. + */ +#define EC_CMD_CROS_EC_STATE 0x60 + +/* Provide information about the matrix : number of rows and columns */ +#define EC_CMD_CROS_EC_INFO 0x61 + +struct ec_response_cros_ec_info { +	uint32_t rows; +	uint32_t cols; +	uint8_t switches; +} __packed; + +/* Simulate key press */ +#define EC_CMD_CROS_EC_SIMULATE_KEY 0x62 + +struct ec_params_cros_ec_simulate_key { +	uint8_t col; +	uint8_t row; +	uint8_t pressed; +} __packed; + +/* Configure keyboard scanning */ +#define EC_CMD_CROS_EC_SET_CONFIG 0x64 +#define EC_CMD_CROS_EC_GET_CONFIG 0x65 + +/* flags */ +enum cros_ec_config_flags { +	EC_CROS_EC_FLAGS_ENABLE = 1,	/* Enable keyboard scanning */ +}; + +enum cros_ec_config_valid { +	EC_CROS_EC_VALID_SCAN_PERIOD		= 1 << 0, +	EC_CROS_EC_VALID_POLL_TIMEOUT		= 1 << 1, +	EC_CROS_EC_VALID_MIN_POST_SCAN_DELAY	= 1 << 3, +	EC_CROS_EC_VALID_OUTPUT_SETTLE		= 1 << 4, +	EC_CROS_EC_VALID_DEBOUNCE_DOWN		= 1 << 5, +	EC_CROS_EC_VALID_DEBOUNCE_UP		= 1 << 6, +	EC_CROS_EC_VALID_FIFO_MAX_DEPTH		= 1 << 7, +}; + +/* Configuration for our key scanning algorithm */ +struct ec_cros_ec_config { +	uint32_t valid_mask;		/* valid fields */ +	uint8_t flags;		/* some flags (enum cros_ec_config_flags) */ +	uint8_t valid_flags;		/* which flags are valid */ +	uint16_t scan_period_us;	/* period between start of scans */ +	/* revert to interrupt mode after no activity for this long */ +	uint32_t poll_timeout_us; +	/* +	 * minimum post-scan relax time. Once we finish a scan we check +	 * the time until we are due to start the next one. If this time is +	 * shorter this field, we use this instead. +	 */ +	uint16_t min_post_scan_delay_us; +	/* delay between setting up output and waiting for it to settle */ +	uint16_t output_settle_us; +	uint16_t debounce_down_us;	/* time for debounce on key down */ +	uint16_t debounce_up_us;	/* time for debounce on key up */ +	/* maximum depth to allow for fifo (0 = no keyscan output) */ +	uint8_t fifo_max_depth; +} __packed; + +struct ec_params_cros_ec_set_config { +	struct ec_cros_ec_config config; +} __packed; + +struct ec_response_cros_ec_get_config { +	struct ec_cros_ec_config config; +} __packed; + +/* Run the key scan emulation */ +#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66 + +enum ec_keyscan_seq_cmd { +	EC_KEYSCAN_SEQ_STATUS = 0,	/* Get status information */ +	EC_KEYSCAN_SEQ_CLEAR = 1,	/* Clear sequence */ +	EC_KEYSCAN_SEQ_ADD = 2,		/* Add item to sequence */ +	EC_KEYSCAN_SEQ_START = 3,	/* Start running sequence */ +	EC_KEYSCAN_SEQ_COLLECT = 4,	/* Collect sequence summary data */ +}; + +enum ec_collect_flags { +	/* +	 * Indicates this scan was processed by the EC. Due to timing, some +	 * scans may be skipped. +	 */ +	EC_KEYSCAN_SEQ_FLAG_DONE	= 1 << 0, +}; + +struct ec_collect_item { +	uint8_t flags;		/* some flags (enum ec_collect_flags) */ +}; + +struct ec_params_keyscan_seq_ctrl { +	uint8_t cmd;	/* Command to send (enum ec_keyscan_seq_cmd) */ +	union { +		struct { +			uint8_t active;		/* still active */ +			uint8_t num_items;	/* number of items */ +			/* Current item being presented */ +			uint8_t cur_item; +		} status; +		struct { +			/* +			 * Absolute time for this scan, measured from the +			 * start of the sequence. +			 */ +			uint32_t time_us; +			uint8_t scan[0];	/* keyscan data */ +		} add; +		struct { +			uint8_t start_item;	/* First item to return */ +			uint8_t num_items;	/* Number of items to return */ +		} collect; +	}; +} __packed; + +struct ec_result_keyscan_seq_ctrl { +	union { +		struct { +			uint8_t num_items;	/* Number of items */ +			/* Data for each item */ +			struct ec_collect_item item[0]; +		} collect; +	}; +} __packed; + +/*****************************************************************************/ +/* Temperature sensor commands */ + +/* Read temperature sensor info */ +#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70 + +struct ec_params_temp_sensor_get_info { +	uint8_t id; +} __packed; + +struct ec_response_temp_sensor_get_info { +	char sensor_name[32]; +	uint8_t sensor_type; +} __packed; + +/*****************************************************************************/ + +/* + * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI + * commands accidentally sent to the wrong interface.  See the ACPI section + * below. + */ + +/*****************************************************************************/ +/* Host event commands */ + +/* + * Host event mask params and response structures, shared by all of the host + * event commands below. + */ +struct ec_params_host_event_mask { +	uint32_t mask; +} __packed; + +struct ec_response_host_event_mask { +	uint32_t mask; +} __packed; + +/* These all use ec_response_host_event_mask */ +#define EC_CMD_HOST_EVENT_GET_B         0x87 +#define EC_CMD_HOST_EVENT_GET_SMI_MASK  0x88 +#define EC_CMD_HOST_EVENT_GET_SCI_MASK  0x89 +#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d + +/* These all use ec_params_host_event_mask */ +#define EC_CMD_HOST_EVENT_SET_SMI_MASK  0x8a +#define EC_CMD_HOST_EVENT_SET_SCI_MASK  0x8b +#define EC_CMD_HOST_EVENT_CLEAR         0x8c +#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e +#define EC_CMD_HOST_EVENT_CLEAR_B       0x8f + +/*****************************************************************************/ +/* Switch commands */ + +/* Enable/disable LCD backlight */ +#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90 + +struct ec_params_switch_enable_backlight { +	uint8_t enabled; +} __packed; + +/* Enable/disable WLAN/Bluetooth */ +#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91 + +struct ec_params_switch_enable_wireless { +	uint8_t enabled; +} __packed; + +/*****************************************************************************/ +/* GPIO commands. Only available on EC if write protect has been disabled. */ + +/* Set GPIO output value */ +#define EC_CMD_GPIO_SET 0x92 + +struct ec_params_gpio_set { +	char name[32]; +	uint8_t val; +} __packed; + +/* Get GPIO value */ +#define EC_CMD_GPIO_GET 0x93 + +struct ec_params_gpio_get { +	char name[32]; +} __packed; +struct ec_response_gpio_get { +	uint8_t val; +} __packed; + +/*****************************************************************************/ +/* I2C commands. Only available when flash write protect is unlocked. */ + +/* Read I2C bus */ +#define EC_CMD_I2C_READ 0x94 + +struct ec_params_i2c_read { +	uint16_t addr; +	uint8_t read_size; /* Either 8 or 16. */ +	uint8_t port; +	uint8_t offset; +} __packed; +struct ec_response_i2c_read { +	uint16_t data; +} __packed; + +/* Write I2C bus */ +#define EC_CMD_I2C_WRITE 0x95 + +struct ec_params_i2c_write { +	uint16_t data; +	uint16_t addr; +	uint8_t write_size; /* Either 8 or 16. */ +	uint8_t port; +	uint8_t offset; +} __packed; + +/*****************************************************************************/ +/* Charge state commands. Only available when flash write protect unlocked. */ + +/* Force charge state machine to stop in idle mode */ +#define EC_CMD_CHARGE_FORCE_IDLE 0x96 + +struct ec_params_force_idle { +	uint8_t enabled; +} __packed; + +/*****************************************************************************/ +/* Console commands. Only available when flash write protect is unlocked. */ + +/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */ +#define EC_CMD_CONSOLE_SNAPSHOT 0x97 + +/* + * Read next chunk of data from saved snapshot. + * + * Response is null-terminated string.  Empty string, if there is no more + * remaining output. + */ +#define EC_CMD_CONSOLE_READ 0x98 + +/*****************************************************************************/ + +/* + * Cut off battery power output if the battery supports. + * + * For unsupported battery, just don't implement this command and lets EC + * return EC_RES_INVALID_COMMAND. + */ +#define EC_CMD_BATTERY_CUT_OFF 0x99 + +/*****************************************************************************/ +/* USB port mux control. */ + +/* + * Switch USB mux or return to automatic switching. + */ +#define EC_CMD_USB_MUX 0x9a + +struct ec_params_usb_mux { +	uint8_t mux; +} __packed; + +/*****************************************************************************/ +/* LDOs / FETs control. */ + +enum ec_ldo_state { +	EC_LDO_STATE_OFF = 0,	/* the LDO / FET is shut down */ +	EC_LDO_STATE_ON = 1,	/* the LDO / FET is ON / providing power */ +}; + +/* + * Switch on/off a LDO. + */ +#define EC_CMD_LDO_SET 0x9b + +struct ec_params_ldo_set { +	uint8_t index; +	uint8_t state; +} __packed; + +/* + * Get LDO state. + */ +#define EC_CMD_LDO_GET 0x9c + +struct ec_params_ldo_get { +	uint8_t index; +} __packed; + +struct ec_response_ldo_get { +	uint8_t state; +} __packed; + +/*****************************************************************************/ +/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */ + +/* + * Dump charge state machine context. + * + * Response is a binary dump of charge state machine context. + */ +#define EC_CMD_CHARGE_DUMP 0xa0 + +/* + * Set maximum battery charging current. + */ +#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1 + +struct ec_params_current_limit { +	uint32_t limit; +} __packed; + +/*****************************************************************************/ +/* Smart battery pass-through */ + +/* Get / Set 16-bit smart battery registers */ +#define EC_CMD_SB_READ_WORD   0xb0 +#define EC_CMD_SB_WRITE_WORD  0xb1 + +/* Get / Set string smart battery parameters + * formatted as SMBUS "block". + */ +#define EC_CMD_SB_READ_BLOCK  0xb2 +#define EC_CMD_SB_WRITE_BLOCK 0xb3 + +struct ec_params_sb_rd { +	uint8_t reg; +} __packed; + +struct ec_response_sb_rd_word { +	uint16_t value; +} __packed; + +struct ec_params_sb_wr_word { +	uint8_t reg; +	uint16_t value; +} __packed; + +struct ec_response_sb_rd_block { +	uint8_t data[32]; +} __packed; + +struct ec_params_sb_wr_block { +	uint8_t reg; +	uint16_t data[32]; +} __packed; + +/*****************************************************************************/ +/* System commands */ + +/* + * TODO: this is a confusing name, since it doesn't necessarily reboot the EC. + * Rename to "set image" or something similar. + */ +#define EC_CMD_REBOOT_EC 0xd2 + +/* Command */ +enum ec_reboot_cmd { +	EC_REBOOT_CANCEL = 0,        /* Cancel a pending reboot */ +	EC_REBOOT_JUMP_RO = 1,       /* Jump to RO without rebooting */ +	EC_REBOOT_JUMP_RW = 2,       /* Jump to RW without rebooting */ +	/* (command 3 was jump to RW-B) */ +	EC_REBOOT_COLD = 4,          /* Cold-reboot */ +	EC_REBOOT_DISABLE_JUMP = 5,  /* Disable jump until next reboot */ +	EC_REBOOT_HIBERNATE = 6      /* Hibernate EC */ +}; + +/* Flags for ec_params_reboot_ec.reboot_flags */ +#define EC_REBOOT_FLAG_RESERVED0      (1 << 0)  /* Was recovery request */ +#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)  /* Reboot after AP shutdown */ + +struct ec_params_reboot_ec { +	uint8_t cmd;           /* enum ec_reboot_cmd */ +	uint8_t flags;         /* See EC_REBOOT_FLAG_* */ +} __packed; + +/* + * Get information on last EC panic. + * + * Returns variable-length platform-dependent panic information.  See panic.h + * for details. + */ +#define EC_CMD_GET_PANIC_INFO 0xd3 + +/*****************************************************************************/ +/* + * ACPI commands + * + * These are valid ONLY on the ACPI command/data port. + */ + +/* + * ACPI Read Embedded Controller + * + * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). + * + * Use the following sequence: + * + *    - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD + *    - Wait for EC_LPC_CMDR_PENDING bit to clear + *    - Write address to EC_LPC_ADDR_ACPI_DATA + *    - Wait for EC_LPC_CMDR_DATA bit to set + *    - Read value from EC_LPC_ADDR_ACPI_DATA + */ +#define EC_CMD_ACPI_READ 0x80 + +/* + * ACPI Write Embedded Controller + * + * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). + * + * Use the following sequence: + * + *    - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD + *    - Wait for EC_LPC_CMDR_PENDING bit to clear + *    - Write address to EC_LPC_ADDR_ACPI_DATA + *    - Wait for EC_LPC_CMDR_PENDING bit to clear + *    - Write value to EC_LPC_ADDR_ACPI_DATA + */ +#define EC_CMD_ACPI_WRITE 0x81 + +/* + * ACPI Query Embedded Controller + * + * This clears the lowest-order bit in the currently pending host events, and + * sets the result code to the 1-based index of the bit (event 0x00000001 = 1, + * event 0x80000000 = 32), or 0 if no event was pending. + */ +#define EC_CMD_ACPI_QUERY_EVENT 0x84 + +/* Valid addresses in ACPI memory space, for read/write commands */ +/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */ +#define EC_ACPI_MEM_VERSION            0x00 +/* + * Test location; writing value here updates test compliment byte to (0xff - + * value). + */ +#define EC_ACPI_MEM_TEST               0x01 +/* Test compliment; writes here are ignored. */ +#define EC_ACPI_MEM_TEST_COMPLIMENT    0x02 +/* Keyboard backlight brightness percent (0 - 100) */ +#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03 + +/* Current version of ACPI memory address space */ +#define EC_ACPI_MEM_VERSION_CURRENT 1 + + +/*****************************************************************************/ +/* + * Special commands + * + * These do not follow the normal rules for commands.  See each command for + * details. + */ + +/* + * Reboot NOW + * + * This command will work even when the EC LPC interface is busy, because the + * reboot command is processed at interrupt level.  Note that when the EC + * reboots, the host will reboot too, so there is no response to this command. + * + * Use EC_CMD_REBOOT_EC to reboot the EC more politely. + */ +#define EC_CMD_REBOOT 0xd1  /* Think "die" */ + +/* + * Resend last response (not supported on LPC). + * + * Returns EC_RES_UNAVAILABLE if there is no response available - for example, + * there was no previous command, or the previous command's response was too + * big to save. + */ +#define EC_CMD_RESEND_RESPONSE 0xdb + +/* + * This header byte on a command indicate version 0. Any header byte less + * than this means that we are talking to an old EC which doesn't support + * versioning. In that case, we assume version 0. + * + * Header bytes greater than this indicate a later version. For example, + * EC_CMD_VERSION0 + 1 means we are using version 1. + * + * The old EC interface must not use commands 0dc or higher. + */ +#define EC_CMD_VERSION0 0xdc + +#endif  /* !__ACPI__ */ + +#endif  /* __CROS_EC_COMMANDS_H */ diff --git a/include/fdtdec.h b/include/fdtdec.h index 1ece6122f..d93e102ac 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -84,11 +84,14 @@ enum fdt_compat_id {  	COMPAT_SAMSUNG_EXYNOS5_SOUND,	/* Exynos Sound */  	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */  	COMPAT_SAMSUNG_EXYNOS_SPI,	/* Exynos SPI */ +	COMPAT_GOOGLE_CROS_EC,		/* Google CROS_EC Protocol */ +	COMPAT_GOOGLE_CROS_EC_KEYB,	/* Google CROS_EC Keyboard */  	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */  	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */  	COMPAT_SAMSUNG_EXYNOS_TMU,	/* Exynos TMU */  	COMPAT_SAMSUNG_EXYNOS_FIMD,	/* Exynos Display controller */  	COMPAT_SAMSUNG_EXYNOS5_DP,	/* Exynos Display port controller */ +	COMPAT_SAMSUNG_EXYNOS5_DWMMC,	/* Exynos5 DWMMC controller */  	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */  	COMPAT_GENERIC_SPI_FLASH,	/* Generic SPI Flash chip */  	COMPAT_MAXIM_98095_CODEC,	/* MAX98095 Codec */ diff --git a/include/ide.h b/include/ide.h index afea85cdc..f691a74ab 100644 --- a/include/ide.h +++ b/include/ide.h @@ -54,8 +54,9 @@ typedef ulong lbaint_t;   */  void ide_init(void); -ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer); -ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer); +ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer); +ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, +		const void *buffer);  #ifdef CONFIG_IDE_PREINIT  int ide_preinit(void); diff --git a/include/image.h b/include/image.h index 8ccc00b76..a7b93dbef 100644 --- a/include/image.h +++ b/include/image.h @@ -320,13 +320,16 @@ typedef struct bootm_headers {  	int		verify;		/* getenv("verify")[0] != 'n' */  #define	BOOTM_STATE_START	(0x00000001) -#define	BOOTM_STATE_LOADOS	(0x00000002) -#define	BOOTM_STATE_RAMDISK	(0x00000004) -#define	BOOTM_STATE_FDT		(0x00000008) -#define	BOOTM_STATE_OS_CMDLINE	(0x00000010) -#define	BOOTM_STATE_OS_BD_T	(0x00000020) -#define	BOOTM_STATE_OS_PREP	(0x00000040) -#define	BOOTM_STATE_OS_GO	(0x00000080) +#define	BOOTM_STATE_FINDOS	(0x00000002) +#define	BOOTM_STATE_FINDOTHER	(0x00000004) +#define	BOOTM_STATE_LOADOS	(0x00000008) +#define	BOOTM_STATE_RAMDISK	(0x00000010) +#define	BOOTM_STATE_FDT		(0x00000020) +#define	BOOTM_STATE_OS_CMDLINE	(0x00000040) +#define	BOOTM_STATE_OS_BD_T	(0x00000080) +#define	BOOTM_STATE_OS_PREP	(0x00000100) +#define	BOOTM_STATE_OS_FAKE_GO	(0x00000200)	/* 'Almost' run the OS */ +#define	BOOTM_STATE_OS_GO	(0x00000400)  	int		state;  #ifdef CONFIG_LMB @@ -667,11 +670,12 @@ int image_setup_linux(bootm_headers_t *images);  #define FIT_IMAGES_PATH		"/images"  #define FIT_CONFS_PATH		"/configurations" -/* hash node */ +/* hash/signature node */  #define FIT_HASH_NODENAME	"hash"  #define FIT_ALGO_PROP		"algo"  #define FIT_VALUE_PROP		"value"  #define FIT_IGNORE_PROP		"uboot-ignore" +#define FIT_SIG_NODENAME	"signature"  /* image node */  #define FIT_DATA_PROP		"data" @@ -759,12 +763,26 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,  int fit_set_timestamp(void *fit, int noffset, time_t timestamp);  /** - * fit_add_verification_data() - Calculate and add hashes to FIT + * fit_add_verification_data() - add verification data to FIT image nodes   * - * @fit:	Fit image to process - * @return 0 if ok, <0 for error + * @keydir:	Directory containing keys + * @kwydest:	FDT blob to write public key information to + * @fit:	Pointer to the FIT format image header + * @comment:	Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * + * Adds hash values for all component images in the FIT blob. + * Hashes are calculated for all component images which have hash subnodes + * with algorithm property set to one of the supported hash algorithms. + * + * Also add signatures if signature nodes are present. + * + * returns + *     0, on success + *     libfdt error code, on failure   */ -int fit_add_verification_data(void *fit); +int fit_add_verification_data(const char *keydir, void *keydest, void *fit, +			      const char *comment, int require_keys);  int fit_image_verify(const void *fit, int noffset);  int fit_config_verify(const void *fit, int conf_noffset); @@ -801,15 +819,19 @@ int calculate_hash(const void *data, int data_len, const char *algo,  			uint8_t *value, int *value_len);  /* - * At present we only support verification on the device + * At present we only support signing on the host, and verification on the + * device   */  #if defined(CONFIG_FIT_SIGNATURE)  # ifdef USE_HOSTCC +#  define IMAGE_ENABLE_SIGN	1  #  define IMAGE_ENABLE_VERIFY	0  #else +#  define IMAGE_ENABLE_SIGN	0  #  define IMAGE_ENABLE_VERIFY	1  # endif  #else +# define IMAGE_ENABLE_SIGN	0  # define IMAGE_ENABLE_VERIFY	0  #endif @@ -825,6 +847,137 @@ int calculate_hash(const void *data, int data_len, const char *algo,  #define IMAGE_ENABLE_BEST_MATCH	0  #endif +/* Information passed to the signing routines */ +struct image_sign_info { +	const char *keydir;		/* Directory conaining keys */ +	const char *keyname;		/* Name of key to use */ +	void *fit;			/* Pointer to FIT blob */ +	int node_offset;		/* Offset of signature node */ +	struct image_sig_algo *algo;	/* Algorithm information */ +	const void *fdt_blob;		/* FDT containing public keys */ +	int required_keynode;		/* Node offset of key to use: -1=any */ +	const char *require_keys;	/* Value for 'required' property */ +}; + +/* A part of an image, used for hashing */ +struct image_region { +	const void *data; +	int size; +}; + +struct image_sig_algo { +	const char *name;		/* Name of algorithm */ + +	/** +	 * sign() - calculate and return signature for given input data +	 * +	 * @info:	Specifies key and FIT information +	 * @data:	Pointer to the input data +	 * @data_len:	Data length +	 * @sigp:	Set to an allocated buffer holding the signature +	 * @sig_len:	Set to length of the calculated hash +	 * +	 * This computes input data signature according to selected algorithm. +	 * Resulting signature value is placed in an allocated buffer, the +	 * pointer is returned as *sigp. The length of the calculated +	 * signature is returned via the sig_len pointer argument. The caller +	 * should free *sigp. +	 * +	 * @return: 0, on success, -ve on error +	 */ +	int (*sign)(struct image_sign_info *info, +		    const struct image_region region[], +		    int region_count, uint8_t **sigp, uint *sig_len); + +	/** +	 * add_verify_data() - Add verification information to FDT +	 * +	 * Add public key information to the FDT node, suitable for +	 * verification at run-time. The information added depends on the +	 * algorithm being used. +	 * +	 * @info:	Specifies key and FIT information +	 * @keydest:	Destination FDT blob for public key data +	 * @return: 0, on success, -ve on error +	 */ +	int (*add_verify_data)(struct image_sign_info *info, void *keydest); + +	/** +	 * verify() - Verify a signature against some data +	 * +	 * @info:	Specifies key and FIT information +	 * @data:	Pointer to the input data +	 * @data_len:	Data length +	 * @sig:	Signature +	 * @sig_len:	Number of bytes in signature +	 * @return 0 if verified, -ve on error +	 */ +	int (*verify)(struct image_sign_info *info, +		      const struct image_region region[], int region_count, +		      uint8_t *sig, uint sig_len); +}; + +/** + * image_get_sig_algo() - Look up a signature algortihm + * + * @param name		Name of algorithm + * @return pointer to algorithm information, or NULL if not found + */ +struct image_sig_algo *image_get_sig_algo(const char *name); + +/** + * fit_image_verify_required_sigs() - Verify signatures marked as 'required' + * + * @fit:		FIT to check + * @image_noffset:	Offset of image node to check + * @data:		Image data to check + * @size:		Size of image data + * @sig_blob:		FDT containing public keys + * @no_sigsp:		Returns 1 if no signatures were required, and + *			therefore nothing was checked. The caller may wish + *			to fall back to other mechanisms, or refuse to + *			boot. + * @return 0 if all verified ok, <0 on error + */ +int fit_image_verify_required_sigs(const void *fit, int image_noffset, +		const char *data, size_t size, const void *sig_blob, +		int *no_sigsp); + +/** + * fit_image_check_sig() - Check a single image signature node + * + * @fit:		FIT to check + * @noffset:		Offset of signature node to check + * @data:		Image data to check + * @size:		Size of image data + * @required_keynode:	Offset in the control FDT of the required key node, + *			if any. If this is given, then the image wil not + *			pass verification unless that key is used. If this is + *			-1 then any signature will do. + * @err_msgp:		In the event of an error, this will be pointed to a + *			help error string to display to the user. + * @return 0 if all verified ok, <0 on error + */ +int fit_image_check_sig(const void *fit, int noffset, const void *data, +		size_t size, int required_keynode, char **err_msgp); + +/** + * fit_region_make_list() - Make a list of regions to hash + * + * Given a list of FIT regions (offset, size) provided by libfdt, create + * a list of regions (void *, size) for use by the signature creationg + * and verification code. + * + * @fit:		FIT image to process + * @fdt_regions:	Regions as returned by libfdt + * @count:		Number of regions returned by libfdt + * @region:		Place to put list of regions (NULL to allocate it) + * @return pointer to list of regions, or NULL if out of memory + */ +struct image_region *fit_region_make_list(const void *fit, +		struct fdt_region *fdt_regions, int count, +		struct image_region *region); +  static inline int fit_image_check_target_arch(const void *fdt, int node)  {  	return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT); diff --git a/include/libfdt.h b/include/libfdt.h index c5ec2acfd..765d84f5e 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -1511,4 +1511,68 @@ int fdt_del_node(void *fdt, int nodeoffset);  const char *fdt_strerror(int errval); +struct fdt_region { +	int offset; +	int size; +}; + +/** + * fdt_find_regions() - find regions in device tree + * + * Given a list of nodes to include and properties to exclude, find + * the regions of the device tree which describe those included parts. + * + * The intent is to get a list of regions which will be invariant provided + * those parts are invariant. For example, if you request a list of regions + * for all nodes but exclude the property "data", then you will get the + * same region contents regardless of any change to "data" properties. + * + * This function can be used to produce a byte-stream to send to a hashing + * function to verify that critical parts of the FDT have not changed. + * + * Nodes which are given in 'inc' are included in the region list, as + * are the names of the immediate subnodes nodes (but not the properties + * or subnodes of those subnodes). + * + * For eaxample "/" means to include the root node, all root properties + * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter + * ensures that we capture the names of the subnodes. In a hashing situation + * it prevents the root node from changing at all Any change to non-excluded + * properties, names of subnodes or number of subnodes would be detected. + * + * When used with FITs this provides the ability to hash and sign parts of + * the FIT based on different configurations in the FIT. Then it is + * impossible to change anything about that configuration (include images + * attached to the configuration), but it may be possible to add new + * configurations, new images or new signatures within the existing + * framework. + * + * Adding new properties to a device tree may result in the string table + * being extended (if the new property names are different from those + * already added). This function can optionally include a region for + * the string table so that this can be part of the hash too. + * + * The device tree header is not included in the list. + * + * @fdt:	Device tree to check + * @inc:	List of node paths to included + * @inc_count:	Number of node paths in list + * @exc_prop:	List of properties names to exclude + * @exc_prop_count:	Number of properties in exclude list + * @region:	Returns list of regions + * @max_region:	Maximum length of region list + * @path:	Pointer to a temporary string for the function to use for + *		building path names + * @path_len:	Length of path, must be large enough to hold the longest + *		path in the tree + * @add_string_tab:	1 to add a region for the string table + * @return number of regions in list. If this is >max_regions then the + * region array was exhausted. You should increase max_regions and try + * the call again. + */ +int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, +		     char * const exc_prop[], int exc_prop_count, +		     struct fdt_region region[], int max_regions, +		     char *path, int path_len, int add_string_tab); +  #endif /* _LIBFDT_H */ diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index fcb20fe10..f6dbdb096 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -580,6 +580,8 @@ enum ethtool_sfeatures_retval_bits {  #define SUPPORTED_10000baseKX4_Full	(1 << 18)  #define SUPPORTED_10000baseKR_Full	(1 << 19)  #define SUPPORTED_10000baseR_FEC	(1 << 20) +#define SUPPORTED_1000baseX_Half	(1 << 21) +#define SUPPORTED_1000baseX_Full	(1 << 22)  /* Indicates what features are advertised by the interface. */  #define ADVERTISED_10baseT_Half		(1 << 0) @@ -603,6 +605,8 @@ enum ethtool_sfeatures_retval_bits {  #define ADVERTISED_10000baseKX4_Full	(1 << 18)  #define ADVERTISED_10000baseKR_Full	(1 << 19)  #define ADVERTISED_10000baseR_FEC	(1 << 20) +#define ADVERTISED_1000baseX_Half	(1 << 21) +#define ADVERTISED_1000baseX_Full	(1 << 22)  /* The following are all involved in forcing a particular link   * mode for the device for setting things.  When getting the diff --git a/include/linux/mii.h b/include/linux/mii.h index 8b9269214..66b83d83d 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -115,6 +115,8 @@  #define EXPANSION_MFAULTS	0x0010	/* Multiple faults detected    */  #define EXPANSION_RESV		0xffe0	/* Unused...		       */ +#define ESTATUS_1000_XFULL	0x8000	/* Can do 1000BX Full */ +#define ESTATUS_1000_XHALF	0x4000	/* Can do 1000BX Half */  #define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */  #define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */ diff --git a/include/micrel.h b/include/micrel.h index 25e8a4624..e1c62d83c 100644 --- a/include/micrel.h +++ b/include/micrel.h @@ -8,9 +8,20 @@  #define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW	0x105  #define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW	0x106  #define MII_KSZ9021_EXT_ANALOG_TEST		0x107 +/* Register operations */ +#define MII_KSZ9031_MOD_REG			0x0000 +/* Data operations */ +#define MII_KSZ9031_MOD_DATA_NO_POST_INC	0x4000 +#define MII_KSZ9031_MOD_DATA_POST_INC_RW	0x8000 +#define MII_KSZ9031_MOD_DATA_POST_INC_W		0xC000  struct phy_device;  int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val);  int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum); +int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr, +			       int regnum, u16 mode, u16 val); +int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, +			      int regnum, u16 mode); +  #endif diff --git a/include/mmc.h b/include/mmc.h index ea198d87b..583c30e27 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -93,6 +93,11 @@  #define MMC_CMD_APP_CMD			55  #define MMC_CMD_SPI_READ_OCR		58  #define MMC_CMD_SPI_CRC_ON_OFF		59 +#define MMC_CMD_RES_MAN			62 + +#define MMC_CMD62_ARG1			0xefac62ec +#define MMC_CMD62_ARG2			0xcbaea7 +  #define SD_CMD_SEND_RELATIVE_ADDR	3  #define SD_CMD_SWITCH_FUNC		6 @@ -162,6 +167,7 @@  #define EXT_CSD_PARTITIONING_SUPPORT	160	/* RO */  #define EXT_CSD_RPMB_MULT		168	/* RO */  #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */ +#define EXT_CSD_BOOT_BUS_WIDTH		177  #define EXT_CSD_PART_CONF		179	/* R/W */  #define EXT_CSD_BUS_WIDTH		183	/* R/W */  #define EXT_CSD_HS_TIMING		185	/* R/W */ @@ -187,6 +193,16 @@  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */ +#define EXT_CSD_BOOT_ACK_ENABLE			(1 << 6) +#define EXT_CSD_BOOT_PARTITION_ENABLE		(1 << 3) +#define EXT_CSD_PARTITION_ACCESS_ENABLE		(1 << 0) +#define EXT_CSD_PARTITION_ACCESS_DISABLE	(0 << 0) + +#define EXT_CSD_BOOT_ACK(x)		(x << 6) +#define EXT_CSD_BOOT_PART_NUM(x)	(x << 3) +#define EXT_CSD_PARTITION_ACCESS(x)	(x << 0) + +  #define R1_ILLEGAL_COMMAND		(1 << 22)  #define R1_APP_CMD			(1 << 5) @@ -214,6 +230,11 @@  /* Maximum block size for MMC */  #define MMC_MAX_BLOCK_LEN	512 +/* The number of MMC physical partitions.  These consist of: + * boot partitions (2), general purpose partitions (4) in MMC v4.4. + */ +#define MMC_NUM_BOOT_PARTITION	2 +  struct mmc_cid {  	unsigned long psn;  	unsigned short oid; @@ -298,6 +319,11 @@ int mmc_switch_part(int dev_num, unsigned int part_num);  int mmc_getcd(struct mmc *mmc);  int mmc_getwp(struct mmc *mmc);  void spl_mmc_load(void) __noreturn; +/* Function to change the size of boot partition and rpmb partitions */ +int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, +					unsigned long rpmbsize); +/* Function to send commands to open/close the specified boot partition */ +int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access);  /**   * Start device initialization and return immediately; it does not block on diff --git a/include/net.h b/include/net.h index 23fb94729..767347004 100644 --- a/include/net.h +++ b/include/net.h @@ -39,7 +39,7 @@  #define PKTALIGN	ARCH_DMA_MINALIGN  /* IPv4 addresses are always 32 bits in size */ -typedef u32		IPaddr_t; +typedef __be32		IPaddr_t;  /** diff --git a/include/netdev.h b/include/netdev.h index df454b50c..917d8746f 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -67,10 +67,12 @@ int fecmxc_initialize(bd_t *bis);  int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);  int ftgmac100_initialize(bd_t *bits);  int ftmac100_initialize(bd_t *bits); +int ftmac110_initialize(bd_t *bits);  int greth_initialize(bd_t *bis);  void gt6426x_eth_initialize(bd_t *bis);  int inca_switch_initialize(bd_t *bis);  int ks8695_eth_initialize(void); +int ks8851_mll_initialize(u8 dev_num, int base_addr);  int lan91c96_initialize(u8 dev_num, int base_addr);  int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);  int mcdmafec_initialize(bd_t *bis); @@ -93,6 +95,7 @@ int sh_eth_initialize(bd_t *bis);  int skge_initialize(bd_t *bis);  int smc91111_initialize(u8 dev_num, int base_addr);  int smc911x_initialize(u8 dev_num, int base_addr); +int sunxi_wemac_initialize(bd_t *bis);  int tsi108_eth_initialize(bd_t *bis);  int uec_standard_init(bd_t *bis);  int uli526x_initialize(bd_t *bis); diff --git a/include/part.h b/include/part.h index f7c7cc59f..35c1c5b5f 100644 --- a/include/part.h +++ b/include/part.h @@ -43,15 +43,15 @@ typedef struct block_dev_desc {  	char		product[20+1];	/* IDE Serial no, SCSI product */  	char		revision[8+1];	/* firmware revision */  	unsigned long	(*block_read)(int dev, -				      unsigned long start, +				      lbaint_t start,  				      lbaint_t blkcnt,  				      void *buffer);  	unsigned long	(*block_write)(int dev, -				       unsigned long start, +				       lbaint_t start,  				       lbaint_t blkcnt,  				       const void *buffer);  	unsigned long   (*block_erase)(int dev, -				       unsigned long start, +				       lbaint_t start,  				       lbaint_t blkcnt);  	void		*priv;		/* driver private struct pointer */  }block_dev_desc_t; diff --git a/include/pci.h b/include/pci.h index f9c514825..98ba151f9 100644 --- a/include/pci.h +++ b/include/pci.h @@ -462,7 +462,7 @@ struct pci_region {  #define PCI_REGION_SYS_MEMORY	0x00000100	/* System memory */  #define PCI_REGION_RO		0x00000200	/* Read-only memory */ -extern __inline__ void pci_set_region(struct pci_region *reg, +static inline void pci_set_region(struct pci_region *reg,  				      pci_addr_t bus_start,  				      phys_addr_t phys_start,  				      pci_size_t size, @@ -548,7 +548,7 @@ struct pci_controller {  	void *priv_data;  }; -extern __inline__ void pci_set_ops(struct pci_controller *hose, +static inline void pci_set_ops(struct pci_controller *hose,  				   int (*read_byte)(struct pci_controller*,  						    pci_dev_t, int where, u8 *),  				   int (*read_word)(struct pci_controller*, diff --git a/include/phy.h b/include/phy.h index 75bf3b472..dbf32740b 100644 --- a/include/phy.h +++ b/include/phy.h @@ -214,6 +214,7 @@ int phy_register(struct phy_driver *drv);  int genphy_config_aneg(struct phy_device *phydev);  int genphy_restart_aneg(struct phy_device *phydev);  int genphy_update_link(struct phy_device *phydev); +int genphy_parse_link(struct phy_device *phydev);  int genphy_config(struct phy_device *phydev);  int genphy_startup(struct phy_device *phydev);  int genphy_shutdown(struct phy_device *phydev); diff --git a/include/rsa.h b/include/rsa.h new file mode 100644 index 000000000..a5dd676b6 --- /dev/null +++ b/include/rsa.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _RSA_H +#define _RSA_H + +#include <errno.h> +#include <image.h> + +#if IMAGE_ENABLE_SIGN +/** + * sign() - calculate and return signature for given input data + * + * @info:	Specifies key and FIT information + * @data:	Pointer to the input data + * @data_len:	Data length + * @sigp:	Set to an allocated buffer holding the signature + * @sig_len:	Set to length of the calculated hash + * + * This computes input data signature according to selected algorithm. + * Resulting signature value is placed in an allocated buffer, the + * pointer is returned as *sigp. The length of the calculated + * signature is returned via the sig_len pointer argument. The caller + * should free *sigp. + * + * @return: 0, on success, -ve on error + */ +int rsa_sign(struct image_sign_info *info, +	     const struct image_region region[], +	     int region_count, uint8_t **sigp, uint *sig_len); + +/** + * add_verify_data() - Add verification information to FDT + * + * Add public key information to the FDT node, suitable for + * verification at run-time. The information added depends on the + * algorithm being used. + * + * @info:	Specifies key and FIT information + * @keydest:	Destination FDT blob for public key data + * @return: 0, on success, -ve on error +*/ +int rsa_add_verify_data(struct image_sign_info *info, void *keydest); +#else +static inline int rsa_sign(struct image_sign_info *info, +		const struct image_region region[], int region_count, +		uint8_t **sigp, uint *sig_len) +{ +	return -ENXIO; +} + +static inline int rsa_add_verify_data(struct image_sign_info *info, +				      void *keydest) +{ +	return -ENXIO; +} +#endif + +#if IMAGE_ENABLE_VERIFY +/** + * rsa_verify() - Verify a signature against some data + * + * Verify a RSA PKCS1.5 signature against an expected hash. + * + * @info:	Specifies key and FIT information + * @data:	Pointer to the input data + * @data_len:	Data length + * @sig:	Signature + * @sig_len:	Number of bytes in signature + * @return 0 if verified, -ve on error + */ +int rsa_verify(struct image_sign_info *info, +	       const struct image_region region[], int region_count, +	       uint8_t *sig, uint sig_len); +#else +static inline int rsa_verify(struct image_sign_info *info, +		const struct image_region region[], int region_count, +		uint8_t *sig, uint sig_len) +{ +	return -ENXIO; +} +#endif + +#endif diff --git a/include/spi.h b/include/spi.h index 1638b5039..e8e654467 100644 --- a/include/spi.h +++ b/include/spi.h @@ -247,4 +247,20 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte)  	return ret < 0 ? ret : din[1];  } +/** + * Set up a SPI slave for a particular device tree node + * + * This calls spi_setup_slave() with the correct bus number. Call + * spi_free_slave() to free it later. + * + * @param blob		Device tree blob + * @param node		SPI peripheral node to use + * @param cs		Chip select to use + * @param max_hz	Maximum SCK rate in Hz (0 for default) + * @param mode		Clock polarity, clock phase and other parameters + * @return pointer to new spi_slave structure + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, +		unsigned int cs, unsigned int max_hz, unsigned int mode); +  #endif	/* _SPI_H_ */ diff --git a/include/spi_flash.h b/include/spi_flash.h index 3b6a44edc..e80785f55 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -38,6 +38,16 @@ struct spi_flash {  	u32		page_size;  	/* Erase (sector) size */  	u32		sector_size; +#ifdef CONFIG_SPI_FLASH_BAR +	/* Bank read cmd */ +	u8		bank_read_cmd; +	/* Bank write cmd */ +	u8		bank_write_cmd; +	/* Current flash bank */ +	u8		bank_curr; +#endif +	/* Poll cmd - for flash erase/program */ +	u8		poll_cmd;  	void *memory_map;	/* Address of read-only SPI flash access */  	int		(*read)(struct spi_flash *flash, u32 offset, diff --git a/include/trace.h b/include/trace.h new file mode 100644 index 000000000..8082466f5 --- /dev/null +++ b/include/trace.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __TRACE_H +#define __TRACE_H + +enum { +	/* +	 * This affects the granularity of our trace. We can bin function +	 * entry points into groups on the basis that functions typically +	 * have a minimum size, so entry points can't appear any closer +	 * than this to each other. +	 * +	 * The value here assumes a minimum instruction size of 4 bytes, +	 * or that instructions are 2 bytes but there are at least 2 of +	 * them in every function. +	 * +	 * Increasing this value reduces the number of functions we can +	 * resolve, but reduces the size of the uintptr_t array used for +	 * our function list, which is the length of the code divided by +	 * this value. +	 */ +	FUNC_SITE_SIZE	= 4,	/* distance between function sites */ +}; + +enum trace_chunk_type { +	TRACE_CHUNK_FUNCS, +	TRACE_CHUNK_CALLS, +}; + +/* A trace record for a function, as written to the profile output file */ +struct trace_output_func { +	uint32_t offset;		/* Function offset into code */ +	uint32_t call_count;		/* Number of times called */ +}; + +/* A header at the start of the trace output buffer */ +struct trace_output_hdr { +	enum trace_chunk_type type;	/* Record type */ +	uint32_t rec_count;		/* Number of records */ +}; + +/* Print statistics about traced function calls */ +void trace_print_stats(void); + +/** + * Dump a list of functions and call counts into a buffer + * + * Each record in the buffer is a struct trace_func_stats. The 'needed' + * parameter returns the number of bytes needed to complete the operation, + * which may be more than buff_size if your buffer is too small. + * + * @param buff		Buffer in which to place data, or NULL to count size + * @param buff_size	Size of buffer + * @param needed	Returns number of bytes used / needed + * @return 0 if ok, -1 on error (buffer exhausted) + */ +int trace_list_functions(void *buff, int buff_size, unsigned *needed); + +/* Flags for ftrace_record */ +enum ftrace_flags { +	FUNCF_EXIT		= 0UL << 30, +	FUNCF_ENTRY		= 1UL << 30, +	FUNCF_TEXTBASE		= 2UL << 30, + +	FUNCF_TIMESTAMP_MASK	= 0x3fffffff, +}; + +#define TRACE_CALL_TYPE(call)	((call)->flags & 0xc0000000UL) + +/* Information about a single function entry/exit */ +struct trace_call { +	uint32_t func;		/* Function offset */ +	uint32_t caller;	/* Caller function offset */ +	uint32_t flags;		/* Flags and timestamp */ +}; + +int trace_list_calls(void *buff, int buff_size, unsigned int *needed); + +/** + * Turn function tracing on and off + * + * Don't enable trace if it has not been initialised. + * + * @param enabled	1 to enable trace, 0 to disable + */ +void trace_set_enabled(int enabled); + +#ifdef CONFIG_TRACE_EARLY +int trace_early_init(void); +#else +static inline int trace_early_init(void) +{ +	return 0; +} +#endif + +/** + * Init the trace system + * + * This should be called after relocation with a suitably large buffer + * (typically as large as the U-Boot text area) + * + * @param buff		Pointer to trace buffer + * @param buff_size	Size of trace buffer + */ +int trace_init(void *buff, size_t buff_size); + +#endif diff --git a/include/vsprintf.h b/include/vsprintf.h index 651077ca4..6568854fb 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -178,4 +178,15 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);  #define vscnprintf(buf, size, fmt, args...) vsprintf(buf, fmt, ##args)  #endif /* CONFIG_SYS_VSNPRINTF */ +/** + * print_grouped_ull() - print a value with digits grouped by ',' + * + * This prints a value with grouped digits, like 12,345,678 to make it easier + * to read. + * + * @val:	Value to print + * @digits:	Number of digiits to print + */ +void print_grouped_ull(unsigned long long int_val, int digits); +  #endif diff --git a/lib/Makefile b/lib/Makefile index 5d586098d..f5a8819f3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,7 +26,6 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)libgeneric.o  ifndef CONFIG_SPL_BUILD -COBJS-$(CONFIG_ADDR_MAP) += addr_map.o  COBJS-$(CONFIG_AES) += aes.o  COBJS-$(CONFIG_BZIP2) += bzlib.o  COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o @@ -36,13 +35,10 @@ COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o  COBJS-$(CONFIG_USB_TTY) += circbuf.o  COBJS-y += crc7.o  COBJS-y += crc16.o -COBJS-y += display_options.o -COBJS-y += errno.o  COBJS-$(CONFIG_OF_CONTROL) += fdtdec.o  COBJS-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o  COBJS-$(CONFIG_GZIP) += gunzip.o  COBJS-$(CONFIG_GZIP_COMPRESSED) += gzip.o -COBJS-y += hashtable.o  COBJS-y += initcall.o  COBJS-$(CONFIG_LMB) += lmb.o  COBJS-y += ldiv.o @@ -60,14 +56,12 @@ endif  ifdef CONFIG_SPL_BUILD  COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += crc32.o -ifneq ($(CONFIG_SPL_SPI_FLASH_SUPPORT)$(CONFIG_SPL_NET_SUPPORT),) -COBJS-y += display_options.o -endif -COBJS-$(CONFIG_SPL_NET_SUPPORT) += errno.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += hashtable.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o  endif +COBJS-$(CONFIG_ADDR_MAP) += addr_map.o +COBJS-y += hashtable.o +COBJS-y += errno.o +COBJS-y += display_options.o  COBJS-$(CONFIG_BCH) += bch.o  COBJS-y += crc32.o  COBJS-y += ctype.o @@ -77,6 +71,7 @@ COBJS-y += linux_string.o  COBJS-$(CONFIG_REGEX) += slre.o  COBJS-y += string.o  COBJS-y += time.o +COBJS-$(CONFIG_TRACE) += trace.o  COBJS-$(CONFIG_BOOTP_PXE) += uuid.o  COBJS-y += vsprintf.o  COBJS-$(CONFIG_RANDOM_MACADDR) += rand.o diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 005ad3d53..b3142685a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -57,11 +57,14 @@ static const char * const compat_names[COMPAT_COUNT] = {  	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),  	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),  	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), +	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), +	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),  	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),  	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),  	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),  	COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"),  	COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"), +	COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"),  	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),  	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),  	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index 63e67b78c..b9e3c4a74 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -120,3 +120,132 @@ int fdt_nop_node(void *fdt, int nodeoffset)  			endoffset - nodeoffset);  	return 0;  } + +#define FDT_MAX_DEPTH	32 + +static int str_in_list(const char *str, char * const list[], int count) +{ +	int i; + +	for (i = 0; i < count; i++) +		if (!strcmp(list[i], str)) +			return 1; + +	return 0; +} + +int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, +		     char * const exc_prop[], int exc_prop_count, +		     struct fdt_region region[], int max_regions, +		     char *path, int path_len, int add_string_tab) +{ +	int stack[FDT_MAX_DEPTH]; +	char *end; +	int nextoffset = 0; +	uint32_t tag; +	int count = 0; +	int start = -1; +	int depth = -1; +	int want = 0; +	int base = fdt_off_dt_struct(fdt); + +	end = path; +	*end = '\0'; +	do { +		const struct fdt_property *prop; +		const char *name; +		const char *str; +		int include = 0; +		int stop_at = 0; +		int offset; +		int len; + +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); +		stop_at = nextoffset; + +		switch (tag) { +		case FDT_PROP: +			include = want >= 2; +			stop_at = offset; +			prop = fdt_get_property_by_offset(fdt, offset, NULL); +			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); +			if (str_in_list(str, exc_prop, exc_prop_count)) +				include = 0; +			break; + +		case FDT_NOP: +			include = want >= 2; +			stop_at = offset; +			break; + +		case FDT_BEGIN_NODE: +			depth++; +			if (depth == FDT_MAX_DEPTH) +				return -FDT_ERR_BADSTRUCTURE; +			name = fdt_get_name(fdt, offset, &len); +			if (end - path + 2 + len >= path_len) +				return -FDT_ERR_NOSPACE; +			if (end != path + 1) +				*end++ = '/'; +			strcpy(end, name); +			end += len; +			stack[depth] = want; +			if (want == 1) +				stop_at = offset; +			if (str_in_list(path, inc, inc_count)) +				want = 2; +			else if (want) +				want--; +			else +				stop_at = offset; +			include = want; +			break; + +		case FDT_END_NODE: +			include = want; +			want = stack[depth--]; +			while (end > path && *--end != '/') +				; +			*end = '\0'; +			break; + +		case FDT_END: +			include = 1; +			break; +		} + +		if (include && start == -1) { +			/* Should we merge with previous? */ +			if (count && count <= max_regions && +			    offset == region[count - 1].offset + +					region[count - 1].size - base) +				start = region[--count].offset - base; +			else +				start = offset; +		} + +		if (!include && start != -1) { +			if (count < max_regions) { +				region[count].offset = base + start; +				region[count].size = stop_at - start; +			} +			count++; +			start = -1; +		} +	} while (tag != FDT_END); + +	if (nextoffset != fdt_size_dt_struct(fdt)) +		return -FDT_ERR_BADLAYOUT; + +	/* Add a region for the END tag and the string table */ +	if (count < max_regions) { +		region[count].offset = base + start; +		region[count].size = nextoffset - start; +		if (add_string_tab) +			region[count].size += fdt_size_dt_strings(fdt); +	} +	count++; + +	return count; +} diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile new file mode 100644 index 000000000..9eb3e40f5 --- /dev/null +++ b/lib/rsa/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2013, Google Inc. +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)librsa.o + +ifdef CONFIG_FIT_SIGNATURE +COBJS-$(CONFIG_RSA) += rsa-verify.o +endif + +COBJS	:= $(sort $(COBJS-y)) +SRCS	:= $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c new file mode 100644 index 000000000..a75ae245e --- /dev/null +++ b/lib/rsa/rsa-sign.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "mkimage.h" +#include <stdio.h> +#include <string.h> +#include <error.h> +#include <image.h> +#include <time.h> +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <openssl/evp.h> + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#define HAVE_ERR_REMOVE_THREAD_STATE +#endif + +static int rsa_err(const char *msg) +{ +	unsigned long sslErr = ERR_get_error(); + +	fprintf(stderr, "%s", msg); +	fprintf(stderr, ": %s\n", +		ERR_error_string(sslErr, 0)); + +	return -1; +} + +/** + * rsa_get_pub_key() - read a public key from a .crt file + * + * @keydir:	Directory containins the key + * @name	Name of key file (will have a .crt extension) + * @rsap	Returns RSA object, or NULL on failure + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) + */ +static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap) +{ +	char path[1024]; +	EVP_PKEY *key; +	X509 *cert; +	RSA *rsa; +	FILE *f; +	int ret; + +	*rsap = NULL; +	snprintf(path, sizeof(path), "%s/%s.crt", keydir, name); +	f = fopen(path, "r"); +	if (!f) { +		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", +			path, strerror(errno)); +		return -EACCES; +	} + +	/* Read the certificate */ +	cert = NULL; +	if (!PEM_read_X509(f, &cert, NULL, NULL)) { +		rsa_err("Couldn't read certificate"); +		ret = -EINVAL; +		goto err_cert; +	} + +	/* Get the public key from the certificate. */ +	key = X509_get_pubkey(cert); +	if (!key) { +		rsa_err("Couldn't read public key\n"); +		ret = -EINVAL; +		goto err_pubkey; +	} + +	/* Convert to a RSA_style key. */ +	rsa = EVP_PKEY_get1_RSA(key); +	if (!rsa) { +		rsa_err("Couldn't convert to a RSA style key"); +		goto err_rsa; +	} +	fclose(f); +	EVP_PKEY_free(key); +	X509_free(cert); +	*rsap = rsa; + +	return 0; + +err_rsa: +	EVP_PKEY_free(key); +err_pubkey: +	X509_free(cert); +err_cert: +	fclose(f); +	return ret; +} + +/** + * rsa_get_priv_key() - read a private key from a .key file + * + * @keydir:	Directory containins the key + * @name	Name of key file (will have a .key extension) + * @rsap	Returns RSA object, or NULL on failure + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) + */ +static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap) +{ +	char path[1024]; +	RSA *rsa; +	FILE *f; + +	*rsap = NULL; +	snprintf(path, sizeof(path), "%s/%s.key", keydir, name); +	f = fopen(path, "r"); +	if (!f) { +		fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", +			path, strerror(errno)); +		return -ENOENT; +	} + +	rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path); +	if (!rsa) { +		rsa_err("Failure reading private key"); +		fclose(f); +		return -EPROTO; +	} +	fclose(f); +	*rsap = rsa; + +	return 0; +} + +static int rsa_init(void) +{ +	int ret; + +	ret = SSL_library_init(); +	if (!ret) { +		fprintf(stderr, "Failure to init SSL library\n"); +		return -1; +	} +	SSL_load_error_strings(); + +	OpenSSL_add_all_algorithms(); +	OpenSSL_add_all_digests(); +	OpenSSL_add_all_ciphers(); + +	return 0; +} + +static void rsa_remove(void) +{ +	CRYPTO_cleanup_all_ex_data(); +	ERR_free_strings(); +#ifdef HAVE_ERR_REMOVE_THREAD_STATE +	ERR_remove_thread_state(NULL); +#else +	ERR_remove_state(0); +#endif +	EVP_cleanup(); +} + +static int rsa_sign_with_key(RSA *rsa, const struct image_region region[], +		int region_count, uint8_t **sigp, uint *sig_size) +{ +	EVP_PKEY *key; +	EVP_MD_CTX *context; +	int size, ret = 0; +	uint8_t *sig; +	int i; + +	key = EVP_PKEY_new(); +	if (!key) +		return rsa_err("EVP_PKEY object creation failed"); + +	if (!EVP_PKEY_set1_RSA(key, rsa)) { +		ret = rsa_err("EVP key setup failed"); +		goto err_set; +	} + +	size = EVP_PKEY_size(key); +	sig = malloc(size); +	if (!sig) { +		fprintf(stderr, "Out of memory for signature (%d bytes)\n", +			size); +		ret = -ENOMEM; +		goto err_alloc; +	} + +	context = EVP_MD_CTX_create(); +	if (!context) { +		ret = rsa_err("EVP context creation failed"); +		goto err_create; +	} +	EVP_MD_CTX_init(context); +	if (!EVP_SignInit(context, EVP_sha1())) { +		ret = rsa_err("Signer setup failed"); +		goto err_sign; +	} + +	for (i = 0; i < region_count; i++) { +		if (!EVP_SignUpdate(context, region[i].data, region[i].size)) { +			ret = rsa_err("Signing data failed"); +			goto err_sign; +		} +	} + +	if (!EVP_SignFinal(context, sig, sig_size, key)) { +		ret = rsa_err("Could not obtain signature"); +		goto err_sign; +	} +	EVP_MD_CTX_cleanup(context); +	EVP_MD_CTX_destroy(context); +	EVP_PKEY_free(key); + +	debug("Got signature: %d bytes, expected %d\n", *sig_size, size); +	*sigp = sig; +	*sig_size = size; + +	return 0; + +err_sign: +	EVP_MD_CTX_destroy(context); +err_create: +	free(sig); +err_alloc: +err_set: +	EVP_PKEY_free(key); +	return ret; +} + +int rsa_sign(struct image_sign_info *info, +	     const struct image_region region[], int region_count, +	     uint8_t **sigp, uint *sig_len) +{ +	RSA *rsa; +	int ret; + +	ret = rsa_init(); +	if (ret) +		return ret; + +	ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); +	if (ret) +		goto err_priv; +	ret = rsa_sign_with_key(rsa, region, region_count, sigp, sig_len); +	if (ret) +		goto err_sign; + +	RSA_free(rsa); +	rsa_remove(); + +	return ret; + +err_sign: +	RSA_free(rsa); +err_priv: +	rsa_remove(); +	return ret; +} + +/* + * rsa_get_params(): - Get the important parameters of an RSA public key + */ +int rsa_get_params(RSA *key, uint32_t *n0_invp, BIGNUM **modulusp, +		   BIGNUM **r_squaredp) +{ +	BIGNUM *big1, *big2, *big32, *big2_32; +	BIGNUM *n, *r, *r_squared, *tmp; +	BN_CTX *bn_ctx = BN_CTX_new(); +	int ret = 0; + +	/* Initialize BIGNUMs */ +	big1 = BN_new(); +	big2 = BN_new(); +	big32 = BN_new(); +	r = BN_new(); +	r_squared = BN_new(); +	tmp = BN_new(); +	big2_32 = BN_new(); +	n = BN_new(); +	if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 || +	    !n) { +		fprintf(stderr, "Out of memory (bignum)\n"); +		return -ENOMEM; +	} + +	if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) || +	    !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) +		ret = -1; + +	/* big2_32 = 2^32 */ +	if (!BN_exp(big2_32, big2, big32, bn_ctx)) +		ret = -1; + +	/* Calculate n0_inv = -1 / n[0] mod 2^32 */ +	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || +	    !BN_sub(tmp, big2_32, tmp)) +		ret = -1; +	*n0_invp = BN_get_word(tmp); + +	/* Calculate R = 2^(# of key bits) */ +	if (!BN_set_word(tmp, BN_num_bits(n)) || +	    !BN_exp(r, big2, tmp, bn_ctx)) +		ret = -1; + +	/* Calculate r_squared = R^2 mod n */ +	if (!BN_copy(r_squared, r) || +	    !BN_mul(tmp, r_squared, r, bn_ctx) || +	    !BN_mod(r_squared, tmp, n, bn_ctx)) +		ret = -1; + +	*modulusp = n; +	*r_squaredp = r_squared; + +	BN_free(big1); +	BN_free(big2); +	BN_free(big32); +	BN_free(r); +	BN_free(tmp); +	BN_free(big2_32); +	if (ret) { +		fprintf(stderr, "Bignum operations failed\n"); +		return -ENOMEM; +	} + +	return ret; +} + +static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, +			  BIGNUM *num, int num_bits) +{ +	int nwords = num_bits / 32; +	int size; +	uint32_t *buf, *ptr; +	BIGNUM *tmp, *big2, *big32, *big2_32; +	BN_CTX *ctx; +	int ret; + +	tmp = BN_new(); +	big2 = BN_new(); +	big32 = BN_new(); +	big2_32 = BN_new(); +	if (!tmp || !big2 || !big32 || !big2_32) { +		fprintf(stderr, "Out of memory (bignum)\n"); +		return -ENOMEM; +	} +	ctx = BN_CTX_new(); +	if (!tmp) { +		fprintf(stderr, "Out of memory (bignum context)\n"); +		return -ENOMEM; +	} +	BN_set_word(big2, 2L); +	BN_set_word(big32, 32L); +	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ + +	size = nwords * sizeof(uint32_t); +	buf = malloc(size); +	if (!buf) { +		fprintf(stderr, "Out of memory (%d bytes)\n", size); +		return -ENOMEM; +	} + +	/* Write out modulus as big endian array of integers */ +	for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { +		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ +		*ptr = cpu_to_fdt32(BN_get_word(tmp)); +		BN_rshift(num, num, 32); /*  N = N/B */ +	} + +	ret = fdt_setprop(blob, noffset, prop_name, buf, size); +	if (ret) { +		fprintf(stderr, "Failed to write public key to FIT\n"); +		return -ENOSPC; +	} +	free(buf); +	BN_free(tmp); +	BN_free(big2); +	BN_free(big32); +	BN_free(big2_32); + +	return ret; +} + +int rsa_add_verify_data(struct image_sign_info *info, void *keydest) +{ +	BIGNUM *modulus, *r_squared; +	uint32_t n0_inv; +	int parent, node; +	char name[100]; +	int ret; +	int bits; +	RSA *rsa; + +	debug("%s: Getting verification data\n", __func__); +	ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); +	if (ret) +		return ret; +	ret = rsa_get_params(rsa, &n0_inv, &modulus, &r_squared); +	if (ret) +		return ret; +	bits = BN_num_bits(modulus); +	parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); +	if (parent == -FDT_ERR_NOTFOUND) { +		parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); +		if (parent < 0) { +			fprintf(stderr, "Couldn't create signature node: %s\n", +				fdt_strerror(parent)); +			return -EINVAL; +		} +	} + +	/* Either create or overwrite the named key node */ +	snprintf(name, sizeof(name), "key-%s", info->keyname); +	node = fdt_subnode_offset(keydest, parent, name); +	if (node == -FDT_ERR_NOTFOUND) { +		node = fdt_add_subnode(keydest, parent, name); +		if (node < 0) { +			fprintf(stderr, "Could not create key subnode: %s\n", +				fdt_strerror(node)); +			return -EINVAL; +		} +	} else if (node < 0) { +		fprintf(stderr, "Cannot select keys parent: %s\n", +			fdt_strerror(node)); +		return -ENOSPC; +	} + +	ret = fdt_setprop_string(keydest, node, "key-name-hint", +				 info->keyname); +	ret |= fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); +	ret |= fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); +	ret |= fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits); +	ret |= fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits); +	ret |= fdt_setprop_string(keydest, node, FIT_ALGO_PROP, +				  info->algo->name); +	if (info->require_keys) { +		fdt_setprop_string(keydest, node, "required", +				   info->require_keys); +	} +	BN_free(modulus); +	BN_free(r_squared); +	if (ret) +		return -EIO; + +	return 0; +} diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c new file mode 100644 index 000000000..6a0268919 --- /dev/null +++ b/lib/rsa/rsa-verify.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <fdtdec.h> +#include <rsa.h> +#include <sha1.h> +#include <asm/byteorder.h> +#include <asm/errno.h> +#include <asm/unaligned.h> + +/** + * struct rsa_public_key - holder for a public key + * + * An RSA public key consists of a modulus (typically called N), the inverse + * and R^2, where R is 2^(# key bits). + */ +struct rsa_public_key { +	uint len;		/* Length of modulus[] in number of uint32_t */ +	uint32_t n0inv;		/* -1 / modulus[0] mod 2^32 */ +	uint32_t *modulus;	/* modulus as little endian array */ +	uint32_t *rr;		/* R^2 as little endian array */ +}; + +#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby))) + +#define RSA2048_BYTES	(2048 / 8) + +/* This is the minimum/maximum key size we support, in bits */ +#define RSA_MIN_KEY_BITS	2048 +#define RSA_MAX_KEY_BITS	2048 + +/* This is the maximum signature length that we support, in bits */ +#define RSA_MAX_SIG_BITS	2048 + +static const uint8_t padding_sha1_rsa2048[RSA2048_BYTES - SHA1_SUM_LEN] = { +	0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30, +	0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, +	0x05, 0x00, 0x04, 0x14 +}; + +/** + * subtract_modulus() - subtract modulus from the given value + * + * @key:	Key containing modulus to subtract + * @num:	Number to subtract modulus from, as little endian word array + */ +static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[]) +{ +	int64_t acc = 0; +	uint i; + +	for (i = 0; i < key->len; i++) { +		acc += (uint64_t)num[i] - key->modulus[i]; +		num[i] = (uint32_t)acc; +		acc >>= 32; +	} +} + +/** + * greater_equal_modulus() - check if a value is >= modulus + * + * @key:	Key containing modulus to check + * @num:	Number to check against modulus, as little endian word array + * @return 0 if num < modulus, 1 if num >= modulus + */ +static int greater_equal_modulus(const struct rsa_public_key *key, +				 uint32_t num[]) +{ +	uint32_t i; + +	for (i = key->len - 1; i >= 0; i--) { +		if (num[i] < key->modulus[i]) +			return 0; +		if (num[i] > key->modulus[i]) +			return 1; +	} + +	return 1;  /* equal */ +} + +/** + * montgomery_mul_add_step() - Perform montgomery multiply-add step + * + * Operation: montgomery result[] += a * b[] / n0inv % modulus + * + * @key:	RSA key + * @result:	Place to put result, as little endian word array + * @a:		Multiplier + * @b:		Multiplicand, as little endian word array + */ +static void montgomery_mul_add_step(const struct rsa_public_key *key, +		uint32_t result[], const uint32_t a, const uint32_t b[]) +{ +	uint64_t acc_a, acc_b; +	uint32_t d0; +	uint i; + +	acc_a = (uint64_t)a * b[0] + result[0]; +	d0 = (uint32_t)acc_a * key->n0inv; +	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a; +	for (i = 1; i < key->len; i++) { +		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i]; +		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] + +				(uint32_t)acc_a; +		result[i - 1] = (uint32_t)acc_b; +	} + +	acc_a = (acc_a >> 32) + (acc_b >> 32); + +	result[i - 1] = (uint32_t)acc_a; + +	if (acc_a >> 32) +		subtract_modulus(key, result); +} + +/** + * montgomery_mul() - Perform montgomery mutitply + * + * Operation: montgomery result[] = a[] * b[] / n0inv % modulus + * + * @key:	RSA key + * @result:	Place to put result, as little endian word array + * @a:		Multiplier, as little endian word array + * @b:		Multiplicand, as little endian word array + */ +static void montgomery_mul(const struct rsa_public_key *key, +		uint32_t result[], uint32_t a[], const uint32_t b[]) +{ +	uint i; + +	for (i = 0; i < key->len; ++i) +		result[i] = 0; +	for (i = 0; i < key->len; ++i) +		montgomery_mul_add_step(key, result, a[i], b); +} + +/** + * pow_mod() - in-place public exponentiation + * + * @key:	RSA key + * @inout:	Big-endian word array containing value and result + */ +static int pow_mod(const struct rsa_public_key *key, uint32_t *inout) +{ +	uint32_t *result, *ptr; +	uint i; + +	/* Sanity check for stack size - key->len is in 32-bit words */ +	if (key->len > RSA_MAX_KEY_BITS / 32) { +		debug("RSA key words %u exceeds maximum %d\n", key->len, +		      RSA_MAX_KEY_BITS / 32); +		return -EINVAL; +	} + +	uint32_t val[key->len], acc[key->len], tmp[key->len]; +	result = tmp;  /* Re-use location. */ + +	/* Convert from big endian byte array to little endian word array. */ +	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--) +		val[i] = get_unaligned_be32(ptr); + +	montgomery_mul(key, acc, val, key->rr);  /* axx = a * RR / R mod M */ +	for (i = 0; i < 16; i += 2) { +		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */ +		montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */ +	} +	montgomery_mul(key, result, acc, val);  /* result = XX * a / R mod M */ + +	/* Make sure result < mod; result is at most 1x mod too large. */ +	if (greater_equal_modulus(key, result)) +		subtract_modulus(key, result); + +	/* Convert to bigendian byte array */ +	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++) +		put_unaligned_be32(result[i], ptr); + +	return 0; +} + +static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, +		const uint32_t sig_len, const uint8_t *hash) +{ +	const uint8_t *padding; +	int pad_len; +	int ret; + +	if (!key || !sig || !hash) +		return -EIO; + +	if (sig_len != (key->len * sizeof(uint32_t))) { +		debug("Signature is of incorrect length %d\n", sig_len); +		return -EINVAL; +	} + +	/* Sanity check for stack size */ +	if (sig_len > RSA_MAX_SIG_BITS / 8) { +		debug("Signature length %u exceeds maximum %d\n", sig_len, +		      RSA_MAX_SIG_BITS / 8); +		return -EINVAL; +	} + +	uint32_t buf[sig_len / sizeof(uint32_t)]; + +	memcpy(buf, sig, sig_len); + +	ret = pow_mod(key, buf); +	if (ret) +		return ret; + +	/* Determine padding to use depending on the signature type. */ +	padding = padding_sha1_rsa2048; +	pad_len = RSA2048_BYTES - SHA1_SUM_LEN; + +	/* Check pkcs1.5 padding bytes. */ +	if (memcmp(buf, padding, pad_len)) { +		debug("In RSAVerify(): Padding check failed!\n"); +		return -EINVAL; +	} + +	/* Check hash. */ +	if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) { +		debug("In RSAVerify(): Hash check failed!\n"); +		return -EACCES; +	} + +	return 0; +} + +static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len) +{ +	int i; + +	for (i = 0; i < len; i++) +		dst[i] = fdt32_to_cpu(src[len - 1 - i]); +} + +static int rsa_verify_with_keynode(struct image_sign_info *info, +		const void *hash, uint8_t *sig, uint sig_len, int node) +{ +	const void *blob = info->fdt_blob; +	struct rsa_public_key key; +	const void *modulus, *rr; +	int ret; + +	if (node < 0) { +		debug("%s: Skipping invalid node", __func__); +		return -EBADF; +	} +	if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) { +		debug("%s: Missing rsa,n0-inverse", __func__); +		return -EFAULT; +	} +	key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0); +	key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0); +	modulus = fdt_getprop(blob, node, "rsa,modulus", NULL); +	rr = fdt_getprop(blob, node, "rsa,r-squared", NULL); +	if (!key.len || !modulus || !rr) { +		debug("%s: Missing RSA key info", __func__); +		return -EFAULT; +	} + +	/* Sanity check for stack size */ +	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) { +		debug("RSA key bits %u outside allowed range %d..%d\n", +		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS); +		return -EFAULT; +	} +	key.len /= sizeof(uint32_t) * 8; +	uint32_t key1[key.len], key2[key.len]; + +	key.modulus = key1; +	key.rr = key2; +	rsa_convert_big_endian(key.modulus, modulus, key.len); +	rsa_convert_big_endian(key.rr, rr, key.len); +	if (!key.modulus || !key.rr) { +		debug("%s: Out of memory", __func__); +		return -ENOMEM; +	} + +	debug("key length %d\n", key.len); +	ret = rsa_verify_key(&key, sig, sig_len, hash); +	if (ret) { +		printf("%s: RSA failed to verify: %d\n", __func__, ret); +		return ret; +	} + +	return 0; +} + +int rsa_verify(struct image_sign_info *info, +	       const struct image_region region[], int region_count, +	       uint8_t *sig, uint sig_len) +{ +	const void *blob = info->fdt_blob; +	uint8_t hash[SHA1_SUM_LEN]; +	int ndepth, noffset; +	int sig_node, node; +	char name[100]; +	sha1_context ctx; +	int ret, i; + +	sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME); +	if (sig_node < 0) { +		debug("%s: No signature node found\n", __func__); +		return -ENOENT; +	} + +	sha1_starts(&ctx); +	for (i = 0; i < region_count; i++) +		sha1_update(&ctx, region[i].data, region[i].size); +	sha1_finish(&ctx, hash); + +	/* See if we must use a particular key */ +	if (info->required_keynode != -1) { +		ret = rsa_verify_with_keynode(info, hash, sig, sig_len, +			info->required_keynode); +		if (!ret) +			return ret; +	} + +	/* Look for a key that matches our hint */ +	snprintf(name, sizeof(name), "key-%s", info->keyname); +	node = fdt_subnode_offset(blob, sig_node, name); +	ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node); +	if (!ret) +		return ret; + +	/* No luck, so try each of the keys in turn */ +	for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth); +			(noffset >= 0) && (ndepth > 0); +			noffset = fdt_next_node(info->fit, noffset, &ndepth)) { +		if (ndepth == 1 && noffset != node) { +			ret = rsa_verify_with_keynode(info, hash, sig, sig_len, +						      noffset); +			if (!ret) +				break; +		} +	} + +	return ret; +} diff --git a/lib/trace.c b/lib/trace.c new file mode 100644 index 000000000..e7455bcfe --- /dev/null +++ b/lib/trace.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <trace.h> +#include <asm/io.h> +#include <asm/sections.h> + +DECLARE_GLOBAL_DATA_PTR; + +static char trace_enabled __attribute__((section(".data"))); +static char trace_inited __attribute__((section(".data"))); + +/* The header block at the start of the trace memory area */ +struct trace_hdr { +	int func_count;		/* Total number of function call sites */ +	u64 call_count;		/* Total number of tracked function calls */ +	u64 untracked_count;	/* Total number of untracked function calls */ +	int funcs_used;		/* Total number of functions used */ + +	/* +	 * Call count for each function. This is indexed by the word offset +	 * of the function from gd->relocaddr +	 */ +	uintptr_t *call_accum; + +	/* Function trace list */ +	struct trace_call *ftrace;	/* The function call records */ +	ulong ftrace_size;	/* Num. of ftrace records we have space for */ +	ulong ftrace_count;	/* Num. of ftrace records written */ +	ulong ftrace_too_deep_count;	/* Functions that were too deep */ + +	int depth; +	int depth_limit; +	int max_depth; +}; + +static struct trace_hdr *hdr;	/* Pointer to start of trace buffer */ + +static inline uintptr_t __attribute__((no_instrument_function)) +		func_ptr_to_num(void *func_ptr) +{ +	uintptr_t offset = (uintptr_t)func_ptr; + +#ifdef CONFIG_SANDBOX +	offset -= (uintptr_t)&_init; +#else +	if (gd->flags & GD_FLG_RELOC) +		offset -= gd->relocaddr; +	else +		offset -= CONFIG_SYS_TEXT_BASE; +#endif +	return offset / FUNC_SITE_SIZE; +} + +static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr, +				void *caller, ulong flags) +{ +	if (hdr->depth > hdr->depth_limit) { +		hdr->ftrace_too_deep_count++; +		return; +	} +	if (hdr->ftrace_count < hdr->ftrace_size) { +		struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; + +		rec->func = func_ptr_to_num(func_ptr); +		rec->caller = func_ptr_to_num(caller); +		rec->flags = flags | (timer_get_us() & FUNCF_TIMESTAMP_MASK); +	} +	hdr->ftrace_count++; +} + +static void __attribute__((no_instrument_function)) add_textbase(void) +{ +	if (hdr->ftrace_count < hdr->ftrace_size) { +		struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; + +		rec->func = CONFIG_SYS_TEXT_BASE; +		rec->caller = 0; +		rec->flags = FUNCF_TEXTBASE; +	} +	hdr->ftrace_count++; +} + +/** + * This is called on every function entry + * + * We add to our tally for this function and add to the list of called + * functions. + * + * @param func_ptr	Pointer to function being entered + * @param caller	Pointer to function which called this function + */ +void __attribute__((no_instrument_function)) __cyg_profile_func_enter( +		void *func_ptr, void *caller) +{ +	if (trace_enabled) { +		int func; + +		add_ftrace(func_ptr, caller, FUNCF_ENTRY); +		func = func_ptr_to_num(func_ptr); +		if (func < hdr->func_count) { +			hdr->call_accum[func]++; +			hdr->call_count++; +		} else { +			hdr->untracked_count++; +		} +		hdr->depth++; +		if (hdr->depth > hdr->depth_limit) +			hdr->max_depth = hdr->depth; +	} +} + +/** + * This is called on every function exit + * + * We do nothing here. + * + * @param func_ptr	Pointer to function being entered + * @param caller	Pointer to function which called this function + */ +void __attribute__((no_instrument_function)) __cyg_profile_func_exit( +		void *func_ptr, void *caller) +{ +	if (trace_enabled) { +		add_ftrace(func_ptr, caller, FUNCF_EXIT); +		hdr->depth--; +	} +} + +/** + * Produce a list of called functions + * + * The information is written into the supplied buffer - a header followed + * by a list of function records. + * + * @param buff		Buffer to place list into + * @param buff_size	Size of buffer + * @param needed	Returns size of buffer needed, which may be + *			greater than buff_size if we ran out of space. + * @return 0 if ok, -1 if space was exhausted + */ +int trace_list_functions(void *buff, int buff_size, unsigned int *needed) +{ +	struct trace_output_hdr *output_hdr = NULL; +	void *end, *ptr = buff; +	int func; +	int upto; + +	end = buff ? buff + buff_size : NULL; + +	/* Place some header information */ +	if (ptr + sizeof(struct trace_output_hdr) < end) +		output_hdr = ptr; +	ptr += sizeof(struct trace_output_hdr); + +	/* Add information about each function */ +	for (func = upto = 0; func < hdr->func_count; func++) { +		int calls = hdr->call_accum[func]; + +		if (!calls) +			continue; + +		if (ptr + sizeof(struct trace_output_func) < end) { +			struct trace_output_func *stats = ptr; + +			stats->offset = func * FUNC_SITE_SIZE; +			stats->call_count = calls; +			upto++; +		} +		ptr += sizeof(struct trace_output_func); +	} + +	/* Update the header */ +	if (output_hdr) { +		output_hdr->rec_count = upto; +		output_hdr->type = TRACE_CHUNK_FUNCS; +	} + +	/* Work out how must of the buffer we used */ +	*needed = ptr - buff; +	if (ptr > end) +		return -1; +	return 0; +} + +int trace_list_calls(void *buff, int buff_size, unsigned *needed) +{ +	struct trace_output_hdr *output_hdr = NULL; +	void *end, *ptr = buff; +	int rec, upto; +	int count; + +	end = buff ? buff + buff_size : NULL; + +	/* Place some header information */ +	if (ptr + sizeof(struct trace_output_hdr) < end) +		output_hdr = ptr; +	ptr += sizeof(struct trace_output_hdr); + +	/* Add information about each call */ +	count = hdr->ftrace_count; +	if (count > hdr->ftrace_size) +		count = hdr->ftrace_size; +	for (rec = upto = 0; rec < count; rec++) { +		if (ptr + sizeof(struct trace_call) < end) { +			struct trace_call *call = &hdr->ftrace[rec]; +			struct trace_call *out = ptr; + +			out->func = call->func * FUNC_SITE_SIZE; +			out->caller = call->caller * FUNC_SITE_SIZE; +			out->flags = call->flags; +			upto++; +		} +		ptr += sizeof(struct trace_call); +	} + +	/* Update the header */ +	if (output_hdr) { +		output_hdr->rec_count = upto; +		output_hdr->type = TRACE_CHUNK_CALLS; +	} + +	/* Work out how must of the buffer we used */ +	*needed = ptr - buff; +	if (ptr > end) +		return -1; +	return 0; +} + +/* Print basic information about tracing */ +void trace_print_stats(void) +{ +	ulong count; + +#ifndef FTRACE +	puts("Warning: make U-Boot with FTRACE to enable function instrumenting.\n"); +	puts("You will likely get zeroed data here\n"); +#endif +	if (!trace_inited) { +		printf("Trace is disabled\n"); +		return; +	} +	print_grouped_ull(hdr->func_count, 10); +	puts(" function sites\n"); +	print_grouped_ull(hdr->call_count, 10); +	puts(" function calls\n"); +	print_grouped_ull(hdr->untracked_count, 10); +	puts(" untracked function calls\n"); +	count = min(hdr->ftrace_count, hdr->ftrace_size); +	print_grouped_ull(count, 10); +	puts(" traced function calls"); +	if (hdr->ftrace_count > hdr->ftrace_size) { +		printf(" (%lu dropped due to overflow)", +		       hdr->ftrace_count - hdr->ftrace_size); +	} +	puts("\n"); +	printf("%15d maximum observed call depth\n", hdr->max_depth); +	printf("%15d call depth limit\n", hdr->depth_limit); +	print_grouped_ull(hdr->ftrace_too_deep_count, 10); +	puts(" calls not traced due to depth\n"); +} + +void __attribute__((no_instrument_function)) trace_set_enabled(int enabled) +{ +	trace_enabled = enabled != 0; +} + +/** + * Init the tracing system ready for used, and enable it + * + * @param buff		Pointer to trace buffer + * @param buff_size	Size of trace buffer + */ +int __attribute__((no_instrument_function)) trace_init(void *buff, +		size_t buff_size) +{ +	ulong func_count = gd->mon_len / FUNC_SITE_SIZE; +	size_t needed; +	int was_disabled = !trace_enabled; + +	if (!was_disabled) { +#ifdef CONFIG_TRACE_EARLY +		char *end; +		ulong used; + +		/* +		 * Copy over the early trace data if we have it. Disable +		 * tracing while we are doing this. +		 */ +		trace_enabled = 0; +		hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, +				 CONFIG_TRACE_EARLY_SIZE); +		end = (char *)&hdr->ftrace[hdr->ftrace_count]; +		used = end - (char *)hdr; +		printf("trace: copying %08lx bytes of early data from %x to %08lx\n", +		       used, CONFIG_TRACE_EARLY_ADDR, +		       (ulong)map_to_sysmem(buff)); +		memcpy(buff, hdr, used); +#else +		puts("trace: already enabled\n"); +		return -1; +#endif +	} +	hdr = (struct trace_hdr *)buff; +	needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); +	if (needed > buff_size) { +		printf("trace: buffer size %zd bytes: at least %zd needed\n", +		       buff_size, needed); +		return -1; +	} + +	if (was_disabled) +		memset(hdr, '\0', needed); +	hdr->func_count = func_count; +	hdr->call_accum = (uintptr_t *)(hdr + 1); + +	/* Use any remaining space for the timed function trace */ +	hdr->ftrace = (struct trace_call *)(buff + needed); +	hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); +	add_textbase(); + +	puts("trace: enabled\n"); +	hdr->depth_limit = 15; +	trace_enabled = 1; +	trace_inited = 1; +	return 0; +} + +#ifdef CONFIG_TRACE_EARLY +int __attribute__((no_instrument_function)) trace_early_init(void) +{ +	ulong func_count = gd->mon_len / FUNC_SITE_SIZE; +	size_t buff_size = CONFIG_TRACE_EARLY_SIZE; +	size_t needed; + +	/* We can ignore additional calls to this function */ +	if (trace_enabled) +		return 0; + +	hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE); +	needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); +	if (needed > buff_size) { +		printf("trace: buffer size is %zd bytes, at least %zd needed\n", +		       buff_size, needed); +		return -1; +	} + +	memset(hdr, '\0', needed); +	hdr->call_accum = (uintptr_t *)(hdr + 1); +	hdr->func_count = func_count; + +	/* Use any remaining space for the timed function trace */ +	hdr->ftrace = (struct trace_call *)((char *)hdr + needed); +	hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); +	add_textbase(); +	hdr->depth_limit = 200; +	printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR); + +	trace_enabled = 1; +	return 0; +} +#endif diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 533a96b85..82e5c1365 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -870,3 +870,19 @@ char *simple_itoa(ulong i)  	} while (i > 0);  	return p + 1;  } + +/* We don't seem to have %'d in U-Boot */ +void print_grouped_ull(unsigned long long int_val, int digits) +{ +	char str[21], *s; +	int grab = 3; + +	digits = (digits + 2) / 3; +	sprintf(str, "%*llu", digits * 3, int_val); +	for (s = str; *s; s += grab) { +		if (s != str) +			putc(s[-1] != ' ' ? ',' : ' '); +		printf("%.*s", grab, s); +		grab = 3; +	} +} diff --git a/nand_spl/board/freescale/p1010rdb/Makefile b/nand_spl/board/freescale/p1010rdb/Makefile deleted file mode 100644 index f7bdf9207..000000000 --- a/nand_spl/board/freescale/p1010rdb/Makefile +++ /dev/null @@ -1,142 +0,0 @@ -# -# (C) Copyright 2007 -# Stefan Roese, DENX Software Engineering, sr@denx.de. -# -# Copyright 2011 Freescale Semiconductor, Inc. -# -# See file CREDITS for list of people who contributed to this -# project. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, -# MA 02111-1307 USA -# - -NAND_SPL := y -CONFIG_SYS_TEXT_BASE_SPL := 0xff800000 -PAD_TO := 0xff802000 - -include $(TOPDIR)/config.mk - -nandobj	:= $(OBJTREE)/nand_spl/ - -LDSCRIPT= $(TOPDIR)/$(CPUDIR)/u-boot-nand_spl.lds -LDFLAGS := -T $(nandobj)u-boot-nand_spl.lds -Ttext $(CONFIG_SYS_TEXT_BASE_SPL) $(LDFLAGS) \ -	   $(LDFLAGS_FINAL) -AFLAGS	+= -DCONFIG_NAND_SPL -CFLAGS	+= -DCONFIG_NAND_SPL - -SOBJS	= start.o resetvec.o ticks.o -COBJS	= cache.o cpu_init_early.o spl_minimal.o fsl_law.o law.o \ -	  nand_boot.o nand_boot_fsl_ifc.o ns16550.o tlb.o tlb_table.o - -SRCS	:= $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c)) -OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) -__OBJS	:= $(SOBJS) $(COBJS) -LNDIR	:= $(nandobj)board/$(BOARDDIR) - -ALL	= $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin - -all:	$(obj).depend $(ALL) - -$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl -	$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@ - -$(nandobj)u-boot-spl.bin:	$(nandobj)u-boot-spl -	$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ - -$(nandobj)u-boot-spl:	$(OBJS) $(nandobj)u-boot-nand_spl.lds -	cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) $(PLATFORM_LIBS) \ -		-Map $(nandobj)u-boot-spl.map \ -		-o $(nandobj)u-boot-spl - -$(nandobj)u-boot-nand_spl.lds: $(LDSCRIPT) -	$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -I$(nandobj)board/$(BOARDDIR) \ -		 -ansi -D__ASSEMBLY__ -P - <$< >$@ - -# create symbolic links for common files - -$(obj)cache.c: -	@rm -f $(obj)cache.c -	ln -sf $(SRCTREE)/arch/powerpc/lib/cache.c $(obj)cache.c - -$(obj)cpu_init_early.c: -	@rm -f $(obj)cpu_init_early.c -	ln -sf $(SRCTREE)/$(CPUDIR)/cpu_init_early.c $(obj)cpu_init_early.c - -$(obj)spl_minimal.c: -	@rm -f $(obj)spl_minimal.c -	ln -sf $(SRCTREE)/$(CPUDIR)/spl_minimal.c $(obj)spl_minimal.c - -$(obj)fsl_law.c: -	@rm -f $(obj)fsl_law.c -	ln -sf $(SRCTREE)/arch/powerpc/cpu/mpc8xxx/law.c $(obj)fsl_law.c - -$(obj)law.c: -	@rm -f $(obj)law.c -	ln -sf $(SRCTREE)/board/$(BOARDDIR)/law.c $(obj)law.c - -$(obj)nand_boot_fsl_ifc.c: -	@rm -f $(obj)nand_boot_fsl_ifc.c -	ln -sf $(SRCTREE)/nand_spl/nand_boot_fsl_ifc.c \ -	       $(obj)nand_boot_fsl_ifc.c - -$(obj)ns16550.c: -	@rm -f $(obj)ns16550.c -	ln -sf $(SRCTREE)/drivers/serial/ns16550.c $(obj)ns16550.c - -$(obj)resetvec.S: -	@rm -f $(obj)resetvec.S -	ln -s $(SRCTREE)/$(CPUDIR)/resetvec.S $(obj)resetvec.S - -$(obj)fixed_ivor.S: -	@rm -f $(obj)fixed_ivor.S -	ln -sf $(SRCTREE)/$(CPUDIR)/fixed_ivor.S $(obj)fixed_ivor.S - -$(obj)start.S: $(obj)fixed_ivor.S -	@rm -f $(obj)start.S -	ln -sf $(SRCTREE)/$(CPUDIR)/start.S $(obj)start.S - -$(obj)ticks.S: -	@rm -f $(obj)ticks.S -	ln -sf $(SRCTREE)/arch/powerpc/lib/ticks.S $(obj)ticks.S - -$(obj)tlb.c: -	@rm -f $(obj)tlb.c -	ln -sf $(SRCTREE)/$(CPUDIR)/tlb.c $(obj)tlb.c - -$(obj)tlb_table.c: -	@rm -f $(obj)tlb_table.c -	ln -sf $(SRCTREE)/board/$(BOARDDIR)/tlb.c $(obj)tlb_table.c - -ifneq ($(OBJTREE), $(SRCTREE)) -$(obj)nand_boot.c: -	@rm -f $(obj)nand_boot.c -	ln -s $(SRCTREE)/nand_spl/board/$(BOARDDIR)/nand_boot.c $(obj)nand_boot.c -endif - -######################################################################### - -$(obj)%.o:	$(obj)%.S -	$(CC) $(AFLAGS) -c -o $@ $< - -$(obj)%.o:	$(obj)%.c -	$(CC) $(CFLAGS) -c -o $@ $< - -# defines $(obj).depend target -include $(SRCTREE)/rules.mk - -sinclude $(obj).depend - -######################################################################### diff --git a/net/link_local.c b/net/link_local.c index 1ba796ebd..4152fae5b 100644 --- a/net/link_local.c +++ b/net/link_local.c @@ -206,6 +206,7 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)  {  	int source_ip_conflict;  	int target_ip_conflict; +	IPaddr_t null_ip = 0;  	if (state == DISABLED)  		return; @@ -267,10 +268,18 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)  	) {  		source_ip_conflict = 1;  	} -	if (arp->ar_op == htons(ARPOP_REQUEST) -	 && memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 -	 && memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0 -	) { + +	/* +	 * According to RFC 3927, section 2.2.1: +	 * Check if packet is an ARP probe by checking for a null source IP +	 * then check that target IP is equal to ours and source hw addr +	 * is not equal to ours. This condition should cause a conflict only +	 * during probe. +	 */ +	if (arp->ar_op == htons(ARPOP_REQUEST) && +	    memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 && +	    memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 && +	    memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) {  		target_ip_conflict = 1;  	} @@ -271,7 +271,8 @@ static void NetInitLoop(void)  #endif  		env_changed_id = env_id;  	} -	memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); +	if (eth_get_dev()) +		memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);  	return;  } @@ -37,10 +37,14 @@  # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT  #endif +#define NFS_RPC_ERR	1 +#define NFS_RPC_DROP	124 +  static int fs_mounted;  static unsigned long rpc_id;  static int nfs_offset = -1;  static int nfs_len; +static ulong nfs_timeout = NFS_TIMEOUT;  static char dirfh[NFS_FHSIZE];	/* file handle of directory */  static char filefh[NFS_FHSIZE]; /* file handle of kernel image */ @@ -399,8 +403,10 @@ rpc_lookup_reply(int prog, uchar *pkt, unsigned len)  	debug("%s\n", __func__); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -428,8 +434,10 @@ nfs_mount_reply(uchar *pkt, unsigned len)  	memcpy((unsigned char *)&rpc_pkt, pkt, len); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -452,8 +460,10 @@ nfs_umountall_reply(uchar *pkt, unsigned len)  	memcpy((unsigned char *)&rpc_pkt, pkt, len); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -475,8 +485,10 @@ nfs_lookup_reply(uchar *pkt, unsigned len)  	memcpy((unsigned char *)&rpc_pkt, pkt, len); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -499,8 +511,10 @@ nfs_readlink_reply(uchar *pkt, unsigned len)  	memcpy((unsigned char *)&rpc_pkt, pkt, len); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -534,8 +548,10 @@ nfs_read_reply(uchar *pkt, unsigned len)  	memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply)); -	if (ntohl(rpc_pkt.u.reply.id) != rpc_id) -		return -1; +	if (ntohl(rpc_pkt.u.reply.id) > rpc_id) +		return -NFS_RPC_ERR; +	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) +		return -NFS_RPC_DROP;  	if (rpc_pkt.u.reply.rstatus  ||  	    rpc_pkt.u.reply.verifier || @@ -574,7 +590,8 @@ NfsTimeout(void)  		NetStartAgain();  	} else {  		puts("T "); -		NetSetTimeout(NFS_TIMEOUT, NfsTimeout); +		NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount, +			      NfsTimeout);  		NfsSend();  	}  } @@ -583,6 +600,7 @@ static void  NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  {  	int rlen; +	int reply;  	debug("%s\n", __func__); @@ -591,19 +609,24 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  	switch (NfsState) {  	case STATE_PRCLOOKUP_PROG_MOUNT_REQ: -		rpc_lookup_reply(PROG_MOUNT, pkt, len); +		if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) +			break;  		NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;  		NfsSend();  		break;  	case STATE_PRCLOOKUP_PROG_NFS_REQ: -		rpc_lookup_reply(PROG_NFS, pkt, len); +		if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) +			break;  		NfsState = STATE_MOUNT_REQ;  		NfsSend();  		break;  	case STATE_MOUNT_REQ: -		if (nfs_mount_reply(pkt, len)) { +		reply = nfs_mount_reply(pkt, len); +		if (reply == -NFS_RPC_DROP) +			break; +		else if (reply == -NFS_RPC_ERR) {  			puts("*** ERROR: Cannot mount\n");  			/* just to be sure... */  			NfsState = STATE_UMOUNT_REQ; @@ -615,7 +638,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  		break;  	case STATE_UMOUNT_REQ: -		if (nfs_umountall_reply(pkt, len)) { +		reply = nfs_umountall_reply(pkt, len); +		if (reply == -NFS_RPC_DROP) +			break; +		else if (reply == -NFS_RPC_ERR) {  			puts("*** ERROR: Cannot umount\n");  			net_set_state(NETLOOP_FAIL);  		} else { @@ -625,7 +651,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  		break;  	case STATE_LOOKUP_REQ: -		if (nfs_lookup_reply(pkt, len)) { +		reply = nfs_lookup_reply(pkt, len); +		if (reply == -NFS_RPC_DROP) +			break; +		else if (reply == -NFS_RPC_ERR) {  			puts("*** ERROR: File lookup fail\n");  			NfsState = STATE_UMOUNT_REQ;  			NfsSend(); @@ -638,7 +667,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  		break;  	case STATE_READLINK_REQ: -		if (nfs_readlink_reply(pkt, len)) { +		reply = nfs_readlink_reply(pkt, len); +		if (reply == -NFS_RPC_DROP) +			break; +		else if (reply == -NFS_RPC_ERR) {  			puts("*** ERROR: Symlink fail\n");  			NfsState = STATE_UMOUNT_REQ;  			NfsSend(); @@ -654,7 +686,7 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)  	case STATE_READ_REQ:  		rlen = nfs_read_reply(pkt, len); -		NetSetTimeout(NFS_TIMEOUT, NfsTimeout); +		NetSetTimeout(nfs_timeout, NfsTimeout);  		if (rlen > 0) {  			nfs_offset += rlen;  			NfsSend(); @@ -738,7 +770,7 @@ NfsStart(void)  	printf("\nLoad address: 0x%lx\n"  		"Loading: *\b", load_addr); -	NetSetTimeout(NFS_TIMEOUT, NfsTimeout); +	NetSetTimeout(nfs_timeout, NfsTimeout);  	net_set_udp_handler(NfsHandler);  	NfsTimeoutCount = 0; diff --git a/net/tftp.c b/net/tftp.c index 09790eb7c..6d333d559 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -446,8 +446,8 @@ static void  TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,  	    unsigned len)  { -	ushort proto; -	ushort *s; +	__be16 proto; +	__be16 *s;  	int i;  	if (dest != TftpOurPort) { @@ -465,7 +465,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,  		return;  	len -= 2;  	/* warning: don't use increment (++) in ntohs() macros!! */ -	s = (ushort *)pkt; +	s = (__be16 *)pkt;  	proto = *s++;  	pkt = (uchar *)s;  	switch (ntohs(proto)) { @@ -556,7 +556,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,  		if (len < 2)  			return;  		len -= 2; -		TftpBlock = ntohs(*(ushort *)pkt); +		TftpBlock = ntohs(*(__be16 *)pkt);  		update_block_number(); @@ -644,9 +644,9 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,  	case TFTP_ERROR:  		printf("\nTFTP error: '%s' (%d)\n", -		       pkt + 2, ntohs(*(ushort *)pkt)); +		       pkt + 2, ntohs(*(__be16 *)pkt)); -		switch (ntohs(*(ushort *)pkt)) { +		switch (ntohs(*(__be16 *)pkt)) {  		case TFTP_ERR_FILE_NOT_FOUND:  		case TFTP_ERR_ACCESS_DENIED:  			puts("Not retrying...\n"); diff --git a/spl/Makefile b/spl/Makefile index d8fe948ff..01873de2b 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -98,6 +98,14 @@ LIBS-y += arch/$(ARCH)/cpu/tegra-common/libcputegra-common.o  LIBS-y += $(CPUDIR)/tegra-common/libtegra-common.o  endif +ifneq ($(CONFIG_MX23)$(CONFIG_MX35),) +LIBS-y += arch/$(ARCH)/imx-common/libimx-common.o +endif + +ifeq ($(SOC),exynos) +LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o +endif +  # Add GCC lib  ifeq ("$(USE_PRIVATE_LIBGCC)", "yes")  PLATFORM_LIBGCC = $(SPLTREE)/arch/$(ARCH)/lib/libgcc.o diff --git a/test/image/test-fit.py b/test/image/test-fit.py index c4e821116..aad9f5901 100755 --- a/test/image/test-fit.py +++ b/test/image/test-fit.py @@ -272,12 +272,13 @@ def set_test(name):      test_name = name      print name -def fail(msg): +def fail(msg, stdout):      """Raise an error with a helpful failure message      Args:          msg: Message to display      """ +    print stdout      raise ValueError("Test '%s' failed: %s" % (test_name, msg))  def run_fit_test(mkimage, u_boot): @@ -341,11 +342,11 @@ def run_fit_test(mkimage, u_boot):      set_test('Kernel load')      stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)      if read_file(kernel) != read_file(kernel_out): -        fail('Kernel not loaded') +        fail('Kernel not loaded', stdout)      if read_file(control_dtb) == read_file(fdt_out): -        fail('FDT loaded but should be ignored') +        fail('FDT loaded but should be ignored', stdout)      if read_file(ramdisk) == read_file(ramdisk_out): -        fail('Ramdisk loaded but should not be') +        fail('Ramdisk loaded but should not be', stdout)      # Find out the offset in the FIT where U-Boot has found the FDT      line = find_matching(stdout, 'Booting using the fdt blob at ') @@ -357,7 +358,7 @@ def run_fit_test(mkimage, u_boot):      real_fit_offset = data.find(fdt_magic, 4)      if fit_offset != real_fit_offset:          fail('U-Boot loaded FDT from offset %#x, FDT is actually at %#x' % -                (fit_offset, real_fit_offset)) +                (fit_offset, real_fit_offset), stdout)      # Now a kernel and an FDT      set_test('Kernel + FDT load') @@ -365,11 +366,11 @@ def run_fit_test(mkimage, u_boot):      fit = make_fit(mkimage, params)      stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)      if read_file(kernel) != read_file(kernel_out): -        fail('Kernel not loaded') +        fail('Kernel not loaded', stdout)      if read_file(control_dtb) != read_file(fdt_out): -        fail('FDT not loaded') +        fail('FDT not loaded', stdout)      if read_file(ramdisk) == read_file(ramdisk_out): -        fail('Ramdisk loaded but should not be') +        fail('Ramdisk loaded but should not be', stdout)      # Try a ramdisk      set_test('Kernel + FDT + Ramdisk load') @@ -378,7 +379,7 @@ def run_fit_test(mkimage, u_boot):      fit = make_fit(mkimage, params)      stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd)      if read_file(ramdisk) != read_file(ramdisk_out): -        fail('Ramdisk not loaded') +        fail('Ramdisk not loaded', stdout)  def run_tests():      """Parse options, run the FIT tests and print the result""" diff --git a/test/trace/test-trace.sh b/test/trace/test-trace.sh new file mode 100755 index 000000000..696a39675 --- /dev/null +++ b/test/trace/test-trace.sh @@ -0,0 +1,89 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# Simple test script for tracing with sandbox + +OUTPUT_DIR=sandbox +TRACE_OPT="FTRACE=1" + +fail() { +	echo "Test failed: $1" +	if [ -n ${tmp} ]; then +		rm ${tmp} +	fi +	exit 1 +} + +build_uboot() { +	echo "Build sandbox" +	OPTS="O=${OUTPUT_DIR} ${TRACE_OPT}" +	NUM_CPUS=$(grep -c processor /proc/cpuinfo) +	make ${OPTS} sandbox_config +	make ${OPTS} -s -j${NUM_CPUS} +} + +run_trace() { +	echo "Run trace" +	./${OUTPUT_DIR}/u-boot <<END +	trace stats +	hash sha256 0 10000 +	trace pause +	trace stats +	hash sha256 0 10000 +	trace stats +	trace resume +	hash sha256 0 10000 +	trace pause +	trace stats +	reset +END +} + +check_results() { +	echo "Check results" + +	# Expect sha256 to run 3 times, so we see the string 6 times +	if [ $(grep -c sha256 ${tmp}) -ne 6 ]; then +		fail "sha256 error" +	fi + +	# 4 sets of results (output of 'trace stats') +	if [ $(grep -c "traced function calls" ${tmp}) -ne 4 ]; then +		fail "trace output error" +	fi + +	# Check trace counts. We expect to see an increase in the number of +	# traced function calls between each 'trace stats' command, except +	# between calls 2 and 3, where tracing is paused. +	# This code gets the sign of the difference between each number and +	# its predecessor. +	counts="$(tr -d , <${tmp} | awk '/traced function calls/ { diff = $1 - upto; upto = $1; printf "%d ", diff < 0 ? -1 : (diff > 0 ? 1 : 0)}')" + +	if [ "${counts}" != "1 1 0 1 " ]; then +		fail "trace collection error: ${counts}" +	fi +} + +echo "Simple trace test / sanity check using sandbox" +echo +tmp="$(tempfile)" +build_uboot +run_trace >${tmp} +check_results ${tmp} +rm ${tmp} +echo "Test passed" diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore new file mode 100644 index 000000000..463124270 --- /dev/null +++ b/test/vboot/.gitignore @@ -0,0 +1,3 @@ +/*.dtb +/test.fit +/dev-keys diff --git a/test/vboot/sandbox-kernel.dts b/test/vboot/sandbox-kernel.dts new file mode 100644 index 000000000..a1e853c9c --- /dev/null +++ b/test/vboot/sandbox-kernel.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { +	model = "Sandbox Verified Boot Test"; +	compatible = "sandbox"; + +}; diff --git a/test/vboot/sandbox-u-boot.dts b/test/vboot/sandbox-u-boot.dts new file mode 100644 index 000000000..a1e853c9c --- /dev/null +++ b/test/vboot/sandbox-u-boot.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { +	model = "Sandbox Verified Boot Test"; +	compatible = "sandbox"; + +}; diff --git a/test/vboot/sign-configs.its b/test/vboot/sign-configs.its new file mode 100644 index 000000000..db2ed7935 --- /dev/null +++ b/test/vboot/sign-configs.its @@ -0,0 +1,45 @@ +/dts-v1/; + +/ { +	description = "Chrome OS kernel image with one or more FDT blobs"; +	#address-cells = <1>; + +	images { +		kernel@1 { +			data = /incbin/("test-kernel.bin"); +			type = "kernel_noload"; +			arch = "sandbox"; +			os = "linux"; +			compression = "none"; +			load = <0x4>; +			entry = <0x8>; +			kernel-version = <1>; +			hash@1 { +				algo = "sha1"; +			}; +		}; +		fdt@1 { +			description = "snow"; +			data = /incbin/("sandbox-kernel.dtb"); +			type = "flat_dt"; +			arch = "sandbox"; +			compression = "none"; +			fdt-version = <1>; +			hash@1 { +				algo = "sha1"; +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +				sign-images = "fdt", "kernel"; +			}; +		}; +	}; +}; diff --git a/test/vboot/sign-images.its b/test/vboot/sign-images.its new file mode 100644 index 000000000..f69326a39 --- /dev/null +++ b/test/vboot/sign-images.its @@ -0,0 +1,42 @@ +/dts-v1/; + +/ { +	description = "Chrome OS kernel image with one or more FDT blobs"; +	#address-cells = <1>; + +	images { +		kernel@1 { +			data = /incbin/("test-kernel.bin"); +			type = "kernel_noload"; +			arch = "sandbox"; +			os = "linux"; +			compression = "none"; +			load = <0x4>; +			entry = <0x8>; +			kernel-version = <1>; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +			}; +		}; +		fdt@1 { +			description = "snow"; +			data = /incbin/("sandbox-kernel.dtb"); +			type = "flat_dt"; +			arch = "sandbox"; +			compression = "none"; +			fdt-version = <1>; +			signature@1 { +				algo = "sha1,rsa2048"; +				key-name-hint = "dev"; +			}; +		}; +	}; +	configurations { +		default = "conf@1"; +		conf@1 { +			kernel = "kernel@1"; +			fdt = "fdt@1"; +		}; +	}; +}; diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh new file mode 100755 index 000000000..c3cfadeb1 --- /dev/null +++ b/test/vboot/vboot_test.sh @@ -0,0 +1,126 @@ +#!/bin/sh +# +# Copyright (c) 2013, Google Inc. +# +# Simple Verified Boot Test Script +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA + +set -e + +# Run U-Boot and report the result +# Args: +#	$1:	Test message +run_uboot() { +	echo -n "Test Verified Boot Run: $1: " +	${uboot} -d sandbox-u-boot.dtb >${tmp} -c ' +sb load host 0 100 test.fit; +fdt addr 100; +bootm 100; +reset' +	if ! grep -q "$2" ${tmp}; then +		echo +		echo "Verified boot key check failed, output follows:" +		cat ${tmp} +		false +	else +		echo "OK" +	fi +} + +echo "Simple Verified Boot Test" +echo "=========================" +echo +echo "Please see doc/uImage.FIT/verified-boot.txt for more information" +echo + +err=0 +tmp=/tmp/vboot_test.$$ + +dir=$(dirname $0) + +if [ -z ${O} ]; then +	O=. +fi +O=$(readlink -f ${O}) + +dtc="-I dts -O dtb -p 2000" +uboot="${O}/u-boot" +mkimage="${O}/tools/mkimage" +keys="${dir}/dev-keys" +echo ${mkimage} -D "${dtc}" + +echo "Build keys" +mkdir -p ${keys} + +# Create an RSA key pair +openssl genrsa -F4 -out ${keys}/dev.key 2048 2>/dev/null + +# Create a certificate containing the public key +openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt + +pushd ${dir} >/dev/null + +# Compile our device tree files for kernel and U-Boot (CONFIG_OF_CONTROL) +dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb +dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb + +# Create a number kernel image with zeroes +head -c 5000 /dev/zero >test-kernel.bin + +# Build the FIT, but don't sign anything yet +echo Build FIT with signed images +${mkimage} -D "${dtc}" -f sign-images.its test.fit >${tmp} + +run_uboot "unsigned signatures:" "dev-" + +# Sign images with our dev keys +echo Sign images +${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} + +run_uboot "signed images" "dev+" + + +# Create a fresh .dtb without the public keys +dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb + +echo Build FIT with signed configuration +${mkimage} -D "${dtc}" -f sign-configs.its test.fit >${tmp} + +run_uboot "unsigned config" "sha1+ OK" + +# Sign images with our dev keys +echo Sign images +${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} + +run_uboot "signed config" "dev+" + +# Increment the first byte of the signature, which should cause failure +sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value) +newbyte=$(printf %x $((0x${sig:0:2} + 1))) +sig="${newbyte} ${sig:2}" +fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig} + +run_uboot "signed config with bad hash" "Bad Data Hash" + +popd >/dev/null + +echo +if ${ok}; then +	echo "Test passed" +else +	echo "Test failed" +fi diff --git a/tools/.gitignore b/tools/.gitignore index 9bce71947..a7fee26cd 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -9,6 +9,7 @@  /mxsboot  /ncb  /ncp +/proftool  /ubsha1  /xway-swap-bytes  /*.exe diff --git a/tools/Makefile b/tools/Makefile index 4630f03dc..46159b23d 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -74,11 +74,13 @@ BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)  BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)  BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)  BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX) +BIN_FILES-y += proftool(SFX)  # Source files which exist outside the tools directory  EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o  EXT_OBJ_FILES-y += common/image.o  EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o +EXT_OBJ_FILES-y += common/image-sig.o  EXT_OBJ_FILES-y += lib/crc32.o  EXT_OBJ_FILES-y += lib/md5.o  EXT_OBJ_FILES-y += lib/sha1.o @@ -87,6 +89,7 @@ EXT_OBJ_FILES-y += lib/sha1.o  OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o  OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o  NOPED_OBJ_FILES-y += default_image.o +NOPED_OBJ_FILES-y += proftool.o  OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o  NOPED_OBJ_FILES-y += fit_image.o  OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o @@ -122,6 +125,9 @@ LIBFDT_OBJ_FILES-y += fdt_rw.o  LIBFDT_OBJ_FILES-y += fdt_strerror.o  LIBFDT_OBJ_FILES-y += fdt_wip.o +# RSA objects +RSA_OBJ_FILES-$(CONFIG_FIT_SIGNATURE) += rsa-sign.o +  # Generated LCD/video logo  LOGO_H = $(OBJTREE)/include/bmp_logo.h  LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h @@ -149,8 +155,14 @@ endif # !LOGO_BMP  HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))  HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))  HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c)) +HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c))  BINS	:= $(addprefix $(obj),$(sort $(BIN_FILES-y)))  LIBFDT_OBJS	:= $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y)) +RSA_OBJS	:= $(addprefix $(obj),$(RSA_OBJ_FILES-y)) + +# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host +FIT_SIG_OBJ_FILES	:= image-sig.o +FIT_SIG_OBJS		:= $(addprefix $(obj),$(FIT_SIG_OBJ_FILES))  HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y))  NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y)) @@ -180,6 +192,10 @@ $(obj)bmp_logo$(SFX):	$(obj)bmp_logo.o  	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^  	$(HOSTSTRIP) $@ +$(obj)proftool(SFX):	$(obj)proftool.o +	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ +	$(HOSTSTRIP) $@ +  $(obj)envcrc$(SFX):	$(obj)crc32.o $(obj)env_embedded.o $(obj)envcrc.o $(obj)sha1.o  	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ @@ -207,6 +223,7 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \  			$(obj)image-fit.o \  			$(obj)image.o \  			$(obj)image-host.o \ +			$(FIT_SIG_OBJS) \  			$(obj)imximage.o \  			$(obj)kwbimage.o \  			$(obj)pblimage.o \ @@ -216,8 +233,9 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \  			$(obj)omapimage.o \  			$(obj)sha1.o \  			$(obj)ublimage.o \ -			$(LIBFDT_OBJS) -	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ +			$(LIBFDT_OBJS) \ +			$(RSA_OBJS) +	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)  	$(HOSTSTRIP) $@  $(obj)mk$(BOARD)spl$(SFX):	$(obj)mkexynosspl.o @@ -253,6 +271,9 @@ $(obj)%.o: $(SRCTREE)/lib/%.c  $(obj)%.o: $(SRCTREE)/lib/libfdt/%.c  	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< +$(obj)%.o: $(SRCTREE)/lib/rsa/%.c +	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< +  subdirs:  ifeq ($(TOOLSUBDIRS),)  	@: diff --git a/tools/fit_image.c b/tools/fit_image.c index cc123dd37..281c2bda1 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -105,9 +105,11 @@ static int fit_handle_file (struct mkimage_params *params)  {  	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];  	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; -	int tfd; +	int tfd, destfd = 0; +	void *dest_blob = NULL;  	struct stat sbuf;  	void *ptr; +	off_t destfd_size = 0;  	/* Flattened Image Tree (FIT) format  handling */  	debug ("FIT format handling\n"); @@ -122,29 +124,44 @@ static int fit_handle_file (struct mkimage_params *params)  	}  	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); -	/* dtc -I dts -O dtb -p 500 datafile > tmpfile */ -	sprintf (cmd, "%s %s %s > %s", -		MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); -	debug ("Trying to execute \"%s\"\n", cmd); +	/* We either compile the source file, or use the existing FIT image */ +	if (params->datafile) { +		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */ +		snprintf(cmd, sizeof(cmd), "%s %s %s > %s", +			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); +		debug("Trying to execute \"%s\"\n", cmd); +	} else { +		snprintf(cmd, sizeof(cmd), "cp %s %s", +			 params->imagefile, tmpfile); +	}  	if (system (cmd) == -1) {  		fprintf (stderr, "%s: system(%s) failed: %s\n",  				params->cmdname, cmd, strerror(errno));  		goto err_system;  	} +	if (params->keydest) { +		destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf); +		if (destfd < 0) +			goto err_keydest; +		destfd_size = sbuf.st_size; +	} +  	tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);  	if (tfd < 0)  		goto err_mmap;  	/* set hashes for images in the blob */ -	if (fit_add_verification_data(ptr)) { -		fprintf (stderr, "%s Can't add hashes to FIT blob", -				params->cmdname); +	if (fit_add_verification_data(params->keydir, +				      dest_blob, ptr, params->comment, +				      params->require_keys)) { +		fprintf(stderr, "%s Can't add hashes to FIT blob\n", +			params->cmdname);  		goto err_add_hashes;  	} -	/* add a timestamp at offset 0 i.e., root  */ -	if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) { +	/* for first image creation, add a timestamp at offset 0 i.e., root  */ +	if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {  		fprintf (stderr, "%s: Can't add image timestamp\n",  				params->cmdname);  		goto err_add_timestamp; @@ -153,6 +170,10 @@ static int fit_handle_file (struct mkimage_params *params)  	munmap ((void *)ptr, sbuf.st_size);  	close (tfd); +	if (dest_blob) { +		munmap(dest_blob, destfd_size); +		close(destfd); +	}  	if (rename (tmpfile, params->imagefile) == -1) {  		fprintf (stderr, "%s: Can't rename %s to %s: %s\n", @@ -168,6 +189,9 @@ err_add_timestamp:  err_add_hashes:  	munmap(ptr, sbuf.st_size);  err_mmap: +	if (dest_blob) +		munmap(dest_blob, destfd_size); +err_keydest:  err_system:  	unlink(tmpfile);  	return -1; diff --git a/tools/image-host.c b/tools/image-host.c index d944d0ff4..932384bea 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -26,12 +26,8 @@   */  #include "mkimage.h" -#include <bootstage.h>  #include <image.h> -#include <sha1.h> -#include <time.h> -#include <u-boot/crc.h> -#include <u-boot/md5.h> +#include <version.h>  /**   * fit_set_hash_value - set hash value in requested has node @@ -108,9 +104,165 @@ static int fit_image_process_hash(void *fit, const char *image_name,  }  /** - * fit_image_add_verification_data() - calculate/set hash data for image node + * fit_image_write_sig() - write the signature to a FIT   * - * This adds hash values for a component image node. + * This writes the signature and signer data to the FIT. + * + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: signature value to be set + * @value_len: signature value length + * @comment: Text comment to write (NULL for none) + * + * returns + *     0, on success + *     -FDT_ERR_..., on failure + */ +static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, +		int value_len, const char *comment, const char *region_prop, +		int region_proplen) +{ +	int string_size; +	int ret; + +	/* +	 * Get the current string size, before we update the FIT and add +	 * more +	 */ +	string_size = fdt_size_dt_strings(fit); + +	ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); +	if (!ret) { +		ret = fdt_setprop_string(fit, noffset, "signer-name", +					 "mkimage"); +	} +	if (!ret) { +		ret = fdt_setprop_string(fit, noffset, "signer-version", +				  PLAIN_VERSION); +	} +	if (comment && !ret) +		ret = fdt_setprop_string(fit, noffset, "comment", comment); +	if (!ret) +		ret = fit_set_timestamp(fit, noffset, time(NULL)); +	if (region_prop && !ret) { +		uint32_t strdata[2]; + +		ret = fdt_setprop(fit, noffset, "hashed-nodes", +				   region_prop, region_proplen); +		strdata[0] = 0; +		strdata[1] = cpu_to_fdt32(string_size); +		if (!ret) { +			ret = fdt_setprop(fit, noffset, "hashed-strings", +					  strdata, sizeof(strdata)); +		} +	} + +	return ret; +} + +static int fit_image_setup_sig(struct image_sign_info *info, +		const char *keydir, void *fit, const char *image_name, +		int noffset, const char *require_keys) +{ +	const char *node_name; +	char *algo_name; + +	node_name = fit_get_name(fit, noffset, NULL); +	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { +		printf("Can't get algo property for '%s' signature node in '%s' image node\n", +		       node_name, image_name); +		return -1; +	} + +	memset(info, '\0', sizeof(*info)); +	info->keydir = keydir; +	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); +	info->fit = fit; +	info->node_offset = noffset; +	info->algo = image_get_sig_algo(algo_name); +	info->require_keys = require_keys; +	if (!info->algo) { +		printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", +		       algo_name, node_name, image_name); +		return -1; +	} + +	return 0; +} + +/** + * fit_image_process_sig- Process a single subnode of the images/ node + * + * Check each subnode and process accordingly. For signature nodes we + * generate a signed hash of the supplised data and store it in the node. + * + * @keydir:	Directory containing keys to use for signing + * @keydest:	Destination FDT blob to write public keys into + * @fit:	pointer to the FIT format image header + * @image_name:	name of image being processes (used to display errors) + * @noffset:	subnode offset + * @data:	data to process + * @size:	size of data in bytes + * @comment:	Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * @return 0 if ok, -1 on error + */ +static int fit_image_process_sig(const char *keydir, void *keydest, +		void *fit, const char *image_name, +		int noffset, const void *data, size_t size, +		const char *comment, int require_keys) +{ +	struct image_sign_info info; +	struct image_region region; +	const char *node_name; +	uint8_t *value; +	uint value_len; +	int ret; + +	if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, +				require_keys ? "image" : NULL)) +		return -1; + +	node_name = fit_get_name(fit, noffset, NULL); +	region.data = data; +	region.size = size; +	ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); +	if (ret) { +		printf("Failed to sign '%s' signature node in '%s' image node: %d\n", +		       node_name, image_name, ret); + +		/* We allow keys to be missing */ +		if (ret == -ENOENT) +			return 0; +		return -1; +	} + +	ret = fit_image_write_sig(fit, noffset, value, value_len, comment, +			NULL, 0); +	if (ret) { +		printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", +		       node_name, image_name, fdt_strerror(ret)); +		return -1; +	} +	free(value); + +	/* Get keyname again, as FDT has changed and invalidated our pointer */ +	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + +	/* Write the public key into the supplied FDT file */ +	if (keydest && info.algo->add_verify_data(&info, keydest)) { +		printf("Failed to add verification data for '%s' signature node in '%s' image node\n", +		       node_name, image_name); +		return -1; +	} + +	return 0; +} + +/** + * fit_image_add_verification_data() - calculate/set verig. data for image node + * + * This adds hash and signature values for an component image node.   *   * All existing hash subnodes are checked, if algorithm property is set to   * one of the supported hash algorithms, hash value is computed and @@ -133,11 +285,17 @@ static int fit_image_process_hash(void *fit, const char *image_name,   *   * For signature details, please see doc/uImage.FIT/signature.txt   * + * @keydir	Directory containing *.key and *.crt files (or NULL) + * @keydest	FDT Blob to write public keys into (NULL if none)   * @fit:	Pointer to the FIT format image header   * @image_noffset: Requested component image node + * @comment:	Comment to add to signature nodes + * @require_keys: Mark all keys as 'required'   * @return: 0 on success, <0 on failure   */ -int fit_image_add_verification_data(void *fit, int image_noffset) +int fit_image_add_verification_data(const char *keydir, void *keydest, +		void *fit, int image_noffset, const char *comment, +		int require_keys)  {  	const char *image_name;  	const void *data; @@ -169,6 +327,12 @@ int fit_image_add_verification_data(void *fit, int image_noffset)  			     strlen(FIT_HASH_NODENAME))) {  			ret = fit_image_process_hash(fit, image_name, noffset,  						data, size); +		} else if (IMAGE_ENABLE_SIGN && keydir && +			   !strncmp(node_name, FIT_SIG_NODENAME, +				strlen(FIT_SIG_NODENAME))) { +			ret = fit_image_process_sig(keydir, keydest, +				fit, image_name, noffset, data, size, +				comment, require_keys);  		}  		if (ret)  			return -1; @@ -177,9 +341,326 @@ int fit_image_add_verification_data(void *fit, int image_noffset)  	return 0;  } -int fit_add_verification_data(void *fit) +struct strlist { +	int count; +	char **strings; +}; + +static void strlist_init(struct strlist *list) +{ +	memset(list, '\0', sizeof(*list)); +} + +static void strlist_free(struct strlist *list) +{ +	int i; + +	for (i = 0; i < list->count; i++) +		free(list->strings[i]); +	free(list->strings); +} + +static int strlist_add(struct strlist *list, const char *str) +{ +	char *dup; + +	dup = strdup(str); +	list->strings = realloc(list->strings, +				(list->count + 1) * sizeof(char *)); +	if (!list || !str) +		return -1; +	list->strings[list->count++] = dup; + +	return 0; +} + +static const char *fit_config_get_image_list(void *fit, int noffset, +		int *lenp, int *allow_missingp) +{ +	static const char default_list[] = FIT_KERNEL_PROP "\0" +			FIT_FDT_PROP; +	const char *prop; + +	/* If there is an "image" property, use that */ +	prop = fdt_getprop(fit, noffset, "sign-images", lenp); +	if (prop) { +		*allow_missingp = 0; +		return *lenp ? prop : NULL; +	} + +	/* Default image list */ +	*allow_missingp = 1; +	*lenp = sizeof(default_list); + +	return default_list; +} + +static int fit_config_get_hash_list(void *fit, int conf_noffset, +				    int sig_offset, struct strlist *node_inc) +{ +	int allow_missing; +	const char *prop, *iname, *end; +	const char *conf_name, *sig_name; +	char name[200], path[200]; +	int image_count; +	int ret, len; + +	conf_name = fit_get_name(fit, conf_noffset, NULL); +	sig_name = fit_get_name(fit, sig_offset, NULL); + +	/* +	 * Build a list of nodes we need to hash. We always need the root +	 * node and the configuration. +	 */ +	strlist_init(node_inc); +	snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); +	if (strlist_add(node_inc, "/") || +	    strlist_add(node_inc, name)) +		goto err_mem; + +	/* Get a list of images that we intend to sign */ +	prop = fit_config_get_image_list(fit, conf_noffset, &len, +					&allow_missing); +	if (!prop) +		return 0; + +	/* Locate the images */ +	end = prop + len; +	image_count = 0; +	for (iname = prop; iname < end; iname += strlen(iname) + 1) { +		int noffset; +		int image_noffset; +		int hash_count; + +		image_noffset = fit_conf_get_prop_node(fit, conf_noffset, +						       iname); +		if (image_noffset < 0) { +			printf("Failed to find image '%s' in  configuration '%s/%s'\n", +			       iname, conf_name, sig_name); +			if (allow_missing) +				continue; + +			return -ENOENT; +		} + +		ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); +		if (ret < 0) +			goto err_path; +		if (strlist_add(node_inc, path)) +			goto err_mem; + +		snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, +			 conf_name); + +		/* Add all this image's hashes */ +		hash_count = 0; +		for (noffset = fdt_first_subnode(fit, image_noffset); +		     noffset >= 0; +		     noffset = fdt_next_subnode(fit, noffset)) { +			const char *name = fit_get_name(fit, noffset, NULL); + +			if (strncmp(name, FIT_HASH_NODENAME, +				    strlen(FIT_HASH_NODENAME))) +				continue; +			ret = fdt_get_path(fit, noffset, path, sizeof(path)); +			if (ret < 0) +				goto err_path; +			if (strlist_add(node_inc, path)) +				goto err_mem; +			hash_count++; +		} + +		if (!hash_count) { +			printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n", +			       conf_name, sig_name, iname); +			return -ENOMSG; +		} + +		image_count++; +	} + +	if (!image_count) { +		printf("Failed to find any images for configuration '%s/%s'\n", +		       conf_name, sig_name); +		return -ENOMSG; +	} + +	return 0; + +err_mem: +	printf("Out of memory processing configuration '%s/%s'\n", conf_name, +	       sig_name); +	return -ENOMEM; + +err_path: +	printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", +	       iname, conf_name, sig_name, fdt_strerror(ret)); +	return -ENOENT; +} + +static int fit_config_get_data(void *fit, int conf_noffset, int noffset, +		struct image_region **regionp, int *region_countp, +		char **region_propp, int *region_proplen)  { -	int images_noffset; +	char * const exc_prop[] = {"data"}; +	struct strlist node_inc; +	struct image_region *region; +	struct fdt_region fdt_regions[100]; +	const char *conf_name, *sig_name; +	char path[200]; +	int count, i; +	char *region_prop; +	int ret, len; + +	conf_name = fit_get_name(fit, conf_noffset, NULL); +	sig_name = fit_get_name(fit, conf_noffset, NULL); +	debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); + +	/* Get a list of nodes we want to hash */ +	ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); +	if (ret) +		return ret; + +	/* Get a list of regions to hash */ +	count = fdt_find_regions(fit, node_inc.strings, node_inc.count, +			exc_prop, ARRAY_SIZE(exc_prop), +			fdt_regions, ARRAY_SIZE(fdt_regions), +			path, sizeof(path), 1); +	if (count < 0) { +		printf("Failed to hash configuration '%s/%s': %s\n", conf_name, +		       sig_name, fdt_strerror(ret)); +		return -EIO; +	} +	if (count == 0) { +		printf("No data to hash for configuration '%s/%s': %s\n", +		       conf_name, sig_name, fdt_strerror(ret)); +		return -EINVAL; +	} + +	/* Build our list of data blocks */ +	region = fit_region_make_list(fit, fdt_regions, count, NULL); +	if (!region) { +		printf("Out of memory hashing configuration '%s/%s'\n", +		       conf_name, sig_name); +		return -ENOMEM; +	} + +	/* Create a list of all hashed properties */ +	debug("Hash nodes:\n"); +	for (i = len = 0; i < node_inc.count; i++) { +		debug("   %s\n", node_inc.strings[i]); +		len += strlen(node_inc.strings[i]) + 1; +	} +	region_prop = malloc(len); +	if (!region_prop) { +		printf("Out of memory setting up regions for configuration '%s/%s'\n", +		       conf_name, sig_name); +		return -ENOMEM; +	} +	for (i = len = 0; i < node_inc.count; +	     len += strlen(node_inc.strings[i]) + 1, i++) +		strcpy(region_prop + len, node_inc.strings[i]); +	strlist_free(&node_inc); + +	*region_countp = count; +	*regionp = region; +	*region_propp = region_prop; +	*region_proplen = len; + +	return 0; +} + +static int fit_config_process_sig(const char *keydir, void *keydest, +		void *fit, const char *conf_name, int conf_noffset, +		int noffset, const char *comment, int require_keys) +{ +	struct image_sign_info info; +	const char *node_name; +	struct image_region *region; +	char *region_prop; +	int region_proplen; +	int region_count; +	uint8_t *value; +	uint value_len; +	int ret; + +	node_name = fit_get_name(fit, noffset, NULL); +	if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, +				®ion_count, ®ion_prop, ®ion_proplen)) +		return -1; + +	if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, +				require_keys ? "conf" : NULL)) +		return -1; + +	ret = info.algo->sign(&info, region, region_count, &value, &value_len); +	free(region); +	if (ret) { +		printf("Failed to sign '%s' signature node in '%s' conf node\n", +		       node_name, conf_name); + +		/* We allow keys to be missing */ +		if (ret == -ENOENT) +			return 0; +		return -1; +	} + +	if (fit_image_write_sig(fit, noffset, value, value_len, comment, +				region_prop, region_proplen)) { +		printf("Can't write signature for '%s' signature node in '%s' conf node\n", +		       node_name, conf_name); +		return -1; +	} +	free(value); +	free(region_prop); + +	/* Get keyname again, as FDT has changed and invalidated our pointer */ +	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + +	/* Write the public key into the supplied FDT file */ +	if (keydest && info.algo->add_verify_data(&info, keydest)) { +		printf("Failed to add verification data for '%s' signature node in '%s' image node\n", +		       node_name, conf_name); +		return -1; +	} + +	return 0; +} + +static int fit_config_add_verification_data(const char *keydir, void *keydest, +		void *fit, int conf_noffset, const char *comment, +		int require_keys) +{ +	const char *conf_name; +	int noffset; + +	conf_name = fit_get_name(fit, conf_noffset, NULL); + +	/* Process all hash subnodes of the configuration node */ +	for (noffset = fdt_first_subnode(fit, conf_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		const char *node_name; +		int ret = 0; + +		node_name = fit_get_name(fit, noffset, NULL); +		if (!strncmp(node_name, FIT_SIG_NODENAME, +			     strlen(FIT_SIG_NODENAME))) { +			ret = fit_config_process_sig(keydir, keydest, +				fit, conf_name, conf_noffset, noffset, comment, +				require_keys); +		} +		if (ret) +			return ret; +	} + +	return 0; +} + +int fit_add_verification_data(const char *keydir, void *keydest, void *fit, +			      const char *comment, int require_keys) +{ +	int images_noffset, confs_noffset;  	int noffset;  	int ret; @@ -199,7 +680,31 @@ int fit_add_verification_data(void *fit)  		 * Direct child node of the images parent node,  		 * i.e. component image node.  		 */ -		ret = fit_image_add_verification_data(fit, noffset); +		ret = fit_image_add_verification_data(keydir, keydest, +				fit, noffset, comment, require_keys); +		if (ret) +			return ret; +	} + +	/* If there are no keys, we can't sign configurations */ +	if (!IMAGE_ENABLE_SIGN || !keydir) +		return 0; + +	/* Find configurations parent node offset */ +	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); +	if (confs_noffset < 0) { +		printf("Can't find images parent node '%s' (%s)\n", +		       FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); +		return -ENOENT; +	} + +	/* Process its subnodes, print out component images details */ +	for (noffset = fdt_first_subnode(fit, confs_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		ret = fit_config_add_verification_data(keydir, keydest, +						       fit, noffset, comment, +						       require_keys);  		if (ret)  			return ret;  	} diff --git a/tools/mkimage.c b/tools/mkimage.c index e43b09f76..d312844e9 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -183,6 +183,11 @@ main (int argc, char **argv)  					genimg_get_arch_id (*++argv)) < 0)  					usage ();  				goto NXTARG; +			case 'c': +				if (--argc <= 0) +					usage(); +				params.comment = *++argv; +				goto NXTARG;  			case 'C':  				if ((--argc <= 0) ||  					(params.comp = @@ -240,19 +245,34 @@ main (int argc, char **argv)  			case 'f':  				if (--argc <= 0)  					usage (); +				params.datafile = *++argv; +				/* no break */ +			case 'F':  				/*  				 * The flattened image tree (FIT) format  				 * requires a flattened device tree image type  				 */  				params.type = IH_TYPE_FLATDT; -				params.datafile = *++argv;  				params.fflag = 1;  				goto NXTARG; +			case 'k': +				if (--argc <= 0) +					usage(); +				params.keydir = *++argv; +				goto NXTARG; +			case 'K': +				if (--argc <= 0) +					usage(); +				params.keydest = *++argv; +				goto NXTARG;  			case 'n':  				if (--argc <= 0)  					usage ();  				params.imagename = *++argv;  				goto NXTARG; +			case 'r': +				params.require_keys = 1; +				break;  			case 'R':  				if (--argc <= 0)  					usage(); @@ -623,8 +643,20 @@ usage ()  			 "          -d ==> use image data from 'datafile'\n"  			 "          -x ==> set XIP (execute in place)\n",  		params.cmdname); -	fprintf (stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n", +	fprintf(stderr, "       %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",  		params.cmdname); +	fprintf(stderr, "          -D => set options for device tree compiler\n" +			"          -f => input filename for FIT source\n"); +#ifdef CONFIG_FIT_SIGNATURE +	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n" +			"          -k => set directory containing private keys\n" +			"          -K => write public keys to this .dtb file\n" +			"          -c => add comment in signature node\n" +			"          -F => re-sign existing FIT image\n" +			"          -r => mark keys used as 'required' in dtb\n"); +#else +	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); +#endif  	fprintf (stderr, "       %s -V ==> print version information and exit\n",  		params.cmdname); diff --git a/tools/mkimage.h b/tools/mkimage.h index 03c6c8f52..1d9984e1a 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -87,6 +87,10 @@ struct mkimage_params {  	char *datafile;  	char *imagefile;  	char *cmdname; +	const char *keydir;	/* Directory holding private keys */ +	const char *keydest;	/* Destination .dtb for public key */ +	const char *comment;	/* Comment to add to signature node */ +	int require_keys;	/* 1 to mark signing keys as 'required' */  };  /* diff --git a/tools/pblimage.c b/tools/pblimage.c index 508a747a3..5f39dc5bb 100644 --- a/tools/pblimage.c +++ b/tools/pblimage.c @@ -26,18 +26,14 @@  #include "pblimage.h"  /* - * The PBL can load up to 64 bytes at a time, so we split the U-Boot - * image into 64 byte chunks. PBL needs a command for each piece, of - * the form "81xxxxxx", where "xxxxxx" is the offset. SYS_TEXT_BASE - * is 0xFFF80000 for PBL boot, and PBL only cares about low 24-bit, - * so it starts from 0x81F80000. + * Initialize to an invalid value.   */ -static uint32_t next_pbl_cmd = 0x81F80000; +static uint32_t next_pbl_cmd = 0x82000000;  /*   * need to store all bytes in memory for calculating crc32, then write the   * bytes to image file for PBL boot.   */ -static unsigned char mem_buf[600000]; +static unsigned char mem_buf[1000000];  static unsigned char *pmem_buf = mem_buf;  static int pbl_size;  static char *fname = "Unknown"; @@ -52,6 +48,27 @@ static union  #define ENDIANNESS ((char)endian_test.l) +/* + * The PBL can load up to 64 bytes at a time, so we split the U-Boot + * image into 64 byte chunks. PBL needs a command for each piece, of + * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the + * start offset by subtracting the size of the u-boot image from the + * top of the allowable 24-bit range. + */ +static void init_next_pbl_cmd(FILE *fp_uboot) +{ +	struct stat st; +	int fd = fileno(fp_uboot); + +	if (fstat(fd, &st) == -1) { +		printf("Error: Could not determine u-boot image size. %s\n", +			strerror(errno)); +		exit(EXIT_FAILURE); +	} + +	next_pbl_cmd = 0x82000000 - st.st_size; +} +  static void generate_pbl_cmd(void)  {  	uint32_t val = next_pbl_cmd; @@ -80,6 +97,7 @@ static void pbl_fget(size_t size, FILE *stream)  /* load split u-boot with PBI command 81xxxxxx. */  static void load_uboot(FILE *fp_uboot)  { +	init_next_pbl_cmd(fp_uboot);  	while (next_pbl_cmd < 0x82000000) {  		generate_pbl_cmd();  		pbl_fget(64, fp_uboot); diff --git a/tools/proftool.c b/tools/proftool.c new file mode 100644 index 000000000..a48ed286a --- /dev/null +++ b/tools/proftool.c @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* Decode and dump U-Boot profiling information */ + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <regex.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + +#include <compiler.h> +#include <trace.h> + +#define MAX_LINE_LEN 500 + +enum { +	FUNCF_TRACE	= 1 << 0,	/* Include this function in trace */ +}; + +struct func_info { +	unsigned long offset; +	const char *name; +	unsigned long code_size; +	unsigned long call_count; +	unsigned flags; +	/* the section this function is in */ +	struct objsection_info *objsection; +}; + +enum trace_line_type { +	TRACE_LINE_INCLUDE, +	TRACE_LINE_EXCLUDE, +}; + +struct trace_configline_info { +	struct trace_configline_info *next; +	enum trace_line_type type; +	const char *name;	/* identifier name / wildcard */ +	regex_t regex;		/* Regex to use if name starts with / */ +}; + +/* The contents of the trace config file */ +struct trace_configline_info *trace_config_head; + +struct func_info *func_list; +int func_count; +struct trace_call *call_list; +int call_count; +int verbose;	/* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */ +unsigned long text_offset;		/* text address of first function */ + +static void outf(int level, const char *fmt, ...) +		__attribute__ ((format (__printf__, 2, 3))); +#define error(fmt, b...) outf(0, fmt, ##b) +#define warn(fmt, b...) outf(1, fmt, ##b) +#define notice(fmt, b...) outf(2, fmt, ##b) +#define info(fmt, b...) outf(3, fmt, ##b) +#define debug(fmt, b...) outf(4, fmt, ##b) + + +static void outf(int level, const char *fmt, ...) +{ +	if (verbose >= level) { +		va_list args; + +		va_start(args, fmt); +		vfprintf(stderr, fmt, args); +		va_end(args); +	} +} + +static void usage(void) +{ +	fprintf(stderr, +		"Usage: proftool -cds -v3 <cmd> <profdata>\n" +		"\n" +		"Commands\n" +		"   dump-ftrace\t\tDump out textual data in ftrace format\n" +		"\n" +		"Options:\n" +		"   -m <map>\tSpecify Systen.map file\n" +		"   -t <trace>\tSpecific trace data file (from U-Boot)\n" +		"   -v <0-4>\tSpecify verbosity\n"); +	exit(EXIT_FAILURE); +} + +static int h_cmp_offset(const void *v1, const void *v2) +{ +	const struct func_info *f1 = v1, *f2 = v2; + +	return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE); +} + +static int read_system_map(FILE *fin) +{ +	unsigned long offset, start = 0; +	struct func_info *func; +	char buff[MAX_LINE_LEN]; +	char symtype; +	char symname[MAX_LINE_LEN + 1]; +	int linenum; +	int alloced; + +	for (linenum = 1, alloced = func_count = 0;; linenum++) { +		int fields = 0; + +		if (fgets(buff, sizeof(buff), fin)) +			fields = sscanf(buff, "%lx %c %100s\n", &offset, +				&symtype, symname); +		if (fields == 2) { +			continue; +		} else if (feof(fin)) { +			break; +		} else if (fields < 2) { +			error("Map file line %d: invalid format\n", linenum); +			return 1; +		} + +		/* Must be a text symbol */ +		symtype = tolower(symtype); +		if (symtype != 't' && symtype != 'w') +			continue; + +		if (func_count == alloced) { +			alloced += 256; +			func_list = realloc(func_list, +					sizeof(struct func_info) * alloced); +			assert(func_list); +		} +		if (!func_count) +			start = offset; + +		func = &func_list[func_count++]; +		memset(func, '\0', sizeof(*func)); +		func->offset = offset - start; +		func->name = strdup(symname); +		func->flags = FUNCF_TRACE;	/* trace by default */ + +		/* Update previous function's code size */ +		if (func_count > 1) +			func[-1].code_size = func->offset - func[-1].offset; +	} +	notice("%d functions found in map file\n", func_count); +	text_offset = start; +	return 0; +} + +static int read_data(FILE *fin, void *buff, int size) +{ +	int err; + +	err = fread(buff, 1, size, fin); +	if (!err) +		return 1; +	if (err != size) { +		error("Cannot read profile file at pos %ld\n", ftell(fin)); +		return -1; +	} +	return 0; +} + +static struct func_info *find_func_by_offset(uint32_t offset) +{ +	struct func_info key, *found; + +	key.offset = offset; +	found = bsearch(&key, func_list, func_count, sizeof(struct func_info), +			h_cmp_offset); + +	return found; +} + +/* This finds the function which contains the given offset */ +static struct func_info *find_caller_by_offset(uint32_t offset) +{ +	int low;	/* least function that could be a match */ +	int high;	/* greated function that could be a match */ +	struct func_info key; + +	low = 0; +	high = func_count - 1; +	key.offset = offset; +	while (high > low + 1) { +		int mid = (low + high) / 2; +		int result; + +		result = h_cmp_offset(&key, &func_list[mid]); +		if (result > 0) +			low = mid; +		else if (result < 0) +			high = mid; +		else +			return &func_list[mid]; +	} + +	return low >= 0 ? &func_list[low] : NULL; +} + +static int read_calls(FILE *fin, int count) +{ +	struct trace_call *call_data; +	int i; + +	notice("call count: %d\n", count); +	call_list = (struct trace_call *)calloc(count, sizeof(*call_data)); +	if (!call_list) { +		error("Cannot allocate call_list\n"); +		return -1; +	} +	call_count = count; + +	call_data = call_list; +	for (i = 0; i < count; i++, call_data++) { +		if (read_data(fin, call_data, sizeof(*call_data))) +			return 1; +	} +	return 0; +} + +static int read_profile(FILE *fin, int *not_found) +{ +	struct trace_output_hdr hdr; + +	*not_found = 0; +	while (!feof(fin)) { +		int err; + +		err = read_data(fin, &hdr, sizeof(hdr)); +		if (err == 1) +			break; /* EOF */ +		else if (err) +			return 1; + +		switch (hdr.type) { +		case TRACE_CHUNK_FUNCS: +			/* Ignored at present */ +			break; + +		case TRACE_CHUNK_CALLS: +			if (read_calls(fin, hdr.rec_count)) +				return 1; +			break; +		} +	} +	return 0; +} + +static int read_map_file(const char *fname) +{ +	FILE *fmap; +	int err = 0; + +	fmap = fopen(fname, "r"); +	if (!fmap) { +		error("Cannot open map file '%s'\n", fname); +		return 1; +	} +	if (fmap) { +		err = read_system_map(fmap); +		fclose(fmap); +	} +	return err; +} + +static int read_profile_file(const char *fname) +{ +	int not_found = INT_MAX; +	FILE *fprof; +	int err; + +	fprof = fopen(fname, "rb"); +	if (!fprof) { +		error("Cannot open profile data file '%s'\n", +		      fname); +		return 1; +	} else { +		err = read_profile(fprof, ¬_found); +		fclose(fprof); +		if (err) +			return err; + +		if (not_found) { +			warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n", +			     not_found); +			return 1; +		} +	} +	return 0; +} + +static int regex_report_error(regex_t *regex, int err, const char *op, +			      const char *name) +{ +	char buf[200]; + +	regerror(err, regex, buf, sizeof(buf)); +	error("Regex error '%s' in %s '%s'\n", buf, op, name); +	return -1; +} + +static void check_trace_config_line(struct trace_configline_info *item) +{ +	struct func_info *func, *end; +	int err; + +	debug("Checking trace config line '%s'\n", item->name); +	for (func = func_list, end = func + func_count; func < end; func++) { +		err = regexec(&item->regex, func->name, 0, NULL, 0); +		debug("   - regex '%s', string '%s': %d\n", item->name, +		      func->name, err); +		if (err == REG_NOMATCH) +			continue; + +		if (err != REG_NOERROR) { +			regex_report_error(&item->regex, err, "match", +					   item->name); +			break; +		} + +		/* It matches, so perform the action */ +		switch (item->type) { +		case TRACE_LINE_INCLUDE: +			info("      include %s at %lx\n", func->name, +			     text_offset + func->offset); +			func->flags |= FUNCF_TRACE; +			break; + +		case TRACE_LINE_EXCLUDE: +			info("      exclude %s at %lx\n", func->name, +			     text_offset + func->offset); +			func->flags &= ~FUNCF_TRACE; +			break; +		} +	} +} + +static void check_trace_config(void) +{ +	struct trace_configline_info *line; + +	for (line = trace_config_head; line; line = line->next) +		check_trace_config_line(line); +} + +/** + * Check the functions to see if they each have an objsection. If not, then + * the linker must have eliminated them. + */ +static void check_functions(void) +{ +	struct func_info *func, *end; +	unsigned long removed_code_size = 0; +	int not_found = 0; + +	/* Look for missing functions */ +	for (func = func_list, end = func + func_count; func < end; func++) { +		if (!func->objsection) { +			removed_code_size += func->code_size; +			not_found++; +		} +	} + +	/* Figure out what functions we want to trace */ +	check_trace_config(); + +	warn("%d functions removed by linker, %ld code size\n", +	     not_found, removed_code_size); +} + +static int read_trace_config(FILE *fin) +{ +	char buff[200]; +	int linenum = 0; +	struct trace_configline_info **tailp = &trace_config_head; + +	while (fgets(buff, sizeof(buff), fin)) { +		int len = strlen(buff); +		struct trace_configline_info *line; +		char *saveptr; +		char *s, *tok; +		int err; + +		linenum++; +		if (len && buff[len - 1] == '\n') +			buff[len - 1] = '\0'; + +		/* skip blank lines and comments */ +		for (s = buff; *s == ' ' || *s == '\t'; s++) +			; +		if (!*s || *s == '#') +			continue; + +		line = (struct trace_configline_info *)calloc(1, +							      sizeof(*line)); +		if (!line) { +			error("Cannot allocate config line\n"); +			return -1; +		} + +		tok = strtok_r(s, " \t", &saveptr); +		if (!tok) { +			error("Invalid trace config data on line %d\n", +			      linenum); +			return -1; +		} +		if (0 == strcmp(tok, "include-func")) { +			line->type = TRACE_LINE_INCLUDE; +		} else if (0 == strcmp(tok, "exclude-func")) { +			line->type = TRACE_LINE_EXCLUDE; +		} else { +			error("Unknown command in trace config data line %d\n", +			      linenum); +			return -1; +		} + +		tok = strtok_r(NULL, " \t", &saveptr); +		if (!tok) { +			error("Missing pattern in trace config data line %d\n", +			      linenum); +			return -1; +		} + +		err = regcomp(&line->regex, tok, REG_NOSUB); +		if (err) { +			free(line); +			return regex_report_error(&line->regex, err, "compile", +						  tok); +		} + +		/* link this new one to the end of the list */ +		line->name = strdup(tok); +		line->next = NULL; +		*tailp = line; +		tailp = &line->next; +	} + +	if (!feof(fin)) { +		error("Cannot read from trace config file at position %ld\n", +		      ftell(fin)); +		return -1; +	} +	return 0; +} + +static int read_trace_config_file(const char *fname) +{ +	FILE *fin; +	int err; + +	fin = fopen(fname, "r"); +	if (!fin) { +		error("Cannot open trace_config file '%s'\n", fname); +		return -1; +	} +	err = read_trace_config(fin); +	fclose(fin); +	return err; +} + +static void out_func(ulong func_offset, int is_caller, const char *suffix) +{ +	struct func_info *func; + +	func = (is_caller ? find_caller_by_offset : find_func_by_offset) +		(func_offset); + +	if (func) +		printf("%s%s", func->name, suffix); +	else +		printf("%lx%s", func_offset, suffix); +} + +/* + * # tracer: function + * # + * #           TASK-PID   CPU#    TIMESTAMP  FUNCTION + * #              | |      |          |         | + * #           bash-4251  [01] 10152.583854: path_put <-path_walk + * #           bash-4251  [01] 10152.583855: dput <-path_put + * #           bash-4251  [01] 10152.583855: _atomic_dec_and_lock <-dput + */ +static int make_ftrace(void) +{ +	struct trace_call *call; +	int missing_count = 0, skip_count = 0; +	int i; + +	printf("# tracer: ftrace\n" +		"#\n" +		"#           TASK-PID   CPU#    TIMESTAMP  FUNCTION\n" +		"#              | |      |          |         |\n"); +	for (i = 0, call = call_list; i < call_count; i++, call++) { +		struct func_info *func = find_func_by_offset(call->func); +		ulong time = call->flags & FUNCF_TIMESTAMP_MASK; + +		if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY && +		    TRACE_CALL_TYPE(call) != FUNCF_EXIT) +			continue; +		if (!func) { +			warn("Cannot find function at %lx\n", +			     text_offset + call->func); +			missing_count++; +			continue; +		} + +		if (!(func->flags & FUNCF_TRACE)) { +			debug("Funcion '%s' is excluded from trace\n", +			      func->name); +			skip_count++; +			continue; +		} + +		printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1, +		       time / 1000000, time % 1000000); + +		out_func(call->func, 0, " <- "); +		out_func(call->caller, 1, "\n"); +	} +	info("ftrace: %d functions not found, %d excluded\n", missing_count, +	     skip_count); + +	return 0; +} + +static int prof_tool(int argc, char * const argv[], +		     const char *prof_fname, const char *map_fname, +		     const char *trace_config_fname) +{ +	int err = 0; + +	if (read_map_file(map_fname)) +		return -1; +	if (prof_fname && read_profile_file(prof_fname)) +		return -1; +	if (trace_config_fname && read_trace_config_file(trace_config_fname)) +		return -1; + +	check_functions(); + +	for (; argc; argc--, argv++) { +		const char *cmd = *argv; + +		if (0 == strcmp(cmd, "dump-ftrace")) +			err = make_ftrace(); +		else +			warn("Unknown command '%s'\n", cmd); +	} + +	return err; +} + +int main(int argc, char *argv[]) +{ +	const char *map_fname = "System.map"; +	const char *prof_fname = NULL; +	const char *trace_config_fname = NULL; +	int opt; + +	verbose = 2; +	while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) { +		switch (opt) { +		case 'm': +			map_fname = optarg; +			break; + +		case 'p': +			prof_fname = optarg; +			break; + +		case 't': +			trace_config_fname = optarg; +			break; + +		case 'v': +			verbose = atoi(optarg); +			break; + +		default: +			usage(); +		} +	} +	argc -= optind; argv += optind; +	if (argc < 1) +		usage(); + +	debug("Debug enabled\n"); +	return prof_tool(argc, argv, prof_fname, map_fname, +			 trace_config_fname); +}  |