public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
From: William J Beksi <wjbeksi@setabox.com>
To: linux-mtd@lists.infradead.org
Subject: [PATCH] command function for nand flash through IDE
Date: Thu, 16 Dec 2004 21:11:11 +0800	[thread overview]
Message-ID: <41C1896F.9000107@setabox.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 233 bytes --]

Hi,
This driver includes command and select chip functions specifically for  
accessing nand flash through an IDE port. Should be useful for anyone 
developing and testing on a PC. It works with the latest MTD snapshot.

-- 
William

[-- Attachment #2: ide.c --]
[-- Type: text/x-c, Size: 5375 bytes --]

/*
 *  drivers/mtd/nand/ide.c
 *
 *  Copyright (C) 2004 William J Beksi <wjbeksi@users.sourceforge.net> 
 *
 *  Derived from drivers/mtd/nand/spia.c
 *   Copyright (C) 2000 Steven J. Hill <sjhill@realitydiluted.com>
 *
 *  $Id: ide.c,v 1.18 2004/12/07 05:17:46 wjbeksi Exp $
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  Overview:
 *   This device driver allows a NAND flash device to be accessed from
 *   an IDE interface.  
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <asm/io.h>

/*
 * IDE MTD structure
 */
static struct mtd_info *ide_mtd = NULL;

/*
 * Values specific to the IDE
 */
#define BASEPORT1 0x1F0		/* IDE1 NAND flash I/O base address */
#define BASEPORT2 0x170		/* IDE2 NAND flash I/O base address */

#define IDE_IO_BASE	BASEPORT1

/*
 * Define partitions for flash device
 */
const static struct mtd_partition partition_info[] = {
    { 
		.name   = "IDE flash partition 1", 
		.offset = 0,  
		.size   = 3*1024*1024 
	},
	{
		.name   = "IDE flash partition 2",
		.offset = 3*1024*1024,
		.size   = 3*1024*1024
	}
};
#define NUM_PARTITIONS  2 

/*
 * IDE specific command function
 */
static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
	register struct nand_chip *this = mtd->priv;
	unsigned int    ide_io_addr_1    = (unsigned int) this->IO_ADDR_R+1;
	unsigned int    ide_io_addr_2    = (unsigned int) this->IO_ADDR_R+2;

	/*
	 * Write out the command to the device
	 */
	if (command == NAND_CMD_SEQIN) {
		int readcmd;

		if (column >= mtd->oobblock) {
			/* OOB area */
			column -= mtd->oobblock;
			readcmd = NAND_CMD_READOOB;
		} else if (column < 256) {
			/* First 256 bytes --> READ0 */
			readcmd = NAND_CMD_READ0;
		} else {
			column -= 256;
			readcmd = NAND_CMD_READ1;
		}
		outb(readcmd, ide_io_addr_1);
	}
	outb(command, ide_io_addr_1);

	if (column != -1 || page_addr != -1) {
		/* Serially input address */
		if (column != -1) {
			/* Adjust columns for 16 bit buswidth */
			if (this->options & NAND_BUSWIDTH_16)
				column >>= 1;
			outb(column, ide_io_addr_2);
		}
		if (page_addr != -1) {
			outb((unsigned char) (page_addr & 0xff), ide_io_addr_2);
			outb((unsigned char) ((page_addr >> 8) & 0xff), ide_io_addr_2);
			/* One more address cycle for devices > 32MiB */
			if (this->chipsize > (32 << 20))
				outb((unsigned char) ((page_addr >> 16) & 0x0f),
						ide_io_addr_2);
		}
	}
	
	/* 
	 * Program and erase have their own busy handlers status and sequential 
	 * in needs no delay
	 */
	switch (command) {
			
	case NAND_CMD_PAGEPROG:
	case NAND_CMD_ERASE1:
	case NAND_CMD_ERASE2:
	case NAND_CMD_SEQIN:
	case NAND_CMD_STATUS:
		return;

	case NAND_CMD_RESET:
		if (this->dev_ready)	
			break;
		udelay(this->chip_delay);
		outb(NAND_CMD_STATUS, ide_io_addr_1);
		while (!(this->read_byte(mtd) & 0x40));
		return;

	/* This applies to read commands */	
	default:
		/* 
		 * If we don't have access to the busy pin, we apply the given
		 * command delay
		 */
		if (!this->dev_ready) {
			udelay(this->chip_delay);
			return;
		}	
	}
	
	/* 
	 * Apply this short delay always to ensure that we do wait tWB in
	 * any case on any machine
	 */
	ndelay(100);
	/* Wait until command is processed */
	while (!this->dev_ready(mtd));
}

static void nand_select_chip(struct mtd_info *mtd, int chip)
{
	nand_command(mtd, NAND_CMD_RESET, -1, -1);
}

/*
 * Main initialization routine
 */
int __init ide_init(void)
{
	struct nand_chip *this;

	/* Allocate memory for MTD device structure and private data */
	ide_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
	if (!ide_mtd) {
		printk("Unable to allocate IDE NAND MTD structure\n");
		return -ENOMEM;
	}

	/* Get pointer to private data */
	this = (struct nand_chip *) (&ide_mtd[1]);

	/* Initialize structures */
	memset((char *) ide_mtd, 0, sizeof(struct mtd_info));
	memset((char *) this, 0, sizeof(struct nand_chip));

	/* Link the private data with the MTD structure */
	ide_mtd->priv = this;

	/* Set address of NAND IO lines */
	this->IO_ADDR_R  = (void __iomem *) IDE_IO_BASE;
	this->IO_ADDR_W  = (void __iomem *) IDE_IO_BASE;

	/* Set command function for IDE */
	this->cmdfunc = nand_command;
	/* Set select chip function for IDE */
	this->select_chip = nand_select_chip;
	/* 20 us command delay time */
	this->chip_delay = 20;
	/* Set the ECC generator mode */
	this->eccmode = NAND_ECC_SOFT;

	/* Scan to find existance of the device */
	if (nand_scan(ide_mtd, 1)) {
		kfree(ide_mtd);
		return -ENXIO;
	}

	/* Register the partitions */
	add_mtd_partitions(ide_mtd, partition_info, NUM_PARTITIONS);

	/* Return happy */
	return 0;
}
module_init(ide_init);

/*
 * Clean up routine
 */
#ifdef MODULE
static void __exit ide_cleanup (void)
{
	/* Release resources, unregister the device */
	nand_release(ide_mtd);	

	/* Free the MTD device structure */
	kfree(ide_mtd);
}
module_exit(ide_cleanup);
#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("William J Beksi <wjbeksi@users.sourceforge.net>");
MODULE_DESCRIPTION("Glue layer for NAND flash through an IDE interface");

             reply	other threads:[~2004-12-16 13:11 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-12-16 13:11 William J Beksi [this message]
2004-12-20  8:09 ` [PATCH] command function for nand flash through IDE Thomas Gleixner
     [not found]   ` <41C7F8C7.8050607@setabox.com>
2004-12-21 15:27     ` Thomas Gleixner
2004-12-31  4:14       ` William J Beksi
2004-12-31  9:18         ` Thomas Gleixner
2005-01-01 10:50           ` William J Beksi
2005-01-01 10:59             ` Thomas Gleixner
2005-01-01 15:08               ` William J Beksi

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=41C1896F.9000107@setabox.com \
    --to=wjbeksi@setabox.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox