mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 07:22:33 +00:00
c49f135f72
SVN-Revision: 16547
1080 lines
29 KiB
Diff
1080 lines
29 KiB
Diff
From c9e68ea1a541b9762ec0b656509aef3cdd75e035 Mon Sep 17 00:00:00 2001
|
|
From: Kurt Mahan <kmahan@freescale.com>
|
|
Date: Mon, 19 Nov 2007 12:01:34 -0700
|
|
Subject: [PATCH] Add support for the M5445x ATA controller.
|
|
|
|
LTIBName: m5445x-ata
|
|
Signed-off-by: Kurt Mahan <kmahan@freescale.com>
|
|
---
|
|
arch/m68k/coldfire/Makefile | 1 +
|
|
arch/m68k/coldfire/head.S | 5 +
|
|
arch/m68k/coldfire/mcf5445x-devices.c | 125 +++++
|
|
drivers/ata/Kconfig | 11 +-
|
|
drivers/ata/Makefile | 2 +-
|
|
drivers/ata/pata_fsl.c | 829 +++++++++++++++++++++++++++++++++
|
|
include/asm-m68k/pci.h | 10 +-
|
|
include/linux/fsl_devices.h | 11 +
|
|
8 files changed, 990 insertions(+), 4 deletions(-)
|
|
create mode 100644 arch/m68k/coldfire/mcf5445x-devices.c
|
|
create mode 100644 drivers/ata/pata_fsl.c
|
|
|
|
--- a/arch/m68k/coldfire/Makefile
|
|
+++ b/arch/m68k/coldfire/Makefile
|
|
@@ -9,3 +9,4 @@ ifneq ($(strip $(CONFIG_USB) $(CONFIG_US
|
|
endif
|
|
|
|
obj-$(CONFIG_PCI) += pci.o mcf5445x-pci.o iomap.o
|
|
+obj-$(CONFIG_M54455) += mcf5445x-devices.o
|
|
--- a/arch/m68k/coldfire/head.S
|
|
+++ b/arch/m68k/coldfire/head.S
|
|
@@ -374,6 +374,11 @@ ENTRY(__start)
|
|
MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \
|
|
0, MMUDR_LK, %d0
|
|
|
|
+ /* Map ATA registers -- sacrifice a data TLB due to the hw design */
|
|
+ mmu_map (0x90000000), (0x90000000), 0, 0, \
|
|
+ MMUTR_SG, MMUDR_SZ16M, MMUDR_DNCP, MMUDR_SP, MMUDR_R, MMUDR_W, \
|
|
+ 0, MMUDR_LK, %d0
|
|
+
|
|
/* Do unity mapping to enable the MMU. Map first 16 MB in place as
|
|
code (delete TLBs after MMU is enabled and we are executing in high
|
|
memory). */
|
|
--- /dev/null
|
|
+++ b/arch/m68k/coldfire/mcf5445x-devices.c
|
|
@@ -0,0 +1,125 @@
|
|
+/*
|
|
+ * arch/m68k/coldfire/mcf5445x-devices.c
|
|
+ *
|
|
+ * Coldfire M5445x Platform Device Configuration
|
|
+ *
|
|
+ * Based on the Freescale MXC devices.c
|
|
+ *
|
|
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
|
|
+ * Kurt Mahan <kmahan@freescale.com>
|
|
+ */
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/fsl_devices.h>
|
|
+
|
|
+#include <asm/coldfire.h>
|
|
+#include <asm/mcfsim.h>
|
|
+
|
|
+/* ATA Interrupt */
|
|
+#define IRQ_ATA (64 + 64 + 54)
|
|
+
|
|
+/* ATA Base */
|
|
+#define BASE_IO_ATA 0x90000000
|
|
+
|
|
+#define ATA_IER MCF_REG08(BASE_IO_ATA+0x2c) /* int enable reg */
|
|
+#define ATA_ICR MCF_REG08(BASE_IO_ATA+0x30) /* int clear reg */
|
|
+
|
|
+/*
|
|
+ * On-chip PATA
|
|
+ */
|
|
+#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE)
|
|
+static int ata_init(struct platform_device *pdev)
|
|
+{
|
|
+ /* clear ints */
|
|
+ ATA_IER = 0x00;
|
|
+ ATA_ICR = 0xff;
|
|
+
|
|
+ /* setup shared pins */
|
|
+ MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC & MCF_GPIO_PAR_FEC_FEC1_MASK) |
|
|
+ MCF_GPIO_PAR_FEC_FEC1_ATA;
|
|
+
|
|
+ MCF_GPIO_PAR_FECI2C = (MCF_GPIO_PAR_FECI2C &
|
|
+ (MCF_GPIO_PAR_FECI2C_MDC1_MASK &
|
|
+ MCF_GPIO_PAR_FECI2C_MDIO1_MASK)) |
|
|
+ MCF_GPIO_PAR_FECI2C_MDC1_ATA_DIOR |
|
|
+ MCF_GPIO_PAR_FECI2C_MDIO1_ATA_DIOW;
|
|
+
|
|
+ MCF_GPIO_PAR_ATA = MCF_GPIO_PAR_ATA_BUFEN |
|
|
+ MCF_GPIO_PAR_ATA_CS1 |
|
|
+ MCF_GPIO_PAR_ATA_CS0 |
|
|
+ MCF_GPIO_PAR_ATA_DA2 |
|
|
+ MCF_GPIO_PAR_ATA_DA1 |
|
|
+ MCF_GPIO_PAR_ATA_DA0 |
|
|
+ MCF_GPIO_PAR_ATA_RESET_RESET |
|
|
+ MCF_GPIO_PAR_ATA_DMARQ_DMARQ |
|
|
+ MCF_GPIO_PAR_ATA_IORDY_IORDY;
|
|
+
|
|
+ MCF_GPIO_PAR_PCI = (MCF_GPIO_PAR_PCI &
|
|
+ (MCF_GPIO_PAR_PCI_GNT3_MASK &
|
|
+ MCF_GPIO_PAR_PCI_REQ3_MASK)) |
|
|
+ MCF_GPIO_PAR_PCI_GNT3_ATA_DMACK |
|
|
+ MCF_GPIO_PAR_PCI_REQ3_ATA_INTRQ;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ata_exit(void)
|
|
+{
|
|
+ printk(KERN_INFO "** ata_exit\n");
|
|
+}
|
|
+
|
|
+static int ata_get_clk_rate(void)
|
|
+{
|
|
+ return MCF_BUSCLK;
|
|
+}
|
|
+
|
|
+static struct fsl_ata_platform_data ata_data = {
|
|
+ .init = ata_init,
|
|
+ .exit = ata_exit,
|
|
+ .get_clk_rate = ata_get_clk_rate,
|
|
+};
|
|
+
|
|
+static struct resource pata_fsl_resources[] = {
|
|
+ [0] = { /* I/O */
|
|
+ .start = BASE_IO_ATA,
|
|
+ .end = BASE_IO_ATA + 0x000000d8,
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ },
|
|
+ [2] = { /* IRQ */
|
|
+ .start = IRQ_ATA,
|
|
+ .end = IRQ_ATA,
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device pata_fsl_device = {
|
|
+ .name = "pata_fsl",
|
|
+ .id = -1,
|
|
+ .num_resources = ARRAY_SIZE(pata_fsl_resources),
|
|
+ .resource = pata_fsl_resources,
|
|
+ .dev = {
|
|
+ .platform_data = &ata_data,
|
|
+ .coherent_dma_mask = ~0, /* $$$ REVISIT */
|
|
+ },
|
|
+};
|
|
+
|
|
+static inline void mcf5445x_init_pata(void)
|
|
+{
|
|
+ (void)platform_device_register(&pata_fsl_device);
|
|
+}
|
|
+#else
|
|
+static inline void mcf5445x_init_pata(void)
|
|
+{
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int __init mcf5445x_init_devices(void)
|
|
+{
|
|
+ printk(KERN_INFO "MCF5445x INIT_DEVICES\n");
|
|
+ mcf5445x_init_pata();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+arch_initcall(mcf5445x_init_devices);
|
|
--- a/drivers/ata/Kconfig
|
|
+++ b/drivers/ata/Kconfig
|
|
@@ -6,7 +6,7 @@ menuconfig ATA
|
|
tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
|
|
depends on HAS_IOMEM
|
|
depends on BLOCK
|
|
- depends on !(M32R || M68K) || BROKEN
|
|
+ depends on !M32R || BROKEN
|
|
depends on !SUN4 || BROKEN
|
|
select SCSI
|
|
---help---
|
|
@@ -679,4 +679,13 @@ config PATA_BF54X
|
|
|
|
If unsure, say N.
|
|
|
|
+config PATA_FSL
|
|
+ tristate "Freescale on-chip PATA support"
|
|
+ depends on (ARCH_MX3 || ARCH_MX27 || PPC_512x || M54455)
|
|
+ help
|
|
+ On Freescale processors, say Y here if you wish to use the on-chip
|
|
+ ATA interface.
|
|
+
|
|
+ If you are unsure, say N to this.
|
|
+
|
|
endif # ATA
|
|
--- a/drivers/ata/Makefile
|
|
+++ b/drivers/ata/Makefile
|
|
@@ -1,4 +1,3 @@
|
|
-
|
|
obj-$(CONFIG_ATA) += libata.o
|
|
|
|
obj-$(CONFIG_SATA_AHCI) += ahci.o
|
|
@@ -71,6 +70,7 @@ obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
|
|
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
|
|
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
|
|
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
|
|
+obj-$(CONFIG_PATA_FSL) += pata_fsl.o
|
|
# Should be last but two libata driver
|
|
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
|
|
# Should be last but one libata driver
|
|
--- /dev/null
|
|
+++ b/drivers/ata/pata_fsl.c
|
|
@@ -0,0 +1,829 @@
|
|
+/*
|
|
+ * Freescale integrated PATA driver
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * The code contained herein is licensed under the GNU General Public
|
|
+ * License. You may obtain a copy of the GNU General Public License
|
|
+ * Version 2 or later at the following locations:
|
|
+ *
|
|
+ * http://www.opensource.org/licenses/gpl-license.html
|
|
+ * http://www.gnu.org/copyleft/gpl.html
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/blkdev.h>
|
|
+#include <scsi/scsi_host.h>
|
|
+#include <linux/ata.h>
|
|
+#include <linux/libata.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/fsl_devices.h>
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+#include <asm/dma.h>
|
|
+#endif
|
|
+
|
|
+#define DRV_NAME "pata_fsl"
|
|
+#define DRV_VERSION "1.0"
|
|
+
|
|
+#ifdef CONFIG_M54455
|
|
+#define WRITE_ATA8(val, reg) \
|
|
+ __raw_writeb(val, (ata_regs + reg));
|
|
+#define WRITE_ATA16(val, reg) \
|
|
+ __raw_writew(val, (ata_regs + reg));
|
|
+#else
|
|
+#define WRITE_ATA8(val, reg) \
|
|
+ __raw_writel(val, (ata_regs + reg));
|
|
+#define WRITE_ATA16(val, reg) \
|
|
+ __raw_writel(val, (ata_regs + reg));
|
|
+#endif
|
|
+
|
|
+struct pata_fsl_priv {
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ int ultra;
|
|
+#endif
|
|
+ u8 *fsl_ata_regs;
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ int dma_rchan;
|
|
+ int dma_wchan;
|
|
+ int dma_done;
|
|
+ int dma_dir;
|
|
+#endif
|
|
+};
|
|
+
|
|
+enum {
|
|
+ /* various constants */
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ FSL_ATA_MAX_SG_LEN = 65534,
|
|
+#endif
|
|
+
|
|
+ /* offsets to registers */
|
|
+
|
|
+ FSL_ATA_TIMING_REGS = 0x00,
|
|
+ FSL_ATA_FIFO_FILL = 0x20,
|
|
+ FSL_ATA_CONTROL = 0x24,
|
|
+ FSL_ATA_INT_PEND = 0x28,
|
|
+ FSL_ATA_INT_EN = 0x2C,
|
|
+ FSL_ATA_INT_CLEAR = 0x30,
|
|
+ FSL_ATA_FIFO_ALARM = 0x34,
|
|
+ FSL_ATA_DRIVE_DATA = 0xA0,
|
|
+ FSL_ATA_DRIVE_CONTROL = 0xD8,
|
|
+
|
|
+ /* bits within FSL_ATA_CONTROL */
|
|
+
|
|
+ FSL_ATA_CTRL_FIFO_RST_B = 0x80,
|
|
+ FSL_ATA_CTRL_ATA_RST_B = 0x40,
|
|
+ FSL_ATA_CTRL_FIFO_TX_EN = 0x20,
|
|
+ FSL_ATA_CTRL_FIFO_RCV_EN = 0x10,
|
|
+ FSL_ATA_CTRL_DMA_PENDING = 0x08,
|
|
+ FSL_ATA_CTRL_DMA_ULTRA = 0x04,
|
|
+ FSL_ATA_CTRL_DMA_WRITE = 0x02,
|
|
+ FSL_ATA_CTRL_IORDY_EN = 0x01,
|
|
+
|
|
+ /* bits within the interrupt control registers */
|
|
+
|
|
+ FSL_ATA_INTR_ATA_INTRQ1 = 0x80,
|
|
+ FSL_ATA_INTR_FIFO_UNDERFLOW = 0x40,
|
|
+ FSL_ATA_INTR_FIFO_OVERFLOW = 0x20,
|
|
+ FSL_ATA_INTR_CTRL_IDLE = 0x10,
|
|
+ FSL_ATA_INTR_ATA_INTRQ2 = 0x08,
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This structure contains the timing parameters for
|
|
+ * ATA bus timing in the 5 PIO modes. The timings
|
|
+ * are in nanoseconds, and are converted to clock
|
|
+ * cycles before being stored in the ATA controller
|
|
+ * timing registers.
|
|
+ */
|
|
+static struct {
|
|
+ short t0, t1, t2_8, t2_16, t2i, t4, t9, tA;
|
|
+} pio_specs[] = {
|
|
+ [0] = {
|
|
+ .t0 = 600, .t1 = 70, .t2_8 = 290, .t2_16 = 165, .t2i = 0,
|
|
+ .t4 = 30,.t9 = 20,.tA = 50
|
|
+ },
|
|
+ [1] = {
|
|
+ .t0 = 383, .t1 = 50, .t2_8 = 290, .t2_16 = 125, .t2i = 0,
|
|
+ .t4 = 20, .t9 = 15, .tA = 50
|
|
+ },
|
|
+ [2] = {
|
|
+ .t0 = 240, .t1 = 30, .t2_8 = 290, .t2_16 = 100, .t2i = 0,
|
|
+ .t4 = 15, .t9 = 10, .tA = 50
|
|
+ },
|
|
+ [3] = {
|
|
+ .t0 = 180, .t1 = 30, .t2_8 = 80, .t2_16 = 80, .t2i = 0,
|
|
+ .t4 = 10, .t9 = 10, .tA = 50
|
|
+ },
|
|
+ [4] = {
|
|
+ .t0 = 120, .t1 = 25, .t2_8 = 70, .t2_16 = 70, .t2i = 0,
|
|
+ .t4 = 10, .t9 = 10, .tA = 50
|
|
+ },
|
|
+};
|
|
+
|
|
+#define NR_PIO_SPECS (sizeof pio_specs / sizeof pio_specs[0])
|
|
+
|
|
+/*
|
|
+ * This structure contains the timing parameters for
|
|
+ * ATA bus timing in the 3 MDMA modes. The timings
|
|
+ * are in nanoseconds, and are converted to clock
|
|
+ * cycles before being stored in the ATA controller
|
|
+ * timing registers.
|
|
+ */
|
|
+static struct {
|
|
+ short t0M, tD, tH, tJ, tKW, tM, tN, tJNH;
|
|
+} mdma_specs[] = {
|
|
+ [0] = {
|
|
+ .t0M = 480, .tD = 215, .tH = 20, .tJ = 20, .tKW = 215,
|
|
+ .tM = 50, .tN = 15, .tJNH = 20
|
|
+ },
|
|
+ [1] = {
|
|
+ .t0M = 150, .tD = 80, .tH = 15, .tJ = 5, .tKW = 50,
|
|
+ .tM = 30, .tN = 10, .tJNH = 15
|
|
+ },
|
|
+ [2] = {
|
|
+ .t0M = 120, .tD = 70, .tH = 10, .tJ = 5, .tKW = 25,
|
|
+ .tM = 25, .tN = 10, .tJNH = 10
|
|
+ },
|
|
+};
|
|
+
|
|
+#define NR_MDMA_SPECS (sizeof mdma_specs / sizeof mdma_specs[0])
|
|
+
|
|
+/*
|
|
+ * This structure contains the timing parameters for
|
|
+ * ATA bus timing in the 6 UDMA modes. The timings
|
|
+ * are in nanoseconds, and are converted to clock
|
|
+ * cycles before being stored in the ATA controller
|
|
+ * timing registers.
|
|
+ */
|
|
+static struct {
|
|
+ short t2CYC, tCYC, tDS, tDH, tDVS, tDVH, tCVS, tCVH, tFS_min, tLI_max,
|
|
+ tMLI, tAZ, tZAH, tENV_min, tSR, tRFS, tRP, tACK, tSS, tDZFS;
|
|
+} udma_specs[] = {
|
|
+ [0] = {
|
|
+ .t2CYC = 235, .tCYC = 114, .tDS = 15, .tDH = 5, .tDVS = 70,
|
|
+ .tDVH = 6, .tCVS = 70, .tCVH = 6, .tFS_min = 0,
|
|
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 50, .tRFS = 75, .tRP = 160,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 80
|
|
+ },
|
|
+ [1] = {
|
|
+ .t2CYC = 156, .tCYC = 75, .tDS = 10, .tDH = 5, .tDVS = 48,
|
|
+ .tDVH = 6, .tCVS = 48, .tCVH = 6, .tFS_min = 0,
|
|
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 30, .tRFS = 70, .tRP = 125,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 63
|
|
+ },
|
|
+ [2] = {
|
|
+ .t2CYC = 117, .tCYC = 55, .tDS = 7, .tDH = 5, .tDVS = 34,
|
|
+ .tDVH = 6, .tCVS = 34, .tCVH = 6, .tFS_min = 0,
|
|
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 47
|
|
+ },
|
|
+ [3] = {
|
|
+ .t2CYC = 86, .tCYC = 39, .tDS = 7, .tDH = 5, .tDVS = 20,
|
|
+ .tDVH = 6, .tCVS = 20, .tCVH = 6, .tFS_min = 0,
|
|
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 35
|
|
+ },
|
|
+ [4] = {
|
|
+ .t2CYC = 57, .tCYC = 25, .tDS = 5, .tDH = 5, .tDVS = 7,
|
|
+ .tDVH = 6, .tCVS = 7, .tCVH = 6, .tFS_min = 0,
|
|
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 50, .tRFS = 60, .tRP = 100,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 25
|
|
+ },
|
|
+ [5] = {
|
|
+ .t2CYC = 38, .tCYC = 17, .tDS = 4, .tDH = 5, .tDVS = 5,
|
|
+ .tDVH = 6, .tCVS = 10, .tCVH = 10, .tFS_min = 0,
|
|
+ .tLI_max = 75, .tMLI = 20, .tAZ = 10, .tZAH = 20,
|
|
+ .tENV_min = 20, .tSR = 20, .tRFS = 50, .tRP = 85,
|
|
+ .tACK = 20, .tSS = 50, .tDZFS = 40
|
|
+ },
|
|
+};
|
|
+
|
|
+#define NR_UDMA_SPECS (sizeof udma_specs / sizeof udma_specs[0])
|
|
+
|
|
+struct fsl_ata_time_regs {
|
|
+ u8 time_off, time_on, time_1, time_2w;
|
|
+ u8 time_2r, time_ax, time_pio_rdx, time_4;
|
|
+ u8 time_9, time_m, time_jn, time_d;
|
|
+ u8 time_k, time_ack, time_env, time_rpx;
|
|
+ u8 time_zah, time_mlix, time_dvh, time_dzfs;
|
|
+ u8 time_dvs, time_cvh, time_ss, time_cyc;
|
|
+};
|
|
+
|
|
+static void update_timing_config(struct fsl_ata_time_regs *tp, struct ata_host *host)
|
|
+{
|
|
+ u32 *lp = (u32 *)tp;
|
|
+ struct pata_fsl_priv *priv = host->private_data;
|
|
+ u32 *ctlp = (u32 *)priv->fsl_ata_regs;
|
|
+ int i;
|
|
+
|
|
+ /*
|
|
+ * JKM - this could have endianess issues on BE depending
|
|
+ * on how the controller is glued to the bus -- probably
|
|
+ * should rewrite this to write byte at a time.
|
|
+ */
|
|
+ for (i = 0; i < 5; i++) {
|
|
+ __raw_writel(*lp, ctlp);
|
|
+ lp++;
|
|
+ ctlp++;
|
|
+ }
|
|
+ mb();
|
|
+}
|
|
+
|
|
+/*!
|
|
+ * Calculate values for the ATA bus timing registers and store
|
|
+ * them into the hardware.
|
|
+ *
|
|
+ * @param xfer_mode specifies XFER xfer_mode
|
|
+ * @param pdev specifies platform_device
|
|
+ *
|
|
+ * @return EINVAL speed out of range, or illegal mode
|
|
+ */
|
|
+static int set_ata_bus_timing(u8 xfer_mode, struct platform_device *pdev)
|
|
+{
|
|
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
|
|
+ pdev->dev.platform_data;
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
+
|
|
+ /* get the bus clock cycle time, in ns */
|
|
+ int T = 1 * 1000 * 1000 * 1000 / plat->get_clk_rate();
|
|
+ struct fsl_ata_time_regs tr = {0};
|
|
+ DPRINTK("clk_rate = %d T = %d\n",plat->get_clk_rate(), T);
|
|
+
|
|
+ /*
|
|
+ * every mode gets the same t_off and t_on
|
|
+ */
|
|
+ tr.time_off = 3;
|
|
+ tr.time_on = 3;
|
|
+
|
|
+ if (xfer_mode >= XFER_UDMA_0) {
|
|
+ int speed = xfer_mode - XFER_UDMA_0;
|
|
+ if (speed >= NR_UDMA_SPECS) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ tr.time_ack = (udma_specs[speed].tACK + T) / T;
|
|
+ tr.time_env = (udma_specs[speed].tENV_min + T) / T;
|
|
+ tr.time_rpx = (udma_specs[speed].tRP + T) / T + 2;
|
|
+
|
|
+ tr.time_zah = (udma_specs[speed].tZAH + T) / T;
|
|
+ tr.time_mlix = (udma_specs[speed].tMLI + T) / T;
|
|
+ tr.time_dvh = (udma_specs[speed].tDVH + T) / T + 1;
|
|
+ tr.time_dzfs = (udma_specs[speed].tDZFS + T) / T;
|
|
+
|
|
+ tr.time_dvs = (udma_specs[speed].tDVS + T) / T;
|
|
+ tr.time_cvh = (udma_specs[speed].tCVH + T) / T;
|
|
+ tr.time_ss = (udma_specs[speed].tSS + T) / T;
|
|
+ tr.time_cyc = (udma_specs[speed].tCYC + T) / T;
|
|
+ } else if (xfer_mode >= XFER_MW_DMA_0) {
|
|
+ int speed = xfer_mode - XFER_MW_DMA_0;
|
|
+ if (speed >= NR_MDMA_SPECS) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ tr.time_m = (mdma_specs[speed].tM + T) / T;
|
|
+ tr.time_jn = (mdma_specs[speed].tJNH + T) / T;
|
|
+ tr.time_d = (mdma_specs[speed].tD + T) / T;
|
|
+
|
|
+ tr.time_k = (mdma_specs[speed].tKW + T) / T;
|
|
+ } else {
|
|
+ int speed = xfer_mode - XFER_PIO_0;
|
|
+ if (speed >= NR_PIO_SPECS) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ tr.time_1 = (pio_specs[speed].t1 + T) / T;
|
|
+ tr.time_2w = (pio_specs[speed].t2_8 + T) / T;
|
|
+
|
|
+ tr.time_2r = (pio_specs[speed].t2_8 + T) / T;
|
|
+ tr.time_ax = (pio_specs[speed].tA + T) / T + 2;
|
|
+ tr.time_pio_rdx = 1;
|
|
+ tr.time_4 = (pio_specs[speed].t4 + T) / T;
|
|
+
|
|
+ tr.time_9 = (pio_specs[speed].t9 + T) / T;
|
|
+ }
|
|
+
|
|
+ update_timing_config(&tr, host);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void pata_fsl_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
|
+{
|
|
+ set_ata_bus_timing(adev->pio_mode, to_platform_device(ap->dev));
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+static void pata_fsl_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
|
+{
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+
|
|
+ priv->ultra = adev->dma_mode >= XFER_UDMA_0;
|
|
+
|
|
+ set_ata_bus_timing(adev->dma_mode, to_platform_device(ap->dev));
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int pata_fsl_port_start(struct ata_port *ap)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+static void dma_callback(void *arg, int error_status, unsigned int count)
|
|
+{
|
|
+ struct ata_port *ap = arg;
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+ u8 *ata_regs = priv->fsl_ata_regs;
|
|
+
|
|
+ priv->dma_done = 1;
|
|
+ /*
|
|
+ * DMA is finished, so unmask INTRQ from the drive to allow the
|
|
+ * normal ISR to fire.
|
|
+ */
|
|
+#if 0
|
|
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
|
|
+#else
|
|
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
|
|
+#endif
|
|
+ mb();
|
|
+}
|
|
+
|
|
+static void pata_fsl_bmdma_setup(struct ata_queued_cmd *qc)
|
|
+{
|
|
+ int nr_sg = 0;
|
|
+ int chan;
|
|
+ int dma_mode = 0, dma_ultra;
|
|
+ u8 ata_control;
|
|
+ struct ata_port *ap = qc->ap;
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+ u8 *ata_regs = priv->fsl_ata_regs;
|
|
+ struct fsl_ata_platform_data *plat = ap->dev->platform_data;
|
|
+ struct scatterlist tmp[plat->max_sg], *tsg, *sg;
|
|
+ int err;
|
|
+
|
|
+ DPRINTK("ENTER\n");
|
|
+
|
|
+ priv->dma_dir = qc->dma_dir;
|
|
+
|
|
+ /*
|
|
+ * Configure the on-chip ATA interface hardware.
|
|
+ */
|
|
+ dma_ultra = priv->ultra ?
|
|
+ FSL_ATA_CTRL_DMA_ULTRA : 0;
|
|
+
|
|
+ ata_control = FSL_ATA_CTRL_FIFO_RST_B |
|
|
+ FSL_ATA_CTRL_ATA_RST_B |
|
|
+ FSL_ATA_CTRL_DMA_PENDING |
|
|
+ dma_ultra;
|
|
+
|
|
+ if (qc->dma_dir == DMA_TO_DEVICE) {
|
|
+ chan = priv->dma_wchan;
|
|
+ ata_control |= FSL_ATA_CTRL_FIFO_TX_EN |
|
|
+ FSL_ATA_CTRL_DMA_WRITE;
|
|
+ dma_mode = DMA_MODE_WRITE;
|
|
+ } else {
|
|
+ chan = priv->dma_rchan;
|
|
+ ata_control |= FSL_ATA_CTRL_FIFO_RCV_EN;
|
|
+ dma_mode = DMA_MODE_READ;
|
|
+ }
|
|
+#if 0
|
|
+ __raw_writel(ata_control, ata_regs + FSL_ATA_CONTROL);
|
|
+ __raw_writel(plat->fifo_alarm, ata_regs + FSL_ATA_FIFO_ALARM);
|
|
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ1, ata_regs + FSL_ATA_INT_EN);
|
|
+#else
|
|
+ WRITE_ATA8(ata_control, FSL_ATA_CONTROL);
|
|
+ WRITE_ATA8(plat->fifo_alarm, FSL_ATA_FIFO_ALARM);
|
|
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ1, FSL_ATA_INT_EN);
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ /*
|
|
+ * Set up the DMA completion callback.
|
|
+ */
|
|
+ mxc_dma_callback_set(chan, dma_callback, (void *)ap);
|
|
+
|
|
+ /*
|
|
+ * Copy the sg list to an array.
|
|
+ */
|
|
+ tsg = tmp;
|
|
+ ata_for_each_sg(sg, qc) {
|
|
+ memcpy(tsg, sg, sizeof *sg);
|
|
+ tsg++;
|
|
+ nr_sg++;
|
|
+ }
|
|
+
|
|
+ err = mxc_dma_sg_config(chan, tmp, nr_sg, 0, dma_mode);
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "pata_fsl_bmdma_setup: error %d\n", err);
|
|
+ }
|
|
+ DPRINTK("EXIT\n");
|
|
+}
|
|
+
|
|
+static void pata_fsl_bmdma_start(struct ata_queued_cmd *qc)
|
|
+{
|
|
+ struct ata_port *ap = qc->ap;
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+ int chan;
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * Start the channel.
|
|
+ */
|
|
+ chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan;
|
|
+
|
|
+ priv->dma_done = 0;
|
|
+
|
|
+ err = mxc_dma_enable(chan);
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "%s: : error %d\n", __func__, err);
|
|
+ }
|
|
+
|
|
+ ap->ops->exec_command(ap, &qc->tf);
|
|
+}
|
|
+
|
|
+static void pata_fsl_bmdma_stop(struct ata_queued_cmd *qc)
|
|
+{
|
|
+ struct ata_port *ap = qc->ap;
|
|
+
|
|
+ /* do a dummy read as in ata_bmdma_stop */
|
|
+ ata_altstatus(ap);
|
|
+}
|
|
+
|
|
+static u8 pata_fsl_bmdma_status(struct ata_port *ap)
|
|
+{
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+
|
|
+ return priv->dma_done ? ATA_DMA_INTR : 0;
|
|
+}
|
|
+
|
|
+static void pata_fsl_dma_init(struct ata_port *ap)
|
|
+{
|
|
+ struct pata_fsl_priv *priv = ap->host->private_data;
|
|
+
|
|
+ priv->dma_rchan = -1;
|
|
+ priv->dma_wchan = -1;
|
|
+
|
|
+ priv->dma_rchan = mxc_dma_request(MXC_DMA_ATA_RX, "MXC ATA RX");
|
|
+ if (priv->dma_rchan < 0) {
|
|
+ dev_printk(KERN_ERR, ap->dev, "couldn't get RX DMA channel\n");
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ priv->dma_wchan = mxc_dma_request(MXC_DMA_ATA_TX, "MXC ATA TX");
|
|
+ if (priv->dma_wchan < 0) {
|
|
+ dev_printk(KERN_ERR, ap->dev, "couldn't get TX DMA channel\n");
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ dev_printk(KERN_ERR, ap->dev, "rchan=%d wchan=%d\n", priv->dma_rchan,
|
|
+ priv->dma_wchan);
|
|
+ return;
|
|
+
|
|
+err_out:
|
|
+ ap->mwdma_mask = 0;
|
|
+ ap->udma_mask = 0;
|
|
+ mxc_dma_free(priv->dma_rchan);
|
|
+ mxc_dma_free(priv->dma_wchan);
|
|
+ kfree(priv);
|
|
+}
|
|
+#endif /* CONFIG_FSL_PATA_USE_DMA */
|
|
+
|
|
+static u8 pata_fsl_irq_ack(struct ata_port *ap, unsigned int chk_drq)
|
|
+{
|
|
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
|
|
+ u8 status;
|
|
+
|
|
+ status = ata_busy_wait(ap, bits, 1000);
|
|
+ if (status & bits)
|
|
+ if (ata_msg_err(ap))
|
|
+ printk(KERN_ERR "abnormal status 0x%X\n", status);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+static void ata_dummy_noret(struct ata_port *ap) { return; }
|
|
+
|
|
+static struct scsi_host_template pata_fsl_sht = {
|
|
+ .module = THIS_MODULE,
|
|
+ .name = DRV_NAME,
|
|
+ .ioctl = ata_scsi_ioctl,
|
|
+ .queuecommand = ata_scsi_queuecmd,
|
|
+ .can_queue = ATA_DEF_QUEUE,
|
|
+ .this_id = ATA_SHT_THIS_ID,
|
|
+ .sg_tablesize = LIBATA_MAX_PRD,
|
|
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
|
+ .emulated = ATA_SHT_EMULATED,
|
|
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
|
|
+ .proc_name = DRV_NAME,
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ .dma_boundary = FSL_ATA_MAX_SG_LEN,
|
|
+#endif
|
|
+ .slave_configure = ata_scsi_slave_config,
|
|
+ .slave_destroy = ata_scsi_slave_destroy,
|
|
+ .bios_param = ata_std_bios_param,
|
|
+};
|
|
+
|
|
+static struct ata_port_operations pata_fsl_port_ops = {
|
|
+ .set_piomode = pata_fsl_set_piomode,
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ .set_dmamode = pata_fsl_set_dmamode,
|
|
+#endif
|
|
+
|
|
+ .port_disable = ata_port_disable,
|
|
+ .tf_load = ata_tf_load,
|
|
+ .tf_read = ata_tf_read,
|
|
+ .check_status = ata_check_status,
|
|
+ .exec_command = ata_exec_command,
|
|
+ .dev_select = ata_std_dev_select,
|
|
+
|
|
+ .freeze = ata_bmdma_freeze,
|
|
+ .thaw = ata_bmdma_thaw,
|
|
+ .error_handler = ata_bmdma_error_handler,
|
|
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
|
|
+ .cable_detect = ata_cable_unknown,
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ .bmdma_setup = pata_fsl_bmdma_setup,
|
|
+ .bmdma_start = pata_fsl_bmdma_start,
|
|
+#endif
|
|
+
|
|
+ .qc_prep = ata_noop_qc_prep,
|
|
+ .qc_issue = ata_qc_issue_prot,
|
|
+
|
|
+ .data_xfer = ata_data_xfer_noirq,
|
|
+
|
|
+ .irq_clear = ata_dummy_noret,
|
|
+ .irq_on = ata_irq_on,
|
|
+ .irq_ack = pata_fsl_irq_ack,
|
|
+
|
|
+ .port_start = pata_fsl_port_start,
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ .bmdma_stop = pata_fsl_bmdma_stop,
|
|
+ .bmdma_status = pata_fsl_bmdma_status,
|
|
+#endif
|
|
+};
|
|
+
|
|
+static void fsl_setup_port(struct ata_ioports *ioaddr)
|
|
+{
|
|
+ unsigned int shift = 2;
|
|
+
|
|
+ ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift);
|
|
+ ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift);
|
|
+ ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift);
|
|
+ ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift);
|
|
+ ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift);
|
|
+ ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift);
|
|
+ ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift);
|
|
+ ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift);
|
|
+ ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift);
|
|
+ ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * pata_fsl_probe - attach a platform interface
|
|
+ * @pdev: platform device
|
|
+ *
|
|
+ * Register a platform bus integrated ATA host controller
|
|
+ *
|
|
+ * The 3 platform device resources are used as follows:
|
|
+ *
|
|
+ * - I/O Base (IORESOURCE_MEM) virt. addr. of ATA controller regs
|
|
+ * - CTL Base (IORESOURCE_MEM) unused
|
|
+ * - IRQ (IORESOURCE_IRQ) platform IRQ assigned to ATA
|
|
+ *
|
|
+ */
|
|
+static int __devinit pata_fsl_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct resource *io_res;
|
|
+ struct ata_host *host;
|
|
+ struct ata_port *ap;
|
|
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
|
|
+ pdev->dev.platform_data;
|
|
+ struct pata_fsl_priv *priv;
|
|
+ u8 *ata_regs;
|
|
+ int ret;
|
|
+
|
|
+ DPRINTK("ENTER\n");
|
|
+ /*
|
|
+ * Get an ata_host structure for this device
|
|
+ */
|
|
+ host = ata_host_alloc(&pdev->dev, 1);
|
|
+ if (!host)
|
|
+ return -ENOMEM;
|
|
+ ap = host->ports[0];
|
|
+
|
|
+ /*
|
|
+ * Allocate private data
|
|
+ */
|
|
+ priv = kzalloc(sizeof (struct pata_fsl_priv), GFP_KERNEL);
|
|
+ if(priv == NULL) {
|
|
+ /* free(host); */
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ host->private_data = priv;
|
|
+
|
|
+ /*
|
|
+ * Set up resources
|
|
+ */
|
|
+ if (unlikely(pdev->num_resources != 3)) {
|
|
+ dev_err(&pdev->dev, "invalid number of resources\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
+ ata_regs = (u8 *)io_res->start;
|
|
+ priv->fsl_ata_regs = ata_regs;
|
|
+ ap->ioaddr.cmd_addr = (void *)(ata_regs + FSL_ATA_DRIVE_DATA);
|
|
+ ap->ioaddr.ctl_addr = (void *)(ata_regs + FSL_ATA_DRIVE_CONTROL);
|
|
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
|
|
+ ap->ops = &pata_fsl_port_ops;
|
|
+ ap->pio_mask = 0x7F;
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ ap->mwdma_mask = 0x7F;
|
|
+ ap->udma_mask = plat->udma_mask;
|
|
+ pata_fsl_sht.sg_tablesize = plat->max_sg;
|
|
+#else
|
|
+ ap->mwdma_mask = 0x00;
|
|
+ ap->udma_mask = 0x00;
|
|
+#endif
|
|
+ fsl_setup_port(&ap->ioaddr);
|
|
+
|
|
+ /*
|
|
+ * Do platform-specific initialization (e.g. allocate pins,
|
|
+ * turn on clock). After this call it is assumed that
|
|
+ * plat->get_clk_rate() can be called to calculate
|
|
+ * timing.
|
|
+ */
|
|
+ if (plat->init && plat->init(pdev)) {
|
|
+ /* REVISIT: don't leak what ata_host_alloc() allocated */
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /* Deassert the reset bit to enable the interface */
|
|
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL);
|
|
+ mb();
|
|
+
|
|
+ /* Set initial timing and mode */
|
|
+ set_ata_bus_timing(XFER_PIO_4, pdev);
|
|
+
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ /* get DMA ready */
|
|
+ pata_fsl_dma_init(ap);
|
|
+#endif
|
|
+
|
|
+ /*
|
|
+ * Enable the ATA INTRQ interrupt from the bus, but
|
|
+ * only allow the CPU to see it (INTRQ2) at this point.
|
|
+ * INTRQ1, which goes to the DMA, will be enabled later.
|
|
+ */
|
|
+#if 0
|
|
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
|
|
+#else
|
|
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ /* activate */
|
|
+ ret = ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
|
|
+ 0, &pata_fsl_sht);
|
|
+ DPRINTK("EXIT ret=%d\n", ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * pata_fsl_remove - unplug a platform interface
|
|
+ * @pdev: platform device
|
|
+ *
|
|
+ * A platform bus ATA device has been unplugged. Perform the needed
|
|
+ * cleanup. Also called on module unload for any active devices.
|
|
+ */
|
|
+static int __devexit pata_fsl_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct ata_host *host = dev_get_drvdata(dev);
|
|
+ struct pata_fsl_priv *priv = host->private_data;
|
|
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
|
|
+ pdev->dev.platform_data;
|
|
+ u8 *ata_regs = priv->fsl_ata_regs;
|
|
+
|
|
+#if 0
|
|
+ __raw_writel(0, ata_regs + FSL_ATA_INT_EN); /* Disable interrupts */
|
|
+#else
|
|
+ WRITE_ATA8(0, FSL_ATA_INT_EN); /* Disable interrupts */
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ ata_host_detach(host);
|
|
+
|
|
+ if (plat->exit)
|
|
+ plat->exit();
|
|
+
|
|
+ kfree(priv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM
|
|
+static int pata_fsl_suspend(struct platform_device *pdev, pm_message_t state)
|
|
+{
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
+ struct pata_fsl_priv *priv = host->private_data;
|
|
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
|
|
+ pdev->dev.platform_data;
|
|
+ u8 *ata_regs = priv->fsl_ata_regs;
|
|
+
|
|
+ /* Disable interrupts. */
|
|
+#if 0
|
|
+ __raw_writel(0, ata_regs + FSL_ATA_INT_EN);
|
|
+#else
|
|
+ WRITE_ATA8(0, FSL_ATA_INT_EN);
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ if (plat->exit)
|
|
+ plat->exit();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pata_fsl_resume(struct platform_device *pdev)
|
|
+{
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
+ struct pata_fsl_priv *priv = host->private_data;
|
|
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
|
|
+ pdev->dev.platform_data;
|
|
+ u8 *ata_regs = priv->fsl_ata_regs;
|
|
+
|
|
+ if (plat->init && plat->init(pdev)) {
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /* Deassert the reset bit to enable the interface */
|
|
+#if 0
|
|
+ __raw_writel(FSL_ATA_CTRL_ATA_RST_B, ata_regs + FSL_ATA_CONTROL);
|
|
+#else
|
|
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL);
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ /* Set initial timing and mode */
|
|
+ set_ata_bus_timing(XFER_PIO_4, pdev);
|
|
+
|
|
+ /*
|
|
+ * Enable hardware interrupts.
|
|
+ */
|
|
+#if 0
|
|
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
|
|
+#else
|
|
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
|
|
+#endif
|
|
+ mb();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static struct platform_driver pata_fsl_driver = {
|
|
+ .probe = pata_fsl_probe,
|
|
+ .remove = __devexit_p(pata_fsl_remove),
|
|
+#ifdef CONFIG_PM
|
|
+ .suspend = pata_fsl_suspend,
|
|
+ .resume = pata_fsl_resume,
|
|
+#endif
|
|
+ .driver = {
|
|
+ .name = DRV_NAME,
|
|
+ .owner = THIS_MODULE,
|
|
+ },
|
|
+};
|
|
+
|
|
+static int __init pata_fsl_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ DPRINTK("ENTER\n");
|
|
+ ret = platform_driver_register(&pata_fsl_driver);
|
|
+ DPRINTK("EXIT ret=%d\n", ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void __exit pata_fsl_exit(void)
|
|
+{
|
|
+ platform_driver_unregister(&pata_fsl_driver);
|
|
+}
|
|
+module_init(pata_fsl_init);
|
|
+module_exit(pata_fsl_exit);
|
|
+
|
|
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
|
+MODULE_DESCRIPTION("low-level driver for Freescale ATA");
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_VERSION(DRV_VERSION);
|
|
--- a/include/asm-m68k/pci.h
|
|
+++ b/include/asm-m68k/pci.h
|
|
@@ -7,8 +7,14 @@
|
|
#ifndef _ASM_M68K_PCI_H
|
|
#define _ASM_M68K_PCI_H
|
|
|
|
-#ifdef CONFIG_PCI
|
|
-
|
|
+#ifndef CONFIG_PCI
|
|
+/*
|
|
+ * The PCI address space does equal the physical memory
|
|
+ * address space. The networking and block device layers use
|
|
+ * this boolean for bounce buffer decisions.
|
|
+ */
|
|
+#define PCI_DMA_BUS_IS_PHYS (1)
|
|
+#else
|
|
#include <asm-generic/pci-dma-compat.h>
|
|
|
|
/*
|
|
--- a/include/linux/fsl_devices.h
|
|
+++ b/include/linux/fsl_devices.h
|
|
@@ -126,5 +126,16 @@ struct mpc8xx_pcmcia_ops {
|
|
int(*voltage_set)(int slot, int vcc, int vpp);
|
|
};
|
|
|
|
+struct fsl_ata_platform_data {
|
|
+#ifdef CONFIG_FSL_PATA_USE_DMA
|
|
+ int udma_mask; /* UDMA modes h/w can handle */
|
|
+ int fifo_alarm; /* value for fifo_alarm reg */
|
|
+ int max_sg; /* longest sglist h/w can handle */
|
|
+#endif
|
|
+ int (*init)(struct platform_device *pdev);
|
|
+ void (*exit)(void);
|
|
+ int (*get_clk_rate)(void);
|
|
+};
|
|
+
|
|
#endif /* _FSL_DEVICE_H_ */
|
|
#endif /* __KERNEL__ */
|