lkml.org 
[lkml]   [2010]   [Jan]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 6/9] mtd: common module for smartmedia/xD support
    From
    Date
    >From 06cb6f7fa6d9c708ca0a208b33c6e3b5969aab44 Mon Sep 17 00:00:00 2001
    From: Maxim Levitsky <maximlevitsky@gmail.com>
    Date: Wed, 6 Jan 2010 22:52:56 +0200
    Subject: [PATCH 6/9] mtd: common module for smartmedia/xD support

    ---
    drivers/mtd/Kconfig | 9 ++
    drivers/mtd/Makefile | 1 +
    drivers/mtd/sm_common.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++
    drivers/mtd/sm_common.h | 31 +++++++
    4 files changed, 249 insertions(+), 0 deletions(-)
    create mode 100644 drivers/mtd/sm_common.c
    create mode 100644 drivers/mtd/sm_common.h

    diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
    index ecf90f5..ebeabd6 100644
    --- a/drivers/mtd/Kconfig
    +++ b/drivers/mtd/Kconfig
    @@ -25,6 +25,15 @@ config MTD_DEBUG_VERBOSE
    help
    Determines the verbosity level of the MTD debugging messages.

    +config MTD_NAND_SMARTMEDIA
    + boolean
    +
    +config MTD_SM_COMMON
    + depends on MTD_NAND
    + select MTD_NAND_SMARTMEDIA
    + tristate
    + default n
    +
    config MTD_TESTS
    tristate "MTD tests support"
    depends on m
    diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
    index 82d1e4d..02c5b17 100644
    --- a/drivers/mtd/Makefile
    +++ b/drivers/mtd/Makefile
    @@ -7,6 +7,7 @@ obj-$(CONFIG_MTD) += mtd.o
    mtd-y := mtdcore.o mtdsuper.o mtdbdi.o
    mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o

    +obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
    obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
    obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
    obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
    diff --git a/drivers/mtd/sm_common.c b/drivers/mtd/sm_common.c
    new file mode 100644
    index 0000000..3d57f40
    --- /dev/null
    +++ b/drivers/mtd/sm_common.c
    @@ -0,0 +1,208 @@
    +/*
    + * Copyright (C) 2009 - Maxim Levitsky
    + * Common routines & support for xD format
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +
    +#include <linux/kernel.h>
    +#include <linux/bitops.h>
    +#include <linux/log2.h>
    +#include "sm_common.h"
    +
    +#if 0
    +static struct nand_ecclayout nand_oob_sm = {
    + .eccbytes = 6,
    + .eccpos = {8, 9, 10, 13, 14, 15},
    + .oobfree = {
    + {.offset = 0 , .length = 4}, /* reserved */
    + {.offset = 4 , .length = 2}, /* data & block status */
    + {.offset = 6 , .length = 2}, /* LBA1 */
    + {.offset = 11, .length = 2} /* LBA2 */
    + }
    +};
    +#endif
    +
    +static struct nand_ecclayout nand_oob_sm = {
    + .eccbytes = 0,
    + .oobfree = {
    + {.offset = 0 , .length = 16}, /* reserved */
    + }
    +};
    +
    +static int sm_get_lba(u8 *lba)
    +{
    + /* check fixed bits */
    + if ((lba[0] & 0xF8) != 0x10)
    + return -2;
    +
    + /* check parity - endianess doesn't matter */
    + if (hweight16(*(u16*)lba) & 1)
    + return -2;
    +
    + return (lba[1] >> 1) | ((lba[0] & 0x07) << 7);
    +}
    +
    +
    +/*
    + * Read LBA asscociated with block
    + * returns -1, if block is erased
    + * returns -2 if error happens
    + */
    +int sm_read_lba(struct sm_oob *oob)
    +{
    + static const u32 erased_pattern[4] =
    + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
    +
    + u16 lba_test;
    + int lba;
    + //int i;
    +
    + /* First test for erased block */
    + if (!memcmp(oob, erased_pattern, sizeof(erased_pattern)))
    + return -1;
    +
    + /* Now check is both copies of the LBA differ too much */
    + lba_test = *(u16*)oob->lba_copy1 ^ *(u16*)oob->lba_copy2;
    + if (lba_test && !is_power_of_2(lba_test))
    + return -2;
    +
    +
    + /* And read it */
    + if ((lba = sm_get_lba(oob->lba_copy1)) == -2)
    + lba = sm_get_lba(oob->lba_copy2);
    +
    + return lba;
    +}
    +EXPORT_SYMBOL_GPL(sm_read_lba);
    +
    +void sm_write_lba(struct sm_oob *oob, u16 lba)
    +{
    + u8 tmp[2];
    +
    + WARN_ON(lba > 1000);
    +
    + tmp[0] = 0x10 | ((lba >> 7) & 0x07);
    + tmp[1] = (lba << 1) & 0xFF;
    +
    + if(hweight16(*(u16*)tmp) & 0x01)
    + tmp[1] |= 1;
    +
    + oob->lba_copy1[0] = oob->lba_copy2[0] = tmp[0];
    + oob->lba_copy1[1] = oob->lba_copy2[1] = tmp[1];
    +}
    +EXPORT_SYMBOL_GPL(sm_write_lba);
    +
    +/* Test if whole block is valid, or at least is marked as such...*/
    +int sm_block_valid(struct sm_oob *oob)
    +{
    + /* test block status */
    + if (hweight16(oob->block_status) < 7)
    + return -EIO;
    +
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(sm_block_valid);
    +
    +
    +/* Test if sector is valid */
    +int sm_sector_valid(struct sm_oob *oob)
    +{
    + /* test data status */
    + if (hweight16(oob->data_status) < 5)
    + return -EIO;
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(sm_sector_valid);
    +
    +
    +
    +/* Nand interface helpers */
    +static int sm_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
    +{
    + struct nand_chip *chip = (struct nand_chip *)mtd->priv;
    + struct mtd_oob_ops ops;
    + struct sm_oob oob;
    + int ret;
    +
    + ops.mode = MTD_OOB_RAW;
    + ops.ooboffs = 0;
    + ops.ooblen = SM_OOB_SIZE;
    + ops.oobbuf = (void*)&oob;
    + ops.datbuf = NULL;
    +
    + /* TODO: This doesn't take controller lock,
    + but we know that all xD cards are single chip. */
    + if (getchip)
    + chip->select_chip(mtd, 0);
    +
    + ret = nand_do_read_oob(mtd, ofs, &ops);
    + if (ret < 0 || ops.oobretlen != SM_OOB_SIZE)
    + goto out;
    +
    + ret = sm_block_valid(&oob) ? 1 : 0;
    +out:
    + if (getchip)
    + chip->select_chip(mtd, -1);
    +
    + if (ret)
    + printk(KERN_NOTICE "sm_common: bad sector at %i\n", (int)ofs);
    + return ret;
    +}
    +
    +static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
    +{
    + struct mtd_oob_ops ops;
    + struct sm_oob oob;
    + int ret;
    +
    + memset (&oob, -1, sizeof(oob));
    + oob.block_status = 0xF0;
    +
    + ops.mode = MTD_OOB_RAW;
    + ops.ooboffs = 0;
    + ops.ooblen = SM_OOB_SIZE;
    + ops.oobbuf = (void*)&oob;
    + ops.datbuf = NULL;
    +
    + ret = nand_do_write_oob(mtd, ofs, &ops);
    + if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
    + printk(KERN_NOTICE "sm_common: can't mark sector at %i as bad\n",
    + (int)ofs);
    + return 1;
    + }
    +
    + return 0;
    +}
    +
    +int sm_register_device(struct mtd_info *mtd)
    +{
    + struct nand_chip *chip = (struct nand_chip *)mtd->priv;
    +
    + chip->options |= NAND_SKIP_BBTSCAN | NAND_NO_AUTOINCR;
    +
    + chip->block_bad = sm_block_bad;
    + chip->block_markbad = sm_block_markbad;
    + chip->ecc.layout = &nand_oob_sm;
    +
    + if (nand_scan(mtd, 1))
    + return -ENODEV;
    +
    + /* TODO: support small page devices */
    + if (mtd->writesize != 512)
    + return -ENODEV;
    +
    +
    + if (add_mtd_device(mtd))
    + return -ENODEV;
    +
    + return 0;
    +}
    +
    +EXPORT_SYMBOL_GPL(sm_register_device);
    +
    +MODULE_LICENSE("GPL");
    +MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
    +MODULE_DESCRIPTION("Common SmartMedia/xD functions");
    \ No newline at end of file
    diff --git a/drivers/mtd/sm_common.h b/drivers/mtd/sm_common.h
    new file mode 100644
    index 0000000..d546770
    --- /dev/null
    +++ b/drivers/mtd/sm_common.h
    @@ -0,0 +1,31 @@
    +/*
    + * Copyright (C) 2009 - Maxim Levitsky
    + * Common routines & support for SmartMedia/xD format
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +
    +#include <linux/mtd/nand.h>
    +
    +struct sm_oob {
    + u32 reserved;
    + u8 data_status;
    + u8 block_status;
    + u8 lba_copy1[2];
    + u8 ecc2[3];
    + u8 lba_copy2[2];
    + u8 ecc1[3];
    +} __attribute__((packed));
    +
    +
    +#define SM_SECTOR_SIZE 512
    +#define SM_OOB_SIZE 16
    +#define SM_SMALL_PAGE 256
    +
    +extern int sm_register_device(struct mtd_info *mtd);
    +extern int sm_read_lba(struct sm_oob *oob);
    +extern void sm_write_lba(struct sm_oob *oob, u16 lba);
    +extern int sm_block_valid(struct sm_oob *oob);
    +extern int sm_sector_valid(struct sm_oob *oob);
    \ No newline at end of file
    --
    1.6.3.3




    \
     
     \ /
      Last update: 2010-01-06 22:55    [W:0.035 / U:0.152 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site