diff options
Diffstat (limited to 'arch/arm/cpu')
28 files changed, 1421 insertions, 187 deletions
| diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index b98e3d9fa..32a4c244c 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -141,16 +141,6 @@ void flush_cache(unsigned long start, unsigned long size)  	flush_dcache_range(start, start + size);  } -void enable_caches(void) -{ -#ifndef CONFIG_SYS_ICACHE_OFF -	icache_enable(); -#endif -#ifndef CONFIG_SYS_DCACHE_OFF -	dcache_enable(); -#endif -} -  #else /* #ifndef CONFIG_SYS_DCACHE_OFF */  void invalidate_dcache_all(void)  { @@ -172,3 +162,15 @@ void flush_cache(unsigned long start, unsigned long size)  {  }  #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ + +#if !defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF) +void enable_caches(void) +{ +#ifndef CONFIG_SYS_ICACHE_OFF +	icache_enable(); +#endif +#ifndef CONFIG_SYS_DCACHE_OFF +	dcache_enable(); +#endif +} +#endif diff --git a/arch/arm/cpu/arm1176/s3c64xx/Makefile b/arch/arm/cpu/arm1176/s3c64xx/Makefile index 0785b194c..266a0739c 100644 --- a/arch/arm/cpu/arm1176/s3c64xx/Makefile +++ b/arch/arm/cpu/arm1176/s3c64xx/Makefile @@ -31,7 +31,7 @@ LIB	= $(obj)lib$(SOC).o  SOBJS	= reset.o  COBJS-$(CONFIG_S3C6400)	+= cpu_init.o speed.o -COBJS-y	+= timer.o +COBJS-y	+= timer.o init.o  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS-y)) diff --git a/arch/arm/cpu/arm1176/s3c64xx/init.c b/arch/arm/cpu/arm1176/s3c64xx/init.c new file mode 100644 index 000000000..f113d8ed4 --- /dev/null +++ b/arch/arm/cpu/arm1176/s3c64xx/init.c @@ -0,0 +1,26 @@ +/* + * (C) Copyright 2012 Ashok Kumar Reddy Kourla + * ashokkourla2000@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include<common.h> + +int arch_cpu_init(void) +{ +	icache_enable(); + +	return 0; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/reset.c b/arch/arm/cpu/arm926ejs/davinci/reset.c index 968fb035c..80f1ce9d3 100644 --- a/arch/arm/cpu/arm926ejs/davinci/reset.c +++ b/arch/arm/cpu/arm926ejs/davinci/reset.c @@ -16,7 +16,7 @@  void reset_cpu(unsigned long a)  {  	struct davinci_timer *const wdttimer = -		(struct davinci_timer *)DAVINCI_TIMER1_BASE; +		(struct davinci_timer *)DAVINCI_WDOG_BASE;  	writel(0x08, &wdttimer->tgcr);  	writel(readl(&wdttimer->tgcr) | 0x03, &wdttimer->tgcr);  	writel(0, &wdttimer->tim12); diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c index bfea6abeb..4ff19c37e 100644 --- a/arch/arm/cpu/arm926ejs/mxs/clock.c +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -333,6 +333,8 @@ uint32_t mxc_get_clock(enum mxc_clock clk)  		return mx28_get_sspclk(MXC_SSPCLK2);  	case MXC_SSP3_CLK:  		return mx28_get_sspclk(MXC_SSPCLK3); +	case MXC_XTAL_CLK: +		return XTAL_FREQ_KHZ * 1000;  	}  	return 0; diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile index 74875b325..70c443edb 100644 --- a/arch/arm/cpu/armv7/am33xx/Makefile +++ b/arch/arm/cpu/armv7/am33xx/Makefile @@ -18,10 +18,12 @@ LIB	= $(obj)lib$(SOC).o  COBJS	+= clock.o  COBJS	+= sys_info.o +COBJS	+= mem.o  COBJS	+= ddr.o  COBJS	+= emif4.o  COBJS	+= board.o  COBJS	+= mux.o +COBJS-$(CONFIG_NAND_OMAP_GPMC)	+= elm.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(COBJS) $(COBJS-y) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c index da5bc7318..ab313265d 100644 --- a/arch/arm/cpu/armv7/am33xx/board.c +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -25,6 +25,7 @@  #include <asm/arch/ddr_defs.h>  #include <asm/arch/clock.h>  #include <asm/arch/gpio.h> +#include <asm/arch/mem.h>  #include <asm/arch/mmc_host_def.h>  #include <asm/arch/sys_proto.h>  #include <asm/io.h> diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c index 0b4cb4e52..d7d98d111 100644 --- a/arch/arm/cpu/armv7/am33xx/clock.c +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -151,6 +151,16 @@ static void enable_per_clocks(void)  		;  #endif /* CONFIG_SERIAL6 */ +	/* GPMC */ +	writel(PRCM_MOD_EN, &cmper->gpmcclkctrl); +	while (readl(&cmper->gpmcclkctrl) != PRCM_MOD_EN) +		; + +	/* ELM */ +	writel(PRCM_MOD_EN, &cmper->elmclkctrl); +	while (readl(&cmper->elmclkctrl) != PRCM_MOD_EN) +		; +  	/* MMC0*/  	writel(PRCM_MOD_EN, &cmper->mmc0clkctrl);  	while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN) diff --git a/arch/arm/cpu/armv7/am33xx/elm.c b/arch/arm/cpu/armv7/am33xx/elm.c new file mode 100644 index 000000000..9eed23d75 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/elm.c @@ -0,0 +1,212 @@ +/* + * (C) Copyright 2010-2011 Texas Instruments, <www.ti.com> + * Mansoor Ahamed <mansoor.ahamed@ti.com> + * + * BCH Error Location Module (ELM) support. + * + * NOTE: + * 1. Supports only continuous mode. Dont see need for page mode in uboot + * 2. Supports only syndrome polynomial 0. i.e. poly local variable is + *    always set to ELM_DEFAULT_POLY. Dont see need for other polynomial + *    sets in uboot + * + * 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/errno.h> +#include <asm/arch/cpu.h> +#include <asm/arch/omap_gpmc.h> +#include <asm/arch/elm.h> + +#define ELM_DEFAULT_POLY (0) + +struct elm *elm_cfg; + +/** + * elm_load_syndromes - Load BCH syndromes based on nibble selection + * @syndrome: BCH syndrome + * @nibbles: + * @poly: Syndrome Polynomial set to use + * + * Load BCH syndromes based on nibble selection + */ +static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) +{ +	u32 *ptr; +	u32 val; + +	/* reg 0 */ +	ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; +	val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | +				(syndrome[3] << 24); +	writel(val, ptr); +	/* reg 1 */ +	ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; +	val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | +				(syndrome[7] << 24); +	writel(val, ptr); + +	/* BCH 8-bit with 26 nibbles (4*8=32) */ +	if (nibbles > 13) { +		/* reg 2 */ +		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; +		val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | +				(syndrome[11] << 24); +		writel(val, ptr); +		/* reg 3 */ +		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; +		val = syndrome[12] | (syndrome[13] << 8) | +			(syndrome[14] << 16) | (syndrome[15] << 24); +		writel(val, ptr); +	} + +	/* BCH 16-bit with 52 nibbles (7*8=56) */ +	if (nibbles > 26) { +		/* reg 4 */ +		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; +		val = syndrome[16] | (syndrome[17] << 8) | +			(syndrome[18] << 16) | (syndrome[19] << 24); +		writel(val, ptr); + +		/* reg 5 */ +		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; +		val = syndrome[20] | (syndrome[21] << 8) | +			(syndrome[22] << 16) | (syndrome[23] << 24); +		writel(val, ptr); + +		/* reg 6 */ +		ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; +		val = syndrome[24] | (syndrome[25] << 8) | +			(syndrome[26] << 16) | (syndrome[27] << 24); +		writel(val, ptr); +	} +} + +/** + * elm_check_errors - Check for BCH errors and return error locations + * @syndrome: BCH syndrome + * @nibbles: + * @error_count: Returns number of errrors in the syndrome + * @error_locations: Returns error locations (in decimal) in this array + * + * Check the provided syndrome for BCH errors and return error count + * and locations in the array passed. Returns -1 if error is not correctable, + * else returns 0 + */ +int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, +		u32 *error_locations) +{ +	u8 poly = ELM_DEFAULT_POLY; +	s8 i; +	u32 location_status; + +	elm_load_syndromes(syndrome, nibbles, poly); + +	/* start processing */ +	writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) +				| ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), +		&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); + +	/* wait for processing to complete */ +	while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) +		; +	/* clear status */ +	writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), +			&elm_cfg->irqstatus); + +	/* check if correctable */ +	location_status = readl(&elm_cfg->error_location[poly].location_status); +	if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) +		return -1; + +	/* get error count */ +	*error_count = readl(&elm_cfg->error_location[poly].location_status) & +					ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; + +	for (i = 0; i < *error_count; i++) { +		error_locations[i] = +			readl(&elm_cfg->error_location[poly].error_location_x[i]); +	} + +	return 0; +} + + +/** + * elm_config - Configure ELM module + * @level: 4 / 8 / 16 bit BCH + * + * Configure ELM module based on BCH level. + * Set mode as continuous mode. + * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. + * Also, the mode is set only for syndrome 0 + */ +int elm_config(enum bch_level level) +{ +	u32 val; +	u8 poly = ELM_DEFAULT_POLY; +	u32 buffer_size = 0x7FF; + +	/* config size and level */ +	val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; +	val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & +				ELM_LOCATION_CONFIG_ECC_SIZE_MASK); +	writel(val, &elm_cfg->location_config); + +	/* config continous mode */ +	/* enable interrupt generation for syndrome polynomial set */ +	writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), +			&elm_cfg->irqenable); +	/* set continuous mode for the syndrome polynomial set */ +	writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), +			&elm_cfg->page_ctrl); + +	return 0; +} + +/** + * elm_reset - Do a soft reset of ELM + * + * Perform a soft reset of ELM and return after reset is done. + */ +void elm_reset(void) +{ +	/* initiate reset */ +	writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), +				&elm_cfg->sysconfig); + +	/* wait for reset complete and normal operation */ +	while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != +		ELM_SYSSTATUS_RESETDONE) +		; +} + +/** + * elm_init - Initialize ELM module + * + * Initialize ELM support. Currently it does only base address init + * and ELM reset. + */ +void elm_init(void) +{ +	elm_cfg = (struct elm *)ELM_BASE; +	elm_reset(); +} diff --git a/arch/arm/cpu/armv7/am33xx/mem.c b/arch/arm/cpu/armv7/am33xx/mem.c new file mode 100644 index 000000000..b8f54abae --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/mem.c @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Author : + *     Mansoor Ahamed <mansoor.ahamed@ti.com> + * + * Initial Code from: + *     Manikandan Pillai <mani.pillai@ti.com> + *     Richard Woodruff <r-woodruff2@ti.com> + *     Syed Mohammed Khasim <khasim@ti.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 <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/mem.h> +#include <asm/arch/sys_proto.h> +#include <command.h> + +struct gpmc *gpmc_cfg; + +#if defined(CONFIG_CMD_NAND) +static const u32 gpmc_m_nand[GPMC_MAX_REG] = { +	M_NAND_GPMC_CONFIG1, +	M_NAND_GPMC_CONFIG2, +	M_NAND_GPMC_CONFIG3, +	M_NAND_GPMC_CONFIG4, +	M_NAND_GPMC_CONFIG5, +	M_NAND_GPMC_CONFIG6, 0 +}; +#endif + + +void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, +			u32 size) +{ +	writel(0, &cs->config7); +	sdelay(1000); +	/* Delay for settling */ +	writel(gpmc_config[0], &cs->config1); +	writel(gpmc_config[1], &cs->config2); +	writel(gpmc_config[2], &cs->config3); +	writel(gpmc_config[3], &cs->config4); +	writel(gpmc_config[4], &cs->config5); +	writel(gpmc_config[5], &cs->config6); +	/* Enable the config */ +	writel((((size & 0xF) << 8) | ((base >> 24) & 0x3F) | +		(1 << 6)), &cs->config7); +	sdelay(2000); +} + +/***************************************************** + * gpmc_init(): init gpmc bus + * Init GPMC for x16, MuxMode (SDRAM in x32). + * This code can only be executed from SRAM or SDRAM. + *****************************************************/ +void gpmc_init(void) +{ +	/* putting a blanket check on GPMC based on ZeBu for now */ +	gpmc_cfg = (struct gpmc *)GPMC_BASE; + +#ifdef CONFIG_CMD_NAND +	const u32 *gpmc_config = NULL; +	u32 base = 0; +	u32 size = 0; +#endif +	/* global settings */ +	writel(0x00000008, &gpmc_cfg->sysconfig); +	writel(0x00000100, &gpmc_cfg->irqstatus); +	writel(0x00000200, &gpmc_cfg->irqenable); +	writel(0x00000012, &gpmc_cfg->config); +	/* +	 * Disable the GPMC0 config set by ROM code +	 */ +	writel(0, &gpmc_cfg->cs[0].config7); +	sdelay(1000); + +#ifdef CONFIG_CMD_NAND +	gpmc_config = gpmc_m_nand; + +	base = PISMO1_NAND_BASE; +	size = PISMO1_NAND_SIZE; +	enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[0], base, size); +#endif +} diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c index 1b4e808a7..5f6d0396f 100644 --- a/arch/arm/cpu/armv7/cache_v7.c +++ b/arch/arm/cpu/armv7/cache_v7.c @@ -297,6 +297,12 @@ void arm_init_before_mmu(void)  	v7_inval_tlb();  } +void mmu_page_table_flush(unsigned long start, unsigned long stop) +{ +	flush_dcache_range(start, stop); +	v7_inval_tlb(); +} +  /*   * Flush range from all levels of d-cache/unified-cache used:   * Affects the range [start, start + size - 1] @@ -329,6 +335,11 @@ void arm_init_before_mmu(void)  void  flush_cache(unsigned long start, unsigned long size)  {  } + +void mmu_page_table_flush(unsigned long start, unsigned long stop) +{ +} +  #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */  #ifndef CONFIG_SYS_ICACHE_OFF diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 4f3b451be..74599798c 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -25,42 +25,32 @@  #include <asm/io.h>  #include <asm/arch/clock.h>  #include <asm/arch/clk.h> +#include <asm/arch/periph.h> -/* exynos4: return pll clock frequency */ -static unsigned long exynos4_get_pll_clk(int pllreg) +/* Epll Clock division values to achive different frequency output */ +static struct set_epll_con_val exynos5_epll_div[] = { +	{ 192000000, 0, 48, 3, 1, 0 }, +	{ 180000000, 0, 45, 3, 1, 0 }, +	{  73728000, 1, 73, 3, 3, 47710 }, +	{  67737600, 1, 90, 4, 3, 20762 }, +	{  49152000, 0, 49, 3, 3, 9961 }, +	{  45158400, 0, 45, 3, 3, 10381 }, +	{ 180633600, 0, 45, 3, 1, 10381 } +}; + +/* exynos: return pll clock frequency */ +static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  { -	struct exynos4_clock *clk = -		(struct exynos4_clock *)samsung_get_base_clock(); -	unsigned long r, m, p, s, k = 0, mask, fout; +	unsigned long m, p, s = 0, mask, fout;  	unsigned int freq; - -	switch (pllreg) { -	case APLL: -		r = readl(&clk->apll_con0); -		break; -	case MPLL: -		r = readl(&clk->mpll_con0); -		break; -	case EPLL: -		r = readl(&clk->epll_con0); -		k = readl(&clk->epll_con1); -		break; -	case VPLL: -		r = readl(&clk->vpll_con0); -		k = readl(&clk->vpll_con1); -		break; -	default: -		printf("Unsupported PLL (%d)\n", pllreg); -		return 0; -	} -  	/*  	 * APLL_CON: MIDV [25:16]  	 * MPLL_CON: MIDV [25:16]  	 * EPLL_CON: MIDV [24:16]  	 * VPLL_CON: MIDV [24:16] +	 * BPLL_CON: MIDV [25:16]: Exynos5  	 */ -	if (pllreg == APLL || pllreg == MPLL) +	if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)  		mask = 0x3ff;  	else  		mask = 0x1ff; @@ -92,13 +82,43 @@ static unsigned long exynos4_get_pll_clk(int pllreg)  	return fout;  } +/* exynos4: return pll clock frequency */ +static unsigned long exynos4_get_pll_clk(int pllreg) +{ +	struct exynos4_clock *clk = +		(struct exynos4_clock *)samsung_get_base_clock(); +	unsigned long r, k = 0; + +	switch (pllreg) { +	case APLL: +		r = readl(&clk->apll_con0); +		break; +	case MPLL: +		r = readl(&clk->mpll_con0); +		break; +	case EPLL: +		r = readl(&clk->epll_con0); +		k = readl(&clk->epll_con1); +		break; +	case VPLL: +		r = readl(&clk->vpll_con0); +		k = readl(&clk->vpll_con1); +		break; +	default: +		printf("Unsupported PLL (%d)\n", pllreg); +		return 0; +	} + +	return exynos_get_pll_clk(pllreg, r, k); +} +  /* exynos5: return pll clock frequency */  static unsigned long exynos5_get_pll_clk(int pllreg)  {  	struct exynos5_clock *clk =  		(struct exynos5_clock *)samsung_get_base_clock(); -	unsigned long r, m, p, s, k = 0, mask, fout; -	unsigned int freq, pll_div2_sel, fout_sel; +	unsigned long r, k = 0, fout; +	unsigned int pll_div2_sel, fout_sel;  	switch (pllreg) {  	case APLL: @@ -123,41 +143,7 @@ static unsigned long exynos5_get_pll_clk(int pllreg)  		return 0;  	} -	/* -	 * APLL_CON: MIDV [25:16] -	 * MPLL_CON: MIDV [25:16] -	 * EPLL_CON: MIDV [24:16] -	 * VPLL_CON: MIDV [24:16] -	 * BPLL_CON: MIDV [25:16] -	 */ -	if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL) -		mask = 0x3ff; -	else -		mask = 0x1ff; - -	m = (r >> 16) & mask; - -	/* PDIV [13:8] */ -	p = (r >> 8) & 0x3f; -	/* SDIV [2:0] */ -	s = r & 0x7; - -	freq = CONFIG_SYS_CLK_FREQ; - -	if (pllreg == EPLL) { -		k = k & 0xffff; -		/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */ -		fout = (m + k / 65536) * (freq / (p * (1 << s))); -	} else if (pllreg == VPLL) { -		k = k & 0xfff; -		/* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */ -		fout = (m + k / 1024) * (freq / (p * (1 << s))); -	} else { -		if (s < 1) -			s = 1; -		/* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */ -		fout = m * (freq / (p * (1 << (s - 1)))); -	} +	fout = exynos_get_pll_clk(pllreg, r, k);  	/* According to the user manual, in EVT1 MPLL and BPLL always gives  	 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/ @@ -732,6 +718,224 @@ static unsigned long exynos5_get_i2c_clk(void)  	return aclk_66;  } +int exynos5_set_epll_clk(unsigned long rate) +{ +	unsigned int epll_con, epll_con_k; +	unsigned int i; +	unsigned int lockcnt; +	unsigned int start; +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); + +	epll_con = readl(&clk->epll_con0); +	epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << +			EPLL_CON0_LOCK_DET_EN_SHIFT) | +		EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | +		EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | +		EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); + +	for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) { +		if (exynos5_epll_div[i].freq_out == rate) +			break; +	} + +	if (i == ARRAY_SIZE(exynos5_epll_div)) +		return -1; + +	epll_con_k = exynos5_epll_div[i].k_dsm << 0; +	epll_con |= exynos5_epll_div[i].en_lock_det << +				EPLL_CON0_LOCK_DET_EN_SHIFT; +	epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; +	epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; +	epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; + +	/* +	 * Required period ( in cycles) to genarate a stable clock output. +	 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs +	 * frequency input (as per spec) +	 */ +	lockcnt = 3000 * exynos5_epll_div[i].p_div; + +	writel(lockcnt, &clk->epll_lock); +	writel(epll_con, &clk->epll_con0); +	writel(epll_con_k, &clk->epll_con1); + +	start = get_timer(0); + +	 while (!(readl(&clk->epll_con0) & +			(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { +		if (get_timer(start) > TIMEOUT_EPLL_LOCK) { +			debug("%s: Timeout waiting for EPLL lock\n", __func__); +			return -1; +		} +	} +	return 0; +} + +void exynos5_set_i2s_clk_source(void) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); + +	clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, +			(CLK_SRC_SCLK_EPLL)); +} + +int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, +					unsigned int dst_frq) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); +	unsigned int div; + +	if ((dst_frq == 0) || (src_frq == 0)) { +		debug("%s: Invalid requency input for prescaler\n", __func__); +		debug("src frq = %d des frq = %d ", src_frq, dst_frq); +		return -1; +	} + +	div = (src_frq / dst_frq); +	if (div > AUDIO_1_RATIO_MASK) { +		debug("%s: Frequency ratio is out of range\n", __func__); +		debug("src frq = %d des frq = %d ", src_frq, dst_frq); +		return -1; +	} +	clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, +				(div & AUDIO_1_RATIO_MASK)); +	return 0; +} + +/** + * Linearly searches for the most accurate main and fine stage clock scalars + * (divisors) for a specified target frequency and scalar bit sizes by checking + * all multiples of main_scalar_bits values. Will always return scalars up to or + * slower than target. + * + * @param main_scalar_bits	Number of main scalar bits, must be > 0 and < 32 + * @param fine_scalar_bits	Number of fine scalar bits, must be > 0 and < 32 + * @param input_freq		Clock frequency to be scaled in Hz + * @param target_freq		Desired clock frequency in Hz + * @param best_fine_scalar	Pointer to store the fine stage divisor + * + * @return best_main_scalar	Main scalar for desired frequency or -1 if none + * found + */ +static int clock_calc_best_scalar(unsigned int main_scaler_bits, +	unsigned int fine_scalar_bits, unsigned int input_rate, +	unsigned int target_rate, unsigned int *best_fine_scalar) +{ +	int i; +	int best_main_scalar = -1; +	unsigned int best_error = target_rate; +	const unsigned int cap = (1 << fine_scalar_bits) - 1; +	const unsigned int loops = 1 << main_scaler_bits; + +	debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate, +			target_rate, cap); + +	assert(best_fine_scalar != NULL); +	assert(main_scaler_bits <= fine_scalar_bits); + +	*best_fine_scalar = 1; + +	if (input_rate == 0 || target_rate == 0) +		return -1; + +	if (target_rate >= input_rate) +		return 1; + +	for (i = 1; i <= loops; i++) { +		const unsigned int effective_div = max(min(input_rate / i / +							target_rate, cap), 1); +		const unsigned int effective_rate = input_rate / i / +							effective_div; +		const int error = target_rate - effective_rate; + +		debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div, +				effective_rate, error); + +		if (error >= 0 && error <= best_error) { +			best_error = error; +			best_main_scalar = i; +			*best_fine_scalar = effective_div; +		} +	} + +	return best_main_scalar; +} + +static int exynos5_set_spi_clk(enum periph_id periph_id, +					unsigned int rate) +{ +	struct exynos5_clock *clk = +		(struct exynos5_clock *)samsung_get_base_clock(); +	int main; +	unsigned int fine; +	unsigned shift, pre_shift; +	unsigned mask = 0xff; +	u32 *reg; + +	main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); +	if (main < 0) { +		debug("%s: Cannot set clock rate for periph %d", +				__func__, periph_id); +		return -1; +	} +	main = main - 1; +	fine = fine - 1; + +	switch (periph_id) { +	case PERIPH_ID_SPI0: +		reg = &clk->div_peric1; +		shift = 0; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI1: +		reg = &clk->div_peric1; +		shift = 16; +		pre_shift = 24; +		break; +	case PERIPH_ID_SPI2: +		reg = &clk->div_peric2; +		shift = 0; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI3: +		reg = &clk->sclk_div_isp; +		shift = 0; +		pre_shift = 4; +		break; +	case PERIPH_ID_SPI4: +		reg = &clk->sclk_div_isp; +		shift = 12; +		pre_shift = 16; +		break; +	default: +		debug("%s: Unsupported peripheral ID %d\n", __func__, +		      periph_id); +		return -1; +	} +	clrsetbits_le32(reg, mask << shift, (main & mask) << shift); +	clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift); + +	return 0; +} + +static unsigned long exynos4_get_i2c_clk(void) +{ +	struct exynos4_clock *clk = +		(struct exynos4_clock *)samsung_get_base_clock(); +	unsigned long sclk, aclk_100; +	unsigned int ratio; + +	sclk = get_pll_clk(APLL); + +	ratio = (readl(&clk->div_top)) >> 4; +	ratio &= 0xf; +	aclk_100 = sclk / (ratio + 1); +	return aclk_100; +} +  unsigned long get_pll_clk(int pllreg)  {  	if (cpu_is_exynos5()) @@ -752,6 +956,8 @@ unsigned long get_i2c_clk(void)  {  	if (cpu_is_exynos5()) {  		return exynos5_get_i2c_clk(); +	} else if (cpu_is_exynos4()) { +		return exynos4_get_i2c_clk();  	} else {  		debug("I2C clock is not set for this CPU\n");  		return 0; @@ -803,3 +1009,34 @@ void set_mipi_clk(void)  	if (cpu_is_exynos4())  		exynos4_set_mipi_clk();  } + +int set_spi_clk(int periph_id, unsigned int rate) +{ +	if (cpu_is_exynos5()) +		return exynos5_set_spi_clk(periph_id, rate); +	else +		return 0; +} + +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{ + +	if (cpu_is_exynos5()) +		return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq); +	else +		return 0; +} + +void set_i2s_clk_source(void) +{ +	if (cpu_is_exynos5()) +		exynos5_set_i2s_clk_source(); +} + +int set_epll_clk(unsigned long rate) +{ +	if (cpu_is_exynos5()) +		return exynos5_set_epll_clk(rate); +	else +		return 0; +} diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 7776add9d..20a4b8414 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -112,6 +112,7 @@ static int exynos5_mmc_config(int peripheral, int flags)  		s5p_gpio_set_pull(bank, i, GPIO_PULL_UP);  		s5p_gpio_set_drv(bank, i, GPIO_DRV_4X);  	} +  	return 0;  } @@ -230,6 +231,59 @@ static void exynos5_i2c_config(int peripheral, int flags)  	}  } +static void exynos5_i2s_config(int peripheral) +{ +	int i; +	struct exynos5_gpio_part1 *gpio1 = +		(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); + +	for (i = 0; i < 5; i++) +		s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02)); +} + +void exynos5_spi_config(int peripheral) +{ +	int cfg = 0, pin = 0, i; +	struct s5p_gpio_bank *bank = NULL; +	struct exynos5_gpio_part1 *gpio1 = +		(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); +	struct exynos5_gpio_part2 *gpio2 = +		(struct exynos5_gpio_part2 *) samsung_get_base_gpio_part2(); + +	switch (peripheral) { +	case PERIPH_ID_SPI0: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI1: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 4; +		break; +	case PERIPH_ID_SPI2: +		bank = &gpio1->b1; +		cfg = GPIO_FUNC(0x5); +		pin = 1; +		break; +	case PERIPH_ID_SPI3: +		bank = &gpio2->f1; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI4: +		for (i = 0; i < 2; i++) { +			s5p_gpio_cfg_pin(&gpio2->f0, i + 2, GPIO_FUNC(0x4)); +			s5p_gpio_cfg_pin(&gpio2->e0, i + 4, GPIO_FUNC(0x4)); +		} +		break; +	} +	if (peripheral != PERIPH_ID_SPI4) { +		for (i = pin; i < pin + 4; i++) +			s5p_gpio_cfg_pin(bank, i, cfg); +	} +} +  static int exynos5_pinmux_config(int peripheral, int flags)  {  	switch (peripheral) { @@ -257,6 +311,78 @@ static int exynos5_pinmux_config(int peripheral, int flags)  	case PERIPH_ID_I2C7:  		exynos5_i2c_config(peripheral, flags);  		break; +	case PERIPH_ID_I2S1: +		exynos5_i2s_config(peripheral); +		break; +	case PERIPH_ID_SPI0: +	case PERIPH_ID_SPI1: +	case PERIPH_ID_SPI2: +	case PERIPH_ID_SPI3: +	case PERIPH_ID_SPI4: +		exynos5_spi_config(peripheral); +		break; +	default: +		debug("%s: invalid peripheral %d", __func__, peripheral); +		return -1; +	} + +	return 0; +} + +static void exynos4_i2c_config(int peripheral, int flags) +{ +	struct exynos4_gpio_part1 *gpio1 = +		(struct exynos4_gpio_part1 *) samsung_get_base_gpio_part1(); + +	switch (peripheral) { +	case PERIPH_ID_I2C0: +		s5p_gpio_cfg_pin(&gpio1->d1, 0, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->d1, 1, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C1: +		s5p_gpio_cfg_pin(&gpio1->d1, 2, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->d1, 3, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C2: +		s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C3: +		s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C4: +		s5p_gpio_cfg_pin(&gpio1->b, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->b, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C5: +		s5p_gpio_cfg_pin(&gpio1->b, 6, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->b, 7, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C6: +		s5p_gpio_cfg_pin(&gpio1->c1, 3, GPIO_FUNC(0x4)); +		s5p_gpio_cfg_pin(&gpio1->c1, 4, GPIO_FUNC(0x4)); +		break; +	case PERIPH_ID_I2C7: +		s5p_gpio_cfg_pin(&gpio1->d0, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->d0, 3, GPIO_FUNC(0x3)); +		break; +	} +} + +static int exynos4_pinmux_config(int peripheral, int flags) +{ +	switch (peripheral) { +	case PERIPH_ID_I2C0: +	case PERIPH_ID_I2C1: +	case PERIPH_ID_I2C2: +	case PERIPH_ID_I2C3: +	case PERIPH_ID_I2C4: +	case PERIPH_ID_I2C5: +	case PERIPH_ID_I2C6: +	case PERIPH_ID_I2C7: +		exynos4_i2c_config(peripheral, flags); +		break;  	default:  		debug("%s: invalid peripheral %d", __func__, peripheral);  		return -1; @@ -269,6 +395,8 @@ int exynos_pinmux_config(int peripheral, int flags)  {  	if (cpu_is_exynos5())  		return exynos5_pinmux_config(peripheral, flags); +	else if (cpu_is_exynos4()) +		return exynos4_pinmux_config(peripheral, flags);  	else {  		debug("pinmux functionality not supported\n");  		return -1; diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 1f2fa027c..0efc80dde 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -25,9 +25,8 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)libomap-common.o -SOBJS	:= reset.o - -COBJS	:= timer.o +COBJS	:= reset.o +COBJS	+= timer.o  COBJS	+= utils.o  ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) diff --git a/arch/arm/cpu/armv7/omap-common/boot-common.c b/arch/arm/cpu/armv7/omap-common/boot-common.c index 0f19141cc..2b584e0a5 100644 --- a/arch/arm/cpu/armv7/omap-common/boot-common.c +++ b/arch/arm/cpu/armv7/omap-common/boot-common.c @@ -21,6 +21,7 @@  #include <asm/omap_common.h>  #include <asm/arch/omap.h>  #include <asm/arch/mmc_host_def.h> +#include <asm/arch/sys_proto.h>  /*   * This is used to verify if the configuration header diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c index 30dcf1b0b..88253cf8c 100644 --- a/arch/arm/cpu/armv7/omap-common/emif-common.c +++ b/arch/arm/cpu/armv7/omap-common/emif-common.c @@ -33,6 +33,8 @@  #include <asm/utils.h>  #include <linux/compiler.h> +static int emif1_enabled = -1, emif2_enabled = -1; +  void set_lpmode_selfrefresh(u32 base)  {  	struct emif_reg_struct *emif = (struct emif_reg_struct *)base; @@ -1109,6 +1111,7 @@ void emif_post_init_config(u32 base)  void dmm_init(u32 base)  {  	const struct dmm_lisa_map_regs *lisa_map_regs; +	u32 i, section, valid;  #ifdef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS  	emif_get_dmm_regs(&lisa_map_regs); @@ -1216,6 +1219,29 @@ void dmm_init(u32 base)  		writel(lisa_map_regs->dmm_lisa_map_0,  			&hw_lisa_map_regs->dmm_lisa_map_0);  	} + +	/* +	 * EMIF should be configured only when +	 * memory is mapped on it. Using emif1_enabled +	 * and emif2_enabled variables for this. +	 */ +	emif1_enabled = 0; +	emif2_enabled = 0; +	for (i = 0; i < 4; i++) { +		section	= __raw_readl(DMM_BASE + i*4); +		valid = (section & EMIF_SDRC_MAP_MASK) >> +			(EMIF_SDRC_MAP_SHIFT); +		if (valid == 3) { +			emif1_enabled = 1; +			emif2_enabled = 1; +			break; +		} else if (valid == 1) { +			emif1_enabled = 1; +		} else if (valid == 2) { +			emif2_enabled = 1; +		} +	} +  }  /* @@ -1255,15 +1281,20 @@ void sdram_init(void)  			writel(CM_DLL_CTRL_NO_OVERRIDE, &prcm->cm_dll_ctrl);  	} -	do_sdram_init(EMIF1_BASE); -	do_sdram_init(EMIF2_BASE); -  	if (!in_sdram)  		dmm_init(DMM_BASE); +	if (emif1_enabled) +		do_sdram_init(EMIF1_BASE); + +	if (emif2_enabled) +		do_sdram_init(EMIF2_BASE); +  	if (!(in_sdram || warm_reset())) { -		emif_post_init_config(EMIF1_BASE); -		emif_post_init_config(EMIF2_BASE); +		if (emif1_enabled) +			emif_post_init_config(EMIF1_BASE); +		if (emif2_enabled) +			emif_post_init_config(EMIF2_BASE);  	}  	/* for the shadow registers to take effect */ diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c index f3cd81ad9..89c587e31 100644 --- a/arch/arm/cpu/armv7/omap3/board.c +++ b/arch/arm/cpu/armv7/omap3/board.c @@ -478,7 +478,7 @@ void omap3_outer_cache_disable(void)  	 */  	omap3_update_aux_cr(0, 0x2);  } -#endif +#endif /* !CONFIG_SYS_L2CACHE_OFF */  #ifndef CONFIG_SYS_DCACHE_OFF  void enable_caches(void) @@ -486,4 +486,4 @@ void enable_caches(void)  	/* Enable D-cache. I-cache is already enabled in start.S */  	dcache_enable();  } -#endif +#endif /* !CONFIG_SYS_DCACHE_OFF */ diff --git a/arch/arm/cpu/armv7/omap3/mem.c b/arch/arm/cpu/armv7/omap3/mem.c index 2fe5ac7c3..d04a5a10d 100644 --- a/arch/arm/cpu/armv7/omap3/mem.c +++ b/arch/arm/cpu/armv7/omap3/mem.c @@ -42,14 +42,7 @@ static const u32 gpmc_m_nand[GPMC_MAX_REG] = {  	M_NAND_GPMC_CONFIG5,  	M_NAND_GPMC_CONFIG6, 0  }; - -#if defined(CONFIG_ENV_IS_IN_NAND) -#define GPMC_CS 0 -#else -#define GPMC_CS 1 -#endif - -#endif +#endif /* CONFIG_CMD_NAND */  #if defined(CONFIG_CMD_ONENAND)  static const u32 gpmc_onenand[GPMC_MAX_REG] = { @@ -60,14 +53,7 @@ static const u32 gpmc_onenand[GPMC_MAX_REG] = {  	ONENAND_GPMC_CONFIG5,  	ONENAND_GPMC_CONFIG6, 0  }; - -#if defined(CONFIG_ENV_IS_IN_ONENAND) -#define GPMC_CS 0 -#else -#define GPMC_CS 1 -#endif - -#endif +#endif /* CONFIG_CMD_ONENAND */  /********************************************************   *  mem_ok() - test used to see if timings are correct diff --git a/arch/arm/cpu/armv7/omap3/sdrc.c b/arch/arm/cpu/armv7/omap3/sdrc.c index f6d9b97bb..e32bf118b 100644 --- a/arch/arm/cpu/armv7/omap3/sdrc.c +++ b/arch/arm/cpu/armv7/omap3/sdrc.c @@ -113,18 +113,18 @@ u32 get_sdr_cs_offset(u32 cs)   *  - Test CS to make sure it's OK for use   */  static void write_sdrc_timings(u32 cs, struct sdrc_actim *sdrc_actim_base, -		u32 mcfg, u32 ctrla, u32 ctrlb, u32 rfr_ctrl, u32 mr) +			struct board_sdrc_timings *timings)  {  	/* Setup timings we got from the board. */ -	writel(mcfg, &sdrc_base->cs[cs].mcfg); -	writel(ctrla, &sdrc_actim_base->ctrla); -	writel(ctrlb, &sdrc_actim_base->ctrlb); -	writel(rfr_ctrl, &sdrc_base->cs[cs].rfr_ctrl); +	writel(timings->mcfg, &sdrc_base->cs[cs].mcfg); +	writel(timings->ctrla, &sdrc_actim_base->ctrla); +	writel(timings->ctrlb, &sdrc_actim_base->ctrlb); +	writel(timings->rfr_ctrl, &sdrc_base->cs[cs].rfr_ctrl);  	writel(CMD_NOP, &sdrc_base->cs[cs].manual);  	writel(CMD_PRECHARGE, &sdrc_base->cs[cs].manual);  	writel(CMD_AUTOREFRESH, &sdrc_base->cs[cs].manual);  	writel(CMD_AUTOREFRESH, &sdrc_base->cs[cs].manual); -	writel(mr, &sdrc_base->cs[cs].mr); +	writel(timings->mr, &sdrc_base->cs[cs].mr);  	/*  	 * Test ram in this bank @@ -143,7 +143,7 @@ static void write_sdrc_timings(u32 cs, struct sdrc_actim *sdrc_actim_base,  void do_sdrc_init(u32 cs, u32 early)  {  	struct sdrc_actim *sdrc_actim_base0, *sdrc_actim_base1; -	u32 mcfg, ctrla, ctrlb, rfr_ctrl, mr; +	struct board_sdrc_timings timings;  	sdrc_actim_base0 = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE;  	sdrc_actim_base1 = (struct sdrc_actim *)SDRC_ACTIM_CTRL1_BASE; @@ -158,7 +158,7 @@ void do_sdrc_init(u32 cs, u32 early)  	 * setup CS1.  	 */  #ifdef CONFIG_SPL_BUILD -	get_board_mem_timings(&mcfg, &ctrla, &ctrlb, &rfr_ctrl, &mr); +	get_board_mem_timings(&timings);  #endif  	if (early) {  		/* reset sdrc controller */ @@ -177,11 +177,9 @@ void do_sdrc_init(u32 cs, u32 early)  		writel(ENADLL | DLLPHASE_90, &sdrc_base->dlla_ctrl);  		sdelay(0x20000);  #ifdef CONFIG_SPL_BUILD -		write_sdrc_timings(CS0, sdrc_actim_base0, mcfg, ctrla, ctrlb, -				rfr_ctrl, mr); +		write_sdrc_timings(CS0, sdrc_actim_base0, &timings);  		make_cs1_contiguous(); -		write_sdrc_timings(CS1, sdrc_actim_base1, mcfg, ctrla, ctrlb, -				rfr_ctrl, mr); +		write_sdrc_timings(CS1, sdrc_actim_base1, &timings);  #endif  	} @@ -193,14 +191,12 @@ void do_sdrc_init(u32 cs, u32 early)  	 * so we may be asked now to setup CS1.  	 */  	if (cs == CS1) { -		mcfg = readl(&sdrc_base->cs[CS0].mcfg), -		rfr_ctrl = readl(&sdrc_base->cs[CS0].rfr_ctrl); -		ctrla = readl(&sdrc_actim_base0->ctrla), -		ctrlb = readl(&sdrc_actim_base0->ctrlb); -		mr = readl(&sdrc_base->cs[CS0].mr); -		write_sdrc_timings(cs, sdrc_actim_base1, mcfg, ctrla, ctrlb, -				rfr_ctrl, mr); - +		timings.mcfg = readl(&sdrc_base->cs[CS0].mcfg), +		timings.rfr_ctrl = readl(&sdrc_base->cs[CS0].rfr_ctrl); +		timings.ctrla = readl(&sdrc_actim_base0->ctrla); +		timings.ctrlb = readl(&sdrc_actim_base0->ctrlb); +		timings.mr = readl(&sdrc_base->cs[CS0].mr); +		write_sdrc_timings(cs, sdrc_actim_base1, &timings);  	}  } diff --git a/arch/arm/cpu/armv7/omap4/clocks.c b/arch/arm/cpu/armv7/omap4/clocks.c index 5bd0a88fd..12c58033d 100644 --- a/arch/arm/cpu/armv7/omap4/clocks.c +++ b/arch/arm/cpu/armv7/omap4/clocks.c @@ -44,7 +44,7 @@   */  #define printf(fmt, args...)  #define puts(s) -#endif +#endif /* !CONFIG_SPL_BUILD */  struct omap4_prcm_regs *const prcm = (struct omap4_prcm_regs *)0x4A004100; diff --git a/arch/arm/cpu/armv7/omap4/hwinit.c b/arch/arm/cpu/armv7/omap4/hwinit.c index 2c34e48f4..f4123aaff 100644 --- a/arch/arm/cpu/armv7/omap4/hwinit.c +++ b/arch/arm/cpu/armv7/omap4/hwinit.c @@ -116,7 +116,7 @@ void do_io_settings(void)  	if ((omap4_rev < OMAP4460_ES1_0) || !readl(&ctrl->control_efuse_2))  		writel(CONTROL_EFUSE_2_OVERRIDE, &ctrl->control_efuse_2);  } -#endif +#endif /* CONFIG_SPL_BUILD */  /* dummy fuction for omap4 */  void config_data_eye_leveling_samples(u32 emif_base) @@ -182,4 +182,4 @@ void v7_outer_cache_disable(void)  {  	set_pl310_ctrl_reg(0);  } -#endif +#endif /* !CONFIG_SYS_L2CACHE_OFF */ 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/s5p-common/wdt.c b/arch/arm/cpu/armv7/s5p-common/wdt.c deleted file mode 100644 index 94acc1e4b..000000000 --- a/arch/arm/cpu/armv7/s5p-common/wdt.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * Minkyu Kang <mk7.kang@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 <asm/io.h> -#include <asm/arch/watchdog.h> - -#define PRESCALER_VAL 255 - -void wdt_stop(void) -{ -	struct s5p_watchdog *wdt = -		(struct s5p_watchdog *)samsung_get_base_watchdog(); -	unsigned int wtcon; - -	wtcon = readl(&wdt->wtcon); -	wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET); - -	writel(wtcon, &wdt->wtcon); -} - -void wdt_start(unsigned int timeout) -{ -	struct s5p_watchdog *wdt = -		(struct s5p_watchdog *)samsung_get_base_watchdog(); -	unsigned int wtcon; - -	wdt_stop(); - -	wtcon = readl(&wdt->wtcon); -	wtcon |= (WTCON_EN | WTCON_CLK(WTCON_CLK_128)); -	wtcon &= ~WTCON_INT; -	wtcon |= WTCON_RESET; -	wtcon |= WTCON_PRESCALER(PRESCALER_VAL); - -	writel(timeout, &wdt->wtdat); -	writel(timeout, &wdt->wtcnt); -	writel(wtcon, &wdt->wtcon); -} 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; |