mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
ide: remove the legacy ide driver
The legay ide driver has been replace with libata starting in 2003 and has been scheduled for removal for a while. Finally kill it off so that we can start cleaning up various bits of cruft it forced on the block layer. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
committed by
Jens Axboe
parent
b90257bfdd
commit
b7fb14d3ac
File diff suppressed because it is too large
Load Diff
16
MAINTAINERS
16
MAINTAINERS
@@ -8763,22 +8763,6 @@ L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-icy.c
|
||||
|
||||
IDE SUBSYSTEM
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
L: linux-ide@vger.kernel.org
|
||||
S: Maintained
|
||||
Q: http://patchwork.ozlabs.org/project/linux-ide/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git
|
||||
F: Documentation/ide/
|
||||
F: drivers/ide/
|
||||
F: include/linux/ide.h
|
||||
|
||||
IDE/ATAPI DRIVERS
|
||||
L: linux-ide@vger.kernel.org
|
||||
S: Orphan
|
||||
F: Documentation/cdrom/ide-cd.rst
|
||||
F: drivers/ide/ide-cd*
|
||||
|
||||
IDEAPAD LAPTOP EXTRAS DRIVER
|
||||
M: Ike Panhc <ike.pan@canonical.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
||||
@@ -33,8 +33,6 @@ source "drivers/nvme/Kconfig"
|
||||
|
||||
source "drivers/misc/Kconfig"
|
||||
|
||||
source "drivers/ide/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
||||
source "drivers/ata/Kconfig"
|
||||
|
||||
@@ -78,7 +78,6 @@ obj-$(CONFIG_CXL_BUS) += cxl/
|
||||
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
|
||||
obj-$(CONFIG_NUBUS) += nubus/
|
||||
obj-y += macintosh/
|
||||
obj-$(CONFIG_IDE) += ide/
|
||||
obj-y += scsi/
|
||||
obj-y += nvme/
|
||||
obj-$(CONFIG_ATA) += ata/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,109 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# link order is important here
|
||||
#
|
||||
|
||||
ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
|
||||
ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
|
||||
ide-io-std.o ide-eh.o
|
||||
|
||||
# core IDE code
|
||||
ide-core-$(CONFIG_IDE_XFER_MODE) += ide-pio-blacklist.o ide-xfer-mode.o
|
||||
ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
|
||||
ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF) += ide-dma-sff.o
|
||||
ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
|
||||
ide-core-$(CONFIG_IDE_LEGACY) += ide-legacy.o
|
||||
|
||||
obj-$(CONFIG_IDE) += ide-core.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
|
||||
obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
|
||||
obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
|
||||
obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
|
||||
obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
|
||||
obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
|
||||
obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
|
||||
obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
|
||||
obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
|
||||
obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
|
||||
obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
|
||||
obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
|
||||
obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
|
||||
obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
|
||||
obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
|
||||
obj-$(CONFIG_BLK_DEV_CS5536) += cs5536.o
|
||||
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
|
||||
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
|
||||
obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
|
||||
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
|
||||
obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
|
||||
obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
|
||||
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
|
||||
obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
|
||||
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
|
||||
obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
|
||||
obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
|
||||
obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
|
||||
obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
|
||||
obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
|
||||
obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
|
||||
obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
|
||||
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
|
||||
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
|
||||
obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
|
||||
obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
|
||||
obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
|
||||
obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
|
||||
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
|
||||
|
||||
# Must appear at the end of the block
|
||||
obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
|
||||
|
||||
obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o
|
||||
|
||||
obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
|
||||
obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
|
||||
|
||||
ide-gd_mod-y += ide-gd.o
|
||||
ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
|
||||
|
||||
ifeq ($(CONFIG_IDE_GD_ATA), y)
|
||||
ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
|
||||
ifeq ($(CONFIG_IDE_PROC_FS), y)
|
||||
ide-gd_mod-y += ide-disk_proc.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_IDE_GD_ATAPI), y)
|
||||
ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
|
||||
ifeq ($(CONFIG_IDE_PROC_FS), y)
|
||||
ide-gd_mod-y += ide-floppy_proc.o
|
||||
endif
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_IDE_GD) += ide-gd_mod.o
|
||||
obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
|
||||
obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
|
||||
obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
|
||||
obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o
|
||||
obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o
|
||||
@@ -1,331 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
|
||||
* Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "aec62xx"
|
||||
|
||||
struct chipset_bus_clock_list_entry {
|
||||
u8 xfer_speed;
|
||||
u8 chipset_settings;
|
||||
u8 ultra_settings;
|
||||
};
|
||||
|
||||
static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
|
||||
{ XFER_UDMA_6, 0x31, 0x07 },
|
||||
{ XFER_UDMA_5, 0x31, 0x06 },
|
||||
{ XFER_UDMA_4, 0x31, 0x05 },
|
||||
{ XFER_UDMA_3, 0x31, 0x04 },
|
||||
{ XFER_UDMA_2, 0x31, 0x03 },
|
||||
{ XFER_UDMA_1, 0x31, 0x02 },
|
||||
{ XFER_UDMA_0, 0x31, 0x01 },
|
||||
|
||||
{ XFER_MW_DMA_2, 0x31, 0x00 },
|
||||
{ XFER_MW_DMA_1, 0x31, 0x00 },
|
||||
{ XFER_MW_DMA_0, 0x0a, 0x00 },
|
||||
{ XFER_PIO_4, 0x31, 0x00 },
|
||||
{ XFER_PIO_3, 0x33, 0x00 },
|
||||
{ XFER_PIO_2, 0x08, 0x00 },
|
||||
{ XFER_PIO_1, 0x0a, 0x00 },
|
||||
{ XFER_PIO_0, 0x00, 0x00 },
|
||||
{ 0, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
|
||||
{ XFER_UDMA_6, 0x41, 0x06 },
|
||||
{ XFER_UDMA_5, 0x41, 0x05 },
|
||||
{ XFER_UDMA_4, 0x41, 0x04 },
|
||||
{ XFER_UDMA_3, 0x41, 0x03 },
|
||||
{ XFER_UDMA_2, 0x41, 0x02 },
|
||||
{ XFER_UDMA_1, 0x41, 0x01 },
|
||||
{ XFER_UDMA_0, 0x41, 0x01 },
|
||||
|
||||
{ XFER_MW_DMA_2, 0x41, 0x00 },
|
||||
{ XFER_MW_DMA_1, 0x42, 0x00 },
|
||||
{ XFER_MW_DMA_0, 0x7a, 0x00 },
|
||||
{ XFER_PIO_4, 0x41, 0x00 },
|
||||
{ XFER_PIO_3, 0x43, 0x00 },
|
||||
{ XFER_PIO_2, 0x78, 0x00 },
|
||||
{ XFER_PIO_1, 0x7a, 0x00 },
|
||||
{ XFER_PIO_0, 0x70, 0x00 },
|
||||
{ 0, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
/*
|
||||
* TO DO: active tuning and correction of cards without a bios.
|
||||
*/
|
||||
static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
|
||||
{
|
||||
for ( ; chipset_table->xfer_speed ; chipset_table++)
|
||||
if (chipset_table->xfer_speed == speed) {
|
||||
return chipset_table->chipset_settings;
|
||||
}
|
||||
return chipset_table->chipset_settings;
|
||||
}
|
||||
|
||||
static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
|
||||
{
|
||||
for ( ; chipset_table->xfer_speed ; chipset_table++)
|
||||
if (chipset_table->xfer_speed == speed) {
|
||||
return chipset_table->ultra_settings;
|
||||
}
|
||||
return chipset_table->ultra_settings;
|
||||
}
|
||||
|
||||
static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
struct ide_host *host = pci_get_drvdata(dev);
|
||||
struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
|
||||
u16 d_conf = 0;
|
||||
u8 ultra = 0, ultra_conf = 0;
|
||||
u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
|
||||
const u8 speed = drive->dma_mode;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */
|
||||
pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
|
||||
tmp0 = pci_bus_clock_list(speed, bus_clock);
|
||||
d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf);
|
||||
pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
|
||||
|
||||
tmp1 = 0x00;
|
||||
tmp2 = 0x00;
|
||||
pci_read_config_byte(dev, 0x54, &ultra);
|
||||
tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
|
||||
ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
|
||||
tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
|
||||
pci_write_config_byte(dev, 0x54, tmp2);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
struct ide_host *host = pci_get_drvdata(dev);
|
||||
struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
|
||||
u8 unit = drive->dn & 1;
|
||||
u8 tmp1 = 0, tmp2 = 0;
|
||||
u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
|
||||
const u8 speed = drive->dma_mode;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* high 4-bits: Active, low 4-bits: Recovery */
|
||||
pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
|
||||
drive_conf = pci_bus_clock_list(speed, bus_clock);
|
||||
pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
|
||||
|
||||
pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
|
||||
tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
|
||||
ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
|
||||
tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
|
||||
pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
drive->dma_mode = drive->pio_mode;
|
||||
hwif->port_ops->set_dma_mode(hwif, drive);
|
||||
}
|
||||
|
||||
static int init_chipset_aec62xx(struct pci_dev *dev)
|
||||
{
|
||||
/* These are necessary to get AEC6280 Macintosh cards to work */
|
||||
if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
|
||||
(dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
|
||||
u8 reg49h = 0, reg4ah = 0;
|
||||
/* Clear reset and test bits. */
|
||||
pci_read_config_byte(dev, 0x49, ®49h);
|
||||
pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
|
||||
/* Enable chip interrupt output. */
|
||||
pci_read_config_byte(dev, 0x4a, ®4ah);
|
||||
pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
|
||||
/* Enable burst mode. */
|
||||
pci_read_config_byte(dev, 0x4a, ®4ah);
|
||||
pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 atp86x_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
|
||||
|
||||
pci_read_config_byte(dev, 0x49, &ata66);
|
||||
|
||||
return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops atp850_port_ops = {
|
||||
.set_pio_mode = aec_set_pio_mode,
|
||||
.set_dma_mode = aec6210_set_mode,
|
||||
};
|
||||
|
||||
static const struct ide_port_ops atp86x_port_ops = {
|
||||
.set_pio_mode = aec_set_pio_mode,
|
||||
.set_dma_mode = aec6260_set_mode,
|
||||
.cable_detect = atp86x_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_port_info aec62xx_chipsets[] = {
|
||||
{ /* 0: AEC6210 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_aec62xx,
|
||||
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
|
||||
.port_ops = &atp850_port_ops,
|
||||
.host_flags = IDE_HFLAG_SERIALIZE |
|
||||
IDE_HFLAG_NO_ATAPI_DMA |
|
||||
IDE_HFLAG_NO_DSC |
|
||||
IDE_HFLAG_OFF_BOARD,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA2,
|
||||
},
|
||||
{ /* 1: AEC6260 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_aec62xx,
|
||||
.port_ops = &atp86x_port_ops,
|
||||
.host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
|
||||
IDE_HFLAG_OFF_BOARD,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
},
|
||||
{ /* 2: AEC6260R */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_aec62xx,
|
||||
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
|
||||
.port_ops = &atp86x_port_ops,
|
||||
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
|
||||
IDE_HFLAG_NON_BOOTABLE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
},
|
||||
{ /* 3: AEC6280 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_aec62xx,
|
||||
.port_ops = &atp86x_port_ops,
|
||||
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
|
||||
IDE_HFLAG_OFF_BOARD,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
},
|
||||
{ /* 4: AEC6280R */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_aec62xx,
|
||||
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
|
||||
.port_ops = &atp86x_port_ops,
|
||||
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
|
||||
IDE_HFLAG_OFF_BOARD,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* aec62xx_init_one - called when a AEC is found
|
||||
* @dev: the aec62xx device
|
||||
* @id: the matching pci id
|
||||
*
|
||||
* Called when the PCI registration layer (or the IDE initialization)
|
||||
* finds a device matching our IDE device tables.
|
||||
*
|
||||
* NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
|
||||
* chips, pass a local copy of 'struct ide_port_info' down the call chain.
|
||||
*/
|
||||
|
||||
static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct chipset_bus_clock_list_entry *bus_clock;
|
||||
struct ide_port_info d;
|
||||
u8 idx = id->driver_data;
|
||||
int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
|
||||
int err;
|
||||
|
||||
if (bus_speed <= 33)
|
||||
bus_clock = aec6xxx_33_base;
|
||||
else
|
||||
bus_clock = aec6xxx_34_base;
|
||||
|
||||
err = pci_enable_device(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
d = aec62xx_chipsets[idx];
|
||||
|
||||
if (idx == 3 || idx == 4) {
|
||||
unsigned long dma_base = pci_resource_start(dev, 4);
|
||||
|
||||
if (inb(dma_base + 2) & 0x10) {
|
||||
printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected"
|
||||
"\n", pci_name(dev), (idx == 4) ? "R" : "");
|
||||
d.udma_mask = ATA_UDMA6;
|
||||
}
|
||||
}
|
||||
|
||||
err = ide_pci_init_one(dev, &d, (void *)bus_clock);
|
||||
if (err)
|
||||
pci_disable_device(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void aec62xx_remove(struct pci_dev *dev)
|
||||
{
|
||||
ide_pci_remove(dev);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
static const struct pci_device_id aec62xx_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
|
||||
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
|
||||
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
|
||||
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
|
||||
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
|
||||
|
||||
static struct pci_driver aec62xx_pci_driver = {
|
||||
.name = "AEC62xx_IDE",
|
||||
.id_table = aec62xx_pci_tbl,
|
||||
.probe = aec62xx_init_one,
|
||||
.remove = aec62xx_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init aec62xx_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&aec62xx_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit aec62xx_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&aec62xx_pci_driver);
|
||||
}
|
||||
|
||||
module_init(aec62xx_ide_init);
|
||||
module_exit(aec62xx_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("Andre Hedrick");
|
||||
MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,250 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 1996 Linus Torvalds & author (see below)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ALI M14xx chipset EIDE controller
|
||||
*
|
||||
* Works for ALI M1439/1443/1445/1487/1489 chipsets.
|
||||
*
|
||||
* Adapted from code developed by derekn@vw.ece.cmu.edu. -ml
|
||||
* Derek's notes follow:
|
||||
*
|
||||
* I think the code should be pretty understandable,
|
||||
* but I'll be happy to (try to) answer questions.
|
||||
*
|
||||
* The critical part is in the setupDrive function. The initRegisters
|
||||
* function doesn't seem to be necessary, but the DOS driver does it, so
|
||||
* I threw it in.
|
||||
*
|
||||
* I've only tested this on my system, which only has one disk. I posted
|
||||
* it to comp.sys.linux.hardware, so maybe some other people will try it
|
||||
* out.
|
||||
*
|
||||
* Derek Noonburg (derekn@ece.cmu.edu)
|
||||
* 95-sep-26
|
||||
*
|
||||
* Update 96-jul-13:
|
||||
*
|
||||
* I've since upgraded to two disks and a CD-ROM, with no trouble, and
|
||||
* I've also heard from several others who have used it successfully.
|
||||
* This driver appears to work with both the 1443/1445 and the 1487/1489
|
||||
* chipsets. I've added support for PIO mode 4 for the 1487. This
|
||||
* seems to work just fine on the 1443 also, although I'm not sure it's
|
||||
* advertised as supporting mode 4. (I've been running a WDC AC21200 in
|
||||
* mode 4 for a while now with no trouble.) -Derek
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "ali14xx"
|
||||
|
||||
/* port addresses for auto-detection */
|
||||
#define ALI_NUM_PORTS 4
|
||||
static const int ports[ALI_NUM_PORTS] __initconst =
|
||||
{ 0x074, 0x0f4, 0x034, 0x0e4 };
|
||||
|
||||
/* register initialization data */
|
||||
typedef struct { u8 reg, data; } RegInitializer;
|
||||
|
||||
static const RegInitializer initData[] __initconst = {
|
||||
{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
|
||||
{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
|
||||
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
|
||||
{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
|
||||
{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
|
||||
{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
|
||||
{0x35, 0x03}, {0x00, 0x00}
|
||||
};
|
||||
|
||||
/* timing parameter registers for each drive */
|
||||
static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
|
||||
{0x03, 0x26, 0x04, 0x27}, /* drive 0 */
|
||||
{0x05, 0x28, 0x06, 0x29}, /* drive 1 */
|
||||
{0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */
|
||||
{0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */
|
||||
};
|
||||
|
||||
static int basePort; /* base port address */
|
||||
static int regPort; /* port for register number */
|
||||
static int dataPort; /* port for register data */
|
||||
static u8 regOn; /* output to base port to access registers */
|
||||
static u8 regOff; /* output to base port to close registers */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Read a controller register.
|
||||
*/
|
||||
static inline u8 inReg(u8 reg)
|
||||
{
|
||||
outb_p(reg, regPort);
|
||||
return inb(dataPort);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a controller register.
|
||||
*/
|
||||
static void outReg(u8 data, u8 reg)
|
||||
{
|
||||
outb_p(reg, regPort);
|
||||
outb_p(data, dataPort);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(ali14xx_lock);
|
||||
|
||||
/*
|
||||
* Set PIO mode for the specified drive.
|
||||
* This function computes timing parameters
|
||||
* and sets controller registers accordingly.
|
||||
*/
|
||||
static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
int driveNum;
|
||||
int time1, time2;
|
||||
u8 param1, param2, param3, param4;
|
||||
unsigned long flags;
|
||||
int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
|
||||
|
||||
/* calculate timing, according to PIO mode */
|
||||
time1 = ide_pio_cycle_time(drive, pio);
|
||||
time2 = t->active;
|
||||
param3 = param1 = (time2 * bus_speed + 999) / 1000;
|
||||
param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
|
||||
if (pio < 3) {
|
||||
param3 += 8;
|
||||
param4 += 8;
|
||||
}
|
||||
printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
|
||||
drive->name, pio, time1, time2, param1, param2, param3, param4);
|
||||
|
||||
/* stuff timing parameters into controller registers */
|
||||
driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
|
||||
spin_lock_irqsave(&ali14xx_lock, flags);
|
||||
outb_p(regOn, basePort);
|
||||
outReg(param1, regTab[driveNum].reg1);
|
||||
outReg(param2, regTab[driveNum].reg2);
|
||||
outReg(param3, regTab[driveNum].reg3);
|
||||
outReg(param4, regTab[driveNum].reg4);
|
||||
outb_p(regOff, basePort);
|
||||
spin_unlock_irqrestore(&ali14xx_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Auto-detect the IDE controller port.
|
||||
*/
|
||||
static int __init findPort(void)
|
||||
{
|
||||
int i;
|
||||
u8 t;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < ALI_NUM_PORTS; ++i) {
|
||||
basePort = ports[i];
|
||||
regOff = inb(basePort);
|
||||
for (regOn = 0x30; regOn <= 0x33; ++regOn) {
|
||||
outb_p(regOn, basePort);
|
||||
if (inb(basePort) == regOn) {
|
||||
regPort = basePort + 4;
|
||||
dataPort = basePort + 8;
|
||||
t = inReg(0) & 0xf0;
|
||||
outb_p(regOff, basePort);
|
||||
local_irq_restore(flags);
|
||||
if (t != 0x50)
|
||||
return 0;
|
||||
return 1; /* success */
|
||||
}
|
||||
}
|
||||
outb_p(regOff, basePort);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize controller registers with default values.
|
||||
*/
|
||||
static int __init initRegisters(void)
|
||||
{
|
||||
const RegInitializer *p;
|
||||
u8 t;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
outb_p(regOn, basePort);
|
||||
for (p = initData; p->reg != 0; ++p)
|
||||
outReg(p->data, p->reg);
|
||||
outb_p(0x01, regPort);
|
||||
t = inb(regPort) & 0x01;
|
||||
outb_p(regOff, basePort);
|
||||
local_irq_restore(flags);
|
||||
return t;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops ali14xx_port_ops = {
|
||||
.set_pio_mode = ali14xx_set_pio_mode,
|
||||
};
|
||||
|
||||
static const struct ide_port_info ali14xx_port_info = {
|
||||
.name = DRV_NAME,
|
||||
.chipset = ide_ali14xx,
|
||||
.port_ops = &ali14xx_port_ops,
|
||||
.host_flags = IDE_HFLAG_NO_DMA,
|
||||
.pio_mask = ATA_PIO4,
|
||||
};
|
||||
|
||||
static int __init ali14xx_probe(void)
|
||||
{
|
||||
printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
|
||||
basePort, regOn);
|
||||
|
||||
/* initialize controller registers */
|
||||
if (!initRegisters()) {
|
||||
printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ide_legacy_device_add(&ali14xx_port_info, 0);
|
||||
}
|
||||
|
||||
static bool probe_ali14xx;
|
||||
|
||||
module_param_named(probe, probe_ali14xx, bool, 0);
|
||||
MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
|
||||
|
||||
static int __init ali14xx_init(void)
|
||||
{
|
||||
if (probe_ali14xx == 0)
|
||||
goto out;
|
||||
|
||||
/* auto-detect IDE controller port */
|
||||
if (findPort()) {
|
||||
if (ali14xx_probe())
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
printk(KERN_ERR "ali14xx: not found.\n");
|
||||
out:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
module_init(ali14xx_init);
|
||||
|
||||
MODULE_AUTHOR("see local file");
|
||||
MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,343 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
|
||||
* IDE driver for Linux.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik
|
||||
* Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* Based on the work of:
|
||||
* Andre Hedrick
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
#define DRV_NAME "amd74xx"
|
||||
|
||||
enum {
|
||||
AMD_IDE_CONFIG = 0x41,
|
||||
AMD_CABLE_DETECT = 0x42,
|
||||
AMD_DRIVE_TIMING = 0x48,
|
||||
AMD_8BIT_TIMING = 0x4e,
|
||||
AMD_ADDRESS_SETUP = 0x4c,
|
||||
AMD_UDMA_TIMING = 0x50,
|
||||
};
|
||||
|
||||
static unsigned int amd_80w;
|
||||
static unsigned int amd_clock;
|
||||
|
||||
static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
|
||||
static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
|
||||
|
||||
static inline u8 amd_offset(struct pci_dev *dev)
|
||||
{
|
||||
return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* amd_set_speed() writes timing values to the chipset registers
|
||||
*/
|
||||
|
||||
static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
|
||||
struct ide_timing *timing)
|
||||
{
|
||||
u8 t = 0, offset = amd_offset(dev);
|
||||
|
||||
pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
|
||||
t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
|
||||
pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
|
||||
|
||||
pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
|
||||
((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
|
||||
|
||||
pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
|
||||
((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
|
||||
|
||||
switch (udma_mask) {
|
||||
case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
|
||||
case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break;
|
||||
case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break;
|
||||
case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (timing->udma)
|
||||
pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t);
|
||||
}
|
||||
|
||||
/*
|
||||
* amd_set_drive() computes timing values and configures the chipset
|
||||
* to a desired transfer mode. It also can be called by upper layers.
|
||||
*/
|
||||
|
||||
static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
ide_drive_t *peer = ide_get_pair_dev(drive);
|
||||
struct ide_timing t, p;
|
||||
int T, UT;
|
||||
u8 udma_mask = hwif->ultra_mask;
|
||||
const u8 speed = drive->dma_mode;
|
||||
|
||||
T = 1000000000 / amd_clock;
|
||||
UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
|
||||
|
||||
ide_timing_compute(drive, speed, &t, T, UT);
|
||||
|
||||
if (peer) {
|
||||
ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
|
||||
ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
|
||||
}
|
||||
|
||||
if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
|
||||
if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
|
||||
|
||||
amd_set_speed(dev, drive->dn, udma_mask, &t);
|
||||
}
|
||||
|
||||
/*
|
||||
* amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
|
||||
*/
|
||||
|
||||
static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
drive->dma_mode = drive->pio_mode;
|
||||
amd_set_drive(hwif, drive);
|
||||
}
|
||||
|
||||
static void amd7409_cable_detect(struct pci_dev *dev)
|
||||
{
|
||||
/* no host side cable detection */
|
||||
amd_80w = 0x03;
|
||||
}
|
||||
|
||||
static void amd7411_cable_detect(struct pci_dev *dev)
|
||||
{
|
||||
int i;
|
||||
u32 u = 0;
|
||||
u8 t = 0, offset = amd_offset(dev);
|
||||
|
||||
pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
|
||||
pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
|
||||
amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
|
||||
for (i = 24; i >= 0; i -= 8)
|
||||
if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
|
||||
printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set "
|
||||
"cable bits correctly. Enabling workaround.\n",
|
||||
pci_name(dev));
|
||||
amd_80w |= (1 << (1 - (i >> 4)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The initialization callback. Initialize drive independent registers.
|
||||
*/
|
||||
|
||||
static int init_chipset_amd74xx(struct pci_dev *dev)
|
||||
{
|
||||
u8 t = 0, offset = amd_offset(dev);
|
||||
|
||||
/*
|
||||
* Check 80-wire cable presence.
|
||||
*/
|
||||
|
||||
if (dev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
|
||||
; /* no UDMA > 2 */
|
||||
else if (dev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
|
||||
amd7409_cable_detect(dev);
|
||||
else
|
||||
amd7411_cable_detect(dev);
|
||||
|
||||
/*
|
||||
* Take care of prefetch & postwrite.
|
||||
*/
|
||||
|
||||
pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
|
||||
/*
|
||||
* Check for broken FIFO support.
|
||||
*/
|
||||
if (dev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
|
||||
t &= 0x0f;
|
||||
else
|
||||
t |= 0xf0;
|
||||
pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 amd_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
if ((amd_80w >> hwif->channel) & 1)
|
||||
return ATA_CBL_PATA80;
|
||||
else
|
||||
return ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops amd_port_ops = {
|
||||
.set_pio_mode = amd_set_pio_mode,
|
||||
.set_dma_mode = amd_set_drive,
|
||||
.cable_detect = amd_cable_detect,
|
||||
};
|
||||
|
||||
#define IDE_HFLAGS_AMD \
|
||||
(IDE_HFLAG_PIO_NO_BLACKLIST | \
|
||||
IDE_HFLAG_POST_SET_MODE | \
|
||||
IDE_HFLAG_IO_32BIT | \
|
||||
IDE_HFLAG_UNMASK_IRQS)
|
||||
|
||||
#define DECLARE_AMD_DEV(swdma, udma) \
|
||||
{ \
|
||||
.name = DRV_NAME, \
|
||||
.init_chipset = init_chipset_amd74xx, \
|
||||
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
|
||||
.port_ops = &amd_port_ops, \
|
||||
.host_flags = IDE_HFLAGS_AMD, \
|
||||
.pio_mask = ATA_PIO5, \
|
||||
.swdma_mask = swdma, \
|
||||
.mwdma_mask = ATA_MWDMA2, \
|
||||
.udma_mask = udma, \
|
||||
}
|
||||
|
||||
#define DECLARE_NV_DEV(udma) \
|
||||
{ \
|
||||
.name = DRV_NAME, \
|
||||
.init_chipset = init_chipset_amd74xx, \
|
||||
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
|
||||
.port_ops = &amd_port_ops, \
|
||||
.host_flags = IDE_HFLAGS_AMD, \
|
||||
.pio_mask = ATA_PIO5, \
|
||||
.swdma_mask = ATA_SWDMA2, \
|
||||
.mwdma_mask = ATA_MWDMA2, \
|
||||
.udma_mask = udma, \
|
||||
}
|
||||
|
||||
static const struct ide_port_info amd74xx_chipsets[] = {
|
||||
/* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2),
|
||||
/* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4),
|
||||
/* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
|
||||
/* 3: AMD8111 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6),
|
||||
|
||||
/* 4: NFORCE */ DECLARE_NV_DEV(ATA_UDMA5),
|
||||
/* 5: >= NFORCE2 */ DECLARE_NV_DEV(ATA_UDMA6),
|
||||
|
||||
/* 6: AMD5536 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
|
||||
};
|
||||
|
||||
static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ide_port_info d;
|
||||
u8 idx = id->driver_data;
|
||||
|
||||
d = amd74xx_chipsets[idx];
|
||||
|
||||
/*
|
||||
* Check for bad SWDMA and incorrectly wired Serenade mainboards.
|
||||
*/
|
||||
if (idx == 1) {
|
||||
if (dev->revision <= 7)
|
||||
d.swdma_mask = 0;
|
||||
d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
|
||||
} else if (idx == 3) {
|
||||
if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
|
||||
dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
|
||||
d.udma_mask = ATA_UDMA5;
|
||||
}
|
||||
|
||||
/*
|
||||
* It seems that on some nVidia controllers using AltStatus
|
||||
* register can be unreliable so default to Status register
|
||||
* if the device is in Compatibility Mode.
|
||||
*/
|
||||
if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
|
||||
ide_pci_is_in_compatibility_mode(dev))
|
||||
d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
|
||||
|
||||
printk(KERN_INFO "%s %s: UDMA%s controller\n",
|
||||
d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
|
||||
|
||||
/*
|
||||
* Determine the system bus clock.
|
||||
*/
|
||||
amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
|
||||
|
||||
switch (amd_clock) {
|
||||
case 33000: amd_clock = 33333; break;
|
||||
case 37000: amd_clock = 37500; break;
|
||||
case 41000: amd_clock = 41666; break;
|
||||
}
|
||||
|
||||
if (amd_clock < 20000 || amd_clock > 50000) {
|
||||
printk(KERN_WARNING "%s: User given PCI clock speed impossible"
|
||||
" (%d), using 33 MHz instead.\n",
|
||||
d.name, amd_clock);
|
||||
amd_clock = 33333;
|
||||
}
|
||||
|
||||
return ide_pci_init_one(dev, &d, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id amd74xx_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 2 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 2 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 3 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 4 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 5 },
|
||||
#ifdef CONFIG_BLK_DEV_IDE_SATA
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 5 },
|
||||
#endif
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 5 },
|
||||
#ifdef CONFIG_BLK_DEV_IDE_SATA
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 5 },
|
||||
#endif
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 5 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 6 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
|
||||
|
||||
static struct pci_driver amd74xx_pci_driver = {
|
||||
.name = "AMD_IDE",
|
||||
.id_table = amd74xx_pci_tbl,
|
||||
.probe = amd74xx_probe,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init amd74xx_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&amd74xx_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit amd74xx_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&amd74xx_pci_driver);
|
||||
}
|
||||
|
||||
module_init(amd74xx_ide_init);
|
||||
module_exit(amd74xx_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("AMD PCI IDE driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,212 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2003 ATI Inc. <hyu@ati.com>
|
||||
* Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRV_NAME "atiixp"
|
||||
|
||||
#define ATIIXP_IDE_PIO_TIMING 0x40
|
||||
#define ATIIXP_IDE_MDMA_TIMING 0x44
|
||||
#define ATIIXP_IDE_PIO_CONTROL 0x48
|
||||
#define ATIIXP_IDE_PIO_MODE 0x4a
|
||||
#define ATIIXP_IDE_UDMA_CONTROL 0x54
|
||||
#define ATIIXP_IDE_UDMA_MODE 0x56
|
||||
|
||||
struct atiixp_ide_timing {
|
||||
u8 command_width;
|
||||
u8 recover_width;
|
||||
};
|
||||
|
||||
static struct atiixp_ide_timing pio_timing[] = {
|
||||
{ 0x05, 0x0d },
|
||||
{ 0x04, 0x07 },
|
||||
{ 0x03, 0x04 },
|
||||
{ 0x02, 0x02 },
|
||||
{ 0x02, 0x00 },
|
||||
};
|
||||
|
||||
static struct atiixp_ide_timing mdma_timing[] = {
|
||||
{ 0x07, 0x07 },
|
||||
{ 0x02, 0x01 },
|
||||
{ 0x02, 0x00 },
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(atiixp_lock);
|
||||
|
||||
/**
|
||||
* atiixp_set_pio_mode - set host controller for PIO mode
|
||||
* @hwif: port
|
||||
* @drive: drive
|
||||
*
|
||||
* Set the interface PIO mode.
|
||||
*/
|
||||
|
||||
static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
unsigned long flags;
|
||||
int timing_shift = (drive->dn ^ 1) * 8;
|
||||
u32 pio_timing_data;
|
||||
u16 pio_mode_data;
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
|
||||
spin_lock_irqsave(&atiixp_lock, flags);
|
||||
|
||||
pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
|
||||
pio_mode_data &= ~(0x07 << (drive->dn * 4));
|
||||
pio_mode_data |= (pio << (drive->dn * 4));
|
||||
pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
|
||||
|
||||
pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
|
||||
pio_timing_data &= ~(0xff << timing_shift);
|
||||
pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
|
||||
(pio_timing[pio].command_width << (timing_shift + 4));
|
||||
pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
|
||||
|
||||
spin_unlock_irqrestore(&atiixp_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* atiixp_set_dma_mode - set host controller for DMA mode
|
||||
* @hwif: port
|
||||
* @drive: drive
|
||||
*
|
||||
* Set a ATIIXP host controller to the desired DMA mode. This involves
|
||||
* programming the right timing data into the PCI configuration space.
|
||||
*/
|
||||
|
||||
static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
unsigned long flags;
|
||||
int timing_shift = (drive->dn ^ 1) * 8;
|
||||
u32 tmp32;
|
||||
u16 tmp16;
|
||||
u16 udma_ctl = 0;
|
||||
const u8 speed = drive->dma_mode;
|
||||
|
||||
spin_lock_irqsave(&atiixp_lock, flags);
|
||||
|
||||
pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
|
||||
|
||||
if (speed >= XFER_UDMA_0) {
|
||||
pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
|
||||
tmp16 &= ~(0x07 << (drive->dn * 4));
|
||||
tmp16 |= ((speed & 0x07) << (drive->dn * 4));
|
||||
pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
|
||||
|
||||
udma_ctl |= (1 << drive->dn);
|
||||
} else if (speed >= XFER_MW_DMA_0) {
|
||||
u8 i = speed & 0x03;
|
||||
|
||||
pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
|
||||
tmp32 &= ~(0xff << timing_shift);
|
||||
tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
|
||||
(mdma_timing[i].command_width << (timing_shift + 4));
|
||||
pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
|
||||
|
||||
udma_ctl &= ~(1 << drive->dn);
|
||||
}
|
||||
|
||||
pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
|
||||
|
||||
spin_unlock_irqrestore(&atiixp_lock, flags);
|
||||
}
|
||||
|
||||
static u8 atiixp_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(hwif->dev);
|
||||
u8 udma_mode = 0, ch = hwif->channel;
|
||||
|
||||
pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
|
||||
|
||||
if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
|
||||
return ATA_CBL_PATA80;
|
||||
else
|
||||
return ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops atiixp_port_ops = {
|
||||
.set_pio_mode = atiixp_set_pio_mode,
|
||||
.set_dma_mode = atiixp_set_dma_mode,
|
||||
.cable_detect = atiixp_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_port_info atiixp_pci_info[] = {
|
||||
{ /* 0: IXP200/300/400/700 */
|
||||
.name = DRV_NAME,
|
||||
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
|
||||
.port_ops = &atiixp_port_ops,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
},
|
||||
{ /* 1: IXP600 */
|
||||
.name = DRV_NAME,
|
||||
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
|
||||
.port_ops = &atiixp_port_ops,
|
||||
.host_flags = IDE_HFLAG_SINGLE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* atiixp_init_one - called when a ATIIXP is found
|
||||
* @dev: the atiixp device
|
||||
* @id: the matching pci id
|
||||
*
|
||||
* Called when the PCI registration layer (or the IDE initialization)
|
||||
* finds a device matching our IDE device tables.
|
||||
*/
|
||||
|
||||
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id atiixp_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
|
||||
|
||||
static struct pci_driver atiixp_pci_driver = {
|
||||
.name = "ATIIXP_IDE",
|
||||
.id_table = atiixp_pci_tbl,
|
||||
.probe = atiixp_init_one,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init atiixp_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&atiixp_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit atiixp_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&atiixp_pci_driver);
|
||||
}
|
||||
|
||||
module_init(atiixp_ide_init);
|
||||
module_exit(atiixp_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("HUI YU");
|
||||
MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* Amiga Buddha, Catweasel and X-Surf IDE Driver
|
||||
*
|
||||
* Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
|
||||
*
|
||||
* This driver was written based on the specifications in README.buddha and
|
||||
* the X-Surf info from Inside_XSurf.txt available at
|
||||
* http://www.jschoenfeld.com
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*
|
||||
* TODO:
|
||||
* - test it :-)
|
||||
* - tune the timings using the speed-register
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/zorro.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
|
||||
|
||||
/*
|
||||
* The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
|
||||
*/
|
||||
|
||||
#define BUDDHA_NUM_HWIFS 2
|
||||
#define CATWEASEL_NUM_HWIFS 3
|
||||
#define XSURF_NUM_HWIFS 2
|
||||
|
||||
#define MAX_NUM_HWIFS 3
|
||||
|
||||
/*
|
||||
* Bases of the IDE interfaces (relative to the board address)
|
||||
*/
|
||||
|
||||
#define BUDDHA_BASE1 0x800
|
||||
#define BUDDHA_BASE2 0xa00
|
||||
#define BUDDHA_BASE3 0xc00
|
||||
|
||||
#define XSURF_BASE1 0xb000 /* 2.5" Interface */
|
||||
#define XSURF_BASE2 0xd000 /* 3.5" Interface */
|
||||
|
||||
static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
|
||||
BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
|
||||
};
|
||||
|
||||
static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
|
||||
XSURF_BASE1, XSURF_BASE2
|
||||
};
|
||||
|
||||
/*
|
||||
* Offsets from one of the above bases
|
||||
*/
|
||||
|
||||
#define BUDDHA_CONTROL 0x11a
|
||||
|
||||
/*
|
||||
* Other registers
|
||||
*/
|
||||
|
||||
#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */
|
||||
#define BUDDHA_IRQ2 0xf40 /* interrupt */
|
||||
#define BUDDHA_IRQ3 0xf80
|
||||
|
||||
#define XSURF_IRQ1 0x7e
|
||||
#define XSURF_IRQ2 0x7e
|
||||
|
||||
static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
|
||||
BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
|
||||
};
|
||||
|
||||
static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
|
||||
XSURF_IRQ1, XSURF_IRQ2
|
||||
};
|
||||
|
||||
#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */
|
||||
|
||||
|
||||
/*
|
||||
* Board information
|
||||
*/
|
||||
|
||||
typedef enum BuddhaType_Enum {
|
||||
BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
|
||||
} BuddhaType;
|
||||
|
||||
static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
|
||||
|
||||
/*
|
||||
* Check and acknowledge the interrupt status
|
||||
*/
|
||||
|
||||
static int buddha_test_irq(ide_hwif_t *hwif)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
ch = z_readb(hwif->io_ports.irq_addr);
|
||||
if (!(ch & 0x80))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void xsurf_clear_irq(ide_drive_t *drive)
|
||||
{
|
||||
/*
|
||||
* X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0
|
||||
*/
|
||||
z_writeb(0, drive->hwif->io_ports.irq_addr);
|
||||
}
|
||||
|
||||
static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
|
||||
unsigned long ctl, unsigned long irq_port)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(hw, 0, sizeof(*hw));
|
||||
|
||||
hw->io_ports.data_addr = base;
|
||||
|
||||
for (i = 1; i < 8; i++)
|
||||
hw->io_ports_array[i] = base + 2 + i * 4;
|
||||
|
||||
hw->io_ports.ctl_addr = ctl;
|
||||
hw->io_ports.irq_addr = irq_port;
|
||||
|
||||
hw->irq = IRQ_AMIGA_PORTS;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops buddha_port_ops = {
|
||||
.test_irq = buddha_test_irq,
|
||||
};
|
||||
|
||||
static const struct ide_port_ops xsurf_port_ops = {
|
||||
.clear_irq = xsurf_clear_irq,
|
||||
.test_irq = buddha_test_irq,
|
||||
};
|
||||
|
||||
static const struct ide_port_info buddha_port_info = {
|
||||
.port_ops = &buddha_port_ops,
|
||||
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
|
||||
.irq_flags = IRQF_SHARED,
|
||||
.chipset = ide_generic,
|
||||
};
|
||||
|
||||
/*
|
||||
* Probe for a Buddha or Catweasel IDE interface
|
||||
*/
|
||||
|
||||
static int __init buddha_init(void)
|
||||
{
|
||||
struct zorro_dev *z = NULL;
|
||||
u_long buddha_board = 0;
|
||||
BuddhaType type;
|
||||
int buddha_num_hwifs, i;
|
||||
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
unsigned long board;
|
||||
struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
|
||||
struct ide_port_info d = buddha_port_info;
|
||||
|
||||
if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
|
||||
buddha_num_hwifs = BUDDHA_NUM_HWIFS;
|
||||
type=BOARD_BUDDHA;
|
||||
} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
|
||||
buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
|
||||
type=BOARD_CATWEASEL;
|
||||
} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
|
||||
buddha_num_hwifs = XSURF_NUM_HWIFS;
|
||||
type=BOARD_XSURF;
|
||||
d.port_ops = &xsurf_port_ops;
|
||||
} else
|
||||
continue;
|
||||
|
||||
board = z->resource.start;
|
||||
|
||||
if(type != BOARD_XSURF) {
|
||||
if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
|
||||
continue;
|
||||
} else {
|
||||
if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
|
||||
continue;
|
||||
if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
|
||||
goto fail_base2;
|
||||
if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
|
||||
release_mem_region(board+XSURF_BASE2, 0x1000);
|
||||
fail_base2:
|
||||
release_mem_region(board+XSURF_BASE1, 0x1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
buddha_board = (unsigned long)ZTWO_VADDR(board);
|
||||
|
||||
/* write to BUDDHA_IRQ_MR to enable the board IRQ */
|
||||
/* X-Surf doesn't have this. IRQs are always on */
|
||||
if (type != BOARD_XSURF)
|
||||
z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
|
||||
|
||||
printk(KERN_INFO "ide: %s IDE controller\n",
|
||||
buddha_board_name[type]);
|
||||
|
||||
for (i = 0; i < buddha_num_hwifs; i++) {
|
||||
unsigned long base, ctl, irq_port;
|
||||
|
||||
if (type != BOARD_XSURF) {
|
||||
base = buddha_board + buddha_bases[i];
|
||||
ctl = base + BUDDHA_CONTROL;
|
||||
irq_port = buddha_board + buddha_irqports[i];
|
||||
} else {
|
||||
base = buddha_board + xsurf_bases[i];
|
||||
/* X-Surf has no CS1* (Control/AltStat) */
|
||||
ctl = 0;
|
||||
irq_port = buddha_board + xsurf_irqports[i];
|
||||
}
|
||||
|
||||
buddha_setup_ports(&hw[i], base, ctl, irq_port);
|
||||
|
||||
hws[i] = &hw[i];
|
||||
}
|
||||
|
||||
ide_host_add(&d, hws, i, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(buddha_init);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,452 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
|
||||
* Due to massive hardware bugs, UltraDMA is only supported
|
||||
* on the 646U2 and not on the 646U.
|
||||
*
|
||||
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
|
||||
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
|
||||
*
|
||||
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
|
||||
* Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
|
||||
* Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "cmd64x"
|
||||
|
||||
/*
|
||||
* CMD64x specific registers definition.
|
||||
*/
|
||||
#define CFR 0x50
|
||||
#define CFR_INTR_CH0 0x04
|
||||
|
||||
#define CMDTIM 0x52
|
||||
#define ARTTIM0 0x53
|
||||
#define DRWTIM0 0x54
|
||||
#define ARTTIM1 0x55
|
||||
#define DRWTIM1 0x56
|
||||
#define ARTTIM23 0x57
|
||||
#define ARTTIM23_DIS_RA2 0x04
|
||||
#define ARTTIM23_DIS_RA3 0x08
|
||||
#define ARTTIM23_INTR_CH1 0x10
|
||||
#define DRWTIM2 0x58
|
||||
#define BRST 0x59
|
||||
#define DRWTIM3 0x5b
|
||||
|
||||
#define BMIDECR0 0x70
|
||||
#define MRDMODE 0x71
|
||||
#define MRDMODE_INTR_CH0 0x04
|
||||
#define MRDMODE_INTR_CH1 0x08
|
||||
#define UDIDETCR0 0x73
|
||||
#define DTPR0 0x74
|
||||
#define BMIDECR1 0x78
|
||||
#define BMIDECSR 0x79
|
||||
#define UDIDETCR1 0x7B
|
||||
#define DTPR1 0x7C
|
||||
|
||||
static void cmd64x_program_timings(ide_drive_t *drive, u8 mode)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
|
||||
int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
|
||||
const unsigned long T = 1000000 / bus_speed;
|
||||
static const u8 recovery_values[] =
|
||||
{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
|
||||
static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
|
||||
static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
|
||||
static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
|
||||
struct ide_timing t;
|
||||
u8 arttim = 0;
|
||||
|
||||
if (drive->dn >= ARRAY_SIZE(drwtim_regs))
|
||||
return;
|
||||
|
||||
ide_timing_compute(drive, mode, &t, T, 0);
|
||||
|
||||
/*
|
||||
* In case we've got too long recovery phase, try to lengthen
|
||||
* the active phase
|
||||
*/
|
||||
if (t.recover > 16) {
|
||||
t.active += t.recover - 16;
|
||||
t.recover = 16;
|
||||
}
|
||||
if (t.active > 16) /* shouldn't actually happen... */
|
||||
t.active = 16;
|
||||
|
||||
/*
|
||||
* Convert values to internal chipset representation
|
||||
*/
|
||||
t.recover = recovery_values[t.recover];
|
||||
t.active &= 0x0f;
|
||||
|
||||
/* Program the active/recovery counts into the DRWTIM register */
|
||||
pci_write_config_byte(dev, drwtim_regs[drive->dn],
|
||||
(t.active << 4) | t.recover);
|
||||
|
||||
/*
|
||||
* The primary channel has individual address setup timing registers
|
||||
* for each drive and the hardware selects the slowest timing itself.
|
||||
* The secondary channel has one common register and we have to select
|
||||
* the slowest address setup timing ourselves.
|
||||
*/
|
||||
if (hwif->channel) {
|
||||
ide_drive_t *pair = ide_get_pair_dev(drive);
|
||||
|
||||
if (pair) {
|
||||
struct ide_timing tp;
|
||||
|
||||
ide_timing_compute(pair, pair->pio_mode, &tp, T, 0);
|
||||
ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP);
|
||||
if (pair->dma_mode) {
|
||||
ide_timing_compute(pair, pair->dma_mode,
|
||||
&tp, T, 0);
|
||||
ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (t.setup > 5) /* shouldn't actually happen... */
|
||||
t.setup = 5;
|
||||
|
||||
/*
|
||||
* Program the address setup clocks into the ARTTIM registers.
|
||||
* Avoid clearing the secondary channel's interrupt bit.
|
||||
*/
|
||||
(void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
|
||||
if (hwif->channel)
|
||||
arttim &= ~ARTTIM23_INTR_CH1;
|
||||
arttim &= ~0xc0;
|
||||
arttim |= setup_values[t.setup];
|
||||
(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to set drive's PIO mode.
|
||||
* Special cases are 8: prefetch off, 9: prefetch on (both never worked)
|
||||
*/
|
||||
|
||||
static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
|
||||
/*
|
||||
* Filter out the prefetch control values
|
||||
* to prevent PIO5 from being programmed
|
||||
*/
|
||||
if (pio == 8 || pio == 9)
|
||||
return;
|
||||
|
||||
cmd64x_program_timings(drive, XFER_PIO_0 + pio);
|
||||
}
|
||||
|
||||
static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
u8 unit = drive->dn & 0x01;
|
||||
u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
|
||||
const u8 speed = drive->dma_mode;
|
||||
|
||||
pci_read_config_byte(dev, pciU, ®U);
|
||||
regU &= ~(unit ? 0xCA : 0x35);
|
||||
|
||||
switch(speed) {
|
||||
case XFER_UDMA_5:
|
||||
regU |= unit ? 0x0A : 0x05;
|
||||
break;
|
||||
case XFER_UDMA_4:
|
||||
regU |= unit ? 0x4A : 0x15;
|
||||
break;
|
||||
case XFER_UDMA_3:
|
||||
regU |= unit ? 0x8A : 0x25;
|
||||
break;
|
||||
case XFER_UDMA_2:
|
||||
regU |= unit ? 0x42 : 0x11;
|
||||
break;
|
||||
case XFER_UDMA_1:
|
||||
regU |= unit ? 0x82 : 0x21;
|
||||
break;
|
||||
case XFER_UDMA_0:
|
||||
regU |= unit ? 0xC2 : 0x31;
|
||||
break;
|
||||
case XFER_MW_DMA_2:
|
||||
case XFER_MW_DMA_1:
|
||||
case XFER_MW_DMA_0:
|
||||
cmd64x_program_timings(drive, speed);
|
||||
break;
|
||||
}
|
||||
|
||||
pci_write_config_byte(dev, pciU, regU);
|
||||
}
|
||||
|
||||
static void cmd648_clear_irq(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
unsigned long base = pci_resource_start(dev, 4);
|
||||
u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
|
||||
MRDMODE_INTR_CH0;
|
||||
u8 mrdmode = inb(base + 1);
|
||||
|
||||
/* clear the interrupt bit */
|
||||
outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
|
||||
base + 1);
|
||||
}
|
||||
|
||||
static void cmd64x_clear_irq(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
int irq_reg = hwif->channel ? ARTTIM23 : CFR;
|
||||
u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
|
||||
CFR_INTR_CH0;
|
||||
u8 irq_stat = 0;
|
||||
|
||||
(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
|
||||
/* clear the interrupt bit */
|
||||
(void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
|
||||
}
|
||||
|
||||
static int cmd648_test_irq(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
unsigned long base = pci_resource_start(dev, 4);
|
||||
u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
|
||||
MRDMODE_INTR_CH0;
|
||||
u8 mrdmode = inb(base + 1);
|
||||
|
||||
pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n",
|
||||
hwif->name, mrdmode, irq_mask);
|
||||
|
||||
return (mrdmode & irq_mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int cmd64x_test_irq(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
int irq_reg = hwif->channel ? ARTTIM23 : CFR;
|
||||
u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
|
||||
CFR_INTR_CH0;
|
||||
u8 irq_stat = 0;
|
||||
|
||||
(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
|
||||
|
||||
pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n",
|
||||
hwif->name, irq_stat, irq_mask);
|
||||
|
||||
return (irq_stat & irq_mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
|
||||
* event order for DMA transfers.
|
||||
*/
|
||||
|
||||
static int cmd646_1_dma_end(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
u8 dma_stat = 0, dma_cmd = 0;
|
||||
|
||||
/* get DMA status */
|
||||
dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
|
||||
/* read DMA command state */
|
||||
dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
|
||||
/* stop DMA */
|
||||
outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
|
||||
/* clear the INTR & ERROR bits */
|
||||
outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
|
||||
/* verify good DMA status */
|
||||
return (dma_stat & 7) != 4;
|
||||
}
|
||||
|
||||
static int init_chipset_cmd64x(struct pci_dev *dev)
|
||||
{
|
||||
u8 mrdmode = 0;
|
||||
|
||||
/* Set a good latency timer and cache line size value. */
|
||||
(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
|
||||
/* FIXME: pci_set_master() to ensure a good latency timer value */
|
||||
|
||||
/*
|
||||
* Enable interrupts, select MEMORY READ LINE for reads.
|
||||
*
|
||||
* NOTE: although not mentioned in the PCI0646U specs,
|
||||
* bits 0-1 are write only and won't be read back as
|
||||
* set or not -- PCI0646U2 specs clarify this point.
|
||||
*/
|
||||
(void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
|
||||
mrdmode &= ~0x30;
|
||||
(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 cmd64x_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01;
|
||||
|
||||
switch (dev->device) {
|
||||
case PCI_DEVICE_ID_CMD_648:
|
||||
case PCI_DEVICE_ID_CMD_649:
|
||||
pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
|
||||
return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
|
||||
default:
|
||||
return ATA_CBL_PATA40;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cmd64x_port_ops = {
|
||||
.set_pio_mode = cmd64x_set_pio_mode,
|
||||
.set_dma_mode = cmd64x_set_dma_mode,
|
||||
.clear_irq = cmd64x_clear_irq,
|
||||
.test_irq = cmd64x_test_irq,
|
||||
.cable_detect = cmd64x_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_port_ops cmd648_port_ops = {
|
||||
.set_pio_mode = cmd64x_set_pio_mode,
|
||||
.set_dma_mode = cmd64x_set_dma_mode,
|
||||
.clear_irq = cmd648_clear_irq,
|
||||
.test_irq = cmd648_test_irq,
|
||||
.cable_detect = cmd64x_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_dma_ops cmd646_rev1_dma_ops = {
|
||||
.dma_host_set = ide_dma_host_set,
|
||||
.dma_setup = ide_dma_setup,
|
||||
.dma_start = ide_dma_start,
|
||||
.dma_end = cmd646_1_dma_end,
|
||||
.dma_test_irq = ide_dma_test_irq,
|
||||
.dma_lost_irq = ide_dma_lost_irq,
|
||||
.dma_timer_expiry = ide_dma_sff_timer_expiry,
|
||||
.dma_sff_read_status = ide_dma_sff_read_status,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cmd64x_chipsets[] = {
|
||||
{ /* 0: CMD643 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_cmd64x,
|
||||
.enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
|
||||
.port_ops = &cmd64x_port_ops,
|
||||
.host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
|
||||
IDE_HFLAG_ABUSE_PREFETCH |
|
||||
IDE_HFLAG_SERIALIZE,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = 0x00, /* no udma */
|
||||
},
|
||||
{ /* 1: CMD646 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_cmd64x,
|
||||
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
|
||||
.port_ops = &cmd648_port_ops,
|
||||
.host_flags = IDE_HFLAG_ABUSE_PREFETCH |
|
||||
IDE_HFLAG_SERIALIZE,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA2,
|
||||
},
|
||||
{ /* 2: CMD648 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_cmd64x,
|
||||
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
|
||||
.port_ops = &cmd648_port_ops,
|
||||
.host_flags = IDE_HFLAG_ABUSE_PREFETCH,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
},
|
||||
{ /* 3: CMD649 */
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_cmd64x,
|
||||
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
|
||||
.port_ops = &cmd648_port_ops,
|
||||
.host_flags = IDE_HFLAG_ABUSE_PREFETCH,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
}
|
||||
};
|
||||
|
||||
static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ide_port_info d;
|
||||
u8 idx = id->driver_data;
|
||||
|
||||
d = cmd64x_chipsets[idx];
|
||||
|
||||
if (idx == 1) {
|
||||
/*
|
||||
* UltraDMA only supported on PCI646U and PCI646U2, which
|
||||
* correspond to revisions 0x03, 0x05 and 0x07 respectively.
|
||||
* Actually, although the CMD tech support people won't
|
||||
* tell me the details, the 0x03 revision cannot support
|
||||
* UDMA correctly without hardware modifications, and even
|
||||
* then it only works with Quantum disks due to some
|
||||
* hold time assumptions in the 646U part which are fixed
|
||||
* in the 646U2.
|
||||
*
|
||||
* So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
|
||||
*/
|
||||
if (dev->revision < 5) {
|
||||
d.udma_mask = 0x00;
|
||||
/*
|
||||
* The original PCI0646 didn't have the primary
|
||||
* channel enable bit, it appeared starting with
|
||||
* PCI0646U (i.e. revision ID 3).
|
||||
*/
|
||||
if (dev->revision < 3) {
|
||||
d.enablebits[0].reg = 0;
|
||||
d.port_ops = &cmd64x_port_ops;
|
||||
if (dev->revision == 1)
|
||||
d.dma_ops = &cmd646_rev1_dma_ops;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ide_pci_init_one(dev, &d, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cmd64x_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
|
||||
|
||||
static struct pci_driver cmd64x_pci_driver = {
|
||||
.name = "CMD64x_IDE",
|
||||
.id_table = cmd64x_pci_tbl,
|
||||
.probe = cmd64x_init_one,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init cmd64x_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&cmd64x_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cmd64x_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cmd64x_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cmd64x_ide_init);
|
||||
module_exit(cmd64x_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* IDE tuning and bus mastering support for the CS5510/CS5520
|
||||
* chipsets
|
||||
*
|
||||
* The CS5510/CS5520 are slightly unusual devices. Unlike the
|
||||
* typical IDE controllers they do bus mastering with the drive in
|
||||
* PIO mode and smarter silicon.
|
||||
*
|
||||
* The practical upshot of this is that we must always tune the
|
||||
* drive for the right PIO mode. We must also ignore all the blacklists
|
||||
* and the drive bus mastering DMA information.
|
||||
*
|
||||
* *** This driver is strictly experimental ***
|
||||
*
|
||||
* (c) Copyright Red Hat Inc 2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* For the avoidance of doubt the "preferred form" of this code is one which
|
||||
* is in an open non patent encumbered format. Where cryptographic key signing
|
||||
* forms part of the process of creating an executable the information
|
||||
* including keys needed to generate an equivalently functional executable
|
||||
* are deemed to be part of the source code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#define DRV_NAME "cs5520"
|
||||
|
||||
struct pio_clocks
|
||||
{
|
||||
int address;
|
||||
int assert;
|
||||
int recovery;
|
||||
};
|
||||
|
||||
static struct pio_clocks cs5520_pio_clocks[]={
|
||||
{3, 6, 11},
|
||||
{2, 5, 6},
|
||||
{1, 4, 3},
|
||||
{1, 3, 2},
|
||||
{1, 2, 1}
|
||||
};
|
||||
|
||||
static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(hwif->dev);
|
||||
int controller = drive->dn > 1 ? 1 : 0;
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
|
||||
/* 8bit CAT/CRT - 8bit command timing for channel */
|
||||
pci_write_config_byte(pdev, 0x62 + controller,
|
||||
(cs5520_pio_clocks[pio].recovery << 4) |
|
||||
(cs5520_pio_clocks[pio].assert));
|
||||
|
||||
/* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */
|
||||
|
||||
/* FIXME: should these use address ? */
|
||||
/* Data read timing */
|
||||
pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1),
|
||||
(cs5520_pio_clocks[pio].recovery << 4) |
|
||||
(cs5520_pio_clocks[pio].assert));
|
||||
/* Write command timing */
|
||||
pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
|
||||
(cs5520_pio_clocks[pio].recovery << 4) |
|
||||
(cs5520_pio_clocks[pio].assert));
|
||||
}
|
||||
|
||||
static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
printk(KERN_ERR "cs55x0: bad ide timing.\n");
|
||||
|
||||
drive->pio_mode = XFER_PIO_0 + 0;
|
||||
cs5520_set_pio_mode(hwif, drive);
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cs5520_port_ops = {
|
||||
.set_pio_mode = cs5520_set_pio_mode,
|
||||
.set_dma_mode = cs5520_set_dma_mode,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cyrix_chipset = {
|
||||
.name = DRV_NAME,
|
||||
.enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } },
|
||||
.port_ops = &cs5520_port_ops,
|
||||
.host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520,
|
||||
.pio_mask = ATA_PIO4,
|
||||
};
|
||||
|
||||
/*
|
||||
* The 5510/5520 are a bit weird. They don't quite set up the way
|
||||
* the PCI helper layer expects so we must do much of the set up
|
||||
* work longhand.
|
||||
*/
|
||||
|
||||
static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct ide_port_info *d = &cyrix_chipset;
|
||||
struct ide_hw hw[2], *hws[] = { NULL, NULL };
|
||||
|
||||
ide_setup_pci_noise(dev, d);
|
||||
|
||||
/* We must not grab the entire device, it has 'ISA' space in its
|
||||
* BARS too and we will freak out other bits of the kernel
|
||||
*/
|
||||
if (pci_enable_device_io(dev)) {
|
||||
printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
pci_set_master(dev);
|
||||
if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) {
|
||||
printk(KERN_WARNING "%s: No suitable DMA available.\n",
|
||||
d->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the chipset is configured we can let the core
|
||||
* do all the device setup for us
|
||||
*/
|
||||
|
||||
ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
|
||||
hw[0].irq = 14;
|
||||
hw[1].irq = 15;
|
||||
|
||||
return ide_host_add(d, hws, 2, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cs5520_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 },
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
|
||||
|
||||
static struct pci_driver cs5520_pci_driver = {
|
||||
.name = "Cyrix_IDE",
|
||||
.id_table = cs5520_pci_tbl,
|
||||
.probe = cs5520_init_one,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init cs5520_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&cs5520_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cs5520_ide_init);
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
|
||||
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
|
||||
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* May be copied or modified under the terms of the GNU General Public License
|
||||
*
|
||||
* Development of this chipset driver was funded
|
||||
* by the nice folks at National Semiconductor.
|
||||
*
|
||||
* Documentation:
|
||||
* CS5530 documentation available from National Semiconductor.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "cs5530"
|
||||
|
||||
/*
|
||||
* Here are the standard PIO mode 0-4 timings for each "format".
|
||||
* Format-0 uses fast data reg timings, with slower command reg timings.
|
||||
* Format-1 uses fast timings for all registers, but won't work with all drives.
|
||||
*/
|
||||
static unsigned int cs5530_pio_timings[2][5] = {
|
||||
{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
|
||||
{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
|
||||
};
|
||||
|
||||
/*
|
||||
* After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
|
||||
*/
|
||||
#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
|
||||
#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
|
||||
|
||||
/**
|
||||
* cs5530_set_pio_mode - set host controller for PIO mode
|
||||
* @hwif: port
|
||||
* @drive: drive
|
||||
*
|
||||
* Handles setting of PIO mode for the chipset.
|
||||
*
|
||||
* The init_hwif_cs5530() routine guarantees that all drives
|
||||
* will have valid default PIO timings set up before we get here.
|
||||
*/
|
||||
|
||||
static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
unsigned long basereg = CS5530_BASEREG(hwif);
|
||||
unsigned int format = (inl(basereg + 4) >> 31) & 1;
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
|
||||
outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5530_udma_filter - UDMA filter
|
||||
* @drive: drive
|
||||
*
|
||||
* cs5530_udma_filter() does UDMA mask filtering for the given drive
|
||||
* taking into the consideration capabilities of the mate device.
|
||||
*
|
||||
* The CS5530 specifies that two drives sharing a cable cannot mix
|
||||
* UDMA/MDMA. It has to be one or the other, for the pair, though
|
||||
* different timings can still be chosen for each drive. We could
|
||||
* set the appropriate timing bits on the fly, but that might be
|
||||
* a bit confusing. So, for now we statically handle this requirement
|
||||
* by looking at our mate drive to see what it is capable of, before
|
||||
* choosing a mode for our own drive.
|
||||
*
|
||||
* Note: This relies on the fact we never fail from UDMA to MWDMA2
|
||||
* but instead drop to PIO.
|
||||
*/
|
||||
|
||||
static u8 cs5530_udma_filter(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
ide_drive_t *mate = ide_get_pair_dev(drive);
|
||||
u16 *mateid;
|
||||
u8 mask = hwif->ultra_mask;
|
||||
|
||||
if (mate == NULL)
|
||||
goto out;
|
||||
mateid = mate->id;
|
||||
|
||||
if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
|
||||
if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
|
||||
(mateid[ATA_ID_UDMA_MODES] & 7))
|
||||
goto out;
|
||||
if (mateid[ATA_ID_MWDMA_MODES] & 7)
|
||||
mask = 0;
|
||||
}
|
||||
out:
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
unsigned long basereg;
|
||||
unsigned int reg, timings = 0;
|
||||
|
||||
switch (drive->dma_mode) {
|
||||
case XFER_UDMA_0: timings = 0x00921250; break;
|
||||
case XFER_UDMA_1: timings = 0x00911140; break;
|
||||
case XFER_UDMA_2: timings = 0x00911030; break;
|
||||
case XFER_MW_DMA_0: timings = 0x00077771; break;
|
||||
case XFER_MW_DMA_1: timings = 0x00012121; break;
|
||||
case XFER_MW_DMA_2: timings = 0x00002020; break;
|
||||
}
|
||||
basereg = CS5530_BASEREG(hwif);
|
||||
reg = inl(basereg + 4); /* get drive0 config register */
|
||||
timings |= reg & 0x80000000; /* preserve PIO format bit */
|
||||
if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */
|
||||
outl(timings, basereg + 4); /* write drive0 config register */
|
||||
} else {
|
||||
if (timings & 0x00100000)
|
||||
reg |= 0x00100000; /* enable UDMA timings for both drives */
|
||||
else
|
||||
reg &= ~0x00100000; /* disable UDMA timings for both drives */
|
||||
outl(reg, basereg + 4); /* write drive0 config register */
|
||||
outl(timings, basereg + 12); /* write drive1 config register */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init_chipset_5530 - set up 5530 bridge
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Initialize the cs5530 bridge for reliable IDE DMA operation.
|
||||
*/
|
||||
|
||||
static int init_chipset_cs5530(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
|
||||
|
||||
if (pci_resource_start(dev, 4) == 0)
|
||||
return -EFAULT;
|
||||
|
||||
dev = NULL;
|
||||
while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
|
||||
switch (dev->device) {
|
||||
case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
|
||||
master_0 = pci_dev_get(dev);
|
||||
break;
|
||||
case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
|
||||
cs5530_0 = pci_dev_get(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!master_0) {
|
||||
printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
|
||||
goto out;
|
||||
}
|
||||
if (!cs5530_0) {
|
||||
printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
|
||||
* --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
|
||||
*/
|
||||
|
||||
pci_set_master(cs5530_0);
|
||||
pci_try_set_mwi(cs5530_0);
|
||||
|
||||
/*
|
||||
* Set PCI CacheLineSize to 16-bytes:
|
||||
* --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
|
||||
*/
|
||||
|
||||
pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
|
||||
|
||||
/*
|
||||
* Disable trapping of UDMA register accesses (Win98 hack):
|
||||
* --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
|
||||
*/
|
||||
|
||||
pci_write_config_word(cs5530_0, 0xd0, 0x5006);
|
||||
|
||||
/*
|
||||
* Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
|
||||
* The other settings are what is necessary to get the register
|
||||
* into a sane state for IDE DMA operation.
|
||||
*/
|
||||
|
||||
pci_write_config_byte(master_0, 0x40, 0x1e);
|
||||
|
||||
/*
|
||||
* Set max PCI burst size (16-bytes seems to work best):
|
||||
* 16bytes: set bit-1 at 0x41 (reg value of 0x16)
|
||||
* all others: clear bit-1 at 0x41, and do:
|
||||
* 128bytes: OR 0x00 at 0x41
|
||||
* 256bytes: OR 0x04 at 0x41
|
||||
* 512bytes: OR 0x08 at 0x41
|
||||
* 1024bytes: OR 0x0c at 0x41
|
||||
*/
|
||||
|
||||
pci_write_config_byte(master_0, 0x41, 0x14);
|
||||
|
||||
/*
|
||||
* These settings are necessary to get the chip
|
||||
* into a sane state for IDE DMA operation.
|
||||
*/
|
||||
|
||||
pci_write_config_byte(master_0, 0x42, 0x00);
|
||||
pci_write_config_byte(master_0, 0x43, 0xc1);
|
||||
|
||||
out:
|
||||
pci_dev_put(master_0);
|
||||
pci_dev_put(cs5530_0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_hwif_cs5530 - initialise an IDE channel
|
||||
* @hwif: IDE to initialize
|
||||
*
|
||||
* This gets invoked by the IDE driver once for each channel. It
|
||||
* performs channel-specific pre-initialization before drive probing.
|
||||
*/
|
||||
|
||||
static void init_hwif_cs5530 (ide_hwif_t *hwif)
|
||||
{
|
||||
unsigned long basereg;
|
||||
u32 d0_timings;
|
||||
|
||||
basereg = CS5530_BASEREG(hwif);
|
||||
d0_timings = inl(basereg + 0);
|
||||
if (CS5530_BAD_PIO(d0_timings))
|
||||
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
|
||||
if (CS5530_BAD_PIO(inl(basereg + 8)))
|
||||
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cs5530_port_ops = {
|
||||
.set_pio_mode = cs5530_set_pio_mode,
|
||||
.set_dma_mode = cs5530_set_dma_mode,
|
||||
.udma_filter = cs5530_udma_filter,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cs5530_chipset = {
|
||||
.name = DRV_NAME,
|
||||
.init_chipset = init_chipset_cs5530,
|
||||
.init_hwif = init_hwif_cs5530,
|
||||
.port_ops = &cs5530_port_ops,
|
||||
.host_flags = IDE_HFLAG_SERIALIZE |
|
||||
IDE_HFLAG_POST_SET_MODE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA2,
|
||||
};
|
||||
|
||||
static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
return ide_pci_init_one(dev, &cs5530_chipset, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cs5530_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
|
||||
|
||||
static struct pci_driver cs5530_pci_driver = {
|
||||
.name = "CS5530 IDE",
|
||||
.id_table = cs5530_pci_tbl,
|
||||
.probe = cs5530_init_one,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init cs5530_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&cs5530_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5530_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5530_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cs5530_ide_init);
|
||||
module_exit(cs5530_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("Mark Lord");
|
||||
MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,216 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
|
||||
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* History:
|
||||
* 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
|
||||
* - Reworked tuneproc, set_drive, misc mods to prep for mainline
|
||||
* - Work was sponsored by CIS (M) Sdn Bhd.
|
||||
* Ported to Kernel 2.6.11 on June 26, 2005 by
|
||||
* Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
|
||||
* Alexander Kiausch <alex.kiausch@t-online.de>
|
||||
* Originally developed by AMD for 2.4/2.6
|
||||
*
|
||||
* Development of this chipset driver was funded
|
||||
* by the nice folks at National Semiconductor/AMD.
|
||||
*
|
||||
* Documentation:
|
||||
* CS5535 documentation available from AMD
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
#define DRV_NAME "cs5535"
|
||||
|
||||
#define MSR_ATAC_BASE 0x51300000
|
||||
#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
|
||||
#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
|
||||
#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
|
||||
#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
|
||||
#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
|
||||
#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
|
||||
#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
|
||||
#define ATAC_RESET (MSR_ATAC_BASE+0x10)
|
||||
#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
|
||||
#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
|
||||
#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
|
||||
#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
|
||||
#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
|
||||
#define ATAC_BM0_CMD_PRIM 0x00
|
||||
#define ATAC_BM0_STS_PRIM 0x02
|
||||
#define ATAC_BM0_PRD 0x04
|
||||
#define CS5535_CABLE_DETECT 0x48
|
||||
|
||||
/* Format I PIO settings. We separate out cmd and data for safer timings */
|
||||
|
||||
static unsigned int cs5535_pio_cmd_timings[5] =
|
||||
{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
|
||||
static unsigned int cs5535_pio_dta_timings[5] =
|
||||
{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
|
||||
|
||||
static unsigned int cs5535_mwdma_timings[3] =
|
||||
{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
|
||||
|
||||
static unsigned int cs5535_udma_timings[5] =
|
||||
{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
|
||||
|
||||
/* Macros to check if the register is the reset value - reset value is an
|
||||
invalid timing and indicates the register has not been set previously */
|
||||
|
||||
#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
|
||||
#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
|
||||
|
||||
/****
|
||||
* cs5535_set_speed - Configure the chipset to the new speed
|
||||
* @drive: Drive to set up
|
||||
* @speed: desired speed
|
||||
*
|
||||
* cs5535_set_speed() configures the chipset to a new speed.
|
||||
*/
|
||||
static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
|
||||
{
|
||||
u32 reg = 0, dummy;
|
||||
u8 unit = drive->dn & 1;
|
||||
|
||||
/* Set the PIO timings */
|
||||
if (speed < XFER_SW_DMA_0) {
|
||||
ide_drive_t *pair = ide_get_pair_dev(drive);
|
||||
u8 cmd, pioa;
|
||||
|
||||
cmd = pioa = speed - XFER_PIO_0;
|
||||
|
||||
if (pair) {
|
||||
u8 piob = pair->pio_mode - XFER_PIO_0;
|
||||
|
||||
if (piob < cmd)
|
||||
cmd = piob;
|
||||
}
|
||||
|
||||
/* Write the speed of the current drive */
|
||||
reg = (cs5535_pio_cmd_timings[cmd] << 16) |
|
||||
cs5535_pio_dta_timings[pioa];
|
||||
wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
|
||||
|
||||
/* And if nessesary - change the speed of the other drive */
|
||||
rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
|
||||
|
||||
if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
|
||||
cs5535_pio_cmd_timings[cmd]) {
|
||||
reg &= 0x0000FFFF;
|
||||
reg |= cs5535_pio_cmd_timings[cmd] << 16;
|
||||
wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
|
||||
}
|
||||
|
||||
/* Set bit 31 of the DMA register for PIO format 1 timings */
|
||||
rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
|
||||
wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
|
||||
reg | 0x80000000UL, 0);
|
||||
} else {
|
||||
rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
|
||||
|
||||
reg &= 0x80000000UL; /* Preserve the PIO format bit */
|
||||
|
||||
if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
|
||||
reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
|
||||
else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
|
||||
reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
|
||||
else
|
||||
return;
|
||||
|
||||
wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5535_set_dma_mode - set host controller for DMA mode
|
||||
* @hwif: port
|
||||
* @drive: drive
|
||||
*
|
||||
* Programs the chipset for DMA mode.
|
||||
*/
|
||||
|
||||
static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
cs5535_set_speed(drive, drive->dma_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5535_set_pio_mode - set host controller for PIO mode
|
||||
* @hwif: port
|
||||
* @drive: drive
|
||||
*
|
||||
* A callback from the upper layers for PIO-only tuning.
|
||||
*/
|
||||
|
||||
static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
cs5535_set_speed(drive, drive->pio_mode);
|
||||
}
|
||||
|
||||
static u8 cs5535_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
u8 bit;
|
||||
|
||||
/* if a 80 wire cable was detected */
|
||||
pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
|
||||
|
||||
return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cs5535_port_ops = {
|
||||
.set_pio_mode = cs5535_set_pio_mode,
|
||||
.set_dma_mode = cs5535_set_dma_mode,
|
||||
.cable_detect = cs5535_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cs5535_chipset = {
|
||||
.name = DRV_NAME,
|
||||
.port_ops = &cs5535_port_ops,
|
||||
.host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
};
|
||||
|
||||
static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
return ide_pci_init_one(dev, &cs5535_chipset, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cs5535_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
|
||||
|
||||
static struct pci_driver cs5535_pci_driver = {
|
||||
.name = "CS5535_IDE",
|
||||
.id_table = cs5535_pci_tbl,
|
||||
.probe = cs5535_init_one,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init cs5535_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&cs5535_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5535_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5535_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cs5535_ide_init);
|
||||
module_exit(cs5535_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("AMD");
|
||||
MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,294 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* CS5536 PATA support
|
||||
* (C) 2007 Martin K. Petersen <mkp@mkp.net>
|
||||
* (C) 2009 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* Documentation:
|
||||
* Available from AMD web site.
|
||||
*
|
||||
* The IDE timing registers for the CS5536 live in the Geode Machine
|
||||
* Specific Register file and not PCI config space. Most BIOSes
|
||||
* virtualize the PCI registers so the chip looks like a standard IDE
|
||||
* controller. Unfortunately not all implementations get this right.
|
||||
* In particular some have problems with unaligned accesses to the
|
||||
* virtualized PCI registers. This driver always does full dword
|
||||
* writes to work around the issue. Also, in case of a bad BIOS this
|
||||
* driver can be loaded with the "msr=1" parameter which forces using
|
||||
* the Machine Specific Registers to configure the device.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ide.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
#define DRV_NAME "cs5536"
|
||||
|
||||
enum {
|
||||
MSR_IDE_CFG = 0x51300010,
|
||||
PCI_IDE_CFG = 0x40,
|
||||
|
||||
CFG = 0,
|
||||
DTC = 2,
|
||||
CAST = 3,
|
||||
ETC = 4,
|
||||
|
||||
IDE_CFG_CHANEN = (1 << 1),
|
||||
IDE_CFG_CABLE = (1 << 17) | (1 << 16),
|
||||
|
||||
IDE_D0_SHIFT = 24,
|
||||
IDE_D1_SHIFT = 16,
|
||||
IDE_DRV_MASK = 0xff,
|
||||
|
||||
IDE_CAST_D0_SHIFT = 6,
|
||||
IDE_CAST_D1_SHIFT = 4,
|
||||
IDE_CAST_DRV_MASK = 0x3,
|
||||
|
||||
IDE_CAST_CMD_SHIFT = 24,
|
||||
IDE_CAST_CMD_MASK = 0xff,
|
||||
|
||||
IDE_ETC_UDMA_MASK = 0xc0,
|
||||
};
|
||||
|
||||
static int use_msr;
|
||||
|
||||
static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
|
||||
{
|
||||
if (unlikely(use_msr)) {
|
||||
u32 dummy;
|
||||
|
||||
rdmsr(MSR_IDE_CFG + reg, *val, dummy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
|
||||
}
|
||||
|
||||
static int cs5536_write(struct pci_dev *pdev, int reg, int val)
|
||||
{
|
||||
if (unlikely(use_msr)) {
|
||||
wrmsr(MSR_IDE_CFG + reg, val, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
|
||||
}
|
||||
|
||||
static void cs5536_program_dtc(ide_drive_t *drive, u8 tim)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(drive->hwif->dev);
|
||||
int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
||||
u32 dtc;
|
||||
|
||||
cs5536_read(pdev, DTC, &dtc);
|
||||
dtc &= ~(IDE_DRV_MASK << dshift);
|
||||
dtc |= tim << dshift;
|
||||
cs5536_write(pdev, DTC, dtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5536_cable_detect - detect cable type
|
||||
* @hwif: Port to detect on
|
||||
*
|
||||
* Perform cable detection for ATA66 capable cable.
|
||||
*
|
||||
* Returns a cable type.
|
||||
*/
|
||||
|
||||
static u8 cs5536_cable_detect(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(hwif->dev);
|
||||
u32 cfg;
|
||||
|
||||
cs5536_read(pdev, CFG, &cfg);
|
||||
|
||||
if (cfg & IDE_CFG_CABLE)
|
||||
return ATA_CBL_PATA80;
|
||||
else
|
||||
return ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5536_set_pio_mode - PIO timing setup
|
||||
* @hwif: ATA port
|
||||
* @drive: ATA device
|
||||
*/
|
||||
|
||||
static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
static const u8 drv_timings[5] = {
|
||||
0x98, 0x55, 0x32, 0x21, 0x20,
|
||||
};
|
||||
|
||||
static const u8 addr_timings[5] = {
|
||||
0x2, 0x1, 0x0, 0x0, 0x0,
|
||||
};
|
||||
|
||||
static const u8 cmd_timings[5] = {
|
||||
0x99, 0x92, 0x90, 0x22, 0x20,
|
||||
};
|
||||
|
||||
struct pci_dev *pdev = to_pci_dev(hwif->dev);
|
||||
ide_drive_t *pair = ide_get_pair_dev(drive);
|
||||
int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
|
||||
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
|
||||
u32 cast;
|
||||
const u8 pio = drive->pio_mode - XFER_PIO_0;
|
||||
u8 cmd_pio = pio;
|
||||
|
||||
if (pair)
|
||||
cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0);
|
||||
|
||||
timings &= (IDE_DRV_MASK << 8);
|
||||
timings |= drv_timings[pio];
|
||||
ide_set_drivedata(drive, (void *)timings);
|
||||
|
||||
cs5536_program_dtc(drive, drv_timings[pio]);
|
||||
|
||||
cs5536_read(pdev, CAST, &cast);
|
||||
|
||||
cast &= ~(IDE_CAST_DRV_MASK << cshift);
|
||||
cast |= addr_timings[pio] << cshift;
|
||||
|
||||
cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
|
||||
cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT;
|
||||
|
||||
cs5536_write(pdev, CAST, cast);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5536_set_dma_mode - DMA timing setup
|
||||
* @hwif: ATA port
|
||||
* @drive: ATA device
|
||||
*/
|
||||
|
||||
static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
static const u8 udma_timings[6] = {
|
||||
0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
|
||||
};
|
||||
|
||||
static const u8 mwdma_timings[3] = {
|
||||
0x67, 0x21, 0x20,
|
||||
};
|
||||
|
||||
struct pci_dev *pdev = to_pci_dev(hwif->dev);
|
||||
int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
|
||||
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
|
||||
u32 etc;
|
||||
const u8 mode = drive->dma_mode;
|
||||
|
||||
cs5536_read(pdev, ETC, &etc);
|
||||
|
||||
if (mode >= XFER_UDMA_0) {
|
||||
etc &= ~(IDE_DRV_MASK << dshift);
|
||||
etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
|
||||
} else { /* MWDMA */
|
||||
etc &= ~(IDE_ETC_UDMA_MASK << dshift);
|
||||
timings &= IDE_DRV_MASK;
|
||||
timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8;
|
||||
ide_set_drivedata(drive, (void *)timings);
|
||||
}
|
||||
|
||||
cs5536_write(pdev, ETC, etc);
|
||||
}
|
||||
|
||||
static void cs5536_dma_start(ide_drive_t *drive)
|
||||
{
|
||||
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
|
||||
|
||||
if (drive->current_speed < XFER_UDMA_0 &&
|
||||
(timings >> 8) != (timings & IDE_DRV_MASK))
|
||||
cs5536_program_dtc(drive, timings >> 8);
|
||||
|
||||
ide_dma_start(drive);
|
||||
}
|
||||
|
||||
static int cs5536_dma_end(ide_drive_t *drive)
|
||||
{
|
||||
int ret = ide_dma_end(drive);
|
||||
unsigned long timings = (unsigned long)ide_get_drivedata(drive);
|
||||
|
||||
if (drive->current_speed < XFER_UDMA_0 &&
|
||||
(timings >> 8) != (timings & IDE_DRV_MASK))
|
||||
cs5536_program_dtc(drive, timings & IDE_DRV_MASK);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cs5536_port_ops = {
|
||||
.set_pio_mode = cs5536_set_pio_mode,
|
||||
.set_dma_mode = cs5536_set_dma_mode,
|
||||
.cable_detect = cs5536_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_dma_ops cs5536_dma_ops = {
|
||||
.dma_host_set = ide_dma_host_set,
|
||||
.dma_setup = ide_dma_setup,
|
||||
.dma_start = cs5536_dma_start,
|
||||
.dma_end = cs5536_dma_end,
|
||||
.dma_test_irq = ide_dma_test_irq,
|
||||
.dma_lost_irq = ide_dma_lost_irq,
|
||||
.dma_timer_expiry = ide_dma_sff_timer_expiry,
|
||||
.dma_sff_read_status = ide_dma_sff_read_status,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cs5536_info = {
|
||||
.name = DRV_NAME,
|
||||
.port_ops = &cs5536_port_ops,
|
||||
.dma_ops = &cs5536_dma_ops,
|
||||
.host_flags = IDE_HFLAG_SINGLE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
};
|
||||
|
||||
/**
|
||||
* cs5536_init_one
|
||||
* @dev: PCI device
|
||||
* @id: Entry in match table
|
||||
*/
|
||||
|
||||
static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
u32 cfg;
|
||||
|
||||
if (use_msr)
|
||||
printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n");
|
||||
|
||||
cs5536_read(dev, CFG, &cfg);
|
||||
|
||||
if ((cfg & IDE_CFG_CHANEN) == 0) {
|
||||
printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ide_pci_init_one(dev, &cs5536_info, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cs5536_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cs5536_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cs5536_pci_tbl,
|
||||
.probe = cs5536_init_one,
|
||||
.remove = ide_pci_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
module_pci_driver(cs5536_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl);
|
||||
|
||||
module_param_named(msr, use_msr, int, 0644);
|
||||
MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
|
||||
@@ -1,234 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
|
||||
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
|
||||
* Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* CYPRESS CY82C693 chipset IDE controller
|
||||
*
|
||||
* The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "cy82c693"
|
||||
|
||||
/*
|
||||
* NOTE: the value for busmaster timeout is tricky and I got it by
|
||||
* trial and error! By using a to low value will cause DMA timeouts
|
||||
* and drop IDE performance, and by using a to high value will cause
|
||||
* audio playback to scatter.
|
||||
* If you know a better value or how to calc it, please let me know.
|
||||
*/
|
||||
|
||||
/* twice the value written in cy82c693ub datasheet */
|
||||
#define BUSMASTER_TIMEOUT 0x50
|
||||
/*
|
||||
* the value above was tested on my machine and it seems to work okay
|
||||
*/
|
||||
|
||||
/* here are the offset definitions for the registers */
|
||||
#define CY82_IDE_CMDREG 0x04
|
||||
#define CY82_IDE_ADDRSETUP 0x48
|
||||
#define CY82_IDE_MASTER_IOR 0x4C
|
||||
#define CY82_IDE_MASTER_IOW 0x4D
|
||||
#define CY82_IDE_SLAVE_IOR 0x4E
|
||||
#define CY82_IDE_SLAVE_IOW 0x4F
|
||||
#define CY82_IDE_MASTER_8BIT 0x50
|
||||
#define CY82_IDE_SLAVE_8BIT 0x51
|
||||
|
||||
#define CY82_INDEX_PORT 0x22
|
||||
#define CY82_DATA_PORT 0x23
|
||||
|
||||
#define CY82_INDEX_CHANNEL0 0x30
|
||||
#define CY82_INDEX_CHANNEL1 0x31
|
||||
#define CY82_INDEX_TIMEOUT 0x32
|
||||
|
||||
/*
|
||||
* set DMA mode a specific channel for CY82C693
|
||||
*/
|
||||
|
||||
static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
const u8 mode = drive->dma_mode;
|
||||
u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
|
||||
|
||||
index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
|
||||
|
||||
data = (mode & 3) | (single << 2);
|
||||
|
||||
outb(index, CY82_INDEX_PORT);
|
||||
outb(data, CY82_DATA_PORT);
|
||||
|
||||
/*
|
||||
* note: below we set the value for Bus Master IDE TimeOut Register
|
||||
* I'm not absolutely sure what this does, but it solved my problem
|
||||
* with IDE DMA and sound, so I now can play sound and work with
|
||||
* my IDE driver at the same time :-)
|
||||
*
|
||||
* If you know the correct (best) value for this register please
|
||||
* let me know - ASK
|
||||
*/
|
||||
|
||||
data = BUSMASTER_TIMEOUT;
|
||||
outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
|
||||
outb(data, CY82_DATA_PORT);
|
||||
}
|
||||
|
||||
static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
|
||||
const unsigned long T = 1000000 / bus_speed;
|
||||
unsigned int addrCtrl;
|
||||
struct ide_timing t;
|
||||
u8 time_16, time_8;
|
||||
|
||||
/* select primary or secondary channel */
|
||||
if (drive->dn > 1) { /* drive is on the secondary channel */
|
||||
dev = pci_get_slot(dev->bus, dev->devfn+1);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "%s: tune_drive: "
|
||||
"Cannot find secondary interface!\n",
|
||||
drive->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
|
||||
|
||||
time_16 = clamp_val(t.recover - 1, 0, 15) |
|
||||
(clamp_val(t.active - 1, 0, 15) << 4);
|
||||
time_8 = clamp_val(t.act8b - 1, 0, 15) |
|
||||
(clamp_val(t.rec8b - 1, 0, 15) << 4);
|
||||
|
||||
/* now let's write the clocks registers */
|
||||
if ((drive->dn & 1) == 0) {
|
||||
/*
|
||||
* set master drive
|
||||
* address setup control register
|
||||
* is 32 bit !!!
|
||||
*/
|
||||
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
|
||||
|
||||
addrCtrl &= (~0xF);
|
||||
addrCtrl |= clamp_val(t.setup - 1, 0, 15);
|
||||
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
|
||||
|
||||
/* now let's set the remaining registers */
|
||||
pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16);
|
||||
pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16);
|
||||
pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8);
|
||||
} else {
|
||||
/*
|
||||
* set slave drive
|
||||
* address setup control register
|
||||
* is 32 bit !!!
|
||||
*/
|
||||
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
|
||||
|
||||
addrCtrl &= (~0xF0);
|
||||
addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4);
|
||||
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
|
||||
|
||||
/* now let's set the remaining registers */
|
||||
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16);
|
||||
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
|
||||
pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
|
||||
}
|
||||
if (drive->dn > 1)
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
|
||||
static void init_iops_cy82c693(ide_hwif_t *hwif)
|
||||
{
|
||||
static ide_hwif_t *primary;
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
|
||||
if (PCI_FUNC(dev->devfn) == 1)
|
||||
primary = hwif;
|
||||
else {
|
||||
hwif->mate = primary;
|
||||
hwif->channel = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ide_port_ops cy82c693_port_ops = {
|
||||
.set_pio_mode = cy82c693_set_pio_mode,
|
||||
.set_dma_mode = cy82c693_set_dma_mode,
|
||||
};
|
||||
|
||||
static const struct ide_port_info cy82c693_chipset = {
|
||||
.name = DRV_NAME,
|
||||
.init_iops = init_iops_cy82c693,
|
||||
.port_ops = &cy82c693_port_ops,
|
||||
.host_flags = IDE_HFLAG_SINGLE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.swdma_mask = ATA_SWDMA2,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
};
|
||||
|
||||
static int cy82c693_init_one(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct pci_dev *dev2;
|
||||
int ret = -ENODEV;
|
||||
|
||||
/* CY82C693 is more than only a IDE controller.
|
||||
Function 1 is primary IDE channel, function 2 - secondary. */
|
||||
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
|
||||
PCI_FUNC(dev->devfn) == 1) {
|
||||
dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
|
||||
ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL);
|
||||
if (ret)
|
||||
pci_dev_put(dev2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cy82c693_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct ide_host *host = pci_get_drvdata(dev);
|
||||
struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
|
||||
|
||||
ide_pci_remove(dev);
|
||||
pci_dev_put(dev2);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cy82c693_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 },
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
|
||||
|
||||
static struct pci_driver cy82c693_pci_driver = {
|
||||
.name = "Cypress_IDE",
|
||||
.id_table = cy82c693_pci_tbl,
|
||||
.probe = cy82c693_init_one,
|
||||
.remove = cy82c693_remove,
|
||||
.suspend = ide_pci_suspend,
|
||||
.resume = ide_pci_resume,
|
||||
};
|
||||
|
||||
static int __init cy82c693_ide_init(void)
|
||||
{
|
||||
return ide_pci_register_driver(&cy82c693_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cy82c693_ide_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cy82c693_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cy82c693_ide_init);
|
||||
module_exit(cy82c693_ide_exit);
|
||||
|
||||
MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Created 20 Oct 2004 by Mark Lord
|
||||
*
|
||||
* Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
|
||||
*
|
||||
* Modeled after the 16-bit PCMCIA driver: ide-cs.c
|
||||
*
|
||||
* This is slightly peculiar, in that it is a PCI driver,
|
||||
* but is NOT an IDE PCI driver -- the IDE layer does not directly
|
||||
* support hot insertion/removal of PCI interfaces, so this driver
|
||||
* is unable to use the IDE PCI interfaces. Instead, it uses the
|
||||
* same interfaces as the ide-cs (PCMCIA) driver uses.
|
||||
* On the plus side, the driver is also smaller/simpler this way.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* No chip documentation has yet been found,
|
||||
* so these configuration values were pulled from
|
||||
* a running Win98 system using "debug".
|
||||
* This gives around 3MByte/second read performance,
|
||||
* which is about 2/3 of what the chip is capable of.
|
||||
*
|
||||
* There is also a 4KByte mmio region on the card,
|
||||
* but its purpose has yet to be reverse-engineered.
|
||||
*/
|
||||
static const u8 setup[] = {
|
||||
0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
|
||||
0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
|
||||
};
|
||||
|
||||
static const struct ide_port_ops delkin_cb_port_ops = {
|
||||
.quirkproc = ide_undecoded_slave,
|
||||
};
|
||||
|
||||
static int delkin_cb_init_chipset(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long base = pci_resource_start(dev, 0);
|
||||
int i;
|
||||
|
||||
outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
|
||||
inb(base + 0x17); /* read status to clear interrupts */
|
||||
|
||||
for (i = 0; i < sizeof(setup); ++i) {
|
||||
if (setup[i])
|
||||
outb(setup[i], base + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ide_port_info delkin_cb_port_info = {
|
||||
.port_ops = &delkin_cb_port_ops,
|
||||
.host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
|
||||
IDE_HFLAG_NO_DMA,
|
||||
.irq_flags = IRQF_SHARED,
|
||||
.init_chipset = delkin_cb_init_chipset,
|
||||
.chipset = ide_pci,
|
||||
};
|
||||
|
||||
static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ide_host *host;
|
||||
unsigned long base;
|
||||
int rc;
|
||||
struct ide_hw hw, *hws[] = { &hw };
|
||||
|
||||
rc = pci_enable_device(dev);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
rc = pci_request_regions(dev, "delkin_cb");
|
||||
if (rc) {
|
||||
printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
|
||||
pci_disable_device(dev);
|
||||
return rc;
|
||||
}
|
||||
base = pci_resource_start(dev, 0);
|
||||
|
||||
delkin_cb_init_chipset(dev);
|
||||
|
||||
memset(&hw, 0, sizeof(hw));
|
||||
ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
|
||||
hw.irq = dev->irq;
|
||||
hw.dev = &dev->dev;
|
||||
|
||||
rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host);
|
||||
if (rc)
|
||||
goto out_disable;
|
||||
|
||||
pci_set_drvdata(dev, host);
|
||||
|
||||
return 0;
|
||||
|
||||
out_disable:
|
||||
pci_release_regions(dev);
|
||||
pci_disable_device(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
delkin_cb_remove (struct pci_dev *dev)
|
||||
{
|
||||
struct ide_host *host = pci_get_drvdata(dev);
|
||||
|
||||
ide_host_remove(host);
|
||||
|
||||
pci_release_regions(dev);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state)
|
||||
{
|
||||
pci_save_state(dev);
|
||||
pci_disable_device(dev);
|
||||
pci_set_power_state(dev, pci_choose_state(dev, state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delkin_cb_resume(struct pci_dev *dev)
|
||||
{
|
||||
struct ide_host *host = pci_get_drvdata(dev);
|
||||
int rc;
|
||||
|
||||
pci_set_power_state(dev, PCI_D0);
|
||||
|
||||
rc = pci_enable_device(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_restore_state(dev);
|
||||
pci_set_master(dev);
|
||||
|
||||
if (host->init_chipset)
|
||||
host->init_chipset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define delkin_cb_suspend NULL
|
||||
#define delkin_cb_resume NULL
|
||||
#endif
|
||||
|
||||
static struct pci_device_id delkin_cb_pci_tbl[] = {
|
||||
{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ 0, },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
|
||||
|
||||
static struct pci_driver delkin_cb_pci_driver = {
|
||||
.name = "Delkin-ASKA-Workbit Cardbus IDE",
|
||||
.id_table = delkin_cb_pci_tbl,
|
||||
.probe = delkin_cb_probe,
|
||||
.remove = delkin_cb_remove,
|
||||
.suspend = delkin_cb_suspend,
|
||||
.resume = delkin_cb_resume,
|
||||
};
|
||||
|
||||
module_pci_driver(delkin_cb_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Mark Lord");
|
||||
MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user