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