[PATCH 4/4] ppc32/ide: Add support for MPC52xx on-chip ATA controller
Sylvain Munaut
tnt at 246tNt.com
Sun Mar 26 22:38:40 EST 2006
ppc32/ide: Add support for MPC52xx on-chip ATA controller
This patch adds initial support for Freescale MPC52xx on-chip ATA
controller. It's currently PIO-mode only and all the erratas are
not handled since some of them requires hw tricks ...
Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
---
commit f3180ffadd5dddcfa9d11da4f7637e3e907e6aaa
tree d9bf294057a0dcdda25ba6c6ea3fcc9748d87e93
parent 67015426ff51ba857b7678a993f4ffd6def1941e
author Sylvain Munaut <tnt at 246tNt.com> 1139147442 +0100
committer Sylvain Munaut <tnt at 246tNt.com> 1143312600 +0100
drivers/ide/Kconfig | 4
drivers/ide/Makefile | 1
drivers/ide/ppc/mpc52xx_ide.c | 420 +++++++++++++++++++++++++++++++++++++
drivers/ide/ppc/mpc52xx_ide.h | 129 +++++++++++
drivers/ide/ppc/mpc52xx_ide_iops.c | 151 +++++++++++++
include/linux/ide.h | 2
6 files changed, 706 insertions(+), 1 deletion(-)
---
f3180ffadd5dddcfa9d11da4f7637e3e907e6aaa
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index d633081..3a10fec 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -962,6 +962,10 @@ config IDE_EXT_DIRECT
endchoice
+config BLK_DEV_MPC52xx_IDE
+ tristate "MPC52xx Builtin IDE support"
+ depends on PPC_MPC52xx && IDE=y
+
# no isa -> no vlb
config IDE_CHIPSETS
bool "Other IDE chipset support"
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae7..fcca1f3 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -34,6 +34,7 @@ ide-core-$(CONFIG_BLK_DEV_MAC_IDE) += le
ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o
# built-in only drivers from ppc/
+ide-core-$(CONFIG_BLK_DEV_MPC52xx_IDE) += ppc/mpc52xx_ide.o ppc/mpc52xx_ide_iops.o
ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o
ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o
diff --git a/drivers/ide/ppc/mpc52xx_ide.c b/drivers/ide/ppc/mpc52xx_ide.c
new file mode 100644
index 0000000..5970f7b
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide.c
@@ -0,0 +1,420 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide.h
+ *
+ * Driver for the Freescale MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt at 246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/ppcboot.h>
+
+#include "mpc52xx_ide.h"
+
+
+
+/* Private structures used by the driver */
+struct mpc52xx_ata_timings {
+ u32 pio1;
+ u32 pio2;
+ u32 mdma1;
+ u32 mdma2;
+ u32 udma1;
+ u32 udma2;
+ u32 udma3;
+ u32 udma4;
+ u32 udma5;
+ int using_udma;
+};
+
+struct mpc52xx_ide_priv {
+ unsigned int ipb_period; /* in ps */
+ struct mpc52xx_ata __iomem *ata_regs;
+ struct mpc52xx_ata_timings timings[2];
+};
+
+/* ATAPI-4 PIO specs (arranged for the 5200, cfr User Manual) */
+/* numbers in ns, extrapolation done by code */
+static int ataspec_t0[5] = {600, 383, 240, 180, 120};
+static int ataspec_t1[5] = { 70, 50, 30, 30, 25};
+static int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
+static int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
+static int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
+static int ataspec_t4[5] = { 30, 20, 15, 10, 10};
+static int ataspec_ta[5] = { 35, 35, 35, 35, 35};
+
+/* Helpers to compute timing parameters */
+#define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c)
+
+
+/* ======================================================================== */
+/* IDE Driver & Aux functions */
+/* ======================================================================== */
+
+static void
+mpc52xx_ide_apply_timing(
+ struct mpc52xx_ata __iomem *regs, struct mpc52xx_ata_timings *timing)
+{
+ out_be32(®s->pio1, timing->pio1);
+ out_be32(®s->pio2, timing->pio2);
+ out_be32(®s->mdma1, timing->mdma1);
+ out_be32(®s->mdma2, timing->mdma2);
+ out_be32(®s->udma1, timing->udma1);
+ out_be32(®s->udma2, timing->udma2);
+ out_be32(®s->udma3, timing->udma3);
+ out_be32(®s->udma4, timing->udma4);
+ out_be32(®s->udma5, timing->udma5);
+}
+
+static void
+mpc52xx_ide_compute_pio_timing(
+ struct mpc52xx_ata_timings *timing, unsigned int ipb_period, u8 pio)
+{
+ u32 t0, t2_8, t2_16, t2i, t4, t1, ta;
+
+ /* We add 1 as a 'margin' */
+ t0 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t0[pio]);
+ t2_8 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_8[pio]);
+ t2_16 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_16[pio]);
+ t2i = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2i[pio]);
+ t4 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t4[pio]);
+ t1 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t1[pio]);
+ ta = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_ta[pio]);
+
+ timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
+ timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
+}
+
+
+static void
+mpc52xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ int w = drive->select.b.unit & 0x01;
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+
+ printk("%s: Setting PIO %d timings\n", drive->name, pio);
+
+ mpc52xx_ide_compute_pio_timing(&priv->timings[w], priv->ipb_period, pio);
+
+ if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+ mpc52xx_ide_apply_timing(regs, &priv->timings[w]);
+
+ /* Should we do it here or only in speedproc ? */
+ ide_config_drive_speed(drive, pio + XFER_PIO_0);
+}
+
+static int
+mpc52xx_ide_speedproc(ide_drive_t *drive, u8 speed)
+{
+ /* Configure PIO Mode */
+ if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+ mpc52xx_ide_tuneproc(drive, speed - XFER_PIO_0);
+ return 0;
+ }
+
+ /* DMA settings currently unsupported */
+ printk(KERN_ERR
+ "mpc52xx-ide: speedproc called with unsupported mode %d\n",
+ speed);
+
+ return 1;
+}
+
+static void
+mpc52xx_ide_selectproc(ide_drive_t *drive)
+{
+ /* Change the PIO timings to the ones of the
+ currently selected drive */
+ struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+ mpc52xx_ide_apply_timing(regs,
+ &priv->timings[drive->select.b.unit & 0x01]);
+}
+
+
+static int
+mpc52xx_ide_setup(
+ struct mpc52xx_ata __iomem *regs, struct mpc52xx_ide_priv *priv)
+{
+ /* Vars */
+ extern bd_t __res;
+ bd_t *bd = (bd_t *)&__res;
+ int tslot;
+
+ /* All sample code do this */
+ out_be32(®s->share_cnt, 0);
+
+ /* Configure & Reset host */
+ out_be32(®s->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY |
+ MPC52xx_ATA_HOSTCONF_SMR |
+ MPC52xx_ATA_HOSTCONF_FR);
+ udelay(10);
+ out_be32(®s->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY);
+
+ /* Get IPB bus period */
+ priv->ipb_period = 1000000000 / (bd->bi_ipbfreq/1000);
+
+ /* Try to set the time slot to around 1us = 1000000 ps */
+ tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000);
+ out_be32(®s->share_cnt, tslot << 16);
+
+ /* Init imings to PIO0 (safest) */
+ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
+
+ mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, 0);
+ mpc52xx_ide_compute_pio_timing(&priv->timings[1], priv->ipb_period, 0);
+
+ mpc52xx_ide_apply_timing(regs, &priv->timings[0]);
+
+ return 0;
+}
+
+static void
+mpc52xx_ide_setup_hwif_ports(hw_regs_t *hw, struct mpc52xx_ata __iomem *regs)
+{
+ /* It's MMIO and we handle all the io ops ourself, */
+ /* so theses address are really virtual addresses */
+ hw->io_ports[IDE_DATA_OFFSET] = (unsigned long) ®s->tf_data;
+ hw->io_ports[IDE_ERROR_OFFSET] = (unsigned long) ®s->tf_features;
+ hw->io_ports[IDE_NSECTOR_OFFSET] = (unsigned long) ®s->tf_sec_count;
+ hw->io_ports[IDE_SECTOR_OFFSET] = (unsigned long) ®s->tf_sec_num;
+ hw->io_ports[IDE_LCYL_OFFSET] = (unsigned long) ®s->tf_cyl_low;
+ hw->io_ports[IDE_HCYL_OFFSET] = (unsigned long) ®s->tf_cyl_high;
+ hw->io_ports[IDE_SELECT_OFFSET] = (unsigned long) ®s->tf_dev_head;
+ hw->io_ports[IDE_STATUS_OFFSET] = (unsigned long) ®s->tf_command;
+ hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long) ®s->tf_control;
+}
+
+
+/* ======================================================================== */
+/* Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ide_probe(struct platform_device *dev)
+{
+ /* Vars */
+ ide_hwif_t *hwif;
+ struct mpc52xx_ide_priv *priv;
+ struct mpc52xx_gpio __iomem *gpio_regs = NULL;
+ struct mpc52xx_ata __iomem *ata_regs = NULL;
+ int ata_irq;
+ struct resource *res_mem;
+ u32 reg;
+ int i, rv;
+
+ /* Get an empty slot */
+ for (i=0; i<MAX_HWIFS && ide_hwifs[i].io_ports[IDE_DATA_OFFSET]; i++);
+ if (i >= MAX_HWIFS) {
+ printk(KERN_ERR "mpc52xx-ide: No free hwif slot !\n");
+ return -ENOMEM;
+ }
+
+ hwif = &ide_hwifs[i];
+
+ /* Check port muxing for compatibility */
+ gpio_regs = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+ if (!gpio_regs) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Unable to ioremap MPC52xx_GPIO zone\n");
+ return -ENOMEM;
+ }
+
+ reg = in_be32(&gpio_regs->port_config);
+ iounmap(gpio_regs);
+
+ if (!(reg & 0x03000000ul)) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Invalid port config, no ATA CS !\n");
+ return -ENODEV;
+ }
+
+ /* Get the resources of this device */
+ ata_irq = platform_get_irq(dev, 0);
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+ if (ata_irq<0 || res_mem==NULL) {
+ printk(KERN_ERR "mpc52xx-ide: Invalid resource set !\n");
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(res_mem->start, sizeof(struct mpc52xx_ata),
+ "mpc52xx-ide")) {
+ printk(KERN_ERR "mpc52xx-ide: Memory zone unavailable !\n");
+ return -EBUSY;
+ }
+
+ ata_regs = ioremap(res_mem->start, sizeof(struct mpc52xx_ata));
+ if (!ata_regs) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Unable to ioremap ATA registers\n");
+ rv = -ENOMEM;
+ goto error;
+ }
+
+ /* Setup private structure */
+ priv = kmalloc(sizeof(struct mpc52xx_ide_priv), GFP_ATOMIC);
+ if (!priv) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Can't allocate private structure !\n");
+ rv = -ENOMEM;
+ goto error;
+ }
+
+ priv->ata_regs = ata_regs;
+
+ /* Setup the ATA controller */
+ rv = mpc52xx_ide_setup(ata_regs, priv);
+ if (rv) {
+ printk(KERN_ERR "mpc52xx-ide: Controller setup failed !\n");
+ goto error;
+ }
+
+ /* Setup the hwif structure */
+ hwif->irq = ata_irq;
+ hwif->mmio = 2;
+ mpc52xx_ide_setup_hwif_iops(hwif);
+ mpc52xx_ide_setup_hwif_ports(&hwif->hw, ata_regs);
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+
+ hwif->atapi_dma = 0;
+ hwif->ultra_mask = 0x00;
+ hwif->mwdma_mask = 0x00;
+ hwif->swdma_mask = 0x00;
+ hwif->chipset = ide_mpc52xx;
+ hwif->tuneproc = mpc52xx_ide_tuneproc;
+ hwif->speedproc = mpc52xx_ide_speedproc;
+ hwif->selectproc = mpc52xx_ide_selectproc;
+ hwif->noprobe = 0;
+ hwif->hold = 1;
+ hwif->autodma = 0;
+ hwif->udma_four = 0;
+ hwif->no_lba48 = 1; /* FIXME ? Did some one test that ? */
+ hwif->no_lba48_dma = 1;
+
+ hwif->drives[0].unmask = 1;
+ hwif->drives[0].autotune = 0; /* default */
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[0].no_io_32bit = 1; /* Anyone tried ? */
+
+ hwif->drives[1].unmask = 1;
+ hwif->drives[1].autotune = 0; /* default */
+ hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[1].no_io_32bit = 1; /* Anyone tried ? */
+
+ hwif->hwif_data = priv;
+ platform_set_drvdata(dev, hwif);
+
+ /* Lauch probe */
+ probe_hwif_init(hwif);
+
+ /* We're good ! */
+ printk(KERN_INFO
+ "mpc52xx-ide: Setup successful for %s (mem=%08lx-%08lx irq=%d)\n",
+ hwif->name, res_mem->start, res_mem->end, ata_irq);
+
+ return 0;
+
+
+ /* Error path */
+error:
+ if (ata_regs)
+ iounmap(ata_regs);
+
+ release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));
+
+ return rv;
+}
+
+static int
+mpc52xx_ide_remove(struct platform_device *dev)
+{
+ ide_hwif_t *hwif = platform_get_drvdata(dev);
+ struct mpc52xx_ide_priv *priv = hwif->hwif_data;
+ struct resource *res_mem;
+
+ ide_unregister(hwif - ide_hwifs);
+
+ iounmap(priv->ata_regs);
+
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_ide_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+static int
+mpc52xx_ide_resume(struct platform_device *dev)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+#endif
+
+static struct platform_driver mpc52xx_ide_platform_driver = {
+ .probe = mpc52xx_ide_probe,
+ .remove = mpc52xx_ide_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_ide_suspend,
+ .resume = mpc52xx_ide_resume,
+#endif
+ .driver = {
+ .name = "mpc52xx-ata",
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_ide_init(void)
+{
+ printk(KERN_INFO "ide: MPC52xx IDE/ATA driver\n");
+ return platform_driver_register(&mpc52xx_ide_platform_driver);
+}
+
+static void __exit
+mpc52xx_ide_exit(void)
+{
+ platform_driver_unregister(&mpc52xx_ide_platform_driver);
+}
+
+
+module_init(mpc52xx_ide_init);
+module_exit(mpc52xx_ide_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt at 246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/ppc/mpc52xx_ide.h b/drivers/ide/ppc/mpc52xx_ide.h
new file mode 100644
index 0000000..e2490a8
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide.h
@@ -0,0 +1,129 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide.h
+ *
+ * Definitions for the Freescale MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt at 246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __MPC52xx_IDE_H__
+#define __MPC52xx_IDE_H__
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+
+
+/* Bit definitions inside the registers */
+
+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */
+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */
+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */
+
+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */
+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */
+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */
+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
+
+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+
+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */
+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */
+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */
+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+
+
+/* Structure of the hardware registers */
+struct mpc52xx_ata {
+
+ /* Host interface registers */
+ u32 config; /* ATA + 0x00 Host configuration */
+ u32 host_status; /* ATA + 0x04 Host controller status */
+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */
+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */
+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */
+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */
+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */
+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */
+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */
+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */
+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */
+ u32 share_cnt; /* ATA + 0x2c ATA share counter */
+ u32 reserved0[3];
+
+ /* FIFO registers */
+ u32 fifo_data; /* ATA + 0x3c */
+ u8 fifo_status_frame; /* ATA + 0x40 */
+ u8 fifo_status; /* ATA + 0x41 */
+ u16 reserved7[1];
+ u8 fifo_control; /* ATA + 0x44 */
+ u8 reserved8[5];
+ u16 fifo_alarm; /* ATA + 0x4a */
+ u16 reserved9;
+ u16 fifo_rdp; /* ATA + 0x4e */
+ u16 reserved10;
+ u16 fifo_wrp; /* ATA + 0x52 */
+ u16 reserved11;
+ u16 fifo_lfrdp; /* ATA + 0x56 */
+ u16 reserved12;
+ u16 fifo_lfwrp; /* ATA + 0x5a */
+
+ /* Drive TaskFile registers */
+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */
+ u8 reserved13[3];
+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */
+ u16 reserved14;
+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */
+ u8 reserved15[3];
+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */
+ u8 reserved16[3];
+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */
+ u8 reserved17[3];
+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */
+ u8 reserved18[3];
+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */
+ u8 reserved19[3];
+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */
+ u8 reserved20[3];
+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */
+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */
+ u8 reserved21[2];
+};
+
+
+/* Function definition */
+
+static inline void
+mpc52xx_ide_wait_tip_bit_clear(struct mpc52xx_ata __iomem *regs)
+{
+ int timeout = 1000;
+
+ while (in_be32(®s->host_status) & MPC52xx_ATA_HOSTSTAT_TIP)
+ if (timeout-- == 0) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Timeout waiting for TIP clear\n");
+ break;
+ }
+ udelay(10); /* FIXME: Necessary ??? */
+}
+
+extern void mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif);
+
+
+#endif /* __MPC52xx_IDE_H__ */
+
diff --git a/drivers/ide/ppc/mpc52xx_ide_iops.c b/drivers/ide/ppc/mpc52xx_ide_iops.c
new file mode 100644
index 0000000..6ced54e
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide_iops.c
@@ -0,0 +1,151 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide_iops.c
+ *
+ * Utility functions for MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt at 246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "mpc52xx_ide.h"
+
+
+
+static u8
+mpc52xx_ide_inb(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u8) readb((void __iomem *) port);
+}
+
+static u16
+mpc52xx_ide_inw(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u16) readw((void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_insw(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_insw((void __iomem *) port, addr, count);
+}
+
+static u32
+mpc52xx_ide_inl(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u32) readl((void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_insl(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_insl((void __iomem *) port, addr, count);
+}
+
+static void
+mpc52xx_ide_outb(u8 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writeb(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writeb(value, (void __iomem *) port);
+}
+
+
+static void
+mpc52xx_ide_outw(u16 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writew(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outsw(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_outsw((void __iomem *) port, addr, count);
+}
+
+static void
+mpc52xx_ide_outl(u32 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writel(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outsl(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_outsl((void __iomem *) port, addr, count);
+}
+
+
+void
+mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif)
+{
+ hwif->OUTB = mpc52xx_ide_outb;
+ hwif->OUTBSYNC = mpc52xx_ide_outbsync;
+ hwif->OUTW = mpc52xx_ide_outw;
+ hwif->OUTL = mpc52xx_ide_outl;
+ hwif->OUTSW = mpc52xx_ide_outsw;
+ hwif->OUTSL = mpc52xx_ide_outsl;
+ hwif->INB = mpc52xx_ide_inb;
+ hwif->INW = mpc52xx_ide_inw;
+ hwif->INL = mpc52xx_ide_inl;
+ hwif->INSW = mpc52xx_ide_insw;
+ hwif->INSL = mpc52xx_ide_insl;
+}
+
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 8d2db41..793c70a 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -203,7 +203,7 @@ typedef enum { ide_unknown, ide_generic,
ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
ide_pmac, ide_etrax100, ide_acorn,
- ide_au1xxx, ide_forced
+ ide_au1xxx, ide_mpc52xx, ide_forced
} hwif_chipset_t;
/*
More information about the Linuxppc-embedded
mailing list