1 /*
2 * Copyright 2007-2013 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_regs.h"
30 #include "efx_impl.h"
31
32 #if EFSYS_OPT_FALCON
33
34 /* Commands common to all known devices */
35
36 #define SPI_CMD_WRSR 0x01 /* write status register */
37 #define SPI_CMD_WRITE 0x02 /* Write data to memory array */
38 #define SPI_CMD_READ 0x03 /* Read data from memory array */
39 #define SPI_CMD_WRDI 0x04 /* reset write enable latch */
40 #define SPI_CMD_RDSR 0x05 /* read status register */
41 #define SPI_CMD_WREN 0x06 /* set write enable latch */
42
43 #define SPI_CMD_SECE 0x52 /* erase one sector */
44
45 #define SPI_STATUS_WPEN_LBN 7
46 #define SPI_STATUS_WPEN_WIDTH 1
47 #define SPI_STATUS_BP2_LBN 4
48 #define SPI_STATUS_BP2_WIDTH 1
49 #define SPI_STATUS_BP1_LBN 3
50 #define SPI_STATUS_BP1_WIDTH 1
51 #define SPI_STATUS_BP0_LBN 2
52 #define SPI_STATUS_BP0_WIDTH 1
53 #define SPI_STATUS_WEN_LBN 1
54 #define SPI_STATUS_WEN_WIDTH 1
55 #define SPI_STATUS_NRDY_LBN 0
56 #define SPI_STATUS_NRDY_WIDTH 1
57
58 static __checkReturn int
59 falcon_spi_wait(
60 __in efx_nic_t *enp)
61 {
62 unsigned int count;
63 int rc;
64
65 count = 0;
66 do {
67 efx_oword_t oword;
68
69 EFSYS_PROBE1(wait, unsigned int, count);
70
71 EFX_BAR_READO(enp, FR_AB_EE_SPI_HCMD_REG, &oword);
72
73 if (EFX_OWORD_FIELD(oword, FRF_AB_EE_SPI_HCMD_CMD_EN) == 0)
74 goto done;
75
76 /* Spin for 10 us */
77 EFSYS_SPIN(10);
78 } while (++count < 10000);
79
80 rc = ETIMEDOUT;
81 goto fail1;
82
83 done:
84 return (0);
85
86 fail1:
87 EFSYS_PROBE1(fail1, int, rc);
88
89 return (rc);
90 }
91
92 #define FALCON_SPI_COPY(_dst, _src, _size) \
93 do { \
94 unsigned int index; \
95 \
96 for (index = 0; index < (unsigned int)(_size); index++) \
97 *((uint8_t *)(_dst) + index) = \
98 *((uint8_t *)(_src) + index); \
99 \
100 _NOTE(CONSTANTCONDITION) \
101 } while (B_FALSE)
102
103 static __checkReturn int
104 falcon_spi_cmd(
105 __in efx_nic_t *enp,
106 __in uint32_t sf_sel,
107 __in uint32_t adbcnt,
108 __in uint32_t cmd,
109 __in uint32_t addr,
110 __in boolean_t munge,
111 __drv_when(cmd == SPI_CMD_WRSR || cmd == SPI_CMD_WRITE,
112 __drv_in(__byte_readableTo(dabcnt)))
113 __drv_when(cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ,
114 __drv_out(__byte_readableTo(dabcnt)))
115 caddr_t base,
116 __in uint32_t dabcnt)
117 {
118 uint32_t enc;
119 efx_oword_t oword;
120 int rc;
121
122 EFSYS_ASSERT3U(dabcnt, <=, sizeof (efx_oword_t));
123
124 /* Wait for the SPI to become available */
125 if ((rc = falcon_spi_wait(enp)) != 0)
126 goto fail1;
127
128 /* Program the data register */
129 if (cmd == SPI_CMD_WRSR || cmd == SPI_CMD_WRITE) {
130 EFSYS_ASSERT(base != NULL);
131 EFSYS_ASSERT(dabcnt != 0);
132 EFX_ZERO_OWORD(oword);
133 FALCON_SPI_COPY(&oword, base, dabcnt);
134 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HDATA_REG, &oword);
135 }
136
137 /* Program the address register */
138 if (cmd == SPI_CMD_READ || cmd == SPI_CMD_WRITE ||
139 cmd == SPI_CMD_SECE) {
140 EFX_POPULATE_OWORD_1(oword, FRF_AB_EE_SPI_HADR_ADR, addr);
141 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HADR_REG, &oword);
142
143 enc = (munge) ? (cmd | ((addr >> 8) << 3)) : cmd;
144 } else {
145 enc = cmd;
146 }
147
148 /* Issue command */
149 EFX_POPULATE_OWORD_6(oword, FRF_AB_EE_SPI_HCMD_CMD_EN, 1,
150 FRF_AB_EE_SPI_HCMD_SF_SEL, sf_sel,
151 FRF_AB_EE_SPI_HCMD_DABCNT, dabcnt,
152 FRF_AB_EE_SPI_HCMD_DUBCNT, 0,
153 FRF_AB_EE_SPI_HCMD_ADBCNT, adbcnt,
154 FRF_AB_EE_SPI_HCMD_ENC, enc);
155
156 EFX_SET_OWORD_FIELD(oword,
157 FRF_AB_EE_SPI_HCMD_READ,
158 (cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ) ? 1 : 0);
159
160 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HCMD_REG, &oword);
161
162 /* Wait for read to complete */
163 if ((rc = falcon_spi_wait(enp)) != 0)
164 goto fail2;
165
166 /* Read the data register */
167 if (cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ) {
168 EFX_BAR_READO(enp, FR_AB_EE_SPI_HDATA_REG, &oword);
169 EFSYS_ASSERT(base != NULL);
170 FALCON_SPI_COPY(base, &oword, dabcnt);
171 }
172
173 return (0);
174
175 fail2:
176 EFSYS_PROBE(fail2);
177 fail1:
178 EFSYS_PROBE1(fail1, int, rc);
179
180 return (rc);
181 }
182
183 static __checkReturn int
184 falcon_spi_dev_wait(
185 __in efx_nic_t *enp,
186 __in falcon_spi_dev_t *fsdp,
187 __in unsigned int us,
188 __in unsigned int n)
189 {
190 unsigned int count;
191 int rc;
192
193 count = 0;
194 do {
195 efx_byte_t byte;
196
197 EFSYS_PROBE1(wait, unsigned int, count);
198
199 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
200 fsdp->fsd_adbcnt, SPI_CMD_RDSR, 0, fsdp->fsd_munge,
201 (caddr_t)&byte, sizeof (efx_byte_t))) != 0)
202 goto fail1;
203
204 if (EFX_BYTE_FIELD(byte, SPI_STATUS_NRDY) == 0)
205 goto done;
206
207 EFSYS_SPIN(us);
208 } while (++count < n);
209
210 rc = ETIMEDOUT;
211 goto fail2;
212
213 done:
214 return (0);
215
216 fail2:
217 EFSYS_PROBE(fail2);
218 fail1:
219 EFSYS_PROBE1(fail1, int, rc);
220
221 return (rc);
222 }
223
224 __checkReturn int
225 falcon_spi_dev_read(
226 __in efx_nic_t *enp,
227 __in falcon_spi_type_t type,
228 __in uint32_t addr,
229 __out_bcount(size) caddr_t base,
230 __in size_t size)
231 {
232 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]);
233 uint32_t end = addr + size;
234 int state;
235 int rc;
236
237 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES);
238
239 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON);
240
241 if (fsdp == NULL) {
242 rc = ENODEV;
243 goto fail1;
244 }
245
246 EFSYS_LOCK(enp->en_eslp, state);
247
248 while (addr != end) {
249 uint32_t dabcnt = MIN(end - addr, sizeof (efx_oword_t));
250
251 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
252 fsdp->fsd_adbcnt, SPI_CMD_READ, addr, fsdp->fsd_munge,
253 base, dabcnt)) != 0)
254 goto fail2;
255
256 EFSYS_ASSERT3U(addr, <, end);
257 addr += dabcnt;
258 base += dabcnt;
259 }
260
261 EFSYS_UNLOCK(enp->en_eslp, state);
262 return (0);
263
264 fail2:
265 EFSYS_PROBE(fail2);
266
267 EFSYS_UNLOCK(enp->en_eslp, state);
268
269 fail1:
270 EFSYS_PROBE1(fail1, int, rc);
271
272 return (rc);
273 }
274
275 __checkReturn int
276 falcon_spi_dev_write(
277 __in efx_nic_t *enp,
278 __in falcon_spi_type_t type,
279 __in uint32_t addr,
280 __in_bcount(size) caddr_t base,
281 __in size_t size)
282 {
283 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]);
284 uint32_t end = addr + size;
285 int state;
286 int rc;
287
288 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES);
289
290 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON);
291
292 if (fsdp == NULL) {
293 rc = ENODEV;
294 goto fail1;
295 }
296
297 EFSYS_LOCK(enp->en_eslp, state);
298
299 while (addr != end) {
300 efx_oword_t oword;
301 uint32_t dabcnt;
302 unsigned int index;
303
304 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
305 fsdp->fsd_adbcnt, SPI_CMD_WREN, 0, fsdp->fsd_munge,
306 NULL, 0)) != 0)
307 goto fail2;
308
309 dabcnt = MIN(end - addr, fsdp->fsd_write_size -
310 (addr & (fsdp->fsd_write_size - 1)));
311 dabcnt = MIN(dabcnt, sizeof (efx_oword_t));
312
313 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
314 fsdp->fsd_adbcnt, SPI_CMD_WRITE, addr,
315 fsdp->fsd_munge, base, dabcnt)) != 0)
316 goto fail3;
317
318 if ((rc = falcon_spi_dev_wait(enp, fsdp, 1000, 20)) != 0)
319 goto fail4;
320
321 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
322 fsdp->fsd_adbcnt, SPI_CMD_READ, addr,
323 fsdp->fsd_munge, (caddr_t)&oword, dabcnt)) != 0)
324 goto fail5;
325
326 for (index = 0; index < dabcnt; index++) {
327 if (oword.eo_u8[index] != *(uint8_t *)(base + index)) {
328 rc = EIO;
329 goto fail6;
330 }
331 }
332
333 EFSYS_ASSERT3U(addr, <, end);
334 addr += dabcnt;
335 base += dabcnt;
336 }
337
338 EFSYS_UNLOCK(enp->en_eslp, state);
339 return (0);
340
341 fail6:
342 EFSYS_PROBE(fail6);
343 fail5:
344 EFSYS_PROBE(fail5);
345 fail4:
346 EFSYS_PROBE(fail4);
347 fail3:
348 EFSYS_PROBE(fail3);
349 fail2:
350 EFSYS_PROBE(fail2);
351
352 EFSYS_UNLOCK(enp->en_eslp, state);
353 fail1:
354 EFSYS_PROBE1(fail1, int, rc);
355
356 return (rc);
357 }
358
359 __checkReturn int
360 falcon_spi_dev_erase(
361 __in efx_nic_t *enp,
362 __in falcon_spi_type_t type,
363 __in uint32_t addr,
364 __in size_t size)
365 {
366 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]);
367 uint32_t end = addr + size;
368 int state;
369 int rc;
370
371 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES);
372
373 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON);
374
375 if (fsdp == NULL) {
376 rc = ENODEV;
377 goto fail1;
378 }
379
380 if (fsdp->fsd_erase_cmd == 0) {
381 rc = ENOTSUP;
382 goto fail2;
383 }
384
385 if (!IS_P2ALIGNED(addr, fsdp->fsd_erase_size) ||
386 !IS_P2ALIGNED(size, fsdp->fsd_erase_size)) {
387 rc = EINVAL;
388 goto fail3;
389 }
390
391 EFSYS_LOCK(enp->en_eslp, state);
392
393 while (addr != end) {
394 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
395 fsdp->fsd_adbcnt, SPI_CMD_WREN, 0, fsdp->fsd_munge,
396 NULL, 0)) != 0)
397 goto fail4;
398
399 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel,
400 fsdp->fsd_adbcnt, fsdp->fsd_erase_cmd, addr,
401 fsdp->fsd_munge, NULL, 0)) != 0)
402 goto fail5;
403
404 if ((rc = falcon_spi_dev_wait(enp, fsdp, 40000, 100)) != 0)
405 goto fail6;
406
407 EFSYS_ASSERT3U(addr, <, end);
408 addr += fsdp->fsd_erase_size;
409 }
410
411 EFSYS_UNLOCK(enp->en_eslp, state);
412 return (0);
413
414 fail6:
415 EFSYS_PROBE(fail6);
416 fail5:
417 EFSYS_PROBE(fail5);
418 fail4:
419 EFSYS_PROBE(fail4);
420
421 EFSYS_UNLOCK(enp->en_eslp, state);
422
423 fail3:
424 EFSYS_PROBE(fail3);
425 fail2:
426 EFSYS_PROBE(fail2);
427 fail1:
428 EFSYS_PROBE1(fail1, int, rc);
429
430 return (rc);
431 }
432
433 #endif /* EFSYS_OPT_FALCON */