Commit 9382310f authored by Jens Axboe's avatar Jens Axboe

sis5513 update

parent 49bbaa0c
/*
* linux/drivers/ide/sis5513.c Version 0.13 March 6, 2002
* linux/drivers/ide/sis5513.c Version 0.14 July 24, 2002
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
......@@ -16,13 +16,13 @@
*
* Original tests and design on the SiS620/5513 chipset.
* ATA100 tests and design on the SiS735/5513 chipset.
* ATA16/33 design from specs
* ATA16/33 support from specs
* ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
*/
/*
* TODO:
* - Get ridden of SisHostChipInfo[] completness dependancy.
* - Get ATA-133 datasheets, implement ATA-133 init code.
* - Study drivers/ide/ide-timing.h.
* - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
* or remove ATA_00 define
......@@ -51,6 +51,7 @@
#include <asm/irq.h>
#include "ide_modes.h"
#include "sis5513.h"
/* When DEBUG is defined it outputs initial PCI config register
values and changes made to them by the driver */
......@@ -58,7 +59,6 @@
/* When BROKEN_LEVEL is defined it limits the DMA mode
at boot time to its value */
// #define BROKEN_LEVEL XFER_SW_DMA_0
#define DISPLAY_SIS_TIMINGS
/* Miscellaneaous flags */
#define SIS5513_LATENCY 0x01
......@@ -71,44 +71,33 @@
#define ATA_66 0x03
#define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout
#define ATA_100 0x05
#define ATA_133 0x06
#define ATA_133a 0x06 // SiS961b with 133 support
#define ATA_133 0x07 // SiS962
/* 2/ variable holding the controller chipset family value */
static unsigned char chipset_family;
static u8 chipset_family;
/*
* Debug code: following IDE config registers' changes
*/
#ifdef DEBUG
/* Copy of IDE Config registers 0x00 -> 0x57
Fewer might be used depending on the actual chipset */
static unsigned char ide_regs_copy[0x58];
static byte sis5513_max_config_register(void) {
switch(chipset_family) {
case ATA_00:
case ATA_16: return 0x4f;
case ATA_33: return 0x52;
case ATA_66:
case ATA_100a:
case ATA_100:
case ATA_133:
default: return 0x57;
}
}
/* Copy of IDE Config registers fewer will be used
* Some odd chipsets hang if unused registers are accessed
* -> We only access them in #DEBUG code (then we'll see if SiS did
* it right from day one) */
static u8 ide_regs_copy[0xff];
/* Read config registers, print differences from previous read */
static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
int i;
byte reg_val;
byte changed=0;
byte max = sis5513_max_config_register();
u8 reg_val;
u8 changed=0;
printk("SIS5513: %s, changed registers:\n", info);
for(i=0; i<=max; i++) {
for(i=0; i<=0xff; i++) {
pci_read_config_byte(dev, i, &reg_val);
if (reg_val != ide_regs_copy[i]) {
printk("%0#x: %0#x -> %0#x\n",
printk("%02x: %02x -> %02x\n",
i, ide_regs_copy[i], reg_val);
ide_regs_copy[i]=reg_val;
changed=1;
......@@ -123,39 +112,26 @@ static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
/* Load config registers, no printing */
static void sis5513_load_registers(struct pci_dev* dev) {
int i;
byte max = sis5513_max_config_register();
for(i=0; i<=max; i++) {
for(i=0; i<=0xff; i++) {
pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
}
}
/* Print a register */
static void sis5513_print_register(int reg) {
printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
}
/* Print valuable registers */
/* Print config space registers a la "lspci -vxxx" */
static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
int i;
byte max = sis5513_max_config_register();
int i,j;
sis5513_load_registers(dev);
printk("SIS5513 %s\n", marker);
printk("SIS5513 dump:");
for(i=0x00; i<0x40; i++) {
if ((i % 0x10)==0) printk("\n ");
sis5513_print_register(i);
}
for(; i<49; i++) {
sis5513_print_register(i);
}
printk("\n ");
for(; i<=max; i++) {
sis5513_print_register(i);
for(i=0; i<=0xf; i++) {
printk("SIS5513 dump: %d" "0:", i);
for(j=0; j<=0xf; j++) {
printk(" %02x", ide_regs_copy[(i<<16)+j]);
}
printk("\n");
}
}
#endif
......@@ -165,21 +141,30 @@ static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
*/
static const struct {
const char *name;
unsigned short host_id;
unsigned char chipset_family;
unsigned char flags;
u16 host_id;
u8 chipset_family;
u8 flags;
} SiSHostChipInfo[] = {
{ "SiS750", PCI_DEVICE_ID_SI_750, ATA_100, SIS5513_LATENCY },
{ "SiS745", PCI_DEVICE_ID_SI_745, ATA_100, SIS5513_LATENCY },
{ "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, SIS5513_LATENCY },
{ "SiS752", PCI_DEVICE_ID_SI_752, ATA_133, 0 },
{ "SiS751", PCI_DEVICE_ID_SI_751, ATA_133, 0 },
{ "SiS750", PCI_DEVICE_ID_SI_750, ATA_133, 0 },
{ "SiS748", PCI_DEVICE_ID_SI_748, ATA_133, 0 },
{ "SiS746", PCI_DEVICE_ID_SI_746, ATA_133, 0 },
{ "SiS745", PCI_DEVICE_ID_SI_745, ATA_133, 0 },
{ "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, 0 },
{ "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY },
{ "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a, SIS5513_LATENCY },
{ "SiS650", PCI_DEVICE_ID_SI_650, ATA_100, SIS5513_LATENCY },
{ "SiS645", PCI_DEVICE_ID_SI_645, ATA_100, SIS5513_LATENCY },
{ "SiS652", PCI_DEVICE_ID_SI_652, ATA_133, 0 },
{ "SiS651", PCI_DEVICE_ID_SI_651, ATA_133, 0 },
{ "SiS650", PCI_DEVICE_ID_SI_650, ATA_133, 0 },
{ "SiS648", PCI_DEVICE_ID_SI_648, ATA_133, 0 },
{ "SiS646", PCI_DEVICE_ID_SI_646, ATA_133, 0 },
{ "SiS645", PCI_DEVICE_ID_SI_645, ATA_133, 0 },
{ "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY },
{ "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY },
{ "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY },
{ "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY },
{ "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a, 0},
{ "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0},
{ "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0},
{ "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0},
......@@ -193,21 +178,68 @@ static const struct {
/* Cycle time bits and values vary accross chip dma capabilities
These three arrays hold the register layout and the values to set.
Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
static byte cycle_time_range[] = {0,0,2,3,3,4,4};
static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
{0,0,0,0,0,0}, /* no udma */
{0,0,0,0,0,0}, /* no udma */
{3,2,1,0,0,0},
{7,5,3,2,1,0},
{7,5,3,2,1,0},
{11,7,5,4,2,1},
{0,0,0,0,0,0} /* not yet known, ask SiS */
/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
{0,0,0,0,0,0,0}, /* no udma */
{0,0,0,0,0,0,0}, /* no udma */
{3,2,1,0,0,0,0}, /* ATA_33 */
{7,5,3,2,1,0,0}, /* ATA_66 */
{7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
{11,7,5,4,2,1,0}, /* ATA_100 */
{15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
{15,10,7,5,3,2,1}, /* ATA_133 */
};
/* CRC Valid Setup Time vary accross IDE clock setting 33/66/100/133
See SiS962 data sheet for more detail */
static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
{0,0,0,0,0,0,0}, /* no udma */
{0,0,0,0,0,0,0}, /* no udma */
{2,1,1,0,0,0,0},
{4,3,2,1,0,0,0},
{4,3,2,1,0,0,0},
{6,4,3,1,1,1,0},
{9,6,4,2,2,2,2},
{9,6,4,2,2,2,2},
};
/* Initialize time, Active time, Recovery time vary accross
IDE clock settings. These 3 arrays hold the register value
for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
static u8 ini_time_value[][8] = {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{2,1,0,0,0,1,0,0},
{4,3,1,1,1,3,1,1},
{4,3,1,1,1,3,1,1},
{6,4,2,2,2,4,2,2},
{9,6,3,3,3,6,3,3},
{9,6,3,3,3,6,3,3},
};
static u8 act_time_value[][8] = {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{9,9,9,2,2,7,2,2},
{19,19,19,5,4,14,5,4},
{19,19,19,5,4,14,5,4},
{28,28,28,7,6,21,7,6},
{38,38,38,10,9,28,10,9},
{38,38,38,10,9,28,10,9},
};
static u8 rco_time_value[][8] = {
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{9,2,0,2,0,7,1,1},
{19,5,1,5,2,16,3,2},
{19,5,1,5,2,16,3,2},
{30,9,3,9,4,25,6,4},
{40,12,4,12,5,34,12,5},
{40,12,4,12,5,34,12,5},
};
static struct pci_dev *host_dev = NULL;
/*
* Printing configuration
*/
......@@ -215,8 +247,8 @@ static struct pci_dev *host_dev = NULL;
#include <linux/stat.h>
#include <linux/proc_fs.h>
static int sis_get_info(char *, char **, off_t, int);
extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
static u8 sis_proc = 0;
static struct pci_dev *bmide_dev;
static char* cable_type[] = {
......@@ -249,17 +281,25 @@ static char* cycle_time[] = {
"7 CLK", "8 CLK",
"9 CLK", "10 CLK",
"11 CLK", "12 CLK",
"Reserved", "Reserved",
"Reserved", "Reserved"
"13 CLK", "14 CLK",
"15 CLK", "16 CLK"
};
static char* chipset_capability[] = {
"ATA", "ATA 16",
"ATA 33", "ATA 66",
"ATA 100", "ATA 100",
"ATA 133", "ATA 133"
};
/* Generic add master or slave info function */
static char* get_drives_info (char *buffer, byte pos)
static char* get_drives_info (char *buffer, u8 pos)
{
byte reg00, reg01, reg10, reg11; /* timing registers */
u8 reg00, reg01, reg10, reg11; /* timing registers */
char* p = buffer;
/* Postwrite/Prefetch */
if (chipset_family < ATA_133) {
pci_read_config_byte(bmide_dev, 0x4b, &reg00);
p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n",
pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
......@@ -267,11 +307,12 @@ static char* get_drives_info (char *buffer, byte pos)
p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
(reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
(reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
}
/* UDMA */
if (chipset_family >= ATA_33) {
......@@ -284,7 +325,8 @@ static char* get_drives_info (char *buffer, byte pos)
case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
case ATA_66:
case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
case ATA_100: p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
case ATA_100:
case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
case ATA_133:
default: p += sprintf(p, "133+ ?"); break;
}
......@@ -293,7 +335,8 @@ static char* get_drives_info (char *buffer, byte pos)
case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
case ATA_66:
case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
case ATA_100: p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
case ATA_100:
case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
case ATA_133:
default: p += sprintf(p, "133+ ?"); break;
}
......@@ -308,7 +351,8 @@ static char* get_drives_info (char *buffer, byte pos)
case ATA_33:
case ATA_66:
case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
case ATA_100:
case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
case ATA_133:
default: p += sprintf(p, "133+ ?"); break;
}
......@@ -319,7 +363,8 @@ static char* get_drives_info (char *buffer, byte pos)
case ATA_33:
case ATA_66:
case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
case ATA_100:
case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
case ATA_133:
default: p += sprintf(p, "133+ ?"); break;
}
......@@ -327,8 +372,10 @@ static char* get_drives_info (char *buffer, byte pos)
/* Data Recovery */
/* warning: may need (reg&0x07) for pre ATA66 chips */
if (chipset_family < ATA_133) {
p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n",
recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
}
return p;
}
......@@ -347,7 +394,7 @@ static char* get_slaves_info(char* buffer)
static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
byte reg;
u8 reg;
u16 reg2, reg3;
p += sprintf(p, "\nSiS 5513 ");
......@@ -358,8 +405,9 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
case ATA_66: p += sprintf(p, "Ultra 66"); break;
case ATA_100a:
case ATA_100: p += sprintf(p, "Ultra 100"); break;
case ATA_133:
default: p+= sprintf(p, "Ultra 133+"); break;
case ATA_133a:
case ATA_133: p += sprintf(p, "Ultra 133"); break;
default: p+= sprintf(p, "Unknown???"); break;
}
p += sprintf(p, " chipset\n");
p += sprintf(p, "--------------- Primary Channel "
......@@ -368,15 +416,23 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
/* Status */
pci_read_config_byte(bmide_dev, 0x4a, &reg);
if (chipset_family == ATA_133) {
pci_read_config_word(bmide_dev, 0x50, &reg2);
pci_read_config_word(bmide_dev, 0x52, &reg3);
}
p += sprintf(p, "Channel Status: ");
if (chipset_family < ATA_66) {
p += sprintf(p, "%s \t \t \t \t %s\n",
(reg & 0x04) ? "On" : "Off",
(reg & 0x02) ? "On" : "Off");
} else {
} else if (chipset_family < ATA_133) {
p += sprintf(p, "%s \t \t \t \t %s \n",
(reg & 0x02) ? "On" : "Off",
(reg & 0x04) ? "On" : "Off");
} else { /* ATA_133 */
p += sprintf(p, "%s \t \t \t \t %s \n",
(reg2 & 0x02) ? "On" : "Off",
(reg3 & 0x02) ? "On" : "Off");
}
/* Operation Mode */
......@@ -386,7 +442,11 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
(reg & 0x04) ? "Native" : "Compatible");
/* 80-pin cable ? */
if (chipset_family > ATA_33) {
if (chipset_family >= ATA_133) {
p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
(reg2 & 0x01) ? cable_type[1] : cable_type[0],
(reg3 & 0x01) ? cable_type[1] : cable_type[0]);
} else if (chipset_family > ATA_33) {
pci_read_config_byte(bmide_dev, 0x48, &reg);
p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
(reg & 0x10) ? cable_type[1] : cable_type[0],
......@@ -394,10 +454,12 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
}
/* Prefetch Count */
if (chipset_family < ATA_133) {
pci_read_config_word(bmide_dev, 0x4c, &reg2);
pci_read_config_word(bmide_dev, 0x4e, &reg3);
p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
reg2, reg3);
}
p = get_masters_info(p);
p = get_slaves_info(p);
......@@ -406,51 +468,37 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
}
#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
byte sis_proc = 0;
static byte sis5513_ratemask (ide_drive_t *drive)
static u8 sis5513_ratemask (ide_drive_t *drive)
{
// struct pci_dev *dev = HWIF(drive)->pci_dev;
byte mode = 0x00;
#if 0
u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
u8 mode = rates[chipset_family];
#else
u8 mode;
switch(chipset_family) {
case ATA_133: // { mode |= 0x04; break; }
case ATA_133:
case ATA_133a:
mode = 4;
break;
case ATA_100:
case ATA_100a: { mode |= 0x03; break; }
case ATA_66: { mode |= 0x02; break; }
case ATA_33: { mode |= 0x01; break; }
case ATA_100a:
mode = 3;
break;
case ATA_66:
mode = 2;
break;
case ATA_33:
return 1;
case ATA_16:
case ATA_00:
default:
return (mode &= ~0xF8);
}
if (!eighty_ninty_three(drive)) {
mode &= ~0xFE;
mode |= 0x01;
}
return (mode &= ~0xF8);
}
static byte sis5513_ratefilter (ide_drive_t *drive, byte speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
byte mode = sis5513_ratemask(drive);
switch(mode) {
case 0x04: while (speed > XFER_UDMA_6) speed--; break;
case 0x03: while (speed > XFER_UDMA_5) speed--; break;
case 0x02: while (speed > XFER_UDMA_4) speed--; break;
case 0x01: while (speed > XFER_UDMA_2) speed--; break;
case 0x00:
default: while (speed > XFER_MW_DMA_2) speed--; break;
break;
return 0;
}
#else
while (speed > XFER_PIO_4) speed--;
#endif /* CONFIG_BLK_DEV_IDEDMA */
// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
return speed;
#endif
if (!eighty_ninty_three(drive))
mode = min(mode, (u8)1);
return mode;
}
/*
......@@ -462,8 +510,8 @@ static void config_drive_art_rwp (ide_drive_t *drive)
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
byte reg4bh = 0;
byte rw_prefetch = (0x11 << drive->dn);
u8 reg4bh = 0;
u8 rw_prefetch = (0x11 << drive->dn);
#ifdef DEBUG
printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
......@@ -483,15 +531,15 @@ static void config_drive_art_rwp (ide_drive_t *drive)
/* Set per-drive active and recovery time */
static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
byte timing, drive_pci, test1, test2;
u8 timing, drive_pci, test1, test2;
unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
unsigned short xfer_pio = drive->id->eide_pio_modes;
u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
u16 xfer_pio = drive->id->eide_pio_modes;
#ifdef DEBUG
sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
......@@ -517,16 +565,21 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
timing = (xfer_pio >= pio) ? xfer_pio : pio;
#ifdef DEBUG
printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
printk("SIS5513: config_drive_art_rwp_pio, "
"drive %d, pio %d, timing %d\n",
drive->dn, pio, timing);
#endif
switch(drive->dn) {
case 0: drive_pci = 0x40; break;
case 1: drive_pci = 0x42; break;
case 2: drive_pci = 0x44; break;
case 3: drive_pci = 0x46; break;
default: return;
/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
drive_pci = 0x40;
/* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
if (chipset_family >= ATA_133) {
u32 reg54h;
pci_read_config_dword(dev, 0x54, &reg54h);
if (reg54h & 0x40000000) drive_pci = 0x70;
drive_pci += ((drive->dn)*0x4);
} else {
drive_pci += ((drive->dn)*0x2);
}
/* register layout changed with newer ATA100 chips */
......@@ -547,7 +600,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
}
pci_write_config_byte(dev, drive_pci, test1);
pci_write_config_byte(dev, drive_pci+1, test2);
} else {
} else if (chipset_family < ATA_133) {
switch(timing) { /* active recovery
v v */
case 4: test1 = 0x30|0x01; break;
......@@ -557,6 +610,20 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
default: break;
}
pci_write_config_byte(dev, drive_pci, test1);
} else { /* ATA_133 */
u32 test3;
pci_read_config_dword(dev, drive_pci, &test3);
test3 &= 0xc0c00fff;
if (test3 & 0x08) {
test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12;
test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16;
test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24;
} else {
test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12;
test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16;
test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24;
}
pci_write_config_dword(dev, drive_pci, test3);
}
#ifdef DEBUG
......@@ -564,9 +631,13 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
#endif
}
static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
{
byte speed;
#if 0
config_art_rwp_pio(drive, pio);
return ide_config_drive_speed(drive, (XFER_PIO_0 + pio));
#else
u8 speed;
switch(pio) {
case 4: speed = XFER_PIO_4; break;
......@@ -577,58 +648,83 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
}
config_art_rwp_pio(drive, pio);
return (ide_config_drive_speed(drive, speed));
return ide_config_drive_speed(drive, speed);
#endif
}
static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
byte speed = sis5513_ratefilter(drive, xferspeed);
byte drive_pci, reg;
u8 drive_pci, reg;
u32 regdw;
#ifdef DEBUG
sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
drive->dn, speed);
#endif
#if 1
switch(drive->dn) {
case 0: drive_pci = 0x40; break;
case 1: drive_pci = 0x42; break;
case 2: drive_pci = 0x44; break;
case 3: drive_pci = 0x46; break;
default: return ide_dma_off;
}
#else
// drive_pci = (0x40 + ((drive->dn) *2));
// drive_pci = 0x40;
// drive_pci |= ((drive->dn) << 1);
#endif
#ifdef BROKEN_LEVEL
#ifdef DEBUG
printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL);
#endif
if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
#endif
u8 speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
/* See config_art_rwp_pio for drive pci config registers */
drive_pci = 0x40;
if (chipset_family >= ATA_133) {
u32 reg54h;
pci_read_config_dword(dev, 0x54, &reg54h);
if (reg54h & 0x40000000) drive_pci = 0x70;
drive_pci += ((drive->dn)*0x4);
pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
/* Disable UDMA bit for non UDMA modes on UDMA chips */
if (speed < XFER_UDMA_0) {
regdw &= 0xfffffffb;
pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
}
} else {
drive_pci += ((drive->dn)*0x2);
pci_read_config_byte(dev, drive_pci+1, &reg);
/* Disable UDMA bit for non UDMA modes on UDMA chips */
if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
reg &= 0x7F;
pci_write_config_byte(dev, drive_pci+1, reg);
}
}
/* Config chip for mode */
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA
case XFER_UDMA_6:
case XFER_UDMA_5:
case XFER_UDMA_4:
case XFER_UDMA_3:
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
if (chipset_family >= ATA_133) {
regdw |= 0x04;
regdw &= 0xfffff00f;
/* check if ATA133 enable */
if (regdw & 0x08) {
regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8;
} else {
/* if ATA133 disable, we should not set speed above UDMA5 */
if (speed > XFER_UDMA_5)
speed = XFER_UDMA_5;
regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8;
}
pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
} else {
/* Force the UDMA bit on if we want to use UDMA */
reg |= 0x80;
/* clean reg cycle time bits */
......@@ -638,6 +734,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
<< cycle_time_offset[chipset_family];
pci_write_config_byte(dev, drive_pci+1, reg);
}
break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
......@@ -660,7 +757,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
return ((int) ide_config_drive_speed(drive, speed));
}
static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
{
(void) config_chipset_for_pio(drive, pio);
}
......@@ -671,127 +768,75 @@ static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
*/
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
byte mode = sis5513_ratemask(drive);
byte speed = 0;
u8 speed = ide_dma_speed(drive, sis5513_ratemask(drive));
#ifdef DEBUG
printk("SIS5513: config_chipset_for_dma, drive %d ultra %d\n",
drive->dn, mode);
printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x, udma_66 %x\n",
drive->dn, drive->id->dma_ultra);
#endif
switch(mode) {
case 0x04:
if (id->dma_ultra & 0x0040)
{ speed = XFER_UDMA_6; break; }
case 0x03:
if (id->dma_ultra & 0x0020)
{ speed = XFER_UDMA_5; break; }
case 0x02:
if (id->dma_ultra & 0x0010)
{ speed = XFER_UDMA_4; break; }
if (id->dma_ultra & 0x0008)
{ speed = XFER_UDMA_3; break; }
case 0x01:
if (id->dma_ultra & 0x0004)
{ speed = XFER_UDMA_2; break; }
if (id->dma_ultra & 0x0002)
{ speed = XFER_UDMA_1; break; }
if (id->dma_ultra & 0x0001)
{ speed = XFER_UDMA_0; break; }
case 0x00:
if (id->dma_mword & 0x0004)
{ speed = XFER_MW_DMA_2; break; }
if (id->dma_mword & 0x0002)
{ speed = XFER_MW_DMA_1; break; }
if (id->dma_mword & 0x0001)
{ speed = XFER_MW_DMA_0; break; }
if (id->dma_1word & 0x0004)
{ speed = XFER_SW_DMA_2; break; }
if (id->dma_1word & 0x0002)
{ speed = XFER_SW_DMA_1; break; }
if (id->dma_1word & 0x0001)
{ speed = XFER_SW_DMA_0; break; }
default:
return ((int) ide_dma_off_quietly);
}
if (!(speed))
return 0;
sis5513_tune_chipset(drive, speed);
// return ((int) ide_dma_on);
return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
((id->dma_ultra >> 11) & 7) ? ide_dma_on :
((id->dma_ultra >> 8) & 7) ? ide_dma_on :
((id->dma_mword >> 8) & 7) ? ide_dma_on :
((id->dma_1word >> 8) & 7) ? ide_dma_on :
ide_dma_off_quietly);
return ide_dma_enable(drive);
}
static int config_drive_xfer_rate (ide_drive_t *drive)
static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_off_quietly;
drive->init_speed = 0;
if (id && (id->capability & 1) && HWIF(drive)->autodma) {
if (id && (id->capability & 1) && drive->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
if (hwif->ide_dma_bad_drive(drive))
goto fast_ata_pio;
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
if (id->dma_ultra & 0x003F) {
if (id->dma_ultra & hwif->ultra_mask) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive);
if ((id->field_valid & 2) &&
(dma_func != ide_dma_on))
int dma = config_chipset_for_dma(drive);
if ((id->field_valid & 2) && !dma)
goto try_dma_modes;
}
} else if (id->field_valid & 2) {
try_dma_modes:
if ((id->dma_mword & 0x0007) ||
(id->dma_1word & 0x0007)) {
if ((id->dma_mword & hwif->mwdma_mask) ||
(id->dma_1word & hwif->swdma_mask)) {
/* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive);
if (dma_func != ide_dma_on)
if (!config_chipset_for_dma(drive))
goto no_dma_set;
}
} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
(id->eide_dma_time > 150)) {
} else if (hwif->ide_dma_good_drive(drive) &&
(id->eide_dma_time < 150)) {
/* Consult the list of known "good" drives */
dma_func = config_chipset_for_dma(drive);
if (dma_func != ide_dma_on)
if (!config_chipset_for_dma(drive))
goto no_dma_set;
} else {
goto fast_ata_pio;
}
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
dma_func = ide_dma_off_quietly;
no_dma_set:
sis5513_tune_drive(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
return HWIF(drive)->dmaproc(dma_func, drive);
return hwif->ide_dma_on(drive);
}
/* initiates/aborts (U)DMA read/write operations on a drive. */
int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
static int sis5513_config_xfer_rate (ide_drive_t *drive)
{
switch (func) {
case ide_dma_check:
config_drive_art_rwp(drive);
config_art_rwp_pio(drive, 5);
return config_drive_xfer_rate(drive);
default:
break;
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
return sis5513_config_drive_xfer_rate(drive);
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
/* Chip detection and general config */
unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
{
struct pci_dev *host;
int i = 0;
......@@ -806,7 +851,37 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
host_dev = host;
chipset_family = SiSHostChipInfo[i].chipset_family;
/* check 100/133 chipset family */
if (chipset_family == ATA_133) {
u32 reg54h;
u16 reg02h;
pci_read_config_dword(dev, 0x54, &reg54h);
pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff));
pci_read_config_word(dev, 0x02, &reg02h);
pci_write_config_dword(dev, 0x54, reg54h);
/* devid 5518 here means SiS962 or later
which supports ATA133 */
if (reg02h != 0x5518) {
u8 reg49h;
unsigned long sbrev;
/* SiS961 family */
/*
* FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING
*/
outl(0x80001008, 0x0cf8);
sbrev = inl(0x0cfc);
pci_read_config_byte(dev, 0x49, &reg49h);
if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80))
chipset_family = ATA_133a;
else
chipset_family = ATA_100;
}
}
printk(SiSHostChipInfo[i].name);
printk(" %s controller", chipset_capability[chipset_family]);
printk("\n");
#ifdef DEBUG
......@@ -814,7 +889,7 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
#endif
if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
}
}
......@@ -823,9 +898,19 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
1/ tell IDE channels to operate in Compabitility mode only
2/ tell old chips to allow per drive IDE timings */
if (host_dev) {
byte reg;
u8 reg;
u16 regw;
switch(chipset_family) {
case ATA_133:
/* SiS962 operation mode */
pci_read_config_word(dev, 0x50, &regw);
if (regw & 0x08)
pci_write_config_word(dev, 0x50, regw&0xfff7);
pci_read_config_word(dev, 0x52, &regw);
if (regw & 0x08)
pci_write_config_word(dev, 0x52, regw&0xfff7);
break;
case ATA_133a:
case ATA_100:
/* Set compatibility bit */
pci_read_config_byte(dev, 0x49, &reg);
......@@ -863,7 +948,7 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
if (!sis_proc) {
sis_proc = 1;
bmide_dev = dev;
sis_display_info = &sis_get_info;
ide_pci_register_host_proc(&sis_procs[0]);
}
#endif
}
......@@ -873,55 +958,90 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
return 0;
}
unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
{
byte reg48h = 0, ata66 = 0;
byte mask = hwif->channel ? 0x20 : 0x10;
u8 ata66 = 0;
if (chipset_family >= ATA_133) {
u16 regw = 0;
u16 reg_addr = hwif->channel ? 0x52: 0x50;
pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
ata66 = (regw & 0x8000) ? 0 : 1;
} else if (chipset_family >= ATA_66) {
u8 reg48h = 0;
u8 mask = hwif->channel ? 0x20 : 0x10;
pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
if (chipset_family >= ATA_66) {
ata66 = (reg48h & mask) ? 0 : 1;
}
return ata66;
}
void __init ide_init_sis5513 (ide_hwif_t *hwif)
static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
{
hwif->autodma = 0;
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
hwif->tuneproc = &sis5513_tune_drive;
hwif->speedproc = &sis5513_tune_chipset;
if (!(hwif->dma_base)) {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
hwif->autodma = 0;
if (!(hwif->dma_base))
return;
}
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
#ifdef CONFIG_BLK_DEV_IDEDMA
if (host_dev) {
if (chipset_family > ATA_16)
hwif->dmaproc = &sis5513_dmaproc;
else
hwif->autodma = 0;
}
# ifdef CONFIG_IDEDMA_AUTO
if (!host_dev)
return;
if (!(hwif->udma_four))
hwif->udma_four = ata66_sis5513(hwif);
if (chipset_family > ATA_16) {
hwif->ide_dma_check = &sis5513_config_xfer_rate;
if (!noautodma)
hwif->autodma = 1;
# endif /* CONFIG_IDEDMA_AUTO */
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
hwif->drives[0].autodma = hwif->autodma;
hwif->drives[1].autodma = hwif->autodma;
#endif
return;
}
extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
void __init fixup_device_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
{
if (dev->resource[0].start != 0x01F1)
ide_register_xp_fix(dev);
ide_setup_dma(hwif, dmabase, 8);
}
printk("%s: IDE controller on PCI bus %02x dev %02x\n",
d->name, dev->bus->number, dev->devfn);
extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
static void __init init_setup_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
{
ide_setup_pci_device(dev, d);
}
int __init sis5513_scan_pcidev (struct pci_dev *dev)
{
ide_pci_device_t *d;
if (dev->vendor != PCI_VENDOR_ID_SI)
return 0;
for (d = sis5513_chipsets; d && d->vendor && d->device; ++d) {
if (((d->vendor == dev->vendor) &&
(d->device == dev->device)) &&
(d->init_setup)) {
d->init_setup(dev, d);
return 1;
}
}
return 0;
}
#ifndef SIS5513_H
#define SIS5513_H
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/ide.h>
#define DISPLAY_SIS_TIMINGS
#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
static u8 sis_proc;
static int sis_get_info(char *, char **, off_t, int);
static ide_pci_host_proc_t sis_procs[] __initdata = {
{
name: "sis",
set: 1,
get_info: sis_get_info,
parent: NULL,
},
};
#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
static void init_setup_sis5513(struct pci_dev *, ide_pci_device_t *);
static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
static void init_hwif_sis5513(ide_hwif_t *);
static void init_dma_sis5513(ide_hwif_t *, unsigned long);
static ide_pci_device_t sis5513_chipsets[] __initdata = {
{
vendor: PCI_VENDOR_ID_SI,
device: PCI_DEVICE_ID_SI_5513,
name: "SIS5513",
init_setup: init_setup_sis5513,
init_chipset: init_chipset_sis5513,
init_iops: NULL,
init_hwif: init_hwif_sis5513,
init_dma: init_dma_sis5513,
channels: 2,
autodma: NOAUTODMA,
enablebits: {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
bootable: ON_BOARD,
extra: 0
},{
vendor: 0,
device: 0,
channels: 0,
bootable: EOL,
}
};
#endif /* SIS5513_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment