[PATCH] Add MPC52xx PIO/ATA support for arch/powerpc
Nicolas DET
nd at bplan-gmbh.de
Sun Nov 5 22:57:06 EST 2006
This patch adds ATA/PIO support for Freescale MPC5200 plaforms.
It's based on a previous patch:
http://patchwork.ozlabs.org/linuxppc/patch?id=4364
But, it now uses of_platform and a of_device_id to match the appropriate devices.
Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
---
diff -uprN a/drivers/ide/ppc/mpc52xx_ide.c b/drivers/ide/ppc/mpc52xx_ide.c
--- a/drivers/ide/ppc/mpc52xx_ide.c 1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/ide/ppc/mpc52xx_ide.c 2006-11-05 10:40:49.000000000 +0100
@@ -0,0 +1,428 @@
+/*
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc52xx.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];
+ resource_size_t resmem_start;
+ size_t resmem_size;
+};
+
+/* 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;
+ unsigned long ipb_freq = 133 *1000 *1000;
+ 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 / (ipb_freq /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;
+}
+
+
+/* ======================================================================== */
+/* OF Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ide_probe(struct of_device *op, const struct of_device_id *match)
+{
+ /* Vars */
+ ide_hwif_t *hwif;
+ int ret;
+ struct mpc52xx_ide_priv *priv;
+ struct mpc52xx_ata __iomem *ata_regs = NULL;
+ int ata_irq;
+ struct resource res_mem;
+ size_t res_mem_size;
+ 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];
+
+ /* Get the resources of this device */
+ ata_irq = irq_of_parse_and_map(op->node, 0);
+ if (ata_irq == NO_IRQ) {
+ printk(KERN_ERR "mpc52xx-ide: Invalid IRQ!\n");
+ return -EINVAL;
+ }
+ //res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if ((ret = of_address_to_resource(op->node, 0, &res_mem)) != 0)
+ {
+ printk(KERN_ERR "mpc52xx-ide: Can not find IO mem!\n");
+ return ret;
+ }
+
+ res_mem_size = res_mem.end - res_mem.start + 1;
+
+ if (!request_mem_region(res_mem.start, res_mem_size,
+ "mpc52xx-ide")) {
+ printk(KERN_ERR "mpc52xx-ide: Memory zone unavailable !\n");
+ return -EBUSY;
+ }
+
+ ata_regs = ioremap(res_mem.start, res_mem_size);
+ 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->resmem_size = res_mem_size;
+ priv->resmem_start = res_mem.start;
+ 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_forced;
+ 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;
+ dev_set_drvdata(&op->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, (unsigned long) res_mem.start, (unsigned long) res_mem.end, ata_irq);
+
+ return 0;
+
+
+ /* Error path */
+error:
+ if (ata_regs)
+ iounmap(ata_regs);
+
+ release_mem_region(res_mem.start, res_mem_size);
+
+ return rv;
+}
+
+static int
+mpc52xx_ide_remove(struct of_device *op)
+{
+ ide_hwif_t *hwif = dev_get_drvdata(&op->dev);
+ struct mpc52xx_ide_priv *priv = hwif->hwif_data;
+
+ ide_unregister(hwif - ide_hwifs);
+
+ iounmap(priv->ata_regs);
+
+ release_mem_region(priv->resmem_start, priv->resmem_size);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_ide_suspend(struct of_device *op, pm_message_t state)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+static int
+mpc52xx_ide_resume(struct of_device *op)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+#endif
+
+
+static struct of_device_id mpc52xx_ide_of_match[] = {
+ {
+ .name = "ata",
+ .compatible = "mpc5200-ata",
+ },
+ {
+ .name = "ata",
+ .compatible = "mpc52xx-ata",
+ },
+ {},
+};
+
+
+static struct of_platform_driver mpc52xx_ide_of_platform_driver = {
+ .name = "mpc52xx-ata",
+ .match_table = mpc52xx_ide_of_match,
+ .probe = mpc52xx_ide_probe,
+ .remove = mpc52xx_ide_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_ide_suspend,
+ .resume = mpc52xx_ide_resume,
+#endif
+ .driver = {
+ .name = "mpc52xx-ata",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_ide_init(void)
+{
+ printk(KERN_INFO "ide: MPC52xx IDE/ATA driver\n");
+ return of_register_driver(&mpc52xx_ide_of_platform_driver);
+}
+
+static void __exit
+mpc52xx_ide_exit(void)
+{
+ of_unregister_driver(&mpc52xx_ide_of_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 -uprN a/drivers/ide/ppc/mpc52xx_ide.h b/drivers/ide/ppc/mpc52xx_ide.h
--- a/drivers/ide/ppc/mpc52xx_ide.h 1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/ide/ppc/mpc52xx_ide.h 2006-11-05 10:40:49.000000000 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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/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 -uprN a/drivers/ide/ppc/mpc52xx_ide_iops.c b/drivers/ide/ppc/mpc52xx_ide_iops.c
--- a/drivers/ide/ppc/mpc52xx_ide_iops.c 1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/ide/ppc/mpc52xx_ide_iops.c 2006-11-05 10:40:49.000000000 +0100
@@ -0,0 +1,150 @@
+/*
+ * 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/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;
+}
+
--- a/drivers/ide/Kconfig 2006-11-04 15:29:27.000000000 +0100
+++ b/drivers/ide/Kconfig 2006-11-05 10:40:49.000000000 +0100
@@ -955,6 +955,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"
--- a/drivers/ide/Makefile 2006-09-20 05:42:06.000000000 +0200
+++ b/drivers/ide/Makefile 2006-11-05 10:40:49.000000000 +0100
@@ -36,6 +36,7 @@ ide-core-$(CONFIG_BLK_DEV_Q40IDE) += leg
# 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
+ide-core-$(CONFIG_BLK_DEV_MPC52xx_IDE) += ppc/mpc52xx_ide.o ppc/mpc52xx_ide_iops.o
# built-in only drivers from h8300/
ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o
More information about the Linuxppc-embedded
mailing list