Commit 6141df44 authored by Jens Axboe's avatar Jens Axboe

trm290 update

parent e686e408
...@@ -139,10 +139,12 @@ ...@@ -139,10 +139,12 @@
#include <asm/io.h> #include <asm/io.h>
#include "trm290.h"
static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
unsigned int reg; u16 reg = 0;
unsigned long flags; unsigned long flags;
/* select PIO or DMA */ /* select PIO or DMA */
...@@ -153,15 +155,16 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) ...@@ -153,15 +155,16 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
if (reg != hwif->select_data) { if (reg != hwif->select_data) {
hwif->select_data = reg; hwif->select_data = reg;
/* set PIO/DMA */ /* set PIO/DMA */
OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1); hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
OUT_WORD(reg & 0xff, hwif->config_data); hwif->OUTW(reg & 0xff, hwif->config_data);
} }
/* enable IRQ if not probing */ /* enable IRQ if not probing */
if (drive->present) { if (drive->present) {
reg = IN_WORD(hwif->config_data+3) & 0x13; reg = hwif->INW(hwif->config_data + 3);
reg &= 0x13;
reg &= ~(1 << hwif->channel); reg &= ~(1 << hwif->channel);
OUT_WORD(reg, hwif->config_data+3); hwif->OUTW(reg, hwif->config_data+3);
} }
local_irq_restore(flags); local_irq_restore(flags);
...@@ -173,116 +176,185 @@ static void trm290_selectproc (ide_drive_t *drive) ...@@ -173,116 +176,185 @@ static void trm290_selectproc (ide_drive_t *drive)
} }
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
// ide_task_t *args = HWGROUP(drive)->rq->special; struct request *rq = HWGROUP(drive)->rq;
// ide_task_t *args = rq->special;
task_ioreg_t command = WIN_NOP;
unsigned int count, reading = 2, writing = 0; unsigned int count, reading = 2, writing = 0;
switch (func) {
case ide_dma_write:
reading = 0; reading = 0;
writing = 1; writing = 1;
#ifdef TRM290_NO_DMA_WRITES #ifdef TRM290_NO_DMA_WRITES
break; /* always use PIO for writes */ /* always use PIO for writes */
trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
#endif #endif
case ide_dma_read: if (!(count = ide_build_dmatable(drive, rq))) {
if (!(count = ide_build_dmatable(drive, func)))
/* try PIO instead of DMA */ /* try PIO instead of DMA */
break; trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
/* select DMA xfer */ /* select DMA xfer */
trm290_prepare_drive(drive, 1); trm290_prepare_drive(drive, 1);
outl(hwif->dmatable_dma|reading|writing, hwif->dma_base); hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
drive->waiting_for_dma = 1; drive->waiting_for_dma = 1;
/* start DMA */ /* start DMA */
OUT_WORD((count * 2) - 1, hwif->dma_base+2); hwif->OUTW((count * 2) - 1, hwif->dma_status);
if (drive->media != ide_disk) if (drive->media != ide_disk)
return 0; return 0;
if (HWGROUP(drive)->handler != NULL) /* paranoia check */ if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG(); BUG();
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
/* /*
* FIX ME to use only ACB ide_task_t args Struct * FIX ME to use only ACB ide_task_t args Struct
*/ */
#if 0 #if 0
{ {
ide_task_t *args = HWGROUP(drive)->rq->special; ide_task_t *args = rq->special;
OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); command = args->tfRegister[IDE_COMMAND_OFFSET];
} }
#else #else
if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) { command = /* (lba48) ? WIN_READDMA_EXT : */ WIN_READDMA;
ide_task_t *args = HWGROUP(drive)->rq->special; if (rq->flags & REQ_DRIVE_TASKFILE) {
OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); ide_task_t *args = rq->special;
} else if (drive->addressing == 1) command = args->tfRegister[IDE_COMMAND_OFFSET];
OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); }
else
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
#endif #endif
return HWIF(drive)->dmaproc(ide_dma_begin, drive); /* issue cmd to drive */
case ide_dma_begin: hwif->OUTB(command, IDE_COMMAND_REG);
return HWIF(drive)->ide_dma_count(drive);
}
static int trm290_ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
{
ide_hwif_t *hwif = HWIF(drive);
struct request *rq = HWGROUP(drive)->rq;
// ide_task_t *args = rq->special;
task_ioreg_t command = WIN_NOP;
unsigned int count, reading = 2, writing = 0;
if (!(count = ide_build_dmatable(drive, rq))) {
/* try PIO instead of DMA */
trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
/* select DMA xfer */
trm290_prepare_drive(drive, 1);
hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
drive->waiting_for_dma = 1;
/* start DMA */
hwif->OUTW((count * 2) - 1, hwif->dma_status);
if (drive->media != ide_disk)
return 0; return 0;
case ide_dma_end: if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG();
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
/*
* FIX ME to use only ACB ide_task_t args Struct
*/
#if 0
{
ide_task_t *args = rq->special;
command = args->tfRegister[IDE_COMMAND_OFFSET];
}
#else
command = /* (lba48) ? WIN_WRITEDMA_EXT : */ WIN_WRITEDMA;
if (rq->flags & REQ_DRIVE_TASKFILE) {
ide_task_t *args = rq->special;
command = args->tfRegister[IDE_COMMAND_OFFSET];
}
#endif
/* issue cmd to drive */
hwif->OUTB(command, IDE_COMMAND_REG);
return HWIF(drive)->ide_dma_count(drive);
}
static int trm290_ide_dma_begin (ide_drive_t *drive)
{
return 0;
}
static int trm290_ide_dma_end (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u16 status = 0;;
drive->waiting_for_dma = 0; drive->waiting_for_dma = 0;
/* purge DMA mappings */ /* purge DMA mappings */
ide_destroy_dmatable(drive); ide_destroy_dmatable(drive);
return (IN_WORD(hwif->dma_base+2) != 0x00ff); status = hwif->INW(hwif->dma_status);
case ide_dma_test_irq: return (status != 0x00ff);
return (IN_WORD(hwif->dma_base+2) == 0x00ff); }
default:
return ide_dmaproc(func, drive); static int trm290_ide_dma_test_irq (ide_drive_t *drive)
} {
trm290_prepare_drive(drive, 0); /* select PIO xfer */ ide_hwif_t *hwif = HWIF(drive);
return 1; u16 status = 0;
status = hwif->INW(hwif->dma_status);
return (status == 0x00ff);
} }
#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_BLK_DEV_IDEDMA */
/* /*
* Invoked from ide-dma.c at boot time. * Invoked from ide-dma.c at boot time.
*/ */
void __init ide_init_trm290 (ide_hwif_t *hwif) void __init init_hwif_trm290 (ide_hwif_t *hwif)
{ {
unsigned int cfgbase = 0; unsigned int cfgbase = 0;
unsigned long flags; unsigned long flags;
byte reg; u8 reg = 0;
struct pci_dev *dev = hwif->pci_dev; struct pci_dev *dev = hwif->pci_dev;
hwif->addressing = 1;
hwif->chipset = ide_trm290; hwif->chipset = ide_trm290;
cfgbase = pci_resource_start(dev, 4); cfgbase = pci_resource_start(dev, 4);
if ((dev->class & 5) && cfgbase) { if ((dev->class & 5) && cfgbase) {
hwif->config_data = cfgbase; hwif->config_data = cfgbase;
printk("TRM290: chip config base at 0x%04lx\n", printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
hwif->config_data); hwif->config_data);
} else { } else {
hwif->config_data = 0x3df0; hwif->config_data = 0x3df0;
printk("TRM290: using default config base at 0x%04lx\n", printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
hwif->config_data); hwif->config_data);
} }
local_irq_save(flags); local_irq_save(flags);
/* put config reg into first byte of hwif->select_data */ /* put config reg into first byte of hwif->select_data */
OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1); hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
/* select PIO as default */ /* select PIO as default */
hwif->select_data = 0x21; hwif->select_data = 0x21;
OUT_BYTE(hwif->select_data, hwif->config_data); hwif->OUTB(hwif->select_data, hwif->config_data);
/* get IRQ info */ /* get IRQ info */
reg = IN_BYTE(hwif->config_data+3); reg = hwif->INB(hwif->config_data+3);
/* mask IRQs for both ports */ /* mask IRQs for both ports */
reg = (reg & 0x10) | 0x03; reg = (reg & 0x10) | 0x03;
OUT_BYTE(reg, hwif->config_data+3); hwif->OUTB(reg, hwif->config_data+3);
local_irq_restore(flags); local_irq_restore(flags);
if ((reg & 0x10)) if ((reg & 0x10))
hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ /* legacy mode */
hwif->irq = hwif->channel ? 15 : 14;
else if (!hwif->irq && hwif->mate && hwif->mate->irq) else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */ /* sharing IRQ with mate */
hwif->irq = hwif->mate->irq;
ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &trm290_dmaproc; hwif->ide_dma_write = &trm290_ide_dma_write;
hwif->ide_dma_read = &trm290_ide_dma_read;
hwif->ide_dma_begin = &trm290_ide_dma_begin;
hwif->ide_dma_end = &trm290_ide_dma_end;
hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_BLK_DEV_IDEDMA */
hwif->selectproc = &trm290_selectproc; hwif->selectproc = &trm290_selectproc;
hwif->autodma = 0; /* play it safe for now */ hwif->autodma = 0; /* play it safe for now */
hwif->drives[0].autodma = hwif->autodma;
hwif->drives[1].autodma = hwif->autodma;
#if 1 #if 1
{ {
/* /*
...@@ -290,26 +362,60 @@ void __init ide_init_trm290 (ide_hwif_t *hwif) ...@@ -290,26 +362,60 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
* for the control basereg, so this kludge ensures that we use only * for the control basereg, so this kludge ensures that we use only
* values that are known to work. Ugh. -ml * values that are known to work. Ugh. -ml
*/ */
unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4; u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
static unsigned short next_offset = 0; static u16 next_offset = 0;
u8 old_mask;
OUT_BYTE(0x54|(hwif->channel<<3), hwif->config_data+1); hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
old = IN_WORD(hwif->config_data) & ~1; old = hwif->INW(hwif->config_data);
if (old != compat && IN_BYTE(old+2) == 0xff) { old &= ~1;
compat += (next_offset += 0x400); /* leave lower 10 bits untouched */ old_mask = hwif->INB(old+2);
#if 1 if (old != compat && old_mask == 0xff) {
if (ide_check_region(compat + 2, 1)) /* leave lower 10 bits untouched */
printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2)); compat += (next_offset += 0x400);
# if 1
if (check_region(compat + 2, 1))
printk(KERN_ERR "%s: check_region failure at 0x%04x\n",
hwif->name, (compat + 2));
/* /*
* The region check is not needed; however......... * The region check is not needed; however.........
* Since this is the checked in ide-probe.c, * Since this is the checked in ide-probe.c,
* this is only an assignment. * this is only an assignment.
*/ */
#endif # endif
hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
OUT_WORD(compat|1, hwif->config_data); hwif->OUTW(compat|1, hwif->config_data);
printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, IN_WORD(hwif->config_data) & ~1); new = hwif->INW(hwif->config_data);
printk(KERN_INFO "%s: control basereg workaround: "
"old=0x%04x, new=0x%04x\n",
hwif->name, old, new & ~1);
} }
} }
#endif #endif
} }
extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
void __init init_setup_trm290 (struct pci_dev *dev, ide_pci_device_t *d)
{
ide_setup_pci_device(dev, d);
}
int __init trm290_scan_pcidev (struct pci_dev *dev)
{
ide_pci_device_t *d;
if (dev->vendor != PCI_VENDOR_ID_TEKRAM)
return 0;
for (d = trm290_chipsets; d && d->vendor && d->device; ++d) {
if (((d->vendor == dev->vendor) &&
(d->device == dev->device)) &&
(d->init_setup)) {
d->init_setup(dev, d);
return 1;
}
}
return 0;
}
#ifndef TRM290_H
#define TRM290_H
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/ide.h>
extern void init_setup_trm290(struct pci_dev *, ide_pci_device_t *);
extern void init_hwif_trm290(ide_hwif_t *);
static ide_pci_device_t trm290_chipsets[] __initdata = {
{
vendor: PCI_VENDOR_ID_TEKRAM,
device: PCI_DEVICE_ID_TEKRAM_DC290,
name: "TRM290",
init_setup: init_setup_trm290,
init_chipset: NULL,
init_iops: NULL,
init_hwif: init_hwif_trm290,
init_dma: NULL,
channels: 2,
autodma: NOAUTODMA,
enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
bootable: ON_BOARD,
extra: 0,
},{
vendor: 0,
device: 0,
channels: 0,
bootable: EOL,
}
};
#endif /* TRM290_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment