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

📄 pata_bf54x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * File:         drivers/ata/pata_bf54x.c * Author:       Sonic Zhang <sonic.zhang@analog.com> * * Created: * Description:  PATA Driver for blackfin 54x * * Modified: *               Copyright 2007 Analog Devices Inc. * * Bugs:         Enter bugs at http://blackfin.uclinux.org/ * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see the file COPYING, or write * to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <linux/libata.h>#include <linux/platform_device.h>#include <asm/dma.h>#include <asm/gpio.h>#include <asm/portmux.h>#define DRV_NAME		"pata-bf54x"#define DRV_VERSION		"0.9"#define ATA_REG_CTRL		0x0E#define ATA_REG_ALTSTATUS	ATA_REG_CTRL/* These are the offset of the controller's registers */#define ATAPI_OFFSET_CONTROL		0x00#define ATAPI_OFFSET_STATUS		0x04#define ATAPI_OFFSET_DEV_ADDR		0x08#define ATAPI_OFFSET_DEV_TXBUF		0x0c#define ATAPI_OFFSET_DEV_RXBUF		0x10#define ATAPI_OFFSET_INT_MASK		0x14#define ATAPI_OFFSET_INT_STATUS		0x18#define ATAPI_OFFSET_XFER_LEN		0x1c#define ATAPI_OFFSET_LINE_STATUS	0x20#define ATAPI_OFFSET_SM_STATE		0x24#define ATAPI_OFFSET_TERMINATE		0x28#define ATAPI_OFFSET_PIO_TFRCNT		0x2c#define ATAPI_OFFSET_DMA_TFRCNT		0x30#define ATAPI_OFFSET_UMAIN_TFRCNT	0x34#define ATAPI_OFFSET_UDMAOUT_TFRCNT	0x38#define ATAPI_OFFSET_REG_TIM_0		0x40#define ATAPI_OFFSET_PIO_TIM_0		0x44#define ATAPI_OFFSET_PIO_TIM_1		0x48#define ATAPI_OFFSET_MULTI_TIM_0	0x50#define ATAPI_OFFSET_MULTI_TIM_1	0x54#define ATAPI_OFFSET_MULTI_TIM_2	0x58#define ATAPI_OFFSET_ULTRA_TIM_0	0x60#define ATAPI_OFFSET_ULTRA_TIM_1	0x64#define ATAPI_OFFSET_ULTRA_TIM_2	0x68#define ATAPI_OFFSET_ULTRA_TIM_3	0x6c#define ATAPI_GET_CONTROL(base)\	bfin_read16(base + ATAPI_OFFSET_CONTROL)#define ATAPI_SET_CONTROL(base, val)\	bfin_write16(base + ATAPI_OFFSET_CONTROL, val)#define ATAPI_GET_STATUS(base)\	bfin_read16(base + ATAPI_OFFSET_STATUS)#define ATAPI_GET_DEV_ADDR(base)\	bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)#define ATAPI_SET_DEV_ADDR(base, val)\	bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)#define ATAPI_GET_DEV_TXBUF(base)\	bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)#define ATAPI_SET_DEV_TXBUF(base, val)\	bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)#define ATAPI_GET_DEV_RXBUF(base)\	bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)#define ATAPI_SET_DEV_RXBUF(base, val)\	bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)#define ATAPI_GET_INT_MASK(base)\	bfin_read16(base + ATAPI_OFFSET_INT_MASK)#define ATAPI_SET_INT_MASK(base, val)\	bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)#define ATAPI_GET_INT_STATUS(base)\	bfin_read16(base + ATAPI_OFFSET_INT_STATUS)#define ATAPI_SET_INT_STATUS(base, val)\	bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)#define ATAPI_GET_XFER_LEN(base)\	bfin_read16(base + ATAPI_OFFSET_XFER_LEN)#define ATAPI_SET_XFER_LEN(base, val)\	bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)#define ATAPI_GET_LINE_STATUS(base)\	bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)#define ATAPI_GET_SM_STATE(base)\	bfin_read16(base + ATAPI_OFFSET_SM_STATE)#define ATAPI_GET_TERMINATE(base)\	bfin_read16(base + ATAPI_OFFSET_TERMINATE)#define ATAPI_SET_TERMINATE(base, val)\	bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)#define ATAPI_GET_PIO_TFRCNT(base)\	bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)#define ATAPI_GET_DMA_TFRCNT(base)\	bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)#define ATAPI_GET_UMAIN_TFRCNT(base)\	bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)#define ATAPI_GET_UDMAOUT_TFRCNT(base)\	bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)#define ATAPI_GET_REG_TIM_0(base)\	bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)#define ATAPI_SET_REG_TIM_0(base, val)\	bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)#define ATAPI_GET_PIO_TIM_0(base)\	bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)#define ATAPI_SET_PIO_TIM_0(base, val)\	bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)#define ATAPI_GET_PIO_TIM_1(base)\	bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)#define ATAPI_SET_PIO_TIM_1(base, val)\	bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)#define ATAPI_GET_MULTI_TIM_0(base)\	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)#define ATAPI_SET_MULTI_TIM_0(base, val)\	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)#define ATAPI_GET_MULTI_TIM_1(base)\	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)#define ATAPI_SET_MULTI_TIM_1(base, val)\	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)#define ATAPI_GET_MULTI_TIM_2(base)\	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)#define ATAPI_SET_MULTI_TIM_2(base, val)\	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)#define ATAPI_GET_ULTRA_TIM_0(base)\	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)#define ATAPI_SET_ULTRA_TIM_0(base, val)\	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)#define ATAPI_GET_ULTRA_TIM_1(base)\	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)#define ATAPI_SET_ULTRA_TIM_1(base, val)\	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)#define ATAPI_GET_ULTRA_TIM_2(base)\	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)#define ATAPI_SET_ULTRA_TIM_2(base, val)\	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)#define ATAPI_GET_ULTRA_TIM_3(base)\	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)#define ATAPI_SET_ULTRA_TIM_3(base, val)\	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)/** * PIO Mode - Frequency compatibility *//* mode: 0         1         2         3         4 */static const u32 pio_fsclk[] ={ 33333333, 33333333, 33333333, 33333333, 33333333 };/** * MDMA Mode - Frequency compatibility *//*               mode:      0         1         2        */static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };/** * UDMA Mode - Frequency compatibility * * UDMA5 - 100 MB/s   - SCLK  = 133 MHz * UDMA4 - 66 MB/s    - SCLK >=  80 MHz * UDMA3 - 44.4 MB/s  - SCLK >=  50 MHz * UDMA2 - 33 MB/s    - SCLK >=  40 MHz *//* mode: 0         1         2         3         4          5 */static const u32 udma_fsclk[] ={ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };/** * Register transfer timing table *//*               mode:       0    1    2    3    4    *//* Cycle Time                     */static const u32 reg_t0min[]   = { 600, 383, 330, 180, 120 };/* DIOR/DIOW to end cycle         */static const u32 reg_t2min[]   = { 290, 290, 290, 70,  25  };/* DIOR/DIOW asserted pulse width */static const u32 reg_teocmin[] = { 290, 290, 290, 80,  70  };/** * PIO timing table *//*               mode:       0    1    2    3    4    *//* Cycle Time                     */static const u32 pio_t0min[]   = { 600, 383, 240, 180, 120 };/* Address valid to DIOR/DIORW    */static const u32 pio_t1min[]   = { 70,  50,  30,  30,  25  };/* DIOR/DIOW to end cycle         */static const u32 pio_t2min[]   = { 165, 125, 100, 80,  70  };/* DIOR/DIOW asserted pulse width */static const u32 pio_teocmin[] = { 165, 125, 100, 70,  25  };/* DIOW data hold                 */static const u32 pio_t4min[]   = { 30,  20,  15,  10,  10  };/* ****************************************************************** * Multiword DMA timing table * ****************************************************************** *//*               mode:       0   1    2        *//* Cycle Time                     */static const u32 mdma_t0min[]  = { 480, 150, 120 };/* DIOR/DIOW asserted pulse width */static const u32 mdma_tdmin[]  = { 215, 80,  70  };/* DMACK to read data released    */static const u32 mdma_thmin[]  = { 20,  15,  10  };/* DIOR/DIOW to DMACK hold        */static const u32 mdma_tjmin[]  = { 20,  5,   5   };/* DIOR negated pulse width       */static const u32 mdma_tkrmin[] = { 50,  50,  25  };/* DIOR negated pulse width       */static const u32 mdma_tkwmin[] = { 215, 50,  25  };/* CS[1:0] valid to DIOR/DIOW     */static const u32 mdma_tmmin[]  = { 50,  30,  25  };/* DMACK to read data released    */static const u32 mdma_tzmax[]  = { 20,  25,  25  };/** * Ultra DMA timing table *//*               mode:         0    1    2    3    4    5       */static const u32 udma_tcycmin[]  = { 112, 73,  54,  39,  25,  17 };static const u32 udma_tdvsmin[]  = { 70,  48,  31,  20,  7,   5  };static const u32 udma_tenvmax[]  = { 70,  70,  70,  55,  55,  50 };static const u32 udma_trpmin[]   = { 160, 125, 100, 100, 100, 85 };static const u32 udma_tmin[]     = { 5,   5,   5,   5,   3,   3  };static const u32 udma_tmlimin = 20;static const u32 udma_tzahmin = 20;static const u32 udma_tenvmin = 20;static const u32 udma_tackmin = 20;static const u32 udma_tssmin = 50;/** * *	Function:       num_clocks_min * *	Description: *	calculate number of SCLK cycles to meet minimum timing */static unsigned short num_clocks_min(unsigned long tmin,				unsigned long fsclk){	unsigned long tmp ;	unsigned short result;	tmp = tmin * (fsclk/1000/1000) / 1000;	result = (unsigned short)tmp;	if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {		result++;	}	return result;}/** *	bfin_set_piomode - Initialize host controller PATA PIO timings *	@ap: Port whose timings we are configuring *	@adev: um * *	Set PIO mode for device. * *	LOCKING: *	None (inherited from caller). */static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev){	int mode = adev->pio_mode - XFER_PIO_0;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	unsigned int fsclk = get_sclk();	unsigned short teoc_reg, t2_reg, teoc_pio;	unsigned short t4_reg, t2_pio, t1_reg;	unsigned short n0, n6, t6min = 5;	/* the most restrictive timing value is t6 and tc, the DIOW - data hold	* If one SCLK pulse is longer than this minimum value then register	* transfers cannot be supported at this frequency.	*/	n6 = num_clocks_min(t6min, fsclk);	if (mode >= 0 && mode <= 4 && n6 >= 1) {		pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);		/* calculate the timing values for register transfers. */		while (mode > 0 && pio_fsclk[mode] > fsclk)			mode--;		/* DIOR/DIOW to end cycle time */		t2_reg = num_clocks_min(reg_t2min[mode], fsclk);		/* DIOR/DIOW asserted pulse width */		teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);		/* Cycle Time */		n0  = num_clocks_min(reg_t0min[mode], fsclk);		/* increase t2 until we meed the minimum cycle length */		if (t2_reg + teoc_reg < n0)			t2_reg = n0 - teoc_reg;		/* calculate the timing values for pio transfers. */		/* DIOR/DIOW to end cycle time */		t2_pio = num_clocks_min(pio_t2min[mode], fsclk);		/* DIOR/DIOW asserted pulse width */		teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);		/* Cycle Time */		n0  = num_clocks_min(pio_t0min[mode], fsclk);		/* increase t2 until we meed the minimum cycle length */		if (t2_pio + teoc_pio < n0)			t2_pio = n0 - teoc_pio;		/* Address valid to DIOR/DIORW */		t1_reg = num_clocks_min(pio_t1min[mode], fsclk);		/* DIOW data hold */		t4_reg = num_clocks_min(pio_t4min[mode], fsclk);		ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));		ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));		ATAPI_SET_PIO_TIM_1(base, teoc_pio);		if (mode > 2) {			ATAPI_SET_CONTROL(base,				ATAPI_GET_CONTROL(base) | IORDY_EN);		} else {			ATAPI_SET_CONTROL(base,				ATAPI_GET_CONTROL(base) & ~IORDY_EN);		}		/* Disable host ATAPI PIO interrupts */		ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)			& ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));		SSYNC();	}}/** *	bfin_set_dmamode - Initialize host controller PATA DMA timings *	@ap: Port whose timings we are configuring *	@adev: um *	@udma: udma mode, 0 - 6 * *	Set UDMA mode for device. * *	LOCKING: *	None (inherited from caller). */static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev){	int mode;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	unsigned long fsclk = get_sclk();	unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;	unsigned short tm, td, tkr, tkw, teoc, th;	unsigned short n0, nf, tfmin = 5;	unsigned short nmin, tcyc;	mode = adev->dma_mode - XFER_UDMA_0;	if (mode >= 0 && mode <= 5) {		pr_debug("set udmamode: mode=%d\n", mode);		/* the most restrictive timing value is t6 and tc,		 * the DIOW - data hold. If one SCLK pulse is longer		 * than this minimum value then register		 * transfers cannot be supported at this frequency.		 */		while (mode > 0 && udma_fsclk[mode] > fsclk)			mode--;		nmin = num_clocks_min(udma_tmin[mode], fsclk);		if (nmin >= 1) {			/* calculate the timing values for Ultra DMA. */			tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);			tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);			tcyc_tdvs = 2;			/* increase tcyc - tdvs (tcyc_tdvs) until we meed			 * the minimum cycle length			 */			if (tdvs + tcyc_tdvs < tcyc)				tcyc_tdvs = tcyc - tdvs;			/* Mow assign the values required for the timing			 * registers			 */			if (tcyc_tdvs < 2)				tcyc_tdvs = 2;			if (tdvs < 2)				tdvs = 2;			tack = num_clocks_min(udma_tackmin, fsclk);			tss = num_clocks_min(udma_tssmin, fsclk);			tmli = num_clocks_min(udma_tmlimin, fsclk);			tzah = num_clocks_min(udma_tzahmin, fsclk);			trp = num_clocks_min(udma_trpmin[mode], fsclk);			tenv = num_clocks_min(udma_tenvmin, fsclk);			if (tenv <= udma_tenvmax[mode]) {				ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));				ATAPI_SET_ULTRA_TIM_1(base,					(tcyc_tdvs<<8 | tdvs));				ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));				ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));				/* Enable host ATAPI Untra DMA interrupts */				ATAPI_SET_INT_MASK(base,					ATAPI_GET_INT_MASK(base)					| UDMAIN_DONE_MASK					| UDMAOUT_DONE_MASK					| UDMAIN_TERM_MASK					| UDMAOUT_TERM_MASK);			}		}	}	mode = adev->dma_mode - XFER_MW_DMA_0;	if (mode >= 0 && mode <= 2) {		pr_debug("set mdmamode: mode=%d\n", mode);		/* the most restrictive timing value is tf, the DMACK to		 * read data released. If one SCLK pulse is longer than		 * this maximum value then the MDMA mode		 * cannot be supported at this frequency.		 */		while (mode > 0 && mdma_fsclk[mode] > fsclk)			mode--;		nf = num_clocks_min(tfmin, fsclk);		if (nf >= 1) {			/* calculate the timing values for Multi-word DMA. */			/* DIOR/DIOW asserted pulse width */			td = num_clocks_min(mdma_tdmin[mode], fsclk);			/* DIOR negated pulse width */			tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);			/* Cycle Time */			n0  = num_clocks_min(mdma_t0min[mode], fsclk);			/* increase tk until we meed the minimum cycle length */			if (tkw + td < n0)				tkw = n0 - td;			/* DIOR negated pulse width - read */			tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);			/* CS{1:0] valid to DIOR/DIOW */			tm = num_clocks_min(mdma_tmmin[mode], fsclk);			/* DIOR/DIOW to DMACK hold */			teoc = num_clocks_min(mdma_tjmin[mode], fsclk);			/* DIOW Data hold */			th = num_clocks_min(mdma_thmin[mode], fsclk);			ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));			ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));			ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));			/* Enable host ATAPI Multi DMA interrupts */			ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)				| MULTI_DONE_MASK | MULTI_TERM_MASK);			SSYNC();		}	}	return;}/** * *    Function:       wait_complete * *    Description:    Waits the interrupt from device * */static inline void wait_complete(void __iomem *base, unsigned short mask){	unsigned short status;	unsigned int i = 0;#define PATA_BF54X_WAIT_TIMEOUT		10000	for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {		status = ATAPI_GET_INT_STATUS(base) & mask;		if (status)			break;	}	ATAPI_SET_INT_STATUS(base, mask);}/** * *    Function:       write_atapi_register * *    Description:    Writes to ATA Device Resgister * */static void write_atapi_register(void __iomem *base,		unsigned long ata_reg, unsigned short value){	/* Program the ATA_DEV_TXBUF register with write data (to be	 * written into the device).	 */	ATAPI_SET_DEV_TXBUF(base, value);	/* Program the ATA_DEV_ADDR register with address of the	 * device register (0x01 to 0x0F).	 */	ATAPI_SET_DEV_ADDR(base, ata_reg);	/* Program the ATA_CTRL register with dir set to write (1)	 */	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));	/* ensure PIO DMA is not set */	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));	/* and start the transfer */	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));	/* Wait for the interrupt to indicate the end of the transfer.	 * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)	 */	wait_complete(base, PIO_DONE_INT);}/** *

⌨️ 快捷键说明

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