diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index d4b2820168a..241068fc4cd 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -7595,6 +7595,13 @@ endmenu menu "SDIO Configuration" depends on STM32_SDIO +config STM32_SDIO_CARD + bool "SDIO Card support" + default n + ---help--- + Build in additional support needed only for SDIO cards (vs. SD + memory cards) + config STM32_SDIO_DMA bool "Support DMA data transfers" default y if STM32_DMA2 diff --git a/arch/arm/src/stm32/stm32_sdio.c b/arch/arm/src/stm32/stm32_sdio.c index 1d9f99e72b2..4480a302dd8 100644 --- a/arch/arm/src/stm32/stm32_sdio.c +++ b/arch/arm/src/stm32/stm32_sdio.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32/stm32_sdio.c * - * Copyright (C) 2009, 2011-2014, 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2009, 2011-2014, 2016-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -335,6 +335,14 @@ struct stm32_dev_s size_t remaining; /* Number of bytes remaining in the transfer */ uint32_t xfrmask; /* Interrupt enables for data transfer */ +#ifdef CONFIG_STM32_SDIO_CARD + /* Interrupt at SDIO_D1 pin, only for SDIO cards */ + + uint32_t sdiointmask; /* STM32 SDIO register mask */ + int (*do_sdio_card)(void *); /* SDIO card ISR */ + void *do_sdio_arg; /* arg for SDIO card ISR */ +#endif + /* Fixed transfer block size support */ #ifdef CONFIG_SDIO_BLOCKSETUP @@ -703,7 +711,14 @@ static void stm32_configwaitints(struct stm32_dev_s *priv, uint32_t waitmask, #ifdef CONFIG_STM32_SDIO_DMA priv->xfrflags = 0; #endif + +#ifdef CONFIG_STM32_SDIO_CARD + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + STM32_SDIO_MASK); +#else putreg32(priv->xfrmask | priv->waitmask, STM32_SDIO_MASK); +#endif + leave_critical_section(flags); } @@ -725,9 +740,15 @@ static void stm32_configwaitints(struct stm32_dev_s *priv, uint32_t waitmask, static void stm32_configxfrints(struct stm32_dev_s *priv, uint32_t xfrmask) { irqstate_t flags; + flags = enter_critical_section(); priv->xfrmask = xfrmask; +#ifdef CONFIG_STM32_SDIO_CARD + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + STM32_SDIO_MASK); +#else putreg32(priv->xfrmask | priv->waitmask, STM32_SDIO_MASK); +#endif leave_critical_section(flags); } @@ -1534,6 +1555,23 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg) } } } + +#ifdef CONFIG_STM32_SDIO_CARD + /* Handle SDIO card interrupt */ + + pending = enabled & priv->sdiointmask; + if (pending != 0) + { + putreg32(SDIO_STA_SDIOIT, STM32_SDIO_ICR); + + /* Perform callback */ + + if (priv->do_sdio_card) + { + priv->do_sdio_card(priv->do_sdio_arg); + } + } +#endif } return OK; @@ -1617,6 +1655,10 @@ static void stm32_reset(FAR struct sdio_dev_s *dev) priv->remaining = 0; /* Number of bytes remaining in the transfer */ priv->xfrmask = 0; /* Interrupt enables for data transfer */ +#ifdef CONFIG_STM32_SDIO_CARD + priv->sdiointmask = 0; /* SDIO card in-band interrupt mask */ +#endif + /* DMA data transfer support */ priv->widebus = false; /* Required for DMA support */ @@ -3100,4 +3142,44 @@ void sdio_wrprotect(FAR struct sdio_dev_s *dev, bool wrprotect) mcinfo("cdstatus: %02x\n", priv->cdstatus); leave_critical_section(flags); } + +/**************************************************************************** + * Name: sdio_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_SDIO_CARD +void sdio_set_sdio_card_isr(FAR struct sdio_dev_s *dev, + int (*func)(void *), void *arg) +{ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + + priv->do_sdio_card = func; + + if (func != NULL) + { + priv->sdiointmask = SDIO_STA_SDIOIT; + priv->do_sdio_arg = arg; + } + else + { + priv->sdiointmask = 0; + } + + putreg32(priv->xfrmask | priv->waitmask | priv->sdiointmask, + STM32_SDIO_MASK); +} +#endif + #endif /* CONFIG_STM32_SDIO */ diff --git a/arch/arm/src/stm32/stm32_sdio.h b/arch/arm/src/stm32/stm32_sdio.h index 4fc477a0e44..f9d7487a381 100644 --- a/arch/arm/src/stm32/stm32_sdio.h +++ b/arch/arm/src/stm32/stm32_sdio.h @@ -118,6 +118,27 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot); void sdio_wrprotect(FAR struct sdio_dev_s *dev, bool wrprotect); +/**************************************************************************** + * Name: sdio_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_SDIO_CARD +void sdio_set_sdio_card_isr(FAR struct sdio_dev_s *dev, + int (*func)(void *), void *arg); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/configs/photon/README.txt b/configs/photon/README.txt index 584f626cd94..4b761752273 100644 --- a/configs/photon/README.txt +++ b/configs/photon/README.txt @@ -114,6 +114,29 @@ Flashing NuttX in the Photon board Download done. File downloaded successfully + 3) Restore the original firmware + + If you config to use the stock bootloader of Photon, you may + reload the original firmware with dfu-utils as you like. Otherwize + you must have backuped the whole image beforehand, and reload it + via SWD debug port. + +NSH via telnet +============== + + After you successfully downloaded nuttx.bin, reset the board and it + automatically connects to the corresponding wifi AP. You may login + your router to see its IP address. Assume that it's 192.168.1.111 + + Open a terminal on your computer and telnet your Photon: + + $ telnet 192.168.1.111 + Trying 192.168.1.111... + Connected to 192.168.1.111. + Escape character is '^]' + + NuttShell (NSH) NuttX-7.24 + nsh> Serial console configuration ============================ diff --git a/configs/photon/src/stm32_wlan.c b/configs/photon/src/stm32_wlan.c index 9e886807e00..2a2eec68517 100644 --- a/configs/photon/src/stm32_wlan.c +++ b/configs/photon/src/stm32_wlan.c @@ -1,7 +1,7 @@ /**************************************************************************** * configs/photon/src/stm32_wlan.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,12 @@ #include "photon.h" +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct sdio_dev_s *g_sdio_dev; + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -102,18 +108,19 @@ void bcmf_board_initialize(int minor) * Name: bcmf_board_setup_oob_irq ****************************************************************************/ -void bcmf_board_setup_oob_irq(int minor, xcpt_t func, void *arg) +void bcmf_board_setup_oob_irq(int minor, int (*func)(void *), void *arg) { if (minor != SDIO_WLAN0_MINOR) { return; } - /* Configure interrupt pin */ + /* Configure SDIO card in-band interrupt callback */ - stm32_configgpio(GPIO_WLAN0_OOB_INT); - - stm32_gpiosetevent(GPIO_WLAN0_OOB_INT, true, false, false, func, arg); + if (g_sdio_dev != NULL) + { + sdio_set_sdio_card_isr(g_sdio_dev, func, arg); + } } /**************************************************************************** @@ -123,15 +130,14 @@ void bcmf_board_setup_oob_irq(int minor, xcpt_t func, void *arg) int photon_wlan_initialize() { int ret; - struct sdio_dev_s *sdio_dev; /* Initialize sdio interface */ wlinfo("Initializing SDIO slot %d\n", SDIO_WLAN0_SLOTNO); - sdio_dev = sdio_initialize(SDIO_WLAN0_SLOTNO); + g_sdio_dev = sdio_initialize(SDIO_WLAN0_SLOTNO); - if (!sdio_dev) + if (!g_sdio_dev) { wlerr("ERROR: Failed to initialize SDIO with slot %d\n", SDIO_WLAN0_SLOTNO); @@ -140,7 +146,7 @@ int photon_wlan_initialize() /* Bind the SDIO interface to the bcmf driver */ - ret = bcmf_sdio_initialize(SDIO_WLAN0_MINOR, sdio_dev); + ret = bcmf_sdio_initialize(SDIO_WLAN0_MINOR, g_sdio_dev); if (ret != OK) { diff --git a/drivers/wireless/ieee80211/Kconfig b/drivers/wireless/ieee80211/Kconfig index 853b870b9c5..b34514326be 100644 --- a/drivers/wireless/ieee80211/Kconfig +++ b/drivers/wireless/ieee80211/Kconfig @@ -13,6 +13,11 @@ config IEEE80211_BROADCOM_BCM43362 depends on IEEE80211_BROADCOM_FULLMAC default n +config IEEE80211_BROADCOM_BCM43438 + bool "Broadcom 43438 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 diff --git a/drivers/wireless/ieee80211/Make.defs b/drivers/wireless/ieee80211/Make.defs index a648f70a932..7d924e2f60e 100644 --- a/drivers/wireless/ieee80211/Make.defs +++ b/drivers/wireless/ieee80211/Make.defs @@ -58,6 +58,10 @@ ifeq ($(CONFIG_IEEE80211_BROADCOM_BCM43362),y) CSRCS += bcmf_chip_43362.c endif +ifeq ($(CONFIG_IEEE80211_BROADCOM_BCM43438),y) +CSRCS += bcmf_chip_43438.c +endif + endif # CONFIG_IEEE80211_BROADCOM_FULLMAC # Include IEEE 802.11 build support diff --git a/drivers/wireless/ieee80211/bcmf_bdc.c b/drivers/wireless/ieee80211/bcmf_bdc.c index 509106fdc14..3ce6efeedb0 100644 --- a/drivers/wireless/ieee80211/bcmf_bdc.c +++ b/drivers/wireless/ieee80211/bcmf_bdc.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/ieee80211/bcmf_bdc.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -66,8 +66,8 @@ 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 */ + uint8_t flags2; /* bdc frame additional flags */ + uint8_t data_offset; /* Offset from end of header to payload data, in 4-bytes count */ }; struct __attribute__((packed)) bcmf_eth_header @@ -138,7 +138,7 @@ int bcmf_bdc_process_event_frame(FAR struct bcmf_dev_s *priv, header = (struct bcmf_bdc_header *)frame->data; - data_size -= sizeof(struct bcmf_bdc_header) + header->data_offset; + data_size -= sizeof(struct bcmf_bdc_header) + header->data_offset * 4; if (data_size < sizeof(struct bcmf_event_msg)) { @@ -151,7 +151,7 @@ int bcmf_bdc_process_event_frame(FAR struct bcmf_dev_s *priv, event_msg = (struct bcmf_event_msg *)(frame->data + sizeof(struct bcmf_bdc_header) + - header->data_offset); + header->data_offset * 4); if (event_msg->eth.ether_type != BCMF_EVENT_ETHER_TYPE || memcmp(event_msg->bcm_eth.oui, bcmf_broadcom_oui, 3)) @@ -258,6 +258,7 @@ 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); + struct bcmf_bdc_header *header; /* Process bdc header */ @@ -272,6 +273,7 @@ struct bcmf_frame_s *bcmf_bdc_rx_frame(FAR struct bcmf_dev_s *priv) /* Transmit frame to upper layer */ - frame->data += sizeof(struct bcmf_bdc_header); + header = (struct bcmf_bdc_header*)frame->data; + frame->data += sizeof(struct bcmf_bdc_header) + header->data_offset * 4; return frame; } diff --git a/drivers/wireless/ieee80211/bcmf_bdc.h b/drivers/wireless/ieee80211/bcmf_bdc.h index 37d9225b5e9..1cf2786fd6d 100644 --- a/drivers/wireless/ieee80211/bcmf_bdc.h +++ b/drivers/wireless/ieee80211/bcmf_bdc.h @@ -33,15 +33,19 @@ * ****************************************************************************/ +#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H +#define __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H + /**************************************************************************** * Included Files ****************************************************************************/ -#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H -#define __DRIVERS_WIRELESS_IEEE80211_BCMF_BDC_H - #include "bcmf_driver.h" +/**************************************************************************** + * Public Types + ****************************************************************************/ + /* Event frame content */ struct __attribute__((packed)) bcmf_event_s diff --git a/drivers/wireless/ieee80211/bcmf_chip_43438.c b/drivers/wireless/ieee80211/bcmf_chip_43438.c new file mode 100644 index 00000000000..eab18dc555d --- /dev/null +++ b/drivers/wireless/ieee80211/bcmf_chip_43438.c @@ -0,0 +1,89 @@ +/**************************************************************************** + * drivers/wireless/ieee80211/bcmf_chip_43438.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Simon Piriou + * + * 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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define WRAPPER_REGISTER_OFFSET 0x100000 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const char ap6212_nvram_image[]; +extern const unsigned int ap6212_nvram_image_len; + +extern const uint8_t ap6212_firmware_image[]; +extern const unsigned int ap6212_firmware_len; + +extern const uint8_t ap6212_clm_blob[]; +extern const unsigned int ap6212_clm_blob_len; + +const struct bcmf_sdio_chip bcmf_43438_config_sdio = +{ + + /* General chip stats */ + + .ram_size = 512*1024, + + /* 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 *)ap6212_firmware_image, + .firmware_image_size = (unsigned int *)&ap6212_firmware_len, + + .nvram_image = (uint8_t *)ap6212_nvram_image, + .nvram_image_size = (unsigned int *)&ap6212_nvram_image_len, + + .clm_blob_image = (uint8_t *)ap6212_clm_blob, + .clm_blob_image_size = (unsigned int *)&ap6212_clm_blob_len, +}; diff --git a/drivers/wireless/ieee80211/bcmf_core.c b/drivers/wireless/ieee80211/bcmf_core.c index eba356264e1..170f1d97639 100644 --- a/drivers/wireless/ieee80211/bcmf_core.c +++ b/drivers/wireless/ieee80211/bcmf_core.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/ieee80211/bcmf_core.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -55,6 +55,7 @@ ****************************************************************************/ /* 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 */ @@ -74,8 +75,14 @@ #define BCMA_RESET_CTL_RESET 0x0001 +/* SOCSRAM core registers */ + +#define SOCSRAM_BANKX_INDEX ((uint32_t) (0x18004000 + 0x10) ) +#define SOCSRAM_BANKX_PDA ((uint32_t) (0x18004000 + 0x44) ) + /* Transfer size properties */ -#define BCMF_UPLOAD_TRANSFER_SIZE (64 * 256) + +#define BCMF_UPLOAD_TRANSFER_SIZE (64 * 256) /**************************************************************************** * Private Types @@ -87,11 +94,9 @@ 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); - + uint32_t address, uint8_t *buf, + unsigned int len); static int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus); /**************************************************************************** @@ -169,6 +174,7 @@ int bcmf_upload_binary(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, address += size; buf += size; } + return OK; } @@ -202,7 +208,8 @@ int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus) /* Write the length token to the last word */ - ret = bcmf_write_sbreg(sbus, sbus->chip->ram_size - 4, (uint8_t *)&token, 4); + ret = bcmf_write_sbreg(sbus, sbus->chip->ram_size - 4, + (FAR uint8_t *)&token, 4); if (ret != OK) { return ret; @@ -220,7 +227,7 @@ int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus) ****************************************************************************/ int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, - uint8_t *reg, unsigned int len) + FAR uint8_t *reg, unsigned int len) { int ret = bcmf_core_set_backplane_window(sbus, address); if (ret != OK) @@ -228,6 +235,13 @@ int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, return ret; } + /* Map to 32-bit access if len == 4 */ + + if (len == 4) + { + address |= SBSDIO_SB_ACCESS_2_4B_FLAG; + } + return bcmf_transfer_bytes(sbus, false, 1, address & SBSDIO_SB_OFT_ADDR_MASK, reg, len); } @@ -237,7 +251,7 @@ int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, ****************************************************************************/ int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, - uint8_t *reg, unsigned int len) + FAR uint8_t *reg, unsigned int len) { int ret = bcmf_core_set_backplane_window(sbus, address); @@ -246,6 +260,13 @@ int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address, return ret; } + /* Map to 32-bit access if len == 4 */ + + if (len == 4) + { + address |= SBSDIO_SB_ACCESS_2_4B_FLAG; + } + return bcmf_transfer_bytes(sbus, true, 1, address & SBSDIO_SB_OFT_ADDR_MASK, reg, len); } @@ -260,12 +281,23 @@ int bcmf_core_upload_firmware(FAR struct bcmf_sdio_dev_s *sbus) wlinfo("upload firmware\n"); - /* Disable ARMCM3 core and reset SOCRAM core - * to set device in firmware upload mode */ + /* 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); + /* Do chip specific initialization */ + + if (sbus->cur_chip_id == SDIO_DEVICE_ID_BROADCOM_43430) + { + /* Disable remap for SRAM_3. Only for 4343x */ + + bcmf_write_sbregw(sbus, SOCSRAM_BANKX_INDEX, 0x3); + bcmf_write_sbregw(sbus, SOCSRAM_BANKX_PDA, 0); + } + up_mdelay(50); /* Flash chip firmware */ diff --git a/drivers/wireless/ieee80211/bcmf_driver.c b/drivers/wireless/ieee80211/bcmf_driver.c index 6c17b2b7a91..12c9acf79af 100644 --- a/drivers/wireless/ieee80211/bcmf_driver.c +++ b/drivers/wireless/ieee80211/bcmf_driver.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/ieee80211/bcmf_driver.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -69,15 +69,43 @@ #define BCMF_AUTH_TIMEOUT_MS 10000 #define BCMF_SCAN_RESULT_SIZE 1024 +/* clm file is cut into pieces of MAX_CHUNK_LEN. + * It is relatively small because dongles (FW) have a small maximum size input + * payload restriction for ioctl's ... something like 1900'ish bytes. So chunk + * len should not exceed 1400 bytes + */ + +#define MAX_CHUNK_LEN (CONFIG_NET_ETH_MTU > 1500 ? 1400 : CONFIG_NET_ETH_MTU - 100) + /* Helper to get iw_event size */ #define BCMF_IW_EVENT_SIZE(field) \ (offsetof(struct iw_event, u)+sizeof(((union iwreq_data*)0)->field)) +/* Clm blob marcos */ + +#define DLOAD_HANDLER_VER 1 /* Downloader version */ +#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ +#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ + +#define DL_CRC_NOT_INUSE 0x0001 +#define DL_BEGIN 0x0002 +#define DL_END 0x0004 + /**************************************************************************** * Private Types ****************************************************************************/ +/* clm blob download head */ + +struct wl_dload_data +{ + uint16_t flag; + uint16_t dload_type; + uint32_t len; + uint32_t crc; +}; + /* AP scan state machine status */ enum @@ -88,6 +116,14 @@ enum BCMF_SCAN_DONE }; +/* Generic download types & flags */ + +enum +{ + DL_TYPE_UCODE = 1, + DL_TYPE_CLM = 2 +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -97,6 +133,8 @@ static void bcmf_free_device(FAR struct bcmf_dev_s *priv); static int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv); +static int bcmf_driver_download_clm(FAR struct bcmf_dev_s *priv); + // FIXME only for debug purpose static void bcmf_wl_default_event_handler(FAR struct bcmf_dev_s *priv, @@ -213,6 +251,73 @@ int bcmf_wl_set_mac_address(FAR struct bcmf_dev_s *priv, struct ifreq *req) return OK; } +int bcmf_driver_download_clm(FAR struct bcmf_dev_s *priv) +{ + FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; + FAR uint8_t *srcbuff = sbus->chip->clm_blob_image; + FAR uint8_t *downloadbuff; + unsigned int datalen = *sbus->chip->clm_blob_image_size; + uint16_t dl_flag; + int ret = 0; + + if (srcbuff == NULL || datalen <= 0) + { + wlinfo("Skip clm blob...\n"); + return 0; + } + else + { + wlinfo("Download %d bytes @ 0x%08x\n", datalen, srcbuff); + } + + /* Divide clm blob into chunks */ + + downloadbuff = kmm_malloc(sizeof(struct wl_dload_data) + MAX_CHUNK_LEN); + if (!downloadbuff) + { + wlerr("No memory for clm data\n"); + return -ENOMEM; + } + + dl_flag = DL_BEGIN; + do + { + FAR struct wl_dload_data *dlhead; + unsigned int chunk_len = datalen >= MAX_CHUNK_LEN ? MAX_CHUNK_LEN : datalen; + uint32_t out_len; + + memcpy(downloadbuff + sizeof(struct wl_dload_data), srcbuff, chunk_len); + datalen -= chunk_len; + srcbuff += chunk_len; + + if (datalen <= 0) + { + dl_flag |= DL_END; + } + + /* clm header */ + + dlhead = (struct wl_dload_data *)downloadbuff; + dlhead->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | dl_flag; + dlhead->dload_type = DL_TYPE_CLM; + dlhead->len = chunk_len; + dlhead->crc = 0; + + out_len = chunk_len + sizeof(struct wl_dload_data); + out_len = (out_len + 7) & ~0x7U; + + ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true, + IOVAR_STR_CLMLOAD, downloadbuff, + &out_len); + + dl_flag &= (uint16_t)~DL_BEGIN; + } + while ((datalen > 0) && (ret == OK)); + + kmm_free(downloadbuff); + return ret; +} + int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv) { int ret; @@ -221,11 +326,19 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv) uint8_t tmp_buf[64]; int interface = CHIP_STA_INTERFACE; + /* Download clm blob if needed */ + + ret = bcmf_driver_download_clm(priv); + if (ret != OK) + { + return -EIO; + } + /* Disable TX Gloming feature */ out_len = 4; - *(uint32_t *)tmp_buf = 0; - ret = bcmf_cdc_iovar_request(priv, interface, false, + *(FAR uint32_t *)tmp_buf = 0; + ret = bcmf_cdc_iovar_request(priv, interface, true, IOVAR_STR_TX_GLOM, tmp_buf, &out_len); if (ret != OK) @@ -236,9 +349,9 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv) /* FIXME disable power save mode */ out_len = 4; - value = 0; - ret = bcmf_cdc_ioctl(priv, interface, true, WLC_SET_PM, - (uint8_t *)&value, &out_len); + value = 0; + ret = bcmf_cdc_ioctl(priv, interface, true, WLC_SET_PM, + (uint8_t *)&value, &out_len); if (ret != OK) { return ret; @@ -258,16 +371,17 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv) /* TODO configure roaming if needed. Disable for now */ out_len = 4; - value = 1; - ret = bcmf_cdc_iovar_request(priv, interface, true, IOVAR_STR_ROAM_OFF, - (uint8_t *)&value, - &out_len); + value = 1; + ret = bcmf_cdc_iovar_request(priv, interface, true, + IOVAR_STR_ROAM_OFF, + (FAR uint8_t *)&value, + &out_len); /* TODO configure EAPOL version to default */ out_len = 8; - ((uint32_t *)tmp_buf)[0] = interface; - ((uint32_t *)tmp_buf)[1] = (uint32_t)-1; + ((FAR uint32_t *)tmp_buf)[0] = interface; + ((FAR uint32_t *)tmp_buf)[1] = (uint32_t)-1; if (bcmf_cdc_iovar_request(priv, interface, true, "bsscfg:"IOVAR_STR_SUP_WPA2_EAPVER, tmp_buf, @@ -279,9 +393,9 @@ int bcmf_driver_initialize(FAR struct bcmf_dev_s *priv) /* Query firmware version string */ out_len = sizeof(tmp_buf); - ret = bcmf_cdc_iovar_request(priv, interface, false, - IOVAR_STR_VERSION, tmp_buf, - &out_len); + ret = bcmf_cdc_iovar_request(priv, interface, false, + IOVAR_STR_VERSION, tmp_buf, + &out_len); if (ret != OK) { return -EIO; diff --git a/drivers/wireless/ieee80211/bcmf_ioctl.h b/drivers/wireless/ieee80211/bcmf_ioctl.h index 48d69bf1843..f306ec137f5 100644 --- a/drivers/wireless/ieee80211/bcmf_ioctl.h +++ b/drivers/wireless/ieee80211/bcmf_ioctl.h @@ -712,6 +712,7 @@ typedef struct wlc_iov_trx_s #define IOVAR_STR_AMPDU_MPDU "ampdu_mpdu" #define IOVAR_STR_AMPDU_RX_FACTOR "ampdu_rx_factor" #define IOVAR_STR_MIMO_BW_CAP "mimo_bw_cap" +#define IOVAR_STR_CLMLOAD "clmload" #define WLC_IOCTL_MAGIC ( 0x14e46c77 ) #define WLC_IOCTL_VERSION ( 1 ) diff --git a/drivers/wireless/ieee80211/bcmf_netdev.c b/drivers/wireless/ieee80211/bcmf_netdev.c index 98501006219..7452d863932 100644 --- a/drivers/wireless/ieee80211/bcmf_netdev.c +++ b/drivers/wireless/ieee80211/bcmf_netdev.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/bcmf_netdev.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -110,22 +110,14 @@ #define BUF ((struct eth_hdr_s *)priv->bc_dev.d_buf) -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /* Common TX logic */ -static int bcmf_transmit(FAR struct bcmf_dev_s *priv, - struct bcmf_frame_s *frame); +static int bcmf_transmit(FAR struct bcmf_dev_s *priv, + FAR struct bcmf_frame_s *frame); static void bcmf_receive(FAR struct bcmf_dev_s *priv); static int bcmf_txpoll(FAR struct net_driver_s *dev); static void bcmf_rxpoll(FAR void *arg); @@ -145,10 +137,10 @@ static int bcmf_txavail(FAR struct net_driver_s *dev); #if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) static int bcmf_addmac(FAR struct net_driver_s *dev, - FAR const uint8_t *mac); + FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP static int bcmf_rmmac(FAR struct net_driver_s *dev, - FAR const uint8_t *mac); + FAR const uint8_t *mac); #endif #ifdef CONFIG_NET_ICMPv6 static void bcmf_ipv6multicast(FAR struct bcmf_dev_s *priv); @@ -156,7 +148,7 @@ static void bcmf_ipv6multicast(FAR struct bcmf_dev_s *priv); #endif #ifdef CONFIG_NETDEV_IOCTL static int bcmf_ioctl(FAR struct net_driver_s *dev, int cmd, - unsigned long arg); + unsigned long arg); #endif /**************************************************************************** @@ -244,7 +236,7 @@ static int bcmf_transmit(FAR struct bcmf_dev_s *priv, static void bcmf_receive(FAR struct bcmf_dev_s *priv) { struct bcmf_frame_s *frame; - // wlinfo("Entry\n"); + do { /* Request frame buffer from bus interface */ @@ -254,12 +246,14 @@ static void bcmf_receive(FAR struct bcmf_dev_s *priv) if (frame == NULL) { /* No more frame to process */ + break; } if (!priv->bc_bifup) { /* Interface down, drop frame */ + priv->bus->free_frame(priv, frame); continue; } @@ -275,6 +269,24 @@ static void bcmf_receive(FAR struct bcmf_dev_s *priv) pkt_input(&priv->bc_dev); #endif + /* Check if this is an 802.1Q VLAN tagged packet */ + + if (BUF->type == HTONS(TPID_8021QVLAN)) + { + /* Need to remove the 4 octet VLAN Tag, by moving src and dest + * addresses 4 octets to the right, and then read the actual + * ethertype. The VLAN ID and priority fields are currently + * ignored. + */ + + uint8_t temp_buffer[12]; + memcpy( temp_buffer, frame->data, 12); + memcpy( frame->data + 4, temp_buffer, 12); + + priv->bc_dev.d_buf = frame->data = frame->data + 4; + priv->bc_dev.d_len -= 4; + } + /* We only accept IP packets of the configured type and ARP packets */ #ifdef CONFIG_NET_IPv4 @@ -392,7 +404,11 @@ static void bcmf_receive(FAR struct bcmf_dev_s *priv) else #endif { - wlerr("ERROR: RX dropped\n"); + /* On some routers, it may constantly receive mysterious packet... + * https://www.wireshark.org/docs/wsar_html/epan/etypes_8h.html + * for more etypes definitions. + */ + NETDEV_RXDROPPED(&priv->bc_dev); priv->bus->free_frame(priv, frame); } diff --git a/drivers/wireless/ieee80211/bcmf_sdio.c b/drivers/wireless/ieee80211/bcmf_sdio.c index d13276c2636..57c09bfd44f 100644 --- a/drivers/wireless/ieee80211/bcmf_sdio.c +++ b/drivers/wireless/ieee80211/bcmf_sdio.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/ieee80211/bcmf_sdio.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -67,9 +67,13 @@ #include "bcmf_sdio_regs.h" /* Supported chip configurations */ + #ifdef CONFIG_IEEE80211_BROADCOM_BCM43362 extern const struct bcmf_sdio_chip bcmf_43362_config_sdio; #endif +#ifdef CONFIG_IEEE80211_BROADCOM_BCM43438 + extern const struct bcmf_sdio_chip bcmf_43438_config_sdio; +#endif /**************************************************************************** * Pre-processor Definitions @@ -84,6 +88,12 @@ #define BCMF_WAITDOG_TIMEOUT_TICK (5*CLOCKS_PER_SEC) +/* Chipcommon registers */ + +#define CHIPCOMMON_GPIO_CONTROL ((uint32_t)(0x18000000 + 0x6C) ) +#define CHIPCOMMON_SR_CONTROL0 ((uint32_t)(0x18000000 + 0x504) ) +#define CHIPCOMMON_SR_CONTROL1 ((uint32_t)(0x18000000 + 0x508) ) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -97,7 +107,7 @@ static int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus); static void bcmf_hwuninitialize(FAR struct bcmf_sdio_dev_s *sbus); static int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus); -static int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg); +static int bcmf_oob_irq(FAR void *arg); static int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep); @@ -106,11 +116,15 @@ static int bcmf_sdio_thread(int argc, char **argv); static int bcmf_sdio_find_block_size(unsigned int size); +static int bcmf_sdio_sr_init(FAR struct bcmf_sdio_dev_s *sbus); +static bool brcm_chip_sr_capable(FAR struct bcmf_sdio_dev_s *sbus); + /**************************************************************************** * Private Data ****************************************************************************/ /* FIXME remove */ + FAR struct bcmf_dev_s *g_sdio_priv; /* Buffer pool for SDIO bus interface @@ -125,18 +139,18 @@ static struct bcmf_sdio_frame g_pktframes[BCMF_PKT_POOL_SIZE]; * Private Functions ****************************************************************************/ -int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg) +int bcmf_oob_irq(FAR void *arg) { - FAR struct bcmf_sdio_dev_s *sbus = (struct bcmf_sdio_dev_s *)arg; + FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)arg; if (sbus->ready) { - /* Signal bmcf thread */ + /* Signal bmcf thread */ sbus->irq_pending = true; - nxsem_post(&sbus->thread_signal); } + return OK; } @@ -158,22 +172,22 @@ int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep) } else { - /* Request HT Avail */ - - ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_HT_AVAIL_REQ | SBSDIO_FORCE_HT); - if (ret != OK) - { - wlerr("HT Avail request failed %d\n", ret); - return ret; - } - - /* Wait for High Troughput clock */ - - loops = 20; + loops = 200; while (--loops > 0) { - up_mdelay(1); + /* Request HT Avail */ + + ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_HT_AVAIL_REQ | SBSDIO_FORCE_HT); + if (ret != OK) + { + wlerr("HT Avail request failed %d\n", ret); + return ret; + } + + /* Wait for High Throughput clock */ + + up_mdelay(100); ret = bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value); if (ret != OK) @@ -184,6 +198,7 @@ int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep) if (value & SBSDIO_HT_AVAIL) { /* High Throughput clock is ready */ + break; } } @@ -246,7 +261,8 @@ int bcmf_probe(FAR struct bcmf_sdio_dev_s *sbus) } /* Default device clock speed is up to 25 Mhz - * We could set EHS bit to operate at a clock rate up to 50 Mhz */ + * We could set EHS bit to operate at a clock rate up to 50 Mhz. + */ SDIO_CLOCK(sbus->sdio_dev, CLOCK_SD_TRANSFER_4BIT); up_mdelay(BCMF_CLOCK_SETUP_DELAY_MS); @@ -280,9 +296,9 @@ int bcmf_businitialize(FAR struct bcmf_sdio_dev_s *sbus) /* Send Active Low-Power clock request */ ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF | - SBSDIO_ALP_AVAIL_REQ | - SBSDIO_FORCE_ALP); + SBSDIO_FORCE_HW_CLKREQ_OFF | + SBSDIO_ALP_AVAIL_REQ | + SBSDIO_FORCE_ALP); if (ret != OK) { @@ -303,6 +319,7 @@ int bcmf_businitialize(FAR struct bcmf_sdio_dev_s *sbus) if (value & SBSDIO_ALP_AVAIL) { /* Active Low-Power clock is ready */ + break; } } @@ -371,20 +388,24 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_sdio_dev_s *sbus) { return ret; } + ret = sdio_enable_interrupt(sbus->sdio_dev, 2); if (ret != OK) { return ret; } +#ifndef CONFIG_BCMFMAC_NO_OOB /* Redirect, configure and enable io for out-of-band interrupt signal */ ret = bcmf_write_reg(sbus, 0, SDIO_CCCR_BRCM_SEPINT, - SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI); + SDIO_SEPINT_MASK | SDIO_SEPINT_OE | + SDIO_SEPINT_ACT_HI); if (ret != OK) { return ret; } +#endif /* Wake up chip to be sure function 2 is running */ @@ -404,8 +425,9 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_sdio_dev_s *sbus) CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID], funcintmask), 2); - bcmf_write_reg(sbus, 1, SBSDIO_WATERMARK, 8); + /* Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped. */ + bcmf_write_reg(sbus, 1, SBSDIO_WATERMARK, 8); return OK; } @@ -457,6 +479,7 @@ int bcmf_sdio_find_block_size(unsigned int size) { int ret = 0; int size_copy = size; + while (size_copy) { size_copy >>= 1; @@ -471,6 +494,65 @@ int bcmf_sdio_find_block_size(unsigned int size) return 1 << (ret - 1); } +/* Init save-restore if the firmware support it: */ + +static int bcmf_sdio_sr_init(FAR struct bcmf_sdio_dev_s *sbus) +{ + uint8_t data; + + if (brcm_chip_sr_capable(sbus)) + { + /* Configure WakeupCtrl register to set HtAvail request bit in + * chipClockCSR register after the sdiod core is powered on. + */ + + bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_WAKEUPCTRL, &data); + data |= SBSDIO_FUNC1_WCTRL_HTWAIT_MASK; + bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_WAKEUPCTRL, data); + + /* Set brcmCardCapability to noCmdDecode mode. + * It makes sdiod_aos to wakeup host for any activity of cmd line, + * even though module won't decode cmd or respond + */ + + bcmf_write_reg(sbus, 0, SDIO_CCCR_BRCM_CARDCAP, SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC); + bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT); + + /* Enable KeepSdioOn (KSO) bit for normal operation */ + + bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_SLEEPCSR, &data); + if((data & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK) == 0) + { + data |= SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; + bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_SLEEPCSR, data); + } + } + + return OK; +} + +/* Check if the firmware supports save restore feature. + * TODO: Add more chip specific logic, and move it to a new bcmf_chip.c file. + */ + +static bool brcm_chip_sr_capable(FAR struct bcmf_sdio_dev_s *sbus) +{ + uint32_t srctrl = 0; + int ret; + + /* Check if fw initialized sr engine */ + + ret = bcmf_read_sbregw(sbus, CHIPCOMMON_SR_CONTROL1, &srctrl); + if (ret != OK) + { + return false; + } + else + { + return (srctrl != 0); + } +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -500,6 +582,7 @@ int bcmf_transfer_bytes(FAR struct bcmf_sdio_dev_s *sbus, bool write, return sdio_io_rw_direct(sbus->sdio_dev, write, function, address, *buf, NULL); } + return sdio_io_rw_direct(sbus->sdio_dev, write, function, address, 0, buf); } @@ -551,7 +634,7 @@ int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function, ****************************************************************************/ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, - int minor, FAR struct sdio_dev_s *dev) + int minor, FAR struct sdio_dev_s *dev) { int ret; FAR struct bcmf_sdio_dev_s *sbus; @@ -568,16 +651,16 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, /* Initialize sdio bus device structure */ memset(sbus, 0, sizeof(*sbus)); - sbus->sdio_dev = dev; - sbus->minor = minor; - sbus->ready = false; - sbus->sleeping = true; + sbus->sdio_dev = dev; + sbus->minor = minor; + sbus->ready = false; + sbus->sleeping = true; - sbus->bus.txframe = bcmf_sdpcm_queue_frame; - sbus->bus.rxframe = bcmf_sdpcm_get_rx_frame; + sbus->bus.txframe = bcmf_sdpcm_queue_frame; + sbus->bus.rxframe = bcmf_sdpcm_get_rx_frame; sbus->bus.allocate_frame = bcmf_sdpcm_alloc_frame; - sbus->bus.free_frame = bcmf_sdpcm_free_frame; - sbus->bus.stop = NULL; // TODO + sbus->bus.free_frame = bcmf_sdpcm_free_frame; + sbus->bus.stop = NULL; // TODO /* Init transmit frames queue */ @@ -591,8 +674,8 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, sq_init(&sbus->free_queue); /* Setup free buffer list */ - // FIXME this should be static to driver + for (ret = 0; ret < BCMF_PKT_POOL_SIZE; ret++) { bcmf_dqueue_push(&sbus->free_queue, &g_pktframes[ret].list_entry); @@ -622,7 +705,6 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, /* Initialize device hardware */ ret = bcmf_hwinitialize(sbus); - if (ret != OK) { goto exit_free_waitdog; @@ -631,7 +713,6 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, /* Probe device */ ret = bcmf_probe(sbus); - if (ret != OK) { goto exit_uninit_hw; @@ -640,7 +721,6 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, /* Initialize device bus */ ret = bcmf_businitialize(sbus); - if (ret != OK) { goto exit_uninit_hw; @@ -656,7 +736,14 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, goto exit_uninit_hw; } + ret = bcmf_sdio_sr_init(sbus); + if (ret != OK) + { + goto exit_uninit_hw; + } + /* FIXME global variable for now */ + g_sdio_priv = priv; /* Register sdio bus */ @@ -683,14 +770,16 @@ int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv, sbus->thread_id = ret; - /* sdio bus is up and running */ + /* SDIO bus is up and running */ return OK; exit_uninit_hw: bcmf_hwuninitialize(sbus); + exit_free_waitdog: wd_delete(sbus->waitdog); + exit_free_bus: kmm_free(sbus); priv->bus = NULL; @@ -699,8 +788,9 @@ exit_free_bus: int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus) { - int ret; uint32_t value = 0; + int chipid; + int ret; ret = bcmf_read_sbregw(sbus, SI_ENUM_BASE, &value); if (ret != OK) @@ -708,7 +798,9 @@ int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus) return ret; } - int chipid = value & 0xffff; + chipid = value & 0xffff; + sbus->cur_chip_id = chipid; + switch (chipid) { #ifdef CONFIG_IEEE80211_BROADCOM_BCM43362 @@ -717,10 +809,19 @@ int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus) sbus->chip = (struct bcmf_sdio_chip *)&bcmf_43362_config_sdio; break; #endif + +#ifdef CONFIG_IEEE80211_BROADCOM_BCM43438 + case SDIO_DEVICE_ID_BROADCOM_43430: + wlinfo("bcm43438 chip detected\n"); + sbus->chip = (struct bcmf_sdio_chip *)&bcmf_43438_config_sdio; + break; +#endif + default: wlerr("chip 0x%x is not supported\n", chipid); return -ENODEV; - } + } + return OK; } @@ -741,7 +842,7 @@ int bcmf_sdio_thread(int argc, char **argv) FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; int ret; - wlinfo("Enter\n"); + wlinfo(" Enter\n"); /* FIXME wait for the chip to be ready to receive commands */ @@ -774,23 +875,20 @@ int bcmf_sdio_thread(int argc, char **argv) sbus->irq_pending = false; bcmf_read_sbregw(sbus, - CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID], - intstatus), &sbus->intstatus); + CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID], + intstatus), &sbus->intstatus); /* Clear interrupts */ bcmf_write_sbregw(sbus, - CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID], - intstatus), sbus->intstatus); - // wlinfo("intstatus %x\n", sbus->intstatus); + CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID], + intstatus), sbus->intstatus); } /* On frame indication, read available frames */ if (sbus->intstatus & I_HMB_FRAME_IND) { - // wlinfo("Frames available\n"); - do { ret = bcmf_sdpcm_readframe(priv); @@ -830,7 +928,6 @@ int bcmf_sdio_thread(int argc, char **argv) } wlinfo("Exit\n"); - return 0; } @@ -843,7 +940,7 @@ struct bcmf_sdio_frame *bcmf_sdio_allocate_frame(FAR struct bcmf_dev_s *priv, while (1) { - if (nxsem_wait(&sbus->queue_mutex < 0)) + if (nxsem_wait(&sbus->queue_mutex) < 0) { PANIC(); } @@ -867,27 +964,28 @@ struct bcmf_sdio_frame *bcmf_sdio_allocate_frame(FAR struct bcmf_dev_s *priv, if (block) { // TODO use signaling semaphore + wlinfo("alloc failed %d\n", tx); up_mdelay(100); continue; } + wlinfo("No avail buffer\n"); return NULL; } sframe = container_of(entry, struct bcmf_sdio_frame, list_entry); - sframe->header.len = HEADER_SIZE + MAX_NET_DEV_MTU; + sframe->header.len = HEADER_SIZE + MAX_NET_DEV_MTU; sframe->header.base = sframe->data; sframe->header.data = sframe->data; - sframe->tx = tx; + sframe->tx = tx; return sframe; } void bcmf_sdio_free_frame(FAR struct bcmf_dev_s *priv, struct bcmf_sdio_frame *sframe) { - // wlinfo("free %p\n", sframe); FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; if (nxsem_wait(&sbus->queue_mutex) < 0) @@ -901,5 +999,6 @@ void bcmf_sdio_free_frame(FAR struct bcmf_dev_s *priv, { sbus->tx_queue_count -= 1; } + nxsem_post(&sbus->queue_mutex); } diff --git a/drivers/wireless/ieee80211/bcmf_sdio.h b/drivers/wireless/ieee80211/bcmf_sdio.h index 692b1a92516..a08746c4468 100644 --- a/drivers/wireless/ieee80211/bcmf_sdio.h +++ b/drivers/wireless/ieee80211/bcmf_sdio.h @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/wireless/ieee80211/bcmf_sdio.h * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -69,6 +69,9 @@ struct bcmf_sdio_chip uint8_t *nvram_image; unsigned int *nvram_image_size; + + uint8_t *clm_blob_image; + unsigned int *clm_blob_image_size; }; /* sdio bus structure extension */ @@ -79,6 +82,7 @@ struct bcmf_sdio_dev_s FAR struct sdio_dev_s *sdio_dev; /* The SDIO device bound to this instance */ int minor; /* Device minor number */ + int cur_chip_id; /* Chip ID read from the card */ struct bcmf_sdio_chip *chip; /* Chip specific configuration */ volatile bool ready; /* Current device status */ @@ -144,4 +148,4 @@ struct bcmf_sdio_frame *bcmf_sdio_allocate_frame(FAR struct bcmf_dev_s *priv, void bcmf_sdio_free_frame(FAR struct bcmf_dev_s *priv, struct bcmf_sdio_frame *sframe); -#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H */ \ No newline at end of file +#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H */ diff --git a/drivers/wireless/ieee80211/bcmf_sdio_core.h b/drivers/wireless/ieee80211/bcmf_sdio_core.h index 6131b1be3aa..eb66320867b 100644 --- a/drivers/wireless/ieee80211/bcmf_sdio_core.h +++ b/drivers/wireless/ieee80211/bcmf_sdio_core.h @@ -30,11 +30,12 @@ #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_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 +#define SDIO_DEVICE_ID_BROADCOM_43430 43430 /* Core reg address translation. * Both macro's returns a 32 bits byte address on the backplane bus. diff --git a/include/nuttx/wireless/ieee80211/bcmf_board.h b/include/nuttx/wireless/ieee80211/bcmf_board.h index fc1c4ff9ac3..23a5330f18b 100644 --- a/include/nuttx/wireless/ieee80211/bcmf_board.h +++ b/include/nuttx/wireless/ieee80211/bcmf_board.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/wireless/ieee80211/bcmf_board.h * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Simon Piriou * * Redistribution and use in source and binary forms, with or without @@ -69,6 +69,7 @@ extern "C" * Input Parameters: * minor - zero based minor device number which is unique * for each wlan device. + * ************************************************************************************/ void bcmf_board_initialize(int minor); @@ -84,6 +85,7 @@ void bcmf_board_initialize(int minor); * minor - zero based minor device number which is unique * for each wlan device. * power - true to power WLAN chip else false + * ************************************************************************************/ void bcmf_board_power(int minor, bool power); @@ -99,6 +101,7 @@ void bcmf_board_power(int minor, bool power); * minor - zero based minor device number which is unique * for each wlan device. * reset - true to set WLAN chip in reset state else false + * ************************************************************************************/ void bcmf_board_reset(int minor, bool reset); @@ -115,9 +118,10 @@ void bcmf_board_reset(int minor, bool reset); * for each wlan device. * func - WLAN chip callback function that must be called on gpio event * arg - WLAN chip internal structure that must be passed to callback + * ************************************************************************************/ -void bcmf_board_setup_oob_irq(int minor, xcpt_t func, void *arg); +void bcmf_board_setup_oob_irq(int minor, int (*func)(void *), void *arg); #undef EXTERN #ifdef __cplusplus diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 19fa1c411c6..64ac5ac7739 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -958,7 +958,8 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, if (dev) { #ifdef CONFIG_NET_ETHERNET - if (dev->d_lltype == NET_LL_ETHERNET) + if (dev->d_lltype == NET_LL_ETHERNET || + dev->d_lltype == NET_LL_IEEE80211) { req->ifr_hwaddr.sa_family = AF_INETX; memcpy(req->ifr_hwaddr.sa_data,