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