/*
 *  sata_stm.c - STMicroelectronics SATA
 *
 *  Copyright 2005 STMicroelectronics Ltd.
 *
 *  The contents of this file are subject to the Open
 *  Software License version 1.1 that can be found at
 *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
 *  by reference.
 *
 *  Alternatively, the contents of this file may be used under the terms
 *  of the GNU General Public License version 2 (the "GPL") as distributed
 *  in the kernel source COPYING file, in which case the provisions of
 *  the GPL are applicable instead of the above.  If you wish to allow
 *  the use of your version of this file only under the terms of the
 *  GPL and not to allow others to use your version of this file under
 *  the OSL, indicate your decision by deleting the provisions above and
 *  replace them with the notice and other provisions required by the GPL.
 *  If you do not delete the provisions above, a recipient may use your
 *  version of this file under either the OSL or the GPL.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport.h>
#include <linux/libata.h>
#include <linux/stm/platform.h>
#include <linux/stm/device.h>
#include <linux/stm/miphy.h>

#define DRV_NAME			"sata-stm"
#define DRV_VERSION			"0.8"

/* Offsets of the component blocks */
#define SATA_AHB2STBUS_BASE			0x00000000
#define SATA_AHBDMA_BASE			0x00000400
#define SATA_AHBHOST_BASE			0x00000800

/* AHB_STBus protocol converter */
#define SATA_AHB2STBUS_STBUS_OPC		(SATA_AHB2STBUS_BASE + 0x0000)
#define SATA_AHB2STBUS_MESSAGE_SIZE_CONFIG	(SATA_AHB2STBUS_BASE + 0x0004)
#define SATA_AHB2STBUS_CHUNK_SIZE_CONFIG	(SATA_AHB2STBUS_BASE + 0x0008)
#define SATA_AHB2STBUS_SW_RESET			(SATA_AHB2STBUS_BASE + 0x000c)
#define SATA_AHB2STBUS_PC_STATUS		(SATA_AHB2STBUS_BASE + 0x0010)
#define SATA_PC_GLUE_LOGIC			(SATA_AHB2STBUS_BASE + 0x0014)
#define SATA_PC_GLUE_LOGICH			(SATA_AHB2STBUS_BASE + 0x0018)

/* AHB DMA controller */
#define DMAC_SAR0				(SATA_AHBDMA_BASE + 0x00000000)
#define DMAC_DAR0				(SATA_AHBDMA_BASE + 0x00000008)
#define DMAC_LLP0				(SATA_AHBDMA_BASE + 0x00000010)
#define DMAC_CTL0_0				(SATA_AHBDMA_BASE + 0x00000018)
#define DMAC_CTL0_1				(SATA_AHBDMA_BASE + 0x0000001c)
#define DMAC_SSTAT0				(SATA_AHBDMA_BASE + 0x00000020)
#define DMAC_DSTAT0				(SATA_AHBDMA_BASE + 0x00000028)
#define DMAC_SSTATAR0				(SATA_AHBDMA_BASE + 0x00000030)
#define DMAC_DSTATAR0				(SATA_AHBDMA_BASE + 0x00000038)
#define DMAC_CFG0_0				(SATA_AHBDMA_BASE + 0x00000040)
#define DMAC_CFG0_1				(SATA_AHBDMA_BASE + 0x00000044)
#define DMAC_SGR0				(SATA_AHBDMA_BASE + 0x00000048)
#define DMAC_DSR0				(SATA_AHBDMA_BASE + 0x00000050)
#define DMAC_RAWTFR				(SATA_AHBDMA_BASE + 0x000002c0)
#define DMAC_RAWBLOCK				(SATA_AHBDMA_BASE + 0x000002c8)
#define DMAC_RAWSRCTRAN				(SATA_AHBDMA_BASE + 0x000002d0)
#define DMAC_RAWDSTTRAN				(SATA_AHBDMA_BASE + 0x000002d8)
#define DMAC_RAWERR				(SATA_AHBDMA_BASE + 0x000002e0)
#define DMAC_STATUSTFR				(SATA_AHBDMA_BASE + 0x000002e8)
#define DMAC_STATUSBLOCK			(SATA_AHBDMA_BASE + 0x000002f0)
#define DMAC_STATUSSRCTRAN			(SATA_AHBDMA_BASE + 0x000002f8)
#define DMAC_STATUSDSTTRAN			(SATA_AHBDMA_BASE + 0x00000300)
#define DMAC_STATUSERR				(SATA_AHBDMA_BASE + 0x00000308)
#define DMAC_MASKTFR				(SATA_AHBDMA_BASE + 0x00000310)
#define DMAC_MASKBLOCK				(SATA_AHBDMA_BASE + 0x00000318)
#define DMAC_MASKSRCTRAN			(SATA_AHBDMA_BASE + 0x00000320)
#define DMAC_MASKDSTTRAN			(SATA_AHBDMA_BASE + 0x00000328)
#define DMAC_MASKERR				(SATA_AHBDMA_BASE + 0x00000330)
#define DMAC_CLEARTFR				(SATA_AHBDMA_BASE + 0x00000338)
#define DMAC_CLEARBLOCK				(SATA_AHBDMA_BASE + 0x00000340)
#define DMAC_CLEARSRCTRAN			(SATA_AHBDMA_BASE + 0x00000348)
#define DMAC_CLEARDSTTRAN			(SATA_AHBDMA_BASE + 0x00000350)
#define DMAC_CLEARERR				(SATA_AHBDMA_BASE + 0x00000358)
#define DMAC_STATUSINT				(SATA_AHBDMA_BASE + 0x00000360)
#define DMAC_REQSRCREG				(SATA_AHBDMA_BASE + 0x00000368)
#define DMAC_REQDSTREG				(SATA_AHBDMA_BASE + 0x00000370)
#define DMAC_SGLREQSRCREG			(SATA_AHBDMA_BASE + 0x00000378)
#define DMAC_SGLREQDSTREG			(SATA_AHBDMA_BASE + 0x00000380)
#define DMAC_LSTSRCREG				(SATA_AHBDMA_BASE + 0x00000388)
#define DMAC_LSTDSTREG				(SATA_AHBDMA_BASE + 0x00000390)
#define DMAC_DmaCfgReg				(SATA_AHBDMA_BASE + 0x00000398)
#define DMAC_ChEnReg				(SATA_AHBDMA_BASE + 0x000003a0)
#define DMAC_DMAIDREG				(SATA_AHBDMA_BASE + 0x000003a8)
#define DMAC_DMATESTREG				(SATA_AHBDMA_BASE + 0x000003b0)
#define DMAC_DMA_COMP_VERSION			(SATA_AHBDMA_BASE + 0x000003b8)
#define DMAC_COMP_PARAMS_2			(SATA_AHBDMA_BASE + 0x000003e8)
#define DMAC_COMP_TYPE				(SATA_AHBDMA_BASE + 0x000003f8)
#define DMAC_COMP_VERSION			(SATA_AHBDMA_BASE + 0x000003fc)

#define DMAC_CTL_INT_EN			(1<<0)
#define DMAC_CTL_DST_TR_WIDTH_32	(2<<1)
#define DMAC_CTL_SRC_TR_WIDTH_32	(2<<4)
#define DMAC_CTL_DINC_INC		(0<<7)
#define DMAC_CTL_DINC_DEC		(1<<7)
#define DMAC_CTL_DINC_NC		(2<<7)
#define DMAC_CTL_SINC_INC		(0<<9)
#define DMAC_CTL_SINC_DEC		(1<<9)
#define DMAC_CTL_SINC_NC		(2<<9)
#define DMAC_CTL_DEST_MSIZE_1		(0<<11)
#define DMAC_CTL_DEST_MSIZE_4		(1<<11)
#define DMAC_CTL_DEST_MSIZE_8		(2<<11)
#define DMAC_CTL_DEST_MSIZE_16		(3<<11)
#define DMAC_CTL_SRC_MSIZE_1		(0<<14)
#define DMAC_CTL_SRC_MSIZE_4		(1<<14)
#define DMAC_CTL_SRC_MSIZE_8		(2<<14)
#define DMAC_CTL_SRC_MSIZE_16		(3<<14)
#define DMAC_CTL_SRC_GATHER_EN		(1<<17)
#define DMAC_CTL_DST_SCATTER_EN		(1<<18)
#define DMAC_CTL_TT_FC_M2M_DMAC		(0<<20)	/* memory to memory | DMAC */
#define DMAC_CTL_TT_FC_M2P_DMAC		(1<<20)	/* memory to periph | DMAC */
#define DMAC_CTL_TT_FC_P2M_DMAC		(2<<20)	/* periph to memory | DMAC */
#define DMAC_CTL_TT_FC_P2P_DMAC		(3<<20)	/* periph to periph | DMAC */
#define DMAC_CTL_TT_FC_P2M_PER		(4<<20)	/* periph to memory | periph */
#define DMAC_CTL_TT_FC_P2P_SPER		(5<<20)	/* periph to periph | src periph */
#define DMAC_CTL_TT_FC_M2P_PER		(6<<20)	/* memory to periph | periph */
#define DMAC_CTL_TT_FC_P2P_DPER		(7<<20)	/* periph to periph | dest periph */
#define DMAC_CTL_DMS_1		(0<<23)
#define DMAC_CTL_DMS_2		(1<<23)
#define DMAC_CTL_SMS_1		(0<<25)
#define DMAC_CTL_SMS_2		(1<<25)
#define DMAC_CTL_LLP_DST_EN	(1<<27)
#define DMAC_CTL_LLP_SRC_EN	(1<<28)

#define DMAC_CTL_BLOCK_TS	(1<<32)
#define DMAC_CTL_DONE		(1<<44)

#define DMA_CFG_CH_PRIOR_0	(0<<5)
#define DMA_CFG_CH_SUSP		(1<<8)
#define DMA_CFG_FIFO_EMPTY	(1<<9)
#define DMA_CFG_HS_SEL_DST_HW	(0<<10)
#define DMA_CFG_HS_SEL_DST_SW	(1<<10)
#define DMA_CFG_HS_SEL_SRC_HW	(0<<11)
#define DMA_CFG_HS_SEL_SRC_SW	(1<<11)
/*efine DMA_CFG_LOCK_CH_L	(1<<12) not in config */
/*efine DMA_CFG_LOCK_B_L	(1<<14) not in config */
/*efine DMA_CFG_LOCK_CH		(1<<16) not in config */
/*efine DMA_CFG_LOCK_B		(1<<17) not in config */
#define DMA_CFG_DST_HS_POL_HI	(0<<18)
#define DMA_CFG_DST_HS_POL_LO	(1<<18)
#define DMA_CFG_SRC_HS_POL_HI	(0<<19)
#define DMA_CFG_SRC_HS_POL_LO	(1<<19)
#define DMA_CFG_MAX_ABRST_UNLIMITED	(0<<20)
#define DMA_CFG_RELOAD_SRC	(1<<30)
#define DMA_CFG_RELOAD_DST	(1<<31)

#define DMA_CFG_1_FCMODE		(1<<(32-32))
#define DMA_CFG_1_FIFO_MODE		(1<<(33-32))
#define DMA_CFG_1_PROTCTL		(1<<(34-32))
#define DMA_CFG_1_DS_UPD_EN		(1<<(37-32))
/*efine DMA_CFG_1_SS_UPD_EN		(1<<(38-32)) not in config */
#define DMA_CFG_1_SRC_PER_0		(0<<(39-32))
#define DMA_CFG_1_SRC_PER_1		(1<<(39-32))
#define DMA_CFG_1_DEST_PER_0		(0<<(43-32))
#define DMA_CFG_1_DEST_PER_1		(1<<(43-32))

#define DMAC_DmaCfgReg_DMA_EN	(1<<0)

#define DMAC_COMP_PARAMS_2_CH0_HC_LLP	(1<<13)

/* AHB host controller */
#define SATA_CDR0				(SATA_AHBHOST_BASE + 0x00000000)
#define SATA_CDR1				(SATA_AHBHOST_BASE + 0x00000004)
#define SATA_CDR2				(SATA_AHBHOST_BASE + 0x00000008)
#define SATA_CDR3				(SATA_AHBHOST_BASE + 0x0000000c)
#define SATA_CDR4				(SATA_AHBHOST_BASE + 0x00000010)
#define SATA_CDR5				(SATA_AHBHOST_BASE + 0x00000014)
#define SATA_CDR6				(SATA_AHBHOST_BASE + 0x00000018)
#define SATA_CDR7				(SATA_AHBHOST_BASE + 0x0000001c)
#define SATA_CLR0				(SATA_AHBHOST_BASE + 0x00000020)
#define SATA_SCR0				(SATA_AHBHOST_BASE + 0x00000024)
#define SATA_SCR1				(SATA_AHBHOST_BASE + 0x00000028)
#define SATA_SCR2				(SATA_AHBHOST_BASE + 0x0000002c)
#define SATA_SCR3				(SATA_AHBHOST_BASE + 0x00000030)
#define SATA_SCR4				(SATA_AHBHOST_BASE + 0x00000034)
#define SATA_FPTAGR				(SATA_AHBHOST_BASE + 0x00000064)
#define SATA_FPBOR				(SATA_AHBHOST_BASE + 0x00000068)
#define SATA_FPTCR				(SATA_AHBHOST_BASE + 0x0000006c)
#define SATA_DMACR				(SATA_AHBHOST_BASE + 0x00000070)
#define SATA_DBTSR				(SATA_AHBHOST_BASE + 0x00000074)
#define SATA_INTPR				(SATA_AHBHOST_BASE + 0x00000078)
#define SATA_INTMR				(SATA_AHBHOST_BASE + 0x0000007c)
#define SATA_ERRMR				(SATA_AHBHOST_BASE + 0x00000080)
#define SATA_LLCR				(SATA_AHBHOST_BASE + 0x00000084)
#define SATA_PHYCR				(SATA_AHBHOST_BASE + 0x00000088)
#define SATA_PHYSR				(SATA_AHBHOST_BASE + 0x0000008c)
#define SATA_RXBISTPD				(SATA_AHBHOST_BASE + 0x00000090)
#define SATA_RXBISTD1				(SATA_AHBHOST_BASE + 0x00000094)
#define SATA_RXBISTD2				(SATA_AHBHOST_BASE + 0x00000098)
#define SATA_TXBISTPD				(SATA_AHBHOST_BASE + 0x0000009c)
#define SATA_TXBISTD1				(SATA_AHBHOST_BASE + 0x000000a0)
#define SATA_TXBISTD2				(SATA_AHBHOST_BASE + 0x000000a4)
#define SATA_BISTCR				(SATA_AHBHOST_BASE + 0x000000a8)
#define SATA_BISTFCTR				(SATA_AHBHOST_BASE + 0x000000ac)
#define SATA_BISTSR				(SATA_AHBHOST_BASE + 0x000000b0)
#define SATA_BISTDECR				(SATA_AHBHOST_BASE + 0x000000b4)
#define SATA_OOBR				(SATA_AHBHOST_BASE + 0x000000bc)
#define SATA_TESTR				(SATA_AHBHOST_BASE + 0x000000f4)
#define SATA_VERSIONR				(SATA_AHBHOST_BASE + 0x000000f8)
#define SATA_IDR				(SATA_AHBHOST_BASE + 0x000000fc)


