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

📄 ide-cris.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $ * * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. * Copyright (c) 2000-2005 Axis Communications AB * * Authors:    Bjorn Wesen        (initial version) *             Mikael Starvik     (crisv32 port) *//* Regarding DMA: * * There are two forms of DMA - "DMA handshaking" between the interface and the drive, * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's * something built-in in the Etrax. However only some drives support the DMA-mode handshaking * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the * device can't do DMA handshaking for some stupid reason. We don't need to do that. */#undef REALLY_SLOW_IO           /* most systems can safely undef this */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/blkdev.h>#include <linux/hdreg.h>#include <linux/ide.h>#include <linux/init.h>#include <asm/io.h>#include <asm/dma.h>/* number of DMA descriptors */#define MAX_DMA_DESCRS 64/* number of times to retry busy-flags when reading/writing IDE-registers * this can't be too high because a hung harddisk might cause the watchdog * to trigger (sometimes INB and OUTB are called with irq's disabled) */#define IDE_REGISTER_TIMEOUT 300#define LOWDB(x)#define D(x)enum /* Transfer types */{	TYPE_PIO,	TYPE_DMA,	TYPE_UDMA};/* CRISv32 specifics */#ifdef CONFIG_ETRAX_ARCH_V32#include <asm/arch/hwregs/ata_defs.h>#include <asm/arch/hwregs/dma_defs.h>#include <asm/arch/hwregs/dma.h>#include <asm/arch/pinmux.h>#define ATA_UDMA2_CYC    2#define ATA_UDMA2_DVS    3#define ATA_UDMA1_CYC    2#define ATA_UDMA1_DVS    4#define ATA_UDMA0_CYC    4#define ATA_UDMA0_DVS    6#define ATA_DMA2_STROBE  7#define ATA_DMA2_HOLD    1#define ATA_DMA1_STROBE  8#define ATA_DMA1_HOLD    3#define ATA_DMA0_STROBE 25#define ATA_DMA0_HOLD   19#define ATA_PIO4_SETUP   3#define ATA_PIO4_STROBE  7#define ATA_PIO4_HOLD    1#define ATA_PIO3_SETUP   3#define ATA_PIO3_STROBE  9#define ATA_PIO3_HOLD    3#define ATA_PIO2_SETUP   3#define ATA_PIO2_STROBE 13#define ATA_PIO2_HOLD    5#define ATA_PIO1_SETUP   5#define ATA_PIO1_STROBE 23#define ATA_PIO1_HOLD    9#define ATA_PIO0_SETUP   9#define ATA_PIO0_STROBE 39#define ATA_PIO0_HOLD    9intcris_ide_ack_intr(ide_hwif_t* hwif){	reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2,	                         int, hwif->io_ports[0]);	REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel);	return 1;}static inline intcris_ide_busy(void){	reg_ata_rs_stat_data stat_data;	stat_data = REG_RD(ata, regi_ata, rs_stat_data);	return stat_data.busy;}static inline intcris_ide_ready(void){	return !cris_ide_busy();}static inline intcris_ide_data_available(unsigned short* data){	reg_ata_rs_stat_data stat_data;	stat_data = REG_RD(ata, regi_ata, rs_stat_data);	*data = stat_data.data;	return stat_data.dav;}static voidcris_ide_write_command(unsigned long command){	REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */}static voidcris_ide_set_speed(int type, int setup, int strobe, int hold){	reg_ata_rw_ctrl0 ctrl0 = REG_RD(ata, regi_ata, rw_ctrl0);	reg_ata_rw_ctrl1 ctrl1 = REG_RD(ata, regi_ata, rw_ctrl1);	if (type == TYPE_PIO) {		ctrl0.pio_setup = setup;		ctrl0.pio_strb = strobe;		ctrl0.pio_hold = hold;	} else if (type == TYPE_DMA) {		ctrl0.dma_strb = strobe;		ctrl0.dma_hold = hold;	} else if (type == TYPE_UDMA) {		ctrl1.udma_tcyc = setup;		ctrl1.udma_tdvs = strobe;	}	REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);	REG_WR(ata, regi_ata, rw_ctrl1, ctrl1);}static unsigned longcris_ide_base_address(int bus){	reg_ata_rw_ctrl2 ctrl2 = {0};	ctrl2.sel = bus;	return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);}static unsigned longcris_ide_reg_addr(unsigned long addr, int cs0, int cs1){	reg_ata_rw_ctrl2 ctrl2 = {0};	ctrl2.addr = addr;	ctrl2.cs1 = cs1;	ctrl2.cs0 = cs0;	return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);}static __init voidcris_ide_reset(unsigned val){	reg_ata_rw_ctrl0 ctrl0 = {0};	ctrl0.rst = val ? regk_ata_active : regk_ata_inactive;	REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);}static __init voidcris_ide_init(void){	reg_ata_rw_ctrl0 ctrl0 = {0};	reg_ata_rw_intr_mask intr_mask = {0};	ctrl0.en = regk_ata_yes;	REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);	intr_mask.bus0 = regk_ata_yes;	intr_mask.bus1 = regk_ata_yes;	intr_mask.bus2 = regk_ata_yes;	intr_mask.bus3 = regk_ata_yes;	REG_WR(ata, regi_ata, rw_intr_mask, intr_mask);	crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);	crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);	crisv32_pinmux_alloc_fixed(pinmux_ata);	crisv32_pinmux_alloc_fixed(pinmux_ata0);	crisv32_pinmux_alloc_fixed(pinmux_ata1);	crisv32_pinmux_alloc_fixed(pinmux_ata2);	crisv32_pinmux_alloc_fixed(pinmux_ata3);	DMA_RESET(regi_dma2);	DMA_ENABLE(regi_dma2);	DMA_RESET(regi_dma3);	DMA_ENABLE(regi_dma3);	DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2);	DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);}static dma_descr_context mycontext __attribute__ ((__aligned__(32)));#define cris_dma_descr_type dma_descr_data#define cris_pio_read regk_ata_rd#define cris_ultra_mask 0x7#define MAX_DESCR_SIZE 0xffffffffULstatic unsigned longcris_ide_get_reg(unsigned long reg){	return (reg & 0x0e000000) >> 25;}static voidcris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last){	d->buf = (char*)virt_to_phys(buf);	d->after = d->buf + len;	d->eol = last;}static voidcris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len){	reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG);	reg_ata_rw_trf_cnt trf_cnt = {0};	mycontext.saved_data = (dma_descr_data*)virt_to_phys(d);	mycontext.saved_data_buf = d->buf;	/* start the dma channel */	DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext));	/* initiate a multi word dma read using PIO handshaking */	trf_cnt.cnt = len >> 1;	/* Due to a "feature" the transfer count has to be one extra word for UDMA. */	if (type == TYPE_UDMA)		trf_cnt.cnt++;	REG_WR(ata, regi_ata, rw_trf_cnt, trf_cnt);	ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr;	ctrl2.trf_mode = regk_ata_dma;	ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio :	            type == TYPE_DMA ? regk_ata_dma : regk_ata_udma;	ctrl2.multi = regk_ata_yes;	ctrl2.dma_size = regk_ata_word;	REG_WR(ata, regi_ata, rw_ctrl2, ctrl2);}static voidcris_ide_wait_dma(int dir){	reg_dma_rw_stat status;	do	{		status = REG_RD(dma, dir ? regi_dma3 : regi_dma2, rw_stat);	} while(status.list_state != regk_dma_data_at_eol);}static int cris_dma_test_irq(ide_drive_t *drive){	int intr = REG_RD_INT(ata, regi_ata, r_intr);	reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG);	return intr & (1 << ctrl2.sel) ? 1 : 0;}static void cris_ide_initialize_dma(int dir){}#else/* CRISv10 specifics */#include <asm/arch/svinto.h>#include <asm/arch/io_interface_mux.h>/* PIO timing (in R_ATA_CONFIG) * *                        _____________________________ * ADDRESS :     ________/ * *                            _______________ * DIOR    :     ____________/               \__________ * *                               _______________ * DATA    :     XXXXXXXXXXXXXXXX_______________XXXXXXXX * * * DIOR is unbuffered while address and data is buffered. * This creates two problems: * 1. The DIOR pulse is to early (because it is unbuffered) * 2. The rise time of DIOR is long * * There are at least three different plausible solutions * 1. Use a pad capable of larger currents in Etrax * 2. Use an external buffer * 3. Make the strobe pulse longer * * Some of the strobe timings below are modified to compensate * for this. This implies a slight performance decrease. * * THIS SHOULD NEVER BE CHANGED! * * TODO: Is this true for the latest LX boards still ? */#define ATA_UDMA2_CYC    0 /* No UDMA supported, just to make it compile. */#define ATA_UDMA2_DVS    0#define ATA_UDMA1_CYC    0#define ATA_UDMA1_DVS    0#define ATA_UDMA0_CYC    0#define ATA_UDMA0_DVS    0#define ATA_DMA2_STROBE  4#define ATA_DMA2_HOLD    0#define ATA_DMA1_STROBE  4#define ATA_DMA1_HOLD    1#define ATA_DMA0_STROBE 12#define ATA_DMA0_HOLD    9#define ATA_PIO4_SETUP   1#define ATA_PIO4_STROBE  5#define ATA_PIO4_HOLD    0#define ATA_PIO3_SETUP   1#define ATA_PIO3_STROBE  5#define ATA_PIO3_HOLD    1#define ATA_PIO2_SETUP   1#define ATA_PIO2_STROBE  6#define ATA_PIO2_HOLD    2#define ATA_PIO1_SETUP   2#define ATA_PIO1_STROBE 11#define ATA_PIO1_HOLD    4#define ATA_PIO0_SETUP   4#define ATA_PIO0_STROBE 19#define ATA_PIO0_HOLD    4intcris_ide_ack_intr(ide_hwif_t* hwif){	return 1;}static inline intcris_ide_busy(void){	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ;}static inline intcris_ide_ready(void){	return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ;}static inline intcris_ide_data_available(unsigned short* data){	unsigned long status = *R_ATA_STATUS_DATA;	*data = (unsigned short)status;	return status & IO_MASK(R_ATA_STATUS_DATA, dav);}static voidcris_ide_write_command(unsigned long command){	*R_ATA_CTRL_DATA = command;}static voidcris_ide_set_speed(int type, int setup, int strobe, int hold){	static int pio_setup = ATA_PIO4_SETUP;	static int pio_strobe = ATA_PIO4_STROBE;	static int pio_hold = ATA_PIO4_HOLD;	static int dma_strobe = ATA_DMA2_STROBE;	static int dma_hold = ATA_DMA2_HOLD;	if (type == TYPE_PIO) {		pio_setup = setup;		pio_strobe = strobe;		pio_hold = hold;	} else if (type == TYPE_DMA) {		dma_strobe = strobe;	  dma_hold = hold;	}	*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |	  IO_FIELD( R_ATA_CONFIG, dma_strobe, dma_strobe ) |		IO_FIELD( R_ATA_CONFIG, dma_hold,   dma_hold ) |		IO_FIELD( R_ATA_CONFIG, pio_setup,  pio_setup ) |		IO_FIELD( R_ATA_CONFIG, pio_strobe, pio_strobe ) |		IO_FIELD( R_ATA_CONFIG, pio_hold,   pio_hold ) );}static unsigned longcris_ide_base_address(int bus){	return IO_FIELD(R_ATA_CTRL_DATA, sel, bus);}static unsigned longcris_ide_reg_addr(unsigned long addr, int cs0, int cs1){	return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) |	       IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) |	       IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1);}static __init voidcris_ide_reset(unsigned val){#ifdef CONFIG_ETRAX_IDE_G27_RESET	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val);#endif#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET	REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val);#endif#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET	REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val);#endif#ifdef CONFIG_ETRAX_IDE_PB7_RESET	port_pb_dir_shadow = port_pb_dir_shadow |		IO_STATE(R_PORT_PB_DIR, dir7, output);	*R_PORT_PB_DIR = port_pb_dir_shadow;	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, val);#endif}static __init voidcris_ide_init(void){	volatile unsigned int dummy;	*R_ATA_CTRL_DATA = 0;	*R_ATA_TRANSFER_CNT = 0;	*R_ATA_CONFIG = 0;	if (cris_request_io_interface(if_ata, "ETRAX100LX IDE")) {		printk(KERN_CRIT "ide: Failed to get IO interface\n");		return;	} else if (cris_request_dma(ATA_TX_DMA_NBR,		                          "ETRAX100LX IDE TX",		                          DMA_VERBOSE_ON_ERROR,		                          dma_ata)) {		cris_free_io_interface(if_ata);		printk(KERN_CRIT "ide: Failed to get Tx DMA channel\n");		return;	} else if (cris_request_dma(ATA_RX_DMA_NBR,		                          "ETRAX100LX IDE RX",		                          DMA_VERBOSE_ON_ERROR,		                          dma_ata)) {		cris_free_dma(ATA_TX_DMA_NBR, "ETRAX100LX IDE Tx");		cris_free_io_interface(if_ata);		printk(KERN_CRIT "ide: Failed to get Rx DMA channel\n");		return;	}	/* make a dummy read to set the ata controller in a proper state */	dummy = *R_ATA_STATUS_DATA;	*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ));	*R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw,   read) |	                     IO_FIELD( R_ATA_CTRL_DATA, addr, 1   ) );	while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/	*R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |	                     IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |	                     IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |	                     IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );	/* reset the dma channels we will use */	RESET_DMA(ATA_TX_DMA_NBR);	RESET_DMA(ATA_RX_DMA_NBR);	WAIT_DMA(ATA_TX_DMA_NBR);	WAIT_DMA(ATA_RX_DMA_NBR);}#define cris_dma_descr_type etrax_dma_descr#define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read)#define cris_ultra_mask 0x0#define MAX_DESCR_SIZE 0x10000ULstatic unsigned longcris_ide_get_reg(unsigned long reg){	return (reg & 0x0e000000) >> 25;}static voidcris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last){	d->buf = virt_to_phys(buf);	d->sw_len = len == MAX_DESCR_SIZE ? 0 : len;	if (last)		d->ctrl |= d_eol;}static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len){	unsigned long cmd;	if (dir) {		/* need to do this before RX DMA due to a chip bug		 * it is enough to just flush the part of the cache that		 * corresponds to the buffers we start, but since HD transfers		 * usually are more than 8 kB, it is easier to optimize for the		 * normal case and just flush the entire cache. its the only		 * way to be sure! (OB movie quote)		 */		flush_etrax_cache();		*R_DMA_CH3_FIRST = virt_to_phys(d);		*R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);	} else {		*R_DMA_CH2_FIRST = virt_to_phys(d);		*R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);	}	/* initiate a multi word dma read using DMA handshaking */	*R_ATA_TRANSFER_CNT =		IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1);	cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write);	cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) :	                          IO_STATE(R_ATA_CTRL_DATA, handsh, dma);	*R_ATA_CTRL_DATA =		cmd |		IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |		IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma)  |		IO_STATE(R_ATA_CTRL_DATA, multi,    on)   |		IO_STATE(R_ATA_CTRL_DATA, dma_size, word);}static voidcris_ide_wait_dma(int dir){	if (dir)		WAIT_DMA(ATA_RX_DMA_NBR);	else		WAIT_DMA(ATA_TX_DMA_NBR);}static int cris_dma_test_irq(ide_drive_t *drive){	int intr = *R_IRQ_MASK0_RD;	int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, IDE_DATA_REG);

⌨️ 快捷键说明

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