xref: /openbmc/linux/drivers/scsi/mvsas/mv_64xx.c (revision 20b09c2992fefbe78f8cede7b404fb143a413c52)
1dd4969a8SJeff Garzik /*
2*20b09c29SAndy Yan  * Marvell 88SE64xx hardware specific
3*20b09c29SAndy Yan  *
4*20b09c29SAndy Yan  * Copyright 2007 Red Hat, Inc.
5*20b09c29SAndy Yan  * Copyright 2008 Marvell. <kewei@marvell.com>
6*20b09c29SAndy Yan  *
7*20b09c29SAndy Yan  * This file is licensed under GPLv2.
8*20b09c29SAndy Yan  *
9*20b09c29SAndy Yan  * This program is free software; you can redistribute it and/or
10*20b09c29SAndy Yan  * modify it under the terms of the GNU General Public License as
11*20b09c29SAndy Yan  * published by the Free Software Foundation; version 2 of the
12*20b09c29SAndy Yan  * License.
13*20b09c29SAndy Yan  *
14*20b09c29SAndy Yan  * This program is distributed in the hope that it will be useful,
15*20b09c29SAndy Yan  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*20b09c29SAndy Yan  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17*20b09c29SAndy Yan  * General Public License for more details.
18*20b09c29SAndy Yan  *
19*20b09c29SAndy Yan  * You should have received a copy of the GNU General Public License
20*20b09c29SAndy Yan  * along with this program; if not, write to the Free Software
21*20b09c29SAndy Yan  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22*20b09c29SAndy Yan  * USA
23dd4969a8SJeff Garzik */
24dd4969a8SJeff Garzik 
25dd4969a8SJeff Garzik #include "mv_sas.h"
26dd4969a8SJeff Garzik #include "mv_64xx.h"
27dd4969a8SJeff Garzik #include "mv_chips.h"
28dd4969a8SJeff Garzik 
29*20b09c29SAndy Yan static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
30dd4969a8SJeff Garzik {
31dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
32dd4969a8SJeff Garzik 	u32 reg;
33dd4969a8SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[i];
34dd4969a8SJeff Garzik 
35dd4969a8SJeff Garzik 	/* TODO check & save device type */
36*20b09c29SAndy Yan 	reg = mr32(MVS_GBL_PORT_TYPE);
37*20b09c29SAndy Yan 	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
38dd4969a8SJeff Garzik 	if (reg & MODE_SAS_SATA & (1 << i))
39dd4969a8SJeff Garzik 		phy->phy_type |= PORT_TYPE_SAS;
40dd4969a8SJeff Garzik 	else
41dd4969a8SJeff Garzik 		phy->phy_type |= PORT_TYPE_SATA;
42dd4969a8SJeff Garzik }
43dd4969a8SJeff Garzik 
44*20b09c29SAndy Yan static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
45dd4969a8SJeff Garzik {
46dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
47dd4969a8SJeff Garzik 	u32 tmp;
48dd4969a8SJeff Garzik 
49*20b09c29SAndy Yan 	tmp = mr32(MVS_PCS);
50dd4969a8SJeff Garzik 	if (mvi->chip->n_phy <= 4)
51*20b09c29SAndy Yan 		tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
52dd4969a8SJeff Garzik 	else
53*20b09c29SAndy Yan 		tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
54*20b09c29SAndy Yan 	mw32(MVS_PCS, tmp);
55dd4969a8SJeff Garzik }
56dd4969a8SJeff Garzik 
57*20b09c29SAndy Yan static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
58dd4969a8SJeff Garzik {
59dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
60dd4969a8SJeff Garzik 
61*20b09c29SAndy Yan 	mvs_phy_hacks(mvi);
62dd4969a8SJeff Garzik 
63*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
64dd4969a8SJeff Garzik 		/* TEST - for phy decoding error, adjust voltage levels */
65*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_ADDR + 0, 0x8);
66*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_DATA + 0, 0x2F0);
67dd4969a8SJeff Garzik 
68*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_ADDR + 8, 0x8);
69*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_DATA + 8, 0x2F0);
70dd4969a8SJeff Garzik 
71*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_ADDR + 16, 0x8);
72*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_DATA + 16, 0x2F0);
73dd4969a8SJeff Garzik 
74*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_ADDR + 24, 0x8);
75*20b09c29SAndy Yan 		mw32(MVS_P0_VSR_DATA + 24, 0x2F0);
76*20b09c29SAndy Yan 	} else {
77*20b09c29SAndy Yan 		int i;
78*20b09c29SAndy Yan 		/* disable auto port detection */
79*20b09c29SAndy Yan 		mw32(MVS_GBL_PORT_TYPE, 0);
80*20b09c29SAndy Yan 		for (i = 0; i < mvi->chip->n_phy; i++) {
81*20b09c29SAndy Yan 			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7);
82*20b09c29SAndy Yan 			mvs_write_port_vsr_data(mvi, i, 0x90000000);
83*20b09c29SAndy Yan 			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9);
84*20b09c29SAndy Yan 			mvs_write_port_vsr_data(mvi, i, 0x50f2);
85*20b09c29SAndy Yan 			mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11);
86*20b09c29SAndy Yan 			mvs_write_port_vsr_data(mvi, i, 0x0e);
87*20b09c29SAndy Yan 		}
88*20b09c29SAndy Yan 	}
89dd4969a8SJeff Garzik }
90dd4969a8SJeff Garzik 
91*20b09c29SAndy Yan static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
92*20b09c29SAndy Yan {
93*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
94*20b09c29SAndy Yan 	u32 reg, tmp;
95*20b09c29SAndy Yan 
96*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
97*20b09c29SAndy Yan 		if (phy_id < 4)
98*20b09c29SAndy Yan 			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
99*20b09c29SAndy Yan 		else
100*20b09c29SAndy Yan 			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
101*20b09c29SAndy Yan 
102*20b09c29SAndy Yan 	} else
103*20b09c29SAndy Yan 		reg = mr32(MVS_PHY_CTL);
104*20b09c29SAndy Yan 
105*20b09c29SAndy Yan 	tmp = reg;
106*20b09c29SAndy Yan 	if (phy_id < 4)
107*20b09c29SAndy Yan 		tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
108*20b09c29SAndy Yan 	else
109*20b09c29SAndy Yan 		tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
110*20b09c29SAndy Yan 
111*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
112*20b09c29SAndy Yan 		if (phy_id < 4) {
113*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
114*20b09c29SAndy Yan 			mdelay(10);
115*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
116*20b09c29SAndy Yan 		} else {
117*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
118*20b09c29SAndy Yan 			mdelay(10);
119*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg);
120*20b09c29SAndy Yan 		}
121*20b09c29SAndy Yan 	} else {
122*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
123*20b09c29SAndy Yan 		mdelay(10);
124*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, reg);
125*20b09c29SAndy Yan 	}
126*20b09c29SAndy Yan }
127*20b09c29SAndy Yan 
128*20b09c29SAndy Yan static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
129*20b09c29SAndy Yan {
130*20b09c29SAndy Yan 	u32 tmp;
131*20b09c29SAndy Yan 	tmp = mvs_read_port_irq_stat(mvi, phy_id);
132*20b09c29SAndy Yan 	tmp &= ~PHYEV_RDY_CH;
133*20b09c29SAndy Yan 	mvs_write_port_irq_stat(mvi, phy_id, tmp);
134*20b09c29SAndy Yan 	tmp = mvs_read_phy_ctl(mvi, phy_id);
135*20b09c29SAndy Yan 	if (hard)
136*20b09c29SAndy Yan 		tmp |= PHY_RST_HARD;
137*20b09c29SAndy Yan 	else
138*20b09c29SAndy Yan 		tmp |= PHY_RST;
139*20b09c29SAndy Yan 	mvs_write_phy_ctl(mvi, phy_id, tmp);
140*20b09c29SAndy Yan 	if (hard) {
141*20b09c29SAndy Yan 		do {
142*20b09c29SAndy Yan 			tmp = mvs_read_phy_ctl(mvi, phy_id);
143*20b09c29SAndy Yan 		} while (tmp & PHY_RST_HARD);
144*20b09c29SAndy Yan 	}
145*20b09c29SAndy Yan }
146*20b09c29SAndy Yan 
147*20b09c29SAndy Yan static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
148*20b09c29SAndy Yan {
149*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
150*20b09c29SAndy Yan 	u32 tmp;
151*20b09c29SAndy Yan 	int i;
152*20b09c29SAndy Yan 
153*20b09c29SAndy Yan 	/* make sure interrupts are masked immediately (paranoia) */
154*20b09c29SAndy Yan 	mw32(MVS_GBL_CTL, 0);
155*20b09c29SAndy Yan 	tmp = mr32(MVS_GBL_CTL);
156*20b09c29SAndy Yan 
157*20b09c29SAndy Yan 	/* Reset Controller */
158*20b09c29SAndy Yan 	if (!(tmp & HBA_RST)) {
159*20b09c29SAndy Yan 		if (mvi->flags & MVF_PHY_PWR_FIX) {
160*20b09c29SAndy Yan 			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
161*20b09c29SAndy Yan 			tmp &= ~PCTL_PWR_OFF;
162*20b09c29SAndy Yan 			tmp |= PCTL_PHY_DSBL;
163*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
164*20b09c29SAndy Yan 
165*20b09c29SAndy Yan 			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
166*20b09c29SAndy Yan 			tmp &= ~PCTL_PWR_OFF;
167*20b09c29SAndy Yan 			tmp |= PCTL_PHY_DSBL;
168*20b09c29SAndy Yan 			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
169*20b09c29SAndy Yan 		}
170*20b09c29SAndy Yan 	}
171*20b09c29SAndy Yan 
172*20b09c29SAndy Yan 	/* make sure interrupts are masked immediately (paranoia) */
173*20b09c29SAndy Yan 	mw32(MVS_GBL_CTL, 0);
174*20b09c29SAndy Yan 	tmp = mr32(MVS_GBL_CTL);
175*20b09c29SAndy Yan 
176*20b09c29SAndy Yan 	/* Reset Controller */
177*20b09c29SAndy Yan 	if (!(tmp & HBA_RST)) {
178*20b09c29SAndy Yan 		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
179*20b09c29SAndy Yan 		mw32_f(MVS_GBL_CTL, HBA_RST);
180*20b09c29SAndy Yan 	}
181*20b09c29SAndy Yan 
182*20b09c29SAndy Yan 	/* wait for reset to finish; timeout is just a guess */
183*20b09c29SAndy Yan 	i = 1000;
184*20b09c29SAndy Yan 	while (i-- > 0) {
185*20b09c29SAndy Yan 		msleep(10);
186*20b09c29SAndy Yan 
187*20b09c29SAndy Yan 		if (!(mr32(MVS_GBL_CTL) & HBA_RST))
188*20b09c29SAndy Yan 			break;
189*20b09c29SAndy Yan 	}
190*20b09c29SAndy Yan 	if (mr32(MVS_GBL_CTL) & HBA_RST) {
191*20b09c29SAndy Yan 		dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n");
192*20b09c29SAndy Yan 		return -EBUSY;
193*20b09c29SAndy Yan 	}
194*20b09c29SAndy Yan 	return 0;
195*20b09c29SAndy Yan }
196*20b09c29SAndy Yan 
197*20b09c29SAndy Yan static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
198*20b09c29SAndy Yan {
199*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
200*20b09c29SAndy Yan 	u32 tmp;
201*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
202*20b09c29SAndy Yan 		u32 offs;
203*20b09c29SAndy Yan 		if (phy_id < 4)
204*20b09c29SAndy Yan 			offs = PCR_PHY_CTL;
205*20b09c29SAndy Yan 		else {
206*20b09c29SAndy Yan 			offs = PCR_PHY_CTL2;
207*20b09c29SAndy Yan 			phy_id -= 4;
208*20b09c29SAndy Yan 		}
209*20b09c29SAndy Yan 		pci_read_config_dword(mvi->pdev, offs, &tmp);
210*20b09c29SAndy Yan 		tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
211*20b09c29SAndy Yan 		pci_write_config_dword(mvi->pdev, offs, tmp);
212*20b09c29SAndy Yan 	} else {
213*20b09c29SAndy Yan 		tmp = mr32(MVS_PHY_CTL);
214*20b09c29SAndy Yan 		tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
215*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
216*20b09c29SAndy Yan 	}
217*20b09c29SAndy Yan }
218*20b09c29SAndy Yan 
219*20b09c29SAndy Yan static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
220*20b09c29SAndy Yan {
221*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
222*20b09c29SAndy Yan 	u32 tmp;
223*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
224*20b09c29SAndy Yan 		u32 offs;
225*20b09c29SAndy Yan 		if (phy_id < 4)
226*20b09c29SAndy Yan 			offs = PCR_PHY_CTL;
227*20b09c29SAndy Yan 		else {
228*20b09c29SAndy Yan 			offs = PCR_PHY_CTL2;
229*20b09c29SAndy Yan 			phy_id -= 4;
230*20b09c29SAndy Yan 		}
231*20b09c29SAndy Yan 		pci_read_config_dword(mvi->pdev, offs, &tmp);
232*20b09c29SAndy Yan 		tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
233*20b09c29SAndy Yan 		pci_write_config_dword(mvi->pdev, offs, tmp);
234*20b09c29SAndy Yan 	} else {
235*20b09c29SAndy Yan 		tmp = mr32(MVS_PHY_CTL);
236*20b09c29SAndy Yan 		tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
237*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
238*20b09c29SAndy Yan 	}
239*20b09c29SAndy Yan }
240*20b09c29SAndy Yan 
241*20b09c29SAndy Yan static int __devinit mvs_64xx_init(struct mvs_info *mvi)
242*20b09c29SAndy Yan {
243*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
244*20b09c29SAndy Yan 	int i;
245*20b09c29SAndy Yan 	u32 tmp, cctl;
246*20b09c29SAndy Yan 
247*20b09c29SAndy Yan 	if (mvi->pdev && mvi->pdev->revision == 0)
248*20b09c29SAndy Yan 		mvi->flags |= MVF_PHY_PWR_FIX;
249*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
250*20b09c29SAndy Yan 		mvs_show_pcie_usage(mvi);
251*20b09c29SAndy Yan 		tmp = mvs_64xx_chip_reset(mvi);
252*20b09c29SAndy Yan 		if (tmp)
253*20b09c29SAndy Yan 			return tmp;
254*20b09c29SAndy Yan 	} else {
255*20b09c29SAndy Yan 		tmp = mr32(MVS_PHY_CTL);
256*20b09c29SAndy Yan 		tmp &= ~PCTL_PWR_OFF;
257*20b09c29SAndy Yan 		tmp |= PCTL_PHY_DSBL;
258*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
259*20b09c29SAndy Yan 	}
260*20b09c29SAndy Yan 
261*20b09c29SAndy Yan 	/* Init Chip */
262*20b09c29SAndy Yan 	/* make sure RST is set; HBA_RST /should/ have done that for us */
263*20b09c29SAndy Yan 	cctl = mr32(MVS_CTL) & 0xFFFF;
264*20b09c29SAndy Yan 	if (cctl & CCTL_RST)
265*20b09c29SAndy Yan 		cctl &= ~CCTL_RST;
266*20b09c29SAndy Yan 	else
267*20b09c29SAndy Yan 		mw32_f(MVS_CTL, cctl | CCTL_RST);
268*20b09c29SAndy Yan 
269*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
270*20b09c29SAndy Yan 		/* write to device control _AND_ device status register */
271*20b09c29SAndy Yan 		pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
272*20b09c29SAndy Yan 		tmp &= ~PRD_REQ_MASK;
273*20b09c29SAndy Yan 		tmp |= PRD_REQ_SIZE;
274*20b09c29SAndy Yan 		pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
275*20b09c29SAndy Yan 
276*20b09c29SAndy Yan 		pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
277*20b09c29SAndy Yan 		tmp &= ~PCTL_PWR_OFF;
278*20b09c29SAndy Yan 		tmp &= ~PCTL_PHY_DSBL;
279*20b09c29SAndy Yan 		pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
280*20b09c29SAndy Yan 
281*20b09c29SAndy Yan 		pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
282*20b09c29SAndy Yan 		tmp &= PCTL_PWR_OFF;
283*20b09c29SAndy Yan 		tmp &= ~PCTL_PHY_DSBL;
284*20b09c29SAndy Yan 		pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
285*20b09c29SAndy Yan 	} else {
286*20b09c29SAndy Yan 		tmp = mr32(MVS_PHY_CTL);
287*20b09c29SAndy Yan 		tmp &= ~PCTL_PWR_OFF;
288*20b09c29SAndy Yan 		tmp |= PCTL_COM_ON;
289*20b09c29SAndy Yan 		tmp &= ~PCTL_PHY_DSBL;
290*20b09c29SAndy Yan 		tmp |= PCTL_LINK_RST;
291*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
292*20b09c29SAndy Yan 		msleep(100);
293*20b09c29SAndy Yan 		tmp &= ~PCTL_LINK_RST;
294*20b09c29SAndy Yan 		mw32(MVS_PHY_CTL, tmp);
295*20b09c29SAndy Yan 		msleep(100);
296*20b09c29SAndy Yan 	}
297*20b09c29SAndy Yan 
298*20b09c29SAndy Yan 	/* reset control */
299*20b09c29SAndy Yan 	mw32(MVS_PCS, 0);		/* MVS_PCS */
300*20b09c29SAndy Yan 	/* init phys */
301*20b09c29SAndy Yan 	mvs_64xx_phy_hacks(mvi);
302*20b09c29SAndy Yan 
303*20b09c29SAndy Yan 	/* enable auto port detection */
304*20b09c29SAndy Yan 	mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN);
305*20b09c29SAndy Yan 
306*20b09c29SAndy Yan 	mw32(MVS_CMD_LIST_LO, mvi->slot_dma);
307*20b09c29SAndy Yan 	mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
308*20b09c29SAndy Yan 
309*20b09c29SAndy Yan 	mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma);
310*20b09c29SAndy Yan 	mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
311*20b09c29SAndy Yan 
312*20b09c29SAndy Yan 	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ);
313*20b09c29SAndy Yan 	mw32(MVS_TX_LO, mvi->tx_dma);
314*20b09c29SAndy Yan 	mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16);
315*20b09c29SAndy Yan 
316*20b09c29SAndy Yan 	mw32(MVS_RX_CFG, MVS_RX_RING_SZ);
317*20b09c29SAndy Yan 	mw32(MVS_RX_LO, mvi->rx_dma);
318*20b09c29SAndy Yan 	mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16);
319*20b09c29SAndy Yan 
320*20b09c29SAndy Yan 	for (i = 0; i < mvi->chip->n_phy; i++) {
321*20b09c29SAndy Yan 		/* set phy local SAS address */
322*20b09c29SAndy Yan 		/* should set little endian SAS address to 64xx chip */
323*20b09c29SAndy Yan 		mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI,
324*20b09c29SAndy Yan 				cpu_to_be64(mvi->phy[i].dev_sas_addr));
325*20b09c29SAndy Yan 
326*20b09c29SAndy Yan 		mvs_64xx_enable_xmt(mvi, i);
327*20b09c29SAndy Yan 
328*20b09c29SAndy Yan 		mvs_64xx_phy_reset(mvi, i, 1);
329*20b09c29SAndy Yan 		msleep(500);
330*20b09c29SAndy Yan 		mvs_64xx_detect_porttype(mvi, i);
331*20b09c29SAndy Yan 	}
332*20b09c29SAndy Yan 	if (mvi->flags & MVF_FLAG_SOC) {
333*20b09c29SAndy Yan 		/* set select registers */
334*20b09c29SAndy Yan 		writel(0x0E008000, regs + 0x000);
335*20b09c29SAndy Yan 		writel(0x59000008, regs + 0x004);
336*20b09c29SAndy Yan 		writel(0x20, regs + 0x008);
337*20b09c29SAndy Yan 		writel(0x20, regs + 0x00c);
338*20b09c29SAndy Yan 		writel(0x20, regs + 0x010);
339*20b09c29SAndy Yan 		writel(0x20, regs + 0x014);
340*20b09c29SAndy Yan 		writel(0x20, regs + 0x018);
341*20b09c29SAndy Yan 		writel(0x20, regs + 0x01c);
342*20b09c29SAndy Yan 	}
343*20b09c29SAndy Yan 	for (i = 0; i < mvi->chip->n_phy; i++) {
344*20b09c29SAndy Yan 		/* clear phy int status */
345*20b09c29SAndy Yan 		tmp = mvs_read_port_irq_stat(mvi, i);
346*20b09c29SAndy Yan 		tmp &= ~PHYEV_SIG_FIS;
347*20b09c29SAndy Yan 		mvs_write_port_irq_stat(mvi, i, tmp);
348*20b09c29SAndy Yan 
349*20b09c29SAndy Yan 		/* set phy int mask */
350*20b09c29SAndy Yan 		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
351*20b09c29SAndy Yan 			PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR |
352*20b09c29SAndy Yan 			PHYEV_DEC_ERR;
353*20b09c29SAndy Yan 		mvs_write_port_irq_mask(mvi, i, tmp);
354*20b09c29SAndy Yan 
355*20b09c29SAndy Yan 		msleep(100);
356*20b09c29SAndy Yan 		mvs_update_phyinfo(mvi, i, 1);
357*20b09c29SAndy Yan 	}
358*20b09c29SAndy Yan 
359*20b09c29SAndy Yan 	/* FIXME: update wide port bitmaps */
360*20b09c29SAndy Yan 
361*20b09c29SAndy Yan 	/* little endian for open address and command table, etc. */
362*20b09c29SAndy Yan 	/*
363*20b09c29SAndy Yan 	 * it seems that ( from the spec ) turning on big-endian won't
364*20b09c29SAndy Yan 	 * do us any good on big-endian machines, need further confirmation
365*20b09c29SAndy Yan 	 */
366*20b09c29SAndy Yan 	cctl = mr32(MVS_CTL);
367*20b09c29SAndy Yan 	cctl |= CCTL_ENDIAN_CMD;
368*20b09c29SAndy Yan 	cctl |= CCTL_ENDIAN_DATA;
369*20b09c29SAndy Yan 	cctl &= ~CCTL_ENDIAN_OPEN;
370*20b09c29SAndy Yan 	cctl |= CCTL_ENDIAN_RSP;
371*20b09c29SAndy Yan 	mw32_f(MVS_CTL, cctl);
372*20b09c29SAndy Yan 
373*20b09c29SAndy Yan 	/* reset CMD queue */
374*20b09c29SAndy Yan 	tmp = mr32(MVS_PCS);
375*20b09c29SAndy Yan 	tmp |= PCS_CMD_RST;
376*20b09c29SAndy Yan 	mw32(MVS_PCS, tmp);
377*20b09c29SAndy Yan 	/* interrupt coalescing may cause missing HW interrput in some case,
378*20b09c29SAndy Yan 	 * and the max count is 0x1ff, while our max slot is 0x200,
379*20b09c29SAndy Yan 	 * it will make count 0.
380*20b09c29SAndy Yan 	 */
381*20b09c29SAndy Yan 	tmp = 0;
382*20b09c29SAndy Yan 	mw32(MVS_INT_COAL, tmp);
383*20b09c29SAndy Yan 
384*20b09c29SAndy Yan 	tmp = 0x100;
385*20b09c29SAndy Yan 	mw32(MVS_INT_COAL_TMOUT, tmp);
386*20b09c29SAndy Yan 
387*20b09c29SAndy Yan 	/* ladies and gentlemen, start your engines */
388*20b09c29SAndy Yan 	mw32(MVS_TX_CFG, 0);
389*20b09c29SAndy Yan 	mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
390*20b09c29SAndy Yan 	mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN);
391*20b09c29SAndy Yan 	/* enable CMD/CMPL_Q/RESP mode */
392*20b09c29SAndy Yan 	mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN |
393*20b09c29SAndy Yan 		PCS_CMD_EN | PCS_CMD_STOP_ERR);
394*20b09c29SAndy Yan 
395*20b09c29SAndy Yan 	/* enable completion queue interrupt */
396*20b09c29SAndy Yan 	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
397*20b09c29SAndy Yan 		CINT_DMA_PCIE);
398*20b09c29SAndy Yan 
399*20b09c29SAndy Yan 	mw32(MVS_INT_MASK, tmp);
400*20b09c29SAndy Yan 
401*20b09c29SAndy Yan 	/* Enable SRS interrupt */
402*20b09c29SAndy Yan 	mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
403*20b09c29SAndy Yan 
404*20b09c29SAndy Yan 	return 0;
405*20b09c29SAndy Yan }
406*20b09c29SAndy Yan 
407*20b09c29SAndy Yan static int mvs_64xx_ioremap(struct mvs_info *mvi)
408*20b09c29SAndy Yan {
409*20b09c29SAndy Yan 	if (!mvs_ioremap(mvi, 4, 2))
410*20b09c29SAndy Yan 		return 0;
411*20b09c29SAndy Yan 	return -1;
412*20b09c29SAndy Yan }
413*20b09c29SAndy Yan 
414*20b09c29SAndy Yan static void mvs_64xx_iounmap(struct mvs_info *mvi)
415*20b09c29SAndy Yan {
416*20b09c29SAndy Yan 	mvs_iounmap(mvi->regs);
417*20b09c29SAndy Yan 	mvs_iounmap(mvi->regs_ex);
418*20b09c29SAndy Yan }
419*20b09c29SAndy Yan 
420*20b09c29SAndy Yan static void mvs_64xx_interrupt_enable(struct mvs_info *mvi)
421dd4969a8SJeff Garzik {
422dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
423dd4969a8SJeff Garzik 	u32 tmp;
424dd4969a8SJeff Garzik 
425*20b09c29SAndy Yan 	tmp = mr32(MVS_GBL_CTL);
426*20b09c29SAndy Yan 	mw32(MVS_GBL_CTL, tmp | INT_EN);
427dd4969a8SJeff Garzik }
428dd4969a8SJeff Garzik 
429*20b09c29SAndy Yan static void mvs_64xx_interrupt_disable(struct mvs_info *mvi)
430dd4969a8SJeff Garzik {
431dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
432dd4969a8SJeff Garzik 	u32 tmp;
433dd4969a8SJeff Garzik 
434*20b09c29SAndy Yan 	tmp = mr32(MVS_GBL_CTL);
435*20b09c29SAndy Yan 	mw32(MVS_GBL_CTL, tmp & ~INT_EN);
436dd4969a8SJeff Garzik }
437dd4969a8SJeff Garzik 
438*20b09c29SAndy Yan static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq)
439*20b09c29SAndy Yan {
440*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
441*20b09c29SAndy Yan 	u32 stat;
442*20b09c29SAndy Yan 
443*20b09c29SAndy Yan 	if (!(mvi->flags & MVF_FLAG_SOC)) {
444*20b09c29SAndy Yan 		stat = mr32(MVS_GBL_INT_STAT);
445*20b09c29SAndy Yan 
446*20b09c29SAndy Yan 		if (stat == 0 || stat == 0xffffffff)
447*20b09c29SAndy Yan 			return 0;
448*20b09c29SAndy Yan 	} else
449*20b09c29SAndy Yan 		stat = 1;
450*20b09c29SAndy Yan 	return stat;
451*20b09c29SAndy Yan }
452*20b09c29SAndy Yan 
453*20b09c29SAndy Yan static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat)
454*20b09c29SAndy Yan {
455*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
456*20b09c29SAndy Yan 
457*20b09c29SAndy Yan 	/* clear CMD_CMPLT ASAP */
458*20b09c29SAndy Yan 	mw32_f(MVS_INT_STAT, CINT_DONE);
459*20b09c29SAndy Yan #ifndef MVS_USE_TASKLET
460*20b09c29SAndy Yan 	spin_lock(&mvi->lock);
461*20b09c29SAndy Yan #endif
462*20b09c29SAndy Yan 	mvs_int_full(mvi);
463*20b09c29SAndy Yan #ifndef MVS_USE_TASKLET
464*20b09c29SAndy Yan 	spin_unlock(&mvi->lock);
465*20b09c29SAndy Yan #endif
466*20b09c29SAndy Yan 	return IRQ_HANDLED;
467*20b09c29SAndy Yan }
468*20b09c29SAndy Yan 
469*20b09c29SAndy Yan static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx)
470*20b09c29SAndy Yan {
471*20b09c29SAndy Yan 	u32 tmp;
472*20b09c29SAndy Yan 	mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32));
473*20b09c29SAndy Yan 	mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32));
474*20b09c29SAndy Yan 	do {
475*20b09c29SAndy Yan 		tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3));
476*20b09c29SAndy Yan 	} while (tmp & 1 << (slot_idx % 32));
477*20b09c29SAndy Yan 	do {
478*20b09c29SAndy Yan 		tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3));
479*20b09c29SAndy Yan 	} while (tmp & 1 << (slot_idx % 32));
480*20b09c29SAndy Yan }
481*20b09c29SAndy Yan 
482*20b09c29SAndy Yan static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
483*20b09c29SAndy Yan 				u32 tfs)
484*20b09c29SAndy Yan {
485*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
486*20b09c29SAndy Yan 	u32 tmp;
487*20b09c29SAndy Yan 
488*20b09c29SAndy Yan 	if (type == PORT_TYPE_SATA) {
489*20b09c29SAndy Yan 		tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
490*20b09c29SAndy Yan 		mw32(MVS_INT_STAT_SRS_0, tmp);
491*20b09c29SAndy Yan 	}
492*20b09c29SAndy Yan 	mw32(MVS_INT_STAT, CINT_CI_STOP);
493*20b09c29SAndy Yan 	tmp = mr32(MVS_PCS) | 0xFF00;
494*20b09c29SAndy Yan 	mw32(MVS_PCS, tmp);
495*20b09c29SAndy Yan }
496*20b09c29SAndy Yan 
497*20b09c29SAndy Yan static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
498dd4969a8SJeff Garzik {
499dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
500dd4969a8SJeff Garzik 	u32 tmp, offs;
501dd4969a8SJeff Garzik 
502dd4969a8SJeff Garzik 	if (*tfs == MVS_ID_NOT_MAPPED)
503dd4969a8SJeff Garzik 		return;
504dd4969a8SJeff Garzik 
505dd4969a8SJeff Garzik 	offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
506dd4969a8SJeff Garzik 	if (*tfs < 16) {
507*20b09c29SAndy Yan 		tmp = mr32(MVS_PCS);
508*20b09c29SAndy Yan 		mw32(MVS_PCS, tmp & ~offs);
509dd4969a8SJeff Garzik 	} else {
510*20b09c29SAndy Yan 		tmp = mr32(MVS_CTL);
511*20b09c29SAndy Yan 		mw32(MVS_CTL, tmp & ~offs);
512dd4969a8SJeff Garzik 	}
513dd4969a8SJeff Garzik 
514*20b09c29SAndy Yan 	tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs);
515dd4969a8SJeff Garzik 	if (tmp)
516*20b09c29SAndy Yan 		mw32(MVS_INT_STAT_SRS_0, tmp);
517dd4969a8SJeff Garzik 
518dd4969a8SJeff Garzik 	*tfs = MVS_ID_NOT_MAPPED;
519*20b09c29SAndy Yan 	return;
520dd4969a8SJeff Garzik }
521dd4969a8SJeff Garzik 
522*20b09c29SAndy Yan static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
523dd4969a8SJeff Garzik {
524dd4969a8SJeff Garzik 	int i;
525dd4969a8SJeff Garzik 	u32 tmp, offs;
526dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
527dd4969a8SJeff Garzik 
528*20b09c29SAndy Yan 	if (*tfs != MVS_ID_NOT_MAPPED)
529dd4969a8SJeff Garzik 		return 0;
530dd4969a8SJeff Garzik 
531*20b09c29SAndy Yan 	tmp = mr32(MVS_PCS);
532dd4969a8SJeff Garzik 
533dd4969a8SJeff Garzik 	for (i = 0; i < mvi->chip->srs_sz; i++) {
534dd4969a8SJeff Garzik 		if (i == 16)
535*20b09c29SAndy Yan 			tmp = mr32(MVS_CTL);
536dd4969a8SJeff Garzik 		offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
537dd4969a8SJeff Garzik 		if (!(tmp & offs)) {
538*20b09c29SAndy Yan 			*tfs = i;
539dd4969a8SJeff Garzik 
540dd4969a8SJeff Garzik 			if (i < 16)
541*20b09c29SAndy Yan 				mw32(MVS_PCS, tmp | offs);
542dd4969a8SJeff Garzik 			else
543*20b09c29SAndy Yan 				mw32(MVS_CTL, tmp | offs);
544*20b09c29SAndy Yan 			tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i);
545dd4969a8SJeff Garzik 			if (tmp)
546*20b09c29SAndy Yan 				mw32(MVS_INT_STAT_SRS_0, tmp);
547dd4969a8SJeff Garzik 			return 0;
548dd4969a8SJeff Garzik 		}
549dd4969a8SJeff Garzik 	}
550dd4969a8SJeff Garzik 	return MVS_ID_NOT_MAPPED;
551dd4969a8SJeff Garzik }
552dd4969a8SJeff Garzik 
553*20b09c29SAndy Yan void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
554*20b09c29SAndy Yan {
555*20b09c29SAndy Yan 	int i;
556*20b09c29SAndy Yan 	struct scatterlist *sg;
557*20b09c29SAndy Yan 	struct mvs_prd *buf_prd = prd;
558*20b09c29SAndy Yan 	for_each_sg(scatter, sg, nr, i) {
559*20b09c29SAndy Yan 		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
560*20b09c29SAndy Yan 		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
561*20b09c29SAndy Yan 		buf_prd++;
562*20b09c29SAndy Yan 	}
563*20b09c29SAndy Yan }
564*20b09c29SAndy Yan 
565*20b09c29SAndy Yan static int mvs_64xx_oob_done(struct mvs_info *mvi, int i)
566*20b09c29SAndy Yan {
567*20b09c29SAndy Yan 	u32 phy_st;
568*20b09c29SAndy Yan 	mvs_write_port_cfg_addr(mvi, i,
569*20b09c29SAndy Yan 			PHYR_PHY_STAT);
570*20b09c29SAndy Yan 	phy_st = mvs_read_port_cfg_data(mvi, i);
571*20b09c29SAndy Yan 	if (phy_st & PHY_OOB_DTCTD)
572*20b09c29SAndy Yan 		return 1;
573*20b09c29SAndy Yan 	return 0;
574*20b09c29SAndy Yan }
575*20b09c29SAndy Yan 
576*20b09c29SAndy Yan static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i,
577*20b09c29SAndy Yan 				struct sas_identify_frame *id)
578*20b09c29SAndy Yan 
579*20b09c29SAndy Yan {
580*20b09c29SAndy Yan 	struct mvs_phy *phy = &mvi->phy[i];
581*20b09c29SAndy Yan 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
582*20b09c29SAndy Yan 
583*20b09c29SAndy Yan 	sas_phy->linkrate =
584*20b09c29SAndy Yan 		(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
585*20b09c29SAndy Yan 			PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
586*20b09c29SAndy Yan 
587*20b09c29SAndy Yan 	phy->minimum_linkrate =
588*20b09c29SAndy Yan 		(phy->phy_status &
589*20b09c29SAndy Yan 			PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
590*20b09c29SAndy Yan 	phy->maximum_linkrate =
591*20b09c29SAndy Yan 		(phy->phy_status &
592*20b09c29SAndy Yan 			PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
593*20b09c29SAndy Yan 
594*20b09c29SAndy Yan 	mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
595*20b09c29SAndy Yan 	phy->dev_info = mvs_read_port_cfg_data(mvi, i);
596*20b09c29SAndy Yan 
597*20b09c29SAndy Yan 	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
598*20b09c29SAndy Yan 	phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
599*20b09c29SAndy Yan 
600*20b09c29SAndy Yan 	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
601*20b09c29SAndy Yan 	phy->att_dev_sas_addr =
602*20b09c29SAndy Yan 	     (u64) mvs_read_port_cfg_data(mvi, i) << 32;
603*20b09c29SAndy Yan 	mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
604*20b09c29SAndy Yan 	phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
605*20b09c29SAndy Yan 	phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr);
606*20b09c29SAndy Yan }
607*20b09c29SAndy Yan 
608*20b09c29SAndy Yan static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
609*20b09c29SAndy Yan {
610*20b09c29SAndy Yan 	u32 tmp;
611*20b09c29SAndy Yan 	struct mvs_phy *phy = &mvi->phy[i];
612*20b09c29SAndy Yan 	/* workaround for HW phy decoding error on 1.5g disk drive */
613*20b09c29SAndy Yan 	mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
614*20b09c29SAndy Yan 	tmp = mvs_read_port_vsr_data(mvi, i);
615*20b09c29SAndy Yan 	if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
616*20b09c29SAndy Yan 	     PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
617*20b09c29SAndy Yan 		SAS_LINK_RATE_1_5_GBPS)
618*20b09c29SAndy Yan 		tmp &= ~PHY_MODE6_LATECLK;
619*20b09c29SAndy Yan 	else
620*20b09c29SAndy Yan 		tmp |= PHY_MODE6_LATECLK;
621*20b09c29SAndy Yan 	mvs_write_port_vsr_data(mvi, i, tmp);
622*20b09c29SAndy Yan }
623*20b09c29SAndy Yan 
624*20b09c29SAndy Yan void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
625*20b09c29SAndy Yan 			struct sas_phy_linkrates *rates)
626*20b09c29SAndy Yan {
627*20b09c29SAndy Yan 	u32 lrmin = 0, lrmax = 0;
628*20b09c29SAndy Yan 	u32 tmp;
629*20b09c29SAndy Yan 
630*20b09c29SAndy Yan 	tmp = mvs_read_phy_ctl(mvi, phy_id);
631*20b09c29SAndy Yan 	lrmin = (rates->minimum_linkrate << 8);
632*20b09c29SAndy Yan 	lrmax = (rates->maximum_linkrate << 12);
633*20b09c29SAndy Yan 
634*20b09c29SAndy Yan 	if (lrmin) {
635*20b09c29SAndy Yan 		tmp &= ~(0xf << 8);
636*20b09c29SAndy Yan 		tmp |= lrmin;
637*20b09c29SAndy Yan 	}
638*20b09c29SAndy Yan 	if (lrmax) {
639*20b09c29SAndy Yan 		tmp &= ~(0xf << 12);
640*20b09c29SAndy Yan 		tmp |= lrmax;
641*20b09c29SAndy Yan 	}
642*20b09c29SAndy Yan 	mvs_write_phy_ctl(mvi, phy_id, tmp);
643*20b09c29SAndy Yan 	mvs_64xx_phy_reset(mvi, phy_id, 1);
644*20b09c29SAndy Yan }
645*20b09c29SAndy Yan 
646*20b09c29SAndy Yan static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
647*20b09c29SAndy Yan {
648*20b09c29SAndy Yan 	u32 tmp;
649*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs;
650*20b09c29SAndy Yan 	tmp = mr32(MVS_PCS);
651*20b09c29SAndy Yan 	mw32(MVS_PCS, tmp & 0xFFFF);
652*20b09c29SAndy Yan 	mw32(MVS_PCS, tmp);
653*20b09c29SAndy Yan 	tmp = mr32(MVS_CTL);
654*20b09c29SAndy Yan 	mw32(MVS_CTL, tmp & 0xFFFF);
655*20b09c29SAndy Yan 	mw32(MVS_CTL, tmp);
656*20b09c29SAndy Yan }
657*20b09c29SAndy Yan 
658*20b09c29SAndy Yan 
659*20b09c29SAndy Yan u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
660*20b09c29SAndy Yan {
661*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs_ex;
662*20b09c29SAndy Yan 	return ior32(SPI_DATA_REG_64XX);
663*20b09c29SAndy Yan }
664*20b09c29SAndy Yan 
665*20b09c29SAndy Yan void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
666*20b09c29SAndy Yan {
667*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs_ex;
668*20b09c29SAndy Yan 	 iow32(SPI_DATA_REG_64XX, data);
669*20b09c29SAndy Yan }
670*20b09c29SAndy Yan 
671*20b09c29SAndy Yan 
672*20b09c29SAndy Yan int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
673*20b09c29SAndy Yan 			u32      *dwCmd,
674*20b09c29SAndy Yan 			u8       cmd,
675*20b09c29SAndy Yan 			u8       read,
676*20b09c29SAndy Yan 			u8       length,
677*20b09c29SAndy Yan 			u32      addr
678*20b09c29SAndy Yan 			)
679*20b09c29SAndy Yan {
680*20b09c29SAndy Yan 	u32  dwTmp;
681*20b09c29SAndy Yan 
682*20b09c29SAndy Yan 	dwTmp = ((u32)cmd << 24) | ((u32)length << 19);
683*20b09c29SAndy Yan 	if (read)
684*20b09c29SAndy Yan 		dwTmp |= 1U<<23;
685*20b09c29SAndy Yan 
686*20b09c29SAndy Yan 	if (addr != MV_MAX_U32) {
687*20b09c29SAndy Yan 		dwTmp |= 1U<<22;
688*20b09c29SAndy Yan 		dwTmp |= (addr & 0x0003FFFF);
689*20b09c29SAndy Yan 	}
690*20b09c29SAndy Yan 
691*20b09c29SAndy Yan 	*dwCmd = dwTmp;
692*20b09c29SAndy Yan 	return 0;
693*20b09c29SAndy Yan }
694*20b09c29SAndy Yan 
695*20b09c29SAndy Yan 
696*20b09c29SAndy Yan int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
697*20b09c29SAndy Yan {
698*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs_ex;
699*20b09c29SAndy Yan 	int     retry;
700*20b09c29SAndy Yan 
701*20b09c29SAndy Yan 	for (retry = 0; retry < 1; retry++) {
702*20b09c29SAndy Yan 		iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE);
703*20b09c29SAndy Yan 		iow32(SPI_CMD_REG_64XX, cmd);
704*20b09c29SAndy Yan 		iow32(SPI_CTRL_REG_64XX,
705*20b09c29SAndy Yan 			SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART);
706*20b09c29SAndy Yan 	}
707*20b09c29SAndy Yan 
708*20b09c29SAndy Yan 	return 0;
709*20b09c29SAndy Yan }
710*20b09c29SAndy Yan 
711*20b09c29SAndy Yan int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
712*20b09c29SAndy Yan {
713*20b09c29SAndy Yan 	void __iomem *regs = mvi->regs_ex;
714*20b09c29SAndy Yan 	u32 i, dwTmp;
715*20b09c29SAndy Yan 
716*20b09c29SAndy Yan 	for (i = 0; i < timeout; i++) {
717*20b09c29SAndy Yan 		dwTmp = ior32(SPI_CTRL_REG_64XX);
718*20b09c29SAndy Yan 		if (!(dwTmp & SPI_CTRL_SPISTART))
719*20b09c29SAndy Yan 			return 0;
720*20b09c29SAndy Yan 		msleep(10);
721*20b09c29SAndy Yan 	}
722*20b09c29SAndy Yan 
723*20b09c29SAndy Yan 	return -1;
724*20b09c29SAndy Yan }
725*20b09c29SAndy Yan 
726*20b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX
727*20b09c29SAndy Yan void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
728*20b09c29SAndy Yan {
729*20b09c29SAndy Yan 	int i;
730*20b09c29SAndy Yan 	struct mvs_prd *buf_prd = prd;
731*20b09c29SAndy Yan 	buf_prd	+= from;
732*20b09c29SAndy Yan 	for (i = 0; i < MAX_SG_ENTRY - from; i++) {
733*20b09c29SAndy Yan 		buf_prd->addr = cpu_to_le64(buf_dma);
734*20b09c29SAndy Yan 		buf_prd->len = cpu_to_le32(buf_len);
735*20b09c29SAndy Yan 		++buf_prd;
736*20b09c29SAndy Yan 	}
737*20b09c29SAndy Yan }
738*20b09c29SAndy Yan #endif
739*20b09c29SAndy Yan 
740*20b09c29SAndy Yan const struct mvs_dispatch mvs_64xx_dispatch = {
741*20b09c29SAndy Yan 	"mv64xx",
742*20b09c29SAndy Yan 	mvs_64xx_init,
743*20b09c29SAndy Yan 	NULL,
744*20b09c29SAndy Yan 	mvs_64xx_ioremap,
745*20b09c29SAndy Yan 	mvs_64xx_iounmap,
746*20b09c29SAndy Yan 	mvs_64xx_isr,
747*20b09c29SAndy Yan 	mvs_64xx_isr_status,
748*20b09c29SAndy Yan 	mvs_64xx_interrupt_enable,
749*20b09c29SAndy Yan 	mvs_64xx_interrupt_disable,
750*20b09c29SAndy Yan 	mvs_read_phy_ctl,
751*20b09c29SAndy Yan 	mvs_write_phy_ctl,
752*20b09c29SAndy Yan 	mvs_read_port_cfg_data,
753*20b09c29SAndy Yan 	mvs_write_port_cfg_data,
754*20b09c29SAndy Yan 	mvs_write_port_cfg_addr,
755*20b09c29SAndy Yan 	mvs_read_port_vsr_data,
756*20b09c29SAndy Yan 	mvs_write_port_vsr_data,
757*20b09c29SAndy Yan 	mvs_write_port_vsr_addr,
758*20b09c29SAndy Yan 	mvs_read_port_irq_stat,
759*20b09c29SAndy Yan 	mvs_write_port_irq_stat,
760*20b09c29SAndy Yan 	mvs_read_port_irq_mask,
761*20b09c29SAndy Yan 	mvs_write_port_irq_mask,
762*20b09c29SAndy Yan 	mvs_get_sas_addr,
763*20b09c29SAndy Yan 	mvs_64xx_command_active,
764*20b09c29SAndy Yan 	mvs_64xx_issue_stop,
765*20b09c29SAndy Yan 	mvs_start_delivery,
766*20b09c29SAndy Yan 	mvs_rx_update,
767*20b09c29SAndy Yan 	mvs_int_full,
768*20b09c29SAndy Yan 	mvs_64xx_assign_reg_set,
769*20b09c29SAndy Yan 	mvs_64xx_free_reg_set,
770*20b09c29SAndy Yan 	mvs_get_prd_size,
771*20b09c29SAndy Yan 	mvs_get_prd_count,
772*20b09c29SAndy Yan 	mvs_64xx_make_prd,
773*20b09c29SAndy Yan 	mvs_64xx_detect_porttype,
774*20b09c29SAndy Yan 	mvs_64xx_oob_done,
775*20b09c29SAndy Yan 	mvs_64xx_fix_phy_info,
776*20b09c29SAndy Yan 	mvs_64xx_phy_work_around,
777*20b09c29SAndy Yan 	mvs_64xx_phy_set_link_rate,
778*20b09c29SAndy Yan 	mvs_hw_max_link_rate,
779*20b09c29SAndy Yan 	mvs_64xx_phy_disable,
780*20b09c29SAndy Yan 	mvs_64xx_phy_enable,
781*20b09c29SAndy Yan 	mvs_64xx_phy_reset,
782*20b09c29SAndy Yan 	mvs_64xx_stp_reset,
783*20b09c29SAndy Yan 	mvs_64xx_clear_active_cmds,
784*20b09c29SAndy Yan 	mvs_64xx_spi_read_data,
785*20b09c29SAndy Yan 	mvs_64xx_spi_write_data,
786*20b09c29SAndy Yan 	mvs_64xx_spi_buildcmd,
787*20b09c29SAndy Yan 	mvs_64xx_spi_issuecmd,
788*20b09c29SAndy Yan 	mvs_64xx_spi_waitdataready,
789*20b09c29SAndy Yan #ifndef DISABLE_HOTPLUG_DMA_FIX
790*20b09c29SAndy Yan 	mvs_64xx_fix_dma,
791*20b09c29SAndy Yan #endif
792*20b09c29SAndy Yan };
793*20b09c29SAndy Yan 
794