Merge remote-tracking branch 'origin/master' into ieee802154

This commit is contained in:
Gregory Nutt
2017-05-04 07:11:19 -06:00
121 changed files with 39623 additions and 212 deletions
+6
View File
@@ -141,3 +141,9 @@ config DAC_AD5410
select SPI
endif # DAC
config OPAMP
bool "Operational Amplifier"
default n
---help---
Select to enable support for Operational Amplifiers (OPAMPs).
+17
View File
@@ -60,6 +60,16 @@ CSRCS += comp.c
endif
# Check for OPAMP devices
ifeq ($(CONFIG_OPAMP),y)
# Include the common OPAMP character driver
CSRCS += opamp.c
endif
# Check for ADC devices
ifeq ($(CONFIG_ADC),y)
@@ -105,6 +115,13 @@ ifeq ($(CONFIG_COMP),y)
DEPPATH += --dep-path analog
VPATH += :analog
CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog}
else
ifeq ($(CONFIG_OPAMP),y)
DEPPATH += --dep-path analog
VPATH += :analog
CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog}
endif
endif
endif
endif
+243
View File
@@ -0,0 +1,243 @@
/****************************************************************************
* drivers/analog/opamp.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Mateusz Szafoni <raiden00@railab.me>
*
* 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 <sys/types.h>
#include <stdint.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/analog/opamp.h>
#include <nuttx/irq.h>
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int opamp_open(FAR struct file *filep);
static int opamp_close(FAR struct file *filep);
static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations opamp_fops =
{
opamp_open, /* open */
opamp_close, /* close */
NULL, /* read */
NULL, /* write */
NULL, /* seek */
opamp_ioctl /* ioctl */
#ifndef CONFIG_DISABLE_POLL
, NULL /* poll */
#endif
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
, NULL /* unlink */
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: opamp_open
*
* Description:
* This function is called whenever the OPAMP device is opened.
*
****************************************************************************/
static int opamp_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct opamp_dev_s *dev = inode->i_private;
uint8_t tmp;
int ret = OK;
/* If the port is the middle of closing, wait until the close is finished */
if (sem_wait(&dev->ad_closesem) != OK)
{
ret = -errno;
}
else
{
/* Increment the count of references to the device. If this the first
* time that the driver has been opened for this device, then initialize
* the device.
*/
tmp = dev->ad_ocount + 1;
if (tmp == 0)
{
/* More than 255 opens; uint8_t overflows to zero */
ret = -EMFILE;
}
else
{
/* Check if this is the first time that the driver has been opened. */
if (tmp == 1)
{
/* Yes.. perform one time hardware initialization. */
irqstate_t flags = enter_critical_section();
ret = dev->ad_ops->ao_setup(dev);
if (ret == OK)
{
/* Save the new open count on success */
dev->ad_ocount = tmp;
}
leave_critical_section(flags);
}
}
sem_post(&dev->ad_closesem);
}
return ret;
}
/****************************************************************************
* Name: opamp_close
*
* Description:
* This routine is called when the OPAMP device is closed.
* It waits for the last remaining data to be sent.
*
****************************************************************************/
static int opamp_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct opamp_dev_s *dev = inode->i_private;
irqstate_t flags;
int ret = OK;
if (sem_wait(&dev->ad_closesem) != OK)
{
ret = -errno;
}
else
{
/* Decrement the references to the driver. If the reference count will
* decrement to 0, then uninitialize the driver.
*/
if (dev->ad_ocount > 1)
{
dev->ad_ocount--;
sem_post(&dev->ad_closesem);
}
else
{
/* There are no more references to the port */
dev->ad_ocount = 0;
/* Free the IRQ and disable the OPAMP device */
flags = enter_critical_section(); /* Disable interrupts */
dev->ad_ops->ao_shutdown(dev); /* Disable the OPAMP */
leave_critical_section(flags);
sem_post(&dev->ad_closesem);
}
}
return ret;
}
/****************************************************************************
* Name: opamp_ioctl
****************************************************************************/
static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR struct opamp_dev_s *dev = inode->i_private;
int ret;
ret = dev->ad_ops->ao_ioctl(dev, cmd, arg);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: opamp_register
****************************************************************************/
int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev)
{
int ret;
/* Initialize the OPAMP device structure */
dev->ad_ocount = 0;
/* Initialize semaphores */
sem_init(&dev->ad_closesem, 0, 1);
/* Register the OPAMP character driver */
ret = register_driver(path, &opamp_fops, 0444, dev);
if (ret < 0)
{
sem_destroy(&dev->ad_closesem);
}
return ret;
}
+34
View File
@@ -8,6 +8,11 @@ if DRIVERS_IEEE80211
config IEEE80211_BROADCOM_FULLMAC
bool
config IEEE80211_BROADCOM_BCM43362
bool "Broadcom 43362 chip support"
depends on IEEE80211_BROADCOM_FULLMAC
default n
config IEEE80211_BROADCOM_FULLMAC_SDIO
bool "Broadcom FullMAC driver on SDIO bus"
depends on ARCH_HAVE_SDIO
@@ -17,4 +22,33 @@ config IEEE80211_BROADCOM_FULLMAC_SDIO
This selection enables support for broadcom
FullMAC-compliant devices using SDIO bus.
if IEEE80211_BROADCOM_FULLMAC
choice
prompt "Broadcom FullMAC driver work queue"
default IEEE80211_BROADCOM_LPWORK if SCHED_LPWORK
default IEEE80211_BROADCOM_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
depends on SCHED_WORKQUEUE
---help---
Work queue support is required to use the loopback driver. If the
low priority work queue is available, then it should be used by the
loopback driver.
config IEEE80211_BROADCOM_HPWORK
bool "High priority"
depends on SCHED_HPWORK
config IEEE80211_BROADCOM_LPWORK
bool "Low priority"
depends on SCHED_LPWORK
endchoice # Work queue
config IEEE80211_BROADCOM_NINTERFACES
int "Number of Broadcom FullMAC interfaces"
default 1
depends on EXPERIMENTAL
endif # IEEE80211_BROADCOM_FULLMAC
endif # DRIVERS_IEEE80211
+16
View File
@@ -40,10 +40,26 @@ ifeq ($(CONFIG_DRIVERS_IEEE80211),y)
# Include IEEE 802.11 drivers into the build
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC),y)
CSRCS += bcmf_driver.c
CSRCS += bcmf_cdc.c
CSRCS += bcmf_bdc.c
CSRCS += bcmf_utils.c
CSRCS += bcmf_netdev.c
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO),y)
CSRCS += mmc_sdio.c
CSRCS += bcmf_sdio.c
CSRCS += bcmf_core.c
CSRCS += bcmf_sdpcm.c
endif
ifeq ($(CONFIG_IEEE80211_BROADCOM_BCM43362),y)
CSRCS += bcmf_chip_43362.c
endif
endif # CONFIG_IEEE80211_BROADCOM_FULLMAC
# Include IEEE 802.11 build support
DEPPATH += --dep-path wireless$(DELIM)ieee80211
+277
View File
@@ -0,0 +1,277 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_bdc.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 <string.h>
#include <net/ethernet.h>
#include "bcmf_driver.h"
#include "bcmf_ioctl.h"
#include "bcmf_cdc.h"
#include "bcmf_bdc.h"
#include "bcmf_utils.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define BCMF_EVENT_ETHER_TYPE 0x6C88 /* Ether type of event frames */
/****************************************************************************
* Private Types
****************************************************************************/
struct __attribute__((packed)) bcmf_bdc_header
{
uint8_t flags; /* bdc frame flags */
uint8_t priority; /* bdc frame priority */
uint8_t flags2; /* bdc frame additionnal flags */
uint8_t data_offset; /* Offset from end of header to payload data */
};
struct __attribute__((packed)) bcmf_eth_header
{
uint16_t type; /* Vendor specific type */
uint16_t len; /* Event data length */
uint8_t version; /* Protocol version */
uint8_t oui[3]; /* Organizationally unique identifier */
uint16_t usr_type; /* User specific type */
};
struct __attribute__((packed)) bcmf_event_msg
{
struct ether_header eth;
struct bcmf_eth_header bcm_eth;
struct bcmf_event_s event;
uint8_t data[0];
};
/****************************************************************************
* Private Data
****************************************************************************/
static const uint8_t bcmf_broadcom_oui[] = {0x00, 0x10, 0x18};
/****************************************************************************
* Public Functions
****************************************************************************/
struct bcmf_frame_s *bcmf_bdc_allocate_frame(FAR struct bcmf_dev_s *priv,
uint32_t len, bool block)
{
struct bcmf_frame_s *frame;
/* Allocate data frame */
// TODO check for integer overflow
frame = priv->bus->allocate_frame(priv,
sizeof(struct bcmf_bdc_header) + len, block, false);
if (!frame)
{
return NULL;
}
frame->data += sizeof(struct bcmf_bdc_header);
return frame;
}
int bcmf_bdc_process_event_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
int data_size;
struct bcmf_bdc_header *header;
struct bcmf_event_msg *event_msg;
uint32_t event_id;
event_handler_t handler;
/* Check frame header */
data_size = frame->len - (int)(frame->data - frame->base);
if (data_size < sizeof(struct bcmf_bdc_header))
{
goto exit_invalid_frame;
}
header = (struct bcmf_bdc_header *)frame->data;
data_size -= sizeof(struct bcmf_bdc_header) + header->data_offset;
if (data_size < sizeof(struct bcmf_event_msg))
{
goto exit_invalid_frame;
}
data_size -= sizeof(struct ether_header) + sizeof(struct bcmf_eth_header);
/* Check ethernet header */
event_msg = (struct bcmf_event_msg *)(frame->data +
sizeof(struct bcmf_bdc_header) +
header->data_offset);
if (event_msg->eth.ether_type != BCMF_EVENT_ETHER_TYPE ||
memcmp(event_msg->bcm_eth.oui, bcmf_broadcom_oui, 3))
{
goto exit_invalid_frame;
}
event_id = bcmf_getle32(&event_msg->event.type);
if (event_id >= BCMF_EVENT_COUNT)
{
wlinfo("Invalid event id %d\n", event_id);
return -EINVAL;
}
/* Dispatch event to registered handler */
handler = priv->event_handlers[event_id];
if (handler != NULL)
{
handler(priv, &event_msg->event, data_size);
}
return OK;
exit_invalid_frame:
wlerr("Invalid event frame\n");
bcmf_hexdump(frame->base, frame->len, (unsigned long)frame->base);
return -EINVAL;
}
int bcmf_event_register(FAR struct bcmf_dev_s *priv, event_handler_t handler,
unsigned int event_id)
{
if (event_id >= BCMF_EVENT_COUNT)
{
/* Invalid event id */
return -EINVAL;
}
priv->event_handlers[event_id] = handler;
return OK;
}
int bcmf_event_unregister(FAR struct bcmf_dev_s *priv,
unsigned int event_id)
{
return bcmf_event_register(priv, NULL, event_id);
}
int bcmf_event_push_config(FAR struct bcmf_dev_s *priv)
{
int i;
uint32_t out_len;
uint8_t event_mask[(BCMF_EVENT_COUNT + 7) >> 3];
memset(event_mask, 0, sizeof(event_mask));
for (i = 0; i < BCMF_EVENT_COUNT; i++)
{
if (priv->event_handlers[i] != NULL)
{
event_mask[i >> 3] |= 1 << (i & 0x7);
}
}
/* Send event mask to chip */
out_len = sizeof(event_mask);
if (bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_EVENT_MSGS, event_mask,
&out_len))
{
return -EIO;
}
return OK;
}
int bcmf_bdc_transmit_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
struct bcmf_bdc_header *header;
/* Set frame data for lower layer */
frame->data -= sizeof(struct bcmf_bdc_header);
header = (struct bcmf_bdc_header *)frame->data;
/* Setup data frame header */
header->flags = 0x20; /* Set bdc protocol version */
header->priority = 0; // TODO handle priority
header->flags2 = CHIP_STA_INTERFACE;
header->data_offset = 0;
/* Send frame */
return priv->bus->txframe(priv, frame, false);
}
struct bcmf_frame_s *bcmf_bdc_rx_frame(FAR struct bcmf_dev_s *priv)
{
unsigned int frame_len;
struct bcmf_frame_s *frame = priv->bus->rxframe(priv);
/* Process bdc header */
frame_len = frame->len - (unsigned int)(frame->data - frame->base);
if (frame_len < sizeof(struct bcmf_bdc_header))
{
wlerr("Data frame too small\n");
priv->bus->free_frame(priv, frame);
return NULL;
}
/* Transmit frame to upper layer */
frame->data += sizeof(struct bcmf_bdc_header);
return frame;
}
+96
View File
@@ -0,0 +1,96 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_bdc.h
*
* 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
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H
#include "bcmf_driver.h"
/* Event frame content */
struct __attribute__((packed)) bcmf_event_s
{
uint16_t version; /* Vendor specific type */
uint16_t flags;
uint32_t type; /* Id of received event */
uint32_t status; /* Event status code */
uint32_t reason; /* Reason code */
uint32_t auth_type;
uint32_t len; /* Data size following this header */
struct ether_addr addr; /* AP MAC address */
char src_name[16]; /* Event source interface name */
uint8_t dst_id; /* Event destination interface id */
uint8_t bss_cfg_id;
};
/* Event callback handler */
typedef void (*event_handler_t)(FAR struct bcmf_dev_s *priv,
struct bcmf_event_s *event, unsigned int len);
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Function called from lower layer */
int bcmf_bdc_process_event_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
/* Function called from upper layer */
struct bcmf_frame_s *bcmf_bdc_allocate_frame(FAR struct bcmf_dev_s *priv,
uint32_t len, bool block);
int bcmf_bdc_transmit_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
struct bcmf_frame_s *bcmf_bdc_rx_frame(FAR struct bcmf_dev_s *priv);
/* Event frames API */
int bcmf_event_register(FAR struct bcmf_dev_s *priv, event_handler_t handler,
unsigned int event_id);
int bcmf_event_unregister(FAR struct bcmf_dev_s *priv,
unsigned int event_id);
int bcmf_event_push_config(FAR struct bcmf_dev_s *priv);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H */
+330
View File
@@ -0,0 +1,330 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_cdc.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 <string.h>
#include <semaphore.h>
#include "bcmf_driver.h"
#include "bcmf_ioctl.h"
#include "bcmf_utils.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Control header flags */
#define BCMF_CONTROL_ERROR 0x01 /* Command failure flag */
#define BCMF_CONTROL_SET 0x02 /* Command type: SET = 1, GET = 0 */
#define BCMF_CONTROL_INTERFACE_SHIFT 12
#define BCMF_CONTROL_REQID_SHIFT 16
#define BCMF_CONTROL_TIMEOUT_MS 1000
/****************************************************************************
* Private Types
****************************************************************************/
struct __attribute__((packed)) bcmf_cdc_header {
uint32_t cmd; /* Command to be sent */
uint32_t len; /* Size of command data */
uint32_t flags; /* cdc request flags, see above */
uint32_t status; /* Returned status code from chip */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static struct bcmf_frame_s *bcmf_cdc_allocate_frame(
FAR struct bcmf_dev_s *priv, char *name,
uint8_t *data, uint32_t len);
static int bcmf_cdc_sendframe(FAR struct bcmf_dev_s *priv, uint32_t cmd,
int ifidx, bool set, struct bcmf_frame_s *frame);
static int bcmf_cdc_control_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len);
static int bcmf_cdc_control_request_unsafe(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len);
/****************************************************************************
* Private Functions
****************************************************************************/
struct bcmf_frame_s *bcmf_cdc_allocate_frame(FAR struct bcmf_dev_s *priv,
char *name, uint8_t *data,
uint32_t len)
{
uint32_t data_len;
uint16_t name_len;
struct bcmf_frame_s *frame;
if (name)
{
name_len = strlen(name) + 1;
}
else
{
name_len = 0;
}
if (data)
{
data_len = len;
}
else
{
data_len = 0;
}
/* Allocate control frame */
frame = priv->bus->allocate_frame(priv,
sizeof(struct bcmf_cdc_header) + data_len + name_len,
true, true);
if (!frame)
{
return NULL;
}
/* Copy name string and data */
memcpy(frame->data + sizeof(struct bcmf_cdc_header), name, name_len);
memcpy(frame->data + sizeof(struct bcmf_cdc_header)
+ name_len, data, data_len);
return frame;
}
int bcmf_cdc_sendframe(FAR struct bcmf_dev_s *priv, uint32_t cmd,
int ifidx, bool set, struct bcmf_frame_s *frame)
{
struct bcmf_cdc_header *header =
(struct bcmf_cdc_header *)frame->data;
/* Setup control frame header */
uint32_t cdc_data_len = frame->len - (uint32_t)(frame->data-frame->base);
header->cmd = cmd;
header->len = cdc_data_len-sizeof(struct bcmf_cdc_header);
header->status = 0;
header->flags = ++priv->control_reqid << BCMF_CONTROL_REQID_SHIFT;
header->flags |= ifidx << BCMF_CONTROL_INTERFACE_SHIFT;
if (set)
{
header->flags |= BCMF_CONTROL_SET;
}
/* Send frame */
return priv->bus->txframe(priv, frame, true);
}
int bcmf_cdc_control_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len)
{
int ret;
/* Take device control mutex */
if ((ret = sem_wait(&priv->control_mutex)) != OK)
{
return ret;
}
ret = bcmf_cdc_control_request_unsafe(priv, ifidx, set, cmd,
name, data, len);
sem_post(&priv->control_mutex);
return ret;
}
int bcmf_cdc_control_request_unsafe(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len)
{
int ret;
struct bcmf_frame_s *frame;
uint32_t out_len = *len;
*len = 0;
/* Prepare control frame */
frame = bcmf_cdc_allocate_frame(priv, name, data, out_len);
if (!frame)
{
wlerr("Cannot allocate cdc frame\n");
return -ENOMEM;
}
/* Setup buffer to store response */
priv->control_rxdata = set ? NULL : data;
priv->control_rxdata_len = out_len;
/* Send control frame. iovar buffer is freed when sent */
ret = bcmf_cdc_sendframe(priv, cmd, ifidx, set, frame);
if (ret != OK)
{
/* Free allocated iovar buffer */
priv->bus->free_frame(priv, frame);
return ret;
}
ret = bcmf_sem_wait(&priv->control_timeout, BCMF_CONTROL_TIMEOUT_MS);
if (ret != OK)
{
wlerr("Error while waiting for control response %d\n", ret);
return ret;
}
*len = priv->control_rxdata_len;
/* Check frame status */
if (priv->control_status != 0)
{
wlerr("Invalid cdc status 0x%x\n", priv->control_status);
return -EINVAL;
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int bcmf_cdc_iovar_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, char *name,
uint8_t *data, uint32_t *len)
{
return bcmf_cdc_control_request(priv, ifidx, set,
set ? WLC_SET_VAR : WLC_GET_VAR, name,
data, len);
}
int bcmf_cdc_iovar_request_unsafe(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, char *name,
uint8_t *data, uint32_t *len)
{
return bcmf_cdc_control_request_unsafe(priv, ifidx, set,
set ? WLC_SET_VAR : WLC_GET_VAR, name,
data, len);
}
int bcmf_cdc_ioctl(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
uint8_t *data, uint32_t *len)
{
return bcmf_cdc_control_request(priv, ifidx, set, cmd, NULL, data, len);
}
int bcmf_cdc_process_control_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
unsigned int data_size;
struct bcmf_cdc_header *cdc_header;
/* Check frame */
data_size = frame->len - (unsigned int)(frame->data - frame->base);
if (data_size < sizeof(struct bcmf_cdc_header))
{
wlerr("Control frame too small\n");
return -EINVAL;
}
cdc_header = (struct bcmf_cdc_header *)frame->data;
if (data_size < cdc_header->len ||
data_size < sizeof(struct bcmf_cdc_header) + cdc_header->len)
{
wlerr("Invalid control frame size\n");
return -EINVAL;
}
// TODO check interface ?
if (cdc_header->flags >> BCMF_CONTROL_REQID_SHIFT == priv->control_reqid)
{
/* Expected frame received, send it back to user */
priv->control_status = cdc_header->status;
if (priv->control_rxdata)
{
if (priv->control_rxdata_len > cdc_header->len)
{
wlerr("Not enough data %d %d\n",
priv->control_rxdata_len, cdc_header->len);
priv->control_rxdata_len = cdc_header->len;
}
memcpy(priv->control_rxdata, (uint8_t *)&cdc_header[1],
priv->control_rxdata_len);
}
sem_post(&priv->control_timeout);
return OK;
}
wlinfo("Got unexpected control frame\n");
return -EINVAL;
}
+69
View File
@@ -0,0 +1,69 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_cdc.h
*
* 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
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H
#include "bcmf_driver.h"
#include <stdbool.h>
#include <stdint.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Send safe cdc request */
int bcmf_cdc_iovar_request(FAR struct bcmf_dev_s *priv, uint32_t ifidx,
bool set, char *name, uint8_t *data, uint32_t *len);
int bcmf_cdc_ioctl(FAR struct bcmf_dev_s *priv, uint32_t ifidx, bool set,
uint32_t cmd, uint8_t *data, uint32_t *len);
/* Send cdc request without locking control_mutex */
int bcmf_cdc_iovar_request_unsafe(FAR struct bcmf_dev_s *priv, uint32_t ifidx,
bool set, char *name, uint8_t *data, uint32_t *len);
/* Callback used by bus layer to notify cdc response frame is available */
int bcmf_cdc_process_control_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H */
@@ -0,0 +1,76 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_chip_43362.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.
*
****************************************************************************/
#include "bcmf_sdio.h"
#include <stdint.h>
#define WRAPPER_REGISTER_OFFSET 0x100000
extern const char bcm43362_nvram_image[];
extern const unsigned int bcm43362_nvram_image_len;
extern const uint8_t bcm43362_firmware_image[];
extern const unsigned int bcm43362_firmware_image_len;
const struct bcmf_sdio_chip bcmf_43362_config_sdio =
{
/* General chip stats */
.ram_size = 0x3C000,
/* Backplane architecture */
.core_base =
{
[CHIPCOMMON_CORE_ID] = 0x18000000, /* Chipcommon core register base */
[DOT11MAC_CORE_ID] = 0x18001000, /* dot11mac core register base */
[SDIOD_CORE_ID] = 0x18002000, /* SDIOD Device core register base */
[WLAN_ARMCM3_CORE_ID] = 0x18003000 + /* ARMCM3 core register base */
WRAPPER_REGISTER_OFFSET,
[SOCSRAM_CORE_ID] = 0x18004000 + /* SOCSRAM core register base */
WRAPPER_REGISTER_OFFSET
},
/* Firmware images */
// TODO find something smarter than using image_len references
.firmware_image = (uint8_t *)bcm43362_firmware_image,
.firmware_image_size = (unsigned int *)&bcm43362_firmware_image_len,
.nvram_image = (uint8_t *)bcm43362_nvram_image,
.nvram_image_size = (unsigned int *)&bcm43362_nvram_image_len
};
+401
View File
@@ -0,0 +1,401 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_core.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 "bcmf_core.h"
#include "bcmf_sdio.h"
#include "bcmf_sdio_regs.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Agent registers (common for every core) */
#define BCMA_IOCTL 0x0408 /* IO control */
#define BCMA_IOST 0x0500 /* IO status */
#define BCMA_RESET_CTL 0x0800 /* Reset control */
#define BCMA_RESET_ST 0x0804
#define BCMA_IOCTL_CLK 0x0001
#define BCMA_IOCTL_FGC 0x0002
#define BCMA_IOCTL_CORE_BITS 0x3FFC
#define BCMA_IOCTL_PME_EN 0x4000
#define BCMA_IOCTL_BIST_EN 0x8000
#define BCMA_IOST_CORE_BITS 0x0FFF
#define BCMA_IOST_DMA64 0x1000
#define BCMA_IOST_GATED_CLK 0x2000
#define BCMA_IOST_BIST_ERROR 0x4000
#define BCMA_IOST_BIST_DONE 0x8000
#define BCMA_RESET_CTL_RESET 0x0001
/* Transfer size properties */
#define BCMF_UPLOAD_TRANSFER_SIZE (64 * 256)
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int bcmf_core_set_backplane_window(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address);
static int bcmf_upload_binary(FAR struct bcmf_sdio_dev_s *sbusv,
uint32_t address, uint8_t *buf,
unsigned int len);
static int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus);
/****************************************************************************
* Private Functions
****************************************************************************/
int bcmf_core_set_backplane_window(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address)
{
int ret;
int i;
address &= ~SBSDIO_SB_OFT_ADDR_MASK;
for (i = 1; i < 4; i++)
{
uint8_t addr_part = (address >> (8*i)) & 0xff;
uint8_t cur_addr_part = (sbus->backplane_current_addr >> (8*i)) & 0xff;
if (addr_part != cur_addr_part)
{
/* Update current backplane base address */
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_SBADDRLOW+i-1,
addr_part);
if (ret != OK)
{
return ret;
}
sbus->backplane_current_addr &= ~(0xff << (8*i));
sbus->backplane_current_addr |= addr_part << (8*i);
}
}
return OK;
}
int bcmf_upload_binary(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *buf, unsigned int len)
{
unsigned int size;
while (len > 0)
{
/* Set the backplane window to include the start address */
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
}
if (len > BCMF_UPLOAD_TRANSFER_SIZE)
{
size = BCMF_UPLOAD_TRANSFER_SIZE;
}
else
{
size = len;
}
/* Transfer firmware data */
ret = bcmf_transfer_bytes(sbus, true, 1,
address & SBSDIO_SB_OFT_ADDR_MASK, buf, size);
if (ret != OK)
{
wlerr("transfer failed %d %x %d\n", ret, address, size);
return ret;
}
len -= size;
address += size;
buf += size;
}
return OK;
}
int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
uint32_t nvram_sz;
uint32_t token;
/* Round up the size of the image */
nvram_sz = (*sbus->chip->nvram_image_size + 63) & (-64);
wlinfo("nvram size is %d %d bytes\n", nvram_sz,
*sbus->chip->nvram_image_size);
/* Write image */
ret = bcmf_upload_binary(sbus, sbus->chip->ram_size - 4 - nvram_sz,
sbus->chip->nvram_image,
*sbus->chip->nvram_image_size);
if (ret != OK)
{
return ret;
}
/* Generate length token */
token = nvram_sz / 4;
token = (~token << 16) | (token & 0x0000FFFF);
/* Write the length token to the last word */
ret = bcmf_write_sbreg(sbus, sbus->chip->ram_size - 4, (uint8_t *)&token, 4);
if (ret != OK)
{
return ret;
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: bcmf_read_sbreg
****************************************************************************/
int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len)
{
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
}
return bcmf_transfer_bytes(sbus, false, 1,
address & SBSDIO_SB_OFT_ADDR_MASK, reg, len);
}
/****************************************************************************
* Name: bcmf_write_sbreg
****************************************************************************/
int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len)
{
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
}
return bcmf_transfer_bytes(sbus, true, 1, address & SBSDIO_SB_OFT_ADDR_MASK,
reg, len);
}
/****************************************************************************
* Name: bcmf_core_upload_firmware
****************************************************************************/
int bcmf_core_upload_firmware(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
wlinfo("upload firmware\n");
/* Disable ARMCM3 core and reset SOCRAM core
* to set device in firmware upload mode */
bcmf_core_disable(sbus, WLAN_ARMCM3_CORE_ID);
bcmf_core_reset(sbus, SOCSRAM_CORE_ID);
up_mdelay(50);
/* Flash chip firmware */
wlinfo("firmware size is %d bytes\n", *sbus->chip->firmware_image_size);
ret = bcmf_upload_binary(sbus, 0, sbus->chip->firmware_image,
*sbus->chip->firmware_image_size);
if (ret != OK)
{
wlerr("Failed to upload firmware\n");
return ret;
}
/* Flash NVRAM configuration file */
wlinfo("upload nvram configuration\n");
ret = bcmf_upload_nvram(sbus);
if (ret != OK)
{
wlerr("Failed to upload nvram\n");
return ret;
}
/* Firmware upload done, restart ARMCM3 core */
up_mdelay(10);
bcmf_core_reset(sbus, WLAN_ARMCM3_CORE_ID);
/* Check ARMCM3 core is running */
up_mdelay(10);
if (!bcmf_core_isup(sbus, WLAN_ARMCM3_CORE_ID))
{
wlerr("Cannot start ARMCM3 core\n");
return -ETIMEDOUT;
}
return OK;
}
bool bcmf_core_isup(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint32_t value = 0;
if (core >= MAX_CORE_ID)
{
wlerr("Invalid core id %d\n", core);
return false;
}
uint32_t base = sbus->chip->core_base[core];
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
if ((value & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) != BCMA_IOCTL_CLK)
{
return false;
}
bcmf_read_sbregw(sbus, base + BCMA_RESET_CTL, &value);
return (value & BCMA_RESET_CTL_RESET) == 0;
}
void bcmf_core_disable(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint8_t value;
if (core >= MAX_CORE_ID)
{
wlerr("Invalid core id %d\n", core);
return;
}
uint32_t base = sbus->chip->core_base[core];
/* Check if core is already in reset state */
bcmf_read_sbregb(sbus, base + BCMA_RESET_CTL, &value);
if ((value & BCMA_RESET_CTL_RESET) != 0)
{
/* Core already disabled */
return;
}
/* Ensure no backplane operation is pending */
up_mdelay(10);
/* Set core in reset state */
bcmf_write_sbregb(sbus, base + BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
up_udelay(1);
/* Write 0 to the IO control and read it back */
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, 0);
bcmf_read_sbregb(sbus, base + BCMA_IOCTL, &value);
up_udelay(10);
}
void bcmf_core_reset(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint32_t value;
if (core >= MAX_CORE_ID)
{
wlerr("Invalid core id %d\n", core);
return;
}
uint32_t base = sbus->chip->core_base[core];
/* Put core in reset state */
bcmf_core_disable(sbus, core);
/* Run initialization sequence */
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
bcmf_write_sbregb(sbus, base + BCMA_RESET_CTL, 0);
bcmf_read_sbregw(sbus, base + BCMA_RESET_CTL, &value);
up_udelay(1);
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, BCMA_IOCTL_CLK);
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
up_udelay(1);
}
+82
View File
@@ -0,0 +1,82 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_core.h
*
* 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.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_CORE_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_CORE_H
#include <stdint.h>
#include <stdbool.h>
#include "bcmf_sdio.h"
int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len);
int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len);
bool bcmf_core_isup(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
void bcmf_core_disable(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
void bcmf_core_reset(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
int bcmf_core_upload_firmware(FAR struct bcmf_sdio_dev_s *sbus);
static inline int bcmf_read_sbregb(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint8_t *reg)
{
return bcmf_read_sbreg(sbus, address, reg, 1);
}
static inline int bcmf_read_sbregw(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint32_t *reg)
{
return bcmf_read_sbreg(sbus, address, (uint8_t *)reg, 4);
}
static inline int bcmf_write_sbregb(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint8_t reg)
{
return bcmf_write_sbreg(sbus, address, &reg, 1);
}
static inline int bcmf_write_sbregw(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint32_t reg)
{
return bcmf_write_sbreg(sbus, address, (uint8_t *)&reg, 4);
}
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_CORE_H */
File diff suppressed because it is too large Load Diff
+153
View File
@@ -0,0 +1,153 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_driver.h
*
* 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.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H
#include <stdbool.h>
#include <stdint.h>
#include <semaphore.h>
#include <nuttx/net/netdev.h>
#include <net/if.h>
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include "bcmf_ioctl.h"
struct bcmf_dev_s;
struct bcmf_frame_s;
#include "bcmf_bdc.h"
struct bcmf_bus_dev_s;
/* Chip interfaces */
#define CHIP_STA_INTERFACE 0
#define CHIP_AP_INTERFACE 1
#define CHIP_P2P_INTERFACE 2
/* This structure contains the unique state of the Broadcom FullMAC driver */
struct bcmf_dev_s
{
FAR struct bcmf_bus_dev_s *bus; /* Bus interface structure */
bool bc_bifup; /* true:ifup false:ifdown */
WDOG_ID bc_txpoll; /* TX poll timer */
struct work_s bc_irqwork; /* For deferring interrupt work to the work queue */
struct work_s bc_pollwork; /* For deferring poll work to the work queue */
/* This holds the information visible to the NuttX network */
struct net_driver_s bc_dev; /* Network interface structure */
struct bcmf_frame_s *cur_tx_frame; /* Frame used to interface network layer */
/* Event registration array */
event_handler_t event_handlers[BCMF_EVENT_COUNT];
// FIXME use mutex instead of semaphore
sem_t control_mutex; /* Cannot handle multiple control requests */
sem_t control_timeout; /* Semaphore to wait for control frame rsp */
uint16_t control_reqid; /* Current control request id */
uint16_t control_rxdata_len; /* Received control frame out buffer length */
uint8_t *control_rxdata; /* Received control frame out buffer */
uint32_t control_status; /* Last received frame status */
/* AP Scan state machine.
* During scan, control_mutex is locked to prevent control requests */
int scan_status; /* Current scan status */
WDOG_ID scan_timeout; /* Scan timeout timer */
sem_t auth_signal; /* Authentication notification signal */
int auth_status; /* Authentication status */
};
/* Default bus interface structure */
struct bcmf_bus_dev_s
{
void (*stop)(FAR struct bcmf_dev_s *priv);
int (*txframe)(FAR struct bcmf_dev_s *priv, struct bcmf_frame_s *frame,
bool control);
struct bcmf_frame_s *(*rxframe)(FAR struct bcmf_dev_s *priv);
/* Frame buffer allocation primitives
* len - requested payload length
* control - true if control frame else false
* block - true to block until free frame is available
*/
struct bcmf_frame_s *(*allocate_frame)(FAR struct bcmf_dev_s *priv,
unsigned int len, bool block,
bool control);
void (*free_frame)(FAR struct bcmf_dev_s *priv, struct bcmf_frame_s *frame);
};
/* bcmf frame definition */
struct bcmf_frame_s
{
uint8_t *base; /* Frame base buffer used by low level layer (SDIO) */
uint8_t *data; /* Payload data (Control, data and event messages) */
uint16_t len; /* Frame buffer size */
};
/* IOCTLs network interface implementation */
int bcmf_wl_set_mac_address(FAR struct bcmf_dev_s *priv, struct ifreq *req);
int bcmf_wl_enable(FAR struct bcmf_dev_s *priv, bool enable);
/* IOCTLs AP scan interface implementation */
int bcmf_wl_start_scan(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_get_scan_results(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
/* IOCTLs authentication interface implementation */
int bcmf_wl_set_auth_param(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_encode_ext(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_mode(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
int bcmf_wl_set_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_netdev.h
*
* 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.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_NETDEV_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_NETDEV_H
#include "bcmf_driver.h"
int bcmf_netdev_register(FAR struct bcmf_dev_s *priv);
void bcmf_netdev_notify_rx(FAR struct bcmf_dev_s *priv);
void bcmf_netdev_notify_tx_done(FAR struct bcmf_dev_s *priv);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_NETDEV_H */
File diff suppressed because it is too large Load Diff
+147
View File
@@ -0,0 +1,147 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_sdio.h
*
* 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
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H
#include "bcmf_driver.h"
#include <stdint.h>
#include <stdbool.h>
#include <queue.h>
#include <semaphore.h>
#include <nuttx/sdio.h>
#include "bcmf_sdio_core.h"
#define HEADER_SIZE 0x12 /* Default sdpcm + bdc header size */
// TODO move to Kconfig
#define BCMF_PKT_POOL_SIZE 4 /* Frame pool size */
/****************************************************************************
* Public Types
****************************************************************************/
/* sdio chip configuration structure */
struct bcmf_sdio_chip
{
uint32_t ram_size;
uint32_t core_base[MAX_CORE_ID];
uint8_t *firmware_image;
unsigned int *firmware_image_size;
uint8_t *nvram_image;
unsigned int *nvram_image_size;
};
/* sdio bus structure extension */
struct bcmf_sdio_dev_s
{
struct bcmf_bus_dev_s bus; /* Default bcmf bus structure */
FAR struct sdio_dev_s *sdio_dev; /* The SDIO device bound to this instance */
int minor; /* Device minor number */
struct bcmf_sdio_chip *chip; /* Chip specific configuration */
volatile bool ready; /* Current device status */
bool sleeping; /* Current sleep status */
int thread_id; /* Processing thread id */
sem_t thread_signal; /* Semaphore for processing thread event */
struct wdog_s *waitdog; /* Processing thread waitdog */
uint32_t backplane_current_addr; /* Current function 1 backplane base addr */
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) */
sem_t queue_mutex; /* Lock for TX/RX/free queues */
dq_queue_t free_queue; /* Queue of available frames */
dq_queue_t tx_queue; /* Queue of frames to tramsmit */
dq_queue_t rx_queue; /* Queue of frames used to receive */
volatile int tx_queue_count; /* Count of items in TX queue */
};
/* Structure used to manage SDIO frames */
struct bcmf_sdio_frame
{
struct bcmf_frame_s header;
bool tx;
dq_entry_t list_entry;
uint8_t data[HEADER_SIZE + MAX_NET_DEV_MTU +
CONFIG_NET_GUARDSIZE];
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
int minor, FAR struct sdio_dev_s *dev);
/* 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_sdio_dev_s *sbus, bool write,
uint8_t function, uint32_t address,
uint8_t *buf, unsigned int len);
int bcmf_read_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t *reg);
int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t reg);
struct bcmf_sdio_frame *bcmf_sdio_allocate_frame(FAR struct bcmf_dev_s *priv,
bool block, bool tx);
void bcmf_sdio_free_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_sdio_frame *sframe);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H */
+226
View File
@@ -0,0 +1,226 @@
/****************************************************************************
* Copyright (c) 2011 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_CORE_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_CORE_H
#include <stdint.h>
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif
/* SDIO device ID */
#define SDIO_DEVICE_ID_BROADCOM_43143 43143
#define SDIO_DEVICE_ID_BROADCOM_43241 0x4324
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334
#define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335
#define SDIO_DEVICE_ID_BROADCOM_43362 43362
/* Core reg address translation.
* Both macro's returns a 32 bits byte address on the backplane bus.
*/
#define CORE_CC_REG(base, field) \
(base + offsetof(struct chipcregs, field))
#define CORE_BUS_REG(base, field) \
(base + offsetof(struct sdpcmd_regs, field))
#define CORE_SB(base, field) \
(base + offsetof(struct sbconfig, field))
#define BRCMF_MAX_CORENUM 6
#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
/* Target state register description */
#define SSB_TMSLOW_RESET 0x00000001 /* Reset */
#define SSB_TMSLOW_REJECT 0x00000002 /* Reject (Standard Backplane) */
#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */
#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */
#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */
#define I_HMB_SW_MASK ( (uint32_t) 0x000000F0 )
#define I_HMB_FRAME_IND ( 1<<6 )
/* 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 */
enum
{
CHIPCOMMON_CORE_ID = 0,
DOT11MAC_CORE_ID,
SDIOD_CORE_ID,
WLAN_ARMCM3_CORE_ID,
SOCSRAM_CORE_ID,
MAX_CORE_ID
};
struct chip_core_info
{
uint16_t id;
uint16_t rev;
uint32_t base;
uint32_t wrapbase;
uint32_t caps;
uint32_t cib;
};
struct sbconfig
{
uint8_t PAD[0xf00];
uint32_t PAD[2];
uint32_t sbipsflag; /* initiator port ocp slave flag */
uint32_t PAD[3];
uint32_t sbtpsflag; /* target port ocp slave flag */
uint32_t PAD[11];
uint32_t sbtmerrloga; /* (sonics >= 2.3) */
uint32_t PAD;
uint32_t sbtmerrlog; /* (sonics >= 2.3) */
uint32_t PAD[3];
uint32_t sbadmatch3; /* address match3 */
uint32_t PAD;
uint32_t sbadmatch2; /* address match2 */
uint32_t PAD;
uint32_t sbadmatch1; /* address match1 */
uint32_t PAD[7];
uint32_t sbimstate; /* initiator agent state */
uint32_t sbintvec; /* interrupt mask */
uint32_t sbtmstatelow; /* target state */
uint32_t sbtmstatehigh; /* target state */
uint32_t sbbwa0; /* bandwidth allocation table0 */
uint32_t PAD;
uint32_t sbimconfiglow; /* initiator configuration */
uint32_t sbimconfighigh; /* initiator configuration */
uint32_t sbadmatch0; /* address match0 */
uint32_t PAD;
uint32_t sbtmconfiglow; /* target configuration */
uint32_t sbtmconfighigh; /* target configuration */
uint32_t sbbconfig; /* broadcast configuration */
uint32_t PAD;
uint32_t sbbstate; /* broadcast state */
uint32_t PAD[3];
uint32_t sbactcnfg; /* activate configuration */
uint32_t PAD[3];
uint32_t sbflagst; /* current sbflags */
uint32_t PAD[3];
uint32_t sbidlow; /* identification */
uint32_t sbidhigh; /* identification */
};
/* sdio core registers */
struct sdpcmd_regs
{
uint32_t corecontrol; /* 0x00, rev8 */
uint32_t corestatus; /* rev8 */
uint32_t PAD[1];
uint32_t biststatus; /* rev8 */
/* PCMCIA access */
uint16_t pcmciamesportaladdr; /* 0x010, rev8 */
uint16_t PAD[1];
uint16_t pcmciamesportalmask; /* rev8 */
uint16_t PAD[1];
uint16_t pcmciawrframebc; /* rev8 */
uint16_t PAD[1];
uint16_t pcmciaunderflowtimer; /* rev8 */
uint16_t PAD[1];
/* interrupt */
uint32_t intstatus; /* 0x020, rev8 */
uint32_t hostintmask; /* rev8 */
uint32_t intmask; /* rev8 */
uint32_t sbintstatus; /* rev8 */
uint32_t sbintmask; /* rev8 */
uint32_t funcintmask; /* rev4 */
uint32_t PAD[2];
uint32_t tosbmailbox; /* 0x040, rev8 */
uint32_t tohostmailbox; /* rev8 */
uint32_t tosbmailboxdata; /* rev8 */
uint32_t tohostmailboxdata; /* rev8 */
/* synchronized access to registers in SDIO clock domain */
uint32_t sdioaccess; /* 0x050, rev8 */
uint32_t PAD[3];
/* PCMCIA frame control */
uint8_t pcmciaframectrl; /* 0x060, rev8 */
uint8_t PAD[3];
uint8_t pcmciawatermark; /* rev8 */
uint8_t PAD[155];
/* interrupt batching control */
uint32_t intrcvlazy; /* 0x100, rev8 */
uint32_t PAD[3];
/* counters */
uint32_t cmd52rd; /* 0x110, rev8 */
uint32_t cmd52wr; /* rev8 */
uint32_t cmd53rd; /* rev8 */
uint32_t cmd53wr; /* rev8 */
uint32_t abort; /* rev8 */
uint32_t datacrcerror; /* rev8 */
uint32_t rdoutofsync; /* rev8 */
uint32_t wroutofsync; /* rev8 */
uint32_t writebusy; /* rev8 */
uint32_t readwait; /* rev8 */
uint32_t readterm; /* rev8 */
uint32_t writeterm; /* rev8 */
uint32_t PAD[40];
uint32_t clockctlstatus; /* rev8 */
uint32_t PAD[7];
uint32_t PAD[128]; /* DMA engines */
/* SDIO/PCMCIA CIS region */
char cis[512]; /* 0x400-0x5ff, rev6 */
/* PCMCIA function control registers */
char pcmciafcr[256]; /* 0x600-6ff, rev6 */
uint16_t PAD[55];
/* PCMCIA backplane access */
uint16_t backplanecsr; /* 0x76E, rev6 */
uint16_t backplaneaddr0; /* rev6 */
uint16_t backplaneaddr1; /* rev6 */
uint16_t backplaneaddr2; /* rev6 */
uint16_t backplaneaddr3; /* rev6 */
uint16_t backplanedata0; /* rev6 */
uint16_t backplanedata1; /* rev6 */
uint16_t backplanedata2; /* rev6 */
uint16_t backplanedata3; /* rev6 */
uint16_t PAD[31];
/* sprom "size" & "blank" info */
uint16_t spromstatus; /* 0x7BE, rev2 */
uint32_t PAD[464];
uint16_t PAD[0x80];
};
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_CORE_H */
+248
View File
@@ -0,0 +1,248 @@
/****************************************************************************
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_REGS_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_REGS_H
#define SDIO_FUNC_0 0
#define SDIO_FUNC_1 1
#define SDIO_FUNC_2 2
#define SDIOD_FBR_SIZE 0x100
/* io_en */
#define SDIO_FUNC_ENABLE_1 0x02
#define SDIO_FUNC_ENABLE_2 0x04
/* io_rdys */
#define SDIO_FUNC_READY_1 0x02
#define SDIO_FUNC_READY_2 0x04
/* intr_status */
#define INTR_STATUS_FUNC1 0x2
#define INTR_STATUS_FUNC2 0x4
/* Maximum number of I/O funcs */
#define SDIOD_MAX_IOFUNCS 7
/* mask of register map */
#define REG_F0_REG_MASK 0x7FF
#define REG_F1_MISC_MASK 0x1FFFF
/* as of sdiod rev 0, supports 3 functions */
#define SBSDIO_NUM_FUNCTION 3
/* function 0 vendor specific CCCR registers */
#define SDIO_CCCR_BRCM_CARDCAP 0xf0
#define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02
#define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04
#define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08
#define SDIO_CCCR_BRCM_CARDCTRL 0xf1
#define SDIO_CCCR_BRCM_CARDCTRL_WLANRESET 0x02
#define SDIO_CCCR_BRCM_SEPINT 0xf2
#define SDIO_SEPINT_MASK 0x01
#define SDIO_SEPINT_OE 0x02
#define SDIO_SEPINT_ACT_HI 0x04
/* function 1 miscellaneous registers */
/* sprom command and status */
#define SBSDIO_SPROM_CS 0x10000
/* sprom info register */
#define SBSDIO_SPROM_INFO 0x10001
/* sprom indirect access data byte 0 */
#define SBSDIO_SPROM_DATA_LOW 0x10002
/* sprom indirect access data byte 1 */
#define SBSDIO_SPROM_DATA_HIGH 0x10003
/* sprom indirect access addr byte 0 */
#define SBSDIO_SPROM_ADDR_LOW 0x10004
/* sprom indirect access addr byte 0 */
#define SBSDIO_SPROM_ADDR_HIGH 0x10005
/* xtal_pu (gpio) output */
#define SBSDIO_CHIP_CTRL_DATA 0x10006
/* xtal_pu (gpio) enable */
#define SBSDIO_CHIP_CTRL_EN 0x10007
/* rev < 7, watermark for sdio device */
#define SBSDIO_WATERMARK 0x10008
/* control busy signal generation */
#define SBSDIO_DEVICE_CTL 0x10009
/* SB Address Window Low (b15) */
#define SBSDIO_FUNC1_SBADDRLOW 0x1000A
/* SB Address Window Mid (b23:b16) */
#define SBSDIO_FUNC1_SBADDRMID 0x1000B
/* SB Address Window High (b31:b24) */
#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C
/* Frame Control (frame term/abort) */
#define SBSDIO_FUNC1_FRAMECTRL 0x1000D
/* Read Frame Terminate */
#define SFC_RF_TERM (1 << 0)
/* Write Frame Terminate */
#define SFC_WF_TERM (1 << 1)
/* CRC error for write out of sync */
#define SFC_CRC4WOOS (1 << 2)
/* Abort all in-progress frames */
#define SFC_ABORTALL (1 << 3)
/* ChipClockCSR (ALP/HT ctl/status) */
#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E
/* Force ALP request to backplane */
#define SBSDIO_FORCE_ALP 0x01
/* Force HT request to backplane */
#define SBSDIO_FORCE_HT 0x02
/* Force ILP request to backplane */
#define SBSDIO_FORCE_ILP 0x04
/* Make ALP ready (power up xtal) */
#define SBSDIO_ALP_AVAIL_REQ 0x08
/* Make HT ready (power up PLL) */
#define SBSDIO_HT_AVAIL_REQ 0x10
/* Squelch clock requests from HW */
#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
/* Status: ALP is ready */
#define SBSDIO_ALP_AVAIL 0x40
/* Status: HT is ready */
#define SBSDIO_HT_AVAIL 0x80
/* SdioPullUp (on cmd, d0-d2) */
#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F
/* Write Frame Byte Count Low */
#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019
/* Write Frame Byte Count High */
#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A
/* Read Frame Byte Count Low */
#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
/* Read Frame Byte Count High */
#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
/* MesBusyCtl (rev 11) */
#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D
/* Sdio Core Rev 12 */
#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E
#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1
#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0
#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2
#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1
#define SBSDIO_FUNC1_SLEEPCSR 0x1001F
#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1
#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0
#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1
#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2
#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1
#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
#define SBSDIO_CLKAV(regval, alponly) \
(SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001F /* f1 misc register end */
/* function 1 OCP space */
/* sb offset addr is <= 15 bits, 32k */
#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
/* with b15, maps to 32-bit SB access */
#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
/* Address bits from SBADDR regs */
#define SBSDIO_SBWINDOW_MASK 0xffff8000
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_REGS_H */
+464
View File
@@ -0,0 +1,464 @@
/****************************************************************************
* 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 <assert.h>
#include <nuttx/arch.h>
#include <stddef.h>
#include <string.h>
#include <queue.h>
#include <semaphore.h>
#include "bcmf_sdio.h"
#include "bcmf_core.h"
#include "bcmf_sdpcm.h"
#include "bcmf_cdc.h"
#include "bcmf_bdc.h"
#include "bcmf_utils.h"
#include "bcmf_netdev.h"
#include "bcmf_sdio_regs.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define SDPCM_CONTROL_CHANNEL 0 /* Control frame id */
#define SDPCM_EVENT_CHANNEL 1 /* Asynchronous event frame id */
#define SDPCM_DATA_CHANNEL 2 /* Data frame id */
/****************************************************************************
* Private Types
****************************************************************************/
struct __attribute__((packed)) bcmf_sdpcm_header {
uint16_t size;
uint16_t checksum;
uint8_t sequence;
uint8_t channel;
uint8_t next_length;
uint8_t data_offset;
uint8_t flow_control;
uint8_t credit;
uint16_t padding;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int bcmf_sdpcm_rxfail(FAR struct bcmf_sdio_dev_s *sbus, bool retry);
static int bcmf_sdpcm_process_header(FAR struct bcmf_sdio_dev_s *sbus,
struct bcmf_sdpcm_header *header);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
int bcmf_sdpcm_rxfail(FAR struct bcmf_sdio_dev_s *sbus, bool retry)
{
/* issue abort command for F2 through F0 */
bcmf_write_reg(sbus, 0, SDIO_CCCR_IOABORT, 2);
bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM);
/* TODO Wait until the packet has been flushed (device/FIFO stable) */
if (retry)
{
/* Send NAK to retry to read frame */
bcmf_write_sbregb(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
tosbmailbox), SMB_NAK);
}
return 0;
}
int bcmf_sdpcm_process_header(FAR struct bcmf_sdio_dev_s *sbus,
struct bcmf_sdpcm_header *header)
{
if (header->data_offset < sizeof(struct bcmf_sdpcm_header) ||
header->data_offset > header->size)
{
wlerr("Invalid data offset\n");
bcmf_sdpcm_rxfail(sbus, false);
return -ENXIO;
}
/* Update tx credits */
sbus->max_seq = header->credit;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
{
int ret;
uint16_t len, checksum;
struct bcmf_sdpcm_header *header;
struct bcmf_sdio_frame *sframe;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
/* Request free frame buffer */
sframe = bcmf_sdio_allocate_frame(priv, false, false);
if (sframe == NULL)
{
wlinfo("fail alloc\n");
return -EAGAIN;
}
header = (struct bcmf_sdpcm_header *)sframe->data;
/* Read header */
ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t *)header, 4);
if (ret != OK)
{
wlinfo("failread size\n");
ret = -EIO;
goto exit_abort;
}
len = header->size;
checksum = header->checksum;
/* All zero means no more to read */
if (!(len | checksum))
{
ret = -ENODATA;
goto exit_free_frame;
}
if (((~len & 0xffff) ^ checksum) || len < sizeof(struct bcmf_sdpcm_header))
{
wlerr("Invalid header checksum or len %x %x\n", len, checksum);
ret = -EINVAL;
goto exit_abort;
}
if (len > sframe->header.len)
{
wlerr("Frame is too large, cancel %d %d\n", len, sframe->header.len);
ret = -ENOMEM;
goto exit_abort;
}
/* Read remaining frame data */
ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t *)header + 4, len - 4);
if (ret != OK)
{
ret = -EIO;
goto exit_abort;
}
// wlinfo("Receive frame %p %d\n", sframe, len);
// bcmf_hexdump((uint8_t *)header, header->size, (unsigned int)header);
/* Process and validate header */
ret = bcmf_sdpcm_process_header(sbus, header);
if (ret != OK)
{
wlerr("Error while processing header %d\n", ret);
ret = -EINVAL;
goto exit_free_frame;
}
/* Update frame structure */
sframe->header.len = header->size;
sframe->header.data += header->data_offset;
/* Process received frame content */
switch (header->channel & 0x0f)
{
case SDPCM_CONTROL_CHANNEL:
ret = bcmf_cdc_process_control_frame(priv, &sframe->header);
goto exit_free_frame;
case SDPCM_EVENT_CHANNEL:
if (header->data_offset == header->size)
{
/* Empty event, ignore */
ret = OK;
}
else
{
ret = bcmf_bdc_process_event_frame(priv, &sframe->header);
}
goto exit_free_frame;
case SDPCM_DATA_CHANNEL:
/* Queue frame and notify network layer frame is available */
if (sem_wait(&sbus->queue_mutex))
{
PANIC();
}
bcmf_dqueue_push(&sbus->rx_queue, &sframe->list_entry);
sem_post(&sbus->queue_mutex);
bcmf_netdev_notify_rx(priv);
/* Upper layer have to free all received frames */
ret = OK;
break;
default:
wlerr("Got unexpected message type %d\n", header->channel);
ret = -EINVAL;
goto exit_free_frame;
}
return ret;
exit_abort:
bcmf_sdpcm_rxfail(sbus, false);
exit_free_frame:
bcmf_sdio_free_frame(priv, sframe);
return ret;
}
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
{
int ret;
bool is_txframe;
dq_entry_t *entry;
struct bcmf_sdio_frame *sframe;
struct bcmf_sdpcm_header *header;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
if (sbus->tx_queue.tail == NULL)
{
/* No more frames to send */
return -ENODATA;
}
if (sbus->tx_seq == sbus->max_seq)
{
// TODO handle this case
wlerr("No credit to send frame\n");
return -EAGAIN;
}
if (sem_wait(&sbus->queue_mutex))
{
PANIC();
}
entry = sbus->tx_queue.tail;
sframe = container_of(entry, struct bcmf_sdio_frame, list_entry);
header = (struct bcmf_sdpcm_header *)sframe->header.base;
/* Set frame sequence id */
header->sequence = sbus->tx_seq++;
// wlinfo("Send frame %p\n", sframe);
// bcmf_hexdump(sframe->header.base, sframe->header.len,
// (unsigned long)sframe->header.base);
ret = bcmf_transfer_bytes(sbus, true, 2, 0, sframe->header.base,
sframe->header.len);
if (ret != OK)
{
wlinfo("fail send frame %d\n", ret);
ret = -EIO;
goto exit_abort;
// TODO handle retry count and remove frame from queue + abort TX
}
/* Frame sent, remove it from queue */
bcmf_dqueue_pop_tail(&sbus->tx_queue);
sem_post(&sbus->queue_mutex);
is_txframe = sframe->tx;
/* Free frame buffer */
bcmf_sdio_free_frame(priv, sframe);
if (is_txframe)
{
/* Notify upper layer at least one TX buffer is available */
bcmf_netdev_notify_tx_done(priv);
}
return OK;
exit_abort:
// bcmf_sdpcm_txfail(sbus, false);
sem_post(&sbus->queue_mutex);
return ret;
}
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame, bool control)
{
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
struct bcmf_sdio_frame *sframe = (struct bcmf_sdio_frame *)frame;
struct bcmf_sdpcm_header *header = (struct bcmf_sdpcm_header *)sframe->data;
/* Prepare sw header */
memset(header, 0, sizeof(struct bcmf_sdpcm_header));
header->size = frame->len;
header->checksum = ~header->size;
header->data_offset = (uint8_t)(frame->data - frame->base);
if (control)
{
header->channel = SDPCM_CONTROL_CHANNEL;
}
else
{
header->channel = SDPCM_DATA_CHANNEL;
}
/* Add frame in tx queue */
if (sem_wait(&sbus->queue_mutex))
{
PANIC();
}
bcmf_dqueue_push(&sbus->tx_queue, &sframe->list_entry);
sem_post(&sbus->queue_mutex);
/* Notify bcmf thread tx frame is ready */
sem_post(&sbus->thread_signal);
return OK;
}
struct bcmf_frame_s *bcmf_sdpcm_alloc_frame(FAR struct bcmf_dev_s *priv,
unsigned int len, bool block,
bool control)
{
struct bcmf_sdio_frame *sframe;
unsigned int header_len = sizeof(struct bcmf_sdpcm_header);
if (!control)
{
header_len += 2; /* Data frames need alignment padding */
}
if (len + header_len > MAX_NET_DEV_MTU + HEADER_SIZE ||
len > len + header_len)
{
wlerr("Invalid size %d\n", len);
return NULL;
}
/* Allocate a frame for RX in case of control frame */
sframe = bcmf_sdio_allocate_frame(priv, block, !control);
if (sframe == NULL)
{
return NULL;
}
sframe->header.len = header_len + len;
sframe->header.data += header_len;
return &sframe->header;
}
void bcmf_sdpcm_free_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
return bcmf_sdio_free_frame(priv, (struct bcmf_sdio_frame *)frame);
}
struct bcmf_frame_s *bcmf_sdpcm_get_rx_frame(FAR struct bcmf_dev_s *priv)
{
dq_entry_t *entry;
struct bcmf_sdio_frame *sframe;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
if (sem_wait(&sbus->queue_mutex))
{
PANIC();
}
entry = bcmf_dqueue_pop_tail(&sbus->rx_queue);
sem_post(&sbus->queue_mutex);
if (entry == NULL)
{
return NULL;
}
sframe = container_of(entry, struct bcmf_sdio_frame, list_entry);
return &sframe->header;
}
+64
View File
@@ -0,0 +1,64 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_sdpcm.h
*
* 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.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "bcmf_driver.h"
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv);
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv);
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame, bool control);
void bcmf_sdpcm_free_frame(FAR struct bcmf_dev_s *priv, struct bcmf_frame_s *frame);
struct bcmf_frame_s *bcmf_sdpcm_alloc_frame(FAR struct bcmf_dev_s *priv,
unsigned int len, bool block,
bool control);
struct bcmf_frame_s *bcmf_sdpcm_get_rx_frame(FAR struct bcmf_dev_s *priv);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H */
+167
View File
@@ -0,0 +1,167 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_utils.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 <stdint.h>
#include <string.h>
#include <time.h>
#include <semaphore.h>
#include <debug.h>
#include <stdio.h>
#include <queue.h>
#include "bcmf_utils.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define LINE_LEN 16
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: bcmf_hexdump
****************************************************************************/
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset)
{
unsigned int i;
unsigned int char_count = 0;
char char_line[20];
char hex_line[64];
for (i = 0; i < len; i++)
{
if (char_count >= LINE_LEN)
{
/* Flush line */
wlinfo("%08x: %s%s\n", offset+i-char_count, hex_line, char_line);
char_count = 0;
}
sprintf(hex_line+3*char_count, "%02x ", data[i]);
sprintf(char_line+char_count, "%c",
data[i] < 0x20 || data[i] >= 0x7f? '.': data[i]);
char_count ++;
}
if (char_count > 0)
{
/* Flush last line */
memset(hex_line+3*char_count, ' ', 3*(LINE_LEN-char_count));
hex_line[3*LINE_LEN] = 0;
wlinfo("%08x: %s%s\n", offset+i-char_count, hex_line, char_line);
}
}
/****************************************************************************
* Name: bcmf_sem_wait
****************************************************************************/
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms)
{
struct timespec abstime;
unsigned int timeout_sec;
/* Get the current time */
(void)clock_gettime(CLOCK_REALTIME, &abstime);
timeout_sec = timeout_ms / 1000;
abstime.tv_sec += timeout_sec;
abstime.tv_nsec += 1000 * 1000 * (timeout_ms % 1000);
if (abstime.tv_nsec >= 1000 * 1000 * 1000)
{
abstime.tv_sec++;
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
return sem_timedwait(sem, &abstime);
}
void bcmf_dqueue_push(dq_queue_t *queue, dq_entry_t *entry)
{
if (queue->head == NULL)
{
/* List is empty */
queue->tail = entry;
entry->flink = entry;
entry->blink = entry;
}
else
{
/* Insert entry at list head */
entry->flink = queue->head;
entry->blink = queue->tail;
queue->head->blink = entry;
}
queue->head = entry;
}
dq_entry_t *bcmf_dqueue_pop_tail(dq_queue_t *queue)
{
dq_entry_t *entry = queue->tail;
if (queue->head == queue->tail)
{
/* List is empty */
queue->head = NULL;
queue->tail = NULL;
}
else
{
/* Pop from queue tail */
queue->tail = entry->blink;
entry->blink->flink = queue->head;
}
return entry;
}
+73
View File
@@ -0,0 +1,73 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_utils.h
*
* 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.
*
****************************************************************************/
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
#include <semaphore.h>
#include <queue.h>
#define container_of(ptr, type, member) \
(type *)((uint8_t *)(ptr) - offsetof(type, member))
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset);
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms);
dq_entry_t *bcmf_dqueue_pop_tail(dq_queue_t *queue);
void bcmf_dqueue_push(dq_queue_t *queue, dq_entry_t *entry);
static inline uint16_t bcmf_getle16(uint16_t *val)
{
uint8_t *valb = (uint8_t *)val;
return (uint16_t)valb[0] << 8 | (uint16_t)valb[1];
}
static inline uint16_t bcmf_getle32(uint32_t *val)
{
uint16_t *valw = (uint16_t *)val;
return (uint32_t)bcmf_getle16(valw) << 16 | bcmf_getle16(valw + 1);
}
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H */
+393
View File
@@ -0,0 +1,393 @@
#include <nuttx/wireless/ieee80211/mmc_sdio.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/arch.h>
#define SDIO_CMD53_TIMEOUT_MS 100
#define SDIO_IDLE_DELAY_MS 50
struct __attribute__((packed)) sdio_cmd52
{
uint32_t write_data : 8;
uint32_t reserved_8 : 1;
uint32_t register_address : 17;
uint32_t reserved_26 : 1;
uint32_t raw_flag : 1;
uint32_t function_number : 3;
uint32_t rw_flag : 1;
};
struct __attribute__((packed)) sdio_cmd53
{
uint32_t byte_block_count : 9;
uint32_t register_address : 17;
uint32_t op_code : 1;
uint32_t block_mode : 1;
uint32_t function_number : 3;
uint32_t rw_flag : 1;
};
struct __attribute__((packed)) sdio_resp_R5
{
uint32_t data : 8;
struct
{
uint32_t out_of_range : 1;
uint32_t function_number : 1;
uint32_t rfu : 1;
uint32_t error : 1;
uint32_t io_current_state : 2;
uint32_t illegal_command : 1;
uint32_t com_crc_error : 1;
} flags;
uint32_t reserved_16 : 16;
};
union sdio_cmd5x
{
uint32_t value;
struct sdio_cmd52 cmd52;
struct sdio_cmd53 cmd53;
};
int sdio_sendcmdpoll(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
{
int ret;
/* Send the command */
ret = SDIO_SENDCMD(dev, cmd, arg);
if (ret == OK)
{
/* Then poll-wait until the response is available */
ret = SDIO_WAITRESPONSE(dev, cmd);
if (ret != OK)
{
wlerr("ERROR: Wait for response to cmd: %08x failed: %d\n",
cmd, ret);
}
}
return ret;
}
int sdio_io_rw_direct(FAR struct sdio_dev_s *dev, bool write,
uint8_t function, uint32_t address,
uint8_t inb, uint8_t *outb)
{
union sdio_cmd5x arg;
struct sdio_resp_R5 resp;
int ret;
/* Setup CMD52 argument */
arg.value = 0;
if (write)
{
arg.cmd52.write_data = inb;
}
else
{
arg.cmd52.write_data = 0;
}
arg.cmd52.register_address = address & 0x1ffff;
arg.cmd52.raw_flag = (write && outb);
arg.cmd52.function_number = function & 7;
arg.cmd52.rw_flag = write;
/* Send CMD52 command */
sdio_sendcmdpoll(dev, SDIO_ACMD52, arg.value);
ret = SDIO_RECVR5(dev, SDIO_ACMD52, (uint32_t *)&resp);
if (ret != OK)
{
wlerr("ERROR: SDIO_RECVR5 failed %d\n", ret);
return ret;
}
/* Check for errors */
if (resp.flags.error)
{
return -EIO;
}
if (resp.flags.function_number || resp.flags.out_of_range)
{
return -EINVAL;
}
/* Write output byte */
if (outb)
{
*outb = resp.data & 0xff;
}
return OK;
}
int sdio_io_rw_extended(FAR struct sdio_dev_s *dev, bool write,
uint8_t function, uint32_t address,
bool inc_addr, uint8_t *buf,
unsigned int blocklen, unsigned int nblocks)
{
union sdio_cmd5x arg;
struct sdio_resp_R5 resp;
int ret;
sdio_eventset_t wkupevent;
/* Setup CMD53 argument */
arg.value = 0;
arg.cmd53.register_address = address & 0x1ffff;
arg.cmd53.op_code = inc_addr;
arg.cmd53.function_number = function & 7;
arg.cmd53.rw_flag = write;
if (nblocks == 0 && blocklen < 512)
{
/* Use byte mode */
// wlinfo("byte mode\n");
arg.cmd53.block_mode = 0;
arg.cmd53.byte_block_count = blocklen;
nblocks = 1;
}
else
{
/* Use block mode */
arg.cmd53.block_mode = 1;
arg.cmd53.byte_block_count = nblocks;
}
/* Send CMD53 command */
SDIO_BLOCKSETUP(dev, blocklen, nblocks);
SDIO_WAITENABLE(dev,
SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR);
if (write)
{
// wlinfo("prep write %d %d\n", blocklen, nblocks);
sdio_sendcmdpoll(dev, SDIO_ACMD53, (uint32_t)arg.value);
ret = SDIO_RECVR5(dev, SDIO_ACMD53, (uint32_t *)&resp);
SDIO_DMASENDSETUP(dev, buf, blocklen * nblocks);
wkupevent = SDIO_EVENTWAIT(dev, SDIO_CMD53_TIMEOUT_MS);
}
else
{
// wlinfo("prep read %d\n", blocklen * nblocks);
SDIO_DMARECVSETUP(dev, buf, blocklen * nblocks);
SDIO_SENDCMD(dev, SDIO_ACMD53, (uint32_t)arg.value);
wkupevent = SDIO_EVENTWAIT(dev, SDIO_CMD53_TIMEOUT_MS);
ret = SDIO_RECVR5(dev, SDIO_ACMD53, (uint32_t *)&resp);
}
if (ret != OK)
{
wlerr("ERROR: SDIO_RECVR5 failed %d\n", ret);
return ret;
}
/* Check for errors */
if (wkupevent & SDIOWAIT_TIMEOUT)
{
wlerr("timeout\n");
return -ETIMEDOUT;
}
if (resp.flags.error || (wkupevent & SDIOWAIT_ERROR))
{
wlerr("error 1\n");
return -EIO;
}
if (resp.flags.function_number || resp.flags.out_of_range)
{
wlerr("error 2\n");
return -EINVAL;
}
return OK;
}
int sdio_set_wide_bus(struct sdio_dev_s *dev)
{
int ret;
uint8_t value;
/* Read Bus Interface Control register */
ret = sdio_io_rw_direct(dev, false, 0, SDIO_CCCR_BUS_IF, 0, &value);
if (ret != OK)
{
return ret;
}
/* Set 4 bits bus width setting */
value &= ~SDIO_CCCR_BUS_IF_WIDTH_MASK;
value |= SDIO_CCCR_BUS_IF_4_BITS;
ret = sdio_io_rw_direct(dev, true, 0, SDIO_CCCR_BUS_IF, value, NULL);
if (ret != OK)
{
return ret;
}
SDIO_WIDEBUS(dev, true);
return OK;
}
int sdio_probe(FAR struct sdio_dev_s *dev)
{
int ret;
uint32_t data = 0;
/* Set device state from reset to idle */
sdio_sendcmdpoll(dev, MMCSD_CMD0, 0);
up_mdelay(SDIO_IDLE_DELAY_MS);
/* Device is SDIO card compatible so we can send CMD5 instead of ACMD41 */
sdio_sendcmdpoll(dev, SDIO_CMD5, 0);
/* Receive R4 response */
ret = SDIO_RECVR4(dev, SDIO_CMD5, &data);
if (ret != OK)
{
return ret;
}
/* Device is in Card Identification Mode, request device RCA */
sdio_sendcmdpoll(dev, SD_CMD3, 0);
ret = SDIO_RECVR6(dev, SD_CMD3, &data);
if (ret != OK)
{
wlerr("ERROR: RCA request failed: %d\n", ret);
return ret;
}
wlinfo("rca is %x\n", data >> 16);
/* Send CMD7 with the argument == RCA in order to select the card
* and put it in Transfer State */
sdio_sendcmdpoll(dev, MMCSD_CMD7S, data & 0xffff0000);
ret = SDIO_RECVR1(dev, MMCSD_CMD7S, &data);
if (ret != OK)
{
wlerr("ERROR: card selection failed: %d\n", ret);
return ret;
}
/* Configure 4 bits bus width */
ret = sdio_set_wide_bus(dev);
if (ret != OK)
{
return ret;
}
return OK;
}
int sdio_set_blocksize(FAR struct sdio_dev_s *dev, uint8_t function,
uint16_t blocksize)
{
int ret;
ret = sdio_io_rw_direct(dev, true, 0,
(function << SDIO_FBR_SHIFT) + SDIO_CCCR_FN0_BLKSIZE_0,
blocksize & 0xff, NULL);
if (ret != OK)
{
return ret;
}
ret = sdio_io_rw_direct(dev, true, 0,
(function << SDIO_FBR_SHIFT) + SDIO_CCCR_FN0_BLKSIZE_1,
(blocksize >> 8), NULL);
if (ret != OK)
{
return ret;
}
return OK;
}
int sdio_enable_function(FAR struct sdio_dev_s *dev, uint8_t function)
{
int ret;
uint8_t value;
/* Read current I/O Enable register */
ret = sdio_io_rw_direct(dev, false, 0, SDIO_CCCR_IOEN, 0, &value);
if (ret != OK)
{
return ret;
}
ret = sdio_io_rw_direct(dev, true, 0, SDIO_CCCR_IOEN, value | (1 << function), NULL);
if (ret != OK)
{
return ret;
}
/* Wait 10ms for function to be enabled */
int loops = 10;
while (loops-- > 0)
{
up_mdelay(1);
ret = sdio_io_rw_direct(dev, false, 0, SDIO_CCCR_IOEN, 0, &value);
if (ret != OK)
{
return ret;
}
if (value & (1 << function))
{
/* Function enabled */
wlinfo("Function %d enabled\n", function);
return OK;
}
}
return -ETIMEDOUT;
}
int sdio_enable_interrupt(FAR struct sdio_dev_s *dev, uint8_t function)
{
int ret;
uint8_t value;
/* Read current Int Enable register */
ret = sdio_io_rw_direct(dev, false, 0, SDIO_CCCR_INTEN, 0, &value);
if (ret != OK)
{
return ret;
}
return sdio_io_rw_direct(dev, true, 0, SDIO_CCCR_INTEN, value | (1 << function), NULL);
}