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