diff mbox

[V2,3/7] MTD : add the database for the NANDs

Message ID 1301048581-21321-4-git-send-email-b32955@freescale.com
State New, archived
Headers show

Commit Message

Huang Shijie March 25, 2011, 10:22 a.m. UTC
This is a new database for the NANDs which is searched by the id_bytes.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/mtd/nand/nand_device_info.c |  154 +++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/nand_device_info.h |   83 +++++++++++++++++++
 2 files changed, 237 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/nand_device_info.c
 create mode 100644 drivers/mtd/nand/nand_device_info.h

Comments

Florian Fainelli March 25, 2011, 10:34 a.m. UTC | #1
Hello Huang,

On Friday 25 March 2011 11:22:57 Huang Shijie wrote:
> This is a new database for the NANDs which is searched by the id_bytes.
> 
> Signed-off-by: Huang Shijie <b32955@freescale.com>
> ---
>  drivers/mtd/nand/nand_device_info.c |  154
> +++++++++++++++++++++++++++++++++++ drivers/mtd/nand/nand_device_info.h | 
>  83 +++++++++++++++++++
>  2 files changed, 237 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mtd/nand/nand_device_info.c
>  create mode 100644 drivers/mtd/nand/nand_device_info.h
> 
> diff --git a/drivers/mtd/nand/nand_device_info.c
> b/drivers/mtd/nand/nand_device_info.c new file mode 100644
> index 0000000..3ceec9c
> --- /dev/null
> +++ b/drivers/mtd/nand/nand_device_info.c
> @@ -0,0 +1,154 @@
> +/*
> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +#include <asm/sizes.h>
> +#include <linux/mtd/nand.h>
> +
> +#include "nand_device_info.h"
> +
> +static const struct nand_device_info samsung_nand[] = {
> +	{
> +		.id	= { 0xec, 0xd3, 0x14, 0x25, 0x64, 0xec, 0xd3, 0x14 },
> +		.id_len	= 8,
> +		.desc	= "K9G8G08U0M, K9HAG08U1M",
> +		.attr	= ATTR(MLC, 1LL * SZ_1G, 128, 2 * SZ_1K + 64, 8, 512),
> +	}, {
> +		.id	= { 0xec, 0xd7, 0xd5, 0x29, 0x38, 0x41, 0xec, 0xd7 },
> +		.id_len	= 8,
> +		.desc	= "K9LBG08U0D",
> +		.attr	= ATTR(MLC, 4LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
> +	}, {
> +		.id	= { 0xec, 0xd5, 0x14, 0xb6, 0x74, 0xec, 0xd5, 0x14 },
> +		.id_len	= 8,
> +		.desc	= "K9GAG08U0M",
> +		.attr	= ATTR(MLC, 2LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
> +	}, {
> +		/* end of the table. */
> +		.id	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
> +	},
> +};

Sorry, but I do not see why this is still needed. drivers/mtd/nand_ids.c 
should already recognize all of these chips correctly. If this is not the case 
for you, you should fix nand_get_flash_type() instead.

> +
> +/* macro to get the id bytes */
> +#define ID_GET_MFR_CODE(id)  ((id)[0])
> +
> +void nand_device_print_info(struct nand_device_info *info)
> +{
> +	unsigned    i;
> +	const char  *mfr_name;
> +	const char  *cell_technology_name;
> +	uint64_t    chip_size;
> +	const char  *chip_size_units;
> +	unsigned    page_size;
> +	unsigned    oob_size;
> +	struct nand_attr *attr		= &info->attr;
> +
> +	/* Prepare the manufacturer name. */
> +	mfr_name = "Unknown";
> +	for (i = 0; nand_manuf_ids[i].id; i++) {
> +		if (nand_manuf_ids[i].id == ID_GET_MFR_CODE(info->id)) {
> +			mfr_name = nand_manuf_ids[i].name;
> +			break;
> +		}
> +	}
> +
> +	/* Prepare the name of the cell technology. */
> +	switch (attr->cell_technology) {
> +	case SLC:
> +		cell_technology_name = "SLC";
> +		break;
> +	case MLC:
> +		cell_technology_name = "MLC";
> +		break;
> +	default:
> +		cell_technology_name = "Unknown";
> +		break;
> +	}
> +
> +	/* Prepare the chip size. */
> +	if ((attr->chip_size_in_bytes >= SZ_1G) &&
> +					!(attr->chip_size_in_bytes % SZ_1G)) {
> +		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1G);
> +		chip_size_units = "GiB";
> +	} else if ((attr->chip_size_in_bytes >= SZ_1M) &&
> +					!(attr->chip_size_in_bytes % SZ_1M)) {
> +		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1M);
> +		chip_size_units = "MiB";
> +	} else {
> +		chip_size       = attr->chip_size_in_bytes;
> +		chip_size_units = "B";
> +	}
> +
> +	/* Prepare the page geometry. */
> +	page_size = (1 << (fls(attr->page_total_size_in_bytes) - 1));
> +	oob_size  = attr->page_total_size_in_bytes - page_size;
> +
> +	/* Print the infomation. */
> +	pr_info("--------------------------------------\n");
> +	pr_info("	NAND device infomation (RAW)\n");
> +	pr_info("--------------------------------------\n");
> +	pr_info("Manufacturer      : %s (0x%02x)\n", mfr_name, info->id[0]);
> +	pr_info("Device Code       : 0x%02x\n", info->id[1]);
> +	pr_info("Cell Technology   : %s\n", cell_technology_name);
> +	pr_info("Chip Size         : %llu %s\n", chip_size, chip_size_units);
> +	pr_info("Pages per Block   : %u\n", attr->block_size_in_pages);
> +	pr_info("Page Geometry     : %u+%u\n", page_size, oob_size);
> +	pr_info("ECC Strength      : %u bits\n", attr->ecc_strength_in_bits);
> +	pr_info("ECC Size          : %u B\n", attr->ecc_size_in_bytes);
> +	pr_info("Description       : %s\n", info->desc);
> +}
> +
> +static struct nand_device_info * __init
> +search_table(const struct nand_device_info *table, const uint8_t id[])
> +{
> +	struct nand_device_info *info = (struct nand_device_info *)table;
> +
> +	while (ID_GET_MFR_CODE(info->id)) {
> +		int i;
> +
> +		/* match all the valid id bytes. Is it too strict? */
> +		for (i = 0; i < info->id_len; i++)
> +			if (info->id[i] != id[i])
> +				break;
> +
> +		/* found it */
> +		if (i == info->id_len)
> +			return info;
> +		info++;
> +	}
> +	return NULL;
> +}
> +
> +struct nand_device_mfr_info {
> +	uint8_t                  id;
> +	const struct nand_device_info  *table;
> +};
> +
> +static const struct nand_device_mfr_info  nand_device_mfr_directory[] = {
> +	{ NAND_MFR_SAMSUNG, samsung_nand },
> +	{ 0, NULL },
> +};
> +
> +struct nand_device_info *nand_device_get_info(const uint8_t id[])
> +{
> +	uint8_t mfr_id = ID_GET_MFR_CODE(id);
> +	unsigned i;
> +
> +	for (i = 0; nand_device_mfr_directory[i].id; i++) {
> +		if (nand_device_mfr_directory[i].id == mfr_id) {
> +			const struct nand_device_info  *table;
> +
> +			table = nand_device_mfr_directory[i].table;
> +			return search_table(table, id);
> +		}
> +	}
> +	return NULL;
> +}
> diff --git a/drivers/mtd/nand/nand_device_info.h
> b/drivers/mtd/nand/nand_device_info.h new file mode 100644
> index 0000000..fe22233
> --- /dev/null
> +++ b/drivers/mtd/nand/nand_device_info.h
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +#ifndef __DRIVERS_NAND_DEVICE_INFO_H
> +#define __DRIVERS_NAND_DEVICE_INFO_H
> +
> +enum nand_device_cell_technology {
> +	SLC = 0,
> +	MLC = 1,
> +};
> +
> +/**
> + * @cell_technology:           The storage cell technology.
> + * @chip_size_in_bytes:        The total size of the storage behind a
> single + *                             chip select, in bytes. Notice that
> this is *not* + *                             necessarily the total size
> of the storage in a + *                             *package*, which may
> contain several chips. + * @block_size_in_pages:       The number of pages
> in a block.
> + * @page_total_size_in_bytes:  The total size of a page, in bytes,
> including + *                             both the data and the OOB.
> + * @ecc_strength_in_bits:      The strength of the ECC called for by the
> + *                             manufacturer, in number of correctable
> bits. + * @ecc_size_in_bytes:         The size of the data block over
> which the + *                             manufacturer calls for the given
> ECC algorithm + *                             and strength.
> + */
> +struct nand_attr {
> +	/* Technology */
> +	enum nand_device_cell_technology  cell_technology;
> +
> +	/* Geometry */
> +	uint64_t	chip_size_in_bytes;
> +	uint32_t	block_size_in_pages;
> +	uint32_t	page_total_size_in_bytes;
> +
> +	/* ECC */
> +	uint16_t	ecc_strength_in_bits;
> +	uint16_t	ecc_size_in_bytes;
> +};
> +
> +#define ID_BYTES	(8)
> +/*
> + * struct nand_device_info - Information about a single NAND Flash device.
> + *
> + * This structure contains all the *essential* information about a NAND
> Flash + * device, derived from the device's data sheet.
> + */
> +struct nand_device_info {
> +	/* id */
> +	uint8_t			id[ID_BYTES];
> +	unsigned int		id_len;
> +
> +	/* Description */
> +	const char		*desc;
> +
> +	/* attribute*/
> +	struct nand_attr	attr;
> +};
> +
> +/* macro for the NAND attribute */
> +#define ATTR(_a, _b, _c, _d, _e, _f)			\
> +	{						\
> +		.cell_technology          = (_a),	\
> +		.chip_size_in_bytes       = (_b),	\
> +		.block_size_in_pages      = (_c),	\
> +		.page_total_size_in_bytes = (_d),	\
> +		.ecc_strength_in_bits     = (_e),	\
> +		.ecc_size_in_bytes        = (_f),	\
> +	}
> +
> +struct nand_device_info *nand_device_get_info(const uint8_t id_bytes[]);
> +void nand_device_print_info(struct nand_device_info *info);
> +
> +#endif
Huang Shijie March 28, 2011, 2 a.m. UTC | #2
Hi Florian:

