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

📄 pata_bf54x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *	Function:       read_atapi_register * *Description:    Reads from ATA Device Resgister * */static unsigned short read_atapi_register(void __iomem *base,		unsigned long ata_reg){	/* 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 read (0) and	 */	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.	 * (PIO_DONE interrupt is set and it doesn't seem to matter	 * that we don't clear it)	 */	wait_complete(base, PIO_DONE_INT);	/* Read the ATA_DEV_RXBUF register with write data (to be	 * written into the device).	 */	return ATAPI_GET_DEV_RXBUF(base);}/** * *    Function:       write_atapi_register_data * *    Description:    Writes to ATA Device Resgister * */static void write_atapi_data(void __iomem *base,		int len, unsigned short *buf){	int i;	/* Set transfer length to 1 */	ATAPI_SET_XFER_LEN(base, 1);	/* Program the ATA_DEV_ADDR register with address of the	 * ATA_REG_DATA	 */	ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);	/* 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));	for (i = 0; i < len; i++) {		/* Program the ATA_DEV_TXBUF register with write data (to be		 * written into the device).		 */		ATAPI_SET_DEV_TXBUF(base, buf[i]);		/* 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);	}}/** * *	Function:       read_atapi_register_data * *	Description:    Reads from ATA Device Resgister * */static void read_atapi_data(void __iomem *base,		int len, unsigned short *buf){	int i;	/* Set transfer length to 1 */	ATAPI_SET_XFER_LEN(base, 1);	/* Program the ATA_DEV_ADDR register with address of the	 * ATA_REG_DATA	 */	ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);	/* Program the ATA_CTRL register with dir set to read (0) and	 */	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));	for (i = 0; i < len; i++) {		/* 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.		 * (PIO_DONE interrupt is set and it doesn't seem to matter		 * that we don't clear it)		 */		wait_complete(base, PIO_DONE_INT);		/* Read the ATA_DEV_RXBUF register with write data (to be		 * written into the device).		 */		buf[i] = ATAPI_GET_DEV_RXBUF(base);	}}/** *	bfin_tf_load - send taskfile registers to host controller *	@ap: Port to which output is sent *	@tf: ATA taskfile register set * *	Note: Original code is ata_tf_load(). */static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;	if (tf->ctl != ap->last_ctl) {		write_atapi_register(base, ATA_REG_CTRL, tf->ctl);		ap->last_ctl = tf->ctl;		ata_wait_idle(ap);	}	if (is_addr) {		if (tf->flags & ATA_TFLAG_LBA48) {			write_atapi_register(base, ATA_REG_FEATURE,						tf->hob_feature);			write_atapi_register(base, ATA_REG_NSECT,						tf->hob_nsect);			write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);			write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);			write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);			pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "				 "0x%X 0x%X\n",				tf->hob_feature,				tf->hob_nsect,				tf->hob_lbal,				tf->hob_lbam,				tf->hob_lbah);		}		write_atapi_register(base, ATA_REG_FEATURE, tf->feature);		write_atapi_register(base, ATA_REG_NSECT, tf->nsect);		write_atapi_register(base, ATA_REG_LBAL, tf->lbal);		write_atapi_register(base, ATA_REG_LBAM, tf->lbam);		write_atapi_register(base, ATA_REG_LBAH, tf->lbah);		pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",			tf->feature,			tf->nsect,			tf->lbal,			tf->lbam,			tf->lbah);	}	if (tf->flags & ATA_TFLAG_DEVICE) {		write_atapi_register(base, ATA_REG_DEVICE, tf->device);		pr_debug("device 0x%X\n", tf->device);	}	ata_wait_idle(ap);}/** *	bfin_check_status - Read device status reg & clear interrupt *	@ap: port where the device is * *	Note: Original code is ata_check_status(). */static u8 bfin_check_status(struct ata_port *ap){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	return read_atapi_register(base, ATA_REG_STATUS);}/** *	bfin_tf_read - input device's ATA taskfile shadow registers *	@ap: Port from which input is read *	@tf: ATA taskfile register set for storing input * *	Note: Original code is ata_tf_read(). */static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	tf->command = bfin_check_status(ap);	tf->feature = read_atapi_register(base, ATA_REG_ERR);	tf->nsect = read_atapi_register(base, ATA_REG_NSECT);	tf->lbal = read_atapi_register(base, ATA_REG_LBAL);	tf->lbam = read_atapi_register(base, ATA_REG_LBAM);	tf->lbah = read_atapi_register(base, ATA_REG_LBAH);	tf->device = read_atapi_register(base, ATA_REG_DEVICE);	if (tf->flags & ATA_TFLAG_LBA48) {		write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);		tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);		tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);		tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);		tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);		tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);	}}/** *	bfin_exec_command - issue ATA command to host controller *	@ap: port to which command is being issued *	@tf: ATA taskfile register set * *	Note: Original code is ata_exec_command(). */static void bfin_exec_command(struct ata_port *ap,			      const struct ata_taskfile *tf){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);	write_atapi_register(base, ATA_REG_CMD, tf->command);	ata_pause(ap);}/** *	bfin_check_altstatus - Read device alternate status reg *	@ap: port where the device is */static u8 bfin_check_altstatus(struct ata_port *ap){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	return read_atapi_register(base, ATA_REG_ALTSTATUS);}/** *	bfin_std_dev_select - Select device 0/1 on ATA bus *	@ap: ATA channel to manipulate *	@device: ATA device (numbered from zero) to select * *	Note: Original code is ata_std_dev_select(). */static void bfin_std_dev_select(struct ata_port *ap, unsigned int device){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	u8 tmp;	if (device == 0)		tmp = ATA_DEVICE_OBS;	else		tmp = ATA_DEVICE_OBS | ATA_DEV1;	write_atapi_register(base, ATA_REG_DEVICE, tmp);	ata_pause(ap);}/** *	bfin_bmdma_setup - Set up IDE DMA transaction *	@qc: Info associated with this ATA transaction. * *	Note: Original code is ata_bmdma_setup(). */static void bfin_bmdma_setup(struct ata_queued_cmd *qc){	unsigned short config = WDSIZE_16;	struct scatterlist *sg;	pr_debug("in atapi dma setup\n");	/* Program the ATA_CTRL register with dir */	if (qc->tf.flags & ATA_TFLAG_WRITE) {		/* fill the ATAPI DMA controller */		set_dma_config(CH_ATAPI_TX, config);		set_dma_x_modify(CH_ATAPI_TX, 2);		ata_for_each_sg(sg, qc) {			set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));			set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);		}	} else {		config |= WNR;		/* fill the ATAPI DMA controller */		set_dma_config(CH_ATAPI_RX, config);		set_dma_x_modify(CH_ATAPI_RX, 2);		ata_for_each_sg(sg, qc) {			set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));			set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);		}	}}/** *	bfin_bmdma_start - Start an IDE DMA transaction *	@qc: Info associated with this ATA transaction. * *	Note: Original code is ata_bmdma_start(). */static void bfin_bmdma_start(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	struct scatterlist *sg;	pr_debug("in atapi dma start\n");	if (!(ap->udma_mask || ap->mwdma_mask))		return;	/* start ATAPI DMA controller*/	if (qc->tf.flags & ATA_TFLAG_WRITE) {		/*		 * On blackfin arch, uncacheable memory is not		 * allocated with flag GFP_DMA. DMA buffer from		 * common kenel code should be flushed if WB		 * data cache is enabled. Otherwise, this loop		 * is an empty loop and optimized out.		 */		ata_for_each_sg(sg, qc) {			flush_dcache_range(sg_dma_address(sg),				sg_dma_address(sg) + sg_dma_len(sg));		}		enable_dma(CH_ATAPI_TX);		pr_debug("enable udma write\n");		/* Send ATA DMA write command */		bfin_exec_command(ap, &qc->tf);		/* set ATA DMA write direction */		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)			| XFER_DIR));	} else {		enable_dma(CH_ATAPI_RX);		pr_debug("enable udma read\n");		/* Send ATA DMA read command */		bfin_exec_command(ap, &qc->tf);		/* set ATA DMA read direction */		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)			& ~XFER_DIR));	}	/* Reset all transfer count */	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);		/* Set transfer length to buffer len */	ata_for_each_sg(sg, qc) {		ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));	}	/* Enable ATA DMA operation*/	if (ap->udma_mask)		ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)			| ULTRA_START);	else		ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)			| MULTI_START);}/** *	bfin_bmdma_stop - Stop IDE DMA transfer *	@qc: Command we are ending DMA for */static void bfin_bmdma_stop(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct scatterlist *sg;	pr_debug("in atapi dma stop\n");	if (!(ap->udma_mask || ap->mwdma_mask))		return;	/* stop ATAPI DMA controller*/	if (qc->tf.flags & ATA_TFLAG_WRITE)		disable_dma(CH_ATAPI_TX);	else {		disable_dma(CH_ATAPI_RX);		if (ap->hsm_task_state & HSM_ST_LAST) {			/*			 * On blackfin arch, uncacheable memory is not			 * allocated with flag GFP_DMA. DMA buffer from			 * common kenel code should be invalidated if			 * data cache is enabled. Otherwise, this loop			 * is an empty loop and optimized out.			 */			ata_for_each_sg(sg, qc) {				invalidate_dcache_range(					sg_dma_address(sg),					sg_dma_address(sg)					+ sg_dma_len(sg));			}		}	}}/** *	bfin_devchk - PATA device presence detection *	@ap: ATA channel to examine *	@device: Device to examine (starting at zero) * *	Note: Original code is ata_devchk(). */static unsigned int bfin_devchk(struct ata_port *ap,				unsigned int device){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	u8 nsect, lbal;	bfin_std_dev_select(ap, device);	write_atapi_register(base, ATA_REG_NSECT, 0x55);	write_atapi_register(base, ATA_REG_LBAL, 0xaa);	write_atapi_register(base, ATA_REG_NSECT, 0xaa);	write_atapi_register(base, ATA_REG_LBAL, 0x55);	write_atapi_register(base, ATA_REG_NSECT, 0x55);	write_atapi_register(base, ATA_REG_LBAL, 0xaa);	nsect = read_atapi_register(base, ATA_REG_NSECT);	lbal = read_atapi_register(base, ATA_REG_LBAL);	if ((nsect == 0x55) && (lbal == 0xaa))		return 1;	/* we found a device */	return 0;		/* nothing found */}/** *	bfin_bus_post_reset - PATA device post reset * *	Note: Original code is ata_bus_post_reset(). */static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	unsigned int dev0 = devmask & (1 << 0);	unsigned int dev1 = devmask & (1 << 1);	unsigned long timeout;	/* if device 0 was found in ata_devchk, wait for its	 * BSY bit to clear	 */	if (dev0)		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);	/* if device 1 was found in ata_devchk, wait for	 * register access, then wait for BSY to clear	 */	timeout = jiffies + ATA_TMOUT_BOOT;	while (dev1) {		u8 nsect, lbal;		bfin_std_dev_select(ap, 1);		nsect = read_atapi_register(base, ATA_REG_NSECT);		lbal = read_atapi_register(base, ATA_REG_LBAL);		if ((nsect == 1) && (lbal == 1))			break;		if (time_after(jiffies, timeout)) {			dev1 = 0;			break;		}		msleep(50);	/* give drive a breather */	}	if (dev1)		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);	/* is all this really necessary? */	bfin_std_dev_select(ap, 0);	if (dev1)		bfin_std_dev_select(ap, 1);	if (dev0)		bfin_std_dev_select(ap, 0);}/** *	bfin_bus_softreset - PATA device software reset * *	Note: Original code is ata_bus_softreset(). */static unsigned int bfin_bus_softreset(struct ata_port *ap,				       unsigned int devmask){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	/* software reset.  causes dev0 to be selected */	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);	udelay(20);	write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);	udelay(20);	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);	/* spec mandates ">= 2ms" before checking status.	 * We wait 150ms, because that was the magic delay used for	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time	 * between when the ATA command register is written, and then	 * status is checked.  Because waiting for "a while" before	 * checking status is fine, post SRST, we perform this magic	 * delay here as well.	 *	 * Old drivers/ide uses the 2mS rule and then waits for ready	 */	msleep(150);	/* Before we perform post reset processing we want to see if	 * the bus shows 0xFF because the odd clown forgets the D7	 * pulldown resistor.	 */	if (bfin_check_status(ap) == 0xFF)		return 0;	bfin_bus_post_reset(ap, devmask);	return 0;}/** *	bfin_std_softreset - reset host port via ATA SRST *	@ap: port to reset *	@classes: resulting classes of attached devices

⌨️ 快捷键说明

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