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

📄 omap2.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
字号:
/* * drivers/mtd/nand/omap2.c * * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com> * Copyright (c) 2004 Micron Technology Inc. * Copyright (c) 2004 David Brownell * * 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. */#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/delay.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/io.h>#include <asm/dma.h>#include <asm/arch/gpmc.h>#include <asm/arch/nand.h>#define	DRIVER_NAME	"omap2-nand"#define	NAND_IO_SIZE	SZ_4K#define	NAND_WP_ON	1#define	NAND_WP_OFF	0#define NAND_WP_BIT	0x00000010#define WR_RD_PIN_MONITORING	0x00600000#define	GPMC_BUF_FULL	0x00000001#define	GPMC_BUF_EMPTY	0x00000000static const char *part_probes[] = { "cmdlinepart", NULL }; #define NAND_Ecc_P1e            (1 << 0)#define NAND_Ecc_P2e            (1 << 1)#define NAND_Ecc_P4e            (1 << 2)#define NAND_Ecc_P8e            (1 << 3)#define NAND_Ecc_P16e           (1 << 4)#define NAND_Ecc_P32e           (1 << 5)#define NAND_Ecc_P64e           (1 << 6)#define NAND_Ecc_P128e          (1 << 7)#define NAND_Ecc_P256e          (1 << 8)#define NAND_Ecc_P512e          (1 << 9)#define NAND_Ecc_P1024e         (1 << 10)#define NAND_Ecc_P2048e         (1 << 11)#define NAND_Ecc_P1o            (1 << 16)#define NAND_Ecc_P2o            (1 << 17)#define NAND_Ecc_P4o            (1 << 18)#define NAND_Ecc_P8o            (1 << 19)#define NAND_Ecc_P16o           (1 << 20)#define NAND_Ecc_P32o           (1 << 21)#define NAND_Ecc_P64o           (1 << 22)#define NAND_Ecc_P128o          (1 << 23)#define NAND_Ecc_P256o          (1 << 24)#define NAND_Ecc_P512o          (1 << 25)#define NAND_Ecc_P1024o         (1 << 26)#define NAND_Ecc_P2048o         (1 << 27)#define TF(value)       (value ? 1 : 0)#define P2048e(a)       (TF(a & NAND_Ecc_P2048e)        << 0 )#define P2048o(a)       (TF(a & NAND_Ecc_P2048o)        << 1 )#define P1e(a)          (TF(a & NAND_Ecc_P1e)           << 2 )#define P1o(a)          (TF(a & NAND_Ecc_P1o)           << 3 )#define P2e(a)          (TF(a & NAND_Ecc_P2e)           << 4 )#define P2o(a)          (TF(a & NAND_Ecc_P2o)           << 5 )#define P4e(a)          (TF(a & NAND_Ecc_P4e)           << 6 )#define P4o(a)          (TF(a & NAND_Ecc_P4o)           << 7 )#define P8e(a)          (TF(a & NAND_Ecc_P8e)           << 0 )#define P8o(a)          (TF(a & NAND_Ecc_P8o)           << 1 )#define P16e(a)         (TF(a & NAND_Ecc_P16e)          << 2 )#define P16o(a)         (TF(a & NAND_Ecc_P16o)          << 3 )#define P32e(a)         (TF(a & NAND_Ecc_P32e)          << 4 )#define P32o(a)         (TF(a & NAND_Ecc_P32o)          << 5 )#define P64e(a)         (TF(a & NAND_Ecc_P64e)          << 6 )#define P64o(a)         (TF(a & NAND_Ecc_P64o)          << 7 )#define P128e(a)        (TF(a & NAND_Ecc_P128e)         << 0 )#define P128o(a)        (TF(a & NAND_Ecc_P128o)         << 1 )#define P256e(a)        (TF(a & NAND_Ecc_P256e)         << 2 )#define P256o(a)        (TF(a & NAND_Ecc_P256o)         << 3 )#define P512e(a)        (TF(a & NAND_Ecc_P512e)         << 4 )#define P512o(a)        (TF(a & NAND_Ecc_P512o)         << 5 )#define P1024e(a)       (TF(a & NAND_Ecc_P1024e)        << 6 )#define P1024o(a)       (TF(a & NAND_Ecc_P1024o)        << 7 )#define P8e_s(a)        (TF(a & NAND_Ecc_P8e)           << 0 )#define P8o_s(a)        (TF(a & NAND_Ecc_P8o)           << 1 )#define P16e_s(a)       (TF(a & NAND_Ecc_P16e)          << 2 )#define P16o_s(a)       (TF(a & NAND_Ecc_P16o)          << 3 )#define P1e_s(a)        (TF(a & NAND_Ecc_P1e)           << 4 )#define P1o_s(a)        (TF(a & NAND_Ecc_P1o)           << 5 )#define P2e_s(a)        (TF(a & NAND_Ecc_P2e)           << 6 )#define P2o_s(a)        (TF(a & NAND_Ecc_P2o)           << 7 )#define P4e_s(a)        (TF(a & NAND_Ecc_P4e)           << 0 )#define P4o_s(a)        (TF(a & NAND_Ecc_P4o)           << 1 )struct omap_nand_info {        struct nand_hw_control          controller;        struct omap_nand_platform_data  *pdata;        struct mtd_info                 mtd;        struct mtd_partition            *parts;        struct nand_chip                nand;        struct platform_device          *pdev;        int                             gpmc_cs;        unsigned long                   phys_base;        void __iomem                    *gpmc_cs_baseaddr;        void __iomem                    *gpmc_baseaddr;};/* * omap_nand_wp - This function enable or disable the Write Protect feature on * NAND device * @mtd: MTD device structure * @mode: WP ON/OFF */static void omap_nand_wp(struct mtd_info *mtd, int mode){	struct omap_nand_info *info = container_of(mtd,						struct omap_nand_info, mtd);	unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);	if (mode)		config &= ~(NAND_WP_BIT);	/* WP is ON */	else		config |= (NAND_WP_BIT);	/* WP is OFF */	__raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG)); }/* * hardware specific access to control-lines * NOTE:  boards may use different bits for these!! * ctrl: * 	NAND_NCE: bit 0 - don't care *	NAND_CLE: bit 1 -> Command Latch *	NAND_ALE: bit 2 -> Address Latch */static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl){	struct omap_nand_info *info = container_of(mtd,					struct omap_nand_info, mtd);	switch (ctrl) {	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_COMMAND;		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_DATA;		break;	case NAND_CTRL_CHANGE | NAND_CTRL_ALE:		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_ADDRESS;		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_DATA;		break;	case NAND_CTRL_CHANGE | NAND_NCE:		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_DATA;		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +						GPMC_CS_NAND_DATA;		break;	}	if (cmd != NAND_CMD_NONE)		__raw_writeb(cmd, info->nand.IO_ADDR_W);}/* * omap_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_read_buf(struct mtd_info *mtd, u_char *buf, int len){	struct omap_nand_info *info = container_of(mtd,					struct omap_nand_info, mtd);	u16 *p = (u16 *) buf;	len >>= 1;	while (len--)		*p++ = cpu_to_le16(readw(info->nand.IO_ADDR_R));}/* * omap_write_buf -  write buffer to NAND controller * @mtd: MTD device structure * @buf: data buffer * @len: number of bytes to write * */static void omap_write_buf(struct mtd_info *mtd, const u_char * buf, int len){	struct omap_nand_info *info = container_of(mtd,						struct omap_nand_info, mtd);	u16 *p = (u16 *) buf;	len >>= 1;	while (len--) {		writew(cpu_to_le16(*p++), info->nand.IO_ADDR_W);		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +					GPMC_STATUS) & GPMC_BUF_FULL));	}}/* * omap_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_verify_buf(struct mtd_info *mtd, const u_char * buf, int len){	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,							mtd);	u16 *p = (u16 *) buf;	len >>= 1;	while (len--) {		if (*p++ != cpu_to_le16(readw(info->nand.IO_ADDR_R)))			return -EFAULT;	}	return 0;}/* * omap_wait - Wait function is called during Program and erase * operations and the way it is called from MTD layer, we should wait * till the NAND chip is ready after the programming/erase operation * has completed. * @mtd: MTD device structure * @chip: NAND Chip structure */static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip){        register struct nand_chip *this = mtd->priv;        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,mtd);        int status = 0;        this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_COMMAND;	this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;        while(!(status & 0x40)){                __raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);                status = __raw_readb(this->IO_ADDR_R);        }        return status;}/* * omap_dev_ready - calls the platform specific dev_ready function * @mtd: MTD device structure */static int omap_dev_ready(struct mtd_info *mtd){	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,							mtd);	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);	if ((val & 0x100) == 0x100) {	/* Clear IRQ Interrupt */	val |= 0x100;		val &= ~(0x0);		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQSTATUS);	} else {		unsigned int cnt = 0;		while (cnt++ < 0x1FF) {			if  ((val & 0x100) == 0x100)				return 0;			val = __raw_readl(info->gpmc_baseaddr +							GPMC_IRQSTATUS);		}	}	return 1;}static int __devinit omap_nand_probe(struct platform_device *pdev){	struct omap_nand_info		*info;	struct omap_nand_platform_data	*pdata;	int				err;	unsigned long			val;	pdata = pdev->dev.platform_data;	if (pdata == NULL) {		dev_err(&pdev->dev, "platform data missing\n");		return -ENODEV;	}	info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);	if (!info) return -ENOMEM;	platform_set_drvdata(pdev, info);	spin_lock_init(&info->controller.lock);	init_waitqueue_head(&info->controller.wq);	info->pdev = pdev;	info->gpmc_cs          = pdata->cs;	info->gpmc_baseaddr    = pdata->gpmc_baseaddr;	info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr;	info->mtd.priv  = &info->nand;	info->mtd.name  = pdev->dev.bus_id;	info->mtd.owner = THIS_MODULE;	err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base);	if (err < 0) {		dev_err(&pdev->dev, "Cannot request GPMC CS\n");		goto out_free_info;	}	/* Enable RD PIN Monitoring Reg */	if(pdata->dev_ready) {		val  = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1);		val |= WR_RD_PIN_MONITORING;		gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val);	}	val  = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7);	val &= ~(0xf << 8);	val |=  (0xc & 0xf) << 8;	gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val);	/* NAND write protect off */	omap_nand_wp(&info->mtd, NAND_WP_OFF);		if (!request_mem_region(info->phys_base, NAND_IO_SIZE,				pdev->dev.driver->name)) {		err = -EBUSY;		goto out_free_cs;	}	info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);	if (!info->nand.IO_ADDR_R) {		err = -ENOMEM;		goto out_release_mem_region;	}	info->nand.controller = &info->controller;	info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;	info->nand.cmd_ctrl  = omap_hwcontrol;	info->nand.read_buf   = omap_read_buf;	info->nand.write_buf  = omap_write_buf;	info->nand.verify_buf = omap_verify_buf;		/* 	 * If RDY/BSY line is connected to OMAP then use the omap ready funcrtion         * and the generic nand_wait function which reads the status register after         * monitoring the RDY/BSY line. Otherwise use a standard chip delay which         * is slightly more than tR (AC Timing) of the NAND device and read the         * status register until you get a failure or success         */	if (pdata->dev_ready) {		info->nand.dev_ready = omap_dev_ready;		info->nand.chip_delay = 0;	} else {		info->nand.waitfunc = omap_wait;		info->nand.chip_delay = 50;	}		info->nand.options  |= NAND_SKIP_BBTSCAN;	if((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000) == 0x1000)		info->nand.options  |= NAND_BUSWIDTH_16;		info->nand.ecc.mode = NAND_ECC_SOFT;		/* DIP switches on some boards change between 8 and 16 bit	 * bus widths for flash.  Try the other width if the first try fails.	 */	if (nand_scan(&info->mtd, 1)) {		info->nand.options ^= NAND_BUSWIDTH_16;		if (nand_scan(&info->mtd, 1)) {			err = -ENXIO;			goto out_release_mem_region;		}	} 	err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);	if (err > 0)		add_mtd_partitions(&info->mtd, info->parts, err);	else if (err < 0 && pdata->parts)		add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);	else		add_mtd_device(&info->mtd);	platform_set_drvdata(pdev, &info->mtd);	return 0;out_release_mem_region:	release_mem_region(info->phys_base, NAND_IO_SIZE);out_free_cs:	gpmc_cs_free(info->gpmc_cs);out_free_info:	kfree(info);	return err;}static int omap_nand_remove(struct platform_device *pdev){	struct mtd_info *mtd = platform_get_drvdata(pdev);	struct omap_nand_info *info = mtd->priv;	platform_set_drvdata(pdev, NULL);	/* Release NAND device, its internal structures and partitions */	nand_release(&info->mtd);	iounmap(info->nand.IO_ADDR_R);	kfree(&info->mtd);	return 0;}static struct platform_driver omap_nand_driver = {	.probe		= omap_nand_probe,	.remove		= omap_nand_remove,	.driver		= {		.name	= DRIVER_NAME,		.owner	= THIS_MODULE,	},};MODULE_ALIAS(DRIVER_NAME);static int __init omap_nand_init(void){	printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);	return platform_driver_register(&omap_nand_driver);}static void __exit omap_nand_exit(void){	platform_driver_unregister(&omap_nand_driver);}module_init(omap_nand_init);module_exit(omap_nand_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");

⌨️ 快捷键说明

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