> Hello Huang,
>
> On Friday 25 March 2011 11:22:57 Huang Shijie wrote:
>> This is a new database for the NANDs which is searched by the id_bytes.
>>
>> Signed-off-by: Huang Shijie<b32955@freescale.com>
>> ---
>>   drivers/mtd/nand/nand_device_info.c |  154
>> +++++++++++++++++++++++++++++++++++ drivers/mtd/nand/nand_device_info.h |
>>   83 +++++++++++++++++++
>>   2 files changed, 237 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/mtd/nand/nand_device_info.c
>>   create mode 100644 drivers/mtd/nand/nand_device_info.h
>>
>> diff --git a/drivers/mtd/nand/nand_device_info.c
>> b/drivers/mtd/nand/nand_device_info.c new file mode 100644
>> index 0000000..3ceec9c
>> --- /dev/null
>> +++ b/drivers/mtd/nand/nand_device_info.c
>> @@ -0,0 +1,154 @@
>> +/*
>> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + */
>> +
>> +/*
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */
>> +#include<asm/sizes.h>
>> +#include<linux/mtd/nand.h>
>> +
>> +#include "nand_device_info.h"
>> +
>> +static const struct nand_device_info samsung_nand[] = {
>> +	{
>> +		.id	= { 0xec, 0xd3, 0x14, 0x25, 0x64, 0xec, 0xd3, 0x14 },
>> +		.id_len	= 8,
>> +		.desc	= "K9G8G08U0M, K9HAG08U1M",
>> +		.attr	= ATTR(MLC, 1LL * SZ_1G, 128, 2 * SZ_1K + 64, 8, 512),
>> +	}, {
>> +		.id	= { 0xec, 0xd7, 0xd5, 0x29, 0x38, 0x41, 0xec, 0xd7 },
>> +		.id_len	= 8,
>> +		.desc	= "K9LBG08U0D",
>> +		.attr	= ATTR(MLC, 4LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
>> +	}, {
>> +		.id	= { 0xec, 0xd5, 0x14, 0xb6, 0x74, 0xec, 0xd5, 0x14 },
>> +		.id_len	= 8,
>> +		.desc	= "K9GAG08U0M",
>> +		.attr	= ATTR(MLC, 2LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
>> +	}, {
>> +		/* end of the table. */
>> +		.id	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
>> +	},
>> +};
> Sorry, but I do not see why this is still needed. drivers/mtd/nand_ids.c
> should already recognize all of these chips correctly. If this is not the case
> for you, you should fix nand_get_flash_type() instead.
>
These nands are only a example. I have other nands to add in future.
I will fix nand_get_flash_type() in future, not now. thanks

Btw : I forget to add  the `busw` field in my nand_device_info{}.

>> +
>> +/* macro to get the id bytes */
>> +#define ID_GET_MFR_CODE(id)  ((id)[0])
>> +
>> +void nand_device_print_info(struct nand_device_info *info)
>> +{
>> +	unsigned    i;
>> +	const char  *mfr_name;
>> +	const char  *cell_technology_name;
>> +	uint64_t    chip_size;
>> +	const char  *chip_size_units;
>> +	unsigned    page_size;
>> +	unsigned    oob_size;
>> +	struct nand_attr *attr		=&info->attr;
>> +
>> +	/* Prepare the manufacturer name. */
>> +	mfr_name = "Unknown";
>> +	for (i = 0; nand_manuf_ids[i].id; i++) {
>> +		if (nand_manuf_ids[i].id == ID_GET_MFR_CODE(info->id)) {
>> +			mfr_name = nand_manuf_ids[i].name;
>> +			break;
>> +		}
>> +	}
>> +
>> +	/* Prepare the name of the cell technology. */
>> +	switch (attr->cell_technology) {
>> +	case SLC:
>> +		cell_technology_name = "SLC";
>> +		break;
>> +	case MLC:
>> +		cell_technology_name = "MLC";
>> +		break;
>> +	default:
>> +		cell_technology_name = "Unknown";
>> +		break;
>> +	}
>> +
>> +	/* Prepare the chip size. */
>> +	if ((attr->chip_size_in_bytes>= SZ_1G)&&
>> +					!(attr->chip_size_in_bytes % SZ_1G)) {
>> +		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1G);
>> +		chip_size_units = "GiB";
>> +	} else if ((attr->chip_size_in_bytes>= SZ_1M)&&
>> +					!(attr->chip_size_in_bytes % SZ_1M)) {
>> +		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1M);
>> +		chip_size_units = "MiB";
>> +	} else {
>> +		chip_size       = attr->chip_size_in_bytes;
>> +		chip_size_units = "B";
>> +	}
>> +
>> +	/* Prepare the page geometry. */
>> +	page_size = (1<<  (fls(attr->page_total_size_in_bytes) - 1));
>> +	oob_size  = attr->page_total_size_in_bytes - page_size;
>> +
>> +	/* Print the infomation. */
>> +	pr_info("--------------------------------------\n");
>> +	pr_info("	NAND device infomation (RAW)\n");
>> +	pr_info("--------------------------------------\n");
>> +	pr_info("Manufacturer      : %s (0x%02x)\n", mfr_name, info->id[0]);
>> +	pr_info("Device Code       : 0x%02x\n", info->id[1]);
>> +	pr_info("Cell Technology   : %s\n", cell_technology_name);
>> +	pr_info("Chip Size         : %llu %s\n", chip_size, chip_size_units);
>> +	pr_info("Pages per Block   : %u\n", attr->block_size_in_pages);
>> +	pr_info("Page Geometry     : %u+%u\n", page_size, oob_size);
>> +	pr_info("ECC Strength      : %u bits\n", attr->ecc_strength_in_bits);
>> +	pr_info("ECC Size          : %u B\n", attr->ecc_size_in_bytes);
>> +	pr_info("Description       : %s\n", info->desc);
>> +}
>> +
>> +static struct nand_device_info * __init
>> +search_table(const struct nand_device_info *table, const uint8_t id[])
>> +{
>> +	struct nand_device_info *info = (struct nand_device_info *)table;
>> +
>> +	while (ID_GET_MFR_CODE(info->id)) {
>> +		int i;
>> +
>> +		/* match all the valid id bytes. Is it too strict? */
>> +		for (i = 0; i<  info->id_len; i++)
>> +			if (info->id[i] != id[i])
>> +				break;
>> +
>> +		/* found it */
>> +		if (i == info->id_len)
>> +			return info;
>> +		info++;
>> +	}
>> +	return NULL;
>> +}
>> +
>> +struct nand_device_mfr_info {
>> +	uint8_t                  id;
>> +	const struct nand_device_info  *table;
>> +};
>> +
>> +static const struct nand_device_mfr_info  nand_device_mfr_directory[] = {
>> +	{ NAND_MFR_SAMSUNG, samsung_nand },
>> +	{ 0, NULL },
>> +};
>> +
>> +struct nand_device_info *nand_device_get_info(const uint8_t id[])
>> +{
>> +	uint8_t mfr_id = ID_GET_MFR_CODE(id);
>> +	unsigned i;
>> +
>> +	for (i = 0; nand_device_mfr_directory[i].id; i++) {
>> +		if (nand_device_mfr_directory[i].id == mfr_id) {
>> +			const struct nand_device_info  *table;
>> +
>> +			table = nand_device_mfr_directory[i].table;
>> +			return search_table(table, id);
>> +		}
>> +	}
>> +	return NULL;
>> +}
>> diff --git a/drivers/mtd/nand/nand_device_info.h
>> b/drivers/mtd/nand/nand_device_info.h new file mode 100644
>> index 0000000..fe22233
>> --- /dev/null
>> +++ b/drivers/mtd/nand/nand_device_info.h
>> @@ -0,0 +1,83 @@
>> +/*
>> + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + */
>> +
>> +/*
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */
>> +#ifndef __DRIVERS_NAND_DEVICE_INFO_H
>> +#define __DRIVERS_NAND_DEVICE_INFO_H
>> +
>> +enum nand_device_cell_technology {
>> +	SLC = 0,
>> +	MLC = 1,
>> +};
>> +
>> +/**
>> + * @cell_technology:           The storage cell technology.
>> + * @chip_size_in_bytes:        The total size of the storage behind a
>> single + *                             chip select, in bytes. Notice that
>> this is *not* + *                             necessarily the total size
>> of the storage in a + *                             *package*, which may
>> contain several chips. + * @block_size_in_pages:       The number of pages
>> in a block.
>> + * @page_total_size_in_bytes:  The total size of a page, in bytes,
>> including + *                             both the data and the OOB.
>> + * @ecc_strength_in_bits:      The strength of the ECC called for by the
>> + *                             manufacturer, in number of correctable
>> bits. + * @ecc_size_in_bytes:         The size of the data block over
>> which the + *                             manufacturer calls for the given
>> ECC algorithm + *                             and strength.
>> + */
>> +struct nand_attr {
>> +	/* Technology */
>> +	enum nand_device_cell_technology  cell_technology;
>> +
>> +	/* Geometry */
>> +	uint64_t	chip_size_in_bytes;
>> +	uint32_t	block_size_in_pages;
>> +	uint32_t	page_total_size_in_bytes;
>> +
>> +	/* ECC */
>> +	uint16_t	ecc_strength_in_bits;
>> +	uint16_t	ecc_size_in_bytes;
>> +};
>> +
>> +#define ID_BYTES	(8)
>> +/*
>> + * struct nand_device_info - Information about a single NAND Flash device.
>> + *
>> + * This structure contains all the *essential* information about a NAND
>> Flash + * device, derived from the device's data sheet.
>> + */
>> +struct nand_device_info {
>> +	/* id */
>> +	uint8_t			id[ID_BYTES];
>> +	unsigned int		id_len;
>> +
>> +	/* Description */
>> +	const char		*desc;
>> +
>> +	/* attribute*/
>> +	struct nand_attr	attr;
>> +};
>> +
>> +/* macro for the NAND attribute */
>> +#define ATTR(_a, _b, _c, _d, _e, _f)			\
>> +	{						\
>> +		.cell_technology          = (_a),	\
>> +		.chip_size_in_bytes       = (_b),	\
>> +		.block_size_in_pages      = (_c),	\
>> +		.page_total_size_in_bytes = (_d),	\
>> +		.ecc_strength_in_bits     = (_e),	\
>> +		.ecc_size_in_bytes        = (_f),	\
>> +	}
>> +
>> +struct nand_device_info *nand_device_get_info(const uint8_t id_bytes[]);
>> +void nand_device_print_info(struct nand_device_info *info);
>> +
>> +#endif
Best Regards
Huang Shijie
Artem Bityutskiy March 31, 2011, 10 a.m. UTC | #3
On Mon, 2011-03-28 at 10:00 +0800, Huang Shijie wrote:
> These nands are only a example. I have other nands to add in future.
> I will fix nand_get_flash_type() in future, not now. thanks
> 
> Btw : I forget to add  the `busw` field in my nand_device_info{}. 

