]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Marvell 88SE64xx/88SE94xx register IO interface | |
3 | * | |
4 | * Copyright 2007 Red Hat, Inc. | |
5 | * Copyright 2008 Marvell. <kewei@marvell.com> | |
6 | * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> | |
7 | * | |
8 | * This file is licensed under GPLv2. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; version 2 of the | |
13 | * License. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
23 | * USA | |
24 | */ | |
25 | ||
26 | ||
27 | #ifndef _MV_CHIPS_H_ | |
28 | #define _MV_CHIPS_H_ | |
29 | ||
30 | #define mr32(reg) readl(regs + reg) | |
31 | #define mw32(reg, val) writel((val), regs + reg) | |
32 | #define mw32_f(reg, val) do { \ | |
33 | mw32(reg, val); \ | |
34 | mr32(reg); \ | |
35 | } while (0) | |
36 | ||
37 | #define iow32(reg, val) outl(val, (unsigned long)(regs + reg)) | |
38 | #define ior32(reg) inl((unsigned long)(regs + reg)) | |
39 | #define iow16(reg, val) outw((unsigned long)(val, regs + reg)) | |
40 | #define ior16(reg) inw((unsigned long)(regs + reg)) | |
41 | #define iow8(reg, val) outb((unsigned long)(val, regs + reg)) | |
42 | #define ior8(reg) inb((unsigned long)(regs + reg)) | |
43 | ||
44 | static inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr) | |
45 | { | |
46 | void __iomem *regs = mvi->regs; | |
47 | mw32(MVS_CMD_ADDR, addr); | |
48 | return mr32(MVS_CMD_DATA); | |
49 | } | |
50 | ||
51 | static inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val) | |
52 | { | |
53 | void __iomem *regs = mvi->regs; | |
54 | mw32(MVS_CMD_ADDR, addr); | |
55 | mw32(MVS_CMD_DATA, val); | |
56 | } | |
57 | ||
58 | static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) | |
59 | { | |
60 | void __iomem *regs = mvi->regs; | |
61 | return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) : | |
62 | mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4); | |
63 | } | |
64 | ||
65 | static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) | |
66 | { | |
67 | void __iomem *regs = mvi->regs; | |
68 | if (port < 4) | |
69 | mw32(MVS_P0_SER_CTLSTAT + port * 4, val); | |
70 | else | |
71 | mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val); | |
72 | } | |
73 | ||
74 | static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off, | |
75 | u32 off2, u32 port) | |
76 | { | |
77 | void __iomem *regs = mvi->regs + off; | |
78 | void __iomem *regs2 = mvi->regs + off2; | |
79 | return (port < 4) ? readl(regs + port * 8) : | |
80 | readl(regs2 + (port - 4) * 8); | |
81 | } | |
82 | ||
83 | static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, | |
84 | u32 port, u32 val) | |
85 | { | |
86 | void __iomem *regs = mvi->regs + off; | |
87 | void __iomem *regs2 = mvi->regs + off2; | |
88 | if (port < 4) | |
89 | writel(val, regs + port * 8); | |
90 | else | |
91 | writel(val, regs2 + (port - 4) * 8); | |
92 | } | |
93 | ||
94 | static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) | |
95 | { | |
96 | return mvs_read_port(mvi, MVS_P0_CFG_DATA, | |
97 | MVS_P4_CFG_DATA, port); | |
98 | } | |
99 | ||
100 | static inline void mvs_write_port_cfg_data(struct mvs_info *mvi, | |
101 | u32 port, u32 val) | |
102 | { | |
103 | mvs_write_port(mvi, MVS_P0_CFG_DATA, | |
104 | MVS_P4_CFG_DATA, port, val); | |
105 | } | |
106 | ||
107 | static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi, | |
108 | u32 port, u32 addr) | |
109 | { | |
110 | mvs_write_port(mvi, MVS_P0_CFG_ADDR, | |
111 | MVS_P4_CFG_ADDR, port, addr); | |
112 | mdelay(10); | |
113 | } | |
114 | ||
115 | static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) | |
116 | { | |
117 | return mvs_read_port(mvi, MVS_P0_VSR_DATA, | |
118 | MVS_P4_VSR_DATA, port); | |
119 | } | |
120 | ||
121 | static inline void mvs_write_port_vsr_data(struct mvs_info *mvi, | |
122 | u32 port, u32 val) | |
123 | { | |
124 | mvs_write_port(mvi, MVS_P0_VSR_DATA, | |
125 | MVS_P4_VSR_DATA, port, val); | |
126 | } | |
127 | ||
128 | static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi, | |
129 | u32 port, u32 addr) | |
130 | { | |
131 | mvs_write_port(mvi, MVS_P0_VSR_ADDR, | |
132 | MVS_P4_VSR_ADDR, port, addr); | |
133 | mdelay(10); | |
134 | } | |
135 | ||
136 | static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) | |
137 | { | |
138 | return mvs_read_port(mvi, MVS_P0_INT_STAT, | |
139 | MVS_P4_INT_STAT, port); | |
140 | } | |
141 | ||
142 | static inline void mvs_write_port_irq_stat(struct mvs_info *mvi, | |
143 | u32 port, u32 val) | |
144 | { | |
145 | mvs_write_port(mvi, MVS_P0_INT_STAT, | |
146 | MVS_P4_INT_STAT, port, val); | |
147 | } | |
148 | ||
149 | static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) | |
150 | { | |
151 | return mvs_read_port(mvi, MVS_P0_INT_MASK, | |
152 | MVS_P4_INT_MASK, port); | |
153 | ||
154 | } | |
155 | ||
156 | static inline void mvs_write_port_irq_mask(struct mvs_info *mvi, | |
157 | u32 port, u32 val) | |
158 | { | |
159 | mvs_write_port(mvi, MVS_P0_INT_MASK, | |
160 | MVS_P4_INT_MASK, port, val); | |
161 | } | |
162 | ||
163 | static inline void mvs_phy_hacks(struct mvs_info *mvi) | |
164 | { | |
165 | u32 tmp; | |
166 | ||
167 | tmp = mvs_cr32(mvi, CMD_PHY_TIMER); | |
168 | tmp &= ~(1 << 9); | |
169 | tmp |= (1 << 10); | |
170 | mvs_cw32(mvi, CMD_PHY_TIMER, tmp); | |
171 | ||
172 | /* enable retry 127 times */ | |
173 | mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f); | |
174 | ||
175 | /* extend open frame timeout to max */ | |
176 | tmp = mvs_cr32(mvi, CMD_SAS_CTL0); | |
177 | tmp &= ~0xffff; | |
178 | tmp |= 0x3fff; | |
179 | mvs_cw32(mvi, CMD_SAS_CTL0, tmp); | |
180 | ||
181 | mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000); | |
182 | ||
183 | /* not to halt for different port op during wideport link change */ | |
184 | mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d); | |
185 | } | |
186 | ||
187 | static inline void mvs_int_sata(struct mvs_info *mvi) | |
188 | { | |
189 | u32 tmp; | |
190 | void __iomem *regs = mvi->regs; | |
191 | tmp = mr32(MVS_INT_STAT_SRS_0); | |
192 | if (tmp) | |
193 | mw32(MVS_INT_STAT_SRS_0, tmp); | |
194 | MVS_CHIP_DISP->clear_active_cmds(mvi); | |
195 | } | |
196 | ||
197 | static inline void mvs_int_full(struct mvs_info *mvi) | |
198 | { | |
199 | void __iomem *regs = mvi->regs; | |
200 | u32 tmp, stat; | |
201 | int i; | |
202 | ||
203 | stat = mr32(MVS_INT_STAT); | |
204 | mvs_int_rx(mvi, false); | |
205 | ||
206 | for (i = 0; i < mvi->chip->n_phy; i++) { | |
207 | tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); | |
208 | if (tmp) | |
209 | mvs_int_port(mvi, i, tmp); | |
210 | } | |
211 | ||
212 | if (stat & CINT_NON_SPEC_NCQ_ERROR) | |
213 | MVS_CHIP_DISP->non_spec_ncq_error(mvi); | |
214 | ||
215 | if (stat & CINT_SRS) | |
216 | mvs_int_sata(mvi); | |
217 | ||
218 | mw32(MVS_INT_STAT, stat); | |
219 | } | |
220 | ||
221 | static inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx) | |
222 | { | |
223 | void __iomem *regs = mvi->regs; | |
224 | mw32(MVS_TX_PROD_IDX, tx); | |
225 | } | |
226 | ||
227 | static inline u32 mvs_rx_update(struct mvs_info *mvi) | |
228 | { | |
229 | void __iomem *regs = mvi->regs; | |
230 | return mr32(MVS_RX_CONS_IDX); | |
231 | } | |
232 | ||
233 | static inline u32 mvs_get_prd_size(void) | |
234 | { | |
235 | return sizeof(struct mvs_prd); | |
236 | } | |
237 | ||
238 | static inline u32 mvs_get_prd_count(void) | |
239 | { | |
240 | return MAX_SG_ENTRY; | |
241 | } | |
242 | ||
243 | static inline void mvs_show_pcie_usage(struct mvs_info *mvi) | |
244 | { | |
245 | u16 link_stat, link_spd; | |
246 | const char *spd[] = { | |
247 | "UnKnown", | |
248 | "2.5", | |
249 | "5.0", | |
250 | }; | |
251 | if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0) | |
252 | return; | |
253 | ||
254 | pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat); | |
255 | link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS; | |
256 | if (link_spd >= 3) | |
257 | link_spd = 0; | |
258 | dev_printk(KERN_INFO, mvi->dev, | |
259 | "mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n", | |
260 | (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS, | |
261 | spd[link_spd]); | |
262 | } | |
263 | ||
264 | static inline u32 mvs_hw_max_link_rate(void) | |
265 | { | |
266 | return MAX_LINK_RATE; | |
267 | } | |
268 | ||
269 | #endif /* _MV_CHIPS_H_ */ | |
270 |