[PATCH] Andre's IDE Patch (2/7)

Rob Radez (rob@osinvestor.com)
Sat, 19 Jan 2002 16:58:50 -0500 (EST)


This is the second of seven patches against 2.4.18-pre4, beginning the breakup
of Andre Hedrick's IDE patch into smaller chunks.

Description of patch 2:
This patch touches only one file, drivers/ide/hpt366.c and includes many
fixes to the HPT 366/368/370 driver. Compiled, booted, and recognized my
HPT 370 on-board controller fine. No further testing was done though.

Regards,
Rob Radez

diff -ruN linux-2.4.18-pre3/drivers/ide/hpt366.c linux-2.4.18-pre3-ide-rr/drivers/ide/hpt366.c
--- linux-2.4.18-pre3/drivers/ide/hpt366.c Tue Aug 14 23:01:07 2001
+++ linux-2.4.18-pre3-ide-rr/drivers/ide/hpt366.c Mon Jan 14 19:18:52 2002
@@ -1,7 +1,8 @@
/*
- * linux/drivers/ide/hpt366.c Version 0.18 June. 9, 2000
+ * linux/drivers/ide/hpt366.c Version 0.22 20 Sep 2001
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
* May be copied or modified under the terms of the GNU General Public License
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
*
* Note that final HPT370 support was done by force extraction of GPL.
*
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma
+ * xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma.
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ * just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ * pci clocks as the chip can glitch in those cases. the highpoint
+ * approved workaround slows everything down too much to be useful. in
+ * addition, we would have to serialize access to each chip.
+ * Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ * Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366:
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * Mike Waychison <crlf@sun.com>
*/

#include <linux/config.h>
@@ -28,6 +57,7 @@
#include <linux/init.h>
#include <linux/ide.h>

+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>

@@ -35,6 +65,11 @@

#define DISPLAY_HPT366_TIMINGS

+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
@@ -106,146 +141,302 @@

struct chipset_bus_clock_list_entry {
byte xfer_speed;
- unsigned int chipset_settings_write;
- unsigned int chipset_settings_read;
+ unsigned int chipset_settings;
};

+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
struct chipset_bus_clock_list_entry forty_base [] = {

- { XFER_UDMA_4, 0x900fd943, 0x900fd943 },
- { XFER_UDMA_3, 0x900ad943, 0x900ad943 },
- { XFER_UDMA_2, 0x900bd943, 0x900bd943 },
- { XFER_UDMA_1, 0x9008d943, 0x9008d943 },
- { XFER_UDMA_0, 0x9008d943, 0x9008d943 },
-
- { XFER_MW_DMA_2, 0xa008d943, 0xa008d943 },
- { XFER_MW_DMA_1, 0xa010d955, 0xa010d955 },
- { XFER_MW_DMA_0, 0xa010d9fc, 0xa010d9fc },
-
- { XFER_PIO_4, 0xc008d963, 0xc008d963 },
- { XFER_PIO_3, 0xc010d974, 0xc010d974 },
- { XFER_PIO_2, 0xc010d997, 0xc010d997 },
- { XFER_PIO_1, 0xc010d9c7, 0xc010d9c7 },
- { XFER_PIO_0, 0xc018d9d9, 0xc018d9d9 },
- { 0, 0x0120d9d9, 0x0120d9d9 }
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
};

