diff options
Diffstat (limited to 'arch/arm/cpu/arm926ejs')
22 files changed, 1342 insertions, 90 deletions
diff --git a/arch/arm/cpu/arm926ejs/config.mk b/arch/arm/cpu/arm926ejs/config.mk index ffb2e6c3ea..6a3a1bb354 100644 --- a/arch/arm/cpu/arm926ejs/config.mk +++ b/arch/arm/cpu/arm926ejs/config.mk @@ -31,3 +31,9 @@ PLATFORM_CPPFLAGS += -march=armv5te # ========================================================================= PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT) + +ifneq ($(CONFIG_IMX_CONFIG),) + +ALL-y += $(obj)u-boot.imx + +endif diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile new file mode 100644 index 0000000000..ae1f0a5c0c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS = cpu.o clk.o devices.o timer.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) + +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/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c new file mode 100644 index 0000000000..6f26d626a7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <div64.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +unsigned int get_sys_clk_rate(void) +{ + if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397) + return RTC_CLK_FREQUENCY * 397; + else + return OSC_CLK_FREQUENCY; +} + +unsigned int get_hclk_pll_rate(void) +{ + unsigned long long fin, fref, fcco, fout; + u32 val, m_div, n_div, p_div; + + /* + * Valid frequency ranges: + * 1 * 10^6 <= Fin <= 20 * 10^6 + * 1 * 10^6 <= Fref <= 27 * 10^6 + * 156 * 10^6 <= Fcco <= 320 * 10^6 + */ + + fref = fin = get_sys_clk_rate(); + if (fin > 20000000ULL || fin < 1000000ULL) + return 0; + + val = readl(&clk->hclkpll_ctrl); + m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1; + n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1; + if (val & CLK_HCLK_PLL_DIRECT) + p_div = 0; + else + p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1; + p_div = 1 << p_div; + + if (val & CLK_HCLK_PLL_BYPASS) { + do_div(fin, p_div); + return fin; + } + + do_div(fref, n_div); + if (fref > 27000000ULL || fref < 1000000ULL) + return 0; + + fout = fref * m_div; + if (val & CLK_HCLK_PLL_FEEDBACK) { + fcco = fout; + do_div(fout, p_div); + } else + fcco = fout * p_div; + + if (fcco > 320000000ULL || fcco < 156000000ULL) + return 0; + + return fout; +} + +unsigned int get_hclk_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK; + + return 1 << val; +} + +unsigned int get_hclk_clk_rate(void) +{ + return get_hclk_pll_rate() / get_hclk_clk_div(); +} + +unsigned int get_periph_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK; + + return (val >> 2) + 1; +} + +unsigned int get_periph_clk_rate(void) +{ + if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) + return get_sys_clk_rate(); + + return get_hclk_pll_rate() / get_periph_clk_div(); +} + +int get_serial_clock(void) +{ + return get_periph_clk_rate(); +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c new file mode 100644 index 0000000000..e29e130338 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/wdt.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE; + +void reset_cpu(ulong addr) +{ + /* Enable watchdog clock */ + setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); + + /* Reset pulse length is 13005 peripheral clock frames */ + writel(13000, &wdt->pulse); + + /* Force WDOG_RESET2 and RESOUT_N signal active */ + writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2, + &wdt->mctrl); + + while (1) + /* NOP */; +} + +#if defined(CONFIG_ARCH_CPU_INIT) +int arch_cpu_init(void) +{ + /* + * It might be necessary to flush data cache, if U-boot is loaded + * from kickstart bootloader, e.g. from S1L loader + */ + flush_dcache_all(); + + return 0; +} +#else +#error "You have to select CONFIG_ARCH_CPU_INIT" +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + printf("CPU: NXP LPC32XX\n"); + printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000); + printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000); + printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000); + + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c new file mode 100644 index 0000000000..9f305b5ba5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/uart.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE; + +void lpc32xx_uart_init(unsigned int uart_id) +{ + if (uart_id < 1 || uart_id > 7) + return; + + /* Disable loopback mode, if it is set by S1L bootloader */ + clrbits_le32(&ctrl->loop, + UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART)); + + if (uart_id < 3 || uart_id > 6) + return; + + /* Enable UART system clock */ + setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id)); + + /* Set UART into autoclock mode */ + clrsetbits_le32(&ctrl->clkmode, + UART_CLKMODE_MASK(uart_id), + UART_CLKMODE_AUTO(uart_id)); + + /* Bypass pre-divider of UART clock */ + writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1), + &clk->u3clk + (uart_id - 3)); +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/timer.c b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c new file mode 100644 index 0000000000..1ce2358afd --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/timer.h> +#include <asm/io.h> + +static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE; +static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE; +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +static void lpc32xx_timer_clock(u32 bit, int enable) +{ + if (enable) + setbits_le32(&clk->timclk_ctrl1, bit); + else + clrbits_le32(&clk->timclk_ctrl1, bit); +} + +static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq) +{ + writel(TIMER_TCR_COUNTER_RESET, &timer->tcr); + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); + writel(0, &timer->tc); + writel(0, &timer->pr); + + /* Count mode is every rising PCLK edge */ + writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr); + + /* Set prescale counter value */ + writel((get_periph_clk_rate() / freq) - 1, &timer->pr); +} + +static void lpc32xx_timer_count(struct timer_regs *timer, int enable) +{ + if (enable) + writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr); + else + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); +} + +int timer_init(void) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1); + lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ); + lpc32xx_timer_count(timer0, 1); + + return 0; +} + +ulong get_timer(ulong base) +{ + return readl(&timer0->tc) - base; +} + +void __udelay(unsigned long usec) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1); + lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000); + lpc32xx_timer_count(timer1, 1); + + while (readl(&timer1->tc) < usec) + /* NOP */; + + lpc32xx_timer_count(timer1, 0); + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0); +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/mx25/generic.c b/arch/arm/cpu/arm926ejs/mx25/generic.c index 9cadb7c34c..8b07dae2b9 100644 --- a/arch/arm/cpu/arm926ejs/mx25/generic.c +++ b/arch/arm/cpu/arm926ejs/mx25/generic.c @@ -28,10 +28,15 @@ #include <asm/io.h> #include <asm/arch/imx-regs.h> #include <asm/arch/imx25-pinmux.h> +#include <asm/arch/clock.h> #ifdef CONFIG_MXC_MMC #include <asm/arch/mxcmmc.h> #endif +#ifdef CONFIG_FSL_ESDHC +DECLARE_GLOBAL_DATA_PTR; +#endif + /* * get the system pll clock in Hz * @@ -105,6 +110,20 @@ ulong imx_get_perclk(int clk) return lldiv(fref, div); } +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + if (clk >= MXC_CLK_NUM) + return -1; + switch (clk) { + case MXC_ARM_CLK: + return imx_get_armclk(); + case MXC_FEC_CLK: + return imx_get_ahbclk(); + default: + return imx_get_perclk(clk); + } +} + u32 get_cpu_rev(void) { u32 srev; @@ -182,6 +201,14 @@ int cpu_eth_init(bd_t *bis) #endif } +int get_clocks(void) +{ +#ifdef CONFIG_FSL_ESDHC + gd->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); +#endif + return 0; +} + /* * Initializes on-chip MMC controllers. * to override, implement board_mmc_init() diff --git a/arch/arm/cpu/arm926ejs/mx28/Makefile b/arch/arm/cpu/arm926ejs/mx28/Makefile index a2e3f771c2..674a3af1be 100644 --- a/arch/arm/cpu/arm926ejs/mx28/Makefile +++ b/arch/arm/cpu/arm926ejs/mx28/Makefile @@ -28,7 +28,7 @@ LIB = $(obj)lib$(SOC).o COBJS = clock.o mx28.o iomux.o timer.o ifdef CONFIG_SPL_BUILD -COBJS += spl_boot.o spl_mem_init.o spl_power_init.o +COBJS += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o endif SRCS := $(START:.o=.S) $(COBJS:.o=.c) diff --git a/arch/arm/cpu/arm926ejs/mx28/mx28.c b/arch/arm/cpu/arm926ejs/mx28/mx28.c index dc0338dfb5..a82ff2564b 100644 --- a/arch/arm/cpu/arm926ejs/mx28/mx28.c +++ b/arch/arm/cpu/arm926ejs/mx28/mx28.c @@ -51,9 +51,16 @@ void reset_cpu(ulong ignored) __attribute__((noreturn)); void reset_cpu(ulong ignored) { - struct mx28_rtc_regs *rtc_regs = (struct mx28_rtc_regs *)MXS_RTC_BASE; + struct mx28_lcdif_regs *lcdif_regs = + (struct mx28_lcdif_regs *)MXS_LCDIF_BASE; + + /* + * Shut down the LCD controller as it interferes with BootROM boot mode + * pads sampling. + */ + writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr); /* Wait 1 uS before doing the actual watchdog reset */ writel(1, &rtc_regs->hw_rtc_watchdog); @@ -185,8 +192,12 @@ int arch_cpu_init(void) #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) { + struct mx28_spl_data *data = (struct mx28_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf); + printf("Freescale i.MX28 family at %d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("BOOT: %s\n", mx28_boot_modes[data->boot_mode_idx].mode); return 0; } #endif @@ -279,22 +290,16 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) int mx28_dram_init(void) { - struct mx28_digctl_regs *digctl_regs = - (struct mx28_digctl_regs *)MXS_DIGCTL_BASE; - uint32_t sz[2]; - - sz[0] = readl(&digctl_regs->hw_digctl_scratch0); - sz[1] = readl(&digctl_regs->hw_digctl_scratch1); + struct mx28_spl_data *data = (struct mx28_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf); - if (sz[0] != sz[1]) { + if (data->mem_dram_size == 0) { printf("MX28:\n" - "Error, the RAM size in HW_DIGCTRL_SCRATCH0 and\n" - "HW_DIGCTRL_SCRATCH1 is not the same. Please\n" - "verify these two registers contain valid RAM size!\n"); + "Error, the RAM size passed up from SPL is 0!\n"); hang(); } - gd->ram_size = sz[0]; + gd->ram_size = data->mem_dram_size; return 0; } diff --git a/arch/arm/cpu/arm926ejs/mx28/mx28_init.h b/arch/arm/cpu/arm926ejs/mx28/mx28_init.h index 98d363199d..e3a4493fbd 100644 --- a/arch/arm/cpu/arm926ejs/mx28/mx28_init.h +++ b/arch/arm/cpu/arm926ejs/mx28/mx28_init.h @@ -37,5 +37,9 @@ static inline void mx28_power_wait_pswitch(void) { } #endif void mx28_mem_init(void); +uint32_t mx28_mem_get_size(void); + +void mx28_lradc_init(void); +void mx28_lradc_enable_batt_measurement(void); #endif /* __M28_INIT_H__ */ diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_boot.c b/arch/arm/cpu/arm926ejs/mx28/spl_boot.c index dfb8309e70..a6dfca3f51 100644 --- a/arch/arm/cpu/arm926ejs/mx28/spl_boot.c +++ b/arch/arm/cpu/arm926ejs/mx28/spl_boot.c @@ -28,6 +28,8 @@ #include <asm/io.h> #include <asm/arch/iomux-mx28.h> #include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <asm/gpio.h> #include "mx28_init.h" @@ -46,12 +48,65 @@ void early_delay(int delay) ; } +#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL) +const iomux_cfg_t iomux_boot[] = { + MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, +}; + +uint8_t mx28_get_bootmode_index(void) +{ + uint8_t bootmode = 0; + int i; + uint8_t masked; + + /* Setup IOMUX of bootmode pads to GPIO */ + mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot)); + + /* Setup bootmode pins as GPIO input */ + gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0); + gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1); + gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2); + gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3); + gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4); + gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5); + + /* Read bootmode pads */ + bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; + + for (i = 0; i < ARRAY_SIZE(mx28_boot_modes); i++) { + masked = bootmode & mx28_boot_modes[i].boot_mask; + if (masked == mx28_boot_modes[i].boot_pads) + break; + } + + return i; +} + void mx28_common_spl_init(const iomux_cfg_t *iomux_setup, const unsigned int iomux_size) { + struct mx28_spl_data *data = (struct mx28_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mx28_spl_data)) & ~0xf); + uint8_t bootmode = mx28_get_bootmode_index(); + mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size); mx28_power_init(); + mx28_mem_init(); + data->mem_dram_size = mx28_mem_get_size(); + + data->boot_mode_idx = bootmode; + mx28_power_wait_pswitch(); } @@ -68,8 +123,10 @@ inline void board_init_r(gd_t *id, ulong dest_addr) ; } +#ifndef CONFIG_SPL_SERIAL_SUPPORT void serial_putc(const char c) {} void serial_puts(const char *s) {} +#endif void hang(void) __attribute__ ((noreturn)); void hang(void) { diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c new file mode 100644 index 0000000000..88a603c11d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx28/spl_lradc_init.c @@ -0,0 +1,86 @@ +/* + * Freescale i.MX28 Battery measurement init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +#include "mx28_init.h" + +void mx28_lradc_init(void) +{ + struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE; + + writel(LRADC_CTRL0_SFTRST, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_CLKGATE, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_ONCHIP_GROUNDREF, ®s->hw_lradc_ctrl0_clr); + + clrsetbits_le32(®s->hw_lradc_ctrl3, + LRADC_CTRL3_CYCLE_TIME_MASK, + LRADC_CTRL3_CYCLE_TIME_6MHZ); + + clrsetbits_le32(®s->hw_lradc_ctrl4, + LRADC_CTRL4_LRADC7SELECT_MASK | + LRADC_CTRL4_LRADC6SELECT_MASK, + LRADC_CTRL4_LRADC7SELECT_CHANNEL7 | + LRADC_CTRL4_LRADC6SELECT_CHANNEL10); +} + +void mx28_lradc_enable_batt_measurement(void) +{ + struct mx28_lradc_regs *regs = (struct mx28_lradc_regs *)MXS_LRADC_BASE; + + /* Check if the channel is present at all. */ + if (!(readl(®s->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT)) + return; + + writel(LRADC_CTRL1_LRADC7_IRQ_EN, ®s->hw_lradc_ctrl1_clr); + writel(LRADC_CTRL1_LRADC7_IRQ, ®s->hw_lradc_ctrl1_clr); + + clrsetbits_le32(®s->hw_lradc_conversion, + LRADC_CONVERSION_SCALE_FACTOR_MASK, + LRADC_CONVERSION_SCALE_FACTOR_LI_ION); + writel(LRADC_CONVERSION_AUTOMATIC, ®s->hw_lradc_conversion_set); + + /* Configure the channel. */ + writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, + ®s->hw_lradc_ctrl2_clr); + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + clrbits_le32(®s->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK); + writel(LRADC_CH_ACCUMULATE, ®s->hw_lradc_ch7_clr); + + /* Schedule the channel. */ + writel(1 << 7, ®s->hw_lradc_ctrl0_set); + + /* Start the channel sampling. */ + writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) | + ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) | + 100, ®s->hw_lradc_delay3); + + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + + writel(LRADC_DELAY_KICK, ®s->hw_lradc_delay3_set); +} diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c index 911bbefc06..9fa5d29e6c 100644 --- a/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c +++ b/arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c @@ -39,7 +39,7 @@ uint32_t dram_vals[] = { 0x00000000, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010101, 0x01010101, - 0x000f0f01, 0x0f02010a, 0x00000000, 0x00010101, + 0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101, 0x00000100, 0x00000100, 0x00000000, 0x00000002, 0x01010000, 0x05060302, 0x06005003, 0x0a0000c8, 0x02009c40, 0x0000030c, 0x0036a609, 0x031a0612, @@ -149,6 +149,8 @@ void mx28_mem_setup_cpu_and_hbus(void) /* Disable CPU bypass */ writel(CLKCTRL_CLKSEQ_BYPASS_CPU, &clkctrl_regs->hw_clkctrl_clkseq_clr); + + early_delay(15000); } void mx28_mem_setup_vdda(void) @@ -173,10 +175,8 @@ void mx28_mem_setup_vddd(void) &power_regs->hw_power_vdddctrl); } -void mx28_mem_get_size(void) +uint32_t mx28_mem_get_size(void) { - struct mx28_digctl_regs *digctl_regs = - (struct mx28_digctl_regs *)MXS_DIGCTL_BASE; uint32_t sz, da; uint32_t *vt = (uint32_t *)0x20; /* The following is "subs pc, r14, #4", used as return from DABT. */ @@ -187,11 +187,11 @@ void mx28_mem_get_size(void) vt[4] = data_abort_memdetect_handler; sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); - writel(sz, &digctl_regs->hw_digctl_scratch0); - writel(sz, &digctl_regs->hw_digctl_scratch1); /* Restore the old DABT handler. */ vt[4] = da; + + return sz; } void mx28_mem_init(void) @@ -239,6 +239,4 @@ void mx28_mem_init(void) early_delay(10000); mx28_mem_setup_cpu_and_hbus(); - - mx28_mem_get_size(); } diff --git a/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c b/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c index aa4117d3a2..4b09b0c3ba 100644 --- a/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c +++ b/arch/arm/cpu/arm926ejs/mx28/spl_power_init.c @@ -45,11 +45,11 @@ void mx28_power_clock2pll(void) struct mx28_clkctrl_regs *clkctrl_regs = (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; - writel(CLKCTRL_PLL0CTRL0_POWER, - &clkctrl_regs->hw_clkctrl_pll0ctrl0_set); + setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0, + CLKCTRL_PLL0CTRL0_POWER); early_delay(100); - writel(CLKCTRL_CLKSEQ_BYPASS_CPU, - &clkctrl_regs->hw_clkctrl_clkseq_clr); + setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq, + CLKCTRL_CLKSEQ_BYPASS_CPU); } void mx28_power_clear_auto_restart(void) @@ -104,6 +104,62 @@ void mx28_power_set_linreg(void) POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW); } +int mx28_get_batt_volt(void) +{ + struct mx28_power_regs *power_regs = + (struct mx28_power_regs *)MXS_POWER_BASE; + uint32_t volt = readl(&power_regs->hw_power_battmonitor); + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; + volt *= 8; + return volt; +} + +int mx28_is_batt_ready(void) +{ + return (mx28_get_batt_volt() >= 3600); +} + +int mx28_is_batt_good(void) +{ + struct mx28_power_regs *power_regs = + (struct mx28_power_regs *)MXS_POWER_BASE; + uint32_t volt = mx28_get_batt_volt(); + + if ((volt >= 2400) && (volt <= 4300)) + return 1; + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_charge, + POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + POWER_CHARGE_STOP_ILIMIT_10MA | 0x3); + + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + early_delay(500000); + + volt = mx28_get_batt_volt(); + + if (volt >= 3500) + return 0; + + if (volt >= 2400) + return 1; + + writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + &power_regs->hw_power_charge_clr); + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set); + + return 0; +} + void mx28_power_setup_5v_detect(void) { struct mx28_power_regs *power_regs = @@ -399,9 +455,14 @@ void mx28_power_enable_4p2(void) mx28_power_init_4p2_regulator(); /* Shutdown battery (none present) */ - clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK); - writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); - writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr); + if (!mx28_is_batt_ready()) { + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_BO_MASK); + writel(POWER_CTRL_DCDC4P2_BO_IRQ, + &power_regs->hw_power_ctrl_clr); + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, + &power_regs->hw_power_ctrl_clr); + } mx28_power_init_dcdc_4p2_source(); @@ -459,6 +520,50 @@ void mx28_powerdown(void) &power_regs->hw_power_reset); } +void mx28_batt_boot(void) +{ + struct mx28_power_regs *power_regs = + (struct mx28_power_regs *)MXS_POWER_BASE; + + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC); + + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2); + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr); + + /* 5V to battery handoff. */ + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + early_delay(30); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_minpwr, + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); + + mx28_power_set_linreg(); + + clrbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_DISABLE_FET); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_PWD_CHARGE_4P2_MASK); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_ENABLE_DCDC); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); +} + void mx28_handle_5v_conflict(void) { struct mx28_power_regs *power_regs = @@ -483,23 +588,12 @@ void mx28_handle_5v_conflict(void) mx28_powerdown(); break; } - } -} -int mx28_get_batt_volt(void) -{ - struct mx28_power_regs *power_regs = - (struct mx28_power_regs *)MXS_POWER_BASE; - uint32_t volt = readl(&power_regs->hw_power_battmonitor); - volt &= POWER_BATTMONITOR_BATT_VAL_MASK; - volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; - volt *= 8; - return volt; -} - -int mx28_is_batt_ready(void) -{ - return (mx28_get_batt_volt() >= 3600); + if (tmp & POWER_STS_PSWITCH_MASK) { + mx28_batt_boot(); + break; + } + } } void mx28_5v_boot(void) @@ -553,62 +647,44 @@ void mx28_switch_vddd_to_dcdc_source(void) POWER_VDDDCTRL_DISABLE_STEPPING); } -int mx28_is_batt_good(void) +void mx28_power_configure_power_source(void) { + int batt_ready, batt_good; struct mx28_power_regs *power_regs = (struct mx28_power_regs *)MXS_POWER_BASE; - uint32_t volt; - - volt = readl(&power_regs->hw_power_battmonitor); - volt &= POWER_BATTMONITOR_BATT_VAL_MASK; - volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; - volt *= 8; + struct mx28_lradc_regs *lradc_regs = + (struct mx28_lradc_regs *)MXS_LRADC_BASE; - if ((volt >= 2400) && (volt <= 4300)) - return 1; - - clrsetbits_le32(&power_regs->hw_power_5vctrl, - POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, - 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); - writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, - &power_regs->hw_power_5vctrl_clr); - - clrsetbits_le32(&power_regs->hw_power_charge, - POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, - POWER_CHARGE_STOP_ILIMIT_10MA | 0x3); - - writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr); - writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, - &power_regs->hw_power_5vctrl_clr); - - early_delay(500000); - - volt = readl(&power_regs->hw_power_battmonitor); - volt &= POWER_BATTMONITOR_BATT_VAL_MASK; - volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; - volt *= 8; - - if (volt >= 3500) - return 0; - - if (volt >= 2400) - return 1; - - writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, - &power_regs->hw_power_charge_clr); - writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set); + mx28_src_power_init(); - return 0; -} + batt_ready = mx28_is_batt_ready(); -void mx28_power_configure_power_source(void) -{ - mx28_src_power_init(); + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + batt_good = mx28_is_batt_good(); + if (batt_ready) { + /* 5V source detected, good battery detected. */ + mx28_batt_boot(); + } else { + if (batt_good) { + /* 5V source detected, low battery detceted. */ + } else { + /* 5V source detected, bad battery detected. */ + writel(LRADC_CONVERSION_AUTOMATIC, + &lradc_regs->hw_lradc_conversion_clr); + clrbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_BATT_VAL_MASK); + } + mx28_5v_boot(); + } + } else { + /* 5V not detected, booting from battery. */ + mx28_batt_boot(); + } - mx28_5v_boot(); mx28_power_clock2pll(); mx28_init_batt_bo(); + mx28_switch_vddd_to_dcdc_source(); } @@ -883,6 +959,13 @@ void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout) new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET); } +void mx28_setup_batt_detect(void) +{ + mx28_lradc_init(); + mx28_lradc_enable_batt_measurement(); + early_delay(10); +} + void mx28_power_init(void) { struct mx28_power_regs *power_regs = @@ -892,6 +975,9 @@ void mx28_power_init(void) mx28_power_clear_auto_restart(); mx28_power_set_linreg(); mx28_power_setup_5v_detect(); + + mx28_setup_batt_detect(); + mx28_power_configure_power_source(); mx28_enable_output_rail_protection(); diff --git a/arch/arm/cpu/arm926ejs/rda/Makefile b/arch/arm/cpu/arm926ejs/rda/Makefile new file mode 100644 index 0000000000..a8ebda3a72 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/Makefile @@ -0,0 +1,58 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# 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)lib$(SOC).o + +COBJS-y += timer.o serial.o ifc.o cpu.o + +ifdef CONFIG_SPL_BUILD +COBJS-y += spl.o +endif + +SOBJS = reset.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +SOBJS += lowlevel_init.o +endif + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +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/cpu/arm926ejs/rda/config.mk b/arch/arm/cpu/arm926ejs/rda/config.mk new file mode 100644 index 0000000000..565adda11d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/config.mk @@ -0,0 +1,32 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <gj@denx.de> +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float + +PLATFORM_CPPFLAGS += -march=armv5te +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) diff --git a/arch/arm/cpu/arm926ejs/rda/cpu.c b/arch/arm/cpu/arm926ejs/rda/cpu.c new file mode 100644 index 0000000000..ae7a18ed7c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/cpu.c @@ -0,0 +1,12 @@ +#include <common.h> +#include <asm/arch/hardware.h> + +void enable_caches(void) +{ +#ifndef CONFIG_SYS_ICACHE_OFF + icache_enable(); +#endif +#ifndef CONFIG_SYS_DCACHE_OFF + dcache_enable(); +#endif +} diff --git a/arch/arm/cpu/arm926ejs/rda/ifc.c b/arch/arm/cpu/arm926ejs/rda/ifc.c new file mode 100644 index 0000000000..cdda6935ea --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/ifc.c @@ -0,0 +1,171 @@ +#include "common.h" +#include <errno.h> + +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/reg_ifc.h> +#include <asm/arch/ifc.h> + +#ifdef DEBUG +#include <assert.h> +#else +#define assert(...) +#endif + +#define HAL_TRACE(...) + +HAL_IFC_REQUEST_ID_T g_halModuleIfcChannelOwner[SYS_IFC_STD_CHAN_NB]; + +void hal_IfcOpen(void) +{ + u8 channel; + + // Initialize the channel table with unknown requests. + for (channel = 0; channel < SYS_IFC_STD_CHAN_NB; channel++) + { + g_halModuleIfcChannelOwner[channel] = HAL_IFC_NO_REQWEST; + } +} + +HAL_IFC_REQUEST_ID_T hal_IfcGetOwner(u8 channel) +{ + // Here, we consider the transfer as previously finished. + if (channel == HAL_UNKNOWN_CHANNEL) return HAL_IFC_NO_REQWEST; + + // Channel number too big. + assert(channel < SYS_IFC_STD_CHAN_NB, channel); + + return g_halModuleIfcChannelOwner[channel]; +} + +void hal_IfcChannelRelease(HAL_IFC_REQUEST_ID_T requestId, u8 channel) +{ + //u32 status; + + // Here, we consider the transfer as previously finished. + if (channel == HAL_UNKNOWN_CHANNEL) return; + + // Channel number too big. + assert(channel < SYS_IFC_STD_CHAN_NB, channel); + + //status = hal_SysEnterCriticalSection(); + if (g_halModuleIfcChannelOwner[channel] == requestId) + { + // disable this channel + hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId) + | SYS_IFC_CH_RD_HW_EXCH + | SYS_IFC_DISABLE); + // read the status of this channel + if (hwp_sysIfc->std_ch[channel].status & SYS_IFC_ENABLE) + { + HAL_TRACE(_HAL | TSTDOUT,0," Strange, the released channel not disabled yet"); + } + // Write the TC to 0 for next time the channel is re-enabled + hwp_sysIfc->std_ch[channel].tc = 0; + } + //hal_SysExitCriticalSection(status); +} + +void hal_IfcChannelFlush(HAL_IFC_REQUEST_ID_T requestId, u8 channel) +{ + //u32 status; + + // Here, we consider the transfer as previously finished. + if (channel == HAL_UNKNOWN_CHANNEL) return; + + // Channel number too big. + assert(channel < SYS_IFC_STD_CHAN_NB, channel); + + // Check that the channel is really owned by the peripheral + // which is doing the request, it could have been release + // automatically or by an IRQ handler. + //status = hal_SysEnterCriticalSection(); + if (g_halModuleIfcChannelOwner[channel] == requestId) + { + // If fifo not empty, flush it. + if ( !(hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY) ) + { + hwp_sysIfc->std_ch[channel].control = + hwp_sysIfc->std_ch[channel].control | SYS_IFC_FLUSH; + } + } + //hal_SysExitCriticalSection(status); +} + +BOOL hal_IfcChannelIsFifoEmpty(HAL_IFC_REQUEST_ID_T requestId, u8 channel) +{ + //u32 status; + BOOL fifoIsEmpty = TRUE; + + // Here, we consider the transfer as previously finished. + if (channel == HAL_UNKNOWN_CHANNEL) return fifoIsEmpty; + + // Channel number too big. + assert(channel < SYS_IFC_STD_CHAN_NB, channel); + + // Check that the channel is really owned by the peripheral + // which is doing the request, it could have been release + // automatically or by an IRQ handler. + //status = hal_SysEnterCriticalSection(); + if (g_halModuleIfcChannelOwner[channel] == requestId) + { + fifoIsEmpty = + (FALSE != (hwp_sysIfc->std_ch[channel].status & SYS_IFC_FIFO_EMPTY)); + } + //hal_SysExitCriticalSection(status); + + return fifoIsEmpty; +} + +u8 hal_IfcTransferStart(HAL_IFC_REQUEST_ID_T requestId, u8* memStartAddr, u32 xferSize, HAL_IFC_MODE_T ifcMode) +{ + //u32 status = hal_SysEnterCriticalSection(); + u8 channel; + u8 i; + + // Check buffer alignment depending on the mode + if (ifcMode != HAL_IFC_SIZE_8_MODE_MANUAL && ifcMode != HAL_IFC_SIZE_8_MODE_AUTO) + { + // Then ifcMode == HAL_IFC_SIZE_32, check word alignment + assert(((u32)memStartAddr%4) == 0, + "HAL IFC: 32 bits transfer misaligned 0x@%08X", memStartAddr); + } + else + { + // ifcMode == HAL_IFC_SIZE_8, nothing to check + } + + // Check the requested id is not currently already used. + for (i = 0; i < SYS_IFC_STD_CHAN_NB ; i++) + { + if (GET_BITFIELD(hwp_sysIfc->std_ch[i].control, SYS_IFC_REQ_SRC) == requestId) + { + // This channel is or was used for the requestId request. + // Check it is still in use. + assert((hwp_sysIfc->std_ch[i].status & SYS_IFC_ENABLE) == 0, + "HAL: Attempt to use the IFC to deal with a %d" + " request still active on channel %d", requestId, i); + } + } + + channel = SYS_IFC_CH_TO_USE(hwp_sysIfc->get_ch) ; + + if (channel >= SYS_IFC_STD_CHAN_NB) + { + serial_puts("HAL_UNKNOWN_CHANNEL\n"); + //hal_SysExitCriticalSection(status); + return HAL_UNKNOWN_CHANNEL; + } + + g_halModuleIfcChannelOwner[channel] = requestId; + hwp_sysIfc->std_ch[channel].start_addr = (u32) memStartAddr; + hwp_sysIfc->std_ch[channel].tc = xferSize; + hwp_sysIfc->std_ch[channel].control = (SYS_IFC_REQ_SRC(requestId) + | ifcMode + | SYS_IFC_CH_RD_HW_EXCH + | SYS_IFC_ENABLE); + + //hal_SysExitCriticalSection(status); + return channel; +} + diff --git a/arch/arm/cpu/arm926ejs/rda/reset.S b/arch/arm/cpu/arm926ejs/rda/reset.S new file mode 100644 index 0000000000..51748160ae --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/reset.S @@ -0,0 +1,32 @@ +/* + * Processor reset using WDT for TI TMS320DM644x SoC. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * ----------------------------------------------------- + * + * 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 + */ + +.globl reset_cpu +reset_cpu: + nop + nop + nop + nop +reset_cpu_loop: + b reset_cpu_loop + diff --git a/arch/arm/cpu/arm926ejs/rda/serial.c b/arch/arm/cpu/arm926ejs/rda/serial.c new file mode 100644 index 0000000000..f7c1d2d244 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/serial.c @@ -0,0 +1,132 @@ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/rda_iomap.h> +#include <asm/arch/reg_sysctrl.h> +#include <asm/arch/reg_uart.h> + +DECLARE_GLOBAL_DATA_PTR; + +void _serial_set_baudrate(int rate) +{ + hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x36; // 115200 @ 26MHz + //hwp_sysCtrlAp->Cfg_Clk_Uart[2] = 0x05; // 921600 @ 26MHz +} + +void _serial_enable_rtscts(void) +{ + hwp_uart->ctrl |= UART_AUTO_FLOW_CONTROL; +} + +void _serial_disable_rtscts(void) +{ + hwp_uart->ctrl &= ~UART_AUTO_FLOW_CONTROL; +} + +void _serial_init(void) +{ + _serial_set_baudrate(CONFIG_BAUDRATE); + hwp_uart->triggers = UART_AFC_LEVEL(1); //7 ? + + hwp_uart->ctrl = UART_ENABLE | UART_DATA_BITS_8_BITS | + UART_TX_STOP_BITS_1_BIT | UART_PARITY_ENABLE_NO; + + /* Allow reception */ + hwp_uart->CMD_Set = UART_RTS; +} + +void _serial_deinit(void) +{ + hwp_uart->ctrl = 0; + hwp_uart->CMD_Clr = UART_RTS; +} + +/* + * Test whether a character is in the RX buffer + */ +int _serial_tstc(const int port) +{ + return (GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL)); +} + +int _serial_getc(const int port) +{ + /* wait for character to arrive */ ; + while (!(GET_BITFIELD(hwp_uart->status, UART_RX_FIFO_LEVEL))) + ; + + return (hwp_uart->rxtx_buffer & 0xff); +} + +void _serial_putc_hw(const char c, const int port) +{ + // Place in the TX Fifo ? + while (!(GET_BITFIELD(hwp_uart->status, UART_TX_FIFO_SPACE))) + ; + hwp_uart->rxtx_buffer = (u32)c; +} + +void _serial_putc(const char c, const int port) +{ + if (c == '\n') { + _serial_putc_hw('\r', 0); + } + _serial_putc_hw(c, 0); +} + +void _serial_puts(const char *s, const int port) +{ + while (*s) { + _serial_putc(*s++, 0); + } +} + +static int hwflow = 0; /* turned off by default */ +int hwflow_onoff(int on) +{ + switch(on) { + case 0: + default: + break; /* return current */ + case 1: + hwflow = 1; + _serial_enable_rtscts(); /* turn on */ + break; + case -1: + hwflow = 0; + _serial_disable_rtscts(); /* turn off */ + break; + } + return hwflow; +} + +int serial_init(void) +{ + //_serial_init(); // already init in boot_test + return 0; +} + +int serial_getc(void) +{ + return _serial_getc(0); +} + +int serial_tstc(void) +{ + return _serial_tstc(0); +} + +void serial_putc(const char c) +{ + _serial_putc(c, 0); +} + +void serial_puts(const char *s) +{ + _serial_puts(s, 0); +} + +void serial_setbrg (void) +{ +} + diff --git a/arch/arm/cpu/arm926ejs/rda/spl.c b/arch/arm/cpu/arm926ejs/rda/spl.c new file mode 100644 index 0000000000..5111638288 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/spl.c @@ -0,0 +1,74 @@ +#include <common.h> +#include <asm/u-boot.h> +#include <asm/utils.h> +#include <nand.h> +#include <malloc.h> + +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT + +DECLARE_GLOBAL_DATA_PTR; +/* Define global data structure pointer to it*/ +static gd_t gdata __attribute__ ((section(".data"))); +static bd_t bdata __attribute__ ((section(".data"))); + +#else + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +void putc(char c) +{ +} + +#endif /* CONFIG_SPL_LIBCOMMON_SUPPORT */ + +inline void hang(void) +{ + puts("### ERROR ### Please RESET the board ###\n"); + for (;;) + ; +} + +void board_init_f(ulong dummy) +{ + relocate_code(CONFIG_SPL_STACK, NULL, CONFIG_SPL_TEXT_BASE); +} + +void board_init_r(gd_t *id, ulong dummy) +{ +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT + gd = &gdata; + gd->bd = &bdata; + gd->flags |= GD_FLG_RELOC; + gd->baudrate = CONFIG_BAUDRATE; + serial_init(); /* serial communications setup */ + gd->have_console = 1; +#endif + puts("board_init_r\n"); + while(1) + ; +#if 0 +#ifdef CONFIG_SPL_NAND_LOAD + nand_init(); + puts("Nand boot...\n"); + nand_boot(); +#endif +#ifdef CONFIG_SPL_SPI_LOAD + mem_malloc_init(CONFIG_SYS_TEXT_BASE - CONFIG_SYS_MALLOC_LEN, + CONFIG_SYS_MALLOC_LEN); + + gd = &gdata; + gd->bd = &bdata; + gd->flags |= GD_FLG_RELOC; + gd->baudrate = CONFIG_BAUDRATE; + serial_init(); /* serial communications setup */ + gd->have_console = 1; + + puts("SPI boot...\n"); + spi_boot(); +#endif +#endif +} diff --git a/arch/arm/cpu/arm926ejs/rda/timer.c b/arch/arm/cpu/arm926ejs/rda/timer.c new file mode 100644 index 0000000000..a54081b7b2 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/rda/timer.c @@ -0,0 +1,93 @@ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/rda_iomap.h> + +DECLARE_GLOBAL_DATA_PTR; + +typedef volatile struct +{ + REG32 OSTimer_Ctrl; //0x00000000 + REG32 OSTimer_CurVal; //0x00000004 + REG32 WDTimer_Ctrl; //0x00000008 + REG32 WDTimer_LoadVal; //0x0000000C + REG32 HWTimer_Ctrl; //0x00000010 + REG32 HWTimer_CurVal; //0x00000014 + REG32 Timer_Irq_Mask_Set; //0x00000018 + REG32 Timer_Irq_Mask_Clr; //0x0000001C + REG32 Timer_Irq_Clr; //0x00000020 + REG32 Timer_Irq_Cause; //0x00000024 +} HWP_TIMER_T; + +#define hwp_timer ((HWP_TIMER_T*)(RDA_TIMER_BASE)) + +int timer_init(void) +{ + gd->timer_rate_hz = CONFIG_SYS_HZ_CLOCK; + gd->timer_reset_value = 0; + + /* We are using timer34 in unchained 32-bit mode, full speed */ + return(0); +} + +void reset_timer(void) +{ + gd->timer_reset_value = get_ticks(); +} + +/* + * Get the current 64 bit timer tick count + */ +unsigned long long get_ticks(void) +{ + unsigned long now = hwp_timer->HWTimer_CurVal; + + /* increment tbu if tbl has rolled over */ + if (now < gd->tbl) + gd->tbu++; + gd->tbl = now; + + return (((unsigned long long)gd->tbu) << 32) | gd->tbl; +} + +ulong get_timer(ulong base) +{ + unsigned long long timer_diff; + + timer_diff = get_ticks() - gd->timer_reset_value; + + return (timer_diff / (gd->timer_rate_hz / CONFIG_SYS_HZ)) - base; +} + +#pragma GCC push_options +#pragma GCC optimize ("O0") + +void __udelay(unsigned long usec) +{ +#if 0 /* our timer is 16kHz, can NOT support udelay */ + unsigned long long endtime; + + endtime = ((unsigned long long)usec * gd->timer_rate_hz) / 1000000UL; + endtime += get_ticks(); + + while (get_ticks() < endtime) + ; +#else /* use loop instead */ +#define USEC_LOOP (1) + int i, j; + for (i=0;i<(usec);i++) + for (j=0;j<USEC_LOOP;j++) + ; +#endif +} + +#pragma GCC pop_options + +/* + * 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 CONFIG_SYS_HZ; +} |