// SPDX-License-Identifier: GPL-2.0-only /* * pata_sis.c - SiS ATA driver * * (C) 2005 Red Hat * (C) 2007,2009 Bartlomiej Zolnierkiewicz * * Based upon linux/drivers/ide/pci/sis5513.c * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> * SiS Taiwan : for direct support and hardware. * Daniela Engert : for initial ATA100 advices and numerous others. * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt : * for checking code correctness, providing patches. * Original tests and design on the SiS620 chipset. * ATA100 tests and design on the SiS735 chipset. * ATA16/33 support from specs * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw> * * * TODO * Check MWDMA on drives that don't support MWDMA speed pio cycles ? * More Testing
*/
struct sis_chipset {
u16 device; /* PCI host ID */ conststruct ata_port_info *info; /* Info block */ /* Probably add family, cable detect type etc here to clean
up code later */
};
while (lap->device) { if (lap->device == dev->device &&
lap->subvendor == dev->subsystem_vendor &&
lap->subdevice == dev->subsystem_device) return 1;
lap++;
}
return 0;
}
/** * sis_old_port_base - return PCI configuration base for dev * @adev: device * * Returns the base of the PCI configuration registers for this port * number.
*/
/** * sis_port_base - return PCI configuration base for dev * @adev: device * * Returns the base of the PCI configuration registers for this port * number.
*/
/* The top bit of this register is the cable detect bit */
pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp); if ((tmp & 0x8000) && !sis_short_ata40(pdev)) return ATA_CBL_PATA40; return ATA_CBL_PATA80;
}
/** * sis_66_cable_detect - check for 40/80 pin * @ap: Port * * Perform cable detection on the UDMA66, UDMA100 and early UDMA133 * SiS IDE controllers.
*/
/* Older chips keep cable detect in bits 4/5 of reg 0x48 */
pci_read_config_byte(pdev, 0x48, &tmp);
tmp >>= ap->port_no; if ((tmp & 0x10) && !sis_short_ata40(pdev)) return ATA_CBL_PATA40; return ATA_CBL_PATA80;
}
/** * sis_pre_reset - probe begin * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init
*/
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) return -ENOENT;
/* Clear the FIFO settings. We can't enable the FIFO until
we know we are poking at a disk */
pci_write_config_byte(pdev, 0x4B, 0); return ata_sff_prereset(link, deadline);
}
/** * sis_set_fifo - Set RWP fifo bits for this device * @ap: Port * @adev: Device * * SIS chipsets implement prefetch/postwrite bits for each device * on both channels. This functionality is not ATAPI compatible and * must be configured according to the class of device present
*/
/* This holds various bits including the FIFO control */
pci_read_config_byte(pdev, 0x4B, &fifoctrl);
fifoctrl &= ~mask;
/* Enable for ATA (disk) only */ if (adev->class == ATA_DEV_ATA)
fifoctrl |= mask;
pci_write_config_byte(pdev, 0x4B, fifoctrl);
}
/** * sis_old_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: Device we are configuring for. * * Set PIO mode for device, in host controller PCI config space. This * function handles PIO set up for all chips that are pre ATA100 and * also early ATA100 devices. * * LOCKING: * None (inherited from caller).
*/
staticvoid sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = sis_old_port_base(adev);
u8 t1, t2; int speed = adev->pio_mode - XFER_PIO_0;
pci_write_config_byte(pdev, port, t1);
pci_write_config_byte(pdev, port + 1, t2);
}
/** * sis_100_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: Device we are configuring for. * * Set PIO mode for device, in host controller PCI config space. This * function handles PIO set up for ATA100 devices and early ATA133. * * LOCKING: * None (inherited from caller).
*/
staticvoid sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = sis_old_port_base(adev); int speed = adev->pio_mode - XFER_PIO_0;
/** * sis_133_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: Device we are configuring for. * * Set PIO mode for device, in host controller PCI config space. This * function handles PIO set up for the later ATA133 devices. * * LOCKING: * None (inherited from caller).
*/
/** * sis_old_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: Device to program * * Set UDMA/MWDMA mode for device, in host controller PCI config space. * Handles pre UDMA and UDMA33 devices. Supports MWDMA as well unlike * the old ide/pci driver. * * LOCKING: * None (inherited from caller).
*/
if (adev->dma_mode < XFER_UDMA_0) { /* bits 3-0 hold recovery timing bits 8-10 active timing and
the higher bits are dependent on the device */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else { /* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
speed = adev->dma_mode - XFER_UDMA_0;
timing &= ~0x6000;
timing |= udma_bits[speed];
}
pci_write_config_word(pdev, drive_pci, timing);
}
/** * sis_66_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: Device to program * * Set UDMA/MWDMA mode for device, in host controller PCI config space. * Handles UDMA66 and early UDMA100 devices. Supports MWDMA as well unlike * the old ide/pci driver. * * LOCKING: * None (inherited from caller).
*/
if (adev->dma_mode < XFER_UDMA_0) { /* bits 3-0 hold recovery timing bits 8-10 active timing and
the higher bits are dependent on the device, bit 15 udma */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else { /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
speed = adev->dma_mode - XFER_UDMA_0;
timing &= ~0xF000;
timing |= udma_bits[speed];
}
pci_write_config_word(pdev, drive_pci, timing);
}
/** * sis_100_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: Device to program * * Set UDMA/MWDMA mode for device, in host controller PCI config space. * Handles UDMA66 and early UDMA100 devices. * * LOCKING: * None (inherited from caller).
*/
if (adev->dma_mode < XFER_UDMA_0) { /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
} else { /* Bit 7 is UDMA on/off, bit 0-3 are cycle time */
speed = adev->dma_mode - XFER_UDMA_0;
timing &= ~0x8F;
timing |= udma_bits[speed];
}
pci_write_config_byte(pdev, drive_pci + 1, timing);
}
/** * sis_133_early_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: Device to program * * Set UDMA/MWDMA mode for device, in host controller PCI config space. * Handles early SiS 961 bridges. * * LOCKING: * None (inherited from caller).
*/
if (adev->dma_mode < XFER_UDMA_0) { /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
} else { /* Bit 7 is UDMA on/off, bit 0-3 are cycle time */
speed = adev->dma_mode - XFER_UDMA_0;
timing &= ~0x8F;
timing |= udma_bits[speed];
}
pci_write_config_byte(pdev, drive_pci + 1, timing);
}
/** * sis_133_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: Device to program * * Set UDMA/MWDMA mode for device, in host controller PCI config space. * * LOCKING: * None (inherited from caller).
*/
/** * sis_133_mode_filter - mode selection filter * @adev: ATA device * @mask: received mask to manipulate and pass back * * Block UDMA6 on devices that do not support it.
*/
if (sis->info == &sis_info133_early || sis->info == &sis_info100) { /* Fix up latency */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */
pci_read_config_byte(pdev, 0x49, ®); if (!(reg & 0x01))
pci_write_config_byte(pdev, 0x49, reg | 0x01); return;
}
if (sis->info == &sis_info66 || sis->info == &sis_info100_early) { /* Fix up latency */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */
pci_read_config_byte(pdev, 0x52, ®); if (!(reg & 0x04))
pci_write_config_byte(pdev, 0x52, reg | 0x04); return;
}
if (sis->info == &sis_info33) {
pci_read_config_byte(pdev, PCI_CLASS_PROG, ®); if (( reg & 0x0F ) != 0x00)
pci_write_config_byte(pdev, PCI_CLASS_PROG, reg & 0xF0); /* Fall through to ATA16 fixup below */
}
if (sis->info == &sis_info || sis->info == &sis_info33) { /* force per drive recovery and active timings
needed on ATA_33 and below chips */
pci_read_config_byte(pdev, 0x52, ®); if (!(reg & 0x08))
pci_write_config_byte(pdev, 0x52, reg|0x08); return;
}
BUG();
}
/** * sis_init_one - Register SiS ATA PCI device with kernel services * @pdev: PCI device to register * @ent: Entry in sis_pci_tbl matching with @pdev * * Called from kernel PCI layer. We probe for combined mode (sigh), * and then hand over control to libata, for it to do the rest. * * LOCKING: * Inherited from PCI layer (may sleep). * * RETURNS: * Zero on success, or -ERRNO value.
*/
/* We have to find the bridge first */ for (sets = &sis_chipsets[0]; sets->device; sets++) {
host = pci_get_device(PCI_VENDOR_ID_SI, sets->device, NULL); if (host != NULL) {
chipset = sets; /* Match found */ if (sets->device == 0x630) { /* SIS630 */ if (host->revision >= 0x30) /* 630 ET */
chipset = &sis100_early;
} break;
}
}
/* Look for concealed bridges */ if (chipset == NULL) { /* Second check */
u32 idemisc;
u16 trueid;
/* Disable ID masking and register remapping then
see what the real ID is */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.