A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

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

+1142 -2
+5
apps/main.c
··· 36 36 #include "panic.h" 37 37 #include "menu.h" 38 38 #include "usb.h" 39 + #include "wifi.h" 39 40 #include "powermgmt.h" 40 41 #if !defined(DX50) && !defined(DX90) 41 42 #include "adc.h" ··· 635 636 audio_init(); 636 637 CHART("<audio_init"); 637 638 talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */ 639 + 640 + #ifdef HAVE_WIFI 641 + wifi_init(); 642 + #endif 638 643 639 644 /* runtime database has to be initialized after audio_init() */ 640 645 cpu_boost(false);
+10
firmware/SOURCES
··· 536 536 537 537 #endif /* !defined(BOOTLOADER) */ 538 538 539 + /* WiFi */ 540 + #if !defined(BOOTLOADER) 541 + #if (CONFIG_PLATFORM & PLATFORM_NATIVE) 542 + #if defined(HAVE_W8686_SPI) 543 + drivers/libertas/if_spi.c 544 + #endif 545 + #endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) */ 546 + #endif /* !defined(BOOTLOADER) */ 547 + 539 548 /* CPU Specific - By class then particular chip if applicable */ 540 549 #if defined(CPU_COLDFIRE) 541 550 ··· 1266 1275 target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c 1267 1276 target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c 1268 1277 target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c 1278 + target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c 1269 1279 target/arm/tms320dm320/dma-dm320.c 1270 1280 #endif /* SANSA_CONNECT */ 1271 1281
+22
firmware/drivers/libertas/firmware/LICENCE.Marvell
··· 1 + Copyright © 2019. Marvell International Ltd. All rights reserved. 2 + 3 + Redistribution and use in binary form is permitted provided that the following 4 + conditions are met: 5 + 6 + 1. Redistributions must reproduce the above copyright notice, this list of 7 + conditions and the following disclaimer in the documentation and/or other 8 + materials provided with the distribution. 9 + 10 + 2. Redistribution and use shall be used only with Marvell silicon products. 11 + Any other use, reproduction, modification, translation, or compilation of the 12 + Software is prohibited. 13 + 14 + 3. No reverse engineering, decompilation, or disassembly is permitted. 15 + 16 + TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED 17 + “AS IS” WITHOUT WARRANTY OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ANY EXPRESS 18 + OR IMPLIED WARRANTIES OF MERCHANTABILITY, ACCURACY, FITNESS OR SUFFICIENCY FOR A 19 + PARTICULAR PURPOSE, SATISFACTORY QUALITY, CORRESPONDENCE WITH DESCRIPTION, QUIET 20 + ENJOYMENT OR NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS. 21 + MARVELL, ITS AFFILIATES AND THEIR SUPPLIERS DISCLAIM ANY WARRANTY THAT THE 22 + DELIVERABLES WILL OPERATE WITHOUT INTERRUPTION OR BE ERROR-FREE.
firmware/drivers/libertas/firmware/gspi8686_v9.bin

This is a binary file and will not be displayed.

firmware/drivers/libertas/firmware/gspi8686_v9_helper.bin

This is a binary file and will not be displayed.

