summaryrefslogtreecommitdiff
path: root/firmware/drivers/libertas/if_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/libertas/if_spi.c')
-rw-r--r--firmware/drivers/libertas/if_spi.c674
1 files changed, 674 insertions, 0 deletions
diff --git a/firmware/drivers/libertas/if_spi.c b/firmware/drivers/libertas/if_spi.c
new file mode 100644
index 0000000000..be564cc64f
--- /dev/null
+++ b/firmware/drivers/libertas/if_spi.c
@@ -0,0 +1,674 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 by Tomasz Moń
11 * Ported from Linux libertas driver
12 * Copyright 2008 Analog Devices Inc.
13 * Authors:
14 * Andrey Yurovsky <andrey@cozybit.com>
15 * Colin McCabe <colin@cozybit.com>
16 * Inspired by if_sdio.c, Copyright 2007-2008 Pierre Ossman
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
22 *
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
25 *
26 ****************************************************************************/
27
28#include "config.h"
29/*#define LOGF_ENABLE*/
30#include "logf.h"
31#include "errno.h"
32#include "file.h"
33#include "panic.h"
34#include "system.h"
35#include "tick.h"
36#include <stddef.h>
37#include "if_spi.h"
38#include "if_spi_drv.h"
39
40#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
41#define DIV_ROUND_UP(n,d) (((n) + (d) - 1)/(d))
42
43struct if_spi_card
44{
45 /* The card ID and card revision, as reported by the hardware. */
46 uint16_t card_id;
47 uint8_t card_rev;
48
49 unsigned long spu_port_delay;
50 unsigned long spu_reg_delay;
51
52 uint8_t cmd_buffer[IF_SPI_CMD_BUF_SIZE];
53};
54
55#define MODEL_8686 0x0b
56
57static const struct
58{
59 uint16_t model;
60 const char *helper;
61 const char *main;
62}
63fw_table[] =
64{
65 { MODEL_8686, ROCKBOX_DIR"/libertas/gspi8686_v9_helper.bin", ROCKBOX_DIR"/libertas/gspi8686_v9.bin" },
66 { 0, NULL, NULL }
67};
68
69
70/*
71 * SPI Interface Unit Routines
72 *
73 * The SPU sits between the host and the WLAN module.
74 * All communication with the firmware is through SPU transactions.
75 *
76 * First we have to put a SPU register name on the bus. Then we can
77 * either read from or write to that register.
78 *
79 */
80
81static void spu_transaction_init(struct if_spi_card *card)
82{
83 (void)card;
84 /* Linux delays 400 ns if spu_transaction_finish() was called
85 * within the same jiffy. As we don't have jiffy counter nor
86 * nanosecond delays, simply delay for 1 us. This currently
87 * does not really matter as this driver simply loads firmware.
88 */
89 udelay(1);
90 libertas_spi_cs(0); /* assert CS */
91}
92
93static void spu_transaction_finish(struct if_spi_card *card)
94{
95 (void)card;
96 libertas_spi_cs(1); /* drop CS */
97}
98
99/*
100 * Write out a byte buffer to an SPI register,
101 * using a series of 16-bit transfers.
102 */
103static int spu_write(struct if_spi_card *card, uint16_t reg, const uint8_t *buf, int len)
104{
105 int err = 0;
106 uint8_t reg_out[2];
107
108 /* You must give an even number of bytes to the SPU, even if it
109 * doesn't care about the last one. */
110 if (len & 0x1)
111 panicf("Odd length in spu_write()");
112
113 reg |= IF_SPI_WRITE_OPERATION_MASK;
114 reg_out[0] = (reg & 0x00FF);
115 reg_out[1] = (reg & 0xFF00) >> 8;
116
117 spu_transaction_init(card);
118 libertas_spi_tx(reg_out, sizeof(reg_out));
119 libertas_spi_tx(buf, len);
120 spu_transaction_finish(card);
121 return err;
122}
123
124static inline int spu_write_u16(struct if_spi_card *card, uint16_t reg, uint16_t val)
125{
126 uint8_t buf[2];
127 buf[0] = (val & 0x00FF);
128 buf[1] = (val & 0xFF00) >> 8;
129 return spu_write(card, reg, buf, sizeof(buf));
130}
131
132static inline int spu_reg_is_port_reg(uint16_t reg)
133{
134 switch (reg)
135 {
136 case IF_SPI_IO_RDWRPORT_REG:
137 case IF_SPI_CMD_RDWRPORT_REG:
138 case IF_SPI_DATA_RDWRPORT_REG:
139 return 1;
140 default:
141 return 0;
142 }
143}
144
145static int spu_read(struct if_spi_card *card, uint16_t reg, uint8_t *buf, int len)
146{
147 unsigned int delay;
148 int err = 0;
149 uint8_t reg_out[2];
150
151 /*
152 * You must take an even number of bytes from the SPU, even if you
153 * don't care about the last one.
154 */
155 if (len & 0x1)
156 panicf("Odd length in spu_read()");
157
158 reg |= IF_SPI_READ_OPERATION_MASK;
159 reg_out[0] = (reg & 0x00FF);
160 reg_out[1] = (reg & 0xFF00) >> 8;
161
162 spu_transaction_init(card);
163 libertas_spi_tx(reg_out, sizeof(reg_out));
164
165 delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay;
166 /* Busy-wait while the SPU fills the FIFO */
167 delay = DIV_ROUND_UP((100 + (delay * 10)), 1000);
168 if (delay < 1000)
169 udelay(delay);
170 else
171 mdelay(DIV_ROUND_UP(delay, 1000));
172
173 libertas_spi_rx(buf, len);
174 spu_transaction_finish(card);
175 return err;
176}
177
178/* Read 16 bits from an SPI register */
179static inline int spu_read_u16(struct if_spi_card *card, uint16_t reg, uint16_t *val)
180{
181 uint8_t buf[2];
182 int ret;
183
184 ret = spu_read(card, reg, buf, sizeof(buf));
185 if (ret == 0)
186 *val = buf[0] | (buf[1] << 8);
187
188 return ret;
189}
190
191/*
192 * Read 32 bits from an SPI register.
193 * The low 16 bits are read first.
194 */
195static int spu_read_u32(struct if_spi_card *card, uint16_t reg, uint32_t *val)
196{
197 uint8_t buf[4];
198 int err;
199
200 err = spu_read(card, reg, buf, sizeof(buf));
201 if (!err)
202 *val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
203 return err;
204}
205
206/*
207 * Keep reading 16 bits from an SPI register until you get the correct result.
208 *
209 * If mask = 0, the correct result is any non-zero number.
210 * If mask != 0, the correct result is any number where
211 * number & target_mask == target
212 *
213 * Returns -ETIMEDOUT if a five seconds passes without the correct result.
214 */
215static int spu_wait_for_u16(struct if_spi_card *card, uint16_t reg,
216 uint16_t target_mask, uint16_t target)
217{
218 int err;
219 unsigned long timeout = current_tick + 5*HZ;
220 while (1)
221 {
222 uint16_t val;
223 err = spu_read_u16(card, reg, &val);
224 if (err)
225 return err;
226 if (target_mask)
227 {
228 if ((val & target_mask) == target)
229 return 0;
230 }
231 else
232 {
233 if (val)
234 return 0;
235 }
236 udelay(100);
237 if (TIME_AFTER(current_tick, timeout))
238 {
239 logf("%s: timeout with val=%02x, target_mask=%02x, target=%02x",
240 __func__, val, target_mask, target);
241 return -ETIMEDOUT;
242 }
243 }
244}
245
246/*
247 * Read 16 bits from an SPI register until you receive a specific value.
248 * Returns -ETIMEDOUT if a 4 tries pass without success.
249 */
250static int spu_wait_for_u32(struct if_spi_card *card, uint32_t reg, uint32_t target)
251{
252 int err, try;
253 for (try = 0; try < 4; ++try)
254 {
255 uint32_t val = 0;
256 err = spu_read_u32(card, reg, &val);
257 if (err)
258 return err;
259 if (val == target)
260 return 0;
261 mdelay(100);
262 }
263 return -ETIMEDOUT;
264}
265
266static int spu_set_interrupt_mode(struct if_spi_card *card,
267 int suppress_host_int,
268 int auto_int)
269{
270 int err = 0;
271
272 /*
273 * We can suppress a host interrupt by clearing the appropriate
274 * bit in the "host interrupt status mask" register
275 */
276 if (suppress_host_int) {
277 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
278 if (err)
279 return err;
280 } else {
281 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG,
282 IF_SPI_HISM_TX_DOWNLOAD_RDY |
283 IF_SPI_HISM_RX_UPLOAD_RDY |
284 IF_SPI_HISM_CMD_DOWNLOAD_RDY |
285 IF_SPI_HISM_CARDEVENT |
286 IF_SPI_HISM_CMD_UPLOAD_RDY);
287 if (err)
288 return err;
289 }
290
291 /*
292 * If auto-interrupts are on, the completion of certain transactions
293 * will trigger an interrupt automatically. If auto-interrupts
294 * are off, we need to set the "Card Interrupt Cause" register to
295 * trigger a card interrupt.
296 */
297 if (auto_int) {
298 err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
299 IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
300 IF_SPI_HICT_RX_UPLOAD_OVER_AUTO |
301 IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO |
302 IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO);
303 if (err)
304 return err;
305 } else {
306 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
307 if (err)
308 return err;
309 }
310 return err;
311}
312
313static int spu_get_chip_revision(struct if_spi_card *card,
314 uint16_t *card_id, uint8_t *card_rev)
315{
316 int err = 0;
317 uint32_t dev_ctrl;
318 err = spu_read_u32(card, IF_SPI_DEVICEID_CTRL_REG, &dev_ctrl);
319 if (err)
320 return err;
321 *card_id = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dev_ctrl);
322 *card_rev = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dev_ctrl);
323 return err;
324}
325
326static int spu_set_bus_mode(struct if_spi_card *card, uint16_t mode)
327{
328 int err = 0;
329 uint16_t rval;
330 /* set bus mode */
331 err = spu_write_u16(card, IF_SPI_SPU_BUS_MODE_REG, mode);
332 if (err)
333 return err;
334 /* Check that we were able to read back what we just wrote. */
335 err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
336 if (err)
337 return err;
338 if ((rval & 0xF) != mode)
339 {
340 logf("Can't read bus mode register");
341 return -EIO;
342 }
343 return 0;
344}
345
346static int spu_init(struct if_spi_card *card)
347{
348 int err = 0;
349 uint32_t delay;
350
351 err = spu_set_bus_mode(card,
352 IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
353 IF_SPI_BUS_MODE_DELAY_METHOD_TIMED |
354 IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
355 if (err)
356 return err;
357 card->spu_port_delay = 1000;
358 card->spu_reg_delay = 1000;
359 err = spu_read_u32(card, IF_SPI_DELAY_READ_REG, &delay);
360 if (err)
361 return err;
362 card->spu_port_delay = delay & 0x0000ffff;
363 card->spu_reg_delay = (delay & 0xffff0000) >> 16;
364
365 logf("Initialized SPU unit. "
366 "spu_port_delay=0x%04lx, spu_reg_delay=0x%04lx",
367 card->spu_port_delay, card->spu_reg_delay);
368 return err;
369}
370
371
372/*
373 * Firmware Loading
374 */
375
376static int if_spi_prog_helper_firmware(struct if_spi_card *card, int fd)
377{
378 int err = 0;
379 int bytes_read;
380 uint8_t *temp = card->cmd_buffer;
381
382 err = spu_set_interrupt_mode(card, 1, 0);
383 if (err)
384 goto out;
385
386 /* Load helper firmware image */
387 while ((bytes_read = read(fd, temp, HELPER_FW_LOAD_CHUNK_SZ)) > 0)
388 {
389 /*
390 * Scratch pad 1 should contain the number of bytes we
391 * want to download to the firmware
392 */
393 err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
394 HELPER_FW_LOAD_CHUNK_SZ);
395 if (err)
396 goto out;
397
398 err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
399 IF_SPI_HIST_CMD_DOWNLOAD_RDY,
400 IF_SPI_HIST_CMD_DOWNLOAD_RDY);
401 if (err)
402 goto out;
403
404 /*
405 * Feed the data into the command read/write port reg
406 * in chunks of 64 bytes
407 */
408 memset(temp + bytes_read, 0, HELPER_FW_LOAD_CHUNK_SZ - bytes_read);
409 mdelay(10);
410 err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
411 temp, HELPER_FW_LOAD_CHUNK_SZ);
412 if (err)
413 goto out;
414
415 /* Interrupt the boot code */
416 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
417 if (err)
418 goto out;
419 err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
420 IF_SPI_CIC_CMD_DOWNLOAD_OVER);
421 if (err)
422 goto out;
423 }
424
425 /*
426 * Once the helper / single stage firmware download is complete,
427 * write 0 to scratch pad 1 and interrupt the
428 * bootloader. This completes the helper download.
429 */
430 err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
431 if (err)
432 goto out;
433 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
434 if (err)
435 goto out;
436 err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
437 IF_SPI_CIC_CMD_DOWNLOAD_OVER);
438out:
439 if (err)
440 logf("failed to load helper firmware (err=%d)", err);
441
442 return err;
443}
444
445/*
446 * Returns the length of the next packet the firmware expects us to send.
447 * Sets crc_err if the previous transfer had a CRC error.
448 */
449static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
450 int *crc_err)
451{
452 uint16_t len;
453 int err = 0;
454
455 /*
456 * wait until the host interrupt status register indicates
457 * that we are ready to download
458 */
459 err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
460 IF_SPI_HIST_CMD_DOWNLOAD_RDY,
461 IF_SPI_HIST_CMD_DOWNLOAD_RDY);
462 if (err)
463 {
464 logf("timed out waiting for host_int_status");
465 return err;
466 }
467
468 /* Ask the device how many bytes of firmware it wants. */
469 err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
470 if (err)
471 return err;
472
473 if (len > IF_SPI_CMD_BUF_SIZE)
474 {
475 logf("firmware load device requested a larger transfer than we are prepared to handle (len = %d)",
476 len);
477 return -EIO;
478 }
479 if (len & 0x1) {
480 logf("%s: crc error", __func__);
481 len &= ~0x1;
482 *crc_err = 1;
483 } else
484 *crc_err = 0;
485
486 return len;
487}
488
489static int if_spi_prog_main_firmware(struct if_spi_card *card, int fd)
490{
491 int len;
492 int bytes_read = 0, crc_err = 0, err = 0;
493 uint16_t num_crc_errs;
494
495 err = spu_set_interrupt_mode(card, 1, 0);
496 if (err)
497 goto out;
498
499 err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
500 if (err)
501 {
502 logf("%s: timed out waiting for initial scratch reg = 0", __func__);
503 goto out;
504 }
505
506 num_crc_errs = 0;
507 while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err)))
508 {
509 if (len < 0)
510 {
511 err = len;
512 goto out;
513 }
514 if (crc_err)
515 {
516 /* Previous transfer failed. */
517 if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR)
518 {
519 logf("Too many CRC errors encountered in firmware load.");
520 err = -EIO;
521 goto out;
522 }
523
524 /* Rewind so we read back the data from previous transfer */
525 lseek(fd, -bytes_read, SEEK_CUR);
526 }
527
528 bytes_read = read(fd, card->cmd_buffer, len);
529 if (bytes_read < 0)
530 {
531 /*
532 * If there are no more bytes left, we would normally
533 * expect to have terminated with len = 0
534 */
535 logf("Firmware load wants more bytes than we have to offer.");
536 break;
537 }
538 else if (bytes_read < len)
539 {
540 memset(card->cmd_buffer + bytes_read, 0, len - bytes_read);
541 }
542
543 err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
544 if (err)
545 goto out;
546 err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, card->cmd_buffer, len);
547 if (err)
548 goto out;
549 err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
550 IF_SPI_CIC_CMD_DOWNLOAD_OVER);
551 if (err)
552 goto out;
553 }
554 if (read(fd, card->cmd_buffer, IF_SPI_CMD_BUF_SIZE) > 0)
555 {
556 logf("firmware load wants fewer bytes than we have to offer");
557 }
558
559 /* Confirm firmware download */
560 err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
561 SUCCESSFUL_FW_DOWNLOAD_MAGIC);
562 if (err)
563 {
564 logf("failed to confirm the firmware download");
565 goto out;
566 }
567
568out:
569 if (err)
570 logf("failed to load firmware (err=%d)", err);
571
572 return err;
573}
574
575static int if_spi_init_card(struct if_spi_card *card)
576{
577 int err;
578 size_t i;
579 uint32_t scratch;
580 int fd;
581
582 err = spu_init(card);
583 if (err)
584 goto out;
585 err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
586 if (err)
587 goto out;
588
589 err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
590 if (err)
591 goto out;
592 if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
593 logf("Firmware is already loaded for Marvell WLAN 802.11 adapter");
594 else {
595 /* Check if we support this card */
596 for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
597 if (card->card_id == fw_table[i].model)
598 break;
599 }
600 if (i == ARRAY_SIZE(fw_table)) {
601 logf("Unsupported chip_id: 0x%02x", card->card_id);
602 err = -ENODEV;
603 goto out;
604 }
605
606 logf("Initializing FW for Marvell WLAN 802.11 adapter "
607 "(chip_id = 0x%04x, chip_rev = 0x%02x)",
608 card->card_id, card->card_rev);
609
610 fd = open(fw_table[i].helper, O_RDONLY);
611 if (fd >= 0)
612 {
613 err = if_spi_prog_helper_firmware(card, fd);
614 close(fd);
615 if (err)
616 goto out;
617 }
618 else
619 {
620 logf("failed to find firmware helper (%s)", fw_table[i].helper);
621 err = -ENOENT;
622 goto out;
623 }
624
625 fd = open(fw_table[i].main, O_RDONLY);
626 if (fd >= 0)
627 {
628 err = if_spi_prog_main_firmware(card, fd);
629 close(fd);
630 if (err)
631 goto out;
632 }
633 else
634 {
635 logf("failed to find firmware (%s)", fw_table[i].main);
636 err = -ENOENT;
637 goto out;
638 }
639
640 logf("loaded FW for Marvell WLAN 802.11 adapter");
641 }
642
643 err = spu_set_interrupt_mode(card, 0, 1);
644 if (err)
645 goto out;
646
647out:
648 return err;
649}
650
651void wifi_init(void) INIT_ATTR
652{
653#if 0
654 static struct if_spi_card card;
655 libertas_spi_init();
656 libertas_spi_pd(1);
657 libertas_spi_reset(1);
658 mdelay(100);
659 if (!if_spi_init_card(&card))
660 {
661 /* TODO: Configure card and enter deep sleep */
662 }
663 else
664#else
665 libertas_spi_init();
666 (void)if_spi_init_card;
667#endif
668 {
669 /* Keep the lines in lowest power configuration */
670 libertas_spi_pd(0);
671 libertas_spi_reset(1);
672 libertas_spi_cs(1);
673 }
674}