diff options
Diffstat (limited to 'drivers/scsi/mvsas/mv_64xx.c')
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.c | 184 |
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 | |||
28 | void 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 | |||
43 | void 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 | |||
56 | void __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 | |||
109 | void 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 | |||
119 | void 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 | |||
129 | void 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 | |||
154 | u8 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 | |||