This required manual merging drivers/mtd/nand/Makefile and adding am335x_evm support for CONFIG_SPL_NAND_DRIVERSmaster
commit
79f3877794
@ -0,0 +1,212 @@ |
||||
/*
|
||||
* (C) Copyright 2010-2011 Texas Instruments, <www.ti.com> |
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com> |
||||
* |
||||
* BCH Error Location Module (ELM) support. |
||||
* |
||||
* NOTE: |
||||
* 1. Supports only continuous mode. Dont see need for page mode in uboot |
||||
* 2. Supports only syndrome polynomial 0. i.e. poly local variable is |
||||
* always set to ELM_DEFAULT_POLY. Dont see need for other polynomial |
||||
* sets in uboot |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/errno.h> |
||||
#include <asm/arch/cpu.h> |
||||
#include <asm/arch/omap_gpmc.h> |
||||
#include <asm/arch/elm.h> |
||||
|
||||
#define ELM_DEFAULT_POLY (0) |
||||
|
||||
struct elm *elm_cfg; |
||||
|
||||
/**
|
||||
* elm_load_syndromes - Load BCH syndromes based on nibble selection |
||||
* @syndrome: BCH syndrome |
||||
* @nibbles: |
||||
* @poly: Syndrome Polynomial set to use |
||||
* |
||||
* Load BCH syndromes based on nibble selection |
||||
*/ |
||||
static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) |
||||
{ |
||||
u32 *ptr; |
||||
u32 val; |
||||
|
||||
/* reg 0 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; |
||||
val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | |
||||
(syndrome[3] << 24); |
||||
writel(val, ptr); |
||||
/* reg 1 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; |
||||
val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | |
||||
(syndrome[7] << 24); |
||||
writel(val, ptr); |
||||
|
||||
/* BCH 8-bit with 26 nibbles (4*8=32) */ |
||||
if (nibbles > 13) { |
||||
/* reg 2 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; |
||||
val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | |
||||
(syndrome[11] << 24); |
||||
writel(val, ptr); |
||||
/* reg 3 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; |
||||
val = syndrome[12] | (syndrome[13] << 8) | |
||||
(syndrome[14] << 16) | (syndrome[15] << 24); |
||||
writel(val, ptr); |
||||
} |
||||
|
||||
/* BCH 16-bit with 52 nibbles (7*8=56) */ |
||||
if (nibbles > 26) { |
||||
/* reg 4 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; |
||||
val = syndrome[16] | (syndrome[17] << 8) | |
||||
(syndrome[18] << 16) | (syndrome[19] << 24); |
||||
writel(val, ptr); |
||||
|
||||
/* reg 5 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; |
||||
val = syndrome[20] | (syndrome[21] << 8) | |
||||
(syndrome[22] << 16) | (syndrome[23] << 24); |
||||
writel(val, ptr); |
||||
|
||||
/* reg 6 */ |
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; |
||||
val = syndrome[24] | (syndrome[25] << 8) | |
||||
(syndrome[26] << 16) | (syndrome[27] << 24); |
||||
writel(val, ptr); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* elm_check_errors - Check for BCH errors and return error locations |
||||
* @syndrome: BCH syndrome |
||||
* @nibbles: |
||||
* @error_count: Returns number of errrors in the syndrome |
||||
* @error_locations: Returns error locations (in decimal) in this array |
||||
* |
||||
* Check the provided syndrome for BCH errors and return error count |
||||
* and locations in the array passed. Returns -1 if error is not correctable, |
||||
* else returns 0 |
||||
*/ |
||||
int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, |
||||
u32 *error_locations) |
||||
{ |
||||
u8 poly = ELM_DEFAULT_POLY; |
||||
s8 i; |
||||
u32 location_status; |
||||
|
||||
elm_load_syndromes(syndrome, nibbles, poly); |
||||
|
||||
/* start processing */ |
||||
writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) |
||||
| ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), |
||||
&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); |
||||
|
||||
/* wait for processing to complete */ |
||||
while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) |
||||
; |
||||
/* clear status */ |
||||
writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), |
||||
&elm_cfg->irqstatus); |
||||
|
||||
/* check if correctable */ |
||||
location_status = readl(&elm_cfg->error_location[poly].location_status); |
||||
if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) |
||||
return -1; |
||||
|
||||
/* get error count */ |
||||
*error_count = readl(&elm_cfg->error_location[poly].location_status) & |
||||
ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; |
||||
|
||||
for (i = 0; i < *error_count; i++) { |
||||
error_locations[i] = |
||||
readl(&elm_cfg->error_location[poly].error_location_x[i]); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* elm_config - Configure ELM module |
||||
* @level: 4 / 8 / 16 bit BCH |
||||
* |
||||
* Configure ELM module based on BCH level. |
||||
* Set mode as continuous mode. |
||||
* Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. |
||||
* Also, the mode is set only for syndrome 0 |
||||
*/ |
||||
int elm_config(enum bch_level level) |
||||
{ |
||||
u32 val; |
||||
u8 poly = ELM_DEFAULT_POLY; |
||||
u32 buffer_size = 0x7FF; |
||||
|
||||
/* config size and level */ |
||||
val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; |
||||
val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & |
||||
ELM_LOCATION_CONFIG_ECC_SIZE_MASK); |
||||
writel(val, &elm_cfg->location_config); |
||||
|
||||
/* config continous mode */ |
||||
/* enable interrupt generation for syndrome polynomial set */ |
||||
writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), |
||||
&elm_cfg->irqenable); |
||||
/* set continuous mode for the syndrome polynomial set */ |
||||
writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), |
||||
&elm_cfg->page_ctrl); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* elm_reset - Do a soft reset of ELM |
||||
* |
||||
* Perform a soft reset of ELM and return after reset is done. |
||||
*/ |
||||
void elm_reset(void) |
||||
{ |
||||
/* initiate reset */ |
||||
writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), |
||||
&elm_cfg->sysconfig); |
||||
|
||||
/* wait for reset complete and normal operation */ |
||||
while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != |
||||
ELM_SYSSTATUS_RESETDONE) |
||||
; |
||||
} |
||||
|
||||
/**
|
||||
* elm_init - Initialize ELM module |
||||
* |
||||
* Initialize ELM support. Currently it does only base address init |
||||
* and ELM reset. |
||||
*/ |
||||
void elm_init(void) |
||||
{ |
||||
elm_cfg = (struct elm *)ELM_BASE; |
||||
elm_reset(); |
||||
} |
@ -0,0 +1,101 @@ |
||||
/*
|
||||
* (C) Copyright 2010 |
||||
* Texas Instruments, <www.ti.com> |
||||
* |
||||
* Author : |
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com> |
||||
* |
||||
* Initial Code from: |
||||
* Manikandan Pillai <mani.pillai@ti.com> |
||||
* Richard Woodruff <r-woodruff2@ti.com> |
||||
* Syed Mohammed Khasim <khasim@ti.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/arch/cpu.h> |
||||
#include <asm/arch/mem.h> |
||||
#include <asm/arch/sys_proto.h> |
||||
#include <command.h> |
||||
|
||||
struct gpmc *gpmc_cfg; |
||||
|
||||
#if defined(CONFIG_CMD_NAND) |
||||
static const u32 gpmc_m_nand[GPMC_MAX_REG] = { |
||||
M_NAND_GPMC_CONFIG1, |
||||
M_NAND_GPMC_CONFIG2, |
||||
M_NAND_GPMC_CONFIG3, |
||||
M_NAND_GPMC_CONFIG4, |
||||
M_NAND_GPMC_CONFIG5, |
||||
M_NAND_GPMC_CONFIG6, 0 |
||||
}; |
||||
#endif |
||||
|
||||
|
||||
void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, |
||||
u32 size) |
||||
{ |
||||
writel(0, &cs->config7); |
||||
sdelay(1000); |
||||
/* Delay for settling */ |
||||
writel(gpmc_config[0], &cs->config1); |
||||
writel(gpmc_config[1], &cs->config2); |
||||
writel(gpmc_config[2], &cs->config3); |
||||
writel(gpmc_config[3], &cs->config4); |
||||
writel(gpmc_config[4], &cs->config5); |
||||
writel(gpmc_config[5], &cs->config6); |
||||
/* Enable the config */ |
||||
writel((((size & 0xF) << 8) | ((base >> 24) & 0x3F) | |
||||
(1 << 6)), &cs->config7); |
||||
sdelay(2000); |
||||
} |
||||
|
||||
/*****************************************************
|
||||
* gpmc_init(): init gpmc bus |
||||
* Init GPMC for x16, MuxMode (SDRAM in x32). |
||||
* This code can only be executed from SRAM or SDRAM. |
||||
*****************************************************/ |
||||
void gpmc_init(void) |
||||
{ |
||||
/* putting a blanket check on GPMC based on ZeBu for now */ |
||||
gpmc_cfg = (struct gpmc *)GPMC_BASE; |
||||
|
||||
#ifdef CONFIG_CMD_NAND |
||||
const u32 *gpmc_config = NULL; |
||||
u32 base = 0; |
||||
u32 size = 0; |
||||
#endif |
||||
/* global settings */ |
||||
writel(0x00000008, &gpmc_cfg->sysconfig); |
||||
writel(0x00000100, &gpmc_cfg->irqstatus); |
||||
writel(0x00000200, &gpmc_cfg->irqenable); |
||||
writel(0x00000012, &gpmc_cfg->config); |
||||
/*
|
||||
* Disable the GPMC0 config set by ROM code |
||||
*/ |
||||
writel(0, &gpmc_cfg->cs[0].config7); |
||||
sdelay(1000); |
||||
|
||||
#ifdef CONFIG_CMD_NAND |
||||
gpmc_config = gpmc_m_nand; |
||||
|
||||
base = PISMO1_NAND_BASE; |
||||
size = PISMO1_NAND_SIZE; |
||||
enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[0], base, size); |
||||
#endif |
||||
} |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* (C) Copyright 2010-2011 Texas Instruments, <www.ti.com> |
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com> |
||||
* |
||||
* Derived from work done by Rohit Choraria <rohitkc@ti.com> for omap3 |
||||
* |
||||
* 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 __ASM_ARCH_ELM_H |
||||
#define __ASM_ARCH_ELM_H |
||||
/*
|
||||
* ELM Module Registers |
||||
*/ |
||||
|
||||
/* ELM registers bit fields */ |
||||
#define ELM_SYSCONFIG_SOFTRESET_MASK (0x2) |
||||
#define ELM_SYSCONFIG_SOFTRESET (0x2) |
||||
#define ELM_SYSSTATUS_RESETDONE_MASK (0x1) |
||||
#define ELM_SYSSTATUS_RESETDONE (0x1) |
||||
#define ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK (0x3) |
||||
#define ELM_LOCATION_CONFIG_ECC_SIZE_MASK (0x7FF0000) |
||||
#define ELM_LOCATION_CONFIG_ECC_SIZE_POS (16) |
||||
#define ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID (0x00010000) |
||||
#define ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK (0x100) |
||||
#define ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK (0x1F) |
||||
|
||||
#ifndef __ASSEMBLY__ |
||||
|
||||
enum bch_level { |
||||
BCH_4_BIT = 0, |
||||
BCH_8_BIT, |
||||
BCH_16_BIT |
||||
}; |
||||
|
||||
|
||||
/* BCH syndrome registers */ |
||||
struct syndrome { |
||||
u32 syndrome_fragment_x[7]; /* 0x400, 0x404.... 0x418 */ |
||||
u8 res1[36]; /* 0x41c */ |
||||
}; |
||||
|
||||
/* BCH error status & location register */ |
||||
struct location { |
||||
u32 location_status; /* 0x800 */ |
||||
u8 res1[124]; /* 0x804 */ |
||||
u32 error_location_x[16]; /* 0x880.... */ |
||||
u8 res2[64]; /* 0x8c0 */ |
||||
}; |
||||
|
||||
/* BCH ELM register map - do not try to allocate memmory for this structure.
|
||||
* We have used plenty of reserved variables to fill the slots in the ELM |
||||
* register memory map. |
||||
* Directly initialize the struct pointer to ELM base address. |
||||
*/ |
||||
struct elm { |
||||
u32 rev; /* 0x000 */ |
||||
u8 res1[12]; /* 0x004 */ |
||||
u32 sysconfig; /* 0x010 */ |
||||
u32 sysstatus; /* 0x014 */ |
||||
u32 irqstatus; /* 0x018 */ |
||||
u32 irqenable; /* 0x01c */ |
||||
u32 location_config; /* 0x020 */ |
||||
u8 res2[92]; /* 0x024 */ |
||||
u32 page_ctrl; /* 0x080 */ |
||||
u8 res3[892]; /* 0x084 */ |
||||
struct syndrome syndrome_fragments[8]; /* 0x400 */ |
||||
u8 res4[512]; /* 0x600 */ |
||||
struct location error_location[8]; /* 0x800 */ |
||||
}; |
||||
|
||||
int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, |
||||
u32 *error_locations); |
||||
int elm_config(enum bch_level level); |
||||
void elm_reset(void); |
||||
void elm_init(void); |
||||
#endif /* __ASSEMBLY__ */ |
||||
#endif /* __ASM_ARCH_ELM_H */ |
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* (C) Copyright 2006-2008 |
||||
* Texas Instruments, <www.ti.com> |
||||
* |
||||
* Author |
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com> |
||||
* |
||||
* Initial Code from: |
||||
* Richard Woodruff <r-woodruff2@ti.com> |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#ifndef _MEM_H_ |
||||
#define _MEM_H_ |
||||
|
||||
/*
|
||||
* GPMC settings - |
||||
* Definitions is as per the following format |
||||
* #define <PART>_GPMC_CONFIG<x> <value> |
||||
* Where: |
||||
* PART is the part name e.g. STNOR - Intel Strata Flash |
||||
* x is GPMC config registers from 1 to 6 (there will be 6 macros) |
||||
* Value is corresponding value |
||||
* |
||||
* For every valid PRCM configuration there should be only one definition of |
||||
* the same. if values are independent of the board, this definition will be |
||||
* present in this file if values are dependent on the board, then this should |
||||
* go into corresponding mem-boardName.h file |
||||
* |
||||
* Currently valid part Names are (PART): |
||||
* M_NAND - Micron NAND |
||||
*/ |
||||
#define GPMC_SIZE_256M 0x0 |
||||
#define GPMC_SIZE_128M 0x8 |
||||
#define GPMC_SIZE_64M 0xC |
||||
#define GPMC_SIZE_32M 0xE |
||||
#define GPMC_SIZE_16M 0xF |
||||
|
||||
#define M_NAND_GPMC_CONFIG1 0x00000800 |
||||
#define M_NAND_GPMC_CONFIG2 0x001e1e00 |
||||
#define M_NAND_GPMC_CONFIG3 0x001e1e00 |
||||
#define M_NAND_GPMC_CONFIG4 0x16051807 |
||||
#define M_NAND_GPMC_CONFIG5 0x00151e1e |
||||
#define M_NAND_GPMC_CONFIG6 0x16000f80 |
||||
#define M_NAND_GPMC_CONFIG7 0x00000008 |
||||
|
||||
/* max number of GPMC Chip Selects */ |
||||
#define GPMC_MAX_CS 8 |
||||
/* max number of GPMC regs */ |
||||
#define GPMC_MAX_REG 7 |
||||
|
||||
#define PISMO1_NOR 1 |
||||
#define PISMO1_NAND 2 |
||||
#define PISMO2_CS0 3 |
||||
#define PISMO2_CS1 4 |
||||
#define PISMO1_ONENAND 5 |
||||
#define DBG_MPDB 6 |
||||
#define PISMO2_NAND_CS0 7 |
||||
#define PISMO2_NAND_CS1 8 |
||||
|
||||
/* make it readable for the gpmc_init */ |
||||
#define PISMO1_NOR_BASE FLASH_BASE |
||||
#define PISMO1_NAND_BASE CONFIG_SYS_NAND_BASE |
||||
#define PISMO1_NAND_SIZE GPMC_SIZE_256M |
||||
|
||||
#endif /* endif _MEM_H_ */ |
@ -0,0 +1,120 @@ |
||||
/*
|
||||
* (C) Copyright 2004-2008 Texas Instruments, <www.ti.com> |
||||
* Rohit Choraria <rohitkc@ti.com> |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as |
||||
* published by the Free Software Foundation; either version 2 of |
||||
* the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
*/ |
||||
#ifndef __ASM_ARCH_OMAP_GPMC_H |
||||
#define __ASM_ARCH_OMAP_GPMC_H |
||||
|
||||
#define GPMC_BUF_EMPTY 0 |
||||
#define GPMC_BUF_FULL 1 |
||||
|
||||
#define ECCCLEAR (0x1 << 8) |
||||
#define ECCRESULTREG1 (0x1 << 0) |
||||
#define ECCSIZE512BYTE 0xFF |
||||
#define ECCSIZE1 (ECCSIZE512BYTE << 22) |
||||
#define ECCSIZE0 (ECCSIZE512BYTE << 12) |
||||
#define ECCSIZE0SEL (0x000 << 0) |
||||
|
||||
/* Generic ECC Layouts */ |
||||
/* Large Page x8 NAND device Layout */ |
||||
#ifdef GPMC_NAND_ECC_LP_x8_LAYOUT |
||||
#define GPMC_NAND_HW_ECC_LAYOUT {\ |
||||
.eccbytes = 12,\
|
||||
.eccpos = {1, 2, 3, 4, 5, 6, 7, 8,\
|
||||
9, 10, 11, 12},\
|
||||
.oobfree = {\
|
||||
{.offset = 13,\
|
||||
.length = 51 } } \
|
||||
} |
||||
#endif |
||||
|
||||
/* Large Page x16 NAND device Layout */ |
||||
#ifdef GPMC_NAND_ECC_LP_x16_LAYOUT |
||||
#define GPMC_NAND_HW_ECC_LAYOUT {\ |
||||
.eccbytes = 12,\
|
||||
.eccpos = {2, 3, 4, 5, 6, 7, 8, 9,\
|
||||
10, 11, 12, 13},\
|
||||
.oobfree = {\
|
||||
{.offset = 14,\
|
||||
.length = 50 } } \
|
||||
} |
||||
#endif |
||||
|
||||
/* Small Page x8 NAND device Layout */ |
||||
#ifdef GPMC_NAND_ECC_SP_x8_LAYOUT |
||||
#define GPMC_NAND_HW_ECC_LAYOUT {\ |
||||
.eccbytes = 3,\
|
||||
.eccpos = {1, 2, 3},\
|
||||
.oobfree = {\
|
||||
{.offset = 4,\
|
||||
.length = 12 } } \
|
||||
} |
||||
#endif |
||||
|
||||
/* Small Page x16 NAND device Layout */ |
||||
#ifdef GPMC_NAND_ECC_SP_x16_LAYOUT |
||||
#define GPMC_NAND_HW_ECC_LAYOUT {\ |
||||
.eccbytes = 3,\
|
||||
.eccpos = {2, 3, 4},\
|
||||
.oobfree = {\
|
||||
{.offset = 5,\
|
||||
.length = 11 } } \
|
||||
} |
||||
#endif |
||||
|
||||
#define GPMC_NAND_HW_BCH4_ECC_LAYOUT {\ |
||||
.eccbytes = 32,\
|
||||
.eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,\
|
||||
28, 29, 30, 31, 32, 33},\
|
||||
.oobfree = {\
|
||||
{.offset = 34,\
|
||||
.length = 30 } } \
|
||||
} |
||||
|
||||
#define GPMC_NAND_HW_BCH8_ECC_LAYOUT {\ |
||||
.eccbytes = 56,\
|
||||
.eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,\
|
||||
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,\
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\
|
||||
52, 53, 54, 55, 56, 57},\
|
||||
.oobfree = {\
|
||||
{.offset = 58,\
|
||||
.length = 6 } } \
|
||||
} |
||||
|
||||
#define GPMC_NAND_HW_BCH16_ECC_LAYOUT {\ |
||||
.eccbytes = 104,\
|
||||
.eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,\
|
||||
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,\
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\
|
||||
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,\
|
||||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,\
|
||||
100, 101, 102, 103, 104, 105},\
|
||||
.oobfree = {\
|
||||
{.offset = 106,\
|
||||
.length = 8 } } \
|
||||
} |
||||
#endif /* __ASM_ARCH_OMAP_GPMC_H */ |
@ -0,0 +1,238 @@ |
||||
/*
|
||||
* (C) Copyright 2012 |
||||
* Konstantin Kozhevnikov, Cogent Embedded |
||||
* |
||||
* based on nand_spl_simple code |
||||
* |
||||
* (C) Copyright 2006-2008 |
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de. |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <nand.h> |
||||
#include <asm/io.h> |
||||
#include <linux/mtd/nand_ecc.h> |
||||
|
||||
static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; |
||||
static nand_info_t mtd; |
||||
static struct nand_chip nand_chip; |
||||
|
||||
#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ |
||||
CONFIG_SYS_NAND_ECCSIZE) |
||||
#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) |
||||
|
||||
|
||||
/*
|
||||
* NAND command for large page NAND devices (2k) |
||||
*/ |
||||
static int nand_command(int block, int page, uint32_t offs, |
||||
u8 cmd) |
||||
{ |
||||
struct nand_chip *this = mtd.priv; |
||||
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; |
||||
void (*hwctrl)(struct mtd_info *mtd, int cmd, |
||||
unsigned int ctrl) = this->cmd_ctrl; |
||||
|
||||
while (!this->dev_ready(&mtd)) |
||||
; |
||||
|
||||
/* Emulate NAND_CMD_READOOB */ |
||||
if (cmd == NAND_CMD_READOOB) { |
||||
offs += CONFIG_SYS_NAND_PAGE_SIZE; |
||||
cmd = NAND_CMD_READ0; |
||||
} |
||||
|
||||
/* Begin command latch cycle */ |
||||
hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
||||
|
||||
if (cmd == NAND_CMD_RESET) { |
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
||||
while (!this->dev_ready(&mtd)) |
||||
; |
||||
return 0; |
||||
} |
||||
|
||||
/* Shift the offset from byte addressing to word addressing. */ |
||||
if (this->options & NAND_BUSWIDTH_16) |
||||
offs >>= 1; |
||||
|
||||
/* Set ALE and clear CLE to start address cycle */ |
||||
/* Column address */ |
||||
hwctrl(&mtd, offs & 0xff, |
||||
NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ |
||||
hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ |
||||
/* Row address */ |
||||
hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ |
||||
hwctrl(&mtd, ((page_addr >> 8) & 0xff), |
||||
NAND_CTRL_ALE); /* A[27:20] */ |
||||
#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE |
||||
/* One more address cycle for devices > 128MiB */ |
||||
hwctrl(&mtd, (page_addr >> 16) & 0x0f, |
||||
NAND_CTRL_ALE); /* A[31:28] */ |
||||
#endif |
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
||||
|
||||
if (cmd == NAND_CMD_READ0) { |
||||
/* Latch in address */ |
||||
hwctrl(&mtd, NAND_CMD_READSTART, |
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
||||
|
||||
/*
|
||||
* Wait a while for the data to be ready |
||||
*/ |
||||
while (!this->dev_ready(&mtd)) |
||||
; |
||||
} else if (cmd == NAND_CMD_RNDOUT) { |
||||
hwctrl(&mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | |
||||
NAND_CTRL_CHANGE); |
||||
hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int nand_is_bad_block(int block) |
||||
{ |
||||
struct nand_chip *this = mtd.priv; |
||||
|
||||
nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, |
||||
NAND_CMD_READOOB); |
||||
|
||||
/*
|
||||
* Read one byte (or two if it's a 16 bit chip). |
||||
*/ |
||||
if (this->options & NAND_BUSWIDTH_16) { |
||||
if (readw(this->IO_ADDR_R) != 0xffff) |
||||
return 1; |
||||
} else { |
||||
if (readb(this->IO_ADDR_R) != 0xff) |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int nand_read_page(int block, int page, void *dst) |
||||
{ |
||||
struct nand_chip *this = mtd.priv; |
||||
u_char ecc_calc[ECCTOTAL]; |
||||
u_char ecc_code[ECCTOTAL]; |
||||
u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; |
||||
int i; |
||||
int eccsize = CONFIG_SYS_NAND_ECCSIZE; |
||||
int eccbytes = CONFIG_SYS_NAND_ECCBYTES; |
||||
int eccsteps = ECCSTEPS; |
||||
uint8_t *p = dst; |
||||
uint32_t data_pos = 0; |
||||
uint8_t *oob = &oob_data[0] + nand_ecc_pos[0]; |
||||
uint32_t oob_pos = eccsize * eccsteps + nand_ecc_pos[0]; |
||||
|
||||
nand_command(block, page, 0, NAND_CMD_READ0); |
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
||||
this->ecc.hwctl(&mtd, NAND_ECC_READ); |
||||
nand_command(block, page, data_pos, NAND_CMD_RNDOUT); |
||||
|
||||
this->read_buf(&mtd, p, eccsize); |
||||
|
||||
nand_command(block, page, oob_pos, NAND_CMD_RNDOUT); |
||||
|
||||
this->read_buf(&mtd, oob, eccbytes); |
||||
this->ecc.calculate(&mtd, p, &ecc_calc[i]); |
||||
|
||||
data_pos += eccsize; |
||||
oob_pos += eccbytes; |
||||
oob += eccbytes; |
||||
} |
||||
|
||||
/* Pick the ECC bytes out of the oob data */ |
||||
for (i = 0; i < ECCTOTAL; i++) |
||||
ecc_code[i] = oob_data[nand_ecc_pos[i]]; |
||||
|
||||
eccsteps = ECCSTEPS; |
||||
p = dst; |
||||
|
||||
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
||||
/* No chance to do something with the possible error message
|
||||
* from correct_data(). We just hope that all possible errors |
||||
* are corrected by this routine. |
||||
*/ |
||||
this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) |
||||
{ |
||||
unsigned int block, lastblock; |
||||
unsigned int page; |
||||
|
||||
/*
|
||||
* offs has to be aligned to a page address! |
||||
*/ |
||||
block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; |
||||
lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; |
||||
page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; |
||||
|
||||
while (block <= lastblock) { |
||||
if (!nand_is_bad_block(block)) { |
||||
/*
|
||||
* Skip bad blocks |
||||
*/ |
||||
while (page < CONFIG_SYS_NAND_PAGE_COUNT) { |
||||
nand_read_page(block, page, dst); |
||||
dst += CONFIG_SYS_NAND_PAGE_SIZE; |
||||
page++; |
||||
} |
||||
|
||||
page = 0; |
||||
} else { |
||||
lastblock++; |
||||
} |
||||
|
||||
block++; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* nand_init() - initialize data to make nand usable by SPL */ |
||||
void nand_init(void) |
||||
{ |
||||
/*
|
||||
* Init board specific nand support |
||||
*/ |
||||
mtd.priv = &nand_chip; |
||||
nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = |
||||
(void __iomem *)CONFIG_SYS_NAND_BASE; |
||||
board_nand_init(&nand_chip); |
||||
|
||||
if (nand_chip.select_chip) |
||||
nand_chip.select_chip(&mtd, 0); |
||||
|
||||
/* NAND chip may require reset after power-on */ |
||||
nand_command(0, 0, 0, NAND_CMD_RESET); |
||||
} |
||||
|
||||
/* Unselect after operation */ |
||||
void nand_deselect(void) |
||||
{ |
||||
if (nand_chip.select_chip) |
||||
nand_chip.select_chip(&mtd, -1); |
||||
} |
Loading…
Reference in new issue