blob: 7bb89a07e9ed8062d6d8eb54b114f27afa9e19f7 [file] [log] [blame]
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief Coexistence functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/gpio.h>
#include "coex.h"
#include "coex_struct.h"
#include "fmac_main.h"
#include "fmac_api.h"
LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
static struct nrf_wifi_ctx_zep *rpu_ctx = &rpu_drv_priv_zep.rpu_ctx_zep;
#define CH_BASE_ADDRESS ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL
#define COEX_CONFIG_FIXED_PARAMS 4
#define COEX_REG_CFG_OFFSET_SHIFT 24
/* copied from uccp530_77_registers_ext_sys_bus.h of UCCP toolkit */
#define EXT_SYS_WLANSYSCOEX_CH_CONTROL 0x0000
#define ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL 0xA401BC00UL
#define EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE 0x0004
#define EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS 0x0040
#define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 0x008C
#define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 0x013C
#define EXT_SYS_WLANSYSCOEX_RESET_SHIFT 0
/* copied from uccp530_77_registers.h of UCCP toolkit */
#define ABS_PMB_WLAN_MAC_CTRL_PULSED_SOFTWARE_RESET 0xA5009A00UL
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
#define NRF_RADIO_COEX_NODE DT_NODELABEL(nrf70)
static const struct gpio_dt_spec sr_rf_switch_spec =
GPIO_DT_SPEC_GET(NRF_RADIO_COEX_NODE, srrf_switch_gpios);
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
/* PTA registers configuration of Coexistence Hardware */
/* Separate antenna configuration, WLAN in 2.4GHz. For BLE protocol. */
const uint16_t config_buffer_SEA_ble[] = {
0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
0x00F5, 0x0019, 0x0019, 0x0074, 0x0074,
0x0008, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
0x01F6, 0x0061, 0x0061, 0x01E2, 0x0008,
0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
0x0008, 0x01E2, 0x0051, 0x0051, 0x0074,
0x0074, 0x00F6, 0x0019, 0x0062, 0x0019,
0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
};
/* Separate antenna configuration, WLAN in 2.4GHz. For non BLE protocol */
const uint16_t config_buffer_SEA_non_ble[] = {
0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
0x00F5, 0x0061, 0x0061, 0x0074, 0x0074,
0x01E2, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
0x01F6, 0x0061, 0x0061, 0x01E2, 0x01E2,
0x00C4, 0x00C4, 0x0061, 0x0061, 0x0008,
0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
0x0162, 0x0162, 0x0019, 0x0019, 0x01F6,
0x01F6, 0x00F6, 0x0019, 0x0062, 0x0019,
0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
};
/* Shared antenna configuration, WLAN in 2.4GHz. */
const uint16_t config_buffer_SHA[] = {
0x0019, 0x00F6, 0x0008, 0x00E2, 0x0015,
0x00F5, 0x0019, 0x0019, 0x0004, 0x01F6,
0x0008, 0x01E2, 0x00F5, 0x00F5, 0x01F6,
0x01F6, 0x00E1, 0x00E1, 0x01E2, 0x0008,
0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
0x0008, 0x0015, 0x00F5, 0x00F5, 0x00F5,
0x0008, 0x01E2, 0x00E1, 0x00E1, 0x0004,
0x01F6, 0x00F6, 0x0019, 0x00E2, 0x0019,
0x00F6, 0x0008, 0x00E2, 0x0008, 0x001A
};
/* Shared/separate antennas, WLAN in 5GHz */
const uint16_t config_buffer_5G[] = {
0x0039, 0x0076, 0x0028, 0x0062, 0x0075,
0x0075, 0x0061, 0x0061, 0x0074, 0x0074,
0x0060, 0x0060, 0x0075, 0x0075, 0x0064,
0x0064, 0x0071, 0x0071, 0x0060, 0x0060,
0x0064, 0x0064, 0x0061, 0x0061, 0x0060,
0x0060, 0x0075, 0x0075, 0x0075, 0x0075,
0x0060, 0x0060, 0x0071, 0x0071, 0x0074,
0x0074, 0x0076, 0x0039, 0x0062, 0x0039,
0x0076, 0x0028, 0x0062, 0x0028, 0x003A
};
/* non-PTA register configuration of coexistence hardware */
/* Shared antenna */
const uint32_t ch_config_sha[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000050, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
/* Separate antennas. For BLE protocol. */
const uint32_t ch_config_sep_ble[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
/* Separate antennas. For non BLE protocol. */
const uint32_t ch_config_sep_non_ble[] = {
0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000
};
int nrf_wifi_coex_config_non_pta(bool separate_antennas, bool is_sr_protocol_ble)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
const uint32_t *config_buffer_ptr = NULL;
uint32_t start_offset = 0;
uint32_t num_reg_to_config = 1;
uint32_t cmd_len, index;
/* Offset from the base address of CH */
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE -
EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
/* Number of registers to be configured */
num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS -
EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE) >> 2) + 1;
if (separate_antennas) {
if (is_sr_protocol_ble) {
config_buffer_ptr = ch_config_sep_ble;
} else {
config_buffer_ptr = ch_config_sep_non_ble;
}
} else {
config_buffer_ptr = ch_config_sha;
}
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
for (index = 0; index < num_reg_to_config; index++) {
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(*(config_buffer_ptr + index));
start_offset++;
}
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
return -1;
}
return 0;
}
int nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band, bool separate_antennas,
bool is_sr_protocol_ble)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
const uint16_t *config_buffer_ptr = NULL;
uint32_t start_offset = 0;
uint32_t num_reg_to_config = 1;
uint32_t cmd_len, index;
/* common for both SHA and SEA */
/* Indicates offset from the base address of CH */
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 -
EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
/* Number of contiguous registers to be configured starting from base+offset */
num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 -
EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0) >> 2) + 1;
if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_2_4_GHZ) {
/* WLAN operating in 2.4GHz */
if (separate_antennas) {
/* separate antennas configuration */
if (is_sr_protocol_ble) {
config_buffer_ptr = config_buffer_SEA_ble;
} else {
config_buffer_ptr = config_buffer_SEA_non_ble;
}
} else {
/* Shared antenna configuration */
config_buffer_ptr = config_buffer_SHA;
}
} else if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_5_GHZ) {
/* WLAN operating in 5GHz */
config_buffer_ptr = config_buffer_5G;
} else {
return -EINVAL;
}
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
for (index = 0; index < num_reg_to_config; index++) {
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(*(config_buffer_ptr+index));
start_offset++;
}
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
return -1;
}
return 0;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
int nrf_wifi_config_sr_switch(bool separate_antennas)
{
int ret;
if (!device_is_ready(sr_rf_switch_spec.port)) {
LOG_ERR("Unable to open GPIO device");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
if (ret < 0) {
LOG_ERR("Unable to configure GPIO device");
return -1;
}
if (separate_antennas) {
gpio_pin_set_dt(&sr_rf_switch_spec, 0x0);
LOG_INF("GPIO P1.10 set to 0");
} else {
gpio_pin_set_dt(&sr_rf_switch_spec, 0x1);
LOG_INF("GPIO P1.10 set to 1");
}
return 0;
}
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
int nrf_wifi_coex_hw_reset(void)
{
enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
struct coex_ch_configuration params = { 0 };
uint32_t num_reg_to_config = 1;
uint32_t start_offset = 0;
uint32_t index = 0;
uint32_t coex_hw_reset = 1;
uint32_t cmd_len;
/* reset CH */
params.message_id = HW_CONFIGURATION;
params.num_reg_to_config = num_reg_to_config;
params.hw_to_config = COEX_HARDWARE;
params.hw_block_base_addr = CH_BASE_ADDRESS;
start_offset = ((EXT_SYS_WLANSYSCOEX_CH_CONTROL - EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
(coex_hw_reset << EXT_SYS_WLANSYSCOEX_RESET_SHIFT);
cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
(void *)(&params), cmd_len);
if (status != NRF_WIFI_STATUS_SUCCESS) {
LOG_ERR("CH reset configuration failed");
return -1;
}
return 0;
}
#ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
int sr_gpio_config(void)
{
int ret;
if (!device_is_ready(sr_rf_switch_spec.port)) {
return -ENODEV;
}
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
if (ret) {
LOG_ERR("SR GPIO configuration failed %d", ret);
}
return ret;
}
int sr_gpio_remove(void)
{
int ret;
ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_DISCONNECTED);
if (ret) {
LOG_ERR("SR GPIO remove failed %d", ret);
}
return ret;
}
int sr_ant_switch(unsigned int ant_switch)
{
int ret;
ret = gpio_pin_set_dt(&sr_rf_switch_spec, ant_switch & 0x1);
if (ret) {
LOG_ERR("SR GPIO set failed %d", ret);
}
return ret;
}
#endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */