From: Kyungmin Park Date: Tue, 21 Jul 2009 00:28:17 +0000 (+0900) Subject: Merge branch 'master' of git://git.denx.de/u-boot X-Git-Tag: s5pc110_universal_support~119 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9a37584e071ec11a5618644e5b514173d9b3cdeb;p=kernel%2Fu-boot.git Merge branch 'master' of git://git.denx.de/u-boot Conflicts: Makefile common/env_onenand.c cpu/arm_cortexa8/cpu.c cpu/arm_cortexa8/omap3/Makefile cpu/arm_cortexa8/omap3/cache.c Signed-off-by: Kyungmin Park --- 9a37584e071ec11a5618644e5b514173d9b3cdeb diff --cc Makefile index 03ff56c,4fe3232..9d11b1c --- a/Makefile +++ b/Makefile @@@ -2983,16 -3041,9 +3041,19 @@@ omap3_pandora_config : unconfi omap3_zoom1_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 zoom1 omap3 omap3 + omap3_zoom2_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 zoom2 omap3 omap3 + +s5pc100_universal_config: unconfig + @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h + @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 universal samsung s5pc100 + @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk + +s5pc100_smdkc100_config: unconfig + @echo "#define CONFIG_ONENAND_U_BOOT" > $(obj)include/config.h + @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 smdkc100 samsung s5pc100 + @echo "CONFIG_ONENAND_U_BOOT = y" >> $(obj)include/config.mk + ######################################################################### ## XScale Systems ######################################################################### @@@ -3555,8 -3631,7 +3641,8 @@@ clobber: clea @rm -f $(obj)cpu/mpc824x/bedbug_603e.c @rm -f $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm @[ ! -d $(obj)nand_spl ] || find $(obj)nand_spl -name "*" -type l -print | xargs rm -f - # @[ ! -d $(obj)onenand_ipl ] || find $(obj)onenand_ipl -name "*" -type l -print | xargs rm -f + @[ ! -d $(obj)onenand_ipl ] || find $(obj)onenand_ipl -name "*" -type l -print | xargs rm -f + @[ ! -d $(obj)api_examples ] || find $(obj)api_examples -name "*" -type l -print | xargs rm -f ifeq ($(OBJTREE),$(SRCTREE)) mrproper \ diff --cc board/samsung/universal/onenand.c index 7839891,0000000..11c6379 mode 100644,000000..100644 --- a/board/samsung/universal/onenand.c +++ b/board/samsung/universal/onenand.c @@@ -1,93 -1,0 +1,93 @@@ +/* + * OneNAND initialization at U-Boot + */ + +#include +#include +#include +#include + +#include + +#include + +#include + +#define DPRINTK(format, args...) \ +do { \ + printk("%s[%d]: " format "\n", __func__, __LINE__, ##args); \ +} while (0) + +void onenand_board_init(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + int value; + + /* D0 Domain system 1 clock gating */ + value = S5P_CLK_GATE_D00_REG; + value &= ~(1 << 2); /* CFCON */ + value |= (1 << 2); + S5P_CLK_GATE_D00_REG = value; + + /* D0 Domain memory clock gating */ + value = S5P_CLK_GATE_D01_REG; + value &= ~(1 << 2); /* CLK_ONENANDC */ + value |= (1 << 2); + S5P_CLK_GATE_D01_REG = value; + + /* System Special clock gating */ + value = S5P_CLK_GATE_SCLK0_REG; + value &= ~(1 << 2); /* OneNAND */ + value |= (1 << 2); + S5P_CLK_GATE_SCLK0_REG = value; + + value = S5P_CLK_SRC0_REG; + value &= ~(1 << 24); /* MUX_1nand: 0 from HCLKD0 */ +// value |= (1 << 24); /* MUX_1nand: 1 from DIV_D1_BUS */ + value &= ~(1 << 20); /* MUX_HREF: 0 from FIN_27M */ + S5P_CLK_SRC0_REG = value; + + value = S5P_CLK_DIV1_REG; +// value &= ~(3 << 20); /* DIV_1nand: 1 / (ratio+1) */ +// value |= (0 << 20); /* ratio = 1 */ + value &= ~(3 << 16); + value |= (1 << 16); + S5P_CLK_DIV1_REG = value; + + MEM_RESET0_REG = ONENAND_MEM_RESET_COLD; + + while (!(INT_ERR_STAT0_REG & RST_CMP)) + continue; + + INT_ERR_ACK0_REG = RST_CMP; + + ACC_CLOCK0_REG = 0x3; + + INT_ERR_MASK0_REG = 0x3fff; + INT_PIN_ENABLE0_REG = (1 << 0); /* Enable */ + + value = INT_ERR_MASK0_REG; + value &= ~RDY_ACT; + INT_ERR_MASK0_REG = value; + +#if 0 + MEM_CFG0_REG |= + ONENAND_SYS_CFG1_SYNC_READ | + ONENAND_SYS_CFG1_BRL_4 | + ONENAND_SYS_CFG1_BL_16 | + ONENAND_SYS_CFG1_RDY | + ONENAND_SYS_CFG1_INT | + ONENAND_SYS_CFG1_IOBE + ; + MEM_CFG0_REG |= ONENAND_SYS_CFG1_RDY; + MEM_CFG0_REG |= ONENAND_SYS_CFG1_INT; + MEM_CFG0_REG |= ONENAND_SYS_CFG1_IOBE; +#endif +// MEM_CFG0_REG |= ONENAND_SYS_CFG1_VHF; +// MEM_CFG0_REG |= ONENAND_SYS_CFG1_HF; + + this->base = (void *) 0xe7100000; - // this->base = (void *)CONFIG_SYS_ONENAND_BASE; ++ this->base = (void *)CONFIG_SYS_ONENAND_BASE; + - // s3c_onenand_init(mtd); ++ s3c_onenand_init(mtd); +} diff --cc common/Makefile index f30e05e,3781738..dcfac1e --- a/common/Makefile +++ b/common/Makefile @@@ -153,11 -154,12 +154,13 @@@ COBJS-$(CONFIG_HWCONFIG) += hwconfig. COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o COBJS-y += flash.o COBJS-$(CONFIG_CMD_KGDB) += kgdb.o + COBJS-$(CONFIG_KALLSYMS) += kallsyms.o COBJS-$(CONFIG_LCD) += lcd.o COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o + COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o COBJS-$(CONFIG_UPDATE_TFTP) += update.o COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o +COBJS-$(CONFIG_CMD_USBDOWN) += cmd_usbd.o COBJS := $(sort $(COBJS-y)) diff --cc cpu/arm_cortexa8/config.mk index b021762,5805596..d950c27 --- a/cpu/arm_cortexa8/config.mk +++ b/cpu/arm_cortexa8/config.mk @@@ -30,7 -30,7 +30,7 @@@ PLATFORM_CPPFLAGS += -march=armv # Supply options according to compiler version # # ========================================================================= --PLATFORM_CPPFLAGS +=$(call cc-option) ++PLATFORM_CPPFLAGS +=$(call cc-option,-mabi=aapcs-linux) PLATFORM_CPPFLAGS +=$(call cc-option,-mno-thumb-interwork,) PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,\ -- $(call cc-option,-malignment-traps,)) ++ $(call cc-option,-malignment-traps,)) diff --cc cpu/arm_cortexa8/s5pc100/interrupts.c index 3fc07b8,0000000..f0ddd24 mode 100644,000000..100644 --- a/cpu/arm_cortexa8/s5pc100/interrupts.c +++ b/cpu/arm_cortexa8/s5pc100/interrupts.c @@@ -1,210 -1,0 +1,209 @@@ +/* + * (C) Copyright 2003 + * Texas Instruments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Alex Zuepke + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, + * + * (C) Copyright 2009 + * Heungjun Kim, SAMSUNG Electronics, + * Inki Dae, SAMSUNG Electronics, + * Minkyu Kang, SAMSUNG Electronics, + * + * 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 + +#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */ +#define MUX_DIV_2 (1) /* 1/2 period */ +#define MUX_DIV_4 (2) /* 1/4 period */ +#define MUX_DIV_8 (3) /* 1/8 period */ +#define MUX_DIV_16 (4) /* 1/16 period */ +#define MUX4_DIV_SHIFT 16 + +#define TCON_TIMER4_SHIFT 20 + +static ulong count_value; + +/* Internal tick units */ +static unsigned long long timestamp; /* Monotonic incrementing timer */ +static unsigned long lastdec; /* Last decremneter snapshot */ + +/* macro to read the 16 bit timer */ +static inline ulong READ_TIMER(void) +{ + const s5pc1xx_timers_t *timers = (s5pc1xx_timers_t *) S5P_TIMER_BASE; + + return timers->TCNTO4; +} + - int interrupt_init(void) ++int timer_init(void) +{ + s5pc1xx_timers_t *timers = (s5pc1xx_timers_t *) S5P_TIMER_BASE; + + /* + * @ PWM Timer 4 + * Timer Freq(HZ) = + * PCLK / { (prescaler_value + 1) * (divider_value) } + */ + + /* set prescaler : 16 */ + /* set divider : 2 */ + timers->TCFG0 = (PRESCALER_1 & 0xff) << 8; + timers->TCFG1 = (MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT; + + if (count_value == 0) { + + /* reset initial value */ + /* count_value = 2085937.5(HZ) (per 1 sec)*/ + count_value = get_PCLK() / ((PRESCALER_1 + 1) * + (MUX_DIV_2 + 1)); + + /* count_value / 100 = 20859.375(HZ) (per 10 msec) */ + count_value = count_value / 100; + } + + /* set count value */ + timers->TCNTB4 = count_value; + lastdec = count_value; + + /* auto reload & manual update */ + timers->TCON = (timers->TCON & ~(0x07 << TCON_TIMER4_SHIFT)) | + S5P_TCON4_AUTO_RELOAD | S5P_TCON4_UPDATE; + + /* start PWM timer 4 */ + timers->TCON = (timers->TCON & ~(0x07 << TCON_TIMER4_SHIFT)) | + S5P_TCON4_AUTO_RELOAD | S5P_TCON4_ON; + + timestamp = 0; + + return 0; +} + - +/* + * timer without interrupts + */ +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +/* delay x useconds */ +void udelay(unsigned long usec) +{ + ulong tmo, tmp; + + if (usec >= 1000) { + /* + * if "big" number, spread normalization + * to seconds + * 1. start to normalize for usec to ticks per sec + * 2. find number of "ticks" to wait to achieve target + * 3. finish normalize. + */ + tmo = usec / 1000; + tmo *= CONFIG_SYS_HZ; + tmo /= 1000; + } else { + /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000 * 1000); + } + + /* get current timestamp */ + tmp = get_timer(0); + + /* if setting this fordward will roll time stamp */ + /* reset "advancing" timestamp to 0, set lastdec value */ + /* else, set advancing stamp wake up time */ + if ((tmo + tmp + 1) < tmp) + reset_timer_masked(); + else + tmo += tmp; + + /* loop till event */ + while (get_timer_masked() < tmo) + ; /* nop */ +} + +void reset_timer_masked(void) +{ + /* reset time */ + lastdec = READ_TIMER(); + timestamp = 0; +} + +ulong get_timer_masked(void) +{ + /* current tick value */ + ulong now = READ_TIMER(); + + if (lastdec >= now) + timestamp += lastdec - now; + else + timestamp += lastdec + count_value - now; + + lastdec = now; + + return timestamp; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * 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) +{ + /* We overrun in 100s */ + return CONFIG_SYS_HZ * 100; +} diff --cc drivers/mtd/onenand/Makefile index c9123ad,1d35a57..820bbeb --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@@ -25,10 -25,7 +25,10 @@@ include $(TOPDIR)/config.m LIB := $(obj)libonenand.a - #COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o - #COBJS-$(CONFIG_S3C64XX) += s3c-onenand.o - #COBJS-$(CONFIG_S5PC1XX) += s3c-onenand.o - COBJS-$(CONFIG_S5PC1XX) += onenand_uboot.o lsi_onenand.o + COBJS-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o ++COBJS-$(CONFIG_S3C64XX) += s3c-onenand.o ++COBJS-$(CONFIG_S5PC1XX) += s3c-onenand.o ++#COBJS-$(CONFIG_S5PC1XX) += onenand_uboot.o lsi_onenand.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --cc drivers/mtd/onenand/s3c-onenand.c index f58050d,0000000..313ce8f mode 100644,000000..100644 --- a/drivers/mtd/onenand/s3c-onenand.c +++ b/drivers/mtd/onenand/s3c-onenand.c @@@ -1,623 -1,0 +1,621 @@@ +/* + * S3C64XX/S5PC100 OneNAND driver at U-Boot + * + * Copyright (C) 2008 Samsung Electronics + * Kyungmin Park + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Implementation: + * Emulate the pseudo BufferRAM + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_S3C64XX) +#include +#include +#elif defined(CONFIG_S5PC1XX) +#include +#endif + +#include +#include + +#if 0 +#define DPRINTK(format, args...) \ +do { \ + printk("%s[%d]: " format "\n", __func__, __LINE__, ##args); \ +} while (0) +#else +#define DPRINTK(...) do { } while (0) +#endif + +#if defined(CONFIG_S3C64XX) +#define AHB_ADDR 0x20000000 +#elif defined(CONFIG_S5PC1XX) +#define AHB_ADDR 0xB0000000 +#endif + +#define ONENAND_ERASE_STATUS 0x00 +#define ONENAND_MULTI_ERASE_SET 0x01 +#define ONENAND_ERASE_START 0x03 +#define ONENAND_UNLOCK_START 0x08 +#define ONENAND_UNLOCK_END 0x09 +#define ONENAND_LOCK_START 0x0A +#define ONENAND_LOCK_END 0x0B +#define ONENAND_LOCK_TIGHT_START 0x0C +#define ONENAND_LOCK_TIGHT_END 0x0D +#define ONENAND_UNLOCK_ALL 0x0E +#define ONENAND_OTP_ACCESS 0x12 +#define ONENAND_SPARE_ACCESS_ONLY 0x13 +#define ONENAND_MAIN_ACCESS_ONLY 0x14 +#define ONENAND_ERASE_VERIFY 0x15 +#define ONENAND_MAIN_SPARE_ACCESS 0x16 +#define ONENAND_PIPELINE_READ 0x4000 + +#if defined(CONFIG_S3C64XX) +#define MAP_00 (0x0 << 24) +#define MAP_01 (0x1 << 24) +#define MAP_10 (0x2 << 24) +#define MAP_11 (0x3 << 24) +#elif defined(CONFIG_S5PC1XX) +#define MAP_00 (0x0 << 26) +#define MAP_01 (0x1 << 26) +#define MAP_10 (0x2 << 26) +#define MAP_11 (0x3 << 26) +#endif + +#if defined(CONFIG_S3C64XX) +#define MEM_ADDR(fba, fpa, fsa) (((fba) << 12 | (fpa) << 6 | \ + (fsa) << 4)) +#elif defined(CONFIG_S5PC1XX) +#define MEM_ADDR(fba, fpa, fsa) (((fba) << 13 | (fpa) << 7 | \ + (fsa) << 5)) +#endif + +/* The 'addr' is byte address. It makes a 16-bit word */ +#define CMD_MAP_00(addr) (MAP_00 | ((addr) << 1)) +#define CMD_MAP_01(mem_addr) (MAP_01 | (mem_addr)) +#define CMD_MAP_10(mem_addr) (MAP_10 | (mem_addr)) +#define CMD_MAP_11(addr) (MAP_11 | ((addr) << 2)) + +struct s3c_onenand { + struct mtd_info *mtd; + + void __iomem *base; + void __iomem *ahb_addr; + + int bootram_command; + + void __iomem *page_buf; + void __iomem *oob_buf; + + unsigned int (*mem_addr)(int fba, int fpa, int fsa); +}; + +static struct s3c_onenand *onenand; + +static int s3c_read_reg(int offset) +{ + return readl(onenand->base + offset); +} + +static void s3c_write_reg(int value, int offset) +{ + writel(value, onenand->base + offset); +} + +static int s3c_read_cmd(unsigned int cmd) +{ + return readl(onenand->ahb_addr + cmd); +} + +static void s3c_write_cmd(int value, unsigned int cmd) +{ + writel(value, onenand->ahb_addr + cmd); +} + +static unsigned int s5pc100_mem_addr(int fba, int fpa, int fsa) +{ + return (fba << 13) | (fpa << 7) | (fsa << 5); +} + +static void s3c_onenand_reset(void) +{ + unsigned long timeout = 0x10000; + int stat; + + s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET); + while (1 && timeout--) { + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + if (stat & RST_CMP) + break; + } + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + s3c_write_reg(stat, INT_ERR_ACK_OFFSET); + + /* Clear interrupt */ + s3c_write_reg(0x0, INT_ERR_ACK_OFFSET); + /* Clear the ECC status */ + s3c_write_reg(0x0, ECC_ERR_STAT_OFFSET); +} + +static unsigned short s3c_onenand_readw(void __iomem * addr) +{ + struct onenand_chip *this = onenand->mtd->priv; + int reg = addr - this->base; + int word_addr = reg >> 1; + int value; + + /* It's used for probing time */ + switch (reg) { + case ONENAND_REG_MANUFACTURER_ID: + return s3c_read_reg(MANUFACT_ID_OFFSET); + case ONENAND_REG_DEVICE_ID: + return s3c_read_reg(DEVICE_ID_OFFSET); + case ONENAND_REG_VERSION_ID: + return s3c_read_reg(FLASH_VER_ID_OFFSET); + case ONENAND_REG_DATA_BUFFER_SIZE: + return s3c_read_reg(DATA_BUF_SIZE_OFFSET); + case ONENAND_REG_TECHNOLOGY: + return s3c_read_reg(TECH_OFFSET); + case ONENAND_REG_SYS_CFG1: + return s3c_read_reg(MEM_CFG_OFFSET); + + /* Used at unlock all status */ + case ONENAND_REG_CTRL_STATUS: + return 0; + + case ONENAND_REG_WP_STATUS: + return ONENAND_WP_US; + + default: + break; + } + + /* BootRAM access control */ + if (reg < ONENAND_DATARAM && onenand->bootram_command) { + if (word_addr == 0) + return s3c_read_reg(MANUFACT_ID_OFFSET); + if (word_addr == 1) + return s3c_read_reg(DEVICE_ID_OFFSET); + if (word_addr == 2) + return s3c_read_reg(FLASH_VER_ID_OFFSET); + } + + value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff; + printk(KERN_INFO "s3c_onenand_readw: Illegal access" + " at reg 0x%x, value 0x%x\n", word_addr, value); + return value; +} + +static void s3c_onenand_writew(unsigned short value, void __iomem * addr) +{ + struct onenand_chip *this = onenand->mtd->priv; + int reg = addr - this->base; + int word_addr = reg >> 1; + + /* It's used for probing time */ + switch (reg) { + case ONENAND_REG_SYS_CFG1: + s3c_write_reg(value, MEM_CFG_OFFSET); + return; + + case ONENAND_REG_START_ADDRESS1: + case ONENAND_REG_START_ADDRESS2: + return; + + /* Lock/lock-tight/unlock/unlock_all */ + case ONENAND_REG_START_BLOCK_ADDRESS: + return; + + default: + break; + } + + /* BootRAM access control */ + if (reg < ONENAND_DATARAM) { + if (value == ONENAND_CMD_READID) { + onenand->bootram_command = 1; + return; + } + if (value == ONENAND_CMD_RESET) { + s3c_write_reg(ONENAND_MEM_RESET_COLD, MEM_RESET_OFFSET); + onenand->bootram_command = 0; + return; + } + } + + printk(KERN_INFO "s3c_onenand_writew: Illegal access" + " at reg 0x%x, value 0x%x\n", word_addr, value); + + s3c_write_cmd(value, CMD_MAP_11(word_addr)); +} + +static int s3c_onenand_wait(struct mtd_info *mtd, int state) +{ + unsigned int flags = INT_ACT; + unsigned int stat, ecc; + unsigned long timeout = 0x100000; + + switch (state) { + case FL_READING: + flags |= BLK_RW_CMP | LOAD_CMP; + break; + case FL_WRITING: + flags |= BLK_RW_CMP | PGM_CMP; + break; + case FL_ERASING: + flags |= BLK_RW_CMP | ERS_CMP; + break; + case FL_LOCKING: + flags |= BLK_RW_CMP; + break; + default: + break; + } + + while (1 && timeout--) { + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + if (stat & flags) + break; + for (stat = 0; stat < 2000; stat++) + continue; + } + + /* To get correct interrupt status in timeout case */ + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + s3c_write_reg(stat, INT_ERR_ACK_OFFSET); + + /* + * + * In the Spec. it checks the controller status first + * However if you get the correct information in case of + * power off recovery (POR) test, it should read ECC status first + */ + if (stat & LOAD_CMP) { + ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET); + if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) { + printk(KERN_INFO "onenand_wait: ECC error = 0x%04x\n", ecc); + mtd->ecc_stats.failed++; + return -EBADMSG; + } +#if 0 + } else if (ecc & ONENAND_ECC_1BIT_ALL) { + printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); + mtd->ecc_stats.corrected++; + } +#endif + } + + if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) { + printk(KERN_INFO "s3c_onenand_wait: controller error = 0x%04x\n", stat); + if (stat & LOCKED_BLK) + printk(KERN_INFO "s3c_onenand_wait: it's locked error = 0x%04x\n", stat); + + return -EIO; + } + + return 0; +} + +static int s3c_onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, + size_t len) +{ + struct onenand_chip *this = mtd->priv; + unsigned int *m, *s; + int fba, fpa, fsa = 0; + unsigned int mem_addr; + int i, mcount, scount; + int index; + + fba = (int) (addr >> this->erase_shift); + fpa = (int) (addr >> this->page_shift); + fpa &= this->page_mask; + + mem_addr = onenand->mem_addr(fba, fpa, fsa); + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + case ONENAND_CMD_BUFFERRAM: + ONENAND_SET_NEXT_BUFFERRAM(this); + default: + break; + } + + index = ONENAND_CURRENT_BUFFERRAM(this); + + /* + * Emulate Two BufferRAMs and access with 4 bytes pointer + */ + m = (unsigned int *) onenand->page_buf; + s = (unsigned int *) onenand->oob_buf; + + if (index) { + m += (this->writesize >> 2); + s += (mtd->oobsize >> 2); + } + + mcount = mtd->writesize >> 2; + scount = mtd->oobsize >> 2; + + switch (cmd) { + case ONENAND_CMD_READ: + /* Main */ + for (i = 0; i < mcount; i++) + *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + return 0; + + case ONENAND_CMD_READOOB: + s3c_write_reg(TSRF, TRANS_SPARE_OFFSET); + /* Main */ + for (i = 0; i < mcount; i++) + *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + + /* Spare */ + for (i = 0; i < scount; i++) + *s++ = s3c_read_cmd(CMD_MAP_01(mem_addr)); + + s3c_write_reg(0, TRANS_SPARE_OFFSET); + return 0; + + case ONENAND_CMD_PROG: + /* Main */ + for (i = 0; i < mcount; i++) + s3c_write_cmd(*m++, CMD_MAP_01(mem_addr)); + return 0; + + case ONENAND_CMD_PROGOOB: + s3c_write_reg(TSRF, TRANS_SPARE_OFFSET); + + /* Main - dummy write */ + for (i = 0; i < mcount; i++) + s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr)); + + /* Spare */ + for (i = 0; i < scount; i++) + s3c_write_cmd(*s++, CMD_MAP_01(mem_addr)); + + s3c_write_reg(0, TRANS_SPARE_OFFSET); + return 0; + + case ONENAND_CMD_UNLOCK_ALL: + s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr)); + return 0; + + case ONENAND_CMD_ERASE: + s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr)); + return 0; + + default: + break; + } + + return 0; +} + +static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area) +{ + struct onenand_chip *this = mtd->priv; + int index = ONENAND_CURRENT_BUFFERRAM(this); + unsigned char *p; + + if (area == ONENAND_DATARAM) { + p = (unsigned char *) onenand->page_buf; + if (index == 1) + p += this->writesize; + } else { + p = (unsigned char *) onenand->oob_buf; + if (index == 1) + p += mtd->oobsize; + } + + return p; +} + +static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, + unsigned char *buffer, int offset, + size_t count) +{ + unsigned char *p; + + p = s3c_get_bufferram(mtd, area); + memcpy(buffer, p + offset, count); + return 0; +} + +static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, + const unsigned char *buffer, int offset, + size_t count) +{ + unsigned char *p; + + p = s3c_get_bufferram(mtd, area); + memcpy(p + offset, buffer, count); + return 0; +} + +static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state) +{ + unsigned int flags = INT_ACT | LOAD_CMP; + unsigned int stat; + unsigned long timeout = 0x10000; + + while (1 && timeout--) { + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + if (stat & flags) + break; + } + /* To get correct interrupt status in timeout case */ + stat = s3c_read_reg(INT_ERR_STAT_OFFSET); + s3c_write_reg(stat, INT_ERR_ACK_OFFSET); + + if (stat & LD_FAIL_ECC_ERR) { + s3c_onenand_reset(); + return ONENAND_BBT_READ_ERROR; + } + + if (stat & LOAD_CMP) { + int ecc = s3c_read_reg(ECC_ERR_STAT_OFFSET); + if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) { + s3c_onenand_reset(); + return ONENAND_BBT_READ_ERROR; + } + } + + return 0; +} + +static void s3c_onenand_check_lock_status(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned int block, end; + int tmp; + + end = this->chipsize >> this->erase_shift; + + for (block = 0; block < end; block++) { + tmp = s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0))); + + if (s3c_read_reg(INT_ERR_STAT_OFFSET) & LOCKED_BLK) { + printf("block %d is write-protected!\n", block); + s3c_write_reg(LOCKED_BLK, INT_ERR_ACK_OFFSET); + } + } +} + +static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd) +{ + struct onenand_chip *this = mtd->priv; + int start, end, start_mem_addr, end_mem_addr; + + start = ofs >> this->erase_shift; + start_mem_addr = onenand->mem_addr(start, 0, 0); + end = start + (len >> this->erase_shift) - 1; + end_mem_addr = onenand->mem_addr(end, 0, 0); + + if (cmd == ONENAND_CMD_LOCK) { + s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr)); + s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr)); + } else { + s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr)); + s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr)); + } + + this->wait(mtd, FL_LOCKING); +} + +static void s3c_onenand_unlock_all(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + loff_t ofs = 0; + size_t len = this->chipsize; + + if (this->options & ONENAND_HAS_UNLOCK_ALL) { + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); + + /* No need to check return value */ + this->wait(mtd, FL_LOCKING); + + /* Workaround for all block unlock in DDP */ + if (!ONENAND_IS_DDP(this)) { + s3c_onenand_check_lock_status(mtd); + return; + } + + /* All blocks on another chip */ + ofs = this->chipsize >> 1; + len = this->chipsize >> 1; + } + + s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + +// s3c_onenand_check_lock_status(mtd); +} + +#ifdef CONFIG_S3C64XX +static void s3c_set_width_regs(struct onenand_chip *this) +{ + int dev_id, density; + int fba, fpa, fsa; + int dbs_dfs; + + dev_id = DEVICE_ID0_REG; + + density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf; + dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP); + + fba = density + 7; + if (dbs_dfs) + fba--; /* Decrease the fba */ + fpa = 6; + if (density >= ONENAND_DEVICE_DENSITY_512Mb) + fsa = 2; + else + fsa = 1; + + DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu", + FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG, + DDP_DEVICE_REG); + + DPRINTK("mem_cfg0 0x%lx, sync mode %lu, dev_page_size %lu, BURST LEN %lu", + MEM_CFG0_REG, + SYNC_MODE_REG, + DEV_PAGE_SIZE_REG, + BURST_LEN0_REG + ); + + DEV_PAGE_SIZE_REG = 0x1; + + FBA_WIDTH0_REG = fba; + FPA_WIDTH0_REG = fpa; + FSA_WIDTH0_REG = fsa; + DBS_DFS_WIDTH0_REG = dbs_dfs; +} +#endif + +void s3c_onenand_init(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + + onenand = malloc(sizeof(struct s3c_onenand)); + if (!onenand) + return; + + onenand->page_buf = malloc(SZ_4K * sizeof(char)); + if (!onenand->page_buf) + return; + memset(onenand->page_buf, 0xFF, SZ_4K); + + onenand->oob_buf = malloc(128 * sizeof(char)); + if (!onenand->oob_buf) + return; + memset(onenand->oob_buf, 0xFF, 128); + + onenand->mtd = mtd; + + /* S5PC100 specific values */ + onenand->base = (void *) 0xE7100000; + onenand->ahb_addr = (void *) 0xB0000000; + onenand->mem_addr = s5pc100_mem_addr; + + this->read_word = s3c_onenand_readw; + this->write_word = s3c_onenand_writew; + + this->wait = s3c_onenand_wait; + this->bbt_wait = s3c_onenand_bbt_wait; + this->unlock_all = s3c_onenand_unlock_all; + this->command = s3c_onenand_command; + + this->read_bufferram = onenand_read_bufferram; + this->write_bufferram = onenand_write_bufferram; - - this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK; +} diff --cc include/configs/s5pc100_universal.h index b225156,0000000..a2a52ce mode 100644,000000..100644 --- a/include/configs/s5pc100_universal.h +++ b/include/configs/s5pc100_universal.h @@@ -1,289 -1,0 +1,291 @@@ +/* + * Copyright (C) 2009 Samsung Electronics + * Minkyu Kang + * + * Configuation settings for the SAMSUNG Universal (s5pc100) board. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#include + +/* + * High Level Configuration Options + * (easy to change) + */ +#define CONFIG_ARMCORTEXA8 1 /* This is an ARM V7 CPU core */ +#define CONFIG_SAMSUNG 1 /* in a SAMSUNG core */ +#define CONFIG_S5PC1XX 1 /* which is in a S5PC1XX Family */ +#define CONFIG_S5PC100 1 /* which is in a S5PC100 */ +#define CONFIG_UNIVERSAL 1 /* working with Universal */ + +#include /* get chip and board defs */ + +#define CONFIG_SYS_SDRAM_BASE 0x20000000 + +/* input clock of PLL: Universal has 12MHz input clock */ +#define CONFIG_SYS_CLK_FREQ 12000000 + +#if !defined(CONFIG_NAND_SPL) && (TEXT_BASE >= 0xc0000000) +#define CONFIG_ENABLE_MMU +#endif + +#define CONFIG_MEMORY_UPPER_CODE + +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_CMDLINE_TAG +#define CONFIG_INITRD_TAG +#define CONFIG_REVISION_TAG + +/* Clock Defines */ +#define V_OSCK 26000000 /* Clock output from T2 */ +#define V_SCLK (V_OSCK >> 1) + +/* + * Architecture magic and machine type + */ +#define MACH_TYPE 3000 + +#define CONFIG_DISPLAY_CPUINFO + +#undef CONFIG_SKIP_RELOCATE_UBOOT + +/* + * Size of malloc() pool + */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 1024 * 1024) +#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes for initial data */ + +/* + * select serial console configuration + */ +#define CONFIG_SERIAL2 1 /* we use SERIAL 2 on S5PC100 */ + +#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ +#ifdef CONFIG_SYS_HUSH_PARSER +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#endif + +#define CONFIG_CMDLINE_EDITING + +/* allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_BAUDRATE 115200 +#define CONFIG_L2_OFF + +/*********************************************************** + * Command definition + ***********************************************************/ +#include + +#undef CONFIG_CMD_LOADB +#undef CONFIG_CMD_LOADS +#undef CONFIG_CMD_BOOTD +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_XIMG +#undef CONFIG_CMD_NAND +#undef CONFIG_CMD_IMLS +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +#undef CONFIG_CMD_NET +#define CONFIG_CMD_CACHE +#define CONFIG_CMD_REGINFO +#define CONFIG_CMD_ONENAND +#define CONFIG_CMD_ELF +#define CONFIG_CMD_FAT +#define CONFIG_CMD_MTDPARTS + +#define CONFIG_BOOTDELAY 1 + +#define CONFIG_ZERO_BOOTDELAY_CHECK + ++#define CONFIG_MTD_DEVICE +#define CONFIG_MTD_PARTITIONS + +#define MTDIDS_DEFAULT "onenand0=s3c-onenand" +#define MTDPARTS_DEFAULT "mtdparts=s3c-onenand:256k(bootloader)"\ + ",128k@0x40000(params)"\ + ",3m@0x60000(kernel)"\ + ",16m@0x260000(test)"\ + ",-(UBI)" + +#define NORMAL_MTDPARTS_DEFAULT MTDPARTS_DEFAULT + +#if 1 +#define CONFIG_BOOTCOMMAND "run ubifsboot" +#else +#define CONFIG_BOOTCOMMAND "bootm 0x21008000" +#endif + +#define CONFIG_RAMDISK_BOOT "root=/dev/ram0 rw rootfstype=ext2" \ + " console=ttySAC2,115200n8" \ + " ${meminfo}" + +#define CONFIG_COMMON_BOOT "console=ttySAC2,115200n8" \ + " ${meminfo} " \ + " " MTDPARTS_DEFAULT + +#define CONFIG_BOOTARGS "root=/dev/mtdblock5 ubi.mtd=4" \ + " rootfstype=cramfs " CONFIG_COMMON_BOOT + ++#define CONFIG_USE_BIG_UBOOT 1 +#ifdef CONFIG_USE_BIG_UBOOT +#define CONFIG_UPDATEB "updateb=onenand erase 0x0 0x40000;" \ + " onenand write 0x22008000 0x0 0x40000\0" +#else +#define CONFIG_UPDATEB "updateb=onenand erase 0x0 0x40000;" \ + " onenand write 0x22008000 0x0 0x20000;" \ + " onenand write 0x22008000 0x20000 0x20000\0" +#endif + +#define CONFIG_ENV_OVERWRITE +#define CONFIG_EXTRA_ENV_SETTINGS \ + CONFIG_UPDATEB \ + "updatek=onenand erase 0x60000 0x200000;" \ + " onenand write 0x21008000 0x60000 0x200000\0" \ + "updateu=onenand erase block 147-4095;" \ + " onenand write 0x22000000 0x1260000 0x8C0000\0" \ + "bootk=onenand read 0x20007FC0 0x60000 0x300000;" \ + " bootm 0x20007FC0\0" \ + "flashboot=set bootargs root=/dev/mtdblock${bootblock}" \ + " rootfstype=${rootfstype}" \ + " ubi.mtd=${ubiblock} ${opts} " CONFIG_COMMON_BOOT "; run bootk\0" \ + "ubifsboot=set bootargs root=ubi0!rootfs rootfstype=ubifs" \ + " ubi.mtd=${ubiblock} ${opts} " CONFIG_COMMON_BOOT "; run bootk\0" \ + "boottrace=setenv opts initcall_debug; run bootcmd\0" \ + "android=set bootargs root=ubi0!ramdisk ubi.mtd=${ubiblock}" \ + " rootfstype=ubifs init=/init.sh " CONFIG_COMMON_BOOT "; run bootk\0" \ + "nfsboot=set bootargs root=/dev/nfs ubi.mtd=${ubiblock}" \ + " nfsroot=${nfsroot},nolock ip=${ipaddr}:${serverip}:${gatewayip}:" \ + " ${netmask}:nowplus:usb0:off " CONFIG_COMMON_BOOT "; run bootk\0" \ + "ramboot=set bootargs " CONFIG_RAMDISK_BOOT \ + " initrd=0x23000000,8M ramdisk=8192\0" \ + "rootfstype=cramfs\0" \ + "mtdparts=" MTDPARTS_DEFAULT "\0" \ + "meminfo=mem=208M\0" \ + "nfsroot=/nfsroot/arm\0" \ + "bootblock=5\0" \ + "ubiblock=4\0" \ + "ubi=enabled" + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_PROMPT "Universal # " /* Monitor Command Prompt */ +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE 384 /* Print Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE /* Boot Argument Buffer Size */ + +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE /* memtest works on */ +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x4e00000) + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x4e00000) + +#define CONFIG_SYS_TIMERBASE (OMAP34XX_GPT2) +#define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */ +#define CONFIG_SYS_HZ 2085900 /* at PCLK 66.75MHz */ + +/* valid baudrates */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE 0x40000 /* regular stack 256KB */ + +/******************************* + Support Clock Settings(APLL) + ******************************* + ARMCLK HCLKD0 PCLKD0 + ------------------------------- + 667 166 83 + 600 150 75 + 533 133 66 + 500 166 66 + 467 117 59 + 400 100 50 + *******************************/ + +#define CONFIG_CLK_667_166_83 +/*#define CONFIG_CLK_600_150_75*/ +/*#define CONFIG_CLK_533_133_66*/ +/*#define CONFIG_CLK_500_166_66*/ +/*#define CONFIG_CLK_467_117_59*/ +/*#define CONFIG_CLK_400_100_50*/ + +/* Universal has 2 banks of DRAM, but swap the bank */ +#define CONFIG_NR_DRAM_BANKS 2 +#define CONFIG_S5PC1XX_SWAP_MEMORY_BANK 1 +#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE /* OneDRAM Bank #0 */ +#define PHYS_SDRAM_1_SIZE 0x05000000 /* 80 MB in Bank #0 */ +#define PHYS_SDRAM_2 0x28000000 /* MobileDDR Bank #1 */ +#define PHYS_SDRAM_2_SIZE 0x08000000 /* 128 MB in Bank #1 */ + +#define CONFIG_SYS_MONITOR_BASE 0x00000000 + +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#define CONFIG_SYS_NO_FLASH 1 + +#define CONFIG_SYS_MONITOR_LEN SZ_256K /* Reserve 2 sectors */ + +#ifdef CONFIG_ENABLE_MMU +#define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000 +#else +#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE +#endif + +/* Boot configuration (define only one of next 3) */ +//#define CONFIG_BOOT_ONENAND + +#define CONFIG_ENV_IS_IN_ONENAND 1 +#define CONFIG_ENV_SIZE 0x20000 +#define CONFIG_ENV_ADDR 0x40000 +#define CONFIG_ENV_OFFSET 0x40000 + +#define CONFIG_USE_ONENAND_BOARD_INIT +#define CONFIG_SYS_ONENAND_BASE 0x00000000 + +#define CONFIG_DOS_PARTITION 1 + +#define CONFIG_MISC_INIT_R + +/* I2C */ +#define CONFIG_DRIVER_S5PC1XX_I2C +#define CONFIG_HARD_I2C 1 +#define CONFIG_SYS_I2C_SPEED 50000 +#define CONFIG_SYS_I2C_SLAVE 0xFE +#define CONFIG_SYS_I2C_0 1 + +/* USB Downloader */ +#define CONFIG_CMD_USBDOWN +#define CONFIG_SAMSUNG_USB +#define CONFIG_OTG_CLK_OSCC +#define CONFIG_SYS_DOWN_ADDR CONFIG_SYS_SDRAM_BASE +#define CONFIG_RAMDISK_ADDR 0x23000000 + +#endif /* __CONFIG_H */