Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7abd3ef9 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

[MTD] Refactor NAND hwcontrol to cmd_ctrl



The hwcontrol function enforced a step by step state machine
for any kind of hardware chip access. Let the hardware driver
know which control bits are set and inform it about a change
of the control lines. Let the hardware driver write out the
command and address bytes directly. This gives a peformance
advantage for address bus controlled chips and simplifies the
quirks in the hardware drivers.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 3821720d
Loading
Loading
Loading
Loading
+28 −28
Original line number Diff line number Diff line
@@ -34,13 +34,6 @@ static struct mtd_info *ams_delta_mtd = NULL;

#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)

#define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0)
#define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE)
#define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0)
#define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE)
#define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0)
#define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE)

/*
 * Define partitions for flash devices
 */
@@ -66,25 +59,6 @@ static struct mtd_partition partition_info[] = {
	  .size		=  3 * SZ_256K },
};

/*
 *	hardware specific access to control-lines
*/

static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd)
{
	switch (cmd) {

		case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
		case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;

		case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
		case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;

		case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
		case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
	}
}

static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{
	struct nand_chip *this = mtd->priv;
@@ -141,6 +115,32 @@ static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
	return 0;
}

/*
 * Command control function
 *
 * ctrl:
 * NAND_NCE: bit 0 -> bit 2
 * NAND_CLE: bit 1 -> bit 7
 * NAND_ALE: bit 2 -> bit 6
 */
static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
				unsigned int ctrl)
{

	if (ctrl & NAND_CTRL_CHANGE) {
		unsigned long bits;

		bits = (~ctrl & NAND_NCE) << 2;
		bits |= (ctrl & NAND_CLE) << 7;
		bits |= (ctrl & NAND_ALE) << 6;

		ams_delta_latch2_write(0xC2, bits);
	}

	if (cmd != NAND_CMD_NONE)
		ams_delta_write_byte(mtd, cmd);
}

static int ams_delta_nand_ready(struct mtd_info *mtd)
{
	return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
@@ -183,7 +183,7 @@ static int __init ams_delta_init(void)
	this->write_buf = ams_delta_write_buf;
	this->read_buf = ams_delta_read_buf;
	this->verify_buf = ams_delta_verify_buf;
	this->hwcontrol = ams_delta_hwcontrol;
	this->cmd_ctrl = ams_delta_hwcontrol;
	if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
		this->dev_ready = ams_delta_nand_ready;
	} else {
+18 −7
Original line number Diff line number Diff line
@@ -269,6 +269,18 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
	return 0;
}

/* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE		1
/* Deselect the chip by setting nCE to high */
#define NAND_CTL_CLRNCE		2
/* Select the command latch by setting CLE to high */
#define NAND_CTL_SETCLE		3
/* Deselect the command latch by setting CLE to low */
#define NAND_CTL_CLRCLE		4
/* Select the address latch by setting ALE to high */
#define NAND_CTL_SETALE		5
/* Deselect the address latch by setting ALE to low */
#define NAND_CTL_CLRALE		6

static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
{
@@ -349,7 +361,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
	ulong flags;

	/* Begin command latch cycle */
	this->hwcontrol(mtd, NAND_CTL_SETCLE);
	au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
	/*
	 * Write out the command to the device.
	 */
@@ -372,10 +384,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
	this->write_byte(mtd, command);

	/* Set ALE and clear CLE to start address cycle */
	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
	au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);

	if (column != -1 || page_addr != -1) {
		this->hwcontrol(mtd, NAND_CTL_SETALE);
		au1550_hwcontrol(mtd, NAND_CTL_SETALE);

		/* Serially input address */
		if (column != -1) {
@@ -400,7 +412,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
				 */
				ce_override = 1;
				local_irq_save(flags);
				this->hwcontrol(mtd, NAND_CTL_SETNCE);
				au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
			}

			this->write_byte(mtd, (u8)(page_addr >> 8));
@@ -410,7 +422,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
				this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f));
		}
		/* Latch in address */
		this->hwcontrol(mtd, NAND_CTL_CLRALE);
		au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
	}

	/*
@@ -443,7 +455,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
			udelay(1);

		/* Release -CE and re-enable interrupts. */
		this->hwcontrol(mtd, NAND_CTL_CLRNCE);
		au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
		local_irq_restore(flags);
		return;
	}
@@ -571,7 +583,6 @@ static int __init au1xxx_nand_init(void)
		nand_width = au_readl(MEM_STCFG3) & (1 << 22);

	/* Set address of hardware control function */
	this->hwcontrol = au1550_hwcontrol;
	this->dev_ready = au1550_device_ready;
	this->select_chip = au1550_select_chip;
	this->cmdfunc = au1550_command;
+48 −29
Original line number Diff line number Diff line
@@ -42,11 +42,6 @@
 * MTD structure for AUTCPU12 board
 */
