xref: /openbmc/linux/drivers/ata/sata_mv.c (revision d9f9c6bc91c14f53ffa782ffcd42259ecae1d38c)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  * sata_mv.c - Marvell SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  * Copyright 2005: EMC Corporation, all rights reserved.
5c6fd2807SJeff Garzik  * Copyright 2005 Red Hat, Inc.  All rights reserved.
6c6fd2807SJeff Garzik  *
7c6fd2807SJeff Garzik  * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
8c6fd2807SJeff Garzik  *
9c6fd2807SJeff Garzik  * This program is free software; you can redistribute it and/or modify
10c6fd2807SJeff Garzik  * it under the terms of the GNU General Public License as published by
11c6fd2807SJeff Garzik  * the Free Software Foundation; version 2 of the License.
12c6fd2807SJeff Garzik  *
13c6fd2807SJeff Garzik  * This program is distributed in the hope that it will be useful,
14c6fd2807SJeff Garzik  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c6fd2807SJeff Garzik  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16c6fd2807SJeff Garzik  * GNU General Public License for more details.
17c6fd2807SJeff Garzik  *
18c6fd2807SJeff Garzik  * You should have received a copy of the GNU General Public License
19c6fd2807SJeff Garzik  * along with this program; if not, write to the Free Software
20c6fd2807SJeff Garzik  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21c6fd2807SJeff Garzik  *
22c6fd2807SJeff Garzik  */
23c6fd2807SJeff Garzik 
244a05e209SJeff Garzik /*
254a05e209SJeff Garzik   sata_mv TODO list:
264a05e209SJeff Garzik 
274a05e209SJeff Garzik   1) Needs a full errata audit for all chipsets.  I implemented most
284a05e209SJeff Garzik   of the errata workarounds found in the Marvell vendor driver, but
294a05e209SJeff Garzik   I distinctly remember a couple workarounds (one related to PCI-X)
304a05e209SJeff Garzik   are still needed.
314a05e209SJeff Garzik 
324a05e209SJeff Garzik   2) Convert to LibATA new EH.  Required for hotplug, NCQ, and sane
334a05e209SJeff Garzik   probing/error handling in general.  MUST HAVE.
344a05e209SJeff Garzik 
354a05e209SJeff Garzik   3) Add hotplug support (easy, once new-EH support appears)
364a05e209SJeff Garzik 
374a05e209SJeff Garzik   4) Add NCQ support (easy to intermediate, once new-EH support appears)
384a05e209SJeff Garzik 
394a05e209SJeff Garzik   5) Investigate problems with PCI Message Signalled Interrupts (MSI).
404a05e209SJeff Garzik 
414a05e209SJeff Garzik   6) Add port multiplier support (intermediate)
424a05e209SJeff Garzik 
434a05e209SJeff Garzik   7) Test and verify 3.0 Gbps support
444a05e209SJeff Garzik 
454a05e209SJeff Garzik   8) Develop a low-power-consumption strategy, and implement it.
464a05e209SJeff Garzik 
474a05e209SJeff Garzik   9) [Experiment, low priority] See if ATAPI can be supported using
484a05e209SJeff Garzik   "unknown FIS" or "vendor-specific FIS" support, or something creative
494a05e209SJeff Garzik   like that.
504a05e209SJeff Garzik 
514a05e209SJeff Garzik   10) [Experiment, low priority] Investigate interrupt coalescing.
524a05e209SJeff Garzik   Quite often, especially with PCI Message Signalled Interrupts (MSI),
534a05e209SJeff Garzik   the overhead reduced by interrupt mitigation is quite often not
544a05e209SJeff Garzik   worth the latency cost.
554a05e209SJeff Garzik 
564a05e209SJeff Garzik   11) [Experiment, Marvell value added] Is it possible to use target
574a05e209SJeff Garzik   mode to cross-connect two Linux boxes with Marvell cards?  If so,
584a05e209SJeff Garzik   creating LibATA target mode support would be very interesting.
594a05e209SJeff Garzik 
604a05e209SJeff Garzik   Target mode, for those without docs, is the ability to directly
614a05e209SJeff Garzik   connect two SATA controllers.
624a05e209SJeff Garzik 
634a05e209SJeff Garzik   13) Verify that 7042 is fully supported.  I only have a 6042.
644a05e209SJeff Garzik 
654a05e209SJeff Garzik */
664a05e209SJeff Garzik 
674a05e209SJeff Garzik 
68c6fd2807SJeff Garzik #include <linux/kernel.h>
69c6fd2807SJeff Garzik #include <linux/module.h>
70c6fd2807SJeff Garzik #include <linux/pci.h>
71c6fd2807SJeff Garzik #include <linux/init.h>
72c6fd2807SJeff Garzik #include <linux/blkdev.h>
73c6fd2807SJeff Garzik #include <linux/delay.h>
74c6fd2807SJeff Garzik #include <linux/interrupt.h>
75c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
76c6fd2807SJeff Garzik #include <linux/device.h>
77c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
78c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
79c6fd2807SJeff Garzik #include <linux/libata.h>
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik #define DRV_NAME	"sata_mv"
828bc3fc47SJeff Garzik #define DRV_VERSION	"0.81"
83c6fd2807SJeff Garzik 
84c6fd2807SJeff Garzik enum {
85c6fd2807SJeff Garzik 	/* BAR's are enumerated in terms of pci_resource_start() terms */
86c6fd2807SJeff Garzik 	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */
87c6fd2807SJeff Garzik 	MV_IO_BAR		= 2,	/* offset 0x18: IO space */
88c6fd2807SJeff Garzik 	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */
89c6fd2807SJeff Garzik 
90c6fd2807SJeff Garzik 	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */
91c6fd2807SJeff Garzik 	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */
92c6fd2807SJeff Garzik 
93c6fd2807SJeff Garzik 	MV_PCI_REG_BASE		= 0,
94c6fd2807SJeff Garzik 	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
95c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
96c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
97c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
98c6fd2807SJeff Garzik 	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
99c6fd2807SJeff Garzik 	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
100c6fd2807SJeff Garzik 
101c6fd2807SJeff Garzik 	MV_SATAHC0_REG_BASE	= 0x20000,
102c6fd2807SJeff Garzik 	MV_FLASH_CTL		= 0x1046c,
103c6fd2807SJeff Garzik 	MV_GPIO_PORT_CTL	= 0x104f0,
104c6fd2807SJeff Garzik 	MV_RESET_CFG		= 0x180d8,
105c6fd2807SJeff Garzik 
106c6fd2807SJeff Garzik 	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,
107c6fd2807SJeff Garzik 	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,
108c6fd2807SJeff Garzik 	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
109c6fd2807SJeff Garzik 	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
110c6fd2807SJeff Garzik 
111c6fd2807SJeff Garzik 	MV_USE_Q_DEPTH		= ATA_DEF_QUEUE,
112c6fd2807SJeff Garzik 
113c6fd2807SJeff Garzik 	MV_MAX_Q_DEPTH		= 32,
114c6fd2807SJeff Garzik 	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
115c6fd2807SJeff Garzik 
116c6fd2807SJeff Garzik 	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
117c6fd2807SJeff Garzik 	 * CRPB needs alignment on a 256B boundary. Size == 256B
118c6fd2807SJeff Garzik 	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
119c6fd2807SJeff Garzik 	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
120c6fd2807SJeff Garzik 	 */
121c6fd2807SJeff Garzik 	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
122c6fd2807SJeff Garzik 	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
123c6fd2807SJeff Garzik 	MV_MAX_SG_CT		= 176,
124c6fd2807SJeff Garzik 	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
125c6fd2807SJeff Garzik 	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
126c6fd2807SJeff Garzik 
127c6fd2807SJeff Garzik 	MV_PORTS_PER_HC		= 4,
128c6fd2807SJeff Garzik 	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
129c6fd2807SJeff Garzik 	MV_PORT_HC_SHIFT	= 2,
130c6fd2807SJeff Garzik 	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
131c6fd2807SJeff Garzik 	MV_PORT_MASK		= 3,
132c6fd2807SJeff Garzik 
133c6fd2807SJeff Garzik 	/* Host Flags */
134c6fd2807SJeff Garzik 	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
135c6fd2807SJeff Garzik 	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
136c6fd2807SJeff Garzik 	MV_COMMON_FLAGS		= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
137c6fd2807SJeff Garzik 				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
138c6fd2807SJeff Garzik 				   ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
139c6fd2807SJeff Garzik 	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,
140c6fd2807SJeff Garzik 
141c6fd2807SJeff Garzik 	CRQB_FLAG_READ		= (1 << 0),
142c6fd2807SJeff Garzik 	CRQB_TAG_SHIFT		= 1,
143c6fd2807SJeff Garzik 	CRQB_CMD_ADDR_SHIFT	= 8,
144c6fd2807SJeff Garzik 	CRQB_CMD_CS		= (0x2 << 11),
145c6fd2807SJeff Garzik 	CRQB_CMD_LAST		= (1 << 15),
146c6fd2807SJeff Garzik 
147c6fd2807SJeff Garzik 	CRPB_FLAG_STATUS_SHIFT	= 8,
148c6fd2807SJeff Garzik 
149c6fd2807SJeff Garzik 	EPRD_FLAG_END_OF_TBL	= (1 << 31),
150c6fd2807SJeff Garzik 
151c6fd2807SJeff Garzik 	/* PCI interface registers */
152c6fd2807SJeff Garzik 
153c6fd2807SJeff Garzik 	PCI_COMMAND_OFS		= 0xc00,
154c6fd2807SJeff Garzik 
155c6fd2807SJeff Garzik 	PCI_MAIN_CMD_STS_OFS	= 0xd30,
156c6fd2807SJeff Garzik 	STOP_PCI_MASTER		= (1 << 2),
157c6fd2807SJeff Garzik 	PCI_MASTER_EMPTY	= (1 << 3),
158c6fd2807SJeff Garzik 	GLOB_SFT_RST		= (1 << 4),
159c6fd2807SJeff Garzik 
160c6fd2807SJeff Garzik 	MV_PCI_MODE		= 0xd00,
161c6fd2807SJeff Garzik 	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,
162c6fd2807SJeff Garzik 	MV_PCI_DISC_TIMER	= 0xd04,
163c6fd2807SJeff Garzik 	MV_PCI_MSI_TRIGGER	= 0xc38,
164c6fd2807SJeff Garzik 	MV_PCI_SERR_MASK	= 0xc28,
165c6fd2807SJeff Garzik 	MV_PCI_XBAR_TMOUT	= 0x1d04,
166c6fd2807SJeff Garzik 	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,
167c6fd2807SJeff Garzik 	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,
168c6fd2807SJeff Garzik 	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,
169c6fd2807SJeff Garzik 	MV_PCI_ERR_COMMAND	= 0x1d50,
170c6fd2807SJeff Garzik 
171c6fd2807SJeff Garzik 	PCI_IRQ_CAUSE_OFS		= 0x1d58,
172c6fd2807SJeff Garzik 	PCI_IRQ_MASK_OFS		= 0x1d5c,
173c6fd2807SJeff Garzik 	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
174c6fd2807SJeff Garzik 
175c6fd2807SJeff Garzik 	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
176c6fd2807SJeff Garzik 	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
177c6fd2807SJeff Garzik 	PORT0_ERR		= (1 << 0),	/* shift by port # */
178c6fd2807SJeff Garzik 	PORT0_DONE		= (1 << 1),	/* shift by port # */
179c6fd2807SJeff Garzik 	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
180c6fd2807SJeff Garzik 	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
181c6fd2807SJeff Garzik 	PCI_ERR			= (1 << 18),
182c6fd2807SJeff Garzik 	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
183c6fd2807SJeff Garzik 	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
184fb621e2fSJeff Garzik 	PORTS_0_3_COAL_DONE	= (1 << 8),
185fb621e2fSJeff Garzik 	PORTS_4_7_COAL_DONE	= (1 << 17),
186c6fd2807SJeff Garzik 	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
187c6fd2807SJeff Garzik 	GPIO_INT		= (1 << 22),
188c6fd2807SJeff Garzik 	SELF_INT		= (1 << 23),
189c6fd2807SJeff Garzik 	TWSI_INT		= (1 << 24),
190c6fd2807SJeff Garzik 	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
191fb621e2fSJeff Garzik 	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
192c6fd2807SJeff Garzik 	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
193c6fd2807SJeff Garzik 				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
194c6fd2807SJeff Garzik 				   HC_MAIN_RSVD),
195fb621e2fSJeff Garzik 	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
196fb621e2fSJeff Garzik 				   HC_MAIN_RSVD_5),
197c6fd2807SJeff Garzik 
198c6fd2807SJeff Garzik 	/* SATAHC registers */
199c6fd2807SJeff Garzik 	HC_CFG_OFS		= 0,
200c6fd2807SJeff Garzik 
201c6fd2807SJeff Garzik 	HC_IRQ_CAUSE_OFS	= 0x14,
202c6fd2807SJeff Garzik 	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
203c6fd2807SJeff Garzik 	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
204c6fd2807SJeff Garzik 	DEV_IRQ			= (1 << 8),	/* shift by port # */
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik 	/* Shadow block registers */
207c6fd2807SJeff Garzik 	SHD_BLK_OFS		= 0x100,
208c6fd2807SJeff Garzik 	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
209c6fd2807SJeff Garzik 
210c6fd2807SJeff Garzik 	/* SATA registers */
211c6fd2807SJeff Garzik 	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
212c6fd2807SJeff Garzik 	SATA_ACTIVE_OFS		= 0x350,
213c6fd2807SJeff Garzik 	PHY_MODE3		= 0x310,
214c6fd2807SJeff Garzik 	PHY_MODE4		= 0x314,
215c6fd2807SJeff Garzik 	PHY_MODE2		= 0x330,
216c6fd2807SJeff Garzik 	MV5_PHY_MODE		= 0x74,
217c6fd2807SJeff Garzik 	MV5_LT_MODE		= 0x30,
218c6fd2807SJeff Garzik 	MV5_PHY_CTL		= 0x0C,
219c6fd2807SJeff Garzik 	SATA_INTERFACE_CTL	= 0x050,
220c6fd2807SJeff Garzik 
221c6fd2807SJeff Garzik 	MV_M2_PREAMP_MASK	= 0x7e0,
222c6fd2807SJeff Garzik 
223c6fd2807SJeff Garzik 	/* Port registers */
224c6fd2807SJeff Garzik 	EDMA_CFG_OFS		= 0,
225c6fd2807SJeff Garzik 	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
226c6fd2807SJeff Garzik 	EDMA_CFG_NCQ		= (1 << 5),
227c6fd2807SJeff Garzik 	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
228c6fd2807SJeff Garzik 	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
229c6fd2807SJeff Garzik 	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
230c6fd2807SJeff Garzik 
231c6fd2807SJeff Garzik 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
232c6fd2807SJeff Garzik 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
233c6fd2807SJeff Garzik 	EDMA_ERR_D_PAR		= (1 << 0),
234c6fd2807SJeff Garzik 	EDMA_ERR_PRD_PAR	= (1 << 1),
235c6fd2807SJeff Garzik 	EDMA_ERR_DEV		= (1 << 2),
236c6fd2807SJeff Garzik 	EDMA_ERR_DEV_DCON	= (1 << 3),
237c6fd2807SJeff Garzik 	EDMA_ERR_DEV_CON	= (1 << 4),
238c6fd2807SJeff Garzik 	EDMA_ERR_SERR		= (1 << 5),
239c6fd2807SJeff Garzik 	EDMA_ERR_SELF_DIS	= (1 << 7),
240c6fd2807SJeff Garzik 	EDMA_ERR_BIST_ASYNC	= (1 << 8),
241c6fd2807SJeff Garzik 	EDMA_ERR_CRBQ_PAR	= (1 << 9),
242c6fd2807SJeff Garzik 	EDMA_ERR_CRPB_PAR	= (1 << 10),
243c6fd2807SJeff Garzik 	EDMA_ERR_INTRL_PAR	= (1 << 11),
244c6fd2807SJeff Garzik 	EDMA_ERR_IORDY		= (1 << 12),
245c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),
246c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
247c6fd2807SJeff Garzik 	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),
248c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),
249c6fd2807SJeff Garzik 	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),
250c6fd2807SJeff Garzik 	EDMA_ERR_TRANS_PROTO	= (1 << 31),
251c6fd2807SJeff Garzik 	EDMA_ERR_FATAL		= (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
252c6fd2807SJeff Garzik 				   EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
253c6fd2807SJeff Garzik 				   EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
254c6fd2807SJeff Garzik 				   EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
255c6fd2807SJeff Garzik 				   EDMA_ERR_LNK_DATA_RX |
256c6fd2807SJeff Garzik 				   EDMA_ERR_LNK_DATA_TX |
257c6fd2807SJeff Garzik 				   EDMA_ERR_TRANS_PROTO),
258c6fd2807SJeff Garzik 
259c6fd2807SJeff Garzik 	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
260c6fd2807SJeff Garzik 	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
261c6fd2807SJeff Garzik 
262c6fd2807SJeff Garzik 	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
263c6fd2807SJeff Garzik 	EDMA_REQ_Q_PTR_SHIFT	= 5,
264c6fd2807SJeff Garzik 
265c6fd2807SJeff Garzik 	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
266c6fd2807SJeff Garzik 	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
267c6fd2807SJeff Garzik 	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
268c6fd2807SJeff Garzik 	EDMA_RSP_Q_PTR_SHIFT	= 3,
269c6fd2807SJeff Garzik 
270c6fd2807SJeff Garzik 	EDMA_CMD_OFS		= 0x28,
271c6fd2807SJeff Garzik 	EDMA_EN			= (1 << 0),
272c6fd2807SJeff Garzik 	EDMA_DS			= (1 << 1),
273c6fd2807SJeff Garzik 	ATA_RST			= (1 << 2),
274c6fd2807SJeff Garzik 
275c6fd2807SJeff Garzik 	EDMA_IORDY_TMOUT	= 0x34,
276c6fd2807SJeff Garzik 	EDMA_ARB_CFG		= 0x38,
277c6fd2807SJeff Garzik 
278c6fd2807SJeff Garzik 	/* Host private flags (hp_flags) */
279c6fd2807SJeff Garzik 	MV_HP_FLAG_MSI		= (1 << 0),
280c6fd2807SJeff Garzik 	MV_HP_ERRATA_50XXB0	= (1 << 1),
281c6fd2807SJeff Garzik 	MV_HP_ERRATA_50XXB2	= (1 << 2),
282c6fd2807SJeff Garzik 	MV_HP_ERRATA_60X1B2	= (1 << 3),
283c6fd2807SJeff Garzik 	MV_HP_ERRATA_60X1C0	= (1 << 4),
284c6fd2807SJeff Garzik 	MV_HP_ERRATA_XX42A0	= (1 << 5),
285c6fd2807SJeff Garzik 	MV_HP_50XX		= (1 << 6),
286c6fd2807SJeff Garzik 	MV_HP_GEN_IIE		= (1 << 7),
287c6fd2807SJeff Garzik 
288c6fd2807SJeff Garzik 	/* Port private flags (pp_flags) */
289c6fd2807SJeff Garzik 	MV_PP_FLAG_EDMA_EN	= (1 << 0),
290c6fd2807SJeff Garzik 	MV_PP_FLAG_EDMA_DS_ACT	= (1 << 1),
291c6fd2807SJeff Garzik };
292c6fd2807SJeff Garzik 
293c6fd2807SJeff Garzik #define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
294c6fd2807SJeff Garzik #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
295c6fd2807SJeff Garzik #define IS_GEN_I(hpriv) IS_50XX(hpriv)
296c6fd2807SJeff Garzik #define IS_GEN_II(hpriv) IS_60XX(hpriv)
297c6fd2807SJeff Garzik #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
298c6fd2807SJeff Garzik 
299c6fd2807SJeff Garzik enum {
300d88184fbSJeff Garzik 	MV_DMA_BOUNDARY		= 0xffffffffU,
301c6fd2807SJeff Garzik 
302c6fd2807SJeff Garzik 	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
303c6fd2807SJeff Garzik 
304c6fd2807SJeff Garzik 	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
305c6fd2807SJeff Garzik };
306c6fd2807SJeff Garzik 
307c6fd2807SJeff Garzik enum chip_type {
308c6fd2807SJeff Garzik 	chip_504x,
309c6fd2807SJeff Garzik 	chip_508x,
310c6fd2807SJeff Garzik 	chip_5080,
311c6fd2807SJeff Garzik 	chip_604x,
312c6fd2807SJeff Garzik 	chip_608x,
313c6fd2807SJeff Garzik 	chip_6042,
314c6fd2807SJeff Garzik 	chip_7042,
315c6fd2807SJeff Garzik };
316c6fd2807SJeff Garzik 
317c6fd2807SJeff Garzik /* Command ReQuest Block: 32B */
318c6fd2807SJeff Garzik struct mv_crqb {
319c6fd2807SJeff Garzik 	__le32			sg_addr;
320c6fd2807SJeff Garzik 	__le32			sg_addr_hi;
321c6fd2807SJeff Garzik 	__le16			ctrl_flags;
322c6fd2807SJeff Garzik 	__le16			ata_cmd[11];
323c6fd2807SJeff Garzik };
324c6fd2807SJeff Garzik 
325c6fd2807SJeff Garzik struct mv_crqb_iie {
326c6fd2807SJeff Garzik 	__le32			addr;
327c6fd2807SJeff Garzik 	__le32			addr_hi;
328c6fd2807SJeff Garzik 	__le32			flags;
329c6fd2807SJeff Garzik 	__le32			len;
330c6fd2807SJeff Garzik 	__le32			ata_cmd[4];
331c6fd2807SJeff Garzik };
332c6fd2807SJeff Garzik 
333c6fd2807SJeff Garzik /* Command ResPonse Block: 8B */
334c6fd2807SJeff Garzik struct mv_crpb {
335c6fd2807SJeff Garzik 	__le16			id;
336c6fd2807SJeff Garzik 	__le16			flags;
337c6fd2807SJeff Garzik 	__le32			tmstmp;
338c6fd2807SJeff Garzik };
339c6fd2807SJeff Garzik 
340c6fd2807SJeff Garzik /* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
341c6fd2807SJeff Garzik struct mv_sg {
342c6fd2807SJeff Garzik 	__le32			addr;
343c6fd2807SJeff Garzik 	__le32			flags_size;
344c6fd2807SJeff Garzik 	__le32			addr_hi;
345c6fd2807SJeff Garzik 	__le32			reserved;
346c6fd2807SJeff Garzik };
347c6fd2807SJeff Garzik 
348c6fd2807SJeff Garzik struct mv_port_priv {
349c6fd2807SJeff Garzik 	struct mv_crqb		*crqb;
350c6fd2807SJeff Garzik 	dma_addr_t		crqb_dma;
351c6fd2807SJeff Garzik 	struct mv_crpb		*crpb;
352c6fd2807SJeff Garzik 	dma_addr_t		crpb_dma;
353c6fd2807SJeff Garzik 	struct mv_sg		*sg_tbl;
354c6fd2807SJeff Garzik 	dma_addr_t		sg_tbl_dma;
355c6fd2807SJeff Garzik 	u32			pp_flags;
356c6fd2807SJeff Garzik };
357c6fd2807SJeff Garzik 
358c6fd2807SJeff Garzik struct mv_port_signal {
359c6fd2807SJeff Garzik 	u32			amps;
360c6fd2807SJeff Garzik 	u32			pre;
361c6fd2807SJeff Garzik };
362c6fd2807SJeff Garzik 
363c6fd2807SJeff Garzik struct mv_host_priv;
364c6fd2807SJeff Garzik struct mv_hw_ops {
365c6fd2807SJeff Garzik 	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
366c6fd2807SJeff Garzik 			   unsigned int port);
367c6fd2807SJeff Garzik 	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
368c6fd2807SJeff Garzik 	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
369c6fd2807SJeff Garzik 			   void __iomem *mmio);
370c6fd2807SJeff Garzik 	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
371c6fd2807SJeff Garzik 			unsigned int n_hc);
372c6fd2807SJeff Garzik 	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
373c6fd2807SJeff Garzik 	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
374c6fd2807SJeff Garzik };
375c6fd2807SJeff Garzik 
376c6fd2807SJeff Garzik struct mv_host_priv {
377c6fd2807SJeff Garzik 	u32			hp_flags;
378c6fd2807SJeff Garzik 	struct mv_port_signal	signal[8];
379c6fd2807SJeff Garzik 	const struct mv_hw_ops	*ops;
380c6fd2807SJeff Garzik };
381c6fd2807SJeff Garzik 
382c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap);
383c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
384c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
385c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
386c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
387c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap);
388c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
389c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap);
390c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap);
391c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc);
392c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
393c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
394c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap);
395c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
396c6fd2807SJeff Garzik 
397c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
398c6fd2807SJeff Garzik 			   unsigned int port);
399c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
400c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
401c6fd2807SJeff Garzik 			   void __iomem *mmio);
402c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
403c6fd2807SJeff Garzik 			unsigned int n_hc);
404c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
405c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
406c6fd2807SJeff Garzik 
407c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
408c6fd2807SJeff Garzik 			   unsigned int port);
409c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
410c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
411c6fd2807SJeff Garzik 			   void __iomem *mmio);
412c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
413c6fd2807SJeff Garzik 			unsigned int n_hc);
414c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
415c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
416c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
417c6fd2807SJeff Garzik 			     unsigned int port_no);
418c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap);
419c6fd2807SJeff Garzik 
420c6fd2807SJeff Garzik static struct scsi_host_template mv_sht = {
421c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
422c6fd2807SJeff Garzik 	.name			= DRV_NAME,
423c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
424c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
425c6fd2807SJeff Garzik 	.can_queue		= MV_USE_Q_DEPTH,
426c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
427d88184fbSJeff Garzik 	.sg_tablesize		= MV_MAX_SG_CT,
428c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
429c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
430d88184fbSJeff Garzik 	.use_clustering		= 1,
431c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
432c6fd2807SJeff Garzik 	.dma_boundary		= MV_DMA_BOUNDARY,
433c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
434c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
435c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
436c6fd2807SJeff Garzik };
437c6fd2807SJeff Garzik 
438c6fd2807SJeff Garzik static const struct ata_port_operations mv5_ops = {
439c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
440c6fd2807SJeff Garzik 
441c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
442c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
443c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
444c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
445c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
446c6fd2807SJeff Garzik 
447c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
448cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
449c6fd2807SJeff Garzik 
450c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep,
451c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
4520d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
453c6fd2807SJeff Garzik 
454c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
455c6fd2807SJeff Garzik 
456c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
457246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
458246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
459c6fd2807SJeff Garzik 
460c6fd2807SJeff Garzik 	.scr_read		= mv5_scr_read,
461c6fd2807SJeff Garzik 	.scr_write		= mv5_scr_write,
462c6fd2807SJeff Garzik 
463c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
464c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
465c6fd2807SJeff Garzik };
466c6fd2807SJeff Garzik 
467c6fd2807SJeff Garzik static const struct ata_port_operations mv6_ops = {
468c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
469c6fd2807SJeff Garzik 
470c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
471c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
472c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
473c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
474c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
475c6fd2807SJeff Garzik 
476c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
477cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
478c6fd2807SJeff Garzik 
479c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep,
480c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
4810d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
482c6fd2807SJeff Garzik 
483c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
484c6fd2807SJeff Garzik 
485c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
486246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
487246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
488c6fd2807SJeff Garzik 
489c6fd2807SJeff Garzik 	.scr_read		= mv_scr_read,
490c6fd2807SJeff Garzik 	.scr_write		= mv_scr_write,
491c6fd2807SJeff Garzik 
492c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
493c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
494c6fd2807SJeff Garzik };
495c6fd2807SJeff Garzik 
496c6fd2807SJeff Garzik static const struct ata_port_operations mv_iie_ops = {
497c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
498c6fd2807SJeff Garzik 
499c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
500c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
501c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
502c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
503c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
504c6fd2807SJeff Garzik 
505c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
506cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
507c6fd2807SJeff Garzik 
508c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep_iie,
509c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
5100d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
511c6fd2807SJeff Garzik 
512c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
513c6fd2807SJeff Garzik 
514c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
515246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
516246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
517c6fd2807SJeff Garzik 
518c6fd2807SJeff Garzik 	.scr_read		= mv_scr_read,
519c6fd2807SJeff Garzik 	.scr_write		= mv_scr_write,
520c6fd2807SJeff Garzik 
521c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
522c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
523c6fd2807SJeff Garzik };
524c6fd2807SJeff Garzik 
525c6fd2807SJeff Garzik static const struct ata_port_info mv_port_info[] = {
526c6fd2807SJeff Garzik 	{  /* chip_504x */
527cca3974eSJeff Garzik 		.flags		= MV_COMMON_FLAGS,
528c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
529c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
530c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
531c6fd2807SJeff Garzik 	},
532c6fd2807SJeff Garzik 	{  /* chip_508x */
533cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
534c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
535c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
536c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
537c6fd2807SJeff Garzik 	},
538c6fd2807SJeff Garzik 	{  /* chip_5080 */
539cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
540c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
541c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
542c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
543c6fd2807SJeff Garzik 	},
544c6fd2807SJeff Garzik 	{  /* chip_604x */
545cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
546c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
547c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
548c6fd2807SJeff Garzik 		.port_ops	= &mv6_ops,
549c6fd2807SJeff Garzik 	},
550c6fd2807SJeff Garzik 	{  /* chip_608x */
551cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
552c6fd2807SJeff Garzik 				   MV_FLAG_DUAL_HC),
553c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
554c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
555c6fd2807SJeff Garzik 		.port_ops	= &mv6_ops,
556c6fd2807SJeff Garzik 	},
557c6fd2807SJeff Garzik 	{  /* chip_6042 */
558cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
559c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
560c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
561c6fd2807SJeff Garzik 		.port_ops	= &mv_iie_ops,
562c6fd2807SJeff Garzik 	},
563c6fd2807SJeff Garzik 	{  /* chip_7042 */
564e93f09dcSOlof Johansson 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
565c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
566c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
567c6fd2807SJeff Garzik 		.port_ops	= &mv_iie_ops,
568c6fd2807SJeff Garzik 	},
569c6fd2807SJeff Garzik };
570c6fd2807SJeff Garzik 
571c6fd2807SJeff Garzik static const struct pci_device_id mv_pci_tbl[] = {
5722d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
5732d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
5742d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
5752d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
576c6fd2807SJeff Garzik 
5772d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
5782d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
5792d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
5802d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
5812d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
582c6fd2807SJeff Garzik 
5832d2744fcSJeff Garzik 	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
5842d2744fcSJeff Garzik 
585*d9f9c6bcSFlorian Attenberger 	/* Adaptec 1430SA */
586*d9f9c6bcSFlorian Attenberger 	{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
587*d9f9c6bcSFlorian Attenberger 
588e93f09dcSOlof Johansson 	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
589e93f09dcSOlof Johansson 
5906a3d586dSMorrison, Tom 	/* add Marvell 7042 support */
5916a3d586dSMorrison, Tom 	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
5926a3d586dSMorrison, Tom 
593c6fd2807SJeff Garzik 	{ }			/* terminate list */
594c6fd2807SJeff Garzik };
595c6fd2807SJeff Garzik 
596c6fd2807SJeff Garzik static struct pci_driver mv_pci_driver = {
597c6fd2807SJeff Garzik 	.name			= DRV_NAME,
598c6fd2807SJeff Garzik 	.id_table		= mv_pci_tbl,
599c6fd2807SJeff Garzik 	.probe			= mv_init_one,
600c6fd2807SJeff Garzik 	.remove			= ata_pci_remove_one,
601c6fd2807SJeff Garzik };
602c6fd2807SJeff Garzik 
603c6fd2807SJeff Garzik static const struct mv_hw_ops mv5xxx_ops = {
604c6fd2807SJeff Garzik 	.phy_errata		= mv5_phy_errata,
605c6fd2807SJeff Garzik 	.enable_leds		= mv5_enable_leds,
606c6fd2807SJeff Garzik 	.read_preamp		= mv5_read_preamp,
607c6fd2807SJeff Garzik 	.reset_hc		= mv5_reset_hc,
608c6fd2807SJeff Garzik 	.reset_flash		= mv5_reset_flash,
609c6fd2807SJeff Garzik 	.reset_bus		= mv5_reset_bus,
610c6fd2807SJeff Garzik };
611c6fd2807SJeff Garzik 
612c6fd2807SJeff Garzik static const struct mv_hw_ops mv6xxx_ops = {
613c6fd2807SJeff Garzik 	.phy_errata		= mv6_phy_errata,
614c6fd2807SJeff Garzik 	.enable_leds		= mv6_enable_leds,
615c6fd2807SJeff Garzik 	.read_preamp		= mv6_read_preamp,
616c6fd2807SJeff Garzik 	.reset_hc		= mv6_reset_hc,
617c6fd2807SJeff Garzik 	.reset_flash		= mv6_reset_flash,
618c6fd2807SJeff Garzik 	.reset_bus		= mv_reset_pci_bus,
619c6fd2807SJeff Garzik };
620c6fd2807SJeff Garzik 
621c6fd2807SJeff Garzik /*
622c6fd2807SJeff Garzik  * module options
623c6fd2807SJeff Garzik  */
624c6fd2807SJeff Garzik static int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
625c6fd2807SJeff Garzik 
626c6fd2807SJeff Garzik 
627d88184fbSJeff Garzik /* move to PCI layer or libata core? */
628d88184fbSJeff Garzik static int pci_go_64(struct pci_dev *pdev)
629d88184fbSJeff Garzik {
630d88184fbSJeff Garzik 	int rc;
631d88184fbSJeff Garzik 
632d88184fbSJeff Garzik 	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
633d88184fbSJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
634d88184fbSJeff Garzik 		if (rc) {
635d88184fbSJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
636d88184fbSJeff Garzik 			if (rc) {
637d88184fbSJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
638d88184fbSJeff Garzik 					   "64-bit DMA enable failed\n");
639d88184fbSJeff Garzik 				return rc;
640d88184fbSJeff Garzik 			}
641d88184fbSJeff Garzik 		}
642d88184fbSJeff Garzik 	} else {
643d88184fbSJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
644d88184fbSJeff Garzik 		if (rc) {
645d88184fbSJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
646d88184fbSJeff Garzik 				   "32-bit DMA enable failed\n");
647d88184fbSJeff Garzik 			return rc;
648d88184fbSJeff Garzik 		}
649d88184fbSJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
650d88184fbSJeff Garzik 		if (rc) {
651d88184fbSJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
652d88184fbSJeff Garzik 				   "32-bit consistent DMA enable failed\n");
653d88184fbSJeff Garzik 			return rc;
654d88184fbSJeff Garzik 		}
655d88184fbSJeff Garzik 	}
656d88184fbSJeff Garzik 
657d88184fbSJeff Garzik 	return rc;
658d88184fbSJeff Garzik }
659d88184fbSJeff Garzik 
660c6fd2807SJeff Garzik /*
661c6fd2807SJeff Garzik  * Functions
662c6fd2807SJeff Garzik  */
663c6fd2807SJeff Garzik 
664c6fd2807SJeff Garzik static inline void writelfl(unsigned long data, void __iomem *addr)
665c6fd2807SJeff Garzik {
666c6fd2807SJeff Garzik 	writel(data, addr);
667c6fd2807SJeff Garzik 	(void) readl(addr);	/* flush to avoid PCI posted write */
668c6fd2807SJeff Garzik }
669c6fd2807SJeff Garzik 
670c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
671c6fd2807SJeff Garzik {
672c6fd2807SJeff Garzik 	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
673c6fd2807SJeff Garzik }
674c6fd2807SJeff Garzik 
675c6fd2807SJeff Garzik static inline unsigned int mv_hc_from_port(unsigned int port)
676c6fd2807SJeff Garzik {
677c6fd2807SJeff Garzik 	return port >> MV_PORT_HC_SHIFT;
678c6fd2807SJeff Garzik }
679c6fd2807SJeff Garzik 
680c6fd2807SJeff Garzik static inline unsigned int mv_hardport_from_port(unsigned int port)
681c6fd2807SJeff Garzik {
682c6fd2807SJeff Garzik 	return port & MV_PORT_MASK;
683c6fd2807SJeff Garzik }
684c6fd2807SJeff Garzik 
685c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
686c6fd2807SJeff Garzik 						 unsigned int port)
687c6fd2807SJeff Garzik {
688c6fd2807SJeff Garzik 	return mv_hc_base(base, mv_hc_from_port(port));
689c6fd2807SJeff Garzik }
690c6fd2807SJeff Garzik 
691c6fd2807SJeff Garzik static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
692c6fd2807SJeff Garzik {
693c6fd2807SJeff Garzik 	return  mv_hc_base_from_port(base, port) +
694c6fd2807SJeff Garzik 		MV_SATAHC_ARBTR_REG_SZ +
695c6fd2807SJeff Garzik 		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
696c6fd2807SJeff Garzik }
697c6fd2807SJeff Garzik 
698c6fd2807SJeff Garzik static inline void __iomem *mv_ap_base(struct ata_port *ap)
699c6fd2807SJeff Garzik {
7000d5ff566STejun Heo 	return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
701c6fd2807SJeff Garzik }
702c6fd2807SJeff Garzik 
703cca3974eSJeff Garzik static inline int mv_get_hc_count(unsigned long port_flags)
704c6fd2807SJeff Garzik {
705cca3974eSJeff Garzik 	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
706c6fd2807SJeff Garzik }
707c6fd2807SJeff Garzik 
708c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap)
709c6fd2807SJeff Garzik {
710c6fd2807SJeff Garzik }
711c6fd2807SJeff Garzik 
712c6fd2807SJeff Garzik /**
713c6fd2807SJeff Garzik  *      mv_start_dma - Enable eDMA engine
714c6fd2807SJeff Garzik  *      @base: port base address
715c6fd2807SJeff Garzik  *      @pp: port private data
716c6fd2807SJeff Garzik  *
717c6fd2807SJeff Garzik  *      Verify the local cache of the eDMA state is accurate with a
718c6fd2807SJeff Garzik  *      WARN_ON.
719c6fd2807SJeff Garzik  *
720c6fd2807SJeff Garzik  *      LOCKING:
721c6fd2807SJeff Garzik  *      Inherited from caller.
722c6fd2807SJeff Garzik  */
723c6fd2807SJeff Garzik static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
724c6fd2807SJeff Garzik {
725c6fd2807SJeff Garzik 	if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
726c6fd2807SJeff Garzik 		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
727c6fd2807SJeff Garzik 		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
728c6fd2807SJeff Garzik 	}
729c6fd2807SJeff Garzik 	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
730c6fd2807SJeff Garzik }
731c6fd2807SJeff Garzik 
732c6fd2807SJeff Garzik /**
733c6fd2807SJeff Garzik  *      mv_stop_dma - Disable eDMA engine
734c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
735c6fd2807SJeff Garzik  *
736c6fd2807SJeff Garzik  *      Verify the local cache of the eDMA state is accurate with a
737c6fd2807SJeff Garzik  *      WARN_ON.
738c6fd2807SJeff Garzik  *
739c6fd2807SJeff Garzik  *      LOCKING:
740c6fd2807SJeff Garzik  *      Inherited from caller.
741c6fd2807SJeff Garzik  */
742c6fd2807SJeff Garzik static void mv_stop_dma(struct ata_port *ap)
743c6fd2807SJeff Garzik {
744c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
745c6fd2807SJeff Garzik 	struct mv_port_priv *pp	= ap->private_data;
746c6fd2807SJeff Garzik 	u32 reg;
747c6fd2807SJeff Garzik 	int i;
748c6fd2807SJeff Garzik 
749c6fd2807SJeff Garzik 	if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
750c6fd2807SJeff Garzik 		/* Disable EDMA if active.   The disable bit auto clears.
751c6fd2807SJeff Garzik 		 */
752c6fd2807SJeff Garzik 		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
753c6fd2807SJeff Garzik 		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
754c6fd2807SJeff Garzik 	} else {
755c6fd2807SJeff Garzik 		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
756c6fd2807SJeff Garzik   	}
757c6fd2807SJeff Garzik 
758c6fd2807SJeff Garzik 	/* now properly wait for the eDMA to stop */
759c6fd2807SJeff Garzik 	for (i = 1000; i > 0; i--) {
760c6fd2807SJeff Garzik 		reg = readl(port_mmio + EDMA_CMD_OFS);
761c6fd2807SJeff Garzik 		if (!(EDMA_EN & reg)) {
762c6fd2807SJeff Garzik 			break;
763c6fd2807SJeff Garzik 		}
764c6fd2807SJeff Garzik 		udelay(100);
765c6fd2807SJeff Garzik 	}
766c6fd2807SJeff Garzik 
767c6fd2807SJeff Garzik 	if (EDMA_EN & reg) {
768c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
769c6fd2807SJeff Garzik 		/* FIXME: Consider doing a reset here to recover */
770c6fd2807SJeff Garzik 	}
771c6fd2807SJeff Garzik }
772c6fd2807SJeff Garzik 
773c6fd2807SJeff Garzik #ifdef ATA_DEBUG
774c6fd2807SJeff Garzik static void mv_dump_mem(void __iomem *start, unsigned bytes)
775c6fd2807SJeff Garzik {
776c6fd2807SJeff Garzik 	int b, w;
777c6fd2807SJeff Garzik 	for (b = 0; b < bytes; ) {
778c6fd2807SJeff Garzik 		DPRINTK("%p: ", start + b);
779c6fd2807SJeff Garzik 		for (w = 0; b < bytes && w < 4; w++) {
780c6fd2807SJeff Garzik 			printk("%08x ",readl(start + b));
781c6fd2807SJeff Garzik 			b += sizeof(u32);
782c6fd2807SJeff Garzik 		}
783c6fd2807SJeff Garzik 		printk("\n");
784c6fd2807SJeff Garzik 	}
785c6fd2807SJeff Garzik }
786c6fd2807SJeff Garzik #endif
787c6fd2807SJeff Garzik 
788c6fd2807SJeff Garzik static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
789c6fd2807SJeff Garzik {
790c6fd2807SJeff Garzik #ifdef ATA_DEBUG
791c6fd2807SJeff Garzik 	int b, w;
792c6fd2807SJeff Garzik 	u32 dw;
793c6fd2807SJeff Garzik 	for (b = 0; b < bytes; ) {
794c6fd2807SJeff Garzik 		DPRINTK("%02x: ", b);
795c6fd2807SJeff Garzik 		for (w = 0; b < bytes && w < 4; w++) {
796c6fd2807SJeff Garzik 			(void) pci_read_config_dword(pdev,b,&dw);
797c6fd2807SJeff Garzik 			printk("%08x ",dw);
798c6fd2807SJeff Garzik 			b += sizeof(u32);
799c6fd2807SJeff Garzik 		}
800c6fd2807SJeff Garzik 		printk("\n");
801c6fd2807SJeff Garzik 	}
802c6fd2807SJeff Garzik #endif
803c6fd2807SJeff Garzik }
804c6fd2807SJeff Garzik static void mv_dump_all_regs(void __iomem *mmio_base, int port,
805c6fd2807SJeff Garzik 			     struct pci_dev *pdev)
806c6fd2807SJeff Garzik {
807c6fd2807SJeff Garzik #ifdef ATA_DEBUG
808c6fd2807SJeff Garzik 	void __iomem *hc_base = mv_hc_base(mmio_base,
809c6fd2807SJeff Garzik 					   port >> MV_PORT_HC_SHIFT);
810c6fd2807SJeff Garzik 	void __iomem *port_base;
811c6fd2807SJeff Garzik 	int start_port, num_ports, p, start_hc, num_hcs, hc;
812c6fd2807SJeff Garzik 
813c6fd2807SJeff Garzik 	if (0 > port) {
814c6fd2807SJeff Garzik 		start_hc = start_port = 0;
815c6fd2807SJeff Garzik 		num_ports = 8;		/* shld be benign for 4 port devs */
816c6fd2807SJeff Garzik 		num_hcs = 2;
817c6fd2807SJeff Garzik 	} else {
818c6fd2807SJeff Garzik 		start_hc = port >> MV_PORT_HC_SHIFT;
819c6fd2807SJeff Garzik 		start_port = port;
820c6fd2807SJeff Garzik 		num_ports = num_hcs = 1;
821c6fd2807SJeff Garzik 	}
822c6fd2807SJeff Garzik 	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
823c6fd2807SJeff Garzik 		num_ports > 1 ? num_ports - 1 : start_port);
824c6fd2807SJeff Garzik 
825c6fd2807SJeff Garzik 	if (NULL != pdev) {
826c6fd2807SJeff Garzik 		DPRINTK("PCI config space regs:\n");
827c6fd2807SJeff Garzik 		mv_dump_pci_cfg(pdev, 0x68);
828c6fd2807SJeff Garzik 	}
829c6fd2807SJeff Garzik 	DPRINTK("PCI regs:\n");
830c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xc00, 0x3c);
831c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xd00, 0x34);
832c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xf00, 0x4);
833c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0x1d00, 0x6c);
834c6fd2807SJeff Garzik 	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
835c6fd2807SJeff Garzik 		hc_base = mv_hc_base(mmio_base, hc);
836c6fd2807SJeff Garzik 		DPRINTK("HC regs (HC %i):\n", hc);
837c6fd2807SJeff Garzik 		mv_dump_mem(hc_base, 0x1c);
838c6fd2807SJeff Garzik 	}
839c6fd2807SJeff Garzik 	for (p = start_port; p < start_port + num_ports; p++) {
840c6fd2807SJeff Garzik 		port_base = mv_port_base(mmio_base, p);
841c6fd2807SJeff Garzik 		DPRINTK("EDMA regs (port %i):\n",p);
842c6fd2807SJeff Garzik 		mv_dump_mem(port_base, 0x54);
843c6fd2807SJeff Garzik 		DPRINTK("SATA regs (port %i):\n",p);
844c6fd2807SJeff Garzik 		mv_dump_mem(port_base+0x300, 0x60);
845c6fd2807SJeff Garzik 	}
846c6fd2807SJeff Garzik #endif
847c6fd2807SJeff Garzik }
848c6fd2807SJeff Garzik 
849c6fd2807SJeff Garzik static unsigned int mv_scr_offset(unsigned int sc_reg_in)
850c6fd2807SJeff Garzik {
851c6fd2807SJeff Garzik 	unsigned int ofs;
852c6fd2807SJeff Garzik 
853c6fd2807SJeff Garzik 	switch (sc_reg_in) {
854c6fd2807SJeff Garzik 	case SCR_STATUS:
855c6fd2807SJeff Garzik 	case SCR_CONTROL:
856c6fd2807SJeff Garzik 	case SCR_ERROR:
857c6fd2807SJeff Garzik 		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
858c6fd2807SJeff Garzik 		break;
859c6fd2807SJeff Garzik 	case SCR_ACTIVE:
860c6fd2807SJeff Garzik 		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
861c6fd2807SJeff Garzik 		break;
862c6fd2807SJeff Garzik 	default:
863c6fd2807SJeff Garzik 		ofs = 0xffffffffU;
864c6fd2807SJeff Garzik 		break;
865c6fd2807SJeff Garzik 	}
866c6fd2807SJeff Garzik 	return ofs;
867c6fd2807SJeff Garzik }
868c6fd2807SJeff Garzik 
869c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
870c6fd2807SJeff Garzik {
871c6fd2807SJeff Garzik 	unsigned int ofs = mv_scr_offset(sc_reg_in);
872c6fd2807SJeff Garzik 
87335177265SJeff Garzik 	if (0xffffffffU != ofs)
874c6fd2807SJeff Garzik 		return readl(mv_ap_base(ap) + ofs);
87535177265SJeff Garzik 	else
876c6fd2807SJeff Garzik 		return (u32) ofs;
877c6fd2807SJeff Garzik }
878c6fd2807SJeff Garzik 
879c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
880c6fd2807SJeff Garzik {
881c6fd2807SJeff Garzik 	unsigned int ofs = mv_scr_offset(sc_reg_in);
882c6fd2807SJeff Garzik 
88335177265SJeff Garzik 	if (0xffffffffU != ofs)
884c6fd2807SJeff Garzik 		writelfl(val, mv_ap_base(ap) + ofs);
885c6fd2807SJeff Garzik }
886c6fd2807SJeff Garzik 
887c6fd2807SJeff Garzik static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
888c6fd2807SJeff Garzik {
889c6fd2807SJeff Garzik 	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
890c6fd2807SJeff Garzik 
891c6fd2807SJeff Garzik 	/* set up non-NCQ EDMA configuration */
892c6fd2807SJeff Garzik 	cfg &= ~(1 << 9);	/* disable equeue */
893c6fd2807SJeff Garzik 
894e728eabeSJeff Garzik 	if (IS_GEN_I(hpriv)) {
895e728eabeSJeff Garzik 		cfg &= ~0x1f;		/* clear queue depth */
896c6fd2807SJeff Garzik 		cfg |= (1 << 8);	/* enab config burst size mask */
897e728eabeSJeff Garzik 	}
898c6fd2807SJeff Garzik 
899e728eabeSJeff Garzik 	else if (IS_GEN_II(hpriv)) {
900e728eabeSJeff Garzik 		cfg &= ~0x1f;		/* clear queue depth */
901c6fd2807SJeff Garzik 		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
902e728eabeSJeff Garzik 		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
903e728eabeSJeff Garzik 	}
904c6fd2807SJeff Garzik 
905c6fd2807SJeff Garzik 	else if (IS_GEN_IIE(hpriv)) {
906e728eabeSJeff Garzik 		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
907e728eabeSJeff Garzik 		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
908c6fd2807SJeff Garzik 		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
909c6fd2807SJeff Garzik 		cfg |= (1 << 18);	/* enab early completion */
910e728eabeSJeff Garzik 		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
911e728eabeSJeff Garzik 		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
912e728eabeSJeff Garzik 		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
913c6fd2807SJeff Garzik 	}
914c6fd2807SJeff Garzik 
915c6fd2807SJeff Garzik 	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
916c6fd2807SJeff Garzik }
917c6fd2807SJeff Garzik 
918c6fd2807SJeff Garzik /**
919c6fd2807SJeff Garzik  *      mv_port_start - Port specific init/start routine.
920c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
921c6fd2807SJeff Garzik  *
922c6fd2807SJeff Garzik  *      Allocate and point to DMA memory, init port private memory,
923c6fd2807SJeff Garzik  *      zero indices.
924c6fd2807SJeff Garzik  *
925c6fd2807SJeff Garzik  *      LOCKING:
926c6fd2807SJeff Garzik  *      Inherited from caller.
927c6fd2807SJeff Garzik  */
928c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap)
929c6fd2807SJeff Garzik {
930cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
931cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
932c6fd2807SJeff Garzik 	struct mv_port_priv *pp;
933c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
934c6fd2807SJeff Garzik 	void *mem;
935c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
93624dc5f33STejun Heo 	int rc;
937c6fd2807SJeff Garzik 
93824dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
939c6fd2807SJeff Garzik 	if (!pp)
94024dc5f33STejun Heo 		return -ENOMEM;
941c6fd2807SJeff Garzik 
94224dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
943c6fd2807SJeff Garzik 				  GFP_KERNEL);
944c6fd2807SJeff Garzik 	if (!mem)
94524dc5f33STejun Heo 		return -ENOMEM;
946c6fd2807SJeff Garzik 	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
947c6fd2807SJeff Garzik 
948c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
949c6fd2807SJeff Garzik 	if (rc)
95024dc5f33STejun Heo 		return rc;
951c6fd2807SJeff Garzik 
952c6fd2807SJeff Garzik 	/* First item in chunk of DMA memory:
953c6fd2807SJeff Garzik 	 * 32-slot command request table (CRQB), 32 bytes each in size
954c6fd2807SJeff Garzik 	 */
955c6fd2807SJeff Garzik 	pp->crqb = mem;
956c6fd2807SJeff Garzik 	pp->crqb_dma = mem_dma;
957c6fd2807SJeff Garzik 	mem += MV_CRQB_Q_SZ;
958c6fd2807SJeff Garzik 	mem_dma += MV_CRQB_Q_SZ;
959c6fd2807SJeff Garzik 
960c6fd2807SJeff Garzik 	/* Second item:
961c6fd2807SJeff Garzik 	 * 32-slot command response table (CRPB), 8 bytes each in size
962c6fd2807SJeff Garzik 	 */
963c6fd2807SJeff Garzik 	pp->crpb = mem;
964c6fd2807SJeff Garzik 	pp->crpb_dma = mem_dma;
965c6fd2807SJeff Garzik 	mem += MV_CRPB_Q_SZ;
966c6fd2807SJeff Garzik 	mem_dma += MV_CRPB_Q_SZ;
967c6fd2807SJeff Garzik 
968c6fd2807SJeff Garzik 	/* Third item:
969c6fd2807SJeff Garzik 	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
970c6fd2807SJeff Garzik 	 */
971c6fd2807SJeff Garzik 	pp->sg_tbl = mem;
972c6fd2807SJeff Garzik 	pp->sg_tbl_dma = mem_dma;
973c6fd2807SJeff Garzik 
974c6fd2807SJeff Garzik 	mv_edma_cfg(hpriv, port_mmio);
975c6fd2807SJeff Garzik 
976c6fd2807SJeff Garzik 	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
977c6fd2807SJeff Garzik 	writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
978c6fd2807SJeff Garzik 		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
979c6fd2807SJeff Garzik 
980c6fd2807SJeff Garzik 	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
981c6fd2807SJeff Garzik 		writelfl(pp->crqb_dma & 0xffffffff,
982c6fd2807SJeff Garzik 			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
983c6fd2807SJeff Garzik 	else
984c6fd2807SJeff Garzik 		writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
985c6fd2807SJeff Garzik 
986c6fd2807SJeff Garzik 	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
987c6fd2807SJeff Garzik 
988c6fd2807SJeff Garzik 	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
989c6fd2807SJeff Garzik 		writelfl(pp->crpb_dma & 0xffffffff,
990c6fd2807SJeff Garzik 			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
991c6fd2807SJeff Garzik 	else
992c6fd2807SJeff Garzik 		writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
993c6fd2807SJeff Garzik 
994c6fd2807SJeff Garzik 	writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
995c6fd2807SJeff Garzik 		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
996c6fd2807SJeff Garzik 
997c6fd2807SJeff Garzik 	/* Don't turn on EDMA here...do it before DMA commands only.  Else
998c6fd2807SJeff Garzik 	 * we'll be unable to send non-data, PIO, etc due to restricted access
999c6fd2807SJeff Garzik 	 * to shadow regs.
1000c6fd2807SJeff Garzik 	 */
1001c6fd2807SJeff Garzik 	ap->private_data = pp;
1002c6fd2807SJeff Garzik 	return 0;
1003c6fd2807SJeff Garzik }
1004c6fd2807SJeff Garzik 
1005c6fd2807SJeff Garzik /**
1006c6fd2807SJeff Garzik  *      mv_port_stop - Port specific cleanup/stop routine.
1007c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1008c6fd2807SJeff Garzik  *
1009c6fd2807SJeff Garzik  *      Stop DMA, cleanup port memory.
1010c6fd2807SJeff Garzik  *
1011c6fd2807SJeff Garzik  *      LOCKING:
1012cca3974eSJeff Garzik  *      This routine uses the host lock to protect the DMA stop.
1013c6fd2807SJeff Garzik  */
1014c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap)
1015c6fd2807SJeff Garzik {
1016c6fd2807SJeff Garzik 	unsigned long flags;
1017c6fd2807SJeff Garzik 
1018cca3974eSJeff Garzik 	spin_lock_irqsave(&ap->host->lock, flags);
1019c6fd2807SJeff Garzik 	mv_stop_dma(ap);
1020cca3974eSJeff Garzik 	spin_unlock_irqrestore(&ap->host->lock, flags);
1021c6fd2807SJeff Garzik }
1022c6fd2807SJeff Garzik 
1023c6fd2807SJeff Garzik /**
1024c6fd2807SJeff Garzik  *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
1025c6fd2807SJeff Garzik  *      @qc: queued command whose SG list to source from
1026c6fd2807SJeff Garzik  *
1027c6fd2807SJeff Garzik  *      Populate the SG list and mark the last entry.
1028c6fd2807SJeff Garzik  *
1029c6fd2807SJeff Garzik  *      LOCKING:
1030c6fd2807SJeff Garzik  *      Inherited from caller.
1031c6fd2807SJeff Garzik  */
1032d88184fbSJeff Garzik static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
1033c6fd2807SJeff Garzik {
1034c6fd2807SJeff Garzik 	struct mv_port_priv *pp = qc->ap->private_data;
1035d88184fbSJeff Garzik 	unsigned int n_sg = 0;
1036c6fd2807SJeff Garzik 	struct scatterlist *sg;
1037d88184fbSJeff Garzik 	struct mv_sg *mv_sg;
1038c6fd2807SJeff Garzik 
1039d88184fbSJeff Garzik 	mv_sg = pp->sg_tbl;
1040c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
1041d88184fbSJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1042d88184fbSJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1043c6fd2807SJeff Garzik 
1044d88184fbSJeff Garzik 		mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
1045d88184fbSJeff Garzik 		mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1046d88184fbSJeff Garzik 		mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
1047c6fd2807SJeff Garzik 
1048d88184fbSJeff Garzik 		if (ata_sg_is_last(sg, qc))
1049d88184fbSJeff Garzik 			mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
1050c6fd2807SJeff Garzik 
1051d88184fbSJeff Garzik 		mv_sg++;
1052d88184fbSJeff Garzik 		n_sg++;
1053c6fd2807SJeff Garzik 	}
1054d88184fbSJeff Garzik 
1055d88184fbSJeff Garzik 	return n_sg;
1056c6fd2807SJeff Garzik }
1057c6fd2807SJeff Garzik 
1058c6fd2807SJeff Garzik static inline unsigned mv_inc_q_index(unsigned index)
1059c6fd2807SJeff Garzik {
1060c6fd2807SJeff Garzik 	return (index + 1) & MV_MAX_Q_DEPTH_MASK;
1061c6fd2807SJeff Garzik }
1062c6fd2807SJeff Garzik 
1063c6fd2807SJeff Garzik static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
1064c6fd2807SJeff Garzik {
1065c6fd2807SJeff Garzik 	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
1066c6fd2807SJeff Garzik 		(last ? CRQB_CMD_LAST : 0);
1067c6fd2807SJeff Garzik 	*cmdw = cpu_to_le16(tmp);
1068c6fd2807SJeff Garzik }
1069c6fd2807SJeff Garzik 
1070c6fd2807SJeff Garzik /**
1071c6fd2807SJeff Garzik  *      mv_qc_prep - Host specific command preparation.
1072c6fd2807SJeff Garzik  *      @qc: queued command to prepare
1073c6fd2807SJeff Garzik  *
1074c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1075c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it handles prep of the CRQB
1076c6fd2807SJeff Garzik  *      (command request block), does some sanity checking, and calls
1077c6fd2807SJeff Garzik  *      the SG load routine.
1078c6fd2807SJeff Garzik  *
1079c6fd2807SJeff Garzik  *      LOCKING:
1080c6fd2807SJeff Garzik  *      Inherited from caller.
1081c6fd2807SJeff Garzik  */
1082c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc)
1083c6fd2807SJeff Garzik {
1084c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1085c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1086c6fd2807SJeff Garzik 	__le16 *cw;
1087c6fd2807SJeff Garzik 	struct ata_taskfile *tf;
1088c6fd2807SJeff Garzik 	u16 flags = 0;
1089c6fd2807SJeff Garzik 	unsigned in_index;
1090c6fd2807SJeff Garzik 
1091c6fd2807SJeff Garzik  	if (ATA_PROT_DMA != qc->tf.protocol)
1092c6fd2807SJeff Garzik 		return;
1093c6fd2807SJeff Garzik 
1094c6fd2807SJeff Garzik 	/* Fill in command request block
1095c6fd2807SJeff Garzik 	 */
1096c6fd2807SJeff Garzik 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1097c6fd2807SJeff Garzik 		flags |= CRQB_FLAG_READ;
1098c6fd2807SJeff Garzik 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1099c6fd2807SJeff Garzik 	flags |= qc->tag << CRQB_TAG_SHIFT;
1100c6fd2807SJeff Garzik 
1101c6fd2807SJeff Garzik 	/* get current queue index from hardware */
1102c6fd2807SJeff Garzik 	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
1103c6fd2807SJeff Garzik 			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1104c6fd2807SJeff Garzik 
1105c6fd2807SJeff Garzik 	pp->crqb[in_index].sg_addr =
1106c6fd2807SJeff Garzik 		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1107c6fd2807SJeff Garzik 	pp->crqb[in_index].sg_addr_hi =
1108c6fd2807SJeff Garzik 		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1109c6fd2807SJeff Garzik 	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
1110c6fd2807SJeff Garzik 
1111c6fd2807SJeff Garzik 	cw = &pp->crqb[in_index].ata_cmd[0];
1112c6fd2807SJeff Garzik 	tf = &qc->tf;
1113c6fd2807SJeff Garzik 
1114c6fd2807SJeff Garzik 	/* Sadly, the CRQB cannot accomodate all registers--there are
1115c6fd2807SJeff Garzik 	 * only 11 bytes...so we must pick and choose required
1116c6fd2807SJeff Garzik 	 * registers based on the command.  So, we drop feature and
1117c6fd2807SJeff Garzik 	 * hob_feature for [RW] DMA commands, but they are needed for
1118c6fd2807SJeff Garzik 	 * NCQ.  NCQ will drop hob_nsect.
1119c6fd2807SJeff Garzik 	 */
1120c6fd2807SJeff Garzik 	switch (tf->command) {
1121c6fd2807SJeff Garzik 	case ATA_CMD_READ:
1122c6fd2807SJeff Garzik 	case ATA_CMD_READ_EXT:
1123c6fd2807SJeff Garzik 	case ATA_CMD_WRITE:
1124c6fd2807SJeff Garzik 	case ATA_CMD_WRITE_EXT:
1125c6fd2807SJeff Garzik 	case ATA_CMD_WRITE_FUA_EXT:
1126c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
1127c6fd2807SJeff Garzik 		break;
1128c6fd2807SJeff Garzik #ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
1129c6fd2807SJeff Garzik 	case ATA_CMD_FPDMA_READ:
1130c6fd2807SJeff Garzik 	case ATA_CMD_FPDMA_WRITE:
1131c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
1132c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
1133c6fd2807SJeff Garzik 		break;
1134c6fd2807SJeff Garzik #endif				/* FIXME: remove this line when NCQ added */
1135c6fd2807SJeff Garzik 	default:
1136c6fd2807SJeff Garzik 		/* The only other commands EDMA supports in non-queued and
1137c6fd2807SJeff Garzik 		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
1138c6fd2807SJeff Garzik 		 * of which are defined/used by Linux.  If we get here, this
1139c6fd2807SJeff Garzik 		 * driver needs work.
1140c6fd2807SJeff Garzik 		 *
1141c6fd2807SJeff Garzik 		 * FIXME: modify libata to give qc_prep a return value and
1142c6fd2807SJeff Garzik 		 * return error here.
1143c6fd2807SJeff Garzik 		 */
1144c6fd2807SJeff Garzik 		BUG_ON(tf->command);
1145c6fd2807SJeff Garzik 		break;
1146c6fd2807SJeff Garzik 	}
1147c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
1148c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
1149c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
1150c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
1151c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
1152c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
1153c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
1154c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
1155c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
1156c6fd2807SJeff Garzik 
1157c6fd2807SJeff Garzik 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1158c6fd2807SJeff Garzik 		return;
1159c6fd2807SJeff Garzik 	mv_fill_sg(qc);
1160c6fd2807SJeff Garzik }
1161c6fd2807SJeff Garzik 
1162c6fd2807SJeff Garzik /**
1163c6fd2807SJeff Garzik  *      mv_qc_prep_iie - Host specific command preparation.
1164c6fd2807SJeff Garzik  *      @qc: queued command to prepare
1165c6fd2807SJeff Garzik  *
1166c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1167c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it handles prep of the CRQB
1168c6fd2807SJeff Garzik  *      (command request block), does some sanity checking, and calls
1169c6fd2807SJeff Garzik  *      the SG load routine.
1170c6fd2807SJeff Garzik  *
1171c6fd2807SJeff Garzik  *      LOCKING:
1172c6fd2807SJeff Garzik  *      Inherited from caller.
1173c6fd2807SJeff Garzik  */
1174c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1175c6fd2807SJeff Garzik {
1176c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1177c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1178c6fd2807SJeff Garzik 	struct mv_crqb_iie *crqb;
1179c6fd2807SJeff Garzik 	struct ata_taskfile *tf;
1180c6fd2807SJeff Garzik 	unsigned in_index;
1181c6fd2807SJeff Garzik 	u32 flags = 0;
1182c6fd2807SJeff Garzik 
1183c6fd2807SJeff Garzik  	if (ATA_PROT_DMA != qc->tf.protocol)
1184c6fd2807SJeff Garzik 		return;
1185c6fd2807SJeff Garzik 
1186c6fd2807SJeff Garzik 	/* Fill in Gen IIE command request block
1187c6fd2807SJeff Garzik 	 */
1188c6fd2807SJeff Garzik 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1189c6fd2807SJeff Garzik 		flags |= CRQB_FLAG_READ;
1190c6fd2807SJeff Garzik 
1191c6fd2807SJeff Garzik 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1192c6fd2807SJeff Garzik 	flags |= qc->tag << CRQB_TAG_SHIFT;
1193c6fd2807SJeff Garzik 
1194c6fd2807SJeff Garzik 	/* get current queue index from hardware */
1195c6fd2807SJeff Garzik 	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
1196c6fd2807SJeff Garzik 			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1197c6fd2807SJeff Garzik 
1198c6fd2807SJeff Garzik 	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1199c6fd2807SJeff Garzik 	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1200c6fd2807SJeff Garzik 	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1201c6fd2807SJeff Garzik 	crqb->flags = cpu_to_le32(flags);
1202c6fd2807SJeff Garzik 
1203c6fd2807SJeff Garzik 	tf = &qc->tf;
1204c6fd2807SJeff Garzik 	crqb->ata_cmd[0] = cpu_to_le32(
1205c6fd2807SJeff Garzik 			(tf->command << 16) |
1206c6fd2807SJeff Garzik 			(tf->feature << 24)
1207c6fd2807SJeff Garzik 		);
1208c6fd2807SJeff Garzik 	crqb->ata_cmd[1] = cpu_to_le32(
1209c6fd2807SJeff Garzik 			(tf->lbal << 0) |
1210c6fd2807SJeff Garzik 			(tf->lbam << 8) |
1211c6fd2807SJeff Garzik 			(tf->lbah << 16) |
1212c6fd2807SJeff Garzik 			(tf->device << 24)
1213c6fd2807SJeff Garzik 		);
1214c6fd2807SJeff Garzik 	crqb->ata_cmd[2] = cpu_to_le32(
1215c6fd2807SJeff Garzik 			(tf->hob_lbal << 0) |
1216c6fd2807SJeff Garzik 			(tf->hob_lbam << 8) |
1217c6fd2807SJeff Garzik 			(tf->hob_lbah << 16) |
1218c6fd2807SJeff Garzik 			(tf->hob_feature << 24)
1219c6fd2807SJeff Garzik 		);
1220c6fd2807SJeff Garzik 	crqb->ata_cmd[3] = cpu_to_le32(
1221c6fd2807SJeff Garzik 			(tf->nsect << 0) |
1222c6fd2807SJeff Garzik 			(tf->hob_nsect << 8)
1223c6fd2807SJeff Garzik 		);
1224c6fd2807SJeff Garzik 
1225c6fd2807SJeff Garzik 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1226c6fd2807SJeff Garzik 		return;
1227c6fd2807SJeff Garzik 	mv_fill_sg(qc);
1228c6fd2807SJeff Garzik }
1229c6fd2807SJeff Garzik 
1230c6fd2807SJeff Garzik /**
1231c6fd2807SJeff Garzik  *      mv_qc_issue - Initiate a command to the host
1232c6fd2807SJeff Garzik  *      @qc: queued command to start
1233c6fd2807SJeff Garzik  *
1234c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1235c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it sanity checks our local
1236c6fd2807SJeff Garzik  *      caches of the request producer/consumer indices then enables
1237c6fd2807SJeff Garzik  *      DMA and bumps the request producer index.
1238c6fd2807SJeff Garzik  *
1239c6fd2807SJeff Garzik  *      LOCKING:
1240c6fd2807SJeff Garzik  *      Inherited from caller.
1241c6fd2807SJeff Garzik  */
1242c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
1243c6fd2807SJeff Garzik {
1244c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(qc->ap);
1245c6fd2807SJeff Garzik 	struct mv_port_priv *pp = qc->ap->private_data;
1246c6fd2807SJeff Garzik 	unsigned in_index;
1247c6fd2807SJeff Garzik 	u32 in_ptr;
1248c6fd2807SJeff Garzik 
1249c6fd2807SJeff Garzik 	if (ATA_PROT_DMA != qc->tf.protocol) {
1250c6fd2807SJeff Garzik 		/* We're about to send a non-EDMA capable command to the
1251c6fd2807SJeff Garzik 		 * port.  Turn off EDMA so there won't be problems accessing
1252c6fd2807SJeff Garzik 		 * shadow block, etc registers.
1253c6fd2807SJeff Garzik 		 */
1254c6fd2807SJeff Garzik 		mv_stop_dma(qc->ap);
1255c6fd2807SJeff Garzik 		return ata_qc_issue_prot(qc);
1256c6fd2807SJeff Garzik 	}
1257c6fd2807SJeff Garzik 
1258c6fd2807SJeff Garzik 	in_ptr   = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
1259c6fd2807SJeff Garzik 	in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1260c6fd2807SJeff Garzik 
1261c6fd2807SJeff Garzik 	/* until we do queuing, the queue should be empty at this point */
1262c6fd2807SJeff Garzik 	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1263c6fd2807SJeff Garzik 		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
1264c6fd2807SJeff Garzik 
1265c6fd2807SJeff Garzik 	in_index = mv_inc_q_index(in_index);	/* now incr producer index */
1266c6fd2807SJeff Garzik 
1267c6fd2807SJeff Garzik 	mv_start_dma(port_mmio, pp);
1268c6fd2807SJeff Garzik 
1269c6fd2807SJeff Garzik 	/* and write the request in pointer to kick the EDMA to life */
1270c6fd2807SJeff Garzik 	in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
1271c6fd2807SJeff Garzik 	in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
1272c6fd2807SJeff Garzik 	writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
1273c6fd2807SJeff Garzik 
1274c6fd2807SJeff Garzik 	return 0;
1275c6fd2807SJeff Garzik }
1276c6fd2807SJeff Garzik 
1277c6fd2807SJeff Garzik /**
1278c6fd2807SJeff Garzik  *      mv_get_crpb_status - get status from most recently completed cmd
1279c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1280c6fd2807SJeff Garzik  *
1281c6fd2807SJeff Garzik  *      This routine is for use when the port is in DMA mode, when it
1282c6fd2807SJeff Garzik  *      will be using the CRPB (command response block) method of
1283c6fd2807SJeff Garzik  *      returning command completion information.  We check indices
1284c6fd2807SJeff Garzik  *      are good, grab status, and bump the response consumer index to
1285c6fd2807SJeff Garzik  *      prove that we're up to date.
1286c6fd2807SJeff Garzik  *
1287c6fd2807SJeff Garzik  *      LOCKING:
1288c6fd2807SJeff Garzik  *      Inherited from caller.
1289c6fd2807SJeff Garzik  */
1290c6fd2807SJeff Garzik static u8 mv_get_crpb_status(struct ata_port *ap)
1291c6fd2807SJeff Garzik {
1292c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1293c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1294c6fd2807SJeff Garzik 	unsigned out_index;
1295c6fd2807SJeff Garzik 	u32 out_ptr;
1296c6fd2807SJeff Garzik 	u8 ata_status;
1297c6fd2807SJeff Garzik 
1298c6fd2807SJeff Garzik 	out_ptr   = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
1299c6fd2807SJeff Garzik 	out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1300c6fd2807SJeff Garzik 
1301c6fd2807SJeff Garzik 	ata_status = le16_to_cpu(pp->crpb[out_index].flags)
1302c6fd2807SJeff Garzik 					>> CRPB_FLAG_STATUS_SHIFT;
1303c6fd2807SJeff Garzik 
1304c6fd2807SJeff Garzik 	/* increment our consumer index... */
1305c6fd2807SJeff Garzik 	out_index = mv_inc_q_index(out_index);
1306c6fd2807SJeff Garzik 
1307c6fd2807SJeff Garzik 	/* and, until we do NCQ, there should only be 1 CRPB waiting */
1308c6fd2807SJeff Garzik 	WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1309c6fd2807SJeff Garzik 		>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
1310c6fd2807SJeff Garzik 
1311c6fd2807SJeff Garzik 	/* write out our inc'd consumer index so EDMA knows we're caught up */
1312c6fd2807SJeff Garzik 	out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
1313c6fd2807SJeff Garzik 	out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
1314c6fd2807SJeff Garzik 	writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
1315c6fd2807SJeff Garzik 
1316c6fd2807SJeff Garzik 	/* Return ATA status register for completed CRPB */
1317c6fd2807SJeff Garzik 	return ata_status;
1318c6fd2807SJeff Garzik }
1319c6fd2807SJeff Garzik 
1320c6fd2807SJeff Garzik /**
1321c6fd2807SJeff Garzik  *      mv_err_intr - Handle error interrupts on the port
1322c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1323c6fd2807SJeff Garzik  *      @reset_allowed: bool: 0 == don't trigger from reset here
1324c6fd2807SJeff Garzik  *
1325c6fd2807SJeff Garzik  *      In most cases, just clear the interrupt and move on.  However,
1326c6fd2807SJeff Garzik  *      some cases require an eDMA reset, which is done right before
1327c6fd2807SJeff Garzik  *      the COMRESET in mv_phy_reset().  The SERR case requires a
1328c6fd2807SJeff Garzik  *      clear of pending errors in the SATA SERROR register.  Finally,
1329c6fd2807SJeff Garzik  *      if the port disabled DMA, update our cached copy to match.
1330c6fd2807SJeff Garzik  *
1331c6fd2807SJeff Garzik  *      LOCKING:
1332c6fd2807SJeff Garzik  *      Inherited from caller.
1333c6fd2807SJeff Garzik  */
1334c6fd2807SJeff Garzik static void mv_err_intr(struct ata_port *ap, int reset_allowed)
1335c6fd2807SJeff Garzik {
1336c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1337c6fd2807SJeff Garzik 	u32 edma_err_cause, serr = 0;
1338c6fd2807SJeff Garzik 
1339c6fd2807SJeff Garzik 	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1340c6fd2807SJeff Garzik 
1341c6fd2807SJeff Garzik 	if (EDMA_ERR_SERR & edma_err_cause) {
1342c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_ERROR, &serr);
1343c6fd2807SJeff Garzik 		sata_scr_write_flush(ap, SCR_ERROR, serr);
1344c6fd2807SJeff Garzik 	}
1345c6fd2807SJeff Garzik 	if (EDMA_ERR_SELF_DIS & edma_err_cause) {
1346c6fd2807SJeff Garzik 		struct mv_port_priv *pp	= ap->private_data;
1347c6fd2807SJeff Garzik 		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1348c6fd2807SJeff Garzik 	}
1349c6fd2807SJeff Garzik 	DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
135044877b4eSTejun Heo 		"SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr);
1351c6fd2807SJeff Garzik 
1352c6fd2807SJeff Garzik 	/* Clear EDMA now that SERR cleanup done */
1353c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1354c6fd2807SJeff Garzik 
1355c6fd2807SJeff Garzik 	/* check for fatal here and recover if needed */
1356c6fd2807SJeff Garzik 	if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
1357c6fd2807SJeff Garzik 		mv_stop_and_reset(ap);
1358c6fd2807SJeff Garzik }
1359c6fd2807SJeff Garzik 
1360c6fd2807SJeff Garzik /**
1361c6fd2807SJeff Garzik  *      mv_host_intr - Handle all interrupts on the given host controller
1362cca3974eSJeff Garzik  *      @host: host specific structure
1363c6fd2807SJeff Garzik  *      @relevant: port error bits relevant to this host controller
1364c6fd2807SJeff Garzik  *      @hc: which host controller we're to look at
1365c6fd2807SJeff Garzik  *
1366c6fd2807SJeff Garzik  *      Read then write clear the HC interrupt status then walk each
1367c6fd2807SJeff Garzik  *      port connected to the HC and see if it needs servicing.  Port
1368c6fd2807SJeff Garzik  *      success ints are reported in the HC interrupt status reg, the
1369c6fd2807SJeff Garzik  *      port error ints are reported in the higher level main
1370c6fd2807SJeff Garzik  *      interrupt status register and thus are passed in via the
1371c6fd2807SJeff Garzik  *      'relevant' argument.
1372c6fd2807SJeff Garzik  *
1373c6fd2807SJeff Garzik  *      LOCKING:
1374c6fd2807SJeff Garzik  *      Inherited from caller.
1375c6fd2807SJeff Garzik  */
1376cca3974eSJeff Garzik static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
1377c6fd2807SJeff Garzik {
13780d5ff566STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
1379c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1380c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
1381c6fd2807SJeff Garzik 	u32 hc_irq_cause;
1382c6fd2807SJeff Garzik 	int shift, port, port0, hard_port, handled;
1383c6fd2807SJeff Garzik 	unsigned int err_mask;
1384c6fd2807SJeff Garzik 
138535177265SJeff Garzik 	if (hc == 0)
1386c6fd2807SJeff Garzik 		port0 = 0;
138735177265SJeff Garzik 	else
1388c6fd2807SJeff Garzik 		port0 = MV_PORTS_PER_HC;
1389c6fd2807SJeff Garzik 
1390c6fd2807SJeff Garzik 	/* we'll need the HC success int register in most cases */
1391c6fd2807SJeff Garzik 	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
139235177265SJeff Garzik 	if (hc_irq_cause)
1393c6fd2807SJeff Garzik 		writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
1394c6fd2807SJeff Garzik 
1395c6fd2807SJeff Garzik 	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
1396c6fd2807SJeff Garzik 		hc,relevant,hc_irq_cause);
1397c6fd2807SJeff Garzik 
1398c6fd2807SJeff Garzik 	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
1399c6fd2807SJeff Garzik 		u8 ata_status = 0;
1400cca3974eSJeff Garzik 		struct ata_port *ap = host->ports[port];
1401c6fd2807SJeff Garzik 		struct mv_port_priv *pp = ap->private_data;
1402c6fd2807SJeff Garzik 
1403c6fd2807SJeff Garzik 		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1404c6fd2807SJeff Garzik 		handled = 0;	/* ensure ata_status is set if handled++ */
1405c6fd2807SJeff Garzik 
1406c6fd2807SJeff Garzik 		/* Note that DEV_IRQ might happen spuriously during EDMA,
1407c6fd2807SJeff Garzik 		 * and should be ignored in such cases.
1408c6fd2807SJeff Garzik 		 * The cause of this is still under investigation.
1409c6fd2807SJeff Garzik 		 */
1410c6fd2807SJeff Garzik 		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1411c6fd2807SJeff Garzik 			/* EDMA: check for response queue interrupt */
1412c6fd2807SJeff Garzik 			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
1413c6fd2807SJeff Garzik 				ata_status = mv_get_crpb_status(ap);
1414c6fd2807SJeff Garzik 				handled = 1;
1415c6fd2807SJeff Garzik 			}
1416c6fd2807SJeff Garzik 		} else {
1417c6fd2807SJeff Garzik 			/* PIO: check for device (drive) interrupt */
1418c6fd2807SJeff Garzik 			if ((DEV_IRQ << hard_port) & hc_irq_cause) {
14190d5ff566STejun Heo 				ata_status = readb(ap->ioaddr.status_addr);
1420c6fd2807SJeff Garzik 				handled = 1;
1421c6fd2807SJeff Garzik 				/* ignore spurious intr if drive still BUSY */
1422c6fd2807SJeff Garzik 				if (ata_status & ATA_BUSY) {
1423c6fd2807SJeff Garzik 					ata_status = 0;
1424c6fd2807SJeff Garzik 					handled = 0;
1425c6fd2807SJeff Garzik 				}
1426c6fd2807SJeff Garzik 			}
1427c6fd2807SJeff Garzik 		}
1428c6fd2807SJeff Garzik 
1429c6fd2807SJeff Garzik 		if (ap && (ap->flags & ATA_FLAG_DISABLED))
1430c6fd2807SJeff Garzik 			continue;
1431c6fd2807SJeff Garzik 
1432c6fd2807SJeff Garzik 		err_mask = ac_err_mask(ata_status);
1433c6fd2807SJeff Garzik 
1434c6fd2807SJeff Garzik 		shift = port << 1;		/* (port * 2) */
1435c6fd2807SJeff Garzik 		if (port >= MV_PORTS_PER_HC) {
1436c6fd2807SJeff Garzik 			shift++;	/* skip bit 8 in the HC Main IRQ reg */
1437c6fd2807SJeff Garzik 		}
1438c6fd2807SJeff Garzik 		if ((PORT0_ERR << shift) & relevant) {
1439c6fd2807SJeff Garzik 			mv_err_intr(ap, 1);
1440c6fd2807SJeff Garzik 			err_mask |= AC_ERR_OTHER;
1441c6fd2807SJeff Garzik 			handled = 1;
1442c6fd2807SJeff Garzik 		}
1443c6fd2807SJeff Garzik 
1444c6fd2807SJeff Garzik 		if (handled) {
1445c6fd2807SJeff Garzik 			qc = ata_qc_from_tag(ap, ap->active_tag);
1446c6fd2807SJeff Garzik 			if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
1447c6fd2807SJeff Garzik 				VPRINTK("port %u IRQ found for qc, "
1448c6fd2807SJeff Garzik 					"ata_status 0x%x\n", port,ata_status);
1449c6fd2807SJeff Garzik 				/* mark qc status appropriately */
1450c6fd2807SJeff Garzik 				if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
1451c6fd2807SJeff Garzik 					qc->err_mask |= err_mask;
1452c6fd2807SJeff Garzik 					ata_qc_complete(qc);
1453c6fd2807SJeff Garzik 				}
1454c6fd2807SJeff Garzik 			}
1455c6fd2807SJeff Garzik 		}
1456c6fd2807SJeff Garzik 	}
1457c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1458c6fd2807SJeff Garzik }
1459c6fd2807SJeff Garzik 
1460c6fd2807SJeff Garzik /**
1461c6fd2807SJeff Garzik  *      mv_interrupt -
1462c6fd2807SJeff Garzik  *      @irq: unused
1463c6fd2807SJeff Garzik  *      @dev_instance: private data; in this case the host structure
1464c6fd2807SJeff Garzik  *      @regs: unused
1465c6fd2807SJeff Garzik  *
1466c6fd2807SJeff Garzik  *      Read the read only register to determine if any host
1467c6fd2807SJeff Garzik  *      controllers have pending interrupts.  If so, call lower level
1468c6fd2807SJeff Garzik  *      routine to handle.  Also check for PCI errors which are only
1469c6fd2807SJeff Garzik  *      reported here.
1470c6fd2807SJeff Garzik  *
1471c6fd2807SJeff Garzik  *      LOCKING:
1472cca3974eSJeff Garzik  *      This routine holds the host lock while processing pending
1473c6fd2807SJeff Garzik  *      interrupts.
1474c6fd2807SJeff Garzik  */
14757d12e780SDavid Howells static irqreturn_t mv_interrupt(int irq, void *dev_instance)
1476c6fd2807SJeff Garzik {
1477cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1478c6fd2807SJeff Garzik 	unsigned int hc, handled = 0, n_hcs;
14790d5ff566STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
1480c6fd2807SJeff Garzik 	struct mv_host_priv *hpriv;
1481c6fd2807SJeff Garzik 	u32 irq_stat;
1482c6fd2807SJeff Garzik 
1483c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
1484c6fd2807SJeff Garzik 
1485c6fd2807SJeff Garzik 	/* check the cases where we either have nothing pending or have read
1486c6fd2807SJeff Garzik 	 * a bogus register value which can indicate HW removal or PCI fault
1487c6fd2807SJeff Garzik 	 */
148835177265SJeff Garzik 	if (!irq_stat || (0xffffffffU == irq_stat))
1489c6fd2807SJeff Garzik 		return IRQ_NONE;
1490c6fd2807SJeff Garzik 
1491cca3974eSJeff Garzik 	n_hcs = mv_get_hc_count(host->ports[0]->flags);
1492cca3974eSJeff Garzik 	spin_lock(&host->lock);
1493c6fd2807SJeff Garzik 
1494c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hcs; hc++) {
1495c6fd2807SJeff Garzik 		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
1496c6fd2807SJeff Garzik 		if (relevant) {
1497cca3974eSJeff Garzik 			mv_host_intr(host, relevant, hc);
1498c6fd2807SJeff Garzik 			handled++;
1499c6fd2807SJeff Garzik 		}
1500c6fd2807SJeff Garzik 	}
1501c6fd2807SJeff Garzik 
1502cca3974eSJeff Garzik 	hpriv = host->private_data;
1503c6fd2807SJeff Garzik 	if (IS_60XX(hpriv)) {
1504c6fd2807SJeff Garzik 		/* deal with the interrupt coalescing bits */
1505c6fd2807SJeff Garzik 		if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
1506c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
1507c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
1508c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
1509c6fd2807SJeff Garzik 		}
1510c6fd2807SJeff Garzik 	}
1511c6fd2807SJeff Garzik 
1512c6fd2807SJeff Garzik 	if (PCI_ERR & irq_stat) {
1513c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
1514c6fd2807SJeff Garzik 		       readl(mmio + PCI_IRQ_CAUSE_OFS));
1515c6fd2807SJeff Garzik 
1516c6fd2807SJeff Garzik 		DPRINTK("All regs @ PCI error\n");
1517cca3974eSJeff Garzik 		mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1518c6fd2807SJeff Garzik 
1519c6fd2807SJeff Garzik 		writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
1520c6fd2807SJeff Garzik 		handled++;
1521c6fd2807SJeff Garzik 	}
1522cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1523c6fd2807SJeff Garzik 
1524c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1525c6fd2807SJeff Garzik }
1526c6fd2807SJeff Garzik 
1527c6fd2807SJeff Garzik static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1528c6fd2807SJeff Garzik {
1529c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1530c6fd2807SJeff Garzik 	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1531c6fd2807SJeff Garzik 
1532c6fd2807SJeff Garzik 	return hc_mmio + ofs;
1533c6fd2807SJeff Garzik }
1534c6fd2807SJeff Garzik 
1535c6fd2807SJeff Garzik static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1536c6fd2807SJeff Garzik {
1537c6fd2807SJeff Garzik 	unsigned int ofs;
1538c6fd2807SJeff Garzik 
1539c6fd2807SJeff Garzik 	switch (sc_reg_in) {
1540c6fd2807SJeff Garzik 	case SCR_STATUS:
1541c6fd2807SJeff Garzik 	case SCR_ERROR:
1542c6fd2807SJeff Garzik 	case SCR_CONTROL:
1543c6fd2807SJeff Garzik 		ofs = sc_reg_in * sizeof(u32);
1544c6fd2807SJeff Garzik 		break;
1545c6fd2807SJeff Garzik 	default:
1546c6fd2807SJeff Garzik 		ofs = 0xffffffffU;
1547c6fd2807SJeff Garzik 		break;
1548c6fd2807SJeff Garzik 	}
1549c6fd2807SJeff Garzik 	return ofs;
1550c6fd2807SJeff Garzik }
1551c6fd2807SJeff Garzik 
1552c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
1553c6fd2807SJeff Garzik {
15540d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
15550d5ff566STejun Heo 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1556c6fd2807SJeff Garzik 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1557c6fd2807SJeff Garzik 
1558c6fd2807SJeff Garzik 	if (ofs != 0xffffffffU)
15590d5ff566STejun Heo 		return readl(addr + ofs);
1560c6fd2807SJeff Garzik 	else
1561c6fd2807SJeff Garzik 		return (u32) ofs;
1562c6fd2807SJeff Garzik }
1563c6fd2807SJeff Garzik 
1564c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1565c6fd2807SJeff Garzik {
15660d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
15670d5ff566STejun Heo 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1568c6fd2807SJeff Garzik 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1569c6fd2807SJeff Garzik 
1570c6fd2807SJeff Garzik 	if (ofs != 0xffffffffU)
15710d5ff566STejun Heo 		writelfl(val, addr + ofs);
1572c6fd2807SJeff Garzik }
1573c6fd2807SJeff Garzik 
1574c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1575c6fd2807SJeff Garzik {
1576c6fd2807SJeff Garzik 	u8 rev_id;
1577c6fd2807SJeff Garzik 	int early_5080;
1578c6fd2807SJeff Garzik 
1579c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
1580c6fd2807SJeff Garzik 
1581c6fd2807SJeff Garzik 	early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
1582c6fd2807SJeff Garzik 
1583c6fd2807SJeff Garzik 	if (!early_5080) {
1584c6fd2807SJeff Garzik 		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1585c6fd2807SJeff Garzik 		tmp |= (1 << 0);
1586c6fd2807SJeff Garzik 		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1587c6fd2807SJeff Garzik 	}
1588c6fd2807SJeff Garzik 
1589c6fd2807SJeff Garzik 	mv_reset_pci_bus(pdev, mmio);
1590c6fd2807SJeff Garzik }
1591c6fd2807SJeff Garzik 
1592c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1593c6fd2807SJeff Garzik {
1594c6fd2807SJeff Garzik 	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1595c6fd2807SJeff Garzik }
1596c6fd2807SJeff Garzik 
1597c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1598c6fd2807SJeff Garzik 			   void __iomem *mmio)
1599c6fd2807SJeff Garzik {
1600c6fd2807SJeff Garzik 	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1601c6fd2807SJeff Garzik 	u32 tmp;
1602c6fd2807SJeff Garzik 
1603c6fd2807SJeff Garzik 	tmp = readl(phy_mmio + MV5_PHY_MODE);
1604c6fd2807SJeff Garzik 
1605c6fd2807SJeff Garzik 	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1606c6fd2807SJeff Garzik 	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1607c6fd2807SJeff Garzik }
1608c6fd2807SJeff Garzik 
1609c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1610c6fd2807SJeff Garzik {
1611c6fd2807SJeff Garzik 	u32 tmp;
1612c6fd2807SJeff Garzik 
1613c6fd2807SJeff Garzik 	writel(0, mmio + MV_GPIO_PORT_CTL);
1614c6fd2807SJeff Garzik 
1615c6fd2807SJeff Garzik 	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1616c6fd2807SJeff Garzik 
1617c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1618c6fd2807SJeff Garzik 	tmp |= ~(1 << 0);
1619c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1620c6fd2807SJeff Garzik }
1621c6fd2807SJeff Garzik 
1622c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
1623c6fd2807SJeff Garzik 			   unsigned int port)
1624c6fd2807SJeff Garzik {
1625c6fd2807SJeff Garzik 	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1626c6fd2807SJeff Garzik 	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1627c6fd2807SJeff Garzik 	u32 tmp;
1628c6fd2807SJeff Garzik 	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1629c6fd2807SJeff Garzik 
1630c6fd2807SJeff Garzik 	if (fix_apm_sq) {
1631c6fd2807SJeff Garzik 		tmp = readl(phy_mmio + MV5_LT_MODE);
1632c6fd2807SJeff Garzik 		tmp |= (1 << 19);
1633c6fd2807SJeff Garzik 		writel(tmp, phy_mmio + MV5_LT_MODE);
1634c6fd2807SJeff Garzik 
1635c6fd2807SJeff Garzik 		tmp = readl(phy_mmio + MV5_PHY_CTL);
1636c6fd2807SJeff Garzik 		tmp &= ~0x3;
1637c6fd2807SJeff Garzik 		tmp |= 0x1;
1638c6fd2807SJeff Garzik 		writel(tmp, phy_mmio + MV5_PHY_CTL);
1639c6fd2807SJeff Garzik 	}
1640c6fd2807SJeff Garzik 
1641c6fd2807SJeff Garzik 	tmp = readl(phy_mmio + MV5_PHY_MODE);
1642c6fd2807SJeff Garzik 	tmp &= ~mask;
1643c6fd2807SJeff Garzik 	tmp |= hpriv->signal[port].pre;
1644c6fd2807SJeff Garzik 	tmp |= hpriv->signal[port].amps;
1645c6fd2807SJeff Garzik 	writel(tmp, phy_mmio + MV5_PHY_MODE);
1646c6fd2807SJeff Garzik }
1647c6fd2807SJeff Garzik 
1648c6fd2807SJeff Garzik 
1649c6fd2807SJeff Garzik #undef ZERO
1650c6fd2807SJeff Garzik #define ZERO(reg) writel(0, port_mmio + (reg))
1651c6fd2807SJeff Garzik static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1652c6fd2807SJeff Garzik 			     unsigned int port)
1653c6fd2807SJeff Garzik {
1654c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port);
1655c6fd2807SJeff Garzik 
1656c6fd2807SJeff Garzik 	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1657c6fd2807SJeff Garzik 
1658c6fd2807SJeff Garzik 	mv_channel_reset(hpriv, mmio, port);
1659c6fd2807SJeff Garzik 
1660c6fd2807SJeff Garzik 	ZERO(0x028);	/* command */
1661c6fd2807SJeff Garzik 	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1662c6fd2807SJeff Garzik 	ZERO(0x004);	/* timer */
1663c6fd2807SJeff Garzik 	ZERO(0x008);	/* irq err cause */
1664c6fd2807SJeff Garzik 	ZERO(0x00c);	/* irq err mask */
1665c6fd2807SJeff Garzik 	ZERO(0x010);	/* rq bah */
1666c6fd2807SJeff Garzik 	ZERO(0x014);	/* rq inp */
1667c6fd2807SJeff Garzik 	ZERO(0x018);	/* rq outp */
1668c6fd2807SJeff Garzik 	ZERO(0x01c);	/* respq bah */
1669c6fd2807SJeff Garzik 	ZERO(0x024);	/* respq outp */
1670c6fd2807SJeff Garzik 	ZERO(0x020);	/* respq inp */
1671c6fd2807SJeff Garzik 	ZERO(0x02c);	/* test control */
1672c6fd2807SJeff Garzik 	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1673c6fd2807SJeff Garzik }
1674c6fd2807SJeff Garzik #undef ZERO
1675c6fd2807SJeff Garzik 
1676c6fd2807SJeff Garzik #define ZERO(reg) writel(0, hc_mmio + (reg))
1677c6fd2807SJeff Garzik static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1678c6fd2807SJeff Garzik 			unsigned int hc)
1679c6fd2807SJeff Garzik {
1680c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1681c6fd2807SJeff Garzik 	u32 tmp;
1682c6fd2807SJeff Garzik 
1683c6fd2807SJeff Garzik 	ZERO(0x00c);
1684c6fd2807SJeff Garzik 	ZERO(0x010);
1685c6fd2807SJeff Garzik 	ZERO(0x014);
1686c6fd2807SJeff Garzik 	ZERO(0x018);
1687c6fd2807SJeff Garzik 
1688c6fd2807SJeff Garzik 	tmp = readl(hc_mmio + 0x20);
1689c6fd2807SJeff Garzik 	tmp &= 0x1c1c1c1c;
1690c6fd2807SJeff Garzik 	tmp |= 0x03030303;
1691c6fd2807SJeff Garzik 	writel(tmp, hc_mmio + 0x20);
1692c6fd2807SJeff Garzik }
1693c6fd2807SJeff Garzik #undef ZERO
1694c6fd2807SJeff Garzik 
1695c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1696c6fd2807SJeff Garzik 			unsigned int n_hc)
1697c6fd2807SJeff Garzik {
1698c6fd2807SJeff Garzik 	unsigned int hc, port;
1699c6fd2807SJeff Garzik 
1700c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hc; hc++) {
1701c6fd2807SJeff Garzik 		for (port = 0; port < MV_PORTS_PER_HC; port++)
1702c6fd2807SJeff Garzik 			mv5_reset_hc_port(hpriv, mmio,
1703c6fd2807SJeff Garzik 					  (hc * MV_PORTS_PER_HC) + port);
1704c6fd2807SJeff Garzik 
1705c6fd2807SJeff Garzik 		mv5_reset_one_hc(hpriv, mmio, hc);
1706c6fd2807SJeff Garzik 	}
1707c6fd2807SJeff Garzik 
1708c6fd2807SJeff Garzik 	return 0;
1709c6fd2807SJeff Garzik }
1710c6fd2807SJeff Garzik 
1711c6fd2807SJeff Garzik #undef ZERO
1712c6fd2807SJeff Garzik #define ZERO(reg) writel(0, mmio + (reg))
1713c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1714c6fd2807SJeff Garzik {
1715c6fd2807SJeff Garzik 	u32 tmp;
1716c6fd2807SJeff Garzik 
1717c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_PCI_MODE);
1718c6fd2807SJeff Garzik 	tmp &= 0xff00ffff;
1719c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_PCI_MODE);
1720c6fd2807SJeff Garzik 
1721c6fd2807SJeff Garzik 	ZERO(MV_PCI_DISC_TIMER);
1722c6fd2807SJeff Garzik 	ZERO(MV_PCI_MSI_TRIGGER);
1723c6fd2807SJeff Garzik 	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1724c6fd2807SJeff Garzik 	ZERO(HC_MAIN_IRQ_MASK_OFS);
1725c6fd2807SJeff Garzik 	ZERO(MV_PCI_SERR_MASK);
1726c6fd2807SJeff Garzik 	ZERO(PCI_IRQ_CAUSE_OFS);
1727c6fd2807SJeff Garzik 	ZERO(PCI_IRQ_MASK_OFS);
1728c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_LOW_ADDRESS);
1729c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1730c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_ATTRIBUTE);
1731c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_COMMAND);
1732c6fd2807SJeff Garzik }
1733c6fd2807SJeff Garzik #undef ZERO
1734c6fd2807SJeff Garzik 
1735c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1736c6fd2807SJeff Garzik {
1737c6fd2807SJeff Garzik 	u32 tmp;
1738c6fd2807SJeff Garzik 
1739c6fd2807SJeff Garzik 	mv5_reset_flash(hpriv, mmio);
1740c6fd2807SJeff Garzik 
1741c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_GPIO_PORT_CTL);
1742c6fd2807SJeff Garzik 	tmp &= 0x3;
1743c6fd2807SJeff Garzik 	tmp |= (1 << 5) | (1 << 6);
1744c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_GPIO_PORT_CTL);
1745c6fd2807SJeff Garzik }
1746c6fd2807SJeff Garzik 
1747c6fd2807SJeff Garzik /**
1748c6fd2807SJeff Garzik  *      mv6_reset_hc - Perform the 6xxx global soft reset
1749c6fd2807SJeff Garzik  *      @mmio: base address of the HBA
1750c6fd2807SJeff Garzik  *
1751c6fd2807SJeff Garzik  *      This routine only applies to 6xxx parts.
1752c6fd2807SJeff Garzik  *
1753c6fd2807SJeff Garzik  *      LOCKING:
1754c6fd2807SJeff Garzik  *      Inherited from caller.
1755c6fd2807SJeff Garzik  */
1756c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1757c6fd2807SJeff Garzik 			unsigned int n_hc)
1758c6fd2807SJeff Garzik {
1759c6fd2807SJeff Garzik 	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1760c6fd2807SJeff Garzik 	int i, rc = 0;
1761c6fd2807SJeff Garzik 	u32 t;
1762c6fd2807SJeff Garzik 
1763c6fd2807SJeff Garzik 	/* Following procedure defined in PCI "main command and status
1764c6fd2807SJeff Garzik 	 * register" table.
1765c6fd2807SJeff Garzik 	 */
1766c6fd2807SJeff Garzik 	t = readl(reg);
1767c6fd2807SJeff Garzik 	writel(t | STOP_PCI_MASTER, reg);
1768c6fd2807SJeff Garzik 
1769c6fd2807SJeff Garzik 	for (i = 0; i < 1000; i++) {
1770c6fd2807SJeff Garzik 		udelay(1);
1771c6fd2807SJeff Garzik 		t = readl(reg);
1772c6fd2807SJeff Garzik 		if (PCI_MASTER_EMPTY & t) {
1773c6fd2807SJeff Garzik 			break;
1774c6fd2807SJeff Garzik 		}
1775c6fd2807SJeff Garzik 	}
1776c6fd2807SJeff Garzik 	if (!(PCI_MASTER_EMPTY & t)) {
1777c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
1778c6fd2807SJeff Garzik 		rc = 1;
1779c6fd2807SJeff Garzik 		goto done;
1780c6fd2807SJeff Garzik 	}
1781c6fd2807SJeff Garzik 
1782c6fd2807SJeff Garzik 	/* set reset */
1783c6fd2807SJeff Garzik 	i = 5;
1784c6fd2807SJeff Garzik 	do {
1785c6fd2807SJeff Garzik 		writel(t | GLOB_SFT_RST, reg);
1786c6fd2807SJeff Garzik 		t = readl(reg);
1787c6fd2807SJeff Garzik 		udelay(1);
1788c6fd2807SJeff Garzik 	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
1789c6fd2807SJeff Garzik 
1790c6fd2807SJeff Garzik 	if (!(GLOB_SFT_RST & t)) {
1791c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
1792c6fd2807SJeff Garzik 		rc = 1;
1793c6fd2807SJeff Garzik 		goto done;
1794c6fd2807SJeff Garzik 	}
1795c6fd2807SJeff Garzik 
1796c6fd2807SJeff Garzik 	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
1797c6fd2807SJeff Garzik 	i = 5;
1798c6fd2807SJeff Garzik 	do {
1799c6fd2807SJeff Garzik 		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
1800c6fd2807SJeff Garzik 		t = readl(reg);
1801c6fd2807SJeff Garzik 		udelay(1);
1802c6fd2807SJeff Garzik 	} while ((GLOB_SFT_RST & t) && (i-- > 0));
1803c6fd2807SJeff Garzik 
1804c6fd2807SJeff Garzik 	if (GLOB_SFT_RST & t) {
1805c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
1806c6fd2807SJeff Garzik 		rc = 1;
1807c6fd2807SJeff Garzik 	}
1808c6fd2807SJeff Garzik done:
1809c6fd2807SJeff Garzik 	return rc;
1810c6fd2807SJeff Garzik }
1811c6fd2807SJeff Garzik 
1812c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
1813c6fd2807SJeff Garzik 			   void __iomem *mmio)
1814c6fd2807SJeff Garzik {
1815c6fd2807SJeff Garzik 	void __iomem *port_mmio;
1816c6fd2807SJeff Garzik 	u32 tmp;
1817c6fd2807SJeff Garzik 
1818c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_RESET_CFG);
1819c6fd2807SJeff Garzik 	if ((tmp & (1 << 0)) == 0) {
1820c6fd2807SJeff Garzik 		hpriv->signal[idx].amps = 0x7 << 8;
1821c6fd2807SJeff Garzik 		hpriv->signal[idx].pre = 0x1 << 5;
1822c6fd2807SJeff Garzik 		return;
1823c6fd2807SJeff Garzik 	}
1824c6fd2807SJeff Garzik 
1825c6fd2807SJeff Garzik 	port_mmio = mv_port_base(mmio, idx);
1826c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PHY_MODE2);
1827c6fd2807SJeff Garzik 
1828c6fd2807SJeff Garzik 	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
1829c6fd2807SJeff Garzik 	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
1830c6fd2807SJeff Garzik }
1831c6fd2807SJeff Garzik 
1832c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1833c6fd2807SJeff Garzik {
1834c6fd2807SJeff Garzik 	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
1835c6fd2807SJeff Garzik }
1836c6fd2807SJeff Garzik 
1837c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
1838c6fd2807SJeff Garzik 			   unsigned int port)
1839c6fd2807SJeff Garzik {
1840c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port);
1841c6fd2807SJeff Garzik 
1842c6fd2807SJeff Garzik 	u32 hp_flags = hpriv->hp_flags;
1843c6fd2807SJeff Garzik 	int fix_phy_mode2 =
1844c6fd2807SJeff Garzik 		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
1845c6fd2807SJeff Garzik 	int fix_phy_mode4 =
1846c6fd2807SJeff Garzik 		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
1847c6fd2807SJeff Garzik 	u32 m2, tmp;
1848c6fd2807SJeff Garzik 
1849c6fd2807SJeff Garzik 	if (fix_phy_mode2) {
1850c6fd2807SJeff Garzik 		m2 = readl(port_mmio + PHY_MODE2);
1851c6fd2807SJeff Garzik 		m2 &= ~(1 << 16);
1852c6fd2807SJeff Garzik 		m2 |= (1 << 31);
1853c6fd2807SJeff Garzik 		writel(m2, port_mmio + PHY_MODE2);
1854c6fd2807SJeff Garzik 
1855c6fd2807SJeff Garzik 		udelay(200);
1856c6fd2807SJeff Garzik 
1857c6fd2807SJeff Garzik 		m2 = readl(port_mmio + PHY_MODE2);
1858c6fd2807SJeff Garzik 		m2 &= ~((1 << 16) | (1 << 31));
1859c6fd2807SJeff Garzik 		writel(m2, port_mmio + PHY_MODE2);
1860c6fd2807SJeff Garzik 
1861c6fd2807SJeff Garzik 		udelay(200);
1862c6fd2807SJeff Garzik 	}
1863c6fd2807SJeff Garzik 
1864c6fd2807SJeff Garzik 	/* who knows what this magic does */
1865c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PHY_MODE3);
1866c6fd2807SJeff Garzik 	tmp &= ~0x7F800000;
1867c6fd2807SJeff Garzik 	tmp |= 0x2A800000;
1868c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PHY_MODE3);
1869c6fd2807SJeff Garzik 
1870c6fd2807SJeff Garzik 	if (fix_phy_mode4) {
1871c6fd2807SJeff Garzik 		u32 m4;
1872c6fd2807SJeff Garzik 
1873c6fd2807SJeff Garzik 		m4 = readl(port_mmio + PHY_MODE4);
1874c6fd2807SJeff Garzik 
1875c6fd2807SJeff Garzik 		if (hp_flags & MV_HP_ERRATA_60X1B2)
1876c6fd2807SJeff Garzik 			tmp = readl(port_mmio + 0x310);
1877c6fd2807SJeff Garzik 
1878c6fd2807SJeff Garzik 		m4 = (m4 & ~(1 << 1)) | (1 << 0);
1879c6fd2807SJeff Garzik 
1880c6fd2807SJeff Garzik 		writel(m4, port_mmio + PHY_MODE4);
1881c6fd2807SJeff Garzik 
1882c6fd2807SJeff Garzik 		if (hp_flags & MV_HP_ERRATA_60X1B2)
1883c6fd2807SJeff Garzik 			writel(tmp, port_mmio + 0x310);
1884c6fd2807SJeff Garzik 	}
1885c6fd2807SJeff Garzik 
1886c6fd2807SJeff Garzik 	/* Revert values of pre-emphasis and signal amps to the saved ones */
1887c6fd2807SJeff Garzik 	m2 = readl(port_mmio + PHY_MODE2);
1888c6fd2807SJeff Garzik 
1889c6fd2807SJeff Garzik 	m2 &= ~MV_M2_PREAMP_MASK;
1890c6fd2807SJeff Garzik 	m2 |= hpriv->signal[port].amps;
1891c6fd2807SJeff Garzik 	m2 |= hpriv->signal[port].pre;
1892c6fd2807SJeff Garzik 	m2 &= ~(1 << 16);
1893c6fd2807SJeff Garzik 
1894c6fd2807SJeff Garzik 	/* according to mvSata 3.6.1, some IIE values are fixed */
1895c6fd2807SJeff Garzik 	if (IS_GEN_IIE(hpriv)) {
1896c6fd2807SJeff Garzik 		m2 &= ~0xC30FF01F;
1897c6fd2807SJeff Garzik 		m2 |= 0x0000900F;
1898c6fd2807SJeff Garzik 	}
1899c6fd2807SJeff Garzik 
1900c6fd2807SJeff Garzik 	writel(m2, port_mmio + PHY_MODE2);
1901c6fd2807SJeff Garzik }
1902c6fd2807SJeff Garzik 
1903c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
1904c6fd2807SJeff Garzik 			     unsigned int port_no)
1905c6fd2807SJeff Garzik {
1906c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port_no);
1907c6fd2807SJeff Garzik 
1908c6fd2807SJeff Garzik 	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
1909c6fd2807SJeff Garzik 
1910c6fd2807SJeff Garzik 	if (IS_60XX(hpriv)) {
1911c6fd2807SJeff Garzik 		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
1912c6fd2807SJeff Garzik 		ifctl |= (1 << 7);		/* enable gen2i speed */
1913c6fd2807SJeff Garzik 		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
1914c6fd2807SJeff Garzik 		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
1915c6fd2807SJeff Garzik 	}
1916c6fd2807SJeff Garzik 
1917c6fd2807SJeff Garzik 	udelay(25);		/* allow reset propagation */
1918c6fd2807SJeff Garzik 
1919c6fd2807SJeff Garzik 	/* Spec never mentions clearing the bit.  Marvell's driver does
1920c6fd2807SJeff Garzik 	 * clear the bit, however.
1921c6fd2807SJeff Garzik 	 */
1922c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_CMD_OFS);
1923c6fd2807SJeff Garzik 
1924c6fd2807SJeff Garzik 	hpriv->ops->phy_errata(hpriv, mmio, port_no);
1925c6fd2807SJeff Garzik 
1926c6fd2807SJeff Garzik 	if (IS_50XX(hpriv))
1927c6fd2807SJeff Garzik 		mdelay(1);
1928c6fd2807SJeff Garzik }
1929c6fd2807SJeff Garzik 
1930c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap)
1931c6fd2807SJeff Garzik {
1932cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
19330d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
1934c6fd2807SJeff Garzik 
1935c6fd2807SJeff Garzik 	mv_stop_dma(ap);
1936c6fd2807SJeff Garzik 
1937c6fd2807SJeff Garzik 	mv_channel_reset(hpriv, mmio, ap->port_no);
1938c6fd2807SJeff Garzik 
1939c6fd2807SJeff Garzik 	__mv_phy_reset(ap, 0);
1940c6fd2807SJeff Garzik }
1941c6fd2807SJeff Garzik 
1942c6fd2807SJeff Garzik static inline void __msleep(unsigned int msec, int can_sleep)
1943c6fd2807SJeff Garzik {
1944c6fd2807SJeff Garzik 	if (can_sleep)
1945c6fd2807SJeff Garzik 		msleep(msec);
1946c6fd2807SJeff Garzik 	else
1947c6fd2807SJeff Garzik 		mdelay(msec);
1948c6fd2807SJeff Garzik }
1949c6fd2807SJeff Garzik 
1950c6fd2807SJeff Garzik /**
1951c6fd2807SJeff Garzik  *      __mv_phy_reset - Perform eDMA reset followed by COMRESET
1952c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1953c6fd2807SJeff Garzik  *
1954c6fd2807SJeff Garzik  *      Part of this is taken from __sata_phy_reset and modified to
1955c6fd2807SJeff Garzik  *      not sleep since this routine gets called from interrupt level.
1956c6fd2807SJeff Garzik  *
1957c6fd2807SJeff Garzik  *      LOCKING:
1958c6fd2807SJeff Garzik  *      Inherited from caller.  This is coded to safe to call at
1959c6fd2807SJeff Garzik  *      interrupt level, i.e. it does not sleep.
1960c6fd2807SJeff Garzik  */
1961c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
1962c6fd2807SJeff Garzik {
1963c6fd2807SJeff Garzik 	struct mv_port_priv *pp	= ap->private_data;
1964cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
1965c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1966c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1967c6fd2807SJeff Garzik 	struct ata_device *dev = &ap->device[0];
1968c6fd2807SJeff Garzik 	unsigned long timeout;
1969c6fd2807SJeff Garzik 	int retry = 5;
1970c6fd2807SJeff Garzik 	u32 sstatus;
1971c6fd2807SJeff Garzik 
1972c6fd2807SJeff Garzik 	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
1973c6fd2807SJeff Garzik 
1974c6fd2807SJeff Garzik 	DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
1975c6fd2807SJeff Garzik 		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
1976c6fd2807SJeff Garzik 		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
1977c6fd2807SJeff Garzik 
1978c6fd2807SJeff Garzik 	/* Issue COMRESET via SControl */
1979c6fd2807SJeff Garzik comreset_retry:
1980c6fd2807SJeff Garzik 	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
1981c6fd2807SJeff Garzik 	__msleep(1, can_sleep);
1982c6fd2807SJeff Garzik 
1983c6fd2807SJeff Garzik 	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
1984c6fd2807SJeff Garzik 	__msleep(20, can_sleep);
1985c6fd2807SJeff Garzik 
1986c6fd2807SJeff Garzik 	timeout = jiffies + msecs_to_jiffies(200);
1987c6fd2807SJeff Garzik 	do {
1988c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_STATUS, &sstatus);
1989dd1dc802SJeff Garzik 		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
1990c6fd2807SJeff Garzik 			break;
1991c6fd2807SJeff Garzik 
1992c6fd2807SJeff Garzik 		__msleep(1, can_sleep);
1993c6fd2807SJeff Garzik 	} while (time_before(jiffies, timeout));
1994c6fd2807SJeff Garzik 
1995c6fd2807SJeff Garzik 	/* work around errata */
1996c6fd2807SJeff Garzik 	if (IS_60XX(hpriv) &&
1997c6fd2807SJeff Garzik 	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
1998c6fd2807SJeff Garzik 	    (retry-- > 0))
1999c6fd2807SJeff Garzik 		goto comreset_retry;
2000c6fd2807SJeff Garzik 
2001c6fd2807SJeff Garzik 	DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
2002c6fd2807SJeff Garzik 		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
2003c6fd2807SJeff Garzik 		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
2004c6fd2807SJeff Garzik 
2005c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
2006c6fd2807SJeff Garzik 		ata_port_probe(ap);
2007c6fd2807SJeff Garzik 	} else {
2008c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_STATUS, &sstatus);
2009c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO,
2010c6fd2807SJeff Garzik 				"no device found (phy stat %08x)\n", sstatus);
2011c6fd2807SJeff Garzik 		ata_port_disable(ap);
2012c6fd2807SJeff Garzik 		return;
2013c6fd2807SJeff Garzik 	}
2014c6fd2807SJeff Garzik 
2015c6fd2807SJeff Garzik 	/* even after SStatus reflects that device is ready,
2016c6fd2807SJeff Garzik 	 * it seems to take a while for link to be fully
2017c6fd2807SJeff Garzik 	 * established (and thus Status no longer 0x80/0x7F),
2018c6fd2807SJeff Garzik 	 * so we poll a bit for that, here.
2019c6fd2807SJeff Garzik 	 */
2020c6fd2807SJeff Garzik 	retry = 20;
2021c6fd2807SJeff Garzik 	while (1) {
2022c6fd2807SJeff Garzik 		u8 drv_stat = ata_check_status(ap);
2023c6fd2807SJeff Garzik 		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
2024c6fd2807SJeff Garzik 			break;
2025c6fd2807SJeff Garzik 		__msleep(500, can_sleep);
2026c6fd2807SJeff Garzik 		if (retry-- <= 0)
2027c6fd2807SJeff Garzik 			break;
2028c6fd2807SJeff Garzik 	}
2029c6fd2807SJeff Garzik 
20300d5ff566STejun Heo 	tf.lbah = readb(ap->ioaddr.lbah_addr);
20310d5ff566STejun Heo 	tf.lbam = readb(ap->ioaddr.lbam_addr);
20320d5ff566STejun Heo 	tf.lbal = readb(ap->ioaddr.lbal_addr);
20330d5ff566STejun Heo 	tf.nsect = readb(ap->ioaddr.nsect_addr);
2034c6fd2807SJeff Garzik 
2035c6fd2807SJeff Garzik 	dev->class = ata_dev_classify(&tf);
2036c6fd2807SJeff Garzik 	if (!ata_dev_enabled(dev)) {
2037c6fd2807SJeff Garzik 		VPRINTK("Port disabled post-sig: No device present.\n");
2038c6fd2807SJeff Garzik 		ata_port_disable(ap);
2039c6fd2807SJeff Garzik 	}
2040c6fd2807SJeff Garzik 
2041c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2042c6fd2807SJeff Garzik 
2043c6fd2807SJeff Garzik 	pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
2044c6fd2807SJeff Garzik 
2045c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2046c6fd2807SJeff Garzik }
2047c6fd2807SJeff Garzik 
2048c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap)
2049c6fd2807SJeff Garzik {
2050c6fd2807SJeff Garzik 	__mv_phy_reset(ap, 1);
2051c6fd2807SJeff Garzik }
2052c6fd2807SJeff Garzik 
2053c6fd2807SJeff Garzik /**
2054c6fd2807SJeff Garzik  *      mv_eng_timeout - Routine called by libata when SCSI times out I/O
2055c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
2056c6fd2807SJeff Garzik  *
2057c6fd2807SJeff Garzik  *      Intent is to clear all pending error conditions, reset the
2058c6fd2807SJeff Garzik  *      chip/bus, fail the command, and move on.
2059c6fd2807SJeff Garzik  *
2060c6fd2807SJeff Garzik  *      LOCKING:
2061cca3974eSJeff Garzik  *      This routine holds the host lock while failing the command.
2062c6fd2807SJeff Garzik  */
2063c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap)
2064c6fd2807SJeff Garzik {
20650d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2066c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
2067c6fd2807SJeff Garzik 	unsigned long flags;
2068c6fd2807SJeff Garzik 
2069c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
2070c6fd2807SJeff Garzik 	DPRINTK("All regs @ start of eng_timeout\n");
20710d5ff566STejun Heo 	mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev));
2072c6fd2807SJeff Garzik 
2073c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
2074c6fd2807SJeff Garzik         printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
20750d5ff566STejun Heo 	       mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
2076c6fd2807SJeff Garzik 
2077cca3974eSJeff Garzik 	spin_lock_irqsave(&ap->host->lock, flags);
2078c6fd2807SJeff Garzik 	mv_err_intr(ap, 0);
2079c6fd2807SJeff Garzik 	mv_stop_and_reset(ap);
2080cca3974eSJeff Garzik 	spin_unlock_irqrestore(&ap->host->lock, flags);
2081c6fd2807SJeff Garzik 
2082c6fd2807SJeff Garzik 	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
2083c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_ACTIVE) {
2084c6fd2807SJeff Garzik 		qc->err_mask |= AC_ERR_TIMEOUT;
2085c6fd2807SJeff Garzik 		ata_eh_qc_complete(qc);
2086c6fd2807SJeff Garzik 	}
2087c6fd2807SJeff Garzik }
2088c6fd2807SJeff Garzik 
2089c6fd2807SJeff Garzik /**
2090c6fd2807SJeff Garzik  *      mv_port_init - Perform some early initialization on a single port.
2091c6fd2807SJeff Garzik  *      @port: libata data structure storing shadow register addresses
2092c6fd2807SJeff Garzik  *      @port_mmio: base address of the port
2093c6fd2807SJeff Garzik  *
2094c6fd2807SJeff Garzik  *      Initialize shadow register mmio addresses, clear outstanding
2095c6fd2807SJeff Garzik  *      interrupts on the port, and unmask interrupts for the future
2096c6fd2807SJeff Garzik  *      start of the port.
2097c6fd2807SJeff Garzik  *
2098c6fd2807SJeff Garzik  *      LOCKING:
2099c6fd2807SJeff Garzik  *      Inherited from caller.
2100c6fd2807SJeff Garzik  */
2101c6fd2807SJeff Garzik static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
2102c6fd2807SJeff Garzik {
21030d5ff566STejun Heo 	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
2104c6fd2807SJeff Garzik 	unsigned serr_ofs;
2105c6fd2807SJeff Garzik 
2106c6fd2807SJeff Garzik 	/* PIO related setup
2107c6fd2807SJeff Garzik 	 */
2108c6fd2807SJeff Garzik 	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
2109c6fd2807SJeff Garzik 	port->error_addr =
2110c6fd2807SJeff Garzik 		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
2111c6fd2807SJeff Garzik 	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
2112c6fd2807SJeff Garzik 	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
2113c6fd2807SJeff Garzik 	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
2114c6fd2807SJeff Garzik 	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
2115c6fd2807SJeff Garzik 	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
2116c6fd2807SJeff Garzik 	port->status_addr =
2117c6fd2807SJeff Garzik 		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
2118c6fd2807SJeff Garzik 	/* special case: control/altstatus doesn't have ATA_REG_ address */
2119c6fd2807SJeff Garzik 	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
2120c6fd2807SJeff Garzik 
2121c6fd2807SJeff Garzik 	/* unused: */
21228d9db2d2SRandy Dunlap 	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
2123c6fd2807SJeff Garzik 
2124c6fd2807SJeff Garzik 	/* Clear any currently outstanding port interrupt conditions */
2125c6fd2807SJeff Garzik 	serr_ofs = mv_scr_offset(SCR_ERROR);
2126c6fd2807SJeff Garzik 	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
2127c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2128c6fd2807SJeff Garzik 
2129c6fd2807SJeff Garzik 	/* unmask all EDMA error interrupts */
2130c6fd2807SJeff Garzik 	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
2131c6fd2807SJeff Garzik 
2132c6fd2807SJeff Garzik 	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
2133c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_CFG_OFS),
2134c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
2135c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
2136c6fd2807SJeff Garzik }
2137c6fd2807SJeff Garzik 
21384447d351STejun Heo static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2139c6fd2807SJeff Garzik {
21404447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
21414447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2142c6fd2807SJeff Garzik 	u8 rev_id;
2143c6fd2807SJeff Garzik 	u32 hp_flags = hpriv->hp_flags;
2144c6fd2807SJeff Garzik 
2145c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
2146c6fd2807SJeff Garzik 
2147c6fd2807SJeff Garzik 	switch(board_idx) {
2148c6fd2807SJeff Garzik 	case chip_5080:
2149c6fd2807SJeff Garzik 		hpriv->ops = &mv5xxx_ops;
2150c6fd2807SJeff Garzik 		hp_flags |= MV_HP_50XX;
2151c6fd2807SJeff Garzik 
2152c6fd2807SJeff Garzik 		switch (rev_id) {
2153c6fd2807SJeff Garzik 		case 0x1:
2154c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB0;
2155c6fd2807SJeff Garzik 			break;
2156c6fd2807SJeff Garzik 		case 0x3:
2157c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2158c6fd2807SJeff Garzik 			break;
2159c6fd2807SJeff Garzik 		default:
2160c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2161c6fd2807SJeff Garzik 			   "Applying 50XXB2 workarounds to unknown rev\n");
2162c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2163c6fd2807SJeff Garzik 			break;
2164c6fd2807SJeff Garzik 		}
2165c6fd2807SJeff Garzik 		break;
2166c6fd2807SJeff Garzik 
2167c6fd2807SJeff Garzik 	case chip_504x:
2168c6fd2807SJeff Garzik 	case chip_508x:
2169c6fd2807SJeff Garzik 		hpriv->ops = &mv5xxx_ops;
2170c6fd2807SJeff Garzik 		hp_flags |= MV_HP_50XX;
2171c6fd2807SJeff Garzik 
2172c6fd2807SJeff Garzik 		switch (rev_id) {
2173c6fd2807SJeff Garzik 		case 0x0:
2174c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB0;
2175c6fd2807SJeff Garzik 			break;
2176c6fd2807SJeff Garzik 		case 0x3:
2177c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2178c6fd2807SJeff Garzik 			break;
2179c6fd2807SJeff Garzik 		default:
2180c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2181c6fd2807SJeff Garzik 			   "Applying B2 workarounds to unknown rev\n");
2182c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2183c6fd2807SJeff Garzik 			break;
2184c6fd2807SJeff Garzik 		}
2185c6fd2807SJeff Garzik 		break;
2186c6fd2807SJeff Garzik 
2187c6fd2807SJeff Garzik 	case chip_604x:
2188c6fd2807SJeff Garzik 	case chip_608x:
2189c6fd2807SJeff Garzik 		hpriv->ops = &mv6xxx_ops;
2190c6fd2807SJeff Garzik 
2191c6fd2807SJeff Garzik 		switch (rev_id) {
2192c6fd2807SJeff Garzik 		case 0x7:
2193c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1B2;
2194c6fd2807SJeff Garzik 			break;
2195c6fd2807SJeff Garzik 		case 0x9:
2196c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2197c6fd2807SJeff Garzik 			break;
2198c6fd2807SJeff Garzik 		default:
2199c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2200c6fd2807SJeff Garzik 				   "Applying B2 workarounds to unknown rev\n");
2201c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1B2;
2202c6fd2807SJeff Garzik 			break;
2203c6fd2807SJeff Garzik 		}
2204c6fd2807SJeff Garzik 		break;
2205c6fd2807SJeff Garzik 
2206c6fd2807SJeff Garzik 	case chip_7042:
2207c6fd2807SJeff Garzik 	case chip_6042:
2208c6fd2807SJeff Garzik 		hpriv->ops = &mv6xxx_ops;
2209c6fd2807SJeff Garzik 
2210c6fd2807SJeff Garzik 		hp_flags |= MV_HP_GEN_IIE;
2211c6fd2807SJeff Garzik 
2212c6fd2807SJeff Garzik 		switch (rev_id) {
2213c6fd2807SJeff Garzik 		case 0x0:
2214c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_XX42A0;
2215c6fd2807SJeff Garzik 			break;
2216c6fd2807SJeff Garzik 		case 0x1:
2217c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2218c6fd2807SJeff Garzik 			break;
2219c6fd2807SJeff Garzik 		default:
2220c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2221c6fd2807SJeff Garzik 			   "Applying 60X1C0 workarounds to unknown rev\n");
2222c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2223c6fd2807SJeff Garzik 			break;
2224c6fd2807SJeff Garzik 		}
2225c6fd2807SJeff Garzik 		break;
2226c6fd2807SJeff Garzik 
2227c6fd2807SJeff Garzik 	default:
2228c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
2229c6fd2807SJeff Garzik 		return 1;
2230c6fd2807SJeff Garzik 	}
2231c6fd2807SJeff Garzik 
2232c6fd2807SJeff Garzik 	hpriv->hp_flags = hp_flags;
2233c6fd2807SJeff Garzik 
2234c6fd2807SJeff Garzik 	return 0;
2235c6fd2807SJeff Garzik }
2236c6fd2807SJeff Garzik 
2237c6fd2807SJeff Garzik /**
2238c6fd2807SJeff Garzik  *      mv_init_host - Perform some early initialization of the host.
22394447d351STejun Heo  *	@host: ATA host to initialize
22404447d351STejun Heo  *      @board_idx: controller index
2241c6fd2807SJeff Garzik  *
2242c6fd2807SJeff Garzik  *      If possible, do an early global reset of the host.  Then do
2243c6fd2807SJeff Garzik  *      our port init and clear/unmask all/relevant host interrupts.
2244c6fd2807SJeff Garzik  *
2245c6fd2807SJeff Garzik  *      LOCKING:
2246c6fd2807SJeff Garzik  *      Inherited from caller.
2247c6fd2807SJeff Garzik  */
22484447d351STejun Heo static int mv_init_host(struct ata_host *host, unsigned int board_idx)
2249c6fd2807SJeff Garzik {
2250c6fd2807SJeff Garzik 	int rc = 0, n_hc, port, hc;
22514447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
22524447d351STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
22534447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2254c6fd2807SJeff Garzik 
2255c6fd2807SJeff Garzik 	/* global interrupt mask */
2256c6fd2807SJeff Garzik 	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
2257c6fd2807SJeff Garzik 
22584447d351STejun Heo 	rc = mv_chip_id(host, board_idx);
2259c6fd2807SJeff Garzik 	if (rc)
2260c6fd2807SJeff Garzik 		goto done;
2261c6fd2807SJeff Garzik 
22624447d351STejun Heo 	n_hc = mv_get_hc_count(host->ports[0]->flags);
2263c6fd2807SJeff Garzik 
22644447d351STejun Heo 	for (port = 0; port < host->n_ports; port++)
2265c6fd2807SJeff Garzik 		hpriv->ops->read_preamp(hpriv, port, mmio);
2266c6fd2807SJeff Garzik 
2267c6fd2807SJeff Garzik 	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
2268c6fd2807SJeff Garzik 	if (rc)
2269c6fd2807SJeff Garzik 		goto done;
2270c6fd2807SJeff Garzik 
2271c6fd2807SJeff Garzik 	hpriv->ops->reset_flash(hpriv, mmio);
2272c6fd2807SJeff Garzik 	hpriv->ops->reset_bus(pdev, mmio);
2273c6fd2807SJeff Garzik 	hpriv->ops->enable_leds(hpriv, mmio);
2274c6fd2807SJeff Garzik 
22754447d351STejun Heo 	for (port = 0; port < host->n_ports; port++) {
2276c6fd2807SJeff Garzik 		if (IS_60XX(hpriv)) {
2277c6fd2807SJeff Garzik 			void __iomem *port_mmio = mv_port_base(mmio, port);
2278c6fd2807SJeff Garzik 
2279c6fd2807SJeff Garzik 			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2280c6fd2807SJeff Garzik 			ifctl |= (1 << 7);		/* enable gen2i speed */
2281c6fd2807SJeff Garzik 			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2282c6fd2807SJeff Garzik 			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2283c6fd2807SJeff Garzik 		}
2284c6fd2807SJeff Garzik 
2285c6fd2807SJeff Garzik 		hpriv->ops->phy_errata(hpriv, mmio, port);
2286c6fd2807SJeff Garzik 	}
2287c6fd2807SJeff Garzik 
22884447d351STejun Heo 	for (port = 0; port < host->n_ports; port++) {
2289c6fd2807SJeff Garzik 		void __iomem *port_mmio = mv_port_base(mmio, port);
22904447d351STejun Heo 		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
2291c6fd2807SJeff Garzik 	}
2292c6fd2807SJeff Garzik 
2293c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hc; hc++) {
2294c6fd2807SJeff Garzik 		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2295c6fd2807SJeff Garzik 
2296c6fd2807SJeff Garzik 		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
2297c6fd2807SJeff Garzik 			"(before clear)=0x%08x\n", hc,
2298c6fd2807SJeff Garzik 			readl(hc_mmio + HC_CFG_OFS),
2299c6fd2807SJeff Garzik 			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
2300c6fd2807SJeff Garzik 
2301c6fd2807SJeff Garzik 		/* Clear any currently outstanding hc interrupt conditions */
2302c6fd2807SJeff Garzik 		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
2303c6fd2807SJeff Garzik 	}
2304c6fd2807SJeff Garzik 
2305c6fd2807SJeff Garzik 	/* Clear any currently outstanding host interrupt conditions */
2306c6fd2807SJeff Garzik 	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
2307c6fd2807SJeff Garzik 
2308c6fd2807SJeff Garzik 	/* and unmask interrupt generation for host regs */
2309c6fd2807SJeff Garzik 	writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
2310fb621e2fSJeff Garzik 
2311fb621e2fSJeff Garzik 	if (IS_50XX(hpriv))
2312fb621e2fSJeff Garzik 		writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2313fb621e2fSJeff Garzik 	else
2314c6fd2807SJeff Garzik 		writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
2315c6fd2807SJeff Garzik 
2316c6fd2807SJeff Garzik 	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
2317c6fd2807SJeff Garzik 		"PCI int cause/mask=0x%08x/0x%08x\n",
2318c6fd2807SJeff Garzik 		readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
2319c6fd2807SJeff Garzik 		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
2320c6fd2807SJeff Garzik 		readl(mmio + PCI_IRQ_CAUSE_OFS),
2321c6fd2807SJeff Garzik 		readl(mmio + PCI_IRQ_MASK_OFS));
2322c6fd2807SJeff Garzik 
2323c6fd2807SJeff Garzik done:
2324c6fd2807SJeff Garzik 	return rc;
2325c6fd2807SJeff Garzik }
2326c6fd2807SJeff Garzik 
2327c6fd2807SJeff Garzik /**
2328c6fd2807SJeff Garzik  *      mv_print_info - Dump key info to kernel log for perusal.
23294447d351STejun Heo  *      @host: ATA host to print info about
2330c6fd2807SJeff Garzik  *
2331c6fd2807SJeff Garzik  *      FIXME: complete this.
2332c6fd2807SJeff Garzik  *
2333c6fd2807SJeff Garzik  *      LOCKING:
2334c6fd2807SJeff Garzik  *      Inherited from caller.
2335c6fd2807SJeff Garzik  */
23364447d351STejun Heo static void mv_print_info(struct ata_host *host)
2337c6fd2807SJeff Garzik {
23384447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
23394447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2340c6fd2807SJeff Garzik 	u8 rev_id, scc;
2341c6fd2807SJeff Garzik 	const char *scc_s;
2342c6fd2807SJeff Garzik 
2343c6fd2807SJeff Garzik 	/* Use this to determine the HW stepping of the chip so we know
2344c6fd2807SJeff Garzik 	 * what errata to workaround
2345c6fd2807SJeff Garzik 	 */
2346c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
2347c6fd2807SJeff Garzik 
2348c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
2349c6fd2807SJeff Garzik 	if (scc == 0)
2350c6fd2807SJeff Garzik 		scc_s = "SCSI";
2351c6fd2807SJeff Garzik 	else if (scc == 0x01)
2352c6fd2807SJeff Garzik 		scc_s = "RAID";
2353c6fd2807SJeff Garzik 	else
2354c6fd2807SJeff Garzik 		scc_s = "unknown";
2355c6fd2807SJeff Garzik 
2356c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2357c6fd2807SJeff Garzik 	       "%u slots %u ports %s mode IRQ via %s\n",
23584447d351STejun Heo 	       (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
2359c6fd2807SJeff Garzik 	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
2360c6fd2807SJeff Garzik }
2361c6fd2807SJeff Garzik 
2362c6fd2807SJeff Garzik /**
2363c6fd2807SJeff Garzik  *      mv_init_one - handle a positive probe of a Marvell host
2364c6fd2807SJeff Garzik  *      @pdev: PCI device found
2365c6fd2807SJeff Garzik  *      @ent: PCI device ID entry for the matched host
2366c6fd2807SJeff Garzik  *
2367c6fd2807SJeff Garzik  *      LOCKING:
2368c6fd2807SJeff Garzik  *      Inherited from caller.
2369c6fd2807SJeff Garzik  */
2370c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2371c6fd2807SJeff Garzik {
2372c6fd2807SJeff Garzik 	static int printed_version = 0;
2373c6fd2807SJeff Garzik 	unsigned int board_idx = (unsigned int)ent->driver_data;
23744447d351STejun Heo 	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
23754447d351STejun Heo 	struct ata_host *host;
23764447d351STejun Heo 	struct mv_host_priv *hpriv;
23774447d351STejun Heo 	int n_ports, rc;
2378c6fd2807SJeff Garzik 
2379c6fd2807SJeff Garzik 	if (!printed_version++)
2380c6fd2807SJeff Garzik 		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
2381c6fd2807SJeff Garzik 
23824447d351STejun Heo 	/* allocate host */
23834447d351STejun Heo 	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
23844447d351STejun Heo 
23854447d351STejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
23864447d351STejun Heo 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
23874447d351STejun Heo 	if (!host || !hpriv)
23884447d351STejun Heo 		return -ENOMEM;
23894447d351STejun Heo 	host->private_data = hpriv;
23904447d351STejun Heo 
23914447d351STejun Heo 	/* acquire resources */
239224dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
239324dc5f33STejun Heo 	if (rc)
2394c6fd2807SJeff Garzik 		return rc;
2395c6fd2807SJeff Garzik 
23960d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
23970d5ff566STejun Heo 	if (rc == -EBUSY)
239824dc5f33STejun Heo 		pcim_pin_device(pdev);
23990d5ff566STejun Heo 	if (rc)
240024dc5f33STejun Heo 		return rc;
24014447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
2402c6fd2807SJeff Garzik 
2403d88184fbSJeff Garzik 	rc = pci_go_64(pdev);
2404d88184fbSJeff Garzik 	if (rc)
2405d88184fbSJeff Garzik 		return rc;
2406d88184fbSJeff Garzik 
2407c6fd2807SJeff Garzik 	/* initialize adapter */
24084447d351STejun Heo 	rc = mv_init_host(host, board_idx);
240924dc5f33STejun Heo 	if (rc)
241024dc5f33STejun Heo 		return rc;
2411c6fd2807SJeff Garzik 
2412c6fd2807SJeff Garzik 	/* Enable interrupts */
24136a59dcf8STejun Heo 	if (msi && pci_enable_msi(pdev))
2414c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
2415c6fd2807SJeff Garzik 
2416c6fd2807SJeff Garzik 	mv_dump_pci_cfg(pdev, 0x68);
24174447d351STejun Heo 	mv_print_info(host);
2418c6fd2807SJeff Garzik 
24194447d351STejun Heo 	pci_set_master(pdev);
24204447d351STejun Heo 	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
24214447d351STejun Heo 				 &mv_sht);
2422c6fd2807SJeff Garzik }
2423c6fd2807SJeff Garzik 
2424c6fd2807SJeff Garzik static int __init mv_init(void)
2425c6fd2807SJeff Garzik {
2426c6fd2807SJeff Garzik 	return pci_register_driver(&mv_pci_driver);
2427c6fd2807SJeff Garzik }
2428c6fd2807SJeff Garzik 
2429c6fd2807SJeff Garzik static void __exit mv_exit(void)
2430c6fd2807SJeff Garzik {
2431c6fd2807SJeff Garzik 	pci_unregister_driver(&mv_pci_driver);
2432c6fd2807SJeff Garzik }
2433c6fd2807SJeff Garzik 
2434c6fd2807SJeff Garzik MODULE_AUTHOR("Brett Russ");
2435c6fd2807SJeff Garzik MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
2436c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2437c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
2438c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2439c6fd2807SJeff Garzik 
2440c6fd2807SJeff Garzik module_param(msi, int, 0444);
2441c6fd2807SJeff Garzik MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2442c6fd2807SJeff Garzik 
2443c6fd2807SJeff Garzik module_init(mv_init);
2444c6fd2807SJeff Garzik module_exit(mv_exit);
2445