diff options
202 files changed, 11399 insertions, 1566 deletions
@@ -24,7 +24,7 @@  VERSION = 2013  PATCHLEVEL = 01  SUBLEVEL = -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2  ifneq "$(SUBLEVEL)" ""  U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)  else @@ -316,6 +316,7 @@ LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o  endif  LIBS-y += drivers/rtc/librtc.o  LIBS-y += drivers/serial/libserial.o +LIBS-y += drivers/sound/libsound.o  LIBS-$(CONFIG_GENERIC_LPC_TPM) += drivers/tpm/libtpm.o  LIBS-y += drivers/twserial/libtws.o  LIBS-y += drivers/usb/eth/libusb_eth.o @@ -815,6 +815,8 @@ The following options need to be configured:  		CONFIG_CMD_EDITENV	  edit env variable  		CONFIG_CMD_EEPROM	* EEPROM read/write support  		CONFIG_CMD_ELF		* bootelf, bootvx +		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks +		CONFIG_CMD_ENV_FLAGS	* display details about env flags  		CONFIG_CMD_EXPORTENV	* export the environment  		CONFIG_CMD_EXT2		* ext2 command support  		CONFIG_CMD_EXT4		* ext4 command support @@ -824,8 +826,10 @@ 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_GETTIME	* Get time since boot  		CONFIG_CMD_GO		* the 'go' command (exec code)  		CONFIG_CMD_GREPENV	* search environment +		CONFIG_CMD_HASH		* calculate hash / digest  		CONFIG_CMD_HWFLOW	* RTS/CTS hw flow control  		CONFIG_CMD_I2C		* I2C serial bus support  		CONFIG_CMD_IDE		* IDE harddisk support @@ -860,6 +864,7 @@ The following options need to be configured:  		CONFIG_CMD_PING		* send ICMP ECHO_REQUEST to network  					  host  		CONFIG_CMD_PORTIO	* Port I/O +		CONFIG_CMD_READ		* Read raw data from partition  		CONFIG_CMD_REGINFO	* Register dump  		CONFIG_CMD_RUN		  run command in env variable  		CONFIG_CMD_SAVES	* save S record dump @@ -1481,10 +1486,29 @@ CBFS (Coreboot Filesystem) support  		Normally display is black on white background; define  		CONFIG_SYS_WHITE_ON_BLACK to get it inverted. +		CONFIG_LCD_ALIGNMENT + +		Normally the LCD is page-aligned (tyically 4KB). If this is +		defined then the LCD will be aligned to this value instead. +		For ARM it is sometimes useful to use MMU_SECTION_SIZE +		here, since it is cheaper to change data cache settings on +		a per-section basis. + +		CONFIG_CONSOLE_SCROLL_LINES + +		When the console need to be scrolled, this is the number of +		lines to scroll by. It defaults to 1. Increasing this makes +		the console jump but can help speed up operation when scrolling +		is slow. +  		CONFIG_LCD_BMP_RLE8  		Support drawing of RLE8-compressed bitmaps on the LCD. +		CONFIG_I2C_EDID + +		Enables an 'i2c edid' command which can read EDID +		information over I2C from an attached LCD display.  - Splash Screen Support: CONFIG_SPLASH_SCREEN @@ -2179,6 +2203,11 @@ CBFS (Coreboot Filesystem) support  		serial# is unaffected by this, i. e. it remains  		read-only.] +		The same can be accomplished in a more flexible way +		for any variable by configuring the type of access +		to allow for those variables in the ".flags" variable +		or define CONFIG_ENV_FLAGS_LIST_STATIC. +  - Protected RAM:  		CONFIG_PRAM @@ -2409,6 +2438,23 @@ CBFS (Coreboot Filesystem) support  		A better solution is to properly configure the firewall,  		but sometimes that is not allowed. +- Hashing support: +		CONFIG_CMD_HASH + +		This enables a generic 'hash' command which can produce +		hashes / digests from a few algorithms (e.g. SHA1, SHA256). + +		CONFIG_HASH_VERIFY + +		Enable the hash verify command (hash -v). This adds to code +		size a little. + +		CONFIG_SHA1 - support SHA1 hashing +		CONFIG_SHA256 - support SHA256 hashing + +		Note: There is also a sha1sum command, which should perhaps +		be deprecated in favour of 'hash sha1'. +  - Show boot progress:  		CONFIG_SHOW_BOOT_PROGRESS @@ -2943,9 +2989,6 @@ Configuration Settings:  		non page size aligned address and this could cause major  		problems. -- CONFIG_SYS_TFTP_LOADADDR: -		Default load address for network file downloads -  - CONFIG_SYS_LOADS_BAUD_CHANGE:  		Enable temporary baudrate change while serial download @@ -3087,6 +3130,49 @@ Configuration Settings:  	cases. This setting can be used to tune behaviour; see  	lib/hashtable.c for details. +- CONFIG_ENV_FLAGS_LIST_DEFAULT +- CONFIG_ENV_FLAGS_LIST_STATIC +	Enable validation of the values given to enviroment variables when +	calling env set.  Variables can be restricted to only decimal, +	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined, +	the variables can also be restricted to IP address or MAC address. + +	The format of the list is: +		type_attribute = [s|d|x|b|i|m] +		access_atribute = [a|r|o|c] +		attributes = type_attribute[access_atribute] +		entry = variable_name[:attributes] +		list = entry[,list] + +	The type attributes are: +		s - String (default) +		d - Decimal +		x - Hexadecimal +		b - Boolean ([1yYtT|0nNfF]) +		i - IP address +		m - MAC address + +	The access attributes are: +		a - Any (default) +		r - Read-only +		o - Write-once +		c - Change-default + +	- CONFIG_ENV_FLAGS_LIST_DEFAULT +		Define this to a list (string) to define the ".flags" +		envirnoment variable in the default or embedded environment. + +	- CONFIG_ENV_FLAGS_LIST_STATIC +		Define this to a list (string) to define validation that +		should be done if an entry is not found in the ".flags" +		environment variable.  To override a setting in the static +		list, simply add an entry for the same variable name to the +		".flags" variable. + +- CONFIG_ENV_ACCESS_IGNORE_FORCE +	If defined, don't allow the -f switch to env set override variable +	access flags. +  The following definitions that deal with the placement and management  of environment data (variable area); in general, we support the  following configurations: @@ -4188,6 +4274,36 @@ Please note that changes to some configuration parameters may take  only effect after the next boot (yes, that's just like Windoze :-). +Callback functions for environment variables: +--------------------------------------------- + +For some environment variables, the behavior of u-boot needs to change +when their values are changed.  This functionailty allows functions to +be associated with arbitrary variables.  On creation, overwrite, or +deletion, the callback will provide the opportunity for some side +effect to happen or for the change to be rejected. + +The callbacks are named and associated with a function using the +U_BOOT_ENV_CALLBACK macro in your board or driver code. + +These callbacks are associated with variables in one of two ways.  The +static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC +in the board configuration to a string that defines a list of +associations.  The list must be in the following format: + +	entry = variable_name[:callback_name] +	list = entry[,list] + +If the callback name is not specified, then the callback is deleted. +Spaces are also allowed anywhere in the list. + +Callbacks can also be associated by defining the ".callbacks" variable +with the same list format above.  Any association in ".callbacks" will +override any association in the static list. You can define +CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the +".callbacks" envirnoment variable in the default or embedded environment. + +  Command Line Parsing:  ===================== diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index b98e3d9fa..32a4c244c 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -141,16 +141,6 @@ void flush_cache(unsigned long start, unsigned long size)  	flush_dcache_range(start, start + size);  } -void enable_caches(void) -{ -#ifndef CONFIG_SYS_ICACHE_OFF -	icache_enable(); -#endif -#ifndef CONFIG_SYS_DCACHE_OFF -	dcache_enable(); -#endif -} -  #else /* #ifndef CONFIG_SYS_DCACHE_OFF */  void invalidate_dcache_all(void)  { @@ -172,3 +162,15 @@ void flush_cache(unsigned long start, unsigned long size)  {  }  #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ + +#if !defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF) +void enable_caches(void) +{ +#ifndef CONFIG_SYS_ICACHE_OFF +	icache_enable(); +#endif +#ifndef CONFIG_SYS_DCACHE_OFF +	dcache_enable(); +#endif +} +#endif diff --git a/arch/arm/cpu/arm1176/s3c64xx/Makefile b/arch/arm/cpu/arm1176/s3c64xx/Makefile index 0785b194c..266a0739c 100644 --- a/arch/arm/cpu/arm1176/s3c64xx/Makefile +++ b/arch/arm/cpu/arm1176/s3c64xx/Makefile @@ -31,7 +31,7 @@ LIB	= $(obj)lib$(SOC).o  SOBJS	= reset.o  COBJS-$(CONFIG_S3C6400)	+= cpu_init.o speed.o -COBJS-y	+= timer.o +COBJS-y	+= timer.o init.o  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS-y)) diff --git a/arch/arm/cpu/arm1176/s3c64xx/init.c b/arch/arm/cpu/arm1176/s3c64xx/init.c new file mode 100644 index 000000000..f113d8ed4 --- /dev/null +++ b/arch/arm/cpu/arm1176/s3c64xx/init.c @@ -0,0 +1,26 @@ +/* + * (C) Copyright 2012 Ashok Kumar Reddy Kourla + * ashokkourla2000@gmail.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. + */ + +#include<common.h> + +int arch_cpu_init(void) +{ +	icache_enable(); + +	return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c index bfea6abeb..4ff19c37e 100644 --- a/arch/arm/cpu/arm926ejs/mxs/clock.c +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -333,6 +333,8 @@ uint32_t mxc_get_clock(enum mxc_clock clk)  		return mx28_get_sspclk(MXC_SSPCLK2);  	case MXC_SSP3_CLK:  		return mx28_get_sspclk(MXC_SSPCLK3); +	case MXC_XTAL_CLK: +		return XTAL_FREQ_KHZ * 1000;  	}  	return 0; diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c index 1b4e808a7..5f6d0396f 100644 --- a/arch/arm/cpu/armv7/cache_v7.c +++ b/arch/arm/cpu/armv7/cache_v7.c @@ -297,6 +297,12 @@ void arm_init_before_mmu(void)  	v7_inval_tlb();  } +void mmu_page_table_flush(unsigned long start, unsigned long stop) +{ +	flush_dcache_range(start, stop); +	v7_inval_tlb(); +} +  /*   * Flush range from all levels of d-cache/unified-cache used:   * Affects the range [start, start + size - 1] @@ -329,6 +335,11 @@ void arm_init_before_mmu(void)  void  flush_cache(unsigned long start, unsigned long size)  {  } + +void mmu_page_table_flush(unsigned long start, unsigned long stop) +{ +} +  #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */  #ifndef CONFIG_SYS_ICACHE_OFF diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 4f3b451be..74599798c 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -25,42 +25,32 @@  #include <asm/io.h>  #include <asm/arch/clock.h>  #include <asm/arch/clk.h> +#include <asm/arch/periph.h> -/* exynos4: return pll clock frequency */ -static unsigned long exynos4_get_pll_clk(int pllreg) +/* Epll Clock division values to achive different frequency output */ +static struct set_epll_con_val exynos5_epll_div[] = { +	{ 192000000, 0, 48, 3, 1, 0 }, +	{ 180000000, 0, 45, 3, 1, 0 }, +	{  73728000, 1, 73, 3, 3, 47710 }, +	{  67737600, 1, 90, 4, 3, 20762 }, +	{  49152000, 0, 49, 3, 3, 9961 }, +	{  45158400, 0, 45, 3, 3, 10381 }, +	{ 180633600, 0, 45, 3, 1, 10381 } +}; + +/* exynos: return pll clock frequency */ +static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  { -	struct exynos4_clock *clk = -		(struct exynos4_clock *)samsung_get_base_clock(); -	unsigned long r, m, p, s, k = 0, mask, fout; +	unsigned long m, p, s = 0, mask, fout;  	unsigned int freq; - -	switch (pllreg) { -	case APLL: -		r = readl(&clk->apll_con0); -		break; -	case MPLL: -		r = readl(&clk->mpll_con0); -		break; -	case EPLL: -		r = readl(&clk->epll_con0); -		k = readl(&clk->epll_con1); -		break; -	case VPLL: -		r = readl(&clk->vpll_con0); -		k = readl(&clk->vpll_con1); -		break; -	default: -		printf("Unsupported PLL (%d)\n", pllreg); -		return 0; -	} -  	/*  	 * APLL_CON: MIDV [25:16]  	 * MPLL_CON: MIDV [25:16]  	 * EPLL_CON: MIDV [24:16]  	 * VPLL_CON: MIDV [24:16] +	 * BPLL_CON: MIDV [25:16]: Exynos5  	 */ -	if (pllreg == APLL || pllreg == MPLL) +	if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)  		mask = 0x3ff;  	else  		mask = 0x1ff; @@ -92,13 +82,43 @@ static unsigned long exynos4_get_pll_clk(int pllreg)  	return fout;  } +/* exynos4: return pll clock frequency */ +static unsigned long exynos4_get_pll_clk(int pllreg) +{ +	struct exynos4_clock *clk = +		(struct exynos4_clock *)samsung_get_base_clock(); +	unsigned long r, k = 0; + +	switch (pllreg) { +	case APLL: +		r = readl(&clk->apll_con0); +		break; +	case MPLL: +		r = readl(&clk->mpll_con0); +		break; +	case EPLL: +		r = readl(&clk->epll_con0); +		k = readl(&clk->epll_con1); +		break; +	case VPLL: +		r = readl(&clk->vpll_con0); +		k = readl(&clk->vpll_con1); +		break; +	default: +		printf("Unsupported PLL (%d)\n", pllreg); +		return 0; +	} + +	return exynos_get_pll_clk(pllreg, r, k); +} +  /* exynos5: return pll clock frequency */  static unsigned long exynos5_get_pll_clk(int pllreg)  {  	struct exynos5_clock *clk =  		(struct exynos5_clock *)samsung_get_base_clock(); -	unsigned long r, m, p, s, k = 0, mask, fout; -	unsigned int freq, pll_div2_sel, fout_sel; +	unsigned long r, k = 0, fout; +	unsigned int pll_div2_sel, fout_sel;  	switch (pllreg) {  	case APLL: @@ -123,41 +143,7 @@ static unsigned long exynos5_get_pll_clk(int pllreg)  		return 0;  	} -	/* -	 * APLL_CON: MIDV [25:16] -	 * MPLL_CON: MIDV [25:16] -	 * EPLL_CON: MIDV [24:16] -	 * VPLL_CON: MIDV [24:16] -	 * BPLL_CON: MIDV [25:16] -	 */ -	if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL) -		mask = 0x3ff; -	else -		mask = 0x1ff; - -	m = (r >> 16) & mask; - -	/* PDIV [13:8] */ -	p = (r >> 8) & 0x3f; -	/* SDIV [2:0] */ -	s = r & 0x7; - -	freq = CONFIG_SYS_CLK_FREQ; - -	if (pllreg == EPLL) { -		k = k & 0xffff; -		/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */ -		fout = (m + k / 65536) * (freq / (p * (1 << s))); -	} else if (pllreg == VPLL) { -		k = k & 0xfff; -		/* 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 = exynos_get_pll_clk(pllreg, r, k);  	/* According to the user manual, in EVT1 MPLL and BPLL always gives  	 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/ @@ -732,6 +718,224 @@ static unsigned long exynos5_get_i2c_clk(void)  	return aclk_66;  } +int exynos5_set_epll_clk(unsigned long rate) +{ +	unsigned int epll_con, epll_con_k; +	unsigned int i; +	unsigned int lockcnt; +	unsigned int start; +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); + +	epll_con = readl(&clk->epll_con0); +	epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << +			EPLL_CON0_LOCK_DET_EN_SHIFT) | +		EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | +		EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | +		EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); + +	for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) { +		if (exynos5_epll_div[i].freq_out == rate) +			break; +	} + +	if (i == ARRAY_SIZE(exynos5_epll_div)) +		return -1; + +	epll_con_k = exynos5_epll_div[i].k_dsm << 0; +	epll_con |= exynos5_epll_div[i].en_lock_det << +				EPLL_CON0_LOCK_DET_EN_SHIFT; +	epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; +	epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; +	epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; + +	/* +	 * Required period ( in cycles) to genarate a stable clock output. +	 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs +	 * frequency input (as per spec) +	 */ +	lockcnt = 3000 * exynos5_epll_div[i].p_div; + +	writel(lockcnt, &clk->epll_lock); +	writel(epll_con, &clk->epll_con0); +	writel(epll_con_k, &clk->epll_con1); + +	start = get_timer(0); + +	 while (!(readl(&clk->epll_con0) & +			(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { +		if (get_timer(start) > TIMEOUT_EPLL_LOCK) { +			debug("%s: Timeout waiting for EPLL lock\n", __func__); +			return -1; +		} +	} +	return 0; +} + +void exynos5_set_i2s_clk_source(void) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); + +	clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, +			(CLK_SRC_SCLK_EPLL)); +} + +int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, +					unsigned int dst_frq) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); +	unsigned int div; + +	if ((dst_frq == 0) || (src_frq == 0)) { +		debug("%s: Invalid requency input for prescaler\n", __func__); +		debug("src frq = %d des frq = %d ", src_frq, dst_frq); +		return -1; +	} + +	div = (src_frq / dst_frq); +	if (div > AUDIO_1_RATIO_MASK) { +		debug("%s: Frequency ratio is out of range\n", __func__); +		debug("src frq = %d des frq = %d ", src_frq, dst_frq); +		return -1; +	} +	clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, +				(div & AUDIO_1_RATIO_MASK)); +	return 0; +} + +/** + * Linearly searches for the most accurate main and fine stage clock scalars + * (divisors) for a specified target frequency and scalar bit sizes by checking + * all multiples of main_scalar_bits values. Will always return scalars up to or + * slower than target. + * + * @param main_scalar_bits	Number of main scalar bits, must be > 0 and < 32 + * @param fine_scalar_bits	Number of fine scalar bits, must be > 0 and < 32 + * @param input_freq		Clock frequency to be scaled in Hz + * @param target_freq		Desired clock frequency in Hz + * @param best_fine_scalar	Pointer to store the fine stage divisor + * + * @return best_main_scalar	Main scalar for desired frequency or -1 if none + * found + */ +static int clock_calc_best_scalar(unsigned int main_scaler_bits, +	unsigned int fine_scalar_bits, unsigned int input_rate, +	unsigned int target_rate, unsigned int *best_fine_scalar) +{ +	int i; +	int best_main_scalar = -1; +	unsigned int best_error = target_rate; +	const unsigned int cap = (1 << fine_scalar_bits) - 1; +	const unsigned int loops = 1 << main_scaler_bits; + +	debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate, +			target_rate, cap); + +	assert(best_fine_scalar != NULL); +	assert(main_scaler_bits <= fine_scalar_bits); + +	*best_fine_scalar = 1; + +	if (input_rate == 0 || target_rate == 0) +		return -1; + +	if (target_rate >= input_rate) +		return 1; + +	for (i = 1; i <= loops; i++) { +		const unsigned int effective_div = max(min(input_rate / i / +							target_rate, cap), 1); +		const unsigned int effective_rate = input_rate / i / +							effective_div; +		const int error = target_rate - effective_rate; + +		debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div, +				effective_rate, error); + +		if (error >= 0 && error <= best_error) { +			best_error = error; +			best_main_scalar = i; +			*best_fine_scalar = effective_div; +		} +	} + +	return best_main_scalar; +} + +static int exynos5_set_spi_clk(enum periph_id periph_id, +					unsigned int rate) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); +	int main; +	unsigned int fine; +	unsigned shift, pre_shift; +	unsigned mask = 0xff; +	u32 *reg; + +	main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); +	if (main < 0) { +		debug("%s: Cannot set clock rate for periph %d", +				__func__, periph_id); +		return -1; +	} +	main = main - 1; +	fine = fine - 1; + +	switch (periph_id) { +	case PERIPH_ID_SPI0: +		reg = &clk->div_peric1; +		shift = 0; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI1: +		reg = &clk->div_peric1; +		shift = 16; +		pre_shift = 24; +		break; +	case PERIPH_ID_SPI2: +		reg = &clk->div_peric2; +		shift = 0; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI3: +		reg = &clk->sclk_div_isp; +		shift = 0; +		pre_shift = 4; +		break; +	case PERIPH_ID_SPI4: +		reg = &clk->sclk_div_isp; +		shift = 12; +		pre_shift = 16; +		break; +	default: +		debug("%s: Unsupported peripheral ID %d\n", __func__, +		      periph_id); +		return -1; +	} +	clrsetbits_le32(reg, mask << shift, (main & mask) << shift); +	clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift); + +	return 0; +} + +static unsigned long exynos4_get_i2c_clk(void) +{ +	struct exynos4_clock *clk = +		(struct exynos4_clock *)samsung_get_base_clock(); +	unsigned long sclk, aclk_100; +	unsigned int ratio; + +	sclk = get_pll_clk(APLL); + +	ratio = (readl(&clk->div_top)) >> 4; +	ratio &= 0xf; +	aclk_100 = sclk / (ratio + 1); +	return aclk_100; +} +  unsigned long get_pll_clk(int pllreg)  {  	if (cpu_is_exynos5()) @@ -752,6 +956,8 @@ unsigned long get_i2c_clk(void)  {  	if (cpu_is_exynos5()) {  		return exynos5_get_i2c_clk(); +	} else if (cpu_is_exynos4()) { +		return exynos4_get_i2c_clk();  	} else {  		debug("I2C clock is not set for this CPU\n");  		return 0; @@ -803,3 +1009,34 @@ void set_mipi_clk(void)  	if (cpu_is_exynos4())  		exynos4_set_mipi_clk();  } + +int set_spi_clk(int periph_id, unsigned int rate) +{ +	if (cpu_is_exynos5()) +		return exynos5_set_spi_clk(periph_id, rate); +	else +		return 0; +} + +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{ + +	if (cpu_is_exynos5()) +		return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq); +	else +		return 0; +} + +void set_i2s_clk_source(void) +{ +	if (cpu_is_exynos5()) +		exynos5_set_i2s_clk_source(); +} + +int set_epll_clk(unsigned long rate) +{ +	if (cpu_is_exynos5()) +		return exynos5_set_epll_clk(rate); +	else +		return 0; +} diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 7776add9d..20a4b8414 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -112,6 +112,7 @@ static int exynos5_mmc_config(int peripheral, int flags)  		s5p_gpio_set_pull(bank, i, GPIO_PULL_UP);  		s5p_gpio_set_drv(bank, i, GPIO_DRV_4X);  	} +  	return 0;  } @@ -230,6 +231,59 @@ static void exynos5_i2c_config(int peripheral, int flags)  	}  } +static void exynos5_i2s_config(int peripheral) +{ +	int i; +	struct exynos5_gpio_part1 *gpio1 = +		(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); + +	for (i = 0; i < 5; i++) +		s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02)); +} + +void exynos5_spi_config(int peripheral) +{ +	int cfg = 0, pin = 0, i; +	struct s5p_gpio_bank *bank = NULL; +	struct exynos5_gpio_part1 *gpio1 = +		(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); +	struct exynos5_gpio_part2 *gpio2 = +		(struct exynos5_gpio_part2 *) samsung_get_base_gpio_part2(); + +	switch (peripheral) { +	case PERIPH_ID_SPI0: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI1: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 4; +		break; +	case PERIPH_ID_SPI2: +		bank = &gpio1->b1; +		cfg = GPIO_FUNC(0x5); +		pin = 1; +		break; +	case PERIPH_ID_SPI3: +		bank = &gpio2->f1; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI4: +		for (i = 0; i < 2; i++) { +			s5p_gpio_cfg_pin(&gpio2->f0, i + 2, GPIO_FUNC(0x4)); +			s5p_gpio_cfg_pin(&gpio2->e0, i + 4, GPIO_FUNC(0x4)); +		} +		break; +	} +	if (peripheral != PERIPH_ID_SPI4) { +		for (i = pin; i < pin + 4; i++) +			s5p_gpio_cfg_pin(bank, i, cfg); +	} +} +  static int exynos5_pinmux_config(int peripheral, int flags)  {  	switch (peripheral) { @@ -257,6 +311,78 @@ static int exynos5_pinmux_config(int peripheral, int flags)  	case PERIPH_ID_I2C7:  		exynos5_i2c_config(peripheral, flags);  		break; +	case PERIPH_ID_I2S1: +		exynos5_i2s_config(peripheral); +		break; +	case PERIPH_ID_SPI0: +	case PERIPH_ID_SPI1: +	case PERIPH_ID_SPI2: +	case PERIPH_ID_SPI3: +	case PERIPH_ID_SPI4: +		exynos5_spi_config(peripheral); +		break; +	default: +		debug("%s: invalid peripheral %d", __func__, peripheral); +		return -1; +	} + +	return 0; +} + +static void exynos4_i2c_config(int peripheral, int flags) +{ +	struct exynos4_gpio_part1 *gpio1 = +		(struct exynos4_gpio_part1 *) samsung_get_base_gpio_part1(); + +	switch (peripheral) { +	case PERIPH_ID_I2C0: +		s5p_gpio_cfg_pin(&gpio1->d1, 0, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->d1, 1, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C1: +		s5p_gpio_cfg_pin(&gpio1->d1, 2, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->d1, 3, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C2: +		s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C3: +		s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C4: +		s5p_gpio_cfg_pin(&gpio1->b, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->b, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C5: +		s5p_gpio_cfg_pin(&gpio1->b, 6, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->b, 7, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C6: +		s5p_gpio_cfg_pin(&gpio1->c1, 3, GPIO_FUNC(0x4)); +		s5p_gpio_cfg_pin(&gpio1->c1, 4, GPIO_FUNC(0x4)); +		break; +	case PERIPH_ID_I2C7: +		s5p_gpio_cfg_pin(&gpio1->d0, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->d0, 3, GPIO_FUNC(0x3)); +		break; +	} +} + +static int exynos4_pinmux_config(int peripheral, int flags) +{ +	switch (peripheral) { +	case PERIPH_ID_I2C0: +	case PERIPH_ID_I2C1: +	case PERIPH_ID_I2C2: +	case PERIPH_ID_I2C3: +	case PERIPH_ID_I2C4: +	case PERIPH_ID_I2C5: +	case PERIPH_ID_I2C6: +	case PERIPH_ID_I2C7: +		exynos4_i2c_config(peripheral, flags); +		break;  	default:  		debug("%s: invalid peripheral %d", __func__, peripheral);  		return -1; @@ -269,6 +395,8 @@ int exynos_pinmux_config(int peripheral, int flags)  {  	if (cpu_is_exynos5())  		return exynos5_pinmux_config(peripheral, flags); +	else if (cpu_is_exynos4()) +		return exynos4_pinmux_config(peripheral, flags);  	else {  		debug("pinmux functionality not supported\n");  		return -1; diff --git a/arch/arm/cpu/armv7/s5p-common/Makefile b/arch/arm/cpu/armv7/s5p-common/Makefile index f975f3f06..17053995b 100644 --- a/arch/arm/cpu/armv7/s5p-common/Makefile +++ b/arch/arm/cpu/armv7/s5p-common/Makefile @@ -28,7 +28,6 @@ LIB	= $(obj)libs5p-common.o  COBJS-y		+= cpu_info.o  COBJS-y		+= timer.o  COBJS-y		+= sromc.o -COBJS-y		+= wdt.o  COBJS-$(CONFIG_PWM)	+= pwm.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/tegra20/Makefile b/arch/arm/cpu/armv7/tegra20/Makefile index 09a0314d0..54ed8c48b 100644 --- a/arch/arm/cpu/armv7/tegra20/Makefile +++ b/arch/arm/cpu/armv7/tegra20/Makefile @@ -28,6 +28,8 @@ include $(TOPDIR)/config.mk  LIB	=  $(obj)lib$(SOC).o  COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o +COBJS-$(CONFIG_PWM_TEGRA) += pwm.o +COBJS-$(CONFIG_VIDEO_TEGRA) += display.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/tegra20/display.c b/arch/arm/cpu/armv7/tegra20/display.c new file mode 100644 index 000000000..031f9a850 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra20/display.c @@ -0,0 +1,409 @@ +/* + *  (C) Copyright 2010 + *  NVIDIA Corporation <www.nvidia.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 <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/tegra.h> +#include <asm/arch/display.h> +#include <asm/arch/dc.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/timer.h> + +static struct fdt_disp_config config; + +static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win) +{ +	unsigned h_dda, v_dda; +	unsigned long val; + +	val = readl(&dc->cmd.disp_win_header); +	val |= WINDOW_A_SELECT; +	writel(val, &dc->cmd.disp_win_header); + +	writel(win->fmt, &dc->win.color_depth); + +	clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK, +			BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT); + +	val = win->out_x << H_POSITION_SHIFT; +	val |= win->out_y << V_POSITION_SHIFT; +	writel(val, &dc->win.pos); + +	val = win->out_w << H_SIZE_SHIFT; +	val |= win->out_h << V_SIZE_SHIFT; +	writel(val, &dc->win.size); + +	val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT; +	val |= win->h << V_PRESCALED_SIZE_SHIFT; +	writel(val, &dc->win.prescaled_size); + +	writel(0, &dc->win.h_initial_dda); +	writel(0, &dc->win.v_initial_dda); + +	h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1); +	v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1); + +	val = h_dda << H_DDA_INC_SHIFT; +	val |= v_dda << V_DDA_INC_SHIFT; +	writel(val, &dc->win.dda_increment); + +	writel(win->stride, &dc->win.line_stride); +	writel(0, &dc->win.buf_stride); + +	val = WIN_ENABLE; +	if (win->bpp < 24) +		val |= COLOR_EXPAND; +	writel(val, &dc->win.win_opt); + +	writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr); +	writel(win->x, &dc->winbuf.addr_h_offset); +	writel(win->y, &dc->winbuf.addr_v_offset); + +	writel(0xff00, &dc->win.blend_nokey); +	writel(0xff00, &dc->win.blend_1win); + +	val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; +	val |= GENERAL_UPDATE | WIN_A_UPDATE; +	writel(val, &dc->cmd.state_ctrl); +} + +static void write_pair(struct fdt_disp_config *config, int item, u32 *reg) +{ +	writel(config->horiz_timing[item] | +			(config->vert_timing[item] << 16), reg); +} + +static int update_display_mode(struct dc_disp_reg *disp, +		struct fdt_disp_config *config) +{ +	unsigned long val; +	unsigned long rate; +	unsigned long div; + +	writel(0x0, &disp->disp_timing_opt); +	write_pair(config, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync); +	write_pair(config, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width); +	write_pair(config, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch); +	write_pair(config, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch); + +	writel(config->width | (config->height << 16), &disp->disp_active); + +	val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT; +	val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT; +	writel(val, &disp->data_enable_opt); + +	val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT; +	val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; +	val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; +	writel(val, &disp->disp_interface_ctrl); + +	/* +	 * The pixel clock divider is in 7.1 format (where the bottom bit +	 * represents 0.5). Here we calculate the divider needed to get from +	 * the display clock (typically 600MHz) to the pixel clock. We round +	 * up or down as requried. +	 */ +	rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL); +	div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2; +	debug("Display clock %lu, divider %lu\n", rate, div); + +	writel(0x00010001, &disp->shift_clk_opt); + +	val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; +	val |= div << SHIFT_CLK_DIVIDER_SHIFT; +	writel(val, &disp->disp_clk_ctrl); + +	return 0; +} + +/* Start up the display and turn on power to PWMs */ +static void basic_init(struct dc_cmd_reg *cmd) +{ +	u32 val; + +	writel(0x00000100, &cmd->gen_incr_syncpt_ctrl); +	writel(0x0000011a, &cmd->cont_syncpt_vsync); +	writel(0x00000000, &cmd->int_type); +	writel(0x00000000, &cmd->int_polarity); +	writel(0x00000000, &cmd->int_mask); +	writel(0x00000000, &cmd->int_enb); + +	val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE; +	val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE; +	val |= PM1_ENABLE; +	writel(val, &cmd->disp_pow_ctrl); + +	val = readl(&cmd->disp_cmd); +	val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT; +	writel(val, &cmd->disp_cmd); +} + +static void basic_init_timer(struct dc_disp_reg *disp) +{ +	writel(0x00000020, &disp->mem_high_pri); +	writel(0x00000001, &disp->mem_high_pri_timer); +} + +static const u32 rgb_enb_tab[PIN_REG_COUNT] = { +	0x00000000, +	0x00000000, +	0x00000000, +	0x00000000, +}; + +static const u32 rgb_polarity_tab[PIN_REG_COUNT] = { +	0x00000000, +	0x01000000, +	0x00000000, +	0x00000000, +}; + +static const u32 rgb_data_tab[PIN_REG_COUNT] = { +	0x00000000, +	0x00000000, +	0x00000000, +	0x00000000, +}; + +static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = { +	0x00000000, +	0x00000000, +	0x00000000, +	0x00000000, +	0x00210222, +	0x00002200, +	0x00020000, +}; + +static void rgb_enable(struct dc_com_reg *com) +{ +	int i; + +	for (i = 0; i < PIN_REG_COUNT; i++) { +		writel(rgb_enb_tab[i], &com->pin_output_enb[i]); +		writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]); +		writel(rgb_data_tab[i], &com->pin_output_data[i]); +	} + +	for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++) +		writel(rgb_sel_tab[i], &com->pin_output_sel[i]); +} + +int setup_window(struct disp_ctl_win *win, struct fdt_disp_config *config) +{ +	win->x = 0; +	win->y = 0; +	win->w = config->width; +	win->h = config->height; +	win->out_x = 0; +	win->out_y = 0; +	win->out_w = config->width; +	win->out_h = config->height; +	win->phys_addr = config->frame_buffer; +	win->stride = config->width * (1 << config->log2_bpp) / 8; +	debug("%s: depth = %d\n", __func__, config->log2_bpp); +	switch (config->log2_bpp) { +	case 5: +	case 24: +		win->fmt = COLOR_DEPTH_R8G8B8A8; +		win->bpp = 32; +		break; +	case 4: +		win->fmt = COLOR_DEPTH_B5G6R5; +		win->bpp = 16; +		break; + +	default: +		debug("Unsupported LCD bit depth"); +		return -1; +	} + +	return 0; +} + +struct fdt_disp_config *tegra_display_get_config(void) +{ +	return config.valid ? &config : NULL; +} + +static void debug_timing(const char *name, unsigned int timing[]) +{ +#ifdef DEBUG +	int i; + +	debug("%s timing: ", name); +	for (i = 0; i < FDT_LCD_TIMING_COUNT; i++) +		debug("%d ", timing[i]); +	debug("\n"); +#endif +} + +/** + * Decode panel information from the fdt, according to a standard binding + * + * @param blob		fdt blob + * @param node		offset of fdt node to read from + * @param config	structure to store fdt config into + * @return 0 if ok, -ve on error + */ +static int tegra_decode_panel(const void *blob, int node, +			      struct fdt_disp_config *config) +{ +	int front, back, ref; + +	config->width = fdtdec_get_int(blob, node, "xres", -1); +	config->height = fdtdec_get_int(blob, node, "yres", -1); +	config->pixel_clock = fdtdec_get_int(blob, node, "clock", 0); +	if (!config->pixel_clock || config->width == -1 || +			config->height == -1) { +		debug("%s: Pixel parameters missing\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} + +	back = fdtdec_get_int(blob, node, "left-margin", -1); +	front = fdtdec_get_int(blob, node, "right-margin", -1); +	ref = fdtdec_get_int(blob, node, "hsync-len", -1); +	if ((back | front | ref) == -1) { +		debug("%s: Horizontal parameters missing\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} + +	/* Use a ref-to-sync of 1 always, and take this from the front porch */ +	config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; +	config->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; +	config->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back; +	config->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - +		config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC]; +	debug_timing("horiz", config->horiz_timing); + +	back = fdtdec_get_int(blob, node, "upper-margin", -1); +	front = fdtdec_get_int(blob, node, "lower-margin", -1); +	ref = fdtdec_get_int(blob, node, "vsync-len", -1); +	if ((back | front | ref) == -1) { +		debug("%s: Vertical parameters missing\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} + +	config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; +	config->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; +	config->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back; +	config->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - +		config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC]; +	debug_timing("vert", config->vert_timing); + +	return 0; +} + +/** + * Decode the display controller information from the fdt. + * + * @param blob		fdt blob + * @param config	structure to store fdt config into + * @return 0 if ok, -ve on error + */ +static int tegra_display_decode_config(const void *blob, +				       struct fdt_disp_config *config) +{ +	int node, rgb; +	int bpp, bit; + +	/* TODO: Support multiple controllers */ +	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_DC); +	if (node < 0) { +		debug("%s: Cannot find display controller node in fdt\n", +		      __func__); +		return node; +	} +	config->disp = (struct disp_ctlr *)fdtdec_get_addr(blob, node, "reg"); +	if (!config->disp) { +		debug("%s: No display controller address\n", __func__); +		return -1; +	} + +	rgb = fdt_subnode_offset(blob, node, "rgb"); + +	config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel"); +	if (!config->panel_node < 0) { +		debug("%s: Cannot find panel information\n", __func__); +		return -1; +	} + +	if (tegra_decode_panel(blob, config->panel_node, config)) { +		debug("%s: Failed to decode panel information\n", __func__); +		return -1; +	} + +	bpp = fdtdec_get_int(blob, config->panel_node, "nvidia,bits-per-pixel", +			     -1); +	bit = ffs(bpp) - 1; +	if (bpp == (1 << bit)) +		config->log2_bpp = bit; +	else +		config->log2_bpp = bpp; +	if (bpp == -1) { +		debug("%s: Pixel bpp parameters missing\n", __func__); +		return -FDT_ERR_NOTFOUND; +	} +	config->bpp = bpp; + +	config->valid = 1;	/* we have a valid configuration */ + +	return 0; +} + +int tegra_display_probe(const void *blob, void *default_lcd_base) +{ +	struct disp_ctl_win window; +	struct dc_ctlr *dc; + +	if (tegra_display_decode_config(blob, &config)) +		return -1; + +	config.frame_buffer = (u32)default_lcd_base; + +	dc = (struct dc_ctlr *)config.disp; + +	/* +	 * A header file for clock constants was NAKed upstream. +	 * TODO: Put this into the FDT and fdt_lcd struct when we have clock +	 * support there +	 */ +	clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, +			       144 * 1000000); +	clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL, +			       600 * 1000000); +	basic_init(&dc->cmd); +	basic_init_timer(&dc->disp); +	rgb_enable(&dc->com); + +	if (config.pixel_clock) +		update_display_mode(&dc->disp, &config); + +	if (setup_window(&window, &config)) +		return -1; + +	update_window(dc, &window); + +	return 0; +} diff --git a/arch/arm/cpu/armv7/tegra20/pwm.c b/arch/arm/cpu/armv7/tegra20/pwm.c new file mode 100644 index 000000000..b655c5cd0 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra20/pwm.c @@ -0,0 +1,101 @@ +/* + * Tegra2 pulse width frequency modulator definitions + * + * Copyright (c) 2011 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 <fdtdec.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/pwm.h> + +struct pwm_info { +	struct pwm_ctlr *pwm;		/* Registers for our pwm controller */ +	int pwm_node;			/* PWM device tree node */ +} local; + +void pwm_enable(unsigned channel, int rate, int pulse_width, int freq_divider) +{ +	u32 reg; + +	assert(channel < PWM_NUM_CHANNELS); + +	/* TODO: Can we use clock_adjust_periph_pll_div() here? */ +	clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, rate); + +	reg = PWM_ENABLE_MASK; +	reg |= pulse_width << PWM_WIDTH_SHIFT; +	reg |= freq_divider << PWM_DIVIDER_SHIFT; +	writel(reg, &local.pwm[channel].control); +	debug("%s: channel=%d, rate=%d\n", __func__, channel, rate); +} + +int pwm_request(const void *blob, int node, const char *prop_name) +{ +	int pwm_node; +	u32 data[3]; + +	if (fdtdec_get_int_array(blob, node, prop_name, data, +			ARRAY_SIZE(data))) { +		debug("%s: Cannot decode PWM property '%s'\n", __func__, +		      prop_name); +		return -1; +	} + +	pwm_node = fdt_node_offset_by_phandle(blob, data[0]); +	if (pwm_node != local.pwm_node) { +		debug("%s: PWM property '%s' phandle %d not recognised" +		      "- expecting %d\n", __func__, prop_name, data[0], +		      local.pwm_node); +		return -1; +	} +	if (data[1] >= PWM_NUM_CHANNELS) { +		debug("%s: PWM property '%s': invalid channel %u\n", __func__, +		      prop_name, data[1]); +		return -1; +	} + +	/* +	 * TODO: We could maintain a list of requests, but it might not be +	 * worth it for U-Boot. +	 */ +	return data[1]; +} + +int pwm_init(const void *blob) +{ +	local.pwm_node = fdtdec_next_compatible(blob, 0, +						COMPAT_NVIDIA_TEGRA20_PWM); +	if (local.pwm_node < 0) { +		debug("%s: Cannot find device tree node\n", __func__); +		return -1; +	} + +	local.pwm = (struct pwm_ctlr *)fdtdec_get_addr(blob, local.pwm_node, +						       "reg"); +	if (local.pwm == (struct pwm_ctlr *)FDT_ADDR_T_NONE) { +		debug("%s: Cannot find pwm reg address\n", __func__); +		return -1; +	} +	debug("Tegra PWM at %p, node %d\n", local.pwm, local.pwm_node); + +	return 0; +} diff --git a/arch/arm/cpu/tegra20-common/funcmux.c b/arch/arm/cpu/tegra20-common/funcmux.c index 00b8029eb..ece7ad9ec 100644 --- a/arch/arm/cpu/tegra20-common/funcmux.c +++ b/arch/arm/cpu/tegra20-common/funcmux.c @@ -25,6 +25,30 @@  #include <asm/arch/funcmux.h>  #include <asm/arch/pinmux.h> +/* + * The PINMUX macro is used to set up pinmux tables. + */ +#define PINMUX(grp, mux, pupd, tri)                   \ +	{PINGRP_##grp, PMUX_FUNC_##mux, PMUX_PULL_##pupd, PMUX_TRI_##tri} + +static const struct pingroup_config disp1_default[] = { +	PINMUX(LDI,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP1,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP2,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHS,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LM0,   RSVD4,      NORMAL,    NORMAL), +	PINMUX(LPP,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LPW0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LPW2,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LSC0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LSPI,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LVP1,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LVS,   DISPA,      NORMAL,    NORMAL), +	PINMUX(SLXD,  SPDIF,      NORMAL,    NORMAL), +}; + +  int funcmux_select(enum periph_id id, int config)  {  	int bad_config = config != FUNCMUX_DEFAULT; @@ -257,6 +281,19 @@ int funcmux_select(enum periph_id id, int config)  			break;  		}  		break; +	case PERIPH_ID_DISP1: +		if (config == FUNCMUX_DEFAULT) { +			int i; + +			for (i = PINGRP_LD0; i <= PINGRP_LD17; i++) { +				pinmux_set_func(i, PMUX_FUNC_DISPA); +				pinmux_tristate_disable(i); +				pinmux_set_pullupdown(i, PMUX_PULL_NORMAL); +			} +			pinmux_config_table(disp1_default, +					    ARRAY_SIZE(disp1_default)); +		} +		break;  	default:  		debug("%s: invalid periph_id %d", __func__, id); diff --git a/arch/arm/cpu/tegra20-common/pinmux.c b/arch/arm/cpu/tegra20-common/pinmux.c index 08b83055d..a2a09169e 100644 --- a/arch/arm/cpu/tegra20-common/pinmux.c +++ b/arch/arm/cpu/tegra20-common/pinmux.c @@ -554,7 +554,7 @@ void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func)  	writel(reg, muxctl);  } -void pinmux_config_pingroup(struct pingroup_config *config) +void pinmux_config_pingroup(const struct pingroup_config *config)  {  	enum pmux_pingrp pin = config->pingroup; @@ -563,7 +563,7 @@ void pinmux_config_pingroup(struct pingroup_config *config)  	pinmux_set_tristate(pin, config->tristate);  } -void pinmux_config_table(struct pingroup_config *config, int len) +void pinmux_config_table(const struct pingroup_config *config, int len)  {  	int i; diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index d936b1e7e..636ec2c1f 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -211,4 +211,109 @@  		compatible = "nvidia,tegra20-nand";  		reg = <0x70008000 0x100>;  	}; + +	pwm: pwm@7000a000 { +		compatible = "nvidia,tegra20-pwm"; +		reg = <0x7000a000 0x100>; +		#pwm-cells = <2>; +	}; + +	host1x { +		compatible = "nvidia,tegra20-host1x", "simple-bus"; +		reg = <0x50000000 0x00024000>; +		interrupts = <0 65 0x04   /* mpcore syncpt */ +			      0 67 0x04>; /* mpcore general */ +		status = "disabled"; + +		#address-cells = <1>; +		#size-cells = <1>; + +		ranges = <0x54000000 0x54000000 0x04000000>; + +		/* video-encoding/decoding */ +		mpe { +			reg = <0x54040000 0x00040000>; +			interrupts = <0 68 0x04>; +			status = "disabled"; +		}; + +		/* video input */ +		vi { +			reg = <0x54080000 0x00040000>; +			interrupts = <0 69 0x04>; +			status = "disabled"; +		}; + +		/* EPP */ +		epp { +			reg = <0x540c0000 0x00040000>; +			interrupts = <0 70 0x04>; +			status = "disabled"; +		}; + +		/* ISP */ +		isp { +			reg = <0x54100000 0x00040000>; +			interrupts = <0 71 0x04>; +			status = "disabled"; +		}; + +		/* 2D engine */ +		gr2d { +			reg = <0x54140000 0x00040000>; +			interrupts = <0 72 0x04>; +			status = "disabled"; +		}; + +		/* 3D engine */ +		gr3d { +			reg = <0x54180000 0x00040000>; +			status = "disabled"; +		}; + +		/* display controllers */ +		dc@54200000 { +			compatible = "nvidia,tegra20-dc"; +			reg = <0x54200000 0x00040000>; +			interrupts = <0 73 0x04>; +			status = "disabled"; + +			rgb { +				status = "disabled"; +			}; +		}; + +		dc@54240000 { +			compatible = "nvidia,tegra20-dc"; +			reg = <0x54240000 0x00040000>; +			interrupts = <0 74 0x04>; +			status = "disabled"; + +			rgb { +				status = "disabled"; +			}; +		}; + +		/* outputs */ +		hdmi { +			compatible = "nvidia,tegra20-hdmi"; +			reg = <0x54280000 0x00040000>; +			interrupts = <0 75 0x04>; +			status = "disabled"; +		}; + +		tvo { +			compatible = "nvidia,tegra20-tvo"; +			reg = <0x542c0000 0x00040000>; +			interrupts = <0 76 0x04>; +			status = "disabled"; +		}; + +		dsi { +			compatible = "nvidia,tegra20-dsi"; +			reg = <0x54300000 0x00040000>; +			status = "disabled"; +		}; +	}; +  }; diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 552902573..cd1232350 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -38,5 +38,9 @@ void set_mmc_clk(int dev_index, unsigned int div);  unsigned long get_lcd_clk(void);  void set_lcd_clk(void);  void set_mipi_clk(void); +void set_i2s_clk_source(void); +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +int set_epll_clk(unsigned long rate); +int set_spi_clk(int periph_id, unsigned int rate);  #endif diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index fce38efbb..ff6781aae 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -595,9 +595,38 @@ struct exynos5_clock {  	unsigned int	pll_div2_sel;  	unsigned char	res123[0xf5d8];  }; + +/* structure for epll configuration used in audio clock configuration */ +struct set_epll_con_val { +	unsigned int freq_out;		/* frequency out */ +	unsigned int en_lock_det;	/* enable lock detect */ +	unsigned int m_div;		/* m divider value */ +	unsigned int p_div;		/* p divider value */ +	unsigned int s_div;		/* s divider value */ +	unsigned int k_dsm;		/* k value of delta signal modulator */ +};  #endif  #define MPLL_FOUT_SEL_SHIFT	4 +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT	29  /* EPLL Locked bit position*/ +#define TIMEOUT_EPLL_LOCK		1000 + +#define AUDIO_0_RATIO_MASK		0x0f +#define AUDIO_1_RATIO_MASK		0x0f + +#define AUDIO1_SEL_MASK			0xf +#define CLK_SRC_SCLK_EPLL		0x7 + +/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK		0x1ff +#define EPLL_CON0_PDIV_MASK		0x3f +#define EPLL_CON0_SDIV_MASK		0x7 +#define EPLL_CON0_MDIV_SHIFT		16 +#define EPLL_CON0_PDIV_SHIFT		8 +#define EPLL_CON0_SDIV_SHIFT		0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT	28 +#define EPLL_CON0_LOCK_DET_EN_MASK	1 +  #define MPLL_FOUT_SEL_MASK	0x1  #define BPLL_FOUT_SEL_SHIFT	0  #define BPLL_FOUT_SEL_MASK	0x1 diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 2cd4ae152..f06af2eb8 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -28,6 +28,8 @@  #define EXYNOS4_ADDR_BASE		0x10000000  /* EXYNOS4 */ +#define EXYNOS4_I2C_SPACING		0x10000 +  #define EXYNOS4_GPIO_PART3_BASE		0x03860000  #define EXYNOS4_PRO_ID			0x10000000  #define EXYNOS4_SYSREG_BASE		0x10010000 @@ -51,12 +53,15 @@  #define EXYNOS4_UART_BASE		0x13800000  #define EXYNOS4_I2C_BASE		0x13860000  #define EXYNOS4_ADC_BASE		0x13910000 +#define EXYNOS4_SPI_BASE		0x13920000  #define EXYNOS4_PWMTIMER_BASE		0x139D0000  #define EXYNOS4_MODEM_BASE		0x13A00000  #define EXYNOS4_USBPHY_CONTROL		0x10020704 +#define EXYNOS4_I2S_BASE		0xE2100000  #define EXYNOS4_GPIO_PART4_BASE		DEVICE_NOT_AVAILABLE  #define EXYNOS4_DP_BASE			DEVICE_NOT_AVAILABLE +#define EXYNOS4_SPI_ISP_BASE		DEVICE_NOT_AVAILABLE  /* EXYNOS5 */  #define EXYNOS5_I2C_SPACING		0x10000 @@ -81,7 +86,10 @@  #define EXYNOS5_SROMC_BASE		0x12250000  #define EXYNOS5_UART_BASE		0x12C00000  #define EXYNOS5_I2C_BASE		0x12C60000 +#define EXYNOS5_SPI_BASE		0x12D20000 +#define EXYNOS5_I2S_BASE		0x12D60000  #define EXYNOS5_PWMTIMER_BASE		0x12DD0000 +#define EXYNOS5_SPI_ISP_BASE		0x131A0000  #define EXYNOS5_GPIO_PART2_BASE		0x13400000  #define EXYNOS5_FIMD_BASE		0x14400000  #define EXYNOS5_DP_BASE			0x145B0000 @@ -139,6 +147,15 @@ static inline int cpu_is_##type(void)			\  IS_SAMSUNG_TYPE(exynos4, 0x4)  IS_SAMSUNG_TYPE(exynos5, 0x5) +#define IS_EXYNOS_TYPE(type, id)			\ +static inline int proid_is_##type(void)			\ +{							\ +	return s5p_cpu_id == id;			\ +} + +IS_EXYNOS_TYPE(exynos4210, 0x4210) +IS_EXYNOS_TYPE(exynos5250, 0x5250) +  #define SAMSUNG_BASE(device, base)				\  static inline unsigned int samsung_get_base_##device(void)	\  {								\ @@ -156,6 +173,7 @@ SAMSUNG_BASE(dp, DP_BASE)  SAMSUNG_BASE(sysreg, SYSREG_BASE)  SAMSUNG_BASE(fimd, FIMD_BASE)  SAMSUNG_BASE(i2c, I2C_BASE) +SAMSUNG_BASE(i2s, I2S_BASE)  SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE)  SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE)  SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE) @@ -173,6 +191,8 @@ SAMSUNG_BASE(usb_ehci, USB_HOST_EHCI_BASE)  SAMSUNG_BASE(usb_otg, USBOTG_BASE)  SAMSUNG_BASE(watchdog, WATCHDOG_BASE)  SAMSUNG_BASE(power, POWER_BASE) +SAMSUNG_BASE(spi, SPI_BASE) +SAMSUNG_BASE(spi_isp, SPI_ISP_BASE)  #endif  #endif	/* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/gpio.h b/arch/arm/include/asm/arch-exynos/gpio.h index 97be4eac0..4db8fd640 100644 --- a/arch/arm/include/asm/arch-exynos/gpio.h +++ b/arch/arm/include/asm/arch-exynos/gpio.h @@ -207,6 +207,25 @@ static inline unsigned int s5p_gpio_base(int nr)  	return 0;  } +static inline unsigned int s5p_gpio_part_max(int nr) +{ +	if (cpu_is_exynos5()) { +		if (nr < EXYNOS5_GPIO_PART1_MAX) +			return 0; +		else if (nr < EXYNOS5_GPIO_PART2_MAX) +			return EXYNOS5_GPIO_PART1_MAX; +		else +			return EXYNOS5_GPIO_PART2_MAX; + +	} else if (cpu_is_exynos4()) { +		if (nr < EXYNOS4_GPIO_PART1_MAX) +			return 0; +		else +			return EXYNOS4_GPIO_PART1_MAX; +	} + +	return 0; +}  #endif  /* Pin configurations */ diff --git a/arch/arm/include/asm/arch-exynos/i2s-regs.h b/arch/arm/include/asm/arch-exynos/i2s-regs.h new file mode 100644 index 000000000..2326ca036 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/i2s-regs.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar <rcsekar@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 + */ + +#ifndef __I2S_REGS_H__ +#define __I2S_REGS_H__ + +#define CON_TXFIFO_FULL		(1 << 8) +#define CON_TXCH_PAUSE		(1 << 4) +#define CON_ACTIVE		(1 << 0) + +#define MOD_BLCP_SHIFT		24 +#define MOD_BLCP_16BIT		(0 << MOD_BLCP_SHIFT) +#define MOD_BLCP_8BIT		(1 << MOD_BLCP_SHIFT) +#define MOD_BLCP_24BIT		(2 << MOD_BLCP_SHIFT) +#define MOD_BLCP_MASK		(3 << MOD_BLCP_SHIFT) + +#define MOD_BLC_16BIT		(0 << 13) +#define MOD_BLC_8BIT		(1 << 13) +#define MOD_BLC_24BIT		(2 << 13) +#define MOD_BLC_MASK		(3 << 13) + +#define MOD_SLAVE		(1 << 11) +#define MOD_MASK		(3 << 8) +#define MOD_LR_LLOW		(0 << 7) +#define MOD_LR_RLOW		(1 << 7) +#define MOD_SDF_IIS		(0 << 5) +#define MOD_SDF_MSB		(1 << 5) +#define MOD_SDF_LSB		(2 << 5) +#define MOD_SDF_MASK		(3 << 5) +#define MOD_RCLK_256FS		(0 << 3) +#define MOD_RCLK_512FS		(1 << 3) +#define MOD_RCLK_384FS		(2 << 3) +#define MOD_RCLK_768FS		(3 << 3) +#define MOD_RCLK_MASK		(3 << 3) +#define MOD_BCLK_32FS		(0 << 1) +#define MOD_BCLK_48FS		(1 << 1) +#define MOD_BCLK_16FS		(2 << 1) +#define MOD_BCLK_24FS		(3 << 1) +#define MOD_BCLK_MASK		(3 << 1) + +#define MOD_CDCLKCON		(1 << 12) + +#define FIC_TXFLUSH		(1 << 15) +#define FIC_RXFLUSH		(1 << 7) + +#endif /* __I2S_REGS_H__ */ diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index b861d7d58..13abd2d70 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -38,11 +38,18 @@ enum periph_id {  	PERIPH_ID_I2C5,  	PERIPH_ID_I2C6,  	PERIPH_ID_I2C7, +	PERIPH_ID_I2S1,  	PERIPH_ID_SDMMC0,  	PERIPH_ID_SDMMC1,  	PERIPH_ID_SDMMC2,  	PERIPH_ID_SDMMC3, +	PERIPH_ID_SDMMC4,  	PERIPH_ID_SROMC, +	PERIPH_ID_SPI0, +	PERIPH_ID_SPI1, +	PERIPH_ID_SPI2, +	PERIPH_ID_SPI3, +	PERIPH_ID_SPI4,  	PERIPH_ID_UART0,  	PERIPH_ID_UART1,  	PERIPH_ID_UART2, diff --git a/arch/arm/include/asm/arch-exynos/sound.h b/arch/arm/include/asm/arch-exynos/sound.h new file mode 100644 index 000000000..d1bd2f696 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/sound.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Rajeshwari Shinde <rajeshwari.s@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 + */ + + +#ifndef __SOUND_ARCH_H__ +#define __SOUND_ARCH_H__ + +/* I2S values */ +#define I2S_PLL_CLK		192000000 +#define I2S_SAMPLING_RATE	48000 +#define I2S_BITS_PER_SAMPLE	16 +#define I2S_CHANNELS		2 +#define I2S_RFS			256 +#define I2S_BFS			32 + +/* I2C values */ +#define AUDIO_I2C_BUS		1 +#define AUDIO_I2C_REG		0x1a + +/* Audio Codec */ +#define AUDIO_CODEC		"wm8994" + +#define AUDIO_COMPAT		1 +#endif diff --git a/arch/arm/include/asm/arch-exynos/spi.h b/arch/arm/include/asm/arch-exynos/spi.h new file mode 100644 index 000000000..7cab1e991 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/spi.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna <padma.v@samsung.com> + * + * 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 __ASM_ARCH_EXYNOS_COMMON_SPI_H_ +#define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ + +#ifndef __ASSEMBLY__ + +/* SPI peripheral register map; padded to 64KB */ +struct exynos_spi { +	unsigned int		ch_cfg;		/* 0x00 */ +	unsigned char		reserved0[4]; +	unsigned int		mode_cfg;	/* 0x08 */ +	unsigned int		cs_reg;		/* 0x0c */ +	unsigned char		reserved1[4]; +	unsigned int		spi_sts;	/* 0x14 */ +	unsigned int		tx_data;	/* 0x18 */ +	unsigned int		rx_data;	/* 0x1c */ +	unsigned int		pkt_cnt;	/* 0x20 */ +	unsigned char		reserved2[4]; +	unsigned char		reserved3[4]; +	unsigned int		fb_clk;		/* 0x2c */ +	unsigned char		padding[0xffd0]; +}; + +#define EXYNOS_SPI_MAX_FREQ	50000000 + +#define SPI_TIMEOUT_MS		10 + +/* SPI_CHCFG */ +#define SPI_CH_HS_EN		(1 << 6) +#define SPI_CH_RST		(1 << 5) +#define SPI_SLAVE_MODE		(1 << 4) +#define SPI_CH_CPOL_L		(1 << 3) +#define SPI_CH_CPHA_B		(1 << 2) +#define SPI_RX_CH_ON		(1 << 1) +#define SPI_TX_CH_ON		(1 << 0) + +/* SPI_MODECFG */ +#define SPI_MODE_CH_WIDTH_WORD	(0x2 << 29) +#define SPI_MODE_BUS_WIDTH_WORD	(0x2 << 17) + +/* SPI_CSREG */ +#define SPI_SLAVE_SIG_INACT	(1 << 0) + +/* SPI_STS */ +#define SPI_ST_TX_DONE		(1 << 25) +#define SPI_FIFO_LVL_MASK	0x1ff +#define SPI_TX_LVL_OFFSET	6 +#define SPI_RX_LVL_OFFSET	15 + +/* Feedback Delay */ +#define SPI_CLK_BYPASS		(0 << 0) +#define SPI_FB_DELAY_90		(1 << 0) +#define SPI_FB_DELAY_180	(2 << 0) +#define SPI_FB_DELAY_270	(3 << 0) + +/* Packet Count */ +#define SPI_PACKET_CNT_EN	(1 << 16) + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/arch/arm/include/asm/arch-mxs/clock.h b/arch/arm/include/asm/arch-mxs/clock.h index 1700fe391..3d39ef235 100644 --- a/arch/arm/include/asm/arch-mxs/clock.h +++ b/arch/arm/include/asm/arch-mxs/clock.h @@ -35,6 +35,7 @@ enum mxc_clock {  	MXC_SSP1_CLK,  	MXC_SSP2_CLK,  	MXC_SSP3_CLK, +	MXC_XTAL_CLK,  };  enum mxs_ioclock { diff --git a/arch/arm/include/asm/arch-s5pc1xx/gpio.h b/arch/arm/include/asm/arch-s5pc1xx/gpio.h index 76b901b39..00e498d83 100644 --- a/arch/arm/include/asm/arch-s5pc1xx/gpio.h +++ b/arch/arm/include/asm/arch-s5pc1xx/gpio.h @@ -143,7 +143,12 @@ static inline unsigned int s5p_gpio_base(int nr)  	return S5PC110_GPIO_BASE;  } -#define s5pc110_gpio_get_nr(bank, pin) \ +static inline unsigned int s5p_gpio_part_max(int nr) +{ +	return 0; +} + +#define s5pc110_gpio_get_nr(bank, pin)	  \  	((((((unsigned int)&(((struct s5pc110_gpio *)S5PC110_GPIO_BASE)->bank))\  	    - S5PC110_GPIO_BASE) / sizeof(struct s5p_gpio_bank)) \  	  * GPIO_PER_BANK) + pin) diff --git a/arch/arm/include/asm/arch-tegra20/dc.h b/arch/arm/include/asm/arch-tegra20/dc.h new file mode 100644 index 000000000..37934e1c6 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra20/dc.h @@ -0,0 +1,545 @@ +/* + *  (C) Copyright 2010 + *  NVIDIA Corporation <www.nvidia.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 __ASM_ARCH_TEGRA_DC_H +#define __ASM_ARCH_TEGRA_DC_H + +/* Register definitions for the Tegra display controller */ + +/* CMD register 0x000 ~ 0x43 */ +struct dc_cmd_reg { +	/* Address 0x000 ~ 0x002 */ +	uint gen_incr_syncpt;		/* _CMD_GENERAL_INCR_SYNCPT_0 */ +	uint gen_incr_syncpt_ctrl;	/* _CMD_GENERAL_INCR_SYNCPT_CNTRL_0 */ +	uint gen_incr_syncpt_err;	/* _CMD_GENERAL_INCR_SYNCPT_ERROR_0 */ + +	uint reserved0[5];		/* reserved_0[5] */ + +	/* Address 0x008 ~ 0x00a */ +	uint win_a_incr_syncpt;		/* _CMD_WIN_A_INCR_SYNCPT_0 */ +	uint win_a_incr_syncpt_ctrl;	/* _CMD_WIN_A_INCR_SYNCPT_CNTRL_0 */ +	uint win_a_incr_syncpt_err;	/* _CMD_WIN_A_INCR_SYNCPT_ERROR_0 */ + +	uint reserved1[5];		/* reserved_1[5] */ + +	/* Address 0x010 ~ 0x012 */ +	uint win_b_incr_syncpt;		/* _CMD_WIN_B_INCR_SYNCPT_0 */ +	uint win_b_incr_syncpt_ctrl;	/* _CMD_WIN_B_INCR_SYNCPT_CNTRL_0 */ +	uint win_b_incr_syncpt_err;	/* _CMD_WIN_B_INCR_SYNCPT_ERROR_0 */ + +	uint reserved2[5];		/* reserved_2[5] */ + +	/* Address 0x018 ~ 0x01a */ +	uint win_c_incr_syncpt;		/* _CMD_WIN_C_INCR_SYNCPT_0 */ +	uint win_c_incr_syncpt_ctrl;	/* _CMD_WIN_C_INCR_SYNCPT_CNTRL_0 */ +	uint win_c_incr_syncpt_err;	/* _CMD_WIN_C_INCR_SYNCPT_ERROR_0 */ + +	uint reserved3[13];		/* reserved_3[13] */ + +	/* Address 0x028 */ +	uint cont_syncpt_vsync;		/* _CMD_CONT_SYNCPT_VSYNC_0 */ + +	uint reserved4[7];		/* reserved_4[7] */ + +	/* Address 0x030 ~ 0x033 */ +	uint ctxsw;			/* _CMD_CTXSW_0 */ +	uint disp_cmd_opt0;		/* _CMD_DISPLAY_COMMAND_OPTION0_0 */ +	uint disp_cmd;			/* _CMD_DISPLAY_COMMAND_0 */ +	uint sig_raise;			/* _CMD_SIGNAL_RAISE_0 */ + +	uint reserved5[2];		/* reserved_0[2] */ + +	/* Address 0x036 ~ 0x03e */ +	uint disp_pow_ctrl;		/* _CMD_DISPLAY_POWER_CONTROL_0 */ +	uint int_stat;			/* _CMD_INT_STATUS_0 */ +	uint int_mask;			/* _CMD_INT_MASK_0 */ +	uint int_enb;			/* _CMD_INT_ENABLE_0 */ +	uint int_type;			/* _CMD_INT_TYPE_0 */ +	uint int_polarity;		/* _CMD_INT_POLARITY_0 */ +	uint sig_raise1;		/* _CMD_SIGNAL_RAISE1_0 */ +	uint sig_raise2;		/* _CMD_SIGNAL_RAISE2_0 */ +	uint sig_raise3;		/* _CMD_SIGNAL_RAISE3_0 */ + +	uint reserved6;			/* reserved_6 */ + +	/* Address 0x040 ~ 0x043 */ +	uint state_access;		/* _CMD_STATE_ACCESS_0 */ +	uint state_ctrl;		/* _CMD_STATE_CONTROL_0 */ +	uint disp_win_header;		/* _CMD_DISPLAY_WINDOW_HEADER_0 */ +	uint reg_act_ctrl;		/* _CMD_REG_ACT_CONTROL_0 */ +}; + +enum { +	PIN_REG_COUNT		= 4, +	PIN_OUTPUT_SEL_COUNT	= 7, +}; + +/* COM register 0x300 ~ 0x329 */ +struct dc_com_reg { +	/* Address 0x300 ~ 0x301 */ +	uint crc_ctrl;			/* _COM_CRC_CONTROL_0 */ +	uint crc_checksum;		/* _COM_CRC_CHECKSUM_0 */ + +	/* _COM_PIN_OUTPUT_ENABLE0/1/2/3_0: Address 0x302 ~ 0x305 */ +	uint pin_output_enb[PIN_REG_COUNT]; + +	/* _COM_PIN_OUTPUT_POLARITY0/1/2/3_0: Address 0x306 ~ 0x309 */ +	uint pin_output_polarity[PIN_REG_COUNT]; + +	/* _COM_PIN_OUTPUT_DATA0/1/2/3_0: Address 0x30a ~ 0x30d */ +	uint pin_output_data[PIN_REG_COUNT]; + +	/* _COM_PIN_INPUT_ENABLE0_0: Address 0x30e ~ 0x311 */ +	uint pin_input_enb[PIN_REG_COUNT]; + +	/* Address 0x312 ~ 0x313 */ +	uint pin_input_data0;		/* _COM_PIN_INPUT_DATA0_0 */ +	uint pin_input_data1;		/* _COM_PIN_INPUT_DATA1_0 */ + +	/* _COM_PIN_OUTPUT_SELECT0/1/2/3/4/5/6_0: Address 0x314 ~ 0x31a */ +	uint pin_output_sel[PIN_OUTPUT_SEL_COUNT]; + +	/* Address 0x31b ~ 0x329 */ +	uint pin_misc_ctrl;		/* _COM_PIN_MISC_CONTROL_0 */ +	uint pm0_ctrl;			/* _COM_PM0_CONTROL_0 */ +	uint pm0_duty_cycle;		/* _COM_PM0_DUTY_CYCLE_0 */ +	uint pm1_ctrl;			/* _COM_PM1_CONTROL_0 */ +	uint pm1_duty_cycle;		/* _COM_PM1_DUTY_CYCLE_0 */ +	uint spi_ctrl;			/* _COM_SPI_CONTROL_0 */ +	uint spi_start_byte;		/* _COM_SPI_START_BYTE_0 */ +	uint hspi_wr_data_ab;		/* _COM_HSPI_WRITE_DATA_AB_0 */ +	uint hspi_wr_data_cd;		/* _COM_HSPI_WRITE_DATA_CD */ +	uint hspi_cs_dc;		/* _COM_HSPI_CS_DC_0 */ +	uint scratch_reg_a;		/* _COM_SCRATCH_REGISTER_A_0 */ +	uint scratch_reg_b;		/* _COM_SCRATCH_REGISTER_B_0 */ +	uint gpio_ctrl;			/* _COM_GPIO_CTRL_0 */ +	uint gpio_debounce_cnt;		/* _COM_GPIO_DEBOUNCE_COUNTER_0 */ +	uint crc_checksum_latched;	/* _COM_CRC_CHECKSUM_LATCHED_0 */ +}; + +enum dc_disp_h_pulse_pos { +	H_PULSE0_POSITION_A, +	H_PULSE0_POSITION_B, +	H_PULSE0_POSITION_C, +	H_PULSE0_POSITION_D, +	H_PULSE0_POSITION_COUNT, +}; + +struct _disp_h_pulse { +	/* _DISP_H_PULSE0/1/2_CONTROL_0 */ +	uint h_pulse_ctrl; +	/* _DISP_H_PULSE0/1/2_POSITION_A/B/C/D_0 */ +	uint h_pulse_pos[H_PULSE0_POSITION_COUNT]; +}; + +enum dc_disp_v_pulse_pos { +	V_PULSE0_POSITION_A, +	V_PULSE0_POSITION_B, +	V_PULSE0_POSITION_C, +	V_PULSE0_POSITION_COUNT, +}; + +struct _disp_v_pulse0 { +	/* _DISP_H_PULSE0/1_CONTROL_0 */ +	uint v_pulse_ctrl; +	/* _DISP_H_PULSE0/1_POSITION_A/B/C_0 */ +	uint v_pulse_pos[V_PULSE0_POSITION_COUNT]; +}; + +struct _disp_v_pulse2 { +	/* _DISP_H_PULSE2/3_CONTROL_0 */ +	uint v_pulse_ctrl; +	/* _DISP_H_PULSE2/3_POSITION_A_0 */ +	uint v_pulse_pos_a; +}; + +enum dc_disp_h_pulse_reg { +	H_PULSE0, +	H_PULSE1, +	H_PULSE2, +	H_PULSE_COUNT, +}; + +enum dc_disp_pp_select { +	PP_SELECT_A, +	PP_SELECT_B, +	PP_SELECT_C, +	PP_SELECT_D, +	PP_SELECT_COUNT, +}; + +/* DISP register 0x400 ~ 0x4c1 */ +struct dc_disp_reg { +	/* Address 0x400 ~ 0x40a */ +	uint disp_signal_opt0;		/* _DISP_DISP_SIGNAL_OPTIONS0_0 */ +	uint disp_signal_opt1;		/* _DISP_DISP_SIGNAL_OPTIONS1_0 */ +	uint disp_win_opt;		/* _DISP_DISP_WIN_OPTIONS_0 */ +	uint mem_high_pri;		/* _DISP_MEM_HIGH_PRIORITY_0 */ +	uint mem_high_pri_timer;	/* _DISP_MEM_HIGH_PRIORITY_TIMER_0 */ +	uint disp_timing_opt;		/* _DISP_DISP_TIMING_OPTIONS_0 */ +	uint ref_to_sync;		/* _DISP_REF_TO_SYNC_0 */ +	uint sync_width;		/* _DISP_SYNC_WIDTH_0 */ +	uint back_porch;		/* _DISP_BACK_PORCH_0 */ +	uint disp_active;		/* _DISP_DISP_ACTIVE_0 */ +	uint front_porch;		/* _DISP_FRONT_PORCH_0 */ + +	/* Address 0x40b ~ 0x419: _DISP_H_PULSE0/1/2_  */ +	struct _disp_h_pulse h_pulse[H_PULSE_COUNT]; + +	/* Address 0x41a ~ 0x421 */ +	struct _disp_v_pulse0 v_pulse0;	/* _DISP_V_PULSE0_ */ +	struct _disp_v_pulse0 v_pulse1;	/* _DISP_V_PULSE1_ */ + +	/* Address 0x422 ~ 0x425 */ +	struct _disp_v_pulse2 v_pulse3;	/* _DISP_V_PULSE2_ */ +	struct _disp_v_pulse2 v_pulse4;	/* _DISP_V_PULSE3_ */ + +	/* Address 0x426 ~ 0x429 */ +	uint m0_ctrl;			/* _DISP_M0_CONTROL_0 */ +	uint m1_ctrl;			/* _DISP_M1_CONTROL_0 */ +	uint di_ctrl;			/* _DISP_DI_CONTROL_0 */ +	uint pp_ctrl;			/* _DISP_PP_CONTROL_0 */ + +	/* Address 0x42a ~ 0x42d: _DISP_PP_SELECT_A/B/C/D_0 */ +	uint pp_select[PP_SELECT_COUNT]; + +	/* Address 0x42e ~ 0x435 */ +	uint disp_clk_ctrl;		/* _DISP_DISP_CLOCK_CONTROL_0 */ +	uint disp_interface_ctrl;	/* _DISP_DISP_INTERFACE_CONTROL_0 */ +	uint disp_color_ctrl;		/* _DISP_DISP_COLOR_CONTROL_0 */ +	uint shift_clk_opt;		/* _DISP_SHIFT_CLOCK_OPTIONS_0 */ +	uint data_enable_opt;		/* _DISP_DATA_ENABLE_OPTIONS_0 */ +	uint serial_interface_opt;	/* _DISP_SERIAL_INTERFACE_OPTIONS_0 */ +	uint lcd_spi_opt;		/* _DISP_LCD_SPI_OPTIONS_0 */ +	uint border_color;		/* _DISP_BORDER_COLOR_0 */ + +	/* Address 0x436 ~ 0x439 */ +	uint color_key0_lower;		/* _DISP_COLOR_KEY0_LOWER_0 */ +	uint color_key0_upper;		/* _DISP_COLOR_KEY0_UPPER_0 */ +	uint color_key1_lower;		/* _DISP_COLOR_KEY1_LOWER_0 */ +	uint color_key1_upper;		/* _DISP_COLOR_KEY1_UPPER_0 */ + +	uint reserved0[2];		/* reserved_0[2] */ + +	/* Address 0x43c ~ 0x442 */ +	uint cursor_foreground;		/* _DISP_CURSOR_FOREGROUND_0 */ +	uint cursor_background;		/* _DISP_CURSOR_BACKGROUND_0 */ +	uint cursor_start_addr;		/* _DISP_CURSOR_START_ADDR_0 */ +	uint cursor_start_addr_ns;	/* _DISP_CURSOR_START_ADDR_NS_0 */ +	uint cursor_pos;		/* _DISP_CURSOR_POSITION_0 */ +	uint cursor_pos_ns;		/* _DISP_CURSOR_POSITION_NS_0 */ +	uint seq_ctrl;			/* _DISP_INIT_SEQ_CONTROL_0 */ + +	/* Address 0x442 ~ 0x446 */ +	uint spi_init_seq_data_a;	/* _DISP_SPI_INIT_SEQ_DATA_A_0 */ +	uint spi_init_seq_data_b;	/* _DISP_SPI_INIT_SEQ_DATA_B_0 */ +	uint spi_init_seq_data_c;	/* _DISP_SPI_INIT_SEQ_DATA_C_0 */ +	uint spi_init_seq_data_d;	/* _DISP_SPI_INIT_SEQ_DATA_D_0 */ + +	uint reserved1[0x39];		/* reserved1[0x39], */ + +	/* Address 0x480 ~ 0x484 */ +	uint dc_mccif_fifoctrl;		/* _DISP_DC_MCCIF_FIFOCTRL_0 */ +	uint mccif_disp0a_hyst;		/* _DISP_MCCIF_DISPLAY0A_HYST_0 */ +	uint mccif_disp0b_hyst;		/* _DISP_MCCIF_DISPLAY0B_HYST_0 */ +	uint mccif_disp0c_hyst;		/* _DISP_MCCIF_DISPLAY0C_HYST_0 */ +	uint mccif_disp1b_hyst;		/* _DISP_MCCIF_DISPLAY1B_HYST_0 */ + +	uint reserved2[0x3b];		/* reserved2[0x3b] */ + +	/* Address 0x4c0 ~ 0x4c1 */ +	uint dac_crt_ctrl;		/* _DISP_DAC_CRT_CTRL_0 */ +	uint disp_misc_ctrl;		/* _DISP_DISP_MISC_CONTROL_0 */ +}; + +enum dc_winc_filter_p { +	WINC_FILTER_COUNT	= 0x10, +}; + +/* Window A/B/C register 0x500 ~ 0x628 */ +struct dc_winc_reg { + +	/* Address 0x500 */ +	uint color_palette;		/* _WINC_COLOR_PALETTE_0 */ + +	uint reserved0[0xff];		/* reserved_0[0xff] */ + +	/* Address 0x600 */ +	uint palette_color_ext;		/* _WINC_PALETTE_COLOR_EXT_0 */ + +	/* _WINC_H_FILTER_P00~0F_0 */ +	/* Address 0x601 ~ 0x610 */ +	uint h_filter_p[WINC_FILTER_COUNT]; + +	/* Address 0x611 ~ 0x618 */ +	uint csc_yof;			/* _WINC_CSC_YOF_0 */ +	uint csc_kyrgb;			/* _WINC_CSC_KYRGB_0 */ +	uint csc_kur;			/* _WINC_CSC_KUR_0 */ +	uint csc_kvr;			/* _WINC_CSC_KVR_0 */ +	uint csc_kug;			/* _WINC_CSC_KUG_0 */ +	uint csc_kvg;			/* _WINC_CSC_KVG_0 */ +	uint csc_kub;			/* _WINC_CSC_KUB_0 */ +	uint csc_kvb;			/* _WINC_CSC_KVB_0 */ + +	/* Address 0x619 ~ 0x628: _WINC_V_FILTER_P00~0F_0 */ +	uint v_filter_p[WINC_FILTER_COUNT]; +}; + +/* WIN A/B/C Register 0x700 ~ 0x714*/ +struct dc_win_reg { +	/* Address 0x700 ~ 0x714 */ +	uint win_opt;			/* _WIN_WIN_OPTIONS_0 */ +	uint byte_swap;			/* _WIN_BYTE_SWAP_0 */ +	uint buffer_ctrl;		/* _WIN_BUFFER_CONTROL_0 */ +	uint color_depth;		/* _WIN_COLOR_DEPTH_0 */ +	uint pos;			/* _WIN_POSITION_0 */ +	uint size;			/* _WIN_SIZE_0 */ +	uint prescaled_size;		/* _WIN_PRESCALED_SIZE_0 */ +	uint h_initial_dda;		/* _WIN_H_INITIAL_DDA_0 */ +	uint v_initial_dda;		/* _WIN_V_INITIAL_DDA_0 */ +	uint dda_increment;		/* _WIN_DDA_INCREMENT_0 */ +	uint line_stride;		/* _WIN_LINE_STRIDE_0 */ +	uint buf_stride;		/* _WIN_BUF_STRIDE_0 */ +	uint uv_buf_stride;		/* _WIN_UV_BUF_STRIDE_0 */ +	uint buffer_addr_mode;		/* _WIN_BUFFER_ADDR_MODE_0 */ +	uint dv_ctrl;			/* _WIN_DV_CONTROL_0 */ +	uint blend_nokey;		/* _WIN_BLEND_NOKEY_0 */ +	uint blend_1win;		/* _WIN_BLEND_1WIN_0 */ +	uint blend_2win_x;		/* _WIN_BLEND_2WIN_X_0 */ +	uint blend_2win_y;		/* _WIN_BLEND_2WIN_Y_0 */ +	uint blend_3win_xy;		/* _WIN_BLEND_3WIN_XY_0 */ +	uint hp_fetch_ctrl;		/* _WIN_HP_FETCH_CONTROL_0 */ +}; + +/* WINBUF A/B/C Register 0x800 ~ 0x80a */ +struct dc_winbuf_reg { +	/* Address 0x800 ~ 0x80a */ +	uint start_addr;		/* _WINBUF_START_ADDR_0 */ +	uint start_addr_ns;		/* _WINBUF_START_ADDR_NS_0 */ +	uint start_addr_u;		/* _WINBUF_START_ADDR_U_0 */ +	uint start_addr_u_ns;		/* _WINBUF_START_ADDR_U_NS_0 */ +	uint start_addr_v;		/* _WINBUF_START_ADDR_V_0 */ +	uint start_addr_v_ns;		/* _WINBUF_START_ADDR_V_NS_0 */ +	uint addr_h_offset;		/* _WINBUF_ADDR_H_OFFSET_0 */ +	uint addr_h_offset_ns;		/* _WINBUF_ADDR_H_OFFSET_NS_0 */ +	uint addr_v_offset;		/* _WINBUF_ADDR_V_OFFSET_0 */ +	uint addr_v_offset_ns;		/* _WINBUF_ADDR_V_OFFSET_NS_0 */ +	uint uflow_status;		/* _WINBUF_UFLOW_STATUS_0 */ +}; + +/* Display Controller (DC_) regs */ +struct dc_ctlr { +	struct dc_cmd_reg cmd;		/* CMD register 0x000 ~ 0x43 */ +	uint reserved0[0x2bc]; + +	struct dc_com_reg com;		/* COM register 0x300 ~ 0x329 */ +	uint reserved1[0xd6]; + +	struct dc_disp_reg disp;	/* DISP register 0x400 ~ 0x4c1 */ +	uint reserved2[0x3e]; + +	struct dc_winc_reg winc;	/* Window A/B/C 0x500 ~ 0x628 */ +	uint reserved3[0xd7]; + +	struct dc_win_reg win;		/* WIN A/B/C 0x700 ~ 0x714*/ +	uint reserved4[0xeb]; + +	struct dc_winbuf_reg winbuf;	/* WINBUF A/B/C 0x800 ~ 0x80a */ +}; + +#define BIT(pos)	(1U << pos) + +/* DC_CMD_DISPLAY_COMMAND 0x032 */ +#define CTRL_MODE_SHIFT		5 +#define CTRL_MODE_MASK		(0x3 << CTRL_MODE_SHIFT) +enum { +	CTRL_MODE_STOP, +	CTRL_MODE_C_DISPLAY, +	CTRL_MODE_NC_DISPLAY, +}; + +/* _WIN_COLOR_DEPTH_0 */ +enum win_color_depth_id { +	COLOR_DEPTH_P1, +	COLOR_DEPTH_P2, +	COLOR_DEPTH_P4, +	COLOR_DEPTH_P8, +	COLOR_DEPTH_B4G4R4A4, +	COLOR_DEPTH_B5G5R5A, +	COLOR_DEPTH_B5G6R5, +	COLOR_DEPTH_AB5G5R5, +	COLOR_DEPTH_B8G8R8A8 = 12, +	COLOR_DEPTH_R8G8B8A8, +	COLOR_DEPTH_B6x2G6x2R6x2A8, +	COLOR_DEPTH_R6x2G6x2B6x2A8, +	COLOR_DEPTH_YCbCr422, +	COLOR_DEPTH_YUV422, +	COLOR_DEPTH_YCbCr420P, +	COLOR_DEPTH_YUV420P, +	COLOR_DEPTH_YCbCr422P, +	COLOR_DEPTH_YUV422P, +	COLOR_DEPTH_YCbCr422R, +	COLOR_DEPTH_YUV422R, +	COLOR_DEPTH_YCbCr422RA, +	COLOR_DEPTH_YUV422RA, +}; + +/* DC_CMD_DISPLAY_POWER_CONTROL 0x036 */ +#define PW0_ENABLE		BIT(0) +#define PW1_ENABLE		BIT(2) +#define PW2_ENABLE		BIT(4) +#define PW3_ENABLE		BIT(6) +#define PW4_ENABLE		BIT(8) +#define PM0_ENABLE		BIT(16) +#define PM1_ENABLE		BIT(18) +#define SPI_ENABLE		BIT(24) +#define HSPI_ENABLE		BIT(25) + +/* DC_CMD_STATE_CONTROL 0x041 */ +#define GENERAL_ACT_REQ		BIT(0) +#define WIN_A_ACT_REQ		BIT(1) +#define WIN_B_ACT_REQ		BIT(2) +#define WIN_C_ACT_REQ		BIT(3) +#define GENERAL_UPDATE		BIT(8) +#define WIN_A_UPDATE		BIT(9) +#define WIN_B_UPDATE		BIT(10) +#define WIN_C_UPDATE		BIT(11) + +/* DC_CMD_DISPLAY_WINDOW_HEADER 0x042 */ +#define WINDOW_A_SELECT		BIT(4) +#define WINDOW_B_SELECT		BIT(5) +#define WINDOW_C_SELECT		BIT(6) + +/* DC_DISP_DISP_CLOCK_CONTROL 0x42e */ +#define SHIFT_CLK_DIVIDER_SHIFT	0 +#define SHIFT_CLK_DIVIDER_MASK	(0xff << SHIFT_CLK_DIVIDER_SHIFT) +#define	PIXEL_CLK_DIVIDER_SHIFT	8 +#define	PIXEL_CLK_DIVIDER_MSK	(0xf << PIXEL_CLK_DIVIDER_SHIFT) +enum { +	PIXEL_CLK_DIVIDER_PCD1, +	PIXEL_CLK_DIVIDER_PCD1H, +	PIXEL_CLK_DIVIDER_PCD2, +	PIXEL_CLK_DIVIDER_PCD3, +	PIXEL_CLK_DIVIDER_PCD4, +	PIXEL_CLK_DIVIDER_PCD6, +	PIXEL_CLK_DIVIDER_PCD8, +	PIXEL_CLK_DIVIDER_PCD9, +	PIXEL_CLK_DIVIDER_PCD12, +	PIXEL_CLK_DIVIDER_PCD16, +	PIXEL_CLK_DIVIDER_PCD18, +	PIXEL_CLK_DIVIDER_PCD24, +	PIXEL_CLK_DIVIDER_PCD13, +}; + +/* DC_DISP_DISP_INTERFACE_CONTROL 0x42f */ +#define DATA_FORMAT_SHIFT	0 +#define DATA_FORMAT_MASK	(0xf << DATA_FORMAT_SHIFT) +enum { +	DATA_FORMAT_DF1P1C, +	DATA_FORMAT_DF1P2C24B, +	DATA_FORMAT_DF1P2C18B, +	DATA_FORMAT_DF1P2C16B, +	DATA_FORMAT_DF2S, +	DATA_FORMAT_DF3S, +	DATA_FORMAT_DFSPI, +	DATA_FORMAT_DF1P3C24B, +	DATA_FORMAT_DF1P3C18B, +}; +#define DATA_ALIGNMENT_SHIFT	8 +enum { +	DATA_ALIGNMENT_MSB, +	DATA_ALIGNMENT_LSB, +}; +#define DATA_ORDER_SHIFT	9 +enum { +	DATA_ORDER_RED_BLUE, +	DATA_ORDER_BLUE_RED, +}; + +/* DC_DISP_DATA_ENABLE_OPTIONS 0x432 */ +#define DE_SELECT_SHIFT		0 +#define DE_SELECT_MASK		(0x3 << DE_SELECT_SHIFT) +#define DE_SELECT_ACTIVE_BLANK	0x0 +#define DE_SELECT_ACTIVE	0x1 +#define DE_SELECT_ACTIVE_IS	0x2 +#define DE_CONTROL_SHIFT	2 +#define DE_CONTROL_MASK		(0x7 << DE_CONTROL_SHIFT) +enum { +	DE_CONTROL_ONECLK, +	DE_CONTROL_NORMAL, +	DE_CONTROL_EARLY_EXT, +	DE_CONTROL_EARLY, +	DE_CONTROL_ACTIVE_BLANK, +}; + +/* DC_WIN_WIN_OPTIONS 0x700 */ +#define H_DIRECTION		BIT(0) +enum { +	H_DIRECTION_INCREMENT, +	H_DIRECTION_DECREMENT, +}; +#define V_DIRECTION		BIT(2) +enum { +	V_DIRECTION_INCREMENT, +	V_DIRECTION_DECREMENT, +}; +#define COLOR_EXPAND		BIT(6) +#define CP_ENABLE		BIT(16) +#define DV_ENABLE		BIT(20) +#define WIN_ENABLE		BIT(30) + +/* DC_WIN_BYTE_SWAP 0x701 */ +#define BYTE_SWAP_SHIFT		0 +#define BYTE_SWAP_MASK		(3 << BYTE_SWAP_SHIFT) +enum { +	BYTE_SWAP_NOSWAP, +	BYTE_SWAP_SWAP2, +	BYTE_SWAP_SWAP4, +	BYTE_SWAP_SWAP4HW +}; + +/* DC_WIN_POSITION 0x704 */ +#define H_POSITION_SHIFT	0 +#define H_POSITION_MASK		(0x1FFF << H_POSITION_SHIFT) +#define V_POSITION_SHIFT	16 +#define V_POSITION_MASK		(0x1FFF << V_POSITION_SHIFT) + +/* DC_WIN_SIZE 0x705 */ +#define H_SIZE_SHIFT		0 +#define H_SIZE_MASK		(0x1FFF << H_SIZE_SHIFT) +#define V_SIZE_SHIFT		16 +#define V_SIZE_MASK		(0x1FFF << V_SIZE_SHIFT) + +/* DC_WIN_PRESCALED_SIZE 0x706 */ +#define H_PRESCALED_SIZE_SHIFT	0 +#define H_PRESCALED_SIZE_MASK	(0x7FFF << H_PRESCALED_SIZE) +#define V_PRESCALED_SIZE_SHIFT	16 +#define V_PRESCALED_SIZE_MASK	(0x1FFF << V_PRESCALED_SIZE) + +/* DC_WIN_DDA_INCREMENT 0x709 */ +#define H_DDA_INC_SHIFT		0 +#define H_DDA_INC_MASK		(0xFFFF << H_DDA_INC_SHIFT) +#define V_DDA_INC_SHIFT		16 +#define V_DDA_INC_MASK		(0xFFFF << V_DDA_INC_SHIFT) + +#endif /* __ASM_ARCH_TEGRA_DC_H */ diff --git a/arch/arm/include/asm/arch-tegra20/display.h b/arch/arm/include/asm/arch-tegra20/display.h new file mode 100644 index 000000000..c8709590c --- /dev/null +++ b/arch/arm/include/asm/arch-tegra20/display.h @@ -0,0 +1,152 @@ +/* + *  (C) Copyright 2010 + *  NVIDIA Corporation <www.nvidia.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 __ASM_ARCH_TEGRA_DISPLAY_H +#define __ASM_ARCH_TEGRA_DISPLAY_H + +#include <asm/arch/dc.h> +#include <fdtdec.h> + +/* This holds information about a window which can be displayed */ +struct disp_ctl_win { +	enum win_color_depth_id fmt;	/* Color depth/format */ +	unsigned	bpp;		/* Bits per pixel */ +	phys_addr_t	phys_addr;	/* Physical address in memory */ +	unsigned	x;		/* Horizontal address offset (bytes) */ +	unsigned	y;		/* Veritical address offset (bytes) */ +	unsigned	w;		/* Width of source window */ +	unsigned	h;		/* Height of source window */ +	unsigned	stride;		/* Number of bytes per line */ +	unsigned	out_x;		/* Left edge of output window (col) */ +	unsigned	out_y;		/* Top edge of output window (row) */ +	unsigned	out_w;		/* Width of output window in pixels */ +	unsigned	out_h;		/* Height of output window in pixels */ +}; + +#define FDT_LCD_TIMINGS	4 + +enum { +	FDT_LCD_TIMING_REF_TO_SYNC, +	FDT_LCD_TIMING_SYNC_WIDTH, +	FDT_LCD_TIMING_BACK_PORCH, +	FDT_LCD_TIMING_FRONT_PORCH, + +	FDT_LCD_TIMING_COUNT, +}; + +enum lcd_cache_t { +	FDT_LCD_CACHE_OFF		= 0, +	FDT_LCD_CACHE_WRITE_THROUGH	= 1 << 0, +	FDT_LCD_CACHE_WRITE_BACK	= 1 << 1, +	FDT_LCD_CACHE_FLUSH		= 1 << 2, +	FDT_LCD_CACHE_WRITE_BACK_FLUSH	= FDT_LCD_CACHE_WRITE_BACK | +						FDT_LCD_CACHE_FLUSH, +}; + +/* Information about the display controller */ +struct fdt_disp_config { +	int valid;			/* config is valid */ +	int width;			/* width in pixels */ +	int height;			/* height in pixels */ +	int bpp;			/* number of bits per pixel */ + +	/* +	 * log2 of number of bpp, in general, unless it bpp is 24 in which +	 * case this field holds 24 also! This is a U-Boot thing. +	 */ +	int log2_bpp; +	struct disp_ctlr *disp;		/* Display controller to use */ +	fdt_addr_t frame_buffer;	/* Address of frame buffer */ +	unsigned pixel_clock;		/* Pixel clock in Hz */ +	uint horiz_timing[FDT_LCD_TIMING_COUNT];	/* Horizontal timing */ +	uint vert_timing[FDT_LCD_TIMING_COUNT];		/* Vertical timing */ +	int panel_node;			/* node offset of panel information */ +}; + +/* Information about the LCD panel */ +struct fdt_panel_config { +	int pwm_channel;		/* PWM channel to use for backlight */ +	enum lcd_cache_t cache_type; + +	struct fdt_gpio_state backlight_en;	/* GPIO for backlight enable */ +	struct fdt_gpio_state lvds_shutdown;	/* GPIO for lvds shutdown */ +	struct fdt_gpio_state backlight_vdd;	/* GPIO for backlight vdd */ +	struct fdt_gpio_state panel_vdd;	/* GPIO for panel vdd */ +	/* +	 * Panel required timings +	 * Timing 1: delay between panel_vdd-rise and data-rise +	 * Timing 2: delay between data-rise and backlight_vdd-rise +	 * Timing 3: delay between backlight_vdd and pwm-rise +	 * Timing 4: delay between pwm-rise and backlight_en-rise +	 */ +	uint panel_timings[FDT_LCD_TIMINGS]; +}; + +/** + * Register a new display based on device tree configuration. + * + * The frame buffer can be positioned by U-Boot or overriden by the fdt. + * You should pass in the U-Boot address here, and check the contents of + * struct fdt_disp_config to see what was actually chosen. + * + * @param blob			Device tree blob + * @param default_lcd_base	Default address of LCD frame buffer + * @return 0 if ok, -1 on error (unsupported bits per pixel) + */ +int tegra_display_probe(const void *blob, void *default_lcd_base); + +/** + * Return the current display configuration + * + * @return pointer to display configuration, or NULL if there is no valid + * config + */ +struct fdt_disp_config *tegra_display_get_config(void); + +/** + * Perform the next stage of the LCD init if it is time to do so. + * + * LCD init can be time-consuming because of the number of delays we need + * while waiting for the backlight power supply, etc. This function can + * be called at various times during U-Boot operation to advance the + * initialization of the LCD to the next stage if sufficient time has + * passed since the last stage. It keeps track of what stage it is up to + * and the time that it is permitted to move to the next stage. + * + * The final call should have wait=1 to complete the init. + * + * @param blob	fdt blob containing LCD information + * @param wait	1 to wait until all init is complete, and then return + *		0 to return immediately, potentially doing nothing if it is + *		not yet time for the next init. + */ +int tegra_lcd_check_next_stage(const void *blob, int wait); + +/** + * Set up the maximum LCD size so we can size the frame buffer. + * + * @param blob	fdt blob containing LCD information + */ +void tegra_lcd_early_init(const void *blob); + +#endif /*__ASM_ARCH_TEGRA_DISPLAY_H*/ diff --git a/arch/arm/include/asm/arch-tegra20/pinmux.h b/arch/arm/include/asm/arch-tegra20/pinmux.h index 03fa7ca64..797e158e6 100644 --- a/arch/arm/include/asm/arch-tegra20/pinmux.h +++ b/arch/arm/include/asm/arch-tegra20/pinmux.h @@ -339,7 +339,7 @@ void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd);  void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func);  /* Set the complete configuration for a pin group */ -void pinmux_config_pingroup(struct pingroup_config *config); +void pinmux_config_pingroup(const struct pingroup_config *config);  void pinmux_set_tristate(enum pmux_pingrp pin, int enable); @@ -349,6 +349,6 @@ void pinmux_set_tristate(enum pmux_pingrp pin, int enable);   * @param config	List of config items   * @param len		Number of config items in list   */ -void pinmux_config_table(struct pingroup_config *config, int len); +void pinmux_config_table(const struct pingroup_config *config, int len);  #endif	/* PINMUX_H */ diff --git a/arch/arm/include/asm/arch-tegra20/pwm.h b/arch/arm/include/asm/arch-tegra20/pwm.h new file mode 100644 index 000000000..9e03837cc --- /dev/null +++ b/arch/arm/include/asm/arch-tegra20/pwm.h @@ -0,0 +1,75 @@ +/* + * Tegra pulse width frequency modulator definitions + * + * Copyright (c) 2011 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 __ASM_ARCH_TEGRA_PWM_H +#define __ASM_ARCH_TEGRA_PWM_H + +/* This is a single PWM channel */ +struct pwm_ctlr { +	uint control;		/* Control register */ +	uint reserved[3];	/* Space space */ +}; + +#define PWM_NUM_CHANNELS	4 + +/* PWM_CONTROLLER_PWM_CSR_0/1/2/3_0 */ +#define PWM_ENABLE_SHIFT	31 +#define PWM_ENABLE_MASK	(0x1 << PWM_ENABLE_SHIFT) + +#define PWM_WIDTH_SHIFT	16 +#define PWM_WIDTH_MASK		(0x7FFF << PWM_WIDTH_SHIFT) + +#define PWM_DIVIDER_SHIFT	0 +#define PWM_DIVIDER_MASK	(0x1FFF << PWM_DIVIDER_SHIFT) + +/** + * Program the PWM with the given parameters. + * + * @param channel	PWM channel to update + * @param rate		Clock rate to use for PWM + * @param pulse_width	high pulse width: 0=always low, 1=1/256 pulse high, + *			n = n/256 pulse high + * @param freq_divider	frequency divider value (1 to use rate as is) + */ +void pwm_enable(unsigned channel, int rate, int pulse_width, int freq_divider); + +/** + * Request a pwm channel as referenced by a device tree node. + * + * This channel can then be passed to pwm_enable(). + * + * @param blob		Device tree blob + * @param node		Node containing reference to pwm + * @param prop_name	Property name of pwm reference + * @return channel number, if ok, else -1 + */ +int pwm_request(const void *blob, int node, const char *prop_name); + +/** + * Set up the pwm controller, by looking it up in the fdt. + * + * @return 0 if ok, -1 if the device tree node was not found or invalid. + */ +int pwm_init(const void *blob); + +#endif	/* __ASM_ARCH_TEGRA_PWM_H */ diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 2b28a261b..78ca8e0a6 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -75,6 +75,37 @@ static inline void set_cr(unsigned int val)  	isb();  } +/* options available for data cache on each page */ +enum dcache_option { +	DCACHE_OFF = 0x12, +	DCACHE_WRITETHROUGH = 0x1a, +	DCACHE_WRITEBACK = 0x1e, +}; + +/* Size of an MMU section */ +enum { +	MMU_SECTION_SHIFT	= 20, +	MMU_SECTION_SIZE	= 1 << MMU_SECTION_SHIFT, +}; + +/** + * Change the cache settings for a region. + * + * \param start		start address of memory region to change + * \param size		size of memory region to change + * \param option	dcache option to select + */ +void mmu_set_region_dcache_behaviour(u32 start, int size, +				     enum dcache_option option); + +/** + * Register an update to the page tables, and flush the TLB + * + * \param start		start address of update in page table + * \param stop		stop address of update in page table + */ +void mmu_page_table_flush(unsigned long start, unsigned long stop); +  #endif /* __ASSEMBLY__ */  #define arch_align_stack(x) (x) diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 22a4d9cc0..e0cb6353a 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -540,15 +540,13 @@ void board_init_r(gd_t *id, ulong dest_addr)  	flash_size = flash_init();  	if (flash_size > 0) {  # ifdef CONFIG_SYS_FLASH_CHECKSUM -		char *s = getenv("flashchecksum"); -  		print_size(flash_size, "");  		/*  		 * Compute and print flash CRC if flashchecksum is set to 'y'  		 *  		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  		 */ -		if (s && (*s == 'y')) { +		if (getenv_yesno("flashchecksum") == 1) {  			printf("  CRC: %08X", crc32(0,  				(const unsigned char *) CONFIG_SYS_FLASH_BASE,  				flash_size)); diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index 939de10e0..6edf815d4 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -26,12 +26,6 @@  #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) -#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) -#define CACHE_SETUP	0x1a -#else -#define CACHE_SETUP	0x1e -#endif -  DECLARE_GLOBAL_DATA_PTR;  void __arm_init_before_mmu(void) @@ -50,9 +44,41 @@ static void cp_delay (void)  	asm volatile("" : : : "memory");  } -static inline void dram_bank_mmu_setup(int bank) +void set_section_dcache(int section, enum dcache_option option)  {  	u32 *page_table = (u32 *)gd->tlb_addr; +	u32 value; + +	value = (section << MMU_SECTION_SHIFT) | (3 << 10); +	value |= option; +	page_table[section] = value; +} + +void __mmu_page_table_flush(unsigned long start, unsigned long stop) +{ +	debug("%s: Warning: not implemented\n", __func__); +} + +void mmu_page_table_flush(unsigned long start, unsigned long stop) +	__attribute__((weak, alias("__mmu_page_table_flush"))); + +void mmu_set_region_dcache_behaviour(u32 start, int size, +				     enum dcache_option option) +{ +	u32 *page_table = (u32 *)gd->tlb_addr; +	u32 upto, end; + +	end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT; +	start = start >> MMU_SECTION_SHIFT; +	debug("%s: start=%x, size=%x, option=%d\n", __func__, start, size, +	      option); +	for (upto = start; upto < end; upto++) +		set_section_dcache(upto, option); +	mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]); +} + +static inline void dram_bank_mmu_setup(int bank) +{  	bd_t *bd = gd->bd;  	int	i; @@ -60,21 +86,24 @@ static inline void dram_bank_mmu_setup(int bank)  	for (i = bd->bi_dram[bank].start >> 20;  	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;  	     i++) { -		page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP; +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) +		set_section_dcache(i, DCACHE_WRITETHROUGH); +#else +		set_section_dcache(i, DCACHE_WRITEBACK); +#endif  	}  }  /* to activate the MMU we need to set up virtual memory: use 1M areas */  static inline void mmu_setup(void)  { -	u32 *page_table = (u32 *)gd->tlb_addr;  	int i;  	u32 reg;  	arm_init_before_mmu();  	/* Set up an identity-mapping for all 4GB, rw for everyone */  	for (i = 0; i < 4096; i++) -		page_table[i] = i << 20 | (3 << 10) | 0x12; +		set_section_dcache(i, DCACHE_OFF);  	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {  		dram_bank_mmu_setup(i); @@ -82,7 +111,7 @@ static inline void mmu_setup(void)  	/* Copy the page table address to cp15 */  	asm volatile("mcr p15, 0, %0, c2, c0, 0" -		     : : "r" (page_table) : "memory"); +		     : : "r" (gd->tlb_addr) : "memory");  	/* Set the access control to all-supervisor */  	asm volatile("mcr p15, 0, %0, c3, c0, 0"  		     : : "r" (~0)); diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h index e0773a882..ecf5e56e1 100644 --- a/arch/m68k/include/asm/string.h +++ b/arch/m68k/include/asm/string.h @@ -16,7 +16,7 @@  #endif  extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t);  extern char * strcpy(char *,const char *);  extern char * strncpy(char *,const char *, __kernel_size_t);  extern __kernel_size_t strlen(const char *); diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 02d73fda6..794b8679f 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -462,8 +462,7 @@ void board_init_r (gd_t *id, ulong dest_addr)  		 *  		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  		 */ -		s = getenv ("flashchecksum"); -		if (s && (*s == 'y')) { +		if (getenv_yesno("flashchecksum") == 1) {  			printf ("  CRC: %08X",  					crc32 (0,  						   (const unsigned char *) CONFIG_SYS_FLASH_BASE, diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index efd63cd34..a7c2f7623 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -74,7 +74,6 @@ void board_init_f(ulong not_used)  	gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);  	bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \  						- GENERATED_BD_INFO_SIZE); -	__maybe_unused char *s;  #if defined(CONFIG_CMD_FLASH)  	ulong flash_size = 0;  #endif @@ -143,8 +142,7 @@ void board_init_f(ulong not_used)  		 *  		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  		 */ -		s = getenv ("flashchecksum"); -		if (s && (*s == 'y')) { +		if (getenv_yesno("flashchecksum") == 1) {  			printf ("  CRC: %08X",  				crc32(0, (const u8 *)bd->bi_flashstart,  							flash_size) diff --git a/arch/mips/cpu/mips64/start.S b/arch/mips/cpu/mips64/start.S index 4112de702..2b8d531e7 100644 --- a/arch/mips/cpu/mips64/start.S +++ b/arch/mips/cpu/mips64/start.S @@ -108,7 +108,12 @@ reset:  	mtc0	t0, CP0_CONFIG  #endif -	/* Initialize $gp */ +	/* +	 * Initialize $gp, force 8 byte alignment of bal instruction to forbid +	 * the compiler to put nop's between bal and _gp. This is required to +	 * keep _gp and ra aligned to 8 byte. +	 */ +	.align	3  	bal	1f  	 nop  	.dword	_gp diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index 1c8f4c050..f2dc53356 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -566,7 +566,7 @@ static __inline__ int __test_and_change_bit(int nr, volatile void * addr)   * @nr: bit number to test   * @addr: Address to start counting from   */ -static __inline__ int test_bit(int nr, volatile void *addr) +static __inline__ int test_bit(int nr, const volatile void *addr)  {  	return ((1UL << (nr & 31)) & (((const unsigned int *) addr)[nr >> 5])) != 0;  } diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 7ddd77832..d79e1837d 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -24,6 +24,7 @@  #include <common.h>  #include <command.h>  #include <malloc.h> +#include <serial.h>  #include <stdio_dev.h>  #include <version.h>  #include <net.h> @@ -46,7 +47,7 @@ static char *failed = "*** failed ***\n";   * mips_io_port_base is the begin of the address space to which x86 style   * I/O ports are mapped.   */ -unsigned long mips_io_port_base = -1; +const unsigned long mips_io_port_base = -1;  int __board_early_init_f(void)  { @@ -262,6 +263,8 @@ void board_init_r(gd_t *id, ulong dest_addr)  	monitor_flash_len = (ulong)&uboot_end_data - dest_addr; +	serial_initialize(); +  #if defined(CONFIG_NEEDS_MANUAL_RELOC)  	/*  	 * We have to relocate the command table manually diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c index e1197ac9e..43d483630 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.c +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -46,10 +46,8 @@ u32 get_my_id()   */  int hold_cores_in_reset(int verbose)  { -	const char *s = getenv("mp_holdoff"); -  	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */ -	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) { +	if (getenv_yesno("mp_holdoff") == 1) {  		if (verbose) {  			puts("Secondary cores are being held in reset.\n");  			puts("See 'mp_holdoff' environment variable\n"); diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h index d912a6b5f..036805ede 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -14,7 +14,7 @@  #define __HAVE_ARCH_MEMCHR  extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t);  extern char * strcpy(char *,const char *);  extern char * strncpy(char *,const char *, __kernel_size_t);  extern __kernel_size_t strlen(const char *); diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 1b051e11c..6a7bf4b6c 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -739,16 +739,13 @@ void board_init_r(gd_t *id, ulong dest_addr)  		flash_size = 0;  	} else if ((flash_size = flash_init()) > 0) {  #ifdef CONFIG_SYS_FLASH_CHECKSUM -		char *s; -  		print_size(flash_size, "");  		/*  		 * Compute and print flash CRC if flashchecksum is set to 'y'  		 *  		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  		 */ -		s = getenv("flashchecksum"); -		if (s && (*s == 'y')) { +		if (getenv_yesno("flashchecksum") == 1) {  			printf("  CRC: %08X",  			       crc32(0,  				     (const unsigned char *) @@ -841,9 +838,7 @@ void board_init_r(gd_t *id, ulong dest_addr)  	 * "i2cfast" into account  	 */  	{ -		char *s = getenv("i2cfast"); - -		if (s && ((*s == 'y') || (*s == 'Y'))) { +		if (getenv_yesno("i2cfast") == 1) {  			bd->bi_iic_fast[0] = 1;  			bd->bi_iic_fast[1] = 1;  		} diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h index c6bbc203d..af6faea23 100644 --- a/arch/sparc/include/asm/string.h +++ b/arch/sparc/include/asm/string.h @@ -40,7 +40,7 @@  */  extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t);  extern char *strcpy(char *, const char *);  extern char *strncpy(char *, const char *, __kernel_size_t);  extern __kernel_size_t strlen(const char *); diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 32d025a34..1b5e995b1 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -284,8 +284,7 @@ void board_init_f(ulong bootflag)  		 *  		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX  		 */ -		s = getenv("flashchecksum"); -		if (s && (*s == 'y')) { +		if (getenv_yesno("flashchecksum") == 1) {  			printf("  CRC: %08lX",  			       crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE,  				     flash_size) diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c index 6cae68601..38769e03c 100644 --- a/board/Marvell/db64360/db64360.c +++ b/board/Marvell/db64360/db64360.c @@ -834,15 +834,11 @@ int mem_test_walk (void)  /*********************************************************************/  int testdram (void)  { -	char *s;  	int rundata, runaddress, runwalk; -	s = getenv ("testdramdata"); -	rundata = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramaddress"); -	runaddress = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramwalk"); -	runwalk = (s && (*s == 'y')) ? 1 : 0; +	rundata = getenv_yesno("testdramdata") == 1; +	runaddress = getenv_yesno("testdramaddress") == 1; +	runwalk = getenv_yesno("testdramwalk") == 1;  /*    rundata = 1; */  /*    runaddress = 0; */ diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c index d4f58b321..ddb7ed555 100644 --- a/board/Marvell/db64460/db64460.c +++ b/board/Marvell/db64460/db64460.c @@ -834,15 +834,11 @@ int mem_test_walk (void)  /*********************************************************************/  int testdram (void)  { -	char *s;  	int rundata, runaddress, runwalk; -	s = getenv ("testdramdata"); -	rundata = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramaddress"); -	runaddress = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramwalk"); -	runwalk = (s && (*s == 'y')) ? 1 : 0; +	rundata = getenv_yesno("testdramdata") == 1; +	runaddress = getenv_yesno("testdramaddress") == 1; +	runwalk = getenv_yesno("testdramwalk") == 1;  /*    rundata = 1; */  /*    runaddress = 0; */ diff --git a/board/compal/paz00/paz00.c b/board/compal/paz00/paz00.c index 0725989de..6492d4168 100644 --- a/board/compal/paz00/paz00.c +++ b/board/compal/paz00/paz00.c @@ -61,9 +61,8 @@ int board_mmc_init(bd_t *bd)  	pin_mux_mmc();  	debug("board_mmc_init: init eMMC\n"); -	/* init dev 0, eMMC chip, with 4-bit bus */ -	/* The board has an 8-bit bus, but 8-bit doesn't work yet */ -	tegra_mmc_init(0, 4, -1, -1); +	/* init dev 0, eMMC chip, with 8-bit bus */ +	tegra_mmc_init(0, 8, -1, -1);  	debug("board_mmc_init: init SD slot\n");  	/* init dev 3, SD slot, with 4-bit bus */ diff --git a/board/compulab/dts/tegra20-trimslice.dts b/board/compulab/dts/tegra20-trimslice.dts index db79e7796..4450674a7 100644 --- a/board/compulab/dts/tegra20-trimslice.dts +++ b/board/compulab/dts/tegra20-trimslice.dts @@ -8,6 +8,7 @@  	aliases {  		usb0 = "/usb@c5008000"; +		usb1 = "/usb@c5000000";  	};  	memory { @@ -48,7 +49,7 @@  	};  	usb@c5000000 { -		status = "disabled"; +		nvidia,vbus-gpio = <&gpio 170 0>; /* PV2 */  	};  	usb@c5004000 { diff --git a/board/compulab/trimslice/trimslice.c b/board/compulab/trimslice/trimslice.c index 9ef66fd86..8f4dd09fa 100644 --- a/board/compulab/trimslice/trimslice.c +++ b/board/compulab/trimslice/trimslice.c @@ -34,6 +34,14 @@  #include <mmc.h>  #endif +void pin_mux_usb(void) +{ +	/* +	 * USB1 internal/external mux GPIO, which masquerades as a VBUS GPIO +	 * in the current device tree. +	 */ +	pinmux_tristate_disable(PINGRP_UAC); +}  void pin_mux_spi(void)  { diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c index 98051fb3f..d7deae4a5 100644 --- a/board/esd/cpci750/cpci750.c +++ b/board/esd/cpci750/cpci750.c @@ -953,22 +953,18 @@ int mem_test_walk (void)  /*********************************************************************/  int testdram (void)  { -	char *s;  	int rundata    = 0;  	int runaddress = 0;  	int runwalk    = 0;  #ifdef CONFIG_SYS_DRAM_TEST_DATA -	s = getenv ("testdramdata"); -	rundata = (s && (*s == 'y')) ? 1 : 0; +	rundata = getenv_yesno("testdramdata") == 1;  #endif  #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS -	s = getenv ("testdramaddress"); -	runaddress = (s && (*s == 'y')) ? 1 : 0; +	runaddress = getenv_yesno("testdramaddress") == 1;  #endif  #ifdef CONFIG_SYS_DRAM_TEST_WALK -	s = getenv ("testdramwalk"); -	runwalk = (s && (*s == 'y')) ? 1 : 0; +	runwalk = getenv_yesno("testdramwalk") == 1;  #endif  	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) { diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c index f1ffb7b54..e9a78a303 100644 --- a/board/esd/pmc440/cmd_pmc440.c +++ b/board/esd/pmc440/cmd_pmc440.c @@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));  	envp = (env_t *)nextbase;  	res = (char *)envp->data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c index 77a1e1d3a..64c54d5e8 100644 --- a/board/gw8260/gw8260.c +++ b/board/gw8260/gw8260.c @@ -544,15 +544,11 @@ int mem_test_walk (void)  /*********************************************************************/  int testdram (void)  { -	char *s;  	int rundata, runaddress, runwalk; -	s = getenv ("testdramdata"); -	rundata = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramaddress"); -	runaddress = (s && (*s == 'y')) ? 1 : 0; -	s = getenv ("testdramwalk"); -	runwalk = (s && (*s == 'y')) ? 1 : 0; +	rundata = getenv_yesno("testdramdata") == 1; +	runaddress = getenv_yesno("testdramaddress") == 1; +	runwalk = getenv_yesno("testdramwalk") == 1;  	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {  		printf ("Testing RAM ... "); diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 2c7cd0d40..76ec6876e 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -26,10 +26,12 @@  #include <linux/compiler.h>  #include <asm/io.h>  #include <asm/arch/clock.h> +#include <asm/arch/display.h>  #include <asm/arch/emc.h>  #include <asm/arch/funcmux.h>  #include <asm/arch/pinmux.h>  #include <asm/arch/pmu.h> +#include <asm/arch/pwm.h>  #include <asm/arch/tegra.h>  #include <asm/arch/usb.h>  #include <asm/arch-tegra/board.h> @@ -119,6 +121,13 @@ int board_init(void)  	pin_mux_spi();  	spi_init();  #endif +#ifdef CONFIG_PWM_TEGRA +	if (pwm_init(gd->fdt_blob)) +		debug("%s: Failed to init pwm\n", __func__); +#endif +#ifdef CONFIG_LCD +	tegra_lcd_check_next_stage(gd->fdt_blob, 0); +#endif  	/* boot param addr */  	gd->bd->bi_boot_params = (NV_PA_SDRAM_BASE + 0x100); @@ -144,6 +153,9 @@ int board_init(void)  	pin_mux_usb();  	board_usb_init(gd->fdt_blob);  #endif +#ifdef CONFIG_LCD +	tegra_lcd_check_next_stage(gd->fdt_blob, 0); +#endif  #ifdef CONFIG_TEGRA_NAND  	pin_mux_nand(); @@ -174,7 +186,19 @@ int board_early_init_f(void)  	/* Initialize periph GPIOs */  	gpio_early_init();  	gpio_early_init_uart(); +#ifdef CONFIG_LCD +	tegra_lcd_early_init(gd->fdt_blob); +#endif  	return 0;  }  #endif	/* EARLY_INIT */ + +int board_late_init(void) +{ +#ifdef CONFIG_LCD +	/* Make sure we finish initing the LCD */ +	tegra_lcd_check_next_stage(gd->fdt_blob, 1); +#endif +	return 0; +} diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index 25a63a05d..dd98ca48e 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -163,4 +163,37 @@  			compatible = "hynix,hy27uf4g2b", "nand-flash";  		};  	}; + +	host1x { +		status = "okay"; +		dc@54200000 { +			status = "okay"; +			rgb { +				status = "okay"; +				nvidia,panel = <&lcd_panel>; +			}; +		}; +	}; + +	lcd_panel: panel { +		/* Seaboard has 1366x768 */ +		clock = <70600000>; +		xres = <1366>; +		yres = <768>; +		left-margin = <58>; +		right-margin = <58>; +		hsync-len = <58>; +		lower-margin = <4>; +		upper-margin = <4>; +		vsync-len = <4>; +		hsync-active-high; +		nvidia,bits-per-pixel = <16>; +		nvidia,pwm = <&pwm 2 0>; +		nvidia,backlight-enable-gpios = <&gpio 28 0>;	/* PD4 */ +		nvidia,lvds-shutdown-gpios = <&gpio 10 0>;	/* PB2 */ +		nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */ +		nvidia,panel-vdd-gpios = <&gpio 22 0>;		/* PC6 */ +		nvidia,panel-timings = <400 4 203 17 15>; +	}; +  }; diff --git a/board/nvidia/harmony/harmony.c b/board/nvidia/harmony/harmony.c index c7590ac6c..93430edd3 100644 --- a/board/nvidia/harmony/harmony.c +++ b/board/nvidia/harmony/harmony.c @@ -64,9 +64,8 @@ int board_mmc_init(bd_t *bd)  	pin_mux_mmc();  	debug("board_mmc_init: init SD slot J26\n"); -	/* init dev 0, SD slot J26, with 4-bit bus */ -	/* The board has an 8-bit bus, but 8-bit doesn't work yet */ -	tegra_mmc_init(0, 4, GPIO_PI6, GPIO_PH2); +	/* init dev 0, SD slot J26, with 8-bit bus */ +	tegra_mmc_init(0, 8, GPIO_PI6, GPIO_PH2);  	debug("board_mmc_init: init SD slot J5\n");  	/* init dev 2, SD slot J5, with 4-bit bus */ diff --git a/board/nvidia/seaboard/seaboard.c b/board/nvidia/seaboard/seaboard.c index c412c077d..3e33da0af 100644 --- a/board/nvidia/seaboard/seaboard.c +++ b/board/nvidia/seaboard/seaboard.c @@ -71,9 +71,8 @@ int board_mmc_init(bd_t *bd)  	pin_mux_mmc();  	debug("board_mmc_init: init eMMC\n"); -	/* init dev 0, eMMC chip, with 4-bit bus */ -	/* The board has an 8-bit bus, but 8-bit doesn't work yet */ -	tegra_mmc_init(0, 4, -1, -1); +	/* init dev 0, eMMC chip, with 8-bit bus */ +	tegra_mmc_init(0, 8, -1, -1);  	debug("board_mmc_init: init SD slot\n");  	/* init dev 1, SD slot, with 4-bit bus */ diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c index 389affcde..c3fd19169 100644 --- a/board/prodrive/p3mx/p3mx.c +++ b/board/prodrive/p3mx/p3mx.c @@ -768,22 +768,18 @@ int mem_test_walk (void)  /*********************************************************************/  int testdram (void)  { -	char *s;  	int rundata    = 0;  	int runaddress = 0;  	int runwalk    = 0;  #ifdef CONFIG_SYS_DRAM_TEST_DATA -	s = getenv ("testdramdata"); -	rundata = (s && (*s == 'y')) ? 1 : 0; +	rundata = getenv_yesno("testdramdata") == 1;  #endif  #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS -	s = getenv ("testdramaddress"); -	runaddress = (s && (*s == 'y')) ? 1 : 0; +	runaddress = getenv_yesno("testdramaddress") == 1;  #endif  #ifdef CONFIG_SYS_DRAM_TEST_WALK -	s = getenv ("testdramwalk"); -	runwalk = (s && (*s == 'y')) ? 1 : 0; +	runwalk = getenv_yesno("testdramwalk") == 1;  #endif  	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index 1474fa8a1..47c6a5a46 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -36,7 +36,7 @@ COBJS	+= smdk5250.o  endif  ifdef CONFIG_SPL_BUILD -COBJS	+= mmc_boot.o +COBJS	+= spl_boot.o  endif  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index a5816e445..9c926d6ec 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -24,11 +24,13 @@  #include <asm/io.h>  #include <i2c.h>  #include <netdev.h> +#include <spi.h>  #include <asm/arch/cpu.h>  #include <asm/arch/gpio.h>  #include <asm/arch/mmc.h>  #include <asm/arch/pinmux.h>  #include <asm/arch/sromc.h> +#include <power/pmic.h>  DECLARE_GLOBAL_DATA_PTR; @@ -63,6 +65,9 @@ static int smc9115_pre_init(void)  int board_init(void)  {  	gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); +#ifdef CONFIG_EXYNOS_SPI +	spi_init(); +#endif  	return 0;  } @@ -79,6 +84,16 @@ int dram_init(void)  	return 0;  } +#if defined(CONFIG_POWER) +int power_init_board(void) +{ +	if (pmic_init(I2C_PMIC)) +		return -1; +	else +		return 0; +} +#endif +  void dram_init_banksize(void)  {  	gd->bd->bi_dram[0].start = PHYS_SDRAM_1; diff --git a/board/samsung/smdk5250/mmc_boot.c b/board/samsung/smdk5250/spl_boot.c index 449a919d5..d8f3c1e18 100644 --- a/board/samsung/smdk5250/mmc_boot.c +++ b/board/samsung/smdk5250/spl_boot.c @@ -23,6 +23,16 @@  #include<common.h>  #include<config.h> +enum boot_mode { +	BOOT_MODE_MMC = 4, +	BOOT_MODE_SERIAL = 20, +	/* 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); +  /*  * Copy U-boot from mmc to RAM:  * COPY_BL2_FNPTR_ADDR: Address in iRAM, which Contains @@ -30,9 +40,26 @@  */  void copy_uboot_to_ram(void)  { -	u32 (*copy_bl2)(u32, u32, u32) = (void *) *(u32 *)COPY_BL2_FNPTR_ADDR; +	spi_copy_func_t spi_copy; +	enum boot_mode bootmode; +	u32 (*copy_bl2)(u32, u32, u32); + +	bootmode = readl(EXYNOS5_POWER_BASE) & OM_STAT; -	copy_bl2(BL2_START_OFFSET, BL2_SIZE_BLOC_COUNT, CONFIG_SYS_TEXT_BASE); +	switch (bootmode) { +	case BOOT_MODE_SERIAL: +		spi_copy = *(spi_copy_func_t *)EXYNOS_COPY_SPI_FNPTR_ADDR; +		spi_copy(SPI_FLASH_UBOOT_POS, CONFIG_BL2_SIZE, +						CONFIG_SYS_TEXT_BASE); +		break; +	case BOOT_MODE_MMC: +		copy_bl2 = (void *) *(u32 *)COPY_BL2_FNPTR_ADDR; +		copy_bl2(BL2_START_OFFSET, BL2_SIZE_BLOC_COUNT, +						CONFIG_SYS_TEXT_BASE); +		break; +	default: +		break; +	}  }  void board_init_f(unsigned long bootflag) diff --git a/board/samsung/trats/trats.c b/board/samsung/trats/trats.c index e54019098..472402942 100644 --- a/board/samsung/trats/trats.c +++ b/board/samsung/trats/trats.c @@ -29,6 +29,7 @@  #include <asm/arch/cpu.h>  #include <asm/arch/gpio.h>  #include <asm/arch/mmc.h> +#include <asm/arch/pinmux.h>  #include <asm/arch/clock.h>  #include <asm/arch/clk.h>  #include <asm/arch/mipi_dsim.h> @@ -361,7 +362,9 @@ int power_init_board(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_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);  	return 0;  } @@ -372,6 +375,10 @@ void dram_init_banksize(void)  	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;  	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;  	gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE; +	gd->bd->bi_dram[2].start = PHYS_SDRAM_3; +	gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE; +	gd->bd->bi_dram[3].start = PHYS_SDRAM_4; +	gd->bd->bi_dram[3].size = PHYS_SDRAM_4_SIZE;  }  static unsigned int get_hw_revision(void) @@ -419,54 +426,22 @@ int board_mmc_init(bd_t *bis)  {  	struct exynos4_gpio_part2 *gpio =  		(struct exynos4_gpio_part2 *)samsung_get_base_gpio_part2(); -	int i, err; +	int err;  	/* eMMC_EN: SD_0_CDn: GPK0[2] Output High */  	s5p_gpio_direction_output(&gpio->k0, 2, 1);  	s5p_gpio_set_pull(&gpio->k0, 2, GPIO_PULL_NONE);  	/* -	 * eMMC GPIO: -	 * SDR 8-bit@48MHz at MMC0 -	 * GPK0[0]	SD_0_CLK(2) -	 * GPK0[1]	SD_0_CMD(2) -	 * GPK0[2]	SD_0_CDn	-> Not used -	 * GPK0[3:6]	SD_0_DATA[0:3](2) -	 * GPK1[3:6]	SD_0_DATA[0:3](3) -	 * -	 * DDR 4-bit@26MHz at MMC4 -	 * GPK0[0]	SD_4_CLK(3) -	 * GPK0[1]	SD_4_CMD(3) -	 * GPK0[2]	SD_4_CDn	-> Not used -	 * GPK0[3:6]	SD_4_DATA[0:3](3) -	 * GPK1[3:6]	SD_4_DATA[4:7](4) -	 */ -	for (i = 0; i < 7; i++) { -		if (i == 2) -			continue; -		/* GPK0[0:6] special function 2 */ -		s5p_gpio_cfg_pin(&gpio->k0, i, 0x2); -		/* GPK0[0:6] pull disable */ -		s5p_gpio_set_pull(&gpio->k0, i, GPIO_PULL_NONE); -		/* GPK0[0:6] drv 4x */ -		s5p_gpio_set_drv(&gpio->k0, i, GPIO_DRV_4X); -	} - -	for (i = 3; i < 7; i++) { -		/* GPK1[3:6] special function 3 */ -		s5p_gpio_cfg_pin(&gpio->k1, i, 0x3); -		/* GPK1[3:6] pull disable */ -		s5p_gpio_set_pull(&gpio->k1, i, GPIO_PULL_NONE); -		/* GPK1[3:6] drv 4x */ -		s5p_gpio_set_drv(&gpio->k1, i, GPIO_DRV_4X); -	} - -	/*  	 * MMC device init  	 * mmc0	 : eMMC (8-bit buswidth)  	 * mmc2	 : SD card (4-bit buswidth)  	 */ -	err = s5p_mmc_init(0, 8); +	err = exynos_pinmux_config(PERIPH_ID_SDMMC0, PINMUX_FLAG_8BIT_MODE); +	if (err) +		debug("SDMMC0 not configured\n"); +	else +		err = s5p_mmc_init(0, 8);  	/* T-flash detect */  	s5p_gpio_cfg_pin(&gpio->x3, 4, 0xf); @@ -477,24 +452,11 @@ int board_mmc_init(bd_t *bis)  	 * GPX3[4] T-flash detect pin  	 */  	if (!s5p_gpio_get_value(&gpio->x3, 4)) { -		/* -		 * SD card GPIO: -		 * GPK2[0]	SD_2_CLK(2) -		 * GPK2[1]	SD_2_CMD(2) -		 * GPK2[2]	SD_2_CDn	-> Not used -		 * GPK2[3:6]	SD_2_DATA[0:3](2) -		 */ -		for (i = 0; i < 7; i++) { -			if (i == 2) -				continue; -			/* GPK2[0:6] special function 2 */ -			s5p_gpio_cfg_pin(&gpio->k2, i, 0x2); -			/* GPK2[0:6] pull disable */ -			s5p_gpio_set_pull(&gpio->k2, i, GPIO_PULL_NONE); -			/* GPK2[0:6] drv 4x */ -			s5p_gpio_set_drv(&gpio->k2, i, GPIO_DRV_4X); -		} -		err = s5p_mmc_init(2, 4); +		err = exynos_pinmux_config(PERIPH_ID_SDMMC2, PINMUX_FLAG_NONE); +		if (err) +			debug("SDMMC2 not configured\n"); +		else +			err = s5p_mmc_init(2, 4);  	}  	return err; @@ -629,6 +591,10 @@ static void board_power_init(void)  	writel(0, (unsigned int)&pwr->lcd1_configuration);  	writel(0, (unsigned int)&pwr->gps_configuration);  	writel(0, (unsigned int)&pwr->gps_alive_configuration); + +	/* It is necessary to power down core 1 */ +	/* to successfully boot CPU1 in kernel */ +	writel(0, (unsigned int)&pwr->arm_core1_configuration);  }  static void board_uart_init(void) diff --git a/board/samsung/universal_c210/Makefile b/board/samsung/universal_c210/Makefile index bfec08fa8..587cc1b8c 100644 --- a/board/samsung/universal_c210/Makefile +++ b/board/samsung/universal_c210/Makefile @@ -26,7 +26,6 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(BOARD).o  COBJS-y	:= universal.o onenand.o -SOBJS	:= lowlevel_init.o  SRCS    := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS-y)) diff --git a/board/samsung/universal_c210/lowlevel_init.S b/board/samsung/universal_c210/lowlevel_init.S deleted file mode 100644 index dc7f69ea4..000000000 --- a/board/samsung/universal_c210/lowlevel_init.S +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Lowlevel setup for universal board based on EXYNOS4210 - * - * Copyright (C) 2010 Samsung Electronics - * Kyungmin Park <kyungmin.park@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 <config.h> -#include <version.h> -#include <asm/arch/cpu.h> -#include <asm/arch/clock.h> - -/* - * Register usages: - * - * r5 has zero always - * r7 has GPIO part1 base 0x11400000 - * r6 has GPIO part2 base 0x11000000 - */ - -	.globl lowlevel_init -lowlevel_init: -	mov	r11, lr - -	/* r5 has always zero */ -	mov	r5, #0 - -	ldr	r7, =EXYNOS4_GPIO_PART1_BASE -	ldr	r6, =EXYNOS4_GPIO_PART2_BASE - -	/* System Timer */ -	ldr	r0, =EXYNOS4_SYSTIMER_BASE -	ldr	r1, =0x5000 -	str	r1, [r0, #0x0] -	ldr	r1, =0xffffffff -	str	r1, [r0, #0x8] -	ldr	r1, =0x49 -	str	r1, [r0, #0x4] - -	/* PMIC manual reset */ -	/* nPOWER: XEINT_23: GPX2[7] */ -	add	r0, r6, #0xC40			@ EXYNOS4_GPIO_X2_OFFSET -	ldr	r1, [r0, #0x0] -	bic	r1, r1, #(0xf << 28)		@ 28 = 7 * 4-bit -	orr	r1, r1, #(0x1 << 28)		@ Output -	str	r1, [r0, #0x0] - -	ldr	r1, [r0, #0x4] -	orr	r1, r1, #(1 << 7)		@ 7 = 7 * 1-bit -	str	r1, [r0, #0x4] - -	/* init system clock */ -	bl	system_clock_init - -	/* Disable Watchdog */ -	ldr	r0, =EXYNOS4_WATCHDOG_BASE		@0x10060000 -	str	r5, [r0] - -	/* UART */ -	bl	uart_asm_init - -	/* PMU init */ -	bl	system_power_init - -	bl	tzpc_init - -	mov	lr, r11 -	mov	pc, lr -	nop -	nop -	nop - -/* - * uart_asm_init: Initialize UART's pins - */ -uart_asm_init: -	/* -	 * setup UART0-UART4 GPIOs (part1) -	 * GPA1CON[3] = I2C_3_SCL (3) -	 * GPA1CON[2] = I2C_3_SDA (3) -	 */ -	mov	r0, r7 -	ldr	r1, =0x22222222 -	str	r1, [r0, #0x00]			@ EXYNOS4_GPIO_A0_OFFSET -	ldr	r1, =0x00223322 -	str	r1, [r0, #0x20]			@ EXYNOS4_GPIO_A1_OFFSET - -	/* UART_SEL GPY4[7] (part2) at EXYNOS4 */ -	add	r0, r6, #0x1A0			@ EXYNOS4_GPIO_Y4_OFFSET -	ldr	r1, [r0, #0x0] -	bic	r1, r1, #(0xf << 28)		@ 28 = 7 * 4-bit -	orr	r1, r1, #(0x1 << 28) -	str	r1, [r0, #0x0] - -	ldr	r1, [r0, #0x8] -	bic	r1, r1, #(0x3 << 14)		@ 14 = 7 * 2-bit -	orr	r1, r1, #(0x3 << 14)		@ Pull-up enabled -	str	r1, [r0, #0x8] - -	ldr	r1, [r0, #0x4] -	orr	r1, r1, #(1 << 7)		@ 7 = 7 * 1-bit -	str	r1, [r0, #0x4] - -	mov	pc, lr -	nop -	nop -	nop - -system_clock_init: -	ldr	r0, =EXYNOS4_CLOCK_BASE - -	/* APLL(1), MPLL(1), CORE(0), HPM(0) */ -	ldr	r1, =0x0101 -	ldr	r2, =0x14200			@ CLK_SRC_CPU -	str	r1, [r0, r2] - -	/* wait ?us */ -	mov	r1, #0x10000 -1:	subs	r1, r1, #1 -	bne	1b - -	/* -	 * CLK_SRC_TOP0 -	 * MUX_ONENAND_SEL[28]	0: DOUT133, 1: DOUT166 -	 * MUX_VPLL_SEL[8]	0: FINPLL,  1: FOUTVPLL -	 * MUX_EPLL_SEL[4]	0: FINPLL,  1: FOUTEPLL -	 */ -	ldr	r1, =0x10000110 -	ldr	r2, =0x0C210			@ CLK_SRC_TOP -	str	r1, [r0, r2] - -	/* SATA: SCLKMPLL(0), MMC[0:4]: SCLKMPLL(6) */ -	ldr	r1, =0x0066666 -	ldr	r2, =0x0C240			@ CLK_SRC_FSYS -	str	r1, [r0, r2] -	/* UART[0:5], PWM: SCLKMPLL(6) */ -	ldr	r1, =0x6666666 -	ldr	r2, =0x0C250			@ CLK_SRC_PERIL0_OFFSET -	str	r1, [r0, r2] - -	/* CPU0: CORE, COREM0, COREM1, PERI, ATB, PCLK_DBG, APLL */ -	ldr	r1, =0x0133730 -	ldr	r2, =0x14500			@ CLK_DIV_CPU0 -	str	r1, [r0, r2] -	/* CPU1: COPY, HPM */ -	ldr	r1, =0x03 -	ldr	r2, =0x14504			@ CLK_DIV_CPU1 -	str	r1, [r0, r2] -	/* DMC0: ACP, ACP_PCLK, DPHY, DMC, DMCD, DMCP, COPY2 CORE_TIMER */ -	ldr	r1, =0x13111113 -	ldr	r2, =0x10500			@ CLK_DIV_DMC0 -	str	r1, [r0, r2] -	/* DMC1: PWI, DVSEM, DPM */ -	ldr	r1, =0x01010100 -	ldr	r2, =0x10504			@ CLK_DIV_DMC1 -	str	r1, [r0, r2] -	/* LEFTBUS: GDL, GPL */ -	ldr	r1, =0x13 -	ldr	r2, =0x04500			@ CLK_DIV_LEFTBUS -	str	r1, [r0, r2] -	/* RIGHHTBUS: GDR, GPR */ -	ldr	r1, =0x13 -	ldr	r2, =0x08500			@ CLK_DIV_RIGHTBUS -	str	r1, [r0, r2] -	/* -	 * CLK_DIV_TOP -	 * ONENAND_RATIOD[18:16]: 0 SCLK_ONENAND = MOUTONENAND / (n + 1) -	 * ACLK_200, ACLK_100, ACLK_160, ACLK_133, -	 */ -	ldr	r1, =0x00005473 -	ldr	r2, =0x0C510			@ CLK_DIV_TOP -	str	r1, [r0, r2] -	/* MMC[0:1] */ -	ldr	r1, =0x000f000f			/* 800(MPLL) / (15 + 1) */ -	ldr	r2, =0x0C544			@ CLK_DIV_FSYS1 -	str	r1, [r0, r2] -	/* MMC[2:3] */ -	ldr	r1, =0x000f000f			/* 800(MPLL) / (15 + 1) */ -	ldr	r2, =0x0C548			@ CLK_DIV_FSYS2 -	str	r1, [r0, r2] -	/* MMC4 */ -	ldr	r1, =0x000f			/* 800(MPLL) / (15 + 1) */ -	ldr	r2, =0x0C54C			@ CLK_DIV_FSYS3 -	str	r1, [r0, r2] -	/* UART[0:5] */ -	ldr	r1, =0x774777 -	ldr	r2, =0x0C550			@ CLK_DIV_PERIL0 -	str	r1, [r0, r2] -	/* SLIMBUS: ???, PWM */ -	ldr	r1, =0x8 -	ldr	r2, =0x0C55C			@ CLK_DIV_PERIL3 -	str	r1, [r0, r2] - -	/* PLL Setting */ -	ldr	r1, =0x1C20 -	ldr	r2, =0x14000			@ APLL_LOCK -	str	r1, [r0, r2] -	ldr	r2, =0x14008			@ MPLL_LOCK -	str	r1, [r0, r2] -	ldr	r2, =0x0C010			@ EPLL_LOCK -	str	r1, [r0, r2] -	ldr	r2, =0x0C020			@ VPLL_LOCK -	str	r1, [r0, r2] - -	/* APLL */ -	ldr	r1, =0x8000001c -	ldr	r2, =0x14104			@ APLL_CON1 -	str	r1, [r0, r2] -	ldr	r1, =0x80c80601			@ 800MHz -	ldr	r2, =0x14100			@ APLL_CON0 -	str	r1, [r0, r2] -	/* MPLL */ -	ldr	r1, =0x8000001C -	ldr	r2, =0x1410C			@ MPLL_CON1 -	str	r1, [r0, r2] -	ldr	r1, =0x80c80601			@ 800MHz -	ldr	r2, =0x14108			@ MPLL_CON0 -	str	r1, [r0, r2] -	/* EPLL */ -	ldr	r1, =0x0 -	ldr	r2, =0x0C114			@ EPLL_CON1 -	str	r1, [r0, r2] -	ldr	r1, =0x80300302			@ 96MHz -	ldr	r2, =0x0C110			@ EPLL_CON0 -	str	r1, [r0, r2] -	/* VPLL */ -	ldr	r1, =0x11000400 -	ldr	r2, =0x0C124			@ VPLL_CON1 -	str	r1, [r0, r2] -	ldr	r1, =0x80350302			@ 108MHz -	ldr	r2, =0x0C120			@ VPLL_CON0 -	str	r1, [r0, r2] - -	/* -	 * SMMUJPEG[11], JPEG[6], CSIS1[5]		: 0111 1001 -	 * Turn off all -	 */ -	ldr	r1, =0xFFF80000 -	ldr	r2, =0x0C920			@ CLK_GATE_IP_CAM -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFFC0 -	ldr	r2, =0x0C924			@ CLK_GATE_IP_VP -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFFE0 -	ldr	r2, =0x0C928			@ CLK_GATE_IP_MFC -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFFFC -	ldr	r2, =0x0C92C			@ CLK_GATE_IP_G3D -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFC00 -	ldr	r2, =0x0C930			@ CLK_GATE_IP_IMAGE -	str	r1, [r0, r2] - -	/* DSIM0[3], MDNIE0[2], MIE0[1]			: 0001 */ -	ldr	r1, =0xFFFFFFF1 -	ldr	r2, =0x0C934			@ CLK_GATE_IP_LCD0 -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFFC0 -	ldr	r2, =0x0C938			@ CLK_GATE_IP_LCD1 -	str	r1, [r0, r2] - -	/* -	 * SMMUPCIE[18], NFCON[16]			: 1111 1010 -	 * PCIE[14],  SATA[10], SDMMC43[9:8]		: 1011 1000 -	 * SDMMC1[6], TSI[4], SATAPHY[3], PCIEPHY[2]	: 1010 0011 -	 */ -	ldr	r1, =0xFFFAB8A3 -	ldr	r2, =0x0C940			@ CLK_GATE_IP_FSYS -	str	r1, [r0, r2] - -	/* Turn off all */ -	ldr	r1, =0xFFFFFFFC -	ldr	r2, =0x0C94C			@ CLK_GATE_IP_GPS -	str	r1, [r0, r2] - -	/* -	 * AC97[27], SPDIF[26], SLIMBUS[25]		: 1111 0001 -	 * I2C2[8]					: 1111 1110 -	 */ -	ldr	r1, =0xF1FFFEFF -	ldr	r2, =0x0C950			@ CLK_GATE_IP_PERIL -	str	r1, [r0, r2] - -	/* -	 * KEYIF[16]					: 1111 1110 -	 */ -	ldr	r1, =0xFFFEFFFF -	ldr	r2, =0x0C960			@ CLK_GATE_IP_PERIR -	str	r1, [r0, r2] - -	/* LCD1[5], G3D[3], MFC[2], TV[1]		: 1101 0001 */ -	ldr	r1, =0xFFFFFFD1 -	ldr	r2, =0x0C970			@ CLK_GATE_BLOCK -	str	r1, [r0, r2] -	mov	pc, lr -	nop -	nop -	nop - -system_power_init: -	ldr	r0, =EXYNOS4_POWER_BASE		@ 0x10020000 - -	ldr	r2, =0x330C			@ PS_HOLD_CONTROL -	ldr	r1, [r0, r2] -	orr	r1, r1, #(0x3 << 8)		@ Data High, Output En -	str	r1, [r0, r2] - -	/* Power Down */ -	add	r2, r0, #0x3000 -	str	r5, [r2, #0xC20]		@ TV_CONFIGURATION -	str	r5, [r2, #0xC40]		@ MFC_CONFIGURATION -	str	r5, [r2, #0xC60]		@ G3D_CONFIGURATION -	str	r5, [r2, #0xCA0]		@ LCD1_CONFIGURATION -	str	r5, [r2, #0xCE0]		@ GPS_CONFIGURATION - -	mov	pc, lr -	nop -	nop -	nop - -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] - -	mov	pc, lr diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index 36a047217..e742707f7 100644 --- a/board/samsung/universal_c210/universal.c +++ b/board/samsung/universal_c210/universal.c @@ -23,10 +23,17 @@   */  #include <common.h> +#include <spi.h> +#include <lcd.h>  #include <asm/io.h> +#include <asm/gpio.h>  #include <asm/arch/adc.h>  #include <asm/arch/gpio.h>  #include <asm/arch/mmc.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/watchdog.h> +#include <libtizen.h> +#include <ld9040.h>  #include <power/pmic.h>  #include <usb/s3c_udc.h>  #include <asm/arch/cpu.h> @@ -48,21 +55,7 @@ static int get_hwrev(void)  	return board_rev & 0xFF;  } -static void check_hw_revision(void); - -int board_init(void) -{ -	gpio1 = (struct exynos4_gpio_part1 *) EXYNOS4_GPIO_PART1_BASE; -	gpio2 = (struct exynos4_gpio_part2 *) EXYNOS4_GPIO_PART2_BASE; - -	gd->bd->bi_arch_number = MACH_TYPE_UNIVERSAL_C210; -	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; - -	check_hw_revision(); -	printf("HW Revision:\t0x%x\n", board_rev); - -	return 0; -} +static void init_pmic_lcd(void);  int power_init_board(void)  { @@ -72,6 +65,8 @@ int power_init_board(void)  	if (ret)  		return ret; +	init_pmic_lcd(); +  	return 0;  } @@ -186,7 +181,7 @@ int checkboard(void)  #ifdef CONFIG_GENERIC_MMC  int board_mmc_init(bd_t *bis)  { -	int i, err; +	int err;  	switch (get_hwrev()) {  	case 0: @@ -209,75 +204,30 @@ int board_mmc_init(bd_t *bis)  	}  	/* -	 * eMMC GPIO: -	 * SDR 8-bit@48MHz at MMC0 -	 * GPK0[0]	SD_0_CLK(2) -	 * GPK0[1]	SD_0_CMD(2) -	 * GPK0[2]	SD_0_CDn	-> Not used -	 * GPK0[3:6]	SD_0_DATA[0:3](2) -	 * GPK1[3:6]	SD_0_DATA[0:3](3) -	 * -	 * DDR 4-bit@26MHz at MMC4 -	 * GPK0[0]	SD_4_CLK(3) -	 * GPK0[1]	SD_4_CMD(3) -	 * GPK0[2]	SD_4_CDn	-> Not used -	 * GPK0[3:6]	SD_4_DATA[0:3](3) -	 * GPK1[3:6]	SD_4_DATA[4:7](4) +	 * MMC device init +	 * mmc0	 : eMMC (8-bit buswidth) +	 * mmc2	 : SD card (4-bit buswidth)  	 */ -	for (i = 0; i < 7; i++) { -		if (i == 2) -			continue; -		/* GPK0[0:6] special function 2 */ -		s5p_gpio_cfg_pin(&gpio2->k0, i, 0x2); -		/* GPK0[0:6] pull disable */ -		s5p_gpio_set_pull(&gpio2->k0, i, GPIO_PULL_NONE); -		/* GPK0[0:6] drv 4x */ -		s5p_gpio_set_drv(&gpio2->k0, i, GPIO_DRV_4X); -	} - -	for (i = 3; i < 7; i++) { -		/* GPK1[3:6] special function 3 */ -		s5p_gpio_cfg_pin(&gpio2->k1, i, 0x3); -		/* GPK1[3:6] pull disable */ -		s5p_gpio_set_pull(&gpio2->k1, i, GPIO_PULL_NONE); -		/* GPK1[3:6] drv 4x */ -		s5p_gpio_set_drv(&gpio2->k1, i, GPIO_DRV_4X); -	} +	err = exynos_pinmux_config(PERIPH_ID_SDMMC0, PINMUX_FLAG_8BIT_MODE); +	if (err) +		debug("SDMMC0 not configured\n"); +	else +		err = s5p_mmc_init(0, 8);  	/* T-flash detect */  	s5p_gpio_cfg_pin(&gpio2->x3, 4, 0xf);  	s5p_gpio_set_pull(&gpio2->x3, 4, GPIO_PULL_UP);  	/* -	 * MMC device init -	 * mmc0	 : eMMC (8-bit buswidth) -	 * mmc2	 : SD card (4-bit buswidth) -	 */ -	err = s5p_mmc_init(0, 8); - -	/*  	 * Check the T-flash  detect pin  	 * GPX3[4] T-flash detect pin  	 */  	if (!s5p_gpio_get_value(&gpio2->x3, 4)) { -		/* -		 * SD card GPIO: -		 * GPK2[0]	SD_2_CLK(2) -		 * GPK2[1]	SD_2_CMD(2) -		 * GPK2[2]	SD_2_CDn	-> Not used -		 * GPK2[3:6]	SD_2_DATA[0:3](2) -		 */ -		for (i = 0; i < 7; i++) { -			if (i == 2) -				continue; -			/* GPK2[0:6] special function 2 */ -			s5p_gpio_cfg_pin(&gpio2->k2, i, 0x2); -			/* GPK2[0:6] pull disable */ -			s5p_gpio_set_pull(&gpio2->k2, i, GPIO_PULL_NONE); -			/* GPK2[0:6] drv 4x */ -			s5p_gpio_set_drv(&gpio2->k2, i, GPIO_DRV_4X); -		} -		err = s5p_mmc_init(2, 4); +		err = exynos_pinmux_config(PERIPH_ID_SDMMC2, PINMUX_FLAG_NONE); +		if (err) +			debug("SDMMC2 not configured\n"); +		else +			err = s5p_mmc_init(2, 4);  	}  	return err; @@ -331,3 +281,242 @@ struct s3c_plat_otg_data s5pc210_otg_data = {  	.usb_flags = PHY0_SLEEP,  };  #endif + +int board_early_init_f(void) +{ +	wdt_stop(); + +	return 0; +} + +#ifdef CONFIG_SOFT_SPI +static void soft_spi_init(void) +{ +	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_SCLK, +		CONFIG_SOFT_SPI_MODE & SPI_CPOL); +	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_MOSI, 1); +	gpio_direction_input(CONFIG_SOFT_SPI_GPIO_MISO); +	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_CS, +		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH)); +} + +void spi_cs_activate(struct spi_slave *slave) +{ +	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS, +		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH)); +	SPI_SCL(1); +	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS, +		CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ +	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS, +		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH)); +} + +int  spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +	return bus == 0 && cs == 0; +} + +void universal_spi_scl(int bit) +{ +	gpio_set_value(CONFIG_SOFT_SPI_GPIO_SCLK, bit); +} + +void universal_spi_sda(int bit) +{ +	gpio_set_value(CONFIG_SOFT_SPI_GPIO_MOSI, bit); +} + +int universal_spi_read(void) +{ +	return gpio_get_value(CONFIG_SOFT_SPI_GPIO_MISO); +} +#endif + +static void init_pmic_lcd(void) +{ +	unsigned char val; +	int ret = 0; + +	struct pmic *p = pmic_get("MAX8998_PMIC"); + +	if (!p) +		return; + +	if (pmic_probe(p)) +		return; + +	/* LDO7 1.8V */ +	val = 0x02; /* (1800 - 1600) / 100; */ +	ret |= pmic_reg_write(p,  MAX8998_REG_LDO7, val); + +	/* LDO17 3.0V */ +	val = 0xe; /* (3000 - 1600) / 100; */ +	ret |= pmic_reg_write(p,  MAX8998_REG_LDO17, val); + +	/* Disable unneeded regulators */ +	/* +	 * ONOFF1 +	 * Buck1 ON, Buck2 OFF, Buck3 ON, Buck4 ON +	 * LDO2 ON, LDO3 OFF, LDO4 OFF, LDO5 ON +	 */ +	val = 0xB9; +	ret |= pmic_reg_write(p,  MAX8998_REG_ONOFF1, val); + +	/* ONOFF2 +	 * LDO6 OFF, LDO7 ON, LDO8 OFF, LDO9 ON, +	 * LDO10 OFF, LDO11 OFF, LDO12 OFF, LDO13 OFF +	 */ +	val = 0x50; +	ret |= pmic_reg_write(p,  MAX8998_REG_ONOFF2, val); + +	/* ONOFF3 +	 * LDO14 OFF, LDO15 OFF, LGO16 OFF, LDO17 OFF +	 * EPWRHOLD OFF, EBATTMON OFF, ELBCNFG2 OFF, ELBCNFG1 OFF +	 */ +	val = 0x00; +	ret |= pmic_reg_write(p,  MAX8998_REG_ONOFF3, val); + +	if (ret) +		puts("LCD pmic initialisation error!\n"); +} + +static void lcd_cfg_gpio(void) +{ +	unsigned int i, f3_end = 4; + +	for (i = 0; i < 8; i++) { +		/* set GPF0,1,2[0:7] for RGB Interface and Data lines (32bit) */ +		s5p_gpio_cfg_pin(&gpio1->f0, i, GPIO_FUNC(2)); +		s5p_gpio_cfg_pin(&gpio1->f1, i, GPIO_FUNC(2)); +		s5p_gpio_cfg_pin(&gpio1->f2, i, GPIO_FUNC(2)); +		/* pull-up/down disable */ +		s5p_gpio_set_pull(&gpio1->f0, i, GPIO_PULL_NONE); +		s5p_gpio_set_pull(&gpio1->f1, i, GPIO_PULL_NONE); +		s5p_gpio_set_pull(&gpio1->f2, i, GPIO_PULL_NONE); + +		/* drive strength to max (24bit) */ +		s5p_gpio_set_drv(&gpio1->f0, i, GPIO_DRV_4X); +		s5p_gpio_set_rate(&gpio1->f0, i, GPIO_DRV_SLOW); +		s5p_gpio_set_drv(&gpio1->f1, i, GPIO_DRV_4X); +		s5p_gpio_set_rate(&gpio1->f1, i, GPIO_DRV_SLOW); +		s5p_gpio_set_drv(&gpio1->f2, i, GPIO_DRV_4X); +		s5p_gpio_set_rate(&gpio1->f0, i, GPIO_DRV_SLOW); +	} + +	for (i = 0; i < f3_end; i++) { +		/* set GPF3[0:3] for RGB Interface and Data lines (32bit) */ +		s5p_gpio_cfg_pin(&gpio1->f3, i, GPIO_FUNC(2)); +		/* pull-up/down disable */ +		s5p_gpio_set_pull(&gpio1->f3, i, GPIO_PULL_NONE); +		/* drive strength to max (24bit) */ +		s5p_gpio_set_drv(&gpio1->f3, i, GPIO_DRV_4X); +		s5p_gpio_set_rate(&gpio1->f3, i, GPIO_DRV_SLOW); +	} + +	/* gpio pad configuration for LCD reset. */ +	s5p_gpio_cfg_pin(&gpio2->y4, 5, GPIO_OUTPUT); + +	spi_init(); +} + +static void reset_lcd(void) +{ +	s5p_gpio_set_value(&gpio2->y4, 5, 1); +	udelay(10000); +	s5p_gpio_set_value(&gpio2->y4, 5, 0); +	udelay(10000); +	s5p_gpio_set_value(&gpio2->y4, 5, 1); +	udelay(100); +} + +static void lcd_power_on(void) +{ +	struct pmic *p = pmic_get("MAX8998_PMIC"); + +	if (!p) +		return; + +	if (pmic_probe(p)) +		return; + +	pmic_set_output(p, MAX8998_REG_ONOFF3, MAX8998_LDO17, LDO_ON); +	pmic_set_output(p, MAX8998_REG_ONOFF2, MAX8998_LDO7, LDO_ON); +} + +vidinfo_t panel_info = { +	.vl_freq	= 60, +	.vl_col		= 480, +	.vl_row		= 800, +	.vl_width	= 480, +	.vl_height	= 800, +	.vl_clkp	= CONFIG_SYS_HIGH, +	.vl_hsp		= CONFIG_SYS_HIGH, +	.vl_vsp		= CONFIG_SYS_HIGH, +	.vl_dp		= CONFIG_SYS_HIGH, + +	.vl_bpix	= 5,	/* Bits per pixel */ + +	/* LD9040 LCD Panel */ +	.vl_hspw	= 2, +	.vl_hbpd	= 16, +	.vl_hfpd	= 16, + +	.vl_vspw	= 2, +	.vl_vbpd	= 8, +	.vl_vfpd	= 8, +	.vl_cmd_allow_len = 0xf, + +	.win_id		= 0, +	.cfg_gpio	= lcd_cfg_gpio, +	.backlight_on	= NULL, +	.lcd_power_on	= lcd_power_on, +	.reset_lcd	= reset_lcd, +	.dual_lcd_enabled = 0, + +	.init_delay	= 0, +	.power_on_delay = 10000, +	.reset_delay	= 10000, +	.interface_mode = FIMD_RGB_INTERFACE, +	.mipi_enabled	= 0, +}; + +void init_panel_info(vidinfo_t *vid) +{ +	vid->logo_on	= 1; +	vid->resolution	= HD_RESOLUTION; +	vid->rgb_mode	= MODE_RGB_P; + +#ifdef CONFIG_TIZEN +	get_tizen_logo_info(vid); +#endif + +	/* for LD9040. */ +	vid->pclk_name = 1;	/* MPLL */ +	vid->sclk_div = 1; + +	vid->cfg_ldo = ld9040_cfg_ldo; +	vid->enable_ldo = ld9040_enable_ldo; + +	setenv("lcdinfo", "lcd=ld9040"); +} + +int board_init(void) +{ +	gpio1 = (struct exynos4_gpio_part1 *) EXYNOS4_GPIO_PART1_BASE; +	gpio2 = (struct exynos4_gpio_part2 *) EXYNOS4_GPIO_PART2_BASE; + +	gd->bd->bi_arch_number = MACH_TYPE_UNIVERSAL_C210; +	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; + +#ifdef CONFIG_SOFT_SPI +	soft_spi_init(); +#endif +	check_hw_revision(); +	printf("HW Revision:\t0x%x\n", board_rev); + +	return 0; +} diff --git a/common/Makefile b/common/Makefile index c29a7d82e..54fcc8158 100644 --- a/common/Makefile +++ b/common/Makefile @@ -30,6 +30,7 @@ ifndef CONFIG_SPL_BUILD  COBJS-y += main.o  COBJS-y += command.o  COBJS-y += exports.o +COBJS-y += hash.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o  COBJS-y += s_record.o  COBJS-y += xyzModem.o @@ -43,7 +44,10 @@ 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  XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o @@ -75,6 +79,7 @@ COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o  COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o  COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o  COBJS-$(CONFIG_CMD_DATE) += cmd_date.o +COBJS-$(CONFIG_CMD_SOUND) += cmd_sound.o  ifdef CONFIG_4xx  COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o  endif @@ -100,8 +105,10 @@ ifdef CONFIG_FPGA  COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o  endif  COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o +COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o  COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o  COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o +COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o  COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o  COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o  COBJS-$(CONFIG_CMD_INI) += cmd_ini.o @@ -117,6 +124,7 @@ COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o  COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o  COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o  COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o +COBJS-$(CONFIG_CMD_IO) += cmd_io.o  COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o  COBJS-$(CONFIG_MII) += miiphyutil.o  COBJS-$(CONFIG_CMD_MII) += miiphyutil.o @@ -141,6 +149,7 @@ endif  COBJS-y += cmd_pcmcia.o  COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o  COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o +COBJS-$(CONFIG_CMD_READ) += cmd_read.o  COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o  COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o  COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o @@ -184,6 +193,7 @@ COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o  COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o  COBJS-y += flash.o  COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o +COBJS-$(CONFIG_I2C_EDID) += edid.o  COBJS-$(CONFIG_KALLSYMS) += kallsyms.o  COBJS-$(CONFIG_LCD) += lcd.o  COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o @@ -192,6 +202,7 @@ COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o  COBJS-$(CONFIG_UPDATE_TFTP) += update.o  COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o  COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o +COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o  endif  ifdef CONFIG_SPL_BUILD @@ -200,7 +211,10 @@ 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  endif diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 4dbe952bb..f7595c031 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -537,7 +537,7 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,  		}  			break;  #endif -#if defined(CONFIG_OF_LIBFDT) +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)  		case BOOTM_STATE_FDT:  		{  			boot_fdt_add_mem_rsv_regions(&images.lmb, diff --git a/common/cmd_gettime.c b/common/cmd_gettime.c new file mode 100644 index 000000000..d7d36a987 --- /dev/null +++ b/common/cmd_gettime.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * (C) Copyright 2001 + * 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 + */ + +/* + * Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec + */ +#include <common.h> +#include <command.h> + +static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc, +		      char * const argv[]) +{ +	unsigned long int val = get_timer(0); + +#ifdef CONFIG_SYS_HZ +	printf("Timer val: %lu\n", val); +	printf("Seconds : %lu\n", val / CONFIG_SYS_HZ); +	printf("Remainder : %lu\n", val % CONFIG_SYS_HZ); +	printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ); +#else +	printf("CONFIG_SYS_HZ not defined"); +	printf("Timer Val %lu", val); +#endif + +	return 0; +} + +U_BOOT_CMD( +	gettime,	1,	1,	do_gettime, +	"get timer val elapsed,\n", +	"get time elapsed from uboot start\n" +); diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c new file mode 100644 index 000000000..da7705da6 --- /dev/null +++ b/common/cmd_gpt.c @@ -0,0 +1,333 @@ +/* + * cmd_gpt.c -- GPT (GUID Partition Table) handling command + * + * Copyright (C) 2012 Samsung Electronics + * author: Lukasz Majewski <l.majewski@samsung.com> + * author: Piotr Wilczek <p.wilczek@samsung.com> + * + * 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 <command.h> +#include <mmc.h> +#include <part_efi.h> +#include <exports.h> +#include <linux/ctype.h> + +#ifndef CONFIG_PARTITION_UUIDS +#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled +#endif + +/** + * extract_env(): Expand env name from string format '&{env_name}' + *                and return pointer to the env (if the env is set) + * + * @param str - pointer to string + * @param env - pointer to pointer to extracted env + * + * @return - zero on successful expand and env is set + */ +static char extract_env(const char *str, char **env) +{ +	char *e, *s; + +	if (!str || strlen(str) < 4) +		return -1; + +	if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) { +		s = strdup(str); +		if (s == NULL) +			return -1; +		memset(s + strlen(s) - 1, '\0', 1); +		memmove(s, s + 2, strlen(s) - 1); +		e = getenv(s); +		free(s); +		if (e == NULL) { +			printf("Environmental '%s' not set\n", str); +			return -1; /* env not set */ +		} +		*env = e; +		return 0; +	} + +	return -1; +} + +/** + * extract_val(): Extract value from a key=value pair list (comma separated). + *                Only value for the given key is returend. + *                Function allocates memory for the value, remember to free! + * + * @param str - pointer to string with key=values pairs + * @param key - pointer to the key to search for + * + * @return - pointer to allocated string with the value + */ +static char *extract_val(const char *str, const char *key) +{ +	char *v, *k; +	char *s, *strcopy; +	char *new = NULL; + +	strcopy = strdup(str); +	if (strcopy == NULL) +		return NULL; + +	s = strcopy; +	while (s) { +		v = strsep(&s, ","); +		if (!v) +			break; +		k = strsep(&v, "="); +		if (!k) +			break; +		if  (strcmp(k, key) == 0) { +			new = strdup(v); +			break; +		} +	} + +	free(strcopy); + +	return new; +} + +/** + * set_gpt_info(): Fill partition information from string + *		function allocates memory, remember to free! + * + * @param dev_desc - pointer block device descriptor + * @param str_part - pointer to string with partition information + * @param str_disk_guid - pointer to pointer to allocated string with disk guid + * @param partitions - pointer to pointer to allocated partitions array + * @param parts_count - number of partitions + * + * @return - zero on success, otherwise error + * + */ +static int set_gpt_info(block_dev_desc_t *dev_desc, +			const char *str_part, +			char **str_disk_guid, +			disk_partition_t **partitions, +			u8 *parts_count) +{ +	char *tok, *str, *s; +	int i; +	char *val, *p; +	int p_count; +	disk_partition_t *parts; +	int errno = 0; + +	debug("%s: MMC lba num: 0x%x %d\n", __func__, +	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); + +	if (str_part == NULL) +		return -1; + +	str = strdup(str_part); + +	/* extract disk guid */ +	s = str; +	tok = strsep(&s, ";"); +	val = extract_val(tok, "uuid_disk"); +	if (!val) { +		free(str); +		return -2; +	} +	if (extract_env(val, &p)) +		p = val; +	*str_disk_guid = strdup(p); +	free(val); + +	if (strlen(s) == 0) +		return -3; + +	i = strlen(s) - 1; +	if (s[i] == ';') +		s[i] = '\0'; + +	/* calculate expected number of partitions */ +	p_count = 1; +	p = s; +	while (*p) { +		if (*p++ == ';') +			p_count++; +	} + +	/* allocate memory for partitions */ +	parts = calloc(sizeof(disk_partition_t), p_count); + +	/* retrive partions data from string */ +	for (i = 0; i < p_count; i++) { +		tok = strsep(&s, ";"); + +		if (tok == NULL) +			break; + +		/* uuid */ +		val = extract_val(tok, "uuid"); +		if (!val) { /* 'uuid' is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		if (strlen(p) >= sizeof(parts[i].uuid)) { +			printf("Wrong uuid format for partition %d\n", i); +			errno = -4; +			goto err; +		} +		strcpy((char *)parts[i].uuid, p); +		free(val); + +		/* name */ +		val = extract_val(tok, "name"); +		if (!val) { /* name is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		if (strlen(p) >= sizeof(parts[i].name)) { +			errno = -4; +			goto err; +		} +		strcpy((char *)parts[i].name, p); +		free(val); + +		/* size */ +		val = extract_val(tok, "size"); +		if (!val) { /* 'size' is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		parts[i].size = ustrtoul(p, &p, 0); +		parts[i].size /= dev_desc->blksz; +		free(val); + +		/* start address */ +		val = extract_val(tok, "start"); +		if (val) { /* start address is optional */ +			if (extract_env(val, &p)) +				p = val; +			parts[i].start = ustrtoul(p, &p, 0); +			parts[i].start /= dev_desc->blksz; +			free(val); +		} +	} + +	*parts_count = p_count; +	*partitions = parts; +	free(str); + +	return 0; +err: +	free(str); +	free(*str_disk_guid); +	free(parts); + +	return errno; +} + +static int gpt_mmc_default(int dev, const char *str_part) +{ +	int ret; +	char *str_disk_guid; +	u8 part_count = 0; +	disk_partition_t *partitions = NULL; + +	struct mmc *mmc = find_mmc_device(dev); + +	if (mmc == NULL) { +		printf("%s: mmc dev %d NOT available\n", __func__, dev); +		return CMD_RET_FAILURE; +	} + +	if (!str_part) +		return -1; + +	/* fill partitions */ +	ret = set_gpt_info(&mmc->block_dev, str_part, +			&str_disk_guid, &partitions, &part_count); +	if (ret) { +		if (ret == -1) +			printf("No partition list provided\n"); +		if (ret == -2) +			printf("Missing disk guid\n"); +		if ((ret == -3) || (ret == -4)) +			printf("Partition list incomplete\n"); +		return -1; +	} + +	/* save partitions layout to disk */ +	gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count); +	free(str_disk_guid); +	free(partitions); + +	return 0; +} + +/** + * do_gpt(): Perform GPT operations + * + * @param cmdtp - command name + * @param flag + * @param argc + * @param argv + * + * @return zero on success; otherwise error + */ +static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	int ret = CMD_RET_SUCCESS; +	int dev = 0; +	char *pstr; + +	if (argc < 5) +		return CMD_RET_USAGE; + +	/* command: 'write' */ +	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { +		/* device: 'mmc' */ +		if (strcmp(argv[2], "mmc") == 0) { +			/* check if 'dev' is a number */ +			for (pstr = argv[3]; *pstr != '\0'; pstr++) +				if (!isdigit(*pstr)) { +					printf("'%s' is not a number\n", +						argv[3]); +					return CMD_RET_USAGE; +				} +			dev = (int)simple_strtoul(argv[3], NULL, 10); +			/* write to mmc */ +			if (gpt_mmc_default(dev, argv[4])) +				return CMD_RET_FAILURE; +		} +	} else { +		return CMD_RET_USAGE; +	} +	return ret; +} + +U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, +	"GUID Partition Table", +	"<command> <interface> <dev> <partions_list>\n" +	" - GUID partition table restoration\n" +	" Restore GPT information on a device connected\n" +	" to interface\n" +); diff --git a/common/cmd_hash.c b/common/cmd_hash.c new file mode 100644 index 000000000..689c60857 --- /dev/null +++ b/common/cmd_hash.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@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. + * + * 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 <hash.h> + +static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +#ifdef CONFIG_HASH_VERIFY +	int verify = 0; + +	if (!strcmp(argv[1], "-v")) { +		verify = 1; +		argc--; +		argv++; +	} +#endif +	/* Move forward to 'algorithm' parameter */ +	argc--; +	argv++; +	return hash_command(*argv, verify, cmdtp, flag, argc - 1, argv + 1); +} + +#ifdef CONFIG_HASH_VERIFY +U_BOOT_CMD( +	hash,	6,	1,	do_hash, +	"compute hash message digest", +	"algorithm address count [[*]sum_dest]\n" +		"    - compute message digest [save to env var / *address]\n" +	"hash -v algorithm address count [*]sum\n" +		"    - verify hash of memory area with env var / *address" +); +#else +U_BOOT_CMD( +	hash,	5,	1,	do_hash, +	"compute message digest", +	"algorithm address count [[*]sum_dest]\n" +		"    - compute message digest [save to env var / *address]" +); +#endif diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 4438db594..438079447 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -78,10 +78,12 @@  #include <common.h>  #include <command.h> +#include <edid.h>  #include <environment.h>  #include <i2c.h>  #include <malloc.h>  #include <asm/byteorder.h> +#include <linux/compiler.h>  /* Display values from last command.   * Memory modify remembered values are different from display memory. @@ -132,35 +134,65 @@ DECLARE_GLOBAL_DATA_PTR;  #define DISP_LINE_LEN	16 -/* implement possible board specific board init */ -static void __def_i2c_init_board(void) +/** + * i2c_init_board() - Board-specific I2C bus init + * + * This function is the default no-op implementation of I2C bus + * initialization. This function can be overriden by board-specific + * implementation if needed. + */ +__weak +void i2c_init_board(void)  {  	return;  } -void i2c_init_board(void) -	__attribute__((weak, alias("__def_i2c_init_board")));  /* TODO: Implement architecture-specific get/set functions */ -static unsigned int __def_i2c_get_bus_speed(void) + +/** + * i2c_get_bus_speed() - Return I2C bus speed + * + * This function is the default implementation of function for retrieveing + * the current I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns I2C bus speed in Hz. + */ +__weak +unsigned int i2c_get_bus_speed(void)  {  	return CONFIG_SYS_I2C_SPEED;  } -unsigned int i2c_get_bus_speed(void) -	__attribute__((weak, alias("__def_i2c_get_bus_speed"))); -static int __def_i2c_set_bus_speed(unsigned int speed) +/** + * i2c_set_bus_speed() - Configure I2C bus speed + * @speed:	Newly set speed of the I2C bus in Hz + * + * This function is the default implementation of function for setting + * the I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns zero on success, negative value on error. + */ +__weak +int i2c_set_bus_speed(unsigned int speed)  {  	if (speed != CONFIG_SYS_I2C_SPEED)  		return -1;  	return 0;  } -int i2c_set_bus_speed(unsigned int) -	__attribute__((weak, alias("__def_i2c_set_bus_speed"))); -/* - * get_alen: small parser helper function to get address length - * returns the address length +/** + * get_alen() - Small parser helper function to get address length + * + * Returns the address length.   */  static uint get_alen(char *arg)  { @@ -178,11 +210,19 @@ static uint get_alen(char *arg)  	return alen;  } -/* +/** + * do_i2c_read() - Handle the "i2c read" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr}   */ -  static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	u_char	chip; @@ -271,7 +311,16 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[  	return 0;  } -/* +/** + * do_i2c_md() - Handle the "i2c md" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c md {i2c_chip} {addr}{.0, .1, .2} {len}   */ @@ -363,8 +412,15 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  	return 0;  } - -/* Write (fill) memory +/** + * do_i2c_mw() - Handle the "i2c mw" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] @@ -421,10 +477,20 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  #endif  	} -	return (0); +	return 0;  } -/* Calculate a CRC on memory +/** + * do_i2c_crc() - Handle the "i2c crc32" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Calculate a CRC on memory + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count} @@ -481,13 +547,22 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  	return 0;  } -/* Modify memory. +/** + * mod_i2c_mem() - Handle the "i2c mm" and "i2c nm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Modify memory. + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}   *	i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}   */ -  static int  mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])  { @@ -603,7 +678,16 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg  	return 0;  } -/* +/** + * do_i2c_probe() - Handle the "i2c probe" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c probe {addr}   * @@ -657,7 +741,16 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv  	return (0 == found);  } -/* +/** + * do_i2c_loop() - Handle the "i2c loop" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}]   *	{length} - Number of bytes to read @@ -718,6 +811,8 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  /*   * The SDRAM command is separately configured because many   * (most?) embedded boards don't use SDRAM DIMMs. + * + * FIXME: Document and probably move elsewhere!   */  #if defined(CONFIG_CMD_SDRAM)  static void print_ddr2_tcyc (u_char const b) @@ -1246,7 +1341,48 @@ static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  }  #endif +/* + * Syntax: + *	i2c edid {i2c_chip} + */ +#if defined(CONFIG_I2C_EDID) +int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	u_char chip; +	struct edid1_info edid; + +	if (argc < 2) { +		cmd_usage(cmdtp); +		return 1; +	} + +	chip = simple_strtoul(argv[1], NULL, 16); +	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { +		puts("Error reading EDID content.\n"); +		return 1; +	} + +	if (edid_check_info(&edid)) { +		puts("Content isn't valid EDID.\n"); +		return 1; +	} + +	edid_print_info(&edid); +	return 0; + +} +#endif /* CONFIG_I2C_EDID */ +  #if defined(CONFIG_I2C_MUX) +/** + * do_i2c_add_bus() - Handle the "i2c bus" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero always. + */  static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int ret=0; @@ -1276,6 +1412,16 @@ static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar  #endif  /* CONFIG_I2C_MUX */  #if defined(CONFIG_I2C_MULTI_BUS) +/** + * do_i2c_bus_num() - Handle the "i2c dev" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int bus_idx, ret=0; @@ -1294,6 +1440,16 @@ static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar  }  #endif  /* CONFIG_I2C_MULTI_BUS */ +/** + * do_i2c_bus_speed() - Handle the "i2c speed" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int speed, ret=0; @@ -1311,16 +1467,45 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const  	return ret;  } +/** + * do_i2c_mm() - Handle the "i2c mm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	return mod_i2c_mem (cmdtp, 1, flag, argc, argv);  } +/** + * do_i2c_nm() - Handle the "i2c nm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	return mod_i2c_mem (cmdtp, 0, flag, argc, argv);  } +/** + * do_i2c_reset() - Handle the "i2c reset" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero always. + */  static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -1335,6 +1520,9 @@ static cmd_tbl_t cmd_i2c_sub[] = {  #if defined(CONFIG_I2C_MULTI_BUS)  	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),  #endif  /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) +	U_BOOT_CMD_MKENT(edid, 1, 1, do_edid, "", ""), +#endif  /* CONFIG_I2C_EDID */  	U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""),  	U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""),  	U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""), @@ -1356,6 +1544,16 @@ void i2c_reloc(void) {  }  #endif +/** + * do_i2c() - Handle the "i2c" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	cmd_tbl_t *c; @@ -1385,6 +1583,9 @@ static char i2c_help_text[] =  #if defined(CONFIG_I2C_MULTI_BUS)  	"i2c dev [dev] - show or set current I2C bus\n"  #endif  /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) +	"i2c edid chip - print EDID configuration information\n" +#endif  /* CONFIG_I2C_EDID */  	"i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n"  	"i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n"  	"i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n" diff --git a/common/cmd_io.c b/common/cmd_io.c new file mode 100644 index 000000000..6450cb576 --- /dev/null +++ b/common/cmd_io.c @@ -0,0 +1,93 @@ +/* + * 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 + */ + +/* + * IO space access commands. + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> + +/* + * IO Display + * + * Syntax: + *	iod{.b, .w, .l} {addr} + */ +int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	ulong addr; +	int size; + +	if (argc != 2) +		return CMD_RET_USAGE; + +	size = cmd_get_data_size(argv[0], 4); +	if (size < 0) +		return 1; + +	addr = simple_strtoul(argv[1], NULL, 16); + +	printf("%04x: ", (u16) addr); + +	if (size == 4) +		printf("%08x\n", inl(addr)); +	else if (size == 2) +		printf("%04x\n", inw(addr)); +	else +		printf("%02x\n", inb(addr)); + +	return 0; +} + +int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	ulong addr, size, val; + +	if (argc != 3) +		return CMD_RET_USAGE; + +	size = cmd_get_data_size(argv[0], 4); +	if (size < 0) +		return 1; + +	addr = simple_strtoul(argv[1], NULL, 16); +	val = simple_strtoul(argv[2], NULL, 16); + +	if (size == 4) +		outl((u32) val, addr); +	else if (size == 2) +		outw((u16) val, addr); +	else +		outb((u8) val, addr); + +	return 0; +} + +/**************************************************/ +U_BOOT_CMD(iod, 2, 0, do_io_iod, +	   "IO space display", "[.b, .w, .l] address [# of objects]"); + +U_BOOT_CMD(iow, 3, 0, do_io_iow, +	   "IO space modify (auto-incrementing address)", +	   "[.b, .w, .l] address"); diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 006131f45..7633f0c44 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -47,12 +47,8 @@  #include <errno.h>  #include <malloc.h>  #include <watchdog.h> -#include <serial.h>  #include <linux/stddef.h>  #include <asm/byteorder.h> -#if defined(CONFIG_CMD_NET) -#include <net.h> -#endif  DECLARE_GLOBAL_DATA_PTR; @@ -76,16 +72,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE   */  #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */ -ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */ -ulong save_addr;			/* Default Save Address */ -ulong save_size;			/* Default Save Size (in bytes) */ - -/* - * 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])) -  /*   * This variable is incremented on each do_env_set(), so it can   * be used via get_env_id() as an indication, if the environment @@ -106,7 +92,7 @@ int get_env_id(void)   *   * Returns 0 in case of error, or length of printed string   */ -static int env_print(char *name) +static int env_print(char *name, int flag)  {  	char *res = NULL;  	size_t len; @@ -116,7 +102,7 @@ static int env_print(char *name)  		e.key = name;  		e.data = NULL; -		hsearch_r(e, FIND, &ep, &env_htab); +		hsearch_r(e, FIND, &ep, &env_htab, flag);  		if (ep == NULL)  			return 0;  		len = printf("%s=%s\n", ep->key, ep->data); @@ -124,7 +110,7 @@ static int env_print(char *name)  	}  	/* print whole list */ -	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL); +	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);  	if (len > 0) {  		puts(res); @@ -141,10 +127,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,  {  	int i;  	int rcode = 0; +	int env_flag = H_HIDE_DOT; + +	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { +		argc--; +		argv++; +		env_flag &= ~H_HIDE_DOT; +	}  	if (argc == 1) {  		/* print all env vars */ -		rcode = env_print(NULL); +		rcode = env_print(NULL, env_flag);  		if (!rcode)  			return 1;  		printf("\nEnvironment size: %d/%ld bytes\n", @@ -153,8 +146,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,  	}  	/* print selected env vars */ +	env_flag &= ~H_HIDE_DOT;  	for (i = 1; i < argc; ++i) { -		int rc = env_print(argv[i]); +		int rc = env_print(argv[i], env_flag);  		if (!rc) {  			printf("## Error: \"%s\" not defined\n", argv[i]);  			++rcode; @@ -198,137 +192,32 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,  #endif /* CONFIG_SPL_BUILD */  /* - * Perform consistency checking before setting, replacing, or deleting an - * environment variable, then (if successful) apply the changes to internals so - * to make them effective.  Code for this function was taken out of - * _do_env_set(), which now calls it instead. - * Also called as a callback function by himport_r(). - * Returns 0 in case of success, 1 in case of failure. - * When (flag & H_FORCE) is set, do not print out any error message and force - * overwriting of write-once variables. - */ - -int env_check_apply(const char *name, const char *oldval, -			const char *newval, int flag) -{ -	int   console = -1; - -	/* Default value for NULL to protect string-manipulating functions */ -	newval = newval ? : ""; - -	/* Check for console redirection */ -	if (strcmp(name, "stdin") == 0) -		console = stdin; -	else if (strcmp(name, "stdout") == 0) -		console = stdout; -	else if (strcmp(name, "stderr") == 0) -		console = stderr; - -	if (console != -1) { -		if ((newval == NULL) || (*newval == '\0')) { -			/* We cannot delete stdin/stdout/stderr */ -			if ((flag & H_FORCE) == 0) -				printf("Can't delete \"%s\"\n", name); -			return 1; -		} - -#ifdef CONFIG_CONSOLE_MUX -		if (iomux_doenv(console, newval)) -			return 1; -#else -		/* Try assigning specified device */ -		if (console_assign(console, newval) < 0) -			return 1; -#endif /* CONFIG_CONSOLE_MUX */ -	} - -	/* -	 * Some variables like "ethaddr" and "serial#" can be set only once and -	 * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. -	 */ -#ifndef CONFIG_ENV_OVERWRITE -	if (oldval != NULL &&			/* variable exists */ -		(flag & H_FORCE) == 0) {	/* and we are not forced */ -		if (strcmp(name, "serial#") == 0 || -		    (strcmp(name, "ethaddr") == 0 -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) -		     && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 -#endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ -			)) { -			printf("Can't overwrite \"%s\"\n", name); -			return 1; -		} -	} -#endif -	/* -	 * When we change baudrate, or we are doing an env default -a -	 * (which will erase all variables prior to calling this), -	 * we want the baudrate to actually change - for real. -	 */ -	if (oldval != NULL ||			/* variable exists */ -		(flag & H_NOCLEAR) == 0) {	/* or env is clear */ -		/* -		 * Switch to new baudrate if new baudrate is supported -		 */ -		if (strcmp(name, "baudrate") == 0) { -			int baudrate = simple_strtoul(newval, NULL, 10); -			int i; -			for (i = 0; i < N_BAUDRATES; ++i) { -				if (baudrate == baudrate_table[i]) -					break; -			} -			if (i == N_BAUDRATES) { -				if ((flag & H_FORCE) == 0) -					printf("## Baudrate %d bps not " -						"supported\n", baudrate); -				return 1; -			} -			if (gd->baudrate == baudrate) { -				/* If unchanged, we just say it's OK */ -				return 0; -			} -			printf("## Switch baudrate to %d bps and" -				"press ENTER ...\n", baudrate); -			udelay(50000); -			gd->baudrate = baudrate; -#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) -			gd->bd->bi_baudrate = baudrate; -#endif - -			serial_setbrg(); -			udelay(50000); -			while (getc() != '\r') -				; -		} -	} - -	/* -	 * Some variables should be updated when the corresponding -	 * entry in the environment is changed -	 */ -	if (strcmp(name, "loadaddr") == 0) { -		load_addr = simple_strtoul(newval, NULL, 16); -		return 0; -	} -#if defined(CONFIG_CMD_NET) -	else if (strcmp(name, "bootfile") == 0) { -		copy_filename(BootFile, newval, sizeof(BootFile)); -		return 0; -	} -#endif -	return 0; -} - -/*   * Set a new environment variable,   * or replace or delete an existing one. -*/ + */  static int _do_env_set(int flag, int argc, char * const argv[])  {  	int   i, len;  	char  *name, *value, *s;  	ENTRY e, *ep; +	int env_flag = H_INTERACTIVE; +	debug("Initial value for argc=%d\n", argc); +	while (argc > 1 && **(argv + 1) == '-') { +		char *arg = *++argv; + +		--argc; +		while (*++arg) { +			switch (*arg) { +			case 'f':		/* force */ +				env_flag |= H_FORCE; +				break; +			default: +				return CMD_RET_USAGE; +			} +		} +	} +	debug("Final value for argc=%d\n", argc);  	name = argv[1];  	value = argv[2]; @@ -339,25 +228,10 @@ static int _do_env_set(int flag, int argc, char * const argv[])  	}  	env_id++; -	/* -	 * search if variable with this name already exists -	 */ -	e.key = name; -	e.data = NULL; -	hsearch_r(e, FIND, &ep, &env_htab); - -	/* -	 * Perform requested checks. Notice how since we are overwriting -	 * a single variable, we need to set H_NOCLEAR -	 */ -	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { -		debug("check function did not approve, refusing\n"); -		return 1; -	}  	/* Delete only ? */  	if (argc < 3 || argv[2] == NULL) { -		int rc = hdelete_r(name, &env_htab, 0); +		int rc = hdelete_r(name, &env_htab, env_flag);  		return !rc;  	} @@ -384,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])  	e.key	= name;  	e.data	= value; -	hsearch_r(e, ENTER, &ep, &env_htab); +	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);  	free(value);  	if (!ep) {  		printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -511,6 +385,153 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  }  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +static int print_static_binding(const char *var_name, const char *callback_name) +{ +	printf("\t%-20s %-20s\n", var_name, callback_name); + +	return 0; +} + +static int print_active_callback(ENTRY *entry) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks; + +	if (entry->callback == NULL) +		return 0; + +	/* look up the callback in the linker-list */ +	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) { +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +		if (entry->callback == clbkp->callback + gd->reloc_off) +#else +		if (entry->callback == clbkp->callback) +#endif +			break; +	} + +	if (i == num_callbacks) +		/* this should probably never happen, but just in case... */ +		printf("\t%-20s %p\n", entry->key, entry->callback); +	else +		printf("\t%-20s %-20s\n", entry->key, clbkp->name); + +	return 0; +} + +/* + * Print the callbacks available and what they are bound to + */ +int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks; + +	/* Print the available callbacks */ +	puts("Available callbacks:\n"); +	puts("\tCallback Name\n"); +	puts("\t-------------\n"); +	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) +		printf("\t%s\n", clbkp->name); +	puts("\n"); + +	/* Print the static bindings that may exist */ +	puts("Static callback bindings:\n"); +	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); +	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding); +	puts("\n"); + +	/* walk through each variable and print the callback if it has one */ +	puts("Active callback bindings:\n"); +	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); +	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	hwalk_r(&env_htab, print_active_callback); +	return 0; +} +#endif + +#if defined(CONFIG_CMD_ENV_FLAGS) +static int print_static_flags(const char *var_name, const char *flags) +{ +	enum env_flags_vartype type = env_flags_parse_vartype(flags); +	enum env_flags_varaccess access = env_flags_parse_varaccess(flags); + +	printf("\t%-20s %-20s %-20s\n", var_name, +		env_flags_get_vartype_name(type), +		env_flags_get_varaccess_name(access)); + +	return 0; +} + +static int print_active_flags(ENTRY *entry) +{ +	enum env_flags_vartype type; +	enum env_flags_varaccess access; + +	if (entry->flags == 0) +		return 0; + +	type = (enum env_flags_vartype) +		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); +	access = env_flags_parse_varaccess_from_binflags(entry->flags); +	printf("\t%-20s %-20s %-20s\n", entry->key, +		env_flags_get_vartype_name(type), +		env_flags_get_varaccess_name(access)); + +	return 0; +} + +/* + * Print the flags available and what variables have flags + */ +int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	/* Print the available variable types */ +	printf("Available variable type flags (position %d):\n", +		ENV_FLAGS_VARTYPE_LOC); +	puts("\tFlag\tVariable Type Name\n"); +	puts("\t----\t------------------\n"); +	env_flags_print_vartypes(); +	puts("\n"); + +	/* Print the available variable access types */ +	printf("Available variable access flags (position %d):\n", +		ENV_FLAGS_VARACCESS_LOC); +	puts("\tFlag\tVariable Access Name\n"); +	puts("\t----\t--------------------\n"); +	env_flags_print_varaccess(); +	puts("\n"); + +	/* Print the static flags that may exist */ +	puts("Static flags:\n"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------"); +	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); +	puts("\n"); + +	/* walk through each variable and print the flags if non-default */ +	puts("Active flags:\n"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------"); +	hwalk_r(&env_htab, print_active_flags); +	return 0; +} +#endif +  /*   * Interactively edit an environment variable   */ @@ -552,7 +573,7 @@ char *getenv(const char *name)  		e.key	= name;  		e.data	= NULL; -		hsearch_r(e, FIND, &ep, &env_htab); +		hsearch_r(e, FIND, &ep, &env_htab, 0);  		return ep ? ep->data : NULL;  	} @@ -704,8 +725,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag,  static int do_env_delete(cmd_tbl_t *cmdtp, int flag,  			 int argc, char * const argv[])  { -	printf("Not implemented yet\n"); -	return 0; +	int env_flag = H_INTERACTIVE; +	int ret = 0; + +	debug("Initial value for argc=%d\n", argc); +	while (argc > 1 && **(argv + 1) == '-') { +		char *arg = *++argv; + +		--argc; +		while (*++arg) { +			switch (*arg) { +			case 'f':		/* force */ +				env_flag |= H_FORCE; +				break; +			default: +				return CMD_RET_USAGE; +			} +		} +	} +	debug("Final value for argc=%d\n", argc); + +	env_id++; + +	while (--argc > 0) { +		char *name = *++argv; + +		if (!hdelete_r(name, &env_htab, env_flag)) +			ret = 1; +	} + +	return ret;  }  #ifdef CONFIG_CMD_EXPORTENV @@ -812,7 +861,7 @@ NXTARG:		;  	argv++;  	if (sep) {		/* export as text file */ -		len = hexport_r(&env_htab, sep, &addr, size, argc, argv); +		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);  		if (len < 0) {  			error("Cannot export environment: errno = %d\n", errno);  			return 1; @@ -830,7 +879,7 @@ NXTARG:		;  	else			/* export as raw binary data */  		res = addr; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -951,7 +1000,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,  	}  	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, -			0, NULL, 0 /* do_apply */) == 0) { +			0, NULL) == 0) {  		error("Environment import failed: errno = %d\n", errno);  		return 1;  	} @@ -974,10 +1023,16 @@ static cmd_tbl_t cmd_env_sub[] = {  	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),  #endif  	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), -	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""), +	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),  #if defined(CONFIG_CMD_EDITENV)  	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), +#endif +#if defined(CONFIG_CMD_ENV_FLAGS) +	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), +#endif  #if defined(CONFIG_CMD_EXPORTENV)  	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),  #endif @@ -1028,21 +1083,28 @@ static char env_help_text[] =  #if defined(CONFIG_CMD_ASKENV)  	"ask name [message] [size] - ask for environment variable\nenv "  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +	"callbacks - print callbacks and their associated variables\nenv " +#endif  	"default [-f] -a - [forcibly] reset default environment\n"  	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" +	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"  #if defined(CONFIG_CMD_EDITENV)  	"env edit name - edit environment variable\n"  #endif  #if defined(CONFIG_CMD_EXPORTENV)  	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"  #endif +#if defined(CONFIG_CMD_ENV_FLAGS) +	"env flags - print variables that have non-default flags\n" +#endif  #if defined(CONFIG_CMD_GREPENV)  	"env grep string [...] - search environment\n"  #endif  #if defined(CONFIG_CMD_IMPORTENV)  	"env import [-d] [-t | -b | -c] addr [size] - import environment\n"  #endif -	"env print [name ...] - print environment\n" +	"env print [-a | name ...] - print environment\n"  #if defined(CONFIG_CMD_RUN)  	"env run var [...] - run commands in an environment variable\n"  #endif @@ -1074,7 +1136,7 @@ U_BOOT_CMD_COMPLETE(  U_BOOT_CMD_COMPLETE(  	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,  	"print environment variables", -	"\n    - print values of all environment variables\n" +	"[-a]\n    - print [all] values of all environment variables\n"  	"printenv name ...\n"  	"    - print value of environment variable 'name'",  	var_complete @@ -1093,10 +1155,10 @@ U_BOOT_CMD_COMPLETE(  U_BOOT_CMD_COMPLETE(  	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,  	"set environment variables", -	"name value ...\n" -	"    - set environment variable 'name' to 'value ...'\n" -	"setenv name\n" -	"    - delete environment variable 'name'", +	"[-f] name value ...\n" +	"    - [forcibly] set environment variable 'name' to 'value ...'\n" +	"setenv [-f] name\n" +	"    - [forcibly] delete environment variable 'name'",  	var_complete  ); diff --git a/common/cmd_read.c b/common/cmd_read.c new file mode 100644 index 000000000..f0fc9bfe1 --- /dev/null +++ b/common/cmd_read.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 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. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <part.h> + +int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	char *ep; +	block_dev_desc_t *dev_desc = NULL; +	int dev; +	int part = 0; +	disk_partition_t part_info; +	ulong offset = 0u; +	ulong limit = 0u; +	void *addr; +	uint blk; +	uint cnt; + +	if (argc != 6) { +		cmd_usage(cmdtp); +		return 1; +	} + +	dev = (int)simple_strtoul(argv[2], &ep, 16); +	if (*ep) { +		if (*ep != ':') { +			printf("Invalid block device %s\n", argv[2]); +			return 1; +		} +		part = (int)simple_strtoul(++ep, NULL, 16); +	} + +	dev_desc = get_dev(argv[1], dev); +	if (dev_desc == NULL) { +		printf("Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} + +	addr = (void *)simple_strtoul(argv[3], NULL, 16); +	blk = simple_strtoul(argv[4], NULL, 16); +	cnt = simple_strtoul(argv[5], NULL, 16); + +	if (part != 0) { +		if (get_partition_info(dev_desc, part, &part_info)) { +			printf("Cannot find partition %d\n", part); +			return 1; +		} +		offset = part_info.start; +		limit = part_info.size; +	} else { +		/* Largest address not available in block_dev_desc_t. */ +		limit = ~0; +	} + +	if (cnt + blk > limit) { +		printf("Read out of range\n"); +		return 1; +	} + +	if (dev_desc->block_read(dev, offset + blk, cnt, addr) < 0) { +		printf("Error reading blocks\n"); +		return 1; +	} + +	return 0; +} + +U_BOOT_CMD( +	read,	6,	0,	do_read, +	"Load binary data from a partition", +	"<interface> <dev[:part]> addr blk# cnt" +); diff --git a/common/cmd_sha1sum.c b/common/cmd_sha1sum.c index 8db5456c9..fe927ab24 100644 --- a/common/cmd_sha1sum.c +++ b/common/cmd_sha1sum.c @@ -26,73 +26,11 @@  #include <common.h>  #include <command.h> +#include <hash.h>  #include <sha1.h> -/* - * Store the resulting sum to an address or variable - */ -static void store_result(const u8 *sum, const char *dest) -{ -	unsigned int i; - -	if (*dest == '*') { -		u8 *ptr; - -		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); -		for (i = 0; i < 20; i++) -			*ptr++ = sum[i]; -	} else { -		char str_output[41]; -		char *str_ptr = str_output; - -		for (i = 0; i < 20; i++) { -			sprintf(str_ptr, "%02x", sum[i]); -			str_ptr += 2; -		} -		str_ptr = '\0'; -		setenv(dest, str_output); -	} -} - -#ifdef CONFIG_SHA1SUM_VERIFY -static int parse_verify_sum(char *verify_str, u8 *vsum) -{ -	if (*verify_str == '*') { -		u8 *ptr; - -		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); -		memcpy(vsum, ptr, 20); -	} else { -		unsigned int i; -		char *vsum_str; - -		if (strlen(verify_str) == 40) -			vsum_str = verify_str; -		else { -			vsum_str = getenv(verify_str); -			if (vsum_str == NULL || strlen(vsum_str) != 40) -				return 1; -		} - -		for (i = 0; i < 20; i++) { -			char *nullp = vsum_str + (i + 1) * 2; -			char end = *nullp; - -			*nullp = '\0'; -			*(u8 *)(vsum + i) = -				simple_strtoul(vsum_str + (i * 2), NULL, 16); -			*nullp = end; -		} -	} -	return 0; -} -  int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	ulong addr, len; -	unsigned int i; -	u8 output[20]; -	u8 vsum[20];  	int verify = 0;  	int ac;  	char * const *av; @@ -102,75 +40,16 @@ int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	av = argv + 1;  	ac = argc - 1; +#ifdef CONFIG_SHA1SUM_VERIFY  	if (strcmp(*av, "-v") == 0) {  		verify = 1;  		av++;  		ac--; -		if (ac < 3) -			return CMD_RET_USAGE;  	} +#endif -	addr = simple_strtoul(*av++, NULL, 16); -	len = simple_strtoul(*av++, NULL, 16); - -	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); - -	if (!verify) { -		printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); -		for (i = 0; i < 20; i++) -			printf("%02x", output[i]); -		printf("\n"); - -		if (ac > 2) -			store_result(output, *av); -	} else { -		char *verify_str = *av++; - -		if (parse_verify_sum(verify_str, vsum)) { -			printf("ERROR: %s does not contain a valid SHA1 sum\n", -				verify_str); -			return 1; -		} -		if (memcmp(output, vsum, 20) != 0) { -			printf("SHA1 for %08lx ... %08lx ==> ", addr, -				addr + len - 1); -			for (i = 0; i < 20; i++) -				printf("%02x", output[i]); -			printf(" != "); -			for (i = 0; i < 20; i++) -				printf("%02x", vsum[i]); -			printf(" ** ERROR **\n"); -			return 1; -		} -	} - -	return 0; -} -#else -static int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ -	unsigned long addr, len; -	unsigned int i; -	u8 output[20]; - -	if (argc < 3) -		return CMD_RET_USAGE; - -	addr = simple_strtoul(argv[1], NULL, 16); -	len = simple_strtoul(argv[2], NULL, 16); - -	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); -	printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); -	for (i = 0; i < 20; i++) -		printf("%02x", output[i]); -	printf("\n"); - -	if (argc > 3) -		store_result(output, argv[3]); - -	return 0; +	return hash_command("sha1", verify, cmdtp, flag, ac, av);  } -#endif  #ifdef CONFIG_SHA1SUM_VERIFY  U_BOOT_CMD( diff --git a/common/cmd_sound.c b/common/cmd_sound.c new file mode 100644 index 000000000..459d1ebaf --- /dev/null +++ b/common/cmd_sound.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Rajeshwari Shinde <rajeshwari.s@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 <command.h> +#include <fdtdec.h> +#include <sound.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Initilaise sound subsystem */ +static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	int ret; + +	ret = sound_init(); +	if (ret) { +		printf("Initialise Audio driver failed\n"); +		return CMD_RET_FAILURE; +	} + +	return 0; +} + +/* play sound from buffer */ +static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	int ret = 0; +	int msec = 1000; +	int freq = 400; + +	if (argc > 1) +		msec = simple_strtoul(argv[1], NULL, 10); +	if (argc > 2) +		freq = simple_strtoul(argv[2], NULL, 10); + +	ret = sound_play(msec, freq); +	if (ret) { +		printf("play failed"); +		return CMD_RET_FAILURE; +	} + +	return 0; +} + +static cmd_tbl_t cmd_sound_sub[] = { +	U_BOOT_CMD_MKENT(init, 0, 1, do_init, "", ""), +	U_BOOT_CMD_MKENT(play, 2, 1, do_play, "", ""), +}; + +/* process sound command */ +static int do_sound(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	cmd_tbl_t *c; + +	if (argc < 1) +		return CMD_RET_USAGE; + +	/* Strip off leading 'sound' command argument */ +	argc--; +	argv++; + +	c = find_cmd_tbl(argv[0], &cmd_sound_sub[0], ARRAY_SIZE(cmd_sound_sub)); + +	if (c) +		return c->cmd(cmdtp, flag, argc, argv); +	else +		return CMD_RET_USAGE; +} + +U_BOOT_CMD( +	sound, 4, 1, do_sound, +	"sound sub-system", +	"init - initialise the sound driver\n" +	"sound play [len] [freq] - play a sound for len ms at freq hz\n" +); diff --git a/common/cmd_spl.c b/common/cmd_spl.c index 9ec054af3..e3c543b46 100644 --- a/common/cmd_spl.c +++ b/common/cmd_spl.c @@ -130,10 +130,12 @@ static int spl_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		if (call_bootm(argc, argv, subcmd_list[(int)c->cmd]))  			return -1;  		switch ((int)c->cmd) { +#ifdef CONFIG_OF_LIBFDT  		case SPL_EXPORT_FDT:  			printf("Argument image is now in RAM: 0x%p\n",  				(void *)images.ft_addr);  			break; +#endif  		case SPL_EXPORT_ATAGS:  			printf("Argument image is now in RAM at: 0x%p\n",  				(void *)gd->bd->bi_boot_params); diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c index 6f5cd4895..0970a6fc1 100644 --- a/common/cmd_tpm.c +++ b/common/cmd_tpm.c @@ -63,19 +63,68 @@ static int tpm_process(int argc, char * const argv[], cmd_tbl_t *cmdtp)  	return rv;  } -static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +#define CHECK(exp) do {							\ +		int _rv = exp;						\ +		if (_rv) {						\ +			printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ +		}							\ +	} while (0) + +static int tpm_process_stress(int repeat_count)  { +	int i;  	int rv = 0; +	u8 request[] = {0x0, 0xc1, +			0x0, 0x0, 0x0, 0x16, +			0x0, 0x0, 0x0, 0x65, +			0x0, 0x0, 0x0, 0x4, +			0x0, 0x0, 0x0, 0x4, +			0x0, 0x0, 0x1, 0x9}; +	u8 response[MAX_TRANSACTION_SIZE]; +	u32 rlength = MAX_TRANSACTION_SIZE; + +	CHECK(tis_init()); + +	for (i = 0; i < repeat_count; i++) { +		CHECK(tis_open()); +		rv = tis_sendrecv(request, sizeof(request), response, &rlength); +		if (rv) { +			printf("tpm test failed at step %d with 0x%x\n", i, rv); +			CHECK(tis_close()); +			break; +		} +		CHECK(tis_close()); +		if ((response[6] || response[7] || response[8] || response[9]) +		    && response[9] != 0x26) { +			/* Ignore postinit errors */ +			printf("tpm command failed at step %d\n" +			       "tpm error code: %02x%02x%02x%02x\n", i, +			       response[6], response[7], +			       response[8], response[9]); +			rv = -1; +			break; +		} +	} +	return rv; +} -	/* -	 * Verify that in case it is present, the first argument, it is -	 * exactly one character in size. -	 */ -	if (argc < 7) { + +static int do_tpm_many(cmd_tbl_t *cmdtp, int flag, +		       int argc, char * const argv[], int repeat_count) + +{ +	int rv = 0; + +	if (argc < 7 && repeat_count == 0) {  		puts("command should be at least six bytes in size\n");  		return -1;  	} +	if (repeat_count > 0) { +		rv = tpm_process_stress(repeat_count); +		return rv; +	} +  	if (tis_init()) {  		puts("tis_init() failed!\n");  		return -1; @@ -96,8 +145,40 @@ static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	return rv;  } + +static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	return do_tpm_many(cmdtp, flag, argc, argv, 0); +} + +  U_BOOT_CMD(tpm, MAX_TRANSACTION_SIZE, 1, do_tpm,  	   "<byte> [<byte> ...]   - write data and read response",  	   "send arbitrary data (at least 6 bytes) to the TPM "  	   "device and read the response"  ); + +static int do_tpm_stress(cmd_tbl_t *cmdtp, int flag, +			 int argc, char * const argv[]) +{ +	long unsigned int n; +	int rv; + +	if (argc != 2) { +		puts("usage: tpm_stress <count>\n"); +		return -1; +	} + +	rv = strict_strtoul(argv[1], 10, &n); +	if (rv) { +		puts("tpm_stress: bad count"); +		return -1; +	} + +	return do_tpm_many(cmdtp, flag, argc, argv, n); +} + +U_BOOT_CMD(tpm_stress, 2, 1, do_tpm_stress, +	   "<n>   - stress-test communication with TPM", +	   "Repeat a TPM transaction (request-response) N times" +); diff --git a/common/console.c b/common/console.c index 1177f7d39..bf7317869 100644 --- a/common/console.c +++ b/common/console.c @@ -24,11 +24,78 @@  #include <common.h>  #include <stdarg.h>  #include <malloc.h> +#include <serial.h>  #include <stdio_dev.h>  #include <exports.h> +#include <environment.h>  DECLARE_GLOBAL_DATA_PTR; +static int on_console(const char *name, const char *value, enum env_op op, +	int flags) +{ +	int console = -1; + +	/* Check for console redirection */ +	if (strcmp(name, "stdin") == 0) +		console = stdin; +	else if (strcmp(name, "stdout") == 0) +		console = stdout; +	else if (strcmp(name, "stderr") == 0) +		console = stderr; + +	/* if not actually setting a console variable, we don't care */ +	if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0) +		return 0; + +	switch (op) { +	case env_op_create: +	case env_op_overwrite: + +#ifdef CONFIG_CONSOLE_MUX +		if (iomux_doenv(console, value)) +			return 1; +#else +		/* Try assigning specified device */ +		if (console_assign(console, value) < 0) +			return 1; +#endif /* CONFIG_CONSOLE_MUX */ +		return 0; + +	case env_op_delete: +		if ((flags & H_FORCE) == 0) +			printf("Can't delete \"%s\"\n", name); +		return 1; + +	default: +		return 0; +	} +} +U_BOOT_ENV_CALLBACK(console, on_console); + +#ifdef CONFIG_SILENT_CONSOLE +static int on_silent(const char *name, const char *value, enum env_op op, +	int flags) +{ +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET +	if (flags & H_INTERACTIVE) +		return 0; +#endif +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC +	if ((flags & H_INTERACTIVE) == 0) +		return 0; +#endif + +	if (value != NULL) +		gd->flags |= GD_FLG_SILENT; +	else +		gd->flags &= ~GD_FLG_SILENT; + +	return 0; +} +U_BOOT_ENV_CALLBACK(silent, on_silent); +#endif +  #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV  /*   * if overwrite_console returns 1, the stdin, stderr and stdout @@ -591,7 +658,6 @@ int console_init_f(void)  void stdio_print_current_devices(void)  { -#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	/* Print information */  	puts("In:    ");  	if (stdio_devices[stdin] == NULL) { @@ -613,7 +679,6 @@ void stdio_print_current_devices(void)  	} else {  		printf ("%s\n", stdio_devices[stderr]->name);  	} -#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  }  #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV @@ -683,9 +748,9 @@ int console_init_r(void)  done:  #endif -	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE  	/* set the environment variables (will overwrite previous env settings) */ @@ -694,6 +759,8 @@ done:  	}  #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ +	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ +  #if 0  	/* If nothing usable installed, use only the initial console */  	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) @@ -758,15 +825,17 @@ int console_init_r(void)  #endif  	} -	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  	/* Setting environment variables */  	for (i = 0; i < 3; i++) {  		setenv(stdio_names[i], stdio_devices[i]->name);  	} +	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ +  #if 0  	/* If nothing usable installed, use only the initial console */  	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) diff --git a/common/edid.c b/common/edid.c new file mode 100644 index 000000000..c82c29809 --- /dev/null +++ b/common/edid.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2010 + * Petr Stetiar <ynezz@true.cz> + * + * 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 + * + * Contains stolen code from ddcprobe project which is: + * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> + * + */ + +#include <common.h> +#include <edid.h> +#include <linux/ctype.h> +#include <linux/string.h> + +int edid_check_info(struct edid1_info *edid_info) +{ +	if ((edid_info == NULL) || (edid_info->version == 0)) +		return -1; + +	if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8)) +		return -1; + +	if (edid_info->version == 0xff && edid_info->revision == 0xff) +		return -1; + +	return 0; +} + +int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, +		    unsigned int *hmax, unsigned int *vmin, +		    unsigned int *vmax) +{ +	int i; +	struct edid_monitor_descriptor *monitor; + +	*hmin = *hmax = *vmin = *vmax = 0; +	if (edid_check_info(edid)) +		return -1; + +	for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) { +		monitor = &edid->monitor_details.descriptor[i]; +		if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) { +			*hmin = monitor->data.range_data.horizontal_min; +			*hmax = monitor->data.range_data.horizontal_max; +			*vmin = monitor->data.range_data.vertical_min; +			*vmax = monitor->data.range_data.vertical_max; +			return 0; +		} +	} +	return -1; +} + +/** + * Snip the tailing whitespace/return of a string. + * + * @param string	The string to be snipped + * @return the snipped string + */ +static char *snip(char *string) +{ +	char *s; + +	/* +	 * This is always a 13 character buffer +	 * and it's not always terminated. +	 */ +	string[12] = '\0'; +	s = &string[strlen(string) - 1]; + +	while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' || +			*s == '\0')) +		*(s--) = '\0'; + +	return string; +} + +/** + * Print an EDID monitor descriptor block + * + * @param monitor	The EDID monitor descriptor block + * @have_timing		Modifies to 1 if the desciptor contains timing info + */ +static void edid_print_dtd(struct edid_monitor_descriptor *monitor, +			   unsigned int *have_timing) +{ +	unsigned char *bytes = (unsigned char *)monitor; +	struct edid_detailed_timing *timing = +			(struct edid_detailed_timing *)monitor; + +	if (bytes[0] == 0 && bytes[1] == 0) { +		if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL) +			printf("Monitor serial number: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII) +			printf("Monitor ID: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME) +			printf("Monitor name: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) +			printf("Monitor range limits, horizontal sync: " +			       "%d-%d kHz, vertical refresh: " +			       "%d-%d Hz, max pixel clock: " +			       "%d MHz\n", +			       monitor->data.range_data.horizontal_min, +			       monitor->data.range_data.horizontal_max, +			       monitor->data.range_data.vertical_min, +			       monitor->data.range_data.vertical_max, +			       monitor->data.range_data.pixel_clock_max * 10); +	} else { +		uint32_t pixclock, h_active, h_blanking, v_active, v_blanking; +		uint32_t h_total, v_total, vfreq; + +		pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing); +		h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing); +		h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing); +		v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing); +		v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing); + +		h_total = h_active + h_blanking; +		v_total = v_active + v_blanking; +		if (v_total * h_total) +			vfreq = pixclock / (v_total * h_total); +		else +			vfreq = 1; /* Error case */ +		printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active, +		       v_active, h_active > 1000 ? ' ' : '\t', vfreq); +		*have_timing = 1; +	} +} + +/** + * Get the manufacturer name from an EDID info. + * + * @param edid_info     The EDID info to be printed + * @param name		Returns the string of the manufacturer name + */ +static void edid_get_manufacturer_name(struct edid1_info *edid, char *name) +{ +	name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1; +	name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1; +	name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1; +	name[3] = '\0'; +} + +void edid_print_info(struct edid1_info *edid_info) +{ +	int i; +	char manufacturer[4]; +	unsigned int have_timing = 0; +	uint32_t serial_number; + +	if (edid_check_info(edid_info)) { +		printf("Not a valid EDID\n"); +		return; +	} + +	printf("EDID version: %d.%d\n", +	       edid_info->version, edid_info->revision); + +	printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info)); + +	edid_get_manufacturer_name(edid_info, manufacturer); +	printf("Manufacturer: %s\n", manufacturer); + +	serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info); +	if (serial_number != 0xffffffff) { +		if (strcmp(manufacturer, "MAG") == 0) +			serial_number -= 0x7000000; +		if (strcmp(manufacturer, "OQI") == 0) +			serial_number -= 456150000; +		if (strcmp(manufacturer, "VSC") == 0) +			serial_number -= 640000000; +	} +	printf("Serial number: %08x\n", serial_number); +	printf("Manufactured in week: %d year: %d\n", +	       edid_info->week, edid_info->year + 1990); + +	printf("Video input definition: %svoltage level %d%s%s%s%s%s\n", +	       EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ? +	       "digital signal, " : "analog signal, ", +	       EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info), +	       EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ? +	       ", blank to black" : "", +	       EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ? +	       ", separate sync" : "", +	       EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ? +	       ", composite sync" : "", +	       EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ? +	       ", sync on green" : "", +	       EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ? +	       ", serration v" : ""); + +	printf("Monitor is %s\n", +	       EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB"); + +	printf("Maximum visible display size: %d cm x %d cm\n", +	       edid_info->max_size_horizontal, +	       edid_info->max_size_vertical); + +	printf("Power management features: %s%s, %s%s, %s%s\n", +	       EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ? +	       "" : "no ", "active off", +	       EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend", +	       EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby"); + +	printf("Estabilished timings:\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info)) +		printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info)) +		printf("\t720x400\t\t88 Hz (XGA2)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info)) +		printf("\t640x480\t\t60 Hz (VGA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info)) +		printf("\t640x480\t\t67 Hz (Mac II, Apple)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info)) +		printf("\t640x480\t\t72 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info)) +		printf("\t640x480\t\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info)) +		printf("\t800x600\t\t56 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info)) +		printf("\t800x600\t\t60 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info)) +		printf("\t800x600\t\t72 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info)) +		printf("\t800x600\t\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info)) +		printf("\t832x624\t\t75 Hz (Mac II)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info)) +		printf("\t1024x768\t87 Hz Interlaced (8514A)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info)) +		printf("\t1024x768\t60 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info)) +		printf("\t1024x768\t70 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info)) +		printf("\t1024x768\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info)) +		printf("\t1280x1024\t75 (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info)) +		printf("\t1152x870\t75 (Mac II)\n"); + +	/* Standard timings. */ +	printf("Standard timings:\n"); +	for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) { +		unsigned int aspect = 10000; +		unsigned int x, y; +		unsigned char xres, vfreq; + +		xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i); +		vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i); +		if ((xres != vfreq) || +		    ((xres != 0) && (xres != 1)) || +		    ((vfreq != 0) && (vfreq != 1))) { +			switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info, +					i)) { +			case ASPECT_625: +				aspect = 6250; +				break; +			case ASPECT_75: +				aspect = 7500; +				break; +			case ASPECT_8: +				aspect = 8000; +				break; +			case ASPECT_5625: +				aspect = 5625; +				break; +			} +			x = (xres + 31) * 8; +			y = x * aspect / 10000; +			printf("\t%dx%d%c\t%d Hz\n", x, y, +			       x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60); +			have_timing = 1; +		} +	} + +	/* Detailed timing information. */ +	for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor); +			i++) { +		edid_print_dtd(&edid_info->monitor_details.descriptor[i], +			       &have_timing); +	} + +	if (!have_timing) +		printf("\tNone\n"); +} diff --git a/common/env_attr.c b/common/env_attr.c new file mode 100644 index 000000000..210c98dcf --- /dev/null +++ b/common/env_attr.c @@ -0,0 +1,229 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 + */ + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include <linux/linux_string.h> +#else +#include <common.h> +#endif + +#include <env_attr.h> +#include <errno.h> +#include <linux/string.h> +#include <malloc.h> + +/* + * Iterate through the whole list calling the callback for each found element. + * "attr_list" takes the form: + *	attributes = [^,:\s]* + *	entry = name[:attributes] + *	list = entry[,list] + */ +int env_attr_walk(const char *attr_list, +	int (*callback)(const char *name, const char *attributes)) +{ +	const char *entry, *entry_end; +	char *name, *attributes; + +	if (!attr_list) +		/* list not found */ +		return 1; + +	entry = attr_list; +	do { +		char *entry_cpy = NULL; + +		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); +		/* check if this is the last entry in the list */ +		if (entry_end == NULL) { +			int entry_len = strlen(entry); + +			if (entry_len) { +				/* +				 * allocate memory to copy the entry into since +				 * we will need to inject '\0' chars and squash +				 * white-space before calling the callback +				 */ +				entry_cpy = malloc(entry_len + 1); +				if (entry_cpy) +					/* copy the rest of the list */ +					strcpy(entry_cpy, entry); +				else +					return -ENOMEM; +			} +		} else { +			int entry_len = entry_end - entry; + +			if (entry_len) { +				/* +				 * allocate memory to copy the entry into since +				 * we will need to inject '\0' chars and squash +				 * white-space before calling the callback +				 */ +				entry_cpy = malloc(entry_len + 1); +				if (entry_cpy) { +					/* copy just this entry and null term */ +					strncpy(entry_cpy, entry, entry_len); +					entry_cpy[entry_len] = '\0'; +				} else +					return -ENOMEM; +			} +		} + +		/* check if there is anything to process (e.g. not ",,,") */ +		if (entry_cpy != NULL) { +			attributes = strchr(entry_cpy, ENV_ATTR_SEP); +			/* check if there is a ':' */ +			if (attributes != NULL) { +				/* replace the ':' with '\0' to term name */ +				*attributes++ = '\0'; +				/* remove white-space from attributes */ +				attributes = strim(attributes); +			} +			/* remove white-space from name */ +			name = strim(entry_cpy); + +			/* only call the callback if there is a name */ +			if (strlen(name) != 0) { +				int retval = 0; + +				retval = callback(name, attributes); +				if (retval) { +					free(entry_cpy); +					return retval; +				} +			} +		} + +		free(entry_cpy); +		entry = entry_end + 1; +	} while (entry_end != NULL); + +	return 0; +} + +/* + * Search for the last matching string in another string with the option to + * start looking at a certain point (i.e. ignore anything beyond that point). + */ +static char *reverse_strstr(const char *searched, const char *search_for, +	const char *searched_start) +{ +	char *result = NULL; + +	if (*search_for == '\0') +		return (char *)searched; + +	for (;;) { +		char *match = strstr(searched, search_for); + +		/* +		 * Stop looking if no new match is found or looking past the +		 * searched_start pointer +		 */ +		if (match == NULL || (searched_start != NULL && +		    match + strlen(search_for) > searched_start)) +			break; + +		result = match; +		searched = match + 1; +	} + +	return result; +} + +/* + * Retrieve the attributes string associated with a single name in the list + * There is no protection on attributes being too small for the value + */ +int env_attr_lookup(const char *attr_list, const char *name, char *attributes) +{ +	const char *entry = NULL; + +	if (!attributes) +		/* bad parameter */ +		return -1; +	if (!attr_list) +		/* list not found */ +		return 1; + +	entry = reverse_strstr(attr_list, name, NULL); +	while (entry != NULL) { +		const char *prevch = entry - 1; +		const char *nextch = entry + strlen(name); + +		/* Skip spaces */ +		while (*prevch == ' ') +			prevch--; +		while (*nextch == ' ') +			nextch++; + +		/* check for an exact match */ +		if ((entry == attr_list || +		     *prevch == ENV_ATTR_LIST_DELIM) && +		    (*nextch == ENV_ATTR_SEP || +		     *nextch == ENV_ATTR_LIST_DELIM || +		     *nextch == '\0')) +			break; + +		entry = reverse_strstr(attr_list, name, entry); +	} +	if (entry != NULL) { +		int len; + +		/* skip the name */ +		entry += strlen(name); +		/* skip spaces */ +		while (*entry == ' ') +			entry++; +		if (*entry != ENV_ATTR_SEP) +			len = 0; +		else { +			const char *delim; +			static const char delims[] = { +				ENV_ATTR_LIST_DELIM, ' ', '\0'}; + +			/* skip the attr sep */ +			entry += 1; +			/* skip spaces */ +			while (*entry == ' ') +				entry++; + +			delim = strpbrk(entry, delims); +			if (delim == NULL) +				len = strlen(entry); +			else +				len = delim - entry; +			memcpy(attributes, entry, len); +		} +		attributes[len] = '\0'; + +		/* success */ +		return 0; +	} + +	/* not found in list */ +	return 2; +} diff --git a/common/env_callback.c b/common/env_callback.c new file mode 100644 index 000000000..78ca3674f --- /dev/null +++ b/common/env_callback.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 <environment.h> + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * Look up a callback function pointer by name + */ +struct env_clbk_tbl *find_env_callback(const char *name) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + +	if (name == NULL) +		return NULL; + +	/* look up the callback in the linker-list */ +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) { +		if (strcmp(name, clbkp->name) == 0) +			return clbkp; +	} + +	return NULL; +} + +/* + * Look for a possible callback for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_callback_init(ENTRY *var_entry) +{ +	const char *var_name = var_entry->key; +	const char *callback_list = getenv(ENV_CALLBACK_VAR); +	char callback_name[256] = ""; +	struct env_clbk_tbl *clbkp; +	int ret = 1; + +	/* look in the ".callbacks" var for a reference to this variable */ +	if (callback_list != NULL) +		ret = env_attr_lookup(callback_list, var_name, callback_name); + +	/* only if not found there, look in the static list */ +	if (ret) +		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, +			callback_name); + +	/* if an association was found, set the callback pointer */ +	if (!ret && strlen(callback_name)) { +		clbkp = find_env_callback(callback_name); +		if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +			var_entry->callback = clbkp->callback + gd->reloc_off; +#else +			var_entry->callback = clbkp->callback; +#endif +	} +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a callback association should remove its callback. + */ +static int clear_callback(ENTRY *entry) +{ +	entry->callback = NULL; + +	return 0; +} + +/* + * Call for each element in the list that associates variables to callbacks + */ +static int set_callback(const char *name, const char *value) +{ +	ENTRY e, *ep; +	struct env_clbk_tbl *clbkp; + +	e.key	= name; +	e.data	= NULL; +	hsearch_r(e, FIND, &ep, &env_htab, 0); + +	/* does the env variable actually exist? */ +	if (ep != NULL) { +		/* the assocaition delares no callback, so remove the pointer */ +		if (value == NULL || strlen(value) == 0) +			ep->callback = NULL; +		else { +			/* assign the requested callback */ +			clbkp = find_env_callback(value); +			if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +				ep->callback = clbkp->callback + gd->reloc_off; +#else +				ep->callback = clbkp->callback; +#endif +		} +	} + +	return 0; +} + +static int on_callbacks(const char *name, const char *value, enum env_op op, +	int flags) +{ +	/* remove all callbacks */ +	hwalk_r(&env_htab, clear_callback); + +	/* configure any static callback bindings */ +	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback); +	/* configure any dynamic callback bindings */ +	env_attr_walk(value, set_callback); + +	return 0; +} +U_BOOT_ENV_CALLBACK(callbacks, on_callbacks); diff --git a/common/env_common.c b/common/env_common.c index 3d3cb70a6..906b41fcc 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;  #include <env_default.h>  struct hsearch_data env_htab = { -	.apply = env_check_apply, +	.change_ok = env_flags_validate,  };  static uchar __env_get_char_spec(int index) @@ -81,13 +81,42 @@ const uchar *env_get_addr(int index)  		return &default_environment[index];  } +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var) +{ +	char *s = getenv(var); + +	if (s == NULL) +		return -1; +	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ? +		1 : 0; +} + +/* + * Look up the variable from the default environment + */ +char *getenv_default(const char *name) +{ +	char *ret_val; +	unsigned long really_valid = gd->env_valid; +	unsigned long real_gd_flags = gd->flags; + +	/* Pretend that the image is bad. */ +	gd->flags &= ~GD_FLG_ENV_READY; +	gd->env_valid = 0; +	ret_val = getenv(name); +	gd->env_valid = really_valid; +	gd->flags = real_gd_flags; +	return ret_val; +} +  void set_default_env(const char *s)  { -	/* -	 * By default, do not apply changes as they will eventually -	 * be applied by someone else -	 */ -	int do_apply = 0; +	int flags = 0; +  	if (sizeof(default_environment) > ENV_SIZE) {  		puts("*** Error - default environment is too large\n\n");  		return; @@ -99,14 +128,7 @@ void set_default_env(const char *s)  				"using default environment\n\n",  				s + 1);  		} else { -			/* -			 * This set_to_default was explicitly asked for -			 * by the user, as opposed to being a recovery -			 * mechanism.  Therefore we check every single -			 * variable and apply changes to the system -			 * right away (e.g. baudrate, console). -			 */ -			do_apply = 1; +			flags = H_INTERACTIVE;  			puts(s);  		}  	} else { @@ -114,8 +136,8 @@ void set_default_env(const char *s)  	}  	if (himport_r(&env_htab, (char *)default_environment, -			sizeof(default_environment), '\0', 0, -			0, NULL, do_apply) == 0) +			sizeof(default_environment), '\0', flags, +			0, NULL) == 0)  		error("Environment import failed: errno = %d\n", errno);  	gd->flags |= GD_FLG_ENV_READY; @@ -130,8 +152,8 @@ int set_default_vars(int nvars, char * const vars[])  	 * (and use \0 as a separator)  	 */  	return himport_r(&env_htab, (const char *)default_environment, -				sizeof(default_environment), '\0', H_NOCLEAR, -				nvars, vars, 1 /* do_apply */); +				sizeof(default_environment), '\0', +				H_NOCLEAR | H_INTERACTIVE, nvars, vars);  }  #ifndef CONFIG_SPL_BUILD @@ -155,7 +177,7 @@ int env_import(const char *buf, int check)  	}  	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, -			0, NULL, 0 /* do_apply */)) { +			0, NULL)) {  		gd->flags |= GD_FLG_ENV_READY;  		return 1;  	} @@ -172,6 +194,7 @@ void env_relocate(void)  {  #if defined(CONFIG_NEEDS_MANUAL_RELOC)  	env_reloc(); +	env_htab.change_ok += gd->reloc_off;  #endif  	if (gd->env_valid == 0) {  #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) diff --git a/common/env_dataflash.c b/common/env_dataflash.c index 3c5af37bf..38c96157b 100644 --- a/common/env_dataflash.c +++ b/common/env_dataflash.c @@ -60,7 +60,7 @@ int saveenv(void)  	char	*res;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_eeprom.c b/common/env_eeprom.c index b66bba29f..45c935b6d 100644 --- a/common/env_eeprom.c +++ b/common/env_eeprom.c @@ -139,7 +139,7 @@ int saveenv(void)  	BUG_ON(env_ptr != NULL);  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_fat.c b/common/env_fat.c index 6ef531821..c0f18ab97 100644 --- a/common/env_fat.c +++ b/common/env_fat.c @@ -61,7 +61,7 @@ int saveenv(void)  	int err;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_flags.c b/common/env_flags.c new file mode 100644 index 000000000..336cae4e9 --- /dev/null +++ b/common/env_flags.c @@ -0,0 +1,560 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 <linux/string.h> +#include <linux/ctype.h> + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include "fw_env.h" +#include <env_attr.h> +#include <env_flags.h> +#define getenv fw_getenv +#else +#include <common.h> +#include <environment.h> +#endif + +#ifdef CONFIG_CMD_NET +#define ENV_FLAGS_NET_VARTYPE_REPS "im" +#else +#define ENV_FLAGS_NET_VARTYPE_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +static const char env_flags_varaccess_rep[] = "aroc"; +static const int env_flags_varaccess_mask[] = { +	0, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_CREATE | +		ENV_FLAGS_VARACCESS_PREVENT_OVERWR, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_OVERWR, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; + +#ifdef CONFIG_CMD_ENV_FLAGS +static const char * const env_flags_vartype_names[] = { +	"string", +	"decimal", +	"hexadecimal", +	"boolean", +#ifdef CONFIG_CMD_NET +	"IP address", +	"MAC address", +#endif +}; +static const char * const env_flags_varaccess_names[] = { +	"any", +	"read-only", +	"write-once", +	"change-default", +}; + +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void) +{ +	enum env_flags_vartype curtype = (enum env_flags_vartype)0; + +	while (curtype != env_flags_vartype_end) { +		printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype], +			env_flags_vartype_names[curtype]); +		curtype++; +	} +} + +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void) +{ +	enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0; + +	while (curaccess != env_flags_varaccess_end) { +		printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess], +			env_flags_varaccess_names[curaccess]); +		curaccess++; +	} +} + +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type) +{ +	return env_flags_vartype_names[type]; +} + +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access) +{ +	return env_flags_varaccess_names[access]; +} +#endif /* CONFIG_CMD_ENV_FLAGS */ + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags) +{ +	char *type; + +	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) +		return env_flags_vartype_string; + +	type = strchr(env_flags_vartype_rep, +		flags[ENV_FLAGS_VARTYPE_LOC]); + +	if (type != NULL) +		return (enum env_flags_vartype) +			(type - &env_flags_vartype_rep[0]); + +	printf("## Warning: Unknown environment variable type '%c'\n", +		flags[ENV_FLAGS_VARTYPE_LOC]); +	return env_flags_vartype_string; +} + +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) +{ +	char *access; + +	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) +		return env_flags_varaccess_any; + +	access = strchr(env_flags_varaccess_rep, +		flags[ENV_FLAGS_VARACCESS_LOC]); + +	if (access != NULL) +		return (enum env_flags_varaccess) +			(access - &env_flags_varaccess_rep[0]); + +	printf("## Warning: Unknown environment variable access method '%c'\n", +		flags[ENV_FLAGS_VARACCESS_LOC]); +	return env_flags_varaccess_any; +} + +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) +{ +	int i; + +	for (i = 0; i < sizeof(env_flags_varaccess_mask); i++) +		if (env_flags_varaccess_mask[i] == +		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) +			return (enum env_flags_varaccess)i; + +	printf("Warning: Non-standard access flags. (0x%x)\n", +		binflags & ENV_FLAGS_VARACCESS_BIN_MASK); + +	return env_flags_varaccess_any; +} + +static inline int is_hex_prefix(const char *value) +{ +	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); +} + +static void skip_num(int hex, const char *value, const char **end, +	int max_digits) +{ +	int i; + +	if (hex && is_hex_prefix(value)) +		value += 2; + +	for (i = max_digits; i != 0; i--) { +		if (hex && !isxdigit(*value)) +			break; +		if (!hex && !isdigit(*value)) +			break; +		value++; +	} +	if (end != NULL) +		*end = value; +} + +/* + * Based on the declared type enum, validate that the value string complies + * with that format + */ +static int _env_flags_validate_type(const char *value, +	enum env_flags_vartype type) +{ +	const char *end; +#ifdef CONFIG_CMD_NET +	const char *cur; +	int i; +#endif + +	switch (type) { +	case env_flags_vartype_string: +		break; +	case env_flags_vartype_decimal: +		skip_num(0, value, &end, -1); +		if (*end != '\0') +			return -1; +		break; +	case env_flags_vartype_hex: +		skip_num(1, value, &end, -1); +		if (*end != '\0') +			return -1; +		if (value + 2 == end && is_hex_prefix(value)) +			return -1; +		break; +	case env_flags_vartype_bool: +		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && +		    value[0] != 'Y' && value[0] != 'T' && +		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' && +		    value[0] != 'N' && value[0] != 'F') +			return -1; +		if (value[1] != '\0') +			return -1; +		break; +#ifdef CONFIG_CMD_NET +	case env_flags_vartype_ipaddr: +		cur = value; +		for (i = 0; i < 4; i++) { +			skip_num(0, cur, &end, 3); +			if (cur == end) +				return -1; +			if (i != 3 && *end != '.') +				return -1; +			if (i == 3 && *end != '\0') +				return -1; +			cur = end + 1; +		} +		break; +	case env_flags_vartype_macaddr: +		cur = value; +		for (i = 0; i < 6; i++) { +			skip_num(1, cur, &end, 2); +			if (cur == end) +				return -1; +			if (cur + 2 == end && is_hex_prefix(cur)) +				return -1; +			if (i != 5 && *end != ':') +				return -1; +			if (i == 5 && *end != '\0') +				return -1; +			cur = end + 1; +		} +		break; +#endif +	case env_flags_vartype_end: +		return -1; +	} + +	/* OK */ +	return 0; +} + +/* + * Look for flags in a provided list and failing that the static list + */ +static inline int env_flags_lookup(const char *flags_list, const char *name, +	char *flags) +{ +	int ret = 1; + +	if (!flags) +		/* bad parameter */ +		return -1; + +	/* try the env first */ +	if (flags_list) +		ret = env_attr_lookup(flags_list, name, flags); + +	if (ret != 0) +		/* if not found in the env, look in the static list */ +		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); + +	return ret; +} + +#ifdef USE_HOSTCC /* Functions only used from tools/env */ +/* + * Look up any flags directly from the .flags variable and the static list + * and convert them to the vartype enum. + */ +enum env_flags_vartype env_flags_get_type(const char *name) +{ +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + +	if (env_flags_lookup(flags_list, name, flags)) +		return env_flags_vartype_string; + +	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) +		return env_flags_vartype_string; + +	return env_flags_parse_vartype(flags); +} + +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_varaccess(const char *name) +{ +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + +	if (env_flags_lookup(flags_list, name, flags)) +		return env_flags_varaccess_any; + +	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) +		return env_flags_varaccess_any; + +	return env_flags_parse_varaccess(flags); +} + +/* + * Validate that the proposed new value for "name" is valid according to the + * defined flags for that variable, if any. + */ +int env_flags_validate_type(const char *name, const char *value) +{ +	enum env_flags_vartype type; + +	if (value == NULL) +		return 0; +	type = env_flags_get_type(name); +	if (_env_flags_validate_type(value, type) < 0) { +		printf("## Error: flags type check failure for " +			"\"%s\" <= \"%s\" (type: %c)\n", +			name, value, env_flags_vartype_rep[type]); +		return -1; +	} +	return 0; +} + +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask) +{ +	enum env_flags_varaccess access; +	int access_mask; + +	access = env_flags_get_varaccess(name); +	access_mask = env_flags_varaccess_mask[access]; + +	return (check_mask & access_mask) != 0; +} + +/* + * Validate the parameters to "env set" directly + */ +int env_flags_validate_env_set_params(int argc, char * const argv[]) +{ +	if ((argc >= 3) && argv[2] != NULL) { +		enum env_flags_vartype type = env_flags_get_type(argv[1]); + +		/* +		 * we don't currently check types that need more than +		 * one argument +		 */ +		if (type != env_flags_vartype_string && argc > 3) { +			printf("## Error: too many parameters for setting " +				"\"%s\"\n", argv[1]); +			return -1; +		} +		return env_flags_validate_type(argv[1], argv[2]); +	} +	/* ok */ +	return 0; +} + +#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */ + +/* + * Parse the flag charachters from the .flags attribute list into the binary + * form to be stored in the environment entry->flags field. + */ +static int env_parse_flags_to_bin(const char *flags) +{ +	int binflags; + +	binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; +	binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)]; + +	return binflags; +} + +/* + * Look for possible flags for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_flags_init(ENTRY *var_entry) +{ +	const char *var_name = var_entry->key; +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; +	int ret = 1; + +	/* look in the ".flags" and static for a reference to this variable */ +	ret = env_flags_lookup(flags_list, var_name, flags); + +	/* if any flags were found, set the binary form to the entry */ +	if (!ret && strlen(flags)) +		var_entry->flags = env_parse_flags_to_bin(flags); +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a flag in the flag list should remove its flags. + */ +static int clear_flags(ENTRY *entry) +{ +	entry->flags = 0; + +	return 0; +} + +/* + * Call for each element in the list that defines flags for a variable + */ +static int set_flags(const char *name, const char *value) +{ +	ENTRY e, *ep; + +	e.key	= name; +	e.data	= NULL; +	hsearch_r(e, FIND, &ep, &env_htab, 0); + +	/* does the env variable actually exist? */ +	if (ep != NULL) { +		/* the flag list is empty, so clear the flags */ +		if (value == NULL || strlen(value) == 0) +			ep->flags = 0; +		else +			/* assign the requested flags */ +			ep->flags = env_parse_flags_to_bin(value); +	} + +	return 0; +} + +static int on_flags(const char *name, const char *value, enum env_op op, +	int flags) +{ +	/* remove all flags */ +	hwalk_r(&env_htab, clear_flags); + +	/* configure any static flags */ +	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); +	/* configure any dynamic flags */ +	env_attr_walk(value, set_flags); + +	return 0; +} +U_BOOT_ENV_CALLBACK(flags, on_flags); + +/* + * Perform consistency checking before creating, overwriting, or deleting an + * environment variable. Called as a callback function by hsearch_r() and + * hdelete_r(). Returns 0 in case of success, 1 in case of failure. + * When (flag & H_FORCE) is set, do not print out any error message and force + * overwriting of write-once variables. + */ + +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, +	int flag) +{ +	const char *name; +	const char *oldval = NULL; + +	if (op != env_op_create) +		oldval = item->data; + +	name = item->key; + +	/* Default value for NULL to protect string-manipulating functions */ +	newval = newval ? : ""; + +	/* validate the value to match the variable type */ +	if (op != env_op_delete) { +		enum env_flags_vartype type = (enum env_flags_vartype) +			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); + +		if (_env_flags_validate_type(newval, type) < 0) { +			printf("## Error: flags type check failure for " +				"\"%s\" <= \"%s\" (type: %c)\n", +				name, newval, env_flags_vartype_rep[type]); +			return -1; +		} +	} + +	/* check for access permission */ +#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE +	if (flag & H_FORCE) +		return 0; +#endif +	switch (op) { +	case env_op_delete: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { +			printf("## Error: Can't delete \"%s\"\n", name); +			return 1; +		} +		break; +	case env_op_overwrite: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { +			printf("## Error: Can't overwrite \"%s\"\n", name); +			return 1; +		} else if (item->flags & +		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { +			const char *defval = getenv_default(name); + +			if (defval == NULL) +				defval = ""; +			printf("oldval: %s  defval: %s\n", oldval, defval); +			if (strcmp(oldval, defval) != 0) { +				printf("## Error: Can't overwrite \"%s\"\n", +					name); +				return 1; +			} +		} +		break; +	case env_op_create: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { +			printf("## Error: Can't create \"%s\"\n", name); +			return 1; +		} +		break; +	} + +	return 0; +} + +#endif diff --git a/common/env_flash.c b/common/env_flash.c index aa970d440..e07d336a4 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -142,7 +142,7 @@ int saveenv(void)  		goto done;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; @@ -275,7 +275,7 @@ int saveenv(void)  		goto done;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; diff --git a/common/env_mmc.c b/common/env_mmc.c index a2ff90bf4..ce2167121 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -130,7 +130,7 @@ int saveenv(void)  	}  	res = (char *)&env_new->data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		ret = 1; diff --git a/common/env_nand.c b/common/env_nand.c index 79e803370..22e72a20b 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -186,7 +186,7 @@ int saveenv(void)  		return 1;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -239,7 +239,7 @@ int saveenv(void)  		return 1;  	res = (char *)&env_new->data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_nvram.c b/common/env_nvram.c index 6483db39d..eab0e7be0 100644 --- a/common/env_nvram.c +++ b/common/env_nvram.c @@ -90,7 +90,7 @@ int saveenv(void)  	int	rcode = 0;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_onenand.c b/common/env_onenand.c index da3507125..faa903d2f 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -95,7 +95,7 @@ int saveenv(void)  	};  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_sf.c b/common/env_sf.c index bbd472fcf..d9e908546 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -79,7 +79,7 @@ int saveenv(void)  	}  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -277,7 +277,7 @@ int saveenv(void)  	}  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; diff --git a/common/fdt_support.c b/common/fdt_support.c index 963ea9023..6b9fa0550 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1315,7 +1315,7 @@ int fdt_set_status_by_alias(void *fdt, const char* alias,  	return fdt_set_node_status(fdt, offset, status, error_code);  } -#if defined(CONFIG_VIDEO) +#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD)  int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)  {  	int noff; diff --git a/common/hash.c b/common/hash.c new file mode 100644 index 000000000..e3a6e438a --- /dev/null +++ b/common/hash.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@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. + * + * 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 <hash.h> +#include <sha1.h> +#include <sha256.h> + +/* + * These are the hash algorithms we support. Chips which support accelerated + * crypto could perhaps add named version of these algorithms here. + */ +static struct hash_algo hash_algo[] = { +#ifdef CONFIG_SHA1 +	{ +		"SHA1", +		SHA1_SUM_LEN, +		sha1_csum_wd, +		CHUNKSZ_SHA1, +	}, +#endif +#ifdef CONFIG_SHA256 +	{ +		"SHA256", +		SHA256_SUM_LEN, +		sha256_csum_wd, +		CHUNKSZ_SHA256, +	}, +#endif +}; + +/** + * store_result: Store the resulting sum to an address or variable + * + * @algo:		Hash algorithm being used + * @sum:		Hash digest (algo->digest_size bytes) + * @dest:		Destination, interpreted as a hex address if it starts + *			with * or otherwise as an environment variable. + */ +static void store_result(struct hash_algo *algo, const u8 *sum, +			 const char *dest) +{ +	unsigned int i; + +	if (*dest == '*') { +		u8 *ptr; + +		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); +		memcpy(ptr, sum, algo->digest_size); +	} else { +		char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; +		char *str_ptr = str_output; + +		for (i = 0; i < algo->digest_size; i++) { +			sprintf(str_ptr, "%02x", sum[i]); +			str_ptr += 2; +		} +		str_ptr = '\0'; +		setenv(dest, str_output); +	} +} + +/** + * parse_verify_sum: Parse a hash verification parameter + * + * @algo:		Hash algorithm being used + * @verify_str:		Argument to parse. If it starts with * then it is + *			interpreted as a hex address containing the hash. + *			If the length is exactly the right number of hex digits + *			for the digest size, then we assume it is a hex digest. + *			Otherwise we assume it is an environment variable, and + *			look up its value (it must contain a hex digest). + * @vsum:		Returns binary digest value (algo->digest_size bytes) + * @return 0 if ok, non-zero on error + */ +static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum) +{ +	if (*verify_str == '*') { +		u8 *ptr; + +		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); +		memcpy(vsum, ptr, algo->digest_size); +	} else { +		unsigned int i; +		char *vsum_str; +		int digits = algo->digest_size * 2; + +		/* +		 * As with the original code from sha1sum.c, we assume that a +		 * string which matches the digest size exactly is a hex +		 * string and not an environment variable. +		 */ +		if (strlen(verify_str) == digits) +			vsum_str = verify_str; +		else { +			vsum_str = getenv(verify_str); +			if (vsum_str == NULL || strlen(vsum_str) != digits) { +				printf("Expected %d hex digits in env var\n", +				       digits); +				return 1; +			} +		} + +		for (i = 0; i < algo->digest_size; i++) { +			char *nullp = vsum_str + (i + 1) * 2; +			char end = *nullp; + +			*nullp = '\0'; +			vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); +			*nullp = end; +		} +	} +	return 0; +} + +static struct hash_algo *find_hash_algo(const char *name) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { +		if (!strcasecmp(name, hash_algo[i].name)) +			return &hash_algo[i]; +	} + +	return NULL; +} + +static void show_hash(struct hash_algo *algo, ulong addr, ulong len, +		      u8 *output) +{ +	int i; + +	printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); +	for (i = 0; i < algo->digest_size; i++) +		printf("%02x", output[i]); +} + +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, +		 int argc, char * const argv[]) +{ +	struct hash_algo *algo; +	ulong addr, len; +	u8 output[HASH_MAX_DIGEST_SIZE]; +	u8 vsum[HASH_MAX_DIGEST_SIZE]; + +	if (argc < 2) +		return CMD_RET_USAGE; + +	algo = find_hash_algo(algo_name); +	if (!algo) { +		printf("Unknown hash algorithm '%s'\n", algo_name); +		return CMD_RET_USAGE; +	} +	addr = simple_strtoul(*argv++, NULL, 16); +	len = simple_strtoul(*argv++, NULL, 16); +	argc -= 2; + +	if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { +		puts("HASH_MAX_DIGEST_SIZE exceeded\n"); +		return 1; +	} + +	algo->hash_func_ws((const unsigned char *)addr, len, output, +			   algo->chunk_size); + +	/* Try to avoid code bloat when verify is not needed */ +#ifdef CONFIG_HASH_VERIFY +	if (verify) { +#else +	if (0) { +#endif +		if (!argc) +			return CMD_RET_USAGE; +		if (parse_verify_sum(algo, *argv, vsum)) { +			printf("ERROR: %s does not contain a valid %s sum\n", +				*argv, algo->name); +			return 1; +		} +		if (memcmp(output, vsum, algo->digest_size) != 0) { +			int i; + +			show_hash(algo, addr, len, output); +			printf(" != "); +			for (i = 0; i < algo->digest_size; i++) +				printf("%02x", vsum[i]); +			puts(" ** ERROR **\n"); +			return 1; +		} +	} else { +		show_hash(algo, addr, len, output); +		printf("\n"); + +		if (argc) +			store_result(algo, output, *argv); +	} + +	return 0; +} diff --git a/common/image.c b/common/image.c index e93b6e89c..95498e618 100644 --- a/common/image.c +++ b/common/image.c @@ -43,6 +43,7 @@  #include <rtc.h>  #endif +#include <environment.h>  #include <image.h>  #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) @@ -416,11 +417,25 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,  /* Shared dual-format routines */  /*****************************************************************************/  #ifndef USE_HOSTCC -int getenv_yesno(char *var) +ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */ +ulong save_addr;			/* Default Save Address */ +ulong save_size;			/* Default Save Size (in bytes) */ + +static int on_loadaddr(const char *name, const char *value, enum env_op op, +	int flags)  { -	char *s = getenv(var); -	return (s && (*s == 'n')) ? 0 : 1; +	switch (op) { +	case env_op_create: +	case env_op_overwrite: +		load_addr = simple_strtoul(value, NULL, 16); +		break; +	default: +		break; +	} + +	return 0;  } +U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);  ulong getenv_bootm_low(void)  { diff --git a/common/lcd.c b/common/lcd.c index 4c83a8bf0..4778655a2 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -72,6 +72,15 @@  # endif  #endif +#ifndef CONFIG_LCD_ALIGNMENT +#define CONFIG_LCD_ALIGNMENT PAGE_SIZE +#endif + +/* By default we scroll by a single line */ +#ifndef CONFIG_CONSOLE_SCROLL_LINES +#define CONFIG_CONSOLE_SCROLL_LINES 1 +#endif +  DECLARE_GLOBAL_DATA_PTR;  ulong lcd_setmem (ulong addr); @@ -90,6 +99,9 @@ static void lcd_setbgcolor(int color);  char lcd_is_enabled = 0; +static char lcd_flush_dcache;	/* 1 to flush dcache after each lcd update */ + +  #ifdef	NOT_USED_SO_FAR  static void lcd_getcolreg(ushort regno,  				ushort *red, ushort *green, ushort *blue); @@ -98,15 +110,46 @@ static int lcd_getfgcolor(void);  /************************************************************************/ +/* Flush LCD activity to the caches */ +void lcd_sync(void) +{ +	/* +	 * flush_dcache_range() is declared in common.h but it seems that some +	 * architectures do not actually implement it. Is there a way to find +	 * out whether it exists? For now, ARM is safe. +	 */ +#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF) +	int line_length; + +	if (lcd_flush_dcache) +		flush_dcache_range((u32)lcd_base, +			(u32)(lcd_base + lcd_get_size(&line_length))); +#endif +} + +void lcd_set_flush_dcache(int flush) +{ +	lcd_flush_dcache = (flush != 0); +} +  /*----------------------------------------------------------------------*/  static void console_scrollup(void)  { -	/* Copy up rows ignoring the first one */ -	memcpy(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE); +	const int rows = CONFIG_CONSOLE_SCROLL_LINES; -	/* Clear the last one */ -	memset(CONSOLE_ROW_LAST, COLOR_MASK(lcd_color_bg), CONSOLE_ROW_SIZE); +	/* Copy up rows ignoring those that will be overwritten */ +	memcpy(CONSOLE_ROW_FIRST, +	       lcd_console_address + CONSOLE_ROW_SIZE * rows, +	       CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows); + +	/* Clear the last rows */ +	memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows, +		COLOR_MASK(lcd_color_bg), +	       CONSOLE_ROW_SIZE * rows); + +	lcd_sync(); +	console_row -= rows;  }  /*----------------------------------------------------------------------*/ @@ -135,7 +178,8 @@ static inline void console_newline(void)  	if (console_row >= CONSOLE_ROWS) {  		/* Scroll everything up */  		console_scrollup(); -		--console_row; +	} else { +		lcd_sync();  	}  } @@ -191,6 +235,7 @@ void lcd_puts(const char *s)  	while (*s) {  		lcd_putc(*s++);  	} +	lcd_sync();  }  /*----------------------------------------------------------------------*/ @@ -326,6 +371,12 @@ static void test_pattern(void)  /* ** GENERIC Initialization Routines					*/  /************************************************************************/ +int lcd_get_size(int *line_length) +{ +	*line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; +	return *line_length * panel_info.vl_row; +} +  int drv_lcd_init (void)  {  	struct stdio_dev lcddev; @@ -333,7 +384,7 @@ int drv_lcd_init (void)  	lcd_base = (void *)(gd->fb_base); -	lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8; +	lcd_get_size(&lcd_line_length);  	lcd_init(lcd_base);		/* LCD initialization */ @@ -352,13 +403,6 @@ int drv_lcd_init (void)  }  /*----------------------------------------------------------------------*/ -static -int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) -{ -	lcd_clear(); -	return 0; -} -  void lcd_clear(void)  {  #if LCD_BPP == LCD_MONOCHROME @@ -400,6 +444,14 @@ void lcd_clear(void)  	console_col = 0;  	console_row = 0; +	lcd_sync(); +} + +static int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc, +			char *const argv[]) +{ +	lcd_clear(); +	return 0;  }  U_BOOT_CMD( @@ -445,15 +497,16 @@ static int lcd_init(void *lcdbase)  ulong lcd_setmem(ulong addr)  {  	ulong size; -	int line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; +	int line_length;  	debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,  		panel_info.vl_row, NBITS(panel_info.vl_bpix)); -	size = line_length * panel_info.vl_row; +	size = lcd_get_size(&line_length); -	/* Round up to nearest full page */ -	size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); +	/* Round up to nearest full page, or MMU section if defined */ +	size = ALIGN(size, CONFIG_LCD_ALIGNMENT); +	addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);  	/* Allocate pages for the frame buffer. */  	addr -= size; @@ -610,6 +663,7 @@ void bitmap_plot(int x, int y)  	}  	WATCHDOG_RESET(); +	lcd_sync();  }  #else  static inline void bitmap_plot(int x, int y) {} @@ -975,6 +1029,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  		break;  	}; +	lcd_sync();  	return 0;  }  #endif diff --git a/common/main.c b/common/main.c index 5362781f1..5d8454ea0 100644 --- a/common/main.c +++ b/common/main.c @@ -376,6 +376,8 @@ void main_loop (void)  	char bcs_set[16];  #endif /* CONFIG_BOOTCOUNT_LIMIT */ +	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); +  #ifdef CONFIG_BOOTCOUNT_LIMIT  	bootcount = bootcount_load();  	bootcount++; @@ -1139,8 +1141,16 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout)  					puts (tab_seq+(col&07));  					col += 8 - (col&07);  				} else { -					++col;		/* echo input		*/ -					putc (c); +					char buf[2]; + +					/* +					 * Echo input using puts() to force am +					 * LCD flush if we are using an LCD +					 */ +					++col; +					buf[0] = c; +					buf[1] = '\0'; +					puts(buf);  				}  				*p++ = c;  				++n; diff --git a/common/stdio.c b/common/stdio.c index 9f48e5f50..97ff9cf4a 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -135,7 +135,6 @@ struct stdio_dev* stdio_clone(struct stdio_dev *dev)  		return NULL;  	memcpy(_dev, dev, sizeof(struct stdio_dev)); -	strncpy(_dev->name, dev->name, 16);  	return _dev;  } diff --git a/disk/part_efi.c b/disk/part_efi.c index a3873cebb..766501733 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -34,9 +34,11 @@  #include <command.h>  #include <ide.h>  #include <malloc.h> -#include "part_efi.h" +#include <part_efi.h>  #include <linux/ctype.h> +DECLARE_GLOBAL_DATA_PTR; +  #if defined(CONFIG_CMD_IDE) || \      defined(CONFIG_CMD_SATA) || \      defined(CONFIG_CMD_SCSI) || \ @@ -44,34 +46,6 @@      defined(CONFIG_MMC) || \      defined(CONFIG_SYSTEMACE) -/* Convert char[2] in little endian format to the host format integer - */ -static inline unsigned short le16_to_int(unsigned char *le16) -{ -	return ((le16[1] << 8) + le16[0]); -} - -/* Convert char[4] in little endian format to the host format integer - */ -static inline unsigned long le32_to_int(unsigned char *le32) -{ -	return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]); -} - -/* Convert char[8] in little endian format to the host format integer - */ -static inline unsigned long long le64_to_int(unsigned char *le64) -{ -	return (((unsigned long long)le64[7] << 56) + -		((unsigned long long)le64[6] << 48) + -		((unsigned long long)le64[5] << 40) + -		((unsigned long long)le64[4] << 32) + -		((unsigned long long)le64[3] << 24) + -		((unsigned long long)le64[2] << 16) + -		((unsigned long long)le64[1] << 8) + -		(unsigned long long)le64[0]); -} -  /**   * efi_crc32() - EFI version of crc32 function   * @buf: buffer to calculate crc32 of @@ -79,7 +53,7 @@ static inline unsigned long long le64_to_int(unsigned char *le64)   *   * Description: Returns EFI-style CRC32 value for @buf   */ -static inline unsigned long efi_crc32(const void *buf, unsigned long len) +static inline u32 efi_crc32(const void *buf, u32 len)  {  	return crc32(0, buf, len);  } @@ -90,13 +64,10 @@ static inline unsigned long efi_crc32(const void *buf, unsigned long len)  static int pmbr_part_valid(struct partition *part);  static int is_pmbr_valid(legacy_mbr * mbr); -  static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,  				gpt_header * pgpt_head, gpt_entry ** pgpt_pte); -  static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,  				gpt_header * pgpt_head); -  static int is_pte_valid(gpt_entry * pte);  static char *print_efiname(gpt_entry *pte) @@ -142,6 +113,7 @@ static inline int is_bootable(gpt_entry *p)  			sizeof(efi_guid_t));  } +#ifdef CONFIG_EFI_PARTITION  /*   * Public Functions (include/part.h)   */ @@ -171,14 +143,14 @@ void print_part_efi(block_dev_desc_t * dev_desc)  	printf("\tType UUID\n");  	printf("\tPartition UUID\n"); -	for (i = 0; i < le32_to_int(gpt_head->num_partition_entries); i++) { +	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {  		/* Stop at the first non valid PTE */  		if (!is_pte_valid(&gpt_pte[i]))  			break;  		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1), -			le64_to_int(gpt_pte[i].starting_lba), -			le64_to_int(gpt_pte[i].ending_lba), +			le64_to_cpu(gpt_pte[i].starting_lba), +			le64_to_cpu(gpt_pte[i].ending_lba),  			print_efiname(&gpt_pte[i]));  		printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);  		uuid_string(gpt_pte[i].partition_type_guid.b, uuid); @@ -211,7 +183,7 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,  		return -1;  	} -	if (part > le32_to_int(gpt_head->num_partition_entries) || +	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||  	    !is_pte_valid(&gpt_pte[part - 1])) {  		printf("%s: *** ERROR: Invalid partition number %d ***\n",  			__func__, part); @@ -219,9 +191,9 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,  	}  	/* The ulong casting limits the maximum disk size to 2 TB */ -	info->start = (ulong) le64_to_int(gpt_pte[part - 1].starting_lba); +	info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba);  	/* The ending LBA is inclusive, to calculate size, add 1 to it */ -	info->size = ((ulong)le64_to_int(gpt_pte[part - 1].ending_lba) + 1) +	info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1)  		     - info->start;  	info->blksz = GPT_BLOCK_SIZE; @@ -253,6 +225,281 @@ int test_part_efi(block_dev_desc_t * dev_desc)  	return 0;  } +/** + * set_protective_mbr(): Set the EFI protective MBR + * @param dev_desc - block device descriptor + * + * @return - zero on success, otherwise error + */ +static int set_protective_mbr(block_dev_desc_t *dev_desc) +{ +	legacy_mbr *p_mbr; + +	/* Setup the Protective MBR */ +	p_mbr = calloc(1, sizeof(p_mbr)); +	if (p_mbr == NULL) { +		printf("%s: calloc failed!\n", __func__); +		return -1; +	} +	/* Append signature */ +	p_mbr->signature = MSDOS_MBR_SIGNATURE; +	p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT; +	p_mbr->partition_record[0].start_sect = 1; +	p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba; + +	/* Write MBR sector to the MMC device */ +	if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) { +		printf("** Can't write to device %d **\n", +			dev_desc->dev); +		free(p_mbr); +		return -1; +	} + +	free(p_mbr); +	return 0; +} + +/** + * string_uuid(); Convert UUID stored as string to bytes + * + * @param uuid - UUID represented as string + * @param dst - GUID buffer + * + * @return return 0 on successful conversion + */ +static int string_uuid(char *uuid, u8 *dst) +{ +	efi_guid_t guid; +	u16 b, c, d; +	u64 e; +	u32 a; +	u8 *p; +	u8 i; + +	const u8 uuid_str_len = 36; + +	/* The UUID is written in text: */ +	/* 1        9    14   19   24 */ +	/* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ + +	debug("%s: uuid: %s\n", __func__, uuid); + +	if (strlen(uuid) != uuid_str_len) +		return -1; + +	for (i = 0; i < uuid_str_len; i++) { +		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { +			if (uuid[i] != '-') +				return -1; +		} else { +			if (!isxdigit(uuid[i])) +				return -1; +		} +	} + +	a = (u32)simple_strtoul(uuid, NULL, 16); +	b = (u16)simple_strtoul(uuid + 9, NULL, 16); +	c = (u16)simple_strtoul(uuid + 14, NULL, 16); +	d = (u16)simple_strtoul(uuid + 19, NULL, 16); +	e = (u64)simple_strtoull(uuid + 24, NULL, 16); + +	p = (u8 *) &e; +	guid = EFI_GUID(a, b, c, d >> 8, d & 0xFF, +			*(p + 5), *(p + 4), *(p + 3), +			*(p + 2), *(p + 1) , *p); + +	memcpy(dst, guid.b, sizeof(efi_guid_t)); + +	return 0; +} + +int write_gpt_table(block_dev_desc_t *dev_desc, +		gpt_header *gpt_h, gpt_entry *gpt_e) +{ +	const int pte_blk_num = (gpt_h->num_partition_entries +		* sizeof(gpt_entry)) / dev_desc->blksz; + +	u32 calc_crc32; +	u64 val; + +	debug("max lba: %x\n", (u32) dev_desc->lba); +	/* Setup the Protective MBR */ +	if (set_protective_mbr(dev_desc) < 0) +		goto err; + +	/* Generate CRC for the Primary GPT Header */ +	calc_crc32 = efi_crc32((const unsigned char *)gpt_e, +			      le32_to_cpu(gpt_h->num_partition_entries) * +			      le32_to_cpu(gpt_h->sizeof_partition_entry)); +	gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32); + +	calc_crc32 = efi_crc32((const unsigned char *)gpt_h, +			      le32_to_cpu(gpt_h->header_size)); +	gpt_h->header_crc32 = cpu_to_le32(calc_crc32); + +	/* Write the First GPT to the block right after the Legacy MBR */ +	if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1) +		goto err; + +	if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_num, gpt_e) +	    != pte_blk_num) +		goto err; + +	/* recalculate the values for the Second GPT Header */ +	val = le64_to_cpu(gpt_h->my_lba); +	gpt_h->my_lba = gpt_h->alternate_lba; +	gpt_h->alternate_lba = cpu_to_le64(val); +	gpt_h->header_crc32 = 0; + +	calc_crc32 = efi_crc32((const unsigned char *)gpt_h, +			      le32_to_cpu(gpt_h->header_size)); +	gpt_h->header_crc32 = cpu_to_le32(calc_crc32); + +	if (dev_desc->block_write(dev_desc->dev, +				  le32_to_cpu(gpt_h->last_usable_lba + 1), +				  pte_blk_num, gpt_e) != pte_blk_num) +		goto err; + +	if (dev_desc->block_write(dev_desc->dev, +				  le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1) +		goto err; + +	debug("GPT successfully written to block device!\n"); +	return 0; + + err: +	printf("** Can't write to device %d **\n", dev_desc->dev); +	return -1; +} + +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, +		disk_partition_t *partitions, int parts) +{ +	u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba); +	ulong start; +	int i, k; +	size_t name_len; +#ifdef CONFIG_PARTITION_UUIDS +	char *str_uuid; +#endif + +	for (i = 0; i < parts; i++) { +		/* partition starting lba */ +		start = partitions[i].start; +		if (start && (start < offset)) { +			printf("Partition overlap\n"); +			return -1; +		} +		if (start) { +			gpt_e[i].starting_lba = cpu_to_le64(start); +			offset = start + partitions[i].size; +		} else { +			gpt_e[i].starting_lba = cpu_to_le64(offset); +			offset += partitions[i].size; +		} +		if (offset >= gpt_h->last_usable_lba) { +			printf("Partitions layout exceds disk size\n"); +			return -1; +		} +		/* partition ending lba */ +		if ((i == parts - 1) && (partitions[i].size == 0)) +			/* extend the last partition to maximuim */ +			gpt_e[i].ending_lba = gpt_h->last_usable_lba; +		else +			gpt_e[i].ending_lba = cpu_to_le64(offset - 1); + +		/* partition type GUID */ +		memcpy(gpt_e[i].partition_type_guid.b, +			&PARTITION_BASIC_DATA_GUID, 16); + +#ifdef CONFIG_PARTITION_UUIDS +		str_uuid = partitions[i].uuid; +		if (string_uuid(str_uuid, gpt_e[i].unique_partition_guid.b)) { +			printf("Partition no. %d: invalid guid: %s\n", +				i, str_uuid); +			return -1; +		} +#endif + +		/* partition attributes */ +		memset(&gpt_e[i].attributes, 0, +		       sizeof(gpt_entry_attributes)); + +		/* partition name */ +		name_len = sizeof(gpt_e[i].partition_name) +			/ sizeof(efi_char16_t); +		for (k = 0; k < name_len; k++) +			gpt_e[i].partition_name[k] = +				(efi_char16_t)(partitions[i].name[k]); + +		debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%lx\n", +		      __func__, partitions[i].name, i, +		      offset, i, partitions[i].size); +	} + +	return 0; +} + +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, +		char *str_guid, int parts_count) +{ +	gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); +	gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); +	gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); +	gpt_h->my_lba = cpu_to_le64(1); +	gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1); +	gpt_h->first_usable_lba = cpu_to_le64(34); +	gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34); +	gpt_h->partition_entry_lba = cpu_to_le64(2); +	gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); +	gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); +	gpt_h->header_crc32 = 0; +	gpt_h->partition_entry_array_crc32 = 0; + +	if (string_uuid(str_guid, gpt_h->disk_guid.b)) +		return -1; + +	return 0; +} + +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, +		disk_partition_t *partitions, int parts_count) +{ +	int ret; + +	gpt_header *gpt_h = calloc(1, sizeof(gpt_header)); +	if (gpt_h == NULL) { +		printf("%s: calloc failed!\n", __func__); +		return -1; +	} + +	gpt_entry *gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry)); +	if (gpt_e == NULL) { +		printf("%s: calloc failed!\n", __func__); +		free(gpt_h); +		return -1; +	} + +	/* Generate Primary GPT header (LBA1) */ +	ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count); +	if (ret) +		goto err; + +	/* Generate partition entries */ +	ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count); +	if (ret) +		goto err; + +	/* Write GPT partition table */ +	ret = write_gpt_table(dev_desc, gpt_h, gpt_e); + +err: +	free(gpt_e); +	free(gpt_h); +	return ret; +} +#endif +  /*   * Private functions   */ @@ -264,7 +511,7 @@ int test_part_efi(block_dev_desc_t * dev_desc)  static int pmbr_part_valid(struct partition *part)  {  	if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT && -		le32_to_int(part->start_sect) == 1UL) { +		le32_to_cpu(part->start_sect) == 1UL) {  		return 1;  	} @@ -283,9 +530,8 @@ static int is_pmbr_valid(legacy_mbr * mbr)  {  	int i = 0; -	if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) { +	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)  		return 0; -	}  	for (i = 0; i < 4; i++) {  		if (pmbr_part_valid(&mbr->partition_record[i])) { @@ -308,8 +554,8 @@ static int is_pmbr_valid(legacy_mbr * mbr)  static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,  			gpt_header * pgpt_head, gpt_entry ** pgpt_pte)  { -	unsigned char crc32_backup[4] = { 0 }; -	unsigned long calc_crc32; +	u32 crc32_backup = 0; +	u32 calc_crc32;  	unsigned long long lastlba;  	if (!dev_desc || !pgpt_head) { @@ -324,54 +570,54 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,  	}  	/* Check the GPT header signature */ -	if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) { +	if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {  		printf("GUID Partition Table Header signature is wrong:"  			"0x%llX != 0x%llX\n", -			(unsigned long long)le64_to_int(pgpt_head->signature), -			(unsigned long long)GPT_HEADER_SIGNATURE); +			le64_to_cpu(pgpt_head->signature), +			GPT_HEADER_SIGNATURE);  		return 0;  	}  	/* Check the GUID Partition Table CRC */ -	memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup)); -	memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32)); +	memcpy(&crc32_backup, &pgpt_head->header_crc32, sizeof(crc32_backup)); +	memset(&pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));  	calc_crc32 = efi_crc32((const unsigned char *)pgpt_head, -		le32_to_int(pgpt_head->header_size)); +		le32_to_cpu(pgpt_head->header_size)); -	memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup)); +	memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup)); -	if (calc_crc32 != le32_to_int(crc32_backup)) { +	if (calc_crc32 != le32_to_cpu(crc32_backup)) {  		printf("GUID Partition Table Header CRC is wrong:" -			"0x%08lX != 0x%08lX\n", -			le32_to_int(crc32_backup), calc_crc32); +			"0x%x != 0x%x\n", +		       le32_to_cpu(crc32_backup), calc_crc32);  		return 0;  	}  	/* Check that the my_lba entry points to the LBA that contains the GPT */ -	if (le64_to_int(pgpt_head->my_lba) != lba) { +	if (le64_to_cpu(pgpt_head->my_lba) != lba) {  		printf("GPT: my_lba incorrect: %llX != %llX\n", -			(unsigned long long)le64_to_int(pgpt_head->my_lba), -			(unsigned long long)lba); +			le64_to_cpu(pgpt_head->my_lba), +			lba);  		return 0;  	}  	/* Check the first_usable_lba and last_usable_lba are within the disk. */  	lastlba = (unsigned long long)dev_desc->lba; -	if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) { +	if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) {  		printf("GPT: first_usable_lba incorrect: %llX > %llX\n", -			le64_to_int(pgpt_head->first_usable_lba), lastlba); +			le64_to_cpu(pgpt_head->first_usable_lba), lastlba);  		return 0;  	} -	if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) { +	if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) {  		printf("GPT: last_usable_lba incorrect: %llX > %llX\n", -			le64_to_int(pgpt_head->last_usable_lba), lastlba); +			(u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba);  		return 0;  	}  	debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n", -		le64_to_int(pgpt_head->first_usable_lba), -		le64_to_int(pgpt_head->last_usable_lba), lastlba); +		le64_to_cpu(pgpt_head->first_usable_lba), +		le64_to_cpu(pgpt_head->last_usable_lba), lastlba);  	/* Read and allocate Partition Table Entries */  	*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head); @@ -382,13 +628,13 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,  	/* Check the GUID Partition Table Entry Array CRC */  	calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte, -		le32_to_int(pgpt_head->num_partition_entries) * -		le32_to_int(pgpt_head->sizeof_partition_entry)); +		le32_to_cpu(pgpt_head->num_partition_entries) * +		le32_to_cpu(pgpt_head->sizeof_partition_entry)); -	if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) { +	if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) {  		printf("GUID Partition Table Entry Array CRC is wrong:" -			"0x%08lX != 0x%08lX\n", -			le32_to_int(pgpt_head->partition_entry_array_crc32), +			"0x%x != 0x%x\n", +			le32_to_cpu(pgpt_head->partition_entry_array_crc32),  			calc_crc32);  		free(*pgpt_pte); @@ -419,12 +665,12 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,  		return NULL;  	} -	count = le32_to_int(pgpt_head->num_partition_entries) * -		le32_to_int(pgpt_head->sizeof_partition_entry); +	count = le32_to_cpu(pgpt_head->num_partition_entries) * +		le32_to_cpu(pgpt_head->sizeof_partition_entry); -	debug("%s: count = %lu * %lu = %zu\n", __func__, -		le32_to_int(pgpt_head->num_partition_entries), -		le32_to_int(pgpt_head->sizeof_partition_entry), count); +	debug("%s: count = %u * %u = %zu\n", __func__, +	      (u32) le32_to_cpu(pgpt_head->num_partition_entries), +	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);  	/* Allocate memory for PTE, remember to FREE */  	if (count != 0) { @@ -440,7 +686,7 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,  	/* Read GPT Entries from device */  	if (dev_desc->block_read (dev_desc->dev, -		(unsigned long)le64_to_int(pgpt_head->partition_entry_lba), +		le64_to_cpu(pgpt_head->partition_entry_lba),  		(lbaint_t) (count / GPT_BLOCK_SIZE), pte)  		!= (count / GPT_BLOCK_SIZE)) { diff --git a/doc/README.gpt b/doc/README.gpt new file mode 100644 index 000000000..a9c58b4c9 --- /dev/null +++ b/doc/README.gpt @@ -0,0 +1,201 @@ +# +#  Copyright (C) 2012 Samsung Electronics +# +#  Lukasz Majewski <l.majewski@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 + + +Glossary: +======== +- UUID -(Universally Unique Identifier) +- GUID - (Globally Unique ID) +- EFI - (Extensible Firmware Interface) +- UEFI - (Unified EFI) - EFI evolution +- GPT (GUID Partition Table) - it is the EFI standard part +- partitions - lists of available partitions (defined at u-boot): +  ./include/configs/{target}.h + +Introduction: +============= +This document describes the GPT partition table format and usage of +the gpt command in u-boot. + + +UUID introduction: +==================== + +GPT for marking disks/partitions is using the UUID. It is supposed to be a +globally unique value. A UUID is a 16-byte (128-bit) number. The number of +theoretically possible UUIDs is therefore about 3 x 10^38. +More often UUID is displayed as 32 hexadecimal digits, in 5 groups, +separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters +(32 digits and 4 hyphens) + +For instance, GUID of Linux data partition: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 + +Historically there are 5 methods to generate this number. The oldest one is +combining machine's MAC address and timer (epoch) value. + +Successive versions are using MD5 hash, random numbers and SHA-1 hash. All major +OSes and programming languages are providing libraries to compute UUID (e.g. +uuid command line tool). + +GPT brief explanation: +====================== + +	Layout: +	------- + +	-------------------------------------------------- +	LBA 0          |Protective MBR                   | +	---------------------------------------------------------- +	LBA 1          |Primary GPT Header               | Primary +	-------------------------------------------------- GPT +	LBA 2          |Entry 1|Entry 2| Entry 3| Entry 4| +	-------------------------------------------------- +	LBA 3          |Entries 5 - 128                  | +		       |                                 | +		       |                                 | +	---------------------------------------------------------- +	LBA 34         |Partition 1                      | +		       |                                 | +		       ----------------------------------- +		       |Partition 2                      | +		       |                                 | +		       ----------------------------------- +		       |Partition n                      | +		       |                                 | +	---------------------------------------------------------- +	LBA -34        |Entry 1|Entry 2| Entry 3| Entry 4| Secondary +	-------------------------------------------------- (bkp) +	LBA -33        |Entries 5 - 128                  | GPT +		       |                                 | +		       |                                 | +	LBA -2         |                                 | +	-------------------------------------------------- +	LBA -1         |Secondary GPT Header             | +	---------------------------------------------------------- + + +For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called +"protective MBR". +Its first partition entry ID has 0xEE value, and disk software, which is not +handling the GPT sees it as a storage device without free space. + +It is possible to define 128 linearly placed partition entries. + +"LBA -1" means the last addressable block (in the mmc subsystem: +"dev_desc->lba - 1") + +Primary/Secondary GPT header: +---------------------------- +Offset  Size    Description + +0       8 B     Signature ("EFI PART", 45 46 49 20 50 41 52 54) +8       4 B     Revision (For version 1.0, the value is 00 00 01 00) +12      4 B     Header size (in bytes, usually 5C 00 00 00 meaning 92 bytes) +16      4 B     CRC32 of header (0 to header size), with this field zeroed +		during calculation +20      4 B     Reserved (ZERO); +24      8 B     Current LBA (location of this header copy) +32      8 B     Backup LBA (location of the other header copy) +40      8 B     First usable LBA for partitions (primary partition table last +		LBA + 1) +48      8 B     Last usable LBA (secondary partition table first LBA - 1) +56      16 B    Disk GUID (also referred as UUID on UNIXes) +72      8 B     Partition entries starting LBA (always 2 in primary copy) +80      4 B     Number of partition entries +84      4 B     Size of a partition entry (usually 128) +88      4 B     CRC32 of partition array +92      *       Reserved; must be ZERO (420 bytes for a 512-byte LBA) + +TOTAL: 512 B + + + +IMPORTANT: + +GPT headers and partition entries are protected by CRC32 (the POSIX CRC32). + +Primary GPT header and Secondary GPT header have swapped values of "Current LBA" +and "Backup LBA" and therefore different CRC32 check-sum. + +CRC32 for GPT headers (field "CRC of header") are calculated up till +"Header size" (92), NOT 512 bytes. + +CRC32 for partition entries (field "CRC32 of partition array") is calculated for +the whole array entry ( Number_of_partition_entries * +sizeof(partition_entry_size (usually 128))) + +Observe, how Secondary GPT is placed in the memory. It is NOT a mirror reflect +of the Primary. + + +	   Partition Entry Format: +	   ---------------------- +	   Offset  Size    Description + +	   0       16 B    Partition type GUID +	   16      16 B    Unique partition GUID +	   32      8  B    First LBA (Little Endian) +	   40      8  B    Last LBA (inclusive) +	   48      8  B    Attribute flags [+] +	   56      72 B    Partition name (text) + +	   Attribute flags: +	   Bit 0  - System partition +	   Bit 60 - Read-only +	   Bit 62 - Hidden +	   Bit 63 - Not mount + + +Creating GPT partitions in U-Boot: +============== + +To restore GUID partition table one needs to: +1. Define partition layout in the environment. +   Format of partitions layout: +     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...; +	name=kernel,size=60MiB,uuid=...;" +     or +     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name}, +	size=${uboot_size},uuid=${uboot_uuid};" + +   Fields 'name', 'size' and 'uuid' are mandatory for every partition. +   The field 'start' is optional. + +2. Define 'CONFIG_EFI_PARTITION' and 'CONFIG_CMD_GPT' + +2. From u-boot prompt type: +   gpt write mmc 0 $partitions + + +Useful info: +============ + +Two programs, namely: 'fdisk' and 'parted' are recommended to work with GPT +recovery. Parted is able to handle GUID partitions. Unfortunately the 'fdisk' +hasn't got such ability. +Please, pay attention at -l switch for parted. + +"uuid" program is recommended to generate UUID string. Moreover it can decode +(-d switch) passed in UUID string. It can be used to generate partitions UUID +passed to u-boot environment variables. diff --git a/doc/README.silent b/doc/README.silent index a26e3df0d..70202cece 100644 --- a/doc/README.silent +++ b/doc/README.silent @@ -1,9 +1,15 @@  The config option CONFIG_SILENT_CONSOLE can be used to quiet messages  on the console.  If the option has been enabled, the output can be -silenced by setting the environment variable "silent".  The variable -is latched into the global data at an early stage in the boot process -so deleting it with "setenv" will not take effect until the system is -restarted. +silenced by setting the environment variable "silent". + +- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET +	When the "silent" variable is changed with env set, the change +	will take effect immediately. + +- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC +	Some environments are not available until relocation (e.g. NAND) +	so this will make the value in the flash env take effect at +	relocation.  The following actions are taken if "silent" is set at boot time: diff --git a/doc/device-tree-bindings/pwm/tegra20-pwm.txt b/doc/device-tree-bindings/pwm/tegra20-pwm.txt new file mode 100644 index 000000000..01438ecd6 --- /dev/null +++ b/doc/device-tree-bindings/pwm/tegra20-pwm.txt @@ -0,0 +1,18 @@ +Tegra SoC PWFM controller + +Required properties: +- compatible: should be one of: +  - "nvidia,tegra20-pwm" +  - "nvidia,tegra30-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The +  first cell specifies the per-chip index of the PWM to use and the second +  cell is the period in nanoseconds. + +Example: + +	pwm: pwm@7000a000 { +		compatible = "nvidia,tegra20-pwm"; +		reg = <0x7000a000 0x100>; +		#pwm-cells = <2>; +	}; diff --git a/doc/device-tree-bindings/video/displaymode.txt b/doc/device-tree-bindings/video/displaymode.txt new file mode 100644 index 000000000..45ca42db5 --- /dev/null +++ b/doc/device-tree-bindings/video/displaymode.txt @@ -0,0 +1,42 @@ +videomode bindings +================== + +(from http://lists.freedesktop.org/archives/dri-devel/2012-July/024875.html) + +Required properties: + - xres, yres: Display resolution + - left-margin, right-margin, hsync-len: Horizontal Display timing +   parameters in pixels + - upper-margin, lower-margin, vsync-len: Vertical display timing +   parameters in lines + - clock: display clock in Hz + +Optional properties: + - width-mm, height-mm: Display dimensions in mm + - hsync-active-high (bool): Hsync pulse is active high + - vsync-active-high (bool): Vsync pulse is active high + - interlaced (bool): This is an interlaced mode + - doublescan (bool): This is a doublescan mode + +There are different ways of describing a display mode. The devicetree +representation corresponds to the one used by the Linux Framebuffer +framework described here in Documentation/fb/framebuffer.txt. This +representation has been chosen because it's the only format which does +not allow for inconsistent parameters. Unlike the Framebuffer framework +the devicetree has the clock in Hz instead of ps. + +Example: + +	display@0 { +		/* 1920x1080p24 */ +		clock = <52000000>; +		xres = <1920>; +		yres = <1080>; +		left-margin = <25>; +		right-margin = <25>; +		hsync-len = <25>; +		lower-margin = <2>; +		upper-margin = <2>; +		vsync-len = <2>; +		hsync-active-high; +	}; diff --git a/doc/device-tree-bindings/video/tegra20-dc.txt b/doc/device-tree-bindings/video/tegra20-dc.txt new file mode 100644 index 000000000..4731c3fba --- /dev/null +++ b/doc/device-tree-bindings/video/tegra20-dc.txt @@ -0,0 +1,85 @@ +Display Controller +------------------ + +(there isn't yet a generic binding in Linux, so this describes what is in +U-Boot, and may change based on Linux activity) + +The device node for a display device is as described in the document +"Open Firmware Recommended Practice : Universal Serial Bus" with the +following modifications and additions : + +Required properties : + - compatible : Should be "nvidia,tegra20-dc" + +Required subnode 'rgb' is as follows: + +Required properties (rgb) : + - nvidia,panel : phandle of LCD panel information + + +The panel node describes the panel itself. This has the properties listed in +displaymode.txt as well as: + +Required properties (panel) : + - nvidia,bits-per-pixel: number of bits per pixel (depth) + - nvidia,pwm : pwm to use to set display contrast (see tegra20-pwm.txt) + - nvidia,panel-timings: 4 cells containing required timings in ms: +	* delay before asserting panel_vdd +	* delay between panel_vdd-rise and data-rise +	* delay between data-rise and backlight_vdd-rise +	* delay between backlight_vdd and pwm-rise +	* delay between pwm-rise and backlight_en-rise + +Optional GPIO properies all have (phandle, GPIO number, flags): + - nvidia,backlight-enable-gpios: backlight enable GPIO + - nvidia,lvds-shutdown-gpios: LVDS power shutdown GPIO + - nvidia,backlight-vdd-gpios: backlight power GPIO + - nvidia,panel-vdd-gpios: panel power GPIO + +Example: + +host1x { +	compatible = "nvidia,tegra20-host1x", "simple-bus"; +	reg = <0x50000000 0x00024000>; +	interrupts = <0 65 0x04   /* mpcore syncpt */ +			0 67 0x04>; /* mpcore general */ + +	#address-cells = <1>; +	#size-cells = <1>; +	status = "okay"; + +	ranges = <0x54000000 0x54000000 0x04000000>; + +	dc@54200000 { +		compatible = "nvidia,tegra20-dc"; +		reg = <0x54200000 0x00040000>; +		interrupts = <0 73 0x04>; +		status = "okay"; + +		rgb { +			status = "okay"; +			nvidia,panel = <&lcd_panel>; +		}; +	}; +}; + +lcd_panel: panel { +	/* Seaboard has 1366x768 */ +	clock = <70600000>; +	xres = <1366>; +	yres = <768>; +	left-margin = <58>; +	right-margin = <58>; +	hsync-len = <58>; +	lower-margin = <4>; +	upper-margin = <4>; +	vsync-len = <4>; +	hsync-active-high; +	nvidia,bits-per-pixel = <16>; +	nvidia,pwm = <&pwm 2 0>; +	nvidia,backlight-enable-gpios = <&gpio 28 0>;	/* PD4 */ +	nvidia,lvds-shutdown-gpios = <&gpio 10 0>;	/* PB2 */ +	nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */ +	nvidia,panel-vdd-gpios = <&gpio 22 0>;		/* PC6 */ +	nvidia,panel-timings = <400 4 203 17 15>; +}; diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 47f321392..656bf4a06 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -144,9 +144,11 @@ void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)  struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio)  { -	int bank = gpio / GPIO_PER_BANK; -	bank *= sizeof(struct s5p_gpio_bank); +	int bank; +	unsigned g = gpio - s5p_gpio_part_max(gpio); +	bank = g / GPIO_PER_BANK; +	bank *= sizeof(struct s5p_gpio_bank);  	return (struct s5p_gpio_bank *) (s5p_gpio_base(gpio) + bank);  } diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index bf64a2a64..665387091 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -26,7 +26,12 @@  #include <asm/arch/hardware.h>  #include "designware_i2c.h" -static struct i2c_regs *const i2c_regs_p = +#ifdef CONFIG_I2C_MULTI_BUS +static unsigned int bus_initialized[CONFIG_SYS_I2C_BUS_MAX]; +static unsigned int current_bus = 0; +#endif + +static struct i2c_regs *i2c_regs_p =      (struct i2c_regs *)CONFIG_SYS_I2C_BASE;  /* @@ -39,7 +44,6 @@ static void set_speed(int i2c_spd)  {  	unsigned int cntl;  	unsigned int hcnt, lcnt; -	unsigned int high, low;  	unsigned int enbl;  	/* to set speed cltr must be disabled */ @@ -47,39 +51,38 @@ static void set_speed(int i2c_spd)  	enbl &= ~IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable); -  	cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK));  	switch (i2c_spd) {  	case IC_SPEED_MODE_MAX:  		cntl |= IC_CON_SPD_HS; -		high = MIN_HS_SCL_HIGHTIME; -		low = MIN_HS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_hs_scl_hcnt); +		lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_hs_scl_lcnt);  		break;  	case IC_SPEED_MODE_STANDARD:  		cntl |= IC_CON_SPD_SS; -		high = MIN_SS_SCL_HIGHTIME; -		low = MIN_SS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_ss_scl_hcnt); +		lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_ss_scl_lcnt);  		break;  	case IC_SPEED_MODE_FAST:  	default:  		cntl |= IC_CON_SPD_FS; -		high = MIN_FS_SCL_HIGHTIME; -		low = MIN_FS_SCL_LOWTIME; +		hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; +		writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); +		lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; +		writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt);  		break;  	}  	writel(cntl, &i2c_regs_p->ic_con); -	hcnt = (IC_CLK * high) / NANO_TO_MICRO; -	writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); - -	lcnt = (IC_CLK * low) / NANO_TO_MICRO; -	writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); - -	/* re-enable i2c ctrl back now that speed is set */ +	/* Enable back i2c now speed set */  	enbl |= IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable);  } @@ -150,6 +153,10 @@ void i2c_init(int speed, int slaveadd)  	enbl = readl(&i2c_regs_p->ic_enable);  	enbl |= IC_ENABLE_0B;  	writel(enbl, &i2c_regs_p->ic_enable); + +#ifdef CONFIG_I2C_MULTI_BUS +	bus_initialized[current_bus] = 1; +#endif  }  /* @@ -274,7 +281,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)  	start_time_rx = get_timer(0);  	while (len) { -		writel(IC_CMD, &i2c_regs_p->ic_cmd_data); +		if (len == 1) +			writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data); +		else +			writel(IC_CMD, &i2c_regs_p->ic_cmd_data);  		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) {  			*buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); @@ -313,9 +323,11 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  	start_time_tx = get_timer(0);  	while (len) {  		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { -			writel(*buffer, &i2c_regs_p->ic_cmd_data); +			if (--len == 0) +				writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data); +			else +				writel(*buffer, &i2c_regs_p->ic_cmd_data);  			buffer++; -			len--;  			start_time_tx = get_timer(0);  		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { @@ -344,3 +356,74 @@ int i2c_probe(uchar chip)  	return ret;  } + +#ifdef CONFIG_I2C_MULTI_BUS +int i2c_set_bus_num(unsigned int bus) +{ +	switch (bus) { +	case 0: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE; +		break; +#ifdef CONFIG_SYS_I2C_BASE1 +	case 1: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE1; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE2 +	case 2: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE2; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE3 +	case 3: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE3; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE4 +	case 4: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE4; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE5 +	case 5: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE5; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE6 +	case 6: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE6; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE7 +	case 7: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE7; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE8 +	case 8: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE8; +		break; +#endif +#ifdef CONFIG_SYS_I2C_BASE9 +	case 9: +		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE9; +		break; +#endif +	default: +		printf("Bad bus: %d\n", bus); +		return -1; +	} + +	current_bus = bus; + +	if (!bus_initialized[current_bus]) +		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + +	return 0; +} + +int i2c_get_bus_num(void) +{ +	return current_bus; +} +#endif diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h index 03b520ed4..2faf4a871 100644 --- a/drivers/i2c/designware_i2c.h +++ b/drivers/i2c/designware_i2c.h @@ -60,14 +60,16 @@ struct i2c_regs {  	u32 ic_tx_abrt_source;  }; +#if !defined(IC_CLK)  #define IC_CLK			166 +#endif  #define NANO_TO_MICRO		1000  /* High and low times in different speed modes (in ns) */  #define MIN_SS_SCL_HIGHTIME	4000 -#define MIN_SS_SCL_LOWTIME	5000 -#define MIN_FS_SCL_HIGHTIME	800 -#define MIN_FS_SCL_LOWTIME	1700 +#define MIN_SS_SCL_LOWTIME	4700 +#define MIN_FS_SCL_HIGHTIME	600 +#define MIN_FS_SCL_LOWTIME	1300  #define MIN_HS_SCL_HIGHTIME	60  #define MIN_HS_SCL_LOWTIME	160 @@ -95,6 +97,7 @@ struct i2c_regs {  /* i2c data buffer and command register definitions */  #define IC_CMD			0x0100 +#define IC_STOP			0x0200  /* i2c interrupt status register definitions */  #define IC_GEN_CALL		0x0800 diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 18270b9de..a73b10b9c 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -115,7 +115,7 @@ static uint8_t i2c_imx_get_clk(unsigned int rate)  /*   * Set I2C Bus speed   */ -int bus_i2c_set_bus_speed(void *base, int speed) +static int bus_i2c_set_bus_speed(void *base, int speed)  {  	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;  	u8 clk_idx = i2c_imx_get_clk(speed); @@ -133,7 +133,7 @@ int bus_i2c_set_bus_speed(void *base, int speed)  /*   * Get I2C Speed   */ -unsigned int bus_i2c_get_bus_speed(void *base) +static unsigned int bus_i2c_get_bus_speed(void *base)  {  	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;  	u8 clk_idx = readb(&i2c_regs->ifdr); diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index 2a193c220..b907f7b37 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -28,6 +28,7 @@  #include <common.h>  #include <malloc.h> +#include <i2c.h>  #include <asm/errno.h>  #include <asm/io.h>  #include <asm/arch/clock.h> @@ -40,6 +41,7 @@ void mxs_i2c_reset(void)  {  	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;  	int ret; +	int speed = i2c_get_bus_speed();  	ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);  	if (ret) { @@ -53,6 +55,8 @@ void mxs_i2c_reset(void)  		&i2c_regs->hw_i2c_ctrl1_clr);  	writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set); + +	i2c_set_bus_speed(speed);  }  void mxs_i2c_setup_read(uint8_t chip, int len) @@ -210,37 +214,65 @@ int i2c_probe(uchar chip)  	return ret;  } -void i2c_init(int speed, int slaveadd) +int i2c_set_bus_speed(unsigned int speed)  {  	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; +	/* +	 * The timing derivation algorithm. There is no documentation for this +	 * algorithm available, it was derived by using the scope and fiddling +	 * with constants until the result observed on the scope was good enough +	 * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be +	 * possible to assume the algorithm works for other frequencies as well. +	 * +	 * Note it was necessary to cap the frequency on both ends as it's not +	 * possible to configure completely arbitrary frequency for the I2C bus +	 * clock. +	 */ +	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); +	uint32_t base = ((clk / speed) - 38) / 2; +	uint16_t high_count = base + 3; +	uint16_t low_count = base - 3; +	uint16_t rcv_count = (high_count * 3) / 4; +	uint16_t xmit_count = low_count / 4; -	mxs_i2c_reset(); +	if (speed > 540000) { +		printf("MXS I2C: Speed too high (%d Hz)\n", speed); +		return -EINVAL; +	} -	switch (speed) { -	case 100000: -		writel((0x0078 << I2C_TIMING0_HIGH_COUNT_OFFSET) | -			(0x0030 << I2C_TIMING0_RCV_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing0); -		writel((0x0080 << I2C_TIMING1_LOW_COUNT_OFFSET) | -			(0x0030 << I2C_TIMING1_XMIT_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing1); -		break; -	case 400000: -		writel((0x000f << I2C_TIMING0_HIGH_COUNT_OFFSET) | -			(0x0007 << I2C_TIMING0_RCV_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing0); -		writel((0x001f << I2C_TIMING1_LOW_COUNT_OFFSET) | -			(0x000f << I2C_TIMING1_XMIT_COUNT_OFFSET), -			&i2c_regs->hw_i2c_timing1); -		break; -	default: -		printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed); -		return; +	if (speed < 12000) { +		printf("MXS I2C: Speed too low (%d Hz)\n", speed); +		return -EINVAL;  	} -	writel((0x0015 << I2C_TIMING2_BUS_FREE_OFFSET) | -		(0x000d << I2C_TIMING2_LEADIN_COUNT_OFFSET), +	writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0); +	writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1); + +	writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) | +		(0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET),  		&i2c_regs->hw_i2c_timing2); +	return 0; +} + +unsigned int i2c_get_bus_speed(void) +{ +	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; +	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); +	uint32_t timing0; + +	timing0 = readl(&i2c_regs->hw_i2c_timing0); +	/* +	 * This is a reverse version of the algorithm presented in +	 * i2c_set_bus_speed(). Please refer there for details. +	 */ +	return clk / ((((timing0 >> 16) - 3) * 2) + 38); +} + +void i2c_init(int speed, int slaveadd) +{ +	mxs_i2c_reset(); +	i2c_set_bus_speed(speed); +  	return;  } diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 094305fdf..af454f901 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -179,7 +179,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)  		if (status & I2C_STAT_XRDY) {  			w = tmpbuf[i++];  #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX))  			w |= tmpbuf[i++] << 8;  #endif  			writew(w, &i2c_base->data); @@ -209,7 +210,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)  		}  		if (status & I2C_STAT_RRDY) {  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			*value = readb(&i2c_base->data);  #else  			*value = readw(&i2c_base->data); @@ -239,7 +241,8 @@ static void flush_fifo(void)  		stat = readw(&i2c_base->stat);  		if (stat == I2C_STAT_RRDY) {  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			readb(&i2c_base->data);  #else  			readw(&i2c_base->data); @@ -289,7 +292,8 @@ int i2c_probe(uchar chip)  		if (status & I2C_STAT_RRDY) {  			res = 0;  #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -    defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX)  			readb(&i2c_base->data);  #else  			readw(&i2c_base->data); @@ -376,7 +380,8 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  		if (status & I2C_STAT_XRDY) {  			w = (i < 0) ? tmpbuf[2+i] : buffer[i];  #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ -	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) +	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ +	defined(CONFIG_OMAP54XX))  			w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;  #endif  			writew(w, &i2c_base->data); diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f1d..90d297a28 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,7 +27,7 @@   */  #include <common.h> -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  #include <asm/arch/clk.h>  #include <asm/arch/cpu.h>  #else @@ -62,7 +62,7 @@  static unsigned int g_current_bus;	/* Stores Current I2C Bus */ -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  static int GetI2CSDA(void)  {  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -121,7 +121,12 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c)  static struct s3c24x0_i2c *get_base_i2c(void)  { -#ifdef CONFIG_EXYNOS5 +#ifdef CONFIG_EXYNOS4 +	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() +							+ (EXYNOS4_I2C_SPACING +							* g_current_bus)); +	return i2c; +#elif defined CONFIG_EXYNOS5  	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()  							+ (EXYNOS5_I2C_SPACING  							* g_current_bus)); @@ -134,7 +139,7 @@ static struct s3c24x0_i2c *get_base_i2c(void)  static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)  {  	ulong freq, pres = 16, div; -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	freq = get_i2c_clk();  #else  	freq = get_PCLK(); @@ -188,7 +193,7 @@ unsigned int i2c_get_bus_num(void)  void i2c_init(int speed, int slaveadd)  {  	struct s3c24x0_i2c *i2c; -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();  #endif  	int i; @@ -204,7 +209,7 @@ void i2c_init(int speed, int slaveadd)  		i--;  	} -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {  #ifdef CONFIG_S3C2410  		ulong old_gpecon = readl(&gpio->gpecon); @@ -248,7 +253,7 @@ void i2c_init(int speed, int slaveadd)  		writel(old_gpecon, &gpio->pgcon);  #endif  	} -#endif /* #ifndef CONFIG_EXYNOS5 */ +#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */  	i2c_ch_init(i2c, speed, slaveadd);  } diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 1595c0714..ae3c57392 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -30,6 +30,9 @@  #include <ioports.h>  #include <asm/io.h>  #endif +#if defined(CONFIG_AVR32) +#include <asm/arch/portmux.h> +#endif  #if defined(CONFIG_AT91FAMILY)  #include <asm/io.h>  #include <asm/arch/hardware.h> diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index ab7a9e33e..88471d3ed 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -63,6 +63,7 @@ static struct keyb {  	struct kbc_tegra *kbc;		/* tegra keyboard controller */  	unsigned char inited;		/* 1 if keyboard has been inited */  	unsigned char first_scan;	/* 1 if this is our first key scan */ +	unsigned char created;		/* 1 if driver has been created */  	/*  	 * After init we must wait a short time before polling the keyboard. @@ -306,6 +307,10 @@ static void tegra_kbc_open(void)   */  static int init_tegra_keyboard(void)  { +	/* check if already created */ +	if (config.created) +		return 0; +  #ifdef CONFIG_OF_CONTROL  	int	node; @@ -349,6 +354,7 @@ static int init_tegra_keyboard(void)  	config_kbc_gpio(config.kbc);  	tegra_kbc_open(); +	config.created = 1;  	debug("%s: Tegra keyboard ready\n", __func__);  	return 0; @@ -357,6 +363,8 @@ static int init_tegra_keyboard(void)  int drv_keyboard_init(void)  {  	struct stdio_dev dev; +	char *stdinname = getenv("stdin"); +	int error;  	if (input_init(&config.input, 0)) {  		debug("%s: Cannot set up input\n", __func__); @@ -372,5 +380,13 @@ int drv_keyboard_init(void)  	dev.start = init_tegra_keyboard;  	/* Register the device. init_tegra_keyboard() will be called soon */ -	return input_stdio_register(&dev); +	error = input_stdio_register(&dev); +	if (error) +		return error; +#ifdef CONFIG_CONSOLE_MUX +	error = iomux_doenv(stdin, stdinname); +	if (error) +		return error; +#endif +	return 0;  } diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index b141eafc7..d749ab095 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -565,10 +565,11 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	mmc->getcd = tegra_mmc_getcd;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; +	mmc->host_caps = 0;  	if (bus_width == 8) -		mmc->host_caps = MMC_MODE_8BIT; -	else -		mmc->host_caps = MMC_MODE_4BIT; +		mmc->host_caps |= MMC_MODE_8BIT; +	if (bus_width >= 4) +		mmc->host_caps |= MMC_MODE_4BIT;  	mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;  	/* diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 4701be846..e38e15125 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -1058,6 +1058,8 @@ int mxs_nand_init(struct mxs_nand_info *info)  {  	struct mxs_gpmi_regs *gpmi_regs =  		(struct mxs_gpmi_regs *)MXS_GPMI_BASE; +	struct mxs_bch_regs *bch_regs = +		(struct mxs_bch_regs *)MXS_BCH_BASE;  	int i = 0, j;  	info->desc = malloc(sizeof(struct mxs_dma_desc *) * @@ -1081,6 +1083,7 @@ int mxs_nand_init(struct mxs_nand_info *info)  	/* Reset the GPMI block. */  	mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg); +	mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);  	/*  	 * Choose NAND mode, set IRQ polarity, disable write protection and diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 2d4da4b38..8ba98b27d 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -1688,6 +1688,16 @@ e1000_init_hw(struct eth_device *nic)  		E1000_WRITE_REG(hw, TXDCTL, ctrl);  	} +	/* Set the receive descriptor write back policy */ + +	if (hw->mac_type >= e1000_82571) { +		ctrl = E1000_READ_REG(hw, RXDCTL); +		ctrl = +		    (ctrl & ~E1000_RXDCTL_WTHRESH) | +		    E1000_RXDCTL_FULL_RX_DESC_WB; +		E1000_WRITE_REG(hw, RXDCTL, ctrl); +	} +  	switch (hw->mac_type) {  	default:  		break; diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index fd1d8f871..1bbae5085 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -1551,6 +1551,7 @@ struct e1000_hw {  #define E1000_RXDCTL_HTHRESH 0x00003F00	/* RXDCTL Host Threshold */  #define E1000_RXDCTL_WTHRESH 0x003F0000	/* RXDCTL Writeback Threshold */  #define E1000_RXDCTL_GRAN    0x01000000	/* RXDCTL Granularity */ +#define E1000_RXDCTL_FULL_RX_DESC_WB 0x01010000	/* GRAN=1, WTHRESH=1 */  /* Transmit Descriptor Control */  #define E1000_TXDCTL_PTHRESH 0x0000003F	/* TXDCTL Prefetch Threshold */ diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e51e799e2..4b271989a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -425,6 +425,16 @@ static struct phy_driver M88E1118_driver = {  	.shutdown = &genphy_shutdown,  }; +static struct phy_driver M88E1118R_driver = { +	.name = "Marvell 88E1118R", +	.uid = 0x1410e40, +	.mask = 0xffffff0, +	.features = PHY_GBIT_FEATURES, +	.config = &m88e1118_config, +	.startup = &m88e1118_startup, +	.shutdown = &genphy_shutdown, +}; +  static struct phy_driver M88E1121R_driver = {  	.name = "Marvell 88E1121R",  	.uid = 0x1410cb0, @@ -461,6 +471,7 @@ int phy_marvell_init(void)  	phy_register(&M88E1145_driver);  	phy_register(&M88E1121R_driver);  	phy_register(&M88E1118_driver); +	phy_register(&M88E1118R_driver);  	phy_register(&M88E1111S_driver);  	phy_register(&M88E1011S_driver); diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 2d9cc328b..e6fc8c8bf 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -417,7 +417,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)  		printf(SHETHER_NAME ": 100Base/");  #if defined(SH_ETH_TYPE_GETHER)  		sh_eth_write(eth, GECMR_100B, GECMR); -#elif defined(CONFIG_CPU_SH7757) +#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)  		sh_eth_write(eth, 1, RTRATE);  #elif defined(CONFIG_CPU_SH7724)  		val = ECMR_RTM; @@ -426,7 +426,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)  		printf(SHETHER_NAME ": 10Base/");  #if defined(SH_ETH_TYPE_GETHER)  		sh_eth_write(eth, GECMR_10B, GECMR); -#elif defined(CONFIG_CPU_SH7757) +#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)  		sh_eth_write(eth, 0, RTRATE);  #endif  	} diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 61d2df906..568fafe5f 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -288,7 +288,7 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {  #if defined(CONFIG_CPU_SH7763) || defined(CONFIG_CPU_SH7734)  #define SH_ETH_TYPE_GETHER  #define BASE_IO_ADDR	0xfee00000 -#elif defined(CONFIG_CPU_SH7757) +#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)  #if defined(CONFIG_SH_ETHER_USE_GETHER)  #define SH_ETH_TYPE_GETHER  #define BASE_IO_ADDR	0xfee00000 @@ -346,7 +346,7 @@ enum DMAC_T_BIT {  /* GECMR */  enum GECMR_BIT { -#if defined(CONFIG_CPU_SH7757) +#if defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)  	GECMR_1000B = 0x20, GECMR_100B = 0x01, GECMR_10B = 0x00,  #else  	GECMR_1000B = 0x01, GECMR_100B = 0x04, GECMR_10B = 0x00, diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index e19a9a819..14d426f56 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -28,6 +28,7 @@ LIB	:= $(obj)libpmic.o  COBJS-$(CONFIG_POWER_MAX8998) += pmic_max8998.o  COBJS-$(CONFIG_POWER_MAX8997) += pmic_max8997.o  COBJS-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o +COBJS-$(CONFIG_POWER_MAX77686) += pmic_max77686.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/power/pmic/pmic_max77686.c b/drivers/power/pmic/pmic_max77686.c new file mode 100644 index 000000000..fce0183af --- /dev/null +++ b/drivers/power/pmic/pmic_max77686.c @@ -0,0 +1,48 @@ +/* + *  Copyright (C) 2012 Samsung Electronics + *  Rajeshwari Shinde <rajeshwari.s@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 <power/pmic.h> +#include <power/max77686_pmic.h> +#include <errno.h> + +int pmic_init(unsigned char bus) +{ +	static const char name[] = "MAX77686_PMIC"; +	struct pmic *p = pmic_alloc(); + +	if (!p) { +		printf("%s: POWER allocation error!\n", __func__); +		return -ENOMEM; +	} + +	puts("Board PMIC init\n"); +	p->name = name; +	p->interface = PMIC_I2C; +	p->number_of_regs = PMIC_NUM_OF_REGS; +	p->hw.i2c.addr = MAX77686_I2C_ADDR; +	p->hw.i2c.tx_num = 1; +	p->bus = bus; + +	return 0; +} diff --git a/drivers/serial/s3c64xx.c b/drivers/serial/s3c64xx.c index f53c2bf00..b590992dc 100644 --- a/drivers/serial/s3c64xx.c +++ b/drivers/serial/s3c64xx.c @@ -22,7 +22,8 @@   */  #include <common.h> - +#include <linux/compiler.h> +#include <serial.h>  #include <asm/arch/s3c6400.h>  DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index f5f43a6dd..1f8955a0f 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -22,6 +22,7 @@   */  #include <common.h> +#include <environment.h>  #include <serial.h>  #include <stdio_dev.h>  #include <post.h> @@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR;  static struct serial_device *serial_devices;  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 @@ -46,6 +52,70 @@ static void serial_null(void)  }  /** + * on_baudrate() - Update the actual baudrate when the env var changes + * + * This will check for a valid baudrate and only apply it if valid. + */ +static int on_baudrate(const char *name, const char *value, enum env_op op, +	int flags) +{ +	int i; +	int baudrate; + +	switch (op) { +	case env_op_create: +	case env_op_overwrite: +		/* +		 * Switch to new baudrate if new baudrate is supported +		 */ +		baudrate = simple_strtoul(value, NULL, 10); + +		/* Not actually changing */ +		if (gd->baudrate == baudrate) +			return 0; + +		for (i = 0; i < N_BAUDRATES; ++i) { +			if (baudrate == baudrate_table[i]) +				break; +		} +		if (i == N_BAUDRATES) { +			if ((flags & H_FORCE) == 0) +				printf("## Baudrate %d bps not supported\n", +					baudrate); +			return 1; +		} +		if ((flags & H_INTERACTIVE) != 0) { +			printf("## Switch baudrate to %d" +				" bps and press ENTER ...\n", baudrate); +			udelay(50000); +		} + +		gd->baudrate = baudrate; +#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) +		gd->bd->bi_baudrate = baudrate; +#endif + +		serial_setbrg(); + +		udelay(50000); + +		if ((flags & H_INTERACTIVE) != 0) +			while (1) { +				if (getc() == '\r') +					break; +			} + +		return 0; +	case env_op_delete: +		printf("## Baudrate may not be deleted\n"); +		return 1; +	default: +		return 0; +	} +} +U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); + +/**   * serial_initfunc() - Forward declare of driver registration routine   * @name:	Name of the real driver registration routine.   * diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile new file mode 100644 index 000000000..8fdffb10e --- /dev/null +++ b/drivers/sound/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2012 Samsung Electronics +# R. Chandrasekar <rcsekar@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 $(TOPDIR)/config.mk + +LIB	:= $(obj)libsound.o + +COBJS-$(CONFIG_SOUND)	+= sound.o +COBJS-$(CONFIG_I2S)	+= samsung-i2s.o +COBJS-$(CONFIG_SOUND_WM8994)	+= wm8994.o + +COBJS	:= $(COBJS-y) +SRCS	:= $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) + +all:	$(LIB) + +$(LIB):	$(obj).depend $(OBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +# diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c new file mode 100644 index 000000000..9f3117dd9 --- /dev/null +++ b/drivers/sound/samsung-i2s.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar <rcsekar@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 <asm/arch/clk.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/i2s-regs.h> +#include <asm/io.h> +#include <common.h> +#include <sound.h> +#include <i2s.h> + +#define FIC_TX2COUNT(x)		(((x) >>  24) & 0xf) +#define FIC_TX1COUNT(x)		(((x) >>  16) & 0xf) +#define FIC_TXCOUNT(x)		(((x) >>  8) & 0xf) +#define FIC_RXCOUNT(x)		(((x) >>  0) & 0xf) +#define FICS_TXCOUNT(x)		(((x) >>  8) & 0x7f) + +#define TIMEOUT_I2S_TX		100	/* i2s transfer timeout */ + +/* + * Sets the frame size for I2S LR clock + * + * @param i2s_reg	i2s regiter address + * @param rfs		Frame Size + */ +static void i2s_set_lr_framesize(struct i2s_reg *i2s_reg, unsigned int rfs) +{ +	unsigned int mod = readl(&i2s_reg->mod); + +	mod &= ~MOD_RCLK_MASK; + +	switch (rfs) { +	case 768: +		mod |= MOD_RCLK_768FS; +		break; +	case 512: +		mod |= MOD_RCLK_512FS; +		break; +	case 384: +		mod |= MOD_RCLK_384FS; +		break; +	default: +		mod |= MOD_RCLK_256FS; +		break; +	} + +	writel(mod, &i2s_reg->mod); +} + +/* + * Sets the i2s transfer control + * + * @param i2s_reg	i2s regiter address + * @param on		1 enable tx , 0 disable tx transfer + */ +static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) +{ +	unsigned int con = readl(&i2s_reg->con); +	unsigned int mod = readl(&i2s_reg->mod) & ~MOD_MASK; + +	if (on) { +		con |= CON_ACTIVE; +		con &= ~CON_TXCH_PAUSE; + +	} else { + +		con |=  CON_TXCH_PAUSE; +		con &= ~CON_ACTIVE; +	} + +	writel(mod, &i2s_reg->mod); +	writel(con, &i2s_reg->con); +} + +/* + * set the bit clock frame size (in multiples of LRCLK) + * + * @param i2s_reg	i2s regiter address + * @param bfs		bit Frame Size + */ +static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs) +{ +	unsigned int mod = readl(&i2s_reg->mod); + +	mod &= ~MOD_BCLK_MASK; + +	switch (bfs) { +	case 48: +		mod |= MOD_BCLK_48FS; +		break; +	case 32: +		mod |= MOD_BCLK_32FS; +		break; +	case 24: +		mod |= MOD_BCLK_24FS; +		break; +	case 16: +		mod |= MOD_BCLK_16FS; +		break; +	default: +		return; +	} +	writel(mod, &i2s_reg->mod); +} + +/* + * flushes the i2stx fifo + * + * @param i2s_reg	i2s regiter address + * @param flush		Tx fifo flush command (0x00 - do not flush + *				0x80 - flush tx fifo) + */ +void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush) +{ +	/* Flush the FIFO */ +	setbits_le32(&i2s_reg->fic, flush); +	clrbits_le32(&i2s_reg->fic, flush); +} + +/* + * Set System Clock direction + * + * @param i2s_reg	i2s regiter address + * @param dir		Clock direction + * + * @return		int value 0 for success, -1 in case of error + */ +int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir) +{ +	unsigned int mod = readl(&i2s_reg->mod); + +	if (dir == SND_SOC_CLOCK_IN) +		mod |= MOD_CDCLKCON; +	else +		mod &= ~MOD_CDCLKCON; + +	writel(mod, &i2s_reg->mod); + +	return 0; +} + +/* + * Sets I2S Clcok format + * + * @param fmt		i2s clock properties + * @param i2s_reg	i2s regiter address + * + * @return		int value 0 for success, -1 in case of error + */ +int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) +{ +	unsigned int mod = readl(&i2s_reg->mod); +	unsigned int tmp = 0; +	unsigned int ret = 0; + +	/* Format is priority */ +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_RIGHT_J: +		tmp |= MOD_LR_RLOW; +		tmp |= MOD_SDF_MSB; +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		tmp |= MOD_LR_RLOW; +		tmp |= MOD_SDF_LSB; +		break; +	case SND_SOC_DAIFMT_I2S: +		tmp |= MOD_SDF_IIS; +		break; +	default: +		debug("%s: Invalid format priority [0x%x]\n", __func__, +			(fmt & SND_SOC_DAIFMT_FORMAT_MASK)); +		return -1; +	} + +	/* +	 * INV flag is relative to the FORMAT flag - if set it simply +	 * flips the polarity specified by the Standard +	 */ +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_NB_IF: +		if (tmp & MOD_LR_RLOW) +			tmp &= ~MOD_LR_RLOW; +		else +			tmp |= MOD_LR_RLOW; +		break; +	default: +		debug("%s: Invalid clock ploarity input [0x%x]\n", __func__, +			(fmt & SND_SOC_DAIFMT_INV_MASK)); +		return -1; +	} + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFS: +		tmp |= MOD_SLAVE; +		break; +	case SND_SOC_DAIFMT_CBM_CFM: +		/* Set default source clock in Master mode */ +		ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT); +		if (ret != 0) { +			debug("%s:set i2s clock direction failed\n", __func__); +			return -1; +		} +		break; +	default: +		debug("%s: Invalid master selection [0x%x]\n", __func__, +			(fmt & SND_SOC_DAIFMT_MASTER_MASK)); +		return -1; +	} + +	mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE); +	mod |= tmp; +	writel(mod, &i2s_reg->mod); + +	return 0; +} + +/* + * Sets the sample width in bits + * + * @param blc		samplewidth (size of sample in bits) + * @param i2s_reg	i2s regiter address + * + * @return		int value 0 for success, -1 in case of error + */ +int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) +{ +	unsigned int mod = readl(&i2s_reg->mod); + +	mod &= ~MOD_BLCP_MASK; +	mod &= ~MOD_BLC_MASK; + +	switch (blc) { +	case 8: +		mod |= MOD_BLCP_8BIT; +		mod |= MOD_BLC_8BIT; +		break; +	case 16: +		mod |= MOD_BLCP_16BIT; +		mod |= MOD_BLC_16BIT; +		break; +	case 24: +		mod |= MOD_BLCP_24BIT; +		mod |= MOD_BLC_24BIT; +		break; +	default: +		debug("%s: Invalid sample size input [0x%x]\n", +			__func__, blc); +		return -1; +	} +	writel(mod, &i2s_reg->mod); + +	return 0; +} + +int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data, +				unsigned long data_size) +{ +	int i; +	int start; +	struct i2s_reg *i2s_reg = +				(struct i2s_reg *)pi2s_tx->base_address; + +	if (data_size < FIFO_LENGTH) { +		debug("%s : Invalid data size\n", __func__); +		return -1; /* invalid pcm data size */ +	} + +	/* fill the tx buffer before stating the tx transmit */ +	for (i = 0; i < FIFO_LENGTH; i++) +		writel(*data++, &i2s_reg->txd); + +	data_size -= FIFO_LENGTH; +	i2s_txctrl(i2s_reg, I2S_TX_ON); + +	while (data_size > 0) { +		start = get_timer(0); +		if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) { +			writel(*data++, &i2s_reg->txd); +			data_size--; +		} else { +			if (get_timer(start) > TIMEOUT_I2S_TX) { +				i2s_txctrl(i2s_reg, I2S_TX_OFF); +				debug("%s: I2S Transfer Timeout\n", __func__); +				return -1; +			} +		} +	} +	i2s_txctrl(i2s_reg, I2S_TX_OFF); + +	return 0; +} + +int i2s_tx_init(struct i2stx_info *pi2s_tx) +{ +	int ret; +	struct i2s_reg *i2s_reg = +				(struct i2s_reg *)pi2s_tx->base_address; + +	/* Initialize GPIO for I2s */ +	exynos_pinmux_config(PERIPH_ID_I2S1, 0); + +	/* Set EPLL Clock */ +	ret = set_epll_clk(pi2s_tx->audio_pll_clk); +	if (ret != 0) { +		debug("%s: epll clock set rate falied\n", __func__); +		return -1; +	} + +	/* Select Clk Source for Audio1 */ +	set_i2s_clk_source(); + +	/* Set Prescaler to get MCLK */ +	set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, +				(pi2s_tx->samplingrate * (pi2s_tx->rfs))); + +	/* Configure I2s format */ +	ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +				SND_SOC_DAIFMT_CBM_CFM)); +	if (ret == 0) { +		i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs); +		ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample); +		if (ret != 0) { +			debug("%s:set sample rate failed\n", __func__); +			return -1; +		} + +		i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs); +		/* disable i2s transfer flag and flush the fifo */ +		i2s_txctrl(i2s_reg, I2S_TX_OFF); +		i2s_fifo(i2s_reg, FIC_TXFLUSH); +	} else { +		debug("%s: failed\n", __func__); +	} + +	return ret; +} diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c new file mode 100644 index 000000000..4c74534c9 --- /dev/null +++ b/drivers/sound/sound.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar <rcsekar@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 <malloc.h> +#include <common.h> +#include <asm/io.h> +#include <i2c.h> +#include <i2s.h> +#include <sound.h> +#include "wm8994.h" +#include <asm/arch/sound.h> + +/* defines */ +#define SOUND_400_HZ 400 +#define SOUND_BITS_IN_BYTE 8 + +static struct i2stx_info g_i2stx_pri; +static struct sound_codec_info g_codec_info; + +/* + * get_sound_fdt_values gets fdt values for i2s parameters + * + * @param i2stx_info	i2s transmitter transfer param structure + * @param blob		FDT blob + */ +static void get_sound_i2s_values(struct i2stx_info *i2s) +{ +	i2s->base_address = samsung_get_base_i2s(); +	i2s->audio_pll_clk = I2S_PLL_CLK; +	i2s->samplingrate = I2S_SAMPLING_RATE; +	i2s->bitspersample = I2S_BITS_PER_SAMPLE; +	i2s->channels = I2S_CHANNELS; +	i2s->rfs = I2S_RFS; +	i2s->bfs = I2S_BFS; +} + +/* + * Gets fdt values for wm8994 config parameters + * + * @param pcodec_info	codec information structure + * @param blob		FDT blob + * @return		int value, 0 for success + */ +static int get_sound_wm8994_values(struct sound_codec_info *pcodec_info) +{ +	int error = 0; + +	switch (AUDIO_COMPAT) { +	case AUDIO_COMPAT_SPI: +		debug("%s: Support not added for SPI interface\n", __func__); +		return -1; +		break; +	case AUDIO_COMPAT_I2C: +		pcodec_info->i2c_bus = AUDIO_I2C_BUS; +		pcodec_info->i2c_dev_addr = AUDIO_I2C_REG; +		debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); +		break; +	default: +		debug("%s: Unknown compat id %d\n", __func__, AUDIO_COMPAT); +		return -1; +	} + +	if (error == -1) { +		debug("fail to get wm8994 codec node properties\n"); +		return -1; +	} + +	return 0; +} + +/* + * Gets fdt values for codec config parameters + * + * @param pcodec_info	codec information structure + * @param blob		FDT blob + * @return		int value, 0 for success + */ +static int get_sound_codec_values(struct sound_codec_info *pcodec_info) +{ +	int error = 0; +	const char *codectype; + +	codectype =  AUDIO_CODEC; + +	if (!strcmp(codectype, "wm8994")) { +		pcodec_info->codec_type = CODEC_WM_8994; +		error = get_sound_wm8994_values(pcodec_info); +	} else { +		error = -1; +	} + +	if (error == -1) { +		debug("fail to get sound codec node properties\n"); +		return -1; +	} + +	return 0; +} + +int sound_init(void) +{ +	int ret; +	struct i2stx_info *pi2s_tx = &g_i2stx_pri; +	struct sound_codec_info *pcodec_info = &g_codec_info; + +	/* Get the I2S Values */ +	get_sound_i2s_values(pi2s_tx); + +	/* Get the codec Values */ +	if (get_sound_codec_values(pcodec_info) < 0) +		return -1; + +	ret = i2s_tx_init(pi2s_tx); +	if (ret) { +		debug("%s: Failed to init i2c transmit: ret=%d\n", __func__, +		      ret); +		return ret; +	} + +	/* Check the codec type and initialise the same */ +	if (pcodec_info->codec_type == CODEC_WM_8994) { +		ret = wm8994_init(pcodec_info, WM8994_AIF2, +			pi2s_tx->samplingrate, +			(pi2s_tx->samplingrate * (pi2s_tx->rfs)), +			pi2s_tx->bitspersample, pi2s_tx->channels); +	} else { +		debug("%s: Unknown code type %d\n", __func__, +		      pcodec_info->codec_type); +		return -1; +	} +	if (ret) { +		debug("%s: Codec init failed\n", __func__); +		return -1; +	} + +	return ret; +} + +/* + * Generates square wave sound data for 1 second + * + * @param data          data buffer pointer + * @param size          size of the buffer + * @param freq          frequency of the wave + */ +static void sound_prepare_buffer(unsigned short *data, int size, uint32_t freq) +{ +	const int sample = 48000; +	const unsigned short amplitude = 16000; /* between 1 and 32767 */ +	const int period = freq ? sample / freq : 0; +	const int half = period / 2; + +	assert(freq); + +	/* Make sure we don't overflow our buffer */ +	if (size % 2) +		size--; + +	while (size) { +		int i; +		for (i = 0; size && i < half; i++) { +			size -= 2; +			*data++ = amplitude; +			*data++ = amplitude; +		} +		for (i = 0; size && i < period - half; i++) { +			size -= 2; +			*data++ = -amplitude; +			*data++ = -amplitude; +		} +	} +} + +int sound_play(uint32_t msec, uint32_t frequency) +{ +	unsigned int *data; +	unsigned long data_size; +	unsigned int ret = 0; + +	/*Buffer length computation */ +	data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels; +	data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE); +	data = malloc(data_size); + +	if (data == NULL) { +		debug("%s: malloc failed\n", __func__); +		return -1; +	} + +	sound_prepare_buffer((unsigned short *)data, +				data_size / sizeof(unsigned short), frequency); + +	while (msec >= 1000) { +		ret = i2s_transfer_tx_data(&g_i2stx_pri, data, +					   (data_size / sizeof(int))); +		msec -= 1000; +	} +	if (msec) { +		unsigned long size = +			(data_size * msec) / (sizeof(int) * 1000); + +		ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size); +	} + +	free(data); + +	return ret; +} diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c new file mode 100644 index 000000000..293903ada --- /dev/null +++ b/drivers/sound/wm8994.c @@ -0,0 +1,792 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar <rcsekar@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 <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <common.h> +#include <div64.h> +#include <i2c.h> +#include <i2s.h> +#include <sound.h> +#include "wm8994.h" +#include "wm8994_registers.h" + +/* defines for wm8994 system clock selection */ +#define SEL_MCLK1	0x00 +#define SEL_MCLK2	0x08 +#define SEL_FLL1	0x10 +#define SEL_FLL2	0x18 + +/* fll config to configure fll */ +struct wm8994_fll_config { +	int src;	/* Source */ +	int in;		/* Input frequency in Hz */ +	int out;	/* output frequency in Hz */ +}; + +/* codec private data */ +struct wm8994_priv { +	enum wm8994_type type;		/* codec type of wolfson */ +	int revision;			/* Revision */ +	int sysclk[WM8994_MAX_AIF];	/* System clock frequency in Hz  */ +	int mclk[WM8994_MAX_AIF];	/* master clock frequency in Hz */ +	int aifclk[WM8994_MAX_AIF];	/* audio interface clock in Hz   */ +	struct wm8994_fll_config fll[2]; /* fll config to configure fll */ +}; + +/* wm 8994 supported sampling rate values */ +static unsigned int src_rate[] = { +			 8000, 11025, 12000, 16000, 22050, 24000, +			 32000, 44100, 48000, 88200, 96000 +}; + +/* op clock divisions */ +static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; + +/* lr clock frame size ratio */ +static int fs_ratios[] = { +	64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 +}; + +/* bit clock divisors */ +static int bclk_divs[] = { +	10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, +	640, 880, 960, 1280, 1760, 1920 +}; + +static struct wm8994_priv g_wm8994_info; +static unsigned char g_wm8994_i2c_dev_addr; + +/* + * Initialise I2C for wm 8994 + * + * @param bus no	i2c bus number in which wm8994 is connected + */ +static void wm8994_i2c_init(int bus_no) +{ +	i2c_set_bus_num(bus_no); +} + +/* + * Writes value to a device register through i2c + * + * @param reg	reg number to be write + * @param data	data to be writen to the above registor + * + * @return	int value 1 for change, 0 for no change or negative error code. + */ +static int wm8994_i2c_write(unsigned int reg, unsigned short data) +{ +	unsigned char val[2]; + +	val[0] = (unsigned char)((data >> 8) & 0xff); +	val[1] = (unsigned char)(data & 0xff); +	debug("Write Addr : 0x%04X, Data :  0x%04X\n", reg, data); + +	return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2); +} + +/* + * Read a value from a device register through i2c + * + * @param reg	reg number to be read + * @param data	address of read data to be stored + * + * @return	int value 0 for success, -1 in case of error. + */ +static unsigned int  wm8994_i2c_read(unsigned int reg , unsigned short *data) +{ +	unsigned char val[2]; +	int ret; + +	ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2); +	if (ret != 0) { +		debug("%s: Error while reading register %#04x\n", +		      __func__, reg); +		return -1; +	} + +	*data = val[0]; +	*data <<= 8; +	*data |= val[1]; + +	return 0; +} + +/* + * update device register bits through i2c + * + * @param reg	codec register + * @param mask	register mask + * @param value	new value + * + * @return int value 1 if change in the register value, + * 0 for no change or negative error code. + */ +static int wm8994_update_bits(unsigned int reg, unsigned short mask, +						unsigned short value) +{ +	int change , ret = 0; +	unsigned short old, new; + +	if (wm8994_i2c_read(reg, &old) != 0) +		return -1; +	new = (old & ~mask) | (value & mask); +	change  = (old != new) ? 1 : 0; +	if (change) +		ret = wm8994_i2c_write(reg, new); +	if (ret < 0) +		return ret; + +	return change; +} + +/* + * Sets i2s set format + * + * @param aif_id	Interface ID + * @param fmt		i2S format + * + * @return -1 for error and 0  Success. + */ +int wm8994_set_fmt(int aif_id, unsigned int fmt) +{ +	int ms_reg; +	int aif_reg; +	int ms = 0; +	int aif = 0; +	int aif_clk = 0; +	int error = 0; + +	switch (aif_id) { +	case 1: +		ms_reg = WM8994_AIF1_MASTER_SLAVE; +		aif_reg = WM8994_AIF1_CONTROL_1; +		aif_clk = WM8994_AIF1_CLOCKING_1; +		break; +	case 2: +		ms_reg = WM8994_AIF2_MASTER_SLAVE; +		aif_reg = WM8994_AIF2_CONTROL_1; +		aif_clk = WM8994_AIF2_CLOCKING_1; +		break; +	default: +		debug("%s: Invalid audio interface selection\n", __func__); +		return -1; +	} + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFS: +		break; +	case SND_SOC_DAIFMT_CBM_CFM: +		ms = WM8994_AIF1_MSTR; +		break; +	default: +		debug("%s: Invalid i2s master selection\n", __func__); +		return -1; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_DSP_B: +		aif |= WM8994_AIF1_LRCLK_INV; +	case SND_SOC_DAIFMT_DSP_A: +		aif |= 0x18; +		break; +	case SND_SOC_DAIFMT_I2S: +		aif |= 0x10; +		break; +	case SND_SOC_DAIFMT_RIGHT_J: +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		aif |= 0x8; +		break; +	default: +		debug("%s: Invalid i2s format selection\n", __func__); +		return -1; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_DSP_A: +	case SND_SOC_DAIFMT_DSP_B: +		/* frame inversion not valid for DSP modes */ +		switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +		case SND_SOC_DAIFMT_NB_NF: +			break; +		case SND_SOC_DAIFMT_IB_NF: +			aif |= WM8994_AIF1_BCLK_INV; +			break; +		default: +			debug("%s: Invalid i2s frame inverse selection\n", +			      __func__); +			return -1; +		} +		break; + +	case SND_SOC_DAIFMT_I2S: +	case SND_SOC_DAIFMT_RIGHT_J: +	case SND_SOC_DAIFMT_LEFT_J: +		switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +		case SND_SOC_DAIFMT_NB_NF: +			break; +		case SND_SOC_DAIFMT_IB_IF: +			aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; +			break; +		case SND_SOC_DAIFMT_IB_NF: +			aif |= WM8994_AIF1_BCLK_INV; +			break; +		case SND_SOC_DAIFMT_NB_IF: +			aif |= WM8994_AIF1_LRCLK_INV; +			break; +		default: +			debug("%s: Invalid i2s clock polarity selection\n", +			      __func__); +			return -1; +		} +		break; +	default: +		debug("%s: Invalid i2s format selection\n", __func__); +		return -1; +	} + +	error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV | +			WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif); + +	error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms); +	error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK, +						WM8994_AIF1CLK_ENA); +	if (error < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/* + * Sets hw params FOR WM8994 + * + * @param wm8994		wm8994 information pointer + * @param aif_id		Audio interface ID + * @param sampling_rate		Sampling rate + * @param bits_per_sample	Bits per sample + * @param Channels		Channels in the given audio input + * + * @return -1 for error  and 0  Success. + */ +static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id, +		unsigned int sampling_rate, unsigned int bits_per_sample, +		unsigned int channels) +{ +	int aif1_reg; +	int aif2_reg; +	int bclk_reg; +	int bclk = 0; +	int rate_reg; +	int aif1 = 0; +	int aif2 = 0; +	int rate_val = 0; +	int id = aif_id - 1; +	int i, cur_val, best_val, bclk_rate, best; +	unsigned short reg_data; +	int ret = 0; + +	switch (aif_id) { +	case 1: +		aif1_reg = WM8994_AIF1_CONTROL_1; +		aif2_reg = WM8994_AIF1_CONTROL_2; +		bclk_reg = WM8994_AIF1_BCLK; +		rate_reg = WM8994_AIF1_RATE; +		break; +	case 2: +		aif1_reg = WM8994_AIF2_CONTROL_1; +		aif2_reg = WM8994_AIF2_CONTROL_2; +		bclk_reg = WM8994_AIF2_BCLK; +		rate_reg = WM8994_AIF2_RATE; +		break; +	default: +		return -1; +	} + +	bclk_rate = sampling_rate * 32; +	switch (bits_per_sample) { +	case 16: +		bclk_rate *= 16; +		break; +	case 20: +		bclk_rate *= 20; +		aif1 |= 0x20; +		break; +	case 24: +		bclk_rate *= 24; +		aif1 |= 0x40; +		break; +	case 32: +		bclk_rate *= 32; +		aif1 |= 0x60; +		break; +	default: +		return -1; +	} + +	/* Try to find an appropriate sample rate; look for an exact match. */ +	for (i = 0; i < ARRAY_SIZE(src_rate); i++) +		if (src_rate[i] == sampling_rate) +			break; + +	if (i == ARRAY_SIZE(src_rate)) { +		debug("%s: Could not get the best matching samplingrate\n", +		      __func__); +		return -1; +	} + +	rate_val |= i << WM8994_AIF1_SR_SHIFT; + +	/* AIFCLK/fs ratio; look for a close match in either direction */ +	best = 0; +	best_val = abs((fs_ratios[0] * sampling_rate) +						- wm8994->aifclk[id]); + +	for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { +		cur_val = abs((fs_ratios[i] * sampling_rate) +					- wm8994->aifclk[id]); +		if (cur_val >= best_val) +			continue; +		best = i; +		best_val = cur_val; +	} + +	rate_val |= best; + +	/* +	 * We may not get quite the right frequency if using +	 * approximate clocks so look for the closest match that is +	 * higher than the target (we need to ensure that there enough +	 * BCLKs to clock out the samples). +	 */ +	best = 0; +	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { +		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; +		if (cur_val < 0) /* BCLK table is sorted */ +			break; +		best = i; +	} + +	if (i ==  ARRAY_SIZE(bclk_divs)) { +		debug("%s: Could not get the best matching bclk division\n", +		      __func__); +		return -1; +	} + +	bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best]; +	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; + +	if (wm8994_i2c_read(aif1_reg, ®_data) != 0) { +		debug("%s: AIF1 register read Failed\n", __func__); +		return -1; +	} + +	if ((channels == 1) && ((reg_data & 0x18) == 0x18)) +		aif2 |= WM8994_AIF1_MONO; + +	if (wm8994->aifclk[id] == 0) { +		debug("%s:Audio interface clock not set\n", __func__); +		return -1; +	} + +	ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1); +	ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2); +	ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk); +	ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK | +				WM8994_AIF1CLK_RATE_MASK, rate_val); + +	debug("rate vale = %x , bclk val= %x\n", rate_val, bclk); + +	if (ret < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/* + * Configures Audio interface Clock + * + * @param wm8994	wm8994 information pointer + * @param aif		Audio Interface ID + * + * @return -1 for error  and 0  Success. + */ +static int configure_aif_clock(struct wm8994_priv *wm8994, int aif) +{ +	int rate; +	int reg1 = 0; +	int offset; +	int ret; + +	/* AIF(1/0) register adress offset calculated */ +	if (aif) +		offset = 4; +	else +		offset = 0; + +	switch (wm8994->sysclk[aif]) { +	case WM8994_SYSCLK_MCLK1: +		reg1 |= SEL_MCLK1; +		rate = wm8994->mclk[0]; +		break; + +	case WM8994_SYSCLK_MCLK2: +		reg1 |= SEL_MCLK2; +		rate = wm8994->mclk[1]; +		break; + +	case WM8994_SYSCLK_FLL1: +		reg1 |= SEL_FLL1; +		rate = wm8994->fll[0].out; +		break; + +	case WM8994_SYSCLK_FLL2: +		reg1 |= SEL_FLL2; +		rate = wm8994->fll[1].out; +		break; + +	default: +		debug("%s: Invalid input clock selection [%d]\n", +		      __func__, wm8994->sysclk[aif]); +		return -1; +	} + +	/* if input clock frequenct is more than 135Mhz then divide */ +	if (rate >= WM8994_MAX_INPUT_CLK_FREQ) { +		rate /= 2; +		reg1 |= WM8994_AIF1CLK_DIV; +	} + +	wm8994->aifclk[aif] = rate; + +	ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset, +				WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV, +				reg1); + +	ret |= wm8994_update_bits(WM8994_CLOCKING_1, +			WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK | +			WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC | +			WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); + +	if (ret < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/* + * Configures Audio interface  for the given frequency + * + * @param wm8994	wm8994 information + * @param aif_id	Audio Interface + * @param clk_id	Input Clock ID + * @param freq		Sampling frequency in Hz + * + * @return -1 for error and 0 success. + */ +static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id, +				int clk_id, unsigned int freq) +{ +	int i; +	int ret = 0; + +	wm8994->sysclk[aif_id - 1] = clk_id; + +	switch (clk_id) { +	case WM8994_SYSCLK_MCLK1: +		wm8994->mclk[0] = freq; +		if (aif_id == 2) { +			ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 , +			WM8994_AIF2DAC_DIV_MASK , 0); +		} +		break; + +	case WM8994_SYSCLK_MCLK2: +		/* TODO: Set GPIO AF */ +		wm8994->mclk[1] = freq; +		break; + +	case WM8994_SYSCLK_FLL1: +	case WM8994_SYSCLK_FLL2: +		break; + +	case WM8994_SYSCLK_OPCLK: +		/* +		 * Special case - a division (times 10) is given and +		 * no effect on main clocking. +		 */ +		if (freq) { +			for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) +				if (opclk_divs[i] == freq) +					break; +			if (i == ARRAY_SIZE(opclk_divs)) { +				debug("%s frequency divisor not found\n", +					__func__); +				return -1; +			} +			ret = wm8994_update_bits(WM8994_CLOCKING_2, +					    WM8994_OPCLK_DIV_MASK, i); +			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2, +					    WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); +		} else { +			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2, +					    WM8994_OPCLK_ENA, 0); +		} + +	default: +		debug("%s Invalid input clock selection [%d]\n", +		      __func__, clk_id); +		return -1; +	} + +	ret |= configure_aif_clock(wm8994, aif_id - 1); + +	if (ret < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/* + * Initializes Volume for AIF2 to HP path + * + * @returns -1 for error  and 0 Success. + * + */ +static int wm8994_init_volume_aif2_dac1(void) +{ +	int ret; + +	/* Unmute AIF2DAC */ +	ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1, +			WM8994_AIF2DAC_MUTE_MASK, 0); + + +	ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME, +			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK, +			WM8994_AIF2DAC_VU | 0xff); + +	ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME, +			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK, +			WM8994_AIF2DAC_VU | 0xff); + + +	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME, +			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | +			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); + +	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME, +			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | +			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); +	/* Head Phone Volume */ +	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D); +	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); + +	if (ret < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/* + * Intialise wm8994 codec device + * + * @param wm8994	wm8994 information + * + * @returns -1 for error  and 0 Success. + */ +static int wm8994_device_init(struct wm8994_priv *wm8994) +{ +	const char *devname; +	unsigned short reg_data; +	int ret; + +	wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */ + +	ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, ®_data); +	if (ret < 0) { +		debug("Failed to read ID register\n"); +		goto err; +	} + +	if (reg_data == WM8994_ID) { +		devname = "WM8994"; +		debug("Device registered as type %d\n", wm8994->type); +		wm8994->type = WM8994; +	} else { +		debug("Device is not a WM8994, ID is %x\n", ret); +		ret = -1; +		goto err; +	} + +	ret = wm8994_i2c_read(WM8994_CHIP_REVISION, ®_data); +	if (ret < 0) { +		debug("Failed to read revision register: %d\n", ret); +		goto err; +	} +	wm8994->revision = reg_data; +	debug("%s revision %c\n", devname, 'A' + wm8994->revision); + +	/* VMID Selection */ +	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1, +			WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3); + +	/* Charge Pump Enable */ +	ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK, +					WM8994_CP_ENA); + +	/* Head Phone Power Enable */ +	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1, +			WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA); + +	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1, +				WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA); + +	/* Power enable for AIF2 and DAC1 */ +	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5, +		WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | +		WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK, +		WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | WM8994_DAC1L_ENA | +		WM8994_DAC1R_ENA); + +	/* Head Phone Initialisation */ +	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1, +		WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK, +		WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); + +	ret |= wm8994_update_bits(WM8994_DC_SERVO_1, +			WM8994_DCS_ENA_CHAN_0_MASK | +			WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 | +			WM8994_DCS_ENA_CHAN_1); + +	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1, +			WM8994_HPOUT1L_DLY_MASK | +			WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | +			WM8994_HPOUT1R_OUTP_MASK | +			WM8994_HPOUT1L_RMV_SHORT_MASK | +			WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY | +			WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP | +			WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT | +			WM8994_HPOUT1R_RMV_SHORT); + +	/* MIXER Config DAC1 to HP */ +	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1, +			WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L); + +	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2, +			WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R); + +	/* Routing AIF2 to DAC1 */ +	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING, +			WM8994_AIF2DACL_TO_DAC1L_MASK, +			WM8994_AIF2DACL_TO_DAC1L); + +	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING, +			WM8994_AIF2DACR_TO_DAC1R_MASK, +			WM8994_AIF2DACR_TO_DAC1R); + +	 /* GPIO Settings for AIF2 */ +	 /* B CLK */ +	ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK | +				WM8994_GPIO_FUNCTION_MASK , +				WM8994_GPIO_DIR_OUTPUT | +				WM8994_GPIO_FUNCTION_I2S_CLK); + +	/* LR CLK */ +	ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK | +				WM8994_GPIO_FUNCTION_MASK, +				WM8994_GPIO_DIR_OUTPUT | +				WM8994_GPIO_FUNCTION_I2S_CLK); + +	/* DATA */ +	ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK | +				WM8994_GPIO_FUNCTION_MASK, +				WM8994_GPIO_DIR_OUTPUT | +				WM8994_GPIO_FUNCTION_I2S_CLK); + +	ret |= wm8994_init_volume_aif2_dac1(); +	if (ret < 0) +		goto err; + +	debug("%s: Codec chip init ok\n", __func__); +	return 0; +err: +	debug("%s: Codec chip init error\n", __func__); +	return -1; +} + +/*wm8994 Device Initialisation */ +int wm8994_init(struct sound_codec_info *pcodec_info, +			enum en_audio_interface aif_id, +			int sampling_rate, int mclk_freq, +			int bits_per_sample, unsigned int channels) +{ +	int ret = 0; + +	/* shift the device address by 1 for 7 bit addressing */ +	g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr; +	wm8994_i2c_init(pcodec_info->i2c_bus); + +	if (pcodec_info->codec_type == CODEC_WM_8994) +		g_wm8994_info.type = WM8994; +	else { +		debug("%s: Codec id [%d] not defined\n", __func__, +				pcodec_info->codec_type); +		return -1; +	} + +	ret = wm8994_device_init(&g_wm8994_info); +	if (ret < 0) { +		debug("%s: wm8994 codec chip init failed\n", __func__); +		return ret; +	} + +	ret =  wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1, +							mclk_freq); +	if (ret < 0) { +		debug("%s: wm8994 codec set sys clock failed\n", __func__); +		return ret; +	} + +	ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate, +						bits_per_sample, channels); + +	if (ret == 0) { +		ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S | +						SND_SOC_DAIFMT_NB_NF | +						SND_SOC_DAIFMT_CBS_CFS); +	} +	return ret; +} diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h new file mode 100644 index 000000000..a8f0de18c --- /dev/null +++ b/drivers/sound/wm8994.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chadrasekar <rcsekar@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 + */ + +#ifndef __WM8994_H__ +#define __WM8994_H__ + +/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ +#define WM8994_SYSCLK_MCLK1	1 +#define WM8994_SYSCLK_MCLK2	2 +#define WM8994_SYSCLK_FLL1	3 +#define WM8994_SYSCLK_FLL2	4 + +/*  Avilable audi interface ports in wm8994 codec */ +enum en_audio_interface { +	 WM8994_AIF1 = 1, +	 WM8994_AIF2, +	 WM8994_AIF3 +}; + +/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ +#define WM8994_SYSCLK_OPCLK	5 + +#define WM8994_FLL1	1 +#define WM8994_FLL2	2 + +#define WM8994_FLL_SRC_MCLK1	1 +#define WM8994_FLL_SRC_MCLK2	2 +#define WM8994_FLL_SRC_LRCLK	3 +#define WM8994_FLL_SRC_BCLK	4 + +/* maximum available digital interfac in the dac to configure */ +#define WM8994_MAX_AIF			2 + +#define WM8994_MAX_INPUT_CLK_FREQ	13500000 +#define WM8994_ID			0x8994 + +enum wm8994_vmid_mode { +	WM8994_VMID_NORMAL, +	WM8994_VMID_FORCE, +}; + +/* wm 8994 family devices */ +enum wm8994_type { +	WM8994 = 0, +	WM8958 = 1, +	WM1811 = 2, +}; + +/* + * intialise wm8994 sound codec device for the given configuration + * + * @param pcodec_info		pointer value of the sound codec info structure + *				parsed from device tree + * @param aif_id		enum value of codec interface port in which + *				soc i2s is connected + * @param sampling_rate		Sampling rate ranges between from 8khz to 96khz + * @param mclk_freq		Master clock frequency. + * @param bits_per_sample	bits per Sample can be 16 or 24 + * @param channels		Number of channnels, maximum 2 + * + * @returns -1 for error  and 0  Success. + */ +int wm8994_init(struct sound_codec_info *pcodec_info, +			enum en_audio_interface aif_id, +			int sampling_rate, int mclk_freq, +			int bits_per_sample, unsigned int channels); +#endif /*__WM8994_H__ */ diff --git a/drivers/sound/wm8994_registers.h b/drivers/sound/wm8994_registers.h new file mode 100644 index 000000000..f455b112f --- /dev/null +++ b/drivers/sound/wm8994_registers.h @@ -0,0 +1,299 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * + *  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 __WM8994_REGISTERS_H__ +#define __WM8994_REGISTERS_H__ + +/* + * Register values. + */ +#define WM8994_SOFTWARE_RESET                   0x00 +#define WM8994_POWER_MANAGEMENT_1               0x01 +#define WM8994_POWER_MANAGEMENT_2               0x02 +#define WM8994_POWER_MANAGEMENT_5               0x05 +#define WM8994_LEFT_OUTPUT_VOLUME               0x1C +#define WM8994_RIGHT_OUTPUT_VOLUME              0x1D +#define WM8994_OUTPUT_MIXER_1                   0x2D +#define WM8994_OUTPUT_MIXER_2                   0x2E +#define WM8994_CHARGE_PUMP_1                    0x4C +#define WM8994_DC_SERVO_1                       0x54 +#define WM8994_ANALOGUE_HP_1                    0x60 +#define WM8994_CHIP_REVISION                    0x100 +#define WM8994_AIF1_CLOCKING_1                  0x200 +#define WM8994_AIF1_CLOCKING_2                  0x201 +#define WM8994_AIF2_CLOCKING_1                  0x204 +#define WM8994_CLOCKING_1                       0x208 +#define WM8994_CLOCKING_2                       0x209 +#define WM8994_AIF1_RATE                        0x210 +#define WM8994_AIF2_RATE                        0x211 +#define WM8994_RATE_STATUS                      0x212 +#define WM8994_AIF1_CONTROL_1                   0x300 +#define WM8994_AIF1_CONTROL_2                   0x301 +#define WM8994_AIF1_MASTER_SLAVE                0x302 +#define WM8994_AIF1_BCLK                        0x303 +#define WM8994_AIF2_CONTROL_1                   0x310 +#define WM8994_AIF2_CONTROL_2                   0x311 +#define WM8994_AIF2_MASTER_SLAVE                0x312 +#define WM8994_AIF2_BCLK                        0x313 +#define WM8994_AIF2_DAC_LEFT_VOLUME             0x502 +#define WM8994_AIF2_DAC_RIGHT_VOLUME            0x503 +#define WM8994_AIF2_DAC_FILTERS_1               0x520 +#define WM8994_DAC1_LEFT_MIXER_ROUTING          0x601 +#define WM8994_DAC1_RIGHT_MIXER_ROUTING         0x602 +#define WM8994_DAC1_LEFT_VOLUME                 0x610 +#define WM8994_DAC1_RIGHT_VOLUME                0x611 +#define WM8994_GPIO_3                           0x702 +#define WM8994_GPIO_4                           0x703 +#define WM8994_GPIO_5                           0x704 + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +/* SW_RESET */ +#define WM8994_SW_RESET                              1 +/* + * R1 (0x01) - Power Management (1) + */ +/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA                      0x0200 +/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_MASK                 0x0200 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA                      0x0100 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_MASK                 0x0100 +/* VMID_SEL - [2:1] */ +#define WM8994_VMID_SEL_MASK                    0x0006 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA                         0x0001 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA_MASK                    0x0001 + +/* + * R2 (0x02) - Power Management (2) + */ +/* OPCLK_ENA */ +#define WM8994_OPCLK_ENA                        0x0800 + +/* + * R5 (0x05) - Power Management (5) + */ +/* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA                     0x2000 +#define WM8994_AIF2DACL_ENA_MASK                0x2000 +/* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA                     0x1000 +#define WM8994_AIF2DACR_ENA_MASK                0x1000 +/* DAC1L_ENA */ +#define WM8994_DAC1L_ENA                        0x0002 +#define WM8994_DAC1L_ENA_MASK                   0x0002 +/* DAC1R_ENA */ +#define WM8994_DAC1R_ENA                        0x0001 +#define WM8994_DAC1R_ENA_MASK                   0x0001 + +/* + * R45 (0x2D) - Output Mixer (1) + */ +/* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L                 0x0100 +#define WM8994_DAC1L_TO_HPOUT1L_MASK            0x0100 + +/* + * R46 (0x2E) - Output Mixer (2) + */ +/* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R                 0x0100 +#define WM8994_DAC1R_TO_HPOUT1R_MASK            0x0100 + +/* + * R76 (0x4C) - Charge Pump (1) + */ +/* CP_ENA */ +#define WM8994_CP_ENA                           0x8000 +#define WM8994_CP_ENA_MASK                      0x8000 +/* + * R84 (0x54) - DC Servo (1) + */ +/* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1                   0x0002 +#define WM8994_DCS_ENA_CHAN_1_MASK              0x0002 +/* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0                   0x0001 +#define WM8994_DCS_ENA_CHAN_0_MASK              0x0001 + +/* + * R96 (0x60) - Analogue HP (1) + */ +/* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT                0x0080 +#define WM8994_HPOUT1L_RMV_SHORT_MASK           0x0080 +/* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP                     0x0040 +#define WM8994_HPOUT1L_OUTP_MASK                0x0040 +/* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY                      0x0020 +#define WM8994_HPOUT1L_DLY_MASK                 0x0020 +/* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT                0x0008 +#define WM8994_HPOUT1R_RMV_SHORT_MASK           0x0008 +/* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP                     0x0004 +#define WM8994_HPOUT1R_OUTP_MASK                0x0004 +/* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY                      0x0002 +#define WM8994_HPOUT1R_DLY_MASK                 0x0002 + +/* + * R512 (0x200) - AIF1 Clocking (1) + */ +/* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_SRC_MASK                 0x0018 +/* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV                      0x0002 +/* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA                      0x0001 +#define WM8994_AIF1CLK_ENA_MASK                 0x0001 + +/* + * R517 (0x205) - AIF2 Clocking (2) + */ +/* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2DAC_DIV_MASK                 0x0038 + +/* + * R520 (0x208) - Clocking (1) + */ +/* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA                   0x0004 +#define WM8994_AIF2DSPCLK_ENA_MASK              0x0004 +/* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA                    0x0002 +#define WM8994_SYSDSPCLK_ENA_MASK               0x0002 +/* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC                       0x0001 + +/* + * R521 (0x209) - Clocking (2) + */ +/* OPCLK_DIV - [2:0] */ +#define WM8994_OPCLK_DIV_MASK                   0x0007 + +/* + * R528 (0x210) - AIF1 Rate + */ +/* AIF1_SR - [7:4] */ +#define WM8994_AIF1_SR_MASK                     0x00F0 +#define WM8994_AIF1_SR_SHIFT                         4 +/* AIF1CLK_RATE - [3:0] */ +#define WM8994_AIF1CLK_RATE_MASK                0x000F + +/* + * R768 (0x300) - AIF1 Control (1) + */ +/* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV                    0x0100 +/* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV                   0x0080 +#define WM8994_AIF1_LRCLK_INV_MASK              0x0080 +/* AIF1_WL - [6:5] */ +#define WM8994_AIF1_WL_MASK                     0x0060 +/* AIF1_FMT - [4:3] */ +#define WM8994_AIF1_FMT_MASK                    0x0018 + +/* + * R769 (0x301) - AIF1 Control (2) + */ +/* AIF1_MONO */ +#define WM8994_AIF1_MONO                        0x0100 + +/* + * R770 (0x302) - AIF1 Master/Slave + */ +/* AIF1_MSTR */ +#define WM8994_AIF1_MSTR                        0x4000 +#define WM8994_AIF1_MSTR_MASK                   0x4000 + +/* + * R771 (0x303) - AIF1 BCLK + */ +/* AIF1_BCLK_DIV - [8:4] */ +#define WM8994_AIF1_BCLK_DIV_MASK               0x01F0 +#define WM8994_AIF1_BCLK_DIV_SHIFT                   4 + +/* + * R1282 (0x502) - AIF2 DAC Left Volume + */ +/* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU                       0x0100 +#define WM8994_AIF2DAC_VU_MASK                  0x0100 +/* AIF2DACL_VOL - [7:0] */ +#define WM8994_AIF2DACL_VOL_MASK                0x00FF + +/* + * R1283 (0x503) - AIF2 DAC Right Volume + */ +/* AIF2DACR_VOL - [7:0] */ +#define WM8994_AIF2DACR_VOL_MASK                0x00FF + +/* + * R1312 (0x520) - AIF2 DAC Filters (1) + */ +/* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_MASK                0x0200 + +/* + * R1537 (0x601) - DAC1 Left Mixer Routing + */ +/* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L                0x0004 +#define WM8994_AIF2DACL_TO_DAC1L_MASK           0x0004 + +/* + * R1538 (0x602) - DAC1 Right Mixer Routing + */ +/* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R                0x0004 +#define WM8994_AIF2DACR_TO_DAC1R_MASK           0x0004 + +/* + * R1552 (0x610) - DAC1 Left Volume + */ +/* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_MASK                  0x0200 +/* DAC1_VU */ +#define WM8994_DAC1_VU                          0x0100 +#define WM8994_DAC1_VU_MASK                     0x0100 +/* DAC1L_VOL - [7:0] */ +#define WM8994_DAC1L_VOL_MASK                   0x00FF + +/* + * R1553 (0x611) - DAC1 Right Volume + */ +/* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_MASK                  0x0200 +/* DAC1R_VOL - [7:0] */ +#define WM8994_DAC1R_VOL_MASK                   0x00FF + +/* + *  GPIO + */ +/* OUTPUT PIN */ +#define WM8994_GPIO_DIR_OUTPUT                   0x8000 +/* GPIO PIN MASK */ +#define WM8994_GPIO_DIR_MASK                     0xFFE0 +/* I2S CLK */ +#define WM8994_GPIO_FUNCTION_I2S_CLK             0x0000 +/* GPn FN */ +#define WM8994_GPIO_FUNCTION_MASK                0x001F +#endif diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f0b82c67f..824d357d9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -34,6 +34,7 @@ COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o  COBJS-$(CONFIG_CF_SPI) += cf_spi.o  COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o  COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o +COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o  COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o  COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o  COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c new file mode 100644 index 000000000..3e6c18f87 --- /dev/null +++ b/drivers/spi/exynos_spi.c @@ -0,0 +1,367 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna <padma.v@samsung.com> + * + * 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.h> +#include <asm/arch/clk.h> +#include <asm/arch/clock.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/pinmux.h> +#include <asm/arch-exynos/spi.h> +#include <asm/io.h> + +/* Information about each SPI controller */ +struct spi_bus { +	enum periph_id periph_id; +	s32 frequency;		/* Default clock frequency, -1 for none */ +	struct exynos_spi *regs; +	int inited;		/* 1 if this bus is ready for use */ +}; + +/* A list of spi buses that we know about */ +static struct spi_bus spi_bus[EXYNOS5_SPI_NUM_CONTROLLERS]; + +struct exynos_spi_slave { +	struct spi_slave slave; +	struct exynos_spi *regs; +	unsigned int freq;		/* Default frequency */ +	unsigned int mode; +	enum periph_id periph_id;	/* Peripheral ID for this device */ +	unsigned int fifo_size; +}; + +static struct spi_bus *spi_get_bus(unsigned dev_index) +{ +	if (dev_index < EXYNOS5_SPI_NUM_CONTROLLERS) +		return &spi_bus[dev_index]; +	debug("%s: invalid bus %d", __func__, dev_index); + +	return NULL; +} + +static inline struct exynos_spi_slave *to_exynos_spi(struct spi_slave *slave) +{ +	return container_of(slave, struct exynos_spi_slave, slave); +} + +/** + * Setup the driver private data + * + * @param bus		ID of the bus that the slave is attached to + * @param cs		ID of the chip select connected to the slave + * @param max_hz	Required spi frequency + * @param mode		Required spi mode (clk polarity, clk phase and + *			master or slave) + * @return new device or NULL + */ +struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, +			unsigned int max_hz, unsigned int mode) +{ +	struct exynos_spi_slave *spi_slave; +	struct spi_bus *bus; + +	if (!spi_cs_is_valid(busnum, cs)) { +		debug("%s: Invalid bus/chip select %d, %d\n", __func__, +		      busnum, cs); +		return NULL; +	} + +	spi_slave = malloc(sizeof(*spi_slave)); +	if (!spi_slave) { +		debug("%s: Could not allocate spi_slave\n", __func__); +		return NULL; +	} + +	bus = &spi_bus[busnum]; +	spi_slave->slave.bus = busnum; +	spi_slave->slave.cs = cs; +	spi_slave->regs = bus->regs; +	spi_slave->mode = mode; +	spi_slave->periph_id = bus->periph_id; +	if (bus->periph_id == PERIPH_ID_SPI1 || +	    bus->periph_id == PERIPH_ID_SPI2) +		spi_slave->fifo_size = 64; +	else +		spi_slave->fifo_size = 256; + +	spi_slave->freq = bus->frequency; +	if (max_hz) +		spi_slave->freq = min(max_hz, spi_slave->freq); + +	return &spi_slave->slave; +} + +/** + * Free spi controller + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + */ +void spi_free_slave(struct spi_slave *slave) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + +	free(spi_slave); +} + +/** + * Flush spi tx, rx fifos and reset the SPI controller + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + */ +static void spi_flush_fifo(struct spi_slave *slave) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); +	struct exynos_spi *regs = spi_slave->regs; + +	clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); +	clrbits_le32(®s->ch_cfg, SPI_CH_RST); +	setbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); +} + +/** + * Initialize the spi base registers, set the required clock frequency and + * initialize the gpios + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + * @return zero on success else a negative value + */ +int spi_claim_bus(struct spi_slave *slave) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); +	struct exynos_spi *regs = spi_slave->regs; +	u32 reg = 0; +	int ret; + +	ret = set_spi_clk(spi_slave->periph_id, +					spi_slave->freq); +	if (ret < 0) { +		debug("%s: Failed to setup spi clock\n", __func__); +		return ret; +	} + +	exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE); + +	spi_flush_fifo(slave); + +	reg = readl(®s->ch_cfg); +	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L); + +	if (spi_slave->mode & SPI_CPHA) +		reg |= SPI_CH_CPHA_B; + +	if (spi_slave->mode & SPI_CPOL) +		reg |= SPI_CH_CPOL_L; + +	writel(reg, ®s->ch_cfg); +	writel(SPI_FB_DELAY_180, ®s->fb_clk); + +	return 0; +} + +/** + * Reset the spi H/W and flush the tx and rx fifos + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + */ +void spi_release_bus(struct spi_slave *slave) +{ +	spi_flush_fifo(slave); +} + +static void spi_get_fifo_levels(struct exynos_spi *regs, +	int *rx_lvl, int *tx_lvl) +{ +	uint32_t spi_sts = readl(®s->spi_sts); + +	*rx_lvl = (spi_sts >> SPI_RX_LVL_OFFSET) & SPI_FIFO_LVL_MASK; +	*tx_lvl = (spi_sts >> SPI_TX_LVL_OFFSET) & SPI_FIFO_LVL_MASK; +} + +/** + * If there's something to transfer, do a software reset and set a + * transaction size. + * + * @param regs	SPI peripheral registers + * @param count	Number of bytes to transfer + */ +static void spi_request_bytes(struct exynos_spi *regs, int count) +{ +	assert(count && count < (1 << 16)); +	setbits_le32(®s->ch_cfg, SPI_CH_RST); +	clrbits_le32(®s->ch_cfg, SPI_CH_RST); +	writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt); +} + +static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, +			void **dinp, void const **doutp) +{ +	struct exynos_spi *regs = spi_slave->regs; +	uchar *rxp = *dinp; +	const uchar *txp = *doutp; +	int rx_lvl, tx_lvl; +	uint out_bytes, in_bytes; + +	out_bytes = in_bytes = todo; + +	/* +	 * If there's something to send, do a software reset and set a +	 * transaction size. +	 */ +	spi_request_bytes(regs, todo); + +	/* +	 * Bytes are transmitted/received in pairs. Wait to receive all the +	 * data because then transmission will be done as well. +	 */ +	while (in_bytes) { +		int temp; + +		/* Keep the fifos full/empty. */ +		spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl); +		if (tx_lvl < spi_slave->fifo_size && out_bytes) { +			temp = txp ? *txp++ : 0xff; +			writel(temp, ®s->tx_data); +			out_bytes--; +		} +		if (rx_lvl > 0 && in_bytes) { +			temp = readl(®s->rx_data); +			if (rxp) +				*rxp++ = temp; +			in_bytes--; +		} +	} +	*dinp = rxp; +	*doutp = txp; +} + +/** + * Transfer and receive data + * + * @param slave		Pointer to spi_slave to which controller has to + *			communicate with + * @param bitlen	No of bits to tranfer or receive + * @param dout		Pointer to transfer buffer + * @param din		Pointer to receive buffer + * @param flags		Flags for transfer begin and end + * @return zero on success else a negative value + */ +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +	     void *din, unsigned long flags) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); +	int upto, todo; +	int bytelen; + +	/* spi core configured to do 8 bit transfers */ +	if (bitlen % 8) { +		debug("Non byte aligned SPI transfer.\n"); +		return -1; +	} + +	/* Start the transaction, if necessary. */ +	if ((flags & SPI_XFER_BEGIN)) +		spi_cs_activate(slave); + +	/* Exynos SPI limits each transfer to 65535 bytes */ +	bytelen =  bitlen / 8; +	for (upto = 0; upto < bytelen; upto += todo) { +		todo = min(bytelen - upto, (1 << 16) - 1); +		spi_rx_tx(spi_slave, todo, &din, &dout); +	} + +	/* Stop the transaction, if necessary. */ +	if ((flags & SPI_XFER_END)) +		spi_cs_deactivate(slave); + +	return 0; +} + +/** + * Validates the bus and chip select numbers + * + * @param bus	ID of the bus that the slave is attached to + * @param cs	ID of the chip select connected to the slave + * @return one on success else zero + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +	return spi_get_bus(bus) && cs == 0; +} + +/** + * Activate the CS by driving it LOW + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + */ +void spi_cs_activate(struct spi_slave *slave) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + +	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); +	debug("Activate CS, bus %d\n", spi_slave->slave.bus); +} + +/** + * Deactivate the CS by driving it HIGH + * + * @param slave	Pointer to spi_slave to which controller has to + *		communicate with + */ +void spi_cs_deactivate(struct spi_slave *slave) +{ +	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + +	setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); +	debug("Deactivate CS, bus %d\n", spi_slave->slave.bus); +} + +static inline struct exynos_spi *get_spi_base(int dev_index) +{ +	if (dev_index < 3) +		return (struct exynos_spi *)samsung_get_base_spi() + dev_index; +	else +		return (struct exynos_spi *)samsung_get_base_spi_isp() + +					(dev_index - 3); +} + +/* Sadly there is no error return from this function */ +void spi_init(void) +{ +	int i; +	struct spi_bus *bus; + +	for (i = 0; i < EXYNOS5_SPI_NUM_CONTROLLERS; i++) { +		bus = &spi_bus[i]; +		bus->regs = get_spi_base(i); +		bus->periph_id = PERIPH_ID_SPI0 + i; + +		/* Although Exynos5 supports upto 50Mhz speed, +		 * we are setting it to 10Mhz for safe side +		 */ +		bus->frequency = 10000000; +		bus->inited = 1; +	} +} diff --git a/drivers/video/Makefile b/drivers/video/Makefile index cc3022a2c..170a358b5 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -37,6 +37,7 @@ COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o  COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o  COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o  COBJS-$(CONFIG_S6E63D6) += s6e63d6.o +COBJS-$(CONFIG_LD9040) += ld9040.o  COBJS-$(CONFIG_SED156X) += sed156x.o  COBJS-$(CONFIG_VIDEO_AMBA) += amba.o  COBJS-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o @@ -50,6 +51,7 @@ COBJS-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o  COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o  COBJS-$(CONFIG_VIDEO_SM501) += sm501.o  COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o +COBJS-$(CONFIG_VIDEO_TEGRA) += tegra.o  COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o  COBJS	:= $(sort $(COBJS-y)) diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c index e31a0fd50..d9a3f9ab1 100644 --- a/drivers/video/exynos_fb.c +++ b/drivers/video/exynos_fb.c @@ -70,8 +70,19 @@ static void draw_logo(void)  	int x, y;  	ulong addr; -	x = ((panel_width - panel_info.logo_width) >> 1); -	y = ((panel_height - panel_info.logo_height) >> 1) - 4; +	if (panel_width >= panel_info.logo_width) { +		x = ((panel_width - panel_info.logo_width) >> 1); +	} else { +		x = 0; +		printf("Warning: image width is bigger than display width\n"); +	} + +	if (panel_height >= panel_info.logo_height) { +		y = ((panel_height - panel_info.logo_height) >> 1) - 4; +	} else { +		y = 0; +		printf("Warning: image height is bigger than display height\n"); +	}  	addr = panel_info.logo_addr;  	bmp_display(addr, x, y); diff --git a/drivers/video/ld9040.c b/drivers/video/ld9040.c new file mode 100644 index 000000000..c01ae12bb --- /dev/null +++ b/drivers/video/ld9040.c @@ -0,0 +1,144 @@ +/* + * ld9040 AMOLED LCD panel driver. + * + * Copyright (C) 2012 Samsung Electronics + * Donghwa Lee <dh09.lee@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 <spi.h> + +static const unsigned char SEQ_SWRESET[] = { +	0x01, +}; + +static const unsigned char SEQ_USER_SETTING[] = { +	0xF0, 0x5A, 0x5A +}; + +static const unsigned char SEQ_ELVSS_ON[] = { +	0xB1, 0x0D, 0x00, 0x16, +}; + +static const unsigned char SEQ_TEMP_SWIRE[] = { +	0xB2, 0x06, 0x06, 0x06, 0x06, +}; + +static const unsigned char SEQ_GTCON[] = { +	0xF7, 0x09, 0x00, 0x00, +}; + +static const unsigned char SEQ_PANEL_CONDITION[] = { +	0xF8, 0x05, 0x65, 0x96, 0x71, 0x7D, 0x19, 0x3B, +	0x0D, 0x19, 0x7E, 0x0D, 0xE2, 0x00, 0x00, 0x7E, +	0x7D, 0x07, 0x07, 0x20, 0x20, 0x20, 0x02, 0x02, +}; + +static const unsigned char SEQ_GAMMA_SET1[] = { +	0xF9, 0x00, 0xA7, 0xB4, 0xAE, 0xBF, 0x00, 0x91, +	0x00, 0xB2, 0xB4, 0xAA, 0xBB, 0x00, 0xAC, 0x00, +	0xB3, 0xB1, 0xAA, 0xBC, 0x00, 0xB3, +}; + +static const unsigned char SEQ_GAMMA_CTRL[] = { +	0xFB, 0x02, 0x5A, +}; + +static const unsigned char SEQ_APON[] = { +	0xF3, 0x00, 0x00, 0x00, 0x0A, 0x02, +}; + +static const unsigned char SEQ_DISPCTL[] = { +	0xF2, 0x02, 0x08, 0x08, 0x10, 0x10, +}; + +static const unsigned char SEQ_MANPWR[] = { +	0xB0, 0x04, +}; + +static const unsigned char SEQ_PWR_CTRL[] = { +	0xF4, 0x0A, 0x87, 0x25, 0x6A, 0x44, 0x02, 0x88, +}; + +static const unsigned char SEQ_SLPOUT[] = { +	0x11, +}; + +static const unsigned char SEQ_SLPIN[] = { +	0x10, +}; + +static const unsigned char SEQ_DISPON[] = { +	0x29, +}; + +static const unsigned char SEQ_DISPOFF[] = { +	0x28, +}; + +static void ld9040_spi_write(const unsigned char *wbuf, unsigned int size_cmd) +{ +	int i = 0; + +	/* +	 * Data are transmitted in 9-bit words: +	 * the first bit is command/parameter, the other are the value. +	 * The value's LSB is shifted to MSB position, to be sent as 9th bit +	 */ + +	unsigned int data_out = 0, data_in = 0; +	for (i = 0; i < size_cmd; i++) { +		data_out = wbuf[i] >> 1; +		if (i != 0) +			data_out += 0x0080; +		if (wbuf[i] & 0x01) +			data_out += 0x8000; +		spi_xfer(NULL, 9, &data_out, &data_in, SPI_XFER_BEGIN); +	} +} + +void ld9040_cfg_ldo(void) +{ +	udelay(10); + +	ld9040_spi_write(SEQ_USER_SETTING, +					ARRAY_SIZE(SEQ_USER_SETTING)); +	ld9040_spi_write(SEQ_PANEL_CONDITION, +					ARRAY_SIZE(SEQ_PANEL_CONDITION)); +	ld9040_spi_write(SEQ_DISPCTL, ARRAY_SIZE(SEQ_DISPCTL)); +	ld9040_spi_write(SEQ_MANPWR, ARRAY_SIZE(SEQ_MANPWR)); +	ld9040_spi_write(SEQ_PWR_CTRL, ARRAY_SIZE(SEQ_PWR_CTRL)); +	ld9040_spi_write(SEQ_ELVSS_ON, ARRAY_SIZE(SEQ_ELVSS_ON)); +	ld9040_spi_write(SEQ_GTCON, ARRAY_SIZE(SEQ_GTCON)); +	ld9040_spi_write(SEQ_GAMMA_SET1, ARRAY_SIZE(SEQ_GAMMA_SET1)); +	ld9040_spi_write(SEQ_GAMMA_CTRL, ARRAY_SIZE(SEQ_GAMMA_CTRL)); +	ld9040_spi_write(SEQ_SLPOUT, ARRAY_SIZE(SEQ_SLPOUT)); + +	udelay(120); +} + +void ld9040_enable_ldo(unsigned int onoff) +{ +	if (onoff) +		ld9040_spi_write(SEQ_DISPON, ARRAY_SIZE(SEQ_DISPON)); +	else +		ld9040_spi_write(SEQ_DISPOFF, ARRAY_SIZE(SEQ_DISPOFF)); +} diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c new file mode 100644 index 000000000..750a28343 --- /dev/null +++ b/drivers/video/tegra.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2011 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 <fdtdec.h> +#include <lcd.h> + +#include <asm/system.h> +#include <asm/gpio.h> + +#include <asm/arch/clock.h> +#include <asm/arch/funcmux.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/pwm.h> +#include <asm/arch/display.h> +#include <asm/arch-tegra/timer.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* These are the stages we go throuh in enabling the LCD */ +enum stage_t { +	STAGE_START, +	STAGE_PANEL_VDD, +	STAGE_LVDS, +	STAGE_BACKLIGHT_VDD, +	STAGE_PWM, +	STAGE_BACKLIGHT_EN, +	STAGE_DONE, +}; + +static enum stage_t stage;	/* Current stage we are at */ +static unsigned long timer_next; /* Time we can move onto next stage */ + +/* Our LCD config, set up in handle_stage() */ +static struct fdt_panel_config config; +struct fdt_disp_config *disp_config;	/* Display controller config */ + +enum { +	/* Maximum LCD size we support */ +	LCD_MAX_WIDTH		= 1366, +	LCD_MAX_HEIGHT		= 768, +	LCD_MAX_LOG2_BPP	= 4,		/* 2^4 = 16 bpp */ +}; + +int lcd_line_length; +int lcd_color_fg; +int lcd_color_bg; + +void *lcd_base;			/* Start of framebuffer memory	*/ +void *lcd_console_address;	/* Start of console buffer	*/ + +short console_col; +short console_row; + +vidinfo_t panel_info = { +	/* Insert a value here so that we don't end up in the BSS */ +	.vl_col = -1, +}; + +char lcd_cursor_enabled; + +ushort lcd_cursor_width; +ushort lcd_cursor_height; + +#ifndef CONFIG_OF_CONTROL +#error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support" +#endif + +void lcd_cursor_size(ushort width, ushort height) +{ +	lcd_cursor_width = width; +	lcd_cursor_height = height; +} + +void lcd_toggle_cursor(void) +{ +	ushort x, y; +	uchar *dest; +	ushort row; + +	x = console_col * lcd_cursor_width; +	y = console_row * lcd_cursor_height; +	dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_BPP) / +			8); + +	for (row = 0; row < lcd_cursor_height; ++row, dest += lcd_line_length) { +		ushort *d = (ushort *)dest; +		ushort color; +		int i; + +		for (i = 0; i < lcd_cursor_width; ++i) { +			color = *d; +			color ^= lcd_color_fg; +			*d = color; +			++d; +		} +	} +} + +void lcd_cursor_on(void) +{ +	lcd_cursor_enabled = 1; +	lcd_toggle_cursor(); +} +void lcd_cursor_off(void) +{ +	lcd_cursor_enabled = 0; +	lcd_toggle_cursor(); +} + +char lcd_is_cursor_enabled(void) +{ +	return lcd_cursor_enabled; +} + +static void update_panel_size(struct fdt_disp_config *config) +{ +	panel_info.vl_col = config->width; +	panel_info.vl_row = config->height; +	panel_info.vl_bpix = config->log2_bpp; +} + +/* + *  Main init function called by lcd driver. + *  Inits and then prints test pattern if required. + */ + +void lcd_ctrl_init(void *lcdbase) +{ +	int line_length, size; +	int type = DCACHE_OFF; + +	assert(disp_config); + +	lcd_base = (void *)disp_config->frame_buffer; + +	/* Make sure that we can acommodate the selected LCD */ +	assert(disp_config->width <= LCD_MAX_WIDTH); +	assert(disp_config->height <= LCD_MAX_HEIGHT); +	assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP); +	if (disp_config->width <= LCD_MAX_WIDTH +			&& disp_config->height <= LCD_MAX_HEIGHT +			&& disp_config->log2_bpp <= LCD_MAX_LOG2_BPP) +		update_panel_size(disp_config); +	size = lcd_get_size(&line_length); + +	/* Set up the LCD caching as requested */ +	if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH) +		type = DCACHE_WRITETHROUGH; +	else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK) +		type = DCACHE_WRITEBACK; +	mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type); + +	/* Enable flushing after LCD writes if requested */ +	lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH); + +	debug("LCD frame buffer at %p\n", lcd_base); +} + +ulong calc_fbsize(void) +{ +	return (panel_info.vl_col * panel_info.vl_row * +		NBITS(panel_info.vl_bpix)) / 8; +} + +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ +} + +void tegra_lcd_early_init(const void *blob) +{ +	/* +	 * Go with the maximum size for now. We will fix this up after +	 * relocation. These values are only used for memory alocation. +	 */ +	panel_info.vl_col = LCD_MAX_WIDTH; +	panel_info.vl_row = LCD_MAX_HEIGHT; +	panel_info.vl_bpix = LCD_MAX_LOG2_BPP; +} + +/** + * Decode the panel information from the fdt. + * + * @param blob		fdt blob + * @param config	structure to store fdt config into + * @return 0 if ok, -ve on error + */ +static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config) +{ +	int display_node; + +	disp_config = tegra_display_get_config(); +	if (!disp_config) { +		debug("%s: Display controller is not configured\n", __func__); +		return -1; +	} +	display_node = disp_config->panel_node; +	if (display_node < 0) { +		debug("%s: No panel configuration available\n", __func__); +		return -1; +	} + +	config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm"); +	if (config->pwm_channel < 0) { +		debug("%s: Unable to request PWM channel\n", __func__); +		return -1; +	} + +	config->cache_type = fdtdec_get_int(blob, display_node, +					    "nvidia,cache-type", +					    FDT_LCD_CACHE_WRITE_BACK_FLUSH); + +	/* These GPIOs are all optional */ +	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios", +			    &config->backlight_en); +	fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios", +			   &config->lvds_shutdown); +	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios", +			   &config->backlight_vdd); +	fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios", +			   &config->panel_vdd); + +	return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings", +			config->panel_timings, FDT_LCD_TIMINGS); +} + +/** + * Handle the next stage of device init + */ +static int handle_stage(const void *blob) +{ +	debug("%s: stage %d\n", __func__, stage); + +	/* do the things for this stage */ +	switch (stage) { +	case STAGE_START: +		/* Initialize the Tegra display controller */ +		if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) { +			printf("%s: Failed to probe display driver\n", +			__func__); +			return -1; +		} + +		/* get panel details */ +		if (fdt_decode_lcd(blob, &config)) { +			printf("No valid LCD information in device tree\n"); +			return -1; +		} + +		/* +		 * It is possible that the FDT has requested that the LCD be +		 * disabled. We currently don't support this. It would require +		 * changes to U-Boot LCD subsystem to have LCD support +		 * compiled in but not used. An easier option might be to +		 * still have a frame buffer, but leave the backlight off and +		 * remove all mention of lcd in the stdout environment +		 * variable. +		 */ + +		funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT); + +		fdtdec_setup_gpio(&config.panel_vdd); +		fdtdec_setup_gpio(&config.lvds_shutdown); +		fdtdec_setup_gpio(&config.backlight_vdd); +		fdtdec_setup_gpio(&config.backlight_en); + +		/* +		 * TODO: If fdt includes output flag we can omit this code +		 * since fdtdec_setup_gpio will do it for us. +		 */ +		if (fdt_gpio_isvalid(&config.panel_vdd)) +			gpio_direction_output(config.panel_vdd.gpio, 0); +		if (fdt_gpio_isvalid(&config.lvds_shutdown)) +			gpio_direction_output(config.lvds_shutdown.gpio, 0); +		if (fdt_gpio_isvalid(&config.backlight_vdd)) +			gpio_direction_output(config.backlight_vdd.gpio, 0); +		if (fdt_gpio_isvalid(&config.backlight_en)) +			gpio_direction_output(config.backlight_en.gpio, 0); +		break; +	case STAGE_PANEL_VDD: +		if (fdt_gpio_isvalid(&config.panel_vdd)) +			gpio_direction_output(config.panel_vdd.gpio, 1); +		break; +	case STAGE_LVDS: +		if (fdt_gpio_isvalid(&config.lvds_shutdown)) +			gpio_set_value(config.lvds_shutdown.gpio, 1); +		break; +	case STAGE_BACKLIGHT_VDD: +		if (fdt_gpio_isvalid(&config.backlight_vdd)) +			gpio_set_value(config.backlight_vdd.gpio, 1); +		break; +	case STAGE_PWM: +		/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */ +		pinmux_set_func(PINGRP_GPU, PMUX_FUNC_PWM); +		pinmux_tristate_disable(PINGRP_GPU); + +		pwm_enable(config.pwm_channel, 32768, 0xdf, 1); +		break; +	case STAGE_BACKLIGHT_EN: +		if (fdt_gpio_isvalid(&config.backlight_en)) +			gpio_set_value(config.backlight_en.gpio, 1); +		break; +	case STAGE_DONE: +		break; +	} + +	/* set up timer for next stage */ +	timer_next = timer_get_us(); +	if (stage < FDT_LCD_TIMINGS) +		timer_next += config.panel_timings[stage] * 1000; + +	/* move to next stage */ +	stage++; +	return 0; +} + +int tegra_lcd_check_next_stage(const void *blob, int wait) +{ +	if (stage == STAGE_DONE) +		return 0; + +	do { +		/* wait if we need to */ +		debug("%s: stage %d\n", __func__, stage); +		if (stage != STAGE_START) { +			int delay = timer_next - timer_get_us(); + +			if (delay > 0) { +				if (wait) +					udelay(delay); +				else +					return 0; +			} +		} + +		if (handle_stage(blob)) +			return -1; +	} while (wait && stage != STAGE_DONE); +	if (stage == STAGE_DONE) +		debug("%s: LCD init complete\n", __func__); + +	return 0; +} + +void lcd_enable(void) +{ +	/* +	 * Backlight and power init will be done separately in +	 * tegra_lcd_check_next_stage(), which should be called in +	 * board_late_init(). +	 * +	 * U-Boot code supports only colour depth, selected at compile time. +	 * The device tree setting should match this. Otherwise the display +	 * will not look right, and U-Boot may crash. +	 */ +	if (disp_config->log2_bpp != LCD_BPP) { +		printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)" +			" must match setting of LCD_BPP (%d)\n", __func__, +		       disp_config->log2_bpp, disp_config->bpp, LCD_BPP); +	} +} diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 923acb9f3..bc0912391 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -28,6 +28,7 @@ LIB	:= $(obj)libwatchdog.o  COBJS-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o  COBJS-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o  COBJS-$(CONFIG_TNETV107X_WATCHDOG) += tnetv107x_wdt.o +COBJS-$(CONFIG_S5P)               += s5p_wdt.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/s5p-common/wdt.c b/drivers/watchdog/s5p_wdt.c index 94acc1e4b..94acc1e4b 100644 --- a/arch/arm/cpu/armv7/s5p-common/wdt.c +++ b/drivers/watchdog/s5p_wdt.c diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 23c964940..bfedbe445 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -42,10 +42,11 @@   */  /** - * Request ownership of a GPIO. + * Request a gpio. This should be called before any of the other functions + * are used on this gpio.   * - * @param gpio	GPIO number - * @param label	Name given to the GPIO + * @param gp	GPIO number + * @param label	User label for this GPIO   * @return 0 if ok, -1 on error   */  int gpio_request(unsigned gpio, const char *label); @@ -93,14 +94,4 @@ int gpio_get_value(unsigned gpio);   * @return 0 if ok, -1 on error   */  int gpio_set_value(unsigned gpio, int value); - -/** - * Request a gpio. This should be called before any of the other functions - * are used on this gpio. - * - * @param gp	GPIO number - * @param label	User label for this GPIO - * @return 0 if ok, -1 on error - */ -int gpio_request(unsigned gpio, const char *label);  #endif	/* _ASM_GENERIC_GPIO_H_ */ diff --git a/include/command.h b/include/command.h index 10bc2606c..476e7cffc 100644 --- a/include/command.h +++ b/include/command.h @@ -89,10 +89,10 @@ extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *   */  #if defined(CONFIG_CMD_MEMORY)		\ -    || defined(CONFIG_CMD_I2C)		\ -    || defined(CONFIG_CMD_ITEST)	\ -    || defined(CONFIG_CMD_PCI)		\ -    || defined(CONFIG_CMD_PORTIO) +	|| defined(CONFIG_CMD_I2C)	\ +	|| defined(CONFIG_CMD_ITEST)	\ +	|| defined(CONFIG_CMD_PCI)	\ +	|| defined(CONFIG_CMD_PORTIO)  #define CMD_DATA_SIZE  extern int cmd_get_data_size(char* arg, int default_size);  #endif diff --git a/include/common.h b/include/common.h index 5e3c5eeee..d0bf1e8ab 100644 --- a/include/common.h +++ b/include/common.h @@ -340,6 +340,11 @@ int	envmatch     (uchar *, int);  char	*getenv	     (const char *);  int	getenv_f     (const char *name, char *buf, unsigned len);  ulong getenv_ulong(const char *name, int base, ulong default_val); +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var);  int	saveenv	     (void);  int	setenv	     (const char *, const char *);  int setenv_ulong(const char *varname, ulong value); diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h index f434cd089..e82f6421c 100644 --- a/include/config_cmd_all.h +++ b/include/config_cmd_all.h @@ -40,12 +40,15 @@  #define CONFIG_CMD_FDOS		/* Floppy DOS support		*/  #define CONFIG_CMD_FLASH	/* flinfo, erase, protect	*/  #define CONFIG_CMD_FPGA		/* FPGA configuration Support	*/ +#define CONFIG_CMD_GETTIME	/* Get time since boot         */ +#define CONFIG_CMD_HASH		/* calculate hash / digest	*/  #define CONFIG_CMD_HWFLOW	/* RTS/CTS hw flow control	*/  #define CONFIG_CMD_I2C		/* I2C serial bus support	*/  #define CONFIG_CMD_IDE		/* IDE harddisk support		*/  #define CONFIG_CMD_IMI		/* iminfo			*/  #define CONFIG_CMD_IMLS		/* List all found images	*/  #define CONFIG_CMD_IMMAP	/* IMMR dump support		*/ +#define CONFIG_CMD_IO		/* Access to X86 IO space	*/  #define CONFIG_CMD_IRQ		/* irqinfo			*/  #define CONFIG_CMD_ITEST	/* Integer (and string) test	*/  #define CONFIG_CMD_JFFS2	/* JFFS2 Support		*/ @@ -70,6 +73,7 @@  #define CONFIG_CMD_REGINFO	/* Register dump		*/  #define CONFIG_CMD_REISER	/* Reiserfs support		*/  #define CONFIG_CMD_RARP		/* rarpboot support		*/ +#define CONFIG_CMD_READ		/* Read data from partition	*/  #define CONFIG_CMD_RUN		/* run command in env variable	*/  #define CONFIG_CMD_SAVEENV	/* saveenv			*/  #define CONFIG_CMD_SAVES	/* save S record dump		*/ diff --git a/include/configs/CRAYL1.h b/include/configs/CRAYL1.h index 1daec6967..6bceccbc1 100644 --- a/include/configs/CRAYL1.h +++ b/include/configs/CRAYL1.h @@ -153,7 +153,6 @@  #define CONFIG_SYS_LOAD_ADDR		0x100000	/* where to load what we get from TFTP */ -#define CONFIG_SYS_TFTP_LOADADDR	CONFIG_SYS_LOAD_ADDR  #define CONFIG_SYS_EXTBDINFO		1		/* To use extended board_into (bd_t) */  #define CONFIG_SYS_DRAM_TEST		1 diff --git a/include/configs/GEN860T.h b/include/configs/GEN860T.h index b98caccb8..9a649ca12 100644 --- a/include/configs/GEN860T.h +++ b/include/configs/GEN860T.h @@ -96,11 +96,6 @@  #define	CONFIG_SYS_LOADS_BAUD_CHANGE  /* - * Set default load address for tftp network downloads - */ -#define	CONFIG_SYS_TFTP_LOADADDR				0x01000000 - -/*   * Turn off the watchdog timer   */  #undef	CONFIG_WATCHDOG diff --git a/include/configs/TOP860.h b/include/configs/TOP860.h index 36921ca8b..4849f94c9 100644 --- a/include/configs/TOP860.h +++ b/include/configs/TOP860.h @@ -416,7 +416,6 @@  #define CONFIG_IPADDR					10.0.4.111  #define CONFIG_SYS_LOAD_ADDR		0x00100000	/* default load address */ -#define	CONFIG_SYS_TFTP_LOADADDR	0x00100000  /*   * For booting Linux, the board info and command line data diff --git a/include/configs/ep8260.h b/include/configs/ep8260.h index ccfe032ca..5a87cc5d3 100644 --- a/include/configs/ep8260.h +++ b/include/configs/ep8260.h @@ -371,7 +371,6 @@  #define	CONFIG_CLOCKS_IN_MHZ	1      /* clocks passsed to Linux in MHz */  #define CONFIG_SYS_LOAD_ADDR     0x00100000   /* default load address */ -#define CONFIG_SYS_TFTP_LOADADDR 0x00100000   /* default load address for network file downloads */  #define CONFIG_SYS_HZ            1000         /* decrementer freq: 1 ms ticks */ diff --git a/include/configs/harmony.h b/include/configs/harmony.h index 040bfe48e..8d1fd47af 100644 --- a/include/configs/harmony.h +++ b/include/configs/harmony.h @@ -58,14 +58,16 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /* NAND support */  #define CONFIG_CMD_NAND  #define CONFIG_TEGRA_NAND  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define CONFIG_SYS_NAND_BASE	NV_PA_NAND_BASE  /* Environment in NAND (which is 512M), aligned to start of last sector */  #define CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/m28evk.h b/include/configs/m28evk.h index b49ec8c7d..3f37e8430 100644 --- a/include/configs/m28evk.h +++ b/include/configs/m28evk.h @@ -297,7 +297,7 @@  		"if tftp ${update_nand_full_filename} ; then "		\  		"run update_nand_get_fcb_size ; "			\  		"nand scrub -y 0x0 ${filesize} ; "			\ -		"nand write.raw ${loadaddr} 0x0 ${update_nand_fcb} ; "	\ +		"nand write.raw ${loadaddr} 0x0 ${fcb_sz} ; "	\  		"setexpr update_off ${loadaddr} + ${update_nand_fcb} ; " \  		"setexpr update_sz ${filesize} - ${update_nand_fcb} ; " \  		"nand write ${update_off} ${update_nand_fcb} ${update_sz} ; " \ diff --git a/include/configs/mx28evk.h b/include/configs/mx28evk.h index 8b89b25f7..cdf3e1508 100644 --- a/include/configs/mx28evk.h +++ b/include/configs/mx28evk.h @@ -263,7 +263,7 @@  		"if tftp ${update_nand_full_filename} ; then " \  		"run update_nand_get_fcb_size ; " \  		"nand scrub -y 0x0 ${filesize} ; " \ -		"nand write.raw ${loadaddr} 0x0 ${update_nand_fcb} ; " \ +		"nand write.raw ${loadaddr} 0x0 ${fcb_sz} ; " \  		"setexpr update_off ${loadaddr} + ${update_nand_fcb} ; " \  		"setexpr update_sz ${filesize} - ${update_nand_fcb} ; " \  		"nand write ${update_off} ${update_nand_fcb} ${update_sz} ; " \ diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h index b4d925ed9..fc6e78208 100644 --- a/include/configs/omap3_evm.h +++ b/include/configs/omap3_evm.h @@ -95,10 +95,7 @@  #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME	"u-boot.img"  /* Partition tables */ -/* Only need DOS partition support for SPL, currently */ -#ifndef CONFIG_SPL_BUILD  #define CONFIG_EFI_PARTITION -#endif  #define CONFIG_DOS_PARTITION  /* USB diff --git a/include/configs/palmld.h b/include/configs/palmld.h index c5dd49405..3f9802ca0 100644 --- a/include/configs/palmld.h +++ b/include/configs/palmld.h @@ -28,6 +28,9 @@  #define	CONFIG_CPU_PXA27X		1	/* Marvell PXA270 CPU */  #define	CONFIG_PALMLD		1	/* Palm LifeDrive board */ +/* we will never enable dcache, because we have to setup MMU first */ +#define CONFIG_SYS_DCACHE_OFF +  /*   * Environment settings   */ diff --git a/include/configs/palmtc.h b/include/configs/palmtc.h index 9c948c547..64771e7e8 100644 --- a/include/configs/palmtc.h +++ b/include/configs/palmtc.h @@ -30,6 +30,9 @@  #define	CONFIG_CPU_PXA25X			1	/* Intel PXA255 CPU */  #define	CONFIG_PALMTC			1	/* Palm Tungsten|C board */ +/* we will never enable dcache, because we have to setup MMU first */ +#define CONFIG_SYS_DCACHE_OFF +  /*   * Environment settings   */ diff --git a/include/configs/paz00.h b/include/configs/paz00.h index 5603de962..38c79cfc2 100644 --- a/include/configs/paz00.h +++ b/include/configs/paz00.h @@ -45,8 +45,11 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /* Environment in eMMC, at the end of 2nd "boot sector" */  #define CONFIG_ENV_IS_IN_MMC diff --git a/include/configs/s5pc210_universal.h b/include/configs/s5pc210_universal.h index 894f38bd7..eb13bb3a6 100644 --- a/include/configs/s5pc210_universal.h +++ b/include/configs/s5pc210_universal.h @@ -34,6 +34,7 @@  #define CONFIG_S5P		1	/* which is in a S5P Family */  #define CONFIG_EXYNOS4210	1	/* which is in a EXYNOS4210 */  #define CONFIG_UNIVERSAL	1	/* working with Universal */ +#define CONFIG_TIZEN		1	/* TIZEN lib */  #include <asm/arch/cpu.h>		/* get chip and board defs */ @@ -56,6 +57,8 @@  #define CONFIG_INITRD_TAG  #define CONFIG_REVISION_TAG  #define CONFIG_CMDLINE_EDITING +#define CONFIG_SKIP_LOWLEVEL_INIT +#define CONFIG_BOARD_EARLY_INIT_F  /* Size of malloc() pool */  #define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + (1 << 20)) @@ -261,4 +264,37 @@  #define CONFIG_USB_GADGET_S3C_UDC_OTG  #define CONFIG_USB_GADGET_DUALSPEED +/* + * SPI Settings + */ +#define CONFIG_SOFT_SPI +#define CONFIG_SOFT_SPI_MODE SPI_MODE_3 +#define CONFIG_SOFT_SPI_GPIO_SCLK exynos4_gpio_part2_get_nr(y3, 1) +#define CONFIG_SOFT_SPI_GPIO_MOSI exynos4_gpio_part2_get_nr(y3, 3) +#define CONFIG_SOFT_SPI_GPIO_MISO exynos4_gpio_part2_get_nr(y3, 0) +#define CONFIG_SOFT_SPI_GPIO_CS exynos4_gpio_part2_get_nr(y4, 3) + +#define SPI_DELAY udelay(1) +#undef SPI_INIT +#define SPI_SCL(bit) universal_spi_scl(bit) +#define SPI_SDA(bit) universal_spi_sda(bit) +#define SPI_READ universal_spi_read() +#ifndef	__ASSEMBLY__ +void universal_spi_scl(int bit); +void universal_spi_sda(int bit); +int universal_spi_read(void); +#endif + +/* + * LCD Settings + */ +#define CONFIG_EXYNOS_FB +#define CONFIG_LCD +#define CONFIG_CMD_BMP +#define CONFIG_BMP_32BPP +#define CONFIG_LD9040 +#define CONFIG_EXYNOS_MIPI_DSIM +#define CONFIG_VIDEO_BMP_GZIP +#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((520 * 120 * 4) + (1 << 12)) +  #endif	/* __CONFIG_H */ diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index ab10bd0ab..de0c77781 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -54,6 +54,7 @@  #define CONFIG_MACH_TYPE		MACH_TYPE_SEABOARD  #define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_BOARD_LATE_INIT		/* Make sure LCD init is complete */  /* I2C */  #define CONFIG_TEGRA_I2C @@ -71,8 +72,11 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /* Environment in eMMC, at the end of 2nd "boot sector" */  #define CONFIG_ENV_IS_IN_MMC @@ -102,7 +106,13 @@  /* USB keyboard */  #define CONFIG_USB_KEYBOARD -#include "tegra-common-post.h" +/* LCD support */ +#define CONFIG_LCD +#define CONFIG_PWM_TEGRA +#define CONFIG_VIDEO_TEGRA +#define LCD_BPP				LCD_COLOR16 +#define CONFIG_SYS_WHITE_ON_BLACK +#define CONFIG_CONSOLE_SCROLL_LINES	10  /* NAND support */  #define CONFIG_CMD_NAND @@ -111,6 +121,6 @@  /* Max number of NAND devices */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -/* Somewhat oddly, the NAND base address must be a config option */ -#define CONFIG_SYS_NAND_BASE	NV_PA_NAND_BASE +#include "tegra-common-post.h" +  #endif /* __CONFIG_H */ diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index c0f86228b..75c25c003 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -65,7 +65,7 @@  #define INFORM1_OFFSET			0x804  /* Size of malloc() pool */ -#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + (1 << 20)) +#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + (4 << 20))  /* select serial console configuration */  #define CONFIG_SERIAL3			/* use SERIAL 3 */ @@ -163,7 +163,6 @@  #undef CONFIG_CMD_IMLS  #define CONFIG_IDENT_STRING		" for SMDK5250" -#define CONFIG_ENV_IS_IN_MMC  #define CONFIG_SYS_MMC_ENV_DEV		0  #define CONFIG_SECURE_BL1_ONLY @@ -188,6 +187,11 @@  /* U-boot copy size from boot Media to DRAM.*/  #define BL2_START_OFFSET	(CONFIG_BL2_OFFSET/512)  #define BL2_SIZE_BLOC_COUNT	(CONFIG_BL2_SIZE/512) + +#define OM_STAT				(0x1f << 1) +#define EXYNOS_COPY_SPI_FNPTR_ADDR	0x02020058 +#define SPI_FLASH_UBOOT_POS		(CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE) +  #define CONFIG_DOS_PARTITION  #define CONFIG_IRAM_STACK	0x02050000 @@ -203,6 +207,59 @@  #define CONFIG_I2C_MULTI_BUS  #define CONFIG_MAX_I2C_NUM	8  #define CONFIG_SYS_I2C_SLAVE    0x0 +#define CONFIG_I2C_EDID + +/* PMIC */ +#define CONFIG_PMIC +#define CONFIG_PMIC_I2C +#define CONFIG_PMIC_MAX77686 + +/* SPI */ +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_SPI_FLASH + +#ifdef CONFIG_SPI_FLASH +#define CONFIG_EXYNOS_SPI +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE		SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED		50000000 +#define EXYNOS5_SPI_NUM_CONTROLLERS	5 +#endif + +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_MODE	SPI_MODE_0 +#define CONFIG_ENV_SECT_SIZE	CONFIG_ENV_SIZE +#define CONFIG_ENV_SPI_BUS	1 +#define CONFIG_ENV_SPI_MAX_HZ	50000000 +#endif + +/* PMIC */ +#define CONFIG_POWER +#define CONFIG_POWER_I2C +#define CONFIG_POWER_MAX77686 + +/* SPI */ +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_SPI_FLASH + +#ifdef CONFIG_SPI_FLASH +#define CONFIG_EXYNOS_SPI +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE		SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED		50000000 +#define EXYNOS5_SPI_NUM_CONTROLLERS	5 +#endif + +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_MODE	SPI_MODE_0 +#define CONFIG_ENV_SECT_SIZE	CONFIG_ENV_SIZE +#define CONFIG_ENV_SPI_BUS	1 +#define CONFIG_ENV_SPI_MAX_HZ	50000000 +#endif  /* Ethernet Controllor Driver */  #ifdef CONFIG_CMD_NET @@ -212,7 +269,27 @@  #define CONFIG_ENV_SROM_BANK		1  #endif /*CONFIG_CMD_NET*/ +/* Enable PXE Support */ +#ifdef CONFIG_CMD_NET +#define CONFIG_CMD_PXE +#define CONFIG_MENU +#endif + +/* Sound */ +#define CONFIG_CMD_SOUND +#ifdef CONFIG_CMD_SOUND +#define CONFIG_SOUND +#define CONFIG_I2S +#define CONFIG_SOUND_WM8994 +#endif +  /* Enable devicetree support */  #define CONFIG_OF_LIBFDT +/* SHA hashing */ +#define CONFIG_CMD_HASH +#define CONFIG_HASH_VERIFY +#define CONFIG_SHA1 +#define CONFIG_SHA256 +  #endif	/* __CONFIG_H */ diff --git a/include/configs/tec.h b/include/configs/tec.h index 140d2e663..200cf6664 100644 --- a/include/configs/tec.h +++ b/include/configs/tec.h @@ -54,7 +54,6 @@  #define CONFIG_CMD_NAND  #define CONFIG_TEGRA_NAND  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define CONFIG_SYS_NAND_BASE		NV_PA_NAND_BASE  /* Environment in NAND, aligned to start of last sector */  #define CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index 6f310bee6..ee40cc2a3 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -30,18 +30,6 @@  #else -#ifdef CONFIG_CMD_EXT2 -#define BOOT_FSTYPE_EXT2 "ext2 " -#else -#define BOOT_FSTYPE_EXT2 "" -#endif - -#ifdef CONFIG_CMD_FAT -#define BOOT_FSTYPE_FAT "fat" -#else -#define BOOT_FSTYPE_FAT "" -#endif -  #ifdef CONFIG_CMD_MMC  #define BOOTCMDS_MMC \  	"mmc_boot=" \ @@ -98,7 +86,7 @@  	"rootpart=1\0" \  	\  	"script_boot="                                                    \ -		"if ${fs}load ${devtype} ${devnum}:${rootpart} "          \ +		"if load ${devtype} ${devnum}:${rootpart} "               \  				"${scriptaddr} ${prefix}${script}; then " \  			"echo ${script} found! Executing ...;"            \  			"source ${scriptaddr};"                           \ @@ -106,11 +94,9 @@  	\  	"scan_boot="                                                      \  		"echo Scanning ${devtype} ${devnum}...; "                 \ -		"for fs in ${boot_fstypes}; do "                          \ -			"for prefix in ${boot_prefixes}; do "             \ -				"for script in ${boot_scripts}; do "      \ -					"run script_boot; "               \ -				"done; "                                  \ +		"for prefix in ${boot_prefixes}; do "                     \ +			"for script in ${boot_scripts}; do "              \ +				"run script_boot; "                       \  			"done; "                                          \  		"done;\0"                                                 \  	\ @@ -120,11 +106,6 @@  		BOOT_TARGETS_DHCP " " \  		"\0" \  	\ -	"boot_fstypes=" \ -		BOOT_FSTYPE_EXT2 " " \ -		BOOT_FSTYPE_FAT " " \ -		"\0" \ -	\  	"boot_prefixes=/ /boot/\0" \  	\  	"boot_scripts=boot.scr.uimg boot.scr\0" \ @@ -181,8 +162,8 @@  #define TEGRA_DEVICE_SETTINGS \  	"stdin=serial" STDIN_KBD_KBC STDIN_KBD_USB "\0" \ -	"stdout=serial\0" \ -	"stderr=serial\0" \ +	"stdout=serial,lcd\0" \ +	"stderr=serial,lcd\0" \  #define CONFIG_EXTRA_ENV_SETTINGS \  	TEGRA_DEVICE_SETTINGS \ @@ -226,12 +207,24 @@  #ifdef CONFIG_EFI_PARTITION  #undef CONFIG_EFI_PARTITION  #endif +#ifdef CONFIG_CMD_FS_GENERIC +#undef CONFIG_CMD_FS_GENERIC +#endif +#ifdef CONFIG_CMD_EXT4 +#undef CONFIG_CMD_EXT4 +#endif  #ifdef CONFIG_CMD_EXT2  #undef CONFIG_CMD_EXT2  #endif  #ifdef CONFIG_CMD_FAT  #undef CONFIG_CMD_FAT  #endif +#ifdef CONFIG_FS_EXT4 +#undef CONFIG_FS_EXT4 +#endif +#ifdef CONFIG_FS_FAT +#undef CONFIG_FS_FAT +#endif  /* remove USB */  #ifdef CONFIG_USB_EHCI diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index 5c0833a4d..fe07f7226 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -38,6 +38,9 @@  #include <asm/arch/tegra.h>		/* get chip and board defs */ +/* Align LCD to 1MB boundary */ +#define CONFIG_LCD_ALIGNMENT	MMU_SECTION_SIZE +  /*   * Display CPU and Board information   */ diff --git a/include/configs/trats.h b/include/configs/trats.h index 355029e8d..6efee5c47 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -98,6 +98,7 @@  #undef CONFIG_CMD_MTDPARTS  #define CONFIG_CMD_MMC  #define CONFIG_CMD_DFU +#define CONFIG_CMD_GPT  /* FAT */  #define CONFIG_CMD_FAT @@ -122,6 +123,26 @@  #define CONFIG_BOOTBLOCK		"10"  #define CONFIG_ENV_COMMON_BOOT		"${console} ${meminfo}" +/* Tizen - partitions definitions */ +#define PARTS_CSA		"csa-mmc" +#define PARTS_BOOTLOADER	"u-boot" +#define PARTS_BOOT		"boot" +#define PARTS_ROOT		"platform" +#define PARTS_DATA		"data" +#define PARTS_CSC		"csc" +#define PARTS_UMS		"ums" + +#define PARTS_DEFAULT \ +	"uuid_disk=${uuid_gpt_disk};" \ +	"name="PARTS_CSA",size=8MiB,uuid=${uuid_gpt_"PARTS_CSA"};" \ +	"name="PARTS_BOOTLOADER",size=60MiB," \ +		"uuid=${uuid_gpt_"PARTS_BOOTLOADER"};" \ +	"name="PARTS_BOOT",size=100MiB,uuid=${uuid_gpt_"PARTS_BOOT"};" \ +	"name="PARTS_ROOT",size=1GiB,uuid=${uuid_gpt_"PARTS_ROOT"};" \ +	"name="PARTS_DATA",size=3GiB,uuid=${uuid_gpt_"PARTS_DATA"};" \ +	"name="PARTS_CSC",size=150MiB,uuid=${uuid_gpt_"PARTS_CSC"};" \ +	"name="PARTS_UMS",size=-,uuid=${uuid_gpt_"PARTS_UMS"}\0" \ +  #define CONFIG_DFU_ALT \  	"dfu_alt_info=" \  	"u-boot mmc 80 400;" \ @@ -171,7 +192,8 @@  	"mmcbootpart=2\0" \  	"mmcrootpart=3\0" \  	"opts=always_resume=1\0" \ -	CONFIG_DFU_ALT +	"partitions=" PARTS_DEFAULT \ +	CONFIG_DFU_ALT \  /* Miscellaneous configurable options */  #define CONFIG_SYS_LONGHELP		/* undef to save memory */ @@ -189,12 +211,17 @@  #define CONFIG_SYS_HZ			1000 -/* TRATS has 2 banks of DRAM */ -#define CONFIG_NR_DRAM_BANKS	2 -#define PHYS_SDRAM_1		CONFIG_SYS_SDRAM_BASE	/* LDDDR2 DMC 0 */ -#define PHYS_SDRAM_1_SIZE	(512 << 20)		/* 512 MB in CS 0 */ -#define PHYS_SDRAM_2		0x50000000		/* LPDDR2 DMC 1 */ -#define PHYS_SDRAM_2_SIZE	(512 << 20)		/* 512 MB in CS 0 */ +/* TRATS has 4 banks of DRAM */ +#define CONFIG_NR_DRAM_BANKS	4 +#define SDRAM_BANK_SIZE		(256UL << 20UL)	/* 256 MB */ +#define PHYS_SDRAM_1		CONFIG_SYS_SDRAM_BASE +#define PHYS_SDRAM_1_SIZE	SDRAM_BANK_SIZE +#define PHYS_SDRAM_2		(CONFIG_SYS_SDRAM_BASE + SDRAM_BANK_SIZE) +#define PHYS_SDRAM_2_SIZE	SDRAM_BANK_SIZE +#define PHYS_SDRAM_3		(CONFIG_SYS_SDRAM_BASE + (2 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_3_SIZE	SDRAM_BANK_SIZE +#define PHYS_SDRAM_4		(CONFIG_SYS_SDRAM_BASE + (3 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_4_SIZE	SDRAM_BANK_SIZE  #define CONFIG_SYS_MEM_TOP_HIDE		(1 << 20)	/* ram console */ @@ -208,6 +235,10 @@  #define CONFIG_DOS_PARTITION +/* GPT */ +#define CONFIG_EFI_PARTITION +#define CONFIG_PARTITION_UUIDS +  #define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_LOAD_ADDR - GENERATED_GBL_DATA_SIZE)  #define CONFIG_SYS_CACHELINE_SIZE       32 diff --git a/include/configs/trimslice.h b/include/configs/trimslice.h index eeb0dbe23..334d3a3b8 100644 --- a/include/configs/trimslice.h +++ b/include/configs/trimslice.h @@ -69,8 +69,11 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /* Environment in SPI */  #define CONFIG_ENV_IS_IN_SPI_FLASH @@ -80,6 +83,7 @@  #define CONFIG_ENV_OFFSET		(512 * 1024)  /* USB Host support */ +#define CONFIG_USB_MAX_CONTROLLER_COUNT 3  #define CONFIG_USB_EHCI  #define CONFIG_USB_EHCI_TEGRA  #define CONFIG_USB_STORAGE diff --git a/include/configs/utx8245.h b/include/configs/utx8245.h index d203bb4dd..66568c8d0 100644 --- a/include/configs/utx8245.h +++ b/include/configs/utx8245.h @@ -65,7 +65,6 @@  #define CONFIG_BOOTARGS		"root=/dev/ram console=ttyS0,57600" /* RAMdisk */  #define CONFIG_ETHADDR		00:AA:00:14:00:05	/* UTX5 */  #define CONFIG_SERVERIP		10.8.17.105	/* Spree */ -#define CONFIG_SYS_TFTP_LOADADDR	10000  #define CONFIG_EXTRA_ENV_SETTINGS \  	"kernel_addr=FFA00000\0" \ diff --git a/include/configs/ventana.h b/include/configs/ventana.h index 4c9b31cce..b55ebc9bf 100644 --- a/include/configs/ventana.h +++ b/include/configs/ventana.h @@ -52,8 +52,11 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /* Environment in eMMC, at the end of 2nd "boot sector" */  #define CONFIG_ENV_IS_IN_MMC diff --git a/include/configs/whistler.h b/include/configs/whistler.h index 1c7803b26..1e554d816 100644 --- a/include/configs/whistler.h +++ b/include/configs/whistler.h @@ -61,8 +61,11 @@  #define CONFIG_DOS_PARTITION  #define CONFIG_EFI_PARTITION +#define CONFIG_FS_EXT4 +#define CONFIG_FS_FAT  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_FAT +#define CONFIG_CMD_FS_GENERIC  /*   * Environment in eMMC, at the end of 2nd "boot sector". Note: This assumes diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index bf6394a90..b92f70b53 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -41,6 +41,9 @@  #define CONFIG_ENV_ADDR			0x40000  #define CONFIG_ENV_SIZE			0x20000 +/* we will never enable dcache, because we have to setup MMU first */ +#define CONFIG_SYS_DCACHE_OFF +  #define	CONFIG_SYS_MALLOC_LEN		(128*1024)  #define	CONFIG_ARCH_CPU_INIT diff --git a/include/edid.h b/include/edid.h new file mode 100644 index 000000000..4788de939 --- /dev/null +++ b/include/edid.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2010 + * Petr Stetiar <ynezz@true.cz> + * + * 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 + * + * Contains stolen code from ddcprobe project which is: + * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> + * + */ + +#ifndef __EDID_H_ +#define __EDID_H_ + +#include <linux/types.h> + +#define GET_BIT(_x, _pos) \ +	(((_x) >> (_pos)) & 1) +#define GET_BITS(_x, _pos_msb, _pos_lsb) \ +	(((_x) >> (_pos_lsb)) & ((1 << ((_pos_msb) - (_pos_lsb) + 1)) - 1)) + +/* Aspect ratios used in EDID info. */ +enum edid_aspect { +	ASPECT_625 = 0, +	ASPECT_75, +	ASPECT_8, +	ASPECT_5625, +}; + +/* Detailed timing information used in EDID v1.x */ +struct edid_detailed_timing { +	unsigned char pixel_clock[2]; +#define EDID_DETAILED_TIMING_PIXEL_CLOCK(_x) \ +	(((((uint32_t)(_x).pixel_clock[1]) << 8) + \ +	 (_x).pixel_clock[0]) * 10000) +	unsigned char horizontal_active; +	unsigned char horizontal_blanking; +	unsigned char horizontal_active_blanking_hi; +#define EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(_x) \ +	((GET_BITS((_x).horizontal_active_blanking_hi, 7, 4) << 8) + \ +	 (_x).horizontal_active) +#define EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(_x) \ +	((GET_BITS((_x).horizontal_active_blanking_hi, 3, 0) << 8) + \ +	 (_x).horizontal_blanking) +	unsigned char vertical_active; +	unsigned char vertical_blanking; +	unsigned char vertical_active_blanking_hi; +#define EDID_DETAILED_TIMING_VERTICAL_ACTIVE(_x) \ +	((GET_BITS((_x).vertical_active_blanking_hi, 7, 4) << 8) + \ +	 (_x).vertical_active) +#define EDID_DETAILED_TIMING_VERTICAL_BLANKING(_x) \ +	((GET_BITS((_x).vertical_active_blanking_hi, 3, 0) << 8) + \ +	 (_x).vertical_blanking) +	unsigned char hsync_offset; +	unsigned char hsync_pulse_width; +	unsigned char sync_offset_pulse_width; +	unsigned char hsync_vsync_offset_pulse_width_hi; +#define EDID_DETAILED_TIMING_HSYNC_OFFSET(_x) \ +	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 7, 6) << 8) + \ +	 (_x).hsync_offset) +#define EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(_x) \ +	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 5, 4) << 8) + \ +	 (_x).hsync_pulse_width) +#define EDID_DETAILED_TIMING_VSYNC_OFFSET(_x) \ +	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 3, 2) << 4) + \ +	 GET_BITS((_x).vsync_offset_pulse_width, 7, 4)) +#define EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(_x) \ +	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 1, 0) << 4) + \ +	 GET_BITS((_x).vsync_offset_pulse_width, 3, 0)) +	unsigned char himage_size; +	unsigned char vimage_size; +	unsigned char himage_vimage_size_hi; +#define EDID_DETAILED_TIMING_HIMAGE_SIZE(_x) \ +	((GET_BITS((_x).himage_vimage_size_hi, 7, 4) << 8) + (_x).himage_size) +#define EDID_DETAILED_TIMING_VIMAGE_SIZE(_x) \ +	((GET_BITS((_x).himage_vimage_size_hi, 3, 0) << 8) + (_x).vimage_size) +	unsigned char hborder; +	unsigned char vborder; +	unsigned char flags; +#define EDID_DETAILED_TIMING_FLAG_INTERLACED(_x) \ +	GET_BIT((_x).flags, 7) +#define EDID_DETAILED_TIMING_FLAG_STEREO(_x) \ +	GET_BITS((_x).flags, 6, 5) +#define EDID_DETAILED_TIMING_FLAG_DIGITAL_COMPOSITE(_x) \ +	GET_BITS((_x).flags, 4, 3) +#define EDID_DETAILED_TIMING_FLAG_POLARITY(_x) \ +	GET_BITS((_x).flags, 2, 1) +#define EDID_DETAILED_TIMING_FLAG_INTERLEAVED(_x) \ +	GET_BIT((_x).flags, 0) +} __attribute__ ((__packed__)); + +enum edid_monitor_descriptor_types { +	EDID_MONITOR_DESCRIPTOR_SERIAL = 0xff, +	EDID_MONITOR_DESCRIPTOR_ASCII = 0xfe, +	EDID_MONITOR_DESCRIPTOR_RANGE = 0xfd, +	EDID_MONITOR_DESCRIPTOR_NAME = 0xfc, +}; + +struct edid_monitor_descriptor { +	uint16_t zero_flag_1; +	unsigned char zero_flag_2; +	unsigned char type; +	unsigned char zero_flag_3; +	union { +		char string[13]; +		struct { +			unsigned char vertical_min; +			unsigned char vertical_max; +			unsigned char horizontal_min; +			unsigned char horizontal_max; +			unsigned char pixel_clock_max; +			unsigned char gtf_data[8]; +		} range_data; +	} data; +} __attribute__ ((__packed__)); + +struct edid1_info { +	unsigned char header[8]; +	unsigned char manufacturer_name[2]; +#define EDID1_INFO_MANUFACTURER_NAME_ZERO(_x) \ +	GET_BIT(((_x).manufacturer_name[0]), 7) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR1(_x) \ +	GET_BITS(((_x).manufacturer_name[0]), 6, 2) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR2(_x) \ +	((GET_BITS(((_x).manufacturer_name[0]), 1, 0) << 3) + \ +	 GET_BITS(((_x).manufacturer_name[1]), 7, 5)) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR3(_x) \ +	GET_BITS(((_x).manufacturer_name[1]), 4, 0) +	unsigned char product_code[2]; +#define EDID1_INFO_PRODUCT_CODE(_x) \ +	(((uint16_t)(_x).product_code[1] << 8) + (_x).product_code[0]) +	unsigned char serial_number[4]; +#define EDID1_INFO_SERIAL_NUMBER(_x) \ +	(((uint32_t)(_x).serial_number[3] << 24) + \ +	 ((_x).serial_number[2] << 16) + ((_x).serial_number[1] << 8) + \ +	 (_x).serial_number[0]) +	unsigned char week; +	unsigned char year; +	unsigned char version; +	unsigned char revision; +	unsigned char video_input_definition; +#define EDID1_INFO_VIDEO_INPUT_DIGITAL(_x) \ +	GET_BIT(((_x).video_input_definition), 7) +#define EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(_x) \ +	GET_BITS(((_x).video_input_definition), 6, 5) +#define EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(_x) \ +	GET_BIT(((_x).video_input_definition), 4) +#define EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(_x) \ +	GET_BIT(((_x).video_input_definition), 3) +#define EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(_x) \ +	GET_BIT(((_x).video_input_definition), 2) +#define EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(_x) \ +	GET_BIT(((_x).video_input_definition), 1) +#define EDID1_INFO_VIDEO_INPUT_SERRATION_V(_x) \ +	GET_BIT(((_x).video_input_definition), 0) +	unsigned char max_size_horizontal; +	unsigned char max_size_vertical; +	unsigned char gamma; +	unsigned char feature_support; +#define EDID1_INFO_FEATURE_STANDBY(_x) \ +	GET_BIT(((_x).feature_support), 7) +#define EDID1_INFO_FEATURE_SUSPEND(_x) \ +	GET_BIT(((_x).feature_support), 6) +#define EDID1_INFO_FEATURE_ACTIVE_OFF(_x) \ +	GET_BIT(((_x).feature_support), 5) +#define EDID1_INFO_FEATURE_DISPLAY_TYPE(_x) \ +	GET_BITS(((_x).feature_support), 4, 3) +#define EDID1_INFO_FEATURE_RGB(_x) \ +	GET_BIT(((_x).feature_support), 2) +#define EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(_x) \ +	GET_BIT(((_x).feature_support), 1) +#define EDID1_INFO_FEATURE_DEFAULT_GTF_SUPPORT(_x) \ +	GET_BIT(((_x).feature_support), 0) +	unsigned char color_characteristics[10]; +	unsigned char established_timings[3]; +#define EDID1_INFO_ESTABLISHED_TIMING_720X400_70(_x) \ +	GET_BIT(((_x).established_timings[0]), 7) +#define EDID1_INFO_ESTABLISHED_TIMING_720X400_88(_x) \ +	GET_BIT(((_x).established_timings[0]), 6) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_60(_x) \ +	GET_BIT(((_x).established_timings[0]), 5) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_67(_x) \ +	GET_BIT(((_x).established_timings[0]), 4) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_72(_x) \ +	GET_BIT(((_x).established_timings[0]), 3) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_75(_x) \ +	GET_BIT(((_x).established_timings[0]), 2) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_56(_x) \ +	GET_BIT(((_x).established_timings[0]), 1) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_60(_x) \ +	GET_BIT(((_x).established_timings[0]), 0) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_72(_x) \ +	GET_BIT(((_x).established_timings[1]), 7) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_75(_x) \ +	GET_BIT(((_x).established_timings[1]), 6) +#define EDID1_INFO_ESTABLISHED_TIMING_832X624_75(_x) \ +	GET_BIT(((_x).established_timings[1]), 5) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(_x) \ +	GET_BIT(((_x).established_timings[1]), 4) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(_x) \ +	GET_BIT(((_x).established_timings[1]), 3) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(_x) \ +	GET_BIT(((_x).established_timings[1]), 2) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(_x) \ +	GET_BIT(((_x).established_timings[1]), 1) +#define EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(_x) \ +	GET_BIT(((_x).established_timings[1]), 0) +#define EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(_x) \ +	GET_BIT(((_x).established_timings[2]), 7) +	struct { +		unsigned char xresolution; +		unsigned char aspect_vfreq; +	} __attribute__((__packed__)) standard_timings[8]; +#define EDID1_INFO_STANDARD_TIMING_XRESOLUTION(_x, _i) \ +	(((_x).standard_timings[_i]).xresolution) +#define EDID1_INFO_STANDARD_TIMING_ASPECT(_x, _i) \ +	GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 7, 6) +#define EDID1_INFO_STANDARD_TIMING_VFREQ(_x, _i) \ +	GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 5, 0) +	union { +		unsigned char timing[72]; +		struct edid_monitor_descriptor descriptor[4]; +	} monitor_details; +	unsigned char extension_flag; +	unsigned char checksum; +} __attribute__ ((__packed__)); + +/** + * Print the EDID info. + * + * @param edid_info	The EDID info to be printed + */ +void edid_print_info(struct edid1_info *edid_info); + +/** + * Check the EDID info. + * + * @param info  The EDID info to be checked + * @return 0 on valid, or -1 on invalid + */ +int edid_check_info(struct edid1_info *info); + +/** + * Get the horizontal and vertical rate ranges of the monitor. + * + * @param edid	The EDID info + * @param hmin	Returns the minimum horizontal rate + * @param hmax	Returns the maxium horizontal rate + * @param vmin	Returns the minimum vertical rate + * @param vmax	Returns the maxium vertical rate + * @return 0 on success, or -1 on error + */ +int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, +		    unsigned int *hmax, unsigned int *vmin, +		    unsigned int *vmax); + +#endif /* __EDID_H_ */ diff --git a/include/env_attr.h b/include/env_attr.h new file mode 100644 index 000000000..6ef114f5d --- /dev/null +++ b/include/env_attr.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 __ENV_ATTR_H__ +#define __ENV_ATTR_H__ + +#define ENV_ATTR_LIST_DELIM	',' +#define ENV_ATTR_SEP		':' + +/* + * env_attr_walk takes as input an "attr_list" that takes the form: + *	attributes = [^,:\s]* + *	entry = name[:attributes] + *	list = entry[,list] + * It will call the "callback" function with the "name" and attribute as "value" + * The callback may return a non-0 to abort the list walk. + * This return value will be passed through to the caller. + * 0 is returned on success. + */ +extern int env_attr_walk(const char *attr_list, +	int (*callback)(const char *name, const char *value)); + +/* + * env_attr_lookup takes as input an "attr_list" with the same form as above. + * It also takes as input a "name" to look for. + * If the name is found in the list, it's value is copied into "attributes". + * There is no protection on attributes being too small for the value. + * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if + * "attr_list" is NULL. + * Returns 0 on success. + */ +extern int env_attr_lookup(const char *attr_list, const char *name, +	char *attributes); + +#endif /* __ENV_ATTR_H__ */ diff --git a/include/env_callback.h b/include/env_callback.h new file mode 100644 index 000000000..47fdc6fa9 --- /dev/null +++ b/include/env_callback.h @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 __ENV_CALLBACK_H__ +#define __ENV_CALLBACK_H__ + +#include <env_flags.h> +#include <linker_lists.h> +#include <search.h> + +#define ENV_CALLBACK_VAR ".callbacks" + +/* Board configs can define additional static callback bindings */ +#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC +#define CONFIG_ENV_CALLBACK_LIST_STATIC +#endif + +#ifdef CONFIG_SILENT_CONSOLE +#define SILENT_CALLBACK "silent:silent," +#else +#define SILENT_CALLBACK +#endif + +/* + * This list of callback bindings is static, but may be overridden by defining + * a new association in the ".callbacks" environment variable. + */ +#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ +	ENV_FLAGS_VAR ":flags," \ +	"baudrate:baudrate," \ +	"bootfile:bootfile," \ +	"loadaddr:loadaddr," \ +	SILENT_CALLBACK \ +	"stdin:console,stdout:console,stderr:console," \ +	CONFIG_ENV_CALLBACK_LIST_STATIC + +struct env_clbk_tbl { +	const char *name;		/* Callback name */ +	int (*callback)(const char *name, const char *value, enum env_op op, +		int flags); +}; + +struct env_clbk_tbl *find_env_callback(const char *); +void env_callback_init(ENTRY *var_entry); + +/* + * Define a callback that can be associated with variables. + * when associated through the ".callbacks" environment variable, the callback + * will be executed any time the variable is inserted, overwritten, or deleted. + */ +#define U_BOOT_ENV_CALLBACK(name, callback) \ +	ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \ +	{#name, callback} + +#endif /* __ENV_CALLBACK_H__ */ diff --git a/include/env_default.h b/include/env_default.h index a1db73a2c..39c5b7c6a 100644 --- a/include/env_default.h +++ b/include/env_default.h @@ -24,6 +24,8 @@   * MA 02111-1307 USA   */ +#include <env_callback.h> +  #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED  env_t environment __PPCENV__ = {  	ENV_CRC,	/* CRC Sum */ @@ -36,6 +38,12 @@ static char default_environment[] = {  #else  const uchar default_environment[] = {  #endif +#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT +	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" +#endif +#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT +	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" +#endif  #ifdef	CONFIG_BOOTARGS  	"bootargs="	CONFIG_BOOTARGS			"\0"  #endif diff --git a/include/env_flags.h b/include/env_flags.h new file mode 100644 index 000000000..d1aa1440f --- /dev/null +++ b/include/env_flags.h @@ -0,0 +1,172 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.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 __ENV_FLAGS_H__ +#define __ENV_FLAGS_H__ + +enum env_flags_vartype { +	env_flags_vartype_string, +	env_flags_vartype_decimal, +	env_flags_vartype_hex, +	env_flags_vartype_bool, +#ifdef CONFIG_CMD_NET +	env_flags_vartype_ipaddr, +	env_flags_vartype_macaddr, +#endif +	env_flags_vartype_end +}; + +enum env_flags_varaccess { +	env_flags_varaccess_any, +	env_flags_varaccess_readonly, +	env_flags_varaccess_writeonce, +	env_flags_varaccess_changedefault, +	env_flags_varaccess_end +}; + +#define ENV_FLAGS_VAR ".flags" +#define ENV_FLAGS_ATTR_MAX_LEN 2 +#define ENV_FLAGS_VARTYPE_LOC 0 +#define ENV_FLAGS_VARACCESS_LOC 1 + +#ifndef CONFIG_ENV_FLAGS_LIST_STATIC +#define CONFIG_ENV_FLAGS_LIST_STATIC "" +#endif + +#ifdef CONFIG_CMD_NET +#ifdef CONFIG_ENV_OVERWRITE +#define ETHADDR_FLAGS "ethaddr:ma," +#else +#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE +#define ETHADDR_FLAGS "ethaddr:mc," +#else +#define ETHADDR_FLAGS "ethaddr:mo," +#endif +#endif +#else +#define ETHADDR_FLAGS "" +#endif + +#ifndef CONFIG_ENV_OVERWRITE +#define SERIAL_FLAGS "serial#:so," +#else +#define SERIAL_FLAGS "" +#endif + +#define ENV_FLAGS_LIST_STATIC \ +	ETHADDR_FLAGS \ +	SERIAL_FLAGS \ +	CONFIG_ENV_FLAGS_LIST_STATIC + +#ifdef CONFIG_CMD_ENV_FLAGS +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void); +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void); +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type); +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access); +#endif + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags); +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags); +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags); + +#ifdef USE_HOSTCC +/* + * Look up the type of a variable directly from the .flags var. + */ +enum env_flags_vartype env_flags_get_type(const char *name); +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_access(const char *name); +/* + * Validate the newval for its type to conform with the requirements defined by + * its flags (directly looked at the .flags var). + */ +int env_flags_validate_type(const char *name, const char *newval); +/* + * Validate the newval for its access to conform with the requirements defined + * by its flags (directly looked at the .flags var). + */ +int env_flags_validate_access(const char *name, int check_mask); +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask); +/* + * Validate the parameters passed to "env set" for type compliance + */ +int env_flags_validate_env_set_params(int argc, char * const argv[]); + +#else /* !USE_HOSTCC */ + +#include <search.h> + +/* + * When adding a variable to the environment, initialize the flags for that + * variable. + */ +void env_flags_init(ENTRY *var_entry); + +/* + * Validate the newval for to conform with the requirements defined by its flags + */ +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, +	int flag); + +#endif /* USE_HOSTCC */ + +/* + * These are the binary flags used in the environment entry->flags variable to + * decribe properties of veriables in the table + */ +#define ENV_FLAGS_VARTYPE_BIN_MASK			0x00000007 +/* The actual variable type values use the enum value (within the mask) */ +#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008 +#define ENV_FLAGS_VARACCESS_PREVENT_CREATE		0x00000010 +#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR		0x00000020 +#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR	0x00000040 +#define ENV_FLAGS_VARACCESS_BIN_MASK			0x00000078 + +#endif /* __ENV_FLAGS_H__ */ diff --git a/include/environment.h b/include/environment.h index e8ab7033b..e64b43d2d 100644 --- a/include/environment.h +++ b/include/environment.h @@ -164,6 +164,9 @@ extern void env_reloc(void);  #ifndef DO_DEPS_ONLY +#include <env_attr.h> +#include <env_callback.h> +#include <env_flags.h>  #include <search.h>  extern struct hsearch_data env_htab; @@ -178,6 +181,9 @@ unsigned char env_get_char_memory(int index);  /* Function that updates CRC of the enironment */  void env_crc_update(void); +/* Look up the variable from the default environment */ +char *getenv_default(const char *name); +  /* [re]set to the default environment */  void set_default_env(const char *s); @@ -187,15 +193,6 @@ int set_default_vars(int nvars, char * const vars[]);  /* Import from binary representation into hash table */  int env_import(const char *buf, int check); -/* - * Check if variable "name" can be changed from oldval to newval, - * and if so, apply the changes (e.g. baudrate). - * When (flag & H_FORCE) is set, it does not print out any error - * message and forces overwriting of write-once variables. - */ -int env_check_apply(const char *name, const char *oldval, -			const char *newval, int flag); -  #endif /* DO_DEPS_ONLY */  #endif /* _ENVIRONMENT_H_ */ diff --git a/include/exports.h b/include/exports.h index 63aa4b264..6cf31aa5e 100644 --- a/include/exports.h +++ b/include/exports.h @@ -23,7 +23,7 @@ char *getenv (const char *name);  int setenv (const char *varname, const char *varvalue);  long simple_strtol(const char *cp,char **endp,unsigned int base);  int strcmp(const char * cs,const char * ct); -int ustrtoul(const char *cp, char **endp, unsigned int base); +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base);  #if defined(CONFIG_CMD_I2C)  int i2c_write (uchar, uint, int , uchar* , int);  int i2c_read (uchar, uint, int , uchar* , int); diff --git a/include/fdtdec.h b/include/fdtdec.h index 5164ce24e..70d0e979d 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -68,6 +68,8 @@ enum fdt_compat_id {  	COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */  	COMPAT_NVIDIA_TEGRA20_KBC,	/* Tegra20 Keyboard */  	COMPAT_NVIDIA_TEGRA20_NAND,	/* Tegra2 NAND controller */ +	COMPAT_NVIDIA_TEGRA20_PWM,	/* Tegra 2 PWM controller */ +	COMPAT_NVIDIA_TEGRA20_DC,	/* Tegra 2 Display controller */  	COMPAT_COUNT,  }; diff --git a/include/hash.h b/include/hash.h new file mode 100644 index 000000000..34ba558bd --- /dev/null +++ b/include/hash.h @@ -0,0 +1,69 @@ +/* + * 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 _HASH_H +#define _HASH_H + +#ifdef CONFIG_SHA1SUM_VERIFY +#define CONFIG_HASH_VERIFY +#endif + +struct hash_algo { +	const char *name;			/* Name of algorithm */ +	int digest_size;			/* Length of digest */ +	/** +	 * hash_func_ws: Generic hashing function +	 * +	 * This is the generic prototype for a hashing function. We only +	 * have the watchdog version at present. +	 * +	 * @input:	Input buffer +	 * @ilen:	Input buffer length +	 * @output:	Checksum result (length depends on algorithm) +	 * @chunk_sz:	Trigger watchdog after processing this many bytes +	 */ +	void (*hash_func_ws)(const unsigned char *input, unsigned int ilen, +		unsigned char *output, unsigned int chunk_sz); +	int chunk_size;				/* Watchdog chunk size */ +}; + +/* + * Maximum digest size for all algorithms we support. Having this value + * avoids a malloc() or C99 local declaration in common/cmd_hash.c. + */ +#define HASH_MAX_DIGEST_SIZE	32 + +/** + * hash_command: Process a hash command for a particular algorithm + * + * This common function is used to implement specific hash commands. + * + * @algo_name:		Hash algorithm being used + * @verify:		Non-zero to enable verify mode + * @cmdtp:		Pointer to command table entry + * @flag:		Some flags normally 0 (see CMD_FLAG_.. above) + * @argc:		Number of arguments (arg 0 must be the command text) + * @argv:		Arguments + */ +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, +		 int argc, char * const argv[]); + +#endif diff --git a/include/i2s.h b/include/i2s.h new file mode 100644 index 000000000..75ae75cf2 --- /dev/null +++ b/include/i2s.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar <rcsekar@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 + */ + +#ifndef __I2S_H__ +#define __I2S_H__ + +/* + * DAI hardware audio formats. + * + * Describes the physical PCM data formating and clocking. Add new formats + * to the end. + */ +#define SND_SOC_DAIFMT_I2S		1 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J		2 /* Right Justified mode */ +#define SND_SOC_DAIFMT_LEFT_J		3 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A		4 /* L data MSB after FRM LRC */ +#define SND_SOC_DAIFMT_DSP_B		5 /* L data MSB during FRM LRC */ +#define SND_SOC_DAIFMT_AC97		6 /* AC97 */ +#define SND_SOC_DAIFMT_PDM		7 /* Pulse density modulation */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAIFMT_MSB		SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB		SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI hardware signal inversions. + * + * Specifies whether the DAI can also support inverted clocks for the specified + * format. + */ +#define SND_SOC_DAIFMT_NB_NF	(1 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF	(2 << 8) /* normal BCLK + inv FRM */ +#define SND_SOC_DAIFMT_IB_NF	(3 << 8) /* invert BCLK + nor FRM */ +#define SND_SOC_DAIFMT_IB_IF	(4 << 8) /* invert BCLK + FRM */ + +/* + * DAI hardware clock masters. + * + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and FRM master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM	(1 << 12) /* codec clk & FRM master */ +#define SND_SOC_DAIFMT_CBS_CFM	(2 << 12) /* codec clk slave & FRM master */ +#define SND_SOC_DAIFMT_CBM_CFS	(3 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS	(4 << 12) /* codec clk & FRM slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK	0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK	0x00f0 +#define SND_SOC_DAIFMT_INV_MASK		0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK	0xf000 + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN		0 +#define SND_SOC_CLOCK_OUT		1 + +/* I2S Tx Control */ +#define I2S_TX_ON	1 +#define I2S_TX_OFF	0 + +#define FIFO_LENGTH	64 + +/* I2s Registers */ +struct i2s_reg { +	unsigned int con;	/* base + 0 , Control register */ +	unsigned int mod;	/* Mode register */ +	unsigned int fic;	/* FIFO control register */ +	unsigned int psr;	/* Reserved */ +	unsigned int txd;	/* Transmit data register */ +	unsigned int rxd;	/* Receive Data Register */ +}; + +/* This structure stores the i2s related information */ +struct i2stx_info { +	unsigned int rfs;		/* LR clock frame size */ +	unsigned int bfs;		/* Bit slock frame size */ +	unsigned int audio_pll_clk;	/* Audio pll frequency in Hz */ +	unsigned int samplingrate;	/* sampling rate */ +	unsigned int bitspersample;	/* bits per sample */ +	unsigned int channels;		/* audio channels */ +	unsigned int base_address;	/* I2S Register Base */ +}; + +/* + * Sends the given data through i2s tx + * + * @param pi2s_tx	pointer of i2s transmitter parameter structure. + * @param data		address of the data buffer + * @param data_size	array size of the int buffer (total size / size of int) + * + * @return		int value 0 for success, -1 in case of error + */ +int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data, +				unsigned long data_size); + +/* + * Initialise i2s transmiter + * + * @param pi2s_tx	pointer of i2s transmitter parameter structure. + * + * @return		int value 0 for success, -1 in case of error + */ +int i2s_tx_init(struct i2stx_info *pi2s_tx); + +#endif /* __I2S_H__ */ diff --git a/include/image.h b/include/image.h index f54d98330..b958b18a4 100644 --- a/include/image.h +++ b/include/image.h @@ -460,7 +460,6 @@ static inline void image_set_name(image_header_t *hdr, const char *name)  int image_check_hcrc(const image_header_t *hdr);  int image_check_dcrc(const image_header_t *hdr);  #ifndef USE_HOSTCC -int getenv_yesno(char *var);  ulong getenv_bootm_low(void);  phys_size_t getenv_bootm_size(void);  phys_size_t getenv_bootm_mapsize(void); diff --git a/include/lcd.h b/include/lcd.h index 2517d39d4..c24164a9d 100644 --- a/include/lcd.h +++ b/include/lcd.h @@ -57,6 +57,14 @@ extern void lcd_initcolregs (void);  extern struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp);  extern int bmp_display(ulong addr, int x, int y); +/** + * Set whether we need to flush the dcache when changing the LCD image. This + * defaults to off. + * + * @param flush		non-zero to flush cache after update, 0 to skip + */ +void lcd_set_flush_dcache(int flush); +  #if defined CONFIG_MPC823  /*   * LCD controller stucture for MPC823 CPU @@ -333,6 +341,9 @@ void lcd_position_cursor(unsigned col, unsigned row);  /* Allow boards to customize the information displayed */  void lcd_show_board_info(void); +/* Return the size of the LCD frame buffer, and the line length */ +int lcd_get_size(int *line_length); +  /************************************************************************/  /* ** BITMAP DISPLAY SUPPORT						*/  /************************************************************************/ diff --git a/include/ld9040.h b/include/ld9040.h new file mode 100644 index 000000000..fe99390e5 --- /dev/null +++ b/include/ld9040.h @@ -0,0 +1,32 @@ +/* + * ld9040 AMOLED LCD panel driver. + * + * Copyright (C) 2012 Samsung Electronics + * Donghwa Lee <dh09.lee@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 + */ + +#ifndef __LD9040_H_ +#define __LD9040_H_ + +void ld9040_cfg_ldo(void); +void ld9040_enable_ldo(unsigned int onoff); + +#endif /* __LD9040_H_ */ diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h new file mode 100644 index 000000000..192b4c9be --- /dev/null +++ b/include/linux/linux_string.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_LINUX_STRING_H_ +#define _LINUX_LINUX_STRING_H_ + +extern char * skip_spaces(const char *); + +extern char *strim(char *); + +#endif diff --git a/include/linux/string.h b/include/linux/string.h index 9a8cbc24c..e9b134d14 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -38,8 +38,11 @@ extern int strcmp(const char *,const char *);  #ifndef __HAVE_ARCH_STRNCMP  extern int strncmp(const char *,const char *,__kernel_size_t);  #endif -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ -extern int strnicmp(const char *, const char *, __kernel_size_t); +#ifndef __HAVE_ARCH_STRCASECMP +int strcasecmp(const char *s1, const char *s2); +#endif +#ifndef __HAVE_ARCH_STRNCASECMP +extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len);  #endif  #ifndef __HAVE_ARCH_STRCHR  extern char * strchr(const char *,int); @@ -47,10 +50,7 @@ extern char * strchr(const char *,int);  #ifndef __HAVE_ARCH_STRRCHR  extern char * strrchr(const char *,int);  #endif -extern char * skip_spaces(const char *); - -extern char *strim(char *); - +#include <linux/linux_string.h>  #ifndef __HAVE_ARCH_STRSTR  extern char * strstr(const char *,const char *);  #endif diff --git a/include/part.h b/include/part.h index 27ea283f1..c58a734ad 100644 --- a/include/part.h +++ b/include/part.h @@ -176,10 +176,62 @@ int   test_part_amiga (block_dev_desc_t *dev_desc);  #endif  #ifdef CONFIG_EFI_PARTITION +#include <part_efi.h>  /* disk/part_efi.c */  int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);  void print_part_efi (block_dev_desc_t *dev_desc);  int   test_part_efi (block_dev_desc_t *dev_desc); + +/** + * write_gpt_table() - Write the GUID Partition Table to disk + * + * @param dev_desc - block device descriptor + * @param gpt_h - pointer to GPT header representation + * @param gpt_e - pointer to GPT partition table entries + * + * @return - zero on success, otherwise error + */ +int write_gpt_table(block_dev_desc_t *dev_desc, +		  gpt_header *gpt_h, gpt_entry *gpt_e); + +/** + * gpt_fill_pte(): Fill the GPT partition table entry + * + * @param gpt_h - GPT header representation + * @param gpt_e - GPT partition table entries + * @param partitions - list of partitions + * @param parts - number of partitions + * + * @return zero on success + */ +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, +		disk_partition_t *partitions, int parts); + +/** + * gpt_fill_header(): Fill the GPT header + * + * @param dev_desc - block device descriptor + * @param gpt_h - GPT header representation + * @param str_guid - disk guid string representation + * @param parts_count - number of partitions + * + * @return - error on str_guid conversion error + */ +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, +		char *str_guid, int parts_count); + +/** + * gpt_restore(): Restore GPT partition table + * + * @param dev_desc - block device descriptor + * @param str_disk_guid - disk GUID + * @param partitions - list of partitions + * @param parts - number of partitions + * + * @return zero on success + */ +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, +		disk_partition_t *partitions, const int parts_count);  #endif  #endif /* _PART_H */ diff --git a/disk/part_efi.h b/include/part_efi.h index 4e28d1dcb..6de0a3258 100644 --- a/disk/part_efi.h +++ b/include/part_efi.h @@ -29,6 +29,8 @@   * http://developer.intel.com/technology/efi/efi.htm  */ +#include <linux/compiler.h> +  #ifndef _DISK_PART_EFI_H  #define _DISK_PART_EFI_H @@ -41,6 +43,8 @@  #define GPT_HEADER_REVISION_V1 0x00010000  #define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL  #define GPT_ENTRY_NAME "gpt" +#define GPT_ENTRY_NUMBERS		128 +#define GPT_ENTRY_SIZE			128  #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \  	((efi_guid_t) \ @@ -72,73 +76,72 @@  		0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)  /* linux/include/efi.h */ -typedef unsigned short efi_char16_t; +typedef u16 efi_char16_t;  typedef struct { -	unsigned char b[16]; +	u8 b[16];  } efi_guid_t;  /* based on linux/include/genhd.h */  struct partition { -	unsigned char boot_ind;		/* 0x80 - active */ -	unsigned char head;		/* starting head */ -	unsigned char sector;		/* starting sector */ -	unsigned char cyl;		/* starting cylinder */ -	unsigned char sys_ind;		/* What partition type */ -	unsigned char end_head;		/* end head */ -	unsigned char end_sector;	/* end sector */ -	unsigned char end_cyl;		/* end cylinder */ -	unsigned char start_sect[4];	/* starting sector counting from 0 */ -	unsigned char nr_sects[4];	/* nr of sectors in partition */ -} __attribute__ ((packed)); +	u8 boot_ind;		/* 0x80 - active */ +	u8 head;		/* starting head */ +	u8 sector;		/* starting sector */ +	u8 cyl;			/* starting cylinder */ +	u8 sys_ind;		/* What partition type */ +	u8 end_head;		/* end head */ +	u8 end_sector;		/* end sector */ +	u8 end_cyl;		/* end cylinder */ +	__le32 start_sect;	/* starting sector counting from 0 */ +	__le32 nr_sects;	/* nr of sectors in partition */ +} __packed;  /* based on linux/fs/partitions/efi.h */  typedef struct _gpt_header { -	unsigned char signature[8]; -	unsigned char revision[4]; -	unsigned char header_size[4]; -	unsigned char header_crc32[4]; -	unsigned char reserved1[4]; -	unsigned char my_lba[8]; -	unsigned char alternate_lba[8]; -	unsigned char first_usable_lba[8]; -	unsigned char last_usable_lba[8]; +	__le64 signature; +	__le32 revision; +	__le32 header_size; +	__le32 header_crc32; +	__le32 reserved1; +	__le64 my_lba; +	__le64 alternate_lba; +	__le64 first_usable_lba; +	__le64 last_usable_lba;  	efi_guid_t disk_guid; -	unsigned char partition_entry_lba[8]; -	unsigned char num_partition_entries[4]; -	unsigned char sizeof_partition_entry[4]; -	unsigned char partition_entry_array_crc32[4]; -	unsigned char reserved2[GPT_BLOCK_SIZE - 92]; -} __attribute__ ((packed)) gpt_header; +	__le64 partition_entry_lba; +	__le32 num_partition_entries; +	__le32 sizeof_partition_entry; +	__le32 partition_entry_array_crc32; +	u8 reserved2[GPT_BLOCK_SIZE - 92]; +} __packed gpt_header;  typedef union _gpt_entry_attributes {  	struct { -		unsigned long long required_to_function:1; -		unsigned long long no_block_io_protocol:1; -		unsigned long long legacy_bios_bootable:1; -		unsigned long long reserved:45; -		unsigned long long type_guid_specific:16; +		u64 required_to_function:1; +		u64 no_block_io_protocol:1; +		u64 legacy_bios_bootable:1; +		u64 reserved:45; +		u64 type_guid_specific:16;  	} fields;  	unsigned long long raw; -} __attribute__ ((packed)) gpt_entry_attributes; +} __packed gpt_entry_attributes;  #define PARTNAME_SZ	(72 / sizeof(efi_char16_t))  typedef struct _gpt_entry {  	efi_guid_t partition_type_guid;  	efi_guid_t unique_partition_guid; -	unsigned char starting_lba[8]; -	unsigned char ending_lba[8]; +	__le64 starting_lba; +	__le64 ending_lba;  	gpt_entry_attributes attributes;  	efi_char16_t partition_name[PARTNAME_SZ]; -} -__attribute__ ((packed)) gpt_entry; +} __packed gpt_entry;  typedef struct _legacy_mbr { -	unsigned char boot_code[440]; -	unsigned char unique_mbr_signature[4]; -	unsigned char unknown[2]; +	u8 boot_code[440]; +	__le32 unique_mbr_signature; +	__le16 unknown;  	struct partition partition_record[4]; -	unsigned char signature[2]; -} __attribute__ ((packed)) legacy_mbr; +	__le16 signature; +} __packed legacy_mbr;  #endif	/* _DISK_PART_EFI_H */ diff --git a/include/power/max77686_pmic.h b/include/power/max77686_pmic.h new file mode 100644 index 000000000..d949aced0 --- /dev/null +++ b/include/power/max77686_pmic.h @@ -0,0 +1,158 @@ +/* + *  Copyright (C) 2012 Samsung Electronics + *  Rajeshwari Shinde <rajeshwari.s@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 + */ + +#ifndef __MAX77686_H_ +#define __MAX77686_H_ + +enum { +	MAX77686_REG_PMIC_ID		= 0x0, +	MAX77686_REG_PMIC_INTSRC, +	MAX77686_REG_PMIC_INT1, +	MAX77686_REG_PMIC_INT2, +	MAX77686_REG_PMIC_INT1MSK, +	MAX77686_REG_PMIC_INT2MSK, + +	MAX77686_REG_PMIC_STATUS1, +	MAX77686_REG_PMIC_STATUS2, + +	MAX77686_REG_PMIC_PWRON, +	MAX77686_REG_PMIC_ONOFFDELAY, +	MAX77686_REG_PMIC_MRSTB, + +	MAX77686_REG_PMIC_BUCK1CRTL	= 0x10, +	MAX77686_REG_PMIC_BUCK1OUT, +	MAX77686_REG_PMIC_BUCK2CTRL1, +	MAX77686_REG_PMIC_BUCK234FREQ, +	MAX77686_REG_PMIC_BUCK2DVS1, +	MAX77686_REG_PMIC_BUCK2DVS2, +	MAX77686_REG_PMIC_BUCK2DVS3, +	MAX77686_REG_PMIC_BUCK2DVS4, +	MAX77686_REG_PMIC_BUCK2DVS5, +	MAX77686_REG_PMIC_BUCK2DVS6, +	MAX77686_REG_PMIC_BUCK2DVS7, +	MAX77686_REG_PMIC_BUCK2DVS8, +	MAX77686_REG_PMIC_BUCK3CTRL, +	MAX77686_REG_PMIC_BUCK3DVS1, +	MAX77686_REG_PMIC_BUCK3DVS2, +	MAX77686_REG_PMIC_BUCK3DVS3, +	MAX77686_REG_PMIC_BUCK3DVS4, +	MAX77686_REG_PMIC_BUCK3DVS5, +	MAX77686_REG_PMIC_BUCK3DVS6, +	MAX77686_REG_PMIC_BUCK3DVS7, +	MAX77686_REG_PMIC_BUCK3DVS8, +	MAX77686_REG_PMIC_BUCK4CTRL1, +	MAX77686_REG_PMIC_BUCK4DVS1	= 0x28, +	MAX77686_REG_PMIC_BUCK4DVS2, +	MAX77686_REG_PMIC_BUCK4DVS3, +	MAX77686_REG_PMIC_BUCK4DVS4, +	MAX77686_REG_PMIC_BUCK4DVS5, +	MAX77686_REG_PMIC_BUCK4DVS6, +	MAX77686_REG_PMIC_BUCK4DVS7, +	MAX77686_REG_PMIC_BUCK4DVS8, +	MAX77686_REG_PMIC_BUCK5CTRL, +	MAX77686_REG_PMIC_BUCK5OUT, +	MAX77686_REG_PMIC_BUCK6CRTL, +	MAX77686_REG_PMIC_BUCK6OUT, +	MAX77686_REG_PMIC_BUCK7CRTL, +	MAX77686_REG_PMIC_BUCK7OUT, +	MAX77686_REG_PMIC_BUCK8CRTL, +	MAX77686_REG_PMIC_BUCK8OUT, +	MAX77686_REG_PMIC_BUCK9CRTL, +	MAX77686_REG_PMIC_BUCK9OUT, + +	MAX77686_REG_PMIC_LDO1CTRL1	= 0x40, +	MAX77686_REG_PMIC_LDO2CTRL1, +	MAX77686_REG_PMIC_LDO3CTRL1, +	MAX77686_REG_PMIC_LDO4CTRL1, +	MAX77686_REG_PMIC_LDO5CTRL1, +	MAX77686_REG_PMIC_LDO6CTRL1, +	MAX77686_REG_PMIC_LDO7CTRL1, +	MAX77686_REG_PMIC_LDO8CTRL1, +	MAX77686_REG_PMIC_LDO9CTRL1, +	MAX77686_REG_PMIC_LDO10CTRL1, +	MAX77686_REG_PMIC_LDO11CTRL1, +	MAX77686_REG_PMIC_LDO12CTRL1, +	MAX77686_REG_PMIC_LDO13CTRL1, +	MAX77686_REG_PMIC_LDO14CTRL1, +	MAX77686_REG_PMIC_LDO15CTRL1, +	MAX77686_REG_PMIC_LDO16CTRL1, +	MAX77686_REG_PMIC_LDO17CTRL1, +	MAX77686_REG_PMIC_LDO18CTRL1, +	MAX77686_REG_PMIC_LDO19CTRL1, +	MAX77686_REG_PMIC_LDO20CTRL1, +	MAX77686_REG_PMIC_LDO21CTRL1, +	MAX77686_REG_PMIC_LDO22CTRL1, +	MAX77686_REG_PMIC_LDO23CTRL1, +	MAX77686_REG_PMIC_LDO24CTRL1, +	MAX77686_REG_PMIC_LDO25CTRL1, +	MAX77686_REG_PMIC_LDO26CTRL1, +	MAX77686_REG_PMIC_LDO1CTRL2, +	MAX77686_REG_PMIC_LDO2CTRL2, +	MAX77686_REG_PMIC_LDO3CTRL2, +	MAX77686_REG_PMIC_LDO4CTRL2, +	MAX77686_REG_PMIC_LDO5CTRL2, +	MAX77686_REG_PMIC_LDO6CTRL2, +	MAX77686_REG_PMIC_LDO7CTRL2, +	MAX77686_REG_PMIC_LDO8CTRL2, +	MAX77686_REG_PMIC_LDO9CTRL2, +	MAX77686_REG_PMIC_LDO10CTRL2, +	MAX77686_REG_PMIC_LDO11CTRL2, +	MAX77686_REG_PMIC_LDO12CTRL2, +	MAX77686_REG_PMIC_LDO13CTRL2, +	MAX77686_REG_PMIC_LDO14CTRL2, +	MAX77686_REG_PMIC_LDO15CTRL2, +	MAX77686_REG_PMIC_LDO16CTRL2, +	MAX77686_REG_PMIC_LDO17CTRL2, +	MAX77686_REG_PMIC_LDO18CTRL2, +	MAX77686_REG_PMIC_LDO19CTRL2, +	MAX77686_REG_PMIC_LDO20CTRL2, +	MAX77686_REG_PMIC_LDO21CTRL2, +	MAX77686_REG_PMIC_LDO22CTRL2, +	MAX77686_REG_PMIC_LDO23CTRL2, +	MAX77686_REG_PMIC_LDO24CTRL2, +	MAX77686_REG_PMIC_LDO25CTRL2, +	MAX77686_REG_PMIC_LDO26CTRL2, + +	MAX77686_REG_PMIC_BBAT		= 0x7e, +	MAX77686_REG_PMIC_32KHZ, + +	PMIC_NUM_OF_REGS, +}; + +/* I2C device address for pmic max77686 */ +#define MAX77686_I2C_ADDR (0x12 >> 1) + +enum { +	REG_DISABLE = 0, +	REG_ENABLE +}; + +enum { +	LDO_OFF = 0, +	LDO_ON, + +	DIS_LDO = (0x00 << 6), +	EN_LDO = (0x3 << 6), +}; + +#endif /* __MAX77686_PMIC_H_ */ diff --git a/include/power/max8998_pmic.h b/include/power/max8998_pmic.h index ca21f882c..0e559f986 100644 --- a/include/power/max8998_pmic.h +++ b/include/power/max8998_pmic.h @@ -76,7 +76,9 @@ enum {  #define MAX8998_LDO3		(1 << 2)  #define MAX8998_LDO4		(1 << 1) +#define MAX8998_LDO7		(1 << 6)  #define MAX8998_LDO8		(1 << 5) +#define MAX8998_LDO17		(1 << 4)  #define MAX8998_SAFEOUT1	(1 << 4)  #define MAX8998_I2C_ADDR        (0xCC >> 1) diff --git a/include/search.h b/include/search.h index 93e1cbc6d..13d3be629 100644 --- a/include/search.h +++ b/include/search.h @@ -32,6 +32,12 @@  #define __set_errno(val) do { errno = val; } while (0) +enum env_op { +	env_op_create, +	env_op_delete, +	env_op_overwrite, +}; +  /* Action which shall be performed in the call the hsearch.  */  typedef enum {  	FIND, @@ -41,6 +47,9 @@ typedef enum {  typedef struct entry {  	const char *key;  	char *data; +	int (*callback)(const char *name, const char *value, enum env_op op, +		int flags); +	int flags;  } ENTRY;  /* Opaque type for internal use.  */ @@ -59,21 +68,20 @@ struct hsearch_data {  	unsigned int filled;  /*   * Callback function which will check whether the given change for variable - * "name" from "oldval" to "newval" may be applied or not, and possibly apply - * such change. + * "item" to "newval" may be applied or not, and possibly apply such change.   * When (flag & H_FORCE) is set, it shall not print out any error message and   * shall force overwriting of write-once variables.  .* Must return 0 for approval, 1 for denial.   */ -	int (*apply)(const char *name, const char *oldval, -			const char *newval, int flag); +	int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op, +		int flag);  };  /* Create a new hashing table which will at most contain NEL elements.  */  extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);  /* Destroy current internal hashing table.  */ -extern void hdestroy_r(struct hsearch_data *__htab, int do_apply); +extern void hdestroy_r(struct hsearch_data *__htab);  /*   * Search for entry matching ITEM.key in internal hash table.  If @@ -82,7 +90,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);   * ITEM.data.   * */  extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval, -		     struct hsearch_data *__htab); +		     struct hsearch_data *__htab, int __flag);  /*   * Search for an entry matching `MATCH'.  Otherwise, Same semantics @@ -99,10 +107,10 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval,  /* Search and delete entry matching ITEM.key in internal hash table. */  extern int hdelete_r(const char *__key, struct hsearch_data *__htab, -			int do_apply); +		     int __flag);  extern ssize_t hexport_r(struct hsearch_data *__htab, -		     const char __sep, char **__resp, size_t __size, +		     const char __sep, int __flag, char **__resp, size_t __size,  		     int argc, char * const argv[]);  /* @@ -113,10 +121,15 @@ extern ssize_t hexport_r(struct hsearch_data *__htab,   */  extern int himport_r(struct hsearch_data *__htab,  		     const char *__env, size_t __size, const char __sep, -		     int __flag, int nvars, char * const vars[], int do_apply); +		     int __flag, int nvars, char * const vars[]); + +/* Walk the whole table calling the callback on each element */ +extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *)); -/* Flags for himport_r() */ -#define	H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */ -#define	H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */ +/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */ +#define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */ +#define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */ +#define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */ +#define H_HIDE_DOT	(1 << 3) /* don't print env vars that begin with '.' */  #endif /* search.h */ diff --git a/include/sha1.h b/include/sha1.h index 734d1fb15..da09dab97 100644 --- a/include/sha1.h +++ b/include/sha1.h @@ -59,7 +59,8 @@ void sha1_starts( sha1_context *ctx );   * \param input    buffer holding the  data   * \param ilen	   length of the input data   */ -void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ); +void sha1_update(sha1_context *ctx, const unsigned char *input, +		 unsigned int ilen);  /**   * \brief	   SHA-1 final digest @@ -76,8 +77,8 @@ void sha1_finish( sha1_context *ctx, unsigned char output[20] );   * \param ilen	   length of the input data   * \param output   SHA-1 checksum result   */ -void sha1_csum( unsigned char *input, int ilen, -		unsigned char output[20] ); +void sha1_csum(const unsigned char *input, unsigned int ilen, +		unsigned char *output);  /**   * \brief	   Output = SHA-1( input buffer ), with watchdog triggering @@ -87,17 +88,8 @@ void sha1_csum( unsigned char *input, int ilen,   * \param output   SHA-1 checksum result   * \param chunk_sz watchdog triggering period (in bytes of input processed)   */ -void sha1_csum_wd (unsigned char *input, int ilen, -		unsigned char output[20], unsigned int chunk_sz); - -/** - * \brief	   Output = SHA-1( file contents ) - * - * \param path	   input file name - * \param output   SHA-1 checksum result - * \return	   0 if successful, or 1 if fopen failed - */ -int sha1_file( char *path, unsigned char output[20] ); +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, +		unsigned char *output, unsigned int chunk_sz);  /**   * \brief	   Output = HMAC-SHA-1( input buffer, hmac key ) @@ -108,9 +100,9 @@ int sha1_file( char *path, unsigned char output[20] );   * \param ilen	   length of the input data   * \param output   HMAC-SHA-1 result   */ -void sha1_hmac( unsigned char *key, int keylen, -		unsigned char *input, int ilen, -		unsigned char output[20] ); +void sha1_hmac(const unsigned char *key, int keylen, +		const unsigned char *input, unsigned int ilen, +		unsigned char *output);  /**   * \brief	   Checkup routine diff --git a/include/sha256.h b/include/sha256.h index e38ea898c..beadab35f 100644 --- a/include/sha256.h +++ b/include/sha256.h @@ -3,6 +3,9 @@  #define SHA256_SUM_LEN	32 +/* Reset watchdog each time we process this many bytes */ +#define CHUNKSZ_SHA256	(64 * 1024) +  typedef struct {  	uint32_t total[2];  	uint32_t state[8]; @@ -10,7 +13,10 @@ typedef struct {  } sha256_context;  void sha256_starts(sha256_context * ctx); -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length); +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length);  void sha256_finish(sha256_context * ctx, uint8_t digest[SHA256_SUM_LEN]); +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, +		unsigned char *output, unsigned int chunk_sz); +  #endif /* _SHA256_H */ diff --git a/include/sound.h b/include/sound.h new file mode 100644 index 000000000..ea0b1158f --- /dev/null +++ b/include/sound.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar < rcsekar@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 + */ + +#ifndef __SOUND_H__ +#define __SOUND_H__ + +/* sound codec enum */ +enum en_sound_codec { +	CODEC_WM_8994, +	CODEC_WM_8995, +	CODEC_MAX +}; + +/* sound codec enum */ +enum sound_compat { +	AUDIO_COMPAT_SPI, +	AUDIO_COMPAT_I2C, +}; + +/* Codec information structure to store the info from device tree */ +struct sound_codec_info { +	int i2c_bus; +	int i2c_dev_addr; +	enum en_sound_codec codec_type; +}; + +/* + * Initialises audio sub system + * + * @return	int value 0 for success, -1 for error + */ +int sound_init(void); + +/* + * plays the pcm data buffer in pcm_data.h through i2s1 to make the + * sine wave sound + * + * @return	int 0 for success, -1 for error + */ +int sound_play(uint32_t msec, uint32_t frequency); + +#endif  /* __SOUND__H__ */ diff --git a/lib/Makefile b/lib/Makefile index f83f6e8d8..86ca1a6ec 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -69,6 +69,7 @@ endif  COBJS-y += crc32.o  COBJS-y += ctype.o  COBJS-y += div64.o +COBJS-y += linux_string.o  COBJS-y += string.o  COBJS-y += time.o  COBJS-$(CONFIG_BOOTP_PXE) += uuid.o diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 348144aa7..6dba4389f 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -43,6 +43,8 @@ static const char * const compat_names[COMPAT_COUNT] = {  	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),  	COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),  	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), +	COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), +	COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),  };  const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/lib/hashtable.c b/lib/hashtable.c index 94a7b6171..07ebfb218 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -54,7 +54,9 @@  #define	CONFIG_ENV_MAX_ENTRIES 512  #endif -#include "search.h" +#include <env_callback.h> +#include <env_flags.h> +#include <search.h>  /*   * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -66,12 +68,16 @@   * Instead the interface of all functions is extended to take an argument   * which describes the current status.   */ +  typedef struct _ENTRY {  	int used;  	ENTRY entry;  } _ENTRY; +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, +	int idx); +  /*   * hcreate()   */ @@ -142,7 +148,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab)   * be freed and the local static variable can be marked as not used.   */ -void hdestroy_r(struct hsearch_data *htab, int do_apply) +void hdestroy_r(struct hsearch_data *htab)  {  	int i; @@ -156,10 +162,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply)  	for (i = 1; i <= htab->size; ++i) {  		if (htab->table[i].used > 0) {  			ENTRY *ep = &htab->table[i].entry; -			if (do_apply && htab->apply != NULL) { -				/* deletion is always forced */ -				htab->apply(ep->key, ep->data, NULL, H_FORCE); -			} +  			free((void *)ep->key);  			free(ep->data);  		} @@ -250,14 +253,65 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,  	return 0;  } +/* + * Compare an existing entry with the desired key, and overwrite if the action + * is ENTER.  This is simply a helper function for hsearch_r(). + */ +static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, +	ENTRY **retval, struct hsearch_data *htab, int flag, +	unsigned int hval, unsigned int idx) +{ +	if (htab->table[idx].used == hval +	    && strcmp(item.key, htab->table[idx].entry.key) == 0) { +		/* Overwrite existing value? */ +		if ((action == ENTER) && (item.data != NULL)) { +			/* check for permission */ +			if (htab->change_ok != NULL && htab->change_ok( +			    &htab->table[idx].entry, item.data, +			    env_op_overwrite, flag)) { +				debug("change_ok() rejected setting variable " +					"%s, skipping it!\n", item.key); +				__set_errno(EPERM); +				*retval = NULL; +				return 0; +			} + +			/* If there is a callback, call it */ +			if (htab->table[idx].entry.callback && +			    htab->table[idx].entry.callback(item.key, +			    item.data, env_op_overwrite, flag)) { +				debug("callback() rejected setting variable " +					"%s, skipping it!\n", item.key); +				__set_errno(EINVAL); +				*retval = NULL; +				return 0; +			} + +			free(htab->table[idx].entry.data); +			htab->table[idx].entry.data = strdup(item.data); +			if (!htab->table[idx].entry.data) { +				__set_errno(ENOMEM); +				*retval = NULL; +				return 0; +			} +		} +		/* return found entry */ +		*retval = &htab->table[idx].entry; +		return idx; +	} +	/* keep searching */ +	return -1; +} +  int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, -	      struct hsearch_data *htab) +	      struct hsearch_data *htab, int flag)  {  	unsigned int hval;  	unsigned int count;  	unsigned int len = strlen(item.key);  	unsigned int idx;  	unsigned int first_deleted = 0; +	int ret;  	/* Compute an value for the given string. Perhaps use a better method. */  	hval = len; @@ -289,23 +343,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,  		    && !first_deleted)  			first_deleted = idx; -		if (htab->table[idx].used == hval -		    && strcmp(item.key, htab->table[idx].entry.key) == 0) { -			/* Overwrite existing value? */ -			if ((action == ENTER) && (item.data != NULL)) { -				free(htab->table[idx].entry.data); -				htab->table[idx].entry.data = -					strdup(item.data); -				if (!htab->table[idx].entry.data) { -					__set_errno(ENOMEM); -					*retval = NULL; -					return 0; -				} -			} -			/* return found entry */ -			*retval = &htab->table[idx].entry; -			return idx; -		} +		ret = _compare_and_overwrite_entry(item, action, retval, htab, +			flag, hval, idx); +		if (ret != -1) +			return ret;  		/*  		 * Second hash function: @@ -331,23 +372,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,  				break;  			/* If entry is found use it. */ -			if ((htab->table[idx].used == hval) -			    && strcmp(item.key, htab->table[idx].entry.key) == 0) { -				/* Overwrite existing value? */ -				if ((action == ENTER) && (item.data != NULL)) { -					free(htab->table[idx].entry.data); -					htab->table[idx].entry.data = -						strdup(item.data); -					if (!htab->table[idx].entry.data) { -						__set_errno(ENOMEM); -						*retval = NULL; -						return 0; -					} -				} -				/* return found entry */ -				*retval = &htab->table[idx].entry; -				return idx; -			} +			ret = _compare_and_overwrite_entry(item, action, retval, +				htab, flag, hval, idx); +			if (ret != -1) +				return ret;  		}  		while (htab->table[idx].used);  	} @@ -383,6 +411,34 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,  		++htab->filled; +		/* This is a new entry, so look up a possible callback */ +		env_callback_init(&htab->table[idx].entry); +		/* Also look for flags */ +		env_flags_init(&htab->table[idx].entry); + +		/* check for permission */ +		if (htab->change_ok != NULL && htab->change_ok( +		    &htab->table[idx].entry, item.data, env_op_create, flag)) { +			debug("change_ok() rejected setting variable " +				"%s, skipping it!\n", item.key); +			_hdelete(item.key, htab, &htab->table[idx].entry, idx); +			__set_errno(EPERM); +			*retval = NULL; +			return 0; +		} + +		/* If there is a callback, call it */ +		if (htab->table[idx].entry.callback && +		    htab->table[idx].entry.callback(item.key, item.data, +		    env_op_create, flag)) { +			debug("callback() rejected setting variable " +				"%s, skipping it!\n", item.key); +			_hdelete(item.key, htab, &htab->table[idx].entry, idx); +			__set_errno(EINVAL); +			*retval = NULL; +			return 0; +		} +  		/* return new entry */  		*retval = &htab->table[idx].entry;  		return 1; @@ -404,7 +460,21 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,   * do that.   */ -int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, +	int idx) +{ +	/* free used ENTRY */ +	debug("hdelete: DELETING key \"%s\"\n", key); +	free((void *)ep->key); +	free(ep->data); +	ep->callback = NULL; +	ep->flags = 0; +	htab->table[idx].used = -1; + +	--htab->filled; +} + +int hdelete_r(const char *key, struct hsearch_data *htab, int flag)  {  	ENTRY e, *ep;  	int idx; @@ -413,20 +483,31 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)  	e.key = (char *)key; -	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) { +	idx = hsearch_r(e, FIND, &ep, htab, 0); +	if (idx == 0) {  		__set_errno(ESRCH);  		return 0;	/* not found */  	} -	/* free used ENTRY */ -	debug("hdelete: DELETING key \"%s\"\n", key); -	if (do_apply && htab->apply != NULL) -		htab->apply(ep->key, ep->data, NULL, H_FORCE); -	free((void *)ep->key); -	free(ep->data); -	htab->table[idx].used = -1; +	/* Check for permission */ +	if (htab->change_ok != NULL && +	    htab->change_ok(ep, NULL, env_op_delete, flag)) { +		debug("change_ok() rejected deleting variable " +			"%s, skipping it!\n", key); +		__set_errno(EPERM); +		return 0; +	} -	--htab->filled; +	/* If there is a callback, call it */ +	if (htab->table[idx].entry.callback && +	    htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { +		debug("callback() rejected deleting variable " +			"%s, skipping it!\n", key); +		__set_errno(EINVAL); +		return 0; +	} + +	_hdelete(key, htab, ep, idx);  	return 1;  } @@ -482,7 +563,7 @@ static int cmpkey(const void *p1, const void *p2)  	return (strcmp(e1->key, e2->key));  } -ssize_t hexport_r(struct hsearch_data *htab, const char sep, +ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,  		 char **resp, size_t size,  		 int argc, char * const argv[])  { @@ -519,6 +600,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,  			if ((argc > 0) && (found == 0))  				continue; +			if ((flag & H_HIDE_DOT) && ep->key[0] == '.') +				continue; +  			list[n++] = ep;  			totlen += strlen(ep->key) + 2; @@ -674,7 +758,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])  int himport_r(struct hsearch_data *htab,  		const char *env, size_t size, const char sep, int flag, -		int nvars, char * const vars[], int do_apply) +		int nvars, char * const vars[])  {  	char *data, *sp, *dp, *name, *value;  	char *localvars[nvars]; @@ -704,7 +788,7 @@ int himport_r(struct hsearch_data *htab,  		debug("Destroy Hash Table: %p table = %p\n", htab,  		       htab->table);  		if (htab->table) -			hdestroy_r(htab, do_apply); +			hdestroy_r(htab);  	}  	/* @@ -770,7 +854,7 @@ int himport_r(struct hsearch_data *htab,  			if (!drop_var_from_set(name, nvars, localvars))  				continue; -			if (hdelete_r(name, htab, do_apply) == 0) +			if (hdelete_r(name, htab, flag) == 0)  				debug("DELETE ERROR ##############################\n");  			continue; @@ -794,30 +878,10 @@ int himport_r(struct hsearch_data *htab,  		e.key = name;  		e.data = value; -		/* if there is an apply function, check what it has to say */ -		if (do_apply && htab->apply != NULL) { -			debug("searching before calling cb function" -				" for  %s\n", name); -			/* -			 * Search for variable in existing env, so to pass -			 * its previous value to the apply callback -			 */ -			hsearch_r(e, FIND, &rv, htab); -			debug("previous value was %s\n", rv ? rv->data : ""); -			if (htab->apply(name, rv ? rv->data : NULL, -				value, flag)) { -				debug("callback function refused to set" -					" variable %s, skipping it!\n", name); -				continue; -			} -		} - -		hsearch_r(e, ENTER, &rv, htab); -		if (rv == NULL) { +		hsearch_r(e, ENTER, &rv, htab, flag); +		if (rv == NULL)  			printf("himport_r: can't insert \"%s=%s\" into hash table\n",  				name, value); -			return 0; -		}  		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",  			htab, htab->filled, htab->size, @@ -839,7 +903,7 @@ int himport_r(struct hsearch_data *htab,  		 * b) if the variable was not present in current env, we notify  		 *    it might be a typo  		 */ -		if (hdelete_r(localvars[i], htab, do_apply) == 0) +		if (hdelete_r(localvars[i], htab, flag) == 0)  			printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);  		else  			printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); @@ -848,3 +912,27 @@ int himport_r(struct hsearch_data *htab,  	debug("INSERT: done\n");  	return 1;		/* everything OK */  } + +/* + * hwalk_r() + */ + +/* + * Walk all of the entries in the hash, calling the callback for each one. + * this allows some generic operation to be performed on each element. + */ +int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) +{ +	int i; +	int retval; + +	for (i = 1; i <= htab->size; ++i) { +		if (htab->table[i].used > 0) { +			retval = callback(&htab->table[i].entry); +			if (retval) +				return retval; +		} +	} + +	return 0; +} diff --git a/lib/linux_string.c b/lib/linux_string.c new file mode 100644 index 000000000..d5a5e08d9 --- /dev/null +++ b/lib/linux_string.c @@ -0,0 +1,51 @@ +/* + *  linux/lib/string.c + * + *  Copyright (C) 1991, 1992  Linus Torvalds + */ + +#ifdef USE_HOSTCC +#include <stdio.h> +#endif + +#include <linux/ctype.h> +#include <linux/string.h> + +/** + * skip_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + */ +char *skip_spaces(const char *str) +{ +	while (isspace(*str)) +		++str; +	return (char *)str; +} + +/** + * strim - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +char *strim(char *s) +{ +	size_t size; +	char *end; + +	s = skip_spaces(s); +	size = strlen(s); +	if (!size) +		return s; + +	end = s + size - 1; +	while (end >= s && isspace(*end)) +		end--; +	*(end + 1) = '\0'; + +	return s; +} diff --git a/lib/sha1.c b/lib/sha1.c index da5bc16f3..a12122485 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -73,7 +73,7 @@ void sha1_starts (sha1_context * ctx)  	ctx->state[4] = 0xC3D2E1F0;  } -static void sha1_process (sha1_context * ctx, unsigned char data[64]) +static void sha1_process(sha1_context *ctx, const unsigned char data[64])  {  	unsigned long temp, W[16], A, B, C, D, E; @@ -230,7 +230,8 @@ static void sha1_process (sha1_context * ctx, unsigned char data[64])  /*   * SHA-1 process buffer   */ -void sha1_update (sha1_context * ctx, unsigned char *input, int ilen) +void sha1_update(sha1_context *ctx, const unsigned char *input, +		 unsigned int ilen)  {  	int fill;  	unsigned long left; @@ -305,7 +306,8 @@ void sha1_finish (sha1_context * ctx, unsigned char output[20])  /*   * Output = SHA-1( input buffer )   */ -void sha1_csum (unsigned char *input, int ilen, unsigned char output[20]) +void sha1_csum(const unsigned char *input, unsigned int ilen, +	       unsigned char *output)  {  	sha1_context ctx; @@ -318,12 +320,12 @@ void sha1_csum (unsigned char *input, int ilen, unsigned char output[20])   * Output = SHA-1( input buffer ). Trigger the watchdog every 'chunk_sz'   * bytes of input processed.   */ -void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20], -			unsigned int chunk_sz) +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, +		  unsigned char *output, unsigned int chunk_sz)  {  	sha1_context ctx;  #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) -	unsigned char *end, *curr; +	const unsigned char *end, *curr;  	int chunk;  #endif @@ -350,8 +352,9 @@ void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20],  /*   * Output = HMAC-SHA-1( input buffer, hmac key )   */ -void sha1_hmac (unsigned char *key, int keylen, -		unsigned char *input, int ilen, unsigned char output[20]) +void sha1_hmac(const unsigned char *key, int keylen, +	       const unsigned char *input, unsigned int ilen, +	       unsigned char *output)  {  	int i;  	sha1_context ctx; diff --git a/lib/sha256.c b/lib/sha256.c index deb63a40b..ab2db4890 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -60,7 +60,7 @@ void sha256_starts(sha256_context * ctx)  	ctx->state[7] = 0x5BE0CD19;  } -void sha256_process(sha256_context * ctx, uint8_t data[64]) +static void sha256_process(sha256_context *ctx, const uint8_t data[64])  {  	uint32_t temp1, temp2;  	uint32_t W[64]; @@ -191,7 +191,7 @@ void sha256_process(sha256_context * ctx, uint8_t data[64])  	ctx->state[7] += H;  } -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length) +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length)  {  	uint32_t left, fill; @@ -260,3 +260,36 @@ void sha256_finish(sha256_context * ctx, uint8_t digest[32])  	PUT_UINT32_BE(ctx->state[6], digest, 24);  	PUT_UINT32_BE(ctx->state[7], digest, 28);  } + +/* + * Output = SHA-256( input buffer ). Trigger the watchdog every 'chunk_sz' + * bytes of input processed. + */ +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, +		unsigned char *output, unsigned int chunk_sz) +{ +	sha256_context ctx; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +	unsigned char *end, *curr; +	int chunk; +#endif + +	sha256_starts(&ctx); + +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +	curr = input; +	end = input + ilen; +	while (curr < end) { +		chunk = end - curr; +		if (chunk > chunk_sz) +			chunk = chunk_sz; +		sha256_update(&ctx, curr, chunk); +		curr += chunk; +		WATCHDOG_RESET(); +	} +#else +	sha256_update(&ctx, input, ilen); +#endif + +	sha256_finish(&ctx, output); +} diff --git a/lib/string.c b/lib/string.c index c3ad055e2..09dfae03c 100644 --- a/lib/string.c +++ b/lib/string.c @@ -21,14 +21,13 @@  #include <malloc.h> -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */  /** - * strnicmp - Case insensitive, length-limited string comparison + * strncasecmp - Case insensitive, length-limited string comparison   * @s1: One string   * @s2: The other string   * @len: the maximum number of characters to compare   */ -int strnicmp(const char *s1, const char *s2, size_t len) +int strncasecmp(const char *s1, const char *s2, size_t len)  {  	/* Yes, Virginia, it had better be unsigned */  	unsigned char c1, c2; @@ -52,7 +51,16 @@ int strnicmp(const char *s1, const char *s2, size_t len)  	}  	return (int)c1 - (int)c2;  } -#endif + +/** + * strcasecmp - Case insensitive string comparison + * @s1: One string + * @s2: The other string + */ +int strcasecmp(const char *s1, const char *s2) +{ +	return strncasecmp(s1, s2, -1U); +}  char * ___strtok; @@ -214,45 +222,6 @@ char * strrchr(const char * s, int c)  }  #endif - -/** - * skip_spaces - Removes leading whitespace from @str. - * @str: The string to be stripped. - * - * Returns a pointer to the first non-whitespace character in @str. - */ -char *skip_spaces(const char *str) -{ -	while (isspace(*str)) -		++str; -	return (char *)str; -} - -/** - * strim - Removes leading and trailing whitespace from @s. - * @s: The string to be stripped. - * - * Note that the first trailing whitespace is replaced with a %NUL-terminator - * in the given string @s. Returns a pointer to the first non-whitespace - * character in @s. - */ -char *strim(char *s) -{ -	size_t size; -	char *end; - -	s = skip_spaces(s); -	size = strlen(s); -	if (!size) -		return s; - -	end = s + size - 1; -	while (end >= s && isspace(*end)) -		end--; -	*(end + 1) = '\0'; - -	return s; -}  #ifndef __HAVE_ARCH_STRLEN  /**   * strlen - Find the length of a string diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b7a79c0e0..3c432f876 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -103,7 +103,7 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)  	return simple_strtoul(cp, endp, base);  } -int ustrtoul(const char *cp, char **endp, unsigned int base) +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)  {  	unsigned long result = simple_strtoul(cp, endp, base);  	switch (**endp) { diff --git a/net/link_local.c b/net/link_local.c index d52f13adb..1ba796ebd 100644 --- a/net/link_local.c +++ b/net/link_local.c @@ -103,7 +103,7 @@ static void configure_wait(void)  void link_local_start(void)  {  	ip = getenv_IPaddr("llipaddr"); -	if (ip != 0 && (ip & IN_CLASSB_NET) != LINKLOCAL_ADDR) { +	if (ip != 0 && (ntohl(ip) & IN_CLASSB_NET) != LINKLOCAL_ADDR) {  		puts("invalid link address");  		net_set_state(NETLOOP_FAIL);  		return; @@ -82,6 +82,7 @@  #include <common.h>  #include <command.h> +#include <environment.h>  #include <net.h>  #if defined(CONFIG_STATUS_LED)  #include <miiphy.h> @@ -208,32 +209,46 @@ static int NetTryCount;  /**********************************************************************/ +static int on_bootfile(const char *name, const char *value, enum env_op op, +	int flags) +{ +	switch (op) { +	case env_op_create: +	case env_op_overwrite: +		copy_filename(BootFile, value, sizeof(BootFile)); +		break; +	default: +		break; +	} + +	return 0; +} +U_BOOT_ENV_CALLBACK(bootfile, on_bootfile); +  /*   * Check if autoload is enabled. If so, use either NFS or TFTP to download   * the boot file.   */  void net_auto_load(void)  { +#if defined(CONFIG_CMD_NFS)  	const char *s = getenv("autoload"); -	if (s != NULL) { -		if (*s == 'n') { -			/* -			 * Just use BOOTP/RARP to configure system; -			 * Do not use TFTP to load the bootfile. -			 */ -			net_set_state(NETLOOP_SUCCESS); -			return; -		} -#if defined(CONFIG_CMD_NFS) -		if (strcmp(s, "NFS") == 0) { -			/* -			 * Use NFS to load the bootfile. -			 */ -			NfsStart(); -			return; -		} +	if (s != NULL && strcmp(s, "NFS") == 0) { +		/* +		 * Use NFS to load the bootfile. +		 */ +		NfsStart(); +		return; +	}  #endif +	if (getenv_yesno("autoload") == 0) { +		/* +		 * Just use BOOTP/RARP to configure system; +		 * Do not use TFTP to load the bootfile. +		 */ +		net_set_state(NETLOOP_SUCCESS); +		return;  	}  	TftpStart(TFTPGET);  } diff --git a/net/tftp.c b/net/tftp.c index 59a8ebb3c..09790eb7c 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -40,6 +40,7 @@  static ulong TftpTimeoutMSecs = TIMEOUT;  static int TftpTimeoutCountMax = TIMEOUT_COUNT; +static ulong time_start;   /* Record time we started tftp */  /*   * These globals govern the timeout behavior when attempting a connection to a @@ -299,6 +300,12 @@ static void tftp_complete(void)  		TftpNumchars++;  	}  #endif +	time_start = get_timer(time_start); +	if (time_start > 0) { +		puts("\n\t ");	/* Line up with "Loading: " */ +		print_size(NetBootFileXferSize / +			time_start * 1000, "/s"); +	}  	puts("\ndone\n");  	net_set_state(NETLOOP_SUCCESS);  } @@ -775,6 +782,7 @@ void TftpStart(enum proto_t protocol)  		TftpState = STATE_SEND_RRQ;  	} +	time_start = get_timer(0);  	TftpTimeoutCountMax = TftpRRQTimeoutCountMax;  	NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); diff --git a/tools/env/Makefile b/tools/env/Makefile index ab73c8c74..0e798e094 100644 --- a/tools/env/Makefile +++ b/tools/env/Makefile @@ -24,12 +24,15 @@  include $(TOPDIR)/config.mk  HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c +HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c +HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c  HEADERS	:= fw_env.h $(OBJTREE)/include/config.h  # Compile for a hosted environment on the target  HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \  		-idirafter $(OBJTREE)/include2 \  		-idirafter $(OBJTREE)/include \ +		-idirafter $(SRCTREE)/tools/env \  		-DUSE_HOSTCC \  		-DTEXT_BASE=$(TEXT_BASE) diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 9b023e807..90c7a5d3f 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -25,6 +25,7 @@   */  #include <errno.h> +#include <env_flags.h>  #include <fcntl.h>  #include <linux/stringify.h>  #include <stdio.h> @@ -181,6 +182,32 @@ char *fw_getenv (char *name)  }  /* + * Search the default environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getdefenv(char *name) +{ +	char *env, *nxt; + +	for (env = default_environment; *env; env = nxt + 1) { +		char *val; + +		for (nxt = env; *nxt; ++nxt) { +			if (nxt >= &default_environment[ENV_SIZE]) { +				fprintf(stderr, "## Error: " +					"default environment not terminated\n"); +				return NULL; +			} +		} +		val = envmatch(name, env); +		if (!val) +			continue; +		return val; +	} +	return NULL; +} + +/*   * Print the current definition of one, or more, or all   * environment variables   */ @@ -281,6 +308,7 @@ int fw_env_write(char *name, char *value)  	int len;  	char *env, *nxt;  	char *oldval = NULL; +	int deleting, creating, overwriting;  	/*  	 * search if variable with this name already exists @@ -298,27 +326,49 @@ int fw_env_write(char *name, char *value)  			break;  	} -	/* -	 * Delete any existing definition -	 */ -	if (oldval) { -#ifndef CONFIG_ENV_OVERWRITE -		/* -		 * Ethernet Address and serial# can be set only once -		 */ -		if ( -		    (strcmp(name, "serial#") == 0) || -		    ((strcmp(name, "ethaddr") == 0) -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) -		    && (strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0) -#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ -		   ) ) { -			fprintf (stderr, "Can't overwrite \"%s\"\n", name); +	deleting = (oldval && !(value && strlen(value))); +	creating = (!oldval && (value && strlen(value))); +	overwriting = (oldval && (value && strlen(value))); + +	/* check for permission */ +	if (deleting) { +		if (env_flags_validate_varaccess(name, +		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { +			printf("Can't delete \"%s\"\n", name); +			errno = EROFS; +			return -1; +		} +	} else if (overwriting) { +		if (env_flags_validate_varaccess(name, +		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { +			printf("Can't overwrite \"%s\"\n", name); +			errno = EROFS; +			return -1; +		} else if (env_flags_validate_varaccess(name, +		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { +			const char *defval = fw_getdefenv(name); + +			if (defval == NULL) +				defval = ""; +			if (strcmp(oldval, defval) +			    != 0) { +				printf("Can't overwrite \"%s\"\n", name); +				errno = EROFS; +				return -1; +			} +		} +	} else if (creating) { +		if (env_flags_validate_varaccess(name, +		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { +			printf("Can't create \"%s\"\n", name);  			errno = EROFS;  			return -1;  		} -#endif /* CONFIG_ENV_OVERWRITE */ +	} else +		/* Nothing to do */ +		return 0; +	if (deleting || overwriting) {  		if (*++nxt == '\0') {  			*env = '\0';  		} else { @@ -395,6 +445,9 @@ int fw_setenv(int argc, char *argv[])  	name = argv[1]; +	if (env_flags_validate_env_set_params(argc, argv) < 0) +		return 1; +  	len = 0;  	for (i = 2; i < argc; ++i) {  		char *val = argv[i]; @@ -516,6 +569,11 @@ int fw_parse_script(char *fname)  			name, val ? val : " removed");  #endif +		if (env_flags_validate_type(name, val) < 0) { +			ret = -1; +			break; +		} +  		/*  		 * If there is an error setting a variable,  		 * try to save the environment and returns an error diff --git a/tools/fit_image.c b/tools/fit_image.c index ef9ffeeec..76bbba125 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -80,7 +80,7 @@ static int fit_handle_file (struct mkimage_params *params)  	}  	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); -	/* dtc -I dts -O -p 200 datafile > tmpfile */ +	/* 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);  |