#define SATA_DMACR_TXCHEN	(1<<0)
#define SATA_DMACR_RXCHEN	(1<<1)

/* Bit values for SATA_INTPR and SATA_INTMR */
#define SATA_INT_DMAT		(1<<0)
#define SATA_INT_NEWFP		(1<<1)
#define SATA_INT_PMABORT	(1<<2)
#define SATA_INT_ERR		(1<<3)
#define SATA_INT_NEWBIST	(1<<4)

#define SERROR_ERR_T	(1<<8)
#define SERROR_ERR_C	(1<<9)
#define SERROR_ERR_P	(1<<10)
#define SERROR_ERR_E	(1<<11)
#define SERROR_DIAG_N	(1<<16)
#define SERROR_DIAG_X	(1<<26)

#define SATA_FIS_SIZE	(8*1024)

static int stm_sata_scr_read(struct ata_link *link, unsigned int sc_reg,
			     u32 *val);
static int stm_sata_scr_write(struct ata_link *link, unsigned int sc_reg,
			      u32 val);

/* Layout of a DMAC Linked List Item (LLI)
 * DMAH_CH0_STAT_DST and DMAH_CH0_STAT_SRC are both 0 */
struct stm_lli {
	u32	sar;
	u32	dar;
	u32	llp;
	u32	ctl0;
	u32	ctl1;
};

struct stm_host_priv
{
	unsigned long phy_init;		/* Initial value for PHYCR */
	int oob_wa;			/* OOB-06(a) certification test WA */
	int softsg;			/* If using softsg */
	int shared_dma_host_irq;	/* If we the interrupt from the DMA
					 * and HOSTC are or'ed together */
	struct stm_device_state *device_state;
	void (*host_restart)(int port); /* Full reset of host and phy */
	int port_num;			/* Parameter to host_restart */
	struct stm_miphy *miphy_dev;	/* MiPHY Dev Struct */
};

struct stm_port_priv
{
	struct stm_lli *lli;		/* Base of the allocated lli nodes */
	dma_addr_t lli_dma;		/* Physical version of lli */
	struct stm_lli *softsg_node;	/* Current softsg node */
	struct stm_lli *softsg_end;	/* End of the softsg node */
	char smallburst;		/* Small DMA burst size */
	char pmp;			/* Current SControl.PMP */
	struct ata_link *active_link;	/* Link for last request */
};

/* There is an undocumented restriction that DMA blocks must not span
 * a FIS boundary. So to ensure we have enough LLIs to cope we restrict
 * the maximum number of sectors, and assume a worst case of one
 * LLI per sector.
 */
#define STM_MAX_SECTORS ATA_MAX_SECTORS
#define STM_MAX_LLIS	ATA_MAX_SECTORS
#define STM_LLI_BYTES	(STM_MAX_LLIS * sizeof(struct stm_lli))

static void stm_phy_configure(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	struct stm_host_priv *hpriv = ap->host->private_data;

DPRINTK("ENTER\n");

	/*
	 * "sata1hostc Functional Specification" 1.4 defines the PHYCR as:
	 * phy_ctrl[0]     sendalign
	 * phy_ctrl[1]     at
	 * phy_ctrl[4:2]   divdll[2:0]
	 * phy_ctrl[6:5]   txslew[1:0]
	 * phy_ctrl[8:7]   preemph[1:0]
	 * phy_ctrl[10:9]  sdthres[1:0]
	 * phy_ctrl[13:11] swing[2:0]
	 * phy_ctrl[14]    recen
	 * phy_ctrl[15]    ensigdet
	 * phy_ctrl[16]    enasyncdetneg
	 * phy_ctrl[17]    enasyncdetpos
	 * phy_ctrl[18]    startcomzc
	 * phy_ctrl[19]    startcomsr
	 * phy_ctrl[24:20] iddqsub[4:0]
	 * phy_ctrl[31:25] NOT DEFINED
	 */
	if (hpriv->phy_init) {
		writel(hpriv->phy_init, mmio + SATA_PHYCR);
		mdelay(100);
	}
}

/*
 * We have two problems with the interface between the SATA and DMA
 * controllers:
 *  - it can only handle 32 bit quantities
 *  - when reading from the device, if the data returned by the device
 *    is short (ie less than the length programmed into the DMA engine),
 *    and the end of the data doesn't coincide with a DMA burst boundary,
 *    then the DMA will stall, and as a result the end of transfer
 *    interrupt will never be seen.
 */
static int stm_check_atapi_dma(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	struct stm_port_priv *pp = ap->private_data;
	u8 *scsicmd = qc->scsicmd->cmnd;

	/* Whitelist commands that may use DMA. */
	switch (scsicmd[0]) {
	case WRITE_12:
	case WRITE_10:
	case WRITE_6:
	case READ_12:
	case READ_10:
	case READ_6:
		/* All data is multiples of 2048 */
		pp->smallburst = 0;
		return 0;
	case 0xbe:	/* READ_CD */
		/* Data should be a multiple of four bytes */
		pp->smallburst = 1;
		return 0;
	}

	return 1;
}