static struct mtd_info *autcpu12_mtd = NULL;

static int autcpu12_io_base = CS89712_VIRT_BASE;
static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
static void __iomem *autcpu12_fio_base;

/*
@@ -94,21 +89,32 @@ static struct mtd_partition partition_info128k[] = {
#define NUM_PARTITIONS128K 2
/*
 *	hardware specific access to control-lines
 *
 *	ALE bit 4 autcpu12_pedr
 *	CLE bit 5 autcpu12_pedr
 *	NCE bit 0 fio_ctrl
 *
 */

static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
			       unsigned int ctrl)
{
	switch (cmd) {
	struct nand_chip *chip = mtd->priv;

		case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_CLE; break;
		case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
	if (ctrl & NAND_CTRL_CHANGE) {
		void __iomem *addr
		unsigned char bits;

		case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_ALE; break;
		case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
		addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
		bits = (ctrl & NAND_CLE) << 4;
		bits |= (ctrl & NAND_ALE) << 2;
		writeb((readb(addr) & ~0x30) | bits, addr);

		case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
		case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
		addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
		writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
	}

	if (cmd != NAND_CMD_NONE)
		writeb(cmd, chip->IO_ADDR_W);
}

/*
@@ -116,9 +122,9 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
 */
int autcpu12_device_ready(struct mtd_info *mtd)
{
	void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;

	return ((*(volatile unsigned char *)(autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;

	return readb(addr) & AUTCPU12_SMC_RDY;
}

/*
@@ -130,7 +136,8 @@ static int __init autcpu12_init(void)
	int err = 0;

	/* Allocate memory for MTD device structure and private data */
	autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
	autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
			       GFP_KERNEL);
	if (!autcpu12_mtd) {
		printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
		err = -ENOMEM;
@@ -138,7 +145,7 @@ static int __init autcpu12_init(void)
	}

	/* map physical adress */
	autcpu12_fio_base = ioremap(autcpu12_fio_pbase, SZ_1K);
	autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
	if (!autcpu12_fio_base) {
		printk("Ioremap autcpu12 SmartMedia Card failed\n");
		err = -EIO;
@@ -159,7 +166,7 @@ static int __init autcpu12_init(void)
	/* Set address of NAND IO lines */
	this->IO_ADDR_R = autcpu12_fio_base;
	this->IO_ADDR_W = autcpu12_fio_base;
	this->hwcontrol = autcpu12_hwcontrol;
	this->cmd_ctrl = autcpu12_hwcontrol;
	this->dev_ready = autcpu12_device_ready;
	/* 20 us command delay time */
	this->chip_delay = 20;
@@ -179,10 +186,22 @@ static int __init autcpu12_init(void)

	/* Register the partitions */
	switch (autcpu12_mtd->size) {
		case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
		case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
		case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
		case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
		case SZ_16M:
			add_mtd_partitions(autcpu12_mtd, partition_info16k,
					   NUM_PARTITIONS16K);
			break;
		case SZ_32M:
			add_mtd_partitions(autcpu12_mtd, partition_info32k,
					   NUM_PARTITIONS32K);
			break;
		case SZ_64M:
			add_mtd_partitions(autcpu12_mtd, partition_info64k,
					   NUM_PARTITIONS64K);
			break;
		case SZ_128M:
			add_mtd_partitions(autcpu12_mtd, partition_info128k,
					   NUM_PARTITIONS128K);
			break;
		default:
			printk("Unsupported SmartMedia device\n");
			err = -ENXIO;
@@ -191,7 +210,7 @@ static int __init autcpu12_init(void)
	goto out;

 out_ior:
	iounmap((void *)autcpu12_fio_base);
	iounmap(autcpu12_fio_base);
 out_mtd:
	kfree(autcpu12_mtd);
 out:
@@ -209,7 +228,7 @@ static void __exit autcpu12_cleanup(void)
	nand_release(autcpu12_mtd);

	/* unmap physical adress */
	iounmap((void *)autcpu12_fio_base);
	iounmap(autcpu12_fio_base);

	/* Free the MTD device structure */
	kfree(autcpu12_mtd);
+8 −24
Original line number Diff line number Diff line
@@ -131,34 +131,18 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
	writeb(byte, this->IO_ADDR_W + 0x801);
}

static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd)
static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
			     unsigned int ctrl)
{
	struct nand_chip *this = mtd->priv;
	void __iomem *mmio_base = this->IO_ADDR_R;
	unsigned char ctl;

	switch (cmd) {
	case NAND_CTL_SETCLE:
		ctl = CS_NAND_CTL_CLE;
		break;

	case NAND_CTL_CLRCLE:
	case NAND_CTL_CLRALE:
	case NAND_CTL_SETNCE:
		ctl = 0;
		break;

	case NAND_CTL_SETALE:
		ctl = CS_NAND_CTL_ALE;
		break;

	default:
	case NAND_CTL_CLRNCE:
		ctl = CS_NAND_CTL_CE;
		break;
	}
	if (ctrl & NAND_CTRL_CHANGE) {
		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
		writeb(ctl, mmio_base + MM_NAND_CTL);
	}
	if (cmd != NAND_CMD_NONE)
		cs553x_write_byte(mtd, cmd);
}

static int cs553x_device_ready(struct mtd_info *mtd)
{
@@ -233,7 +217,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
		goto out_mtd;
	}

	this->hwcontrol = cs553x_hwcontrol;
	this->cmd_ctrl = cs553x_hwcontrol;
	this->dev_ready = cs553x_device_ready;
	this->read_byte = cs553x_read_byte;
	this->write_byte = cs553x_write_byte;
+29 −48
Original line number Diff line number Diff line
@@ -95,7 +95,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)

static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
			      unsigned int bitmask);
