diff options
94 files changed, 6297 insertions, 700 deletions
| @@ -313,6 +313,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 @@ -1469,6 +1469,22 @@ 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. +  - Splash Screen Support: CONFIG_SPLASH_SCREEN  		If this option is set, the environment is checked for 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/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..fe61f88af 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,209 @@ 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; +} +  unsigned long get_pll_clk(int pllreg)  {  	if (cpu_is_exynos5()) @@ -803,3 +992,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..f02f441a8 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,72 @@ 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 int exynos4_mmc_config(int peripheral, int flags) +{ +	struct exynos4_gpio_part2 *gpio2 = +		(struct exynos4_gpio_part2 *)samsung_get_base_gpio_part2(); +	struct s5p_gpio_bank *bank, *bank_ext; +	int i; + +	switch (peripheral) { +	case PERIPH_ID_SDMMC0: +		bank = &gpio2->k0; +		bank_ext = &gpio2->k1; +		break; +	case PERIPH_ID_SDMMC2: +		bank = &gpio2->k2; +		bank_ext = &gpio2->k3; +		break; +	default: +		return -1; +	} +	for (i = 0; i < 7; i++) { +		if (i == 2) +			continue; +		s5p_gpio_cfg_pin(bank, i,  GPIO_FUNC(0x2)); +		s5p_gpio_set_pull(bank, i, GPIO_PULL_NONE); +		s5p_gpio_set_drv(bank, i, GPIO_DRV_4X); +	} +	if (flags & PINMUX_FLAG_8BIT_MODE) { +		for (i = 3; i < 7; i++) { +			s5p_gpio_cfg_pin(bank_ext, i,  GPIO_FUNC(0x3)); +			s5p_gpio_set_pull(bank_ext, i, GPIO_PULL_NONE); +			s5p_gpio_set_drv(bank_ext, i, GPIO_DRV_4X); +		} +	} + +	return 0; +} + +static int exynos4_pinmux_config(int peripheral, int flags) +{ +	switch (peripheral) { +	case PERIPH_ID_SDMMC0: +	case PERIPH_ID_SDMMC2: +		return exynos4_mmc_config(peripheral, flags); +	case PERIPH_ID_SDMMC1: +	case PERIPH_ID_SDMMC3: +	case PERIPH_ID_SDMMC4: +		printf("SDMMC device %d not implemented\n", peripheral); +		return -1;  	default:  		debug("%s: invalid peripheral %d", __func__, peripheral);  		return -1; @@ -269,6 +389,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..d1b2ea802 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -51,12 +51,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 +84,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 +145,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 +171,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 +189,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-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/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/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/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/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..4c50342e5 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 <pmic.h>  DECLARE_GLOBAL_DATA_PTR; @@ -63,6 +65,12 @@ static int smc9115_pre_init(void)  int board_init(void)  {  	gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); +#if defined(CONFIG_PMIC) +	pmic_init(); +#endif +#ifdef CONFIG_EXYNOS_SPI +	spi_init(); +#endif  	return 0;  } 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 e11a8922f..d5c681c05 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> @@ -93,7 +94,9 @@ void i2c_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;  } @@ -104,6 +107,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) @@ -151,54 +158,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); @@ -209,24 +184,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; @@ -359,6 +321,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 90fff5cf5..afe3bb0ae 100644 --- a/board/samsung/universal_c210/universal.c +++ b/board/samsung/universal_c210/universal.c @@ -23,14 +23,21 @@   */  #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 <pmic.h>  #include <usb/s3c_udc.h>  #include <asm/arch/cpu.h>  #include <max8998_pmic.h> +#include <asm/arch/watchdog.h> +#include <libtizen.h> +#include <ld9040.h>  DECLARE_GLOBAL_DATA_PTR; @@ -50,24 +57,6 @@ static int get_hwrev(void)  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; - -#if defined(CONFIG_PMIC) -	pmic_init(); -#endif - -	check_hw_revision(); -	printf("HW Revision:\t0x%x\n", board_rev); - -	return 0; -} -  int dram_init(void)  {  	gd->ram_size = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE) + @@ -177,7 +166,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: @@ -200,75 +189,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; @@ -320,3 +264,240 @@ 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 = get_pmic(); + +	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 = get_pmic(); + +	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; + +#if defined(CONFIG_PMIC) +	pmic_init(); +	init_pmic_lcd(); +#endif +#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 9e4332221..ded6318dc 100644 --- a/common/Makefile +++ b/common/Makefile @@ -75,6 +75,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 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/lcd.c b/common/lcd.c index b6be8002d..301760473 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) {} @@ -831,6 +885,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 592ce077d..5fdfff2e2 100644 --- a/common/main.c +++ b/common/main.c @@ -1041,8 +1041,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/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/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/misc/Makefile b/drivers/misc/Makefile index 271463cf1..9fac190a6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -39,6 +39,7 @@ COBJS-$(CONFIG_DIALOG_PMIC) += pmic_dialog.o  COBJS-$(CONFIG_PMIC_FSL) += pmic_fsl.o  COBJS-$(CONFIG_PMIC_I2C) += pmic_i2c.o  COBJS-$(CONFIG_PMIC_SPI) += pmic_spi.o +COBJS-$(CONFIG_PMIC_MAX77686) += pmic_max77686.o  COBJS-$(CONFIG_PMIC_MAX8998) += pmic_max8998.o  COBJS-$(CONFIG_PMIC_MAX8997) += pmic_max8997.o diff --git a/drivers/misc/pmic_max77686.c b/drivers/misc/pmic_max77686.c new file mode 100644 index 000000000..36f7f4dde --- /dev/null +++ b/drivers/misc/pmic_max77686.c @@ -0,0 +1,42 @@ +/* + *  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 <pmic.h> +#include <max77686_pmic.h> + +int pmic_init(void) +{ +	struct pmic *p = get_pmic(); +	static const char name[] = "MAX77686_PMIC"; + +	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 = I2C_PMIC; + +	return 0; +} diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 8fea6a6bf..1fd5592f2 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -547,10 +547,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/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/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 ebb6da823..b3207c83c 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_CT69000) += ct69000.o videomodes.o @@ -49,6 +50,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/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/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 5fc613643..035c27fe9 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 74d3b9488..c2d1c6621 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 @@ -101,10 +105,16 @@  #undef TEGRA_DEVICE_SETTINGS  #define TEGRA_DEVICE_SETTINGS	"stdin=serial,tegra-kbc\0" \ -				"stdout=serial\0" \ -				"stderr=serial\0" +				"stdout=serial,lcd\0" \ +				"stderr=serial,lcd\0" -#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 @@ -113,6 +123,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..e412da8c9 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -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 @@ -204,6 +208,32 @@  #define CONFIG_MAX_I2C_NUM	8  #define CONFIG_SYS_I2C_SLAVE    0x0 +/* 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 +  /* Ethernet Controllor Driver */  #ifdef CONFIG_CMD_NET  #define CONFIG_SMC911X @@ -212,6 +242,20 @@  #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 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 6835155d1..2d0d61dc9 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" \ @@ -207,12 +188,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 15bd9bb14..72b661a89 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 d7808aa71..a24e94531 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -189,12 +189,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 */ 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/ventana.h b/include/configs/ventana.h index b751d58bc..8f455221c 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/fdtdec.h b/include/fdtdec.h index 0b140752f..64e5cffe8 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -66,6 +66,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/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/lcd.h b/include/lcd.h index 42070d763..8f8474196 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 @@ -297,6 +305,9 @@ int	lcd_display_bitmap(ulong bmp_image, int x, int y);  /* 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/max77686_pmic.h b/include/max77686_pmic.h new file mode 100644 index 000000000..d949aced0 --- /dev/null +++ b/include/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/max8998_pmic.h b/include/max8998_pmic.h index ca21f882c..0e559f986 100644 --- a/include/max8998_pmic.h +++ b/include/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/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/fdtdec.c b/lib/fdtdec.c index 4c23f458f..23e020572 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) |