struct chipset_bus_clock_list_entry thirty_three_base [] = {

- { XFER_UDMA_4, 0x90c9a731, 0x90c9a731 },
- { XFER_UDMA_3, 0x90cfa731, 0x90cfa731 },
- { XFER_UDMA_2, 0x90caa731, 0x90caa731 },
- { XFER_UDMA_1, 0x90cba731, 0x90cba731 },
- { XFER_UDMA_0, 0x90c8a731, 0x90c8a731 },
-
- { XFER_MW_DMA_2, 0xa0c8a731, 0xa0c8a731 },
- { XFER_MW_DMA_1, 0xa0c8a732, 0xa0c8a732 }, /* 0xa0c8a733 */
- { XFER_MW_DMA_0, 0xa0c8a797, 0xa0c8a797 },
-
- { XFER_PIO_4, 0xc0c8a731, 0xc0c8a731 },
- { XFER_PIO_3, 0xc0c8a742, 0xc0c8a742 },
- { XFER_PIO_2, 0xc0d0a753, 0xc0d0a753 },
- { XFER_PIO_1, 0xc0d0a7a3, 0xc0d0a7a3 }, /* 0xc0d0a793 */
- { XFER_PIO_0, 0xc0d0a7aa, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
- { 0, 0x0120a7a7, 0x0120a7a7 }
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
};

struct chipset_bus_clock_list_entry twenty_five_base [] = {

- { XFER_UDMA_4, 0x90c98521, 0x90c98521 },
- { XFER_UDMA_3, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_2, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_1, 0x90cb8521, 0x90cb8521 },
- { XFER_UDMA_0, 0x90cb8521, 0x90cb8521 },
-
- { XFER_MW_DMA_2, 0xa0ca8521, 0xa0ca8521 },
- { XFER_MW_DMA_1, 0xa0ca8532, 0xa0ca8532 },
- { XFER_MW_DMA_0, 0xa0ca8575, 0xa0ca8575 },
-
- { XFER_PIO_4, 0xc0ca8521, 0xc0ca8521 },
- { XFER_PIO_3, 0xc0ca8532, 0xc0ca8532 },
- { XFER_PIO_2, 0xc0ca8542, 0xc0ca8542 },
- { XFER_PIO_1, 0xc0d08572, 0xc0d08572 },
- { XFER_PIO_0, 0xc0d08585, 0xc0d08585 },
- { 0, 0x01208585, 0x01208585 }
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
};

+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+#else
+/* from highpoint documentation. these are old values */
struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
- { XFER_UDMA_5, 0x1A85F442, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57, 0x06914e57 },
- { 0, 0x06514e57, 0x06514e57 }
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
};

#define HPT366_DEBUG_DRIVE_INFO 0
#define HPT370_ALLOW_ATA100_5 1
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+#define F_LOW_PCI_33 0x23
+#define F_LOW_PCI_40 0x29
+#define F_LOW_PCI_50 0x2d
+#define F_LOW_PCI_66 0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);

#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
static int hpt366_get_info(char *, char **, off_t, int);
extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;

static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
{
- char *p = buffer;
- u32 bibma = bmide_dev->resource[4].start;
- u32 bibma2 = bmide2_dev->resource[4].start;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
- u8 c0 = 0, c1 = 0;
- u32 class_rev;
-
- pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- /*
- * at that point bibma+0x2 et bibma+0xa are byte registers
- * to investigate:
- */
- c0 = inb_p((unsigned short)bibma + 0x02);
- if (bmide2_dev)
- c1 = inb_p((unsigned short)bibma2 + 0x02);
-
- p += sprintf(p, "\n %s Chipset.\n", chipset_names[class_rev]);
- p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
- p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
- p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
- p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
+ char *p = buffer;
+ char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+ int i;
+
+ p += sprintf(p, "\n "
+ "HighPoint HPT366/368/370\n");
+ for (i = 0; i < n_hpt_devs; i++) {
+ struct pci_dev *dev = hpt_devs[i];
+ unsigned short iobase = dev->resource[4].start;
+ u32 class_rev;
+ u8 c0, c1;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ p += sprintf(p, "\nController: %d\n", i);
+ p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+ p += sprintf(p, "--------------- Primary Channel "
+ "--------------- Secondary Channel "
+ "--------------\n");
+
+ /* get the bus master status registers */
+ c0 = inb_p(iobase + 0x2);
+ c1 = inb_p(iobase + 0xa);
+ p += sprintf(p, "Enabled: %s"
+ " %s\n",
+ (c0 & 0x80) ? "no" : "yes",
+ (c1 & 0x80) ? "no" : "yes");
+
+ if (pci_rev_check_hpt3xx(dev)) {
+ u8 cbl;
+ cbl = inb_p(iobase + 0x7b);
+ outb_p(cbl | 1, iobase + 0x7b);
+ outb_p(cbl & ~1, iobase + 0x7b);
+ cbl = inb_p(iobase + 0x7a);
+ p += sprintf(p, "Cable: ATA-%d"
+ " ATA-%d\n",
+ (cbl & 0x02) ? 33 : 66,
+ (cbl & 0x01) ? 33 : 66);
+ p += sprintf(p, "\n");
+ }

+ p += sprintf(p, "--------------- drive0 --------- drive1 "
+ "------- drive0 ---------- drive1 -------\n");
+ p += sprintf(p, "DMA capable: %s %s"
+ " %s %s\n",
+ (c0 & 0x20) ? "yes" : "no ",
+ (c0 & 0x40) ? "yes" : "no ",
+ (c1 & 0x20) ? "yes" : "no ",
+ (c1 & 0x40) ? "yes" : "no ");
+
+ {
+ u8 c2, c3;
+ /* older revs don't have these registers mapped
+ * into io space */
+ pci_read_config_byte(dev, 0x43, &c0);
+ pci_read_config_byte(dev, 0x47, &c1);
+ pci_read_config_byte(dev, 0x4b, &c2);
+ pci_read_config_byte(dev, 0x4f, &c3);
+
+ p += sprintf(p, "Mode: %s %s"
+ " %s %s\n",
+ (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
+ (c0 & 0x80) ? "PIO " : "off ",
+ (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+ (c1 & 0x80) ? "PIO " : "off ",
+ (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+ (c2 & 0x80) ? "PIO " : "off ",
+ (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+ (c3 & 0x80) ? "PIO " : "off ");
+ }
+ }
+ p += sprintf(p, "\n");
+
return p-buffer;/* => must be less than 4k! */
}
#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */

-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
{
unsigned int class_rev;
@@ -282,16 +473,16 @@
return 0;
}

-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
{
for ( ; chipset_table->xfer_speed ; chipset_table++)
if (chipset_table->xfer_speed == speed) {
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}

-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -314,16 +505,22 @@
/* detect bus speed by looking at control reg timing: */
switch((reg1 >> 8) & 7) {
case 5:
- reg2 = pci_bus_clock_list(speed, direction, forty_base);
+ reg2 = pci_bus_clock_list(speed, forty_base);
break;
case 9:
- reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+ reg2 = pci_bus_clock_list(speed, twenty_five_base);
break;
default:
case 7:
- reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+ reg2 = pci_bus_clock_list(speed, thirty_three_base);
break;
}
+#if 0
+ /* this is a nice idea ... */
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ dev->sysdata);
+#endif
/*
* Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
*/
@@ -337,40 +534,47 @@
pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
}

-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
- byte reg5bh = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
- unsigned int list_conf = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+ unsigned int list_conf = 0;
unsigned int drive_conf = 0;
unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
- byte drive_pci = 0;
- byte drive_fast = 0;
+ byte drive_pci = 0x40 + (drive->dn * 4);
+ byte new_fast, drive_fast = 0;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;

- switch (drive->dn) {
- case 0: drive_pci = 0x40; break;
- case 1: drive_pci = 0x44; break;
- case 2: drive_pci = 0x48; break;
- case 3: drive_pci = 0x4c; break;
- default: return;
- }
/*
* Disable the "fast interrupt" prediction.
+ * don't holdoff on interrupts. (== 0x01 despite what the docs say)
*/
- pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+ pci_read_config_byte(dev, regfast, &drive_fast);
+ new_fast = drive_fast;
+ if (new_fast & 0x02)
+ new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ if (new_fast & 0x01)
+ new_fast &= ~0x01;
+#else
+ if ((new_fast & 0x01) == 0)
+ new_fast |= 0x01;
+#endif
+ if (new_fast != drive_fast)
+ pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);

- pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ dev->sysdata);

+ pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- /*
- * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
- */
- list_conf &= ~0x80000000;
+
+ if (speed < XFER_MW_DMA_0) {
+ list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ }

- pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+ pci_write_config_dword(dev, drive_pci, list_conf);
}

static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -382,9 +586,9 @@
drive->init_speed = speed;

if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
- hpt370_tune_chipset(drive, speed, 0);
+ hpt370_tune_chipset(drive, speed);
} else {
- hpt366_tune_chipset(drive, speed, 0);
+ hpt366_tune_chipset(drive, speed);
}
drive->current_speed = speed;
return ((int) ide_config_drive_speed(drive, speed));
@@ -541,13 +745,6 @@
}
}

-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
- if ((func != ide_dma_write) || (func != ide_dma_read))
- return;
- hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -624,6 +821,13 @@
reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+ /* fall through to a reset */
+#if 0
+ case ide_dma_begin:
+ case ide_dma_end:
+ /* reset the chips state over and over.. */
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+#endif
break;
case ide_dma_timeout:
default:
@@ -634,9 +838,52 @@

int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte regstate = hwif->channel ? 0x54 : 0x50;
+ byte reginfo = hwif->channel ? 0x56 : 0x52;
+ byte dma_stat;
+
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
+ case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+ dma_stat = inb(dma_base+2);
+ return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
+
+ case ide_dma_end:
+ dma_stat = inb(dma_base + 2);
+ if (dma_stat & 0x01) {
+ udelay(20); /* wait a little */
+ dma_stat = inb(dma_base + 2);
+ }
+ if ((dma_stat & 0x01) == 0)
+ break;
+
+ func = ide_dma_timeout;
+ /* fallthrough */
+
+ case ide_dma_timeout:
+ case ide_dma_lostirq:
+ pci_read_config_byte(hwif->pci_dev, reginfo,
+ &dma_stat);
+ printk("%s: %d bytes in FIFO\n", drive->name,
+ dma_stat);
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
+ dma_stat = inb(dma_base);
+ outb(dma_stat & ~0x1, dma_base); /* stop dma */
+ dma_stat = inb(dma_base + 2);
+ outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+ /* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+ case ide_dma_begin:
+#endif
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
+ break;
+
default:
break;
}
@@ -644,6 +891,210 @@
}
#endif /* CONFIG_BLK_DEV_IDEDMA */

+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+ unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
+ byte reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
+ byte reg59h = 0;
+
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte reset = (hwif->channel) ? 0x80 : 0x40;
+ byte state_reg = (hwif->channel) ? 0x57 : 0x53;
+ byte reg59h = 0;
+ byte regXXh = 0;
+
+ if (!hwif)
+ return -EINVAL;
+
+// hwif->bus_state = state;
+
+ pci_read_config_byte(dev, 0x59, &reg59h);
+ pci_read_config_byte(dev, state_reg, &regXXh);
+
+ if (state) {
+ (void) ide_do_reset(drive);
+ pci_write_config_byte(dev, state_reg, regXXh|0x80);
+ pci_write_config_byte(dev, 0x59, reg59h|reset);
+ } else {
+ pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+ pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+ (void) ide_do_reset(drive);
+ }
+ return 0;
+}
+
+/*
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ * 1) soft-reset the drive
+ * 2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT 0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ byte tristate, resetmask, bus_reg;
+ u16 tri_reg;
+
+ if (!hwif)
+ return -EINVAL;
+
+ hwif->bus_state = state;
+
+ if (hwif->channel) {
+ /* secondary channel */
+ tristate = 0x56;
+ resetmask = 0x80;
+ } else {
+ /* primary channel */
+ tristate = 0x52;
+ resetmask = 0x40;
+ }
+
+ /* grab status */
+ pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+ pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+ /* set the state. we don't set it if we don't need to do so.
+ * make sure that the drive knows that it has failed if it's off */
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ if ((bus_reg & resetmask) == 0)
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg &= ~resetmask;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+ return 0;
+ tri_reg |= TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ }
+ pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+ pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+ return 0;
+}
+
+static void __init init_hpt370(struct pci_dev *dev)
+{
+ int adjust, i;
+ u16 freq;
+ u32 pll;
+ byte reg5bh;
+
+ /*
+ * default to pci clock. make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * set up the PLL. we need to adjust it so that it's stable.
+ * freq = Tpll * 192 / Tpci
+ */
+ pci_read_config_word(dev, 0x78, &freq);
+ freq &= 0x1FF;
+ if (freq < 0x9c) {
+ pll = F_LOW_PCI_33;
+ dev->sysdata = (void *) thirty_three_base_hpt370;
+ printk("HPT370: using 33MHz PCI clock\n");
+ } else if (freq < 0xb0) {
+ pll = F_LOW_PCI_40;
+ } else if (freq < 0xc8) {
+ pll = F_LOW_PCI_50;
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz PCI clock\n");
+ } else {
+ pll = F_LOW_PCI_66;
+ dev->sysdata = (void *) sixty_six_base_hpt370;
+ printk("HPT370: using 66MHz PCI clock\n");
+ }
+
+ /*
+ * only try the pll if we don't have a table for the clock
+ * speed that we're running at. NOTE: the internal PLL will
+ * result in slow reads when using a 33MHz PCI clock. we also
+ * don't like to use the PLL because it will cause glitches
+ * on PRST/SRST when the HPT state engine gets reset.
+ */
+ if (dev->sysdata)
+ goto init_hpt370_done;
+
+ /*
+ * adjust PLL based upon PCI clock, enable it, and wait for
+ * stabilization.
+ */
+ adjust = 0;
+ freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+ while (adjust++ < 6) {
+ pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+ pll | 0x100);
+
+ /* wait for clock stabilization */
+ for (i = 0; i < 0x50000; i++) {
+ pci_read_config_byte(dev, 0x5b, &reg5bh);
+ if (reg5bh & 0x80) {
+ /* spin looking for the clock to destabilize */
+ for (i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b,
+ &reg5bh);
+ if ((reg5bh & 0x80) == 0)
+ goto pll_recal;
+ }
+ pci_read_config_dword(dev, 0x5c, &pll);
+ pci_write_config_dword(dev, 0x5c,
+ pll & ~0x100);
+ pci_write_config_byte(dev, 0x5b, 0x21);
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz internal PLL\n");
+ goto init_hpt370_done;
+ }
+ }
+pll_recal:
+ if (adjust & 1)
+ pll -= (adjust >> 1);
+ else
+ pll += (adjust >> 1);
+ }
+
+init_hpt370_done:
+ /* reset state engine */
+ pci_write_config_byte(dev, 0x50, 0x37);
+ pci_write_config_byte(dev, 0x54, 0x37);
+ udelay(100);
+}
+
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
byte test = 0;
@@ -652,14 +1103,8 @@
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);

pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
if (test != (L1_CACHE_BYTES / 4))
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif

pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
if (test != 0x78)
@@ -673,17 +1118,18 @@
if (test != 0x08)
pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);

+ if (pci_rev_check_hpt3xx(dev)) {
+ init_hpt370(dev);
+ hpt_devs[n_hpt_devs++] = dev;
+ } else {
+ hpt_devs[n_hpt_devs++] = dev;
+ }
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
if (!hpt366_proc) {
hpt366_proc = 1;
- bmide_dev = dev;
- if (pci_rev_check_hpt3xx(dev))
- bmide2_dev = dev;
hpt366_display_info = &hpt366_get_info;
}
- if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
- bmide2_dev = dev;
- }
#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */

return dev->irq;
@@ -691,38 +1137,72 @@

unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
{
- byte ata66 = 0;
+ byte ata66 = 0;
+ byte regmask = (hwif->channel) ? 0x01 : 0x02;

- pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+ if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+ byte scr2;
+ /*
+ * The HPT370 uses the CBLID pin outputs as MA15/MA16
+ * address lines to access an external eeprom. To
+ * read cable detect state the pins must be enabled
+ * as inputs by clearing bit 0 of reg 0x5b.
+ */
+ pci_read_config_byte(hwif->pci_dev, 0x5b, &scr2);
+ pci_write_config_byte(hwif->pci_dev, 0x5b, scr2 & ~1);
+ pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+ pci_write_config_byte(hwif->pci_dev, 0x5b, scr2 | 1);
+ } else {
+ pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+ }
#ifdef DEBUG
printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & 0x02) ? "33" : "66",
+ ata66, (ata66 & regmask) ? "33" : "66",
PCI_FUNC(hwif->pci_dev->devfn));
#endif /* DEBUG */
- return ((ata66 & 0x02) ? 0 : 1);
+ return ((ata66 & regmask) ? 0 : 1);
}

void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
+ int hpt_rev;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;

+#ifdef HPT_SERIALIZE_IO
+ /* serialize access to this device */
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+ hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+ if (hpt_rev) {
+ /* set up ioctl for power status. note: power affects both
+ * drives on each channel */
+ hwif->busproc = &hpt370_busproc;
+ }
+
if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
/* do nothing now but will split device types */
+ hwif->resetproc = &hpt3xx_reset;
+/*
+ * don't do until we can parse out the cobalt box argh ...
+ * hwif->busproc = &hpt3xx_tristate;
+ */
}

#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
- if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+ if (hpt_rev) {
byte reg5ah = 0;
pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
if (reg5ah & 0x10) /* interrupt force enable */
pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
hwif->dmaproc = &hpt370_dmaproc;
- hwif->rwproc = &hpt370_rw_proc;
} else {
hwif->dmaproc = &hpt366_dmaproc;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/