summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2021-07-02 12:02:26 +0200
committerTomasz Moń <desowin@gmail.com>2021-07-04 07:41:44 +0000
commite11fa5f74eb49b10ebefbe8882bb50186dffb2a4 (patch)
tree295a28ca58bc4d7b5153629046c1e2894db02f5e
parentc9f2308a1d4401ceefaac47b1ea851530d07e47d (diff)
downloadrockbox-e11fa5f74eb49b10ebefbe8882bb50186dffb2a4.tar.gz
rockbox-e11fa5f74eb49b10ebefbe8882bb50186dffb2a4.zip
Sansa Connect: Initial libertas WiFi driver port
Import non-free firmware image from linux-firmware package. Firmware loading works but is disabled at compile time because just loading firmware without configuring device results in higher power consumption without any benefit to end user. Change-Id: I8fd252c49385ede1ea4e0f9b1e29adeb331ab8ae
-rw-r--r--apps/main.c5
-rw-r--r--firmware/SOURCES10
-rw-r--r--firmware/drivers/libertas/firmware/LICENCE.Marvell22
-rw-r--r--firmware/drivers/libertas/firmware/gspi8686_v9.binbin0 -> 126652 bytes
-rw-r--r--firmware/drivers/libertas/firmware/gspi8686_v9_helper.binbin0 -> 2140 bytes
-rw-r--r--firmware/drivers/libertas/if_spi.c674
-rw-r--r--firmware/drivers/libertas/if_spi.h215
-rw-r--r--firmware/drivers/libertas/if_spi_drv.h34
-rw-r--r--firmware/export/config/sansaconnect.h6
-rw-r--r--firmware/export/wifi.h29
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c10
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h2
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c130
-rw-r--r--firmware/target/arm/tms320dm320/system-dm320.c2
-rwxr-xr-xtools/buildzip.pl5
15 files changed, 1142 insertions, 2 deletions
diff --git a/apps/main.c b/apps/main.c
index c7b223faea..483d280204 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -36,6 +36,7 @@
36#include "panic.h" 36#include "panic.h"
37#include "menu.h" 37#include "menu.h"
38#include "usb.h" 38#include "usb.h"
39#include "wifi.h"
39#include "powermgmt.h" 40#include "powermgmt.h"
40#if !defined(DX50) && !defined(DX90) 41#if !defined(DX50) && !defined(DX90)
41#include "adc.h" 42#include "adc.h"
@@ -636,6 +637,10 @@ static void init(void)
636 CHART("<audio_init"); 637 CHART("<audio_init");
637 talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */ 638 talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */
638 639
640#ifdef HAVE_WIFI
641 wifi_init();
642#endif
643
639 /* runtime database has to be initialized after audio_init() */ 644 /* runtime database has to be initialized after audio_init() */
640 cpu_boost(false); 645 cpu_boost(false);
641 646
diff --git a/firmware/SOURCES b/firmware/SOURCES
index dc1ed865dd..5fcf83fff1 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -536,6 +536,15 @@ target/hosted/sdl/pcm-sdl.c
536 536
537#endif /* !defined(BOOTLOADER) */ 537#endif /* !defined(BOOTLOADER) */
538 538
539/* WiFi */
540#if !defined(BOOTLOADER)
541#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
542#if defined(HAVE_W8686_SPI)
543drivers/libertas/if_spi.c
544#endif
545#endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) */
546#endif /* !defined(BOOTLOADER) */
547
539/* CPU Specific - By class then particular chip if applicable */ 548/* CPU Specific - By class then particular chip if applicable */
540#if defined(CPU_COLDFIRE) 549#if defined(CPU_COLDFIRE)
541 550
@@ -1266,6 +1275,7 @@ target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
1266target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c 1275target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
1267target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c 1276target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
1268target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c 1277target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
1278target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c
1269target/arm/tms320dm320/dma-dm320.c 1279target/arm/tms320dm320/dma-dm320.c
1270#endif /* SANSA_CONNECT */ 1280#endif /* SANSA_CONNECT */
1271 1281
diff --git a/firmware/drivers/libertas/firmware/LICENCE.Marvell b/firmware/drivers/libertas/firmware/LICENCE.Marvell
new file mode 100644
index 0000000000..fdf4cda9c0
--- /dev/null
+++ b/firmware/drivers/libertas/firmware/LICENCE.Marvell
@@ -0,0 +1,22 @@
1Copyright © 2019. Marvell International Ltd. All rights reserved.
2
3Redistribution and use in binary form is permitted provided that the following
4conditions are met:
5
61. Redistributions must reproduce the above copyright notice, this list of
7conditions and the following disclaimer in the documentation and/or other
8materials provided with the distribution.
9
102. Redistribution and use shall be used only with Marvell silicon products.
11Any other use, reproduction, modification, translation, or compilation of the
12Software is prohibited.
13
143. No reverse engineering, decompilation, or disassembly is permitted.
15
16TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
17“AS IS” WITHOUT WARRANTY OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ANY EXPRESS
18OR IMPLIED WARRANTIES OF MERCHANTABILITY, ACCURACY, FITNESS OR SUFFICIENCY FOR A
19PARTICULAR PURPOSE, SATISFACTORY QUALITY, CORRESPONDENCE WITH DESCRIPTION, QUIET
20ENJOYMENT OR NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS.
21MARVELL, ITS AFFILIATES AND THEIR SUPPLIERS DISCLAIM ANY WARRANTY THAT THE
22DELIVERABLES WILL OPERATE WITHOUT INTERRUPTION OR BE ERROR-FREE.
diff --git a/firmware/drivers/libertas/firmware/gspi8686_v9.bin b/firmware/drivers/libertas/firmware/gspi8686_v9.bin
new file mode 100644
index 0000000000..58dc03d30e
--- /dev/null
+++ b/firmware/drivers/libertas/firmware/gspi8686_v9.bin
Binary files differ
diff --git a/firmware/drivers/libertas/firmware/gspi8686_v9_helper.bin b/firmware/drivers/libertas/firmware/gspi8686_v9_helper.bin
new file mode 100644
index 0000000000..424cfb386c
--- /dev/null
+++ b/firmware/drivers/libertas/firmware/gspi8686_v9_helper.bin
Binary files differ
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}
diff --git a/firmware/drivers/libertas/if_spi.h b/firmware/drivers/libertas/if_spi.h
new file mode 100644
index 0000000000..bfca12981a
--- /dev/null
+++ b/firmware/drivers/libertas/if_spi.h
@@ -0,0 +1,215 @@
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 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26
27#ifndef _LBS_IF_SPI_H_
28#define _LBS_IF_SPI_H_
29
30#define IPFIELD_ALIGN_OFFSET 2
31#define IF_SPI_CMD_BUF_SIZE 2400
32
33/***************** Firmware *****************/
34
35#define IF_SPI_FW_NAME_MAX 30
36
37#define MAX_MAIN_FW_LOAD_CRC_ERR 10
38
39/* Chunk size when loading the helper firmware */
40#define HELPER_FW_LOAD_CHUNK_SZ 64
41
42/* Value to write to indicate end of helper firmware dnld */
43#define FIRMWARE_DNLD_OK 0x0000
44
45/* Value to check once the main firmware is downloaded */
46#define SUCCESSFUL_FW_DOWNLOAD_MAGIC 0x88888888
47
48/***************** SPI Interface Unit *****************/
49/* Masks used in SPI register read/write operations */
50#define IF_SPI_READ_OPERATION_MASK 0x0
51#define IF_SPI_WRITE_OPERATION_MASK 0x8000
52
53/* SPI register offsets. 4-byte aligned. */
54#define IF_SPI_DEVICEID_CTRL_REG 0x00 /* DeviceID controller reg */
55#define IF_SPI_IO_READBASE_REG 0x04 /* Read I/O base reg */
56#define IF_SPI_IO_WRITEBASE_REG 0x08 /* Write I/O base reg */
57#define IF_SPI_IO_RDWRPORT_REG 0x0C /* Read/Write I/O port reg */
58
59#define IF_SPI_CMD_READBASE_REG 0x10 /* Read command base reg */
60#define IF_SPI_CMD_WRITEBASE_REG 0x14 /* Write command base reg */
61#define IF_SPI_CMD_RDWRPORT_REG 0x18 /* Read/Write command port reg */
62
63#define IF_SPI_DATA_READBASE_REG 0x1C /* Read data base reg */
64#define IF_SPI_DATA_WRITEBASE_REG 0x20 /* Write data base reg */
65#define IF_SPI_DATA_RDWRPORT_REG 0x24 /* Read/Write data port reg */
66
67#define IF_SPI_SCRATCH_1_REG 0x28 /* Scratch reg 1 */
68#define IF_SPI_SCRATCH_2_REG 0x2C /* Scratch reg 2 */
69#define IF_SPI_SCRATCH_3_REG 0x30 /* Scratch reg 3 */
70#define IF_SPI_SCRATCH_4_REG 0x34 /* Scratch reg 4 */
71
72#define IF_SPI_TX_FRAME_SEQ_NUM_REG 0x38 /* Tx frame sequence number reg */
73#define IF_SPI_TX_FRAME_STATUS_REG 0x3C /* Tx frame status reg */
74
75#define IF_SPI_HOST_INT_CTRL_REG 0x40 /* Host interrupt controller reg */
76
77#define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */
78#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */
79#define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */
80#define IF_SPI_CARD_INT_STATUS_MASK_REG 0x50 /* Card interrupt status mask */
81
82#define IF_SPI_CARD_INT_RESET_SELECT_REG 0x54 /* Card interrupt reset select */
83
84#define IF_SPI_HOST_INT_CAUSE_REG 0x58 /* Host interrupt cause reg */
85#define IF_SPI_HOST_INT_STATUS_REG 0x5C /* Host interrupt status reg */
86#define IF_SPI_HOST_INT_EVENT_MASK_REG 0x60 /* Host interrupt event mask */
87#define IF_SPI_HOST_INT_STATUS_MASK_REG 0x64 /* Host interrupt status mask */
88#define IF_SPI_HOST_INT_RESET_SELECT_REG 0x68 /* Host interrupt reset select */
89
90#define IF_SPI_DELAY_READ_REG 0x6C /* Delay read reg */
91#define IF_SPI_SPU_BUS_MODE_REG 0x70 /* SPU BUS mode reg */
92
93/***************** IF_SPI_DEVICEID_CTRL_REG *****************/
94#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dc) ((dc & 0xffff0000)>>16)
95#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
96
97/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
98/* Host Interrupt Control bit : Wake up */
99#define IF_SPI_HICT_WAKE_UP (1<<0)
100/* Host Interrupt Control bit : WLAN ready */
101#define IF_SPI_HICT_WLAN_READY (1<<1)
102/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */
103/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */
104/*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */
105/* Host Interrupt Control bit : Tx auto download */
106#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5)
107/* Host Interrupt Control bit : Rx auto upload */
108#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6)
109/* Host Interrupt Control bit : Command auto download */
110#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7)
111/* Host Interrupt Control bit : Command auto upload */
112#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8)
113
114/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
115/* Card Interrupt Case bit : Tx download over */
116#define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0)
117/* Card Interrupt Case bit : Rx upload over */
118#define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1)
119/* Card Interrupt Case bit : Command download over */
120#define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2)
121/* Card Interrupt Case bit : Host event */
122#define IF_SPI_CIC_HOST_EVENT (1<<3)
123/* Card Interrupt Case bit : Command upload over */
124#define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4)
125/* Card Interrupt Case bit : Power down */
126#define IF_SPI_CIC_POWER_DOWN (1<<5)
127
128/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
129#define IF_SPI_CIS_TX_DOWNLOAD_OVER (1<<0)
130#define IF_SPI_CIS_RX_UPLOAD_OVER (1<<1)
131#define IF_SPI_CIS_CMD_DOWNLOAD_OVER (1<<2)
132#define IF_SPI_CIS_HOST_EVENT (1<<3)
133#define IF_SPI_CIS_CMD_UPLOAD_OVER (1<<4)
134#define IF_SPI_CIS_POWER_DOWN (1<<5)
135
136/***************** IF_SPI_HOST_INT_CAUSE_REG *****************/
137#define IF_SPI_HICU_TX_DOWNLOAD_RDY (1<<0)
138#define IF_SPI_HICU_RX_UPLOAD_RDY (1<<1)
139#define IF_SPI_HICU_CMD_DOWNLOAD_RDY (1<<2)
140#define IF_SPI_HICU_CARD_EVENT (1<<3)
141#define IF_SPI_HICU_CMD_UPLOAD_RDY (1<<4)
142#define IF_SPI_HICU_IO_WR_FIFO_OVERFLOW (1<<5)
143#define IF_SPI_HICU_IO_RD_FIFO_UNDERFLOW (1<<6)
144#define IF_SPI_HICU_DATA_WR_FIFO_OVERFLOW (1<<7)
145#define IF_SPI_HICU_DATA_RD_FIFO_UNDERFLOW (1<<8)
146#define IF_SPI_HICU_CMD_WR_FIFO_OVERFLOW (1<<9)
147#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10)
148
149/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
150/* Host Interrupt Status bit : Tx download ready */
151#define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0)
152/* Host Interrupt Status bit : Rx upload ready */
153#define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1)
154/* Host Interrupt Status bit : Command download ready */
155#define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2)
156/* Host Interrupt Status bit : Card event */
157#define IF_SPI_HIST_CARD_EVENT (1<<3)
158/* Host Interrupt Status bit : Command upload ready */
159#define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4)
160/* Host Interrupt Status bit : I/O write FIFO overflow */
161#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5)
162/* Host Interrupt Status bit : I/O read FIFO underflow */
163#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6)
164/* Host Interrupt Status bit : Data write FIFO overflow */
165#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7)
166/* Host Interrupt Status bit : Data read FIFO underflow */
167#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8)
168/* Host Interrupt Status bit : Command write FIFO overflow */
169#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9)
170/* Host Interrupt Status bit : Command read FIFO underflow */
171#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10)
172
173/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
174/* Host Interrupt Status Mask bit : Tx download ready */
175#define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0)
176/* Host Interrupt Status Mask bit : Rx upload ready */
177#define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1)
178/* Host Interrupt Status Mask bit : Command download ready */
179#define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2)
180/* Host Interrupt Status Mask bit : Card event */
181#define IF_SPI_HISM_CARDEVENT (1<<3)
182/* Host Interrupt Status Mask bit : Command upload ready */
183#define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4)
184/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
185#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5)
186/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
187#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6)
188/* Host Interrupt Status Mask bit : Data write FIFO overflow */
189#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7)
190/* Host Interrupt Status Mask bit : Data write FIFO underflow */
191#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8)
192/* Host Interrupt Status Mask bit : Command write FIFO overflow */
193#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9)
194/* Host Interrupt Status Mask bit : Command write FIFO underflow */
195#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10)
196
197/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
198/* SCK edge on which the WLAN module outputs data on MISO */
199#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_FALLING 0x8
200#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING 0x0
201
202/* In a SPU read operation, there is a delay between writing the SPU
203 * register name and getting back data from the WLAN module.
204 * This can be specified in terms of nanoseconds or in terms of dummy
205 * clock cycles which the master must output before receiving a response. */
206#define IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK 0x4
207#define IF_SPI_BUS_MODE_DELAY_METHOD_TIMED 0x0
208
209/* Some different modes of SPI operation */
210#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_16_BIT_DATA 0x00
211#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_32_BIT_DATA 0x01
212#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA 0x02
213#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_32_BIT_DATA 0x03
214
215#endif
diff --git a/firmware/drivers/libertas/if_spi_drv.h b/firmware/drivers/libertas/if_spi_drv.h
new file mode 100644
index 0000000000..6c8b5c3d92
--- /dev/null
+++ b/firmware/drivers/libertas/if_spi_drv.h
@@ -0,0 +1,34 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef LIBERTAS_IF_SPI_DRV
23#define LIBERTAS_IF_SPI_DRV
24
25#include <stdint.h>
26
27void libertas_spi_init(void);
28void libertas_spi_reset(int high);
29void libertas_spi_pd(int high);
30void libertas_spi_cs(int high);
31void libertas_spi_tx(const uint8_t *buf, int len);
32void libertas_spi_rx(uint8_t *buf, int len);
33
34#endif
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h
index 5fc91a2794..874b198316 100644
--- a/firmware/export/config/sansaconnect.h
+++ b/firmware/export/config/sansaconnect.h
@@ -135,6 +135,12 @@
135/* Define this if you have a software controlled poweroff */ 135/* Define this if you have a software controlled poweroff */
136#define HAVE_SW_POWEROFF 136#define HAVE_SW_POWEROFF
137 137
138#ifndef BOOTLOADER
139#define HAVE_WIFI
140/* define this if the target has Marvell 88W8686 interfaced over SPI */
141#define HAVE_W8686_SPI
142#endif
143
138/* The number of bytes reserved for loadable codecs */ 144/* The number of bytes reserved for loadable codecs */
139#define CODEC_SIZE 0x100000 145#define CODEC_SIZE 0x100000
140 146
diff --git a/firmware/export/wifi.h b/firmware/export/wifi.h
new file mode 100644
index 0000000000..a70e062cb0
--- /dev/null
+++ b/firmware/export/wifi.h
@@ -0,0 +1,29 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef WIFI_H
23#define WIFI_H
24
25#include "config.h"
26
27void wifi_init(void) INIT_ATTR;
28
29#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
index 12058eba03..a4efe0962a 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -75,7 +75,7 @@
75#define CMD_WHEEL_EN 0xD0 75#define CMD_WHEEL_EN 0xD0
76#define CMD_SET_INTCHRG 0xD1 76#define CMD_SET_INTCHRG 0xD1
77#define CMD_GET_INTCHRG 0xD2 77#define CMD_GET_INTCHRG 0xD2
78#define CMD_UNKNOWN_D3 0xD3 78#define CMD_WIFI_PD 0xD3
79#define CMD_UNKNOWN_D4 0xD4 79#define CMD_UNKNOWN_D4 0xD4
80#define CMD_UNKNOWN_D5 0xD5 80#define CMD_UNKNOWN_D5 0xD5
81#define CMD_UNKNOWN_D6 0xD6 81#define CMD_UNKNOWN_D6 0xD6
@@ -315,7 +315,7 @@ static size_t avr_command_data_size(uint8_t opcode)
315 case CMD_WHEEL_EN: return 1; 315 case CMD_WHEEL_EN: return 1;
316 case CMD_SET_INTCHRG: return 1; 316 case CMD_SET_INTCHRG: return 1;
317 case CMD_GET_INTCHRG: return 1; 317 case CMD_GET_INTCHRG: return 1;
318 case CMD_UNKNOWN_D3: return 1; 318 case CMD_WIFI_PD: return 1;
319 case CMD_UNKNOWN_D4: return 1; 319 case CMD_UNKNOWN_D4: return 1;
320 case CMD_UNKNOWN_D5: return 2; 320 case CMD_UNKNOWN_D5: return 2;
321 case CMD_UNKNOWN_D6: return 2; 321 case CMD_UNKNOWN_D6: return 2;
@@ -536,6 +536,12 @@ void avr_hid_enable_charger(void)
536 avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable)); 536 avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable));
537} 537}
538 538
539void avr_hid_wifi_pd(int high)
540{
541 uint8_t state = high ? 0x01 : 0x00;
542 avr_execute_command(CMD_WIFI_PD, &state, sizeof(state));
543}
544
539static void avr_hid_lcm_power(uint8_t parameter) 545static void avr_hid_lcm_power(uint8_t parameter)
540{ 546{
541 avr_execute_command(CMD_LCM_POWER, &parameter, sizeof(parameter)); 547 avr_execute_command(CMD_LCM_POWER, &parameter, sizeof(parameter));
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
index 64b44675f7..baa7083760 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
@@ -28,6 +28,8 @@ void avr_hid_init(void);
28 28
29void avr_hid_enable_charger(void); 29void avr_hid_enable_charger(void);
30 30
31void avr_hid_wifi_pd(int high);
32
31void avr_hid_lcm_sleep(void); 33void avr_hid_lcm_sleep(void);
32void avr_hid_lcm_wake(void); 34void avr_hid_lcm_wake(void);
33void avr_hid_lcm_power_on(void); 35void avr_hid_lcm_power_on(void);
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c
new file mode 100644
index 0000000000..867b1da477
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c
@@ -0,0 +1,130 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2021 by Tomasz Moń
11*
12* This program is free software; you can redistribute it and/or
13* modify it under the terms of the GNU General Public License
14* as published by the Free Software Foundation; either version 2
15* of the License, or (at your option) any later version.
16*
17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18* KIND, either express or implied.
19*
20****************************************************************************/
21
22#include "kernel.h"
23#include "system.h"
24#include "spi.h"
25#include "avr-sansaconnect.h"
26#include "libertas/if_spi_drv.h"
27
28#define IO_SERIAL0_XMIT (0x100)
29
30void libertas_spi_init(void)
31{
32 IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */);
33 libertas_spi_reset(1);
34 libertas_spi_cs(1);
35
36 /* Enable the clock */
37 bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
38
39 /* Disable transmitter */
40 IO_SERIAL0_TX_ENABLE = 0x0001;
41
42 /* SELSDEN = 0, SLVEN = 0, SIOCLR = 0, SCLKM = 1, MSB = 1, MSSEL = 0,
43 * RATE = 2 -> 15MHz
44 */
45 IO_SERIAL0_MODE = 0x0601;
46
47 /* Disable the clock */
48 bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
49
50 /* Make sure the SPI clock is not inverted */
51 bitclr16(&IO_CLK_INV, CLK_INV_SIF0);
52}
53
54void libertas_spi_reset(int high)
55{
56 if (high)
57 {
58 IO_GIO_BITSET0 = (1 << 3);
59 }
60 else
61 {
62 IO_GIO_BITCLR0 = (1 << 3);
63 }
64}
65
66void libertas_spi_pd(int high)
67{
68 avr_hid_wifi_pd(high);
69}
70
71void libertas_spi_cs(int high)
72{
73 if (high)
74 {
75 IO_GIO_BITSET0 = (1 << 4);
76 }
77 else
78 {
79 IO_GIO_BITCLR0 = (1 << 4);
80 }
81}
82
83void libertas_spi_tx(const uint8_t *buf, int len)
84{
85 /* Enable the clock */
86 bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
87 IO_SERIAL0_TX_ENABLE = 0x0001;
88
89 while (len > 0)
90 {
91 IO_SERIAL0_TX_DATA = *(buf + 1);
92 while (IO_SERIAL0_RX_DATA & IO_SERIAL0_XMIT) {};
93 IO_SERIAL0_TX_DATA = *buf;
94 while (IO_SERIAL0_RX_DATA & IO_SERIAL0_XMIT) {};
95
96 buf += 2;
97 len -= 2;
98 }
99
100 IO_SERIAL0_TX_ENABLE = 0x0000;
101
102 /* Disable the clock */
103 bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
104}
105
106void libertas_spi_rx(uint8_t *buf, int len)
107{
108 /* Enable the clock */
109 bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
110 IO_SERIAL0_TX_ENABLE = 0x0001;
111
112 while (len > 0)
113 {
114 uint16_t data;
115 IO_SERIAL0_TX_DATA = 0;
116 while ((data = IO_SERIAL0_RX_DATA) & IO_SERIAL0_XMIT) {};
117 *(buf + 1) = data & 0xFF;
118 IO_SERIAL0_TX_DATA = 0;
119 while ((data = IO_SERIAL0_RX_DATA) & IO_SERIAL0_XMIT) {};
120 *buf = data & 0xFF;
121
122 buf += 2;
123 len -= 2;
124 }
125
126 IO_SERIAL0_TX_ENABLE = 0x0000;
127
128 /* Disable the clock */
129 bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
130}
diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c
index 935f3609a6..c80082afd8 100644
--- a/firmware/target/arm/tms320dm320/system-dm320.c
+++ b/firmware/target/arm/tms320dm320/system-dm320.c
@@ -369,9 +369,11 @@ void system_init(void)
369#endif 369#endif
370 370
371#ifdef SANSA_CONNECT 371#ifdef SANSA_CONNECT
372#ifndef HAVE_WIFI
372 /* keep WIFI CS and reset high to save power */ 373 /* keep WIFI CS and reset high to save power */
373 IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */); 374 IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */);
374 IO_GIO_BITSET0 = (1 << 4) | (1 << 3); 375 IO_GIO_BITSET0 = (1 << 4) | (1 << 3);
376#endif
375 377
376 i2c_init(); 378 i2c_init();
377 avr_hid_init(); 379 avr_hid_init();
diff --git a/tools/buildzip.pl b/tools/buildzip.pl
index 4e9ba79eeb..43c304ff12 100755
--- a/tools/buildzip.pl
+++ b/tools/buildzip.pl
@@ -387,6 +387,11 @@ sub buildzip {
387 open(NOMEDIA, ">$temp_dir/.nomedia") || die "can't open .nomedia"; 387 open(NOMEDIA, ">$temp_dir/.nomedia") || die "can't open .nomedia";
388 close(NOMEDIA); 388 close(NOMEDIA);
389 } 389 }
390 # copy wifi firmware
391 if ($modelname =~ /sansaconnect/) {
392 glob_mkdir("$temp_dir/libertas");
393 glob_copy("$ROOT/firmware/drivers/libertas/firmware/*", "$temp_dir/libertas/");
394 }
390 395
391 glob_mkdir("$temp_dir/langs"); 396 glob_mkdir("$temp_dir/langs");
392 glob_mkdir("$temp_dir/rocks"); 397 glob_mkdir("$temp_dir/rocks");