📄 pata_bf54x.c
字号:
* 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 + -