1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Aic94xx SAS/SATA driver hardware registers definitions. |
4 | * |
5 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
7 | */ |
8 | |
9 | #ifndef _AIC94XX_REG_H_ |
10 | #define _AIC94XX_REG_H_ |
11 | |
12 | #include <asm/io.h> |
13 | #include "aic94xx_hwi.h" |
14 | |
15 | /* Values */ |
16 | #define AIC9410_DEV_REV_B0 0x8 |
17 | |
18 | /* MBAR0, SWA, SWB, SWC, internal memory space addresses */ |
19 | #define REG_BASE_ADDR 0xB8000000 |
20 | #define REG_BASE_ADDR_CSEQCIO 0xB8002000 |
21 | #define REG_BASE_ADDR_EXSI 0xB8042800 |
22 | |
23 | #define MBAR0_SWA_SIZE 0x58 |
24 | extern u32 MBAR0_SWB_SIZE; |
25 | #define MBAR0_SWC_SIZE 0x8 |
26 | |
27 | /* MBAR1, points to On Chip Memory */ |
28 | #define OCM_BASE_ADDR 0xA0000000 |
29 | #define OCM_MAX_SIZE 0x20000 |
30 | |
31 | /* Smallest address possible to reference */ |
32 | #define ALL_BASE_ADDR OCM_BASE_ADDR |
33 | |
34 | /* PCI configuration space registers */ |
35 | #define PCI_IOBAR_OFFSET 4 |
36 | |
37 | #define PCI_CONF_MBAR1 0x6C |
38 | #define PCI_CONF_MBAR0_SWA 0x70 |
39 | #define PCI_CONF_MBAR0_SWB 0x74 |
40 | #define PCI_CONF_MBAR0_SWC 0x78 |
41 | #define PCI_CONF_MBAR_KEY 0x7C |
42 | #define PCI_CONF_FLSH_BAR 0xB8 |
43 | |
44 | #include "aic94xx_reg_def.h" |
45 | |
46 | u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg); |
47 | u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg); |
48 | u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg); |
49 | |
50 | void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val); |
51 | void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val); |
52 | void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val); |
53 | |
54 | void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, |
55 | u32 offs, int count); |
56 | void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, |
57 | u32 offs, int count); |
58 | |
59 | #define ASD_READ_OCM(type, ord, S) \ |
60 | static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \ |
61 | u32 offs) \ |
62 | { \ |
63 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ |
64 | type val = read##S (io_handle->addr + (unsigned long) offs); \ |
65 | rmb(); \ |
66 | return val; \ |
67 | } |
68 | |
69 | ASD_READ_OCM(u8, byte, b); |
70 | ASD_READ_OCM(u16,word, w); |
71 | ASD_READ_OCM(u32,dword,l); |
72 | |
73 | #define ASD_WRITE_OCM(type, ord, S) \ |
74 | static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \ |
75 | u32 offs, type val) \ |
76 | { \ |
77 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ |
78 | write##S (val, io_handle->addr + (unsigned long) offs); \ |
79 | return; \ |
80 | } |
81 | |
82 | ASD_WRITE_OCM(u8, byte, b); |
83 | ASD_WRITE_OCM(u16,word, w); |
84 | ASD_WRITE_OCM(u32,dword,l); |
85 | |
86 | #define ASD_DDBSITE_READ(type, ord) \ |
87 | static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \ |
88 | u16 ddb_site_no, \ |
89 | u16 offs) \ |
90 | { \ |
91 | asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ |
92 | asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ |
93 | return asd_read_reg_##ord (asd_ha, CTXACCESS); \ |
94 | } |
95 | |
96 | ASD_DDBSITE_READ(u32, dword); |
97 | ASD_DDBSITE_READ(u16, word); |
98 | |
99 | static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha, |
100 | u16 ddb_site_no, |
101 | u16 offs) |
102 | { |
103 | if (offs & 1) |
104 | return asd_ddbsite_read_word(asd_ha, ddb_site_no, |
105 | offs: offs & ~1) >> 8; |
106 | else |
107 | return asd_ddbsite_read_word(asd_ha, ddb_site_no, |
108 | offs) & 0xFF; |
109 | } |
110 | |
111 | |
112 | #define ASD_DDBSITE_WRITE(type, ord) \ |
113 | static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \ |
114 | u16 ddb_site_no, \ |
115 | u16 offs, type val) \ |
116 | { \ |
117 | asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ |
118 | asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ |
119 | asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ |
120 | } |
121 | |
122 | ASD_DDBSITE_WRITE(u32, dword); |
123 | ASD_DDBSITE_WRITE(u16, word); |
124 | |
125 | static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha, |
126 | u16 ddb_site_no, |
127 | u16 offs, u8 val) |
128 | { |
129 | u16 base = offs & ~1; |
130 | u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs: base); |
131 | if (offs & 1) |
132 | rval = (val << 8) | (rval & 0xFF); |
133 | else |
134 | rval = (rval & 0xFF00) | val; |
135 | asd_ddbsite_write_word(asd_ha, ddb_site_no, offs: base, val: rval); |
136 | } |
137 | |
138 | |
139 | #define ASD_SCBSITE_READ(type, ord) \ |
140 | static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \ |
141 | u16 scb_site_no, \ |
142 | u16 offs) \ |
143 | { \ |
144 | asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ |
145 | asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ |
146 | return asd_read_reg_##ord (asd_ha, CTXACCESS); \ |
147 | } |
148 | |
149 | ASD_SCBSITE_READ(u32, dword); |
150 | ASD_SCBSITE_READ(u16, word); |
151 | |
152 | static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha, |
153 | u16 scb_site_no, |
154 | u16 offs) |
155 | { |
156 | if (offs & 1) |
157 | return asd_scbsite_read_word(asd_ha, scb_site_no, |
158 | offs: offs & ~1) >> 8; |
159 | else |
160 | return asd_scbsite_read_word(asd_ha, scb_site_no, |
161 | offs) & 0xFF; |
162 | } |
163 | |
164 | |
165 | #define ASD_SCBSITE_WRITE(type, ord) \ |
166 | static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \ |
167 | u16 scb_site_no, \ |
168 | u16 offs, type val) \ |
169 | { \ |
170 | asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ |
171 | asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ |
172 | asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ |
173 | } |
174 | |
175 | ASD_SCBSITE_WRITE(u32, dword); |
176 | ASD_SCBSITE_WRITE(u16, word); |
177 | |
178 | static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha, |
179 | u16 scb_site_no, |
180 | u16 offs, u8 val) |
181 | { |
182 | u16 base = offs & ~1; |
183 | u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, offs: base); |
184 | if (offs & 1) |
185 | rval = (val << 8) | (rval & 0xFF); |
186 | else |
187 | rval = (rval & 0xFF00) | val; |
188 | asd_scbsite_write_word(asd_ha, scb_site_no, offs: base, val: rval); |
189 | } |
190 | |
191 | /** |
192 | * asd_ddbsite_update_word -- atomically update a word in a ddb site |
193 | * @asd_ha: pointer to host adapter structure |
194 | * @ddb_site_no: the DDB site number |
195 | * @offs: the offset into the DDB |
196 | * @oldval: old value found in that offset |
197 | * @newval: the new value to replace it |
198 | * |
199 | * This function is used when the sequencers are running and we need to |
200 | * update a DDB site atomically without expensive pausing and upausing |
201 | * of the sequencers and accessing the DDB site through the CIO bus. |
202 | * |
203 | * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value |
204 | * is different than the current value at that offset. |
205 | */ |
206 | static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha, |
207 | u16 ddb_site_no, u16 offs, |
208 | u16 oldval, u16 newval) |
209 | { |
210 | u8 done; |
211 | u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs); |
212 | if (oval != oldval) |
213 | return -EAGAIN; |
214 | asd_write_reg_word(asd_ha, AOLDDATA, val: oldval); |
215 | asd_write_reg_word(asd_ha, ANEWDATA, val: newval); |
216 | do { |
217 | done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL); |
218 | } while (!(done & ATOMICDONE)); |
219 | if (done & ATOMICERR) |
220 | return -EFAULT; /* parity error */ |
221 | else if (done & ATOMICWIN) |
222 | return 0; /* success */ |
223 | else |
224 | return -EAGAIN; /* oldval different than current value */ |
225 | } |
226 | |
227 | static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha, |
228 | u16 ddb_site_no, u16 offs, |
229 | u8 _oldval, u8 _newval) |
230 | { |
231 | u16 base = offs & ~1; |
232 | u16 oval; |
233 | u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs: base); |
234 | if (offs & 1) { |
235 | if ((nval >> 8) != _oldval) |
236 | return -EAGAIN; |
237 | nval = (_newval << 8) | (nval & 0xFF); |
238 | oval = (_oldval << 8) | (nval & 0xFF); |
239 | } else { |
240 | if ((nval & 0xFF) != _oldval) |
241 | return -EAGAIN; |
242 | nval = (nval & 0xFF00) | _newval; |
243 | oval = (nval & 0xFF00) | _oldval; |
244 | } |
245 | return asd_ddbsite_update_word(asd_ha, ddb_site_no, offs: base, oldval: oval, newval: nval); |
246 | } |
247 | |
248 | static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg, |
249 | dma_addr_t dma_handle) |
250 | { |
251 | asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle)); |
252 | asd_write_reg_dword(asd_ha, reg: reg+4, ASD_BUSADDR_HI(dma_handle)); |
253 | } |
254 | |
255 | static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha) |
256 | { |
257 | /* DCHREVISION returns 0, possibly broken */ |
258 | u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; |
259 | return ctxmemsize ? 65536 : 32768; |
260 | } |
261 | |
262 | static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha) |
263 | { |
264 | u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; |
265 | return ctxmemsize ? 8192 : 4096; |
266 | } |
267 | |
268 | static inline void asd_disable_ints(struct asd_ha_struct *asd_ha) |
269 | { |
270 | asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); |
271 | } |
272 | |
273 | static inline void asd_enable_ints(struct asd_ha_struct *asd_ha) |
274 | { |
275 | /* Enable COM SAS interrupt on errors, COMSTAT */ |
276 | asd_write_reg_dword(asd_ha, COMSTATEN, |
277 | EN_CSBUFPERR | EN_CSERR | EN_OVLYERR); |
278 | /* Enable DCH SAS CFIFTOERR */ |
279 | asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR); |
280 | /* Enable Host Device interrupts */ |
281 | asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN); |
282 | } |
283 | |
284 | #endif |
285 | |