mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			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__ */
 |