Hi Alan, Thursday, June 25, 2009, 1:29:58 PM, you wrote: > It would be useful I think if you posted the current code, and also to > know if you see the same problem (lost IRQ etc) with ATAPI as well as ATA I've attached the current driver and reduced set of patches I'm trying to port. Truly speaking I have very little knowledge about IDE / ATAPI interfaces and simply try to reproduce the original logic using modern libata functions. As you can see the new pata driver redefines set_piomode / set_dmamode to tune chipset and bmdma_start to flush CPU cache. It works fine in UDMA mode on a newer chipset but I cannot get MW-DMA working on an older chipset. The complete patch for the EM85XX architecture can be found at http://mg35tools.svn.sourceforge.net/viewvc/mg35tools/trunk/sources/linux-2.6/ original 2.4.17 kernel for Sigma EM8500 is published at http://www.uclinux.org/pub/uClinux/ports/arm/EM8500/ -- Best regards, Andrei mailto:andrei.martynov@xxxxxx
Attachment:
em85xx-ide.patch
Description: Binary data
/* ide-jasper.c */ /* jasper specific initialization stuff for ide */ #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 <scsi/scsi_host.h> #include <linux/libata.h> #include <linux/platform_device.h> #define DRV_NAME "pata_jasper" #define DRV_VERSION "0.1" #include <asm/io.h> #include <asm/hardware.h> #include <asm/arch/quasar.h> // updated to match stock ide driver firmware 1.5.2 static int jasper_tune_chipset(int slave, u8 speed) { unsigned short reg54, reg58; speed = speed & 0xFF; printk("jasper_tune_chipset: speed = %02x\n", speed); /*unsigned int */reg54 = inw(JASPER_IDE_BASE + IDE_UDMACTL); /*unsigned int */reg58 = inw(JASPER_IDE_BASE + IDE_UDMATIM); if (speed>=XFER_UDMA_0 && speed<=XFER_UDMA_5) { if(slave != 0) { reg54 |= 0x2; reg58 |= (speed-XFER_UDMA_0)<<4; }else { reg54 |= 0x1; reg58 |= (speed-XFER_UDMA_0); } if (speed == XFER_UDMA_0) { outl(0x11100009 + 0x10C00, JASPER_IDE_BASE + IDE_UDMATIM); outl(5, JASPER_IDE_BASE + 0x5C); } else if (speed == XFER_UDMA_1) { outl(0x11110A06, JASPER_IDE_BASE + IDE_UDMATIM); outl(3, JASPER_IDE_BASE + 0x5C); } else { outl(0x11100004 + 0x10800, JASPER_IDE_BASE + IDE_UDMATIM); outl(2, JASPER_IDE_BASE + 0x5C); } } else { if (!(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)) { if (slave != 0) { reg54 &= ~0x2; } else { reg54 &= ~0x1; } } } outl(0x89000110, JASPER_IDE_BASE + 0x44); outw(reg54, JASPER_IDE_BASE + IDE_UDMACTL); outw(reg58, JASPER_IDE_BASE + IDE_UDMATIM); return 0; //ide_config_drive_speed(drive, speed); } static void jasper_set_dmamode (struct ata_port *ap, struct ata_device *adev) { // int slave = adev->devno; jasper_tune_chipset(0/*slave*/, adev->dma_mode); } static void jasper_set_piomode(struct ata_port *ap, struct ata_device *adev) { // int slave = adev->devno; jasper_tune_chipset(0/*slave*/, adev->pio_mode); } // standard is 2 (!) #define JASPER_ATA_DMA_STATUS 4 // standard is 4 #define JASPER_ATA_DMA_TABLE_OFS 8 static void jasper_bmdma_start(struct ata_queued_cmd *qc) { __asm__( "mcr p15, 0, %0, c7, c10, 0\n" // write-back data cache : : "r" (0) ); ata_bmdma_start(qc); } static struct scsi_host_template jasper_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 = LIBATA_DUMB_MAX_PRD, .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, }; static struct ata_port_operations jasper_port_ops = { .set_piomode = jasper_set_piomode, .set_dmamode = jasper_set_dmamode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = jasper_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, .qc_prep = ata_dumb_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .port_start = ata_port_start/*ata_sff_port_start*/, }; static int __devinit jasper_atapi_probe(struct platform_device *pdev) { struct ata_host *host; struct ata_ioports *ioaddr; struct ata_port_info pi = { .sht = &jasper_sht, .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .port_ops = &jasper_port_ops, #ifdef CONFIG_JASPER_IDE_UDMA .mwdma_mask = 0x07, .udma_mask = 0x07, #endif }; const struct ata_port_info *ppi[] = { &pi, NULL }; int can_udma; int chipsetID = __raw_readl(JASPER_SYSCTRL_BASE + SYSCTRL_CHIP_ID); can_udma = chipsetID > 0x8500; printk("JASPER PATA (IDE) chipset %x: UDMA is %ssupported\n", chipsetID, can_udma ? "" : "not "); // choose ide over dvd loader (DVD_AV_CONTROL) // write 0x8000 to IDETIM outl(/*R1*/ 0xffffff - 0xef0000, /*R0*/ JASPER_PIO0_BASE + PIO_DIR); outl(/*R1*/ 0xffffff - 0xef0000, /* R3 */ JASPER_PIO0_BASE + PIO_DATA); // choose ide over dvd loader (DVD_AV_CONTROL) outl(0x00, JASPER_DVD_BASE + DVD_AV_CTRL); //0x00 select IDE over DVD-loader outw(0x00, JASPER_IDE_BASE + 0x34); outl(0x8400+0xF, JASPER_IDE_BASE + IDE_TIM); // ppi[0] = ppi[1] = π host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); if (!host) return -ENOMEM; ioaddr = &host->ports[0]->ioaddr; ioaddr->cmd_addr = __io(JASPER_IDE_BASE + IDE_PRI_DATA); ioaddr->ctl_addr = __io(JASPER_IDE_BASE + IDE_PRI_DEVICE_CONTROL); ioaddr->altstatus_addr = __io(JASPER_IDE_BASE + IDE_PRI_DEVICE_CONTROL); ioaddr->bmdma_addr = __io(JASPER_IDE_DMA_BASE); ata_std_ports(ioaddr); // sets other regs based on cmd_addr return ata_host_activate(host, IDE_IRQ, ata_interrupt, IRQF_SHARED, &jasper_sht); } /** * jasper_atapi_remove - unplug a jasper atapi interface * @pdev: platform device * * A jasper atapi device has been unplugged. Perform the needed * cleanup. Also called on module unload for any active devices. */ static int __devexit jasper_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; } static struct platform_driver jasper_atapi_driver = { .probe = jasper_atapi_probe, .remove = __devexit_p(jasper_atapi_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, #ifdef CONFIG_PM .suspend = jasper_atapi_suspend, .resume = jasper_atapi_resume, #endif }, }; static int __init jasper_atapi_init(void) { return platform_driver_register(&jasper_atapi_driver); } static void __exit jasper_atapi_exit(void) { platform_driver_unregister(&jasper_atapi_driver); } module_init(jasper_atapi_init); module_exit(jasper_atapi_exit); MODULE_AUTHOR("Anonymous"); MODULE_DESCRIPTION("JASPER IDE driver"); MODULE_LICENSE("GPL");