+674
firmware/drivers/libertas/if_spi.c
··· 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 + 43 + struct 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 + 57 + static const struct 58 + { 59 + uint16_t model; 60 + const char *helper; 61 + const char *main; 62 + } 63 + fw_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 + 81 + static 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 + 93 + static 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 + */ 103 + static 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 + 124 + static 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 + 132 + static 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 + 145 + static 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 */ 179 + static 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 + */ 195 + static 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 + */ 215 + static 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 + */ 250 + static 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 + 266 + static 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 + 313 + static 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 + 326 + static 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 + 346 + static 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 + 376 + static 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); 438 + out: 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 + */ 449 + static 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 + 489 + static 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 + 568 + out: 569 + if (err) 570 + logf("failed to load firmware (err=%d)", err); 571 + 572 + return err; 573 + } 574 + 575 + static 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 + 647 + out: 648 + return err; 649 + } 650 + 651 + void 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 + }
+215
firmware/drivers/libertas/if_spi.h
··· 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
+34
firmware/drivers/libertas/if_spi_drv.h
··· 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 + 27 + void libertas_spi_init(void); 28 + void libertas_spi_reset(int high); 29 + void libertas_spi_pd(int high); 30 + void libertas_spi_cs(int high); 31 + void libertas_spi_tx(const uint8_t *buf, int len); 32 + void libertas_spi_rx(uint8_t *buf, int len); 33 + 34 + #endif
+6
firmware/export/config/sansaconnect.h
··· 135 135 /* Define this if you have a software controlled poweroff */ 136 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 144 /* The number of bytes reserved for loadable codecs */ 139 145 #define CODEC_SIZE 0x100000 140 146
+29
firmware/export/wifi.h
··· 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 + 27 + void wifi_init(void) INIT_ATTR; 28 + 29 + #endif
+8 -2
firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
··· 75 75 #define CMD_WHEEL_EN 0xD0 76 76 #define CMD_SET_INTCHRG 0xD1 77 77 #define CMD_GET_INTCHRG 0xD2 78 - #define CMD_UNKNOWN_D3 0xD3 78 + #define CMD_WIFI_PD 0xD3 79 79 #define CMD_UNKNOWN_D4 0xD4 80 80 #define CMD_UNKNOWN_D5 0xD5 81 81 #define CMD_UNKNOWN_D6 0xD6 ··· 315 315 case CMD_WHEEL_EN: return 1; 316 316 case CMD_SET_INTCHRG: return 1; 317 317 case CMD_GET_INTCHRG: return 1; 318 - case CMD_UNKNOWN_D3: return 1; 318 + case CMD_WIFI_PD: return 1; 319 319 case CMD_UNKNOWN_D4: return 1; 320 320 case CMD_UNKNOWN_D5: return 2; 321 321 case CMD_UNKNOWN_D6: return 2; ··· 534 534 { 535 535 uint8_t enable = 0x01; 536 536 avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable)); 537 + } 538 + 539 + void avr_hid_wifi_pd(int high) 540 + { 541 + uint8_t state = high ? 0x01 : 0x00; 542 + avr_execute_command(CMD_WIFI_PD, &state, sizeof(state)); 537 543 } 538 544 539 545 static void avr_hid_lcm_power(uint8_t parameter)
+2
firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
··· 28 28 29 29 void avr_hid_enable_charger(void); 30 30 31 + void avr_hid_wifi_pd(int high); 32 + 31 33 void avr_hid_lcm_sleep(void); 32 34 void avr_hid_lcm_wake(void); 33 35 void avr_hid_lcm_power_on(void);
+130
firmware/target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c
··· 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 + 30 + void 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 + 54 + void 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 + 66 + void libertas_spi_pd(int high) 67 + { 68 + avr_hid_wifi_pd(high); 69 + } 70 + 71 + void 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 + 83 + void 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 + 106 + void 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 + }
+2
firmware/target/arm/tms320dm320/system-dm320.c
··· 369 369 #endif 370 370 371 371 #ifdef SANSA_CONNECT 372 + #ifndef HAVE_WIFI 372 373 /* keep WIFI CS and reset high to save power */ 373 374 IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */); 374 375 IO_GIO_BITSET0 = (1 << 4) | (1 << 3); 376 + #endif 375 377 376 378 i2c_init(); 377 379 avr_hid_init();
+5
tools/buildzip.pl
··· 387 387 open(NOMEDIA, ">$temp_dir/.nomedia") || die "can't open .nomedia"; 388 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 396 glob_mkdir("$temp_dir/langs"); 392 397 glob_mkdir("$temp_dir/rocks");