photon: add sdpcm + thread support for wlan
This commit is contained in:
parent
e5c4a28c3a
commit
11d3db5c35
@ -186,8 +186,7 @@
|
||||
|
||||
/* Big DTIMER setting */
|
||||
|
||||
// #define SDIO_DTIMER_DATATIMEOUT (0x000fffff)
|
||||
#define SDIO_DTIMER_DATATIMEOUT (0xffffffff)
|
||||
#define SDIO_DTIMER_DATATIMEOUT (0x000fffff)
|
||||
|
||||
/* DMA channel/stream configuration register settings. The following
|
||||
* must be selected. The DMA driver will select the remaining fields.
|
||||
|
@ -43,6 +43,7 @@ ifeq ($(CONFIG_DRIVERS_IEEE80211),y)
|
||||
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO),y)
|
||||
CSRCS += bcmf_sdio.c
|
||||
CSRCS += bcmf_core.c
|
||||
CSRCS += bcmf_sdpcm.c
|
||||
CSRCS += mmc_sdio.c
|
||||
endif
|
||||
|
||||
|
@ -61,94 +61,10 @@
|
||||
/* Chipcommon registers */
|
||||
#define CHIPCOMMON_GPIO_CONTROL ((uint32_t) (CHIPCOMMON_BASE_ADDRESS + 0x6C) )
|
||||
|
||||
/******************************************************
|
||||
* SDIO Constants
|
||||
******************************************************/
|
||||
/* CurrentSdiodProgGuide r23 */
|
||||
|
||||
/* Base registers */
|
||||
#define SDIO_CORE ((uint32_t) (SDIO_BASE_ADDRESS + 0x00) )
|
||||
#define SDIO_INT_STATUS ((uint32_t) (SDIO_BASE_ADDRESS + 0x20) )
|
||||
#define SDIO_TO_SB_MAILBOX ((uint32_t) (SDIO_BASE_ADDRESS + 0x40) )
|
||||
#define SDIO_TO_SB_MAILBOX_DATA ((uint32_t) (SDIO_BASE_ADDRESS + 0x48) )
|
||||
#define SDIO_TO_HOST_MAILBOX_DATA ((uint32_t) (SDIO_BASE_ADDRESS + 0x4C) )
|
||||
#define SDIO_TO_SB_MAIL_BOX ((uint32_t) (SDIO_BASE_ADDRESS + 0x40) )
|
||||
#define SDIO_INT_HOST_MASK ((uint32_t) (SDIO_BASE_ADDRESS + 0x24) )
|
||||
#define SDIO_FUNCTION_INT_MASK ((uint32_t) (SDIO_BASE_ADDRESS + 0x34) )
|
||||
|
||||
/* SDIO Function 0 (SDIO Bus) register addresses */
|
||||
|
||||
/* SDIO Device CCCR offsets */
|
||||
/* TODO: What does CIS/CCCR stand for? */
|
||||
/* CCCR accesses do not require backpane clock */
|
||||
#define SDIOD_CCCR_UHS_I ( (uint32_t) 0x14 ) /* UHS-I Support */
|
||||
#define SDIOD_CCCR_DRIVE ( (uint32_t) 0x15 ) /* Drive Strength */
|
||||
#define SDIOD_CCCR_INTEXT ( (uint32_t) 0x16 ) /* Interrupt Extension */
|
||||
#define SDIOD_SEP_INT_CTL ( (uint32_t) 0xF2 ) /* Separate Interrupt Control*/
|
||||
#define SDIOD_CCCR_F1INFO ( (uint32_t) 0x100 ) /* Function 1 (Backplane) Info */
|
||||
#define SDIOD_CCCR_F1HP ( (uint32_t) 0x102 ) /* Function 1 (Backplane) High Power */
|
||||
#define SDIOD_CCCR_F1CISPTR_0 ( (uint32_t) 0x109 ) /* Function 1 (Backplane) CIS Base Address Pointer Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F1CISPTR_1 ( (uint32_t) 0x10A ) /* Function 1 (Backplane) CIS Base Address Pointer Register 1 */
|
||||
#define SDIOD_CCCR_F1CISPTR_2 ( (uint32_t) 0x10B ) /* Function 1 (Backplane) CIS Base Address Pointer Register 2 (MSB - only bit 1 valid) */
|
||||
#define SDIOD_CCCR_F1BLKSIZE_0 ( (uint32_t) 0x110 ) /* Function 1 (Backplane) SDIO Block Size Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F1BLKSIZE_1 ( (uint32_t) 0x111 ) /* Function 1 (Backplane) SDIO Block Size Register 1 (MSB) */
|
||||
#define SDIOD_CCCR_F2INFO ( (uint32_t) 0x200 ) /* Function 2 (WLAN Data FIFO) Info */
|
||||
#define SDIOD_CCCR_F2HP ( (uint32_t) 0x202 ) /* Function 2 (WLAN Data FIFO) High Power */
|
||||
#define SDIOD_CCCR_F2CISPTR_0 ( (uint32_t) 0x209 ) /* Function 2 (WLAN Data FIFO) CIS Base Address Pointer Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F2CISPTR_1 ( (uint32_t) 0x20A ) /* Function 2 (WLAN Data FIFO) CIS Base Address Pointer Register 1 */
|
||||
#define SDIOD_CCCR_F2CISPTR_2 ( (uint32_t) 0x20B ) /* Function 2 (WLAN Data FIFO) CIS Base Address Pointer Register 2 (MSB - only bit 1 valid) */
|
||||
#define SDIOD_CCCR_F2BLKSIZE_0 ( (uint32_t) 0x210 ) /* Function 2 (WLAN Data FIFO) SDIO Block Size Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F2BLKSIZE_1 ( (uint32_t) 0x211 ) /* Function 2 (WLAN Data FIFO) SDIO Block Size Register 1 (MSB) */
|
||||
#define SDIOD_CCCR_F3INFO ( (uint32_t) 0x300 ) /* Function 3 (Bluetooth Data FIFO) Info */
|
||||
#define SDIOD_CCCR_F3HP ( (uint32_t) 0x302 ) /* Function 3 (Bluetooth Data FIFO) High Power */
|
||||
#define SDIOD_CCCR_F3CISPTR_0 ( (uint32_t) 0x309 ) /* Function 3 (Bluetooth Data FIFO) CIS Base Address Pointer Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F3CISPTR_1 ( (uint32_t) 0x30A ) /* Function 3 (Bluetooth Data FIFO) CIS Base Address Pointer Register 1 */
|
||||
#define SDIOD_CCCR_F3CISPTR_2 ( (uint32_t) 0x30B ) /* Function 3 (Bluetooth Data FIFO) CIS Base Address Pointer Register 2 (MSB - only bit 1 valid) */
|
||||
#define SDIOD_CCCR_F3BLKSIZE_0 ( (uint32_t) 0x310 ) /* Function 3 (Bluetooth Data FIFO) SDIO Block Size Register 0 (LSB) */
|
||||
#define SDIOD_CCCR_F3BLKSIZE_1 ( (uint32_t) 0x311 ) /* Function 3 (Bluetooth Data FIFO) SDIO Block Size Register 1 (MSB) */
|
||||
|
||||
|
||||
/* SDIO Function 1 (Backplane) register addresses */
|
||||
/* Addresses 0x00000000 - 0x0000FFFF are directly access the backplane
|
||||
* throught the backplane window. Addresses above 0x0000FFFF are
|
||||
* registers relating to backplane access, and do not require a backpane
|
||||
* clock to access them
|
||||
*/
|
||||
#define SDIO_GPIO_SELECT ( (uint32_t) 0x10005 )
|
||||
#define SDIO_GPIO_OUTPUT ( (uint32_t) 0x10006 )
|
||||
#define SDIO_GPIO_ENABLE ( (uint32_t) 0x10007 )
|
||||
#define SDIO_FUNCTION2_WATERMARK ( (uint32_t) 0x10008 )
|
||||
#define SDIO_DEVICE_CONTROL ( (uint32_t) 0x10009 )
|
||||
#define SDIO_BACKPLANE_ADDRESS_LOW ( (uint32_t) 0x1000A )
|
||||
#define SDIO_BACKPLANE_ADDRESS_MID ( (uint32_t) 0x1000B )
|
||||
#define SDIO_BACKPLANE_ADDRESS_HIGH ( (uint32_t) 0x1000C )
|
||||
#define SDIO_FRAME_CONTROL ( (uint32_t) 0x1000D )
|
||||
#define SDIO_CHIP_CLOCK_CSR ( (uint32_t) 0x1000E )
|
||||
#define SDIO_PULL_UP ( (uint32_t) 0x1000F )
|
||||
#define SDIO_READ_FRAME_BC_LOW ( (uint32_t) 0x1001B )
|
||||
#define SDIO_READ_FRAME_BC_HIGH ( (uint32_t) 0x1001C )
|
||||
|
||||
#define I_HMB_SW_MASK ( (uint32_t) 0x000000F0 )
|
||||
#define I_HMB_FRAME_IND ( 1<<6 )
|
||||
#define FRAME_AVAILABLE_MASK I_HMB_SW_MASK
|
||||
|
||||
/******************************************************
|
||||
* Bit Masks
|
||||
******************************************************/
|
||||
|
||||
/* SDIO_FRAME_CONTROL Bits */
|
||||
#define SFC_RF_TERM ( (uint32_t) (1 << 0) ) /* Read Frame Terminate */
|
||||
#define SFC_WF_TERM ( (uint32_t) (1 << 1) ) /* Write Frame Terminate */
|
||||
#define SFC_CRC4WOOS ( (uint32_t) (1 << 2) ) /* HW reports CRC error for write out of sync */
|
||||
#define SFC_ABORTALL ( (uint32_t) (1 << 3) ) /* Abort cancels all in-progress frames */
|
||||
|
||||
/* SDIO_TO_SB_MAIL_BOX bits corresponding to intstatus bits */
|
||||
#define SMB_NAK ( (uint32_t) (1 << 0) ) /* To SB Mailbox Frame NAK */
|
||||
#define SMB_INT_ACK ( (uint32_t) (1 << 1) ) /* To SB Mailbox Host Interrupt ACK */
|
||||
#define SMB_USE_OOB ( (uint32_t) (1 << 2) ) /* To SB Mailbox Use OOB Wakeup */
|
||||
#define SMB_DEV_INT ( (uint32_t) (1 << 3) ) /* To SB Mailbox Miscellaneous Interrupt */
|
||||
|
||||
|
||||
#define WL_CHANSPEC_BAND_MASK (0xf000)
|
||||
#define WL_CHANSPEC_BAND_5G (0x1000)
|
||||
#define WL_CHANSPEC_BAND_2G (0x2000)
|
||||
|
@ -36,6 +36,7 @@
|
||||
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H
|
||||
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <nuttx/sdio.h>
|
||||
|
||||
/* This structure contains the unique state of the Broadcom FullMAC driver */
|
||||
@ -49,6 +50,17 @@ struct bcmf_dev_s
|
||||
|
||||
uint32_t (*get_core_base_address)(unsigned int core); /* Get chip specific
|
||||
base address for evey cores */
|
||||
|
||||
sem_t sem; /* Semaphore for processing thread event */
|
||||
struct wdog_s *waitdog; /* Processing thread waitdog */
|
||||
bool ready; /* Current device status */
|
||||
bool sleeping; /* Current sleep status */
|
||||
volatile bool irq_pending; /* True if interrupt is pending */
|
||||
uint32_t intstatus; /* Copy of device current interrupt status */
|
||||
|
||||
uint8_t max_seq; /* Maximum transmit sequence allowed */
|
||||
uint8_t tx_seq; /* Transmit sequence number (next) */
|
||||
uint8_t rx_seq; /* Receive sequence number (expected) */
|
||||
};
|
||||
|
||||
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H */
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/sdio.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/kthread.h>
|
||||
|
||||
#include <nuttx/wireless/ieee80211/mmc_sdio.h>
|
||||
#include <nuttx/wireless/ieee80211/bcmf_sdio.h>
|
||||
@ -56,6 +57,7 @@
|
||||
|
||||
#include "bcmf_sdio.h"
|
||||
#include "bcmf_core.h"
|
||||
#include "bcmf_sdpcm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -65,6 +67,11 @@
|
||||
#define BCMF_DEVICE_START_DELAY_MS 10
|
||||
#define BCMF_CLOCK_SETUP_DELAY_MS 500
|
||||
|
||||
#define BCMF_THREAD_NAME "bcmf"
|
||||
#define BCMF_THREAD_STACK_SIZE 2048
|
||||
|
||||
#define BCMF_WAITDOG_TIMEOUT_TICK (5*CLOCKS_PER_SEC)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
@ -80,6 +87,16 @@ static int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv);
|
||||
|
||||
static int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg);
|
||||
|
||||
static int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep);
|
||||
|
||||
static void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...);
|
||||
static int bcmf_sdio_thread(int argc, char **argv);
|
||||
|
||||
static int bcmf_sdio_find_block_size(unsigned int size);
|
||||
|
||||
/* FIXME remove */
|
||||
FAR struct bcmf_dev_s *g_sdio_priv;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -90,7 +107,79 @@ static int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg);
|
||||
|
||||
int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
/* TODO */
|
||||
FAR struct bcmf_dev_s *priv = (struct bcmf_dev_s*)arg;
|
||||
|
||||
if (priv->ready)
|
||||
{
|
||||
/* Signal bmcf thread */
|
||||
priv->irq_pending = true;
|
||||
|
||||
sem_post(&priv->sem);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep)
|
||||
{
|
||||
int ret;
|
||||
int loops;
|
||||
uint8_t value;
|
||||
|
||||
_info("request %s currently %s\n",
|
||||
(sleep ? "SLEEP" : "WAKE"),
|
||||
(priv->sleeping ? "SLEEP" : "WAKE"));
|
||||
|
||||
if (priv->sleeping == sleep)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (sleep)
|
||||
{
|
||||
priv->sleeping = true;
|
||||
return bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Request HT Avail */
|
||||
|
||||
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
SBSDIO_HT_AVAIL_REQ | SBSDIO_FORCE_HT);
|
||||
if (ret != OK)
|
||||
{
|
||||
_err("HT Avail request failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for High Troughput clock */
|
||||
|
||||
loops = 20;
|
||||
while (--loops > 0)
|
||||
{
|
||||
up_mdelay(1);
|
||||
ret = bcmf_read_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value & SBSDIO_HT_AVAIL)
|
||||
{
|
||||
/* High Throughput clock is ready */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (loops <= 0)
|
||||
{
|
||||
_err("HT clock not ready\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
priv->sleeping = false;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -101,7 +190,6 @@ int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg)
|
||||
int bcmf_probe(FAR struct bcmf_dev_s *priv)
|
||||
{
|
||||
int ret;
|
||||
uint8_t value;
|
||||
|
||||
/* Probe sdio card compatible device */
|
||||
|
||||
@ -248,6 +336,13 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Configure gpio interrupt pin */
|
||||
|
||||
bcmf_board_setup_oob_irq(priv->minor, bcmf_oob_irq, (void*)priv);
|
||||
@ -274,32 +369,12 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
_info("wait high throughput clock\n");
|
||||
/* Wake up chip to be sure function 2 is running */
|
||||
|
||||
/* Wait for High Troughput clock to be sure function 2 is running */
|
||||
|
||||
loops = 10;
|
||||
while (--loops > 0)
|
||||
ret = bcmf_sdio_bus_sleep(priv, false);
|
||||
if (ret != OK)
|
||||
{
|
||||
up_mdelay(10);
|
||||
ret = bcmf_read_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (value & SBSDIO_HT_AVAIL)
|
||||
{
|
||||
/* High Throughput clock is ready */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (loops <= 0)
|
||||
{
|
||||
_err("HT clock not ready\n");
|
||||
return -ETIMEDOUT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* FN2 successfully enabled, set core and enable interrupts */
|
||||
@ -361,6 +436,22 @@ void bcmf_hwuninitialize(FAR struct bcmf_dev_s *priv)
|
||||
bcmf_board_reset(priv->minor, true);
|
||||
}
|
||||
|
||||
int bcmf_sdio_find_block_size(unsigned int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int size_copy = size;
|
||||
while (size_copy) {
|
||||
size_copy >>= 1;
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (size & (size-1))
|
||||
{
|
||||
return 1<<ret;
|
||||
}
|
||||
return 1<<(ret-1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -373,8 +464,16 @@ int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
|
||||
uint8_t function, uint32_t address,
|
||||
uint8_t *buf, unsigned int len)
|
||||
{
|
||||
unsigned int blocklen;
|
||||
unsigned int nblocks;
|
||||
|
||||
/* Use rw_io_direct method if len is 1 */
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len == 1)
|
||||
{
|
||||
if (write)
|
||||
@ -386,32 +485,25 @@ int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
|
||||
function, address, 0, buf);
|
||||
}
|
||||
|
||||
/* Find best block size / count values for transfer */
|
||||
/* Find best block settings for transfer */
|
||||
|
||||
unsigned int blocklen;
|
||||
unsigned int nblocks;
|
||||
if (len >= 64)
|
||||
{
|
||||
/* Use block mode */
|
||||
|
||||
if (len == 64 || len > 0 && len % 64 == 0)
|
||||
{
|
||||
blocklen = 64;
|
||||
nblocks = len / 64;
|
||||
}
|
||||
else if (len > 20)
|
||||
{
|
||||
// FIXME
|
||||
blocklen = 64;
|
||||
nblocks = (len+63) / 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
blocklen = len;
|
||||
/* Use byte mode */
|
||||
|
||||
blocklen = bcmf_sdio_find_block_size(len);
|
||||
nblocks = 0;
|
||||
}
|
||||
// _info("try extended %d %d %d\n", len, blocklen, nblocks);
|
||||
|
||||
return sdio_io_rw_extended(priv->sdio_dev, write,
|
||||
function, address, true, buf, blocklen, nblocks);
|
||||
|
||||
// return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -460,6 +552,24 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->sdio_dev = dev;
|
||||
priv->minor = minor;
|
||||
priv->ready = false;
|
||||
priv->sleeping = true;
|
||||
|
||||
if ((ret = sem_init(&priv->sem, 0, 0)) != OK)
|
||||
{
|
||||
goto exit_free_priv;
|
||||
}
|
||||
if ((ret = sem_setprotocol(&priv->sem, SEM_PRIO_NONE)) != OK)
|
||||
{
|
||||
goto exit_free_priv;
|
||||
}
|
||||
|
||||
priv->waitdog = wd_create();
|
||||
if (!priv->waitdog)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto exit_free_priv;
|
||||
}
|
||||
|
||||
/* Initialize device hardware */
|
||||
|
||||
@ -467,7 +577,7 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
goto exit_free_priv;
|
||||
goto exit_free_waitdog;
|
||||
}
|
||||
|
||||
/* Probe device */
|
||||
@ -488,10 +598,37 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
goto exit_uninit_hw;
|
||||
}
|
||||
|
||||
/* FIXME wait for the chip to be ready to receive commands */
|
||||
|
||||
up_mdelay(100);
|
||||
|
||||
priv->ready = true;
|
||||
|
||||
ret = bcmf_bus_setup_interrupts(priv);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto exit_uninit_hw;
|
||||
}
|
||||
|
||||
/* FIXME global variable for now */
|
||||
g_sdio_priv = priv;
|
||||
|
||||
/* Start the waitdog timer */
|
||||
|
||||
wd_start(priv->waitdog, BCMF_WAITDOG_TIMEOUT_TICK, bcmf_sdio_waitdog_timeout, 0);
|
||||
|
||||
/* Spawn bcmf daemon thread */
|
||||
|
||||
ret = kernel_thread(BCMF_THREAD_NAME, SCHED_PRIORITY_MAX,
|
||||
BCMF_THREAD_STACK_SIZE, bcmf_sdio_thread,
|
||||
(FAR char * const *)NULL);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
_err("Cannot spawn bcmf thread\n");
|
||||
ret = -EBADE;
|
||||
goto exit_uninit_hw;
|
||||
}
|
||||
|
||||
/* Device is up and running
|
||||
TODO Create a wlan device name and register network driver here */
|
||||
|
||||
@ -499,9 +636,11 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
|
||||
exit_uninit_hw:
|
||||
bcmf_hwuninitialize(priv);
|
||||
|
||||
exit_free_waitdog:
|
||||
// TODO
|
||||
exit_free_priv:
|
||||
kmm_free(priv);
|
||||
priv->ready = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -530,3 +669,90 @@ int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv)
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...)
|
||||
{
|
||||
FAR struct bcmf_dev_s *priv = g_sdio_priv;
|
||||
|
||||
/* Notify bcmf thread */
|
||||
sem_post(&priv->sem);
|
||||
}
|
||||
|
||||
int bcmf_sdio_thread(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
FAR struct bcmf_dev_s *priv = g_sdio_priv;
|
||||
|
||||
_info("Enter\n");
|
||||
|
||||
/* FIXME wait for the chip to be ready to receive commands */
|
||||
|
||||
up_mdelay(50);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Wait for event (device interrupt, user request or waitdog timer) */
|
||||
|
||||
ret = sem_wait(&priv->sem);
|
||||
if (ret != OK)
|
||||
{
|
||||
_err("Error while waiting for semaphore\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restart the waitdog timer */
|
||||
|
||||
wd_start(priv->waitdog, BCMF_WAITDOG_TIMEOUT_TICK,
|
||||
bcmf_sdio_waitdog_timeout, 0);
|
||||
|
||||
/* Wake up device */
|
||||
|
||||
bcmf_sdio_bus_sleep(priv, false);
|
||||
|
||||
if (priv->irq_pending)
|
||||
{
|
||||
/* Woken up by interrupt, read device status */
|
||||
|
||||
priv->irq_pending = false;
|
||||
|
||||
_info("process irq\n");
|
||||
|
||||
bcmf_read_sbregw(priv,
|
||||
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
|
||||
intstatus), &priv->intstatus);
|
||||
|
||||
/* Clear interrupts */
|
||||
|
||||
bcmf_write_sbregw(priv,
|
||||
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
|
||||
intstatus), priv->intstatus);
|
||||
_info("intstatus %x\n", priv->intstatus);
|
||||
}
|
||||
|
||||
/* On frame indication, read available frames */
|
||||
|
||||
if (priv->intstatus & I_HMB_FRAME_IND)
|
||||
{
|
||||
_info("Frames available\n");
|
||||
|
||||
do
|
||||
{
|
||||
ret = bcmf_sdpcm_readframe(priv);
|
||||
} while (ret == OK);
|
||||
|
||||
if (ret == -ENODATA)
|
||||
{
|
||||
/* All frames processed */
|
||||
_info("All frames processed\n");
|
||||
priv->intstatus &= ~I_HMB_FRAME_IND;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO send all queued frames
|
||||
|
||||
/* If we're done for now, turn off clock request. */
|
||||
|
||||
bcmf_sdio_bus_sleep(priv, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -8,6 +8,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* FIXME: Low level bus data transfer function
|
||||
* To avoid bus error, len will be aligned to:
|
||||
* - upper power of 2 iflen is lesser than 64
|
||||
* - upper 64 bytes block if len is greater than 64
|
||||
*/
|
||||
|
||||
int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
|
||||
uint8_t function, uint32_t address,
|
||||
uint8_t *buf, unsigned int len);
|
||||
|
@ -59,6 +59,7 @@
|
||||
#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */
|
||||
|
||||
#define I_HMB_SW_MASK ( (uint32_t) 0x000000F0 )
|
||||
#define I_HMB_FRAME_IND ( 1<<6 )
|
||||
|
||||
enum {
|
||||
CHIPCOMMON_CORE_ID,
|
||||
|
217
drivers/wireless/ieee80211/bcmf_sdpcm.c
Normal file
217
drivers/wireless/ieee80211/bcmf_sdpcm.c
Normal file
@ -0,0 +1,217 @@
|
||||
/****************************************************************************
|
||||
* drivers/wireless/ieee80211/bcmf_sdpcm.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Simon Piriou <spiriou31@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form 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.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "bcmf_sdio.h"
|
||||
#include "bcmf_core.h"
|
||||
#include "bcmf_sdpcm.h"
|
||||
|
||||
/* SDA_FRAMECTRL */
|
||||
#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
|
||||
#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
|
||||
#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
|
||||
#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
|
||||
|
||||
/* tosbmailbox bits corresponding to intstatus bits */
|
||||
#define SMB_NAK (1 << 0) /* Frame NAK */
|
||||
#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
|
||||
#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
|
||||
#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int bcmf_sdpcm_rxfail(FAR struct bcmf_dev_s *priv, bool retry);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
int bcmf_sdpcm_rxfail(FAR struct bcmf_dev_s *priv, bool retry)
|
||||
{
|
||||
/* issue abort command for F2 through F0 */
|
||||
|
||||
bcmf_write_reg(priv, 0, SDIO_CCCR_IOABORT, 2);
|
||||
|
||||
bcmf_write_reg(priv, 1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM);
|
||||
|
||||
/* TODO Wait until the packet has been flushed (device/FIFO stable) */
|
||||
|
||||
/* Send NAK to retry to read frame */
|
||||
if (retry)
|
||||
{
|
||||
bcmf_write_sbregb(priv,
|
||||
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
|
||||
tosbmailbox), SMB_NAK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
|
||||
struct bcmf_sdpcm_header *header)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
len = header->frametag[0];
|
||||
|
||||
if (header->data_offset < sizeof(struct bcmf_sdpcm_header) ||
|
||||
header->data_offset > len)
|
||||
{
|
||||
_err("Invalid data offset\n");
|
||||
bcmf_sdpcm_rxfail(priv, false);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Update tx credits */
|
||||
|
||||
_info("update credit %x %x %x\n", header->credit,
|
||||
priv->tx_seq, priv->max_seq);
|
||||
|
||||
if (header->credit - priv->tx_seq > 0x40)
|
||||
{
|
||||
_err("seq %d: max tx seq number error\n", priv->tx_seq);
|
||||
priv->max_seq = priv->tx_seq + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->max_seq = header->credit;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// FIXME remove
|
||||
uint8_t tmp_buffer[512];
|
||||
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
||||
{
|
||||
int ret;
|
||||
uint16_t len, checksum;
|
||||
struct bcmf_sdpcm_header *header = (struct bcmf_sdpcm_header*)tmp_buffer;
|
||||
|
||||
/* Read header */
|
||||
|
||||
ret = bcmf_transfer_bytes(priv, false, 2, 0, (uint8_t*)header, 4);
|
||||
if (ret != OK)
|
||||
{
|
||||
_info("failread size\n");
|
||||
ret = -EIO;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
len = header->frametag[0];
|
||||
checksum = header->frametag[1];
|
||||
|
||||
/* All zero means no more to read */
|
||||
|
||||
if (!(len | checksum))
|
||||
{
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (((~len & 0xffff) ^ checksum) || len < sizeof(struct bcmf_sdpcm_header))
|
||||
{
|
||||
_err("Invalid header checksum or len %x %x\n", len, checksum);
|
||||
ret = -EIO;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
// FIXME define for size
|
||||
if (len > 512)
|
||||
{
|
||||
_err("Frame is too large, cancel %d\n", len);
|
||||
ret = -ENOMEM;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
/* Read remaining frame data */
|
||||
|
||||
ret = bcmf_transfer_bytes(priv, false, 2, 0, (uint8_t*)header+4, len - 4);
|
||||
if (ret != OK)
|
||||
{
|
||||
ret = -EIO;
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
/* Process and validate header */
|
||||
|
||||
ret = bcmf_sdpcm_process_header(priv, header);
|
||||
if (ret != OK)
|
||||
{
|
||||
_err("Error while processing header %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
exit_abort:
|
||||
bcmf_sdpcm_rxfail(priv, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcmf_sdpcm_iovar_data_get(FAR struct bcmf_dev_s *priv, char *name,
|
||||
void *data, unsigned int len)
|
||||
{
|
||||
// TODO implement
|
||||
return -EINVAL;
|
||||
}
|
35
drivers/wireless/ieee80211/bcmf_sdpcm.h
Normal file
35
drivers/wireless/ieee80211/bcmf_sdpcm.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H
|
||||
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H
|
||||
|
||||
#include "bcmf_driver.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct bcmf_sdpcm_header {
|
||||
uint16_t frametag[2];
|
||||
uint8_t sequence;
|
||||
uint8_t channel_flags;
|
||||
uint8_t next_length;
|
||||
uint8_t data_offset;
|
||||
uint8_t flow_control;
|
||||
uint8_t credit;
|
||||
uint16_t padding;
|
||||
};
|
||||
|
||||
struct bcmf_sdpcm_cdc_dcmd {
|
||||
struct bcmf_sdpcm_header header;
|
||||
uint32_t cmd; /* dongle command value */
|
||||
uint32_t len; /* lower 16: output buflen;
|
||||
* upper 16: input buflen (excludes header) */
|
||||
uint32_t flags; /* flag defns given below */
|
||||
uint32_t status; /* status code returned from the device */
|
||||
};
|
||||
|
||||
int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
|
||||
struct bcmf_sdpcm_header *header);
|
||||
|
||||
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv);
|
||||
|
||||
int bcmf_sdpcm_iovar_data_get(FAR struct bcmf_dev_s *priv, char *name,
|
||||
void *data, unsigned int len);
|
||||
|
||||
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H */
|
Loading…
Reference in New Issue
Block a user