diff options
Diffstat (limited to 'arch/arm/imx-common')
| -rw-r--r-- | arch/arm/imx-common/Makefile | 52 | ||||
| -rw-r--r-- | arch/arm/imx-common/cmd_bmode.c | 119 | ||||
| -rw-r--r-- | arch/arm/imx-common/cpu.c | 140 | ||||
| -rw-r--r-- | arch/arm/imx-common/i2c-mxv7.c | 99 | ||||
| -rw-r--r-- | arch/arm/imx-common/iomux-v3.c | 70 | ||||
| -rw-r--r-- | arch/arm/imx-common/speed.c | 45 | ||||
| -rw-r--r-- | arch/arm/imx-common/timer.c | 149 | 
7 files changed, 674 insertions, 0 deletions
diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile new file mode 100644 index 000000000..b3e608e9d --- /dev/null +++ b/arch/arm/imx-common/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2011 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB     = $(obj)libimx-common.o + +ifeq ($(SOC),$(filter $(SOC),mx5 mx6)) +COBJS-y	= iomux-v3.o timer.o cpu.o speed.o +COBJS-$(CONFIG_I2C_MXC) += i2c-mxv7.o +endif +COBJS-$(CONFIG_CMD_BMODE) += cmd_bmode.o +COBJS	:= $(sort $(COBJS-y)) + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all:	$(obj).depend $(LIB) + +$(LIB):	$(OBJS) +	$(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/imx-common/cmd_bmode.c b/arch/arm/imx-common/cmd_bmode.c new file mode 100644 index 000000000..02fe72ed7 --- /dev/null +++ b/arch/arm/imx-common/cmd_bmode.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2012 Boundary Devices Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/imx-common/boot_mode.h> +#include <malloc.h> + +static const struct boot_mode *modes[2]; + +static const struct boot_mode *search_modes(char *arg) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(modes); i++) { +		const struct boot_mode *p = modes[i]; +		if (p) { +			while (p->name) { +				if (!strcmp(p->name, arg)) +					return p; +				p++; +			} +		} +	} +	return NULL; +} + +static int create_usage(char *dest) +{ +	int i; +	int size = 0; + +	for (i = 0; i < ARRAY_SIZE(modes); i++) { +		const struct boot_mode *p = modes[i]; +		if (p) { +			while (p->name) { +				int len = strlen(p->name); +				if (dest) { +					memcpy(dest, p->name, len); +					dest += len; +					*dest++ = '|'; +				} +				size += len + 1; +				p++; +			} +		} +	} +	if (dest) +		memcpy(dest - 1, " [noreset]", 11);	/* include trailing 0 */ +	size += 10; +	return size; +} + +static int do_boot_mode(cmd_tbl_t *cmdtp, int flag, int argc, +		char * const argv[]) +{ +	const struct boot_mode *p; +	int reset_requested = 1; + +	if (argc < 2) +		return CMD_RET_USAGE; +	p = search_modes(argv[1]); +	if (!p) +		return CMD_RET_USAGE; +	if (argc == 3) { +		if (strcmp(argv[2], "noreset")) +			return CMD_RET_USAGE; +		reset_requested = 0; +	} + +	boot_mode_apply(p->cfg_val); +	if (reset_requested && p->cfg_val) +		do_reset(NULL, 0, 0, NULL); +	return 0; +} + +U_BOOT_CMD( +	bmode, 3, 0, do_boot_mode, +	NULL, +	""); + +void add_board_boot_modes(const struct boot_mode *p) +{ +	int size; +	char *dest; + +	if (__u_boot_cmd_bmode.usage) { +		free(__u_boot_cmd_bmode.usage); +		__u_boot_cmd_bmode.usage = NULL; +	} + +	modes[0] = p; +	modes[1] = soc_boot_modes; +	size = create_usage(NULL); +	dest = malloc(size); +	if (dest) { +		create_usage(dest); +		__u_boot_cmd_bmode.usage = dest; +	} +} diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c new file mode 100644 index 000000000..fa1d46804 --- /dev/null +++ b/arch/arm/imx-common/cpu.c @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2007 + * Sascha Hauer, Pengutronix + * + * (C) Copyright 2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/crm_regs.h> + +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif + +char *get_reset_cause(void) +{ +	u32 cause; +	struct src *src_regs = (struct src *)SRC_BASE_ADDR; + +	cause = readl(&src_regs->srsr); +	writel(cause, &src_regs->srsr); + +	switch (cause) { +	case 0x00001: +	case 0x00011: +		return "POR"; +	case 0x00004: +		return "CSU"; +	case 0x00008: +		return "IPP USER"; +	case 0x00010: +		return "WDOG"; +	case 0x00020: +		return "JTAG HIGH-Z"; +	case 0x00040: +		return "JTAG SW"; +	case 0x10000: +		return "WARM BOOT"; +	default: +		return "unknown reset"; +	} +} + +#if defined(CONFIG_DISPLAY_CPUINFO) + +static const char *get_imx_type(u32 imxtype) +{ +	switch (imxtype) { +	case 0x63: +		return "6Q";	/* Quad-core version of the mx6 */ +	case 0x61: +		return "6DS";	/* Dual/Solo version of the mx6 */ +	case 0x60: +		return "6SL";	/* Solo-Lite version of the mx6 */ +	case 0x51: +		return "51"; +	case 0x53: +		return "53"; +	default: +		return "??"; +	} +} + +int print_cpuinfo(void) +{ +	u32 cpurev; + +	cpurev = get_cpu_rev(); + +	printf("CPU:   Freescale i.MX%s rev%d.%d at %d MHz\n", +		get_imx_type((cpurev & 0xFF000) >> 12), +		(cpurev & 0x000F0) >> 4, +		(cpurev & 0x0000F) >> 0, +		mxc_get_clock(MXC_ARM_CLK) / 1000000); +	printf("Reset cause: %s\n", get_reset_cause()); +	return 0; +} +#endif + +int cpu_eth_init(bd_t *bis) +{ +	int rc = -ENODEV; + +#if defined(CONFIG_FEC_MXC) +	rc = fecmxc_initialize(bis); +#endif + +	return rc; +} + +#ifdef CONFIG_FSL_ESDHC +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ +	return fsl_esdhc_mmc_init(bis); +} +#endif + +void reset_cpu(ulong addr) +{ +	__raw_writew(4, WDOG1_BASE_ADDR); +} + +u32 get_ahb_clk(void) +{ +	struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; +	u32 reg, ahb_podf; + +	reg = __raw_readl(&imx_ccm->cbcdr); +	reg &= MXC_CCM_CBCDR_AHB_PODF_MASK; +	ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET; + +	return get_periph_clk() / (ahb_podf + 1); +} diff --git a/arch/arm/imx-common/i2c-mxv7.c b/arch/arm/imx-common/i2c-mxv7.c new file mode 100644 index 000000000..da2b26f43 --- /dev/null +++ b/arch/arm/imx-common/i2c-mxv7.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 Boundary Devices Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <asm/errno.h> +#include <asm/gpio.h> +#include <asm/imx-common/mxc_i2c.h> +#include <watchdog.h> + +static int force_idle_bus(void *priv) +{ +	int i; +	int sda, scl; +	ulong elapsed, start_time; +	struct i2c_pads_info *p = (struct i2c_pads_info *)priv; +	int ret = 0; + +	gpio_direction_input(p->sda.gp); +	gpio_direction_input(p->scl.gp); + +	imx_iomux_v3_setup_pad(p->sda.gpio_mode); +	imx_iomux_v3_setup_pad(p->scl.gpio_mode); + +	sda = gpio_get_value(p->sda.gp); +	scl = gpio_get_value(p->scl.gp); +	if ((sda & scl) == 1) +		goto exit;		/* Bus is idle already */ + +	printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__, +		sda, scl, p->sda.gp, p->scl.gp); +	/* Send high and low on the SCL line */ +	for (i = 0; i < 9; i++) { +		gpio_direction_output(p->scl.gp, 0); +		udelay(50); +		gpio_direction_input(p->scl.gp); +		udelay(50); +	} +	start_time = get_timer(0); +	for (;;) { +		sda = gpio_get_value(p->sda.gp); +		scl = gpio_get_value(p->scl.gp); +		if ((sda & scl) == 1) +			break; +		WATCHDOG_RESET(); +		elapsed = get_timer(start_time); +		if (elapsed > (CONFIG_SYS_HZ / 5)) {	/* .2 seconds */ +			ret = -EBUSY; +			printf("%s: failed to clear bus, sda=%d scl=%d\n", +					__func__, sda, scl); +			break; +		} +	} +exit: +	imx_iomux_v3_setup_pad(p->sda.i2c_mode); +	imx_iomux_v3_setup_pad(p->scl.i2c_mode); +	return ret; +} + +static void * const i2c_bases[] = { +	(void *)I2C1_BASE_ADDR, +	(void *)I2C2_BASE_ADDR, +#ifdef I2C3_BASE_ADDR +	(void *)I2C3_BASE_ADDR, +#endif +}; + +/* i2c_index can be from 0 - 2 */ +void setup_i2c(unsigned i2c_index, int speed, int slave_addr, +		struct i2c_pads_info *p) +{ +	if (i2c_index >= ARRAY_SIZE(i2c_bases)) +		return; +	/* Enable i2c clock */ +	enable_i2c_clk(1, i2c_index); +	/* Make sure bus is idle */ +	force_idle_bus(p); +	bus_i2c_init(i2c_bases[i2c_index], speed, slave_addr, +			force_idle_bus, p); +} diff --git a/arch/arm/imx-common/iomux-v3.c b/arch/arm/imx-common/iomux-v3.c new file mode 100644 index 000000000..da093fbe1 --- /dev/null +++ b/arch/arm/imx-common/iomux-v3.c @@ -0,0 +1,70 @@ +/* + * Based on the iomux-v3.c from Linux kernel: + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + *                       <armlinux@phytec.de> + * + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/imx-common/iomux-v3.h> + +static void *base = (void *)IOMUXC_BASE_ADDR; + +/* + * configures a single pad in the iomuxer + */ +int imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) +{ +	u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; +	u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; +	u32 sel_input_ofs = +		(pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; +	u32 sel_input = +		(pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; +	u32 pad_ctrl_ofs = +		(pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; +	u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; + +	if (mux_ctrl_ofs) +		__raw_writel(mux_mode, base + mux_ctrl_ofs); + +	if (sel_input_ofs) +		__raw_writel(sel_input, base + sel_input_ofs); + +	if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs) +		__raw_writel(pad_ctrl, base + pad_ctrl_ofs); + +	return 0; +} + +int imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count) +{ +	iomux_v3_cfg_t *p = pad_list; +	int i; +	int ret; + +	for (i = 0; i < count; i++) { +		ret = imx_iomux_v3_setup_pad(*p); +		if (ret) +			return ret; +		p++; +	} +	return 0; +} diff --git a/arch/arm/imx-common/speed.c b/arch/arm/imx-common/speed.c new file mode 100644 index 000000000..80989c498 --- /dev/null +++ b/arch/arm/imx-common/speed.c @@ -0,0 +1,45 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +#ifdef CONFIG_FSL_ESDHC +DECLARE_GLOBAL_DATA_PTR; +#endif + +int get_clocks(void) +{ +#ifdef CONFIG_FSL_ESDHC +#ifdef CONFIG_FSL_USDHC +	gd->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); +#else +	gd->sdhc_clk = mxc_get_clock(MXC_IPG_PERCLK); +#endif +#endif +	return 0; +} diff --git a/arch/arm/imx-common/timer.c b/arch/arm/imx-common/timer.c new file mode 100644 index 000000000..e2725e1a6 --- /dev/null +++ b/arch/arm/imx-common/timer.c @@ -0,0 +1,149 @@ +/* + * (C) Copyright 2007 + * Sascha Hauer, Pengutronix + * + * (C) Copyright 2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <div64.h> +#include <asm/arch/imx-regs.h> + +/* General purpose timers registers */ +struct mxc_gpt { +	unsigned int control; +	unsigned int prescaler; +	unsigned int status; +	unsigned int nouse[6]; +	unsigned int counter; +}; + +static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR; + +/* General purpose timers bitfields */ +#define GPTCR_SWR		(1 << 15)	/* Software reset */ +#define GPTCR_FRR		(1 << 9)	/* Freerun / restart */ +#define GPTCR_CLKSOURCE_32	(4 << 6)	/* Clock source */ +#define GPTCR_TEN		1		/* Timer enable */ +#define CLK_32KHZ		32768		/* 32Khz input */ + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->tbl) +#define lastinc (gd->lastinc) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ +	tick *= CONFIG_SYS_HZ; +	do_div(tick, CLK_32KHZ); + +	return tick; +} + +static inline unsigned long long us_to_tick(unsigned long long usec) +{ +	usec = usec * CLK_32KHZ + 999999; +	do_div(usec, 1000000); + +	return usec; +} + +int timer_init(void) +{ +	int i; +	ulong val; + +	/* setup GP Timer 1 */ +	__raw_writel(GPTCR_SWR, &cur_gpt->control); + +	/* We have no udelay by now */ +	for (i = 0; i < 100; i++) +		__raw_writel(0, &cur_gpt->control); + +	__raw_writel(0, &cur_gpt->prescaler); /* 32Khz */ + +	/* Freerun Mode, PERCLK1 input */ +	i = __raw_readl(&cur_gpt->control); +	__raw_writel(i | GPTCR_CLKSOURCE_32 | GPTCR_TEN, &cur_gpt->control); + +	val = __raw_readl(&cur_gpt->counter); +	lastinc = val / (CLK_32KHZ / CONFIG_SYS_HZ); +	timestamp = 0; + +	return 0; +} + +unsigned long long get_ticks(void) +{ +	ulong now = __raw_readl(&cur_gpt->counter); /* current tick value */ + +	if (now >= lastinc) { +		/* +		 * normal mode (non roll) +		 * move stamp forward with absolut diff ticks +		 */ +		timestamp += (now - lastinc); +	} else { +		/* we have rollover of incrementer */ +		timestamp += (0xFFFFFFFF - lastinc) + now; +	} +	lastinc = now; +	return timestamp; +} + +ulong get_timer_masked(void) +{ +	/* +	 * get_ticks() returns a long long (64 bit), it wraps in +	 * 2^64 / CONFIG_MX25_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ +	 * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in +	 * 5 * 10^6 days - long enough. +	 */ +	return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ +	return get_timer_masked() - base; +} + +/* delay x useconds AND preserve advance timstamp value */ +void __udelay(unsigned long usec) +{ +	unsigned long long tmp; +	ulong tmo; + +	tmo = us_to_tick(usec); +	tmp = get_ticks() + tmo;	/* get current timestamp */ + +	while (get_ticks() < tmp)	/* loop till event */ +		 /*NOP*/; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ +	return CLK_32KHZ; +}  |