static void stm_bmdma_setup(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	struct stm_port_priv *pp = ap->private_data;
	struct stm_host_priv *hpriv = ap->host->private_data;
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	u32 cfg0, cfg1;

	cfg0 =	DMA_CFG_CH_PRIOR_0		|
		DMA_CFG_HS_SEL_DST_HW		|
		DMA_CFG_HS_SEL_SRC_HW		|
		DMA_CFG_DST_HS_POL_HI		|
		DMA_CFG_SRC_HS_POL_HI		|
		DMA_CFG_MAX_ABRST_UNLIMITED;

	cfg1 =	DMA_CFG_1_FIFO_MODE		|
		DMA_CFG_1_SRC_PER_0		| /* Used on reads */
		DMA_CFG_1_DEST_PER_1;		  /* Used on writes */

	writel(cfg0, mmio + DMAC_CFG0_0);
	writel(cfg1, mmio + DMAC_CFG0_1);

	/* These reads also have the side effect of flushing any posted
	 * writes to the LLI's */
	writel(pp->lli->ctl0, mmio + DMAC_CTL0_0);
	writel(pp->lli->ctl1, mmio + DMAC_CTL0_1);

	if (hpriv->softsg) {
		/* Write the first node into the DMAC registers */
		writel(pp->lli->sar, mmio + DMAC_SAR0);
		writel(pp->lli->dar, mmio + DMAC_DAR0);

		/* Clear interrupt from the final SG node of the
		 * previous transfer */
		writel(1<<0, mmio + DMAC_CLEARTFR);

		/* If there are multiple nodes in the sg list, prepare
		 * to set up subsequent ones in the interrupt handler.
		 */
		if (pp->softsg_node != pp->softsg_end) {
			pp->softsg_node++;
			writel(1<<8 | 1<<0, mmio + DMAC_MASKTFR);
		}
	} else {
		writel(pp->lli_dma, mmio + DMAC_LLP0);
	}

	/* Set Rx and Tx FIFO threshholds to 16 DWORDS except if using
	 * small burst reads, when we set it to 1 DWORD.
	 * Note: this is reset by a COMRESET.
	 */
	if (pp->smallburst) {
		writel((0x1 << 16) | (0x10 << 0), mmio + SATA_DBTSR);
	} else {
		writel((0x10 << 16) | (0x10 << 0), mmio + SATA_DBTSR);
	}

	/* Enable DMA on the SATA host */
	writel(SATA_DMACR_TXCHEN | SATA_DMACR_RXCHEN,
	       mmio + SATA_DMACR);

DPRINTK("SAR %08lx, DAR %08lx, CTL0 %08lx CTL1 %08lx\n",
       readl(mmio + DMAC_SAR0),
       readl(mmio + DMAC_DAR0),
       readl(mmio + DMAC_CTL0_0),
       readl(mmio + DMAC_CTL0_1));
DPRINTK("CFG0 %08lx CFG1 %08lx\n",
       readl(mmio + DMAC_CFG0_0),
       readl(mmio + DMAC_CFG0_1));
DPRINTK("ChEnReg %08lx DmaCfgReg %08lx\n",
       readl(mmio + DMAC_ChEnReg),
       readl(mmio + DMAC_DmaCfgReg));

	/* issue r/w command */
	ap->ops->sff_exec_command(ap, &qc->tf);
}

static void stm_bmdma_start(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	void __iomem *mmio = ap->ioaddr.cmd_addr;

	DPRINTK("ENTER\n");

	/* Enable channel 0 */
	writel((1<<8) | (1<<0), mmio + DMAC_ChEnReg);
}

static void stm_bmdma_stop(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	void __iomem *mmio = ap->ioaddr.cmd_addr;

DPRINTK("ENTER\n");

	/*
	 * Chanel is automatically disabled on completion of DMA, however
	 * this also gets called from the timeout handler.
	 */

	/* Disable channel 0 */
	writel((1<<8) | (0<<0), mmio + DMAC_ChEnReg);

	/* Disable DMA on the SATA host */
	writel(0, mmio + SATA_DMACR);
}

static u8 stm_bmdma_status(struct ata_port *ap)
{
	/* We should be checking here whether the current interrupt
	 * was raised by this SATA host. Unfortuntaly we have no
	 * visibility of the controller's Interrupt Pending Flag (IPF).
	 */
	return ATA_DMA_INTR;
}

static void stm_fill_sg(struct ata_queued_cmd *qc)
{
	struct scatterlist *sg;
	struct ata_port *ap = qc->ap;
	struct stm_host_priv *hpriv = ap->host->private_data;
        struct stm_port_priv *pp = ap->private_data;
	unsigned int write = (qc->tf.flags & ATA_TFLAG_WRITE);
	unsigned int si, idx;
	u32 sar, dar, ctl0;
	u32 fis_offset;

	DPRINTK("ENTER\n");

	ctl0 = 	DMAC_CTL_DST_TR_WIDTH_32	|
		DMAC_CTL_SRC_TR_WIDTH_32	|
		DMAC_CTL_DINC_INC		|
		DMAC_CTL_SINC_INC;

	if (write) {
		/* memory (master1) to SATA host (master2) transfer */
		ctl0 |= DMAC_CTL_DEST_MSIZE_4		|
			DMAC_CTL_SRC_MSIZE_16		|
			DMAC_CTL_TT_FC_M2P_DMAC		|
			DMAC_CTL_DMS_2			|
			DMAC_CTL_SMS_1;
	} else {
		/* SATA host (master2) to memory (master1) transfer */
		ctl0 |= DMAC_CTL_DEST_MSIZE_16		|
			(pp->smallburst ?
				DMAC_CTL_SRC_MSIZE_1 :
				DMAC_CTL_SRC_MSIZE_16)	|
			DMAC_CTL_TT_FC_P2M_DMAC		|
			DMAC_CTL_DMS_1			|
			DMAC_CTL_SMS_2;
	}

	if (! hpriv->softsg) {
		ctl0 |= DMAC_CTL_LLP_DST_EN	|
			DMAC_CTL_LLP_SRC_EN;
	}

	idx = 0;
	sar = dar = 0;
	fis_offset = 0;
	for_each_sg(qc->sg, sg, qc->n_elem, si) {
		u32 addr;
		u32 sg_len, len;

		addr = sg_dma_address(sg);
		sg_len = sg_dma_len(sg);

		WARN_ON(sg_len & 3);

		while (sg_len) {
			/* Ensure no DMA block crosses a FIS boundary */
			len = sg_len;
			if (len + fis_offset > SATA_FIS_SIZE)
				len = SATA_FIS_SIZE - fis_offset;

			/* SATA host (master2) has a hardwired address of
			 * DMADR, so leave the address set to 0. */
			if (write) {
				sar = addr;
			} else {
				dar = addr;
			}

			pp->lli[idx].sar = sar;
			pp->lli[idx].dar = dar;
			pp->lli[idx].llp = pp->lli_dma +
				(sizeof(struct stm_lli) * (idx+1));
			pp->lli[idx].ctl0 = ctl0;
			pp->lli[idx].ctl1 = len >> 2;

			DPRINTK("lli: %p: SAR %08x, DAR %08x, CTL0 %08x CTL1 %08x\n",
				&pp->lli[idx],
				pp->lli[idx].sar, pp->lli[idx].dar,
				pp->lli[idx].ctl0, pp->lli[idx].ctl1);

			idx++;
			BUG_ON(idx >= STM_MAX_LLIS);
			sg_len -= len;
			addr += len;
			fis_offset = (fis_offset + len) % SATA_FIS_SIZE;
		}
	}

	WARN_ON(idx == 0);
	pp->lli[idx-1].llp = 0;

	if (hpriv->softsg) {
		pp->softsg_node = pp->lli;
		pp->softsg_end  = &pp->lli[idx-1];
	}

}

static void stm_pmp_select(struct ata_port *ap, int pmp)
{
        if (sata_pmp_supported(ap)) {
		struct stm_port_priv *pp = ap->private_data;

		if (pp->pmp != pmp) {
			u32 scontrol;

			stm_sata_scr_read(&ap->link, SCR_CONTROL, &scontrol);
			pp->pmp = pmp;
			stm_sata_scr_write(&ap->link, SCR_CONTROL,
					   (scontrol & 0xff0));
		}
	}
}