static void doc200x_select_chip(struct mtd_info *mtd, int chip);

static int debug = 0;
@@ -402,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
	uint16_t ret;

	doc200x_select_chip(mtd, nr);
	doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
	this->write_byte(mtd, NAND_CMD_READID);
	doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
	doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
	this->write_byte(mtd, 0);
	doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
	doc200x_hwcontrol(mtd, NAND_CMD_READID,
			  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);

	/* We cant' use dev_ready here, but at least we wait for the
	 * command to complete
@@ -425,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
		} ident;
		void __iomem *docptr = doc->virtadr;

		doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
		doc2000_write_byte(mtd, NAND_CMD_READID);
		doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
		doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
		doc2000_write_byte(mtd, 0);
		doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
		doc200x_hwcontrol(mtd, NAND_CMD_READID,
				  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
		doc200x_hwcontrol(mtd, NAND_CMD_NONE,
				  NAND_NCE | NAND_CTRL_CHANGE);

		udelay(50);

@@ -690,55 +688,38 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
	chip -= (floor * doc->chips_per_floor);

	/* 11.4.4 -- deassert CE before changing chip */
	doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);

	WriteDOC(floor, docptr, FloorSelect);
	WriteDOC(chip, docptr, CDSNDeviceSelect);

	doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);

	doc->curchip = chip;
	doc->curfloor = floor;
}

static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)

static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
			      unsigned int ctrl)
{
	struct nand_chip *this = mtd->priv;
	struct doc_priv *doc = this->priv;
	void __iomem *docptr = doc->virtadr;

	switch (cmd) {
	case NAND_CTL_SETNCE:
		doc->CDSNControl |= CDSN_CTRL_CE;
		break;
	case NAND_CTL_CLRNCE:
		doc->CDSNControl &= ~CDSN_CTRL_CE;
		break;
	case NAND_CTL_SETCLE:
		doc->CDSNControl |= CDSN_CTRL_CLE;
		break;
	case NAND_CTL_CLRCLE:
		doc->CDSNControl &= ~CDSN_CTRL_CLE;
		break;
	case NAND_CTL_SETALE:
		doc->CDSNControl |= CDSN_CTRL_ALE;
		break;
	case NAND_CTL_CLRALE:
		doc->CDSNControl &= ~CDSN_CTRL_ALE;
		break;
	case NAND_CTL_SETWP:
		doc->CDSNControl |= CDSN_CTRL_WP;
		break;
	case NAND_CTL_CLRWP:
		doc->CDSNControl &= ~CDSN_CTRL_WP;
		break;
	}
	if (ctrl & NAND_CTRL_CHANGE) {
		doc->CDSNControl &= ~CDSN_CTRL_MSK;
		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
		if (debug)
			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
		/* 11.4.3 -- 4 NOPs after CSDNControl write */
		DoC_Delay(doc, 4);
	}
	if (cmd != NAND_CMD_NONE)
		this->write_byte(mtd, cmd);
}

static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
@@ -1510,7 +1491,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
	this->read_buf = doc2001plus_readbuf;
	this->verify_buf = doc2001plus_verifybuf;
	this->scan_bbt = inftl_scan_bbt;
	this->hwcontrol = NULL;
	this->cmd_ctrl = NULL;
	this->select_chip = doc2001plus_select_chip;
	this->cmdfunc = doc2001plus_command;
	this->ecc.hwctl = doc2001plus_enable_hwecc;
@@ -1670,7 +1651,7 @@ static int __init doc_probe(unsigned long physadr)

	nand->priv		= doc;
	nand->select_chip	= doc200x_select_chip;
	nand->hwcontrol		= doc200x_hwcontrol;
	nand->cmd_ctrl		= doc200x_hwcontrol;
	nand->dev_ready		= doc200x_dev_ready;
	nand->waitfunc		= doc200x_wait;
	nand->block_bad		= doc200x_block_bad;
Loading