[PATCH v6 1/3] MTD : add the common code for GPMI controller driver

Huang Shijie b32955 at freescale.com
Fri Apr 22 05:39:53 EDT 2011


Hi:
> Huang Shijie writes:
>> These files contain the common code for the GPMI driver.
>>
>> Signed-off-by: Huang Shijie<b32955 at freescale.com>
>> ---
>>   drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c | 2501 ++++++++++++++++++++++++++++++++++
>>   drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h |  488 +++++++
>>   2 files changed, 2989 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
>>   create mode 100644 drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h
>>
>> diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
>> new file mode 100644
>> index 0000000..53d6915
>> --- /dev/null
>> +++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
>> @@ -0,0 +1,2501 @@
>> +/*
>> + * Freescale GPMI NFC NAND Flash Driver
>> + *
>> + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
>> + * Copyright (C) 2008 Embedded Alley Solutions, Inc.
>> + *
>> + * 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.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +#include<linux/slab.h>
>> +#include "gpmi-nfc.h"
>> +
>> +/* add our owner bbt descriptor */
>> +static uint8_t scan_ff_pattern[] = { 0xff };
>> +static struct nand_bbt_descr gpmi_bbt_descr = {
>> +	.options	= 0,
>> +	.offs		= 0,
>> +	.len		= 1,
>> +	.pattern	= scan_ff_pattern
>> +};
>> +
>> +/* debug control */
>> +int gpmi_debug;
>> +
> This could be a module_param.
>
thanks.
>> +static ssize_t show_gpmi_debug(struct device *dev,
>> +				struct device_attribute *attr, char *buf)
>> +{
>> +	return sprintf(buf, "%d\n", gpmi_debug);
>> +}
>> +
>> +static ssize_t
>> +store_gpmi_debug(struct device *dev, struct device_attribute *attr,
>> +			const char *buf, size_t size)
>> +{
>> +	const char *p = buf;
>> +	unsigned long v;
>> +
>> +	if (strict_strtoul(p, 0,&v)<  0)
>> +		return size;
>> +
>> +	gpmi_debug = v;
>> +	return size;
>> +}
>> +
>> +static ssize_t show_ignorebad(struct device *dev,
>> +				struct device_attribute *attr, char *buf)
>> +{
>> +	struct gpmi_nfc_data *this = dev_get_drvdata(dev);
>> +	struct mil *mil =&this->mil;
>> +
>> +	return sprintf(buf, "%d\n", mil->ignore_bad_block_marks);
>> +}
>> +
>> +static ssize_t
>> +store_ignorebad(struct device *dev, struct device_attribute *attr,
>> +			const char *buf, size_t size)
>> +{
>> +	struct gpmi_nfc_data *this = dev_get_drvdata(dev);
>> +	struct mil *mil =&this->mil;
>> +	const char *p = buf;
>> +	unsigned long v;
>> +
>> +	if (strict_strtoul(p, 0,&v)<  0)
>> +		return size;
>>
> return -EINVAL would be more appropriate here.
>
>> +
>> +	if (v>  0)
>> +		v = 1;
>> +
>> +	if (v != mil->ignore_bad_block_marks) {
>>
> These lines could be reduced to:
> 	if (!v == mil->ignore_bad_block_marks) {
>
:)
>> +		if (v) {
>> +			/*
>> +			 * This will cause the NAND Flash MTD code to believe
>> +			 * that it never created a BBT and force it to call our
>> +			 * block_bad function.
>> +			 *
>> +			 * See mil_block_bad for more details.
>> +			 */
>> +			mil->saved_bbt = mil->nand.bbt;
>> +			mil->nand.bbt  = NULL;
>> +		} else {
>> +			/*
>> +			 * Restore the NAND Flash MTD's pointer
>> +			 * to its in-memory BBT.
>> +			 */
>> +			mil->nand.bbt = mil->saved_bbt;
>> +		}
>> +		mil->ignore_bad_block_marks = v;
>> +	}
>> +	return size;
>> +}
>> +
> [...]
>> +/* This will be called after the DMA operation is finished. */
>> +static void dma_irq_callback(void *param)
>> +{
>> +	struct gpmi_nfc_data *this = param;
>> +	struct nfc_hal *nfc = this->nfc;
>> +	struct mil *mil =&this->mil;
>> +
>> +	complete(&nfc->dma_done);
>> +
>> +	switch (this->dma_type) {
>> +	case DMA_FOR_COMMAND:
>> +		dma_unmap_sg(this->dev,&mil->cmd_sgl, 1, DMA_TO_DEVICE);
>> +		break;
>> +
>> +	case DMA_FOR_READ_DATA:
>> +		dma_unmap_sg(this->dev,&mil->data_sgl, 1, DMA_FROM_DEVICE);
>> +		if (mil->direct_dma_map_ok == false)
>> +			memcpy(mil->upper_buf, (char *)mil->data_buffer_dma,
>>
> pointless cast.
thanks.
> [...]
>> +static int acquire_dma_channels(struct gpmi_nfc_data *this,
>> +				const char *resource_name,
>> +				unsigned *low_channel, unsigned *high_channel)
>> +{
>> +	struct platform_device *pdev = this->pdev;
> 	struct gpmi_nfc_platform_data *pdata = pdev->dev.platform_data;
> see below.
>
>> +	struct resource *r, *r_dma;
>> +	unsigned int i;
>> +
>> +	r = platform_get_resource_byname(pdev, IORESOURCE_DMA, resource_name);
>> +	r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> +					GPMI_NFC_DMA_INTERRUPT_RES_NAME);
>> +	if (!r || !r_dma) {
>> +		log("Can't get resource for DMA");
>> +		return -ENXIO;
>> +	}
>> +
>> +	/* used in gpmi_dma_filter() */
>> +	this->private = r;
>> +
>> +	for (i = r->start; i<= r->end; i++) {
>> +		dma_cap_mask_t		mask;
>> +		struct dma_chan		*dma_chan;
>> +
> 		if (i - r->start>= pdata->max_chip_count)
> 			break;
>
This is a good idea. it can limits the real dma channels.
>> +		dma_cap_zero(mask);
>> +		dma_cap_set(DMA_SLAVE, mask);
>> +
>> +		/* get the DMA interrupt */
>> +		this->dma_data.chan_irq = r_dma->start +
>> +			((r_dma->start != r_dma->end) ? (i - r->start) : 0);
>> +
>> +		dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
>> +		if (!dma_chan)
>> +			goto acquire_err;
>> +		/* fill the first empty item */
>> +		this->dma_chans[i - r->start] = dma_chan;
>> +	}
>> +
>> +	*low_channel  = r->start;
>> +	*high_channel = r->end;
> 	*high_channel = i;
>
> This will acquire only those DMA channels that are actually needed.
>
> [...]
>> +static int read_page_prepare(struct gpmi_nfc_data *this,
>> +			void *destination, unsigned length,
>> +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
>> +			void **use_virt, dma_addr_t *use_phys)
>> +{
>> +	struct device  *dev = this->dev;
>> +	dma_addr_t destination_phys = ~0;
>> +
>> +	if (virt_addr_valid(destination))
>> +		destination_phys = dma_map_single(dev, (void *)destination,
>>
> pointless cast.
>
> [...]
>> +static int mil_alloc_dma_buffer(struct gpmi_nfc_data *this)
>> +{
>> +	struct nfc_geometry *geo =&this->nfc_geometry;
>> +	struct device *dev = this->dev;
>> +	struct mil *mil =&this->mil;
>> +
>> +	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
>> +	mil->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA);
>> +	if (mil->cmd_buffer == NULL)
>> +		goto error_alloc;
>> +
>> +	/* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */
>> +	mil->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA);
>> +	if (mil->data_buffer_dma == NULL)
>> +		goto error_alloc;
>> +
>> +	/*
>> +	 * [3] Allocate the page buffer.
>> +	 *
>> +	 * Both the payload buffer and the auxiliary buffer must appear on
>> +	 * 32-bit boundaries. We presume the size of the payload buffer is a
>> +	 * power of two and is much larger than four, which guarantees the
>> +	 * auxiliary buffer will appear on a 32-bit boundary.
>> +	 */
>> +	mil->page_buffer_size = geo->payload_size_in_bytes +
>> +				geo->auxiliary_size_in_bytes;
>> +
>> +	mil->page_buffer_virt = dma_alloc_coherent(dev, mil->page_buffer_size,
>> +					&mil->page_buffer_phys, GFP_DMA);
>> +	if (!mil->page_buffer_virt)
>> +		goto error_alloc;
>> +
>> +
>> +	/* Slice up the page buffer. */
>> +	mil->payload_virt = mil->page_buffer_virt;
>> +	mil->payload_phys = mil->page_buffer_phys;
>> +	mil->auxiliary_virt = ((char *) mil->payload_virt) +
>>
> unnecessary cast.
>
> [...]
>
> The functions from here thru gpmi_nfc_probe could be marked __devinit,
> so they can be discarded after boot.
>> +static int nand_boot_set_geometry(struct gpmi_nfc_data *this)
>> +{
>> +	struct boot_rom_geometry *geometry =&this->rom_geometry;
>> +
>> +	/*
>> +	 * Set the boot block stride size.
>> +	 *
>> +	 * In principle, we should be reading this from the OTP bits, since
>> +	 * that's where the ROM is going to get it. In fact, we don't have any
>> +	 * way to read the OTP bits, so we go with the default and hope for the
>> +	 * best.
>> +	 */
>> +	geometry->stride_size_in_pages = 64;
>> +
>> +	/*
>> +	 * Set the search area stride exponent.
>> +	 *
>> +	 * In principle, we should be reading this from the OTP bits, since
>> +	 * that's where the ROM is going to get it. In fact, we don't have any
>> +	 * way to read the OTP bits, so we go with the default and hope for the
>> +	 * best.
>> +	 */
>> +	geometry->search_area_stride_exponent = 2;
>> +
>> +	if (gpmi_debug&  GPMI_DEBUG_INIT)
>> +		log("stride size in page : %d, search areas : %d",
>> +			geometry->stride_size_in_pages,
>> +			geometry->search_area_stride_exponent);
>> +	return 0;
>> +}
>> +
>> +static const char  *fingerprint = "STMP";
>> +static int mx23_check_transcription_stamp(struct gpmi_nfc_data *this)
>> +{
>> +	struct boot_rom_geometry *rom_geo =&this->rom_geometry;
>> +	struct mil *mil =&this->mil;
>> +	struct mtd_info *mtd =&mil->mtd;
>> +	struct nand_chip *nand =&mil->nand;
>> +	unsigned int search_area_size_in_strides;
>> +	unsigned int stride;
>> +	unsigned int page;
>> +	loff_t byte;
>> +	uint8_t *buffer = nand->buffers->databuf;
>> +	int saved_chip_number;
>> +	int found_an_ncb_fingerprint = false;
>> +
>> +	/* Compute the number of strides in a search area. */
>> +	search_area_size_in_strides = 1<<  rom_geo->search_area_stride_exponent;
>> +
>> +	/* Select chip 0. */
>> +	saved_chip_number = mil->current_chip;
>> +	nand->select_chip(mtd, 0);
>> +
>> +	/*
>> +	 * Loop through the first search area, looking for the NCB fingerprint.
>> +	 */
>> +	pr_info("Scanning for an NCB fingerprint...\n");
>> +
>> +	for (stride = 0; stride<  search_area_size_in_strides; stride++) {
>> +		/* Compute the page and byte addresses. */
>> +		page = stride * rom_geo->stride_size_in_pages;
>> +		byte = page   * mtd->writesize;
>> +
>> +		pr_info("  Looking for a fingerprint in page 0x%x\n", page);
>> +
>> +		/*
>> +		 * Read the NCB fingerprint. The fingerprint is four bytes long
>> +		 * and starts in the 12th byte of the page.
>> +		 */
>> +		nand->cmdfunc(mtd, NAND_CMD_READ0, 12, page);
>> +		nand->read_buf(mtd, buffer, strlen(fingerprint));
>> +
>> +		/* Look for the fingerprint. */
>> +		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
>> +			found_an_ncb_fingerprint = true;
>> +			break;
>> +		}
>> +
>> +	}
>> +
>> +	/* Deselect chip 0. */
>> +	nand->select_chip(mtd, saved_chip_number);
>> +
>> +	if (found_an_ncb_fingerprint)
>> +		pr_info("  Found a fingerprint\n");
>> +	else
>> +		pr_info("  No fingerprint found\n");
>> +	return found_an_ncb_fingerprint;
>> +}
>> +
>> +/* Writes a transcription stamp. */
>> +static int mx23_write_transcription_stamp(struct gpmi_nfc_data *this)
>> +{
>> +	struct device *dev = this->dev;
>> +	struct boot_rom_geometry *rom_geo =&this->rom_geometry;
>> +	struct mil *mil =&this->mil;
>> +	struct mtd_info *mtd =&mil->mtd;
>> +	struct nand_chip *nand =&mil->nand;
>> +	unsigned int block_size_in_pages;
>> +	unsigned int search_area_size_in_strides;
>> +	unsigned int search_area_size_in_pages;
>> +	unsigned int search_area_size_in_blocks;
>> +	unsigned int block;
>> +	unsigned int stride;
>> +	unsigned int page;
>> +	loff_t       byte;
>> +	uint8_t      *buffer = nand->buffers->databuf;
>> +	int saved_chip_number;
>> +	int status;
>> +
>> +	/* Compute the search area geometry. */
>> +	block_size_in_pages = mtd->erasesize / mtd->writesize;
>> +	search_area_size_in_strides = 1<<  rom_geo->search_area_stride_exponent;
>> +	search_area_size_in_pages = search_area_size_in_strides *
>> +					rom_geo->stride_size_in_pages;
>> +	search_area_size_in_blocks =
>> +		  (search_area_size_in_pages + (block_size_in_pages - 1)) /
>> +				    block_size_in_pages;
>> +
>> +	pr_info("-------------------------------------------\n");
>> +	pr_info("Search Area Geometry\n");
>> +	pr_info("-------------------------------------------\n");
>> +	pr_info("Search Area Size in Blocks : %u", search_area_size_in_blocks);
>> +	pr_info("Search Area Size in Strides: %u", search_area_size_in_strides);
>> +	pr_info("Search Area Size in Pages  : %u", search_area_size_in_pages);
>> +
>> +	/* Select chip 0. */
>> +	saved_chip_number = mil->current_chip;
>> +	nand->select_chip(mtd, 0);
>> +
>> +	/* Loop over blocks in the first search area, erasing them. */
>> +	pr_info("Erasing the search area...\n");
>> +
>> +	for (block = 0; block<  search_area_size_in_blocks; block++) {
>> +		/* Compute the page address. */
>> +		page = block * block_size_in_pages;
>> +
>> +		/* Erase this block. */
>> +		pr_info("  Erasing block 0x%x\n", block);
>> +		nand->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
>> +		nand->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
>> +
>> +		/* Wait for the erase to finish. */
>> +		status = nand->waitfunc(mtd, nand);
>> +		if (status&  NAND_STATUS_FAIL)
>> +			dev_err(dev, "[%s] Erase failed.\n", __func__);
>> +	}
>> +
>> +	/* Write the NCB fingerprint into the page buffer. */
>> +	memset(buffer, ~0, mtd->writesize);
>> +	memset(nand->oob_poi, ~0, mtd->oobsize);
>> +	memcpy(buffer + 12, fingerprint, strlen(fingerprint));
>> +
>> +	/* Loop through the first search area, writing NCB fingerprints. */
>> +	pr_info("Writing NCB fingerprints...\n");
>> +	for (stride = 0; stride<  search_area_size_in_strides; stride++) {
>> +		/* Compute the page and byte addresses. */
>> +		page = stride * rom_geo->stride_size_in_pages;
>> +		byte = page   * mtd->writesize;
>> +
>> +		/* Write the first page of the current stride. */
>> +		pr_info("  Writing an NCB fingerprint in page 0x%x\n", page);
>> +		nand->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
>> +		nand->ecc.write_page_raw(mtd, nand, buffer);
>> +		nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
>> +
>> +		/* Wait for the write to finish. */
>> +		status = nand->waitfunc(mtd, nand);
>> +		if (status&  NAND_STATUS_FAIL)
>> +			dev_err(dev, "[%s] Write failed.\n", __func__);
>> +	}
>> +
>> +	/* Deselect chip 0. */
>> +	nand->select_chip(mtd, saved_chip_number);
>> +	return 0;
>> +}
>> +
>> +int mx23_boot_init(struct gpmi_nfc_data  *this)
>> +{
>> +	struct device *dev = this->dev;
>> +	struct mil *mil =&this->mil;
>> +	struct nand_chip *nand =&mil->nand;
>> +	struct mtd_info *mtd =&mil->mtd;
>> +	unsigned int block_count;
>> +	unsigned int block;
>> +	int     chip;
>> +	int     page;
>> +	loff_t  byte;
>> +	uint8_t block_mark;
>> +	int     error = 0;
>> +
>> +	/*
>> +	 * If control arrives here, we can't use block mark swapping, which
>> +	 * means we're forced to use transcription. First, scan for the
>> +	 * transcription stamp. If we find it, then we don't have to do
>> +	 * anything -- the block marks are already transcribed.
>> +	 */
>> +	if (mx23_check_transcription_stamp(this))
>> +		return 0;
>> +
>> +	/*
>> +	 * If control arrives here, we couldn't find a transcription stamp, so
>> +	 * so we presume the block marks are in the conventional location.
>> +	 */
>> +	pr_info("Transcribing bad block marks...\n");
>> +
>> +	/* Compute the number of blocks in the entire medium. */
>> +	block_count = nand->chipsize>>  nand->phys_erase_shift;
>> +
>> +	/*
>> +	 * Loop over all the blocks in the medium, transcribing block marks as
>> +	 * we go.
>> +	 */
>> +	for (block = 0; block<  block_count; block++) {
>> +		/*
>> +		 * Compute the chip, page and byte addresses for this block's
>> +		 * conventional mark.
>> +		 */
>> +		chip = block>>  (nand->chip_shift - nand->phys_erase_shift);
>> +		page = block<<  (nand->phys_erase_shift - nand->page_shift);
>> +		byte = block<<   nand->phys_erase_shift;
>> +
>> +		/* Select the chip. */
>> +		nand->select_chip(mtd, chip);
>> +
>> +		/* Send the command to read the conventional block mark. */
>> +		nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
>> +
>> +		/* Read the conventional block mark. */
>> +		block_mark = nand->read_byte(mtd);
>> +
>> +		/*
>> +		 * Check if the block is marked bad. If so, we need to mark it
>> +		 * again, but this time the result will be a mark in the
>> +		 * location where we transcribe block marks.
>> +		 *
>> +		 * Notice that we have to explicitly set the marking_a_bad_block
>> +		 * member before we call through the block_markbad function
>> +		 * pointer in the owning struct nand_chip. If we could call
>> +		 * though the block_markbad function pointer in the owning
>> +		 * struct mtd_info, which we have hooked, then this would be
>> +		 * taken care of for us. Unfortunately, we can't because that
>> +		 * higher-level code path will do things like consulting the
>> +		 * in-memory bad block table -- which doesn't even exist yet!
>> +		 * So, we have to call at a lower level and handle some details
>> +		 * ourselves.
>> +		 */
>> +		if (block_mark != 0xff) {
>> +			pr_info("Transcribing mark in block %u\n", block);
>> +			mil->marking_a_bad_block = true;
>> +			error = nand->block_markbad(mtd, byte);
>> +			mil->marking_a_bad_block = false;
>> +			if (error)
>> +				dev_err(dev, "Failed to mark block bad with "
>> +							"error %d\n", error);
>> +		}
>> +
>> +		/* Deselect the chip. */
>> +		nand->select_chip(mtd, -1);
>> +	}
>> +
>> +	/* Write the stamp that indicates we've transcribed the block marks. */
>> +	mx23_write_transcription_stamp(this);
>> +	return 0;
>> +}
>> +
>> +static int nand_boot_init(struct gpmi_nfc_data  *this)
>> +{
>> +	nand_boot_set_geometry(this);
>> +
>> +	/* This is ROM arch-specific initilization before the BBT scanning. */
>> +	if (GPMI_IS_MX23(this))
>> +		return mx23_boot_init(this);
>> +	return 0;
>> +}
>> +
>> +static void show_nfc_geometry(struct nfc_geometry *geo)
>> +{
>> +	pr_info("---------------------------------------\n");
>> +	pr_info("	NFC Geometry (used by BCH)\n");
>> +	pr_info("---------------------------------------\n");
>> +	pr_info("ECC Algorithm          : %s\n", geo->ecc_algorithm);
>> +	pr_info("ECC Strength           : %u\n", geo->ecc_strength);
>> +	pr_info("Page Size in Bytes     : %u\n", geo->page_size_in_bytes);
>> +	pr_info("Metadata Size in Bytes : %u\n", geo->metadata_size_in_bytes);
>> +	pr_info("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size_in_bytes);
>> +	pr_info("ECC Chunk Count        : %u\n", geo->ecc_chunk_count);
>> +	pr_info("Payload Size in Bytes  : %u\n", geo->payload_size_in_bytes);
>> +	pr_info("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size_in_bytes);
>> +	pr_info("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset);
>> +	pr_info("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset);
>> +	pr_info("Block Mark Bit Offset  : %u\n", geo->block_mark_bit_offset);
>> +}
>> +
>> +static int mil_set_geometry(struct gpmi_nfc_data *this)
>> +{
>> +	struct nfc_hal *nfc = this->nfc;
>> +	struct nfc_geometry *geo =&this->nfc_geometry;
>> +	int error;
>> +
>> +	/* Free the temporary DMA memory for read ID case */
>> +	mil_free_dma_buffer(this);
>> +
>> +	/* Set up the NFC geometry which is used by BCH. */
>> +	error = nfc->set_geometry(this);
>> +	if (error != 0) {
>> +		log("NFC set geometry error : %d", error);
>> +		return error;
>> +	}
>> +	if (gpmi_debug&  GPMI_DEBUG_INIT)
>> +		show_nfc_geometry(geo);
>> +
>> +	/* Alloc the new DMA buffers according to the pagesize and oobsize */
>> +	return mil_alloc_dma_buffer(this);
>> +}
>> +
>> +static int mil_pre_bbt_scan(struct gpmi_nfc_data  *this)
>> +{
>> +	struct nand_chip *nand =&this->mil.nand;
>> +	struct mtd_info *mtd =&this->mil.mtd;
>> +	struct nand_ecclayout *layout = nand->ecc.layout;
>> +	struct nfc_hal *nfc = this->nfc;
>> +	int error;
>> +
>> +	/* fix the ECC layout before the scanning */
>> +	layout->eccbytes          = 0;
>> +	layout->oobavail          = mtd->oobsize;
>> +	layout->oobfree[0].offset = 0;
>> +	layout->oobfree[0].length = mtd->oobsize;
>> +
>> +	mtd->oobavail = nand->ecc.layout->oobavail;
>> +
>> +	/* Set up swap block-mark, must be set before the mil_set_geometry() */
>> +	if (GPMI_IS_MX23(this))
>> +		this->swap_block_mark = false;
>> +	else
>> +		this->swap_block_mark = true;
>> +
>> +	/* Set up the medium geometry */
>> +	error = mil_set_geometry(this);
>> +	if (error)
>> +		return error;
>> +
>> +	/* extra init */
>> +	if (nfc->extra_init) {
>> +		error = nfc->extra_init(this);
>> +		if (error != 0)
>> +			return error;
>> +	}
>> +
>> +	/* NAND boot init, depends on the mil_set_geometry(). */
>> +	return nand_boot_init(this);
>> +}
>> +
>> +static int mil_scan_bbt(struct mtd_info *mtd)
>> +{
>> +	struct nand_chip *nand = mtd->priv;
>> +	struct gpmi_nfc_data *this = nand->priv;
>> +	int error;
>> +
>> +	/* Prepare for the BBT scan. */
>> +	error = mil_pre_bbt_scan(this);
>> +	if (error)
>> +		return error;
>> +
>> +	/* use the default BBT implementation */
>> +	return nand_default_bbt(mtd);
>> +}
>> +
>> +static const char *cmd_parse = "cmdlinepart";
>>
> This should be a NULL terminated list of strings:
> static const char *cmd_parse[] = { "cmdlinepart", NULL };
>
thanks a lot.
>> +static int mil_partitions_init(struct gpmi_nfc_data *this)
>> +{
>> +	struct gpmi_nfc_platform_data *pdata = this->pdata;
>> +	struct mil *mil =&this->mil;
>> +	struct mtd_info *mtd =&mil->mtd;
>> +
>> +	/* use the command line for simple partitions layout */
>> +	mil->partition_count = parse_mtd_partitions(mtd,&cmd_parse,
>> +						&mil->partitions, 0);
>> +	if (mil->partition_count)
>> +		return add_mtd_partitions(mtd, mil->partitions,
>> +					mil->partition_count);
>> +
>> +	/* The complicated partitions layout uses this. */
>> +	if (pdata->partitions&&  pdata->partition_count>  0)
>> +		return add_mtd_partitions(mtd, pdata->partitions,
>> +					pdata->partition_count);
>> +	return 0;
> How about:
> 	return mtd_add_device(mtd);
> so you will get the whole flash registered in case there are no
> partitions defined.
>
no problem.
>> +#ifdef CONFIG_PM
>> +static int gpmi_nfc_suspend(struct platform_device *pdev, pm_message_t state)
>> +{
>> +	return 0;
>> +}
>> +static int gpmi_nfc_resume(struct platform_device *pdev)
>> +{
>> +	return 0;
>> +}
>> +#else
>> +#define gpmi_nfc_suspend NULL
>> +#define gpmi_nfc_resume  NULL
>> +#endif
>> +
> There is no point in adding empty suspend/resume functions.
> Furthermore you should use dev_pm_ops.
>
Ok.  I think the gpmi needs to do nothing when suspend.


Best Regards
Huang shijie
> Lothar Waßmann





More information about the linux-arm-kernel mailing list