lkml.org 
[lkml]   [2013]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 8/8] mtd: gpmi: set the BCH's geometry with the ecc info
    Date
    If the nand chip provides us the ECC info, we can use it firstly.
    The set_geometry_by_ecc_info() will use the ECC info, and
    calculate the parameters we need.

    Rename the old code to lagacy_set_geometry() which will takes effect
    when there is no ECC info from the nand chip or we fails in the ECC info case.

    Signed-off-by: Huang Shijie <b32955@freescale.com>
    Signed-off-by: Huang Shijie <shijie8@gmail.com>
    ---
    drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 128 +++++++++++++++++++++++++++++++-
    1 files changed, 127 insertions(+), 1 deletions(-)

    diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
    index 717881a..e085ade 100644
    --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
    +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
    @@ -113,7 +113,128 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
    return true;
    }

    -int common_nfc_set_geometry(struct gpmi_nand_data *this)
    +/*
    + * If we can get the ECC information from the nand chip, we do not
    + * need to calculate them ourselves.
    + *
    + * We may have available oob space in this case.
    + */
    +static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
    +{
    + struct bch_geometry *geo = &this->bch_geometry;
    + struct mtd_info *mtd = &this->mtd;
    + struct nand_chip *chip = mtd->priv;
    + struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
    + unsigned int block_mark_bit_offset;
    +
    + if (!(chip->ecc_strength > 0 && chip->ecc_size > 0))
    + return false;
    +
    + switch (chip->ecc_size) {
    + case SZ_512:
    + geo->gf_len = 13;
    + break;
    + case SZ_1K:
    + geo->gf_len = 14;
    + break;
    + default:
    + dev_err(this->dev,
    + "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
    + chip->ecc_strength, chip->ecc_size);
    + return false;
    + }
    + geo->ecc_chunk_size = chip->ecc_size;
    + geo->ecc_strength = round_up(chip->ecc_strength, 2);
    + if (!gpmi_check_ecc(this))
    + return false;
    +
    + /* Keep the C >= O */
    + if (geo->ecc_chunk_size < mtd->oobsize) {
    + dev_err(this->dev,
    + "unsupported nand chip. ecc size: %d, oob size : %d\n",
    + chip->ecc_size, mtd->oobsize);
    + return false;
    + }
    +
    + /* The default value, see comment in the lagacy_set_geometry(). */
    + geo->metadata_size = 10;
    +
    + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
    +
    + /*
    + * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
    + *
    + * | P |
    + * |<----------------------------------------------------->|
    + * | |
    + * | (Block Mark) |
    + * | P' | | | |
    + * |<-------------------------------------------->| D | | O' |
    + * | |<---->| |<--->|
    + * V V V V V
    + * +---+----------+-+----------+-+----------+-+----------+-+-----+
    + * | M | data |E| data |E| data |E| data |E| |
    + * +---+----------+-+----------+-+----------+-+----------+-+-----+
    + *
    + * P : the page size for BCH module.
    + * E : The ECC strength.
    + * G : the length of Galois Field.
    + * N : The chunk count of per page.
    + * M : the metasize of per page.
    + * C : the ecc chunk size, aka the "data" above.
    + * P': the nand chip's page size.
    + * O : the nand chip's oob size.
    + * O': the free oob.
    + *
    + * The formula for P is :
    + *
    + * E * G * N
    + * P = ------------ + P' + M
    + * 8
    + *
    + * The position of block mark moves forward in the ECC-based view
    + * of page, and the delta is:
    + *
    + * E * G * (N - 1)
    + * D = (---------------- + M)
    + * 8
    + *
    + * Please see the comment in lagacy_set_geometry().
    + * With the condition C >= O , we still can get same result.
    + * So the bit position of the physical block mark within the ECC-based
    + * view of the page is :
    + * (P' - D) * 8
    + */
    + geo->page_size = mtd->writesize + geo->metadata_size +
    + (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
    +
    + /* The available oob size we have. */
    + if (geo->page_size < mtd->writesize + mtd->oobsize) {
    + of->offset = geo->page_size - mtd->writesize;
    + of->length = mtd->oobsize - of->offset;
    + mtd->oobavail = gpmi_hw_ecclayout.oobavail = of->length;
    + }
    +
    + geo->payload_size = mtd->writesize;
    +
    + geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
    + geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
    + + ALIGN(geo->ecc_chunk_count, 4);
    +
    + if (!this->swap_block_mark)
    + return true;
    +
    + /* For bit swap. */
    + block_mark_bit_offset = mtd->writesize * 8 -
    + (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
    + + geo->metadata_size * 8);
    +
    + geo->block_mark_byte_offset = block_mark_bit_offset / 8;
    + geo->block_mark_bit_offset = block_mark_bit_offset % 8;
    + return true;
    +}
    +
    +static int lagacy_set_geometry(struct gpmi_nand_data *this)
    {
    struct bch_geometry *geo = &this->bch_geometry;
    struct mtd_info *mtd = &this->mtd;
    @@ -225,6 +346,11 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
    return 0;
    }

    +int common_nfc_set_geometry(struct gpmi_nand_data *this)
    +{
    + return set_geometry_by_ecc_info(this) ? 0 : lagacy_set_geometry(this);
    +}
    +
    struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
    {
    int chipnr = this->current_chip;
    --
    1.7.1



    \
     
     \ /
      Last update: 2013-04-22 10:41    [W:2.699 / U:0.584 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site