📄 pata_bf54x.c
字号:
* * Note: Original code is ata_std_softreset(). */static int bfin_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline){ struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0, err_mask; u8 err; if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } /* determine if device 0/1 are present */ if (bfin_devchk(ap, 0)) devmask |= (1 << 0); if (slave_possible && bfin_devchk(ap, 1)) devmask |= (1 << 1); /* select device 0 again */ bfin_std_dev_select(ap, 0); /* issue bus reset */ err_mask = bfin_bus_softreset(ap, devmask); if (err_mask) { ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", err_mask); return -EIO; } /* determine by signature whether we have ATA or ATAPI devices */ classes[0] = ata_dev_try_classify(&ap->link.device[0], devmask & (1 << 0), &err); if (slave_possible && err != 0x81) classes[1] = ata_dev_try_classify(&ap->link.device[1], devmask & (1 << 1), &err); out: return 0;}/** * bfin_bmdma_status - Read IDE DMA status * @ap: Port associated with this ATA transaction. */static unsigned char bfin_bmdma_status(struct ata_port *ap){ unsigned char host_stat = 0; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; unsigned short int_status = ATAPI_GET_INT_STATUS(base); if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) { host_stat |= ATA_DMA_ACTIVE; } if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) { host_stat |= ATA_DMA_INTR; } if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) { host_stat |= ATA_DMA_ERR; } return host_stat;}/** * bfin_data_xfer - Transfer data by PIO * @adev: device for this I/O * @buf: data buffer * @buflen: buffer length * @write_data: read/write * * Note: Original code is ata_data_xfer(). */static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data){ struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; unsigned short *buf16 = (u16 *) buf; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; /* Transfer multiple of 2 bytes */ if (write_data) { write_atapi_data(base, words, buf16); } else { read_atapi_data(base, words, buf16); } /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { unsigned short align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; if (write_data) { memcpy(align_buf, trailing_buf, 1); write_atapi_data(base, 1, align_buf); } else { read_atapi_data(base, 1, align_buf); memcpy(trailing_buf, align_buf, 1); } }}/** * bfin_irq_clear - Clear ATAPI interrupt. * @ap: Port associated with this ATA transaction. * * Note: Original code is ata_bmdma_irq_clear(). */static void bfin_irq_clear(struct ata_port *ap){ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; pr_debug("in atapi irq clear\n"); ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);}/** * bfin_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. * * Note: Original code is ata_irq_on(). */static unsigned char bfin_irq_on(struct ata_port *ap){ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; u8 tmp; pr_debug("in atapi irq on\n"); ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; write_atapi_register(base, ATA_REG_CTRL, ap->ctl); tmp = ata_wait_idle(ap); bfin_irq_clear(ap); return tmp;}/** * bfin_bmdma_freeze - Freeze DMA controller port * @ap: port to freeze * * Note: Original code is ata_bmdma_freeze(). */static void bfin_bmdma_freeze(struct ata_port *ap){ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; pr_debug("in atapi dma freeze\n"); ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; write_atapi_register(base, ATA_REG_CTRL, ap->ctl); /* Under certain circumstances, some controllers raise IRQ on * ATA_NIEN manipulation. Also, many controllers fail to mask * previously pending IRQ on ATA_NIEN assertion. Clear it. */ ata_chk_status(ap); bfin_irq_clear(ap);}/** * bfin_bmdma_thaw - Thaw DMA controller port * @ap: port to thaw * * Note: Original code is ata_bmdma_thaw(). */void bfin_bmdma_thaw(struct ata_port *ap){ bfin_check_status(ap); bfin_irq_clear(ap); bfin_irq_on(ap);}/** * bfin_std_postreset - standard postreset callback * @ap: the target ata_port * @classes: classes of attached devices * * Note: Original code is ata_std_postreset(). */static void bfin_std_postreset(struct ata_link *link, unsigned int *classes){ struct ata_port *ap = link->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; /* re-enable interrupts */ bfin_irq_on(ap); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) bfin_std_dev_select(ap, 1); if (classes[1] != ATA_DEV_NONE) bfin_std_dev_select(ap, 0); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { return; } /* set up device control */ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);}/** * bfin_error_handler - Stock error handler for DMA controller * @ap: port to handle error for */static void bfin_error_handler(struct ata_port *ap){ ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL, bfin_std_postreset);}static void bfin_port_stop(struct ata_port *ap){ pr_debug("in atapi port stop\n"); if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { free_dma(CH_ATAPI_RX); free_dma(CH_ATAPI_TX); }}static int bfin_port_start(struct ata_port *ap){ pr_debug("in atapi port start\n"); if (!(ap->udma_mask || ap->mwdma_mask)) return 0; if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) { if (request_dma(CH_ATAPI_TX, "BFIN ATAPI TX DMA") >= 0) return 0; free_dma(CH_ATAPI_RX); } ap->udma_mask = 0; ap->mwdma_mask = 0; dev_err(ap->dev, "Unable to request ATAPI DMA!" " Continue in PIO mode.\n"); return 0;}static struct scsi_host_template bfin_sht = { .module = THIS_MODULE, .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = SG_NONE, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, .use_clustering = ATA_SHT_USE_CLUSTERING, .proc_name = DRV_NAME, .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param,#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend,#endif};static const struct ata_port_operations bfin_pata_ops = { .set_piomode = bfin_set_piomode, .set_dmamode = bfin_set_dmamode, .tf_load = bfin_tf_load, .tf_read = bfin_tf_read, .exec_command = bfin_exec_command, .check_status = bfin_check_status, .check_altstatus = bfin_check_altstatus, .dev_select = bfin_std_dev_select, .bmdma_setup = bfin_bmdma_setup, .bmdma_start = bfin_bmdma_start, .bmdma_stop = bfin_bmdma_stop, .bmdma_status = bfin_bmdma_status, .data_xfer = bfin_data_xfer, .qc_prep = ata_noop_qc_prep, .qc_issue = ata_qc_issue_prot, .freeze = bfin_bmdma_freeze, .thaw = bfin_bmdma_thaw, .error_handler = bfin_error_handler, .post_internal_cmd = bfin_bmdma_stop, .irq_handler = ata_interrupt, .irq_clear = bfin_irq_clear, .irq_on = bfin_irq_on, .port_start = bfin_port_start, .port_stop = bfin_port_stop,};static struct ata_port_info bfin_port_info[] = { { .sht = &bfin_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0, .udma_mask = 0, .port_ops = &bfin_pata_ops, },};/** * bfin_reset_controller - initialize BF54x ATAPI controller. */static int bfin_reset_controller(struct ata_host *host){ void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr; int count; unsigned short status; /* Disable all ATAPI interrupts */ ATAPI_SET_INT_MASK(base, 0); SSYNC(); /* Assert the RESET signal 25us*/ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST); udelay(30); /* Negate the RESET signal for 2ms*/ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST); msleep(2); /* Wait on Busy flag to clear */ count = 10000000; do { status = read_atapi_register(base, ATA_REG_STATUS); } while (count-- && (status & ATA_BUSY)); /* Enable only ATAPI Device interrupt */ ATAPI_SET_INT_MASK(base, 1); SSYNC(); return (!count);}/** * atapi_io_port - define atapi peripheral port pins. */static unsigned short atapi_io_port[] = { P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, P_ATAPI_CS1, P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, P_ATAPI_IORDY, 0};/** * bfin_atapi_probe - attach a bfin atapi interface * @pdev: platform device * * Register a bfin atapi interface. * * * Platform devices are expected to contain 2 resources per port: * * - I/O Base (IORESOURCE_IO) * - IRQ (IORESOURCE_IRQ) * */static int __devinit bfin_atapi_probe(struct platform_device *pdev){ int board_idx = 0; struct resource *res; struct ata_host *host; unsigned int fsclk = get_sclk(); int udma_mode = 5; const struct ata_port_info *ppi[] = { &bfin_port_info[board_idx], NULL }; /* * Simple resource validation .. */ if (unlikely(pdev->num_resources != 2)) { dev_err(&pdev->dev, "invalid number of resources\n"); return -EINVAL; } /* * Get the register base first */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) return -EINVAL; while (bfin_port_info[board_idx].udma_mask > 0 && udma_fsclk[udma_mode] > fsclk) { udma_mode--; bfin_port_info[board_idx].udma_mask >>= 1; } /* * Now that that's out of the way, wire up the port.. */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); if (!host) return -ENOMEM; host->ports[0]->ioaddr.ctl_addr = (void *)res->start; if (peripheral_request_list(atapi_io_port, "atapi-io-port")) { dev_err(&pdev->dev, "Requesting Peripherals faild\n"); return -EFAULT; } if (bfin_reset_controller(host)) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to reset ATAPI device\n"); return -EFAULT; } if (ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); return -ENODEV; } return 0;}/** * bfin_atapi_remove - unplug a bfin atapi interface * @pdev: platform device * * A bfin atapi device has been unplugged. Perform the needed * cleanup. Also called on module unload for any active devices. */static int __devexit bfin_atapi_remove(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); peripheral_free_list(atapi_io_port); return 0;}#ifdef CONFIG_PMint bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state){ return 0;}int bfin_atapi_resume(struct platform_device *pdev){ return 0;}#endifstatic struct platform_driver bfin_atapi_driver = { .probe = bfin_atapi_probe, .remove = __devexit_p(bfin_atapi_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE,#ifdef CONFIG_PM .suspend = bfin_atapi_suspend, .resume = bfin_atapi_resume,#endif },};#define ATAPI_MODE_SIZE 10static char bfin_atapi_mode[ATAPI_MODE_SIZE];static int __init bfin_atapi_init(void){ pr_info("register bfin atapi driver\n"); switch(bfin_atapi_mode[0]) { case 'p': case 'P': break; case 'm': case 'M': bfin_port_info[0].mwdma_mask = ATA_MWDMA2; break; default: bfin_port_info[0].udma_mask = ATA_UDMA5; }; return platform_driver_register(&bfin_atapi_driver);}static void __exit bfin_atapi_exit(void){ platform_driver_unregister(&bfin_atapi_driver);}module_init(bfin_atapi_init);module_exit(bfin_atapi_exit);/* * ATAPI mode: * pio/PIO * udma/UDMA (default) * mwdma/MWDMA */module_param_string(bfin_atapi_mode, bfin_atapi_mode, ATAPI_MODE_SIZE, 0);MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -