[PATCH][PPC32] PPC4xx ocp ide rewrite/cleanup

Andre' Draszik andid at gmx.net
Mon Feb 7 15:24:55 EST 2005


Hi,

this is a rewrite of the ibm4xx ocp ide driver. In its current state it
doesn't compile with current 2.6 and is completely broken in many other
aspects anyway.
Please consider applying (or tell me how the patch should be changed to
qualify for applying :)

Signed-off-by: Andre' Draszik <andid at gmx.net>

diff -urN -X dontdiff linuxppc-2.5.orig/drivers/ide/Kconfig linuxppc-2.5/drivers/ide/Kconfig
--- linuxppc-2.5.orig/drivers/ide/Kconfig	2005-02-03 20:18:54.000000000 +0100
+++ linuxppc-2.5/drivers/ide/Kconfig	2005-02-06 06:10:56.000000000 +0100
@@ -930,7 +930,7 @@
  endchoice

  config BLK_DEV_IDE_STB04xxx
-	bool "STB04xxx (Redwood-5) IDE support"
+	tristate "STB04xxx (Redwood-5) IDE support"
  	depends on BLK_DEV_IDE && REDWOOD_5
  	help
  	  This option provides support for IDE on IBM STB04xxx Redwood-5
@@ -1016,11 +1016,11 @@
  endif

  config BLK_DEV_IDEDMA
-	def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
+	def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_STB04xxx

  config IDEDMA_IVB
  	bool "IGNORE word93 Validation BITS"
-	depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
+	depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_STB04xxx
  	---help---
  	  There are unclear terms in ATA-4 and ATA-5 standards how certain
  	  hardware (an 80c ribbon) should be detected. Different interpretations
@@ -1035,7 +1035,7 @@
  	  It is normally safe to answer Y; however, the default is N.

  config IDEDMA_AUTO
-	def_bool IDEDMA_PCI_AUTO || IDEDMA_ICS_AUTO
+	def_bool IDEDMA_PCI_AUTO || IDEDMA_ICS_AUTO || BLK_DEV_IDE_STB04xxx

  endif

diff -urN -X dontdiff linuxppc-2.5.orig/drivers/ide/Makefile linuxppc-2.5/drivers/ide/Makefile
--- linuxppc-2.5.orig/drivers/ide/Makefile	2005-02-03 20:18:59.000000000 +0100
+++ linuxppc-2.5/drivers/ide/Makefile	2005-02-06 06:10:56.000000000 +0100
@@ -38,6 +38,11 @@
  # built-in only drivers from ppc/
  ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ppc/mpc8xx.o
  ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ppc/pmac.o
+ifeq ($(CONFIG_BLK_DEV_IDE_STB04xxx),y)
+ide-core-$(CONFIG_BLK_DEV_IDE_STB04xxx)	+= ppc/ibm_ocp_ide.o
+else
+obj-$(CONFIG_BLK_DEV_IDE_STB04xxx)	+= ppc/ibm_ocp_ide.o
+endif

  # built-in only drivers from h8300/
  ide-core-$(CONFIG_H8300)		+= h8300/ide-h8300.o
diff -urN -X dontdiff linuxppc-2.5.orig/drivers/ide/ppc/ibm_ocp_ide.c linuxppc-2.5/drivers/ide/ppc/ibm_ocp_ide.c
--- linuxppc-2.5.orig/drivers/ide/ppc/ibm_ocp_ide.c	2005-02-03 20:18:54.000000000 +0100
+++ linuxppc-2.5/drivers/ide/ppc/ibm_ocp_ide.c	2005-02-07 04:54:12.000000000 +0100
@@ -1,14 +1,26 @@
  /*
- *    Copyright 2002 MontaVista Software Inc.
- *      Completed implementation.
- *      Author: Armin Kuster <akuster at mvista.com>
- *      MontaVista Software, Inc.  <source at mvista.com>
+ * IDE driver for IBM On-chip IDE contollers
+ *    Copyright 2001 - 2002 MontaVista Software Inc.
+ *    Dan Malek.
   *
- *    Module name: ibm_ocp_ide.c
+ *    Version 1.2 (01/30/12) Armin
+ *    Converted to ocp
+ *    merger up to new ide-timing.h
   *
- *    Description:
+ *    Version 2.0 (05/02/15) - armin
+ *    converted to new core_ocp and only supports one interface for now.
   *
- *    Based on ocp_stbxxxx.c
+ *    Version 2.1 (05/25/02) - armin
+ *      name change from *_driver to *_dev
+ *    Version 2.2 06/13/02 - Armin
+ *      changed irq_resource array to just irq
+ *
+ *    Version 2.3 (Feb 2005) - andre
+ *      - big rewrite to fix some serious bugs
+ *      - bring up to date with ide in 2.6.11-rc3
+ *      - DMA works correctly now, even with non-hard-disks
+ *        I snagged bits and pieces from a variety of drivers, primarily
+ *        ide-pmac.c and ide-dma.c .....thanks to previous authors!
   */

  #include <linux/types.h>
@@ -17,54 +29,47 @@
  #include <linux/hdreg.h>
  #include <linux/delay.h>
  #include <linux/ide.h>
-#include "../ide-timing.h"
+#include <ide-timing.h>
  #include <asm/ocp.h>
  #include <asm/io.h>
  #include <asm/scatterlist.h>
-#include <asm/ppc4xx_dma.h>
-
-#include "ide_modes.h"
+#include <asm/dma-mapping.h>

-#define IDE_VER			"2.0"
-ppc_dma_ch_t dma_ch;
+#define OCPVR	"2.3"

-/* use DMA channel 2 for IDE DMA operations */
-#define IDE_DMACH	2	/* 2nd DMA channel */
-#define IDE_DMA_INT	6	/* IDE dma channel 2 interrupt */

-#define WMODE	0		/* default to DMA line mode */
-#define PIOMODE	0

  #define MK_TIMING(AS, DIOP, DIOY, DH) \
-	((FIT((AS),    0, 15) << 27) | \
-	 (FIT((DIOP),  0, 63) << 20) | \
-	 (FIT((DIOY),  0, 63) << 13) | \
-	 (FIT((DH),    0,  7) << 9))
+	((FIT((AS),    0, 0x0f) << 27) | \
+	 (FIT((DIOP),  0, 0x3f) << 20) | \
+	 (FIT((DIOY),  0, 0x3f) << 13) | \
+	 (FIT((DH),    0, 0x07) <<  9))

  #define UTIMING_SETHLD	(EZ(20 /*tACK*/, SYS_CLOCK_NS) - 1 /*fixed cycles*/)
  #define UTIMING_ENV	(EZ(20 /*tENV*/, SYS_CLOCK_NS) - 1 /*fixed cycles*/)
  #define UTIMING_SS	(EZ(50 /*tSS */, SYS_CLOCK_NS) - 3 /*fixed cycles*/)
+
  #define MK_UTIMING(CYC, RP) \
-	((FIT(UTIMING_SETHLD, 0, 15) << 27) | \
-	 (FIT(UTIMING_ENV,    0, 15) << 22) | \
-	 (FIT((CYC),          0, 15) << 17) | \
-	 (FIT((RP),           0, 63) << 10) | \
-	 (FIT(UTIMING_SS,     0, 15) << 5)  | \
+	((FIT(UTIMING_SETHLD, 0, 0x0f) << 27) | \
+	 (FIT(UTIMING_ENV,    0, 0x0f) << 22) | \
+	 (FIT((CYC),          0, 0x0f) << 17) | \
+	 (FIT((RP),           0, 0x3f) << 10) | \
+	 (FIT(UTIMING_SS,     0, 0x0f) <<  5) | \
  	 1 /* Turn on Ultra DMA */)

  /* Define the period of the STB clock used to generate the
   * IDE bus timing.  The clock is actually 63 MHz, but it
- * get rounded in a favorable direction.
+ * gets rounded in a favorable direction.
   */
  #define IDE_SYS_FREQ	63	/* MHz */
-#define SYS_CLOCK_NS	(1000 / IDE_SYS_FREQ)
+#define SYS_CLOCK_NS	(1000 / IDE_SYS_FREQ)   /* 1clock == SYS_CLOCK_NS nanoseconds */

  struct whold_timing {
  	short mode;
  	short whold;
  };

-static struct whold_timing whold_timing[] = {
+static const struct whold_timing whold_timing[] = {

  	{XFER_UDMA_5, 0},
  	{XFER_UDMA_4, 0},
@@ -101,10 +106,10 @@
   * but rather "fast" and "slow" timing.  We have to determeine
   * which is the "fast" device based upon their capability.
   */
-static int pio_mode[2];
+static int pio_mode[2] = { -1, -1 };
+

-/* Structure of the memory mapped IDE control.
-*/
+/* structure of the memory mapped IDE control */
  typedef struct ide_regs {
  	unsigned int si_stat;	/* IDE status */
  	unsigned int si_intenable;	/* IDE interrupt enable */
@@ -114,8 +119,8 @@
  	unsigned int si_c0fpt;	/* Chan 0 Fast PIO transfer timing */
  	unsigned int si_c0timo;	/* Chan 0 timeout */
  	unsigned int pad1[2];
-	unsigned int si_c0d0u;	/* Chan 0 UDMA transfer timing */
-#define si_c0d0m si_c0d0u	/* Chan 0 Multiword DMA timing */
+	unsigned int si_c0d0u;	/* Chan 0 dev 0 UDMA timing */
+#define si_c0d0m si_c0d0u	/* Chan 0 dev 0 Multiword DMA timing */
  	unsigned int pad2;
  	unsigned int si_c0d1u;	/* Chan 0 dev 1 UDMA timing */
  #define si_c0d1m si_c0d1u	/* Chan 0 dev 1 Multiword DMA timing */
@@ -148,84 +153,74 @@
  	unsigned int prd_physptr;
  	unsigned int prd_count;	/* Count only in lower 16 bits */
  } prd_entry_t;
-#define PRD_EOT		(uint)0x80000000	/* Set in prd_count */
+#define PRD_EOT		0x80000000lu	/* Set in prd_count */

  /* The number of PRDs required in a single transfer from the upper IDE
- * functions.  I believe the maximum number is 128, but most seem to
- * code to 256.  It's probably best to keep this under one page......
+ * functions. The maximum number is 128 (ide.h), but most seem to code to
+ * 256 (because of having two IDE channels). must be less than one page.
   */
-#define NUM_PRD	256
+#define NUM_PRD 256

-static volatile ide_t *idp;
-/* Virtual and physical address of the PRD page.
-*/
-static prd_entry_t *prd_table;
-static dma_addr_t prd_phys;
-
-/* Function Prototypes */
-static void ocp_ide_tune_drive(ide_drive_t *, byte);
-static int ocp_ide_dma_off(ide_drive_t * drive);

-/* The STB04 has a fixed number of cycles that get added in
- * regardless.  Adjust an ide_timing struct to accommodate that.
- */
-static void
-ocp_ide_adjust_timing(struct ide_timing *t)
-{
-	t->setup -= 2;
-	t->act8b -= 1;
-	t->rec8b -= 1;
-	t->active -= 1;
-	t->recover -= 1;
-}

-/* this iis barrowed from ide_timing_find_mode so we can find the proper
- * whold parameter
+/* this is borrowed from ide_timing_find_mode so we can find the proper
+ * whold parameter
   */
-
  static short
  whold_timing_find_mode(short speed)
  {
-	struct whold_timing *t;
+	const struct whold_timing *t;
+
+	for (t = whold_timing; likely (t->mode >= 0); t++)
+		if (t->mode == speed)
+			return t->whold;

-	for (t = whold_timing; t->mode != speed; t++)
-		if (t->mode < 0)
-			return 0;
-	return t->whold;
+	return 0;
+}
+
+/* The STB04 has a fixed number of cycles that get added in
+ * regardless.  Adjust an ide_timing struct to accommodate that.
+ */
+static void
+stb04xxx_ide_adjust_timing(struct ide_timing * const t)
+{
+	t->setup   -= 2;
+	t->act8b   -= 1;
+	t->rec8b   -= 1;
+	t->active  -= 1;
+	t->recover -= 1;
  }

  static int
-ocp_ide_set_drive(ide_drive_t * drive, unsigned char speed)
+stb04xxx_ide_tune_chipset (ide_drive_t * const drive,
+			   u8           speed)
  {
-	ide_drive_t *peer;
-	struct ide_timing d, p, merge, *fast;
-	int fast_device;
-	unsigned int ctl;
-	volatile unsigned int *dtiming;
+	volatile ide_t __iomem * const ide_regs  = HWIF (drive)->hwif_data;
+	ide_drive_t       *peer        = HWIF (drive)->drives + (~drive->dn & 1);
+	struct ide_timing  t, p, merge, *fast;
+	int                fast_device;
+	unsigned int       ctl;

  	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
  		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING
-			       "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-			       drive->dn >> 1, drive->dn & 1);
-
-	ide_timing_compute(drive, speed, &d, SYS_CLOCK_NS, SYS_CLOCK_NS);
-	ocp_ide_adjust_timing(&d);
+			printk (KERN_WARNING
+				"ide%d: Drive %d didn't accept speed setting. "
+				"Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);

-	/* This should be set somewhere else, but it isn't.....
-	 */
-	drive->dn = ((drive->select.all & 0x10) != 0);
-	peer = HWIF(drive)->drives + (~drive->dn & 1);
+	ide_timing_compute(drive, speed, &t, SYS_CLOCK_NS, SYS_CLOCK_NS);
+	stb04xxx_ide_adjust_timing(&t);

+	/* peer is the other, i.e. not current, drive */
  	if (peer->present) {
  		ide_timing_compute(peer, peer->current_speed, &p,
  				   SYS_CLOCK_NS, SYS_CLOCK_NS);
-		ocp_ide_adjust_timing(&p);
-		ide_timing_merge(&p, &d, &merge,
+		stb04xxx_ide_adjust_timing(&p);
+		ide_timing_merge(&p, &t, &merge,
  				 IDE_TIMING_8BIT | IDE_TIMING_SETUP);
-	} else {
-		merge = d;
  	}
+	else
+		merge = t;

  	if (!drive->init_speed)
  		drive->init_speed = speed;
@@ -235,58 +230,59 @@
  	 * interface timing.  It would sure be nice if they would
  	 * have just had the timing registers for each device......
  	 */
-	if (drive->dn & 1)
-		pio_mode[1] = (int) speed;
-	else
-		pio_mode[0] = (int) speed;
-
-	if (pio_mode[0] > pio_mode[1])
-		fast_device = 0;
-	else
-		fast_device = 1;
+	/* change pio_mode of current drive */
+	pio_mode[(drive->dn & 1)] = (int) speed;

  	/* Now determine which of the drives
  	 * the first call we only know one device, and on subsequent
  	 * calls the user may manually change drive parameters.
  	 * Make timing[0] the fast device and timing[1] the slow.
  	 */
+
+	/* compare pio_mode of both drives, one of them is
+	   faster than the other */
+	if (pio_mode[0] >= pio_mode[1])
+		fast_device = 0;
+	else
+		fast_device = 1;
+
  	if (fast_device == (drive->dn & 1))
-		fast = &d;
+		/* if fast drive == current drive */
+		fast = &t;
  	else
+		/* if fast drive == peer (other) drive */
  		fast = &p;

  	/* Now we know which device is the fast one and which is
  	 * the slow one.  The merged timing goes into the "regular"
  	 * timing registers and represents the slower of both times.
  	 */
-
-	idp->si_c0rt = MK_TIMING(merge.setup, merge.act8b,
-				 merge.rec8b,
-				 whold_timing_find_mode(merge.mode));
-
-	idp->si_c0fpt = MK_TIMING(fast->setup, fast->act8b,
-				  fast->rec8b,
-				  whold_timing_find_mode(fast->mode));
-
-	/* Tell the interface which drive is the fast one.
-	 */
-	ctl = idp->si_c0c;	/* Chan 0 Control */
-	ctl &= ~0x10000000;
+	ide_regs->si_c0rt = MK_TIMING(merge.setup, merge.act8b,
+				      merge.rec8b,
+				      whold_timing_find_mode(merge.mode));
+
+	ide_regs->si_c0fpt = MK_TIMING(fast->setup, fast->act8b,
+				       fast->rec8b,
+				       whold_timing_find_mode(fast->mode));
+
+	/* tell the interface which drive is the fast one. 	 */
+	ctl = ide_regs->si_c0c; /* Chan 0 Control */
+	ctl &= ~0x10000000ul;
  	ctl |= fast_device << 28;
-	idp->si_c0c = ctl;
+	ide_regs->si_c0c = ctl;

-	/* Set up DMA timing.
-	 */
+	/* Set up DMA timing. */
  	if ((speed & XFER_MODE) != XFER_PIO) {
  		/* NOTE: si_c0d0m and si_c0d0u are two different names
  		 * for the same register.  Whether it is used for
  		 * Multi-word DMA timings or Ultra DMA timings is
  		 * determined by the LSB written into it.  This is also
  		 * true for si_c0d1m and si_c0d1u.  */
+		volatile unsigned int __iomem *dtiming;
  		if (drive->dn & 1)
-			dtiming = &(idp->si_c0d1m);
+			dtiming = &(ide_regs->si_c0d1u);
  		else
-			dtiming = &(idp->si_c0d0m);
+			dtiming = &(ide_regs->si_c0d0u);

  		if ((speed & XFER_MODE) == XFER_UDMA) {
  			static const int tRP[] = {
@@ -295,18 +291,18 @@
  				EZ(100, SYS_CLOCK_NS) - 2 /*fixed cycles */ ,
  				EZ(100, SYS_CLOCK_NS) - 2 /*fixed cycles */ ,
  				EZ(100, SYS_CLOCK_NS) - 2 /*fixed cycles */ ,
-				EZ(85, SYS_CLOCK_NS) - 2	/*fixed cycles */
+				EZ( 85, SYS_CLOCK_NS) - 2 /*fixed cycles */
  			};
  			static const int NUMtRP =
  			    (sizeof (tRP) / sizeof (tRP[0]));
  			*dtiming =
-			    MK_UTIMING(d.udma,
+			    MK_UTIMING(t.udma,
  				       tRP[FIT(speed & 0xf, 0, NUMtRP - 1)]);
  		} else {
-			/* Multi-word DMA.  Note that d.recover/2 is an
+			/* Multi-word DMA.  Note that t.recover/2 is an
  			 * approximation of MAX(tH, MAX(tJ, tN)) */
-			*dtiming = MK_TIMING(d.setup, d.active,
-					     d.recover, d.recover / 2);
+			*dtiming = MK_TIMING(t.setup, t.active,
+					     t.recover, t.recover / 2);
  		}
  		drive->using_dma = 1;
  	}
@@ -314,590 +310,547 @@
  	return 0;
  }

+/**
+ *	stb04xxx_ide_tune_drive - tune a drive attached to a stb04
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode (255 for "best possible")
+ *
+ *	Set the interface PIO mode.
+ */
  static void
-ocp_ide_tune_drive(ide_drive_t * drive, byte pio)
+stb04xxx_ide_tune_drive (ide_drive_t * const drive,
+			 u8           pio)
  {
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	pio = ide_get_best_pio_mode (drive, pio, 4, NULL);
+	stb04xxx_ide_tune_chipset(drive, XFER_PIO_0 + pio);
  }

-/*
- * Fill in the next PRD entry.
- */
-
-static int ocp_ide_build_prd_entry(prd_entry_t **table, unsigned int paddr,
-				   unsigned int size, int *count)
+static int
+stb04xxx_ide_dma_host_off (ide_drive_t * const drive)
  {
+	return 0;
+}
+static int stb04xxx_ide_dma_host_on (ide_drive_t * const drive) __attribute__((alias("stb04xxx_ide_dma_host_off")));

-	/*
-	 * Note that one PRD entry can transfer
-	 * at most 65535 bytes.
-	 */
-
-	while (size) {
-		unsigned int tc = (size < 0xfe00) ? size : 0xfe00;
+static int
+stb04xxx_ide_dma_off_quietly (ide_drive_t * const drive)
+{
+	drive->using_dma = 0;
+	return stb04xxx_ide_dma_host_off (drive);
+}

-		if (++(*count) >= NUM_PRD) {
-		  printk(KERN_WARNING "DMA table too small\n");
-			return 0;	/* revert to PIO for this request */
-		}
-		(*table)->prd_physptr = (paddr & 0xfffffffe);
+#if 0
+static int
+config_drive_for_dma (ide_drive_t * const drive)
+{
+	struct hd_driveid * const id   = drive->id;
+	ide_hwif_t        * const hwif = HWIF (drive);

-		if ((*table)->prd_physptr & 0xF) {
-			printk(KERN_WARNING "DMA buffer not 16 byte aligned.\n");
-			return 0;	/* revert to PIO for this request */
-		}
-		
-		(*table)->prd_count = (tc & 0xfffe);
-		paddr += tc;
-		size -= tc;
-		++(*table);
+	if ((id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (0)
+			return stb04xxx_ide_dma_off_quietly (drive);
+
+		/* enable DMA on any drive that has
+		   UltraDMA (mode 0/1/2/3/4/5) enabled */
+                if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x3f))
+			return stb04xxx_ide_dma_on (drive);
+
+		/* enable DMA on any drive that has mode2 DMA
+		   (multi) enabled */
+		if (id->field_valid & 2)
+                        if ((id->dma_mword & 0x404) == 0x404)
+				return stb04xxx_ide_dma_on (drive);
+
+		/* Consult the list of known "good" drives */
+		if (1)
+			return stb04xxx_ide_dma_on (drive);
  	}
-
-	return 1;
+	return stb04xxx_ide_dma_off_quietly (drive);
  }
+#endif

-
+/**
+ *	stb04xxx_ide_dma_check - set up for DMA if possible
+ *	@drive: IDE drive to set up
+ *
+ *	Set up the drive for the highest supported speed considering the
+ *	driver, controller and cable
+ */
  static int
-ocp_ide_build_dmatable(ide_drive_t * drive, int wr)
+stb04xxx_ide_dma_check (ide_drive_t * const drive)
  {
-	prd_entry_t *table;
-	int count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
-	unsigned long size, vaddr, paddr;
-	unsigned long prd_size, prd_paddr = 0;
-	struct bio_vec *bvec, *bvprv;
-	struct bio *bio;
-	int i;
+#if 0
+	return config_drive_for_dma (drive);
+#else
+	/* Allow UDMA_66 only if an 80 conductor cable is connected. */
+	u16 w80 = HWIF (drive)->udma_four;

-	table = prd_table;
+	/* Section 1.6.2.6 "IDE Controller, ATA/ATAPI-5" in the STB04xxx
+	 * Datasheet says the following modes are supported:
+	 *   PIO modes 0 to 4
+	 *   Multiword DMA modes 0 to 2
+	 *   UltraDMA modes 0 to 4
+	 */
+	int modes = XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA
+		    | (w80 ? XFER_UDMA_66 : 0);
+	int mode;
+
+	/* XFER_EPIO includes both PIO modes 4 and 5.  Mode 5 is not
+	 * valid for the STB04, so mask it out of consideration just
+	 * in case some drive sets it...
+	 */
+	drive->id->eide_pio_modes &= ~4;

-	bvprv = NULL;
-	rq_for_each_bio(bio, rq) {
-		bio_for_each_segment(bvec, bio, i) {
-			paddr = bvec_to_phys(bvec);
-			vaddr = (unsigned long) __va(paddr);
-			size = bvec->bv_len;
-			if (wr)
-				consistent_sync((void *)vaddr,
-						size, PCI_DMA_TODEVICE);
-			else
-				consistent_sync((void *)vaddr,
-						size, PCI_DMA_FROMDEVICE);
-
-			if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) {
-				if (ocp_ide_build_prd_entry(&table,
-							    prd_paddr,
-							    prd_size,
-							    &count) == 0)
-					return 0; /* use PIO */
-				prd_paddr = 0;
-			}
-
-			if (prd_paddr == 0) {
-				prd_paddr = paddr;
-				prd_size = size;
-			} else {
-			  prd_size += size;
-			}
-
-			bvprv = bvec;
-		} /* segments in bio */
-	} /* bios in rq */
-
-	if (prd_paddr) {
-		if (ocp_ide_build_prd_entry(&table,
-					    prd_paddr,
-					    prd_size,
-					    &count) == 0)
-			return 0; /* use PIO */
-	}
+	mode = ide_find_best_mode (drive, modes);

-	/* Add the EOT to the last table entry.
-	 */
-	if (count) {
-		table--;
-		table->prd_count |= PRD_EOT;
-	} else {
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-	}
+	drive->using_dma = 0;
+	stb04xxx_ide_tune_chipset (drive, mode);
+	if (HWIF (drive)->autodma
+	    && (((mode & XFER_MODE) == XFER_PIO)
+		|| ((mode & XFER_MODE) == XFER_EPIO)))
+		drive->using_dma = 0;

-	return 1;
+	return 0;
+#endif
  }

-/*
- * ocp_ide_dma_intr() is the handler for disk read/write DMA interrupts
- * This is taken directly from ide-dma.c, which we can't use because
- * it requires PCI support.
- */
-ide_startstop_t
-ocp_ide_dma_intr(ide_drive_t * drive)
+static int
+stb04xxx_ide_dma_on (ide_drive_t * const drive)
  {
-	int i;
-	byte stat, dma_stat;
-
-	dma_stat = HWIF(drive)->ide_dma_end(drive);
-	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/* get drive status */
-	if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_end_request(drive, 1,
-						rq->current_nr_sectors );
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
-		       drive->name, dma_stat);
-	}
-	return ide_error(drive, "dma_intr", stat);
+	drive->using_dma = 1;
+	return stb04xxx_ide_dma_host_on (drive);
  }

-/* ....and another one....
-*/
-int
-report_drive_dmaing(ide_drive_t * drive)
-{
-	struct hd_driveid *id = drive->id;

-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-		if ((id->dma_ultra >> 13) & 1) {
-			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4) {
-		printk(", (U)DMA");	/* Can be BIOS-enabled! */
-	} else {
-		printk(", DMA");
-	}
-	return 1;
-}

+/* fill in the next PRD entry
+   note that one PRD entry can transfer at most 65536 bytes */
  static int
-ocp_ide_check_dma(ide_drive_t * drive)
+build_prd_entry (prd_entry_t **table,
+		 u32           paddr,
+		 u32           size,
+		 int          *count)
  {
-	struct hd_driveid *id = drive->id;
-	int enable = 1;
-	int speed;
+	while (size) {
+		u16 tc = size & 0xffff;

-	drive->using_dma = 0;
+		if (unlikely (*count >= NUM_PRD)) {
+//			printk (KERN_WARNING "%s: DMA table too small\n",
+//					     __FUNCTION__);
+			return 0;	/* revert to PIO for this request */
+		}

-	if (drive->media == ide_floppy)
-		enable = 0;
+		/* data must be 16 byte aligned */
+		if (unlikely (paddr & 0xf)) {
+//			printk (KERN_WARNING
+//				"%s: DMA buffer not 16 byte aligned.\n",
+//				__FUNCTION__);
+			return 0;	/* revert to PIO for this request */
+		}

-	/* Check timing here, we may be able to include XFER_UDMA_66
-	 * and XFER_UDMA_100.  This basically tells the 'best_mode'
-	 * function to also consider UDMA3 to UDMA5 device timing.
-	 */
-	if (enable) {
-		/* Section 1.6.2.6 "IDE Controller, ATA/ATAPI-5" in the STB04xxx
-		 * Datasheet says the following modes are supported:
-		 *   PIO modes 0 to 4
-		 *   Multiword DMA modes 0 to 2
-		 *   UltraDMA modes 0 to 4
-		 */
-		int map = XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA;
-		/* XFER_EPIO includes both PIO modes 4 and 5.  Mode 5 is not
-		 * valid for the STB04, so mask it out of consideration just
-		 * in case some drive sets it...
-		 */
-		id->eide_pio_modes &= ~4;
-
-		/* Allow UDMA_66 only if an 80 conductor cable is connected. */
-		if (eighty_ninty_three(drive))
-			map |= XFER_UDMA_66;
-
-		speed = ide_find_best_mode(drive, map);
-		ocp_ide_set_drive(drive, speed);
-
-		if (HWIF(drive)->autodma &&
-		    (((speed & XFER_MODE) == XFER_PIO) ||
-		     ((speed & XFER_MODE) == XFER_EPIO))) {
-			drive->using_dma = 0;
+		/* transfer count must be a multiple of 16 */
+		if (unlikely (tc & 0x0f)) {
+//			printk (KERN_WARNING
+//				"%s: invalid DMA transfer count.\n",
+//				__FUNCTION__);
+			return 0;	/* revert to PIO for this request */
  		}
+		
+		(*table)->prd_physptr = paddr;
+		(*table)->prd_count   = tc;
+
+		paddr += (tc ? : 65536);
+		size  -= (tc ? : 65536);
+
+		++(*table);
+		++(*count);
  	}

-	return 0;
+	return 1;
  }

-static int ocp_ide_dma_off_quietly(ide_drive_t * drive)
+static int
+stb04xxx_ide_build_sglist (ide_drive_t        * const drive,
+			   ide_hwif_t         * const hwif,
+			   struct request     * const rq,
+			   struct scatterlist *sg)
  {
-	drive->using_dma = 0;
-	return 0;
-}
+	if ((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256)
+		BUG();

-static int ocp_ide_dma_off(ide_drive_t * drive)
-{
-	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	return ocp_ide_dma_off_quietly(drive);
-}
+	ide_map_sg(drive, rq);

-static int ocp_ide_dma_on(ide_drive_t * drive)
-{
-	return ocp_ide_check_dma(drive);
+	hwif->sg_dma_direction = (rq_data_dir (rq) == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	
+	return dma_map_sg(/* hwif->pci_dev */ NULL, sg, hwif->sg_nents,
+			  hwif->sg_dma_direction);
  }

-static int ocp_ide_dma_check(ide_drive_t * drive)
+static int
+stb04xxx_ide_build_dmatable (ide_drive_t    * const drive,
+			     ide_hwif_t     * const hwif,
+			     struct request * const rq)
  {
-	return ocp_ide_dma_on(drive);
-}
+	prd_entry_t  *table = (prd_entry_t *) hwif->dmatable_cpu;
+	unsigned int  count = 0;
+	int i;
+	struct scatterlist *sg = hwif->sg_table;

-static int __ocp_ide_dma_begin(ide_drive_t * drive, int writing)
-{
-	idp->si_c0tb = (unsigned int) prd_phys;
-	idp->si_c0s0 = 0xdc800000;	/* Clear all status */
-	idp->si_c0ie = 0x90000000;	/* Enable all intr */
-	idp->si_c0dcm = 0;
-	idp->si_c0dcm =
-		(writing ? 0x09000000 : 0x01000000);
-	return 0;
+	hwif->sg_nents = i = stb04xxx_ide_build_sglist (drive, hwif, rq, sg);
+
+	if (unlikely (!i))
+		goto use_pio_instead;
+	
+	++i;
+	while (--i) {
+		if (unlikely (!build_prd_entry (&table,
+						sg_dma_address (sg),
+						sg_dma_len (sg),
+						&count)))
+			goto use_pio_instead;
+
+		++sg;
+	}
+
+	if (likely (count)) {
+		--table;
+		table->prd_count |= PRD_EOT;
+		return count;
+	}
+
+	printk (KERN_ERR "%s: empty DMA table?\n", drive->name);
+
+use_pio_instead:
+	dma_unmap_sg (NULL,
+		      hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction);
+	
+	return 0; /* revert to PIO for this request */
  }
+	

-static int ocp_ide_dma_begin(ide_drive_t * drive)
+static void
+stb04xxx_ide_destroy_dmatable (ide_drive_t * const drive)
  {
-	idp->si_c0tb = (unsigned int) prd_phys;
-	idp->si_c0s0 = 0xdc800000;	/* Clear all status */
-	idp->si_c0ie = 0x90000000;	/* Enable all intr */
-	idp->si_c0dcm = 0;
-	idp->si_c0dcm =	0x01000000;
-	return 0;
+	ide_hwif_t *hwif = drive->hwif;
+	int nents = hwif->sg_nents;
+	
+	if (nents) {
+		dma_unmap_sg (NULL, hwif->sg_table, nents,
+			      hwif->sg_dma_direction);
+		hwif->sg_nents = 0;
+	}
  }

-static int ocp_ide_dma_io(ide_drive_t * drive, int writing)
+
+static int
+stb04xxx_dma_setup (ide_drive_t * const drive)
  {
-	if (!ocp_ide_build_dmatable(drive, writing))
+	ide_hwif_t             * const hwif = HWIF (drive);
+	volatile ide_t __iomem * const ide_regs = (ide_t *) hwif->hwif_data;
+	struct request         * const rq = HWGROUP (drive)->rq;
+
+	/* PRD table */
+	if (unlikely (!stb04xxx_ide_build_dmatable (drive, hwif, rq))) {
+		/* try PIO instead of DMA */
+		ide_map_sg (drive, rq);
  		return 1;
+	}
+
+	ide_regs->si_c0tb = hwif->dmatable_dma; /* address of sg list */
+	ide_regs->si_c0s0 = 0xdc800000ul;       /* clear all status */
+	ide_regs->si_c0ie = 0x90000000ul;       /* enable all intr */
+	/* specify r/w */
+	ide_regs->si_c0dcm = (rq_data_dir (rq) == READ) ? 0x00000000ul : 0x08000000ul;

  	drive->waiting_for_dma = 1;
-	if (drive->media != ide_disk)
-		return 0;
-	ide_set_handler(drive, &ocp_ide_dma_intr, WAIT_CMD, NULL);
-	HWIF(drive)->OUTB(writing ? WIN_WRITEDMA : WIN_READDMA,
-		 IDE_COMMAND_REG);
-	return __ocp_ide_dma_begin(drive, writing);
+	return 0;
  }

-static int ocp_ide_dma_read(ide_drive_t * drive)
+static void
+stb04xxx_dma_exec_cmd (ide_drive_t * const drive,
+		       u8           command)
  {
-	return ocp_ide_dma_io(drive, 0);
+	ide_execute_command (drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
  }

-static int ocp_ide_dma_write(ide_drive_t * drive)
+static void
+stb04xxx_dma_start (ide_drive_t * const drive)
  {
-	return ocp_ide_dma_io(drive, 1);
+	volatile ide_t __iomem * const ide_regs  = (ide_t *) HWIF (drive)->hwif_data;
+
+	/* start DMA */
+	mb ();
+	ide_regs->si_c0dcm |= 0x01000000ul; /* kick it */
  }

-static int ocp_ide_dma_end(ide_drive_t * drive)
+static int
+stb04xxx_ide_dma_end (ide_drive_t * const drive)
  {
-	unsigned int dstat;
+	volatile ide_t __iomem * const ide_regs = (ide_t *) HWIF (drive)->hwif_data;
+	unsigned int    dstat;

  	drive->waiting_for_dma = 0;
-	dstat = idp->si_c0s1;
-	idp->si_c0s0 = 0xdc800000;	/* Clear all status */
+	/* stop DMA */
+	ide_regs->si_c0dcm &= ~0x01000000ul;
+	/* get DMA status */
+	dstat = ide_regs->si_c0s1;
+	/* clear all status bits */
+	ide_regs->si_c0s0 = 0xdc800000ul;
+	wmb ();
+	stb04xxx_ide_destroy_dmatable (drive);
  	/* verify good dma status */
-	return (dstat & 0x80000000);
-}
-
-static int ocp_ide_dma_test_irq(ide_drive_t * drive)
-{
-	return idp->si_c0s0 & 0x10000000 ? 1 : 0;
+	return (dstat & 0x10000000ul) ? 0 : 1; /* return true if DMA still active */
  }

-static int ocp_ide_dma_verbose(ide_drive_t * drive)
-{
-	return report_drive_dmaing(drive);
-}
-
-static unsigned int
-ocp_ide_spinup(int index)
+static int
+stb04xxx_ide_dma_test_irq (ide_drive_t * const drive)
  {
-	int i, ret;
-	ide_ioreg_t *io_ports;
+	/* return 1 if dma irq issued, 0 otherwise */
+	volatile ide_t __iomem * const ide = (ide_t *) HWIF (drive)->hwif_data;

-	ret = 1;
-	printk("OCP ide: waiting for drive spinup");
-	printk("ioports for drive %d @ %p\n",index,ide_hwifs[index].io_ports);
-	io_ports = ide_hwifs[index].io_ports;
-	printk(".");
-	
-	/* wait until drive is not busy (it may be spinning up) */
-	for (i = 0; i < 30; i++) {
-		unsigned char stat;
-		stat = inb_p(io_ports[7]);
-		/* wait for !busy & ready */
-		if ((stat & 0x80) == 0) {
-			break;
-		}
-		udelay(1000 * 1000);	/* 1 second */
+	if (ide->si_c0s0 & 0x10000000ul)
+		return 1;
+	if (!drive->waiting_for_dma) {
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+				    drive->name, __FUNCTION__);	
  	}

-	printk(".");
+	return 0;
+}

-	/* select slave */
-	outb_p(0xa0 | 0x10, io_ports[6]);

-	for (i = 0; i < 30; i++) {
-		unsigned char stat;
-		stat = inb_p(io_ports[7]);
-		/* wait for !busy & ready */
-		if ((stat & 0x80) == 0) {
-			break;
-		}
-		udelay(1000 * 1000);	/* 1 second */
-	}
-	if( i < 30){
-		outb_p(0xa0, io_ports[6]);
-		printk("Drive spun up \n");
-	} else {
-		printk("Drive spin up Failed !\n");
-		ret = 0;
-	}
-	return (ret);
+static int
+stb04xxx_ide_dma_lostirq (ide_drive_t * const drive)
+{
+	printk ("%s: DMA interrupt recovery neccessary\n", drive->name);
+	return 1;
  }

-int
-ocp_ide_default_irq(ide_ioreg_t base)
+static int
+stb04xxx_ide_dma_timeout (ide_drive_t * const drive)
  {
-	return IDE0_IRQ;
+	printk (KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	if (stb04xxx_ide_dma_test_irq (drive))
+		return 0;
+	return stb04xxx_ide_dma_end (drive);
  }

-/*
- * setup_ocp_ide()
- * Completes the setup of a on-chip ide controller card, once found.
- */
-int __init setup_ocp_ide (struct ocp_device *pdev)
+static void
+stb04xxx_ide_setup_dma (ide_hwif_t * const hwif)
  {
-	ide_hwif_t	*hwif;
-	unsigned int uicdcr;
-	
-	hwif = &ide_hwifs[pdev->num];
-	hwif->index = pdev->num;
-#ifdef WMODE
-   /*Word Mode psc(11-12)=00,pwc(13-18)=000110, phc(19-21)=010, 22=1, 30=1  ----  0xCB02*/
-
-    dma_ch.mode	=TM_S_MM;	  /* xfer from peripheral to mem */
-    dma_ch.pwidth = PW_16;
-    dma_ch.pwc = 6;                     /* set the max wait cycles  */
-#else
-/*Line Mode psc(11-12)=00,pwc(13-18)=000001, phc(19-21)=010, 22=1, 30=1  ----  0x2B02*/
+	hwif->autodma = 1;
+	hwif->drives[0].autotune = hwif->drives[1].autotune = IDE_TUNE_AUTO;
+	hwif->drives[0].autodma  = hwif->drives[1].autodma  = hwif->autodma;
+
+	hwif->atapi_dma  = 1;
+	hwif->ultra_mask = hwif->udma_four ? 0x1f : 0x07;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x00;
+
+	/* set everything to something != NULL */
+	hwif->ide_dma_host_off = &stb04xxx_ide_dma_host_off;
+	hwif->ide_dma_host_on  = &stb04xxx_ide_dma_host_on;
+
+	hwif->ide_dma_check = &stb04xxx_ide_dma_check;
+	hwif->ide_dma_off_quietly = &stb04xxx_ide_dma_off_quietly;
+	hwif->ide_dma_on          = &stb04xxx_ide_dma_on;
+
+	hwif->dma_setup    = &stb04xxx_dma_setup;
+	hwif->dma_exec_cmd = &stb04xxx_dma_exec_cmd;
+	hwif->dma_start    = &stb04xxx_dma_start;
+	hwif->ide_dma_end  = &stb04xxx_ide_dma_end;

-    dma_ch.mode	=DMA_MODE_MM_DEVATSRC;	  /* xfer from peripheral to mem */
-    dma_ch.pwidth = PW_64;		/* Line mode on stbs */
-    dma_ch.pwc = 1;                     /* set the max wait cycles  */
-#endif
+	hwif->ide_dma_test_irq = &stb04xxx_ide_dma_test_irq;

-    dma_ch.td	= DMA_TD;
-    dma_ch.buffer_enable = 0;
-    dma_ch.tce_enable = 0;
-    dma_ch.etd_output = 0;
-    dma_ch.pce = 0;
-    dma_ch.pl = EXTERNAL_PERIPHERAL;    /* no op */
-    dma_ch.dai = 1;
-    dma_ch.sai = 0;
-    dma_ch.psc = 0;                      /* set the max setup cycles */
-    dma_ch.phc = 2;                      /* set the max hold cycles  */
-    dma_ch.cp = PRIORITY_LOW;
-    dma_ch.int_enable = 0;
-    dma_ch.ch_enable = 0;		/* No chaining */
-    dma_ch.tcd_disable = 1;		/* No chaining */
-
-    if (hw_init_dma_channel(IDE_DMACH, &dma_ch) != DMA_STATUS_GOOD)
-        return -EBUSY;
-
-    /* init CIC select2 reg to connect external DMA port 3 to internal
-     * DMA channel 2
-     */
-    map_dma_port(IDE_DMACH,EXT_DMA_3,DMA_CHAN_2);
-
-    /* Enable the interface.
-     */
-    idp->si_control = 0x80000000;
-    idp->si_c0s0 = 0xdc800000;	/* Clear all status */
-    idp->si_intenable = 0x80000000;
-
-    /* Per the STB04 data sheet:
-     *  1)  tTO = ((8*RDYT) + 1) * SYS_CLK
-     * and:
-     *  2)  tTO >= 1250 + (2 * SYS_CLK) - t2
-     * Solving the first equation for RDYT:
-     *             (tTO/SYS_CLK) - 1
-     *  3)  RDYT = -----------------
-     *                     8
-     * Substituting equation 2) for tTO in equation 3:
-     *             ((1250 + (2 * SYS_CLK) - t2)/SYS_CLK) - 1
-     *  3)  RDYT = -----------------------------------------
-     *                                8
-     * It's just the timeout so having it too long isn't too
-     * significant, so we'll just assume t2 is zero.  All this math
-     * is handled by the compiler and RDYT ends up being 11 assuming
-     * that SYS_CLOCK_NS is 15.
-     */
-    idp->si_c0timo = (EZ(EZ(1250 + 2 * SYS_CLOCK_NS, SYS_CLOCK_NS) - 1, 8)) << 23;	/* Chan 0 timeout */
-
-    /* Stuff some slow default PIO timing.
-     */
-    idp->si_c0rt = MK_TIMING(6, 19, 15, 2);
-    idp->si_c0fpt = MK_TIMING(6, 19, 15, 2);
-
-    /* We should probably have UIC functions to set external
-     * interrupt level/edge.
-     */
-    uicdcr = mfdcr(DCRN_UIC_PR(UIC0));
-    uicdcr &= ~(0x80000000 >> IDE0_IRQ);
-    mtdcr(DCRN_UIC_PR(UIC0), uicdcr);
-    mtdcr(DCRN_UIC_TR(UIC0), 0x80000000 >> IDE0_IRQ);
-
-    /* Grab a page for the PRD Table.
-     */
-    prd_table = (prd_entry_t *) consistent_alloc(GFP_KERNEL,
-						 NUM_PRD *
-						 sizeof
-						 (prd_entry_t),
-						 &prd_phys);
-
-
-    if(!ocp_ide_spinup(hwif->index))
-	    return 0;
-
-    return 1;
+	hwif->ide_dma_lostirq = &stb04xxx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &stb04xxx_ide_dma_timeout;
  }

-
-static int __devinit ocp_ide_probe(struct ocp_device *pdev)
+static int __init
+stb04xxx_ide_probe (struct ocp_device * const ocp)
  {
-	int i;
-	unsigned int index;
-	hw_regs_t * hw;
-	unsigned char *ip;
-
-	printk("IBM STB04xxx IDE driver version %s\n", IDE_VER);
-
-	hw = kmalloc(sizeof(*hw), GFP_KERNEL);
-	if (!hw)
-		return 0;
-	memset(hw, 0, sizeof(*hw));
-
-	if (!request_region(pdev->paddr, IDE0_SIZE, "IDE")) {
-		printk(KERN_WARNING "ocp_ide: failed request_region\n");
-		return -1;
-	}
-
-	if ((idp = (ide_t *) ioremap(pdev->paddr,
-				     IDE0_SIZE)) == NULL) {
-		printk(KERN_WARNING "ocp_ide: failed ioremap\n");
-		return -1;
+	int                     err;
+	unsigned int            uicdcr;
+	volatile ide_t __iomem *ide_regs;
+	unsigned long           flags;
+	ide_hwif_t             * const hwif = &ide_hwifs[0];
+	unsigned char          * ip;
+	int                     i;
+
+	printk ("IBM STB04xxx OCP IDE driver version %s\n", OCPVR);
+
+	if (!request_region (ocp->def->paddr, sizeof (ide_t), "ide"))
+		return -ENOMEM;
+
+	ocp_force_power_on (ocp);
+
+	ide_regs = ioremap (ocp->def->paddr, sizeof (ide_t));
+	if (unlikely (!ide_regs)) {
+		err = -ENOMEM;
+		goto error1;
  	}

-	pdev->dev.driver_data = (void *) idp;

-	pdev->ocpdev  = (void *) hw;
-	index = pdev->num;
-	ip = (unsigned char *) (&(idp->si_c0d));	/* Chan 0 data */
+	/* Enable the interface. */
+	ide_regs->si_control = 0x80000000ul;
+	ide_regs->si_c0s0 = 0xdc800000ul;       /* Clear all status */
+	ide_regs->si_intenable = 0x80000000ul;
+	/* Per the STB04 data sheet:
+	 *  1)  tTO = ((8*RDYT) + 1) * SYS_CLK
+	 * and:
+	 *  2)  tTO >= 1250 + (2 * SYS_CLK) - t2
+	 * Solving the first equation for RDYT:
+	 *             (tTO/SYS_CLK) - 1
+	 *  3)  RDYT = -----------------
+	 *                     8
+	 * Substituting equation 2) for tTO in equation 3:
+	 *             ((1250 + (2 * SYS_CLK) - t2)/SYS_CLK) - 1
+	 *  3)  RDYT = -----------------------------------------
+	 *                                8
+	 * It's just the timeout so having it too long isn't too
+	 * significant, so we'll just assume t2 is zero.  All this math
+	 * is handled by the compiler and RDYT ends up being 11 assuming
+	 * that SYS_CLOCK_NS is 15.
+	 */
+	ide_regs->si_c0timo = (EZ(EZ(1250 + 2 * SYS_CLOCK_NS, SYS_CLOCK_NS) - 1, 8)) << 23;	/* Chan 0 timeout */

-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = (unsigned long) (ip++);
+	/* stuff some slow default PIO timing */
+	ide_regs->si_c0rt = MK_TIMING(6, 19, 15, 2);
+	ide_regs->si_c0fpt = MK_TIMING(6, 19, 15, 2);
+
+	/* enable 32bit access on both devices */
+	ide_regs->si_c0c |= 0x00008040ul;
+
+	/* we should probably have UIC functions to set external
+	   interrupt level/edge */
+	local_irq_save (flags);
+	uicdcr = mfdcr (DCRN_UIC_PR (UIC0));
+	uicdcr &= ~(0x80000000ul >> IDE0_IRQ);
+	mtdcr (DCRN_UIC_PR(UIC0), uicdcr);
+	mtdcr (DCRN_UIC_TR(UIC0),
+	       mfdcr (DCRN_UIC_TR (UIC0)) | (0x80000000ul >> IDE0_IRQ));
+	local_irq_restore (flags);
+
+
+	/* initialize */
+	hwif->gendev.parent = &ocp->dev;
+	ocp_set_drvdata (ocp, hwif);
+
+	/* setup MMIO ops */
+	default_hwif_mmiops (hwif);
+
+	/* tell common code _not_ to mess with resources */
+	hwif->mmio = 2;
+	ide_set_hwifdata (hwif, (void *) ide_regs);
+
+	ip = (unsigned char *) (&(ide_regs->si_c0d));    /* Chan 0 data */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hwif->hw.io_ports[i] = (int) (ip++);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (int) (&(ide_regs->si_c0adc));
+	memcpy (hwif->io_ports, hwif->hw.io_ports, sizeof (hwif->hw.io_ports));
+	hwif->chipset = ide_generic;
+	hwif->irq     = ocp->def->irq;
+	hwif->noprobe = 0;
+	hwif->hold    = 1;
+	/* Figure out if an 80 conductor cable is connected */
+	hwif->udma_four = (ide_regs->si_c0s1 & 0x20000000ul) != 0;
+	hwif->tuneproc  = &stb04xxx_ide_tune_drive;
+	hwif->speedproc = &stb04xxx_ide_tune_chipset;
+	hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1;
+	hwif->drives[0].unmask   = hwif->drives[1].unmask   = 1;
+	pio_mode[0] = pio_mode[1] = -1;
+	stb04xxx_ide_setup_dma (hwif);
+	
+	/* grab a page for the PRD table. this is save with respect to not
+	   crossing a 64k border because returned memory is page aligned
+	   and NUM_PRD*sizeof(prd_entry_t) end up being 2048 bytes, i.e.
+	   less than one page. */
+	hwif->dmatable_cpu = dma_alloc_coherent (NULL,
+						 NUM_PRD * sizeof (prd_entry_t),
+						 &hwif->dmatable_dma,
+						 GFP_KERNEL | GFP_DMA);
+	if (unlikely (!hwif->dmatable_cpu)) {
+		err = -ENOMEM;
+		goto error2;
  	}
+	hwif->sg_max_nents = NUM_PRD;

-	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long) (&(idp->si_c0adc));
-	hw->irq = pdev->irq;
-
-	/* use DMA channel 2 for IDE DMA operations */
-	hw->dma = IDE_DMACH;
+	probe_hwif_init (hwif);

-	ide_hwifs[index].tuneproc = &ocp_ide_tune_drive;
-	ide_hwifs[index].drives[0].autotune = 1;
-	ide_hwifs[index].autodma = 1;
-	ide_hwifs[index].ide_dma_off = &ocp_ide_dma_off;
-	ide_hwifs[index].ide_dma_off_quietly = &ocp_ide_dma_off_quietly;
-	ide_hwifs[index].ide_dma_host_off = &ocp_ide_dma_off_quietly;
-	ide_hwifs[index].ide_dma_on = &ocp_ide_dma_on;
-	ide_hwifs[index].ide_dma_host_on = &ocp_ide_dma_on;
-	ide_hwifs[index].ide_dma_check = &ocp_ide_dma_check;
-	ide_hwifs[index].ide_dma_read = &ocp_ide_dma_read;
-	ide_hwifs[index].ide_dma_write = &ocp_ide_dma_write;
-	ide_hwifs[index].ide_dma_begin = &ocp_ide_dma_begin;
-	ide_hwifs[index].ide_dma_end = &ocp_ide_dma_end;
-	ide_hwifs[index].ide_dma_test_irq = &ocp_ide_dma_test_irq;
-	ide_hwifs[index].ide_dma_verbose = &ocp_ide_dma_verbose;
-	ide_hwifs[index].speedproc = &ocp_ide_set_drive;
-	ide_hwifs[index].noprobe = 0;
+	create_proc_ide_interfaces ();

-	memcpy(ide_hwifs[index].io_ports, hw->io_ports, sizeof (hw->io_ports));
-	ide_hwifs[index].irq = pdev->irq;
+	return 0;

-	ocp_force_power_on(pdev);
-	return 1;
+error2:
+	ide_set_hwifdata (hwif, NULL);
+	hwif->noprobe = 1;
+	hwif->chipset = ide_unknown;
+	ocp_set_drvdata (ocp, NULL);
+	iounmap (ide_regs);
+error1:
+	ocp_force_power_off (ocp);
+	release_region (ocp->def->paddr, sizeof (ide_t));
+	return err;
  }

-static void __devexit ocp_ide_remove_one (struct ocp_device *pdev)
+static void
+stb04xxx_ide_remove (struct ocp_device * const ocp)
  {
-	ocp_force_power_off(pdev);
+	ide_hwif_t             * const hwif = ocp_get_drvdata (ocp);
+	volatile ide_t __iomem * const ide_regs = ide_get_hwifdata (hwif);
+
+	/* ide_unregister () can't ever handle these correctly for us */
+	dma_free_coherent (NULL, NUM_PRD * sizeof (prd_entry_t),
+			   hwif->dmatable_cpu, hwif->dmatable_dma);
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+
+	ide_unregister (hwif->index);
+	iounmap (ide_regs);
+	release_region (ocp->def->paddr, sizeof (ide_t));
+	
+	ocp_force_power_off (ocp);
  }

-static struct ocp_device_id ocp_ide_id_tbl[] __devinitdata = {
-	{OCP_VENDOR_IBM,OCP_FUNC_IDE},
-	{0,}
+
+static struct ocp_device_id stb04xxx_ide_ids[] __devinitdata =
+{
+        { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IDE},
+        { .vendor = OCP_VENDOR_INVALID }
  };

-MODULE_DEVICE_TABLE(ocp,ocp_ide_id_tbl );
+MODULE_DEVICE_TABLE (ocp, stb04xxx_ide_ids);

-static struct ocp_driver ocp_ide_driver = {
-	.name		= "ocp_ide",
-	.id_table	= ocp_ide_id_tbl,
-	.probe		= ocp_ide_probe,
-	.remove		= __devexit_p(ocp_ide_remove_one),
+static struct ocp_driver stb04xxx_ide_driver = {
+	.name     = "ide",
+	.id_table = stb04xxx_ide_ids,
+	.probe    = stb04xxx_ide_probe,
+	.remove   = __devexit_p (stb04xxx_ide_remove),
  #if defined(CONFIG_PM)
-	.suspend	= ocp_generic_suspend,
-	.resume		= ocp_generic_resume,
-#endif /* CONFIG_PM */
+	.suspend  = NULL,
+	.resume   = NULL,
+#endif
  };


-void __init std_ide_cntl_scan(void)
-{
-	struct ocp_device *dev;
-	int i, max;
-	printk("OCP ide ver:%s\n", IDE_VER);
-
-	ocp_module_init(&ocp_ide_driver);
-	max = ocp_get_num(OCP_FUNC_IDE);
-	for(i = 0; i < max; i++){
-		dev = ocp_get_dev(OCP_FUNC_IDE,i);
-		if(!dev)	
-		  setup_ocp_ide(dev);
-	}
-}
-#if 0
-#if defined (CONFIG_MODULE)
+
  static int __init
-ocp_ide_init(void)
+stb04xxx_ide_init (void)
  {
-	printk("OCP ide ver:%s\n", IDE_VER);
-	return ocp_module_init(&ocp_ide_driver);
+	return ocp_register_driver (&stb04xxx_ide_driver);
  }

-void __exit
-ocp_ide_fini(void)
+static void __exit
+stb04xxx_ide_exit (void)
  {
-	ocp_unregister_driver(&ocp_ide_driver);
+	ocp_unregister_driver (&stb04xxx_ide_driver);
  }

-module_init(ocp_ide_init);
-module_exit(ocp_ide_fini);
-#endif
-#endif
+/* needs to be called after ide has been initialized */
+late_initcall (stb04xxx_ide_init);
+module_exit (stb04xxx_ide_exit);

+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("André Draszik <andid at gmx.net>");
+MODULE_DESCRIPTION ("driver for IBM OCP IDE on STB04xxx");



More information about the Linuxppc-embedded mailing list