mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
mtd: remove bcmring NAND driver
This driver is being removed as part of the cleanup of the bcmring SoC from mainline as it is no longer maintained. Signed-off-by: Christian Daudt <csd@broadcom.com> Reviewed-by: Jiandong Zheng <jdzheng@broadcom.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
1 parent
5ca7f41528
commit
b2bc415b6b
7 files changed
-1255
No files matched your search
@@ -665,15 +665,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: arch/arm/mach-bcmring
|
||||
|
||||
ARM/BCMRING MTD NAND DRIVER
|
||||
M: Jiandong Zheng <jdzheng@broadcom.com>
|
||||
M: Scott Branden <sbranden@broadcom.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
S: Maintained
|
||||
F: drivers/mtd/nand/bcm_umi_nand.c
|
||||
F: drivers/mtd/nand/bcm_umi_bch.c
|
||||
F: drivers/mtd/nand/nand_bcm_umi.h
|
||||
|
||||
ARM/CALXEDA HIGHBANK ARCHITECTURE
|
||||
M: Rob Herring <rob.herring@calxeda.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
||||
@@ -258,22 +258,6 @@ config MTD_NAND_S3C2410_CLKSTOP
|
||||
when the is NAND chip selected or released, but will save
|
||||
approximately 5mA of power when there is nothing happening.
|
||||
|
||||
config MTD_NAND_BCM_UMI
|
||||
tristate "NAND Flash support for BCM Reference Boards"
|
||||
depends on ARCH_BCMRING
|
||||
help
|
||||
This enables the NAND flash controller on the BCM UMI block.
|
||||
|
||||
No board specific support is done by this driver, each board
|
||||
must advertise a platform_device for the driver to attach.
|
||||
|
||||
config MTD_NAND_BCM_UMI_HWCS
|
||||
bool "BCM UMI NAND Hardware CS"
|
||||
depends on MTD_NAND_BCM_UMI
|
||||
help
|
||||
Enable the use of the BCM UMI block's internal CS using NAND.
|
||||
This should only be used if you know the external NAND CS can toggle.
|
||||
|
||||
config MTD_NAND_DISKONCHIP
|
||||
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
|
||||
@@ -48,7 +48,6 @@ obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
|
||||
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
|
||||
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
|
||||
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
|
||||
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
|
||||
*
|
||||
* Unless you and Broadcom execute a separate written software license
|
||||
* agreement governing use of this software, this software is licensed to you
|
||||
* under the terms of the GNU General Public License version 2, available at
|
||||
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
*
|
||||
* Notwithstanding the above, under no circumstances may you combine this
|
||||
* software in any way with any other Broadcom software provided under a
|
||||
* license other than the GPL, without Broadcom's express prior written
|
||||
* consent.
|
||||
*****************************************************************************/
|
||||
|
||||
/* ---- Include Files ---------------------------------------------------- */
|
||||
#include "nand_bcm_umi.h"
|
||||
|
||||
/* ---- External Variable Declarations ----------------------------------- */
|
||||
/* ---- External Function Prototypes ------------------------------------- */
|
||||
/* ---- Public Variables ------------------------------------------------- */
|
||||
/* ---- Private Constants and Types -------------------------------------- */
|
||||
|
||||
/* ---- Private Function Prototypes -------------------------------------- */
|
||||
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
|
||||
static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required);
|
||||
|
||||
/* ---- Private Variables ------------------------------------------------ */
|
||||
|
||||
/*
|
||||
** nand_hw_eccoob
|
||||
** New oob placement block for use with hardware ecc generation.
|
||||
*/
|
||||
static struct nand_ecclayout nand_hw_eccoob_512 = {
|
||||
/* Reserve 5 for BI indicator */
|
||||
.oobfree = {
|
||||
#if (NAND_ECC_NUM_BYTES > 3)
|
||||
{.offset = 0, .length = 2}
|
||||
#else
|
||||
{.offset = 0, .length = 5},
|
||||
{.offset = 6, .length = 7}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
|
||||
** except the BI is at byte 0.
|
||||
*/
|
||||
static struct nand_ecclayout nand_hw_eccoob_2048 = {
|
||||
/* Reserve 0 as BI indicator */
|
||||
.oobfree = {
|
||||
#if (NAND_ECC_NUM_BYTES > 10)
|
||||
{.offset = 1, .length = 2},
|
||||
#elif (NAND_ECC_NUM_BYTES > 7)
|
||||
{.offset = 1, .length = 5},
|
||||
{.offset = 16, .length = 6},
|
||||
{.offset = 32, .length = 6},
|
||||
{.offset = 48, .length = 6}
|
||||
#else
|
||||
{.offset = 1, .length = 8},
|
||||
{.offset = 16, .length = 9},
|
||||
{.offset = 32, .length = 9},
|
||||
{.offset = 48, .length = 9}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
|
||||
* except the BI is at byte 0. */
|
||||
static struct nand_ecclayout nand_hw_eccoob_4096 = {
|
||||
/* Reserve 0 as BI indicator */
|
||||
.oobfree = {
|
||||
#if (NAND_ECC_NUM_BYTES > 10)
|
||||
{.offset = 1, .length = 2},
|
||||
{.offset = 16, .length = 3},
|
||||
{.offset = 32, .length = 3},
|
||||
{.offset = 48, .length = 3},
|
||||
{.offset = 64, .length = 3},
|
||||
{.offset = 80, .length = 3},
|
||||
{.offset = 96, .length = 3},
|
||||
{.offset = 112, .length = 3}
|
||||
#else
|
||||
{.offset = 1, .length = 5},
|
||||
{.offset = 16, .length = 6},
|
||||
{.offset = 32, .length = 6},
|
||||
{.offset = 48, .length = 6},
|
||||
{.offset = 64, .length = 6},
|
||||
{.offset = 80, .length = 6},
|
||||
{.offset = 96, .length = 6},
|
||||
{.offset = 112, .length = 6}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/* ---- Private Functions ------------------------------------------------ */
|
||||
/* ==== Public Functions ================================================= */
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: buffer to store read data
|
||||
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||
*
|
||||
***************************************************************************/
|
||||
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t * buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
int sectorIdx = 0;
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccsteps = chip->ecc.steps;
|
||||
uint8_t *datap = buf;
|
||||
uint8_t eccCalc[NAND_ECC_NUM_BYTES];
|
||||
int sectorOobSize = mtd->oobsize / eccsteps;
|
||||
int stat;
|
||||
unsigned int max_bitflips = 0;
|
||||
|
||||
for (sectorIdx = 0; sectorIdx < eccsteps;
|
||||
sectorIdx++, datap += eccsize) {
|
||||
if (sectorIdx > 0) {
|
||||
/* Seek to page location within sector */
|
||||
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
|
||||
-1);
|
||||
}
|
||||
|
||||
/* Enable hardware ECC before reading the buf */
|
||||
nand_bcm_umi_bch_enable_read_hwecc();
|
||||
|
||||
/* Read in data */
|
||||
bcm_umi_nand_read_buf(mtd, datap, eccsize);
|
||||
|
||||
/* Pause hardware ECC after reading the buf */
|
||||
nand_bcm_umi_bch_pause_read_ecc_calc();
|
||||
|
||||
/* Read the OOB ECC */
|
||||
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
|
||||
mtd->writesize + sectorIdx * sectorOobSize, -1);
|
||||
nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
|
||||
NAND_ECC_NUM_BYTES,
|
||||
chip->oob_poi +
|
||||
sectorIdx * sectorOobSize);
|
||||
|
||||
/* Correct any ECC detected errors */
|
||||
stat =
|
||||
nand_bcm_umi_bch_correct_page(datap, eccCalc,
|
||||
NAND_ECC_NUM_BYTES);
|
||||
|
||||
/* Update Stats */
|
||||
if (stat < 0) {
|
||||
#if defined(NAND_BCM_UMI_DEBUG)
|
||||
printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
|
||||
__func__, sectorIdx);
|
||||
printk(KERN_WARNING "%s data %*ph\n",
|
||||
__func__, 8, datap);
|
||||
printk(KERN_WARNING "%s ecc %*ph\n",
|
||||
__func__, 13, eccCalc);
|
||||
BUG();
|
||||
#endif
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
#if defined(NAND_BCM_UMI_DEBUG)
|
||||
if (stat > 0) {
|
||||
printk(KERN_INFO
|
||||
"%s %d correctable_errors detected\n",
|
||||
__func__, stat);
|
||||
}
|
||||
#endif
|
||||
mtd->ecc_stats.corrected += stat;
|
||||
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
||||
}
|
||||
}
|
||||
return max_bitflips;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
*
|
||||
***************************************************************************/
|
||||
static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
{
|
||||
int sectorIdx = 0;
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccsteps = chip->ecc.steps;
|
||||
const uint8_t *datap = buf;
|
||||
uint8_t *oobp = chip->oob_poi;
|
||||
int sectorOobSize = mtd->oobsize / eccsteps;
|
||||
|
||||
for (sectorIdx = 0; sectorIdx < eccsteps;
|
||||
sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
|
||||
/* Enable hardware ECC before writing the buf */
|
||||
nand_bcm_umi_bch_enable_write_hwecc();
|
||||
bcm_umi_nand_write_buf(mtd, datap, eccsize);
|
||||
nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
|
||||
NAND_ECC_NUM_BYTES);
|
||||
}
|
||||
|
||||
bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,149 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
|
||||
*
|
||||
* Unless you and Broadcom execute a separate written software license
|
||||
* agreement governing use of this software, this software is licensed to you
|
||||
* under the terms of the GNU General Public License version 2, available at
|
||||
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
*
|
||||
* Notwithstanding the above, under no circumstances may you combine this
|
||||
* software in any way with any other Broadcom software provided under a
|
||||
* license other than the GPL, without Broadcom's express prior written
|
||||
* consent.
|
||||
*****************************************************************************/
|
||||
|
||||
/* ---- Include Files ---------------------------------------------------- */
|
||||
#include <mach/reg_umi.h>
|
||||
#include "nand_bcm_umi.h"
|
||||
#ifdef BOOT0_BUILD
|
||||
#include <uart.h>
|
||||
#endif
|
||||
|
||||
/* ---- External Variable Declarations ----------------------------------- */
|
||||
/* ---- External Function Prototypes ------------------------------------- */
|
||||
/* ---- Public Variables ------------------------------------------------- */
|
||||
/* ---- Private Constants and Types -------------------------------------- */
|
||||
/* ---- Private Function Prototypes -------------------------------------- */
|
||||
/* ---- Private Variables ------------------------------------------------ */
|
||||
/* ---- Private Functions ------------------------------------------------ */
|
||||
|
||||
#if NAND_ECC_BCH
|
||||
/****************************************************************************
|
||||
* nand_bch_ecc_flip_bit - Routine to flip an errored bit
|
||||
*
|
||||
* PURPOSE:
|
||||
* This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
|
||||
* errored bit specified
|
||||
*
|
||||
* PARAMETERS:
|
||||
* datap - Container that holds the 512 byte data
|
||||
* errorLocation - Location of the bit that needs to be flipped
|
||||
*
|
||||
* RETURNS:
|
||||
* None
|
||||
****************************************************************************/
|
||||
static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
|
||||
{
|
||||
int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
|
||||
int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
|
||||
int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
|
||||
|
||||
uint8_t errorByte = 0;
|
||||
uint8_t byteMask = 1 << locWithinAByte;
|
||||
|
||||
/* BCH uses big endian, need to change the location
|
||||
* bits to little endian */
|
||||
locWithinAWord = 3 - locWithinAWord;
|
||||
|
||||
errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
|
||||
|
||||
#ifdef BOOT0_BUILD
|
||||
puthexs("\nECC Correct Offset: ",
|
||||
locWithinAPage * sizeof(uint32_t) + locWithinAWord);
|
||||
puthexs(" errorByte:", errorByte);
|
||||
puthex8(" Bit: ", locWithinAByte);
|
||||
#endif
|
||||
|
||||
if (errorByte & byteMask) {
|
||||
/* bit needs to be cleared */
|
||||
errorByte &= ~byteMask;
|
||||
} else {
|
||||
/* bit needs to be set */
|
||||
errorByte |= byteMask;
|
||||
}
|
||||
|
||||
/* write back the value with the fixed bit */
|
||||
datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* nand_correct_page_bch - Routine to correct bit errors when reading NAND
|
||||
*
|
||||
* PURPOSE:
|
||||
* This routine reads the BCH registers to determine if there are any bit
|
||||
* errors during the read of the last 512 bytes of data + ECC bytes. If
|
||||
* errors exists, the routine fixes it.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* datap - Container that holds the 512 byte data
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 or greater = Number of errors corrected
|
||||
* (No errors are found or errors have been fixed)
|
||||
* -1 = Error(s) cannot be fixed
|
||||
****************************************************************************/
|
||||
int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
|
||||
int numEccBytes)
|
||||
{
|
||||
int numErrors;
|
||||
int errorLocation;
|
||||
int idx;
|
||||
uint32_t regValue;
|
||||
|
||||
/* wait for read ECC to be valid */
|
||||
regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
|
||||
|
||||
/*
|
||||
* read the control status register to determine if there
|
||||
* are error'ed bits
|
||||
* see if errors are correctible
|
||||
*/
|
||||
if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numEccBytes; i++) {
|
||||
if (readEccData[i] != 0xff) {
|
||||
/* errors cannot be fixed, return -1 */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* If ECC is unprogrammed then we can't correct,
|
||||
* assume everything OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
|
||||
/* no errors */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix errored bits by doing the following:
|
||||
* 1. Read the number of errors in the control and status register
|
||||
* 2. Read the error location registers that corresponds to the number
|
||||
* of errors reported
|
||||
* 3. Invert the bit in the data
|
||||
*/
|
||||
numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
|
||||
|
||||
for (idx = 0; idx < numErrors; idx++) {
|
||||
errorLocation =
|
||||
REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
|
||||
|
||||
/* Flip bit */
|
||||
nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
|
||||
}
|
||||
/* Errors corrected */
|
||||
return numErrors;
|
||||
}
|
||||
#endif
|
||||
@@ -1,337 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Copyright 2003 - 2009 Broadcom Corporation. All rights reserved.
|
||||
*
|
||||
* Unless you and Broadcom execute a separate written software license
|
||||
* agreement governing use of this software, this software is licensed to you
|
||||
* under the terms of the GNU General Public License version 2, available at
|
||||
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
*
|
||||
* Notwithstanding the above, under no circumstances may you combine this
|
||||
* software in any way with any other Broadcom software provided under a
|
||||
* license other than the GPL, without Broadcom's express prior written
|
||||
* consent.
|
||||
*****************************************************************************/
|
||||
#ifndef NAND_BCM_UMI_H
|
||||
#define NAND_BCM_UMI_H
|
||||
|
||||
/* ---- Include Files ---------------------------------------------------- */
|
||||
#include <mach/reg_umi.h>
|
||||
#include <mach/reg_nand.h>
|
||||
#include <cfg_global.h>
|
||||
|
||||
/* ---- Constants and Types ---------------------------------------------- */
|
||||
#if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
|
||||
#define NAND_ECC_BCH (CFG_GLOBAL_CHIP_REV > 0xA0)
|
||||
#else
|
||||
#define NAND_ECC_BCH 0
|
||||
#endif
|
||||
|
||||
#define CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES 13
|
||||
|
||||
#if NAND_ECC_BCH
|
||||
#ifdef BOOT0_BUILD
|
||||
#define NAND_ECC_NUM_BYTES 13
|
||||
#else
|
||||
#define NAND_ECC_NUM_BYTES CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES
|
||||
#endif
|
||||
#else
|
||||
#define NAND_ECC_NUM_BYTES 3
|
||||
#endif
|
||||
|
||||
#define NAND_DATA_ACCESS_SIZE 512
|
||||
|
||||
/* ---- Variable Externs ------------------------------------------ */
|
||||
/* ---- Function Prototypes --------------------------------------- */
|
||||
int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
|
||||
int numEccBytes);
|
||||
|
||||
/* Check in device is ready */
|
||||
static inline int nand_bcm_umi_dev_ready(void)
|
||||
{
|
||||
return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
|
||||
}
|
||||
|
||||
/* Wait until device is ready */
|
||||
static inline void nand_bcm_umi_wait_till_ready(void)
|
||||
{
|
||||
while (nand_bcm_umi_dev_ready() == 0)
|
||||
;
|
||||
}
|
||||
|
||||
/* Enable Hamming ECC */
|
||||
static inline void nand_bcm_umi_hamming_enable_hwecc(void)
|
||||
{
|
||||
/* disable and reset ECC, 512 byte page */
|
||||
REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
|
||||
REG_UMI_NAND_ECC_CSR_256BYTE);
|
||||
/* enable ECC */
|
||||
REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
|
||||
}
|
||||
|
||||
#if NAND_ECC_BCH
|
||||
/* BCH ECC specifics */
|
||||
#define ECC_BITS_PER_CORRECTABLE_BIT 13
|
||||
|
||||
/* Enable BCH Read ECC */
|
||||
static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
|
||||
{
|
||||
/* disable and reset ECC */
|
||||
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
|
||||
/* Turn on ECC */
|
||||
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
|
||||
}
|
||||
|
||||
/* Enable BCH Write ECC */
|
||||
static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
|
||||
{
|
||||
/* disable and reset ECC */
|
||||
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
|
||||
/* Turn on ECC */
|
||||
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
|
||||
}
|
||||
|
||||
/* Config number of BCH ECC bytes */
|
||||
static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
|
||||
{
|
||||
uint32_t nValue;
|
||||
uint32_t tValue;
|
||||
uint32_t kValue;
|
||||
uint32_t numBits = numEccBytes * 8;
|
||||
|
||||
/* disable and reset ECC */
|
||||
REG_UMI_BCH_CTRL_STATUS =
|
||||
REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
|
||||
REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
|
||||
|
||||
/* Every correctible bit requires 13 ECC bits */
|
||||
tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
|
||||
|
||||
/* Total data in number of bits for generating and computing BCH ECC */
|
||||
nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8;
|
||||
|
||||
/* K parameter is used internally. K = N - (T * 13) */
|
||||
kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
|
||||
|
||||
/* Write the settings */
|
||||
REG_UMI_BCH_N = nValue;
|
||||
REG_UMI_BCH_T = tValue;
|
||||
REG_UMI_BCH_K = kValue;
|
||||
}
|
||||
|
||||
/* Pause during ECC read calculation to skip bytes in OOB */
|
||||
static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
|
||||
{
|
||||
REG_UMI_BCH_CTRL_STATUS =
|
||||
REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
|
||||
REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
|
||||
}
|
||||
|
||||
/* Resume during ECC read calculation after skipping bytes in OOB */
|
||||
static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
|
||||
{
|
||||
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
|
||||
}
|
||||
|
||||
/* Poll read ECC calc to check when hardware completes */
|
||||
static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
|
||||
{
|
||||
uint32_t regVal;
|
||||
|
||||
do {
|
||||
/* wait for ECC to be valid */
|
||||
regVal = REG_UMI_BCH_CTRL_STATUS;
|
||||
} while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
|
||||
|
||||
return regVal;
|
||||
}
|
||||
|
||||
/* Poll write ECC calc to check when hardware completes */
|
||||
static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
|
||||
{
|
||||
/* wait for ECC to be valid */
|
||||
while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
|
||||
== 0)
|
||||
;
|
||||
}
|
||||
|
||||
/* Read the OOB and ECC, for kernel write OOB to a buffer */
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
|
||||
uint8_t *eccCalc, int numEccBytes, uint8_t *oobp)
|
||||
#else
|
||||
static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
|
||||
uint8_t *eccCalc, int numEccBytes)
|
||||
#endif
|
||||
{
|
||||
int eccPos = 0;
|
||||
int numToRead = 16; /* There are 16 bytes per sector in the OOB */
|
||||
|
||||
/* ECC is already paused when this function is called */
|
||||
if (pageSize != NAND_DATA_ACCESS_SIZE) {
|
||||
/* skip BI */
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
*oobp++ = REG_NAND_DATA8;
|
||||
#else
|
||||
REG_NAND_DATA8;
|
||||
#endif
|
||||
numToRead--;
|
||||
}
|
||||
|
||||
while (numToRead > numEccBytes) {
|
||||
/* skip free oob region */
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
*oobp++ = REG_NAND_DATA8;
|
||||
#else
|
||||
REG_NAND_DATA8;
|
||||
#endif
|
||||
numToRead--;
|
||||
}
|
||||
|
||||
if (pageSize == NAND_DATA_ACCESS_SIZE) {
|
||||
/* read ECC bytes before BI */
|
||||
nand_bcm_umi_bch_resume_read_ecc_calc();
|
||||
|
||||
while (numToRead > 11) {
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
*oobp = REG_NAND_DATA8;
|
||||
eccCalc[eccPos++] = *oobp;
|
||||
oobp++;
|
||||
#else
|
||||
eccCalc[eccPos++] = REG_NAND_DATA8;
|
||||
#endif
|
||||
numToRead--;
|
||||
}
|
||||
|
||||
nand_bcm_umi_bch_pause_read_ecc_calc();
|
||||
|
||||
if (numToRead == 11) {
|
||||
/* read BI */
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
*oobp++ = REG_NAND_DATA8;
|
||||
#else
|
||||
REG_NAND_DATA8;
|
||||
#endif
|
||||
numToRead--;
|
||||
}
|
||||
|
||||
}
|
||||
/* read ECC bytes */
|
||||
nand_bcm_umi_bch_resume_read_ecc_calc();
|
||||
while (numToRead) {
|
||||
#if defined(__KERNEL__) && !defined(STANDALONE)
|
||||
*oobp = REG_NAND_DATA8;
|
||||
eccCalc[eccPos++] = *oobp;
|
||||
oobp++;
|
||||
#else
|
||||
eccCalc[eccPos++] = REG_NAND_DATA8;
|
||||
#endif
|
||||
numToRead--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function to write ECC */
|
||||
static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos,
|
||||
uint8_t *oobp, uint8_t eccVal)
|
||||
{
|
||||
if (eccBytePos <= numEccBytes)
|
||||
*oobp = eccVal;
|
||||
}
|
||||
|
||||
/* Write OOB with ECC */
|
||||
static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
|
||||
uint8_t *oobp, int numEccBytes)
|
||||
{
|
||||
uint32_t eccVal = 0xffffffff;
|
||||
|
||||
/* wait for write ECC to be valid */
|
||||
nand_bcm_umi_bch_poll_write_ecc_calc();
|
||||
|
||||
/*
|
||||
** Get the hardware ecc from the 32-bit result registers.
|
||||
** Read after 512 byte accesses. Format B3B2B1B0
|
||||
** where B3 = ecc3, etc.
|
||||
*/
|
||||
|
||||
if (pageSize == NAND_DATA_ACCESS_SIZE) {
|
||||
/* Now fill in the ECC bytes */
|
||||
if (numEccBytes >= 13)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_3;
|
||||
|
||||
/* Usually we skip CM in oob[0,1] */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
|
||||
(eccVal >> 16) & 0xff);
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1],
|
||||
(eccVal >> 8) & 0xff);
|
||||
|
||||
/* Write ECC in oob[2,3,4] */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2],
|
||||
eccVal & 0xff); /* ECC 12 */
|
||||
|
||||
if (numEccBytes >= 9)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_2;
|
||||
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
|
||||
(eccVal >> 24) & 0xff); /* ECC11 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4],
|
||||
(eccVal >> 16) & 0xff); /* ECC10 */
|
||||
|
||||
/* Always Skip BI in oob[5] */
|
||||
} else {
|
||||
/* Always Skip BI in oob[0] */
|
||||
|
||||
/* Now fill in the ECC bytes */
|
||||
if (numEccBytes >= 13)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_3;
|
||||
|
||||
/* Usually skip CM in oob[1,2] */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
|
||||
(eccVal >> 16) & 0xff);
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2],
|
||||
(eccVal >> 8) & 0xff);
|
||||
|
||||
/* Write ECC in oob[3-15] */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3],
|
||||
eccVal & 0xff); /* ECC12 */
|
||||
|
||||
if (numEccBytes >= 9)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_2;
|
||||
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
|
||||
(eccVal >> 24) & 0xff); /* ECC11 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5],
|
||||
(eccVal >> 16) & 0xff); /* ECC10 */
|
||||
}
|
||||
|
||||
/* Fill in the remainder of ECC locations */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6],
|
||||
(eccVal >> 8) & 0xff); /* ECC9 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7],
|
||||
eccVal & 0xff); /* ECC8 */
|
||||
|
||||
if (numEccBytes >= 5)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_1;
|
||||
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
|
||||
(eccVal >> 24) & 0xff); /* ECC7 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9],
|
||||
(eccVal >> 16) & 0xff); /* ECC6 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10],
|
||||
(eccVal >> 8) & 0xff); /* ECC5 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11],
|
||||
eccVal & 0xff); /* ECC4 */
|
||||
|
||||
if (numEccBytes >= 1)
|
||||
eccVal = REG_UMI_BCH_WR_ECC_0;
|
||||
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
|
||||
(eccVal >> 24) & 0xff); /* ECC3 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13],
|
||||
(eccVal >> 16) & 0xff); /* ECC2 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14],
|
||||
(eccVal >> 8) & 0xff); /* ECC1 */
|
||||
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15],
|
||||
eccVal & 0xff); /* ECC0 */
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NAND_BCM_UMI_H */
|
||||
Reference in new issue
Block a user