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
This commit is contained in:
parent
c9f2308a1d
commit
e11fa5f74e
|
@ -36,6 +36,7 @@
|
|||
#include "panic.h"
|
||||
#include "menu.h"
|
||||
#include "usb.h"
|
||||
#include "wifi.h"
|
||||
#include "powermgmt.h"
|
||||
#if !defined(DX50) && !defined(DX90)
|
||||
#include "adc.h"
|
||||
|
@ -636,6 +637,10 @@ static void init(void)
|
|||
CHART("<audio_init");
|
||||
talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */
|
||||
|
||||
#ifdef HAVE_WIFI
|
||||
wifi_init();
|
||||
#endif
|
||||
|
||||
/* runtime database has to be initialized after audio_init() */
|
||||
cpu_boost(false);
|
||||
|
||||
|
|
|
@ -536,6 +536,15 @@ target/hosted/sdl/pcm-sdl.c
|
|||
|
||||
#endif /* !defined(BOOTLOADER) */
|
||||
|
||||
/* WiFi */
|
||||
#if !defined(BOOTLOADER)
|
||||
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
|
||||
#if defined(HAVE_W8686_SPI)
|
||||
drivers/libertas/if_spi.c
|
||||
#endif
|
||||
#endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) */
|
||||
#endif /* !defined(BOOTLOADER) */
|
||||
|
||||
/* CPU Specific - By class then particular chip if applicable */
|
||||
#if defined(CPU_COLDFIRE)
|
||||
|
||||
|
@ -1266,6 +1275,7 @@ target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
|
|||
target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
|
||||
target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
|
||||
target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
|
||||
target/arm/tms320dm320/sansa-connect/wifi-sansaconnect.c
|
||||
target/arm/tms320dm320/dma-dm320.c
|
||||
#endif /* SANSA_CONNECT */
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
Copyright © 2019. Marvell International Ltd. All rights reserved.
|
||||
|
||||
Redistribution and use in binary form is permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
1. Redistributions must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
2. Redistribution and use shall be used only with Marvell silicon products.
|
||||
Any other use, reproduction, modification, translation, or compilation of the
|
||||
Software is prohibited.
|
||||
|
||||
3. No reverse engineering, decompilation, or disassembly is permitted.
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
|
||||
“AS IS” WITHOUT WARRANTY OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES OF MERCHANTABILITY, ACCURACY, FITNESS OR SUFFICIENCY FOR A
|
||||
PARTICULAR PURPOSE, SATISFACTORY QUALITY, CORRESPONDENCE WITH DESCRIPTION, QUIET
|
||||
ENJOYMENT OR NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS.
|
||||
MARVELL, ITS AFFILIATES AND THEIR SUPPLIERS DISCLAIM ANY WARRANTY THAT THE
|
||||
DELIVERABLES WILL OPERATE WITHOUT INTERRUPTION OR BE ERROR-FREE.
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,674 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 by Tomasz Moń
|
||||
* Ported from Linux libertas driver
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
* Authors:
|
||||
* Andrey Yurovsky <andrey@cozybit.com>
|
||||
* Colin McCabe <colin@cozybit.com>
|
||||
* Inspired by if_sdio.c, Copyright 2007-2008 Pierre Ossman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
/*#define LOGF_ENABLE*/
|
||||
#include "logf.h"
|
||||
#include "errno.h"
|
||||
#include "file.h"
|
||||
#include "panic.h"
|
||||
#include "system.h"
|
||||
#include "tick.h"
|
||||
#include <stddef.h>
|
||||
#include "if_spi.h"
|
||||
#include "if_spi_drv.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1)/(d))
|
||||
|
||||
struct if_spi_card
|
||||
{
|
||||
/* The card ID and card revision, as reported by the hardware. */
|
||||
uint16_t card_id;
|
||||
uint8_t card_rev;
|
||||
|
||||
unsigned long spu_port_delay;
|
||||
unsigned long spu_reg_delay;
|
||||
|
||||
uint8_t cmd_buffer[IF_SPI_CMD_BUF_SIZE];
|
||||
};
|
||||
|
||||
#define MODEL_8686 0x0b
|
||||
|
||||
static const struct
|
||||
{
|
||||
uint16_t model;
|
||||
const char *helper;
|
||||
const char *main;
|
||||
}
|
||||
fw_table[] =
|
||||
{
|
||||
{ MODEL_8686, ROCKBOX_DIR"/libertas/gspi8686_v9_helper.bin", ROCKBOX_DIR"/libertas/gspi8686_v9.bin" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* SPI Interface Unit Routines
|
||||
*
|
||||
* The SPU sits between the host and the WLAN module.
|
||||
* All communication with the firmware is through SPU transactions.
|
||||
*
|
||||
* First we have to put a SPU register name on the bus. Then we can
|
||||
* either read from or write to that register.
|
||||
*
|
||||
*/
|
||||
|
||||
static void spu_transaction_init(struct if_spi_card *card)
|
||||
{
|
||||
(void)card;
|
||||
/* Linux delays 400 ns if spu_transaction_finish() was called
|
||||
* within the same jiffy. As we don't have jiffy counter nor
|
||||
* nanosecond delays, simply delay for 1 us. This currently
|
||||
* does not really matter as this driver simply loads firmware.
|
||||
*/
|
||||
udelay(1);
|
||||
libertas_spi_cs(0); /* assert CS */
|
||||
}
|
||||
|
||||
static void spu_transaction_finish(struct if_spi_card *card)
|
||||
{
|
||||
(void)card;
|
||||
libertas_spi_cs(1); /* drop CS */
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a byte buffer to an SPI register,
|
||||
* using a series of 16-bit transfers.
|
||||
*/
|
||||
static int spu_write(struct if_spi_card *card, uint16_t reg, const uint8_t *buf, int len)
|
||||
{
|
||||
int err = 0;
|
||||
uint8_t reg_out[2];
|
||||
|
||||
/* You must give an even number of bytes to the SPU, even if it
|
||||
* doesn't care about the last one. */
|
||||
if (len & 0x1)
|
||||
panicf("Odd length in spu_write()");
|
||||
|
||||
reg |= IF_SPI_WRITE_OPERATION_MASK;
|
||||
reg_out[0] = (reg & 0x00FF);
|
||||
reg_out[1] = (reg & 0xFF00) >> 8;
|
||||
|
||||
spu_transaction_init(card);
|
||||
libertas_spi_tx(reg_out, sizeof(reg_out));
|
||||
libertas_spi_tx(buf, len);
|
||||
spu_transaction_finish(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int spu_write_u16(struct if_spi_card *card, uint16_t reg, uint16_t val)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
buf[0] = (val & 0x00FF);
|
||||
buf[1] = (val & 0xFF00) >> 8;
|
||||
return spu_write(card, reg, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static inline int spu_reg_is_port_reg(uint16_t reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case IF_SPI_IO_RDWRPORT_REG:
|
||||
case IF_SPI_CMD_RDWRPORT_REG:
|
||||
case IF_SPI_DATA_RDWRPORT_REG:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int spu_read(struct if_spi_card *card, uint16_t reg, uint8_t *buf, int len)
|
||||
{
|
||||
unsigned int delay;
|
||||
int err = 0;
|
||||
uint8_t reg_out[2];
|
||||
|
||||
/*
|
||||
* You must take an even number of bytes from the SPU, even if you
|
||||
* don't care about the last one.
|
||||
*/
|
||||
if (len & 0x1)
|
||||
panicf("Odd length in spu_read()");
|
||||
|
||||
reg |= IF_SPI_READ_OPERATION_MASK;
|
||||
reg_out[0] = (reg & 0x00FF);
|
||||
reg_out[1] = (reg & 0xFF00) >> 8;
|
||||
|
||||
spu_transaction_init(card);
|
||||
libertas_spi_tx(reg_out, sizeof(reg_out));
|
||||
|
||||
delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay;
|
||||
/* Busy-wait while the SPU fills the FIFO */
|
||||
delay = DIV_ROUND_UP((100 + (delay * 10)), 1000);
|
||||
if (delay < 1000)
|
||||
udelay(delay);
|
||||
else
|
||||
mdelay(DIV_ROUND_UP(delay, 1000));
|
||||
|
||||
libertas_spi_rx(buf, len);
|
||||
spu_transaction_finish(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Read 16 bits from an SPI register */
|
||||
static inline int spu_read_u16(struct if_spi_card *card, uint16_t reg, uint16_t *val)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
int ret;
|
||||
|
||||
ret = spu_read(card, reg, buf, sizeof(buf));
|
||||
if (ret == 0)
|
||||
*val = buf[0] | (buf[1] << 8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 32 bits from an SPI register.
|
||||
* The low 16 bits are read first.
|
||||
*/
|
||||
static int spu_read_u32(struct if_spi_card *card, uint16_t reg, uint32_t *val)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
int err;
|
||||
|
||||
err = spu_read(card, reg, buf, sizeof(buf));
|
||||
if (!err)
|
||||
*val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep reading 16 bits from an SPI register until you get the correct result.
|
||||
*
|
||||
* If mask = 0, the correct result is any non-zero number.
|
||||
* If mask != 0, the correct result is any number where
|
||||
* number & target_mask == target
|
||||
*
|
||||
* Returns -ETIMEDOUT if a five seconds passes without the correct result.
|
||||
*/
|
||||
static int spu_wait_for_u16(struct if_spi_card *card, uint16_t reg,
|
||||
uint16_t target_mask, uint16_t target)
|
||||
{
|
||||
int err;
|
||||
unsigned long timeout = current_tick + 5*HZ;
|
||||
while (1)
|
||||
{
|
||||
uint16_t val;
|
||||
err = spu_read_u16(card, reg, &val);
|
||||
if (err)
|
||||
return err;
|
||||
if (target_mask)
|
||||
{
|
||||
if ((val & target_mask) == target)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val)
|
||||
return 0;
|
||||
}
|
||||
udelay(100);
|
||||
if (TIME_AFTER(current_tick, timeout))
|
||||
{
|
||||
logf("%s: timeout with val=%02x, target_mask=%02x, target=%02x",
|
||||
__func__, val, target_mask, target);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 16 bits from an SPI register until you receive a specific value.
|
||||
* Returns -ETIMEDOUT if a 4 tries pass without success.
|
||||
*/
|
||||
static int spu_wait_for_u32(struct if_spi_card *card, uint32_t reg, uint32_t target)
|
||||
{
|
||||
int err, try;
|
||||
for (try = 0; try < 4; ++try)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
err = spu_read_u32(card, reg, &val);
|
||||
if (err)
|
||||
return err;
|
||||
if (val == target)
|
||||
return 0;
|
||||
mdelay(100);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int spu_set_interrupt_mode(struct if_spi_card *card,
|
||||
int suppress_host_int,
|
||||
int auto_int)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* We can suppress a host interrupt by clearing the appropriate
|
||||
* bit in the "host interrupt status mask" register
|
||||
*/
|
||||
if (suppress_host_int) {
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG,
|
||||
IF_SPI_HISM_TX_DOWNLOAD_RDY |
|
||||
IF_SPI_HISM_RX_UPLOAD_RDY |
|
||||
IF_SPI_HISM_CMD_DOWNLOAD_RDY |
|
||||
IF_SPI_HISM_CARDEVENT |
|
||||
IF_SPI_HISM_CMD_UPLOAD_RDY);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If auto-interrupts are on, the completion of certain transactions
|
||||
* will trigger an interrupt automatically. If auto-interrupts
|
||||
* are off, we need to set the "Card Interrupt Cause" register to
|
||||
* trigger a card interrupt.
|
||||
*/
|
||||
if (auto_int) {
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
|
||||
IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
|
||||
IF_SPI_HICT_RX_UPLOAD_OVER_AUTO |
|
||||
IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO |
|
||||
IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int spu_get_chip_revision(struct if_spi_card *card,
|
||||
uint16_t *card_id, uint8_t *card_rev)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t dev_ctrl;
|
||||
err = spu_read_u32(card, IF_SPI_DEVICEID_CTRL_REG, &dev_ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
*card_id = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dev_ctrl);
|
||||
*card_rev = IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dev_ctrl);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int spu_set_bus_mode(struct if_spi_card *card, uint16_t mode)
|
||||
{
|
||||
int err = 0;
|
||||
uint16_t rval;
|
||||
/* set bus mode */
|
||||
err = spu_write_u16(card, IF_SPI_SPU_BUS_MODE_REG, mode);
|
||||
if (err)
|
||||
return err;
|
||||
/* Check that we were able to read back what we just wrote. */
|
||||
err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
|
||||
if (err)
|
||||
return err;
|
||||
if ((rval & 0xF) != mode)
|
||||
{
|
||||
logf("Can't read bus mode register");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spu_init(struct if_spi_card *card)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t delay;
|
||||
|
||||
err = spu_set_bus_mode(card,
|
||||
IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
|
||||
IF_SPI_BUS_MODE_DELAY_METHOD_TIMED |
|
||||
IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA);
|
||||
if (err)
|
||||
return err;
|
||||
card->spu_port_delay = 1000;
|
||||
card->spu_reg_delay = 1000;
|
||||
err = spu_read_u32(card, IF_SPI_DELAY_READ_REG, &delay);
|
||||
if (err)
|
||||
return err;
|
||||
card->spu_port_delay = delay & 0x0000ffff;
|
||||
card->spu_reg_delay = (delay & 0xffff0000) >> 16;
|
||||
|
||||
logf("Initialized SPU unit. "
|
||||
"spu_port_delay=0x%04lx, spu_reg_delay=0x%04lx",
|
||||
card->spu_port_delay, card->spu_reg_delay);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Firmware Loading
|
||||
*/
|
||||
|
||||
static int if_spi_prog_helper_firmware(struct if_spi_card *card, int fd)
|
||||
{
|
||||
int err = 0;
|
||||
int bytes_read;
|
||||
uint8_t *temp = card->cmd_buffer;
|
||||
|
||||
err = spu_set_interrupt_mode(card, 1, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Load helper firmware image */
|
||||
while ((bytes_read = read(fd, temp, HELPER_FW_LOAD_CHUNK_SZ)) > 0)
|
||||
{
|
||||
/*
|
||||
* Scratch pad 1 should contain the number of bytes we
|
||||
* want to download to the firmware
|
||||
*/
|
||||
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
|
||||
HELPER_FW_LOAD_CHUNK_SZ);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
|
||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
|
||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Feed the data into the command read/write port reg
|
||||
* in chunks of 64 bytes
|
||||
*/
|
||||
memset(temp + bytes_read, 0, HELPER_FW_LOAD_CHUNK_SZ - bytes_read);
|
||||
mdelay(10);
|
||||
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
|
||||
temp, HELPER_FW_LOAD_CHUNK_SZ);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Interrupt the boot code */
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Once the helper / single stage firmware download is complete,
|
||||
* write 0 to scratch pad 1 and interrupt the
|
||||
* bootloader. This completes the helper download.
|
||||
*/
|
||||
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||
out:
|
||||
if (err)
|
||||
logf("failed to load helper firmware (err=%d)", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the length of the next packet the firmware expects us to send.
|
||||
* Sets crc_err if the previous transfer had a CRC error.
|
||||
*/
|
||||
static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
|
||||
int *crc_err)
|
||||
{
|
||||
uint16_t len;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* wait until the host interrupt status register indicates
|
||||
* that we are ready to download
|
||||
*/
|
||||
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
|
||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
|
||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
|
||||
if (err)
|
||||
{
|
||||
logf("timed out waiting for host_int_status");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Ask the device how many bytes of firmware it wants. */
|
||||
err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (len > IF_SPI_CMD_BUF_SIZE)
|
||||
{
|
||||
logf("firmware load device requested a larger transfer than we are prepared to handle (len = %d)",
|
||||
len);
|
||||
return -EIO;
|
||||
}
|
||||
if (len & 0x1) {
|
||||
logf("%s: crc error", __func__);
|
||||
len &= ~0x1;
|
||||
*crc_err = 1;
|
||||
} else
|
||||
*crc_err = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int if_spi_prog_main_firmware(struct if_spi_card *card, int fd)
|
||||
{
|
||||
int len;
|
||||
int bytes_read = 0, crc_err = 0, err = 0;
|
||||
uint16_t num_crc_errs;
|
||||
|
||||
err = spu_set_interrupt_mode(card, 1, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
|
||||
if (err)
|
||||
{
|
||||
logf("%s: timed out waiting for initial scratch reg = 0", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_crc_errs = 0;
|
||||
while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err)))
|
||||
{
|
||||
if (len < 0)
|
||||
{
|
||||
err = len;
|
||||
goto out;
|
||||
}
|
||||
if (crc_err)
|
||||
{
|
||||
/* Previous transfer failed. */
|
||||
if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR)
|
||||
{
|
||||
logf("Too many CRC errors encountered in firmware load.");
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Rewind so we read back the data from previous transfer */
|
||||
lseek(fd, -bytes_read, SEEK_CUR);
|
||||
}
|
||||
|
||||
bytes_read = read(fd, card->cmd_buffer, len);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
/*
|
||||
* If there are no more bytes left, we would normally
|
||||
* expect to have terminated with len = 0
|
||||
*/
|
||||
logf("Firmware load wants more bytes than we have to offer.");
|
||||
break;
|
||||
}
|
||||
else if (bytes_read < len)
|
||||
{
|
||||
memset(card->cmd_buffer + bytes_read, 0, len - bytes_read);
|
||||
}
|
||||
|
||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, card->cmd_buffer, len);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
if (read(fd, card->cmd_buffer, IF_SPI_CMD_BUF_SIZE) > 0)
|
||||
{
|
||||
logf("firmware load wants fewer bytes than we have to offer");
|
||||
}
|
||||
|
||||
/* Confirm firmware download */
|
||||
err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
|
||||
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
|
||||
if (err)
|
||||
{
|
||||
logf("failed to confirm the firmware download");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
logf("failed to load firmware (err=%d)", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int if_spi_init_card(struct if_spi_card *card)
|
||||
{
|
||||
int err;
|
||||
size_t i;
|
||||
uint32_t scratch;
|
||||
int fd;
|
||||
|
||||
err = spu_init(card);
|
||||
if (err)
|
||||
goto out;
|
||||
err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
|
||||
if (err)
|
||||
goto out;
|
||||
if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
|
||||
logf("Firmware is already loaded for Marvell WLAN 802.11 adapter");
|
||||
else {
|
||||
/* Check if we support this card */
|
||||
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
|
||||
if (card->card_id == fw_table[i].model)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(fw_table)) {
|
||||
logf("Unsupported chip_id: 0x%02x", card->card_id);
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
logf("Initializing FW for Marvell WLAN 802.11 adapter "
|
||||
"(chip_id = 0x%04x, chip_rev = 0x%02x)",
|
||||
card->card_id, card->card_rev);
|
||||
|
||||
fd = open(fw_table[i].helper, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
err = if_spi_prog_helper_firmware(card, fd);
|
||||
close(fd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
logf("failed to find firmware helper (%s)", fw_table[i].helper);
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = open(fw_table[i].main, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
err = if_spi_prog_main_firmware(card, fd);
|
||||
close(fd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
logf("failed to find firmware (%s)", fw_table[i].main);
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
logf("loaded FW for Marvell WLAN 802.11 adapter");
|
||||
}
|
||||
|
||||
err = spu_set_interrupt_mode(card, 0, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void wifi_init(void) INIT_ATTR
|
||||
{
|
||||
#if 0
|
||||
static struct if_spi_card card;
|
||||
libertas_spi_init();
|
||||
libertas_spi_pd(1);
|
||||
libertas_spi_reset(1);
|
||||
mdelay(100);
|
||||
if (!if_spi_init_card(&card))
|
||||
{
|
||||
/* TODO: Configure card and enter deep sleep */
|
||||
}
|
||||
else
|
||||
#else
|
||||
libertas_spi_init();
|
||||
(void)if_spi_init_card;
|
||||
#endif
|
||||
{
|
||||
/* Keep the lines in lowest power configuration */
|
||||
libertas_spi_pd(0);
|
||||
libertas_spi_reset(1);
|
||||
libertas_spi_cs(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 by Tomasz Moń
|
||||
* Ported from Linux libertas driver
|
||||
* Copyright 2008 Analog Devices Inc.
|
||||
* Authors:
|
||||
* Andrey Yurovsky <andrey@cozybit.com>
|
||||
* Colin McCabe <colin@cozybit.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _LBS_IF_SPI_H_
|
||||
#define _LBS_IF_SPI_H_
|
||||
|
||||
#define IPFIELD_ALIGN_OFFSET 2
|
||||
#define IF_SPI_CMD_BUF_SIZE 2400
|
||||
|
||||
/***************** Firmware *****************/
|
||||
|
||||
#define IF_SPI_FW_NAME_MAX 30
|
||||
|
||||
#define MAX_MAIN_FW_LOAD_CRC_ERR 10
|
||||
|
||||
/* Chunk size when loading the helper firmware */
|
||||
#define HELPER_FW_LOAD_CHUNK_SZ 64
|
||||
|
||||
/* Value to write to indicate end of helper firmware dnld */
|
||||
#define FIRMWARE_DNLD_OK 0x0000
|
||||
|
||||
/* Value to check once the main firmware is downloaded */
|
||||
#define SUCCESSFUL_FW_DOWNLOAD_MAGIC 0x88888888
|
||||
|
||||
/***************** SPI Interface Unit *****************/
|
||||
/* Masks used in SPI register read/write operations */
|
||||
#define IF_SPI_READ_OPERATION_MASK 0x0
|
||||
#define IF_SPI_WRITE_OPERATION_MASK 0x8000
|
||||
|
||||
/* SPI register offsets. 4-byte aligned. */
|
||||
#define IF_SPI_DEVICEID_CTRL_REG 0x00 /* DeviceID controller reg */
|
||||
#define IF_SPI_IO_READBASE_REG 0x04 /* Read I/O base reg */
|
||||
#define IF_SPI_IO_WRITEBASE_REG 0x08 /* Write I/O base reg */
|
||||
#define IF_SPI_IO_RDWRPORT_REG 0x0C /* Read/Write I/O port reg */
|
||||
|
||||
#define IF_SPI_CMD_READBASE_REG 0x10 /* Read command base reg */
|
||||
#define IF_SPI_CMD_WRITEBASE_REG 0x14 /* Write command base reg */
|
||||
#define IF_SPI_CMD_RDWRPORT_REG 0x18 /* Read/Write command port reg */
|
||||
|
||||
#define IF_SPI_DATA_READBASE_REG 0x1C /* Read data base reg */
|
||||
#define IF_SPI_DATA_WRITEBASE_REG 0x20 /* Write data base reg */
|
||||
#define IF_SPI_DATA_RDWRPORT_REG 0x24 /* Read/Write data port reg */
|
||||
|
||||
#define IF_SPI_SCRATCH_1_REG 0x28 /* Scratch reg 1 */
|
||||
#define IF_SPI_SCRATCH_2_REG 0x2C /* Scratch reg 2 */
|
||||
#define IF_SPI_SCRATCH_3_REG 0x30 /* Scratch reg 3 */
|
||||
#define IF_SPI_SCRATCH_4_REG 0x34 /* Scratch reg 4 */
|
||||
|
||||
#define IF_SPI_TX_FRAME_SEQ_NUM_REG 0x38 /* Tx frame sequence number reg */
|
||||
#define IF_SPI_TX_FRAME_STATUS_REG 0x3C /* Tx frame status reg */
|
||||
|
||||
#define IF_SPI_HOST_INT_CTRL_REG 0x40 /* Host interrupt controller reg */
|
||||
|
||||
#define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */
|
||||
#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */
|
||||
#define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */
|
||||
#define IF_SPI_CARD_INT_STATUS_MASK_REG 0x50 /* Card interrupt status mask */
|
||||
|
||||
#define IF_SPI_CARD_INT_RESET_SELECT_REG 0x54 /* Card interrupt reset select */
|
||||
|
||||
#define IF_SPI_HOST_INT_CAUSE_REG 0x58 /* Host interrupt cause reg */
|
||||
#define IF_SPI_HOST_INT_STATUS_REG 0x5C /* Host interrupt status reg */
|
||||
#define IF_SPI_HOST_INT_EVENT_MASK_REG 0x60 /* Host interrupt event mask */
|
||||
#define IF_SPI_HOST_INT_STATUS_MASK_REG 0x64 /* Host interrupt status mask */
|
||||
#define IF_SPI_HOST_INT_RESET_SELECT_REG 0x68 /* Host interrupt reset select */
|
||||
|
||||
#define IF_SPI_DELAY_READ_REG 0x6C /* Delay read reg */
|
||||
#define IF_SPI_SPU_BUS_MODE_REG 0x70 /* SPU BUS mode reg */
|
||||
|
||||
/***************** IF_SPI_DEVICEID_CTRL_REG *****************/
|
||||
#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_ID(dc) ((dc & 0xffff0000)>>16)
|
||||
#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
|
||||
|
||||
/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
|
||||
/* Host Interrupt Control bit : Wake up */
|
||||
#define IF_SPI_HICT_WAKE_UP (1<<0)
|
||||
/* Host Interrupt Control bit : WLAN ready */
|
||||
#define IF_SPI_HICT_WLAN_READY (1<<1)
|
||||
/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */
|
||||
/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */
|
||||
/*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */
|
||||
/* Host Interrupt Control bit : Tx auto download */
|
||||
#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5)
|
||||
/* Host Interrupt Control bit : Rx auto upload */
|
||||
#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6)
|
||||
/* Host Interrupt Control bit : Command auto download */
|
||||
#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7)
|
||||
/* Host Interrupt Control bit : Command auto upload */
|
||||
#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8)
|
||||
|
||||
/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
|
||||
/* Card Interrupt Case bit : Tx download over */
|
||||
#define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0)
|
||||
/* Card Interrupt Case bit : Rx upload over */
|
||||
#define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1)
|
||||
/* Card Interrupt Case bit : Command download over */
|
||||
#define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2)
|
||||
/* Card Interrupt Case bit : Host event */
|
||||
#define IF_SPI_CIC_HOST_EVENT (1<<3)
|
||||
/* Card Interrupt Case bit : Command upload over */
|
||||
#define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4)
|
||||
/* Card Interrupt Case bit : Power down */
|
||||
#define IF_SPI_CIC_POWER_DOWN (1<<5)
|
||||
|
||||
/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
|
||||
#define IF_SPI_CIS_TX_DOWNLOAD_OVER (1<<0)
|
||||
#define IF_SPI_CIS_RX_UPLOAD_OVER (1<<1)
|
||||
#define IF_SPI_CIS_CMD_DOWNLOAD_OVER (1<<2)
|
||||
#define IF_SPI_CIS_HOST_EVENT (1<<3)
|
||||
#define IF_SPI_CIS_CMD_UPLOAD_OVER (1<<4)
|
||||
#define IF_SPI_CIS_POWER_DOWN (1<<5)
|
||||
|
||||
/***************** IF_SPI_HOST_INT_CAUSE_REG *****************/
|
||||
#define IF_SPI_HICU_TX_DOWNLOAD_RDY (1<<0)
|
||||
#define IF_SPI_HICU_RX_UPLOAD_RDY (1<<1)
|
||||
#define IF_SPI_HICU_CMD_DOWNLOAD_RDY (1<<2)
|
||||
#define IF_SPI_HICU_CARD_EVENT (1<<3)
|
||||
#define IF_SPI_HICU_CMD_UPLOAD_RDY (1<<4)
|
||||
#define IF_SPI_HICU_IO_WR_FIFO_OVERFLOW (1<<5)
|
||||
#define IF_SPI_HICU_IO_RD_FIFO_UNDERFLOW (1<<6)
|
||||
#define IF_SPI_HICU_DATA_WR_FIFO_OVERFLOW (1<<7)
|
||||
#define IF_SPI_HICU_DATA_RD_FIFO_UNDERFLOW (1<<8)
|
||||
#define IF_SPI_HICU_CMD_WR_FIFO_OVERFLOW (1<<9)
|
||||
#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10)
|
||||
|
||||
/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
|
||||
/* Host Interrupt Status bit : Tx download ready */
|
||||
#define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0)
|
||||
/* Host Interrupt Status bit : Rx upload ready */
|
||||
#define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1)
|
||||
/* Host Interrupt Status bit : Command download ready */
|
||||
#define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2)
|
||||
/* Host Interrupt Status bit : Card event */
|
||||
#define IF_SPI_HIST_CARD_EVENT (1<<3)
|
||||
/* Host Interrupt Status bit : Command upload ready */
|
||||
#define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4)
|
||||
/* Host Interrupt Status bit : I/O write FIFO overflow */
|
||||
#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5)
|
||||
/* Host Interrupt Status bit : I/O read FIFO underflow */
|
||||
#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6)
|
||||
/* Host Interrupt Status bit : Data write FIFO overflow */
|
||||
#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7)
|
||||
/* Host Interrupt Status bit : Data read FIFO underflow */
|
||||
#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8)
|
||||
/* Host Interrupt Status bit : Command write FIFO overflow */
|
||||
#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9)
|
||||
/* Host Interrupt Status bit : Command read FIFO underflow */
|
||||
#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10)
|
||||
|
||||
/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
|
||||
/* Host Interrupt Status Mask bit : Tx download ready */
|
||||
#define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0)
|
||||
/* Host Interrupt Status Mask bit : Rx upload ready */
|
||||
#define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1)
|
||||
/* Host Interrupt Status Mask bit : Command download ready */
|
||||
#define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2)
|
||||
/* Host Interrupt Status Mask bit : Card event */
|
||||
#define IF_SPI_HISM_CARDEVENT (1<<3)
|
||||
/* Host Interrupt Status Mask bit : Command upload ready */
|
||||
#define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4)
|
||||
/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
|
||||
#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5)
|
||||
/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
|
||||
#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6)
|
||||
/* Host Interrupt Status Mask bit : Data write FIFO overflow */
|
||||
#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7)
|
||||
/* Host Interrupt Status Mask bit : Data write FIFO underflow */
|
||||
#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8)
|
||||
/* Host Interrupt Status Mask bit : Command write FIFO overflow */
|
||||
#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9)
|
||||
/* Host Interrupt Status Mask bit : Command write FIFO underflow */
|
||||
#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10)
|
||||
|
||||
/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
|
||||
/* SCK edge on which the WLAN module outputs data on MISO */
|
||||
#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_FALLING 0x8
|
||||
#define IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING 0x0
|
||||
|
||||
/* In a SPU read operation, there is a delay between writing the SPU
|
||||
* register name and getting back data from the WLAN module.
|
||||
* This can be specified in terms of nanoseconds or in terms of dummy
|
||||
* clock cycles which the master must output before receiving a response. */
|
||||
#define IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK 0x4
|
||||
#define IF_SPI_BUS_MODE_DELAY_METHOD_TIMED 0x0
|
||||
|
||||
/* Some different modes of SPI operation */
|
||||
#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_16_BIT_DATA 0x00
|
||||
#define IF_SPI_BUS_MODE_8_BIT_ADDRESS_32_BIT_DATA 0x01
|
||||
#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA 0x02
|
||||
#define IF_SPI_BUS_MODE_16_BIT_ADDRESS_32_BIT_DATA 0x03
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 by Tomasz Moń
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef LIBERTAS_IF_SPI_DRV
|
||||
#define LIBERTAS_IF_SPI_DRV
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void libertas_spi_init(void);
|
||||
void libertas_spi_reset(int high);
|
||||
void libertas_spi_pd(int high);
|
||||
void libertas_spi_cs(int high);
|
||||
void libertas_spi_tx(const uint8_t *buf, int len);
|
||||
void libertas_spi_rx(uint8_t *buf, int len);
|
||||
|
||||
#endif
|
|
@ -135,6 +135,12 @@
|
|||
/* Define this if you have a software controlled poweroff */
|
||||
#define HAVE_SW_POWEROFF
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#define HAVE_WIFI
|
||||
/* define this if the target has Marvell 88W8686 interfaced over SPI */
|
||||
#define HAVE_W8686_SPI
|
||||
#endif
|
||||
|
||||
/* The number of bytes reserved for loadable codecs */
|
||||
#define CODEC_SIZE 0x100000
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 by Tomasz Moń
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef WIFI_H
|
||||
#define WIFI_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void wifi_init(void) INIT_ATTR;
|
||||
|
||||
#endif
|
|
@ -75,7 +75,7 @@
|
|||
#define CMD_WHEEL_EN 0xD0
|
||||
#define CMD_SET_INTCHRG 0xD1
|
||||
#define CMD_GET_INTCHRG 0xD2
|
||||
#define CMD_UNKNOWN_D3 0xD3
|
||||
#define CMD_WIFI_PD 0xD3
|
||||
#define CMD_UNKNOWN_D4 0xD4
|
||||
#define CMD_UNKNOWN_D5 0xD5
|
||||
#define CMD_UNKNOWN_D6 0xD6
|
||||
|
@ -315,7 +315,7 @@ static size_t avr_command_data_size(uint8_t opcode)
|
|||
case CMD_WHEEL_EN: return 1;
|
||||
case CMD_SET_INTCHRG: return 1;
|
||||
case CMD_GET_INTCHRG: return 1;
|
||||
case CMD_UNKNOWN_D3: return 1;
|
||||
case CMD_WIFI_PD: return 1;
|
||||
case CMD_UNKNOWN_D4: return 1;
|
||||
case CMD_UNKNOWN_D5: return 2;
|
||||
case CMD_UNKNOWN_D6: return 2;
|
||||
|
@ -536,6 +536,12 @@ void avr_hid_enable_charger(void)
|
|||
avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable));
|
||||
}
|
||||
|
||||
void avr_hid_wifi_pd(int high)
|
||||
{
|
||||
uint8_t state = high ? 0x01 : 0x00;
|
||||
avr_execute_command(CMD_WIFI_PD, &state, sizeof(state));
|
||||
}
|
||||
|
||||
static void avr_hid_lcm_power(uint8_t parameter)
|
||||
{
|
||||
avr_execute_command(CMD_LCM_POWER, ¶meter, sizeof(parameter));
|
||||
|
|
|
@ -28,6 +28,8 @@ void avr_hid_init(void);
|
|||
|
||||
void avr_hid_enable_charger(void);
|
||||
|
||||
void avr_hid_wifi_pd(int high);
|
||||
|
||||
void avr_hid_lcm_sleep(void);
|
||||
void avr_hid_lcm_wake(void);
|
||||
void avr_hid_lcm_power_on(void);
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 by Tomasz Moń
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "kernel.h"
|
||||
#include "system.h"
|
||||
#include "spi.h"
|
||||
#include "avr-sansaconnect.h"
|
||||
#include "libertas/if_spi_drv.h"
|
||||
|
||||
#define IO_SERIAL0_XMIT (0x100)
|
||||
|
||||
void libertas_spi_init(void)
|
||||
{
|
||||
IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */);
|
||||
libertas_spi_reset(1);
|
||||
libertas_spi_cs(1);
|
||||
|
||||
/* Enable the clock */
|
||||
bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
|
||||
/* Disable transmitter */
|
||||
IO_SERIAL0_TX_ENABLE = 0x0001;
|
||||
|
||||
/* SELSDEN = 0, SLVEN = 0, SIOCLR = 0, SCLKM = 1, MSB = 1, MSSEL = 0,
|
||||
* RATE = 2 -> 15MHz
|
||||
*/
|
||||
IO_SERIAL0_MODE = 0x0601;
|
||||
|
||||
/* Disable the clock */
|
||||
bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
|
||||
/* Make sure the SPI clock is not inverted */
|
||||
bitclr16(&IO_CLK_INV, CLK_INV_SIF0);
|
||||
}
|
||||
|
||||
void libertas_spi_reset(int high)
|
||||
{
|
||||
if (high)
|
||||
{
|
||||
IO_GIO_BITSET0 = (1 << 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
IO_GIO_BITCLR0 = (1 << 3);
|
||||
}
|
||||
}
|
||||
|
||||
void libertas_spi_pd(int high)
|
||||
{
|
||||
avr_hid_wifi_pd(high);
|
||||
}
|
||||
|
||||
void libertas_spi_cs(int high)
|
||||
{
|
||||
if (high)
|
||||
{
|
||||
IO_GIO_BITSET0 = (1 << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
IO_GIO_BITCLR0 = (1 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
void libertas_spi_tx(const uint8_t *buf, int len)
|
||||
{
|
||||
/* Enable the clock */
|
||||
bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
IO_SERIAL0_TX_ENABLE = 0x0001;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
IO_SERIAL0_TX_DATA = *(buf + 1);
|
||||
while (IO_SERIAL0_RX_DATA & IO_SERIAL0_XMIT) {};
|
||||
IO_SERIAL0_TX_DATA = *buf;
|
||||
while (IO_SERIAL0_RX_DATA & IO_SERIAL0_XMIT) {};
|
||||
|
||||
buf += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
IO_SERIAL0_TX_ENABLE = 0x0000;
|
||||
|
||||
/* Disable the clock */
|
||||
bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
}
|
||||
|
||||
void libertas_spi_rx(uint8_t *buf, int len)
|
||||
{
|
||||
/* Enable the clock */
|
||||
bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
IO_SERIAL0_TX_ENABLE = 0x0001;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
uint16_t data;
|
||||
IO_SERIAL0_TX_DATA = 0;
|
||||
while ((data = IO_SERIAL0_RX_DATA) & IO_SERIAL0_XMIT) {};
|
||||
*(buf + 1) = data & 0xFF;
|
||||
IO_SERIAL0_TX_DATA = 0;
|
||||
while ((data = IO_SERIAL0_RX_DATA) & IO_SERIAL0_XMIT) {};
|
||||
*buf = data & 0xFF;
|
||||
|
||||
buf += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
IO_SERIAL0_TX_ENABLE = 0x0000;
|
||||
|
||||
/* Disable the clock */
|
||||
bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF0);
|
||||
}
|
|
@ -369,9 +369,11 @@ void system_init(void)
|
|||
#endif
|
||||
|
||||
#ifdef SANSA_CONNECT
|
||||
#ifndef HAVE_WIFI
|
||||
/* keep WIFI CS and reset high to save power */
|
||||
IO_GIO_DIR0 &= ~((1 << 4) /* CS */ | (1 << 3) /* reset */);
|
||||
IO_GIO_BITSET0 = (1 << 4) | (1 << 3);
|
||||
#endif
|
||||
|
||||
i2c_init();
|
||||
avr_hid_init();
|
||||
|
|
|
@ -387,6 +387,11 @@ sub buildzip {
|
|||
open(NOMEDIA, ">$temp_dir/.nomedia") || die "can't open .nomedia";
|
||||
close(NOMEDIA);
|
||||
}
|
||||
# copy wifi firmware
|
||||
if ($modelname =~ /sansaconnect/) {
|
||||
glob_mkdir("$temp_dir/libertas");
|
||||
glob_copy("$ROOT/firmware/drivers/libertas/firmware/*", "$temp_dir/libertas/");
|
||||
}
|
||||
|
||||
glob_mkdir("$temp_dir/langs");
|
||||
glob_mkdir("$temp_dir/rocks");
|
||||
|
|
Loading…
Reference in New Issue