xref: /openbmc/linux/drivers/scsi/mvsas/mv_64xx.c (revision dd4969a892ea522ecf9d7d826ba1531ce044d46f)
1*dd4969a8SJeff Garzik /*
2*dd4969a8SJeff Garzik 	mv_64xx.c - Marvell 88SE6440 SAS/SATA support
3*dd4969a8SJeff Garzik 
4*dd4969a8SJeff Garzik 	Copyright 2007 Red Hat, Inc.
5*dd4969a8SJeff Garzik 	Copyright 2008 Marvell. <kewei@marvell.com>
6*dd4969a8SJeff Garzik 
7*dd4969a8SJeff Garzik 	This program is free software; you can redistribute it and/or
8*dd4969a8SJeff Garzik 	modify it under the terms of the GNU General Public License as
9*dd4969a8SJeff Garzik 	published by the Free Software Foundation; either version 2,
10*dd4969a8SJeff Garzik 	or (at your option) any later version.
11*dd4969a8SJeff Garzik 
12*dd4969a8SJeff Garzik 	This program is distributed in the hope that it will be useful,
13*dd4969a8SJeff Garzik 	but WITHOUT ANY WARRANTY; without even the implied warranty
14*dd4969a8SJeff Garzik 	of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15*dd4969a8SJeff Garzik 	See the GNU General Public License for more details.
16*dd4969a8SJeff Garzik 
17*dd4969a8SJeff Garzik 	You should have received a copy of the GNU General Public
18*dd4969a8SJeff Garzik 	License along with this program; see the file COPYING.	If not,
19*dd4969a8SJeff Garzik 	write to the Free Software Foundation, 675 Mass Ave, Cambridge,
20*dd4969a8SJeff Garzik 	MA 02139, USA.
21*dd4969a8SJeff Garzik 
22*dd4969a8SJeff Garzik  */
23*dd4969a8SJeff Garzik 
24*dd4969a8SJeff Garzik #include "mv_sas.h"
25*dd4969a8SJeff Garzik #include "mv_64xx.h"
26*dd4969a8SJeff Garzik #include "mv_chips.h"
27*dd4969a8SJeff Garzik 
28*dd4969a8SJeff Garzik void mvs_detect_porttype(struct mvs_info *mvi, int i)
29*dd4969a8SJeff Garzik {
30*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
31*dd4969a8SJeff Garzik 	u32 reg;
32*dd4969a8SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[i];
33*dd4969a8SJeff Garzik 
34*dd4969a8SJeff Garzik 	/* TODO check & save device type */
35*dd4969a8SJeff Garzik 	reg = mr32(GBL_PORT_TYPE);
36*dd4969a8SJeff Garzik 
37*dd4969a8SJeff Garzik 	if (reg & MODE_SAS_SATA & (1 << i))
38*dd4969a8SJeff Garzik 		phy->phy_type |= PORT_TYPE_SAS;
39*dd4969a8SJeff Garzik 	else
40*dd4969a8SJeff Garzik 		phy->phy_type |= PORT_TYPE_SATA;
41*dd4969a8SJeff Garzik }
42*dd4969a8SJeff Garzik 
43*dd4969a8SJeff Garzik void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
44*dd4969a8SJeff Garzik {
45*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
46*dd4969a8SJeff Garzik 	u32 tmp;
47*dd4969a8SJeff Garzik 
48*dd4969a8SJeff Garzik 	tmp = mr32(PCS);
49*dd4969a8SJeff Garzik 	if (mvi->chip->n_phy <= 4)
50*dd4969a8SJeff Garzik 		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
51*dd4969a8SJeff Garzik 	else
52*dd4969a8SJeff Garzik 		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
53*dd4969a8SJeff Garzik 	mw32(PCS, tmp);
54*dd4969a8SJeff Garzik }
55*dd4969a8SJeff Garzik 
56*dd4969a8SJeff Garzik void __devinit mvs_phy_hacks(struct mvs_info *mvi)
57*dd4969a8SJeff Garzik {
58*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
59*dd4969a8SJeff Garzik 	u32 tmp;
60*dd4969a8SJeff Garzik 
61*dd4969a8SJeff Garzik 	/* workaround for SATA R-ERR, to ignore phy glitch */
62*dd4969a8SJeff Garzik 	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
63*dd4969a8SJeff Garzik 	tmp &= ~(1 << 9);
64*dd4969a8SJeff Garzik 	tmp |= (1 << 10);
65*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
66*dd4969a8SJeff Garzik 
67*dd4969a8SJeff Garzik 	/* enable retry 127 times */
68*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
69*dd4969a8SJeff Garzik 
70*dd4969a8SJeff Garzik 	/* extend open frame timeout to max */
71*dd4969a8SJeff Garzik 	tmp = mvs_cr32(regs, CMD_SAS_CTL0);
72*dd4969a8SJeff Garzik 	tmp &= ~0xffff;
73*dd4969a8SJeff Garzik 	tmp |= 0x3fff;
74*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_SAS_CTL0, tmp);
75*dd4969a8SJeff Garzik 
76*dd4969a8SJeff Garzik 	/* workaround for WDTIMEOUT , set to 550 ms */
77*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
78*dd4969a8SJeff Garzik 
79*dd4969a8SJeff Garzik 	/* not to halt for different port op during wideport link change */
80*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
81*dd4969a8SJeff Garzik 
82*dd4969a8SJeff Garzik 	/* workaround for Seagate disk not-found OOB sequence, recv
83*dd4969a8SJeff Garzik 	 * COMINIT before sending out COMWAKE */
84*dd4969a8SJeff Garzik 	tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
85*dd4969a8SJeff Garzik 	tmp &= 0x0000ffff;
86*dd4969a8SJeff Garzik 	tmp |= 0x00fa0000;
87*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
88*dd4969a8SJeff Garzik 
89*dd4969a8SJeff Garzik 	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
90*dd4969a8SJeff Garzik 	tmp &= 0x1fffffff;
91*dd4969a8SJeff Garzik 	tmp |= (2U << 29);	/* 8 ms retry */
92*dd4969a8SJeff Garzik 	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
93*dd4969a8SJeff Garzik 
94*dd4969a8SJeff Garzik 	/* TEST - for phy decoding error, adjust voltage levels */
95*dd4969a8SJeff Garzik 	mw32(P0_VSR_ADDR + 0, 0x8);
96*dd4969a8SJeff Garzik 	mw32(P0_VSR_DATA + 0, 0x2F0);
97*dd4969a8SJeff Garzik 
98*dd4969a8SJeff Garzik 	mw32(P0_VSR_ADDR + 8, 0x8);
99*dd4969a8SJeff Garzik 	mw32(P0_VSR_DATA + 8, 0x2F0);
100*dd4969a8SJeff Garzik 
101*dd4969a8SJeff Garzik 	mw32(P0_VSR_ADDR + 16, 0x8);
102*dd4969a8SJeff Garzik 	mw32(P0_VSR_DATA + 16, 0x2F0);
103*dd4969a8SJeff Garzik 
104*dd4969a8SJeff Garzik 	mw32(P0_VSR_ADDR + 24, 0x8);
105*dd4969a8SJeff Garzik 	mw32(P0_VSR_DATA + 24, 0x2F0);
106*dd4969a8SJeff Garzik 
107*dd4969a8SJeff Garzik }
108*dd4969a8SJeff Garzik 
109*dd4969a8SJeff Garzik void mvs_hba_interrupt_enable(struct mvs_info *mvi)
110*dd4969a8SJeff Garzik {
111*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
112*dd4969a8SJeff Garzik 	u32 tmp;
113*dd4969a8SJeff Garzik 
114*dd4969a8SJeff Garzik 	tmp = mr32(GBL_CTL);
115*dd4969a8SJeff Garzik 
116*dd4969a8SJeff Garzik 	mw32(GBL_CTL, tmp | INT_EN);
117*dd4969a8SJeff Garzik }
118*dd4969a8SJeff Garzik 
119*dd4969a8SJeff Garzik void mvs_hba_interrupt_disable(struct mvs_info *mvi)
120*dd4969a8SJeff Garzik {
121*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
122*dd4969a8SJeff Garzik 	u32 tmp;
123*dd4969a8SJeff Garzik 
124*dd4969a8SJeff Garzik 	tmp = mr32(GBL_CTL);
125*dd4969a8SJeff Garzik 
126*dd4969a8SJeff Garzik 	mw32(GBL_CTL, tmp & ~INT_EN);
127*dd4969a8SJeff Garzik }
128*dd4969a8SJeff Garzik 
129*dd4969a8SJeff Garzik void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
130*dd4969a8SJeff Garzik {
131*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
132*dd4969a8SJeff Garzik 	u32 tmp, offs;
133*dd4969a8SJeff Garzik 	u8 *tfs = &port->taskfileset;
134*dd4969a8SJeff Garzik 
135*dd4969a8SJeff Garzik 	if (*tfs == MVS_ID_NOT_MAPPED)
136*dd4969a8SJeff Garzik 		return;
137*dd4969a8SJeff Garzik 
138*dd4969a8SJeff Garzik 	offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
139*dd4969a8SJeff Garzik 	if (*tfs < 16) {
140*dd4969a8SJeff Garzik 		tmp = mr32(PCS);
141*dd4969a8SJeff Garzik 		mw32(PCS, tmp & ~offs);
142*dd4969a8SJeff Garzik 	} else {
143*dd4969a8SJeff Garzik 		tmp = mr32(CTL);
144*dd4969a8SJeff Garzik 		mw32(CTL, tmp & ~offs);
145*dd4969a8SJeff Garzik 	}
146*dd4969a8SJeff Garzik 
147*dd4969a8SJeff Garzik 	tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
148*dd4969a8SJeff Garzik 	if (tmp)
149*dd4969a8SJeff Garzik 		mw32(INT_STAT_SRS, tmp);
150*dd4969a8SJeff Garzik 
151*dd4969a8SJeff Garzik 	*tfs = MVS_ID_NOT_MAPPED;
152*dd4969a8SJeff Garzik }
153*dd4969a8SJeff Garzik 
154*dd4969a8SJeff Garzik u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
155*dd4969a8SJeff Garzik {
156*dd4969a8SJeff Garzik 	int i;
157*dd4969a8SJeff Garzik 	u32 tmp, offs;
158*dd4969a8SJeff Garzik 	void __iomem *regs = mvi->regs;
159*dd4969a8SJeff Garzik 
160*dd4969a8SJeff Garzik 	if (port->taskfileset != MVS_ID_NOT_MAPPED)
161*dd4969a8SJeff Garzik 		return 0;
162*dd4969a8SJeff Garzik 
163*dd4969a8SJeff Garzik 	tmp = mr32(PCS);
164*dd4969a8SJeff Garzik 
165*dd4969a8SJeff Garzik 	for (i = 0; i < mvi->chip->srs_sz; i++) {
166*dd4969a8SJeff Garzik 		if (i == 16)
167*dd4969a8SJeff Garzik 			tmp = mr32(CTL);
168*dd4969a8SJeff Garzik 		offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
169*dd4969a8SJeff Garzik 		if (!(tmp & offs)) {
170*dd4969a8SJeff Garzik 			port->taskfileset = i;
171*dd4969a8SJeff Garzik 
172*dd4969a8SJeff Garzik 			if (i < 16)
173*dd4969a8SJeff Garzik 				mw32(PCS, tmp | offs);
174*dd4969a8SJeff Garzik 			else
175*dd4969a8SJeff Garzik 				mw32(CTL, tmp | offs);
176*dd4969a8SJeff Garzik 			tmp = mr32(INT_STAT_SRS) & (1U << i);
177*dd4969a8SJeff Garzik 			if (tmp)
178*dd4969a8SJeff Garzik 				mw32(INT_STAT_SRS, tmp);
179*dd4969a8SJeff Garzik 			return 0;
180*dd4969a8SJeff Garzik 		}
181*dd4969a8SJeff Garzik 	}
182*dd4969a8SJeff Garzik 	return MVS_ID_NOT_MAPPED;
183*dd4969a8SJeff Garzik }
184*dd4969a8SJeff Garzik 
185