static void stm_qc_prep(struct ata_queued_cmd *qc)
{
	struct stm_port_priv *pp = qc->ap->private_data;

	stm_pmp_select(qc->ap, qc->dev->link->pmp & 0xf);
	pp->active_link = qc->dev->link;

	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
		return;

	stm_fill_sg(qc);
}

static unsigned int stm_data_xfer(struct ata_device *adev, unsigned char *buf,
				  unsigned int buflen, int rw)
{
	struct ata_port *ap = adev->link->ap;
	unsigned int i;
	unsigned int words = buflen >> 1;
	u16 *buf16 = (u16 *) buf;
	void __iomem *mmio_base = (void __iomem *) ap->ioaddr.cmd_addr;
	void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;

	/* Disable error reporting */
	writel(~SERROR_ERR_E, mmio_base + SATA_ERRMR);

	/* Transfer multiple of 2 bytes */
	if (rw == WRITE) {
		for (i = 0; i < words; i++) {
			writew(le16_to_cpu(buf16[i]), mmio);
			ndelay(120);
		}
	} else {
		for (i = 0; i < words; i++) {
			buf16[i] = cpu_to_le16(readw(mmio));
			ndelay(120);
		}
	}

	/* Transfer trailing 1 byte, if any. */
	if (unlikely(buflen & 0x01)) {
		u16 align_buf[1] = { 0 };
		unsigned char *trailing_buf = buf + buflen - 1;

		if (rw == WRITE) {
			memcpy(align_buf, trailing_buf, 1);
			writew(le16_to_cpu(align_buf[0]), mmio);
		} else {
			align_buf[0] = cpu_to_le16(readw(mmio));
			memcpy(trailing_buf, align_buf, 1);
		}
		words++;
	}

	/* Clear any errors and re-enable error reporting */
	writel(-1, mmio_base + SATA_SCR1);
	writel(0xffffffff, mmio_base + SATA_ERRMR);

	return words << 1;
}

static void stm_freeze(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr;

	DPRINTK("ENTER\n");

	/* Disable interrupts */
	writel(0, mmio + SATA_INTMR);
	readl(mmio + SATA_INTMR);	/* flush */
	ata_sff_freeze(ap);
}

static void stm_thaw(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr;

	DPRINTK("ENTER\n");

	/* Reenable interrupts */
	writel(SATA_INT_ERR, mmio + SATA_INTMR);
	ata_sff_thaw(ap);
}

static int stm_prereset(struct ata_link *link, unsigned long deadline)
{
	struct ata_port *ap = link->ap;
	u32 serror;
	struct stm_host_priv *hpriv = ap->host->private_data;
	struct stm_miphy *miphy_dev = hpriv->miphy_dev;
	u8 miphy_int_status = stm_miphy_sata_status(miphy_dev);

	DPRINTK("ENTER\n");
	stm_sata_scr_read(&ap->link, SCR_ERROR, &serror);

	/*
	 * Defect RnDHV00030463 and STLinux Bugzilla 9770.
	 * Try and detect an ESD event which is resolved by
	 * a reset of both the host and the phy.
	 */
	if (hpriv->host_restart && ((serror & SERROR_ERR_C) ||
		miphy_int_status)) {
		hpriv->host_restart(hpriv->port_num);
		stm_miphy_start(miphy_dev);
	}

	stm_phy_configure(ap);
	return ata_sff_prereset(link, deadline);
}


/*
 * Workaround for drive detection problems (STLinux bugzilla 9873).
 * Need to keep the MiPHY deserializer reset while performing the
 * COMMRESET and wait till COMMWAIT is received from device.
 */
static int stm_sata_do_comreset(void __iomem *mmio_base,
	struct stm_host_priv *hpriv)
{
	/* Make sure that PHY is up */
	int timeout, val, rval = 0;
	struct stm_miphy *miphy_dev = hpriv->miphy_dev;

	/* OOB-6a certification test workaround */
	/* Refer to RnDHV00020989/RnDHV00032380 for more information */
	if (hpriv->oob_wa) {
		writel(readl(mmio_base + SATA_OOBR) | 0x80000000,
			mmio_base + SATA_OOBR);

		writel(readl(mmio_base + SATA_OOBR) & 0x82FFFFFF,
			mmio_base + SATA_OOBR);
	}

	val = readl(mmio_base + SATA_SCR1);
	/* clearing the SATA_SCR1 register */
	writel(val, (mmio_base + SATA_SCR1));

	/* Assert MiPHY deserializer reset */
	stm_miphy_assert_deserializer(miphy_dev, 1);

	/* Send COMMRESET */
	writel(0x1, (mmio_base + SATA_SCR2));
	msleep(1);
	writel(0x0, (mmio_base + SATA_SCR2));

	/* wait a while before checking status*/
	msleep(150);
	/* Wait Till COMWAKE Detected */
	timeout = 100;
	while (timeout-- &&
		((readl(mmio_base + SATA_SCR1) & 0x40000) != 0x40000))
		msleep(1);

	/* Deassert MiPHY deserializer reset */
	stm_miphy_assert_deserializer(miphy_dev, 0);
	if (timeout <= 0) {
		rval = -1;
		goto err;
	}

	timeout = 100;
	/* Waiting for PHYRDY to be detected by Host */
	while (timeout-- && ((readl(mmio_base + SATA_SCR0) & 0x03) != 0x03))
		msleep(1);

	if (timeout <= 0)
		rval = -1;

err:
	if (hpriv->oob_wa)
		writel(readl(mmio_base + SATA_OOBR) & 0x7FFFFFFF,
			mmio_base + SATA_OOBR);


	return rval;
}

static int stm_sata_hardreset(struct ata_link *link, unsigned int *class,
			unsigned long deadline)
{
	struct ata_port *ap = link->ap;
	void __iomem *mmio_base = ap->ioaddr.cmd_addr;
	struct stm_host_priv *hpriv = ap->host->private_data;
	/* Debounce timing */
	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
	u32 rc;

	/* Check if device is detected */
	if (readl(mmio_base + SATA_SCR0) == 0x0)
		return 0; /* No device detected */

	stm_phy_configure(ap);

	if (stm_sata_do_comreset(mmio_base, hpriv))
		return 0; /* Link Offline */

	/* resume with Debounce */
	rc = sata_link_resume(link, timing, deadline);
	if (rc) {
		ata_link_printk(link, KERN_WARNING, "failed to resume "
					"link after reset (errno=%d)\n", rc);
		return rc;
	}
	if (ata_link_offline(link))
		return 0;

	return -EAGAIN;
}

static void stm_postreset(struct ata_link *link, unsigned int *classes)
{
	struct ata_port *ap = link->ap;
	void __iomem *mmio = ap->ioaddr.cmd_addr;

	DPRINTK("ENTER\n");

	/* Enable notification of errors. These are reset by COMRESET. */
	writel(0xffffffff, mmio + SATA_ERRMR);
	writel(SATA_INT_ERR, mmio + SATA_INTMR);

	ata_std_postreset(link, classes);
}

static int stm_pmp_hardreset(struct ata_link *link, unsigned int *class,
			     unsigned long deadline)
{
	DPRINTK("ENTER\n");

	stm_pmp_select(link->ap, sata_srst_pmp(link));
	return sata_std_hardreset(link, class, deadline);
}

static int stm_softreset(struct ata_link *link, unsigned int *class,
			 unsigned long deadline)
{
	DPRINTK("ENTER\n");

	stm_pmp_select(link->ap, sata_srst_pmp(link));
	return ata_sff_softreset(link, class, deadline);
}

static void stm_dev_config(struct ata_device *adev)
{
	struct ata_port *ap = adev->link->ap;
	int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;

	if (adev->max_sectors > STM_MAX_SECTORS) {
		if (print_info)
			ata_dev_printk(adev, KERN_INFO,
				       "restricting to %d max sectors\n",
				       STM_MAX_SECTORS);
		adev->max_sectors = STM_MAX_SECTORS;
	}
}

/* This needs munging to give per controller stats */
static unsigned long error_count;
static unsigned int print_error=1;

static unsigned stm_sata_dma_irq(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	struct stm_port_priv *pp = ap->private_data;
	int handled = 1;

	if (readl(mmio + DMAC_STATUSTFR) & 1) {
		/* DMA Transfer complete update soft S/G */

		/* Ack the interrupt */
		writel(1<<0, mmio + DMAC_CLEARTFR);

		DPRINTK("softsg_node %p, end %p\n",
			pp->softsg_node, pp->softsg_end);

		writel(pp->softsg_node->sar, mmio + DMAC_SAR0);
		writel(pp->softsg_node->dar, mmio + DMAC_DAR0);

		writel(pp->softsg_node->ctl0, mmio + DMAC_CTL0_0);
		writel(pp->softsg_node->ctl1, mmio + DMAC_CTL0_1);

		if (pp->softsg_node != pp->softsg_end) {
			pp->softsg_node++;
		} else {
			writel(1<<8 | 0<<0, mmio + DMAC_MASKTFR);
		}

		writel((1<<8) | (1<<0), mmio + DMAC_ChEnReg);
	} else if (readl(mmio + DMAC_RAWERR) & 1) {
		ata_port_printk(ap, KERN_ERR, "DMA error asserted\n");
	}

	return handled;

}

static unsigned stm_sata_host_irq(struct ata_port *ap)
{
	unsigned int handled = 0;
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	struct ata_eh_info *ehi = &ap->link.eh_info;
	u32 sstatus, serror;

	if (readl(mmio + SATA_INTPR) & (SATA_INT_ERR)) {

		stm_sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
		stm_sata_scr_read(&ap->link, SCR_ERROR, &serror);
		stm_sata_scr_write(&ap->link, SCR_ERROR, serror);

		if (print_error)
			ata_port_printk(ap, KERN_ERR,
					"SStatus 0x%08x, SError 0x%08x\n",
					sstatus, serror);
		error_count++;

		ata_ehi_clear_desc(ehi);
		ata_ehi_push_desc(ehi, "SStatus 0x%08x, SError 0x%08x",
				  sstatus, serror);
		ehi->serror |= serror;

		if (serror & (SERROR_DIAG_N | SERROR_DIAG_X)) {
			ata_ehi_hotplugged(ehi);
			ata_ehi_push_desc(ehi, "Treating as hot-%splug",
					  serror & SERROR_DIAG_X ? "" : "un");
		}

		ata_port_freeze(ap);
		handled = 1;
	} else
		if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
			struct ata_queued_cmd *qc;
			struct stm_port_priv *pp = ap->private_data;

			qc = ata_qc_from_tag(ap, pp->active_link->active_tag);
			/*
			 * ata_qc_issue sets qc->dev->link.active_tag
			 * rather than ap->link.active_tag.  This
			 * means for PMP the host link doesn't have
			 * the tag set.
			 */
			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
				handled += ata_sff_host_intr(ap, qc);
		}

	return handled;
}

static irqreturn_t stm_sata_dma_interrupt(int irq, void *dev_instance)
{
	struct ata_host *host = dev_instance;
	unsigned int handled = 0;
	unsigned int i;
	struct stm_host_priv *hpriv = host->private_data;

	BUG_ON(hpriv->shared_dma_host_irq);

	spin_lock(&host->lock);

	for (i = 0; i < host->n_ports; i++)
		handled += stm_sata_dma_irq(host->ports[i]);

	spin_unlock(&host->lock);

	return IRQ_RETVAL(handled);
}

static irqreturn_t stm_sata_interrupt(int irq, void *dev_instance)
{
	struct ata_host *host = dev_instance;
	unsigned int handled = 0;
	unsigned int i;
	struct stm_host_priv *hpriv = host->private_data;

DPRINTK("ENTER\n");

	spin_lock(&host->lock);

	for (i = 0; i < host->n_ports; i++) {
		if (hpriv->shared_dma_host_irq)
			handled += stm_sata_dma_irq(host->ports[i]);
		handled += stm_sata_host_irq(host->ports[i]);
	}

	spin_unlock(&host->lock);

	return IRQ_RETVAL(handled);
}

static void stm_irq_clear(struct ata_port *ap)
{
	/* TODO */
}

static int stm_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
	void __iomem *mmio = link->ap->ioaddr.cmd_addr;

	if (sc_reg > SCR_CONTROL) return -EINVAL;

	*val = readl(mmio + SATA_SCR0 + (sc_reg * 4));
	return 0;
}

static int stm_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
	void __iomem *mmio = link->ap->ioaddr.cmd_addr;

DPRINTK("%d = %08x\n", sc_reg, val);
	if (sc_reg > SCR_CONTROL) return -EINVAL;

	if (sc_reg == SCR_CONTROL) {
		struct stm_port_priv *pp = link->ap->private_data;

		val &= ~(0xf << 16);
		val |= pp->pmp << 16;
	}

	writel(val, mmio + SATA_SCR0 + (sc_reg * 4));
	return 0;
}

static int stm_port_start (struct ata_port *ap)
{
	struct device *dev = ap->host->dev;
	struct stm_host_priv *hpriv = ap->host->private_data;
	struct stm_port_priv *pp;

	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
	if (pp == NULL)
		return -ENOMEM;

	if (hpriv->softsg) {
		pp->lli = devm_kzalloc(dev, STM_LLI_BYTES, GFP_KERNEL);
	} else {
		pp->lli = dmam_alloc_coherent(dev, STM_LLI_BYTES, &pp->lli_dma,
					      GFP_KERNEL);
	}

	if (pp->lli == NULL)
		return -ENOMEM;

	pp->smallburst = 0;

	ap->private_data = pp;

	return 0;
}

static ssize_t stm_show_serror(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	ssize_t len;

	len = snprintf(buf, PAGE_SIZE, "%ld\n", error_count);
	return len;
}

static ssize_t stm_store_serror(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	error_count = simple_strtoul(buf, NULL, 10);
	return count;
}

static DEVICE_ATTR(serror, S_IRUGO | S_IWUGO,
		   stm_show_serror, stm_store_serror);

static ssize_t stm_show_printerror(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	ssize_t len;

	len = snprintf(buf, PAGE_SIZE, "%d\n", print_error);
	return len;
}

static ssize_t stm_store_printerror(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	print_error = simple_strtoul(buf, NULL, 10);
	return count;
}

static DEVICE_ATTR(printerror, S_IRUGO | S_IWUGO,
		   stm_show_printerror, stm_store_printerror);

/* Host attributes initializer */
static struct device_attribute *stm_host_attrs[] = {
	&dev_attr_serror,
	&dev_attr_printerror,
	NULL,
};

