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

📄 au1xxx-ide.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/ide/mips/au1xxx-ide.c  version 01.30.00        Aug. 02 2005 * * BRIEF MODULE DESCRIPTION * AMD Alchemy Au1xxx IDE interface routines over the Static Bus * * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE *       Interface and Linux Device Driver" Application Note. */#undef REALLY_SLOW_IO           /* most systems can safely undef this */#include <linux/types.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/init.h>#include <linux/ide.h>#include <linux/sysdev.h>#include <linux/dma-mapping.h>#include "ide-timing.h"#include <asm/io.h>#include <asm/mach-au1x00/au1xxx.h>#include <asm/mach-au1x00/au1xxx_dbdma.h>#include <asm/mach-au1x00/au1xxx_ide.h>#define DRV_NAME	"au1200-ide"#define DRV_VERSION	"1.0"#define DRV_AUTHOR	"Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"/* enable the burstmode in the dbdma */#define IDE_AU1XXX_BURSTMODE	1static _auide_hwif auide_hwif;static int dbdma_init_done;#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)void auide_insw(unsigned long port, void *addr, u32 count){	_auide_hwif *ahwif = &auide_hwif;	chan_tab_t *ctp;	au1x_ddma_desc_t *dp;	if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1, 			   DDMA_FLAGS_NOIE)) {		printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);		return;	}	ctp = *((chan_tab_t **)ahwif->rx_chan);	dp = ctp->cur_ptr;	while (dp->dscr_cmd0 & DSCR_CMD0_V)		;	ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);}void auide_outsw(unsigned long port, void *addr, u32 count){	_auide_hwif *ahwif = &auide_hwif;	chan_tab_t *ctp;	au1x_ddma_desc_t *dp;	if(!put_source_flags(ahwif->tx_chan, (void*)addr,			     count << 1, DDMA_FLAGS_NOIE)) {		printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);		return;	}	ctp = *((chan_tab_t **)ahwif->tx_chan);	dp = ctp->cur_ptr;	while (dp->dscr_cmd0 & DSCR_CMD0_V)		;	ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);}#endifstatic void auide_tune_drive(ide_drive_t *drive, byte pio){	int mem_sttime;	int mem_stcfg;	u8 speed;	/* get the best pio mode for the drive */	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);	printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",	       drive->name, pio);	mem_sttime = 0;	mem_stcfg  = au_readl(MEM_STCFG2);	/* set pio mode! */	switch(pio) {	case 0:		mem_sttime = SBC_IDE_TIMING(PIO0);		/* set configuration for RCS2# */		mem_stcfg |= TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;		break;	case 1:		mem_sttime = SBC_IDE_TIMING(PIO1);		/* set configuration for RCS2# */		mem_stcfg |= TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;		break;	case 2:		mem_sttime = SBC_IDE_TIMING(PIO2);		/* set configuration for RCS2# */		mem_stcfg &= ~TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;		break;	case 3:		mem_sttime = SBC_IDE_TIMING(PIO3);		/* set configuration for RCS2# */		mem_stcfg &= ~TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;		break;	case 4:		mem_sttime = SBC_IDE_TIMING(PIO4);		/* set configuration for RCS2# */		mem_stcfg &= ~TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;		break;	}	au_writel(mem_sttime,MEM_STTIME2);	au_writel(mem_stcfg,MEM_STCFG2);	speed = pio + XFER_PIO_0;	ide_config_drive_speed(drive, speed);}static int auide_tune_chipset (ide_drive_t *drive, u8 speed){	int mem_sttime;	int mem_stcfg;	unsigned long mode;#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA	if (ide_use_dma(drive))		mode = ide_dma_speed(drive, 0);#endif	mem_sttime = 0;	mem_stcfg  = au_readl(MEM_STCFG2);	if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {		auide_tune_drive(drive, speed - XFER_PIO_0);		return 0;	}	      	switch(speed) {#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA	case XFER_MW_DMA_2:		mem_sttime = SBC_IDE_TIMING(MDMA2);		/* set configuration for RCS2# */		mem_stcfg &= ~TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;		mode = XFER_MW_DMA_2;		break;	case XFER_MW_DMA_1:		mem_sttime = SBC_IDE_TIMING(MDMA1);		/* set configuration for RCS2# */		mem_stcfg &= ~TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;		mode = XFER_MW_DMA_1;		break;	case XFER_MW_DMA_0:		mem_sttime = SBC_IDE_TIMING(MDMA0);		/* set configuration for RCS2# */		mem_stcfg |= TS_MASK;		mem_stcfg &= ~TCSOE_MASK;		mem_stcfg &= ~TOECS_MASK;		mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;		mode = XFER_MW_DMA_0;		break;#endif	default:		return 1;	}		if (ide_config_drive_speed(drive, mode))		return 1;	au_writel(mem_sttime,MEM_STTIME2);	au_writel(mem_stcfg,MEM_STCFG2);	return 0;}/* * Multi-Word DMA + DbDMA functions */#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMAstatic int auide_build_sglist(ide_drive_t *drive,  struct request *rq){	ide_hwif_t *hwif = drive->hwif;	_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;	struct scatterlist *sg = hwif->sg_table;	ide_map_sg(drive, rq);	if (rq_data_dir(rq) == READ)		hwif->sg_dma_direction = DMA_FROM_DEVICE;	else		hwif->sg_dma_direction = DMA_TO_DEVICE;	return dma_map_sg(ahwif->dev, sg, hwif->sg_nents,			  hwif->sg_dma_direction);}static int auide_build_dmatable(ide_drive_t *drive){	int i, iswrite, count = 0;	ide_hwif_t *hwif = HWIF(drive);	struct request *rq = HWGROUP(drive)->rq;	_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;	struct scatterlist *sg;	iswrite = (rq_data_dir(rq) == WRITE);	/* Save for interrupt context */	ahwif->drive = drive;	/* Build sglist */	hwif->sg_nents = i = auide_build_sglist(drive, rq);	if (!i)		return 0;	/* fill the descriptors */	sg = hwif->sg_table;	while (i && sg_dma_len(sg)) {		u32 cur_addr;		u32 cur_len;		cur_addr = sg_dma_address(sg);		cur_len = sg_dma_len(sg);		while (cur_len) {			u32 flags = DDMA_FLAGS_NOIE;			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;			if (++count >= PRD_ENTRIES) {				printk(KERN_WARNING "%s: DMA table too small\n",				       drive->name);				goto use_pio_instead;			}			/* Lets enable intr for the last descriptor only */			if (1==i)				flags = DDMA_FLAGS_IE;			else				flags = DDMA_FLAGS_NOIE;			if (iswrite) {				if(!put_source_flags(ahwif->tx_chan, 						     (void*)(page_address(sg->page) 							     + sg->offset), 						     tc, flags)) { 					printk(KERN_ERR "%s failed %d\n", 					       __FUNCTION__, __LINE__);				}			} else 			{				if(!put_dest_flags(ahwif->rx_chan, 						   (void*)(page_address(sg->page) 							   + sg->offset), 						   tc, flags)) { 					printk(KERN_ERR "%s failed %d\n", 					       __FUNCTION__, __LINE__);				}			}			cur_addr += tc;			cur_len -= tc;		}		sg++;		i--;	}	if (count)		return 1; use_pio_instead:	dma_unmap_sg(ahwif->dev,		     hwif->sg_table,		     hwif->sg_nents,		     hwif->sg_dma_direction);	return 0; /* revert to PIO for this request */}static int auide_dma_end(ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;	if (hwif->sg_nents) {		dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents,			     hwif->sg_dma_direction);		hwif->sg_nents = 0;	}	return 0;}static void auide_dma_start(ide_drive_t *drive ){}static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command){	/* issue cmd to drive */	ide_execute_command(drive, command, &ide_dma_intr,			    (2*WAIT_CMD), NULL);}static int auide_dma_setup(ide_drive_t *drive){       		struct request *rq = HWGROUP(drive)->rq;	if (!auide_build_dmatable(drive)) {		ide_map_sg(drive, rq);		return 1;	}	drive->waiting_for_dma = 1;	return 0;}static int auide_dma_check(ide_drive_t *drive){	u8 speed;#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA	if( dbdma_init_done == 0 ){		auide_hwif.white_list = ide_in_drive_list(drive->id,							  dma_white_list);		auide_hwif.black_list = ide_in_drive_list(drive->id,							  dma_black_list);		auide_hwif.drive = drive;		auide_ddma_init(&auide_hwif);		dbdma_init_done = 1;	}#endif

⌨️ 快捷键说明

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