diff options
author | Tom Rini <trini@ti.com> | 2012-11-26 14:53:33 -0700 |
---|---|---|
committer | Tom Rini <trini@ti.com> | 2012-11-26 14:53:33 -0700 |
commit | dfe161032d007e4901064ab36b58f054126b1f35 (patch) | |
tree | 5389a370fbb7cfcf070669a0dc190fc765a3c985 /drivers | |
parent | d6bc7dcc0347765c4621c253ea68b07985d8c1f0 (diff) | |
parent | 3287f6d3858faee768a7c47515bd21914ad591a2 (diff) | |
download | u-boot-imx-dfe161032d007e4901064ab36b58f054126b1f35.zip u-boot-imx-dfe161032d007e4901064ab36b58f054126b1f35.tar.gz u-boot-imx-dfe161032d007e4901064ab36b58f054126b1f35.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/fsl_law.c | 333 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 34 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_spl.c | 168 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_ifc_nand.c | 64 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 9 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 188 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 3 | ||||
-rw-r--r-- | drivers/serial/serial_ns16550.c | 4 |
10 files changed, 426 insertions, 380 deletions
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index cdec88b..1f035e6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -27,7 +27,6 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o -COBJS-$(CONFIG_FSL_LAW) += fsl_law.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_NS87308) += ns87308.o diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c deleted file mode 100644 index 223cd5d..0000000 --- a/drivers/misc/fsl_law.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright 2008-2011 Freescale Semiconductor, Inc. - * - * (C) Copyright 2000 - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <common.h> -#include <linux/compiler.h> -#include <asm/fsl_law.h> -#include <asm/io.h> - -DECLARE_GLOBAL_DATA_PTR; - -#define FSL_HW_NUM_LAWS CONFIG_SYS_FSL_NUM_LAWS - -#ifdef CONFIG_FSL_CORENET -#define LAW_BASE (CONFIG_SYS_FSL_CORENET_CCM_ADDR) -#define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar) -#define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh) -#define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl) -#define LAWBAR_SHIFT 0 -#else -#define LAW_BASE (CONFIG_SYS_IMMR + 0xc08) -#define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2) -#define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x) -#define LAWBAR_SHIFT 12 -#endif - - -static inline phys_addr_t get_law_base_addr(int idx) -{ -#ifdef CONFIG_FSL_CORENET - return (phys_addr_t) - ((u64)in_be32(LAWBARH_ADDR(idx)) << 32) | - in_be32(LAWBARL_ADDR(idx)); -#else - return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT; -#endif -} - -static inline void set_law_base_addr(int idx, phys_addr_t addr) -{ -#ifdef CONFIG_FSL_CORENET - out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff); - out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32); -#else - out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT); -#endif -} - -void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id) -{ - gd->used_laws |= (1 << idx); - - out_be32(LAWAR_ADDR(idx), 0); - set_law_base_addr(idx, addr); - out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz); - - /* Read back so that we sync the writes */ - in_be32(LAWAR_ADDR(idx)); -} - -void disable_law(u8 idx) -{ - gd->used_laws &= ~(1 << idx); - - out_be32(LAWAR_ADDR(idx), 0); - set_law_base_addr(idx, 0); - - /* Read back so that we sync the writes */ - in_be32(LAWAR_ADDR(idx)); - - return; -} - -#ifndef CONFIG_NAND_SPL -static int get_law_entry(u8 i, struct law_entry *e) -{ - u32 lawar; - - lawar = in_be32(LAWAR_ADDR(i)); - - if (!(lawar & LAW_EN)) - return 0; - - e->addr = get_law_base_addr(i); - e->size = lawar & 0x3f; - e->trgt_id = (lawar >> 20) & 0xff; - - return 1; -} -#endif - -int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) -{ - u32 idx = ffz(gd->used_laws); - - if (idx >= FSL_HW_NUM_LAWS) - return -1; - - set_law(idx, addr, sz, id); - - return idx; -} - -#ifndef CONFIG_NAND_SPL -int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) -{ - u32 idx; - - /* we have no LAWs free */ - if (gd->used_laws == -1) - return -1; - - /* grab the last free law */ - idx = __ilog2(~(gd->used_laws)); - - if (idx >= FSL_HW_NUM_LAWS) - return -1; - - set_law(idx, addr, sz, id); - - return idx; -} - -struct law_entry find_law(phys_addr_t addr) -{ - struct law_entry entry; - int i; - - entry.index = -1; - entry.addr = 0; - entry.size = 0; - entry.trgt_id = 0; - - for (i = 0; i < FSL_HW_NUM_LAWS; i++) { - u64 upper; - - if (!get_law_entry(i, &entry)) - continue; - - upper = entry.addr + (2ull << entry.size); - if ((addr >= entry.addr) && (addr < upper)) { - entry.index = i; - break; - } - } - - return entry; -} - -void print_laws(void) -{ - int i; - u32 lawar; - - printf("\nLocal Access Window Configuration\n"); - for (i = 0; i < FSL_HW_NUM_LAWS; i++) { - lawar = in_be32(LAWAR_ADDR(i)); -#ifdef CONFIG_FSL_CORENET - printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x", - i, in_be32(LAWBARH_ADDR(i)), - i, in_be32(LAWBARL_ADDR(i))); -#else - printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i))); -#endif - printf(" LAWAR%02d: 0x%08x\n", i, lawar); - printf("\t(EN: %d TGT: 0x%02x SIZE: ", - (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff); - print_size(lawar_size(lawar), ")\n"); - } - - return; -} - -/* use up to 2 LAWs for DDR, used the last available LAWs */ -int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id) -{ - u64 start_align, law_sz; - int law_sz_enc; - - if (start == 0) - start_align = 1ull << (LAW_SIZE_32G + 1); - else - start_align = 1ull << (ffs64(start) - 1); - law_sz = min(start_align, sz); - law_sz_enc = __ilog2_u64(law_sz) - 1; - - if (set_last_law(start, law_sz_enc, id) < 0) - return -1; - - /* recalculate size based on what was actually covered by the law */ - law_sz = 1ull << __ilog2_u64(law_sz); - - /* do we still have anything to map */ - sz = sz - law_sz; - if (sz) { - start += law_sz; - - start_align = 1ull << (ffs64(start) - 1); - law_sz = min(start_align, sz); - law_sz_enc = __ilog2_u64(law_sz) - 1; - - if (set_last_law(start, law_sz_enc, id) < 0) - return -1; - } else { - return 0; - } - - /* do we still have anything to map */ - sz = sz - law_sz; - if (sz) - return 1; - - return 0; -} -#endif - -void init_laws(void) -{ - int i; - -#if FSL_HW_NUM_LAWS < 32 - gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1); -#elif FSL_HW_NUM_LAWS == 32 - gd->used_laws = 0; -#else -#error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes -#endif - - /* - * Any LAWs that were set up before we booted assume they are meant to - * be around and mark them used. - */ - for (i = 0; i < FSL_HW_NUM_LAWS; i++) { - u32 lawar = in_be32(LAWAR_ADDR(i)); - - if (lawar & LAW_EN) - gd->used_laws |= (1 << i); - } - -#if defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) - /* - * in NAND boot we've already parsed the law_table and setup those LAWs - * so don't do it again. - */ - return; -#endif - - for (i = 0; i < num_law_entries; i++) { - if (law_table[i].index == -1) - set_next_law(law_table[i].addr, law_table[i].size, - law_table[i].trgt_id); - else - set_law(law_table[i].index, law_table[i].addr, - law_table[i].size, law_table[i].trgt_id); - } - -#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE - /* check RCW to get which port is used for boot */ - ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; - u32 bootloc = in_be32(&gur->rcwsr[6]); - /* - * in SRIO or PCIE boot we need to set specail LAWs for - * SRIO or PCIE interfaces. - */ - switch ((bootloc & FSL_CORENET_RCWSR6_BOOT_LOC) >> 23) { - case 0x0: /* boot from PCIE1 */ - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_1); - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_1); - break; - case 0x1: /* boot from PCIE2 */ - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_2); - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_2); - break; - case 0x2: /* boot from PCIE3 */ - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_3); - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_PCIE_3); - break; - case 0x8: /* boot from SRIO1 */ - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_RIO_1); - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_RIO_1); - break; - case 0x9: /* boot from SRIO2 */ - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_RIO_2); - set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, - LAW_SIZE_1M, - LAW_TRGT_IF_RIO_2); - break; - default: - break; - } -#endif - - return ; -} diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index beb99ca..28e52bd 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,21 +26,33 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnand.o ifdef CONFIG_CMD_NAND + ifdef CONFIG_SPL_BUILD -ifdef CONFIG_SPL_NAND_SIMPLE -COBJS-y += nand_spl_simple.o -endif -ifdef CONFIG_SPL_NAND_LOAD -COBJS-y += nand_spl_load.o + +ifdef CONFIG_SPL_NAND_DRIVERS +NORMAL_DRIVERS=y endif -else + +COBJS-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o +COBJS-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o +COBJS-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o +COBJS-$(CONFIG_SPL_NAND_BASE) += nand_base.o + +else # not spl + +NORMAL_DRIVERS=y + COBJS-y += nand.o COBJS-y += nand_bbt.o COBJS-y += nand_ids.o COBJS-y += nand_util.o -endif COBJS-y += nand_ecc.o COBJS-y += nand_base.o + +endif # not spl + +ifdef NORMAL_DRIVERS + COBJS-$(CONFIG_NAND_ECC_BCH) += nand_bch.o COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o @@ -65,7 +77,13 @@ COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o COBJS-$(CONFIG_TEGRA_NAND) += tegra_nand.o COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o -endif + +else # minimal SPL drivers + +COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o + +endif # drivers +endif # nand COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 9076ad4..834a8a6 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -748,7 +748,7 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) /* set up nand options */ nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT; + NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; nand->controller = &elbc_ctrl->controller; nand->priv = priv; diff --git a/drivers/mtd/nand/fsl_elbc_spl.c b/drivers/mtd/nand/fsl_elbc_spl.c new file mode 100644 index 0000000..50ff4fe --- /dev/null +++ b/drivers/mtd/nand/fsl_elbc_spl.c @@ -0,0 +1,168 @@ +/* + * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine + * + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + * Author: Scott Wood <scottwood@freescale.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/fsl_lbc.h> +#include <nand.h> + +#define WINDOW_SIZE 8192 + +static void nand_wait(void) +{ + fsl_lbc_t *regs = LBC_BASE_ADDR; + + for (;;) { + uint32_t status = in_be32(®s->ltesr); + + if (status == 1) + return; + + if (status & 1) { + puts("read failed (ltesr)\n"); + for (;;); + } + } +} + +static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) +{ + fsl_lbc_t *regs = LBC_BASE_ADDR; + uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; + const int large = CONFIG_SYS_NAND_OR_PRELIM & OR_FCM_PGS; + const int block_shift = large ? 17 : 14; + const int block_size = 1 << block_shift; + const int page_size = large ? 2048 : 512; + const int bad_marker = large ? page_size + 0 : page_size + 5; + int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; + int pos = 0; + char *dst = vdst; + + if (offs & (block_size - 1)) { + puts("bad offset\n"); + for (;;); + } + + if (large) { + fmr |= FMR_ECCM; + out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | + (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_CW1 << FIR_OP3_SHIFT) | + (FIR_OP_RBW << FIR_OP4_SHIFT)); + } else { + out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_RBW << FIR_OP3_SHIFT)); + } + + out_be32(®s->fbcr, 0); + clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); + + while (pos < uboot_size) { + int i = 0; + out_be32(®s->fbar, offs >> block_shift); + + do { + int j; + unsigned int page_offs = (offs & (block_size - 1)) << 1; + + out_be32(®s->ltesr, ~0); + out_be32(®s->lteatr, 0); + out_be32(®s->fpar, page_offs); + out_be32(®s->fmr, fmr); + out_be32(®s->lsor, 0); + nand_wait(); + + page_offs %= WINDOW_SIZE; + + /* + * If either of the first two pages are marked bad, + * continue to the next block. + */ + if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { + puts("skipping\n"); + offs = (offs + block_size) & ~(block_size - 1); + pos &= ~(block_size - 1); + break; + } + + for (j = 0; j < page_size; j++) + dst[pos + j] = buf[page_offs + j]; + + pos += page_size; + offs += page_size; + } while ((offs & (block_size - 1)) && (pos < uboot_size)); + } + + return 0; +} + +/* + * The main entry for NAND booting. It's necessary that SDRAM is already + * configured and available since this code loads the main U-Boot image + * from NAND into SDRAM and starts it from there. + */ +void nand_boot(void) +{ + __attribute__((noreturn)) void (*uboot)(void); + /* + * Load U-Boot image from NAND into RAM + */ + nand_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_SIZE, + (void *)CONFIG_SYS_NAND_U_BOOT_DST); + +#ifdef CONFIG_NAND_ENV_DST + nand_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST); + +#ifdef CONFIG_ENV_OFFSET_REDUND + nand_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); +#endif +#endif + +#ifdef CONFIG_SPL_FLUSH_IMAGE + /* + * Clean d-cache and invalidate i-cache, to + * make sure that no stale data is executed. + */ + flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif + + puts("transfering control\n"); + /* + * Jump to U-Boot image + */ + uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; + (*uboot)(); +} diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index b3b7c70..0878bec 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -30,6 +30,7 @@ #include <asm/errno.h> #include <asm/fsl_ifc.h> +#define FSL_IFC_V1_1_0 0x01010000 #define MAX_BANKS 4 #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ @@ -738,11 +739,66 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) { } +static void fsl_ifc_sram_init(void) +{ + struct fsl_ifc *ifc = ifc_ctrl->regs; + uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0; + long long end_tick; + + cs = ifc_ctrl->cs_nand >> IFC_NAND_CSEL_SHIFT; + + /* Save CSOR and CSOR_ext */ + csor = in_be32(&ifc_ctrl->regs->csor_cs[cs].csor); + csor_ext = in_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext); + + /* chage PageSize 8K and SpareSize 1K*/ + csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; + out_be32(&ifc_ctrl->regs->csor_cs[cs].csor, csor_8k); + out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, 0x0000400); + + /* READID */ + out_be32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); + out_be32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); + out_be32(&ifc->ifc_nand.row3, 0x0); + + out_be32(&ifc->ifc_nand.nand_fbcr, 0x0); + + /* Program ROW0/COL0 */ + out_be32(&ifc->ifc_nand.row0, 0x0); + out_be32(&ifc->ifc_nand.col0, 0x0); + + /* set the chip select for NAND Transaction */ + out_be32(&ifc->ifc_nand.nand_csel, ifc_ctrl->cs_nand); + + /* start read seq */ + out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); + + /* wait for NAND Machine complete flag or timeout */ + end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks(); + + while (end_tick > get_ticks()) { + ifc_ctrl->status = in_be32(&ifc->ifc_nand.nand_evter_stat); + + if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC) + break; + } + + out_be32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status); + + /* Restore CSOR and CSOR_ext */ + out_be32(&ifc_ctrl->regs->csor_cs[cs].csor, csor); + out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext); +} + int board_nand_init(struct nand_chip *nand) { struct fsl_ifc_mtd *priv; struct nand_ecclayout *layout; - uint32_t cspr = 0, csor = 0; + uint32_t cspr = 0, csor = 0, ver = 0; if (!ifc_ctrl) { fsl_ifc_ctrl_init(); @@ -797,7 +853,7 @@ int board_nand_init(struct nand_chip *nand) /* set up nand options */ nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT; + NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; if (cspr & CSPR_PORT_SIZE_16) { nand->read_byte = fsl_ifc_read_byte16; @@ -861,5 +917,9 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_SOFT; } + ver = in_be32(&ifc_ctrl->regs->ifc_rev); + if (ver == FSL_IFC_V1_1_0) + fsl_ifc_sram_init(); + return 0; } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d3b71a5..a2d06be 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1245,7 +1245,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (unlikely(ops->mode == MTD_OOB_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); - else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) + else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && + !oob) ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else @@ -1256,7 +1257,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { - if (!NAND_SUBPAGE_READ(chip) && !oob && + if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && !(mtd->ecc_stats.failed - stats.failed)) chip->pagebuf = realpage; memcpy(buf, chip->buffers->databuf + col, bytes); @@ -3150,6 +3151,10 @@ int nand_scan_tail(struct mtd_info *mtd) /* Invalidate the pagebuffer reference */ chip->pagebuf = -1; + /* Large page NAND with SOFT_ECC should support subpage reads */ + if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9)) + chip->options |= NAND_SUBPAGE_READ; + /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index c4752a7..2ba0c5e 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -50,8 +50,8 @@ #include <nand.h> #include <jffs2/jffs2.h> -typedef struct erase_info erase_info_t; -typedef struct mtd_info mtd_info_t; +typedef struct erase_info erase_info_t; +typedef struct mtd_info mtd_info_t; /* support only for native endian JFFS2 */ #define cpu_to_je16(x) (x) @@ -59,7 +59,7 @@ typedef struct mtd_info mtd_info_t; /** * nand_erase_opts: - erase NAND flash with support for various options - * (jffs2 formating) + * (jffs2 formatting) * * @param meminfo NAND device to erase * @param opts options, @see struct nand_erase_options @@ -80,8 +80,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) struct mtd_oob_ops oob_opts; struct nand_chip *chip = meminfo->priv; - if ((opts->offset & (meminfo->writesize - 1)) != 0) { - printf("Attempt to erase non page aligned data\n"); + if ((opts->offset & (meminfo->erasesize - 1)) != 0) { + printf("Attempt to erase non block-aligned data\n"); return -1; } @@ -94,8 +94,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) erase_length = lldiv(opts->length + meminfo->erasesize - 1, meminfo->erasesize); - cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); - cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); cleanmarker.totlen = cpu_to_je32(8); /* scrub option allows to erase badblock. To prevent internal @@ -118,7 +118,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) erased_length < erase_length; erase.addr += meminfo->erasesize) { - WATCHDOG_RESET (); + WATCHDOG_RESET(); if (!opts->scrub && bbtest) { int ret = meminfo->block_isbad(meminfo, erase.addr); @@ -259,7 +259,7 @@ int nand_lock(struct mtd_info *mtd, int tight) * flash * * @param mtd nand mtd instance - * @param offset page address to query (muss be page aligned!) + * @param offset page address to query (must be page-aligned!) * * @return -1 in case of error * >0 lock status: @@ -281,7 +281,7 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) if ((offset & (mtd->writesize - 1)) != 0) { - printf ("nand_get_lock_status: " + printf("nand_get_lock_status: " "Start address must be beginning of " "nand page!\n"); ret = -1; @@ -332,20 +332,20 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, /* check the WP bit */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { - printf ("nand_unlock: Device is write protected!\n"); + printf("nand_unlock: Device is write protected!\n"); ret = -1; goto out; } if ((start & (mtd->erasesize - 1)) != 0) { - printf ("nand_unlock: Start address must be beginning of " + printf("nand_unlock: Start address must be beginning of " "nand block!\n"); ret = -1; goto out; } if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { - printf ("nand_unlock: Length must be a multiple of nand block " + printf("nand_unlock: Length must be a multiple of nand block " "size %08x!\n", mtd->erasesize); ret = -1; goto out; @@ -485,7 +485,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, pages = nand->erasesize / nand->writesize; blocksize = (pages * nand->oobsize) + nand->erasesize; if (*length % (nand->writesize + nand->oobsize)) { - printf ("Attempt to write incomplete page" + printf("Attempt to write incomplete page" " in yaffs mode\n"); return -EINVAL; } @@ -507,25 +507,25 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, * partition boundary). So don't try to handle that. */ if ((offset & (nand->writesize - 1)) != 0) { - printf ("Attempt to write non page aligned data\n"); + printf("Attempt to write non page-aligned data\n"); *length = 0; return -EINVAL; } need_skip = check_skip_len(nand, offset, *length); if (need_skip < 0) { - printf ("Attempt to write outside the flash area\n"); + printf("Attempt to write outside the flash area\n"); *length = 0; return -EINVAL; } if (!need_skip && !(flags & WITH_DROP_FFS)) { - rval = nand_write (nand, offset, length, buffer); + rval = nand_write(nand, offset, length, buffer); if (rval == 0) return 0; *length = 0; - printf ("NAND write to offset %llx failed %d\n", + printf("NAND write to offset %llx failed %d\n", offset, rval); return rval; } @@ -534,10 +534,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, size_t block_offset = offset & (nand->erasesize - 1); size_t write_size, truncated_write_size; - WATCHDOG_RESET (); + WATCHDOG_RESET(); - if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skip bad block 0x%08llx\n", + if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { + printf("Skip bad block 0x%08llx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -592,7 +592,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, } if (rval != 0) { - printf ("NAND write to offset %llx failed %d\n", + printf("NAND write to offset %llx failed %d\n", offset, rval); *length -= left_to_write; return rval; @@ -608,13 +608,13 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, * nand_read_skip_bad: * * Read image from NAND flash. - * Blocks that are marked bad are skipped and the next block is readen + * Blocks that are marked bad are skipped and the next block is read * instead as long as the image is short enough to fit even after skipping the * bad blocks. * * @param nand NAND device * @param offset offset in flash - * @param length buffer length, on return holds remaining bytes to read + * @param length buffer length, on return holds number of read bytes * @param buffer buffer to write to * @return 0 in case of success */ @@ -627,25 +627,25 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, int need_skip; if ((offset & (nand->writesize - 1)) != 0) { - printf ("Attempt to read non page aligned data\n"); + printf("Attempt to read non page-aligned data\n"); *length = 0; return -EINVAL; } need_skip = check_skip_len(nand, offset, *length); if (need_skip < 0) { - printf ("Attempt to read outside the flash area\n"); + printf("Attempt to read outside the flash area\n"); *length = 0; return -EINVAL; } if (!need_skip) { - rval = nand_read (nand, offset, length, buffer); + rval = nand_read(nand, offset, length, buffer); if (!rval || rval == -EUCLEAN) return 0; *length = 0; - printf ("NAND read from offset %llx failed %d\n", + printf("NAND read from offset %llx failed %d\n", offset, rval); return rval; } @@ -654,10 +654,10 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, size_t block_offset = offset & (nand->erasesize - 1); size_t read_length; - WATCHDOG_RESET (); + WATCHDOG_RESET(); - if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skipping bad block 0x%08llx\n", + if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { + printf("Skipping bad block 0x%08llx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -668,9 +668,9 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, else read_length = nand->erasesize - block_offset; - rval = nand_read (nand, offset, &read_length, p_buffer); + rval = nand_read(nand, offset, &read_length, p_buffer); if (rval && rval != -EUCLEAN) { - printf ("NAND read from offset %llx failed %d\n", + printf("NAND read from offset %llx failed %d\n", offset, rval); *length -= left_to_read; return rval; @@ -683,3 +683,125 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, return 0; } + +#ifdef CONFIG_CMD_NAND_TORTURE + +/** + * check_pattern: + * + * Check if buffer contains only a certain byte pattern. + * + * @param buf buffer to check + * @param patt the pattern to check + * @param size buffer size in bytes + * @return 1 if there are only patt bytes in buf + * 0 if something else was found + */ +static int check_pattern(const u_char *buf, u_char patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (buf[i] != patt) + return 0; + return 1; +} + +/** + * nand_torture: + * + * Torture a block of NAND flash. + * This is useful to determine if a block that caused a write error is still + * good or should be marked as bad. + * + * @param nand NAND device + * @param offset offset in flash + * @return 0 if the block is still good + */ +int nand_torture(nand_info_t *nand, loff_t offset) +{ + u_char patterns[] = {0xa5, 0x5a, 0x00}; + struct erase_info instr = { + .mtd = nand, + .addr = offset, + .len = nand->erasesize, + }; + size_t retlen; + int err, ret = -1, i, patt_count; + u_char *buf; + + if ((offset & (nand->erasesize - 1)) != 0) { + puts("Attempt to torture a block at a non block-aligned offset\n"); + return -EINVAL; + } + + if (offset + nand->erasesize > nand->size) { + puts("Attempt to torture a block outside the flash area\n"); + return -EINVAL; + } + + patt_count = ARRAY_SIZE(patterns); + + buf = malloc(nand->erasesize); + if (buf == NULL) { + puts("Out of memory for erase block buffer\n"); + return -ENOMEM; + } + + for (i = 0; i < patt_count; i++) { + err = nand->erase(nand, &instr); + if (err) { + printf("%s: erase() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + /* Make sure the block contains only 0xff bytes */ + err = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, 0xff, nand->erasesize); + if (!err) { + printf("Erased block at 0x%llx, but a non-0xff byte was found\n", + offset); + ret = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], nand->erasesize); + err = nand->write(nand, offset, nand->erasesize, &retlen, buf); + if (err || retlen != nand->erasesize) { + printf("%s: write() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, patterns[i], nand->erasesize); + if (!err) { + printf("Pattern 0x%.2x checking failed for block at " + "0x%llx\n", patterns[i], offset); + ret = -EIO; + goto out; + } + } + + ret = 0; + +out: + free(buf); + return ret; +} + +#endif diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 9027781..bbd91ca 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -36,6 +36,9 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) { + while (!(serial_in(&com_port->lsr) & UART_LSR_TEMT)) + ; + serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier); #if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ defined(CONFIG_AM33XX) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index c1c0134..fc01a3c 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -31,6 +31,8 @@ #include <serial.h> +#ifndef CONFIG_NS16550_MIN_FUNCTIONS + DECLARE_GLOBAL_DATA_PTR; #if !defined(CONFIG_CONS_INDEX) @@ -304,3 +306,5 @@ void ns16550_serial_initialize(void) serial_register(&eserial6_device); #endif } + +#endif /* !CONFIG_NS16550_MIN_FUNCTIONS */ |