I think you should consider this as a merge criteria - I do not think we
can allow people to have their own NAND data-bases, even "for now".
Huang Shijie March 31, 2011, 10:12 a.m. UTC | #4
Hi:
> On Mon, 2011-03-28 at 10:00 +0800, Huang Shijie wrote:
>> These nands are only a example. I have other nands to add in future.
>> I will fix nand_get_flash_type() in future, not now. thanks
>>
>> Btw : I forget to add  the `busw` field in my nand_device_info{}.
> I think you should consider this as a merge criteria - I do not think we
> can allow people to have their own NAND data-bases, even "for now".
>
In the version 3, I want to replace the old database.


Thanks
Huang Shijie
diff mbox

Patch

diff --git a/drivers/mtd/nand/nand_device_info.c b/drivers/mtd/nand/nand_device_info.c
new file mode 100644
index 0000000..3ceec9c
--- /dev/null
+++ b/drivers/mtd/nand/nand_device_info.c
@@ -0,0 +1,154 @@ 
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <asm/sizes.h>
+#include <linux/mtd/nand.h>
+
+#include "nand_device_info.h"
+
+static const struct nand_device_info samsung_nand[] = {
+	{
+		.id	= { 0xec, 0xd3, 0x14, 0x25, 0x64, 0xec, 0xd3, 0x14 },
+		.id_len	= 8,
+		.desc	= "K9G8G08U0M, K9HAG08U1M",
+		.attr	= ATTR(MLC, 1LL * SZ_1G, 128, 2 * SZ_1K + 64, 8, 512),
+	}, {
+		.id	= { 0xec, 0xd7, 0xd5, 0x29, 0x38, 0x41, 0xec, 0xd7 },
+		.id_len	= 8,
+		.desc	= "K9LBG08U0D",
+		.attr	= ATTR(MLC, 4LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
+	}, {
+		.id	= { 0xec, 0xd5, 0x14, 0xb6, 0x74, 0xec, 0xd5, 0x14 },
+		.id_len	= 8,
+		.desc	= "K9GAG08U0M",
+		.attr	= ATTR(MLC, 2LL * SZ_1G, 128, 4 * SZ_1K + 218, 16, 512),
+	}, {
+		/* end of the table. */
+		.id	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	},
+};
+
+/* macro to get the id bytes */
+#define ID_GET_MFR_CODE(id)  ((id)[0])
+
+void nand_device_print_info(struct nand_device_info *info)
+{
+	unsigned    i;
+	const char  *mfr_name;
+	const char  *cell_technology_name;
+	uint64_t    chip_size;
+	const char  *chip_size_units;
+	unsigned    page_size;
+	unsigned    oob_size;
+	struct nand_attr *attr		= &info->attr;
+
+	/* Prepare the manufacturer name. */
+	mfr_name = "Unknown";
+	for (i = 0; nand_manuf_ids[i].id; i++) {
+		if (nand_manuf_ids[i].id == ID_GET_MFR_CODE(info->id)) {
+			mfr_name = nand_manuf_ids[i].name;
+			break;
+		}
+	}
+
+	/* Prepare the name of the cell technology. */
+	switch (attr->cell_technology) {
+	case SLC:
+		cell_technology_name = "SLC";
+		break;
+	case MLC:
+		cell_technology_name = "MLC";
+		break;
+	default:
+		cell_technology_name = "Unknown";
+		break;
+	}
+
+	/* Prepare the chip size. */
+	if ((attr->chip_size_in_bytes >= SZ_1G) &&
+					!(attr->chip_size_in_bytes % SZ_1G)) {
+		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1G);
+		chip_size_units = "GiB";
+	} else if ((attr->chip_size_in_bytes >= SZ_1M) &&
+					!(attr->chip_size_in_bytes % SZ_1M)) {
+		chip_size       = attr->chip_size_in_bytes / ((uint64_t) SZ_1M);
+		chip_size_units = "MiB";
+	} else {
+		chip_size       = attr->chip_size_in_bytes;
+		chip_size_units = "B";
+	}
+
+	/* Prepare the page geometry. */
+	page_size = (1 << (fls(attr->page_total_size_in_bytes) - 1));
+	oob_size  = attr->page_total_size_in_bytes - page_size;
+
+	/* Print the infomation. */
+	pr_info("--------------------------------------\n");
+	pr_info("	NAND device infomation (RAW)\n");
+	pr_info("--------------------------------------\n");
+	pr_info("Manufacturer      : %s (0x%02x)\n", mfr_name, info->id[0]);
+	pr_info("Device Code       : 0x%02x\n", info->id[1]);
+	pr_info("Cell Technology   : %s\n", cell_technology_name);
+	pr_info("Chip Size         : %llu %s\n", chip_size, chip_size_units);
+	pr_info("Pages per Block   : %u\n", attr->block_size_in_pages);
+	pr_info("Page Geometry     : %u+%u\n", page_size, oob_size);
+	pr_info("ECC Strength      : %u bits\n", attr->ecc_strength_in_bits);
+	pr_info("ECC Size          : %u B\n", attr->ecc_size_in_bytes);
+	pr_info("Description       : %s\n", info->desc);
+}
+
+static struct nand_device_info * __init
+search_table(const struct nand_device_info *table, const uint8_t id[])
+{
+	struct nand_device_info *info = (struct nand_device_info *)table;
+
+	while (ID_GET_MFR_CODE(info->id)) {
+		int i;
+
+		/* match all the valid id bytes. Is it too strict? */
+		for (i = 0; i < info->id_len; i++)
+			if (info->id[i] != id[i])
+				break;
+
+		/* found it */
+		if (i == info->id_len)
+			return info;
+		info++;
+	}
+	return NULL;
+}
+
+struct nand_device_mfr_info {
+	uint8_t                  id;
+	const struct nand_device_info  *table;
+};
+
+static const struct nand_device_mfr_info  nand_device_mfr_directory[] = {
+	{ NAND_MFR_SAMSUNG, samsung_nand },
+	{ 0, NULL },
+};
+
+struct nand_device_info *nand_device_get_info(const uint8_t id[])
+{
+	uint8_t mfr_id = ID_GET_MFR_CODE(id);
+	unsigned i;
+
+	for (i = 0; nand_device_mfr_directory[i].id; i++) {
+		if (nand_device_mfr_directory[i].id == mfr_id) {
+			const struct nand_device_info  *table;
+
+			table = nand_device_mfr_directory[i].table;
+			return search_table(table, id);
+		}
+	}
+	return NULL;
+}
diff --git a/drivers/mtd/nand/nand_device_info.h b/drivers/mtd/nand/nand_device_info.h
new file mode 100644
index 0000000..fe22233
--- /dev/null
+++ b/drivers/mtd/nand/nand_device_info.h
@@ -0,0 +1,83 @@ 
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __DRIVERS_NAND_DEVICE_INFO_H
+#define __DRIVERS_NAND_DEVICE_INFO_H
+
+enum nand_device_cell_technology {
+	SLC = 0,
+	MLC = 1,
+};
+
+/**
+ * @cell_technology:           The storage cell technology.
+ * @chip_size_in_bytes:        The total size of the storage behind a single
+ *                             chip select, in bytes. Notice that this is *not*
+ *                             necessarily the total size of the storage in a
+ *                             *package*, which may contain several chips.
+ * @block_size_in_pages:       The number of pages in a block.
+ * @page_total_size_in_bytes:  The total size of a page, in bytes, including
+ *                             both the data and the OOB.
+ * @ecc_strength_in_bits:      The strength of the ECC called for by the
+ *                             manufacturer, in number of correctable bits.
+ * @ecc_size_in_bytes:         The size of the data block over which the
+ *                             manufacturer calls for the given ECC algorithm
+ *                             and strength.
+ */
+struct nand_attr {
+	/* Technology */
+	enum nand_device_cell_technology  cell_technology;
+
+	/* Geometry */
+	uint64_t	chip_size_in_bytes;
+	uint32_t	block_size_in_pages;
+	uint32_t	page_total_size_in_bytes;
+
+	/* ECC */
+	uint16_t	ecc_strength_in_bits;
+	uint16_t	ecc_size_in_bytes;
+};
+
+#define ID_BYTES	(8)
+/*
+ * struct nand_device_info - Information about a single NAND Flash device.
+ *
+ * This structure contains all the *essential* information about a NAND Flash
+ * device, derived from the device's data sheet.
+ */
+struct nand_device_info {
+	/* id */
+	uint8_t			id[ID_BYTES];
+	unsigned int		id_len;
+
+	/* Description */
+	const char		*desc;
+
+	/* attribute*/
+	struct nand_attr	attr;
+};
+
+/* macro for the NAND attribute */
+#define ATTR(_a, _b, _c, _d, _e, _f)			\
+	{						\
+		.cell_technology          = (_a),	\
+		.chip_size_in_bytes       = (_b),	\
+		.block_size_in_pages      = (_c),	\
+		.page_total_size_in_bytes = (_d),	\
+		.ecc_strength_in_bits     = (_e),	\
+		.ecc_size_in_bytes        = (_f),	\
+	}
+
+struct nand_device_info *nand_device_get_info(const uint8_t id_bytes[]);
+void nand_device_print_info(struct nand_device_info *info);
+
+#endif