mirror of https://github.com/ARMmbed/mbed-os.git
316 lines
12 KiB
C
Executable File
316 lines
12 KiB
C
Executable File
/***********************************************************************************************//**
|
|
* \file cybsp_wifi.c
|
|
*
|
|
* \brief
|
|
* Provides utility functions that are used by board support packages.
|
|
*
|
|
***************************************************************************************************
|
|
* \copyright
|
|
* Copyright 2018-2021 Cypress Semiconductor Corporation
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
**************************************************************************************************/
|
|
|
|
#include "cybsp.h"
|
|
#include "cybsp_wifi.h"
|
|
#include "cy_network_buffer.h"
|
|
#include "cyabs_rtos.h"
|
|
#include "whd_types.h"
|
|
#include "cyhal.h"
|
|
#if defined(COMPONENT_BSP_DESIGN_MODUS) || defined(COMPONENT_CUSTOM_DESIGN_MODUS)
|
|
#include "cycfg.h"
|
|
#endif
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define THREAD_STACK_SIZE 5120
|
|
#define THREAD_PRIORITY CY_RTOS_PRIORITY_HIGH
|
|
#define COUNTRY WHD_COUNTRY_AUSTRALIA
|
|
#define DEFAULT_OOB_PIN 0
|
|
#define WLAN_POWER_UP_DELAY_MS 250
|
|
#define WLAN_CBUCK_DISCHARGE_MS 10
|
|
|
|
#define SDIO_ENUMERATION_TRIES 500
|
|
#define SDIO_RETRY_DELAY_MS 1
|
|
#define SDIO_BUS_LEVEL_MAX_RETRIES 5
|
|
|
|
#if !defined(CY_WIFI_OOB_INTR_PRIORITY)
|
|
#define CY_WIFI_OOB_INTR_PRIORITY 2
|
|
#endif
|
|
|
|
// Determine whether to use the SDIO oob interrupt.
|
|
// Use CY_WIFI_HOST_WAKE_SW_FORCE to force the enable status.
|
|
#if !defined(CY_WIFI_HOST_WAKE_SW_FORCE)
|
|
#define CY_SDIO_BUS_USE_OOB_INTR (1u)
|
|
#else
|
|
#define CY_SDIO_BUS_USE_OOB_INTR CY_WIFI_HOST_WAKE_SW_FORCE
|
|
#endif // defined(CY_WIFI_HOST_WAKE_SW_FORCE)
|
|
|
|
// *SUSPEND-FORMATTING*
|
|
#if (CY_SDIO_BUS_USE_OOB_INTR != 0)
|
|
// Setup configuration based on configurator or BSP, where configurator has precedence.
|
|
#if defined(CYCFG_WIFI_HOST_WAKE_ENABLED)
|
|
#define CY_WIFI_HOST_WAKE_GPIO CYCFG_WIFI_HOST_WAKE_GPIO
|
|
#define CY_WIFI_HOST_WAKE_IRQ_EVENT CYCFG_WIFI_HOST_WAKE_IRQ_EVENT
|
|
#else
|
|
// Setup host-wake pin
|
|
#if defined(CYBSP_WIFI_HOST_WAKE)
|
|
#define CY_WIFI_HOST_WAKE_GPIO CYBSP_WIFI_HOST_WAKE
|
|
#else
|
|
#error "CYBSP_WIFI_HOST_WAKE must be defined"
|
|
#endif
|
|
// Setup host-wake irq
|
|
#if defined(CYBSP_WIFI_HOST_WAKE_IRQ_EVENT)
|
|
#define CY_WIFI_HOST_WAKE_IRQ_EVENT CYBSP_WIFI_HOST_WAKE_IRQ_EVENT
|
|
#else
|
|
#error "CYBSP_WIFI_HOST_WAKE_IRQ_EVENT must be defined"
|
|
#endif
|
|
#endif // if defined(CYCFG_WIFI_HOST_WAKE_ENABLED)
|
|
#else // if (CY_SDIO_BUS_USE_OOB_INTR != 0)
|
|
#define CY_WIFI_HOST_WAKE_GPIO CYHAL_NC_PIN_VALUE
|
|
#define CY_WIFI_HOST_WAKE_IRQ_EVENT 0
|
|
#endif // (CY_SDIO_BUS_USE_OOB_INTR != 0)
|
|
// *RESUME-FORMATTING*
|
|
|
|
static whd_driver_t whd_drv;
|
|
|
|
extern whd_resource_source_t resource_ops;
|
|
|
|
static whd_buffer_funcs_t buffer_if_default =
|
|
{
|
|
.whd_host_buffer_get = cy_host_buffer_get,
|
|
.whd_buffer_release = cy_buffer_release,
|
|
.whd_buffer_get_current_piece_data_pointer = cy_buffer_get_current_piece_data_pointer,
|
|
.whd_buffer_get_current_piece_size = cy_buffer_get_current_piece_size,
|
|
.whd_buffer_set_size = cy_buffer_set_size,
|
|
.whd_buffer_add_remove_at_front = cy_buffer_add_remove_at_front,
|
|
};
|
|
|
|
static whd_netif_funcs_t netif_if_default =
|
|
{
|
|
.whd_network_process_ethernet_data = cy_network_process_ethernet_data,
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// sdio_try_send_cmd
|
|
//--------------------------------------------------------------------------------------------------
|
|
static cy_rslt_t sdio_try_send_cmd(const cyhal_sdio_t* sdio_object, cyhal_transfer_t direction, \
|
|
cyhal_sdio_command_t command, uint32_t argument,
|
|
uint32_t* response)
|
|
{
|
|
uint8_t loop_count = 0;
|
|
cy_rslt_t result = CYBSP_RSLT_WIFI_SDIO_ENUM_TIMEOUT;
|
|
do
|
|
{
|
|
result = cyhal_sdio_send_cmd(sdio_object, direction, command, argument, response);
|
|
if (result != CY_RSLT_SUCCESS)
|
|
{
|
|
cyhal_system_delay_ms(SDIO_RETRY_DELAY_MS);
|
|
}
|
|
loop_count++;
|
|
} while(result != CY_RSLT_SUCCESS && loop_count <= SDIO_BUS_LEVEL_MAX_RETRIES);
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// cybsp_sdio_enumerate
|
|
//--------------------------------------------------------------------------------------------------
|
|
static cy_rslt_t cybsp_sdio_enumerate(const cyhal_sdio_t* sdio_object)
|
|
{
|
|
cy_rslt_t result = CYBSP_RSLT_WIFI_SDIO_ENUM_TIMEOUT;
|
|
uint32_t loop_count = 0;
|
|
uint32_t rel_addr;
|
|
uint32_t response_ignored = 0;
|
|
uint32_t no_argument = 0;
|
|
|
|
do
|
|
{
|
|
// Send CMD0 to set it to idle state
|
|
sdio_try_send_cmd(sdio_object, CYHAL_WRITE, CYHAL_SDIO_CMD_GO_IDLE_STATE, no_argument,
|
|
&response_ignored /*ignored*/);
|
|
|
|
// CMD5.
|
|
sdio_try_send_cmd(sdio_object, CYHAL_READ, CYHAL_SDIO_CMD_IO_SEND_OP_COND, no_argument,
|
|
&response_ignored /*ignored*/);
|
|
|
|
// Send CMD3 to get RCA.
|
|
result = sdio_try_send_cmd(sdio_object, CYHAL_READ, CYHAL_SDIO_CMD_SEND_RELATIVE_ADDR,
|
|
no_argument, &rel_addr);
|
|
if (result != CY_RSLT_SUCCESS)
|
|
{
|
|
cyhal_system_delay_ms(SDIO_RETRY_DELAY_MS);
|
|
}
|
|
loop_count++;
|
|
} while (result != CY_RSLT_SUCCESS && loop_count <= SDIO_ENUMERATION_TRIES);
|
|
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
// Send CMD7 with the returned RCA to select the card
|
|
result = sdio_try_send_cmd(sdio_object, CYHAL_WRITE, CYHAL_SDIO_CMD_SELECT_CARD, rel_addr,
|
|
&response_ignored);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// reset_wifi_chip
|
|
//--------------------------------------------------------------------------------------------------
|
|
static cy_rslt_t reset_wifi_chip(void)
|
|
{
|
|
// WiFi into reset
|
|
cy_rslt_t result = cyhal_gpio_init(CYBSP_WIFI_WL_REG_ON, CYHAL_GPIO_DIR_OUTPUT,
|
|
CYHAL_GPIO_DRIVE_PULLUP, false);
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
// Allow CBUCK regulator to discharge
|
|
cyhal_system_delay_ms(WLAN_CBUCK_DISCHARGE_MS);
|
|
// WiFi out of reset
|
|
cyhal_gpio_write(CYBSP_WIFI_WL_REG_ON, true);
|
|
cyhal_system_delay_ms(WLAN_POWER_UP_DELAY_MS);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// init_sdio_bus
|
|
//--------------------------------------------------------------------------------------------------
|
|
static cy_rslt_t init_sdio_bus(void)
|
|
{
|
|
cy_rslt_t result = reset_wifi_chip();
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
cyhal_sdio_t* sdio_p = cybsp_get_wifi_sdio_obj();
|
|
result = cybsp_sdio_enumerate(sdio_p);
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
whd_sdio_config_t whd_sdio_config;
|
|
whd_oob_config_t oob_config;
|
|
cyhal_sdio_cfg_t config;
|
|
|
|
// If the configurator reserved the pin, we need to release it here since
|
|
// WHD will try to reserve it again. WHD has no idea about configurators
|
|
// and expects it can reserve the pin that it is going to manage.
|
|
#if defined(CYCFG_WIFI_HOST_WAKE_ENABLED)
|
|
cyhal_resource_inst_t pinRsc = cyhal_utils_get_gpio_resource(CY_WIFI_HOST_WAKE_GPIO);
|
|
cyhal_hwmgr_free(&pinRsc);
|
|
#endif
|
|
|
|
oob_config.host_oob_pin = CY_WIFI_HOST_WAKE_GPIO;
|
|
oob_config.dev_gpio_sel = DEFAULT_OOB_PIN;
|
|
oob_config.is_falling_edge = (CY_WIFI_HOST_WAKE_IRQ_EVENT == CYHAL_GPIO_IRQ_FALL)
|
|
? WHD_TRUE
|
|
: WHD_FALSE;
|
|
oob_config.intr_priority = CY_WIFI_OOB_INTR_PRIORITY;
|
|
|
|
whd_sdio_config.sdio_1bit_mode = WHD_FALSE;
|
|
whd_sdio_config.high_speed_sdio_clock = WHD_FALSE;
|
|
whd_sdio_config.oob_config = oob_config;
|
|
whd_bus_sdio_attach(whd_drv, &whd_sdio_config, sdio_p);
|
|
|
|
// Increase frequency to 25 MHz for better performance
|
|
config.frequencyhal_hz = 25000000;
|
|
config.block_size = 0;
|
|
cyhal_sdio_configure(sdio_p, &config);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// cybsp_wifi_init_primary_extended
|
|
//--------------------------------------------------------------------------------------------------
|
|
cy_rslt_t cybsp_wifi_init_primary_extended(whd_interface_t* interface,
|
|
whd_resource_source_t* resource_if,
|
|
whd_buffer_funcs_t* buffer_if,
|
|
whd_netif_funcs_t* netif_if)
|
|
{
|
|
whd_init_config_t whd_init_config;
|
|
whd_init_config.thread_stack_size = (uint32_t)THREAD_STACK_SIZE;
|
|
whd_init_config.thread_stack_start = NULL;
|
|
whd_init_config.thread_priority = (uint32_t)THREAD_PRIORITY;
|
|
whd_init_config.country = COUNTRY;
|
|
|
|
if (resource_if == NULL)
|
|
{
|
|
resource_if = &resource_ops;
|
|
}
|
|
if (buffer_if == NULL)
|
|
{
|
|
buffer_if = &buffer_if_default;
|
|
}
|
|
if (netif_if == NULL)
|
|
{
|
|
netif_if = &netif_if_default;
|
|
}
|
|
|
|
cy_rslt_t result = whd_init(&whd_drv, &whd_init_config, resource_if, buffer_if, netif_if);
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
result = init_sdio_bus();
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
result = whd_wifi_on(whd_drv, interface);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// cybsp_wifi_init_secondary
|
|
//--------------------------------------------------------------------------------------------------
|
|
cy_rslt_t cybsp_wifi_init_secondary(whd_interface_t* interface, whd_mac_t* mac_address)
|
|
{
|
|
return whd_add_secondary_interface(whd_drv, mac_address, interface);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// cybsp_wifi_deinit
|
|
//--------------------------------------------------------------------------------------------------
|
|
cy_rslt_t cybsp_wifi_deinit(whd_interface_t interface)
|
|
{
|
|
cy_rslt_t result = whd_wifi_off(interface);
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
result = whd_deinit(interface);
|
|
if (result == CY_RSLT_SUCCESS)
|
|
{
|
|
whd_bus_sdio_detach(whd_drv);
|
|
cyhal_gpio_free(CYBSP_WIFI_WL_REG_ON);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// cybsp_get_wifi_driver
|
|
//--------------------------------------------------------------------------------------------------
|
|
whd_driver_t cybsp_get_wifi_driver(void)
|
|
{
|
|
return whd_drv;
|
|
}
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|