All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huang Shijie <b32955@freescale.com>
To: "Lothar Waßmann" <LW@KARO-electronics.de>
Cc: linux-mtd@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org, dedekind1@gmail.com
Subject: Re: [PATCH v6 1/3] MTD : add the common code for GPMI controller driver
Date: Fri, 22 Apr 2011 17:39:53 +0800	[thread overview]
Message-ID: <4DB14CE9.2040602@freescale.com> (raw)
In-Reply-To: <19887.57747.43423.753598@ipc1.ka-ro>

Hi:
> Huang Shijie writes:
>> These files contain the common code for the GPMI driver.
>>
>> Signed-off-by: Huang Shijie<b32955@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

WARNING: multiple messages have this Message-ID (diff)
From: b32955@freescale.com (Huang Shijie)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v6 1/3] MTD : add the common code for GPMI controller driver
Date: Fri, 22 Apr 2011 17:39:53 +0800	[thread overview]
Message-ID: <4DB14CE9.2040602@freescale.com> (raw)
In-Reply-To: <19887.57747.43423.753598@ipc1.ka-ro>

Hi:
> Huang Shijie writes:
>> These files contain the common code for the GPMI driver.
>>
>> Signed-off-by: Huang Shijie<b32955@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

  reply	other threads:[~2011-04-22  9:39 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-20  2:45 [PATCH v6 0/3] add the GPMI controller driver for IMX23/IMX28 Huang Shijie
2011-04-20  2:45 ` Huang Shijie
2011-04-20  2:45 ` [PATCH v6 1/3] MTD : add the common code for GPMI controller driver Huang Shijie
2011-04-20  2:45   ` Huang Shijie
2011-04-21  7:49   ` Lothar Waßmann
2011-04-21  7:49     ` Lothar Waßmann
2011-04-22  9:39     ` Huang Shijie [this message]
2011-04-22  9:39       ` Huang Shijie
2011-04-26  2:52     ` Huang Shijie
2011-04-26  2:52       ` Huang Shijie
2011-04-26 10:09       ` Lothar Waßmann
2011-04-26 10:09         ` Lothar Waßmann
2011-04-28 19:20   ` Russell King - ARM Linux
2011-04-28 19:20     ` Russell King - ARM Linux
2011-04-29  1:42     ` Huang Shijie
2011-04-29  1:42       ` Huang Shijie
2011-04-20  2:45 ` [PATCH v6 2/3] MTD : add support for imx23 and imx28 Huang Shijie
2011-04-20  2:45   ` Huang Shijie
2011-04-20  2:45 ` [PATCH v6 3/3] MTD : add GPMI driver in the config and Makefile Huang Shijie
2011-04-20  2:45   ` Huang Shijie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4DB14CE9.2040602@freescale.com \
    --to=b32955@freescale.com \
    --cc=LW@KARO-electronics.de \
    --cc=dedekind1@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.