static struct scsi_host_template stm_sht = {
	ATA_BMDMA_SHT(DRV_NAME),
	.max_sectors		= STM_MAX_SECTORS,
	.shost_attrs		= stm_host_attrs,
};

static struct ata_port_operations stm_ops = {
	.inherits		= &ata_sff_port_ops,

	.check_atapi_dma	= stm_check_atapi_dma,
	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
	.qc_prep		= stm_qc_prep,

	.dev_config		= stm_dev_config,

	.freeze			= stm_freeze,
	.thaw			= stm_thaw,
	.prereset		= stm_prereset,
	.postreset		= stm_postreset,

	.pmp_hardreset		= stm_pmp_hardreset,
	.pmp_softreset		= stm_softreset,
	.softreset		= stm_softreset,
	.hardreset		= stm_sata_hardreset,
	.error_handler		= sata_pmp_error_handler,

	.scr_read		= stm_sata_scr_read,
	.scr_write		= stm_sata_scr_write,

	.port_start		= stm_port_start,

	.sff_data_xfer		= stm_data_xfer,
	.sff_irq_clear		= stm_irq_clear,

	.bmdma_setup		= stm_bmdma_setup,
	.bmdma_start		= stm_bmdma_start,
	.bmdma_stop		= stm_bmdma_stop,
	.bmdma_status		= stm_bmdma_status,
};

static const struct ata_port_info stm_port_info = {
	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
			  ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET | ATA_FLAG_PMP,
	.pio_mask	= 0x1f, /* pio0-4 */
	.mwdma_mask	= 0x07, /* mwdma0-2 */
	.udma_mask	= ATA_UDMA6,
	.port_ops	= &stm_ops,
};

static int stm_sata_AHB_boot(struct device *dev)
{
	struct stm_plat_sata_data *sata_private_info = dev->platform_data;
	struct ata_host *host = dev_get_drvdata(dev);
	struct ata_port *ap = host->ports[0];
	void __iomem *mmio_base = ap->ioaddr.cmd_addr;

	/* AHB bus wrapper setup */

	/* SATA_AHB2STBUS_STBUS_OPC
	 * 2:0  -- 100 = Store64/Load64
	 * 4    -- 1   = Enable write posting
	 * DMA Read, write posting always = 0
	 * opcode = Load4 |Store 4
	 */
	writel(3, mmio_base + SATA_AHB2STBUS_STBUS_OPC);

	/* SATA_AHB2STBUS_MESSAGE_SIZE_CONFIG
	 * 3:0  -- 0111 = 128 Packets
	 * 3:0  -- 0110 =  64 Packets
	 * WAS: Message size = 64 packet when 6 now 3
	 */
	writel(3, mmio_base + SATA_AHB2STBUS_MESSAGE_SIZE_CONFIG);

	/* SATA_AHB2STBUS_CHUNK_SIZE_CONFIG
	 * 3:0  -- 0110 = 64 Packets
	 * 3:0  -- 0001 =  2 Packets
	 * WAS Chunk size = 2 packet when 1, now 0
	 */
	writel(2, mmio_base + SATA_AHB2STBUS_CHUNK_SIZE_CONFIG);

	/* PC_GLUE_LOGIC
	 * 7:0  -- 0xFF = Set as reset value, 256 STBus Clock Cycles
	 * 8    -- 1  = Time out enabled
	 * (has bit 8 moved to bit 16 on 7109 cut2?)
	 * time out count = 0xa0(160 dec)
	 * time out enable = 1
	 */
	if (sata_private_info->pc_glue_logic_init)
		writel(sata_private_info->pc_glue_logic_init,
		       mmio_base + SATA_PC_GLUE_LOGIC);

	/* DMA controller set up */

	/* Enable DMA controller */
	writel(DMAC_DmaCfgReg_DMA_EN, mmio_base + DMAC_DmaCfgReg);

	/* Clear initial Serror */
	writel(-1, mmio_base + SATA_SCR1);

	/* Finished hardware set up */
	return 0;
}

static int __devinit stm_sata_probe(struct platform_device *pdev)
{
	struct stm_plat_sata_data *sata_private_info = pdev->dev.platform_data;
	struct device *dev = &pdev->dev;
	struct resource *mem_res;
	unsigned long phys_base, phys_size;
	void __iomem *mmio_base;
	const struct ata_port_info *ppi[] = { &stm_port_info, NULL };
	struct ata_host *host;
	struct ata_port *ap;
	struct stm_host_priv *hpriv = NULL;
	unsigned long sata_rev, dmac_rev;
	int dma_irq;
	int ret;


	printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");

	host = ata_host_alloc_pinfo(dev, ppi, 1);
	if (!host)
		return -ENOMEM;

	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
	if (!hpriv)
		return -ENOMEM;

        host->private_data = hpriv;

	hpriv->device_state = devm_stm_device_init(dev,
		sata_private_info->device_config);
	if (!hpriv->device_state)
		return -EBUSY;

	mem_res = platform_get_resource(pdev,IORESOURCE_MEM,0);
	phys_base = mem_res->start;
	phys_size = mem_res->end - mem_res->start + 1;

	if (!devm_request_mem_region(dev, phys_base, phys_size, "STM SATA"))
		return -EBUSY;

	mmio_base = devm_ioremap(dev, phys_base, phys_size);
	if (mmio_base == NULL)
		return ENOMEM;

	/* Set up the ports */
	ap = host->ports[0];
	ap->ioaddr.cmd_addr		= mmio_base;
	ap->ioaddr.data_addr		= mmio_base + SATA_CDR0;
	ap->ioaddr.error_addr		= mmio_base + SATA_CDR1;
	ap->ioaddr.feature_addr		= mmio_base + SATA_CDR1;
	ap->ioaddr.nsect_addr		= mmio_base + SATA_CDR2;
	ap->ioaddr.lbal_addr		= mmio_base + SATA_CDR3;
	ap->ioaddr.lbam_addr		= mmio_base + SATA_CDR4;
	ap->ioaddr.lbah_addr		= mmio_base + SATA_CDR5;
	ap->ioaddr.device_addr		= mmio_base + SATA_CDR6;
	ap->ioaddr.status_addr		= mmio_base + SATA_CDR7;
	ap->ioaddr.command_addr		= mmio_base + SATA_CDR7;

	ap->ioaddr.altstatus_addr	= mmio_base + SATA_CLR0;
	ap->ioaddr.ctl_addr		= mmio_base + SATA_CLR0;

	hpriv->phy_init = sata_private_info->phy_init;
	hpriv->oob_wa = sata_private_info->oob_wa;
	hpriv->host_restart = sata_private_info->host_restart;
	hpriv->port_num = sata_private_info->port_num;
	hpriv->softsg = readl(mmio_base + DMAC_COMP_PARAMS_2) &
		DMAC_COMP_PARAMS_2_CH0_HC_LLP;
	//hpriv->softsg = 1;

	printk(KERN_DEBUG DRV_NAME " using %sware scatter/gather\n",
	       hpriv->softsg ? "soft" : "hard");

	if (sata_private_info->only_32bit) {
		printk(KERN_ERR DRV_NAME " hardware doesn't support "
			"byte/long ops, giving up\n");
		return -EINVAL;
	}

	sata_rev = readl(mmio_base + SATA_VERSIONR);
	dmac_rev = readl(mmio_base + DMAC_COMP_VERSION);
	printk(KERN_DEBUG DRV_NAME " SATA version %c.%c%c DMA version %c.%c%c\n",
	       (int)(sata_rev >> 24) & 0xff,
	       (int)(sata_rev >> 16) & 0xff,
	       (int)(sata_rev >>  8) & 0xff,
	       (int)(dmac_rev >> 24) & 0xff,
	       (int)(dmac_rev >> 16) & 0xff,
	       (int)(dmac_rev >>  8) & 0xff);

	hpriv->miphy_dev = stm_miphy_claim(sata_private_info->miphy_num,
			SATA_MODE, dev);
	if (!hpriv->miphy_dev) {
		printk(KERN_ERR DRV_NAME " Unable to claim MiPHY %d\n",
			sata_private_info->miphy_num);
		return -EBUSY;
	}

	stm_sata_AHB_boot(dev);

	/* Wait & timeout till we detect the disk */
	stm_sata_do_comreset(mmio_base, hpriv);

	/* Now, are we on one of the later SATA IP's, we have the DMA and
	 * host controller interrupt lines separated out. So if we have two
	 * irq resources, then it is one of these
	 */

	dma_irq = platform_get_irq(pdev, 1);
	if (dma_irq > 0) {
		/* We have two interrupts */
		if (devm_request_irq(host->dev, dma_irq, stm_sata_dma_interrupt,
				     0, dev_driver_string(host->dev), host) < 0)
			panic("Cannot register SATA dma interrupt %d\n",
			      dma_irq);
		hpriv->shared_dma_host_irq = 0;
	} else {
		hpriv->shared_dma_host_irq = 1;
	}

	ret = ata_host_activate(host, platform_get_irq(pdev, 0),
				stm_sata_interrupt,
				IRQF_SHARED, &stm_sht);

	if (ret && dma_irq > 0)
		devm_free_irq(host->dev, dma_irq, host);
	else {
		/* by default the device is on */
		pm_runtime_set_active(&pdev->dev);
		pm_suspend_ignore_children(&pdev->dev, 1);
		pm_runtime_enable(&pdev->dev);
	}

	return ret;

}

