photon: add sdpcm + thread support for wlan

This commit is contained in:
Simon Piriou 2017-04-13 20:31:39 +02:00
parent e5c4a28c3a
commit 11d3db5c35
9 changed files with 543 additions and 130 deletions

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View 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;
}

View 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 */