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

📄 au1550nd.c

📁 linux下的MTD设备驱动源代码,配合jffs2 yaffss2文件系统.
💻 C
字号:
/* *  drivers/mtd/nand/au1550nd.c * *  Copyright (C) 2004 Embedded Edge, LLC * * $Id: au1550nd.c,v 1.2 2004/03/27 19:55:53 gleixner 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. * */#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/au1000.h>#ifdef CONFIG_MIPS_PB1550#include <asm/pb1550.h>#endif#define NAND_PHYS_ADDR   0x20000000 #define NUM_PARTITIONS            2/* * MTD structure for Pb1550 board */static struct mtd_info *au1550_mtd = NULL;static volatile u32 p_nand;static int nand_width;/* * Define partitions for flash device */const static struct mtd_partition partition_info[NUM_PARTITIONS] = {	{ 		.name = "Pb1550 NAND FS 0",	  	.offset = 0,	  	.size = 8*1024*1024 	},	{ 		.name = "Pb1550 NAND FS 1",		.offset =  MTDPART_OFS_APPEND, 		.size =    MTDPART_SIZ_FULL	}};static inline void write_cmd_reg(u8 cmd){	if (nand_width)		*((volatile u8 *)(p_nand + MEM_STNAND_CMD)) = cmd;	else		*((volatile u16 *)(p_nand + MEM_STNAND_CMD)) = cmd;	au_sync();}static inline void write_addr_reg(u8 addr){	if (nand_width)		*((volatile u8 *)(p_nand + MEM_STNAND_ADDR)) = addr;	else		*((volatile u16 *)(p_nand + MEM_STNAND_ADDR)) = addr;	au_sync();}static inline void write_data_reg(u8 data){	if (nand_width)		*((volatile u8 *)(p_nand + MEM_STNAND_DATA)) = data;	else		*((volatile u16 *)(p_nand + MEM_STNAND_DATA)) = data;	au_sync();}static inline u32 read_data_reg(void){	u32 data;	if (nand_width) {		data = *((volatile u8 *)(p_nand + MEM_STNAND_DATA));		au_sync();	}	else {		data = *((volatile u16 *)(p_nand + MEM_STNAND_DATA));		au_sync();	}	return data;}void au1550_hwcontrol(struct mtd_info *mtd, int cmd){}int au1550_device_ready(struct mtd_info *mtd){	int ready;	ready = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;	return ready;}static u_char au1550_nand_read_byte(struct mtd_info *mtd){	u_char ret;	ret = read_data_reg();	return ret;}static void au1550_nand_write_byte(struct mtd_info *mtd, u_char byte){	write_data_reg((u8)byte);}static void au1550_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len){	int i;	for (i=0; i<len; i++)		write_data_reg(buf[i]);}static void au1550_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){	int i;	for (i=0; i<len; i++)		buf[i] = (u_char)read_data_reg();}static int au1550_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){	int i;	for (i=0; i<len; i++)		if (buf[i] != (u_char)read_data_reg())			return -EFAULT;	return 0;}static void au1550_nand_select_chip(struct mtd_info *mtd, int chip){	switch(chip) {	case -1:		/* deassert chip enable */		au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL);		break;	case 0:		/* assert (force assert) chip enable */		au_writel(au_readl(MEM_STNDCTL) | 0x20 , MEM_STNDCTL);		break;	default:		BUG();	}}static void au1550_nand_command (struct mtd_info *mtd, unsigned command, 		int column, int page_addr){	register struct nand_chip *this = mtd->priv;	/*	 * 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;		}		write_cmd_reg(readcmd);	}	write_cmd_reg(command);	if (column != -1 || page_addr != -1) {		/* Serially input address */		if (column != -1)			write_addr_reg(column);		if (page_addr != -1) {			write_addr_reg((unsigned char) (page_addr & 0xff));			write_addr_reg(((page_addr >> 8) & 0xff));			/* One more address cycle for higher density devices */			if (mtd->size & 0x0c000000) 				write_addr_reg((unsigned char) ((page_addr >> 16) & 0x0f));		}	}		switch (command) {				case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		break;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		udelay(this->chip_delay);		write_cmd_reg(NAND_CMD_STATUS);		while ( !(read_data_reg() & 0x40));		return;	/* This applies to read commands */		default:		udelay (this->chip_delay);	}		/* wait until command is processed */	while (!this->dev_ready(mtd));}/* * Main initialization routine */int __init au1550_init (void){	struct nand_chip *this;	u16 boot_swapboot = 0; /* default value */	u32 mem_time;	/* Allocate memory for MTD device structure and private data */	au1550_mtd = kmalloc (sizeof(struct mtd_info) + 			sizeof (struct nand_chip), GFP_KERNEL);	if (!au1550_mtd) {		printk ("Unable to allocate Pb1550 NAND MTD dev structure.\n");		return -ENOMEM;	}	/* Get pointer to private data */	this = (struct nand_chip *) (&au1550_mtd[1]);	/* Initialize structures */	memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));	memset((char *) this, 0, sizeof(struct nand_chip));	/* Link the private data with the MTD structure */	au1550_mtd->priv = this;	/* set gpio206 high */	au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);	/* disable interrupts */	au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);#ifdef CONFIG_MIPS_PB1550	boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 		((bcsr->status >> 6)  & 0x1);	switch (boot_swapboot) {		case 0:		case 2:		case 8:		case 0xC:		case 0xD:			/* x16 NAND Flash */			nand_width = 0;			break;		case 1:		case 9:		case 3:		case 0xE:		case 0xF:			/* x8 NAND Flash */			nand_width = 1;			break;		default:			printk("Pb1550 NAND: bad boot:swap\n");			kfree(au1550_mtd);			return 1;	}#endif	au_writel(0x5 | (nand_width << 22), MEM_STCFG1);	au_writel(NAND_TIMING, MEM_STTIME1);	mem_time = au_readl(MEM_STTIME1);	au_sync();	/* setup and enable chip select */	/* we really need to decode offsets only up till 0x20 */	au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | 			(((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), 			MEM_STADDR1);	au_sync();	p_nand = (volatile struct nand_regs *)ioremap(NAND_PHYS_ADDR, 0x1000);	/* Set address of hardware control function */	this->hwcontrol = au1550_hwcontrol;	this->dev_ready = au1550_device_ready;	/* 30 us command delay time */	this->chip_delay = 30;			this->cmdfunc = au1550_nand_command;	this->select_chip = au1550_nand_select_chip;	this->write_byte = au1550_nand_write_byte;	this->read_byte = au1550_nand_read_byte;	this->write_buf = au1550_nand_write_buf;	this->read_buf = au1550_nand_read_buf;	this->verify_buf = au1550_nand_verify_buf;	this->eccmode = NAND_ECC_SOFT;	/* Scan to find existence of the device */	if (nand_scan (au1550_mtd, 1)) {		kfree (au1550_mtd);		return -ENXIO;	}	/* Allocate memory for internal data buffer */	this->data_buf = kmalloc (sizeof(u_char) * (au1550_mtd->oobblock + 				au1550_mtd->oobsize), GFP_KERNEL);	if (!this->data_buf) {		printk ("Unable to allocate NAND data buffer for Pb1550.\n");		kfree (au1550_mtd);		return -ENOMEM;	}	/* Register the partitions */	add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);	return 0;}module_init(au1550_init);/* * Clean up routine */#ifdef MODULEstatic void __exit au1550_cleanup (void){	struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];	iounmap ((void *)p_nand);	/* Unregister partitions */	del_mtd_partitions(au1550_mtd);	/* Unregister the device */	del_mtd_device (au1550_mtd);	/* Free internal data buffer */	kfree (this->data_buf);	/* Free the MTD device structure */	kfree (au1550_mtd);}module_exit(au1550_cleanup);#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("Embedded Edge, LLC");MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");

⌨️ 快捷键说明

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