static int stm_sata_remove(struct platform_device *pdev)
{
	struct ata_host *host = dev_get_drvdata(&pdev->dev);
	struct stm_host_priv *hpriv = host->private_data;

	stm_miphy_release(hpriv->miphy_dev);
	stm_device_power(hpriv->device_state,  stm_device_power_off);

	return 0;
}

#ifdef CONFIG_PM
static int stm_sata_suspend(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;

#ifdef CONFIG_PM_RUNTIME
	if (dev->power.runtime_status != RPM_ACTIVE)
		return 0; /* sata already suspended via runtime_suspend */
#endif

	stm_device_power(hpriv->device_state,  stm_device_power_off);

	return 0;
}

static int stm_sata_resume(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;

#ifdef CONFIG_PM_RUNTIME
	if (dev->power.runtime_status == RPM_SUSPENDED)
		return 0; /* sata wants resume via runtime_resume... */
#endif

	stm_device_power(hpriv->device_state, stm_device_power_on);

	return 0;
}

static int stm_sata_freeze(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;

#ifdef CONFIG_PM_RUNTIME
	if (dev->power.runtime_status != RPM_ACTIVE)
		return 0; /* sata already suspended via runtime_suspend */
#endif

	stm_device_power(hpriv->device_state,  stm_device_power_off);
	stm_miphy_freeze(hpriv->miphy_dev);

	return 0;
}

static int stm_sata_restore(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;
	struct ata_port *port;
	struct Scsi_Host *scsi_host;
	unsigned int nr_port, id, lun, channel;

#ifdef CONFIG_PM_RUNTIME
	if (dev->power.runtime_status == RPM_SUSPENDED)
		return 0; /* sata wants resume via runtime_resume... */
#endif

	stm_device_power(hpriv->device_state, stm_device_power_on);

	stm_sata_AHB_boot(dev);

	for (nr_port = 0; nr_port < host->n_ports; ++nr_port) {
		port = host->ports[nr_port];
		scsi_host = port->scsi_host;

		for (id = 0; id < scsi_host->max_id; ++id)
			for (lun = 0; lun < scsi_host->max_lun; ++lun)
				for (channel = 0;
				     channel < scsi_host->max_channel;
				     ++channel)
					scsi_host->transportt->user_scan(
						scsi_host, channel, id, lun);
	}
	return 0;
}

static int stm_sata_thaw(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;

	stm_miphy_thaw(hpriv->miphy_dev);
	stm_device_power(hpriv->device_state, stm_device_power_on);

	return 0;
}

#ifdef CONFIG_PM_RUNTIME
static int stm_sata_runtime_suspend(struct device *dev)
{
	struct ata_host *host = dev_get_drvdata(dev);
	struct stm_host_priv *hpriv = host->private_data;
	unsigned int nr_port;

	if (dev->power.runtime_status == RPM_SUSPENDED) {
		pr_debug("%s already suspended\n", dev_name(dev));
		return 0;
	}

	for (nr_port = 0; nr_port < host->n_ports; ++nr_port) {
		struct ata_port *port = host->ports[nr_port];
		struct Scsi_Host *scsi_host = port->scsi_host;
		struct scsi_device *sdev, *next_sdev;

		list_for_each_entry_safe(sdev, next_sdev,
			&scsi_host->__devices, siblings)
			/* suspend all the child devices */
			scsi_remove_device(sdev);
	}

	stm_device_power(hpriv->device_state,  stm_device_power_off);
	return 0;
}

static int stm_sata_runtime_resume(struct device *dev)
{
	if (dev->power.runtime_status == RPM_ACTIVE) {
		pr_debug("%s already active\n", dev_name(dev));
		return 0;
	}

	return stm_sata_restore(dev);
}
#else
#define stm_sata_runtime_suspend	NULL
#define stm_sata_runtime_resume		NULL
#endif

static struct dev_pm_ops stm_sata_pm = {
	.suspend = stm_sata_suspend,  /* on standby/memstandby */
	.resume = stm_sata_resume,    /* resume from standby/memstandby */
	.freeze = stm_sata_freeze,
	.thaw = stm_sata_thaw,
	.restore = stm_sata_restore,
	.runtime_suspend = stm_sata_runtime_suspend,
	.runtime_resume = stm_sata_runtime_resume,
};
#else
static struct dev_pm_ops stm_sata_pm;
#endif

static struct platform_driver stm_sata_driver = {
	.driver = {
		.name = DRV_NAME,
		.owner = THIS_MODULE,
		.pm = &stm_sata_pm,
	},
	.probe = stm_sata_probe,
	.remove = stm_sata_remove,
};

static int __init stm_sata_init(void)
{
	return platform_driver_register(&stm_sata_driver);
}

static void __exit stm_sata_exit(void)
{
	platform_driver_unregister(&stm_sata_driver);
}

module_init(stm_sata_init);
module_exit(stm_sata_exit);

MODULE_AUTHOR("Stuart Menefy");
MODULE_DESCRIPTION("low-level driver for STMicroelectronics SATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);