⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 omap-nand-flash.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
字号:
/* *  drivers/mtd/nand/omap-nand-flash.c * *  Copyright (c) 2004 Texas Instruments *  Jian Zhang <jzhang@ti.com> *  Copyright (c) 2004 David Brownell * *  Derived from drivers/mtd/autcpu12.c * *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> * * 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 is a device driver for the NAND flash device found on the *   TI H4/H3/H2  boards.This supports 16-bit 32MiB Samsung k9f5616 chip on H3/H2  *   and 16-bit 64MiB Samsung k9k1216 on H4 board. * * History: * * 2004         Jian Zhang             Initial release. * 2004-11-02   Syed Mohammed Khasim   Modified the driver to add support for OMAP 2420 NAND controller. *  */#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/arch/hardware.h>#include <asm/arch/gpio.h>#include <asm/arch/mux.h>#include <asm/sizes.h>#include <asm/mach-types.h>#ifdef CONFIG_ARCH_OMAP24XX#include <asm/arch/platform.h>#endif#define H3_NAND_RB_GPIO_PIN    10#define H2_NAND_RB_GPIO_PIN    10#ifdef CONFIG_ARCH_OMAP24XX/* Function prototype declaration */static void omap_nandwpoff(void);static void omap_nandwpon(void);/* GPMC Base address */volatile unsigned long GPMC_BASE;#endif/* * MTD structure for H3 board */static struct mtd_info *omap_nand_mtd = NULL;static unsigned long omap_nand_flash_base;/* * Define partitions for flash devices */#ifdef CONFIG_MTD_PARTITIONSstatic struct mtd_partition static_partition[] = {	{.name = "Booting Image",	 .offset = 0,#ifdef CONFIG_ARCH_OMAP24XX	 .size = 256 * 1024,#endif#ifdef CONFIG_ARCH_OMAP16XX	 .size = 64 * 1024,#endif	 .mask_flags = MTD_WRITEABLE	/* force read-only */	 },	{.name = "U-Boot",	 .offset = MTDPART_OFS_APPEND,	 .size = 256 * 1024,	 .mask_flags = MTD_WRITEABLE	/* force read-only */	 },	{.name = "U-Boot Environment",	 .offset = MTDPART_OFS_APPEND,	 .size = 192 * 1024},	{.name = "Kernel",	 .offset = MTDPART_OFS_APPEND,	 .size = 2 * SZ_1M},	{.name = "File System",	 .size = MTDPART_SIZ_FULL,	 .offset = MTDPART_OFS_APPEND,	 },};#define NUM_PARTITIONS 		5#endif/* H2/H3 maps two address LSBs to CLE and ALE; MSBs make CS_2B */#define	MASK_CLE	0x02#define	MASK_ALE	0x04const char *part_probes[] = { "cmdlinepart", NULL, };/*  *	hardware specific access to control-lines*/static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd){	register struct nand_chip *this = mtd->priv;#ifdef CONFIG_ARCH_OMAP24XX/* * Point the IO_ADDR to DATA and ADDRESS registers instead of chip address */	switch (cmd) {	case NAND_CTL_SETCLE:		this->IO_ADDR_W = GPMC_BASE + OFFSET_NAND_COMMAND_0;		this->IO_ADDR_R = GPMC_BASE + OFFSET_NAND_DATA_0;		break;	case NAND_CTL_SETALE:		this->IO_ADDR_W = GPMC_BASE + OFFSET_NAND_ADDRESS_0;		this->IO_ADDR_R = GPMC_BASE + OFFSET_NAND_DATA_0;		break;	case NAND_CTL_CLRCLE:		this->IO_ADDR_W = GPMC_BASE + OFFSET_NAND_DATA_0;		this->IO_ADDR_R = GPMC_BASE + OFFSET_NAND_DATA_0;		break;	case NAND_CTL_CLRALE:		this->IO_ADDR_W = GPMC_BASE + OFFSET_NAND_DATA_0;		this->IO_ADDR_R = GPMC_BASE + OFFSET_NAND_DATA_0;		break;	}#endif#ifdef CONFIG_ARCH_OMAP16XX	this->IO_ADDR_W &= ~(MASK_ALE | MASK_CLE);	switch (cmd) {	case NAND_CTL_SETCLE:		this->IO_ADDR_W |= MASK_CLE;		break;	case NAND_CTL_SETALE:		this->IO_ADDR_W |= MASK_ALE;		break;	}#endif}#ifdef CONFIG_ARCH_OMAP24XX/* * omap_nandwpoff - to switch off the write protect *  */static void omap_nandwpoff(){	unsigned long config = readw(GPMC_BASE + OFFSET_CONFIG);	config |= NAND_WP_BIT;	writew(config, (GPMC_BASE + OFFSET_CONFIG));}/* * omap_nandwpon - to switch on the write protect *  */static void omap_nandwpon(){	unsigned long config = readw(GPMC_BASE + OFFSET_CONFIG);	config &= ~(NAND_WP_BIT);	writew(config, (GPMC_BASE + OFFSET_CONFIG));}/* * omap_nand_write_word -  write one word to the NAND controller * @mtd:        MTD device structure * @word:       data word to write *  */static void omap_nand_write_word(struct mtd_info *mtd, u16 word){	struct nand_chip *this = mtd->priv;	writew(word, this->IO_ADDR_W);}/* * omap_nand_read_word - read one word from the NAND controller * @mtd:        MTD device structure * */static u16 omap_nand_read_word(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	return readw(this->IO_ADDR_R);}/* * omap_nand_write_byte16 - write one byte endianess aware to the NAND controller * @mtd:        MTD device structure * @byte:       pointer to data byte to write * */static void omap_nand_write_byte16(struct mtd_info *mtd, u_char byte){	struct nand_chip *this = mtd->priv;	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);}/* * omap_nand_read_byte16 - read one byte endianess aware from the NAND controller * @mtd:        MTD device structure * */static u_char omap_nand_read_byte16(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));}/* * omap_nand_write_buf -  write buffer to NAND controller * @mtd:        MTD device structure * @buf:        data buffer * @len:        number of bytes to write * */static void omap_nand_write_buf(struct mtd_info *mtd, const u_char * buf,				int len){	int i, j;	struct nand_chip *this = mtd->priv;	union data_tx {		u16 data_16;		u_char data[2];	} write_data;	for (i = 0, j = 0; i < (len / 2); i++) {		write_data.data[0] = buf[j++];		write_data.data[1] = buf[j++];		writew(le16_to_cpu((u16) write_data.data_16), this->IO_ADDR_W);		while (GPMC_BUF_EMPTY ==		       (readw(GPMC_BASE + OFFSET_STATUS) & GPMC_BUF_FULL)) ;	}}/* * omap_nand_read_buf - read data from NAND controller into buffer * @mtd:        MTD device structure * @buf:        buffer to store date * @len:        number of bytes to read * */static void omap_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len){	int i, j;	union data_rx {		u16 data_16;		u_char data[2];	} read_data;	struct nand_chip *this = mtd->priv;	for (i = 0, j = 0; i < (len / 2); i++) {		read_data.data_16 = cpu_to_le16(readw(this->IO_ADDR_R));		buf[j++] = read_data.data[0];		buf[j++] = read_data.data[1];	}}/* * omap_nand_verify_buf - Verify chip data against buffer * @mtd:        MTD device structure * @buf:        buffer containing the data to compare * @len:        number of bytes to compare * */static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char * buf,				int len){	int i, j;	struct nand_chip *this = mtd->priv;	union data_rx {		u16 data_16;		u_char data[2];	} read_data;	for (i = 0, j = 0; i < len / 2; i++) {		read_data.data[0] = buf[j++];		read_data.data[1] = buf[j++];		if (read_data.data_16 != cpu_to_le16(readw(this->IO_ADDR_R)))			return -EFAULT;	}	return 0;}#endif#ifdef CONFIG_ARCH_OMAP16XX/* *	chip busy R/B detection */static int omap_nand_ready(struct mtd_info *mtd){	return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);}#endif/* Scan to find existance of the device at omap_nand_flash_base.   This also allocates oob and data internal buffers */static int probe_nand_chip(void){	struct nand_chip *this;	this = (struct nand_chip *)(&omap_nand_mtd[1]);	/* Initialize structures */	memset((char *)this, 0, sizeof(struct nand_chip));	this->IO_ADDR_R = omap_nand_flash_base;	this->IO_ADDR_W = omap_nand_flash_base;	this->options = NAND_SAMSUNG_LP_OPTIONS;	this->hwcontrol = omap_nand_hwcontrol;#ifdef CONFIG_ARCH_OMAP24XX	this->write_word = omap_nand_write_word;	this->read_word = omap_nand_read_word;	this->write_byte = omap_nand_write_byte16;	this->read_byte = omap_nand_read_byte16;	this->write_buf = omap_nand_write_buf;	this->read_buf = omap_nand_read_buf;	this->verify_buf = omap_nand_verify_buf;#endif	this->eccmode = NAND_ECC_SOFT;	/* try 16-bit chip first */	this->options |= NAND_BUSWIDTH_16;	if (nand_scan(omap_nand_mtd, 1)) {		if (machine_is_omap_h3())			return -ENXIO;		/* then try 8-bit chip for H2 */		memset((char *)this, 0, sizeof(struct nand_chip));		this->IO_ADDR_R = omap_nand_flash_base;		this->IO_ADDR_W = omap_nand_flash_base;		this->options = NAND_SAMSUNG_LP_OPTIONS;		this->hwcontrol = omap_nand_hwcontrol;		this->eccmode = NAND_ECC_SOFT;		if (nand_scan(omap_nand_mtd, 1)) {			return -ENXIO;		}	}	return 0;}/* * Main initialization routine */int __init omap_nand_init(void){	struct nand_chip *this;	struct mtd_partition *dynamic_partition = 0;	int err = 0;#ifdef CONFIG_ARCH_OMAP24XX	unsigned long config1_0;	GPMC_BASE = (unsigned long)ioremap_nocache(OMAP2420_GPMC_BASE, 0x23C);	/* 	 * Enable the Read and Write pin monitoring in NAND controller 	 * this is like R/B in 1710	 */	config1_0 = *(unsigned long *)(GPMC_BASE + OFFSET_CONFIG1_0);	config1_0 |= WR_RD_PIN_MONITORING;	*(unsigned long *)(GPMC_BASE + OFFSET_CONFIG1_0) = config1_0;	/* Write protect off */	omap_nandwpoff();#endif	/* Allocate memory for MTD device structure and private data */	omap_nand_mtd =	    kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),		    GFP_KERNEL);	if (!omap_nand_mtd) {		printk(KERN_WARNING		       "Unable to allocate NAND MTD device structure.\n");		err = -ENOMEM;		goto out;	}	/* Get pointer to private data */	this = (struct nand_chip *)(&omap_nand_mtd[1]);	/* Initialize structures */	memset((char *)omap_nand_mtd, 0,	       sizeof(struct mtd_info) + sizeof(struct nand_chip));	/* Link the private data with the MTD structure */	omap_nand_mtd->priv = this;#ifdef CONFIG_ARCH_OMAP24XX	this->chip_delay = 0;#endif#ifdef CONFIG_ARCH_OMAP16XX	if (machine_is_omap_h3()) {		if (omap_request_gpio(H3_NAND_RB_GPIO_PIN) != 0) {			printk(KERN_ERR			       "NAND: Unable to get GPIO pin for R/B, use delay\n");			/* 15 us command delay time */			this->chip_delay = 15;		} else {			/* GPIO10 for input. it is in GPIO1 module */			omap_set_gpio_direction(H3_NAND_RB_GPIO_PIN, 1);			/* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */			/* GPIO10 pullup/down register, Enable pullup on GPIO10 */			omap_cfg_reg(V2_1710_GPIO10);			this->dev_ready = omap_nand_ready;		}	}	if (machine_is_omap_h2()) {		/* FIXME On H2, R/B is also tied to GPIO10. Not work yet */		/* it will wrongly mark block bad when erasing */		this->chip_delay = 15;		omap_cfg_reg(L3_1610_FLASH_CS2B_OE);		omap_cfg_reg(M8_1610_FLASH_CS2B_WE);	}#endif	/* try the first address */	omap_nand_flash_base =	    (unsigned long)ioremap(OMAP_NAND_FLASH_START1, SZ_4K);	if (probe_nand_chip()) {		/* try the second address */		iounmap((void *)omap_nand_flash_base);		omap_nand_flash_base =		    (unsigned long)ioremap(OMAP_NAND_FLASH_START2, SZ_4K);		if (probe_nand_chip()) {			iounmap((void *)omap_nand_flash_base);			err = -ENXIO;			goto out_mtd;		}	}	/* 	 * The NAND chip on H4 is 64 M So the case is added for handling 64M 	 */	/* Register the partitions */	switch (omap_nand_mtd->size) {	case SZ_64M:#ifdef CONFIG_MTD_PARTITIONS		err =		    parse_mtd_partitions(omap_nand_mtd, part_probes,					 &dynamic_partition, 0);		if (err > 0)			err =			    add_mtd_partitions(omap_nand_mtd, dynamic_partition,					       err);		else			err =			    add_mtd_partitions(omap_nand_mtd, static_partition,					       NUM_PARTITIONS);#else		err = add_mtd_device(omap_nand_mtd);#endif		if (err)			goto out_buf;		break;	case SZ_32M:#ifdef CONFIG_MTD_PARTITIONS		err =		    parse_mtd_partitions(omap_nand_mtd, part_probes,					 &dynamic_partition, 0);		if (err > 0)			err =			    add_mtd_partitions(omap_nand_mtd, dynamic_partition,					       err);		else			err =			    add_mtd_partitions(omap_nand_mtd, static_partition,					       NUM_PARTITIONS);#else		err = add_mtd_device(omap_nand_mtd);#endif		if (err)			goto out_buf;		break;	default:{			printk(KERN_WARNING "Unsupported Nand device\n");			err = -ENXIO;			goto out_buf;		}	}	goto out;      out_buf:	nand_release(omap_nand_mtd);	if (this->dev_ready) {#ifdef CONFIG_ARCH_OMAP16XX		if (machine_is_omap_h3())			omap_free_gpio(H3_NAND_RB_GPIO_PIN);#endif	}	iounmap((void *)omap_nand_flash_base);      out_mtd:	kfree(omap_nand_mtd);	/* Un map the Physical addresses allocated for GPMC */#ifdef CONFIG_ARCH_OMAP24XX	omap_nandwpon();	iounmap((void *)GPMC_BASE);#endif      out:	return err;}module_init(omap_nand_init);/* * Clean up routine */static void __exit omap_nand_cleanup(void){	struct nand_chip *this = omap_nand_mtd->priv;	if (this->dev_ready) {#ifdef CONFIG_ARCH_OMAP16XX		if (machine_is_omap_h3())			omap_free_gpio(H3_NAND_RB_GPIO_PIN);#endif	}	/* nand_release frees MTD partitions, MTD structure	   and nand internal buffers */	nand_release(omap_nand_mtd);	kfree(omap_nand_mtd);#ifdef CONFIG_ARCH_OMAP24XX	omap_nandwpon();	iounmap((void *)GPMC_BASE);#endif	iounmap((void *)omap_nand_flash_base);}module_exit(omap_nand_cleanup);MODULE_LICENSE("GPL");MODULE_AUTHOR("Jian Zhang <jzhang@ti.com>");MODULE_DESCRIPTION("Glue layer for 16-bit NAND flash on H4/H3 board");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -