drivers: mediatek: connectivity: Import MTK OSS connectivity modules from OPLUS

https://github.com/OnePlusOSS/android_kernel_modules_oneplus_mt6877/tree/oneplus/mt6877_t_13.0.0_nord_ce2/
This commit is contained in:
Fede2782 2024-04-27 23:13:59 +02:00
parent 2cecc141df
commit 691010b228
No known key found for this signature in database
GPG key ID: 1DD0FACD495CE046
2564 changed files with 2674511 additions and 0 deletions

View file

@ -0,0 +1,5 @@
--no-tree
--show-types
--max-line-length=120
--no-signoff
--ignore=GERRIT_CHANGE_ID

View file

@ -0,0 +1,49 @@
###############################################################################
# Generally Android.mk can not get KConfig setting
# we can use this way to get
# include the final KConfig
# but there is no $(AUTO_CONF) at the first time (no out folder) when make
#
#ifneq (,$(wildcard $(AUTO_CONF)))
#include $(AUTO_CONF)
#include $(CLEAR_VARS)
#endif
###############################################################################
###############################################################################
# Generally Android.mk can not get KConfig setting #
# #
# do not have any KConfig checking in Android.mk #
# do not have any KConfig checking in Android.mk #
# do not have any KConfig checking in Android.mk #
# #
# e.g. ifeq ($(CONFIG_MTK_COMBO_WIFI), m) #
# xxxx #
# endif #
# #
# e.g. ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),) #
# xxxx #
# endif #
# #
# All the KConfig checking should move to Makefile for each module #
# All the KConfig checking should move to Makefile for each module #
# All the KConfig checking should move to Makefile for each module #
# #
###############################################################################
###############################################################################
LOCAL_PATH := $(call my-dir)
ifeq ($(MTK_BT_SUPPORT),yes)
include $(CLEAR_VARS)
LOCAL_MODULE := btmtk_sdio_unify.ko
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
LOCAL_INIT_RC := init.btmtk_sdio.rc
LOCAL_REQUIRED_MODULES := wlan_sdio_reset.ko
LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%,%,$(shell find $(LOCAL_PATH) -type f -name '*.[cho]')) Makefile
include $(MTK_KERNEL_MODULE)
endif

View file

@ -0,0 +1,174 @@
ifeq ($(LINUX_SRC), )
export KERNEL_SRC := /lib/modules/$(shell uname -r)/build
else
export KERNEL_SRC := $(LINUX_SRC)
endif
#################### Configurations ####################
# Compile Options for bt driver configuration.
CONFIG_SUPPORT_BT_DL_WIFI_PATCH=y
CONFIG_SUPPORT_BT_DL_ZB_PATCH=n
CONFIG_SUPPORT_BLUEZ=n
CONFIG_SUPPORT_DVT=n
CONFIG_SUPPORT_HW_DVT=n
CONFIG_SUPPORT_MULTI_DEV_NODE=n
CONFIG_GKI_SUPPORT=y
CONFIG_SUPPORT_WAKEUP_SER=y
CONFIG_DISABLE_SYMBOL_GET_SET=y
ifeq ($(CONFIG_MP_WAKEUP_SOURCE_SYSFS_STAT), y)
ccflags-y += -DCONFIG_MP_WAKEUP_SOURCE_SYSFS_STAT
endif
ifeq ($(CONFIG_GKI_SUPPORT), y)
ccflags-y += -DCFG_CHIP_RESET_KO_SUPPORT
ccflags-y += -I$(src)/../../wlan_sdio_reset.ko_intermediates/LINKED/reset/include/
ccflags-y += -I$(src)/../../wlan/core/gen4-mt79xx/reset/include/
RESET_DIR = $(shell pwd)/../../ETC/wlan_sdio_reset.ko_intermediates/LINKED/Module.symvers
$(info 'RESET_DIR=' $(RESET_DIR))
KBUILD_EXTRA_SYMBOLS += $(RESET_DIR)
endif
ifeq ($(CONFIG_DISABLE_SYMBOL_GET_SET), y)
ccflags-y += -DCONFIG_DISABLE_SYMBOL_GET_SET
endif
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DBUILD_QA_DBG=1
else
ccflags-y += -DBUILD_QA_DBG=0
endif
ifeq ($(CONFIG_SUPPORT_BT_DL_WIFI_PATCH), y)
ccflags-y += -DCFG_SUPPORT_BT_DL_WIFI_PATCH=1
else
ccflags-y += -DCFG_SUPPORT_BT_DL_WIFI_PATCH=0
endif
ifeq ($(CONFIG_SUPPORT_BT_DL_ZB_PATCH), y)
ccflags-y += -DCFG_SUPPORT_BT_DL_ZB_PATCH=1
else
ccflags-y += -DCFG_SUPPORT_BT_DL_ZB_PATCH=0
endif
ifeq ($(CONFIG_SUPPORT_BLUEZ), y)
ccflags-y += -DCFG_SUPPORT_BLUEZ=1
else
ccflags-y += -DCFG_SUPPORT_BLUEZ=0
endif
ifeq ($(CONFIG_SUPPORT_HW_DVT), y)
ccflags-y += -DCFG_SUPPORT_HW_DVT=1
else
ccflags-y += -DCFG_SUPPORT_HW_DVT=0
endif
ifeq ($(CONFIG_SUPPORT_WAKEUP_SER), y)
ccflags-y += -DCFG_SUPPORT_WAKEUP_IRQ=1
else
ccflags-y += -DCFG_SUPPORT_WAKEUP_IRQ=0
endif
ifeq ($(CONFIG_SUPPORT_DVT), y)
ccflags-y += -DCFG_SUPPORT_DVT=1
else
ccflags-y += -DCFG_SUPPORT_DVT=0
endif
ifeq ($(CONFIG_SUPPORT_MULTI_DEV_NODE), y)
ccflags-y += -DCFG_SUPPORT_MULTI_DEV_NODE=1
else
ccflags-y += -DCFG_SUPPORT_MULTI_DEV_NODE=0
endif
ifeq ($(CONFIG_SUPPORT_BMR_RX_CLK), y)
ccflags-y += -DCFG_SUPPORT_BMR_RX_CLK=1
ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/
else
ccflags-y += -DCFG_SUPPORT_BMR_RX_CLK=0
endif
#################### Configurations ####################
# For chip interface, driver supports "usb", "sdio", "uart_tty", "uart_serdev" and "btif"
MTK_CHIP_IF := sdio
ifeq ($(MTK_CHIP_IF), sdio)
MOD_NAME = btmtk_sdio_unify
CFILES := sdio/btmtksdio.c btmtk_woble.c btmtk_buffer_mode.c btmtk_chip_reset.c
ccflags-y += -DCHIP_IF_SDIO
ccflags-y += -DSDIO_DEBUG=0
ccflags-y += -I$(src)/include/sdio
else ifeq ($(MTK_CHIP_IF), usb)
MOD_NAME = btmtk_usb_unify
CFILES := usb/btmtkusb.c btmtk_woble.c btmtk_chip_reset.c
ccflags-y += -DCHIP_IF_USB
ccflags-y += -I$(src)/include/usb
else ifeq ($(MTK_CHIP_IF), uart_tty)
MOD_NAME = btmtk_uart_unify
CFILES := uart/btmtktty.c btmtk_woble.c btmtk_chip_reset.c
ccflags-y += -DCHIP_IF_UART_TTY
ccflags-y += -I$(src)/include/uart/tty
else ifeq ($(MTK_CHIP_IF), uart_serdev)
MOD_NAME = btmtk_uart_unify
ccflags-y += -DCHIP_IF_UART_SERDEV
CFILES := uart/btmtkserdev.c
ccflags-y += -I$(src)/include/uart/serdev
else
MOD_NAME = btmtkbtif_unify
CFILES := btif/btmtk_btif.c
ccflags-y += -DCHIP_IF_BTIF
ccflags-y += -I$(src)/include/btif
endif
CFILES += btmtk_main.c btmtk_fw_log.c
ccflags-y += -I$(src)/include/ -I$(KERNEL_SRC)/include/ -I$(KERNEL_SRC)/drivers/bluetooth
ccflags-y += -DANDROID_OS
ccflags-y += -Werror
$(MOD_NAME)-objs := $(CFILES:.c=.o)
obj-m += $(MOD_NAME).o
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DBTMTK_DEBUG_SOP
endif
#VPATH = /opt/toolchains/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux
#UART_MOD_NAME = btmtk_uart
#UART_CFILES := \
# btmtk_uart_main.c
#$(UART_MOD_NAME)-objs := $(UART_CFILES:.c=.o)
###############################################################################
# Common
###############################################################################
#obj-m := $(UART_MOD_NAME).o
all:
make -C $(KERNEL_SRC) M=$(PWD) modules
clean:
make -C $(KERNEL_SRC) M=$(PWD) clean
# Check coding style
# export IGNORE_CODING_STYLE_RULES := NEW_TYPEDEFS,LEADING_SPACE,CODE_INDENT,SUSPECT_CODE_INDENT
ccs:
./util/checkpatch.pl -f ./sdio/btmtksdio.c
./util/checkpatch.pl -f ./include/sdio/btmtk_sdio.h
./util/checkpatch.pl -f ./include/btmtk_define.h
./util/checkpatch.pl -f ./include/btmtk_drv.h
./util/checkpatch.pl -f ./include/btmtk_chip_if.h
./util/checkpatch.pl -f ./include/btmtk_main.h
./util/checkpatch.pl -f ./include/btmtk_buffer_mode.h
./util/checkpatch.pl -f ./include/uart/tty/btmtk_uart_tty.h
./util/checkpatch.pl -f ./uart/btmtktty.c
./util/checkpatch.pl -f ./include/btmtk_fw_log.h
./util/checkpatch.pl -f ./include/btmtk_woble.h
./util/checkpatch.pl -f ./include/uart/btmtk_uart.h
./util/checkpatch.pl -f ./uart/btmtk_uart_main.c
./util/checkpatch.pl -f ./include/usb/btmtk_usb.h
./util/checkpatch.pl -f ./usb/btmtkusb.c
./util/checkpatch.pl -f btmtk_fw_log.c
./util/checkpatch.pl -f btmtk_main.c
./util/checkpatch.pl -f btmtk_buffer_mode.c
./util/checkpatch.pl -f btmtk_woble.c
./util/checkpatch.pl -f btmtk_chip_reset.c

View file

@ -0,0 +1,21 @@
#Please follow the example pattern
#There are some SPACES between parameter and parameter
[Country Code]
[Index] BR_EDR_PWR_MODE, | EDR_MAX_TX_PWR, | BLE_DEFAULT_TX_PWR, | BLE_DEFAULT_TX_PWR_2M, | BLE_LR_S2, | BLE_LR_S8
[AU,SA]
[BT0] 1, 1.75, 1.5, 1, 1, 1
[BT1] 1, 2.75, 2.5, 2, 1, 1
[TW,US]
[BT0] 1, 14, 15, 16, 20, 20
[BT1] 1, 17, 17, 17, 20, 20
[JP]
[BT0] 0, 5.25, -3, -3, -2, -2
[BT1] 0, 5.5, -2.5, -2, -2, -2
[DE]
[BT0] 0, -32, -29, -29, -29, -29
[BT1] 0, -32, -29, -29, -29, -29

View file

@ -0,0 +1,306 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#include "btmtk_buffer_mode.h"
static struct btmtk_buffer_mode_struct btmtk_buffer_mode;
static int btmtk_buffer_mode_check_auto_mode(struct btmtk_buffer_mode_struct *buffer_mode)
{
u16 addr = 1;
u8 value = 0;
if (buffer_mode->efuse_mode != AUTO_MODE)
return 0;
if (btmtk_efuse_read(buffer_mode->bdev, addr, &value)) {
BTMTK_WARN("read fail");
BTMTK_WARN("Use EEPROM Bin file mode");
buffer_mode->efuse_mode = BIN_FILE_MODE;
return -EIO;
}
if (value == ((buffer_mode->bdev->chip_id & 0xFF00) >> 8)) {
BTMTK_WARN("get efuse[1]: 0x%02x", value);
BTMTK_WARN("use efuse mode");
buffer_mode->efuse_mode = EFUSE_MODE;
} else {
BTMTK_WARN("get efuse[1]: 0x%02x", value);
BTMTK_WARN("Use EEPROM Bin file mode");
buffer_mode->efuse_mode = BIN_FILE_MODE;
}
return 0;
}
static int btmtk_buffer_mode_parse_mode(uint8_t *buf, size_t buf_size)
{
int efuse_mode = EFUSE_MODE;
char *p_buf = NULL;
char *ptr = NULL, *p = NULL;
if (!buf) {
BTMTK_WARN("buf is null");
return efuse_mode;
} else if (buf_size < (strlen(BUFFER_MODE_SWITCH_FIELD) + 2)) {
BTMTK_WARN("incorrect buf size(%d)", (int)buf_size);
return efuse_mode;
}
p_buf = kmalloc(buf_size + 1, GFP_KERNEL);
if (!p_buf)
return efuse_mode;
memcpy(p_buf, buf, buf_size);
p_buf[buf_size] = '\0';
/* find string */
p = ptr = strstr(p_buf, BUFFER_MODE_SWITCH_FIELD);
if (!ptr) {
BTMTK_ERR("Can't find %s", BUFFER_MODE_SWITCH_FIELD);
goto out;
}
if (p > p_buf) {
p--;
while ((*p == ' ') && (p != p_buf))
p--;
if (*p == '#') {
BTMTK_ERR("It's not EEPROM - Bin file mode");
goto out;
}
}
/* check access mode */
ptr += (strlen(BUFFER_MODE_SWITCH_FIELD) + 1);
BTMTK_WARN("It's EEPROM bin mode: %c", *ptr);
efuse_mode = *ptr - '0';
if (efuse_mode > AUTO_MODE)
efuse_mode = EFUSE_MODE;
out:
kfree(p_buf);
return efuse_mode;
}
static int btmtk_buffer_mode_set_addr(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_ADDRESS_CMD_LEN] = {0x01, 0x1A, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_ADDRESS_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0x1A, 0xFC, 0x00};
int ret = 0;
if (buffer_mode->bt0_mac[0] == 0x00 && buffer_mode->bt0_mac[1] == 0x00
&& buffer_mode->bt0_mac[2] == 0x00 && buffer_mode->bt0_mac[3] == 0x00
&& buffer_mode->bt0_mac[4] == 0x00 && buffer_mode->bt0_mac[5] == 0x00) {
BTMTK_WARN("BDAddr is Zero, not set");
} else {
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 5] = buffer_mode->bt0_mac[0];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 4] = buffer_mode->bt0_mac[1];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 3] = buffer_mode->bt0_mac[2];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 2] = buffer_mode->bt0_mac[3];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 1] = buffer_mode->bt0_mac[4];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET] = buffer_mode->bt0_mac[5];
BTMTK_INFO("%s: SEND BDADDR = "MACSTR, __func__, MAC2STR(buffer_mode->bt0_mac));
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_ADDRESS_CMD_LEN,
event, SET_ADDRESS_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
}
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_radio(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_RADIO_CMD_LEN] = {0x01, 0x2C, 0xFC, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_RADIO_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0x2C, 0xFC, 0x00};
int ret = 0;
cmd[SET_RADIO_CMD_EDR_DEF_OFFSET] = buffer_mode->bt0_radio.radio_0 & 0x3F; /* edr_init_pwr */
cmd[SET_RADIO_CMD_BLE_OFFSET] = buffer_mode->bt0_radio.radio_2 & 0x3F; /* ble_default_pwr */
cmd[SET_RADIO_CMD_EDR_MAX_OFFSET] = buffer_mode->bt0_radio.radio_1 & 0x3F; /* edr_max_pwr */
cmd[SET_RADIO_CMD_EDR_MODE_OFFSET] = (buffer_mode->bt0_radio.radio_0 & 0xC0) >> 6; /* edr_pwr_mode */
BTMTK_INFO_RAW(cmd, SET_RADIO_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_RADIO_CMD_LEN,
event, SET_RADIO_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_group_boundary(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_GRP_CMD_LEN] = {0x01, 0xEA, 0xFC, 0x09, 0x02, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_GRP_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0xEA, 0xFC, 0x00};
int ret = 0;
memcpy(&cmd[SET_GRP_CMD_PAYLOAD_OFFSET], buffer_mode->bt0_ant0_grp_boundary, BUFFER_MODE_GROUP_LENGTH);
BTMTK_INFO_RAW(cmd, SET_GRP_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_GRP_CMD_LEN,
event, SET_GRP_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_power_offset(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_PWR_OFFSET_CMD_LEN] = {0x01, 0xEA, 0xFC, 0x0A,
0x02, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_PWR_OFFSET_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0xEA, 0xFC, 0x00};
int ret = 0;
memcpy(&cmd[SET_PWR_OFFSET_CMD_PAYLOAD_OFFSET], buffer_mode->bt0_ant0_pwr_offset, BUFFER_MODE_CAL_LENGTH);
BTMTK_INFO_RAW(cmd, SET_PWR_OFFSET_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_PWR_OFFSET_CMD_LEN,
event, SET_PWR_OFFSET_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
int btmtk_buffer_mode_send(struct btmtk_buffer_mode_struct *buffer_mode)
{
int ret = 0;
if (buffer_mode == NULL) {
BTMTK_INFO("buffer_mode is NULL, not support");
return -EIO;
}
if (btmtk_buffer_mode_check_auto_mode(buffer_mode)) {
BTMTK_ERR("check auto mode failed");
return -EIO;
}
if (buffer_mode->efuse_mode == BIN_FILE_MODE) {
ret = btmtk_buffer_mode_set_addr(buffer_mode);
if (ret < 0)
BTMTK_ERR("set addr failed");
ret = btmtk_buffer_mode_set_radio(buffer_mode);
if (ret < 0)
BTMTK_ERR("set radio failed");
ret = btmtk_buffer_mode_set_group_boundary(buffer_mode);
if (ret < 0)
BTMTK_ERR("set group_boundary failed");
ret = btmtk_buffer_mode_set_power_offset(buffer_mode);
if (ret < 0)
BTMTK_ERR("set power_offset failed");
}
return 0;
}
void btmtk_buffer_mode_initialize(struct btmtk_dev *bdev, struct btmtk_buffer_mode_struct **buffer_mode)
{
int ret = 0;
u32 code_len = 0;
btmtk_buffer_mode.bdev = bdev;
ret = btmtk_load_code_from_setting_files(BUFFER_MODE_SWITCH_FILE, bdev->intf_dev, &code_len, bdev);
btmtk_buffer_mode.efuse_mode = btmtk_buffer_mode_parse_mode(bdev->setting_file, code_len);
if (btmtk_buffer_mode.efuse_mode == EFUSE_MODE)
return;
if (bdev->flavor)
(void)snprintf(btmtk_buffer_mode.file_name, MAX_BIN_FILE_NAME_LEN, "EEPROM_MT%04x_1a.bin",
bdev->chip_id & 0xffff);
else
(void)snprintf(btmtk_buffer_mode.file_name, MAX_BIN_FILE_NAME_LEN, "EEPROM_MT%04x_1.bin",
bdev->chip_id & 0xffff);
ret = btmtk_load_code_from_setting_files(btmtk_buffer_mode.file_name, bdev->intf_dev, &code_len, bdev);
if (ret < 0) {
BTMTK_ERR("set load %s failed", btmtk_buffer_mode.file_name);
return;
}
if(BT0_MAC_OFFSET + BUFFER_MODE_MAC_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt0_mac, &bdev->setting_file[BT0_MAC_OFFSET],
BUFFER_MODE_MAC_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_MAC_OFFSET);
if(BT1_MAC_OFFSET + BUFFER_MODE_MAC_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt1_mac, &bdev->setting_file[BT1_MAC_OFFSET],
BUFFER_MODE_MAC_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_MAC_OFFSET);
if(BT0_RADIO_OFFSET + BUFFER_MODE_RADIO_LENGTH <= code_len)
memcpy(&btmtk_buffer_mode.bt0_radio, &bdev->setting_file[BT0_RADIO_OFFSET],
BUFFER_MODE_RADIO_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_RADIO_OFFSET);
if(BT1_RADIO_OFFSET + BUFFER_MODE_RADIO_LENGTH <= code_len)
memcpy(&btmtk_buffer_mode.bt1_radio, &bdev->setting_file[BT1_RADIO_OFFSET],
BUFFER_MODE_RADIO_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_RADIO_OFFSET);
if(BT0_GROUP_ANT0_OFFSET + BUFFER_MODE_GROUP_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt0_ant0_grp_boundary, &bdev->setting_file[BT0_GROUP_ANT0_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_GROUP_ANT0_OFFSET);
if(BT0_GROUP_ANT1_OFFSET + BUFFER_MODE_GROUP_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt0_ant1_grp_boundary, &bdev->setting_file[BT0_GROUP_ANT1_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_GROUP_ANT1_OFFSET);
if(BT1_GROUP_ANT0_OFFSET + BUFFER_MODE_GROUP_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt1_ant0_grp_boundary, &bdev->setting_file[BT1_GROUP_ANT0_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_GROUP_ANT0_OFFSET);
if(BT1_GROUP_ANT1_OFFSET + BUFFER_MODE_GROUP_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt1_ant1_grp_boundary, &bdev->setting_file[BT1_GROUP_ANT1_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_GROUP_ANT1_OFFSET);
if(BT0_CAL_ANT0_OFFSET + BUFFER_MODE_CAL_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt0_ant0_pwr_offset, &bdev->setting_file[BT0_CAL_ANT0_OFFSET],
BUFFER_MODE_CAL_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_CAL_ANT0_OFFSET);
if(BT0_CAL_ANT1_OFFSET + BUFFER_MODE_CAL_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt0_ant1_pwr_offset, &bdev->setting_file[BT0_CAL_ANT1_OFFSET],
BUFFER_MODE_CAL_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT0_CAL_ANT1_OFFSET);
if(BT1_CAL_ANT0_OFFSET + BUFFER_MODE_CAL_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt1_ant0_pwr_offset, &bdev->setting_file[BT1_CAL_ANT0_OFFSET],
BUFFER_MODE_CAL_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_CAL_ANT0_OFFSET);
if(BT1_CAL_ANT1_OFFSET + BUFFER_MODE_CAL_LENGTH <= code_len)
memcpy(btmtk_buffer_mode.bt1_ant1_pwr_offset, &bdev->setting_file[BT1_CAL_ANT1_OFFSET],
BUFFER_MODE_CAL_LENGTH);
else
BTMTK_ERR("%s: error address, %x", __func__, BT1_CAL_ANT1_OFFSET);
*buffer_mode = &btmtk_buffer_mode;
}

View file

@ -0,0 +1,206 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#include "btmtk_chip_reset.h"
#if (KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE)
static void btmtk_reset_timer(unsigned long arg)
{
struct btmtk_dev *bdev = (struct btmtk_dev *)arg;
BTMTK_INFO("%s: chip_reset not trigger in %d seconds, trigger it directly",
__func__, CHIP_RESET_TIMEOUT);
schedule_work(&bdev->reset_waker);
}
#else
static void btmtk_reset_timer(struct timer_list *timer)
{
struct btmtk_dev *bdev = from_timer(bdev, timer, chip_reset_timer);
BTMTK_INFO("%s: chip_reset not trigger in %d seconds, trigger it directly",
__func__, CHIP_RESET_TIMEOUT);
schedule_work(&bdev->reset_waker);
}
#endif
void btmtk_reset_timer_add(struct btmtk_dev *bdev)
{
BTMTK_INFO("%s: create chip_reset timer", __func__);
#if (KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE)
init_timer(&bdev->chip_reset_timer);
bdev->chip_reset_timer.function = btmtk_reset_timer;
bdev->chip_reset_timer.data = (unsigned long)bdev;
#else
timer_setup(&bdev->chip_reset_timer, btmtk_reset_timer, 0);
#endif
}
void btmtk_reset_timer_update(struct btmtk_dev *bdev)
{
mod_timer(&bdev->chip_reset_timer, jiffies + CHIP_RESET_TIMEOUT * HZ);
}
void btmtk_reset_timer_del(struct btmtk_dev *bdev)
{
if (timer_pending(&bdev->chip_reset_timer)) {
del_timer_sync(&bdev->chip_reset_timer);
BTMTK_INFO("%s exit", __func__);
}
}
void btmtk_reset_waker(struct work_struct *work)
{
struct btmtk_dev *bdev = container_of(work, struct btmtk_dev, reset_waker);
struct btmtk_cif_state *cif_state = NULL;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
int state = BTMTK_STATE_INIT;
int cif_event = 0, err = 0;
int cur = 0;
/* Check chip state is ok to do reset or not */
state = btmtk_get_chip_state(bdev);
if (state == BTMTK_STATE_SUSPEND) {
BTMTK_INFO("%s suspend state don't do chip reset!", __func__);
return;
}
if (state == BTMTK_STATE_PROBE) {
bmain_info->chip_reset_flag = 1;
BTMTK_INFO("%s just do whole chip reset in probe stage!", __func__);
}
btmtk_reset_timer_del(bdev);
if (atomic_read(&bmain_info->chip_reset) ||
atomic_read(&bmain_info->subsys_reset)) {
BTMTK_INFO("%s return, chip_reset = %d, subsys_reset = %d!", __func__,
atomic_read(&bmain_info->chip_reset), atomic_read(&bmain_info->subsys_reset));
return;
}
#ifdef CFG_CHIP_RESET_KO_SUPPORT
if (rstNotifyWholeChipRstStatus(RST_MODULE_BT, RST_MODULE_STATE_DUMP_START, NULL) == RST_MODULE_RET_FAIL)
return;
#endif
if (bmain_info->hif_hook.dump_debug_sop)
bmain_info->hif_hook.dump_debug_sop(bdev);
#ifdef CFG_CHIP_RESET_KO_SUPPORT
rstNotifyWholeChipRstStatus(RST_MODULE_BT, RST_MODULE_STATE_DUMP_END, NULL);
#endif
DUMP_TIME_STAMP("chip_reset_start");
cif_event = HIF_EVENT_SUBSYS_RESET;
if (BTMTK_CIF_IS_NULL(bdev, cif_event)) {
/* Error */
BTMTK_WARN("%s priv setting is NULL", __func__);
return;
}
if (!bdev->bt_cfg.support_dongle_reset) {
BTMTK_ERR("%s chip_reset is not support", __func__);
return;
}
cif_state = &bdev->cif_state[cif_event];
/* Set Entering state */
btmtk_set_chip_state((void *)bdev, cif_state->ops_enter);
BTMTK_INFO("%s: Receive a byte (0xFF)", __func__);
/* read interrupt EP15 CR */
bdev->sco_num = 0;
if (bmain_info->chip_reset_flag == 0 &&
atomic_read(&bmain_info->subsys_reset_conti_count) < BTMTK_MAX_SUBSYS_RESET_COUNT) {
if (bmain_info->hif_hook.subsys_reset) {
cur = atomic_cmpxchg(&bmain_info->subsys_reset, BTMTK_RESET_DONE, BTMTK_RESET_DOING);
if (cur == BTMTK_RESET_DOING) {
BTMTK_INFO("%s: subsys reset in progress, return", __func__);
return;
}
DUMP_TIME_STAMP("subsys_chip_reset_start");
err = bmain_info->hif_hook.subsys_reset(bdev);
atomic_set(&bmain_info->subsys_reset, BTMTK_RESET_DONE);
if (err < 0) {
BTMTK_INFO("subsys reset failed, do whole chip reset!");
goto L0RESET;
}
atomic_inc(&bmain_info->subsys_reset_count);
atomic_inc(&bmain_info->subsys_reset_conti_count);
DUMP_TIME_STAMP("subsys_chip_reset_end");
bmain_info->reset_stack_flag = HW_ERR_CODE_CHIP_RESET;
err = btmtk_cap_init(bdev);
if (err < 0) {
BTMTK_ERR("btmtk init failed!");
goto L0RESET;
}
err = btmtk_load_rom_patch(bdev);
if (err < 0) {
BTMTK_INFO("btmtk load rom patch failed!");
goto L0RESET;
}
btmtk_send_hw_err_to_host(bdev);
btmtk_woble_wake_unlock(bdev);
if (bmain_info->hif_hook.chip_reset_notify)
bmain_info->hif_hook.chip_reset_notify(bdev);
} else {
err = -1;
BTMTK_INFO("%s: Not support subsys chip reset", __func__);
goto L0RESET;
}
} else {
err = -1;
BTMTK_INFO("%s: chip_reset_flag is %d, subsys_reset_count %d",
__func__,
bmain_info->chip_reset_flag,
atomic_read(&bmain_info->subsys_reset_conti_count));
}
L0RESET:
if (err < 0) {
/* L0.5 reset failed or not support, do whole chip reset */
/* TODO: need to confirm with usb host when suspend fail, to do chip reset,
* because usb3.0 need to toggle reset pin after hub_event unfreeze,
* otherwise, it will not occur disconnect on Capy Platform. When Mstar
* chip has usb3.0 port, we will use Mstar platform to do comparison
* test, then found the final solution.
*/
/* msleep(2000); */
if (bmain_info->hif_hook.whole_reset) {
DUMP_TIME_STAMP("whole_chip_reset_start");
bmain_info->hif_hook.whole_reset(bdev);
atomic_inc(&bmain_info->whole_reset_count);
DUMP_TIME_STAMP("whole_chip_reset_end");
} else {
BTMTK_INFO("%s: Not support whole chip reset", __func__);
}
}
DUMP_TIME_STAMP("chip_reset_end");
/* Set End/Error state */
if (err < 0)
btmtk_set_chip_state((void *)bdev, cif_state->ops_error);
else
btmtk_set_chip_state((void *)bdev, cif_state->ops_end);
}
void btmtk_reset_trigger(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if (atomic_read(&bmain_info->chip_reset) ||
atomic_read(&bmain_info->subsys_reset)) {
BTMTK_INFO("%s return, chip_reset = %d, subsys_reset = %d!", __func__,
atomic_read(&bmain_info->chip_reset), atomic_read(&bmain_info->subsys_reset));
return;
}
schedule_work(&bdev->reset_waker);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,993 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/input.h>
#include <linux/pm_wakeup.h>
#include <linux/interrupt.h>
#include "btmtk_woble.h"
static int is_support_unify_woble(struct btmtk_dev *bdev)
{
if (bdev->bt_cfg.support_unify_woble) {
if (is_mt7902(bdev->chip_id) || is_mt7922(bdev->chip_id) ||
is_mt6639(bdev->chip_id) || is_mt7961(bdev->chip_id))
return 1;
else
return 0;
} else {
return 0;
}
}
static void btmtk_woble_wake_lock(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if (bdev->bt_cfg.support_woble_wakelock) {
BTMTK_INFO("%s: enter", __func__);
__pm_stay_awake(bmain_info->woble_ws);
BTMTK_INFO("%s: exit", __func__);
}
}
void btmtk_woble_wake_unlock(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if (bdev->bt_cfg.support_woble_wakelock) {
BTMTK_INFO("%s: enter", __func__);
__pm_relax(bmain_info->woble_ws);
BTMTK_INFO("%s: exit", __func__);
}
}
#if WAKEUP_BT_IRQ
void btmtk_sdio_irq_wake_lock_timeout(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: enter", __func__);
__pm_wakeup_event(bmain_info->irq_ws, WAIT_POWERKEY_TIMEOUT);
BTMTK_INFO("%s: exit", __func__);
}
#endif
int btmtk_send_apcf_reserved(struct btmtk_dev *bdev)
{
u8 reserve_apcf_cmd[RES_APCF_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x30, 0x02, 0x61, 0x02 };
u8 reserve_apcf_event[RES_APCF_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x11 };
int ret = 0;
if (bdev == NULL) {
BTMTK_ERR("%s: Incorrect bdev", __func__);
ret = -1;
goto exit;
}
if (is_support_unify_woble(bdev)) {
if (is_mt6639(bdev->chip_id) || is_mt7902(bdev->chip_id)
|| is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id))
ret = btmtk_main_send_cmd(bdev, reserve_apcf_cmd, RES_APCF_CMD_LEN,
reserve_apcf_event, RES_APCF_EVT_LEN, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
else
BTMTK_WARN("%s: not support for 0x%x", __func__, bdev->chip_id);
BTMTK_INFO("%s: ret %d", __func__, ret);
}
exit:
return ret;
}
static int btmtk_send_woble_read_BDADDR_cmd(struct btmtk_dev *bdev)
{
u8 cmd[READ_ADDRESS_CMD_LEN] = { 0x01, 0x09, 0x10, 0x00 };
u8 event[READ_ADDRESS_EVT_HDR_LEN] = { 0x04, 0x0E, 0x0A, 0x01, 0x09, 0x10, 0x00, /* AA, BB, CC, DD, EE, FF */ };
int i;
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
if (bdev == NULL || bdev->io_buf == NULL) {
BTMTK_ERR("%s: Incorrect bdev", __func__);
return ret;
}
for (i = 0; i < BD_ADDRESS_SIZE; i++) {
if (bdev->bdaddr[i] != 0) {
ret = 0;
goto done;
}
}
ret = btmtk_main_send_cmd(bdev,
cmd, READ_ADDRESS_CMD_LEN,
event, READ_ADDRESS_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
/*BD address will get in btmtk_rx_work*/
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
done:
BTMTK_INFO("%s, end, ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_unify_woble_suspend_default_cmd(struct btmtk_dev *bdev)
{
u8 cmd[WOBLE_ENABLE_DEFAULT_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x24, 0x01, 0x20, 0x02, 0x00, 0x01,
0x02, 0x01, 0x00, 0x05, 0x10, 0x00, 0x00, 0x40, 0x06,
0x02, 0x40, 0x0A, 0x02, 0x41, 0x0F, 0x05, 0x24, 0x20,
0x04, 0x32, 0x00, 0x09, 0x26, 0xC0, 0x12, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00};
u8 event[WOBLE_ENABLE_DEFAULT_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x00 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, WOBLE_ENABLE_DEFAULT_CMD_LEN,
event, WOBLE_ENABLE_DEFAULT_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
BTMTK_INFO("%s: end. ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_unify_woble_resume_default_cmd(struct btmtk_dev *bdev)
{
u8 cmd[WOBLE_DISABLE_DEFAULT_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00 };
u8 event[WOBLE_DISABLE_DEFAULT_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x01 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, WOBLE_DISABLE_DEFAULT_CMD_LEN,
event, WOBLE_DISABLE_DEFAULT_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
BTMTK_INFO("%s: end. ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_woble_suspend_cmd(struct btmtk_dev *bdev)
{
/* radio off cmd with wobx_mode_disable, used when unify woble off */
u8 radio_off_cmd[RADIO_OFF_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x20, 0x02, 0x00, 0x00 };
u8 event[RADIO_OFF_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x00 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: not support woble, send radio off cmd", __func__);
ret = btmtk_main_send_cmd(bdev,
radio_off_cmd, RADIO_OFF_CMD_LEN,
event, RADIO_OFF_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
return ret;
}
static int btmtk_send_woble_resume_cmd(struct btmtk_dev *bdev)
{
/* radio on cmd with wobx_mode_disable, used when unify woble off */
u8 radio_on_cmd[RADIO_ON_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00 };
u8 event[RADIO_ON_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x01 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
radio_on_cmd, RADIO_ON_CMD_LEN,
event, RADIO_ON_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
return ret;
}
static int btmtk_set_Woble_APCF_filter_parameter(struct btmtk_dev *bdev)
{
u8 cmd[APCF_FILTER_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x0A,
0x01, 0x00, 0x0A, 0x20, 0x00, 0x20, 0x00, 0x01, 0x80, 0x00 };
u8 event[APCF_FILTER_EVT_HDR_LEN] = { 0x04, 0x0E, 0x07,
0x01, 0x57, 0xFD, 0x00, 0x01/*, 00, 63*/ };
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev, cmd, APCF_FILTER_CMD_LEN,
event, APCF_FILTER_EVT_HDR_LEN, 0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: end ret %d", __func__, ret);
else
ret = 0;
BTMTK_INFO("%s: end ret=%d", __func__, ret);
return ret;
}
/**
* Set APCF manufacturer data and filter parameter
*/
static int btmtk_set_Woble_APCF(struct btmtk_woble *bt_woble)
{
u8 manufactur_data[APCF_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x27, 0x06, 0x00, 0x0A,
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x4B, 0x54, 0x4D,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
u8 event[APCF_EVT_HDR_LEN] = { 0x04, 0x0E, 0x07, 0x01, 0x57, 0xFD, 0x00, /* 0x06 00 63 */ };
int ret = -1;
u8 i = 0;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_apcf[0].length %d",
__func__, bt_woble->woble_setting_apcf[0].length);
/* start to send apcf cmd from woble setting file */
if (bt_woble->woble_setting_apcf[0].length) {
for (i = 0; i < WOBLE_SETTING_COUNT; i++) {
if (!bt_woble->woble_setting_apcf[i].length)
continue;
BTMTK_INFO("%s: apcf_fill_mac[%d].content[0] = 0x%02x", __func__, i,
bt_woble->woble_setting_apcf_fill_mac[i].content[0]);
BTMTK_INFO("%s: apcf_fill_mac_location[%d].length = %d", __func__, i,
bt_woble->woble_setting_apcf_fill_mac_location[i].length);
if ((bt_woble->woble_setting_apcf_fill_mac[i].content[0] == 1) &&
bt_woble->woble_setting_apcf_fill_mac_location[i].length) {
/* need add BD addr to apcf cmd */
memcpy(bt_woble->woble_setting_apcf[i].content +
(*bt_woble->woble_setting_apcf_fill_mac_location[i].content + 1),
bdev->bdaddr, BD_ADDRESS_SIZE);
BTMTK_INFO("%s: apcf[%d], add local BDADDR to location %d", __func__, i,
(*bt_woble->woble_setting_apcf_fill_mac_location[i].content));
}
#if CFG_SHOW_FULL_MACADDR
BTMTK_INFO_RAW(bt_woble->woble_setting_apcf[i].content, bt_woble->woble_setting_apcf[i].length,
"Send woble_setting_apcf[%d] ", i);
#endif
ret = btmtk_main_send_cmd(bdev, bt_woble->woble_setting_apcf[i].content,
bt_woble->woble_setting_apcf[i].length, event, APCF_EVT_HDR_LEN, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: manufactur_data error ret %d", __func__, ret);
return ret;
}
}
} else { /* use default */
BTMTK_INFO("%s: use default manufactur data", __func__);
memcpy(manufactur_data + 10, bdev->bdaddr, BD_ADDRESS_SIZE);
ret = btmtk_main_send_cmd(bdev, manufactur_data, APCF_CMD_LEN,
event, APCF_EVT_HDR_LEN, 0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: manufactur_data error ret %d", __func__, ret);
return ret;
}
ret = btmtk_set_Woble_APCF_filter_parameter(bdev);
}
BTMTK_INFO("%s: end ret=%d", __func__, ret);
return 0;
}
static int btmtk_set_Woble_Radio_Off(struct btmtk_woble *bt_woble)
{
int ret = 0;
int length = 0;
char *radio_off = NULL;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_radio_off.length %d", __func__,
bt_woble->woble_setting_radio_off.length);
if (bt_woble->woble_setting_radio_off.length) {
/* start to send radio off cmd from woble setting file */
length = bt_woble->woble_setting_radio_off.length +
bt_woble->woble_setting_wakeup_type.length;
radio_off = kzalloc(length, GFP_KERNEL);
if (!radio_off) {
BTMTK_ERR("%s: alloc memory fail (radio_off)",
__func__);
ret = -ENOMEM;
goto Finish;
}
memcpy(radio_off,
bt_woble->woble_setting_radio_off.content,
bt_woble->woble_setting_radio_off.length);
if (bt_woble->woble_setting_wakeup_type.length) {
memcpy(radio_off + bt_woble->woble_setting_radio_off.length,
bt_woble->woble_setting_wakeup_type.content,
bt_woble->woble_setting_wakeup_type.length);
radio_off[3] += bt_woble->woble_setting_wakeup_type.length;
}
BTMTK_INFO_RAW(radio_off, length, "Send radio off");
ret = btmtk_main_send_cmd(bdev, radio_off, length,
bt_woble->woble_setting_radio_off_comp_event.content,
bt_woble->woble_setting_radio_off_comp_event.length, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
kfree(radio_off);
radio_off = NULL;
} else { /* use default */
BTMTK_INFO("%s: use default radio off cmd", __func__);
ret = btmtk_send_unify_woble_suspend_default_cmd(bdev);
}
Finish:
BTMTK_INFO("%s, end ret=%d", __func__, ret);
return ret;
}
static int btmtk_set_Woble_Radio_On(struct btmtk_woble *bt_woble)
{
int ret = -1;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_radio_on.length %d", __func__,
bt_woble->woble_setting_radio_on.length);
if (bt_woble->woble_setting_radio_on.length) {
/* start to send radio on cmd from woble setting file */
BTMTK_INFO_RAW(bt_woble->woble_setting_radio_on.content,
bt_woble->woble_setting_radio_on.length, "send radio on");
ret = btmtk_main_send_cmd(bdev, bt_woble->woble_setting_radio_on.content,
bt_woble->woble_setting_radio_on.length,
bt_woble->woble_setting_radio_on_comp_event.content,
bt_woble->woble_setting_radio_on_comp_event.length, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
} else { /* use default */
BTMTK_WARN("%s: use default radio on cmd", __func__);
ret = btmtk_send_unify_woble_resume_default_cmd(bdev);
}
BTMTK_INFO("%s, end ret=%d", __func__, ret);
return ret;
}
static int btmtk_del_Woble_APCF_index(struct btmtk_dev *bdev)
{
u8 cmd[APCF_DELETE_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x03, 0x01, 0x01, 0x0A };
u8 event[APCF_DELETE_EVT_HDR_LEN] = { 0x04, 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00, 0x01, /* 00, 63 */ };
int ret = 0;
BTMTK_INFO("%s, enter", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, APCF_DELETE_CMD_LEN,
event, APCF_DELETE_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: got error %d", __func__, ret);
BTMTK_INFO("%s, end", __func__);
return ret;
}
static int btmtk_set_Woble_APCF_Resume(struct btmtk_woble *bt_woble)
{
u8 event[APCF_RESUME_EVT_HDR_LEN] = { 0x04, 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00 };
u8 i = 0;
int ret = -1;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s, enter, bt_woble->woble_setting_apcf_resume[0].length= %d",
__func__, bt_woble->woble_setting_apcf_resume[0].length);
if (bt_woble->woble_setting_apcf_resume[0].length) {
BTMTK_INFO("%s: handle leave woble apcf from file", __func__);
for (i = 0; i < WOBLE_SETTING_COUNT; i++) {
if (!bt_woble->woble_setting_apcf_resume[i].length)
continue;
BTMTK_INFO_RAW(bt_woble->woble_setting_apcf_resume[i].content,
bt_woble->woble_setting_apcf_resume[i].length,
"%s: send apcf resume %d:", __func__, i);
ret = btmtk_main_send_cmd(bdev,
bt_woble->woble_setting_apcf_resume[i].content,
bt_woble->woble_setting_apcf_resume[i].length,
event, APCF_RESUME_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: Send apcf resume fail %d", __func__, ret);
return ret;
}
}
} else { /* use default */
BTMTK_WARN("%s: use default apcf resume cmd", __func__);
ret = btmtk_del_Woble_APCF_index(bdev);
if (ret < 0)
BTMTK_ERR("%s: btmtk_del_Woble_APCF_index return fail %d", __func__, ret);
}
BTMTK_INFO("%s, end", __func__);
return ret;
}
static int btmtk_load_woble_setting(char *bin_name,
struct device *dev, u32 *code_len, struct btmtk_woble *bt_woble)
{
int err;
struct btmtk_dev *bdev = bt_woble->bdev;
*code_len = 0;
err = btmtk_load_code_from_setting_files(bin_name, dev, code_len, bdev);
if (err) {
BTMTK_ERR("woble_setting btmtk_load_code_from_setting_files failed!!");
goto LOAD_END;
}
err = btmtk_load_fw_cfg_setting("APCF",
bt_woble->woble_setting_apcf, WOBLE_SETTING_COUNT, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_ADD_MAC",
bt_woble->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_ADD_MAC_LOCATION",
bt_woble->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOOFF", &bt_woble->woble_setting_radio_off, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
switch (bdev->bt_cfg.unify_woble_type) {
case 0:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_LEGACY", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
case 1:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_WAVEFORM", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
case 2:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_IR", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
default:
BTMTK_WARN("%s: unify_woble_type unknown(%d)", __func__, bdev->bt_cfg.unify_woble_type);
}
if (err)
BTMTK_WARN("%s: Parse unify_woble_type(%d) failed", __func__, bdev->bt_cfg.unify_woble_type);
err = btmtk_load_fw_cfg_setting("RADIOOFF_STATUS_EVENT",
&bt_woble->woble_setting_radio_off_status_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOOFF_COMPLETE_EVENT",
&bt_woble->woble_setting_radio_off_comp_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON",
&bt_woble->woble_setting_radio_on, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON_STATUS_EVENT",
&bt_woble->woble_setting_radio_on_status_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON_COMPLETE_EVENT",
&bt_woble->woble_setting_radio_on_comp_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_RESUME",
bt_woble->woble_setting_apcf_resume, WOBLE_SETTING_COUNT, bdev->setting_file, FW_CFG_INX_LEN_2);
LOAD_END:
/* release setting file memory */
if (bdev) {
kfree(bdev->setting_file);
bdev->setting_file = NULL;
}
if (err)
BTMTK_ERR("%s: error return %d", __func__, err);
return err;
}
static void btmtk_check_wobx_debug_log(struct btmtk_dev *bdev)
{
/* 0xFF, 0xFF, 0xFF, 0xFF is log level */
u8 cmd[CHECK_WOBX_DEBUG_CMD_LEN] = { 0X01, 0xCE, 0xFC, 0x04, 0xFF, 0xFF, 0xFF, 0xFF };
u8 event[CHECK_WOBX_DEBUG_EVT_HDR_LEN] = { 0x04, 0xE8 };
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, CHECK_WOBX_DEBUG_CMD_LEN,
event, CHECK_WOBX_DEBUG_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
/* Driver just print event to kernel log in rx_work,
* Please reference wiki to know what it is.
*/
}
static int btmtk_handle_leaving_WoBLE_state(struct btmtk_woble *bt_woble)
{
int ret = 0;
unsigned char fstate = 0;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: begin", __func__);
#if WAKEUP_BT_IRQ
/* Can't enter woble mode */
BTMTK_INFO("not support woble mode for wakeup bt irq");
return 0;
#endif
fstate = btmtk_fops_get_state(bdev);
if (!bdev->bt_cfg.support_woble_for_bt_disable) {
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not opened, return", __func__);
return 0;
}
}
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d), need to start traffic before leaving woble",
__func__, fstate);
/* start traffic to recv event*/
ret = bmain_info->hif_hook.open(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_open failed", __func__);
goto Finish;
}
}
if (is_support_unify_woble(bdev)) {
ret = btmtk_set_Woble_Radio_On(bt_woble);
if (ret < 0)
goto Finish;
ret = btmtk_set_Woble_APCF_Resume(bt_woble);
if (ret < 0)
goto Finish;
} else {
/* radio on cmd with wobx_mode_disable, used when unify woble off */
ret = btmtk_send_woble_resume_cmd(bdev);
}
Finish:
if (ret < 0) {
BTMTK_INFO("%s: woble_resume_fail!!!", __func__);
} else {
/* It's wobx debug log method. */
btmtk_check_wobx_debug_log(bdev);
if (fstate != BTMTK_FOPS_STATE_OPENED) {
ret = btmtk_send_deinit_cmds(bdev);
if (ret < 0) {
BTMTK_ERR("%s, btmtk_send_deinit_cmds failed", __func__);
goto exit;
}
BTMTK_WARN("%s: fops is not open(%d), need to stop traffic after leaving woble",
__func__, fstate);
/* stop traffic to stop recv data from fw*/
ret = bmain_info->hif_hook.close(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_close failed", __func__);
goto exit;
}
} else
bdev->power_state = BTMTK_DONGLE_STATE_POWER_ON;
BTMTK_INFO("%s: success", __func__);
}
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
static int btmtk_handle_entering_WoBLE_state(struct btmtk_woble *bt_woble)
{
int ret = 0;
unsigned char fstate = 0;
int state = 0;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: begin", __func__);
#if WAKEUP_BT_IRQ
/* Can't enter woble mode */
BTMTK_INFO("not support woble mode for wakeup bt irq");
return 0;
#endif
fstate = btmtk_fops_get_state(bdev);
if (!bdev->bt_cfg.support_woble_for_bt_disable) {
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d)!, return", __func__, fstate);
return 0;
}
}
state = btmtk_get_chip_state(bdev);
if (state == BTMTK_STATE_FW_DUMP) {
BTMTK_WARN("%s: FW dumping ongoing, don't send any cmd to FW!!!", __func__);
goto Finish;
}
if (atomic_read(&bmain_info->chip_reset) || atomic_read(&bmain_info->subsys_reset)) {
BTMTK_ERR("%s chip_reset is %d, subsys_reset is %d", __func__,
atomic_read(&bmain_info->chip_reset), atomic_read(&bmain_info->subsys_reset));
goto Finish;
}
/* Power on first if state is power off */
ret = btmtk_reset_power_on(bdev);
if (ret < 0) {
BTMTK_ERR("%s: reset power_on fail return", __func__);
goto Finish;
}
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d), need to start traffic before enter woble",
__func__, fstate);
/* start traffic to recv event*/
ret = bmain_info->hif_hook.open(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_open failed", __func__);
goto Finish;
}
}
if (is_support_unify_woble(bdev)) {
do {
typedef ssize_t (*func) (u16 u16Key, const char *buf, size_t size);
char *func_name = "MDrv_PM_Write_Key";
func pFunc = NULL;
ssize_t sret = 0;
u8 buf = 0;
pFunc = (func) btmtk_kallsyms_lookup_name(func_name);
if (pFunc && bdev->bt_cfg.unify_woble_type == 1) {
buf = 1;
sret = pFunc(PM_KEY_BTW, &buf, sizeof(u8));
BTMTK_INFO("%s: Invoke %s, buf = %d, sret = %zd", __func__,
func_name, buf, sret);
} else {
BTMTK_WARN("%s: No Exported Func Found [%s]", __func__, func_name);
}
} while (0);
ret = btmtk_send_woble_read_BDADDR_cmd(bdev);
if (ret < 0)
goto STOP_TRAFFIC;
ret = btmtk_set_Woble_APCF(bt_woble);
if (ret < 0)
goto STOP_TRAFFIC;
ret = btmtk_set_Woble_Radio_Off(bt_woble);
if (ret < 0)
goto STOP_TRAFFIC;
} else {
/* radio off cmd with wobx_mode_disable, used when unify woble off */
ret = btmtk_send_woble_suspend_cmd(bdev);
}
STOP_TRAFFIC:
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open(%d), need to stop traffic after enter woble",
__func__, fstate);
/* stop traffic to stop recv data from fw*/
ret = bmain_info->hif_hook.close(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_close failed", __func__);
goto Finish;
}
}
Finish:
if (ret) {
bdev->power_state = BTMTK_DONGLE_STATE_ERROR;
btmtk_woble_wake_lock(bdev);
}
BTMTK_INFO("%s: end ret = %d, power_state =%d", __func__, ret, bdev->power_state);
return ret;
}
int btmtk_woble_suspend(struct btmtk_woble *bt_woble)
{
int ret = 0;
unsigned char fstate = 0;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: enter", __func__);
if (bdev == NULL) {
BTMTK_WARN("%s: bdev is NULL", __func__);
goto exit;
}
fstate = btmtk_fops_get_state(bdev);
if (!is_support_unify_woble(bdev) && (fstate != BTMTK_FOPS_STATE_OPENED)) {
BTMTK_WARN("%s: when not support woble, in bt off state, do nothing!", __func__);
goto exit;
}
ret = btmtk_handle_entering_WoBLE_state(bt_woble);
if (ret)
BTMTK_ERR("%s: btmtk_handle_entering_WoBLE_state return fail %d", __func__, ret);
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
int btmtk_woble_resume(struct btmtk_woble *bt_woble)
{
int ret = 0;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: enter", __func__);
fstate = btmtk_fops_get_state(bdev);
if (!is_support_unify_woble(bdev) && (fstate != BTMTK_FOPS_STATE_OPENED)) {
BTMTK_WARN("%s: when not support woble, in bt off state, do nothing!", __func__);
goto exit;
}
if (bdev->power_state == BTMTK_DONGLE_STATE_ERROR) {
BTMTK_INFO("%s: In BTMTK_DONGLE_STATE_ERROR(Could suspend caused), do assert", __func__);
btmtk_send_assert_cmd(bdev);
ret = -EBADFD;
goto exit;
}
ret = btmtk_handle_leaving_WoBLE_state(bt_woble);
if (ret < 0) {
BTMTK_ERR("%s: btmtk_handle_leaving_WoBLE_state return fail %d", __func__, ret);
/* avoid rtc to to suspend again, do FW dump first */
btmtk_woble_wake_lock(bdev);
goto exit;
}
if (bdev->bt_cfg.reset_stack_after_woble
&& bmain_info->reset_stack_flag == HW_ERR_NONE
&& fstate == BTMTK_FOPS_STATE_OPENED)
bmain_info->reset_stack_flag = HW_ERR_CODE_RESET_STACK_AFTER_WOBLE;
btmtk_send_hw_err_to_host(bdev);
BTMTK_INFO("%s: end(%d), reset_stack_flag = %d, fstate = %d", __func__, ret,
bmain_info->reset_stack_flag, fstate);
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
static irqreturn_t btmtk_woble_isr(int irq, struct btmtk_woble *bt_woble)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_DBG("%s begin", __func__);
disable_irq_nosync(bt_woble->wobt_irq);
atomic_dec(&(bt_woble->irq_enable_count));
BTMTK_INFO("disable BT IRQ, call wake lock");
__pm_wakeup_event(bmain_info->eint_ws, WAIT_POWERKEY_TIMEOUT);
input_report_key(bt_woble->WoBLEInputDev, KEY_WAKEUP, 1);
input_sync(bt_woble->WoBLEInputDev);
input_report_key(bt_woble->WoBLEInputDev, KEY_WAKEUP, 0);
input_sync(bt_woble->WoBLEInputDev);
BTMTK_DBG("%s end", __func__);
return IRQ_HANDLED;
}
static int btmtk_RegisterBTIrq(struct btmtk_woble *bt_woble)
{
struct device_node *eint_node = NULL;
int interrupts[2];
BTMTK_DBG("%s begin", __func__);
eint_node = of_find_compatible_node(NULL, NULL, "mediatek,woble_eint");
if (eint_node) {
BTMTK_INFO("Get woble_eint compatible node");
bt_woble->wobt_irq = irq_of_parse_and_map(eint_node, 0);
BTMTK_INFO("woble_irq number:%d", bt_woble->wobt_irq);
if (bt_woble->wobt_irq) {
of_property_read_u32_array(eint_node, "interrupts",
interrupts, ARRAY_SIZE(interrupts));
bt_woble->wobt_irqlevel = interrupts[1];
if (request_irq(bt_woble->wobt_irq, (void *)btmtk_woble_isr,
bt_woble->wobt_irqlevel, "woble-eint", bt_woble))
BTMTK_INFO("WOBTIRQ LINE NOT AVAILABLE!!");
else {
BTMTK_INFO("disable BT IRQ");
disable_irq_nosync(bt_woble->wobt_irq);
}
} else
BTMTK_INFO("can't find woble_eint irq");
} else {
bt_woble->wobt_irq = 0;
BTMTK_INFO("can't find woble_eint compatible node");
}
BTMTK_DBG("%s end", __func__);
return 0;
}
static int btmtk_woble_input_init(struct btmtk_woble *bt_woble)
{
int ret = 0;
bt_woble->WoBLEInputDev = input_allocate_device();
if (!bt_woble->WoBLEInputDev || IS_ERR(bt_woble->WoBLEInputDev)) {
BTMTK_ERR("input_allocate_device error");
return -ENOMEM;
}
bt_woble->WoBLEInputDev->name = "WOBLE_INPUT_DEVICE";
bt_woble->WoBLEInputDev->id.bustype = BUS_HOST;
bt_woble->WoBLEInputDev->id.vendor = 0x0002;
bt_woble->WoBLEInputDev->id.product = 0x0002;
bt_woble->WoBLEInputDev->id.version = 0x0002;
__set_bit(EV_KEY, bt_woble->WoBLEInputDev->evbit);
__set_bit(KEY_WAKEUP, bt_woble->WoBLEInputDev->keybit);
ret = input_register_device(bt_woble->WoBLEInputDev);
if (ret < 0) {
input_free_device(bt_woble->WoBLEInputDev);
BTMTK_ERR("input_register_device %d", ret);
return ret;
}
return ret;
}
static void btmtk_woble_input_deinit(struct btmtk_woble *bt_woble)
{
if (bt_woble->WoBLEInputDev) {
input_unregister_device(bt_woble->WoBLEInputDev);
/* Do not need to free WOBLE_INPUT_DEVICE, because after unregister it,
* kernel will free it by itself.
*/
/* input_free_device(bt_woble->WoBLEInputDev); */
bt_woble->WoBLEInputDev = NULL;
}
}
static void btmtk_free_woble_setting_file(struct btmtk_woble *bt_woble)
{
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_resume, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off_status_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off_comp_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on_status_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on_comp_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_wakeup_type, 1);
bt_woble->woble_setting_len = 0;
kfree(bt_woble->woble_setting_file_name);
bt_woble->woble_setting_file_name = NULL;
}
int btmtk_woble_initialize(struct btmtk_dev *bdev, struct btmtk_woble *bt_woble)
{
int err = 0;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
bt_woble->bdev = bdev;
/* Need to add Woble flow */
if (is_support_unify_woble(bdev)) {
if (bt_woble->woble_setting_file_name == NULL) {
bt_woble->woble_setting_file_name = kzalloc(MAX_BIN_FILE_NAME_LEN, GFP_KERNEL);
if (!bt_woble->woble_setting_file_name) {
BTMTK_ERR("%s: alloc memory fail (bt_woble->woble_setting_file_name)", __func__);
err = -1;
goto end;
}
}
(void)snprintf(bt_woble->woble_setting_file_name, MAX_BIN_FILE_NAME_LEN,
"%s_%x.%s", WOBLE_CFG_NAME_PREFIX, bdev->chip_id & 0xffff,
WOBLE_CFG_NAME_SUFFIX);
BTMTK_INFO("%s: woble setting file name is %s", __func__, bt_woble->woble_setting_file_name);
btmtk_load_woble_setting(bt_woble->woble_setting_file_name,
bdev->intf_dev,
&bt_woble->woble_setting_len,
bt_woble);
/* if reset_stack is true, when chip reset is done, we need to power on chip to do
* reset stack
*/
if (bmain_info->reset_stack_flag) {
err = btmtk_reset_power_on(bdev);
if (err < 0) {
BTMTK_ERR("reset power on failed!");
goto err;
}
}
}
if (bdev->bt_cfg.support_woble_by_eint) {
btmtk_woble_input_init(bt_woble);
btmtk_RegisterBTIrq(bt_woble);
}
return 0;
err:
btmtk_free_woble_setting_file(bt_woble);
end:
return err;
}
void btmtk_woble_uninitialize(struct btmtk_woble *bt_woble)
{
struct btmtk_dev *bdev = bt_woble->bdev;
if (bdev == NULL) {
BTMTK_ERR("%s: bdev == NULL", __func__);
return;
}
BTMTK_INFO("%s begin", __func__);
if (bdev->bt_cfg.support_woble_by_eint) {
if (bt_woble->wobt_irq != 0 && atomic_read(&(bt_woble->irq_enable_count)) == 1) {
BTMTK_INFO("disable BT IRQ:%d", bt_woble->wobt_irq);
atomic_dec(&(bt_woble->irq_enable_count));
disable_irq_nosync(bt_woble->wobt_irq);
} else
BTMTK_INFO("irq_enable count:%d", atomic_read(&(bt_woble->irq_enable_count)));
if (bt_woble->wobt_irq) {
free_irq(bt_woble->wobt_irq, bt_woble);
bt_woble->wobt_irq = 0;
}
btmtk_woble_input_deinit(bt_woble);
}
btmtk_free_woble_setting_file(bt_woble);
bt_woble->bdev = NULL;
}

View file

@ -0,0 +1,87 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef __BTMTK_BUFFER_MODE_H__
#define __BTMTK_BUFFER_MODE_H__
#include "btmtk_main.h"
#define BUFFER_MODE_SWITCH_FILE "wifi.cfg"
#define BUFFER_MODE_SWITCH_FIELD "EfuseBufferModeCal"
#define BUFFER_MODE_CFG_FILE "EEPROM_MT%X_1.bin"
#define EFUSE_MODE 0
#define BIN_FILE_MODE 1
#define AUTO_MODE 2
#define SET_ADDRESS_CMD_LEN 10
#define SET_ADDRESS_EVT_LEN 7
#define SET_ADDRESS_CMD_PAYLOAD_OFFSET 4
#define SET_RADIO_CMD_LEN 12
#define SET_RADIO_EVT_LEN 7
#define SET_RADIO_CMD_EDR_DEF_OFFSET 4
#define SET_RADIO_CMD_BLE_OFFSET 8
#define SET_RADIO_CMD_EDR_MAX_OFFSET 9
#define SET_RADIO_CMD_EDR_MODE_OFFSET 11
#define SET_GRP_CMD_LEN 13
#define SET_GRP_EVT_LEN 7
#define SET_GRP_CMD_PAYLOAD_OFFSET 8
#define SET_PWR_OFFSET_CMD_LEN 14
#define SET_PWR_OFFSET_EVT_LEN 7
#define SET_PWR_OFFSET_CMD_PAYLOAD_OFFSET 8
#define BUFFER_MODE_MAC_LENGTH 6
#define BT0_MAC_OFFSET 0x139
#define BT1_MAC_OFFSET 0x13F
#define BUFFER_MODE_RADIO_LENGTH 4
#define BT0_RADIO_OFFSET 0x145
#define BT1_RADIO_OFFSET 0x149
#define BUFFER_MODE_GROUP_LENGTH 5
#define BT0_GROUP_ANT0_OFFSET 0x984
#define BT0_GROUP_ANT1_OFFSET 0x9BE
#define BT1_GROUP_ANT0_OFFSET 0x9A1
#define BT1_GROUP_ANT1_OFFSET 0x9DB
#define BUFFER_MODE_CAL_LENGTH 6
#define BT0_CAL_ANT0_OFFSET 0x96C
#define BT0_CAL_ANT1_OFFSET 0x9A6
#define BT1_CAL_ANT0_OFFSET 0x989
#define BT1_CAL_ANT1_OFFSET 0x9C3
struct btmtk_buffer_mode_radio_struct {
u8 radio_0; /* bit 0-5:edr_init_pwr, 6-7:edr_pwr_mode */
u8 radio_1; /* bit 0-5:edr_max_pwr, 6-7:reserved */
u8 radio_2; /* bit 0-5:ble_default_pwr, 6-7:reserved */
u8 radio_3; /* reserved */
};
struct btmtk_buffer_mode_struct {
struct btmtk_dev *bdev;
unsigned char file_name[MAX_BIN_FILE_NAME_LEN];
int efuse_mode;
u8 bt0_mac[BUFFER_MODE_MAC_LENGTH];
u8 bt1_mac[BUFFER_MODE_MAC_LENGTH];
struct btmtk_buffer_mode_radio_struct bt0_radio;
struct btmtk_buffer_mode_radio_struct bt1_radio;
u8 bt0_ant0_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt0_ant1_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt1_ant0_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt1_ant1_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt0_ant0_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt0_ant1_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt1_ant0_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt1_ant1_pwr_offset[BUFFER_MODE_CAL_LENGTH];
};
int btmtk_buffer_mode_send(struct btmtk_buffer_mode_struct *buffer_mode);
void btmtk_buffer_mode_initialize(struct btmtk_dev *bdev, struct btmtk_buffer_mode_struct **buffer_mode);
#endif /* __BTMTK_BUFFER_MODE_H__ */

View file

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#ifndef __BTMTK_CHIP_IF_H__
#define __BTMTK_CHIP_IF_H__
#ifdef CHIP_IF_USB
#include "btmtk_usb.h"
#elif defined(CHIP_IF_SDIO)
#include "btmtk_sdio.h"
#elif defined(CHIP_IF_UART)
#include "btmtk_uart.h"
#elif defined(CHIP_IF_BTIF)
#include "btmtk_btif.h"
#endif
int btmtk_cif_register(void);
int btmtk_cif_deregister(void);
#endif /* __BTMTK_CHIP_IF_H__ */

View file

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#ifndef __BTMTK_CHIP_RESET_H__
#define __BTMTK_CHIP_RESET_H__
#include <linux/version.h>
#include <linux/timer.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_woble.h"
#define CHIP_RESET_TIMEOUT 20
void btmtk_reset_timer_add(struct btmtk_dev *bdev);
void btmtk_reset_timer_update(struct btmtk_dev *bdev);
void btmtk_reset_timer_del(struct btmtk_dev *bdev);
void btmtk_reset_trigger(struct btmtk_dev *bdev);
void btmtk_reset_waker(struct work_struct *work);
#endif /* __BTMTK_WOBLE_H__ */

View file

@ -0,0 +1,395 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef __BTMTK_DEFINE_H__
#define __BTMTK_DEFINE_H__
#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <linux/cdev.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/device.h>
#include <asm/unaligned.h>
/* Define for proce node */
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
/* Define for whole chip reset */
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/vmalloc.h>
#include <linux/rtc.h>
#ifdef CFG_CHIP_RESET_KO_SUPPORT
#include "reset.h"
#endif
/** Driver version */
#define VERSION "7.0.2022053101"
#define SUBVER ":turnkey"
#ifdef CFG_SUPPORT_WAKEUP_IRQ
#define WAKEUP_BT_IRQ 1
#else
#define WAKEUP_BT_IRQ 0
#endif
#define ENABLESTP FALSE
#define BTMTKUART_TX_STATE_ACTIVE 1
#define BTMTKUART_TX_STATE_WAKEUP 2
#define BTMTK_TX_WAIT_VND_EVT 3
#define BTMTKUART_REQUIRED_WAKEUP 4
#define BTMTKUART_REQUIRED_DOWNLOAD 5
#define BTMTK_TX_SKIP_VENDOR_EVT 6
#define BTMTKUART_RX_STATE_ACTIVE 1
#define BTMTKUART_RX_STATE_WAKEUP 2
#define BTMTKUART_RX_STATE_RESET 3
/**
* Maximum rom patch file name length
*/
#define MAX_BIN_FILE_NAME_LEN 64
/**
* Type definition
*/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#ifndef ALIGN_4
#define ALIGN_4(_value) (((_value) + 3) & ~3u)
#endif /* ALIGN_4 */
#ifndef ALIGN_8
#define ALIGN_8(_value) (((_value) + 7) & ~7u)
#endif /* ALIGN_4 */
/* This macro check the DW alignment of the input value.
* _value - value of address need to check
*/
#ifndef IS_ALIGN_4
#define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE)
#endif /* IS_ALIGN_4 */
#ifndef IS_NOT_ALIGN_4
#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE)
#endif /* IS_NOT_ALIGN_4 */
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/**
* Log and level definition
*/
#define BTMTK_LOG_LVL_ERR 1
#define BTMTK_LOG_LVL_WARN 2
#define BTMTK_LOG_LVL_INFO 3
#define BTMTK_LOG_LVL_DBG 4
#define BTMTK_LOG_LVL_MAX BTMTK_LOG_LVL_DBG
#define BTMTK_LOG_LVL_DEF BTMTK_LOG_LVL_INFO /* default setting */
#define HCI_SNOOP_ENTRY_NUM 30
#define HCI_SNOOP_BUF_SIZE 32
#define HCI_SNOOP_MAX_BUF_SIZE 66
#define HCI_SNOOP_TS_STR_LEN 24
#define WMT_OVER_HCI_HEADER_SIZE 3
#define READ_ISO_PACKET_CMD_SIZE 4
extern uint8_t btmtk_log_lvl;
#define BTMTK_ERR(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_ERR) pr_info("[btmtk_err] ***"fmt"***\n", ##__VA_ARGS__); } while (0)
#define BTMTK_WARN(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_WARN) pr_info("[btmtk_warn] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_INFO(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) pr_info("[btmtk_info] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_DBG(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) pr_info("[btmtk_dbg] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_WARN_LIMITTED(fmt, ...) \
do { \
if (btmtk_log_lvl >= BTMTK_LOG_LVL_WARN) \
pr_info(KERN_WARNING "[btmtk_warn_limit] "fmt"\n", ##__VA_ARGS__); \
} while (0)
#define BTMTK_INFO_RAW(p, l, fmt, ...) \
do { \
if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) { \
int cnt_ = 0; \
int len_ = (l <= HCI_SNOOP_MAX_BUF_SIZE ? l : HCI_SNOOP_MAX_BUF_SIZE); \
uint8_t raw_buf[HCI_SNOOP_MAX_BUF_SIZE * 5 + 10]; \
const unsigned char *ptr = p; \
for (cnt_ = 0; cnt_ < len_; ++cnt_) \
(void)snprintf(raw_buf+5*cnt_, 6, "0x%02X ", ptr[cnt_]); \
raw_buf[5*cnt_] = '\0'; \
if (l <= HCI_SNOOP_MAX_BUF_SIZE) { \
pr_cont("[btmtk_info] "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
} else { \
pr_cont("[btmtk_info] "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
} \
} \
} while (0)
#define BTMTK_DBG_RAW(p, l, fmt, ...) \
do { \
if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) { \
int cnt_ = 0; \
int len_ = (l <= HCI_SNOOP_MAX_BUF_SIZE ? l : HCI_SNOOP_MAX_BUF_SIZE); \
uint8_t raw_buf[HCI_SNOOP_MAX_BUF_SIZE * 5 + 10]; \
const unsigned char *ptr = p; \
for (cnt_ = 0; cnt_ < len_; ++cnt_) \
(void)snprintf(raw_buf+5*cnt_, 6, "0x%02X ", ptr[cnt_]); \
raw_buf[5*cnt_] = '\0'; \
if (l <= HCI_SNOOP_MAX_BUF_SIZE) { \
pr_cont("[btmtk_debug] "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
} else { \
pr_cont("[btmtk_debug] "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
} \
} \
} while (0)
#define BTMTK_CIF_IS_NULL(bdev, cif_event) \
(!bdev || !(&bdev->cif_state[cif_event]))
/**
*
* HCI packet type
*/
#define MTK_HCI_COMMAND_PKT 0x01
#define MTK_HCI_ACLDATA_PKT 0x02
#define MTK_HCI_SCODATA_PKT 0x03
#define MTK_HCI_EVENT_PKT 0x04
#define HCI_ISO_PKT 0x05
#define HCI_ISO_PKT_HEADER_SIZE 4
#define HCI_ISO_PKT_WITH_ACL_HEADER_SIZE 5
/**
* ROM patch related
*/
#define PATCH_HCI_HEADER_SIZE 4
#define PATCH_WMT_HEADER_SIZE 5
/*
* Enable STP
* HCI+WMT+STP = 4 + 5 + 1(phase) +(4=STP_HEADER + 2=CRC)
#define PATCH_HEADER_SIZE 16
*/
/*#ifdef ENABLESTP
* #define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE + 1 + 6)
* #define UPLOAD_PATCH_UNIT 916
* #define PATCH_INFO_SIZE 30
*#else
*/
#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE + 1)
/* TODO, If usb use 901 patch unit size, download patch will timeout
* because the timeout has been set to 1s
*/
#define UPLOAD_PATCH_UNIT 1988
#define PATCH_INFO_SIZE 30
/*#endif*/
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 7
#define IO_BUF_SIZE (HCI_MAX_EVENT_SIZE > 256 ? HCI_MAX_EVENT_SIZE : 256)
#define EVENT_COMPARE_SIZE 64
#define SECTION_SPEC_NUM 13
#define BD_ADDRESS_SIZE 6
#define PHASE1_WMT_CMD_COUNT 255
#define VENDOR_CMD_COUNT 255
#define BT_CFG_NAME "bt.cfg"
#define BT_CFG_NAME_PREFIX "bt_mt"
#define BT_CFG_NAME_SUFFIX "cfg"
#define WOBLE_CFG_NAME_PREFIX "woble_setting"
#define WOBLE_CFG_NAME_SUFFIX "bin"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WOBLE_BY_EINT "SUPPORT_WOBLE_BY_EINT"
#define BT_DONGLE_RESET_PIN "BT_DONGLE_RESET_GPIO_PIN"
#define BT_RESET_DONGLE "SUPPORT_DONGLE_RESET"
#define BT_FULL_FW_DUMP "SUPPORT_FULL_FW_DUMP"
#define BT_WOBLE_WAKELOCK "SUPPORT_WOBLE_WAKELOCK"
#define BT_WOBLE_FOR_BT_DISABLE "SUPPORT_WOBLE_FOR_BT_DISABLE"
#define BT_RESET_STACK_AFTER_WOBLE "RESET_STACK_AFTER_WOBLE"
#define BT_AUTO_PICUS "SUPPORT_AUTO_PICUS"
#define BT_AUTO_PICUS_FILTER "PICUS_FILTER_COMMAND"
#define BT_AUTO_PICUS_ENABLE "PICUS_ENABLE_COMMAND"
#define BT_PICUS_TO_HOST "SUPPORT_PICUS_TO_HOST"
#define BT_PHASE1_WMT_CMD "PHASE1_WMT_CMD"
#define BT_VENDOR_CMD "VENDOR_CMD"
#define BT_SINGLE_SKU "SUPPORT_BT_SINGLE_SKU"
#define BT_AUDIO_SET "SUPPORT_BT_AUDIO_SETTING"
#define BT_AUDIO_ENABLE_CMD "AUDIO_ENABLE_CMD"
#define BT_AUDIO_PINMUX_NUM "AUDIO_PINMUX_NUM"
#define BT_AUDIO_PINMUX_MODE "AUDIO_PINMUX_MODE"
#define PM_KEY_BTW (0x0015) /* Notify PM the unify woble type */
#define BTMTK_RESET_DOING 1
#define BTMTK_RESET_DONE 0
#define BTMTK_MAX_SUBSYS_RESET_COUNT 3
/**
* Disable RESUME_RESUME
*/
#ifndef BT_DISABLE_RESET_RESUME
#define BT_DISABLE_RESET_RESUME 0
#endif
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
char *content; /* APCF content or radio off content */
u32 length; /* APCF content or radio off content of length */
};
struct bt_cfg_struct {
bool support_unify_woble; /* support unify woble or not */
bool support_woble_by_eint; /* support woble by eint or not */
bool support_dongle_reset; /* support chip reset or not */
bool support_full_fw_dump; /* dump full fw coredump or not */
bool support_woble_wakelock; /* support when woble error, do wakelock or not */
bool support_woble_for_bt_disable; /* when bt disable, support enter susend or not */
bool reset_stack_after_woble; /* support reset stack to re-connect IOT after resume */
bool support_auto_picus; /* support enable PICUS automatically */
struct fw_cfg_struct picus_filter; /* support on PICUS filter command customization */
struct fw_cfg_struct picus_enable; /* support on PICUS enable command customization */
bool support_picus_to_host; /* support picus log to host (boots/bluedroid) */
int dongle_reset_gpio_pin; /* BT_DONGLE_RESET_GPIO_PIN number */
unsigned int unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct phase1_wmt_cmd[PHASE1_WMT_CMD_COUNT];
struct fw_cfg_struct vendor_cmd[VENDOR_CMD_COUNT];
bool support_bt_single_sku;
bool support_audio_setting; /* support audio set pinmux */
struct fw_cfg_struct audio_cmd; /* support on audio enable command customization */
struct fw_cfg_struct audio_pinmux_num; /* support on set audio pinmux num command customization */
struct fw_cfg_struct audio_pinmux_mode; /* support on set audio pinmux mode command customization */
};
enum debug_reg_index_len {
DEBUG_REG_INX_LEN_NONE = 0,
DEBUG_REG_INX_LEN_2 = 2,
DEBUG_REG_INX_LEN_3 = 3,
};
#define DEBUG_REG_SIZE 10
#define DEBUG_REG_NUM 10
struct debug_reg {
u32 *content;
u32 length;
};
struct debug_reg_struct {
struct debug_reg *reg;
u32 num;
};
struct bt_utc_struct {
struct rtc_time tm;
u32 usec;
};
#define BT_DOWNLOAD 1
#define WIFI_DOWNLOAD 2
#define ZB_DOWNLOAD 3
#define SWAP32(x) \
((u32) (\
(((u32) (x) & (u32) 0x000000ffUL) << 24) | \
(((u32) (x) & (u32) 0x0000ff00UL) << 8) | \
(((u32) (x) & (u32) 0x00ff0000UL) >> 8) | \
(((u32) (x) & (u32) 0xff000000UL) >> 24)))
/* Endian byte swapping codes */
#ifdef __LITTLE_ENDIAN
#define cpu2le32(x) ((uint32_t)(x))
#define le2cpu32(x) ((uint32_t)(x))
#define cpu2be32(x) SWAP32((x))
#define be2cpu32(x) SWAP32((x))
#else
#define cpu2le32(x) SWAP32((x))
#define le2cpu32(x) SWAP32((x))
#define cpu2be32(x) ((uint32_t)(x))
#define be2cpu32(x) ((uint32_t)(x))
#endif
#define FW_VERSION 0x80021004
#define CHIP_ID 0x70010200
#define FLAVOR 0x70010020
#define ZB_ENABLE 0x7C00114C
#ifndef DEBUG_LD_PATCH_TIME
#define DEBUG_LD_PATCH_TIME 0
#endif
#ifndef DEBUG_DUMP_TIME
#define DEBUG_DUMP_TIME 0
#endif
#define ERRNUM 0xFF
#if DEBUG_DUMP_TIME
void btmtk_getUTCtime(struct bt_utc_struct *utc);
#define DUMP_TIME_STAMP(__str) \
do { \
struct bt_utc_struct utc; \
btmtk_getUTCtime(&utc); \
BTMTK_INFO("%s:%d, %s - DUMP_TIME_STAMP UTC: %d-%02d-%02d %02d:%02d:%02d.%06u", \
__func__, __LINE__, __str, \
utc.tm.tm_year, utc.tm.tm_mon, utc.tm.tm_mday, \
utc.tm.tm_hour, utc.tm.tm_min, utc.tm.tm_sec, utc.usec); \
} while (0)
#else
#define DUMP_TIME_STAMP(__str)
#endif
#if CFG_SUPPORT_BMR_RX_CLK
#define ENABLE_DEINT_IRQ 1
#include <mt-plat/mtk_secure_api.h>
extern int mtk_deint_enable(unsigned int eint_num, unsigned int spi_num, unsigned long type);
extern int mtk_deint_ack(unsigned int irq);
#define MTK_SIP_BT_FIQ_REG (0x82000523 | MTK_SIP_SMC_AARCH_BIT)
#define MTK_SIP_BT_GET_CLK (0x82000524 | MTK_SIP_SMC_AARCH_BIT)
#endif
#endif /* __BTMTK_DEFINE_H__ */

View file

@ -0,0 +1,145 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef _BTMTK_DRV_H_
#define _BTMTK_DRV_H_
#include <linux/kthread.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <net/bluetooth/bluetooth.h>
#define SAVE_FW_DUMP_IN_KERNEL 1
#define SUPPORT_FW_DUMP 1
#define BTM_HEADER_LEN 5
#define BTM_UPLD_SIZE 2312
#define MTK_TXDATA_SIZE 2000
#define MTK_RXDATA_SIZE 2000
/* Time to wait until Host Sleep state change in millisecond */
#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000)
/* Time to wait for command response in millisecond */
#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000)
enum rdwr_status {
RDWR_STATUS_SUCCESS = 0,
RDWR_STATUS_FAILURE = 1,
RDWR_STATUS_DONE = 2
};
#define FW_DUMP_MAX_NAME_LEN 8
#define FW_DUMP_HOST_READY 0xEE
#define FW_DUMP_DONE 0xFF
#define FW_DUMP_READ_DONE 0xFE
struct memory_type_mapping {
u8 mem_name[FW_DUMP_MAX_NAME_LEN];
u8 *mem_ptr;
u32 mem_size;
u8 done_flag;
};
#define MTK_VENDOR_PKT 0xFE
/* Vendor specific Bluetooth commands */
#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03
#define BT_CMD_ROUTE_SCO_TO_HOST 0xFC1D
#define BT_CMD_SET_BDADDR 0xFC22
#define BT_CMD_AUTO_SLEEP_MODE 0xFC23
#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59
#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A
#define BT_CMD_MODULE_CFG_REQ 0xFC5B
#define BT_CMD_LOAD_CONFIG_DATA 0xFC61
/* Sub-commands: Module Bringup/Shutdown Request/Response */
#define MODULE_BRINGUP_REQ 0xF1
#define MODULE_BROUGHT_UP 0x00
#define MODULE_ALREADY_UP 0x0C
#define MODULE_SHUTDOWN_REQ 0xF2
/* Vendor specific Bluetooth events */
#define BT_EVENT_AUTO_SLEEP_MODE 0x23
#define BT_EVENT_HOST_SLEEP_CONFIG 0x59
#define BT_EVENT_HOST_SLEEP_ENABLE 0x5A
#define BT_EVENT_MODULE_CFG_REQ 0x5B
#define BT_EVENT_POWER_STATE 0x20
/* Bluetooth Power States */
#define BT_PS_ENABLE 0x02
#define BT_PS_DISABLE 0x03
#define BT_PS_SLEEP 0x01
/* Host Sleep states */
#define HS_ACTIVATED 0x01
#define HS_DEACTIVATED 0x00
/* Power Save modes */
#define PS_SLEEP 0x01
#define PS_AWAKE 0x00
#define BT_CAL_HDR_LEN 4
#define BT_CAL_DATA_SIZE 28
#define FW_DUMP_BUF_SIZE (1024*512)
#define FW_DUMP_FILE_NAME_SIZE 64
/* #define SAVE_FW_DUMP_IN_KERNEL 1 */
/* stpbt device node */
#define BT_NODE "stpbt"
#define BT_DRIVER_NAME "BT_chrdev"
struct btmtk_event {
u8 ec; /* event counter */
u8 length;
u8 data[4];
} __packed;
/* Prototype of global function */
struct btmtk_private *btmtk_add_card(void *card);
int btmtk_remove_card(struct btmtk_private *priv);
void btmtk_interrupt(struct btmtk_private *priv);
bool btmtk_check_evtpkt(struct btmtk_private *priv, struct sk_buff *skb);
int btmtk_process_event(struct btmtk_private *priv, struct sk_buff *skb);
int btmtk_send_module_cfg_cmd(struct btmtk_private *priv, u8 subcmd);
int btmtk_pscan_window_reporting(struct btmtk_private *priv, u8 subcmd);
int btmtk_send_hscfg_cmd(struct btmtk_private *priv);
int btmtk_enable_ps(struct btmtk_private *priv);
int btmtk_prepare_command(struct btmtk_private *priv);
int btmtk_enable_hs(struct btmtk_private *priv);
void btmtk_firmware_dump(struct btmtk_private *priv);
#define META_BUFFER_SIZE (1024*50)
struct _OSAL_UNSLEEPABLE_LOCK_ {
spinlock_t lock;
unsigned long flag;
};
struct ring_buffer {
struct _OSAL_UNSLEEPABLE_LOCK_ spin_lock;
u8 buffer[META_BUFFER_SIZE]; /* MTKSTP_BUFFER_SIZE:1024 */
u32 read_p; /* indicate the current read index */
u32 write_p; /* indicate the current write index */
};
#ifdef CONFIG_DEBUG_FS
#define FW_DUMP_END_EVENT "coredump end"
#endif
#endif

View file

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef __BTMTK_FW_LOG_H__
#define __BTMTK_FW_LOG_H__
#include "btmtk_main.h"
#include "btmtk_chip_reset.h"
#define BT_FWLOG_IOC_MAGIC (0xfc)
#define BT_FWLOG_IOC_ON_OFF _IOW(BT_FWLOG_IOC_MAGIC, 0, int)
#define BT_FWLOG_IOC_SET_LEVEL _IOW(BT_FWLOG_IOC_MAGIC, 1, int)
#define BT_FWLOG_IOC_GET_LEVEL _IOW(BT_FWLOG_IOC_MAGIC, 2, int)
#define BT_FWLOG_OFF 0x00
#define BT_FWLOG_ON 0xFF
#define DRV_RETURN_SPECIFIC_HCE_ONLY 1 /* Currently only allow 0xFC26 */
#define KPI_WITHOUT_TYPE 0 /* bluetooth kpi */
#ifdef STATIC_REGISTER_FWLOG_NODE
#define FIXED_STPBT_MAJOR_DEV_ID 111
#endif
/* Device node */
#if CFG_SUPPORT_MULTI_DEV_NODE
#define BT_FWLOG_DEV_NODE "stpbt_multi_fwlog"
#else
#define BT_FWLOG_DEV_NODE "stpbtfwlog"
#endif
#define PROC_ROOT_DIR "stpbt"
#define PROC_BT_CHIP_RESET_COUNT "bt_chip_reset_count"
struct btmtk_fops_fwlog {
dev_t g_devIDfwlog;
struct cdev BT_cdevfwlog;
wait_queue_head_t fw_log_inq;
struct sk_buff_head fwlog_queue;
struct class *pBTClass;
struct device *pBTDevfwlog;
spinlock_t fwlog_lock;
u8 btmtk_bluetooth_kpi;
struct sk_buff_head usr_opcode_queue;
};
int btmtk_fops_initfwlog(void);
int btmtk_fops_exitfwlog(void);
void fw_log_bt_event_cb(void);
void fw_log_bt_state_cb(uint8_t state);
/** file_operations: stpbtfwlog */
int btmtk_fops_openfwlog(struct inode *inode, struct file *file);
int btmtk_fops_closefwlog(struct inode *inode, struct file *file);
ssize_t btmtk_fops_readfwlog(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t btmtk_fops_writefwlog(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
unsigned int btmtk_fops_pollfwlog(struct file *filp, poll_table *wait);
long btmtk_fops_unlocked_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg);
long btmtk_fops_compat_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg);
int btmtk_dispatch_fwlog(struct btmtk_dev *bdev, struct sk_buff *skb);
int btmtk_dispatch_fwlog_bluetooth_kpi(struct btmtk_dev *bdev, u8 *buf, int len, u8 type);
#endif /* __BTMTK_FW_LOG_H__ */

View file

@ -0,0 +1,816 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#ifndef __BTMTK_MAIN_H__
#define __BTMTK_MAIN_H__
#include "btmtk_define.h"
#define DEFAULT_COUNTRY_TABLE_NAME "btPowerTable.dat"
#ifdef CHIP_IF_USB
#define DEFAULT_DEBUG_SOP_NAME "usb_debug"
#elif defined(CHIP_IF_SDIO)
#define DEFAULT_DEBUG_SOP_NAME "sdio_debug"
#endif
//static inline struct sk_buff *mtk_add_stp(struct btmtk_dev *bdev, struct sk_buff *skb);
#define hci_dev_test_and_clear_flag(hdev, nr) test_and_clear_bit((nr), (hdev)->dev_flags)
/* h4_recv */
#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
#define hci_skb_expect(skb) bt_cb((skb))->expect
#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
#define HCI_SDIO 6
#define HCI_SPI 7
#define HCI_I2C 8
#define HCI_SMD 9
#define HCI_TYPE_SIZE 1
/* this for 7663 need download patch staus
* 0:
* patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1:
* patch download is complete
* 2:
* patch download is not complete/BT get patch semaphore success
*/
#define MT766X_PATCH_IS_DOWNLOAD_BY_OTHER 0
#define MT766X_PATCH_READY 1
#define MT766X_PATCH_NEED_DOWNLOAD 2
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define PATCH_ERR -1
#define PATCH_NEED_DOWNLOAD 0
#define PATCH_IS_DOWNLOAD_BY_OTHER 1
#define PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
#define PATCH_DOWNLOAD_PHASE3_SECURE_BOOT_DELAY_TIME 200
#define TIME_MULTIPL 1000
#define TIME_US_OFFSET_RANGE 2000
/* * delay and retrey for main_send_cmd */
#define WMT_DELAY_TIMES 100
#define DELAY_TIMES 20
#define RETRY_TIMES 20
/* Expected minimum supported interface */
#define BT_MCU_MINIMUM_INTERFACE_NUM 4
/* Bus event */
#define HIF_EVENT_PROBE 0
#define HIF_EVENT_DISCONNECT 1
#define HIF_EVENT_SUSPEND 2
#define HIF_EVENT_RESUME 3
#define HIF_EVENT_STANDBY 4
#define HIF_EVENT_SUBSYS_RESET 5
#define HIF_EVENT_WHOLE_CHIP_RESET 6
#define HIF_EVENT_FW_DUMP 7
#define CHAR2HEX_SIZE 4
/**
* For chip reset pin
*/
#define RESET_PIN_SET_LOW_TIME 100
/* stpbtfwlog setting */
#define FWLOG_QUEUE_COUNT (400 * BT_MCU_MINIMUM_INTERFACE_NUM)
#define FWLOG_ASSERT_QUEUE_COUNT 45000
#define FWLOG_BLUETOOTH_KPI_QUEUE_COUNT 400
#define HCI_MAX_COMMAND_SIZE 255
#define HCI_MAX_COMMAND_BUF_SIZE (HCI_MAX_COMMAND_SIZE * 3)
#ifndef HCI_MAX_ISO_SIZE
#define HCI_MAX_ISO_SIZE 340
#endif
/* fwlog information define */
#define FWLOG_TYPE 0xF0
#define FWLOG_LEN_SIZE 2
#define FWLOG_TL_SIZE (HCI_TYPE_SIZE + FWLOG_LEN_SIZE)
#define FWLOG_ATTR_TYPE_LEN 1
#define FWLOG_ATTR_LEN_LEN 1
#define FWLOG_ATTR_RX_LEN_LEN 2
#define FWLOG_ATTR_TL_SIZE (FWLOG_ATTR_TYPE_LEN + FWLOG_ATTR_LEN_LEN)
#define FWLOG_HCI_IDX 0x00
#define FWLOG_DONGLE_IDX 0x01
#define FWLOG_TX 0x10
#define FWLOG_RX 0x11
/* total fwlog info len */
#define FWLOG_PRSV_LEN 32
#define COUNTRY_CODE_LEN 2
#define EDR_MIN -32
#define EDR_MAX 20
#define EDR_MIN_LV9 13
#define BLE_MIN -29
#define BLE_MAX 20
#define EDR_MIN_R1 -64
#define EDR_MAX_R1 40
#define EDR_MIN_LV9_R1 26
#define BLE_MIN_R1 -58
#define BLE_MAX_R1 40
#define EDR_MIN_R2 -128
#define EDR_MAX_R2 80
#define EDR_MIN_LV9_R2 52
#define BLE_MIN_R2 -116
#define BLE_MAX_R2 80
#define ERR_PWR -9999
#define WAIT_POWERKEY_TIMEOUT 5000
#define SEPARATOR_LEN 2
#define STP_CRC_LEN 2
#define TEMP_LEN 260
#define SEARCH_LEN 32
#define TEXT_LEN 128
#define DUAL_BT_FLAG (0x1 << 5)
/* CMD&Event sent by driver */
#define READ_EFUSE_CMD_LEN 18
#define READ_EFUSE_EVT_HDR_LEN 9
#define READ_EFUSE_CMD_BLOCK_OFFSET 10
#define CHECK_LD_PATCH_CMD_LEN 9
#define CHECK_LD_PATCH_EVT_HDR_LEN 7
#define CHECK_LD_PATCH_EVT_RESULT_OFFSET 6 /* need confirm later */
#define HWERR_EVT_LEN 4
#define LD_PATCH_EVT_LEN 8
#define HCI_RESET_CMD_LEN 4
#define HCI_RESET_EVT_LEN 7
#define WMT_RESET_CMD_LEN 9
#define WMT_RESET_EVT_LEN 8
#define WMT_POWER_ON_CMD_LEN 10
#define WMT_POWER_ON_EVT_HDR_LEN 7
#define WMT_POWER_ON_EVT_RESULT_OFFSET 7
#define WMT_POWER_OFF_CMD_LEN 10
#define WMT_POWER_OFF_EVT_HDR_LEN 7
#define WMT_POWER_OFF_EVT_RESULT_OFFSET 7
#define PICUS_ENABLE_CMD_LEN 8
#define PICUS_ENABLE_EVT_HDR_LEN 9
#define PICUS_DISABLE_CMD_LEN 8
#define PICUS_DISABLE_EVT_HDR_LEN 9
#define RES_APCF_CMD_LEN 9
#define RES_APCF_EVT_LEN 5
#define READ_ADDRESS_CMD_LEN 4
#define READ_ADDRESS_EVT_HDR_LEN 7
#define WOBLE_ENABLE_DEFAULT_CMD_LEN 40
#define WOBLE_ENABLE_DEFAULT_EVT_LEN 5
#define WOBLE_DISABLE_DEFAULT_CMD_LEN 9
#define WOBLE_DISABLE_DEFAULT_EVT_LEN 5
#define RADIO_OFF_CMD_LEN 9
#define RADIO_OFF_EVT_LEN 5
#define RADIO_ON_CMD_LEN 9
#define RADIO_ON_EVT_LEN 5
#define APCF_FILTER_CMD_LEN 14
#define APCF_FILTER_EVT_HDR_LEN 8
#define APCF_CMD_LEN 43
#define APCF_EVT_HDR_LEN 7
#define APCF_DELETE_CMD_LEN 7
#define APCF_DELETE_EVT_HDR_LEN 8
#define APCF_RESUME_EVT_HDR_LEN 7
#define CHECK_WOBX_DEBUG_CMD_LEN 8
#define CHECK_WOBX_DEBUG_EVT_HDR_LEN 2
#define SET_STP_CMD_LEN 13
#define SET_STP_EVT_LEN 9
#define SET_STP1_CMD_LEN 16
#define SET_STP1_EVT_LEN 19
#define SET_SLEEP_CMD_LEN 11
#define SET_SLEEP_EVT_LEN 7
#define EVT_HDR_LEN 2
#define ASSERT_CMD_LEN 9
#define TXPOWER_CMD_LEN 16
#define TXPOWER_EVT_LEN 7
#define FW_COREDUMP_CMD_LEN 4
#define HCI_RESET_CMD_LEN 4
#define READ_ISO_PACKET_SIZE_CMD_HDR_LEN 4
#define AUDIO_SETTING_CMD_LEN 8
#define AUDIO_SETTING_EVT_LEN 7
#define READ_PINMUX_CMD_LEN 8
#define READ_PINMUX_EVT_CMP_LEN 6
#define READ_PINMUX_EVT_REAL_LEN 11
#define WRITE_PINMUX_CMD_LEN 12
#define WRITE_PINMUX_EVT_LEN 7
#define PINMUX_REG_NUM 2
#define WRITE_PINMUX_CMD_LEN_7902 7
#define WRITE_PINMUX_EVT_LEN_7902 7
#define PINMUX_REG_NUM_7902 4
#define FW_VERSION_BUF_SIZE 256
#define FW_VERSION_KEY_WORDS "t-neptune"
#if BUILD_QA_DBG
#define CFG_SHOW_FULL_MACADDR 1
#else
#define CFG_SHOW_FULL_MACADDR 0
#endif
#if CFG_SHOW_FULL_MACADDR
#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
#define MAC2STR(a) ((unsigned char *)a)[0], ((unsigned char *)a)[1], ((unsigned char *)a)[2],\
((unsigned char *)a)[3], ((unsigned char *)a)[4], ((unsigned char *)a)[5]
#else
#define MACSTR "%02X:%02X:**:**:**:%02X"
#define MAC2STR(a) ((unsigned char *)a)[0], ((unsigned char *)a)[1], ((unsigned char *)a)[5]
#endif
enum {
RES_1 = 0,
RES_DOT_5,
RES_DOT_25
};
enum {
CHECK_SINGLE_SKU_PWR_MODE = 0,
CHECK_SINGLE_SKU_EDR_MAX,
CHECK_SINGLE_SKU_BLE,
CHECK_SINGLE_SKU_BLE_2M,
CHECK_SINGLE_SKU_BLE_LR_S2,
CHECK_SINGLE_SKU_BLE_LR_S8,
CHECK_SINGLE_SKU_ALL
};
enum {
DISABLE_LV9 = 0,
ENABLE_LV9
};
enum {
DIFF_MODE_3DB = 0,
DIFF_MODE_0DB
};
struct btmtk_cif_state {
unsigned char ops_enter;
unsigned char ops_end;
unsigned char ops_error;
};
enum TX_TYPE {
BTMTK_TX_CMD_FROM_DRV = 0, /* send hci cmd and wmt cmd by driver */
BTMTK_TX_ACL_FROM_DRV, /* send acl pkt with load rompatch by driver */
BTMTK_TX_PKT_FROM_HOST, /* send pkt from host, include acl and hci */
};
enum bt_state {
FUNC_OFF = 0,
TURNING_ON = 1,
PRE_ON_AFTER_CAL = 2,
FUNC_ON = 3,
RESET_START = 4,
RESET_END = 5
};
struct bt_power_setting {
int8_t EDR_Max;
int8_t LV9;
int8_t DM;
int8_t IR;
int8_t BLE_1M;
int8_t BLE_2M;
int8_t BLE_LR_S2;
int8_t BLE_LR_S8;
char country_code[COUNTRY_CODE_LEN + 1];
};
enum {
BTMTK_DONGLE_STATE_UNKNOWN,
BTMTK_DONGLE_STATE_POWER_ON,
BTMTK_DONGLE_STATE_POWER_OFF,
BTMTK_DONGLE_STATE_ERROR,
};
enum {
HW_ERR_NONE = 0x00,
HW_ERR_CODE_CHIP_RESET = 0xF0,
HW_ERR_CODE_USB_DISC = 0xF1,
HW_ERR_CODE_CORE_DUMP = 0xF2,
HW_ERR_CODE_POWER_ON = 0xF3,
HW_ERR_CODE_POWER_OFF = 0xF4,
HW_ERR_CODE_SET_SLEEP_CMD = 0xF5,
HW_ERR_CODE_RESET_STACK_AFTER_WOBLE = 0xF6,
};
/* Please keep sync with btmtk_set_state function */
enum {
/* BTMTK_STATE_UNKNOWN = 0, */
BTMTK_STATE_INIT = 1,
BTMTK_STATE_DISCONNECT,
BTMTK_STATE_PROBE,
BTMTK_STATE_WORKING,
BTMTK_STATE_SUSPEND,
BTMTK_STATE_RESUME,
BTMTK_STATE_FW_DUMP,
BTMTK_STATE_STANDBY,
BTMTK_STATE_SUBSYS_RESET,
BTMTK_STATE_SEND_ASSERT,
BTMTK_STATE_MSG_NUM
};
/* Please keep sync with btmtk_fops_set_state function */
enum {
/* BTMTK_FOPS_STATE_UNKNOWN = 0, */
BTMTK_FOPS_STATE_INIT = 1,
BTMTK_FOPS_STATE_OPENING, /* during opening */
BTMTK_FOPS_STATE_OPENED, /* open in fops_open */
BTMTK_FOPS_STATE_CLOSING, /* during closing */
BTMTK_FOPS_STATE_CLOSED, /* closed */
BTMTK_FOPS_STATE_MSG_NUM
};
enum {
BTMTK_EVENT_COMPARE_STATE_UNKNOWN,
BTMTK_EVENT_COMPARE_STATE_NOTHING_NEED_COMPARE,
BTMTK_EVENT_COMPARE_STATE_NEED_COMPARE,
BTMTK_EVENT_COMPARE_STATE_COMPARE_SUCCESS,
};
enum {
HCI_SNOOP_TYPE_CMD_STACK = 0,
HCI_SNOOP_TYPE_CMD_HIF,
HCI_SNOOP_TYPE_EVT_STACK,
HCI_SNOOP_TYPE_EVT_HIF,
HCI_SNOOP_TYPE_ADV_EVT_STACK,
HCI_SNOOP_TYPE_ADV_EVT_HIF,
HCI_SNOOP_TYPE_NOCP_EVT_STACK,
HCI_SNOOP_TYPE_NOCP_EVT_HIF,
HCI_SNOOP_TYPE_TX_ACL_STACK,
HCI_SNOOP_TYPE_TX_ACL_HIF,
HCI_SNOOP_TYPE_RX_ACL_STACK,
HCI_SNOOP_TYPE_RX_ACL_HIF,
HCI_SNOOP_TYPE_TX_ISO_STACK,
HCI_SNOOP_TYPE_TX_ISO_HIF,
HCI_SNOOP_TYPE_RX_ISO_STACK,
HCI_SNOOP_TYPE_RX_ISO_HIF,
HCI_SNOOP_TYPE_MAX
};
enum {
DEBUG_SOP_SLEEP,
DEBUG_SOP_WAKEUP,
DEBUG_SOP_NO_RESPONSE,
DEBUG_SOP_NONE
};
struct dump_debug_cr {
u32 addr_w;
u32 value_w;
u32 addr_r;
};
struct h4_recv_pkt {
u8 type; /* Packet type */
u8 hlen; /* Header length */
u8 loff; /* Data length offset in header */
u8 lsize; /* Data length field size */
u16 maxlen; /* Max overall packet length */
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
};
#pragma pack(1)
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 u4SecType;
u32 u4DLModeCrcType;
u32 u4Crc;
u32 reserved[6];
} bin_info_spec;
};
};
#pragma pack()
#define H4_RECV_ACL \
.type = HCI_ACLDATA_PKT, \
.hlen = HCI_ACL_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE \
#define H4_RECV_SCO \
.type = HCI_SCODATA_PKT, \
.hlen = HCI_SCO_HDR_SIZE, \
.loff = 2, \
.lsize = 1, \
.maxlen = HCI_MAX_SCO_SIZE
#define H4_RECV_EVENT \
.type = HCI_EVENT_PKT, \
.hlen = HCI_EVENT_HDR_SIZE, \
.loff = 1, \
.lsize = 1, \
.maxlen = HCI_MAX_EVENT_SIZE
/* yumin todo */
// TODO: replace by kernel constant if kernel support new spec
#define HCI_ISODATA_PKT 0x05
#define HCI_ISO_HDR_SIZE 4
#define H4_RECV_ISO \
.type = HCI_ISODATA_PKT, \
.hlen = HCI_ISO_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE
struct btmtk_dev {
struct hci_dev *hdev;
unsigned long hdev_flags;
unsigned long flags;
void *intf_dev;
void *cif_dev;
struct work_struct work;
struct work_struct waker;
struct work_struct reset_waker;
struct timer_list chip_reset_timer;
int recv_evt_len;
int tx_in_flight;
spinlock_t txlock;
spinlock_t rxlock;
struct sk_buff *evt_skb;
struct sk_buff *sco_skb;
/* For ble iso packet size */
int iso_threshold;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* For tx queue */
unsigned long tx_state;
/* For rx queue */
struct workqueue_struct *workqueue;
struct sk_buff_head rx_q;
struct work_struct rx_work;
struct sk_buff *rx_skb;
wait_queue_head_t p_wait_event_q;
unsigned int subsys_reset;
unsigned int chip_reset;
unsigned char *rom_patch_bin_file_name;
unsigned int chip_id;
unsigned int flavor;
unsigned int dualBT;
unsigned int fw_version;
unsigned char dongle_index;
unsigned char power_state;
unsigned char fops_state;
unsigned char interface_state;
struct btmtk_cif_state *cif_state;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *setting_file;
unsigned char bdaddr[BD_ADDRESS_SIZE];
unsigned char *bt_cfg_file_name;
struct bt_cfg_struct bt_cfg;
/* single sku */
unsigned char *country_file_name;
int get_hci_reset;
/* debug sop */
struct debug_reg_struct debug_sop_reg_dump;
unsigned char debug_sop_file_name[MAX_BIN_FILE_NAME_LEN];
};
typedef int (*cif_bt_init_ptr)(void);
typedef void (*cif_bt_exit_ptr)(void);
typedef int (*cif_open_ptr)(struct hci_dev *hdev);
typedef int (*cif_close_ptr)(struct hci_dev *hdev);
typedef int (*cif_reg_read_ptr)(struct btmtk_dev *bdev, u32 reg, u32 *val);
typedef int (*cif_reg_write_ptr)(struct btmtk_dev *bdev, u32 reg, u32 val);
typedef int (*cif_send_cmd_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb,
int delay, int retry, int pkt_type);
typedef int (*cif_send_and_recv_ptr)(struct btmtk_dev *bdev,
struct sk_buff *skb,
const uint8_t *event, const int event_len,
int delay, int retry, int pkt_type);
typedef int (*cif_event_filter_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb);
typedef int (*cif_subsys_reset_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_whole_reset_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_chip_reset_notify_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_mutex_lock_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_mutex_unlock_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_flush_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_log_init_ptr)(void);
typedef void (*cif_log_register_cb_ptr)(void (*func)(void));
typedef ssize_t (*cif_log_read_to_user_ptr)(char __user *buf, size_t count);
typedef unsigned int (*cif_log_get_buf_size_ptr)(void);
typedef void (*cif_log_deinit_ptr)(void);
typedef void (*cif_open_done_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_dl_dma_ptr)(struct btmtk_dev *bdev, u8 *image,
u8 *fwbuf, int section_dl_size, int section_offset);
typedef void (*cif_dump_debug_sop_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_waker_notify_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_enter_standby_ptr)(void);
struct hif_hook_ptr {
cif_bt_init_ptr init;
cif_bt_exit_ptr exit;
cif_open_ptr open;
cif_close_ptr close;
cif_reg_read_ptr reg_read;
cif_reg_write_ptr reg_write;
cif_send_cmd_ptr send_cmd;
cif_send_and_recv_ptr send_and_recv;
cif_event_filter_ptr event_filter;
cif_subsys_reset_ptr subsys_reset;
cif_whole_reset_ptr whole_reset;
cif_chip_reset_notify_ptr chip_reset_notify;
cif_mutex_lock_ptr cif_mutex_lock;
cif_mutex_unlock_ptr cif_mutex_unlock;
cif_flush_ptr flush;
cif_log_init_ptr log_init;
cif_log_register_cb_ptr log_register_cb;
cif_log_read_to_user_ptr log_read_to_user;
cif_log_get_buf_size_ptr log_get_buf_size;
cif_log_deinit_ptr log_deinit;
cif_open_done_ptr open_done;
cif_dl_dma_ptr dl_dma;
cif_dump_debug_sop_ptr dump_debug_sop;
cif_waker_notify_ptr waker_notify;
cif_enter_standby_ptr enter_standby;
};
struct hci_snoop {
u8 buf[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_MAX_BUF_SIZE];
u8 len[HCI_SNOOP_ENTRY_NUM];
u16 actual_len[HCI_SNOOP_ENTRY_NUM];
char timestamp[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_TS_STR_LEN];
u8 index;
};
struct btmtk_main_info {
int chip_reset_flag;
atomic_t subsys_reset;
atomic_t chip_reset;
atomic_t subsys_reset_count;
atomic_t whole_reset_count;
atomic_t subsys_reset_conti_count;
u8 reset_stack_flag;
struct wakeup_source *fwdump_ws;
struct wakeup_source *woble_ws;
struct wakeup_source *eint_ws;
#if WAKEUP_BT_IRQ
struct wakeup_source *irq_ws;
#endif
struct hif_hook_ptr hif_hook;
struct bt_power_setting PWS;
/* save Hci Snoop for debug*/
struct hci_snoop snoop[HCI_SNOOP_TYPE_MAX];
u8 wmt_over_hci_header[WMT_OVER_HCI_HEADER_SIZE];
u8 read_iso_packet_size_cmd[READ_ISO_PACKET_CMD_SIZE];
#if CFG_SUPPORT_BMR_RX_CLK
u64 bmr_sysclk;
int bmr_irq;
int bmr_irq_cnt;
u32 bmr_irq_flag;
#endif
/* record firmware version */
struct proc_dir_entry *proc_dir;
char fw_version_str[FW_VERSION_BUF_SIZE];
atomic_t fwlog_ref_cnt;
};
static inline int is_mt6639(u32 chip_id)
{
#ifdef SUPPORT_MT6639
chip_id &= 0xFFFF;
if (chip_id == 0x6639)
return 1;
#endif
return 0;
}
static inline int is_mt7902(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7902)
return 1;
return 0;
}
static inline int is_mt7922(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7922)
return 1;
return 0;
}
static inline int is_mt7961(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7961)
return 1;
return 0;
}
static inline int is_mt66xx(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x6631 || chip_id == 0x6635)
return 1;
return 0;
}
/* Get BT whole packet length except hci type */
static inline unsigned int get_pkt_len(unsigned char type, unsigned char *buf)
{
unsigned int len = 0;
switch (type) {
/* Please reference hci header format
* AA = len
* xx = buf[0]
* cmd : 01 xx yy AA + payload
* acl : 02 xx yy AA AA + payload
* sco : 03 xx yy AA + payload
* evt : 04 xx AA + payload
* ISO : 05 xx yy AA AA + payload
*/
case HCI_COMMAND_PKT:
len = buf[2] + 3;
break;
case HCI_ACLDATA_PKT:
len = buf[2] + ((buf[3] << 8) & 0xff00) + 4;
break;
case HCI_SCODATA_PKT:
len = buf[2] + 3;
break;
case HCI_EVENT_PKT:
len = buf[1] + 2;
break;
case HCI_ISO_PKT:
len = buf[2] + (((buf[3] & 0x3F) << 8) & 0xff00) + HCI_ISO_PKT_HEADER_SIZE;
break;
default:
len = 0;
}
return len;
}
unsigned char btmtk_get_chip_state(struct btmtk_dev *bdev);
void btmtk_set_chip_state(struct btmtk_dev *bdev, unsigned char new_state);
int btmtk_allocate_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
void btmtk_free_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
int btmtk_register_hci_device(struct btmtk_dev *bdev);
int btmtk_deregister_hci_device(struct btmtk_dev *bdev);
int btmtk_recv(struct hci_dev *hdev, const u8 *data, size_t count);
int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_recv_acl(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_recv_iso(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_send_init_cmds(struct btmtk_dev *hdev);
int btmtk_send_deinit_cmds(struct btmtk_dev *hdev);
int btmtk_load_rom_patch(struct btmtk_dev *bdev);
struct btmtk_dev *btmtk_get_dev(void);
int btmtk_cap_init(struct btmtk_dev *bdev);
struct btmtk_main_info *btmtk_get_main_info(void);
int btmtk_get_interface_num(void);
int btmtk_reset_power_on(struct btmtk_dev *bdev);
void btmtk_send_hw_err_to_host(struct btmtk_dev *bdev);
void btmtk_free_setting_file(struct btmtk_dev *bdev);
unsigned char btmtk_fops_get_state(struct btmtk_dev *bdev);
void btmtk_hci_snoop_save(unsigned int type, u8 *buf, u32 len);
void btmtk_hci_snoop_print(const u8 *buf, u32 len);
void btmtk_hci_snoop_print_to_log(void);
void *btmtk_kallsyms_lookup_name(const char *name);
void btmtk_get_UTC_time_str(char *ts_str);
void btmtk_reg_hif_hook(struct hif_hook_ptr *hook);
int btmtk_main_cif_initialize(struct btmtk_dev *bdev, int hci_bus);
void btmtk_main_cif_uninitialize(struct btmtk_dev *bdev, int hci_bus);
int btmtk_main_cif_disconnect_notify(struct btmtk_dev *bdev, int hci_bus);
int btmtk_load_code_from_bin(u8 **image, char *bin_name,
struct device *dev, u32 *code_len, u8 retry);
int btmtk_main_send_cmd(struct btmtk_dev *bdev, const uint8_t *cmd,
const int cmd_len, const uint8_t *event, const int event_len, int delay,
int retry, int pkt_type);
int btmtk_load_code_from_setting_files(char *setting_file_name,
struct device *dev, u32 *code_len, struct btmtk_dev *bdev);
int btmtk_load_fw_cfg_setting(char *block_name, struct fw_cfg_struct *save_content,
int counter, u8 *searchcontent, enum fw_cfg_index_len index_length);
int btmtk_send_assert_cmd(struct btmtk_dev *bdev);
void btmtk_free_fw_cfg_struct(struct fw_cfg_struct *fw_cfg, int count);
struct btmtk_dev **btmtk_get_pp_bdev(void);
void btmtk_load_debug_sop_register(char *debug_sop_name, struct device *dev, struct btmtk_dev *bdev);
void btmtk_clean_debug_reg_file(struct btmtk_dev *bdev);
int32_t btmtk_set_sleep(struct hci_dev *hdev, u_int8_t need_wait);
int32_t bgfsys_bt_patch_dl(void);
int btmtk_efuse_read(struct btmtk_dev *bdev, u16 addr, u8 *value);
void btmtk_set_country_code_from_wifi(char *code);
#endif /* __BTMTK_MAIN_H__ */

View file

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 MediaTek Inc.
*/
#ifndef __BTMTK_WOBLE_H__
#define __BTMTK_WOBLE_H__
#include "btmtk_define.h"
#include "btmtk_main.h"
/* Define for WoBLE */
#define WOBLE_SETTING_COUNT 10
#define WOBLE_EVENT_INTERVAL_TIMO 500
#define WOBLE_COMP_EVENT_TIMO 5000
/* WOBX attribute type */
#define WOBX_TRIGGER_INFO_ADDR_TYPE 1
#define WOBX_TRIGGER_INFO_ADV_DATA_TYPE 2
#define WOBX_TRIGGER_INFO_TRACE_LOG_TYPE 3
#define WOBX_TRIGGER_INFO_SCAN_LOG_TYPE 4
#define WOBX_TRIGGER_INFO_TRIGGER_CNT_TYPE 5
struct btmtk_woble {
unsigned char *woble_setting_file_name;
unsigned int woble_setting_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
struct fw_cfg_struct woble_setting_radio_off_status_event;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct fw_cfg_struct woble_setting_radio_on;
struct fw_cfg_struct woble_setting_radio_on_status_event;
struct fw_cfg_struct woble_setting_radio_on_comp_event;
/* set apcf after resume(radio on) */
struct fw_cfg_struct woble_setting_apcf_resume[WOBLE_SETTING_COUNT];
/* Foe Woble eint */
unsigned int wobt_irq;
int wobt_irqlevel;
atomic_t irq_enable_count;
struct input_dev *WoBLEInputDev;
void *bdev;
};
int btmtk_woble_suspend(struct btmtk_woble *bt_woble);
int btmtk_woble_resume(struct btmtk_woble *bt_woble);
int btmtk_woble_initialize(struct btmtk_dev *bdev, struct btmtk_woble *bt_woble);
void btmtk_woble_uninitialize(struct btmtk_woble *bt_woble);
void btmtk_woble_wake_unlock(struct btmtk_dev *bdev);
#if WAKEUP_BT_IRQ
void btmtk_sdio_irq_wake_lock_timeout(struct btmtk_dev *bdev);
#endif
int btmtk_send_apcf_reserved(struct btmtk_dev *bdev);
#endif /* __BTMTK_WOBLE_H__ */

View file

@ -0,0 +1,184 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef _BTMTK_SDIO_H_
#define _BTMTK_SDIO_H_
/* It's for reset procedure */
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_woble.h"
#include "btmtk_buffer_mode.h"
#include "btmtk_chip_reset.h"
#ifndef BTMTK_SDIO_DEBUG
#define BTMTK_SDIO_DEBUG 0
#endif
/**
* Card-relate definition.
*/
#ifndef SDIO_VENDOR_ID_MEDIATEK
#define SDIO_VENDOR_ID_MEDIATEK 0x037A
#endif
#define HCI_HEADER_LEN 4
#define MTK_STP_TLR_SIZE 2
#define STP_HEADER_LEN 4
#define STP_HEADER_CRC_LEN 2
#define HCI_MAX_COMMAND_SIZE 255
#define URB_MAX_BUFFER_SIZE (4*1024)
#define BTMTK_SDIO_FUNC 2
/* common register address */
#define CCIR 0x0000
#define CHLPCR 0x0004
#define CSDIOCSR 0x0008
#define CHCR 0x000C
#define CHISR 0x0010
#define CHIER 0x0014
#define CTDR 0x0018
#define CRDR 0x001C
#define CTFSR 0x0020
#define CRPLR 0x0024
#define CSICR 0x00C0
#define PD2HRM0R 0x00DC
#define SWPCDBGR 0x0154
#define PH2DSM0R 0x00C4
/* PH2DSM0R*/
#define PH2DSM0R_DRIVER_OWN 0x00000001
/* CHLPCR */
#define C_FW_INT_EN_SET 0x00000001
#define C_FW_INT_EN_CLEAR 0x00000002
/* CHISR */
#define RX_PKT_LEN 0xFFFF0000
#define FIRMWARE_INT 0x0000FE00
/* PD2HRM0R */
#define PD2HRM0R_DRIVER_OWN 0x00000001
#define PD2HRM0R_FW_OWN 0x00000000
/* MCU notify host dirver for L0.5 reset */
#define FIRMWARE_INT_BIT31 0x80000000
/* MCU notify host driver for coredump */
#define FIRMWARE_INT_BIT15 0x00008000
#define TX_FIFO_OVERFLOW 0x00000100
#define FW_INT_IND_INDICATOR 0x00000080
#define TX_COMPLETE_COUNT 0x00000070
#define TX_UNDER_THOLD 0x00000008
#define TX_EMPTY 0x00000004
#define RX_DONE 0x00000002
#define FW_OWN_BACK_INT 0x00000001
/* MCU address offset */
#define MCU_ADDRESS_OFFSET_CMD 12
#define MCU_ADDRESS_OFFSET_EVT 16
/* wifi CR */
#define CONDBGCR 0x0034
#define CONDBGCR_SEL 0x0040
#define SDIO_CTRL_EN (1 << 31)
#define WM_MONITER_SEL (~(0x40000000))
#define PC_MONITER_SEL (~(0x20000000))
#define PC_IDX_SWH(val, idx) ((val & (~(0x3F << 16))) | ((0x3F & idx) << 16))
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define SDIO_BLOCK_SIZE 512
#define SDIO_RW_RETRY_COUNT 500
#define MTK_SDIO_PACKET_HEADER_SIZE 4
/* Driver & FW own related */
#define DRIVER_OWN 0
#define FW_OWN 1
#define SET_OWN_LOOP_COUNT 10
/* CMD&Event sent by driver */
#define READ_REGISTER_CMD_LEN 16
#define READ_REGISTER_EVT_HDR_LEN 11
#define FW_ASSERT_CMD_LEN 4
#define FW_ASSERT_CMD1_LEN 9
#define NOTIFY_ALT_EVT_LEN 7
#define READ_ADDRESS_EVT_HDR_LEN 7
#define READ_ADDRESS_EVT_PAYLOAD_OFFSET 7
#define WOBLE_DEBUG_EVT_TYPE 0xE8
#define BLE_EVT_TYPE 0x3E
#define LD_PATCH_CMD_LEN 10
#define LD_PATCH_EVT_LEN 8
#define BTMTK_SDIO_THREAD_STOP (1 << 0)
#define BTMTK_SDIO_THREAD_TX (1 << 1)
#define BTMTK_SDIO_THREAD_RX (1 << 2)
#define BTMTK_SDIO_THREAD_FW_OWN (1 << 3)
#define FW_OWN_TIMEOUT 30
#define FW_OWN_TIMER_INIT 0
#define FW_OWN_TIMER_RUNNING 1
#define CHECK_THREAD_RETRY_TIMES 50
struct btmtk_sdio_hdr {
/* For SDIO Header */
__le16 len;
__le16 reserved;
/* For hci type */
u8 bt_type;
} __packed;
struct btmtk_sdio_thread {
struct task_struct *task;
wait_queue_head_t wait_q;
void *priv;
atomic_t thread_status;
};
struct btmtk_sdio_dev {
struct sdio_func *func;
struct btmtk_dev *bdev;
bool patched;
bool no_fw_own;
atomic_t int_count;
atomic_t tx_rdy;
/* TODO, need to confirm the max size of urb data, also need to confirm
* whether intr_complete and bulk_complete and soc_complete can all share
* this urb_transfer_buf
*/
unsigned char *transfer_buf;
unsigned char *sdio_packet;
struct sk_buff_head tx_queue;
struct btmtk_sdio_thread sdio_thread;
struct btmtk_woble bt_woble;
struct btmtk_buffer_mode_struct *buffer_mode;
struct timer_list fw_own_timer;
atomic_t fw_own_timer_flag;
};
int btmtk_sdio_read_bt_mcu_pc(u32 *val);
int btmtk_sdio_read_conn_infra_pc(u32 *val);
int btmtk_sdio_set_driver_own_for_subsys_reset(int enable);
int btmtk_sdio_whole_reset(struct btmtk_dev *bdev);
int btmtk_sdio_read_wifi_mcu_pc(u8 PcLogSel, u32 *val);
#endif

View file

@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef _BTMTK_UART_H_
#define _BTMTK_UART_H_
#include <linux/serdev.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_buffer_mode.h"
#ifndef UART_DEBUG
#define UART_DEBUG 0
#endif
/**
* Card-relate definition.
*/
#define HCI_HEADER_LEN 4
#define MTK_STP_TLR_SIZE 2
#define STP_HEADER_LEN 4
#define STP_HEADER_CRC_LEN 2
#define HCI_MAX_COMMAND_SIZE 255
#define MAX_BUFFER_SIZE (4*1024)
/* CMD&Event sent by driver */
#define READ_REGISTER_CMD_LEN 16
#define READ_REGISTER_EVT_HDR_LEN 11
/* MCU address offset */
#define MCU_ADDRESS_OFFSET_CMD 12
#define MCU_ADDRESS_OFFSET_EVT 16
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define READ_ADDRESS_EVT_HDR_LEN 7
#define READ_ADDRESS_EVT_PAYLOAD_OFFSET 7
#define WOBLE_DEBUG_EVT_TYPE 0xE8
#define LD_PATCH_CMD_LEN 10
#define LD_PATCH_EVT_LEN 8
struct btmtk_uart_dev {
struct serdev_device *serdev;
struct clk *clk;
struct clk *osc;
unsigned char *transfer_buf;
};
#endif

View file

@ -0,0 +1,183 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef _BTMTK_UART_H_
#define _BTMTK_UART_H_
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_buffer_mode.h"
#include "btmtk_woble.h"
#include "btmtk_chip_reset.h"
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/serial.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/clk.h>
#include <linux/suspend.h>
#define HCI_HEADER_LEN 4
struct mtk_stp_hdr {
u8 prefix;
__be16 dlen;
u8 cs;
} __packed;
#define MTK_STP_TLR_SIZE 2
#define STP_HEADER_LEN 4
#define STP_HEADER_CRC_LEN 2
#define BTMTKUART_FLAG_STANDALONE_HW BIT(0)
/* CMD&Event sent by driver */
#define READ_REGISTER_CMD_LEN 16
#define READ_REGISTER_EVT_HDR_LEN 11
#define WRITE_REGISTER_CMD_LEN 24
#define WRITE_REGISTER_EVT_HDR_LEN 11
/* MCU address offset */
#define MCU_ADDRESS_OFFSET_CMD 12
#define MCU_ADDRESS_OFFSET_EVT 16
/* MCU value offset */
#define MCU_VALUE_OFFSET_CMD 16
/* Pimux Address and Value */
#define BT_PINMUX_CTRL_REG 0x70005054
#define BT_SUBSYS_RST_PINMUX 0x00000020
#define BT_CTSRTS_PINMUX 0x00044000
#define BT_PINMUX_CTRL_ENABLE (BT_SUBSYS_RST_PINMUX | BT_CTSRTS_PINMUX)
#define BT_SUBSYS_RST_REG 0x70002610
#define BT_SUBSYS_RST_ENABLE 0x00000080
#define BT_REG_LEN 4
#define BT_REG_VALUE_LEN 4
/* MCU baud define */
#define BT_FLOWCTRL_OFFSET 12
#define BT_NONE_FC 0x00
#define BT_HW_FC 0x40
#define BT_SW_FC 0x80
#define BT_MTK_SW_FC 0xC0
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define READ_ADDRESS_EVT_HDR_LEN 7
#define READ_ADDRESS_EVT_PAYLOAD_OFFSET 7
#define WOBLE_DEBUG_EVT_TYPE 0xE8
#define LD_PATCH_CMD_LEN 10
#define LD_PATCH_EVT_LEN 8
#define SETBAUD_CMD_LEN 13
#define SETBAUD_EVT_LEN 9
#define GETBAUD_CMD_LEN 9
#define GETBAUD_EVT_LEN 9
#define BAUD_SIZE 4
#define WAKEUP_CMD_LEN 5
#define WAKEUP_EVT_LEN 9
#define FWOWN_CMD_LEN 9
#define DRVOWN_CMD_LEN 9
#define OWNTYPE_EVT_LEN 9
#define BT_UART_DEFAULT_BAUD 115200
/* Delay time between subsys reset GPIO pull low/high */
#define SUBSYS_RESET_GPIO_DELAY_TIME 50
/* Delay time after write data to io_buf */
#define IO_BUF_DELAY_TIME 50
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
enum UART_FC {
UART_DISABLE_FC = 0, /*NO flow control*/
/*MTK SW Flow Control, differs from Linux Flow Control*/
UART_MTK_SW_FC = 1,
UART_LINUX_FC = 2, /*Linux SW Flow Control*/
UART_HW_FC = 3, /*HW Flow Control*/
};
struct UART_CONFIG {
enum UART_FC fc;
int parity;
int stop_bit;
int iBaudrate;
};
struct btmtk_uart_data {
unsigned int flags;
const char *fwname;
};
struct btmtk_uart_dev {
struct hci_dev *hdev;
struct tty_struct *tty;
unsigned long hdev_flags;
/* For tx queue */
struct sk_buff_head tx_queue;
spinlock_t tx_lock;
struct task_struct *tx_task;
unsigned long tx_state;
/* For rx queue */
struct sk_buff *rx_skb;
unsigned long rx_state;
struct sk_buff *evt_skb;
wait_queue_head_t p_wait_event_q;
unsigned int subsys_reset;
unsigned int dongle_state;
unsigned int uart_baudrate_set;
u8 stp_pad[6];
u8 stp_cursor;
u16 stp_dlen;
struct UART_CONFIG uart_cfg;
struct btmtk_woble bt_woble;
};
#define btmtk_uart_is_standalone(bdev) \
((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
#define btmtk_uart_is_builtin_soc(bdev) \
!((bdev)->data->flags & BTMTKUART_FLAG_STANDALONE_HW)
/**
* Maximum rom patch file name length
*/
#define N_MTK (15+1)
/**
* Upper layeard IOCTL
*/
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTSETBAUD _IOW('U', 201, int)
#define HCIUARTGETBAUD _IOW('U', 202, int)
#define HCIUARTSETSTP _IOW('U', 203, int)
#define HCIUARTLOADPATCH _IOW('U', 204, int)
#define HCIUARTSETWAKEUP _IOW('U', 205, int)
#define HCIUARTINIT _IOW('U', 206, int)
//int btmtk_cif_send_calibration(struct hci_dev *hdev);
#endif

View file

@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef _BTMTK_USB_H_
#define _BTMTK_USB_H_
#include <linux/usb.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_woble.h"
#include "btmtk_chip_reset.h"
#define HCI_MAX_COMMAND_SIZE 255
#define URB_MAX_BUFFER_SIZE (4*1024)
#define BT0_MCU_INTERFACE_NUM 0
#define BT1_MCU_INTERFACE_NUM 3
#define BT_MCU_INTERFACE_NUM_MAX 4
#define BT_MCU_NUM_MAX 2
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define HCI_USB_IO_BUF_SIZE 256
/* UHW CR mapping */
#define BT_MISC 0x70002510
#define MCU_BT0_INIT_DONE (0x1 << 8)
#define MCU_BT1_INIT_DONE (0x1 << 9)
#define BT_SUBSYS_RST 0x70002610
#define BT_SUBSYS_RST_6639 0x70028610
#define UDMA_INT_STA_BT 0x74000024
#define UDMA_INT_STA_BT1 0x74000308
#define BT_WDT_STATUS 0x740003A0
#define EP_RST_OPT 0x74011890
#define EP_RST_IN_OUT_OPT 0x00010001
#define BT_GDMA_DONE_ADDR_W 0x74000A0C
#define BT_GDMA_DONE_7921_VALUE_W 0x00403FA9
#define BT_GDMA_DONE_7922_VALUE_W 0x00403EA9
#define BT_GDMA_DONE_7902_VALUE_W 0x00403EA9
#define BT_GDMA_DONE_ADDR_R 0x74000A08
#define BT_GDMA_DONE_VALUE_R 0xFFFFFFFB /* bit2: 0 - dma done, 1 - dma doing */
/* CMD&Event sent by driver */
#define NOTIFY_ALT_EVT_LEN 7
#define LD_PATCH_CMD_LEN 9
#define LD_PATCH_EVT_LEN 8
#define READ_ADDRESS_EVT_HDR_LEN 7
#define READ_ADDRESS_EVT_PAYLOAD_OFFSET 7
#define WOBLE_DEBUG_EVT_TYPE 0xE8
#define BLE_EVT_TYPE 0x3E
#define WMT_TRIGGER_ASSERT_LEN 9
struct btmtk_cif_chip_reset {
/* For Whole chip reset */
pdwnc_func pf_pdwndFunc;
reset_func_ptr2 pf_resetFunc2;
set_gpio_low pf_lowFunc;
set_gpio_high pf_highFunc;
};
struct btmtk_usb_dev {
struct usb_endpoint_descriptor *intr_ep;
/* EP10 OUT */
struct usb_endpoint_descriptor *intr_iso_tx_ep;
/* EP10 IN */
struct usb_endpoint_descriptor *intr_iso_rx_ep;
/* BULK CMD EP1 OUT or EP 11 OUT */
struct usb_endpoint_descriptor *bulk_cmd_tx_ep;
/* EP15 in for reset */
struct usb_endpoint_descriptor *reset_intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
struct usb_device *udev;
struct usb_interface *intf;
struct usb_interface *isoc;
struct usb_interface *iso_channel;
struct usb_anchor tx_anchor;
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
struct usb_anchor ctrl_anchor;
struct usb_anchor ble_isoc_anchor;
__u8 cmdreq_type;
__u8 cmdreq;
int new_isoc_altsetting;
int new_isoc_altsetting_interface;
unsigned char *o_usb_buf;
unsigned char *urb_intr_buf;
unsigned char *urb_bulk_buf;
unsigned char *urb_ble_isoc_buf;
struct btmtk_woble bt_woble;
};
#endif

View file

@ -0,0 +1,3 @@
# load btmtksdio
on boot
exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -d /vendor/lib/modules/ btmtk_sdio_unify.ko

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
THIS_COMPONENT = usb3
ifdef LINUX_DRV_ROOT
export DRV_ROOT = $(LINUX_DRV_ROOT)
else
export DRV_ROOT = $(TARGET_OPEN_ROOT)
endif
SRC =
OBJ =
SUB_COMPONENTS = mt7668
OPTIONAL_SUB_COMPONENTS =
DEFINES +=
CC_INC +=
#############################################################################
#
# Include the makefile common to all components
#
#############################################################################
include $(DRV_ROOT)/driver.mak

View file

@ -0,0 +1,265 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016,2017 MediaTek Inc.
*/
#ifndef __LD_BTMTK_USB_H__
#define __LD_BTMTK_USB_H__
#include "LD_usbbt.h"
/* Memory map for MTK BT */
//#if 0
/* SYS Control */
#define SYSCTL 0x400000
/* WLAN */
#define WLAN 0x410000
/* MCUCTL */
#define CLOCK_CTL 0x0708
#define INT_LEVEL 0x0718
#define COM_REG0 0x0730
#define SEMAPHORE_00 0x07B0
#define SEMAPHORE_01 0x07B4
#define SEMAPHORE_02 0x07B8
#define SEMAPHORE_03 0x07BC
/* Chip definition */
#define CONTROL_TIMEOUT_JIFFIES (300)
#define DEVICE_VENDOR_REQUEST_OUT 0x40
#define DEVICE_VENDOR_REQUEST_IN 0xc0
#define DEVICE_CLASS_REQUEST_OUT 0x20
#define DEVICE_CLASS_REQUEST_IN 0xa0
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
/* ROM Patch */
#define PATCH_HCI_HEADER_SIZE 4
#define PATCH_WMT_HEADER_SIZE 5
#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE)
#define UPLOAD_PATCH_UNIT 2048
#define PATCH_INFO_SIZE 30
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
#define PATCH_LEN_ILM (192 * 1024)
#define BUZZARD_CHIP_ID 0x70010200
#define BUZZARD_FLAVOR 0x70010020
#define BUZZARD_FW_VERSION 0x80021004
/**
* 0: patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1: patch download is complete
* 2: patch download is not complete/BT get patch semaphore success
*/
#define PATCH_ERR -1
#define PATCH_IS_DOWNLOAD_BY_OTHER 0
#define PATCH_READY 1
#define PATCH_NEED_DOWNLOAD 2
#define MAX_BIN_FILE_NAME_LEN 64
#define LD_BT_MAX_EVENT_SIZE 260
#define BD_ADDR_LEN 6
#define WOBLE_SETTING_FILE_NAME_7961 "woble_setting_7961.bin"
#define WOBLE_SETTING_FILE_NAME_7668 "woble_setting_7668.bin"
#define WOBLE_SETTING_FILE_NAME_7663 "woble_setting_7663.bin"
#define WOBLE_SETTING_FILE_NAME "woble_setting.bin"
#define WOBLE_CFG_NAME_PREFIX "woble_setting"
#define WOBLE_CFG_NAME_SUFFIX "bin"
#define BT_CFG_NAME "bt.cfg"
#define BT_CFG_NAME_PREFIX "bt_mt"
#define BT_CFG_NAME_PREFIX_76XX "bt_"
#define BT_CFG_NAME_SUFFIX "cfg"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WMT_CMD "WMT_CMD"
#define WMT_CMD_COUNT 255
#define WAKE_DEV_RECORD "wake_on_ble.conf"
#define WAKE_DEV_RECORD_PATH "misc/bluedroid"
#define APCF_SETTING_COUNT 10
#define WOBLE_SETTING_COUNT 10
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 6
#define SECTION_SPEC_NUM 13
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define BUZZARD_PATCH_ERR -1
#define BUZZARD_PATCH_NEED_DOWNLOAD 0
#define BUZZARD_PATCH_IS_DOWNLOAD_BY_OTHER 1
#define BUZZARD_PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
enum {
BTMTK_EP_TYPE_OUT_CMD = 0, /*EP type out for hci cmd and wmt cmd */
BTMTK_EP_TPYE_OUT_ACL, /* EP type out for acl pkt with load rompatch */
};
typedef enum {
TYPE_APCF_CMD,
} woble_setting_type;
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
u8 *content; /* APCF content or radio off content */
int length; /* APCF content or radio off content of length */
};
struct bt_cfg_struct {
u8 support_unify_woble; /* support unify woble or not */
u8 unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct wmt_cmd[WMT_CMD_COUNT];
};
struct LD_btmtk_usb_data {
mtkbt_dev_t *udev; /* store the usb device informaiton */
unsigned long flags;
int meta_tx;
HC_IF *hcif;
u8 cmdreq_type;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* request for different io operation */
u8 w_request;
u8 r_request;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *fw_image;
unsigned char *fw_header_image;
unsigned char *rom_patch;
unsigned char *rom_patch_header_image;
unsigned char *rom_patch_bin_file_name;
u32 chip_id;
unsigned int flavor;
unsigned int fw_version;
u8 need_load_fw;
u8 need_load_rom_patch;
u32 rom_patch_offset;
u32 rom_patch_len;
u32 fw_len;
int recv_evt_len;
u8 local_addr[BD_ADDR_LEN];
char *woble_setting_file_name;
u8 *setting_file;
u32 setting_file_len;
u8 *wake_dev; /* ADDR:NAP-UAP-LAP, VID/PID:Both Little endian */
u32 wake_dev_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct bt_cfg_struct bt_cfg;
};
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 reserved[9];
}bin_info_spec;
};
};
u8 LD_btmtk_usb_getWoBTW(void);
int LD_btmtk_usb_probe(mtkbt_dev_t *dev,int flag);
void LD_btmtk_usb_disconnect(mtkbt_dev_t *dev);
void LD_btmtk_usb_SetWoble(mtkbt_dev_t *dev);
int Ldbtusb_getBtWakeT(struct LD_btmtk_usb_data *data);
#define REV_MT76x2E3 0x0022
#define MT_REV_LT(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) < (_rev))
#define MT_REV_GTE(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) >= (_rev))
/*
* Load code method
*/
enum LOAD_CODE_METHOD {
BIN_FILE_METHOD,
HEADER_METHOD,
};
#endif

View file

@ -0,0 +1,135 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2005-2007 MediaTek Inc.
*/
#ifndef _GENERIC_ERRNO_H
#define _GENERIC_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#endif

View file

@ -0,0 +1,473 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek Inc.
*/
//#include <command.h>
//#include <common.h>
//#include <ShareType.h>
//#include <CusConfig.h>
//#include <MsVfs.h>
//#include <MsDebug.h>
//#include "usb_def.h"
//#include <MsSystem.h>
#include <stdio.h>
#include "LD_usbbt.h"
#include "LD_btmtk_usb.h"
//#include "hal_usb.h"
usb_vid_pid array_mtk_vid_pid[] = {
{0x0E8D, 0x7668, "MTK7668"}, // 7668
{0x0E8D, 0x76A0, "MTK7662T"}, // 7662T
{0x0E8D, 0x76A1, "MTK7632T"}, // 7632T
{0x0E8D, 0x7663, "MTK7663"}, //7663
{0x0E8D, 0x7961, "MTK7961"}, //7961
{0x0E8D, 0x7902, "MTK7902"}, //7902
};
int max_mtk_wifi_id = (sizeof(array_mtk_vid_pid) / sizeof(array_mtk_vid_pid[0]));
usb_vid_pid *pmtk_wifi = &array_mtk_vid_pid[0];
static mtkbt_dev_t *g_DrvData = NULL;
extern void LDR_Mount(void);
extern UINT32 FAT_getsize(const char* filename);
extern UINT8 FAT_Read(const char* filename, char *buffer,UINT32 filesize);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len)
{
return x_memcpy(dst, src, len);
}
VOID *os_memmove(VOID *dest, const void *src,UINT32 len)
{
return x_memcpy(dest, src, len);
}
VOID *os_memset(VOID *s, int c, size_t n)
{
return x_memset(s,c,n);
}
VOID *os_kzalloc(size_t size, unsigned int flags)
{
VOID *ptr = x_mem_alloc(size);
os_memset(ptr, 0, size);
return ptr;
}
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev, u32 *code_len)
{
int size;
size = FAT_getsize(bin_name);
if (size == -1){
usb_debug("Get file size fail\n");
return;
}
*code_len = size;
*image = x_mem_alloc(size);
FAT_Read(bin_name, (char *)(*image),size);
return;
}
static int usb_bt_bulk_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* not used */
)
{
int ret =0 ;
if(dev == NULL || dev->idev == NULL || dev->bulk_tx_ep == NULL)
{
usb_debug("bulk out error 00\n");
return -1;
}
//usb_debug("[usb_bt_bulk_msg]ep_addr:%x\n", dev->bulk_tx_ep->bEndpointAddress);
//usb_debug("[usb_bt_bulk_msg]ep_maxpkt:%x\n", dev->bulk_tx_ep->wMaxPacketSize);
if(epType == MTKBT_BULK_TX_EP)
{
ret = dev->idev->controller->bulk(dev->bulk_tx_ep, size, data,0);
*realsize = ret;
if(ret<0)
{
usb_debug("bulk out error 01\n");
return -1;
}
if(*realsize == size)
{
//usb_debug("bulk out success 01,size =0x%x\n",size);
return 0;
}
else
{
usb_debug("bulk out fail 02,size =0x%x,realsize =0x%x\n",size,*realsize);
}
}
return -1;
}
static int usb_bt_control_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 request,
u8 requesttype,
u16 value,
u16 index,
u8 *data,
int data_length,
int timeout /* not used */
)
{
int ret = -1;
dev_req_t dr;
dr.bmRequestType = requesttype;
dr.bRequest = request;
dr.wValue = value;
dr.wIndex = index;
dr.wLength = data_length;
if(epType == MTKBT_CTRL_TX_EP)
{
ret = dev->idev->controller->control(dev->idev, OUT, sizeof (dr), &dr, data_length, data);
}
else if (epType == MTKBT_CTRL_RX_EP)
{
ret = dev->idev->controller->control(dev->idev, IN, sizeof (dr), &dr, data_length, data);
}
else
{
usb_debug("control message wrong Type =0x%x\n",epType);
}
if (ret < 0)
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
return ret;
}
static int usb_bt_interrupt_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* unit of 1ms */
)
{
int ret = -1;
usb_debug("epType = 0x%x\n",epType);
if(epType == MTKBT_INTR_EP)
{
ret = dev->idev->controller->intr(dev->intr_ep, size, realsize,data, 2000);
}
usb_debug("realsize=%d reqdata 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",*realsize,data[0],data[1],data[2],data[3],data[4],data[5]);
if(ret < 0 )
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
//usb_debug("ret = 0x%x\n",ret);
return ret;
}
static HC_IF usbbt_host_interface =
{
usb_bt_bulk_msg,
usb_bt_control_msg,
usb_bt_interrupt_msg,
};
static void Ldbtusb_diconnect (btusbdev_t *dev)
{
LD_btmtk_usb_disconnect(g_DrvData);
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
}
static int Ldbtusb_SetWoble(btusbdev_t *dev)
{
if(!g_DrvData)
{
usb_debug("usb set woble fail ,because no drv data\n");
return -1;
}
else
{
LD_btmtk_usb_SetWoble(g_DrvData);
usb_debug("usb set woble end\n");
}
return 0;
}
int Ldbtusb_connect (btusbdev_t *dev, int flag)
{
int ret = 0;
// For Mstar
//struct usb_endpoint_descriptor *ep_desc;
//struct usb_interface *iface;
int i;
//iface = &dev->config.if_desc[0];
if(g_DrvData == NULL)
{
g_DrvData = os_kmalloc(sizeof(mtkbt_dev_t),MTK_GFP_ATOMIC);
if(!g_DrvData)
{
usb_debug("Not enough memory for mtkbt virtual usb device.\n");
return -1;
}
else
{
os_memset(g_DrvData,0,sizeof(mtkbt_dev_t));
g_DrvData->idev = dev;
g_DrvData->connect = Ldbtusb_connect;
g_DrvData->disconnect = Ldbtusb_diconnect;
g_DrvData->SetWoble = Ldbtusb_SetWoble;
}
}
else
{
return -1;
}
for (i = 1; i <= dev->num_endp; i++) {
usb_debug("dev->endpoints[%d].type = %d\n", i, dev->endpoints[i].type);
usb_debug("dev->endpoints[%d].endpoint = %d\n", i, dev->endpoints[i].endpoint);
usb_debug("dev->endpoints[%d].direction = %d\n", i, dev->endpoints[i].direction);
if (dev->endpoints[i].type == BULK)
{
if (dev->endpoints[i].direction == IN)
{
g_DrvData->bulk_rx_ep = &dev->endpoints[i];
}
else if (dev->endpoints[i].direction == OUT &&
dev->endpoints[i].endpoint != 0x01)
{
g_DrvData->bulk_tx_ep = &dev->endpoints[i];
}
continue;
}
if (dev->endpoints[i].type == INTERRUPT &&
dev->endpoints[i].endpoint != 0x8f)
{
g_DrvData->intr_ep = &dev->endpoints[i];
continue;
}
}
if (!g_DrvData->intr_ep || !g_DrvData->bulk_tx_ep || !g_DrvData->bulk_rx_ep)
{
os_kfree(g_DrvData);
g_DrvData = NULL;
usb_debug("btmtk_usb_probe end Error 3\n");
return -1;
}
/* Init HostController interface */
g_DrvData->hci_if = &usbbt_host_interface;
/* btmtk init */
ret = LD_btmtk_usb_probe(g_DrvData, flag);
if (ret != 0)
{
usb_debug("usb probe fail\n");
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
return -1;
}
else
{
usb_debug("usbbt probe success\n");
}
return ret;
}
u8 LDbtusb_getWoBTW(void)
{
return LD_btmtk_usb_getWoBTW();
}
#if 0
static int checkUsbDevicePort(struct usb_device* udev, u16 vendorID, u16 productID, u8 port)
{
struct usb_device* pdev = NULL;
/*#if defined (CONFIG_USB_PREINIT)
usb_stop(port);
if (usb_post_init(port) == 0)
#else
if (usb_init(port) == 0)
#endif*/
#if 0
{
/* get device */
//pdev = usb_get_dev_index(0);
if ((pdev != NULL) && (pdev->descriptor.idVendor == vendorID) && (pdev->descriptor.idProduct == productID)) // MTK 7662
{
Printf("OK\n");
x_memcpy(udev, pdev, sizeof(struct usb_device));
return 0 ;
}
}
#endif
return -1;
}
#endif
#if 0
static int findUsbDevice(struct usb_device* udev)
{
int ret = -1;
u8 idx = 0;
u8 i = 0;
char portNumStr[10] = "\0";
char* pBTUsbPort = NULL;
Printf("IN\n");
if(udev == NULL)
{
Printf("udev can not be NULL\n");
return -1;
}
//use the usb poll function replace----lining
//keys add:find usb port idx
/*#define BT_USB_PORT "bt_usb_port"
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
i = 0;
// search mtk bt usb port
idx = atoi(pBTUsbPort);
usb_debug("find mtk bt usb device from usb prot[%d]\n", idx);
while (i < max_mtk_wifi_id) {
ret = checkUsbDevicePort(udev, (pmtk_wifi + i)->vid, (pmtk_wifi + i)->pid, idx);
if (ret == 0) break;
i++;
#if defined(NEW_RC_CON) && (NEW_RC_CON == TRUE)
usb_debug("fengchen 7668 error");
return -1;
#endif
}
if(ret == 0)
{
return 0;
}
}*/
//keys add:find usb port idx end!!!
// not find mt bt usb device from given usb port, so poll every usb port.
/*#if defined(ENABLE_FIFTH_EHC)
const char u8UsbPortCount = 5;
#elif defined(ENABLE_FOURTH_EHC)
const char u8UsbPortCount = 4;
#elif defined(ENABLE_THIRD_EHC)
const char u8UsbPortCount = 3;
#elif defined(ENABLE_SECOND_EHC)
const char u8UsbPortCount = 2;
#else
const char u8UsbPortCount = 1;
#endif
for(idx = 0; idx < u8UsbPortCount; idx++)
{
i = 0;
while (i < max_mtk_wifi_id) {
ret = checkUsbDevicePort(udev, (pmtk_wifi + i)->vid, (pmtk_wifi + i)->pid, idx);
if (ret == 0) break;
i++;
}
if(ret == 0)
{
// set bt_usb_port to store mt bt usb device port
snprintf(portNumStr, sizeof(portNumStr), "%d", idx);
setenv(BT_USB_PORT, portNumStr);
saveenv();
return 0;
}
}
if(pBTUsbPort != NULL)
{
// env BT_USB_PORT is involid, so delete it
setenv(BT_USB_PORT, NULL);
saveenv();
}*/
Printf("Not find usb device\n");
return -1;
}
#endif
void do_setMtkBT(usbdev_t *dev)
{
int ret = 0;
Printf("IN\n");
LDR_Mount(); //16566
// MTK USB controller
/*ret = findUsbDevice(&udev);
if (ret != 0)
{
Printf("find bt usb device failed\n");
return -1;
}*/
ret = Ldbtusb_connect(dev,0);
if(ret != 0){
Printf("connect to bt usb device failed\n");
return;
}
ret = Ldbtusb_SetWoble(NULL);
if(ret != 0)
{
Printf("set bt usb device woble cmd failed\n");
return;
}
Printf("OK\n");
}
int getMtkBTWakeT(void)
{
int ret = 0;
#if 0
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
Printf("IN\n");
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
Printf("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 1);
if(ret != 0)
{
Printf("connect to bt usb device failed\n");
return -1;
}
if(ret != 0)
{
Printf("set bt usb device woble cmd failed\n");
return -1;
}
Printf("OK\n");
#endif
return ret;
}

View file

@ -0,0 +1,114 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2008-2010 MediaTek Inc.
*/
#ifndef __LD_USBBT_H__
#define __LD_USBBT_H__
//#include <common.h>
//#include "usb_def.h"
//#include <MsTypes.h>
#include "types.h"
#include "loader_if.h"
#include "usb_type.h"
struct _usb_vid_pid_
{
unsigned short vid;
unsigned short pid;
char name[10];
};
typedef struct _usb_vid_pid_ usb_vid_pid;
#define MTKBT_CTRL_TX_EP 0
#define MTKBT_CTRL_RX_EP 1
#define MTKBT_INTR_EP 2
#define MTKBT_BULK_TX_EP 3
#define MTKBT_BULK_RX_EP 4
#define MTK_GFP_ATOMIC 1
#define CRC_CHECK 0
#define BTLDER "[BT-LOADER] "
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define usb_debug(fmt,...) Printf("%s: "fmt, __func__, ##__VA_ARGS__)
#define usb_debug_raw(p, l, fmt, ...) \
do { \
int raw_count = 0; \
const unsigned char *ptr = p; \
Printf("%s: "fmt, __func__, ##__VA_ARGS__); \
for (raw_count = 0; raw_count < l; ++raw_count) \
Printf(" %02X", ptr[raw_count]); \
Printf("\n"); \
} while (0)
#define os_kmalloc(size,flags) x_mem_alloc(size)
#define os_kfree(ptr) x_mem_free(ptr)
#define MTK_UDELAY(x) HAL_Delay_us(x)
#define MTK_MDELAY(x) HAL_Delay_us(x*1000)
//#define btusbdev_t struct usb_interface
#define btusbdev_t struct usbdev
#undef NULL
#define NULL ((void *)0)
#define s32 signed int
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned int UINT32;
typedef signed int INT32;
typedef unsigned char UINT8;
typedef unsigned long ULONG;
typedef unsigned char BOOL;
typedef struct __USBBT_DEVICE__ mtkbt_dev_t;
typedef struct {
int (*usb_bulk_msg) (mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
int (*usb_control_msg) (mtkbt_dev_t *dev, u32 epType, u8 request, u8 requesttype, u16 value, u16 index,
u8 *data, int data_length, int timeout);
int (*usb_interrupt_msg)(mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
} HC_IF;
struct __USBBT_DEVICE__
{
void *priv_data;
btusbdev_t* intf;
struct usbdev *idev;
endpoint_t *intr_ep;
endpoint_t *bulk_tx_ep;
endpoint_t *bulk_rx_ep;
endpoint_t *isoc_tx_ep;
endpoint_t *isoc_rx_ep;
HC_IF *hci_if;
int (*connect)(btusbdev_t *dev, int flag);
void (*disconnect)(btusbdev_t *dev);
int (*SetWoble)(btusbdev_t *dev);
};//mtkbt_dev_t;
#define BT_INST(dev) (dev)
u8 LDbtusb_getWoBTW(void);
int Ldbtusb_connect (btusbdev_t *dev,int falg);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len);
VOID *os_memmove(VOID *dest, const void *src,UINT32 len);
VOID *os_memset(VOID *s, int c, size_t n);
VOID *os_kzalloc(size_t size, unsigned int flags);
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev,u32 *code_len);
void do_setMtkBT(usbdev_t *dev);
int getMtkBTWakeT(void);
#endif

View file

@ -0,0 +1,83 @@
###############################################################################
###########################################################################
# $RCSfile: Makefile,v $
# $Revision: #2 $
# $Date: 2009/04/08 $
# $Author: allen.kao $
#
# Description:
# Leave-level makefile to build the subcomponent of driver library.
#
# Specify the source files to be compile in SRC.
#############################################################################
THIS_COMPONENT = usb3
ifeq "$(UBOOT_LIBRARY)" "y"
include $(TOPDIR)/config.mk
CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/drv_inc -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/inc
CFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/drv_inc -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/inc
CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/include -I$(OSAI_INC)
CFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/include -I$(OSAI_INC)
LIB = lib$(THIS_COMPONENT).a
OBJS := LD_btmtk_usb.o LD_usbbt.o
$(LIB): $(OBJS) $(SOBJS)
$(AR) crv $@ $^
clean:
rm -f $(SOBJS) $(OBJS)
distclean: clean
rm -f $(LIB) core *.bak .depend
#########################################################################
.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
$(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
-include .depend
else # UBOOT_LIBRARY
ifdef LINUX_DRV_ROOT
export DRV_ROOT = $(LINUX_DRV_ROOT)
else
export DRV_ROOT = $(TARGET_OPEN_ROOT)
endif
SRC = LD_btmtk_usb.c LD_usbbt.c
ifeq "$(USRDRV)" "true"
ifeq "$(BUILD_LINUX_LOADER)" ""
SRC += kcu_graphic.c
endif
endif
OBJ =
SUB_COMPONENTS =
OPTIONAL_SUB_COMPONENTS =
DEFINES +=
CC_INC += -I$(KERNEL_ROOT)/$(KERNEL_VER)/include -I$(DRV_ROOT)/usb3/libpayload_usb/
#############################################################################
#
# Include the makefile common to all components
#
include $(DRV_ROOT)/driver.mak
endif # UBOOT_LIBRARY

View file

@ -0,0 +1,268 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_BTMTK_USB_H__
#define __LD_BTMTK_USB_H__
#include <mtk-bt/LD_usbbt.h>
/* Memory map for MTK BT */
//#if 0
/* SYS Control */
#define SYSCTL 0x400000
/* WLAN */
#define WLAN 0x410000
/* MCUCTL */
#define CLOCK_CTL 0x0708
#define INT_LEVEL 0x0718
#define COM_REG0 0x0730
#define SEMAPHORE_00 0x07B0
#define SEMAPHORE_01 0x07B4
#define SEMAPHORE_02 0x07B8
#define SEMAPHORE_03 0x07BC
/* Chip definition */
#define CONTROL_TIMEOUT_JIFFIES (300)
#define DEVICE_VENDOR_REQUEST_OUT 0x40
#define DEVICE_VENDOR_REQUEST_IN 0xc0
#define DEVICE_CLASS_REQUEST_OUT 0x20
#define DEVICE_CLASS_REQUEST_IN 0xa0
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
/* ROM Patch */
#define PATCH_HCI_HEADER_SIZE_BULK_EP 4
#define PATCH_HCI_HEADER_SIZE_CTRL_EP 3
#define PATCH_WMT_HEADER_SIZE 5
#define PATCH_HEADER_SIZE_BULK_EP (PATCH_WMT_HEADER_SIZE + PATCH_HCI_HEADER_SIZE_BULK_EP)
#define PATCH_HEADER_SIZE_CTRL_EP (PATCH_WMT_HEADER_SIZE + PATCH_HCI_HEADER_SIZE_CTRL_EP)
#define UPLOAD_PATCH_UNIT 512
#define PATCH_INFO_SIZE 30
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
#define PATCH_LEN_ILM (192 * 1024)
#define BUZZARD_CHIP_ID 0x70010200
#define BUZZARD_FLAVOR 0x70010020
#define BUZZARD_FW_VERSION 0x80021004
/**
* 0: patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1: patch download is complete
* 2: patch download is not complete/BT get patch semaphore success
*/
#define PATCH_ERR -1
#define PATCH_IS_DOWNLOAD_BY_OTHER 0
#define PATCH_READY 1
#define PATCH_NEED_DOWNLOAD 2
#define MAX_BIN_FILE_NAME_LEN 64
#define LD_BT_MAX_EVENT_SIZE 260
#define BD_ADDR_LEN 6
#define WOBLE_SETTING_FILE_NAME_7961 "woble_setting_7961.bin"
#define WOBLE_SETTING_FILE_NAME_7668 "woble_setting_7668.bin"
#define WOBLE_SETTING_FILE_NAME_7663 "woble_setting_7663.bin"
#define WOBLE_SETTING_FILE_NAME "woble_setting.bin"
#define BT_CFG_NAME "bt.cfg"
#define BT_CFG_NAME_PREFIX "bt_mt"
#define BT_CFG_NAME_SUFFIX "cfg"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WMT_CMD "WMT_CMD"
#define WMT_CMD_COUNT 255
#define WAKE_DEV_RECORD "wake_on_ble.conf"
#define WAKE_DEV_RECORD_PATH "misc/bluedroid"
#define APCF_SETTING_COUNT 10
#define WOBLE_SETTING_COUNT 10
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 6
#define SECTION_SPEC_NUM 13
#define WMT_HEADER_LEN 4
#define LOAD_PATCH_PHASE_LEN 1
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define BUZZARD_PATCH_ERR -1
#define BUZZARD_PATCH_NEED_DOWNLOAD 0
#define BUZZARD_PATCH_IS_DOWNLOAD_BY_OTHER 1
#define BUZZARD_PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_CMD_DELAY_TIME 5
#define PATCH_DOWNLOAD_CMD_RETRY 0
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
#define PM_SOURCE_DISABLE (0xFF)
enum {
BTMTK_EP_TYPE_OUT_CMD = 0, /*EP type out for hci cmd and wmt cmd */
BTMTK_EP_TPYE_OUT_ACL, /* EP type out for acl pkt with load rompatch */
};
typedef enum {
TYPE_APCF_CMD,
} woble_setting_type;
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
u8 *content; /* APCF content or radio off content */
int length; /* APCF content or radio off content of length */
};
#define UNIFY_WOBLE_LEGACY 0
#define UNIFY_WOBLE_WAVEFORM 1
struct bt_cfg_struct {
u8 support_unify_woble; /* support unify woble or not */
u8 unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct wmt_cmd[WMT_CMD_COUNT];
};
struct LD_btmtk_usb_data {
mtkbt_dev_t *udev; /* store the usb device informaiton */
unsigned long flags;
int meta_tx;
HC_IF *hcif;
u8 cmdreq_type;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* request for different io operation */
u8 w_request;
u8 r_request;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *fw_image;
unsigned char *fw_header_image;
unsigned char *fw_bin_file_name;
unsigned char *rom_patch;
unsigned char *rom_patch_header_image;
unsigned char *rom_patch_bin_file_name;
u32 chip_id;
unsigned int flavor;
unsigned int fw_version;
u8 need_load_fw;
u8 need_load_rom_patch;
u32 rom_patch_offset;
u32 rom_patch_len;
u32 fw_len;
int recv_evt_len;
u8 local_addr[BD_ADDR_LEN];
char *woble_setting_file_name;
u8 *setting_file;
u32 setting_file_len;
u8 *wake_dev; /* ADDR:NAP-UAP-LAP, VID/PID:Both Little endian */
u32 wake_dev_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct bt_cfg_struct bt_cfg;
};
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 reserved[9];
}bin_info_spec;
};
};
u8 LD_btmtk_usb_getWoBTW(void);
int LD_btmtk_usb_probe(mtkbt_dev_t *dev, int flag);
void LD_btmtk_usb_disconnect(mtkbt_dev_t *dev);
void LD_btmtk_usb_SetWoble(mtkbt_dev_t *dev);
int Ldbtusb_getBtWakeT(struct LD_btmtk_usb_data *data);
#define REV_MT76x2E3 0x0022
#define MT_REV_LT(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) < (_rev))
#define MT_REV_GTE(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) >= (_rev))
/*
* Load code method
*/
enum LOAD_CODE_METHOD {
BIN_FILE_METHOD,
HEADER_METHOD,
};
#endif

View file

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_USBBT_H__
#define __LD_USBBT_H__
#include <common.h>
#include <malloc.h>
#include <usb.h>
#include <MsTypes.h>
#define MTKBT_CTRL_TX_EP 0
#define MTKBT_CTRL_RX_EP 1
#define MTKBT_INTR_EP 2
#define MTKBT_BULK_TX_EP 3
#define MTKBT_BULK_RX_EP 4
#define USB_INTR_MSG_TIMO 2000
#define MTK_GFP_ATOMIC 1
#define CRC_CHECK 0
#define BT_USB_PORT "bt_usb_port"
#define BTLDER "[BT-LOADER] "
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define usb_debug(fmt,...) printf("%s: "fmt, __func__, ##__VA_ARGS__)
#define usb_debug_raw(p, l, fmt, ...) \
do { \
int raw_count = 0; \
const unsigned char *ptr = p; \
printf("%s: "fmt, __func__, ##__VA_ARGS__); \
for (raw_count = 0; raw_count < l; ++raw_count) \
printf(" %02X", ptr[raw_count]); \
printf("\n"); \
} while (0)
#define os_kmalloc(size,flags) malloc(size)
#define os_kfree(ptr) free(ptr)
#define MTK_UDELAY(x) udelay(x)
#define MTK_MDELAY(x) mdelay(x)
//#define btusbdev_t struct usb_interface
#define btusbdev_t struct usb_device
#undef NULL
#define NULL ((void *)0)
#define s32 signed int
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned int UINT32;
typedef signed int INT32;
typedef unsigned char UINT8;
typedef unsigned long ULONG;
typedef unsigned char BOOL;
typedef struct __USBBT_DEVICE__ mtkbt_dev_t;
typedef struct {
int (*usb_bulk_msg) (mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
int (*usb_control_msg) (mtkbt_dev_t *dev, u32 epType, u8 request, u8 requesttype, u16 value, u16 index,
u8 *data, int data_length, int timeout);
int (*usb_interrupt_msg)(mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
} HC_IF;
struct __USBBT_DEVICE__
{
void *priv_data;
btusbdev_t* intf;
struct usb_device *udev;
struct usb_endpoint_descriptor *intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
HC_IF *hci_if;
int (*connect)(btusbdev_t *dev, int flag);
void (*disconnect)(btusbdev_t *dev);
int (*SetWoble)(btusbdev_t *dev);
u32 chipid;
};//mtkbt_dev_t;
#define BT_INST(dev) (dev)
u8 LDbtusb_getWoBTW(void);
int Ldbtusb_connect (btusbdev_t *dev, int falg);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len);
VOID *os_memmove(VOID *dest, const void *src,UINT32 len);
VOID *os_memset(VOID *s, int c, size_t n);
VOID *os_kzalloc(size_t size, unsigned int flags);
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev,u32 *code_len);
int do_setMtkBT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_getMtkBTWakeT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif

View file

@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _GENERIC_ERRNO_H
#define _GENERIC_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#endif

View file

@ -0,0 +1,556 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <command.h>
#include <common.h>
#include <ShareType.h>
#include <CusConfig.h>
#include <MsVfs.h>
#include <MsDebug.h>
#include <usb.h>
#include <MsSystem.h>
#include <stdio.h>
#include <mtk-bt/LD_usbbt.h>
#include <mtk-bt/LD_btmtk_usb.h>
#define MAX_ROOT_PORTS 8
usb_vid_pid array_mtk_vid_pid[] = {
{0x0E8D, 0x7668, "MTK7668"}, // 7668
{0x0E8D, 0x76A0, "MTK7662T"}, // 7662T
{0x0E8D, 0x76A1, "MTK7632T"}, // 7632T
{0x0E8D, 0x7663, "MTK7663"}, //7663
{0x0E8D, 0x7961, "MTK7961"}, //7961
};
int max_mtk_wifi_id = (sizeof(array_mtk_vid_pid) / sizeof(array_mtk_vid_pid[0]));
usb_vid_pid *pmtk_wifi = &array_mtk_vid_pid[0];
static mtkbt_dev_t *g_DrvData = NULL;
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len)
{
return memcpy(dst, src, len);
}
VOID *os_memmove(VOID *dest, const void *src,UINT32 len)
{
return memmove(dest, src, len);
}
VOID *os_memset(VOID *s, int c, size_t n)
{
return memset(s,c,n);
}
VOID *os_kzalloc(size_t size, unsigned int flags)
{
VOID *ptr = malloc(size);
if (ptr == NULL) {
usb_debug("malloc is fail, ptr is %p\n", ptr);
return ptr;
}
os_memset(ptr, 0, size);
return ptr;
}
int LD_load_code(unsigned char **image, char *partition, char *file, mtkbt_dev_t *dev, u32 *code_len)
{
if (vfs_mount(partition) != 0) {
usb_debug("vfs_mount %s fail\n", partition);
return -1;
}
*code_len = vfs_getsize(file);
if (*code_len == 0) {
usb_debug("Get file size fail\n");
return -1;
}
// malloc buffer to store bt patch file data
*image = malloc(*code_len);
if (*image == NULL) {
usb_debug("malloc fail\n");
*code_len = 0;
return -1;
}
if (vfs_read(*image, file, 0, *code_len) != 0) {
usb_debug("vfs_read %s fail\n", file);
free(*image);
*image = NULL;
*code_len = 0;
return -1;
}
UBOOT_DEBUG("Load file(%s:%s) OK\n", partition, file);
UBOOT_DUMP((unsigned int)*image, 0x200);
return 0;
}
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev, u32 *code_len)
{
#define ENV_BT_FW_PATH "BTFWBinPath"
#define PARTION_NUM 6
char mtk_patch_bin_patch[128] = "\0";
char *bt_env;
char *partition[PARTION_NUM] = {"cusdata", "tvconfig", "vendor", "userdata", "system", "APP"};
int i = 0;
/** implement by mstar/MTK
* path: /system/etc/firmware/mt76XX_patch_eX_hdr.bin
* If argument "path" is NULL, access "/etc/firmware" directly like as request_firmware
* if argument "path" is not NULL, so far only support directory "userdata"
* NOTE: latest vfs_mount seems decided this time access directory
*/
if (path) {
(void)snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", path, bin_name);
printf("File: %s\n", mtk_patch_bin_patch);
} else {
#if (ENABLE_MODULE_ANDROID_BOOT == 1)
(void)snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", "/firmware", bin_name);
#else
(void)snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", "/krl/wifi/ralink/firmware", bin_name);
#endif
printf("mtk_patch_bin_patch: %s\n", mtk_patch_bin_patch);
}
bt_env = getenv(ENV_BT_FW_PATH);
if (bt_env == NULL) {
/* get PATH failed */
printf("bt_env is NULL\n");
for (i = 0; i < PARTION_NUM; i++) {
if (LD_load_code(image, partition[i], mtk_patch_bin_patch, dev, code_len) == 0)
return;
}
} else {
printf("bt_env: %s\n", bt_env);
LD_load_code(image, bt_env, mtk_patch_bin_patch, dev, code_len);
}
return;
}
static int usb_bt_bulk_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* not used */
)
{
int ret =0 ;
if(dev == NULL || dev->udev == NULL || dev->bulk_tx_ep == NULL)
{
usb_debug("bulk out error 00\n");
return -1;
}
if(epType == MTKBT_BULK_TX_EP)
{
// usb_debug_raw(data, size, "%s: usb_bulk_msg:", __func__);
ret = usb_bulk_msg(dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_tx_ep->bEndpointAddress),data,size,realsize,2000);
if(ret)
{
usb_debug("bulk out error 01, ret = %d\n", ret);
return -1;
}
if(*realsize == size)
{
//usb_debug("bulk out success 01,size =0x%x\n",size);
return 0;
}
else
{
usb_debug("bulk out fail 02,size =0x%x,realsize =0x%x\n",size,*realsize);
}
}
return -1;
}
static int usb_bt_control_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 request,
u8 requesttype,
u16 value,
u16 index,
u8 *data,
int data_length,
int timeout /* not used */
)
{
int ret = -1;
if(epType == MTKBT_CTRL_TX_EP)
{
// usb_debug_raw(data, data_length, "%s: usb_control_msg:", __func__);
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), request,
requesttype, value, index, data, data_length,timeout);
}
else if (epType == MTKBT_CTRL_RX_EP)
{
ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), request,
requesttype, value, index, data, data_length,timeout);
}
else
{
usb_debug("control message wrong Type =0x%x\n",epType);
}
if (ret < 0)
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
return ret;
}
static int usb_bt_interrupt_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* unit of 1ms */
)
{
int ret = -1;
usb_debug("epType = 0x%x\n",epType);
if(epType == MTKBT_INTR_EP)
{
ret = usb_submit_int_msg(dev->udev,usb_rcvintpipe(dev->udev,dev->intr_ep->bEndpointAddress),data,size,realsize,timeout);
}
if(ret < 0 )
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
usb_debug("ret = 0x%x\n",ret);
return ret;
}
static HC_IF usbbt_host_interface =
{
usb_bt_bulk_msg,
usb_bt_control_msg,
usb_bt_interrupt_msg,
};
static void Ldbtusb_diconnect (btusbdev_t *dev)
{
LD_btmtk_usb_disconnect(g_DrvData);
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
}
static int Ldbtusb_SetWoble(btusbdev_t *dev)
{
if(!g_DrvData)
{
usb_debug("usb set woble fail ,because no drv data\n");
return -1;
}
else
{
LD_btmtk_usb_SetWoble(g_DrvData);
usb_debug("usb set woble end\n");
}
return 0;
}
static u32 chipid;
int Ldbtusb_connect (btusbdev_t *dev, int flag)
{
int ret = 0;
// For Mstar
struct usb_endpoint_descriptor *ep_desc;
struct usb_interface *iface;
int i;
iface = &dev->config.if_desc[0];
if(g_DrvData == NULL)
{
g_DrvData = os_kmalloc(sizeof(mtkbt_dev_t),MTK_GFP_ATOMIC);
if(!g_DrvData)
{
usb_debug("Not enough memory for mtkbt virtual usb device.\n");
return -1;
}
else
{
os_memset(g_DrvData,0,sizeof(mtkbt_dev_t));
g_DrvData->udev = dev;
g_DrvData->connect = Ldbtusb_connect;
g_DrvData->disconnect = Ldbtusb_diconnect;
g_DrvData->SetWoble = Ldbtusb_SetWoble;
}
}
else
{
return -1;
}
// For Mstar
for (i = 0; i < iface->desc.bNumEndpoints; i++)
{
ep_desc = &iface->ep_desc[i];
usb_debug("dev->endpoints[%d].bmAttributes = 0x%x\n", i, ep_desc->bmAttributes);
usb_debug("dev->endpoints[%d].bEndpointAddress = 0x%x\n", i, ep_desc->bEndpointAddress);
if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
{
if (ep_desc->bEndpointAddress & USB_DIR_IN)
{
usb_debug("set endpoints[%d] to bulk_rx_ep\n", i);
g_DrvData->bulk_rx_ep = ep_desc;
}
else
{
if (ep_desc->bEndpointAddress != 0x1) {
usb_debug("set endpoints[%d] to bulk_tx_ep\n", i);
g_DrvData->bulk_tx_ep = ep_desc;
}
}
continue;
}
/* is it an interrupt endpoint? */
if (((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
&& ep_desc->bEndpointAddress != 0x8f)
{
usb_debug("set endpoints[%d] to intr_ep\n", i);
g_DrvData->intr_ep = ep_desc;
continue;
}
}
if (!g_DrvData->intr_ep || !g_DrvData->bulk_tx_ep || !g_DrvData->bulk_rx_ep)
{
os_kfree(g_DrvData);
g_DrvData = NULL;
usb_debug("btmtk_usb_probe end Error 3\n");
return -1;
}
/* Init HostController interface */
g_DrvData->hci_if = &usbbt_host_interface;
g_DrvData->chipid = chipid;
/* btmtk init */
ret = LD_btmtk_usb_probe(g_DrvData, flag);
if (ret != 0)
{
usb_debug("usb probe fail\n");
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
return -1;
}
else
{
usb_debug("usbbt probe success\n");
}
return ret;
}
u8 LDbtusb_getWoBTW(void)
{
return LD_btmtk_usb_getWoBTW();
}
static int checkUsbDevicePort(struct usb_device *udev, usb_vid_pid *pmtk_dongle, u8 port)
{
struct usb_device *pdev = NULL;
int i;
int dongleCount = 0;
#if defined (CONFIG_USB_PREINIT)
usb_stop(port);
if (usb_post_init(port) == 0)
#else
if (usb_init(port) == 0)
#endif
{
for (i = 0; i < usb_get_dev_num(); i++) {
pdev = usb_get_dev_index(i); // get device
if (pdev != NULL) {
for (dongleCount = 0; dongleCount < max_mtk_wifi_id; dongleCount++) {
if ((pdev->descriptor.idVendor == pmtk_dongle[dongleCount].vid)
&& (pdev->descriptor.idProduct == pmtk_dongle[dongleCount].pid)) {
UBOOT_TRACE("OK\n");
memcpy(udev, pdev, sizeof(struct usb_device));
chipid = pmtk_dongle[dongleCount].pid;
return 0;
}
}
}
}
}
return -1;
}
static int findUsbDevice(struct usb_device* udev)
{
int ret = -1;
u8 idx = 0;
char portNumStr[10] = "\0";
char* pBTUsbPort = NULL;
UBOOT_TRACE("IN\n");
if(udev == NULL)
{
UBOOT_ERROR("udev can not be NULL\n");
return -1;
}
#define BT_USB_PORT "bt_usb_port"
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
// search mtk bt usb port
idx = atoi(pBTUsbPort);
usb_debug("find mtk bt usb device from usb prot[%d]\n", idx);
ret = checkUsbDevicePort(udev, pmtk_wifi, idx);
if(ret == 0)
{
return 0;
}
}
// not find mt bt usb device from given usb port, so poll every usb port.
#if defined(ENABLE_FIFTH_EHC)
const char u8UsbPortCount = 5;
#elif defined(ENABLE_FOURTH_EHC)
const char u8UsbPortCount = 4;
#elif defined(ENABLE_THIRD_EHC)
const char u8UsbPortCount = 3;
#elif defined(ENABLE_SECOND_EHC)
const char u8UsbPortCount = 2;
#else
const char u8UsbPortCount = 1;
#endif
for(idx = 0; idx < u8UsbPortCount; idx++)
{
ret = checkUsbDevicePort(udev, pmtk_wifi, idx);
if(ret == 0)
{
// set bt_usb_port to store mt bt usb device port
(void)snprintf(portNumStr, sizeof(portNumStr), "%d", idx);
setenv(BT_USB_PORT, portNumStr);
saveenv();
return 0;
}
}
if(pBTUsbPort != NULL)
{
// env BT_USB_PORT is involid, so delete it
setenv(BT_USB_PORT, NULL);
saveenv();
}
UBOOT_ERROR("Not find usb device\n");
return -1;
}
int do_setMtkBT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int ret = 0;
char* pBTUsbPort = NULL;
int usbPort = 0;
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
UBOOT_TRACE("IN\n");
if (argc < 1)
{
cmd_usage(cmdtp);
return -1;
}
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
UBOOT_ERROR("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 0);
if(ret != 0){
UBOOT_ERROR("connect to bt usb device failed\n");
return -1;
}
ret = Ldbtusb_SetWoble(&udev);
if(ret != 0)
{
UBOOT_ERROR("set bt usb device woble cmd failed\n");
return -1;
}
usb_debug("ready to do usb_stop\n");
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
// search mtk bt usb port
usbPort = atoi(pBTUsbPort);
if (usbPort < 0 || usbPort >= MAX_ROOT_PORTS) {
UBOOT_ERROR("usbPort(%d) is not in correct scope\n", usbPort);
return -1;
}
usb_debug("stop usb port: %d\n",usbPort);
if(usb_stop(usbPort) != 0){
usb_debug("usb_stop fail\n");
}
}else{
usb_debug("no BT_USB_PORT\n");
}
UBOOT_TRACE("OK\n");
return ret;
}
int do_getMtkBTWakeT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int ret = 0;
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
UBOOT_TRACE("IN\n");
if (argc < 1)
{
cmd_usage(cmdtp);
return -1;
}
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
UBOOT_ERROR("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 1);
if(ret != 0)
{
UBOOT_ERROR("connect to bt usb device failed\n");
return -1;
}
if(ret != 0)
{
UBOOT_ERROR("set bt usb device woble cmd failed\n");
return -1;
}
UBOOT_TRACE("OK\n");
return ret;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
acpi_dock_ops
address_space_operations
backlight_ops
block_device_operations
clk_ops
comedi_lrange
component_ops
dentry_operations
dev_pm_ops
dma_map_ops
driver_info
drm_connector_funcs
drm_encoder_funcs
drm_encoder_helper_funcs
ethtool_ops
extent_io_ops
file_lock_operations
file_operations
hv_ops
ide_dma_ops
ide_port_ops
inode_operations
intel_dvo_dev_ops
irq_domain_ops
item_operations
iwl_cfg
iwl_ops
kgdb_arch
kgdb_io
kset_uevent_ops
lock_manager_operations
machine_desc
microcode_ops
mlxsw_reg_info
mtrr_ops
neigh_ops
net_device_ops
nlmsvc_binding
nvkm_device_chip
of_device_id
pci_raw_ops
pipe_buf_operations
platform_hibernation_ops
platform_suspend_ops
proto_ops
regmap_access_table
rpc_pipe_ops
rtc_class_ops
sd_desc
seq_operations
sirfsoc_padmux
snd_ac97_build_ops
snd_soc_component_driver
soc_pcmcia_socket_ops
stacktrace_ops
sysfs_ops
tty_operations
uart_ops
usb_mon_operations
v4l2_ctrl_ops
v4l2_ioctl_ops
vm_operations_struct
wacom_features
wd_ops

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
LOCAL_PATH := $(call my-dir)
LOCAL_PATH_B := $(LOCAL_PATH)
BT_PLATFORM:=$(subst MTK_CONSYS_MT,,$(MTK_BT_CHIP))
$(info [BT_Drv] MTK_BT_SUPPORT = $(MTK_BT_SUPPORT))
$(info [BT_Drv] MTK_BT_CHIP = $(MTK_BT_CHIP))
ifeq ($(strip $(MTK_BT_SUPPORT)), yes)
ifneq (true,$(strip $(TARGET_NO_KERNEL)))
# connac1x
LOG_TAG := [BT_Drv][wmt]
BT_PLATFORM := connac1x
include $(LOCAL_PATH_B)/wmt/Android.mk
# connac20
LOG_TAG := [BT_Drv][btif]
BT_PLATFORM := 6885
include $(LOCAL_PATH_B)/btif/Android.mk
BT_PLATFORM := 6893
include $(LOCAL_PATH_B)/btif/Android.mk
BT_PLATFORM := 6877
include $(LOCAL_PATH_B)/btif/Android.mk
BT_PLATFORM := 6983
include $(LOCAL_PATH_B)/btif/Android.mk
BT_PLATFORM := 6879
include $(LOCAL_PATH_B)/btif/Android.mk
BT_PLATFORM := 6895
include $(LOCAL_PATH_B)/btif/Android.mk
endif
endif
#dirs := btif
#include $(call all-named-subdir-makefiles, $(dirs))

View file

@ -0,0 +1,111 @@
export KERNEL_SRC := /lib/modules/$(shell uname -r)/build
#################### Configurations ####################
# Compile Options for bt driver configuration.
CONFIG_SUPPORT_BT_DL_WIFI_PATCH=y
CONFIG_SUPPORT_BLUEZ=n
CONFIG_SUPPORT_DVT=n
CONFIG_SUPPORT_MULTI_DEV_NODE=n
ifeq ($(CONFIG_SUPPORT_BT_DL_WIFI_PATCH), y)
ccflags-y += -DCFG_SUPPORT_BT_DL_WIFI_PATCH=1
else
ccflags-y += -DCFG_SUPPORT_BT_DL_WIFI_PATCH=0
endif
ifeq ($(CONFIG_SUPPORT_BLUEZ), y)
ccflags-y += -DCFG_SUPPORT_BLUEZ=1
ccflags-y += -DCFG_SUPPORT_HW_DVT=0
else
ccflags-y += -DCFG_SUPPORT_BLUEZ=0
ccflags-y += -DCFG_SUPPORT_HW_DVT=1
endif
ifeq ($(CONFIG_SUPPORT_DVT), y)
ccflags-y += -DCFG_SUPPORT_DVT=1
else
ccflags-y += -DCFG_SUPPORT_DVT=0
endif
ifeq ($(CONFIG_SUPPORT_DVT), y)
ccflags-y += -DCFG_SUPPORT_DVT=1
else
ccflags-y += -DCFG_SUPPORT_DVT=0
endif
ifeq ($(CONFIG_SUPPORT_MULTI_DEV_NODE), y)
ccflags-y += -DCFG_SUPPORT_MULTI_DEV_NODE=1
else
ccflags-y += -DCFG_SUPPORT_MULTI_DEV_NODE=0
endif
#################### Configurations ####################
# For chip interface, driver supports "usb", "sdio", "uart" and "btif"
MTK_CHIP_IF := usb
ifeq ($(MTK_CHIP_IF), sdio)
MOD_NAME = btmtk_sdio_unify
CFILES := sdio/btmtksdio.c btmtk_woble.c btmtk_buffer_mode.c btmtk_chip_reset.c
ccflags-y += -DCHIP_IF_SDIO
ccflags-y += -DSDIO_DEBUG=0
ccflags-y += -I$(src)/include/sdio
else ifeq ($(MTK_CHIP_IF), usb)
MOD_NAME = btmtk_usb_unify
CFILES := usb/btmtkusb.c btmtk_woble.c btmtk_chip_reset.c
ccflags-y += -DCHIP_IF_USB
ccflags-y += -I$(src)/include/usb
else ifeq ($(MTK_CHIP_IF), uart)
MOD_NAME = btmtk_uart_unify
CFILES := uart/btmtk_uart_main.c
ccflags-y += -DCHIP_IF_UART
ccflags-y += -I$(src)/include/uart
else
MOD_NAME = btmtkbtif_unify
CFILES := btif/btmtk_btif.c
ccflags-y += -DCHIP_IF_BTIF
ccflags-y += -I$(src)/include/btif
endif
CFILES += btmtk_main.c btmtk_fw_log.c
ccflags-y += -I$(src)/include/ -I$(src)/
$(MOD_NAME)-objs := $(CFILES:.c=.o)
obj-m += $(MOD_NAME).o
#VPATH = /opt/toolchains/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux
#UART_MOD_NAME = btmtk_uart
#UART_CFILES := \
# btmtk_uart_main.c
#$(UART_MOD_NAME)-objs := $(UART_CFILES:.c=.o)
###############################################################################
# Common
###############################################################################
#obj-m := $(UART_MOD_NAME).o
all:
make -C $(KERNEL_SRC) M=$(PWD) modules
clean:
make -C $(KERNEL_SRC) M=$(PWD) clean
# Check coding style
# export IGNORE_CODING_STYLE_RULES := NEW_TYPEDEFS,LEADING_SPACE,CODE_INDENT,SUSPECT_CODE_INDENT
ccs:
./util/checkpatch.pl -f ./sdio/btmtksdio.c
./util/checkpatch.pl -f ./include/sdio/btmtk_sdio.h
./util/checkpatch.pl -f ./include/btmtk_define.h
./util/checkpatch.pl -f ./include/btmtk_drv.h
./util/checkpatch.pl -f ./include/btmtk_chip_if.h
./util/checkpatch.pl -f ./include/btmtk_main.h
./util/checkpatch.pl -f ./include/btmtk_buffer_mode.h
./util/checkpatch.pl -f ./include/btmtk_fw_log.h
./util/checkpatch.pl -f ./include/btmtk_woble.h
./util/checkpatch.pl -f ./include/uart/btmtk_uart.h
./util/checkpatch.pl -f ./uart/btmtk_uart_main.c
./util/checkpatch.pl -f ./include/usb/btmtk_usb.h
./util/checkpatch.pl -f ./usb/btmtkusb.c
./util/checkpatch.pl -f btmtk_fw_log.c
./util/checkpatch.pl -f btmtk_main.c
./util/checkpatch.pl -f btmtk_buffer_mode.c
./util/checkpatch.pl -f btmtk_woble.c
./util/checkpatch.pl -f btmtk_chip_reset.c

View file

@ -0,0 +1,21 @@
#Please follow the example pattern
#There are some SPACES between parameter and parameter
[Country Code]
[Index] BR_EDR_PWR_MODE, | EDR_MAX_TX_PWR, | BLE_DEFAULT_TX_PWR, | BLE_DEFAULT_TX_PWR_2M, | BLE_LR_S2, | BLE_LR_S8
[AU,SA]
[BT0] 1, 1.75, 1.5, 1, 1, 1
[BT1] 1, 2.75, 2.5, 2, 1, 1
[TW,US]
[BT0] 1, 14, 15, 16, 20, 20
[BT1] 1, 17, 17, 17, 20, 20
[JP]
[BT0] 0, 5.25, -3, -3, -2, -2
[BT1] 0, 5.5, -2.5, -2, -2, -2
[DE]
[BT0] 0, -32, -29, -29, -29, -29
[BT1] 0, -32, -29, -29, -29, -29

View file

@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := bt_drv_$(BT_PLATFORM).ko
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
LOCAL_INIT_RC := init.bt_drv.rc
LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%,%,$(shell find $(LOCAL_PATH) -type f -name '*.[cho]')) Makefile
LOCAL_REQUIRED_MODULES := conninfra.ko
LOCAL_REQUIRED_MODULES += connfem.ko
include $(MTK_KERNEL_MODULE)
BT_OPTS := BT_PLATFORM=$(BT_PLATFORM) LOG_TAG=$(LOG_TAG)
$(info $(LOG_TAG) BT_OPTS = $(BT_OPTS))
$(linked_module): OPTS += $(BT_OPTS)

View file

@ -0,0 +1,27 @@
LOCAL_PATH := $(call my-dir)
ifneq (true,$(strip $(TARGET_NO_KERNEL)))
include $(CLEAR_VARS)
LOCAL_MODULE := bt_drv.ko
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
LOCAL_INIT_RC := init.bt_drv.rc
LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%,%,$(shell find $(LOCAL_PATH) -type f -name '*.[cho]')) Makefile
LOCAL_REQUIRED_MODULES := conninfra.ko
include $(MTK_KERNEL_MODULE)
#### Copy Module.symvers from $(LOCAL_REQUIRED_MODULES) to this module #######
#### For symbol link (when CONFIG_MODVERSIONS is defined)
CONN_INFRA_EXPORT_SYMBOL := $(subst $(LOCAL_MODULE),$(LOCAL_REQUIRED_MODULES),$(intermediates)/LINKED)/Module.symvers
$(CONN_INFRA_EXPORT_SYMBOL): $(subst $(LOCAL_MODULE),$(LOCAL_REQUIRED_MODULES),$(linked_module))
BT_EXPORT_SYMBOL := $(intermediates)/LINKED/Module.symvers
$(BT_EXPORT_SYMBOL).in: $(intermediates)/LINKED/% : $(CONN_INFRA_EXPORT_SYMBOL)
$(copy-file-to-target)
cp $(CONN_INFRA_EXPORT_SYMBOL) $(BT_EXPORT_SYMBOL)
$(linked_module): $(BT_EXPORT_SYMBOL).in
endif

View file

@ -0,0 +1,112 @@
###############################################################################
# Bluetooth character device driver
###############################################################################
# ---------------------------------------------------
# Compile Options
# ---------------------------------------------------
ifndef TOP
TOP := $(srctree)/..
endif
ifneq ($(KERNEL_OUT),)
ccflags-y += -imacros $(KERNEL_OUT)/include/generated/autoconf.h
endif
# Force build fail on modpost warning
KBUILD_MODPOST_FAIL_ON_WARNINGS := y
# platform
ifeq ($(CONFIG_WLAN_DRV_BUILD_IN),y)
$(info build-in mode!)
$(info _MTK_BT_CHIP = $(_MTK_BT_CHIP))
# _MTK_BT_CHIP comes from conninfra setting
BT_PLATFORM = $(patsubst MTK_CONSYS_MT%,%,$(strip $(_MTK_BT_CHIP)))
endif
$(info $(LOG_TAG) TARGET_BUILD_VARIANT = $(TARGET_BUILD_VARIANT))
ifeq ("$(TARGET_BUILD_VARIANT)","user")
ccflags-y += -D FW_LOG_DEFAULT_ON=0
else
ccflags-y += -D FW_LOG_DEFAULT_ON=1
endif
ccflags-y += -D CONNAC20_CHIPID=$(BT_PLATFORM)
$(info $(LOG_TAG) BT_PLATFORM = $(BT_PLATFORM))
$(info $(LOG_TAG) srctree = $(srctree))
# ---------------------------------------------------
# Compile Options: set feature flag (1: enable, 0: disable)
# ---------------------------------------------------
# build btif interface
ccflags-y += -D CHIP_IF_BTIF
# Use device node or hci_dev as native interface
ccflags-y += -D USE_DEVICE_NODE=1
# Customized fw update feature
#ifndef OPLUS_FEATURE_BT_FW_SAU_MTK
#Add for fw sau
#ccflags-y += -D CUSTOMER_FW_UPDATE=0
#else /* OPLUS_FEATURE_BT_FW_SAU_MTK */
ccflags-y += -D CUSTOMER_FW_UPDATE=1
ccflags-y += -D OPLUS_FEATURE_BT_FW_SAU_MTK=1
#endif /* OPLUS_FEATURE_BT_FW_SAU_MTK */
# pm_qos control
ccflags-y += -D PM_QOS_CONTROL=0
# No function, only for build pass
ccflags-y += -D CONFIG_MP_WAKEUP_SOURCE_SYSFS_STAT=1
# Customized feature, load 1b fw bin
#ccflags-y += -D BT_CUS_FEATURE
# ---------------------------------------------------
# Include Path
# ---------------------------------------------------
CONN_INFRA_SRC := $(TOP)/vendor/mediatek/kernel_modules/connectivity/conninfra
CONNFEM_SRC := $(TOP)/vendor/mediatek/kernel_modules/connectivity/connfem
WMT_SRC := $(TOP)/vendor/mediatek/kernel_modules/connectivity/common
BTIF_SRC := $(srctree)/drivers/misc/mediatek/btif
ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/common
ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/
ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/power_throttling
ccflags-y += -I$(srctree)/drivers/gpu/drm/mediatek/mediatek_v2/
ccflags-y += -I$(CONN_INFRA_SRC)/include
ccflags-y += -I$(CONN_INFRA_SRC)/debug_utility/include
ccflags-y += -I$(CONN_INFRA_SRC)/debug_utility/metlog
ccflags-y += -I$(CONN_INFRA_SRC)/debug_utility/
ccflags-y += -I$(CONNFEM_SRC)/include
ccflags-y += -I$(WMT_SRC)/debug_utility
ccflags-y += -I$(BTIF_SRC)/common/inc
ccflags-y += -I$(src)/core/include
ccflags-y += -I$(src)/connsys/connac_2_0
ccflags-y += -I$(src)/../include
ccflags-y += -I$(src)/../include/btif
# ---------------------------------------------------
# Objects List
# ---------------------------------------------------
MODULE_NAME := bt_drv_$(BT_PLATFORM)
ifeq ($(CONFIG_WLAN_DRV_BUILD_IN),y)
obj-y += $(MODULE_NAME).o
else
obj-m += $(MODULE_NAME).o
endif
CORE_OBJS := btmtk_dbg.o btmtk_dbg_tp_evt_if.o btmtk_irq.o btmtk_char_dev.o ../btmtk_fw_log.o ../btmtk_main.o
CHIP_OBJS := btmtk_mt66xx.o
HIF_OBJS := btmtk_btif_main.o btmtk_queue.o
$(MODULE_NAME)-objs += $(CORE_OBJS)
$(MODULE_NAME)-objs += $(HIF_OBJS)
$(MODULE_NAME)-objs += $(CHIP_OBJS)

View file

@ -0,0 +1,57 @@
CONFIG_MODULE_SIG=n
export KERNEL_SRC := /lib/modules/$(shell uname -r)/build
#################### Configurations ####################
# For chip interface, driver supports "usb", "sdio", "uart" and "btif"
MTK_CHIP_IF := uart
ifeq ($(MTK_CHIP_IF), sdio)
MOD_NAME = btmtksdio
CFILES := btmtk_sdio.c
ccflags-y += -DCHIP_IF_SDIO
else ifeq ($(MTK_CHIP_IF), usb)
MOD_NAME = btmtk_usb
CFILES := btmtkusb.c
ccflags-y += -DCHIP_IF_USB
else ifeq ($(MTK_CHIP_IF), uart)
MOD_NAME = btmtk_uart
CFILES := btmtk_uart_main.c btmtk_mt76xx.c
ccflags-y += -DCHIP_IF_UART
else
MOD_NAME = btmtkbtif
CFILES := btmtk_btif_main.c btmtk_mt66xx.c
ccflags-y += -DCHIP_IF_BTIF
endif
CFILES += btmtk_main.c
ccflags-y += -I$(src)/include/ -I$(src)/
$(MOD_NAME)-objs := $(CFILES:.c=.o)
obj-m += $(MOD_NAME).o
#VPATH = /opt/toolchains/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux
#UART_MOD_NAME = btmtk_uart
#UART_CFILES := \
# btmtk_uart_main.c
#$(UART_MOD_NAME)-objs := $(UART_CFILES:.c=.o)
###############################################################################
# Common
###############################################################################
#obj-m := $(UART_MOD_NAME).o
all:
make -C $(KERNEL_SRC) M=$(PWD) modules
clean:
make -C $(KERNEL_SRC) M=$(PWD) clean
# Check coding style
# export IGNORE_CODING_STYLE_RULES := NEW_TYPEDEFS,LEADING_SPACE,CODE_INDENT,SUSPECT_CODE_INDENT
ccs:
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_main.c
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_sdio.c
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_sdio.h
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_config.h
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_define.h
./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_drv.h

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,640 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "btmtk_main.h"
#include "btmtk_chip_if.h"
#include "btmtk_fw_log.h"
#include "btmtk_dbg_tp_evt_if.h"
MODULE_LICENSE("Dual BSD/GPL");
#if (USE_DEVICE_NODE == 1)
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
#define BT_DRIVER_NAME "mtk_bt_chrdev"
#define BT_DRIVER_NODE_NAME "stpbt"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
#define BT_BUFFER_SIZE (2048)
#define FTRACE_STR_LOG_SIZE (256)
#define COMBO_IOC_MAGIC 0xb0
#define COMBO_IOCTL_BT_HOST_DEBUG _IOW(COMBO_IOC_MAGIC, 4, void*)
#define COMBO_IOCTL_BT_INTTRX _IOW(COMBO_IOC_MAGIC, 5, void*)
#define IOCTL_BT_HOST_DEBUG_BUF_SIZE (32)
#define IOCTL_BT_HOST_INTTRX_SIZE (128)
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
enum chip_reset_state {
CHIP_RESET_NONE,
CHIP_RESET_START,
CHIP_RESET_END,
CHIP_RESET_NOTIFIED
};
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static int32_t BT_devs = 1;
static int32_t BT_major = 192;
module_param(BT_major, uint, 0);
static struct cdev BT_cdev;
static struct class *BT_class;
static struct device *BT_dev;
static uint8_t i_buf[BT_BUFFER_SIZE]; /* Input buffer for read */
static uint8_t o_buf[BT_BUFFER_SIZE]; /* Output buffer for write */
static uint8_t ioc_buf[IOCTL_BT_HOST_INTTRX_SIZE];
extern struct btmtk_dev *g_sbdev;
extern bool g_bt_trace_pt;
extern struct btmtk_btif_dev g_btif_dev;
extern void bthost_debug_init(void);
extern void bthost_debug_save(uint32_t id, uint32_t value, char* desc);
static struct semaphore wr_mtx, rd_mtx;
static struct bt_wake_lock bt_wakelock;
/* Wait queue for poll and read */
static wait_queue_head_t inq;
static DECLARE_WAIT_QUEUE_HEAD(BT_wq);
static int32_t flag;
static int32_t bt_ftrace_flag;
/*
* Reset flag for whole chip reset scenario, to indicate reset status:
* 0 - normal, no whole chip reset occurs
* 1 - reset start
* 2 - reset end, have not sent Hardware Error event yet
* 3 - reset end, already sent Hardware Error event
*/
static uint32_t rstflag = CHIP_RESET_NONE;
static uint8_t HCI_EVT_HW_ERROR[] = {0x04, 0x10, 0x01, 0x00};
static loff_t rd_offset;
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
static int32_t ftrace_print(const uint8_t *str, ...)
{
#ifdef CONFIG_TRACING
va_list args;
uint8_t temp_string[FTRACE_STR_LOG_SIZE];
if (bt_ftrace_flag) {
va_start(args, str);
if (vsnprintf(temp_string, FTRACE_STR_LOG_SIZE, str, args) < 0)
BTMTK_INFO("%s: vsnprintf error", __func__);
va_end(args);
trace_printk("%s\n", temp_string);
}
#endif
return 0;
}
static size_t bt_report_hw_error(uint8_t *buf, size_t count, loff_t *f_pos)
{
size_t bytes_rest, bytes_read;
if (*f_pos == 0)
BTMTK_INFO("Send Hardware Error event to stack to restart Bluetooth");
bytes_rest = sizeof(HCI_EVT_HW_ERROR) - *f_pos;
bytes_read = count < bytes_rest ? count : bytes_rest;
memcpy(buf, HCI_EVT_HW_ERROR + *f_pos, bytes_read);
*f_pos += bytes_read;
return bytes_read;
}
static void bt_state_cb(u_int8_t state)
{
switch (state) {
case FUNC_ON:
rstflag = CHIP_RESET_NONE;
break;
case RESET_START:
rstflag = CHIP_RESET_START;
break;
case FUNC_OFF:
if (rstflag != CHIP_RESET_START) {
rstflag = CHIP_RESET_NONE;
break;
}
case RESET_END:
rstflag = CHIP_RESET_END;
rd_offset = 0;
flag = 1;
wake_up_interruptible(&inq);
wake_up(&BT_wq);
break;
default:
break;
}
return;
}
static void BT_event_cb(void)
{
ftrace_print("%s get called", __func__);
/*
* Hold wakelock for 100ms to avoid system enter suspend in such case:
* FW has sent data to host, STP driver received the data and put it
* into BT rx queue, then send sleep command and release wakelock as
* quick sleep mechanism for low power, BT driver will wake up stack
* hci thread stuck in poll or read.
* But before hci thread comes to read data, system enter suspend,
* hci command timeout timer keeps counting during suspend period till
* expires, then the RTC interrupt wakes up system, command timeout
* handler is executed and meanwhile the event is received.
* This will false trigger FW assert and should never happen.
*/
bt_hold_wake_lock_timeout(&bt_wakelock, 100);
/*
* Finally, wake up any reader blocked in poll or read
*/
flag = 1;
wake_up_interruptible(&inq);
wake_up(&BT_wq);
ftrace_print("%s wake_up triggered", __func__);
}
static unsigned int BT_poll(struct file *filp, poll_table *wait)
{
uint32_t mask = 0;
//bt_dbg_tp_evt(TP_ACT_POLL, 0, 0, NULL);
if ((!btmtk_rx_data_valid() && rstflag == CHIP_RESET_NONE) ||
(rstflag == CHIP_RESET_START) || (rstflag == CHIP_RESET_NOTIFIED)) {
/*
* BT RX queue is empty, or whole chip reset start, or already sent Hardware Error event
* for whole chip reset end, add to wait queue.
*/
poll_wait(filp, &inq, wait);
/*
* Check if condition changes before poll_wait return, in case of
* wake_up_interruptible is called before add_wait_queue, otherwise,
* do_poll will get into sleep and never be waken up until timeout.
*/
if (!((!btmtk_rx_data_valid() && rstflag == CHIP_RESET_NONE) ||
(rstflag == CHIP_RESET_START) || (rstflag == CHIP_RESET_NOTIFIED)))
mask |= POLLIN | POLLRDNORM; /* Readable */
} else {
/* BT RX queue has valid data, or whole chip reset end, have not sent Hardware Error event yet */
mask |= POLLIN | POLLRDNORM; /* Readable */
}
/* Do we need condition here? */
mask |= POLLOUT | POLLWRNORM; /* Writable */
ftrace_print("%s: return mask = 0x%04x", __func__, mask);
return mask;
}
static ssize_t __bt_write(uint8_t *buf, size_t count, uint32_t flags)
{
int32_t retval = 0;
if (g_bt_trace_pt)
bt_dbg_tp_evt(TP_ACT_WR_IN, 0, count, buf);
retval = btmtk_send_data(g_sbdev->hdev, buf, count);
if (retval < 0)
BTMTK_ERR("bt_core_send_data failed, retval %d", retval);
else if (retval == 0) {
/*
* TX queue cannot be digested in time and no space is available for write.
*
* If nonblocking mode, return -EAGAIN to let user retry,
* native program should not call write with no delay.
*/
if (flags & O_NONBLOCK) {
BTMTK_WARN("Non-blocking write, no space is available!");
retval = -EAGAIN;
} else {
/*TODO: blocking write case */
}
} else
BTMTK_DBG("Write bytes %d/%zd", retval, count);
return retval;
}
static ssize_t BT_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
ssize_t retval = 0;
size_t count = iov_iter_count(from);
ftrace_print("%s get called, count %zd", __func__, count);
down(&wr_mtx);
BTMTK_DBG("count %zd", count);
if (rstflag != CHIP_RESET_NONE) {
BTMTK_ERR("whole chip reset occurs! rstflag=%d", rstflag);
retval = -EIO;
goto OUT;
}
if (count > 0) {
if (count > BT_BUFFER_SIZE) {
BTMTK_WARN("Shorten write count from %zd to %d", count, BT_BUFFER_SIZE);
count = BT_BUFFER_SIZE;
}
if (copy_from_iter(o_buf, count, from) != count) {
retval = -EFAULT;
goto OUT;
}
retval = __bt_write(o_buf, count, iocb->ki_filp->f_flags);
}
OUT:
up(&wr_mtx);
return retval;
}
static ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t retval = 0;
ftrace_print("%s get called, count %zd", __func__, count);
down(&wr_mtx);
BTMTK_DBG("count %zd pos %lld", count, *f_pos);
if (rstflag != CHIP_RESET_NONE) {
BTMTK_ERR("whole chip reset occurs! rstflag=%d", rstflag);
retval = -EIO;
goto OUT;
}
if (count > 0) {
if (count > BT_BUFFER_SIZE) {
BTMTK_WARN("Shorten write count from %zd to %d", count, BT_BUFFER_SIZE);
count = BT_BUFFER_SIZE;
}
if (copy_from_user(o_buf, buf, count)) {
retval = -EFAULT;
goto OUT;
}
retval = __bt_write(o_buf, count, filp->f_flags);
}
OUT:
up(&wr_mtx);
return retval;
}
static ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t retval = 0;
if (g_bt_trace_pt)
bt_dbg_tp_evt(TP_ACT_RD_IN, 0, count, NULL);
ftrace_print("%s get called, count %zd", __func__, count);
down(&rd_mtx);
BTMTK_DBG("%s: count %zd pos %lld", __func__, count, *f_pos);
if (rstflag != CHIP_RESET_NONE) {
while (rstflag != CHIP_RESET_END && rstflag != CHIP_RESET_NONE) {
/*
* If nonblocking mode, return -EIO directly.
* O_NONBLOCK is specified during open().
*/
if (filp->f_flags & O_NONBLOCK) {
BTMTK_ERR("Non-blocking read, whole chip reset occurs! rstflag=%d", rstflag);
retval = -EIO;
goto OUT;
}
wait_event(BT_wq, flag != 0);
flag = 0;
}
/*
* Reset end, send Hardware Error event to stack only once.
* To avoid high frequency read from stack before process is killed, set rstflag to 3
* to block poll and read after Hardware Error event is sent.
*/
retval = bt_report_hw_error(i_buf, count, &rd_offset);
if (rd_offset == sizeof(HCI_EVT_HW_ERROR)) {
rd_offset = 0;
rstflag = CHIP_RESET_NOTIFIED;
}
if (copy_to_user(buf, i_buf, retval)) {
retval = -EFAULT;
if (rstflag == CHIP_RESET_NOTIFIED)
rstflag = CHIP_RESET_END;
}
goto OUT;
}
if (count > BT_BUFFER_SIZE) {
BTMTK_WARN("Shorten read count from %zd to %d", count, BT_BUFFER_SIZE);
count = BT_BUFFER_SIZE;
}
do {
retval = btmtk_receive_data(g_sbdev->hdev, i_buf, count);
if (retval < 0) {
BTMTK_ERR("bt_core_receive_data failed, retval %d", retval);
goto OUT;
} else if (retval == 0) { /* Got nothing, wait for RX queue's signal */
/*
* If nonblocking mode, return -EAGAIN to let user retry.
* O_NONBLOCK is specified during open().
*/
if (filp->f_flags & O_NONBLOCK) {
BTMTK_ERR("Non-blocking read, no data is available!");
retval = -EAGAIN;
goto OUT;
}
wait_event(BT_wq, flag != 0);
flag = 0;
} else { /* Got something from RX queue */
if (g_bt_trace_pt)
bt_dbg_tp_evt(TP_ACT_RD_OUT, 0, retval, i_buf);
break;
}
} while (btmtk_rx_data_valid() && rstflag == CHIP_RESET_NONE);
if (retval == 0) {
if (rstflag != CHIP_RESET_END) { /* Should never happen */
WARN(1, "Blocking read is waken up in unexpected case, rstflag=%d", rstflag);
retval = -EIO;
goto OUT;
} else { /* Reset end, send Hardware Error event only once */
retval = bt_report_hw_error(i_buf, count, &rd_offset);
if (rd_offset == sizeof(HCI_EVT_HW_ERROR)) {
rd_offset = 0;
rstflag = CHIP_RESET_NOTIFIED;
}
}
}
if (copy_to_user(buf, i_buf, retval)) {
retval = -EFAULT;
if (rstflag == CHIP_RESET_NOTIFIED)
rstflag = CHIP_RESET_END;
}
OUT:
up(&rd_mtx);
return retval;
}
int _ioctl_copy_evt_to_buf(uint8_t *buf, int len)
{
BTMTK_INFO("%s", __func__);
memset(ioc_buf, 0x00, sizeof(ioc_buf));
ioc_buf[0] = 0x04; // evt packet type
memcpy(ioc_buf + 1, buf, len); // copy evt to ioctl buffer
BTMTK_INFO_RAW(ioc_buf, len + 1, "%s: len[%d] RX: ", __func__, len + 1);
return 0;
}
static long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int32_t retval = 0;
BTMTK_INFO("%s: cmd[0x%08x]", __func__, cmd);
memset(ioc_buf, 0x00, sizeof(ioc_buf));
switch (cmd) {
case COMBO_IOCTL_BT_HOST_DEBUG:
/* input: arg(buf_size = 32): id[0:3], value[4:7], desc[8:31]
output: none
*/
if (copy_from_user(ioc_buf, (uint8_t __user*)arg, IOCTL_BT_HOST_DEBUG_BUF_SIZE))
retval = -EFAULT;
else {
uint32_t* pint32 = (uint32_t*)&ioc_buf[0];
BTMTK_INFO("%s: id[%x], value[0x%08x], desc[%s]", __func__, pint32[0], pint32[1], &ioc_buf[8]);
bthost_debug_save(pint32[0], pint32[1], (char*)&ioc_buf[8]);
}
break;
case COMBO_IOCTL_BT_INTTRX:
/* input: arg(buf_size = 128): hci cmd raw data
output: arg(buf_size = 128): hci evt raw data
*/
if (copy_from_user(ioc_buf, (uint8_t __user*)arg, IOCTL_BT_HOST_INTTRX_SIZE))
retval = -EFAULT;
else {
BTMTK_INFO_RAW(ioc_buf, ioc_buf[3] + 4, "%s: len[%d] TX: ", __func__, ioc_buf[3] + 4);
/* DynamicAdjustTxPower function */
if (ioc_buf[0] == 0x01 && ioc_buf[1] == 0x2D && ioc_buf[2] == 0xFC) {
if (btmtk_inttrx_DynamicAdjustTxPower(ioc_buf[4], ioc_buf[5], _ioctl_copy_evt_to_buf, TRUE) == 0) {
if (copy_to_user((uint8_t __user*)arg, ioc_buf, IOCTL_BT_HOST_INTTRX_SIZE))
retval = -EFAULT;
}
} else
retval = -EFAULT;
}
break;
default:
break;
}
return retval;
}
static long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
return BT_unlocked_ioctl(filp, cmd, arg);
}
static int BT_open(struct inode *inode, struct file *file)
{
int32_t ret;
bt_hold_wake_lock(&bt_wakelock);
BTMTK_INFO("major %d minor %d (pid %d)", imajor(inode), iminor(inode), current->pid);
/* Turn on BT */
ret = g_sbdev->hdev->open(g_sbdev->hdev);
if (ret) {
BTMTK_ERR("BT turn on fail!");
bt_release_wake_lock(&bt_wakelock);
return ret;
}
BTMTK_INFO("BT turn on OK!");
btmtk_register_rx_event_cb(g_sbdev->hdev, BT_event_cb);
bt_ftrace_flag = 1;
bt_release_wake_lock(&bt_wakelock);
bthost_debug_init();
return 0;
}
static int BT_close(struct inode *inode, struct file *file)
{
int32_t ret;
bt_hold_wake_lock(&bt_wakelock);
BTMTK_INFO("major %d minor %d (pid %d)", imajor(inode), iminor(inode), current->pid);
bt_ftrace_flag = 0;
//bt_core_unregister_rx_event_cb();
ret = g_sbdev->hdev->close(g_sbdev->hdev);
bt_release_wake_lock(&bt_wakelock);
bthost_debug_init();
if (ret) {
BTMTK_ERR("BT turn off fail!");
return ret;
}
BTMTK_INFO("BT turn off OK!");
return 0;
}
const struct file_operations BT_fops = {
.open = BT_open,
.release = BT_close,
.read = BT_read,
.write = BT_write,
.write_iter = BT_write_iter,
/* .ioctl = BT_ioctl, */
.unlocked_ioctl = BT_unlocked_ioctl,
.compat_ioctl = BT_compat_ioctl,
.poll = BT_poll
};
int BT_init(void)
{
int32_t alloc_err = 0;
int32_t cdv_err = 0;
dev_t dev = MKDEV(BT_major, 0);
sema_init(&wr_mtx, 1);
sema_init(&rd_mtx, 1);
init_waitqueue_head(&inq);
/* Initialize wake lock for I/O operation */
strncpy(bt_wakelock.name, "bt_drv_io", 9);
bt_wakelock.name[9] = 0;
bt_wake_lock_init(&bt_wakelock);
g_btif_dev.state_change_cb[0] = fw_log_bt_state_cb;
g_btif_dev.state_change_cb[1] = bt_state_cb;
/* Allocate char device */
alloc_err = register_chrdev_region(dev, BT_devs, BT_DRIVER_NAME);
if (alloc_err) {
BTMTK_ERR("Failed to register device numbers");
goto alloc_error;
}
cdev_init(&BT_cdev, &BT_fops);
BT_cdev.owner = THIS_MODULE;
cdv_err = cdev_add(&BT_cdev, dev, BT_devs);
if (cdv_err)
goto cdv_error;
BT_class = class_create(THIS_MODULE, BT_DRIVER_NODE_NAME);
if (IS_ERR(BT_class))
goto create_node_error;
BT_dev = device_create(BT_class, NULL, dev, NULL, BT_DRIVER_NODE_NAME);
if (IS_ERR(BT_dev))
goto create_node_error;
BTMTK_INFO("%s driver(major %d) installed", BT_DRIVER_NAME, BT_major);
return 0;
create_node_error:
if (BT_class && !IS_ERR(BT_class)) {
class_destroy(BT_class);
BT_class = NULL;
}
cdev_del(&BT_cdev);
cdv_error:
unregister_chrdev_region(dev, BT_devs);
alloc_error:
main_driver_exit();
return -1;
}
void BT_exit(void)
{
dev_t dev = MKDEV(BT_major, 0);
if (BT_dev && !IS_ERR(BT_dev)) {
device_destroy(BT_class, dev);
BT_dev = NULL;
}
if (BT_class && !IS_ERR(BT_class)) {
class_destroy(BT_class);
BT_class = NULL;
}
cdev_del(&BT_cdev);
unregister_chrdev_region(dev, BT_devs);
g_btif_dev.state_change_cb[0] = NULL;
g_btif_dev.state_change_cb[1] = NULL;
/* Destroy wake lock */
bt_wake_lock_deinit(&bt_wakelock);
BTMTK_INFO("%s driver removed", BT_DRIVER_NAME);
}
#else
int BT_init(void) {
BTMTK_INFO("%s: not device node, return", __func__);
return 0;
}
void BT_exit(void) {
BTMTK_INFO("%s: not device node, return", __func__);
return;
}
#endif // USE_DEVICE_NODE
#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
/* build-in mode */
int mtk_wcn_stpbt_drv_init(void)
{
return main_driver_init();
}
EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init);
void mtk_wcn_stpbt_drv_exit(void)
{
return main_driver_exit();
}
EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit);
#endif

View file

@ -0,0 +1,901 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/kthread.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "btmtk_define.h"
#include "btmtk_chip_if.h"
#include "btmtk_main.h"
#include "conninfra.h"
#include "connsys_debug_utility.h"
#include "metlog.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
#define BT_DBG_PROCNAME "driver/bt_dbg"
#define BUF_LEN_MAX 384
#define BT_DBG_DUMP_BUF_SIZE 1024
#define BT_DBG_PASSWD "4w2T8M65K5?2af+a "
#define BT_DBG_USER_TRX_PREFIX "[user-trx] "
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
typedef int(*BT_DEV_DBG_FUNC) (int par1, int par2, int par3);
typedef struct {
BT_DEV_DBG_FUNC func;
bool turn_off_availavle; // function can be work when bt off
} tBT_DEV_DBG_STRUCT;
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
bool g_bt_trace_pt = FALSE;
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
static ssize_t bt_dbg_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
static ssize_t bt_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
static int bt_dbg_hwver_get(int par1, int par2, int par3);
static int bt_dbg_chip_rst(int par1, int par2, int par3);
static int bt_dbg_read_chipid(int par1, int par2, int par3);
static int bt_dbg_force_bt_wakeup(int par1, int par2, int par3);
static int bt_dbg_get_fwp_datetime(int par1, int par2, int par3);
static int bt_dbg_get_bt_patch_path(int par1, int par2, int par3);
extern int fwp_if_get_datetime(char *buf, int max_len);
extern int fwp_if_get_bt_patch_path(char *buf, int max_len);
#if (CUSTOMER_FW_UPDATE == 1)
static int bt_dbg_set_fwp_update_enable(int par1, int par2, int par3);
static int bt_dbg_get_fwp_update_info(int par1, int par2, int par3);
extern void fwp_if_set_update_enable(int par);
extern int fwp_if_get_update_info(char *buf, int max_len);
#endif
static int bt_dbg_reg_read(int par1, int par2, int par3);
static int bt_dbg_reg_write(int par1, int par2, int par3);
static int bt_dbg_ap_reg_read(int par1, int par2, int par3);
static int bt_dbg_ap_reg_write(int par1, int par2, int par3);
static int bt_dbg_setlog_level(int par1, int par2, int par3);
static int bt_dbg_set_rt_thread(int par1, int par2, int par3);
static int bt_dbg_get_bt_state(int par1, int par2, int par3);
static int bt_dbg_rx_buf_control(int par1, int par2, int par3);
static int bt_dbg_set_rt_thread_runtime(int par1, int par2, int par3);
static int bt_dbg_fpga_test(int par1, int par2, int par3);
static int bt_dbg_is_adie_work(int par1, int par2, int par3);
static int bt_dbg_met_start_stop(int par1, int par2, int par3);
static int bt_dbg_DynamicAdjustTxPower(int par1, int par2, int par3);
static void bt_dbg_user_trx_proc(char *cmd_raw);
static int bt_dbg_user_trx_cb(uint8_t *buf, int len);
static int bt_dbg_trace_pt(int par1, int par2, int par3);
extern int32_t btmtk_set_wakeup(struct hci_dev *hdev, uint8_t need_wait);
extern int32_t btmtk_set_sleep(struct hci_dev *hdev, u_int8_t need_wait);
extern void bt_trigger_reset(void);
extern int32_t btmtk_set_power_on(struct hci_dev*, u_int8_t for_precal);
extern int32_t btmtk_set_power_off(struct hci_dev*, u_int8_t for_precal);
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
extern struct btmtk_dev *g_sbdev;
extern struct bt_dbg_st g_bt_dbg_st;
static struct proc_dir_entry *g_bt_dbg_entry;
static struct mutex g_bt_lock;
static char g_bt_dump_buf[BT_DBG_DUMP_BUF_SIZE];
static char *g_bt_dump_buf_ptr;
static int g_bt_dump_buf_len;
static bool g_bt_dbg_enable = FALSE;
static const tBT_DEV_DBG_STRUCT bt_dev_dbg_struct[] = {
[0x0] = {bt_dbg_hwver_get, FALSE},
[0x1] = {bt_dbg_chip_rst, FALSE},
[0x2] = {bt_dbg_read_chipid, FALSE},
[0x3] = {bt_dbg_force_bt_wakeup, FALSE},
[0x4] = {bt_dbg_reg_read, FALSE},
[0x5] = {bt_dbg_reg_write, FALSE},
[0x6] = {bt_dbg_get_fwp_datetime, TRUE},
#if (CUSTOMER_FW_UPDATE == 1)
[0x7] = {bt_dbg_set_fwp_update_enable, TRUE},
[0x8] = {bt_dbg_get_fwp_update_info, FALSE},
#endif
[0x9] = {bt_dbg_ap_reg_read, FALSE},
[0xa] = {bt_dbg_ap_reg_write, TRUE},
[0xb] = {bt_dbg_setlog_level, TRUE},
[0xc] = {bt_dbg_get_bt_patch_path, TRUE},
[0xd] = {bt_dbg_set_rt_thread, TRUE},
[0xe] = {bt_dbg_get_bt_state, TRUE},
[0xf] = {bt_dbg_rx_buf_control, TRUE},
[0x10] = {bt_dbg_set_rt_thread_runtime, FALSE},
[0x11] = {bt_dbg_fpga_test, TRUE},
[0x12] = {bt_dbg_is_adie_work, TRUE},
[0x13] = {bt_dbg_met_start_stop, FALSE},
[0x14] = {bt_dbg_DynamicAdjustTxPower, FALSE},
[0x15] = {bt_dbg_trace_pt, FALSE},
};
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
void _bt_dbg_reset_dump_buf(void)
{
memset(g_bt_dump_buf, '\0', BT_DBG_DUMP_BUF_SIZE);
g_bt_dump_buf_ptr = g_bt_dump_buf;
g_bt_dump_buf_len = 0;
}
int bt_dbg_hwver_get(int par1, int par2, int par3)
{
BTMTK_INFO("query chip version");
/* TODO: */
return 0;
}
int bt_dbg_chip_rst(int par1, int par2, int par3)
{
if(par2 == 0)
bt_trigger_reset();
else
conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_BT, "bt_dbg");
return 0;
}
int bt_dbg_trace_pt(int par1, int par2, int par3)
{
if(par2 == 0)
g_bt_trace_pt = FALSE;
else
g_bt_trace_pt = TRUE;
return 0;
}
int bt_dbg_read_chipid(int par1, int par2, int par3)
{
return 0;
}
/* Read BGF SYS address (controller view) by 0x18001104 & 0x18900000 */
int bt_dbg_reg_read(int par1, int par2, int par3)
{
uint32_t *dynamic_remap_addr = NULL;
uint32_t *dynamic_remap_value = NULL;
/* TODO: */
dynamic_remap_addr = ioremap(0x18001104, 4);
if (dynamic_remap_addr) {
*dynamic_remap_addr = par2;
BTMTK_DBG("read address = [0x%08x]", par2);
} else {
BTMTK_ERR("ioremap 0x18001104 fail");
return -1;
}
iounmap(dynamic_remap_addr);
dynamic_remap_value = ioremap(0x18900000, 4);
if (dynamic_remap_value)
BTMTK_INFO("%s: 0x%08x value = [0x%08x]", __func__, par2,
*dynamic_remap_value);
else {
BTMTK_ERR("ioremap 0x18900000 fail");
return -1;
}
iounmap(dynamic_remap_value);
return 0;
}
/* Write BGF SYS address (controller view) by 0x18001104 & 0x18900000 */
int bt_dbg_reg_write(int par1, int par2, int par3)
{
uint32_t *dynamic_remap_addr = NULL;
uint32_t *dynamic_remap_value = NULL;
/* TODO: */
dynamic_remap_addr = ioremap(0x18001104, 4);
if (dynamic_remap_addr) {
*dynamic_remap_addr = par2;
BTMTK_DBG("write address = [0x%08x]", par2);
} else {
BTMTK_ERR("ioremap 0x18001104 fail");
return -1;
}
iounmap(dynamic_remap_addr);
dynamic_remap_value = ioremap(0x18900000, 4);
if (dynamic_remap_value)
*dynamic_remap_value = par3;
else {
BTMTK_ERR("ioremap 0x18900000 fail");
return -1;
}
iounmap(dynamic_remap_value);
return 0;
}
int bt_dbg_ap_reg_read(int par1, int par2, int par3)
{
uint32_t *remap_addr = NULL;
int ret_val = 0;
/* TODO: */
remap_addr = ioremap(par2, 4);
if (!remap_addr) {
BTMTK_ERR("ioremap [0x%08x] fail", par2);
return -1;
}
ret_val = *remap_addr;
BTMTK_INFO("%s: 0x%08x read value = [0x%08x]", __func__, par2, ret_val);
iounmap(remap_addr);
return ret_val;
}
int bt_dbg_ap_reg_write(int par1, int par2, int par3)
{
uint32_t *remap_addr = NULL;
/* TODO: */
remap_addr = ioremap(par2, 4);
if (!remap_addr) {
BTMTK_ERR("ioremap [0x%08x] fail", par2);
return -1;
}
*remap_addr = par3;
BTMTK_INFO("%s: 0x%08x write value = [0x%08x]", __func__, par2, par3);
iounmap(remap_addr);
return 0;
}
int bt_dbg_setlog_level(int par1, int par2, int par3)
{
if (par2 < BTMTK_LOG_LVL_ERR || par2 > BTMTK_LOG_LVL_DBG) {
btmtk_log_lvl = BTMTK_LOG_LVL_INFO;
} else {
btmtk_log_lvl = par2;
}
return 0;
}
int bt_dbg_set_rt_thread(int par1, int par2, int par3)
{
g_bt_dbg_st.rt_thd_enable = par2;
return 0;
}
int bt_dbg_set_rt_thread_runtime(int par1, int par2, int par3)
{
struct sched_param params;
int policy = 0;
int ret = 0;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
/* reference parameter:
- normal: 0x10 0x01(SCHED_FIFO) 0x01
- rt_thd: 0x10 0x01(SCHED_FIFO) 0x50(MAX_RT_PRIO - 20)
*/
if (par2 > SCHED_DEADLINE || par3 > MAX_RT_PRIO) {
BTMTK_INFO("%s: parameter not allow!", __func__);
return 0;
}
policy = par2;
params.sched_priority = par3;
ret = sched_setscheduler(cif_dev->tx_thread, policy, &params);
BTMTK_INFO("%s: ret[%d], policy[%d], sched_priority[%d]", __func__, ret, policy, params.sched_priority);
return 0;
}
int bt_dbg_fpga_test(int par1, int par2, int par3)
{
/* reference parameter:
- 0x12 0x01(power on) 0x00
- 0x12 0x02(power off) 0x00
*/
BTMTK_INFO("%s: par2 = %d", __func__, par2);
switch (par2) {
case 1:
btmtk_set_power_on(g_sbdev->hdev, FALSE);
break;
case 2:
btmtk_set_power_off(g_sbdev->hdev, FALSE);
break;
default:
break;
}
BTMTK_INFO("%s: done", __func__);
return 0;
}
int bt_dbg_is_adie_work(int par1, int par2, int par3)
{
int ret = 0, adie_state = 0;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
if (cif_dev->bt_state == FUNC_ON) {
adie_state = 0; // power on a-die pass
goto end;
}
ret = conninfra_pwr_on(CONNDRV_TYPE_BT);
//if ((ret == CONNINFRA_POWER_ON_A_DIE_FAIL) || (ret == CONNINFRA_POWER_ON_D_DIE_FAIL))
if (ret != 0)
adie_state = 1; // power on a-die fail, may be evb without DTB
else {
adie_state = 0; // power on a-die pass
conninfra_pwr_off(CONNDRV_TYPE_BT);
}
end:
BTMTK_INFO("%s: ret[%d], adie_state[%d]", __func__, ret, adie_state);
_bt_dbg_reset_dump_buf();
g_bt_dump_buf[0] = (adie_state == 0 ? '0' : '1'); // '0': adie pass, '1': adie fail
g_bt_dump_buf[1] = '\0';
g_bt_dump_buf_len = 2;
return 0;
}
int bt_dbg_met_start_stop(int par1, int par2, int par3)
{
uint32_t val = 0, star_addr = 0, end_addr = 0;
int res = 0;
struct conn_metlog_info info;
phys_addr_t emi_base;
BTMTK_INFO("%s, par2 = %d", __func__, par2);
/* reference parameter:
- start: 0x11 0x01 0x00
- stop: 0x11 0x00 0x00
*/
if (par2 == 0x01) {
/*
// Set EMI Writing Range
bt_dbg_ap_reg_write(0, 0x1882140C, 0xF0027000); // BGF_ON_MET_START_ADDR
bt_dbg_ap_reg_write(0, 0x18821410, 0xF002EFFF); // BGF_ON_MET_END_ADDR
*/
// Set Ring Buffer Mode
val = bt_dbg_ap_reg_read(0, 0x18821404, 0);
bt_dbg_ap_reg_write(0, 0x18821404, val | 0x0001); // BGF_ON_MET_CTL1[0] = 0x01
// Set Sampling Rate
val = bt_dbg_ap_reg_read(0, 0x18821400, 0);
bt_dbg_ap_reg_write(0, 0x18821400, (val & 0xFFFF80FF) | 0x00001900); // BGF_ON_MET_CTL0[14:8] = 0x19
// Set Mask Signal
//bt_dbg_ap_reg_write(0, 0x18821400, (val & 0x0000FFFF) | 0x????0000); // BGF_ON_MET_CTL0[31:16] = ?
// Enable Connsys MET
val = bt_dbg_ap_reg_read(0, 0x18821400, 0);
bt_dbg_ap_reg_write(0, 0x18821400, (val & 0xFFFFFFFC) | 0x00000003); // BGF_ON_MET_CTL0[1:0] = 0x03
/* write parameters and start MET test */
conninfra_get_phy_addr(&emi_base, NULL);
info.type = CONNDRV_TYPE_BT;
info.read_cr = 0x18821418;
info.write_cr = 0x18821414;
// FW will write the star_addr & end_addr to cooresponding CRs when bt on
star_addr = bt_dbg_ap_reg_read(0, 0x1882140C, 0);
end_addr = bt_dbg_ap_reg_read(0, 0x18821410, 0);
BTMTK_INFO("%s: star_addr[0x%08x], end_addr[0x%08x]", __func__, star_addr, end_addr);
if (star_addr >= 0x00400000 && star_addr <= 0x0041FFFF) {
// met data on sysram
info.met_base_ap = 0x18440000 + star_addr;
info.met_base_fw = star_addr;
} else if (star_addr >= 0xF0000000 && star_addr <= 0xF3FFFFFF){
// met data on emi
info.met_base_ap = emi_base + MET_EMI_ADDR;
info.met_base_fw = 0xF0000000 + MET_EMI_ADDR;
} else {
// error case
BTMTK_ERR("%s: get unexpected met address!!", __func__);
return 0;
}
info.met_size = end_addr - star_addr + 1;
info.output_len = 32;
res = conn_metlog_start(&info);
BTMTK_INFO("%s: conn_metlog_start, result = %d", __func__, res);
} else {
// stop MET test
res = conn_metlog_stop(CONNDRV_TYPE_BT);
BTMTK_INFO("%s: conn_metlog_stop, result = %d", __func__, res);
// Disable Connsys MET
val = bt_dbg_ap_reg_read(0, 0x18821400, 0);
bt_dbg_ap_reg_write(0, 0x18821400, val & 0xFFFFFFFE); // BGF_ON_MET_CTL0[0] = 0x00
}
return 0;
}
int bt_dbg_DynamicAdjustTxPower_cb(uint8_t *buf, int len)
{
BTMTK_INFO("%s", __func__);
bt_dbg_user_trx_cb(buf, len);
return 0;
}
int bt_dbg_DynamicAdjustTxPower(int par1, int par2, int par3)
{
uint8_t mode = (uint8_t)par2;
int8_t set_val = (int8_t)par3;
/* reference parameter:
- query: 0x14 0x01(query) 0x00
- set: 0x14 0x02(set) 0x??(set_dbm_val)
*/
BTMTK_INFO("%s", __func__);
btmtk_inttrx_DynamicAdjustTxPower(mode, set_val, bt_dbg_DynamicAdjustTxPower_cb, TRUE);
return 0;
}
/*
sample code to use gpio
int bt_dbg_device_is_evb(int par1, int par2, int par3)
{
struct device_node *node = NULL;
int gpio_addr = 0, gpio_val = 0;
node = of_find_compatible_node(NULL, NULL, "mediatek,evb_gpio");
gpio_addr = of_get_named_gpio(node, "evb_gpio", 0);
if (gpio_addr > 0)
gpio_val = gpio_get_value(gpio_addr); // 0x00: phone, 0x01: evb
BTMTK_INFO("%s: gpio_addr[%d], gpio_val[%d]", __func__, gpio_addr, gpio_val);
_bt_dbg_reset_dump_buf();
g_bt_dump_buf[0] = (gpio_val == 0 ? '0' : '1'); // 0x00: phone, 0x01: evb
g_bt_dump_buf[1] = '\0';
g_bt_dump_buf_len = 2;
return 0;
}
dts setting
evb_gpio: evb_gpio@1100c000 {
compatible = "mediatek,evb_gpio";
evb_gpio = <&pio 57 0x0>;
};
*/
int bt_dbg_get_bt_state(int par1, int par2, int par3)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
bool bt_state = 0;
// 0x01: bt on, 0x00: bt off
bt_state = (cif_dev->bt_state == FUNC_ON ? 1 : 0);
BTMTK_INFO("%s: bt_state[%d]", __func__, bt_state);
_bt_dbg_reset_dump_buf();
g_bt_dump_buf[0] = bt_state;
g_bt_dump_buf[1] = '\0';
g_bt_dump_buf_len = 2;
return 0;
}
int bt_dbg_force_bt_wakeup(int par1, int par2, int par3)
{
int ret;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
BTMTK_INFO("%s", __func__);
switch(par2) {
case 0:
cif_dev->psm.force_on = FALSE;
ret = btmtk_set_sleep(g_sbdev->hdev, TRUE);
break;
case 1:
cif_dev->psm.force_on = TRUE;
ret = btmtk_set_wakeup(g_sbdev->hdev, TRUE);
break;
default:
BTMTK_ERR("Not support");
return -1;
}
BTMTK_INFO("bt %s %s", (par2 == 1) ? "wakeup" : "sleep",
(ret) ? "fail" : "success");
return 0;
}
int bt_dbg_get_fwp_datetime(int par1, int par2, int par3)
{
_bt_dbg_reset_dump_buf();
g_bt_dump_buf_len = fwp_if_get_datetime(g_bt_dump_buf, BT_DBG_DUMP_BUF_SIZE);
return 0;
}
int bt_dbg_get_bt_patch_path(int par1, int par2, int par3)
{
_bt_dbg_reset_dump_buf();
g_bt_dump_buf_len = fwp_if_get_bt_patch_path(g_bt_dump_buf, BT_DBG_DUMP_BUF_SIZE);
return 0;
}
#if (CUSTOMER_FW_UPDATE == 1)
int bt_dbg_set_fwp_update_enable(int par1, int par2, int par3)
{
fwp_if_set_update_enable(par2);
return 0;
}
int bt_dbg_get_fwp_update_info(int par1, int par2, int par3)
{
_bt_dbg_reset_dump_buf();
g_bt_dump_buf_len = fwp_if_get_update_info(g_bt_dump_buf, BT_DBG_DUMP_BUF_SIZE);
return 0;
}
#endif
int bt_dbg_rx_buf_control(int par1, int par2, int par3)
{
/*
0x00: disable
0x01: wait rx buffer available for max 200ms
*/
BTMTK_INFO("%s: rx_buf_ctrl[%d] set to [%d]", __func__, g_bt_dbg_st.rx_buf_ctrl, par2);
g_bt_dbg_st.rx_buf_ctrl = par2;
return 0;
}
ssize_t bt_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int ret = 0;
int dump_len;
BTMTK_INFO("%s: count[%zd]", __func__, count);
ret = mutex_lock_killable(&g_bt_lock);
if (ret) {
BTMTK_ERR("%s: dump_lock fail!!", __func__);
return ret;
}
if (g_bt_dump_buf_len == 0)
goto exit;
if (*f_pos == 0)
g_bt_dump_buf_ptr = g_bt_dump_buf;
dump_len = g_bt_dump_buf_len >= count ? count : g_bt_dump_buf_len;
ret = copy_to_user(buf, g_bt_dump_buf_ptr, dump_len);
if (ret) {
BTMTK_ERR("%s: copy to dump info buffer failed, ret:%d", __func__, ret);
ret = -EFAULT;
goto exit;
}
*f_pos += dump_len;
g_bt_dump_buf_len -= dump_len;
g_bt_dump_buf_ptr += dump_len;
BTMTK_INFO("%s: after read, wmt for dump info buffer len(%d)", __func__, g_bt_dump_buf_len);
ret = dump_len;
exit:
mutex_unlock(&g_bt_lock);
return ret;
}
int bt_osal_strtol(const char *str, unsigned int adecimal, long *res)
{
if (sizeof(long) == 4)
return kstrtou32(str, adecimal, (unsigned int *) res);
else
return kstrtol(str, adecimal, res);
}
int bt_dbg_user_trx_cb(uint8_t *buf, int len)
{
unsigned char *ptr = buf;
int i = 0;
_bt_dbg_reset_dump_buf();
// write event packet type
if (snprintf(g_bt_dump_buf, 6, "0x04 ") < 0) {
BTMTK_INFO("%s: snprintf error", __func__);
goto end;
}
for (i = 0; i < len; i++) {
if (snprintf(g_bt_dump_buf + 5*(i+1), 6, "0x%02X ", ptr[i]) < 0) {
BTMTK_INFO("%s: snprintf error", __func__);
goto end;
}
}
len++;
g_bt_dump_buf[5*len] = '\n';
g_bt_dump_buf[5*len + 1] = '\0';
g_bt_dump_buf_len = 5*len + 1;
end:
return 0;
}
void bt_dbg_user_trx_proc(char *cmd_raw)
{
#define LEN_64 64
unsigned char hci_cmd[LEN_64];
int len = 0;
long tmp = 0;
char *ptr = NULL, *pRaw = NULL;
// Parse command raw data
memset(hci_cmd, 0, sizeof(hci_cmd));
pRaw = cmd_raw;
ptr = cmd_raw;
while(*ptr != '\0' && pRaw != NULL) {
if (len > LEN_64 - 1) {
BTMTK_INFO("%s: skip since cmd length exceed!", __func__);
return;
}
ptr = strsep(&pRaw, " ");
if (ptr != NULL) {
bt_osal_strtol(ptr, 16, &tmp);
hci_cmd[len++] = (unsigned char)tmp;
}
}
// Send command and wait for command_complete event
btmtk_btif_internal_trx(hci_cmd, len, bt_dbg_user_trx_cb, TRUE, TRUE);
}
ssize_t bt_dbg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos)
{
bool is_passwd = FALSE, is_turn_on = FALSE;
size_t len = count;
char buf[256], *pBuf;
int x = 0, y = 0, z = 0;
long res = 0;
char* pToken = NULL;
char* pDelimiter = " \t";
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
bool bt_state = 0;
bt_state = (cif_dev->bt_state == FUNC_ON ? 1 : 0);
if (len <= 0 || len >= sizeof(buf)) {
BTMTK_ERR("%s: input handling fail!", __func__);
len = sizeof(buf) - 1;
return -1;
}
memset(buf, 0, sizeof(buf));
if (copy_from_user(buf, buffer, len))
return -EFAULT;
buf[len] = '\0';
BTMTK_INFO("%s: bt_state[%d], dbg_enable[%d], len[%d]",
__func__, bt_state, g_bt_dbg_enable, (int)len);
/* Check debug function is enabled or not
* - not enable yet: user should enable it
* - already enabled: user can disable it
*/
if (len > strlen(BT_DBG_PASSWD) &&
0 == memcmp(buf, BT_DBG_PASSWD, strlen(BT_DBG_PASSWD))) {
is_passwd = TRUE;
if (0 == memcmp(buf + strlen(BT_DBG_PASSWD), "ON", strlen("ON")))
is_turn_on = TRUE;
}
if(!g_bt_dbg_enable) {
if(is_passwd && is_turn_on)
g_bt_dbg_enable = TRUE;
return len;
} else {
if(is_passwd && !is_turn_on) {
g_bt_dbg_enable = FALSE;
return len;
}
}
/* Mode 1: User trx flow: send command, get response */
if (0 == memcmp(buf, BT_DBG_USER_TRX_PREFIX, strlen(BT_DBG_USER_TRX_PREFIX))) {
if(!bt_state) // only work when bt on
return len;
buf[len - 1] = '\0';
bt_dbg_user_trx_proc(buf + strlen(BT_DBG_USER_TRX_PREFIX));
return len;
}
/* Mode 2: Debug cmd flow, parse three parameters */
pBuf = buf;
pToken = strsep(&pBuf, pDelimiter);
if (pToken != NULL) {
bt_osal_strtol(pToken, 16, &res);
x = (int)res;
} else {
x = 0;
}
pToken = strsep(&pBuf, "\t\n ");
if (pToken != NULL) {
bt_osal_strtol(pToken, 16, &res);
y = (int)res;
BTMTK_INFO("%s: y = 0x%08x", __func__, y);
} else {
y = 3000;
/*efuse, register read write default value */
if (0x5 == x || 0x6 == x)
y = 0x80000000;
}
pToken = strsep(&pBuf, "\t\n ");
if (pToken != NULL) {
bt_osal_strtol(pToken, 16, &res);
z = (int)res;
} else {
z = 10;
/*efuse, register read write default value */
if (0x5 == x || 0x6 == x)
z = 0xffffffff;
}
BTMTK_INFO("%s: x(0x%08x), y(0x%08x), z(0x%08x)", __func__, x, y, z);
if (ARRAY_SIZE(bt_dev_dbg_struct) > x && NULL != bt_dev_dbg_struct[x].func) {
if(!bt_state && !bt_dev_dbg_struct[x].turn_off_availavle) {
BTMTK_WARN("%s: command id(0x%08x) only work when bt on!", __func__, x);
} else {
(*bt_dev_dbg_struct[x].func) (x, y, z);
}
} else {
BTMTK_WARN("%s: command id(0x%08x) no handler defined!", __func__, x);
}
return len;
}
int bt_dev_dbg_init(void)
{
int i_ret = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops bt_dbg_fops = {
.proc_read = bt_dbg_read,
.proc_write = bt_dbg_write,
};
#else
static const struct file_operations bt_dbg_fops = {
.owner = THIS_MODULE,
.read = bt_dbg_read,
.write = bt_dbg_write,
};
#endif
// initialize debug function struct
g_bt_dbg_st.rt_thd_enable = FALSE;
g_bt_dbg_st.rx_buf_ctrl = TRUE;
g_bt_dbg_entry = proc_create(BT_DBG_PROCNAME, 0664, NULL, &bt_dbg_fops);
if (g_bt_dbg_entry == NULL) {
BTMTK_ERR("Unable to create [%s] bt proc entry", BT_DBG_PROCNAME);
i_ret = -1;
}
mutex_init(&g_bt_lock);
return i_ret;
}
int bt_dev_dbg_deinit(void)
{
mutex_destroy(&g_bt_lock);
if (g_bt_dbg_entry != NULL) {
proc_remove(g_bt_dbg_entry);
g_bt_dbg_entry = NULL;
}
return 0;
}
/*******************************************************************************
* bt host debug information for low power
********************************************************************************
*/
#define BTHOST_INFO_MAX 16
#define BTHOST_DESC_LEN 16
struct bthost_info{
uint32_t id; //0 for not used
char desc[BTHOST_DESC_LEN];
uint32_t value;
};
struct bthost_info bthost_info_table[BTHOST_INFO_MAX];
void bthost_debug_init(void)
{
uint32_t i = 0;
for (i = 0; i < BTHOST_INFO_MAX; i++){
bthost_info_table[i].id = 0;
bthost_info_table[i].desc[0] = '\0';
bthost_info_table[i].value = 0;
}
}
void bthost_debug_print(void)
{
uint32_t i = 0;
int32_t ret = 0;
uint8_t *pos = NULL, *end = NULL;
uint8_t dump_buffer[700]={0};
pos = &dump_buffer[0];
end = pos + 700 - 1;
ret = snprintf(pos, (end - pos + 1), "[bt host info] ");
if (ret < 0 || ret >= (end - pos + 1)) {
BTMTK_ERR("snprintf [bt host info] fail");
} else {
pos += ret;
}
for (i = 0; i < BTHOST_INFO_MAX; i++){
if (bthost_info_table[i].id == 0){
ret = snprintf(pos, (end - pos + 1),"[%d-%d] not set", i, BTHOST_INFO_MAX);
if (ret < 0 || ret >= (end - pos + 1)){
BTMTK_ERR("%s: snprintf fail i[%d] ret[%d]", __func__, i, ret);
break;
}
pos += ret;
break;
}
else {
ret = snprintf(pos, (end - pos + 1),"[%d][%s : 0x%08x] ", i,
bthost_info_table[i].desc,
bthost_info_table[i].value);
if (ret < 0 || ret >= (end - pos + 1)){
BTMTK_ERR("%s: snprintf fail i[%d] ret[%d]", __func__, i, ret);
break;
}
pos += ret;
}
}
BTMTK_INFO("%s", dump_buffer);
}
void bthost_debug_save(uint32_t id, uint32_t value, char* desc)
{
uint32_t i = 0;
if (id == 0) {
BTMTK_WARN("%s: id (%d) must > 0\n", __func__, id);
return;
}
for (i = 0; i < BTHOST_INFO_MAX; i++){
// if the id is existed, save to the same column
if (bthost_info_table[i].id == id){
bthost_info_table[i].value = value;
return;
}
// save to the new column
if (bthost_info_table[i].id == 0){
bthost_info_table[i].id = id;
strncpy(bthost_info_table[i].desc, desc, BTHOST_DESC_LEN - 1);
bthost_info_table[i].value = value;
return;
}
}
BTMTK_WARN("%s: no space for %d\n", __func__, id);
}

View file

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define CREATE_TRACE_POINTS
#include "btmtk_dbg_tp_evt.h"
#include "btmtk_dbg_tp_evt_if.h"
void bt_dbg_tp_evt(unsigned int pkt_action,
unsigned int parameter,
unsigned int data_len,
char *data)
{
//struct timespec64 kerneltime;
//ktime_get_ts64(&kerneltime);
trace_bt_evt(pkt_action, parameter, data_len, data);
}

View file

@ -0,0 +1,445 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include "btmtk_chip_if.h"
#include "conninfra.h"
#include "connsys_debug_utility.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
unsigned long long irq_timer[12] = {0};
#endif
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
extern struct btmtk_dev *g_sbdev;
static struct bt_irq_ctrl bgf2ap_btif_wakeup_irq = {.name = "BTIF_WAKEUP_IRQ"};
static struct bt_irq_ctrl bgf2ap_sw_irq = {.name = "BGF_SW_IRQ"};
static struct bt_irq_ctrl bt_conn2ap_sw_irq = {.name = "BUS_SW_IRQ"};
static struct bt_irq_ctrl *bt_irq_table[BGF2AP_IRQ_MAX];
static struct work_struct rst_trigger_work;
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/* bt_reset_work
*
* A work thread that handles BT subsys reset request
*
* Arguments:
* [IN] work
*
* Return Value:
* N/A
*
*/
static void bt_reset_work(struct work_struct *work)
{
BTMTK_INFO("Trigger subsys reset");
bt_chip_reset_flow(RESET_LEVEL_0_5, CONNDRV_TYPE_BT, "BT Subsys reset");
}
/* bt_trigger_reset
*
* Trigger reset (could be subsys or whole chip reset)
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
*/
void bt_trigger_reset(void)
{
int32_t ret = conninfra_is_bus_hang();
BTMTK_INFO("%s: conninfra_is_bus_hang ret = %d", __func__, ret);
if (ret > 0)
conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_BT, "bus hang");
else if (ret == CONNINFRA_ERR_RST_ONGOING)
BTMTK_INFO("whole chip reset is onging, skip subsys reset");
else
schedule_work(&rst_trigger_work);
}
/* bt_bgf2ap_irq_handler
*
* Handling BGF2AP_SW_IRQ, include FW log & chip reset
* Please be noticed this handler is running in bt thread
* not interrupt thread
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
*/
void bt_bgf2ap_irq_handler(void)
{
int32_t bgf_status = 0, count = 5;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
cif_dev->bgf2ap_ind = FALSE;
/* wake up conn_infra off */
if(bgfsys_check_conninfra_ready())
return;
/* Read IRQ status CR to identify what happens */
bgf_status = bgfsys_get_sw_irq_status();
/* release conn_infra force on */
CLR_BIT(CONN_INFRA_WAKEUP_BT, BIT(0));
if (bgf_status == RET_SWIRQ_ST_FAIL)
return;
if (bgf_status && !(bgf_status & BGF_FW_LOG_NOTIFY)) {
BTMTK_INFO("bgf_status = 0x%08x", bgf_status);
}else{
BTMTK_DBG("bgf_status = 0x%08x", bgf_status);
}
if (bgf_status == 0xDEADFEED) {
bt_dump_bgfsys_all();
bt_enable_irq(BGF2AP_SW_IRQ);
} else if (bgf_status & BGF_SUBSYS_CHIP_RESET) {
if (cif_dev->rst_level != RESET_LEVEL_NONE)
complete(&cif_dev->rst_comp);
else
schedule_work(&rst_trigger_work);
} else if (bgf_status & BGF_FW_LOG_NOTIFY) {
/* FW notify host to get FW log */
connsys_log_irq_handler(CONN_DEBUG_TYPE_BT);
while(count--){};
bt_enable_irq(BGF2AP_SW_IRQ);
} else if (bgf_status & BGF_WHOLE_CHIP_RESET) {
conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_BT, "FW trigger");
} else {
bt_enable_irq(BGF2AP_SW_IRQ);
}
}
/* bt_conn2ap_irq_handler
*
* Handling BT_CONN2AP_SW_IRQ, include BGF bus hang. And dump SSPM TIMER
* Please be noticed this handler is running in bt thread
* not interrupt thread
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
*/
void bt_conn2ap_irq_handler(void)
{
uint32_t value = 0;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
cif_dev->bt_conn2ap_ind = FALSE;
value = bt_read_cr(BT_SSPM_TIMER);
BTMTK_INFO("%s: [SSPM] [0x%08x] = [0x%08x]", __func__, BT_SSPM_TIMER, value);
bt_trigger_reset();
}
/* btmtk_reset_init()
*
* Inint work thread for subsys chip reset
*
* Arguments:
* N/A
*
* Return Value:
* N/A
*
*/
void btmtk_reset_init(void)
{
INIT_WORK(&rst_trigger_work, bt_reset_work);
}
/* btmtk_irq_handler()
*
* IRQ handler, process following types IRQ
* BGF2AP_BTIF_WAKEUP_IRQ - this IRQ indicates that FW has data to transmit
* BGF2AP_SW_IRQ - this indicates that fw assert / fw log
*
* Arguments:
* [IN] irq - IRQ number
* [IN] arg -
*
* Return Value:
* returns IRQ_HANDLED for handled IRQ, IRQ_NONE otherwise
*
*/
static irqreturn_t btmtk_irq_handler(int irq, void * arg)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[0] = sched_clock();
#endif
if (irq == bgf2ap_btif_wakeup_irq.irq_num) {
if (cif_dev->rst_level == RESET_LEVEL_NONE) {
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[1] = sched_clock();
#endif
bt_disable_irq(BGF2AP_BTIF_WAKEUP_IRQ);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[7] = sched_clock();
#endif
cif_dev->rx_ind = TRUE;
cif_dev->psm.sleep_flag = FALSE;
wake_up_interruptible(&cif_dev->tx_waitq);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[10] = sched_clock();
if (irq_timer[10] - irq_timer[1] > 5000000){
BTMTK_ERR("btif: start1[%llu] b_dis2[%llu] in_dis3[%llu] b_lock4[%llu] a_lock5[%llu] b_unlock6[%llu] a_unlock7[%llu] a_dis8[%llu] end11[%llu]", irq_timer[0], irq_timer[1], irq_timer[2], irq_timer[3], irq_timer[4], irq_timer[5], irq_timer[6], irq_timer[7], irq_timer[10]);
}
#endif
}
return IRQ_HANDLED;
} else if (irq == bgf2ap_sw_irq.irq_num) {
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[8] = sched_clock();
#endif
bt_disable_irq(BGF2AP_SW_IRQ);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[9] = sched_clock();
#endif
cif_dev->bgf2ap_ind = TRUE;
wake_up_interruptible(&cif_dev->tx_waitq);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[11] = sched_clock();
if (irq_timer[11] - irq_timer[8] > 5000000){
BTMTK_ERR("sw: start1[%llu] b_dis9[%llu] in_dis3[%llu] b_lock4[%llu] a_lock5[%llu] b_unlock6[%llu] a_unlock7[%llu] a_dis10[%llu] end11[%llu]", irq_timer[0], irq_timer[8], irq_timer[2], irq_timer[3], irq_timer[4], irq_timer[5], irq_timer[6], irq_timer[9], irq_timer[11]);
}
#endif
return IRQ_HANDLED;
} else if (irq == bt_conn2ap_sw_irq.irq_num) {
bt_disable_irq(BT_CONN2AP_SW_IRQ);
cif_dev->bt_conn2ap_ind = TRUE;
wake_up_interruptible(&cif_dev->tx_waitq);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/* bt_request_irq()
*
* Request IRQ
*
* Arguments:
* [IN] irq_type - IRQ type
*
* Return Value:
* returns 0 for success, fail otherwise
*
*/
int32_t bt_request_irq(enum bt_irq_type irq_type)
{
uint32_t irq_num = 0;
int32_t ret = 0;
unsigned long irq_flags = 0;
struct bt_irq_ctrl *pirq = NULL;
struct device_node *node = NULL;
switch (irq_type) {
case BGF2AP_BTIF_WAKEUP_IRQ:
node = of_find_compatible_node(NULL, NULL, "mediatek,bt");
if (node) {
irq_num = irq_of_parse_and_map(node, 0);
BTMTK_DBG("irqNum of BGF2AP_BTIF_WAKEUP_IRQ = %d", irq_num);
}
else
BTMTK_ERR("WIFI-OF: get bt device node fail");
irq_flags = IRQF_TRIGGER_HIGH | IRQF_SHARED;
pirq = &bgf2ap_btif_wakeup_irq;
break;
case BGF2AP_SW_IRQ:
node = of_find_compatible_node(NULL, NULL, "mediatek,bt");
if (node) {
irq_num = irq_of_parse_and_map(node, 1);
BTMTK_DBG("irqNum of BGF2AP_SW_IRQ = %d", irq_num);
}
else
BTMTK_ERR("WIFI-OF: get bt device node fail");
irq_flags = IRQF_TRIGGER_HIGH | IRQF_SHARED;
pirq = &bgf2ap_sw_irq;
break;
case BT_CONN2AP_SW_IRQ:
node = of_find_compatible_node(NULL, NULL, "mediatek,bt");
if (node) {
irq_num = irq_of_parse_and_map(node, 2);
BTMTK_DBG("irqNum of BT_CONN2AP_SW_IRQ = %d", irq_num);
}
else
BTMTK_ERR("WIFI-OF: get bt device node fail");
irq_flags = IRQF_TRIGGER_HIGH | IRQF_SHARED;
pirq = &bt_conn2ap_sw_irq;
break;
default:
BTMTK_ERR("Invalid irq_type %d!", irq_type);
return -EINVAL;
}
pirq->irq_num = irq_num;
spin_lock_init(&pirq->lock);
pirq->active = TRUE;
ret = request_irq(irq_num, btmtk_irq_handler, irq_flags,
pirq->name, pirq);
if (ret) {
BTMTK_ERR("Request %s (%u) failed! ret(%d)", pirq->name, irq_num, ret);
pirq->active = FALSE;
return ret;
}
ret = enable_irq_wake(irq_num);
if (ret) {
BTMTK_ERR("enable_irq_wake %s (%u) failed! ret(%d)", pirq->name, irq_num, ret);
}
BTMTK_INFO("Request %s (%u) succeed, pirq = %p, flag = 0x%08x", pirq->name, irq_num, pirq, irq_flags);
bt_irq_table[irq_type] = pirq;
return 0;
}
/* bt_enable_irq()
*
* Enable IRQ
*
* Arguments:
* [IN] irq_type - IRQ type
*
* Return Value:
* N/A
*
*/
void bt_enable_irq(enum bt_irq_type irq_type)
{
struct bt_irq_ctrl *pirq;
if (irq_type >= BGF2AP_IRQ_MAX) {
BTMTK_ERR("Invalid irq_type %d!", irq_type);
return;
}
pirq = bt_irq_table[irq_type];
if (pirq) {
spin_lock_irqsave(&pirq->lock, pirq->flags);
if (!pirq->active) {
enable_irq(pirq->irq_num);
pirq->active = TRUE;
}
spin_unlock_irqrestore(&pirq->lock, pirq->flags);
}
}
/* bt_disable_irq()
*
* Disable IRQ
*
* Arguments:
* [IN] irq_type - IRQ type
*
* Return Value:
* N/A
*
*/
void bt_disable_irq(enum bt_irq_type irq_type)
{
struct bt_irq_ctrl *pirq;
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[2] = sched_clock();
#endif
if (irq_type >= BGF2AP_IRQ_MAX) {
BTMTK_ERR("Invalid irq_type %d!", irq_type);
return;
}
pirq = bt_irq_table[irq_type];
if (pirq) {
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[3] = sched_clock();
#endif
spin_lock_irqsave(&pirq->lock, pirq->flags);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[4] = sched_clock();
#endif
if (pirq->active) {
disable_irq_nosync(pirq->irq_num);
pirq->active = FALSE;
}
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[5] = sched_clock();
#endif
spin_unlock_irqrestore(&pirq->lock, pirq->flags);
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
irq_timer[6] = sched_clock();
#endif
}
}
/* bt_disable_irq()
*
* Release IRQ and de-register IRQ
*
* Arguments:
* [IN] irq_type - IRQ type
*
* Return Value:
* N/A
*
*/
void bt_free_irq(enum bt_irq_type irq_type)
{
struct bt_irq_ctrl *pirq;
if (irq_type >= BGF2AP_IRQ_MAX) {
BTMTK_ERR("Invalid irq_type %d!", irq_type);
return;
}
pirq = bt_irq_table[irq_type];
if (pirq) {
disable_irq_wake(pirq->irq_num);
free_irq(pirq->irq_num, pirq);
pirq->active = FALSE;
bt_irq_table[irq_type] = NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,585 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/rtc.h>
#include "btmtk_chip_if.h"
#include "btmtk_main.h"
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
struct workqueue_struct *workqueue_task;
struct delayed_work work;
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
extern struct btmtk_dev *g_sbdev;
extern struct bt_dbg_st g_bt_dbg_st;
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
#if (USE_DEVICE_NODE == 1)
uint8_t is_rx_queue_empty(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
spin_lock(&p_ring->lock);
if (p_ring->read_idx == p_ring->write_idx) {
spin_unlock(&p_ring->lock);
return TRUE;
} else {
spin_unlock(&p_ring->lock);
return FALSE;
}
}
static uint8_t is_rx_queue_res_available(uint32_t length)
{
uint32_t room_left;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
/*
* Get available space of RX Queue
*/
spin_lock(&p_ring->lock);
if (p_ring->read_idx <= p_ring->write_idx)
room_left = RING_BUFFER_SIZE - p_ring->write_idx + p_ring->read_idx - 1;
else
room_left = p_ring->read_idx - p_ring->write_idx - 1;
spin_unlock(&p_ring->lock);
if (room_left < length) {
BTMTK_WARN("RX queue room left (%u) < required (%u)", room_left, length);
return FALSE;
}
return TRUE;
}
static int32_t rx_pkt_enqueue(uint8_t *buffer, uint32_t length)
{
uint32_t tail_len;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
if (length > HCI_MAX_FRAME_SIZE) {
BTMTK_ERR("Abnormal packet length %u, not enqueue!", length);
return -EINVAL;
}
spin_lock(&p_ring->lock);
if (p_ring->write_idx + length < RING_BUFFER_SIZE) {
memcpy(p_ring->buf + p_ring->write_idx, buffer, length);
p_ring->write_idx += length;
} else {
tail_len = RING_BUFFER_SIZE - p_ring->write_idx;
memcpy(p_ring->buf + p_ring->write_idx, buffer, tail_len);
memcpy(p_ring->buf, buffer + tail_len, length - tail_len);
p_ring->write_idx = length - tail_len;
}
spin_unlock(&p_ring->lock);
return 0;
}
int32_t rx_skb_enqueue(struct sk_buff *skb)
{
#define WAIT_TIMES 40
int8_t i = 0;
int32_t ret = 0;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
if ( !skb || skb->len == 0) {
BTMTK_WARN("Inavlid data event, skip, skb = NULL or skb len = 0");
ret = -1;
goto end;
}
/* FW will block the data if it's buffer is full,
driver can wait a interval for native process to read out */
if(g_bt_dbg_st.rx_buf_ctrl == TRUE) {
for(i = 0; i < WAIT_TIMES; i++) {
if (!is_rx_queue_res_available(skb->len + 1)) {
usleep_range(USLEEP_5MS_L, USLEEP_5MS_H);
} else
break;
}
}
if (!is_rx_queue_res_available(skb->len + 1)) {
BTMTK_WARN("rx packet drop!!!");
ret = -1;
goto end;
}
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
ret = rx_pkt_enqueue(skb->data, skb->len);
if (!is_rx_queue_empty() && cif_dev->rx_event_cb)
cif_dev->rx_event_cb();
end:
if (skb)
kfree_skb(skb);
return ret;
}
void rx_dequeue(uint8_t *buffer, uint32_t size, uint32_t *plen)
{
uint32_t copy_len = 0, tail_len;
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
spin_lock(&p_ring->lock);
if (p_ring->read_idx != p_ring->write_idx) {
/*
* RX Queue not empty,
* fill out the retrieving buffer untill it is full, or we have no data.
*/
if (p_ring->read_idx < p_ring->write_idx) {
copy_len = p_ring->write_idx - p_ring->read_idx;
if (copy_len > size)
copy_len = size;
memcpy(buffer, p_ring->buf + p_ring->read_idx, copy_len);
p_ring->read_idx += copy_len;
} else { /* read_idx > write_idx */
tail_len = RING_BUFFER_SIZE - p_ring->read_idx;
if (tail_len > size) { /* exclude equal case to skip wrap check */
copy_len = size;
memcpy(buffer, p_ring->buf + p_ring->read_idx, copy_len);
p_ring->read_idx += copy_len;
} else {
/* 1. copy tail */
memcpy(buffer, p_ring->buf + p_ring->read_idx, tail_len);
/* 2. check if head length is enough */
copy_len = (p_ring->write_idx < (size - tail_len))
? p_ring->write_idx : (size - tail_len);
/* 3. copy header */
memcpy(buffer + tail_len, p_ring->buf, copy_len);
p_ring->read_idx = copy_len;
/* 4. update copy length: head + tail */
copy_len += tail_len;
}
}
}
spin_unlock(&p_ring->lock);
*plen = copy_len;
return;
}
void rx_queue_flush(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
p_ring->read_idx = p_ring->write_idx = 0;
}
void rx_queue_initialize(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_ring_buffer_mgmt *p_ring = &cif_dev->rx_buffer;
p_ring->read_idx = p_ring->write_idx = 0;
spin_lock_init(&p_ring->lock);
}
void rx_queue_destroy(void)
{
rx_queue_flush();
}
/* Interface for device node mechanism */
void btmtk_rx_flush(void)
{
rx_queue_flush();
}
uint8_t btmtk_rx_data_valid(void)
{
return !is_rx_queue_empty();
}
void btmtk_register_rx_event_cb(struct hci_dev *hdev, BT_RX_EVENT_CB cb)
{
struct btmtk_dev *bdev = hci_get_drvdata(hdev);
struct btmtk_btif_dev *cif_dev = bdev->cif_dev;
cif_dev->rx_event_cb = cb;
btmtk_rx_flush();
}
int32_t btmtk_receive_data(struct hci_dev *hdev, uint8_t *buf, uint32_t count)
{
uint32_t read_bytes;
rx_dequeue(buf, count, &read_bytes);
/* TODO: disable quick PS mode by traffic density */
return read_bytes;
}
#endif // (USE_DEVICE_NODE == 1)
#if (DRIVER_CMD_CHECK == 1)
void cmd_list_initialize(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
BTMTK_DBG("%s", __func__);
p_queue = &cif_dev->cmd_queue;
p_queue->head = NULL;
p_queue->tail = NULL;
p_queue->size = 0;
spin_lock_init(&p_queue->lock);
}
struct bt_cmd_node* cmd_free_node(struct bt_cmd_node* node)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
struct bt_cmd_node* next = node->next;
p_queue = &cif_dev->cmd_queue;
kfree(node);
p_queue->size--;
return next;
}
bool cmd_list_isempty(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
p_queue = &cif_dev->cmd_queue;
spin_lock(&p_queue->lock);
if(p_queue->size == 0) {
spin_unlock(&p_queue->lock);
return TRUE;
} else {
spin_unlock(&p_queue->lock);
return FALSE;
}
}
bool cmd_list_append (uint16_t opcode)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
struct bt_cmd_node *node = kzalloc(sizeof(struct bt_cmd_node),GFP_KERNEL);
p_queue = &cif_dev->cmd_queue;
if (!node) {
BTMTK_ERR("%s create node fail",__func__);
return FALSE;
}
spin_lock(&p_queue->lock);
node->next = NULL;
node->opcode = opcode;
if(p_queue->tail == NULL){
p_queue->head = node;
p_queue->tail = node;
} else {
p_queue->tail->next = node;
p_queue->tail = node;
}
p_queue->size ++;
spin_unlock(&p_queue->lock);
return TRUE;
}
bool cmd_list_check(uint16_t opcode)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
struct bt_cmd_node* curr = NULL;
p_queue = &cif_dev->cmd_queue;
if (cmd_list_isempty() == TRUE) return FALSE;
spin_lock(&p_queue->lock);
curr = p_queue->head;
while(curr){
if(curr->opcode == opcode){
spin_unlock(&p_queue->lock);
return TRUE;
}
curr=curr->next;
}
spin_unlock(&p_queue->lock);
return FALSE;
}
bool cmd_list_remove(uint16_t opcode)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
struct bt_cmd_node* prev = NULL;
struct bt_cmd_node* curr = NULL;
p_queue = &cif_dev->cmd_queue;
if (cmd_list_isempty() == TRUE) return FALSE;
spin_lock(&p_queue->lock);
if(p_queue->head->opcode == opcode) {
struct bt_cmd_node* next = cmd_free_node(p_queue->head);
if (p_queue->head == p_queue->tail) p_queue->tail = NULL;
p_queue->head = next;
spin_unlock(&p_queue->lock);
return TRUE;
}
prev = p_queue->head;
curr = p_queue->head->next;
while(curr){
if(curr->opcode == opcode) {
prev->next = cmd_free_node(curr);
if(p_queue->tail == curr) p_queue->tail = prev;
spin_unlock(&p_queue->lock);
return TRUE;
}
prev = curr;
curr = curr->next;
}
BTMTK_ERR("%s No match opcode: %4X", __func__,opcode);
spin_unlock(&p_queue->lock);
return FALSE;
}
void cmd_list_destory(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
struct bt_cmd_node* curr= NULL;
BTMTK_DBG("%s",__func__);
p_queue = &cif_dev->cmd_queue;
spin_lock(&p_queue->lock);
curr = p_queue->head;
while(curr){
curr = cmd_free_node(curr);
}
p_queue->head = NULL;
p_queue->tail = NULL;
p_queue->size = 0;
spin_unlock(&p_queue->lock);
}
void command_response_timeout(struct work_struct *pwork)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
p_queue = &cif_dev->cmd_queue;
if (p_queue->size != 0) {
cif_dev->cmd_timeout_count++;
BTMTK_INFO("[%s] timeout [%d] sleep [%d] force_on [%d]", __func__,
cif_dev->cmd_timeout_count,
cif_dev->psm.sleep_flag,
cif_dev->psm.force_on);
btmtk_cif_dump_rxd_backtrace();
btmtk_cif_dump_fw_no_rsp(BT_BTIF_DUMP_REG);
if (cif_dev->cmd_timeout_count == 4) {
spin_lock(&p_queue->lock);
if (p_queue->head)
BTMTK_ERR("%s, !!!! Command Timeout !!!! opcode 0x%4X", __func__, p_queue->head->opcode);
else
BTMTK_ERR("%s, p_queue head is NULL", __func__);
spin_unlock(&p_queue->lock);
// To-do : Need to consider if it has any condition to check
cif_dev->cmd_timeout_count = 0;
bt_trigger_reset();
} else {
down(&cif_dev->cmd_tout_sem);
if(workqueue_task != NULL) {
queue_delayed_work(workqueue_task, &work, HZ>>1);
}
up(&cif_dev->cmd_tout_sem);
}
}
}
bool cmd_workqueue_init(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
BTMTK_INFO("init workqueue");
workqueue_task = create_singlethread_workqueue("workqueue_task");
if(!workqueue_task){
BTMTK_ERR("fail to init workqueue");
return FALSE;
}
INIT_DELAYED_WORK(&work, command_response_timeout);
cif_dev->cmd_timeout_count = 0;
return TRUE;
}
void update_command_response_workqueue(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_cmd_queue *p_queue = NULL;
p_queue = &cif_dev->cmd_queue;
if (p_queue->size == 0){
BTMTK_DBG("command queue size = 0");
cancel_delayed_work(&work);
} else {
spin_lock(&p_queue->lock);
if (p_queue->head)
BTMTK_DBG("update new command queue : %4X" , p_queue->head->opcode);
else
BTMTK_ERR("%s, p_queue head is NULL", __func__);
spin_unlock(&p_queue->lock);
cif_dev->cmd_timeout_count = 0;
cancel_delayed_work(&work);
down(&cif_dev->cmd_tout_sem);
if(workqueue_task != NULL) {
queue_delayed_work(workqueue_task, &work, HZ>>1);
}
up(&cif_dev->cmd_tout_sem);
}
}
void cmd_workqueue_exit(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
int ret_a = 0, ret_b = 0;
if(workqueue_task != NULL) {
ret_b = cancel_delayed_work(&work);
flush_workqueue(workqueue_task);
ret_a = cancel_delayed_work(&work);
BTMTK_INFO("cancel workqueue before[%d] after[%d] flush", ret_b, ret_a);
down(&cif_dev->cmd_tout_sem);
destroy_workqueue(workqueue_task);
workqueue_task = NULL;
up(&cif_dev->cmd_tout_sem);
}
}
#endif // (DRIVER_CMD_CHECK == 1)
const char* direction_tostring (enum bt_direction_type direction_type) {
char *type[] = {"NONE", "TX", "RX"};
return type[direction_type];
}
void dump_queue_initialize(void)
{
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_dump_queue *d_queue = NULL;
BTMTK_INFO("init dumpqueue");
d_queue = &cif_dev->dump_queue;
d_queue->index = 0;
d_queue->full = 0;
spin_lock_init(&d_queue->lock);
memset(d_queue->queue, 0, MAX_DUMP_QUEUE_SIZE * sizeof(struct bt_dump_packet));
}
void add_dump_packet(const uint8_t *buffer,const uint32_t length, enum bt_direction_type type){
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_dump_queue *d_queue = NULL;
uint32_t index = 0;
struct bt_dump_packet *p_packet = NULL;
uint32_t copysize;
d_queue = &cif_dev->dump_queue;
index = d_queue->index;
p_packet = &d_queue->queue[index];
spin_lock(&d_queue->lock);
if (length > MAX_DUMP_DATA_SIZE)
copysize = MAX_DUMP_DATA_SIZE;
else
copysize = length;
ktime_get_real_ts64(&p_packet->time);
ktime_get_ts64(&p_packet->kerneltime);
memcpy(p_packet->data,buffer,copysize);
p_packet->data_length = length;
p_packet->direction_type = type;
d_queue->index = (d_queue->index+1) % MAX_DUMP_QUEUE_SIZE;
BTMTK_DBG("index: %d", d_queue->index);
if (d_queue->full == FALSE && d_queue->index == 0)
d_queue->full = TRUE;
spin_unlock(&d_queue->lock);
}
void print_dump_packet(struct bt_dump_packet *p_packet){
int32_t copysize;
uint32_t sec, usec, ksec, knsec;
struct rtc_time tm;
sec = p_packet->time.tv_sec;
usec = p_packet->time.tv_nsec/1000;
ksec = p_packet->kerneltime.tv_sec;
knsec = p_packet->kerneltime.tv_nsec;
rtc_time64_to_tm(sec, &tm);
if (p_packet->data_length > MAX_DUMP_DATA_SIZE)
copysize = MAX_DUMP_DATA_SIZE;
else
copysize = p_packet->data_length;
BTMTK_INFO_RAW(p_packet->data, copysize, "Dump: Time:%02d:%02d:%02d.%06u, Kernel Time:%6d.%09u, %s, Size = %3d, Data: "
, tm.tm_hour+8, tm.tm_min, tm.tm_sec, usec, ksec, knsec
, direction_tostring(p_packet->direction_type), p_packet->data_length);
}
void show_all_dump_packet(void) {
struct btmtk_btif_dev *cif_dev = (struct btmtk_btif_dev *)g_sbdev->cif_dev;
struct bt_dump_queue *d_queue = NULL;
int32_t i, j, showsize;
struct bt_dump_packet *p_packet;
d_queue = &cif_dev->dump_queue;
spin_lock(&d_queue->lock);
if (d_queue->full == TRUE) {
showsize = MAX_DUMP_QUEUE_SIZE;
for(i = 0,j = d_queue->index; i < showsize; i++,j++) {
p_packet = &d_queue->queue[j % MAX_DUMP_QUEUE_SIZE];
print_dump_packet(p_packet);
}
} else {
showsize = d_queue->index;
for(i = 0; i < showsize; i++) {
p_packet = &d_queue->queue[i];
print_dump_packet(p_packet);
}
}
spin_unlock(&d_queue->lock);
}

View file

@ -0,0 +1,9 @@
# load bt_drv
on property:vendor.connsys.driver.ready=yes
insmod /vendor/lib/modules/bt_drv_${ro.vendor.bt.platform}.ko
chown bluetooth bluetooth /proc/driver/bt_dbg
chown bluetooth bluetooth /proc/driver/wmt_dbg
on property:vendor.connsys.driver.ready=no
insmod /vendor/lib/modules/bt_drv_${ro.vendor.bt.platform}.ko
chown bluetooth bluetooth /proc/driver/bt_dbg
chown bluetooth bluetooth /proc/driver/wmt_dbg

View file

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_buffer_mode.h"
static struct btmtk_buffer_mode_struct btmtk_buffer_mode;
static int btmtk_buffer_mode_check_auto_mode(struct btmtk_buffer_mode_struct *buffer_mode)
{
u16 addr = 1;
u8 value = 0;
if (buffer_mode->efuse_mode != AUTO_MODE)
return 0;
if (btmtk_efuse_read(buffer_mode->bdev, addr, &value)) {
BTMTK_WARN("read fail");
BTMTK_WARN("Use EEPROM Bin file mode");
buffer_mode->efuse_mode = BIN_FILE_MODE;
return -EIO;
}
if (value == ((buffer_mode->bdev->chip_id & 0xFF00) >> 8)) {
BTMTK_WARN("get efuse[1]: 0x%02x", value);
BTMTK_WARN("use efuse mode");
buffer_mode->efuse_mode = EFUSE_MODE;
} else {
BTMTK_WARN("get efuse[1]: 0x%02x", value);
BTMTK_WARN("Use EEPROM Bin file mode");
buffer_mode->efuse_mode = BIN_FILE_MODE;
}
return 0;
}
static int btmtk_buffer_mode_parse_mode(uint8_t *buf, size_t buf_size)
{
int efuse_mode = EFUSE_MODE;
char *p_buf = NULL;
char *ptr = NULL, *p = NULL;
if (!buf) {
BTMTK_WARN("buf is null");
return efuse_mode;
} else if (buf_size < (strlen(BUFFER_MODE_SWITCH_FIELD) + 2)) {
BTMTK_WARN("incorrect buf size(%d)", (int)buf_size);
return efuse_mode;
}
p_buf = kmalloc(buf_size + 1, GFP_KERNEL);
if (!p_buf)
return efuse_mode;
memcpy(p_buf, buf, buf_size);
p_buf[buf_size] = '\0';
/* find string */
p = ptr = strstr(p_buf, BUFFER_MODE_SWITCH_FIELD);
if (!ptr) {
BTMTK_ERR("Can't find %s", BUFFER_MODE_SWITCH_FIELD);
goto out;
}
if (p > p_buf) {
p--;
while ((*p == ' ') && (p != p_buf))
p--;
if (*p == '#') {
BTMTK_ERR("It's not EEPROM - Bin file mode");
goto out;
}
}
/* check access mode */
ptr += (strlen(BUFFER_MODE_SWITCH_FIELD) + 1);
BTMTK_WARN("It's EEPROM bin mode: %c", *ptr);
efuse_mode = *ptr - '0';
if (efuse_mode > AUTO_MODE)
efuse_mode = EFUSE_MODE;
out:
kfree(p_buf);
return efuse_mode;
}
static int btmtk_buffer_mode_set_addr(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_ADDRESS_CMD_LEN] = {0x01, 0x1A, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_ADDRESS_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0x1A, 0xFC, 0x00};
int ret = 0;
if (buffer_mode->bt0_mac[0] == 0x00 && buffer_mode->bt0_mac[1] == 0x00
&& buffer_mode->bt0_mac[2] == 0x00 && buffer_mode->bt0_mac[3] == 0x00
&& buffer_mode->bt0_mac[4] == 0x00 && buffer_mode->bt0_mac[5] == 0x00) {
BTMTK_WARN("BDAddr is Zero, not set");
} else {
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 5] = buffer_mode->bt0_mac[0];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 4] = buffer_mode->bt0_mac[1];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 3] = buffer_mode->bt0_mac[2];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 2] = buffer_mode->bt0_mac[3];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET + 1] = buffer_mode->bt0_mac[4];
cmd[SET_ADDRESS_CMD_PAYLOAD_OFFSET] = buffer_mode->bt0_mac[5];
BTMTK_INFO_RAW(cmd, SET_ADDRESS_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_ADDRESS_CMD_LEN,
event, SET_ADDRESS_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
}
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_radio(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_RADIO_CMD_LEN] = {0x01, 0x2C, 0xFC, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_RADIO_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0x2C, 0xFC, 0x00};
int ret = 0;
cmd[SET_RADIO_CMD_EDR_DEF_OFFSET] = buffer_mode->bt0_radio.radio_0 & 0x3F; /* edr_init_pwr */
cmd[SET_RADIO_CMD_BLE_OFFSET] = buffer_mode->bt0_radio.radio_2 & 0x3F; /* ble_default_pwr */
cmd[SET_RADIO_CMD_EDR_MAX_OFFSET] = buffer_mode->bt0_radio.radio_1 & 0x3F; /* edr_max_pwr */
cmd[SET_RADIO_CMD_EDR_MODE_OFFSET] = (buffer_mode->bt0_radio.radio_0 & 0xC0) >> 6; /* edr_pwr_mode */
BTMTK_INFO_RAW(cmd, SET_RADIO_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_RADIO_CMD_LEN,
event, SET_RADIO_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_group_boundary(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_GRP_CMD_LEN] = {0x01, 0xEA, 0xFC, 0x09, 0x02, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_GRP_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0xEA, 0xFC, 0x00};
int ret = 0;
memcpy(&cmd[SET_GRP_CMD_PAYLOAD_OFFSET], buffer_mode->bt0_ant0_grp_boundary, BUFFER_MODE_GROUP_LENGTH);
BTMTK_INFO_RAW(cmd, SET_GRP_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_GRP_CMD_LEN,
event, SET_GRP_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
static int btmtk_buffer_mode_set_power_offset(struct btmtk_buffer_mode_struct *buffer_mode)
{
u8 cmd[SET_PWR_OFFSET_CMD_LEN] = {0x01, 0xEA, 0xFC, 0x0A,
0x02, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 event[SET_PWR_OFFSET_EVT_LEN] = {0x04, 0x0E, 0x04, 0x01, 0xEA, 0xFC, 0x00};
int ret = 0;
memcpy(&cmd[SET_PWR_OFFSET_CMD_PAYLOAD_OFFSET], buffer_mode->bt0_ant0_pwr_offset, BUFFER_MODE_CAL_LENGTH);
BTMTK_INFO_RAW(cmd, SET_PWR_OFFSET_CMD_LEN, "%s: Send", __func__);
ret = btmtk_main_send_cmd(buffer_mode->bdev,
cmd, SET_PWR_OFFSET_CMD_LEN,
event, SET_PWR_OFFSET_EVT_LEN,
0, 0, BTMTK_TX_CMD_FROM_DRV);
BTMTK_INFO("%s done", __func__);
return ret;
}
int btmtk_buffer_mode_send(struct btmtk_buffer_mode_struct *buffer_mode)
{
int ret = 0;
if (buffer_mode == NULL) {
BTMTK_INFO("buffer_mode is NULL, not support");
return -EIO;
}
if (btmtk_buffer_mode_check_auto_mode(buffer_mode)) {
BTMTK_ERR("check auto mode failed");
return -EIO;
}
if (buffer_mode->efuse_mode == BIN_FILE_MODE) {
ret = btmtk_buffer_mode_set_addr(buffer_mode);
if (ret < 0)
BTMTK_ERR("set addr failed");
ret = btmtk_buffer_mode_set_radio(buffer_mode);
if (ret < 0)
BTMTK_ERR("set radio failed");
ret = btmtk_buffer_mode_set_group_boundary(buffer_mode);
if (ret < 0)
BTMTK_ERR("set group_boundary failed");
ret = btmtk_buffer_mode_set_power_offset(buffer_mode);
if (ret < 0)
BTMTK_ERR("set power_offset failed");
}
return 0;
}
void btmtk_buffer_mode_initialize(struct btmtk_dev *bdev, struct btmtk_buffer_mode_struct **buffer_mode)
{
int ret = 0;
u32 code_len = 0;
btmtk_buffer_mode.bdev = bdev;
ret = btmtk_load_code_from_setting_files(BUFFER_MODE_SWITCH_FILE, bdev->intf_dev, &code_len, bdev);
btmtk_buffer_mode.efuse_mode = btmtk_buffer_mode_parse_mode(bdev->setting_file, code_len);
if (btmtk_buffer_mode.efuse_mode == EFUSE_MODE)
return;
if (bdev->flavor)
(void)snprintf(btmtk_buffer_mode.file_name, MAX_BIN_FILE_NAME_LEN, "EEPROM_MT%04x_1a.bin",
bdev->chip_id & 0xffff);
else
(void)snprintf(btmtk_buffer_mode.file_name, MAX_BIN_FILE_NAME_LEN, "EEPROM_MT%04x_1.bin",
bdev->chip_id & 0xffff);
ret = btmtk_load_code_from_setting_files(btmtk_buffer_mode.file_name, bdev->intf_dev, &code_len, bdev);
if (ret < 0) {
BTMTK_ERR("set load %s failed", btmtk_buffer_mode.file_name);
return;
}
memcpy(btmtk_buffer_mode.bt0_mac, &bdev->setting_file[BT0_MAC_OFFSET],
BUFFER_MODE_MAC_LENGTH);
memcpy(btmtk_buffer_mode.bt1_mac, &bdev->setting_file[BT1_MAC_OFFSET],
BUFFER_MODE_MAC_LENGTH);
memcpy(&btmtk_buffer_mode.bt0_radio, &bdev->setting_file[BT0_RADIO_OFFSET],
BUFFER_MODE_RADIO_LENGTH);
memcpy(&btmtk_buffer_mode.bt1_radio, &bdev->setting_file[BT1_RADIO_OFFSET],
BUFFER_MODE_RADIO_LENGTH);
memcpy(btmtk_buffer_mode.bt0_ant0_grp_boundary, &bdev->setting_file[BT0_GROUP_ANT0_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
memcpy(btmtk_buffer_mode.bt0_ant1_grp_boundary, &bdev->setting_file[BT0_GROUP_ANT1_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
memcpy(btmtk_buffer_mode.bt1_ant0_grp_boundary, &bdev->setting_file[BT1_GROUP_ANT0_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
memcpy(btmtk_buffer_mode.bt1_ant1_grp_boundary, &bdev->setting_file[BT1_GROUP_ANT1_OFFSET],
BUFFER_MODE_GROUP_LENGTH);
memcpy(btmtk_buffer_mode.bt0_ant0_pwr_offset, &bdev->setting_file[BT0_CAL_ANT0_OFFSET],
BUFFER_MODE_CAL_LENGTH);
memcpy(btmtk_buffer_mode.bt0_ant1_pwr_offset, &bdev->setting_file[BT0_CAL_ANT1_OFFSET],
BUFFER_MODE_CAL_LENGTH);
memcpy(btmtk_buffer_mode.bt1_ant0_pwr_offset, &bdev->setting_file[BT1_CAL_ANT0_OFFSET],
BUFFER_MODE_CAL_LENGTH);
memcpy(btmtk_buffer_mode.bt1_ant1_pwr_offset, &bdev->setting_file[BT1_CAL_ANT1_OFFSET],
BUFFER_MODE_CAL_LENGTH);
*buffer_mode = &btmtk_buffer_mode;
}

View file

@ -0,0 +1,121 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "btmtk_main.h"
#include "btmtk_woble.h"
void btmtk_reset_waker(struct work_struct *work)
{
struct btmtk_dev *bdev = container_of(work, struct btmtk_dev, reset_waker);
struct btmtk_cif_state *cif_state = NULL;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
int cif_event = 0, err = 0;
cif_event = HIF_EVENT_SUBSYS_RESET;
if (BTMTK_CIF_IS_NULL(bdev, cif_event)) {
/* Error */
BTMTK_WARN("%s priv setting is NULL", __func__);
goto Finish;
}
while (!bdev->bt_cfg.support_dongle_reset) {
BTMTK_ERR("%s chip_reset is not support", __func__);
msleep(2000);
}
cif_state = &bdev->cif_state[cif_event];
/* Set Entering state */
btmtk_set_chip_state((void *)bdev, cif_state->ops_enter);
BTMTK_INFO("%s: Receive a byte (0xFF)", __func__);
/* read interrupt EP15 CR */
bdev->subsys_reset = 1;
bdev->sco_num = 0;
if (bmain_info->whole_reset_flag == 0) {
if (bmain_info->hif_hook.subsys_reset)
err = bmain_info->hif_hook.subsys_reset(bdev);
else
BTMTK_INFO("%s: Not support subsys chip reset", __func__);
} else {
err = -1;
BTMTK_INFO("%s: whole_reset_flag is %d", __func__, bmain_info->whole_reset_flag);
}
if (err) {
/* L0.5 reset failed, do whole chip reset */
/* We will add support dongle reset flag, reading from bt.cfg */
bdev->subsys_reset = 0;
/* TODO: need to confirm with usb host when suspend fail, to do chip reset,
* because usb3.0 need to toggle reset pin after hub_event unfreeze,
* otherwise, it will not occur disconnect on Capy Platform. When Mstar
* chip has usb3.0 port, we will use Mstar platform to do comparison
* test, then found the final solution.
*/
/* msleep(2000); */
if (bmain_info->hif_hook.whole_reset)
bmain_info->hif_hook.whole_reset(bdev);
else
BTMTK_INFO("%s: Not support whole chip reset", __func__);
bmain_info->whole_reset_flag = 0;
goto Finish;
}
/* It's a test code for stress test (whole chip reset & L0.5 reset) */
#if 0
if (bdev->bt_cfg.support_dongle_reset == 0) {
err = btmtk_cif_subsys_reset(bdev);
if (err) {
/* L0.5 reset failed, do whole chip reset */
if (main_info.hif_hook->whole_reset)
main_info.hif_hook.whole_reset(bdev);
goto Finish;
}
} else {
/* L0.5 reset failed, do whole chip reset */
/* TODO: need to confirm with usb host when suspend fail, to do chip reset,
* because usb3.0 need to toggle reset pin after hub_event unfreeze,
* otherwise, it will not occur disconnect on Capy Platform. When Mstar
* chip has usb3.0 port, we will use Mstar platform to do comparison
* test, then found the final solution.
*/
/* msleep(2000); */
if (main_info.hif_hook->whole_reset)
main_info.hif_hook.whole_reset(bdev);
/* btmtk_send_hw_err_to_host(bdev); */
goto Finish;
}
#endif
bmain_info->reset_stack_flag = HW_ERR_CODE_CHIP_RESET;
bdev->subsys_reset = 0;
err = btmtk_cap_init(bdev);
if (err < 0) {
BTMTK_ERR("btmtk init failed!");
goto Finish;
}
err = btmtk_load_rom_patch(bdev);
if (err < 0) {
BTMTK_ERR("btmtk load rom patch failed!");
goto Finish;
}
btmtk_send_hw_err_to_host(bdev);
btmtk_woble_wake_unlock(bdev);
Finish:
bmain_info->hif_hook.chip_reset_notify(bdev);
/* Set End/Error state */
if (err < 0)
btmtk_set_chip_state((void *)bdev, cif_state->ops_error);
else
btmtk_set_chip_state((void *)bdev, cif_state->ops_end);
}

View file

@ -0,0 +1,756 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "btmtk_main.h"
#include "btmtk_fw_log.h"
/*
* BT Logger Tool will turn on/off Firmware Picus log, and set 3 log levels (Low, SQC and Debug)
* For extention capability, driver does not check the value range.
*
* Combine log state and log level to below settings:
* - 0x00: OFF
* - 0x01: Low Power
* - 0x02: SQC
* - 0x03: Debug
*/
#if (FW_LOG_DEFAULT_ON == 0)
#define BT_FWLOG_DEFAULT_LEVEL 0x00
#else
#define BT_FWLOG_DEFAULT_LEVEL 0x02
#endif
/* CTD BT log function and log status */
static wait_queue_head_t BT_log_wq;
static struct semaphore ioctl_mtx;
static uint8_t g_bt_on = BT_FWLOG_OFF;
static uint8_t g_log_on = BT_FWLOG_OFF;
static uint8_t g_log_level = BT_FWLOG_DEFAULT_LEVEL;
static uint8_t g_log_current = BT_FWLOG_OFF;
/* For fwlog dev node setting */
static struct btmtk_fops_fwlog *g_fwlog;
const struct file_operations BT_fopsfwlog = {
.open = btmtk_fops_openfwlog,
.release = btmtk_fops_closefwlog,
.read = btmtk_fops_readfwlog,
.write = btmtk_fops_writefwlog,
.poll = btmtk_fops_pollfwlog,
.unlocked_ioctl = btmtk_fops_unlocked_ioctlfwlog,
.compat_ioctl = btmtk_fops_compat_ioctlfwlog
};
__weak int32_t btmtk_intcmd_wmt_utc_sync(void)
{
BTMTK_ERR("weak function %s not implement", __func__);
return -1;
}
__weak int32_t btmtk_intcmd_set_fw_log(uint8_t flag)
{
BTMTK_ERR("weak function %s not implement", __func__);
return -1;
}
void fw_log_bt_state_cb(uint8_t state)
{
uint8_t on_off;
on_off = (state == FUNC_ON) ? BT_FWLOG_ON : BT_FWLOG_OFF;
BTMTK_INFO("bt_on(0x%x) state(%d) on_off(0x%x)", g_bt_on, state, on_off);
if (g_bt_on != on_off) {
// changed
if (on_off == BT_FWLOG_OFF) { // should turn off
g_bt_on = BT_FWLOG_OFF;
BTMTK_INFO("BT func off, no need to send hci cmd");
} else {
g_bt_on = BT_FWLOG_ON;
if (g_log_current) {
btmtk_intcmd_set_fw_log(g_log_current);
btmtk_intcmd_wmt_utc_sync();
}
}
}
}
void fw_log_bt_event_cb(void)
{
BTMTK_DBG("fw_log_bt_event_cb");
wake_up_interruptible(&BT_log_wq);
}
int btmtk_fops_initfwlog(void)
{
static int BT_majorfwlog;
dev_t devIDfwlog = MKDEV(BT_majorfwlog, 0);
int ret = 0;
int cdevErr = 0;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: Start", __func__);
if (g_fwlog == NULL) {
g_fwlog = kzalloc(sizeof(*g_fwlog), GFP_KERNEL);
if (!g_fwlog) {
BTMTK_ERR("%s: alloc memory fail (g_data)", __func__);
return -1;
}
}
//if (is_mt66xx(g_sbdev->chip_id)) {
if (bmain_info->hif_hook.log_init) {
bmain_info->hif_hook.log_init();
bmain_info->hif_hook.log_register_cb(fw_log_bt_event_cb);
init_waitqueue_head(&BT_log_wq);
sema_init(&ioctl_mtx, 1);
} else {
spin_lock_init(&g_fwlog->fwlog_lock);
skb_queue_head_init(&g_fwlog->fwlog_queue);
init_waitqueue_head(&(g_fwlog->fw_log_inq));
}
ret = alloc_chrdev_region(&devIDfwlog, 0, 1, BT_FWLOG_DEV_NODE);
if (ret) {
BTMTK_ERR("%s: fail to allocate chrdev", __func__);
goto alloc_error;
}
BT_majorfwlog = MAJOR(devIDfwlog);
cdev_init(&g_fwlog->BT_cdevfwlog, &BT_fopsfwlog);
g_fwlog->BT_cdevfwlog.owner = THIS_MODULE;
cdevErr = cdev_add(&g_fwlog->BT_cdevfwlog, devIDfwlog, 1);
if (cdevErr)
goto cdv_error;
g_fwlog->pBTClass = class_create(THIS_MODULE, BT_FWLOG_DEV_NODE);
if (IS_ERR(g_fwlog->pBTClass)) {
BTMTK_ERR("%s: class create fail, error code(%ld)\n", __func__, PTR_ERR(g_fwlog->pBTClass));
goto create_node_error;
}
g_fwlog->pBTDevfwlog = device_create(g_fwlog->pBTClass, NULL, devIDfwlog, NULL,
BT_FWLOG_DEV_NODE);
if (IS_ERR(g_fwlog->pBTDevfwlog)) {
BTMTK_ERR("%s: device(stpbtfwlog) create fail, error code(%ld)", __func__,
PTR_ERR(g_fwlog->pBTDevfwlog));
goto create_node_error;
}
BTMTK_INFO("%s: BT_majorfwlog %d, devIDfwlog %d", __func__, BT_majorfwlog, devIDfwlog);
g_fwlog->g_devIDfwlog = devIDfwlog;
BTMTK_INFO("%s: End", __func__);
return 0;
create_node_error:
if (g_fwlog->pBTClass) {
class_destroy(g_fwlog->pBTClass);
g_fwlog->pBTClass = NULL;
}
cdv_error:
if (cdevErr == 0)
cdev_del(&g_fwlog->BT_cdevfwlog);
if (ret == 0)
unregister_chrdev_region(devIDfwlog, 1);
alloc_error:
kfree(g_fwlog);
g_fwlog = NULL;
return -1;
}
int btmtk_fops_exitfwlog(void)
{
dev_t devIDfwlog = g_fwlog->g_devIDfwlog;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: Start\n", __func__);
//if (is_mt66xx(g_sbdev->chip_id))
if (bmain_info->hif_hook.log_deinit)
bmain_info->hif_hook.log_deinit();
if (g_fwlog->pBTDevfwlog) {
device_destroy(g_fwlog->pBTClass, devIDfwlog);
g_fwlog->pBTDevfwlog = NULL;
}
if (g_fwlog->pBTClass) {
class_destroy(g_fwlog->pBTClass);
g_fwlog->pBTClass = NULL;
}
BTMTK_INFO("%s: pBTDevfwlog, pBTClass done\n", __func__);
cdev_del(&g_fwlog->BT_cdevfwlog);
unregister_chrdev_region(devIDfwlog, 1);
BTMTK_INFO("%s: BT_chrdevfwlog driver removed.\n", __func__);
kfree(g_fwlog);
return 0;
}
ssize_t btmtk_fops_readfwlog(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int copyLen = 0;
ulong flags = 0;
struct sk_buff *skb = NULL;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
//if (is_mt66xx(g_sbdev->chip_id)) {
if (bmain_info->hif_hook.log_read_to_user) {
copyLen = bmain_info->hif_hook.log_read_to_user(buf, count);
BTMTK_DBG("BT F/W log from Connsys, len %d", copyLen);
return copyLen;
}
/* picus read a queue, it may occur performace issue */
spin_lock_irqsave(&g_fwlog->fwlog_lock, flags);
if (skb_queue_len(&g_fwlog->fwlog_queue))
skb = skb_dequeue(&g_fwlog->fwlog_queue);
spin_unlock_irqrestore(&g_fwlog->fwlog_lock, flags);
if (skb == NULL)
return 0;
if (skb->len <= count) {
if (copy_to_user(buf, skb->data, skb->len))
BTMTK_ERR("%s: copy_to_user failed!", __func__);
copyLen = skb->len;
} else {
BTMTK_DBG("%s: socket buffer length error(count: %d, skb.len: %d)",
__func__, (int)count, skb->len);
}
kfree_skb(skb);
return copyLen;
}
ssize_t btmtk_fops_writefwlog(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
int i = 0, len = 0, ret = -1;
int hci_idx = 0;
int vlen = 0, index = 3;
struct sk_buff *skb = NULL;
int state = BTMTK_STATE_INIT;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
u8 *i_fwlog_buf = NULL;
u8 *o_fwlog_buf = NULL;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
struct btmtk_dev **pp_bdev = btmtk_get_pp_bdev();
/* only 7xxx will use writefwlog, 66xx not used */
/*if (is_mt66xx(bdev->chip_id)) {
* BTMTK_WARN("%s: not implement!", __func__);
* return 0;
* }
*/
i_fwlog_buf = kmalloc(HCI_MAX_COMMAND_BUF_SIZE, GFP_KERNEL);
if (!i_fwlog_buf) {
BTMTK_ERR("%s: alloc i_fwlog_buf failed", __func__);
ret = -ENOMEM;
goto exit;
}
o_fwlog_buf = kmalloc(HCI_MAX_COMMAND_SIZE, GFP_KERNEL);
if (!o_fwlog_buf) {
BTMTK_ERR("%s: alloc o_fwlog_buf failed", __func__);
ret = -ENOMEM;
goto exit;
}
if (count > HCI_MAX_COMMAND_BUF_SIZE) {
BTMTK_ERR("%s: your command is larger than maximum length, count = %zd",
__func__, count);
ret = -ENOMEM;
goto exit;
}
memset(i_fwlog_buf, 0, HCI_MAX_COMMAND_BUF_SIZE);
memset(o_fwlog_buf, 0, HCI_MAX_COMMAND_SIZE);
if (copy_from_user(i_fwlog_buf, buf, count) != 0) {
BTMTK_ERR("%s: Failed to copy data", __func__);
ret = -ENODATA;
goto exit;
}
/* For log level, EX: echo log_lvl=1 > /dev/stpbtfwlog */
if (strncmp(i_fwlog_buf, "log_lvl=", strlen("log_lvl=")) == 0) {
u8 val = *(i_fwlog_buf + strlen("log_lvl=")) - '0';
if (val > BTMTK_LOG_LVL_MAX || val <= 0) {
BTMTK_ERR("Got incorrect value for log level(%d)", val);
count = -EINVAL;
goto exit;
}
btmtk_log_lvl = val;
BTMTK_INFO("btmtk_log_lvl = %d", btmtk_log_lvl);
ret = count;
goto exit;
}
/* For bperf, EX: echo bperf=1 > /dev/stpbtfwlog */
if (strncmp(i_fwlog_buf, "bperf=", strlen("bperf=")) == 0) {
u8 val = *(i_fwlog_buf + strlen("bperf=")) - '0';
g_fwlog->btmtk_bluetooth_kpi = val;
BTMTK_INFO("%s: set bluetooth KPI feature(bperf) to %d", __func__, g_fwlog->btmtk_bluetooth_kpi);
ret = count;
goto exit;
}
if (strncmp(i_fwlog_buf, "whole chip reset", strlen("whole chip reset")) == 0) {
BTMTK_INFO("whole chip reset start");
bmain_info->whole_reset_flag = 1;
schedule_work(&pp_bdev[hci_idx]->reset_waker);
ret = count;
goto exit;
}
if (strncmp(i_fwlog_buf, "subsys chip reset", strlen("subsys chip reset")) == 0) {
BTMTK_INFO("subsys chip reset");
schedule_work(&pp_bdev[hci_idx]->reset_waker);
ret = count;
goto exit;
}
/* hci input command format : echo 01 be fc 01 05 > /dev/stpbtfwlog */
/* We take the data from index three to end. */
for (i = 0; i < count; i++) {
char *pos = i_fwlog_buf + i;
char temp_str[3] = {'\0'};
long res = 0;
if (*pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n') {
continue;
} else if (*pos == '0' && (*(pos + 1) == 'x' || *(pos + 1) == 'X')) {
i++;
continue;
} else if (!(*pos >= '0' && *pos <= '9') && !(*pos >= 'A' && *pos <= 'F')
&& !(*pos >= 'a' && *pos <= 'f')) {
BTMTK_ERR("%s: There is an invalid input(%c)", __func__, *pos);
ret = -EINVAL;
goto exit;
}
temp_str[0] = *pos;
temp_str[1] = *(pos + 1);
i++;
ret = kstrtol(temp_str, 16, &res);
if (ret == 0)
o_fwlog_buf[len++] = (u8)res;
else
BTMTK_ERR("%s: Convert %s failed(%d)", __func__, temp_str, ret);
}
if (o_fwlog_buf[0] != HCI_COMMAND_PKT && o_fwlog_buf[0] != FWLOG_TYPE) {
BTMTK_ERR("%s: Not support 0x%02X yet", __func__, o_fwlog_buf[0]);
ret = -EPROTONOSUPPORT;
goto exit;
}
/* check HCI command length */
if (len > HCI_MAX_COMMAND_SIZE) {
BTMTK_ERR("%s: command is larger than max buf size, length = %d", __func__, len);
ret = -ENOMEM;
goto exit;
}
skb = alloc_skb(count + BT_SKB_RESERVE, GFP_ATOMIC);
if (!skb) {
BTMTK_ERR("%s allocate skb failed!!", __func__);
ret = -ENOMEM;
goto exit;
}
/* send HCI command */
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
/* format */
/* 0xF0 XX XX 00 01 AA 10 BB CC CC CC CC ... */
/* XX XX total length */
/* 00 : hci index setting type */
/* AA hci index to indicate which hci send following command*/
/* 10 : raw data type*/
/* BB command length */
/* CC command */
if (o_fwlog_buf[0] == FWLOG_TYPE) {
while (index < ((o_fwlog_buf[2] << 8) + o_fwlog_buf[1])) {
switch (o_fwlog_buf[index]) {
case FWLOG_HCI_IDX: /* hci index */
vlen = o_fwlog_buf[index + 1];
hci_idx = o_fwlog_buf[index + 2];
BTMTK_DBG("%s: send to hci%d", __func__, hci_idx);
index += (FWLOG_ATTR_TL_SIZE + vlen);
break;
case FWLOG_TX: /* tx raw data */
vlen = o_fwlog_buf[index + 1];
memcpy(skb->data, o_fwlog_buf + index + FWLOG_ATTR_TL_SIZE, vlen);
skb->len = vlen;
index = index + FWLOG_ATTR_TL_SIZE + vlen;
break;
default:
BTMTK_WARN("Invalid opcode");
ret = -1;
goto free_skb;
}
}
} else {
memcpy(skb->data, o_fwlog_buf, len);
skb->len = len;
pp_bdev[hci_idx]->opcode_usr[0] = o_fwlog_buf[1];
pp_bdev[hci_idx]->opcode_usr[1] = o_fwlog_buf[2];
}
/* won't send command if g_bdev not define */
if (pp_bdev[hci_idx]->hdev == NULL) {
BTMTK_DBG("pp_bdev[%d] not define", hci_idx);
ret = count;
goto free_skb;
}
state = btmtk_get_chip_state(pp_bdev[hci_idx]);
if (state != BTMTK_STATE_WORKING) {
BTMTK_WARN("%s: current is in suspend/resume/standby/dump/disconnect (%d).",
__func__, state);
ret = -EBADFD;
goto free_skb;
}
fstate = btmtk_fops_get_state(pp_bdev[hci_idx]);
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d)!", __func__, fstate);
ret = -ENODEV;
goto free_skb;
}
if (pp_bdev[hci_idx]->power_state == BTMTK_DONGLE_STATE_POWER_OFF) {
BTMTK_WARN("%s: dongle state already power off, do not write", __func__);
ret = -EFAULT;
goto free_skb;
}
/* clean fwlog queue before enable picus log */
if (skb_queue_len(&g_fwlog->fwlog_queue) && skb->data[0] == 0x01
&& skb->data[1] == 0x5d && skb->data[2] == 0xfc && skb->data[4] == 0x00) {
skb_queue_purge(&g_fwlog->fwlog_queue);
BTMTK_INFO("clean fwlog_queue, skb_queue_len = %d", skb_queue_len(&g_fwlog->fwlog_queue));
}
btmtk_dispatch_fwlog_bluetooth_kpi(pp_bdev[hci_idx], skb->data, skb->len, KPI_WITHOUT_TYPE);
ret = bmain_info->hif_hook.send_cmd(pp_bdev[hci_idx], skb, 0, 0, (int)BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s failed!!", __func__);
goto free_skb;
} else
BTMTK_INFO("%s: OK", __func__);
BTMTK_INFO("%s: Write end(len: %d)", __func__, len);
ret = count;
goto exit;
free_skb:
kfree_skb(skb);
skb = NULL;
exit:
kfree(i_fwlog_buf);
kfree(o_fwlog_buf);
return ret; /* If input is correct should return the same length */
}
int btmtk_fops_openfwlog(struct inode *inode, struct file *file)
{
BTMTK_INFO("%s: Start.", __func__);
return 0;
}
int btmtk_fops_closefwlog(struct inode *inode, struct file *file)
{
BTMTK_INFO("%s: Start.", __func__);
return 0;
}
long btmtk_fops_unlocked_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg)
{
long retval = 0;
uint8_t log_tmp = BT_FWLOG_OFF;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
/* only 66xx will use ioctlfwlog, 76xx not used */
/* if (!is_mt66xx(g_sbdev->chip_id)) {
* BTMTK_WARN("%s: not implement!", __func__);
* return 0;
*}
*/
down(&ioctl_mtx);
if (bmain_info->hif_hook.log_hold_sem)
bmain_info->hif_hook.log_hold_sem();
switch (cmd) {
case BT_FWLOG_IOC_ON_OFF:
/* Connsyslogger daemon dynamically enable/disable Picus log */
BTMTK_INFO("[ON_OFF]arg(%lu) bt_on(0x%x) log_on(0x%x) level(0x%x) log_cur(0x%x)",
arg, g_bt_on, g_log_on, g_log_level, g_log_current);
log_tmp = (arg == 0) ? BT_FWLOG_OFF : BT_FWLOG_ON;
if (log_tmp != g_log_on) { // changed
g_log_on = log_tmp;
g_log_current = g_log_on & g_log_level;
if (g_bt_on) {
retval = btmtk_intcmd_set_fw_log(g_log_current);
btmtk_intcmd_wmt_utc_sync();
}
}
break;
case BT_FWLOG_IOC_SET_LEVEL:
/* Connsyslogger daemon dynamically set Picus log level */
BTMTK_INFO("[SET_LEVEL]arg(%lu) bt_on(0x%x) log_on(0x%x) level(0x%x) log_cur(0x%x)",
arg, g_bt_on, g_log_on, g_log_level, g_log_current);
log_tmp = (uint8_t)arg;
if (log_tmp != g_log_level) {
g_log_level = log_tmp;
g_log_current = g_log_on & g_log_level;
if (g_bt_on & g_log_on) {
// driver on and log on
retval = btmtk_intcmd_set_fw_log(g_log_current);
btmtk_intcmd_wmt_utc_sync();
}
}
break;
case BT_FWLOG_IOC_GET_LEVEL:
retval = g_log_level;
BTMTK_INFO("[GET_LEVEL]return %ld", retval);
break;
default:
BTMTK_ERR("Unknown cmd: 0x%08x", cmd);
retval = -EOPNOTSUPP;
break;
}
if (bmain_info->hif_hook.log_release_sem)
bmain_info->hif_hook.log_release_sem();
up(&ioctl_mtx);
return retval;
}
long btmtk_fops_compat_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg)
{
return btmtk_fops_unlocked_ioctlfwlog(filp, cmd, arg);
}
unsigned int btmtk_fops_pollfwlog(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
//if (is_mt66xx(g_sbdev->chip_id)) {
if (bmain_info->hif_hook.log_get_buf_size) {
poll_wait(file, &BT_log_wq, wait);
if (bmain_info->hif_hook.log_get_buf_size() > 0)
mask = (POLLIN | POLLRDNORM);
} else {
poll_wait(file, &g_fwlog->fw_log_inq, wait);
if (skb_queue_len(&g_fwlog->fwlog_queue) > 0)
mask |= POLLIN | POLLRDNORM; /* readable */
}
return mask;
}
static void btmtk_fwdump_wake_lock(void)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: enter", __func__);
__pm_stay_awake(bmain_info->fwdump_ws);
BTMTK_INFO("%s: exit", __func__);
}
static void btmtk_fwdump_wake_unlock(void)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: enter", __func__);
__pm_relax(bmain_info->fwdump_ws);
BTMTK_INFO("%s: exit", __func__);
}
static int btmtk_skb_enq_fwlog(struct btmtk_dev *bdev, void *src, u32 len, u8 type, struct sk_buff_head *queue)
{
struct sk_buff *skb_tmp = NULL;
ulong flags = 0;
int retry = 10, index = FWLOG_TL_SIZE;
do {
skb_tmp = alloc_skb(len + FWLOG_PRSV_LEN, GFP_ATOMIC);
if (skb_tmp != NULL)
break;
else if (retry <= 0) {
pr_info("%s: alloc_skb return 0, error", __func__);
return -ENOMEM;
}
pr_info("%s: alloc_skb return 0, error, retry = %d", __func__, retry);
} while (retry-- > 0);
if (type) {
skb_tmp->data[0] = FWLOG_TYPE;
/* 01 for dongle index */
skb_tmp->data[index] = FWLOG_DONGLE_IDX;
skb_tmp->data[index + 1] = sizeof(bdev->dongle_index);
skb_tmp->data[index + 2] = bdev->dongle_index;
index += (FWLOG_ATTR_RX_LEN_LEN + FWLOG_ATTR_TYPE_LEN);
/* 11 for rx data*/
skb_tmp->data[index] = FWLOG_RX;
if (type == HCI_ACLDATA_PKT || type == HCI_EVENT_PKT || type == HCI_COMMAND_PKT) {
skb_tmp->data[index + 1] = len & 0x00FF;
skb_tmp->data[index + 2] = (len & 0xFF00) >> 8;
skb_tmp->data[index + 3] = type;
index += (HCI_TYPE_SIZE + FWLOG_ATTR_RX_LEN_LEN + FWLOG_ATTR_TYPE_LEN);
} else {
skb_tmp->data[index + 1] = len & 0x00FF;
skb_tmp->data[index + 2] = (len & 0xFF00) >> 8;
index += (FWLOG_ATTR_RX_LEN_LEN + FWLOG_ATTR_TYPE_LEN);
}
memcpy(&skb_tmp->data[index], src, len);
skb_tmp->data[1] = (len + index - FWLOG_TL_SIZE) & 0x00FF;
skb_tmp->data[2] = ((len + index - FWLOG_TL_SIZE) & 0xFF00) >> 8;
skb_tmp->len = len + index;
} else {
memcpy(skb_tmp->data, src, len);
skb_tmp->len = len;
}
spin_lock_irqsave(&g_fwlog->fwlog_lock, flags);
skb_queue_tail(queue, skb_tmp);
spin_unlock_irqrestore(&g_fwlog->fwlog_lock, flags);
return 0;
}
int btmtk_dispatch_fwlog_bluetooth_kpi(struct btmtk_dev *bdev, u8 *buf, int len, u8 type)
{
static u8 fwlog_blocking_warn;
int ret = 0;
if (g_fwlog->btmtk_bluetooth_kpi &&
skb_queue_len(&g_fwlog->fwlog_queue) < FWLOG_BLUETOOTH_KPI_QUEUE_COUNT) {
/* sent event to queue, picus tool will log it for bluetooth KPI feature */
if (btmtk_skb_enq_fwlog(bdev, buf, len, type, &g_fwlog->fwlog_queue) == 0) {
wake_up_interruptible(&g_fwlog->fw_log_inq);
fwlog_blocking_warn = 0;
}
} else {
if (fwlog_blocking_warn == 0) {
fwlog_blocking_warn = 1;
pr_info("btmtk_usb fwlog queue size is full(bluetooth_kpi)");
}
}
return ret;
}
int btmtk_dispatch_fwlog(struct btmtk_dev *bdev, struct sk_buff *skb)
{
static u8 fwlog_picus_blocking_warn;
static u8 fwlog_fwdump_blocking_warn;
int state = BTMTK_STATE_INIT;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if ((bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT) &&
skb->data[0] == 0x6f &&
skb->data[1] == 0xfc) {
static int dump_data_counter;
static int dump_data_length;
state = btmtk_get_chip_state(bdev);
if (state != BTMTK_STATE_FW_DUMP) {
BTMTK_INFO("%s: FW dump begin", __func__);
btmtk_hci_snoop_print_to_log();
/* Print too much log, it may cause kernel panic. */
dump_data_counter = 0;
dump_data_length = 0;
btmtk_set_chip_state(bdev, BTMTK_STATE_FW_DUMP);
btmtk_fwdump_wake_lock();
}
dump_data_counter++;
dump_data_length += skb->len;
/* coredump */
/* print dump data to console */
if (dump_data_counter % 1000 == 0) {
BTMTK_INFO("%s: FW dump on-going, total_packet = %d, total_length = %d",
__func__, dump_data_counter, dump_data_length);
}
/* print dump data to console */
if (dump_data_counter < 20)
BTMTK_INFO("%s: FW dump data (%d): %s",
__func__, dump_data_counter, &skb->data[4]);
/* In the new generation, we will check the keyword of coredump (; coredump end)
* Such as : 79xx
*/
if (skb->data[skb->len - 4] == 'e' &&
skb->data[skb->len - 3] == 'n' &&
skb->data[skb->len - 2] == 'd') {
/* This is the latest coredump packet. */
BTMTK_INFO("%s: FW dump end, dump_data_counter = %d", __func__, dump_data_counter);
/* TODO: Chip reset*/
bmain_info->reset_stack_flag = HW_ERR_CODE_CORE_DUMP;
btmtk_fwdump_wake_unlock();
}
if (skb_queue_len(&g_fwlog->fwlog_queue) < FWLOG_ASSERT_QUEUE_COUNT) {
/* sent picus data to queue, picus tool will log it */
if (btmtk_skb_enq_fwlog(bdev, skb->data, skb->len, 0, &g_fwlog->fwlog_queue) == 0) {
wake_up_interruptible(&g_fwlog->fw_log_inq);
fwlog_fwdump_blocking_warn = 0;
}
} else {
if (fwlog_fwdump_blocking_warn == 0) {
fwlog_fwdump_blocking_warn = 1;
pr_info("btmtk fwlog queue size is full(coredump)");
}
}
if (!bdev->bt_cfg.support_picus_to_host)
return 1;
} else if ((bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT) &&
(skb->data[0] == 0xff || skb->data[0] == 0xfe) &&
skb->data[1] == 0x05 &&
!bdev->bt_cfg.support_picus_to_host) {
/* picus or syslog */
if (skb_queue_len(&g_fwlog->fwlog_queue) < FWLOG_QUEUE_COUNT) {
if (btmtk_skb_enq_fwlog(bdev, skb->data, skb->len,
FWLOG_TYPE, &g_fwlog->fwlog_queue) == 0) {
wake_up_interruptible(&g_fwlog->fw_log_inq);
fwlog_picus_blocking_warn = 0;
}
} else {
if (fwlog_picus_blocking_warn == 0) {
fwlog_picus_blocking_warn = 1;
pr_info("btmtk fwlog queue size is full(picus)");
}
}
return 1;
} else if ((bt_cb(skb)->pkt_type == HCI_EVENT_PKT) &&
skb->data[0] == 0x0E &&
bdev->opcode_usr[0] == skb->data[3] &&
bdev->opcode_usr[1] == skb->data[4]) {
BTMTK_INFO_RAW(skb->data, skb->len, "%s: Discard event from user hci command - ", __func__);
bdev->opcode_usr[0] = 0;
bdev->opcode_usr[1] = 0;
return 1;
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,983 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/input.h>
#include <linux/pm_wakeup.h>
#include <linux/interrupt.h>
#include "btmtk_woble.h"
static int is_support_unify_woble(struct btmtk_dev *bdev)
{
if (bdev->bt_cfg.support_unify_woble) {
if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id) || is_mt7663(bdev->chip_id))
return 1;
else
return 0;
} else {
return 0;
}
}
static void btmtk_woble_wake_lock(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if (bdev->bt_cfg.support_woble_wakelock) {
BTMTK_INFO("%s: enter", __func__);
__pm_stay_awake(bmain_info->woble_ws);
BTMTK_INFO("%s: exit", __func__);
}
}
void btmtk_woble_wake_unlock(struct btmtk_dev *bdev)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
if (bdev->bt_cfg.support_woble_wakelock) {
BTMTK_INFO("%s: enter", __func__);
__pm_relax(bmain_info->woble_ws);
BTMTK_INFO("%s: exit", __func__);
}
}
static int btmtk_send_woble_apcf_reserved(struct btmtk_dev *bdev)
{
u8 reserve_apcf_cmd[RES_APCF_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x30, 0x02, 0x61, 0x02 };
u8 reserve_apcf_event[RES_APCF_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x11 };
int ret = -1;
if (bdev == NULL) {
BTMTK_ERR("%s: Incorrect bdev", __func__);
return ret;
}
if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id))
ret = btmtk_main_send_cmd(bdev, reserve_apcf_cmd, RES_APCF_CMD_LEN,
reserve_apcf_event, RES_APCF_EVT_LEN, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
else
BTMTK_WARN("%s: not support for 0x%x", __func__, bdev->chip_id);
BTMTK_INFO("%s: ret %d", __func__, ret);
return ret;
}
static int btmtk_send_woble_read_BDADDR_cmd(struct btmtk_dev *bdev)
{
u8 cmd[READ_ADDRESS_CMD_LEN] = { 0x01, 0x09, 0x10, 0x00 };
u8 event[READ_ADDRESS_EVT_HDR_LEN] = { 0x04, 0x0E, 0x0A, 0x01, 0x09, 0x10, 0x00, /* AA, BB, CC, DD, EE, FF */ };
int i;
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
if (bdev == NULL || bdev->io_buf == NULL) {
BTMTK_ERR("%s: Incorrect bdev", __func__);
return ret;
}
for (i = 0; i < BD_ADDRESS_SIZE; i++) {
if (bdev->bdaddr[i] != 0) {
ret = 0;
goto done;
}
}
ret = btmtk_main_send_cmd(bdev,
cmd, READ_ADDRESS_CMD_LEN,
event, READ_ADDRESS_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
/*BD address will get in btmtk_rx_work*/
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
done:
BTMTK_INFO("%s, end, ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_unify_woble_suspend_default_cmd(struct btmtk_dev *bdev)
{
u8 cmd[WOBLE_ENABLE_DEFAULT_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x24, 0x01, 0x20, 0x02, 0x00, 0x01,
0x02, 0x01, 0x00, 0x05, 0x10, 0x00, 0x00, 0x40, 0x06,
0x02, 0x40, 0x0A, 0x02, 0x41, 0x0F, 0x05, 0x24, 0x20,
0x04, 0x32, 0x00, 0x09, 0x26, 0xC0, 0x12, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00};
u8 event[WOBLE_ENABLE_DEFAULT_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x00 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, WOBLE_ENABLE_DEFAULT_CMD_LEN,
event, WOBLE_ENABLE_DEFAULT_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
BTMTK_INFO("%s: end. ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_unify_woble_resume_default_cmd(struct btmtk_dev *bdev)
{
u8 cmd[WOBLE_DISABLE_DEFAULT_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00 };
u8 event[WOBLE_DISABLE_DEFAULT_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x01 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, WOBLE_DISABLE_DEFAULT_CMD_LEN,
event, WOBLE_DISABLE_DEFAULT_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
BTMTK_INFO("%s: end. ret = %d", __func__, ret);
return ret;
}
static int btmtk_send_woble_suspend_cmd(struct btmtk_dev *bdev)
{
/* radio off cmd with wobx_mode_disable, used when unify woble off */
u8 radio_off_cmd[RADIO_OFF_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x20, 0x02, 0x00, 0x00 };
u8 event[RADIO_OFF_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x00 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: not support woble, send radio off cmd", __func__);
ret = btmtk_main_send_cmd(bdev,
radio_off_cmd, RADIO_OFF_CMD_LEN,
event, RADIO_OFF_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
return ret;
}
static int btmtk_send_woble_resume_cmd(struct btmtk_dev *bdev)
{
/* radio on cmd with wobx_mode_disable, used when unify woble off */
u8 radio_on_cmd[RADIO_ON_CMD_LEN] = { 0x01, 0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00 };
u8 event[RADIO_ON_EVT_LEN] = { 0x04, 0xE6, 0x02, 0x08, 0x01 };
int ret = 0; /* if successful, 0 */
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
radio_on_cmd, RADIO_ON_CMD_LEN,
event, RADIO_ON_EVT_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
return ret;
}
static int btmtk_set_Woble_APCF_filter_parameter(struct btmtk_dev *bdev)
{
u8 cmd[APCF_FILTER_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x0A,
0x01, 0x00, 0x0A, 0x20, 0x00, 0x20, 0x00, 0x01, 0x80, 0x00 };
u8 event[APCF_FILTER_EVT_HDR_LEN] = { 0x04, 0x0E, 0x07,
0x01, 0x57, 0xFD, 0x00, 0x01/*, 00, 63*/ };
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev, cmd, APCF_FILTER_CMD_LEN,
event, APCF_FILTER_EVT_HDR_LEN, 0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: end ret %d", __func__, ret);
else
ret = 0;
BTMTK_INFO("%s: end ret=%d", __func__, ret);
return ret;
}
/**
* Set APCF manufacturer data and filter parameter
*/
static int btmtk_set_Woble_APCF(struct btmtk_woble *bt_woble)
{
u8 manufactur_data[APCF_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x27, 0x06, 0x00, 0x0A,
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x4B, 0x54, 0x4D,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
u8 event[APCF_EVT_HDR_LEN] = { 0x04, 0x0E, 0x07, 0x01, 0x57, 0xFD, 0x00, /* 0x06 00 63 */ };
int ret = -1;
u8 i = 0;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_apcf[0].length %d",
__func__, bt_woble->woble_setting_apcf[0].length);
/* start to send apcf cmd from woble setting file */
if (bt_woble->woble_setting_apcf[0].length) {
for (i = 0; i < WOBLE_SETTING_COUNT; i++) {
if (!bt_woble->woble_setting_apcf[i].length)
continue;
BTMTK_INFO("%s: apcf_fill_mac[%d].content[0] = 0x%02x", __func__, i,
bt_woble->woble_setting_apcf_fill_mac[i].content[0]);
BTMTK_INFO("%s: apcf_fill_mac_location[%d].length = %d", __func__, i,
bt_woble->woble_setting_apcf_fill_mac_location[i].length);
if ((bt_woble->woble_setting_apcf_fill_mac[i].content[0] == 1) &&
bt_woble->woble_setting_apcf_fill_mac_location[i].length) {
/* need add BD addr to apcf cmd */
memcpy(bt_woble->woble_setting_apcf[i].content +
(*bt_woble->woble_setting_apcf_fill_mac_location[i].content + 1),
bdev->bdaddr, BD_ADDRESS_SIZE);
BTMTK_INFO("%s: apcf[%d], add local BDADDR to location %d", __func__, i,
(*bt_woble->woble_setting_apcf_fill_mac_location[i].content));
}
BTMTK_INFO_RAW(bt_woble->woble_setting_apcf[i].content, bt_woble->woble_setting_apcf[i].length,
"Send woble_setting_apcf[%d] ", i);
ret = btmtk_main_send_cmd(bdev, bt_woble->woble_setting_apcf[i].content,
bt_woble->woble_setting_apcf[i].length, event, APCF_EVT_HDR_LEN, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: manufactur_data error ret %d", __func__, ret);
return ret;
}
}
} else { /* use default */
BTMTK_INFO("%s: use default manufactur data", __func__);
memcpy(manufactur_data + 10, bdev->bdaddr, BD_ADDRESS_SIZE);
ret = btmtk_main_send_cmd(bdev, manufactur_data, APCF_CMD_LEN,
event, APCF_EVT_HDR_LEN, 0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: manufactur_data error ret %d", __func__, ret);
return ret;
}
ret = btmtk_set_Woble_APCF_filter_parameter(bdev);
}
BTMTK_INFO("%s: end ret=%d", __func__, ret);
return 0;
}
static int btmtk_set_Woble_Radio_Off(struct btmtk_woble *bt_woble)
{
int ret = -1;
int length = 0;
char *radio_off = NULL;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_radio_off.length %d", __func__,
bt_woble->woble_setting_radio_off.length);
if (bt_woble->woble_setting_radio_off.length) {
/* start to send radio off cmd from woble setting file */
length = bt_woble->woble_setting_radio_off.length +
bt_woble->woble_setting_wakeup_type.length;
radio_off = kzalloc(length, GFP_KERNEL);
if (!radio_off) {
BTMTK_ERR("%s: alloc memory fail (radio_off)",
__func__);
ret = -ENOMEM;
goto Finish;
}
memcpy(radio_off,
bt_woble->woble_setting_radio_off.content,
bt_woble->woble_setting_radio_off.length);
if (bt_woble->woble_setting_wakeup_type.length) {
memcpy(radio_off + bt_woble->woble_setting_radio_off.length,
bt_woble->woble_setting_wakeup_type.content,
bt_woble->woble_setting_wakeup_type.length);
radio_off[3] += bt_woble->woble_setting_wakeup_type.length;
}
BTMTK_INFO_RAW(radio_off, length, "Send radio off");
ret = btmtk_main_send_cmd(bdev, radio_off, length,
bt_woble->woble_setting_radio_off_comp_event.content,
bt_woble->woble_setting_radio_off_comp_event.length, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
kfree(radio_off);
radio_off = NULL;
} else { /* use default */
BTMTK_INFO("%s: use default radio off cmd", __func__);
ret = btmtk_send_unify_woble_suspend_default_cmd(bdev);
}
Finish:
BTMTK_INFO("%s, end ret=%d", __func__, ret);
return ret;
}
static int btmtk_set_Woble_Radio_On(struct btmtk_woble *bt_woble)
{
int ret = -1;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: woble_setting_radio_on.length %d", __func__,
bt_woble->woble_setting_radio_on.length);
if (bt_woble->woble_setting_radio_on.length) {
/* start to send radio on cmd from woble setting file */
BTMTK_INFO_RAW(bt_woble->woble_setting_radio_on.content,
bt_woble->woble_setting_radio_on.length, "send radio on");
ret = btmtk_main_send_cmd(bdev, bt_woble->woble_setting_radio_on.content,
bt_woble->woble_setting_radio_on.length,
bt_woble->woble_setting_radio_on_comp_event.content,
bt_woble->woble_setting_radio_on_comp_event.length, 0, 0,
BTMTK_TX_PKT_FROM_HOST);
} else { /* use default */
BTMTK_WARN("%s: use default radio on cmd", __func__);
ret = btmtk_send_unify_woble_resume_default_cmd(bdev);
}
BTMTK_INFO("%s, end ret=%d", __func__, ret);
return ret;
}
static int btmtk_del_Woble_APCF_index(struct btmtk_dev *bdev)
{
u8 cmd[APCF_DELETE_CMD_LEN] = { 0x01, 0x57, 0xFD, 0x03, 0x01, 0x01, 0x0A };
u8 event[APCF_DELETE_EVT_HDR_LEN] = { 0x04, 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00, 0x01, /* 00, 63 */ };
int ret = -1;
BTMTK_INFO("%s, enter", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, APCF_DELETE_CMD_LEN,
event, APCF_DELETE_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: got error %d", __func__, ret);
BTMTK_INFO("%s, end", __func__);
return ret;
}
static int btmtk_set_Woble_APCF_Resume(struct btmtk_woble *bt_woble)
{
u8 event[APCF_RESUME_EVT_HDR_LEN] = { 0x04, 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00 };
u8 i = 0;
int ret = -1;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s, enter, bt_woble->woble_setting_apcf_resume[0].length= %d",
__func__, bt_woble->woble_setting_apcf_resume[0].length);
if (bt_woble->woble_setting_apcf_resume[0].length) {
BTMTK_INFO("%s: handle leave woble apcf from file", __func__);
for (i = 0; i < WOBLE_SETTING_COUNT; i++) {
if (!bt_woble->woble_setting_apcf_resume[i].length)
continue;
BTMTK_INFO_RAW(bt_woble->woble_setting_apcf_resume[i].content,
bt_woble->woble_setting_apcf_resume[i].length,
"%s: send apcf resume %d:", __func__, i);
ret = btmtk_main_send_cmd(bdev,
bt_woble->woble_setting_apcf_resume[i].content,
bt_woble->woble_setting_apcf_resume[i].length,
event, APCF_RESUME_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0) {
BTMTK_ERR("%s: Send apcf resume fail %d", __func__, ret);
return ret;
}
}
} else { /* use default */
BTMTK_WARN("%s: use default apcf resume cmd", __func__);
ret = btmtk_del_Woble_APCF_index(bdev);
if (ret < 0)
BTMTK_ERR("%s: btmtk_del_Woble_APCF_index return fail %d", __func__, ret);
}
BTMTK_INFO("%s, end", __func__);
return ret;
}
static int btmtk_load_woble_setting(char *bin_name,
struct device *dev, u32 *code_len, struct btmtk_woble *bt_woble)
{
int err;
struct btmtk_dev *bdev = bt_woble->bdev;
*code_len = 0;
err = btmtk_load_code_from_setting_files(bin_name, dev, code_len, bdev);
if (err) {
BTMTK_ERR("woble_setting btmtk_load_code_from_setting_files failed!!");
goto LOAD_END;
}
err = btmtk_load_fw_cfg_setting("APCF",
bt_woble->woble_setting_apcf, WOBLE_SETTING_COUNT, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_ADD_MAC",
bt_woble->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_ADD_MAC_LOCATION",
bt_woble->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOOFF", &bt_woble->woble_setting_radio_off, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
switch (bdev->bt_cfg.unify_woble_type) {
case 0:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_LEGACY", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
case 1:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_WAVEFORM", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
case 2:
err = btmtk_load_fw_cfg_setting("WAKEUP_TYPE_IR", &bt_woble->woble_setting_wakeup_type, 1,
bdev->setting_file, FW_CFG_INX_LEN_2);
break;
default:
BTMTK_WARN("%s: unify_woble_type unknown(%d)", __func__, bdev->bt_cfg.unify_woble_type);
}
if (err)
BTMTK_WARN("%s: Parse unify_woble_type(%d) failed", __func__, bdev->bt_cfg.unify_woble_type);
err = btmtk_load_fw_cfg_setting("RADIOOFF_STATUS_EVENT",
&bt_woble->woble_setting_radio_off_status_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOOFF_COMPLETE_EVENT",
&bt_woble->woble_setting_radio_off_comp_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON",
&bt_woble->woble_setting_radio_on, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON_STATUS_EVENT",
&bt_woble->woble_setting_radio_on_status_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("RADIOON_COMPLETE_EVENT",
&bt_woble->woble_setting_radio_on_comp_event, 1, bdev->setting_file, FW_CFG_INX_LEN_2);
if (err)
goto LOAD_END;
err = btmtk_load_fw_cfg_setting("APCF_RESUME",
bt_woble->woble_setting_apcf_resume, WOBLE_SETTING_COUNT, bdev->setting_file, FW_CFG_INX_LEN_2);
LOAD_END:
/* release setting file memory */
if (bdev) {
kfree(bdev->setting_file);
bdev->setting_file = NULL;
}
if (err)
BTMTK_ERR("%s: error return %d", __func__, err);
return err;
}
static void btmtk_check_wobx_debug_log(struct btmtk_dev *bdev)
{
/* 0xFF, 0xFF, 0xFF, 0xFF is log level */
u8 cmd[CHECK_WOBX_DEBUG_CMD_LEN] = { 0X01, 0xCE, 0xFC, 0x04, 0xFF, 0xFF, 0xFF, 0xFF };
u8 event[CHECK_WOBX_DEBUG_EVT_HDR_LEN] = { 0x04, 0xE8 };
int ret = -1;
BTMTK_INFO("%s: begin", __func__);
ret = btmtk_main_send_cmd(bdev,
cmd, CHECK_WOBX_DEBUG_CMD_LEN,
event, CHECK_WOBX_DEBUG_EVT_HDR_LEN,
0, 0, BTMTK_TX_PKT_FROM_HOST);
if (ret < 0)
BTMTK_ERR("%s: failed(%d)", __func__, ret);
/* Driver just print event to kernel log in rx_work,
* Please reference wiki to know what it is.
*/
}
static int btmtk_handle_leaving_WoBLE_state(struct btmtk_woble *bt_woble)
{
int ret = -1;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: begin", __func__);
fstate = btmtk_fops_get_state(bdev);
if (!bdev->bt_cfg.support_woble_for_bt_disable) {
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not opened, return", __func__);
return 0;
}
}
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d), need to start traffic before leaving woble",
__func__, fstate);
/* start traffic to recv event*/
ret = bmain_info->hif_hook.open(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_open failed", __func__);
goto Finish;
}
}
if (is_support_unify_woble(bdev)) {
ret = btmtk_set_Woble_Radio_On(bt_woble);
if (ret < 0)
goto Finish;
ret = btmtk_set_Woble_APCF_Resume(bt_woble);
if (ret < 0)
goto Finish;
} else {
/* radio on cmd with wobx_mode_disable, used when unify woble off */
ret = btmtk_send_woble_resume_cmd(bdev);
}
Finish:
if (ret < 0) {
BTMTK_INFO("%s: woble_resume_fail!!!", __func__);
} else {
/* It's wobx debug log method. */
btmtk_check_wobx_debug_log(bdev);
if (fstate != BTMTK_FOPS_STATE_OPENED) {
ret = btmtk_send_deinit_cmds(bdev);
if (ret < 0) {
BTMTK_ERR("%s, btmtk_send_deinit_cmds failed", __func__);
goto exit;
}
BTMTK_WARN("%s: fops is not open(%d), need to stop traffic after leaving woble",
__func__, fstate);
/* stop traffic to stop recv data from fw*/
ret = bmain_info->hif_hook.close(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_close failed", __func__);
goto exit;
}
} else
bdev->power_state = BTMTK_DONGLE_STATE_POWER_ON;
BTMTK_INFO("%s: success", __func__);
}
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
static int btmtk_handle_entering_WoBLE_state(struct btmtk_woble *bt_woble)
{
int ret = -1;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
int state = BTMTK_STATE_INIT;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: begin", __func__);
fstate = btmtk_fops_get_state(bdev);
if (!bdev->bt_cfg.support_woble_for_bt_disable) {
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d)!, return", __func__, fstate);
return 0;
}
}
state = btmtk_get_chip_state(bdev);
if (state == BTMTK_STATE_FW_DUMP) {
BTMTK_WARN("%s: FW dumping ongoing, don't send any cmd to FW!!!", __func__);
goto Finish;
}
if (bdev->chip_reset || bdev->subsys_reset) {
BTMTK_ERR("%s chip_reset is %d, subsys_reset is %d", __func__,
bdev->chip_reset, bdev->subsys_reset);
goto Finish;
}
/* Power on first if state is power off */
ret = btmtk_reset_power_on(bdev);
if (ret < 0) {
BTMTK_ERR("%s: reset power_on fail return", __func__);
goto Finish;
}
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open yet(%d), need to start traffic before enter woble",
__func__, fstate);
/* start traffic to recv event*/
ret = bmain_info->hif_hook.open(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_open failed", __func__);
goto Finish;
}
}
if (is_support_unify_woble(bdev)) {
do {
typedef ssize_t (*func) (u16 u16Key, const char *buf, size_t size);
char *func_name = "MDrv_PM_Write_Key";
func pFunc = NULL;
ssize_t sret = 0;
u8 buf = 0;
pFunc = (func) btmtk_kallsyms_lookup_name(func_name);
if (pFunc && bdev->bt_cfg.unify_woble_type == 1) {
buf = 1;
sret = pFunc(PM_KEY_BTW, &buf, sizeof(u8));
BTMTK_INFO("%s: Invoke %s, buf = %d, sret = %zd", __func__,
func_name, buf, sret);
} else {
BTMTK_WARN("%s: No Exported Func Found [%s]", __func__, func_name);
}
} while (0);
ret = btmtk_send_woble_apcf_reserved(bdev);
if (ret < 0)
goto STOP_TRAFFIC;
ret = btmtk_send_woble_read_BDADDR_cmd(bdev);
if (ret < 0)
goto STOP_TRAFFIC;
ret = btmtk_set_Woble_APCF(bt_woble);
if (ret < 0)
goto STOP_TRAFFIC;
ret = btmtk_set_Woble_Radio_Off(bt_woble);
if (ret < 0)
goto STOP_TRAFFIC;
} else {
/* radio off cmd with wobx_mode_disable, used when unify woble off */
ret = btmtk_send_woble_suspend_cmd(bdev);
}
STOP_TRAFFIC:
if (fstate != BTMTK_FOPS_STATE_OPENED) {
BTMTK_WARN("%s: fops is not open(%d), need to stop traffic after enter woble",
__func__, fstate);
/* stop traffic to stop recv data from fw*/
ret = bmain_info->hif_hook.close(bdev->hdev);
if (ret < 0) {
BTMTK_ERR("%s, cif_close failed", __func__);
goto Finish;
}
}
Finish:
if (ret) {
bdev->power_state = BTMTK_DONGLE_STATE_ERROR;
btmtk_woble_wake_lock(bdev);
}
BTMTK_INFO("%s: end ret = %d, power_state =%d", __func__, ret, bdev->power_state);
return ret;
}
int btmtk_woble_suspend(struct btmtk_woble *bt_woble)
{
int ret = 0;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
struct btmtk_dev *bdev = bt_woble->bdev;
BTMTK_INFO("%s: enter", __func__);
fstate = btmtk_fops_get_state(bdev);
if (!is_support_unify_woble(bdev) && (fstate != BTMTK_FOPS_STATE_OPENED)) {
BTMTK_WARN("%s: when not support woble, in bt off state, do nothing!", __func__);
goto exit;
}
ret = btmtk_handle_entering_WoBLE_state(bt_woble);
if (ret)
BTMTK_ERR("%s: btmtk_handle_entering_WoBLE_state return fail %d", __func__, ret);
if (bdev->bt_cfg.support_woble_by_eint) {
if (bt_woble->wobt_irq != 0 && atomic_read(&(bt_woble->irq_enable_count)) == 0) {
BTMTK_INFO("enable BT IRQ:%d", bt_woble->wobt_irq);
irq_set_irq_wake(bt_woble->wobt_irq, 1);
enable_irq(bt_woble->wobt_irq);
atomic_inc(&(bt_woble->irq_enable_count));
} else
BTMTK_INFO("irq_enable count:%d", atomic_read(&(bt_woble->irq_enable_count)));
}
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
int btmtk_woble_resume(struct btmtk_woble *bt_woble)
{
int ret = -1;
unsigned char fstate = BTMTK_FOPS_STATE_INIT;
struct btmtk_dev *bdev = bt_woble->bdev;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_INFO("%s: enter", __func__);
fstate = btmtk_fops_get_state(bdev);
if (!is_support_unify_woble(bdev) && (fstate != BTMTK_FOPS_STATE_OPENED)) {
BTMTK_WARN("%s: when not support woble, in bt off state, do nothing!", __func__);
goto exit;
}
if (bdev->power_state == BTMTK_DONGLE_STATE_ERROR) {
BTMTK_INFO("%s: In BTMTK_DONGLE_STATE_ERROR(Could suspend caused), do assert", __func__);
btmtk_send_assert_cmd(bdev);
ret = -EBADFD;
goto exit;
}
if (bdev->bt_cfg.support_woble_by_eint) {
if (bt_woble->wobt_irq != 0 && atomic_read(&(bt_woble->irq_enable_count)) == 1) {
BTMTK_INFO("disable BT IRQ:%d", bt_woble->wobt_irq);
atomic_dec(&(bt_woble->irq_enable_count));
disable_irq_nosync(bt_woble->wobt_irq);
} else
BTMTK_INFO("irq_enable count:%d", atomic_read(&(bt_woble->irq_enable_count)));
}
ret = btmtk_handle_leaving_WoBLE_state(bt_woble);
if (ret < 0) {
BTMTK_ERR("%s: btmtk_handle_leaving_WoBLE_state return fail %d", __func__, ret);
/* avoid rtc to to suspend again, do FW dump first */
btmtk_woble_wake_lock(bdev);
btmtk_send_assert_cmd(bdev);
goto exit;
}
if (bdev->bt_cfg.reset_stack_after_woble
&& bmain_info->reset_stack_flag == HW_ERR_NONE
&& fstate == BTMTK_FOPS_STATE_OPENED)
bmain_info->reset_stack_flag = HW_ERR_CODE_RESET_STACK_AFTER_WOBLE;
btmtk_send_hw_err_to_host(bdev);
BTMTK_INFO("%s: end(%d), reset_stack_flag = %d, fstate = %d", __func__, ret,
bmain_info->reset_stack_flag, fstate);
exit:
BTMTK_INFO("%s: end", __func__);
return ret;
}
static irqreturn_t btmtk_woble_isr(int irq, struct btmtk_woble *bt_woble)
{
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
BTMTK_DBG("%s begin", __func__);
disable_irq_nosync(bt_woble->wobt_irq);
atomic_dec(&(bt_woble->irq_enable_count));
BTMTK_INFO("disable BT IRQ, call wake lock");
__pm_wakeup_event(bmain_info->eint_ws, WAIT_POWERKEY_TIMEOUT);
input_report_key(bt_woble->WoBLEInputDev, KEY_WAKEUP, 1);
input_sync(bt_woble->WoBLEInputDev);
input_report_key(bt_woble->WoBLEInputDev, KEY_WAKEUP, 0);
input_sync(bt_woble->WoBLEInputDev);
BTMTK_DBG("%s end", __func__);
return IRQ_HANDLED;
}
static int btmtk_RegisterBTIrq(struct btmtk_woble *bt_woble)
{
struct device_node *eint_node = NULL;
int interrupts[2];
BTMTK_DBG("%s begin", __func__);
eint_node = of_find_compatible_node(NULL, NULL, "mediatek,woble_eint");
if (eint_node) {
BTMTK_INFO("Get woble_eint compatible node");
bt_woble->wobt_irq = irq_of_parse_and_map(eint_node, 0);
BTMTK_INFO("woble_irq number:%d", bt_woble->wobt_irq);
if (bt_woble->wobt_irq) {
of_property_read_u32_array(eint_node, "interrupts",
interrupts, ARRAY_SIZE(interrupts));
bt_woble->wobt_irqlevel = interrupts[1];
if (request_irq(bt_woble->wobt_irq, (void *)btmtk_woble_isr,
bt_woble->wobt_irqlevel, "woble-eint", bt_woble->bdev))
BTMTK_INFO("WOBTIRQ LINE NOT AVAILABLE!!");
else {
BTMTK_INFO("disable BT IRQ");
disable_irq_nosync(bt_woble->wobt_irq);
}
} else
BTMTK_INFO("can't find woble_eint irq");
} else {
bt_woble->wobt_irq = 0;
BTMTK_INFO("can't find woble_eint compatible node");
}
BTMTK_DBG("%s end", __func__);
return 0;
}
static int btmtk_woble_input_init(struct btmtk_woble *bt_woble)
{
int ret = 0;
bt_woble->WoBLEInputDev = input_allocate_device();
if (!bt_woble->WoBLEInputDev || IS_ERR(bt_woble->WoBLEInputDev)) {
BTMTK_ERR("input_allocate_device error");
return -ENOMEM;
}
bt_woble->WoBLEInputDev->name = "WOBLE_INPUT_DEVICE";
bt_woble->WoBLEInputDev->id.bustype = BUS_HOST;
bt_woble->WoBLEInputDev->id.vendor = 0x0002;
bt_woble->WoBLEInputDev->id.product = 0x0002;
bt_woble->WoBLEInputDev->id.version = 0x0002;
__set_bit(EV_KEY, bt_woble->WoBLEInputDev->evbit);
__set_bit(KEY_WAKEUP, bt_woble->WoBLEInputDev->keybit);
ret = input_register_device(bt_woble->WoBLEInputDev);
if (ret < 0) {
input_free_device(bt_woble->WoBLEInputDev);
BTMTK_ERR("input_register_device %d", ret);
return ret;
}
return ret;
}
static void btmtk_woble_input_deinit(struct btmtk_woble *bt_woble)
{
if (bt_woble->WoBLEInputDev) {
input_unregister_device(bt_woble->WoBLEInputDev);
input_free_device(bt_woble->WoBLEInputDev);
bt_woble->WoBLEInputDev = NULL;
}
}
static void btmtk_free_woble_setting_file(struct btmtk_woble *bt_woble)
{
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(bt_woble->woble_setting_apcf_resume, WOBLE_SETTING_COUNT);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off_status_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_off_comp_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on_status_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_radio_on_comp_event, 1);
btmtk_free_fw_cfg_struct(&bt_woble->woble_setting_wakeup_type, 1);
bt_woble->woble_setting_len = 0;
kfree(bt_woble->woble_setting_file_name);
bt_woble->woble_setting_file_name = NULL;
}
int btmtk_woble_initialize(struct btmtk_dev *bdev, struct btmtk_woble *bt_woble)
{
int err = 0;
struct btmtk_main_info *bmain_info = btmtk_get_main_info();
bt_woble->bdev = bdev;
/* Need to add Woble flow */
if (is_support_unify_woble(bdev)) {
if (bt_woble->woble_setting_file_name == NULL) {
bt_woble->woble_setting_file_name = kzalloc(MAX_BIN_FILE_NAME_LEN, GFP_KERNEL);
if (!bt_woble->woble_setting_file_name) {
BTMTK_ERR("%s: alloc memory fail (bt_woble->woble_setting_file_name)", __func__);
err = -1;
goto end;
}
}
if (is_mt7663(bdev->chip_id))
memcpy(bt_woble->woble_setting_file_name, WOBLE_SETTING_FILE_NAME_7663,
sizeof(WOBLE_SETTING_FILE_NAME_7663));
if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id))
memcpy(bt_woble->woble_setting_file_name, WOBLE_SETTING_FILE_NAME_7961,
sizeof(WOBLE_SETTING_FILE_NAME_7961));
BTMTK_INFO("%s: woble setting file name is %s", __func__, bt_woble->woble_setting_file_name);
btmtk_load_woble_setting(bt_woble->woble_setting_file_name,
bdev->intf_dev,
&bt_woble->woble_setting_len,
bt_woble);
/* if reset_stack is true, when chip reset is done, we need to power on chip to do
* reset stack
*/
if (bmain_info->reset_stack_flag) {
err = btmtk_reset_power_on(bdev);
if (err < 0) {
BTMTK_ERR("reset power on failed!");
goto err;
}
}
}
if (bdev->bt_cfg.support_woble_by_eint) {
btmtk_woble_input_init(bt_woble);
btmtk_RegisterBTIrq(bt_woble);
}
return 0;
err:
btmtk_free_woble_setting_file(bt_woble);
end:
return err;
}
void btmtk_woble_uninitialize(struct btmtk_woble *bt_woble)
{
struct btmtk_dev *bdev = bt_woble->bdev;
if (bdev == NULL) {
BTMTK_ERR("%s: bdev == NULL", __func__);
return;
}
BTMTK_INFO("%s begin", __func__);
if (bdev->bt_cfg.support_woble_by_eint) {
if (bt_woble->wobt_irq != 0 && atomic_read(&(bt_woble->irq_enable_count)) == 1) {
BTMTK_INFO("disable BT IRQ:%d", bt_woble->wobt_irq);
atomic_dec(&(bt_woble->irq_enable_count));
disable_irq_nosync(bt_woble->wobt_irq);
} else
BTMTK_INFO("irq_enable count:%d", atomic_read(&(bt_woble->irq_enable_count)));
free_irq(bt_woble->wobt_irq, bdev);
btmtk_woble_input_deinit(bt_woble);
}
btmtk_free_woble_setting_file(bt_woble);
bt_woble->bdev = NULL;
}

View file

@ -0,0 +1,30 @@
# bt.cfg,now just parse '#' for annotation
SUPPORT_UNIFY_WOBLE 1
# this item is valid only when SUPPORT_UNIFY_WOBLE enabled. 0: LEGACY, LOW or HIGH. 1: Waveform. 2: IR
UNIFY_WOBLE_TYPE 1
SUPPORT_LEGACY_WOBLE 0
SUPPORT_WOBLE_BY_EINT 0
BT_DONGLE_RESET_GPIO_PIN 220
SAVE_FW_DUMP_IN_KERNEL 0
# this item is valid only when support save fw_dump in kernel
SYS_LOG_FILE_NAME /sdcard/bt_sys_log
# this item is valid only when support save fw_dump in kernel
FW_DUMP_FILE_NAME /sdcard/bt_fw_dump
SUPPORT_DONGLE_RESET 1
SUPPORT_FULL_FW_DUMP 0
SUPPORT_WOBLE_WAKELOCK 1
SUPPORT_WOBLE_FOR_BT_DISABLE 1
RESET_STACK_AFTER_WOBLE 1
SUPPORT_BT_SINGLE_SKU 1
SUPPORT_PICUS_TO_HOST 0
SUPPORT_AUTO_PICUS 0
PICUS_ENABLE_COMMAND: 0x01, 0x5D, 0xFC, 0x04, 0x00, 0x00, 0x02, 0x02,
PICUS_FILTER_COMMAND: 0x5F, 0xFC, 0x2E, 0x50, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
WMT_CMD000: 0x6F, 0xFC, 0x06, 0x01, 0x06, 0x02, 0x00, 0x03, 0x01,
# phase1 means this wmt cmd should be send to FW after download patch or after BT power on
# this wmt cmd used to enable bus vio
PHASE1_WMT_CMD000: 0x6F, 0xFC, 0x08, 0x01, 0x02, 0x04, 0x00, 0x1D, 0x01, 0x00, 0x00,
#vendor cmd need to send to FW after BT power on
VENDOR_CMD000: 0x96, 0xFD, 0x18, 0x03, 0x03, 0x06, 0x0E, 0x03, 0x03, 0x07, 0x0E, 0x03, 0x03, 0x08, 0x0E, 0x03, 0x03, 0x0B, 0x11, 0x03, 0x03, 0x0D, 0x0C, 0x03, 0x03, 0x13, 0x10,

View file

@ -0,0 +1,28 @@
# File path depends on kernel request_firmware API, EX: /etc/firmware or /lib/firmware
# Format:
# 1. ":" is necessary between name & command
# 2. HEX need prefix '0x'
# 3. Each HEX end need ','
# Only support 10 groups setting, add scan interval and window
Turnkey:
APCF00:0x57, 0xFD, 0x27, 0x06, 0x00, 0x0A, 0x46, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x4B, 0x54, 0x4D, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
APCF_ADD_MAC00:0x01,
APCF_ADD_MAC_LOCATION00:0x09,
APCF01:0x57, 0xFD, 0x0A, 0x01, 0x00, 0x0A, 0x20, 0x00, 0x20, 0x00, 0x01, 0x80, 0x00,
APCF_ADD_MAC01:0x00,
APCF_ADD_MAC_LOCATION01:0x00,
RADIOOFF00:0xC9, 0xFC, 0x1E, 0x01, 0x20, 0x02, 0x00, 0x01, 0x02, 0x01, 0x00, 0x02, 0x40, 0x0A, 0x02, 0x41, 0x0F, 0x05, 0x24, 0x20, 0x04, 0x32, 0x00, 0x09, 0x26, 0xC0, 0x12, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
WAKEUP_TYPE_LEGACY00:0x05, 0x10, 0x00, 0x00, 0x6B, 0x00, 0x04, 0x42, 0x09, 0x01, 0x02, 0x0A, 0x48, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x80,
WAKEUP_TYPE_WAVEFORM00:0x05, 0x10, 0x00, 0x00, 0x20, 0x00, 0x04, 0x42, 0x09, 0x01, 0x02, 0xA2, 0x48, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x00, 0xFE, 0xA5, 0xA5, 0x00, 0x00, 0x10, 0x00, 0x4A, 0xFF, 0x5A, 0x5A, 0x00, 0x00, 0x10, 0x00, 0xB4, 0xFE, 0x96, 0x96, 0x00, 0x00, 0x10, 0x00, 0x2C, 0xFF, 0x69, 0x69, 0x00, 0x00, 0x10, 0x00, 0xD2, 0xFE, 0x78, 0x78, 0x00, 0x00, 0x10, 0x00, 0xF0, 0xFE, 0x11, 0x11, 0x00, 0x00, 0x10, 0x00, 0x22, 0xFE, 0x22, 0x22, 0x00, 0x00, 0x10, 0x00, 0x44, 0xFE, 0x33, 0x33, 0x00, 0x00, 0x10, 0x00, 0x66, 0xFE, 0x44, 0x44, 0x00, 0x00, 0x10, 0x00, 0x88, 0xFE, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00, 0xAA, 0xFE, 0x66, 0x66, 0x00, 0x00, 0x10, 0x00, 0xCC, 0xFE, 0x77, 0x77, 0x00, 0x00, 0x10, 0x00, 0xEE, 0xFE, 0x88, 0x88, 0x00, 0x00, 0x10, 0x00, 0x10, 0xFF, 0x99, 0x99, 0x00, 0x00, 0x10, 0x00, 0x32, 0xFF, 0xAA, 0xAA, 0x00, 0x00, 0x10, 0x00, 0x54, 0xFF, 0xBB, 0xBB, 0x00, 0x00, 0x10, 0x00, 0x76, 0xFF, 0xCC, 0xCC, 0x00, 0x00, 0x10, 0x00, 0x98, 0xFF, 0xDD, 0xDD, 0x00, 0x00, 0x10, 0x00, 0xBA, 0xFF, 0xEE, 0xEE, 0x00, 0x00, 0x10, 0x00, 0xDC, 0xFF,
WAKEUP_TYPE_IR00:
RADIOOFF_STATUS_EVENT00:0x0f, 0x04, 0x00, 0x01, 0xC9, 0xFC,
RADIOOFF_COMPLETE_EVENT00:0xe6, 0x02, 0x08, 0x00,
RADIOON00:0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00,
RADIOON_STATUS_EVENT00:0x0F, 0x04, 0x00, 0x01, 0xC9, 0xFC,
RADIOON_COMPLETE_EVENT00:0xe6, 0x02, 0x08, 0x01,
APCF_RESUME00:0x57, 0xFD, 0x03, 0x01, 0x01, 0x0A,

View file

@ -0,0 +1,570 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_BTIF_H_
#define _BTMTK_BTIF_H_
#include <net/bluetooth/bluetooth.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/workqueue.h>
#include <linux/pm_qos.h>
#include "conninfra.h"
#include "conn_power_throttling.h"
#include "btmtk_define.h"
#include "btmtk_main.h"
#undef __init
#undef __exit
#define __init
#define __exit
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/* Preamble length for HCI Command:
** 2-bytes for opcode and 1 byte for length
*/
#define HCI_CMD_PREAMBLE_SIZE 3
/* Preamble length for ACL Data:
** 2-byte for Handle and 2 byte for length
*/
#define HCI_ACL_PREAMBLE_SIZE 4
/* Preamble length for SCO Data:
** 2-byte for Handle and 1 byte for length
*/
#define HCI_SCO_PREAMBLE_SIZE 3
/* Preamble length for HCI Event:
** 1-byte for opcode and 1 byte for length
*/
#define HCI_EVT_PREAMBLE_SIZE 2
#define HCI_CMD_HDR_LEN (HCI_CMD_PREAMBLE_SIZE + 1)
#define HCI_EVT_HDR_LEN (HCI_EVT_PREAMBLE_SIZE)
/* WMT Event */
#define WMT_EVT_OFFSET (HCI_EVT_HDR_LEN)
#define WMT_EVT_HDR_LEN (4)
#define WAKE_LOCK_NAME_SIZE (16)
#define MT_BGF2AP_BTIF_WAKEUP_IRQ_ID 312 /* temp */
#define MT_BGF2AP_SW_IRQ_ID 271 /* temp */
#define IRQ_NAME_SIZE (20)
#define MAX_STATE_MONITORS (2)
#define RING_BUFFER_SIZE (16384)
#define MAX_DUMP_DATA_SIZE (20)
#define MAX_DUMP_QUEUE_SIZE (100)
/* BT HCI Cmd/Evt */
#define HCI_EVT_COMPLETE_EVT 0x0E
#define HCI_EVT_STATUS_EVT 0x0F
#define HCI_EVT_CC_STATUS_SUCCESS 0x00
#define HCI_CMD_DY_ADJ_PWR_QUERY 0x01
#define HCI_CMD_DY_ADJ_PWR_SET 0x02
/* sleep parameter */
#define USLEEP_1MS_L (1000)
#define USLEEP_1MS_H (1100)
#define USLEEP_5MS_L (5000)
#define USLEEP_5MS_H (5200)
/* function return value*/
#define RET_PWRON_WHOLE_CHIP_RESET (99)
#define RET_SWIRQ_ST_FAIL (-98)
#undef SUPPORT_BT_THREAD
#define SUPPORT_BT_THREAD (1)
#define SUPPORT_COREDUMP (1)
#define DRIVER_CMD_CHECK (1)
typedef void (*BT_RX_EVENT_CB) (void);
typedef int (*BT_RX_EVT_HANDLER_CB) (uint8_t *buf, int len);
enum wmt_evt_result {
WMT_EVT_SUCCESS,
WMT_EVT_FAIL,
WMT_EVT_INVALID,
WMT_EVT_SKIP // normal packet, not for wmt cmd
};
typedef enum wmt_pkt_dir {
WMT_PKT_DIR_HOST_TO_CHIP = 1, /* command */
WMT_PKT_DIR_CHIP_TO_HOST = 2 /* event */
} WMT_PKT_DIR_T;
typedef enum wmt_opcode {
WMT_OPCODE_FUNC_CTRL = 0x06,
WMT_OPCODE_RF_CAL = 0x14,
WMT_OPCODE_0XF0 = 0xF0,
WMT_OPCODE_ANT_EFEM = 0x55,
WMT_OPCODE_MAX
} WMT_OPCODE_T;
enum wmt_blank_state {
// wmt parameter: 0(screen off) / 1(screen on)
WMT_PARA_SCREEN_OFF = 0,
WMT_PARA_SCREEN_ON = 1
};
enum bt_irq_type {
BGF2AP_BTIF_WAKEUP_IRQ,
BGF2AP_SW_IRQ,
BT_CONN2AP_SW_IRQ,
BGF2AP_IRQ_MAX
};
struct bt_irq_ctrl {
uint32_t irq_num;
uint8_t name[IRQ_NAME_SIZE];
u_int8_t active;
spinlock_t lock;
unsigned long flags;
};
struct btif_deepidle_ctrl {
struct semaphore sem;
struct workqueue_struct *task;
struct delayed_work work;
u_int8_t is_dpidle;
};
enum bt_reset_level {
RESET_LEVEL_NONE,
RESET_LEVEL_0_5, /* subsys reset */
RESET_LEVEL_0, /* whole chip reset */
RESET_LEVEL_MAX
};
struct bt_wake_lock {
struct wakeup_source *ws;
uint8_t name[WAKE_LOCK_NAME_SIZE];
#if (PM_QOS_CONTROL == 1)
struct pm_qos_request qos_req;
#endif
};
enum bt_psm_state {
PSM_ST_SLEEP,
PSM_ST_NORMAL_TR,
PSM_ST_MAX
};
struct bt_psm_ctrl {
enum bt_psm_state state;
u_int8_t sleep_flag; /* sleep notify */
u_int8_t wakeup_flag; /* wakeup notify */
struct completion comp; /* request completion */
u_int8_t result; /* request result */
struct bt_wake_lock wake_lock;
u_int8_t force_on;
};
enum bt_direction_type {
NONE,
TX,
RX
};
struct bt_dump_packet {
enum bt_direction_type direction_type;
u_int16_t data_length;
u_int8_t data[MAX_DUMP_DATA_SIZE];
struct timespec64 kerneltime;
struct timespec64 time;
};
struct bt_dump_queue {
struct bt_dump_packet queue[MAX_DUMP_QUEUE_SIZE];
int32_t index;
bool full;
spinlock_t lock;
};
#define BT_BTIF_DUMP_OWN_CR 0x01
#define BT_BTIF_DUMP_REG 0x02
#define BT_BTIF_DUMP_LOG 0x04
#define BT_BTIF_DUMP_DMA 0x08
#define BT_BTIF_DUMP_ALL 0x0F
struct sched_param {
int sched_priority;
};
struct bt_dbg_st {
bool rt_thd_enable;
uint8_t rx_buf_ctrl;
};
typedef void (*BT_STATE_CHANGE_CB) (uint8_t state);
struct wmt_pkt_param {
/* Extensible union */
union {
struct {
uint8_t subsys; /* subsys type:
00 - BT
01 - FM (obsolete)
02 - GPS (obsolete)
03 - WIFI (obsolete) */
uint8_t on; /* 00 - off, 01 - on */
} func_ctrl_cmd;
struct {
uint8_t status;
} func_ctrl_evt;
struct {
uint8_t subop; /* sub operation:
01 - calibration start (obsolete)
02 - restore indication (obsolete)
03 - backup */
} rf_cal_cmd;
struct {
uint8_t status;
uint8_t subop;
uint8_t start_addr[4]; /* start address of cal data, little endian */
uint8_t data_len[2]; /* cal data length, little endian */
uint8_t ready_addr[4]; /* ready bit address, little endian */
} rf_cal_evt;
uint8_t evt_buf[16];
} u;
};
struct bt_rf_cal_data_backup {
uint32_t start_addr; /* calibration data start address on sysram */
uint32_t ready_addr; /* ready bit address on sysram to mark calibration data is ready */
uint8_t *p_cache_buf; /* buffer to cache the calibration data */
uint16_t cache_len; /* cached data length */
};
struct bt_ring_buffer_mgmt {
uint8_t buf[RING_BUFFER_SIZE];
uint32_t write_idx;
uint32_t read_idx;
spinlock_t lock;
};
/*
* WMT Packet Format
*
* NOTICE:
* It is recommanded to define each field in bytes, otherwise we should consider the
* memory alignment by compiler and use __attribute__((__packed__)) if needed.
*/
struct wmt_pkt_hdr {
uint8_t dir;
uint8_t opcode;
uint8_t param_len[2]; /* 2 bytes length, little endian */
};
struct wmt_pkt {
struct wmt_pkt_hdr hdr;
struct wmt_pkt_param params;
};
struct bt_internal_cmd {
uint8_t waiting_event;
uint16_t pending_cmd_opcode;
uint8_t wmt_opcode;
struct completion comp; /* command completion */
u_int8_t result; /* command result */
struct wmt_pkt_param wmt_event_params;
};
#if (DRIVER_CMD_CHECK == 1)
struct bt_cmd_node {
uint16_t opcode;
struct bt_cmd_node *next;
};
struct bt_cmd_queue {
uint8_t size;
struct bt_cmd_node *head, *tail;
spinlock_t lock;
};
#endif
struct bt_DyPwr_st {
int8_t dy_max_dbm;
int8_t dy_min_dbm;
int8_t lp_bdy_dbm;
int8_t fw_sel_dbm;
BT_RX_EVT_HANDLER_CB cb;
/* Power Throttling Feature */
enum conn_pwr_low_battery_level lp_cur_lv;
};
struct internal_trx_st {
spinlock_t lock;
unsigned long flag;
BT_RX_EVT_HANDLER_CB cb;
uint16_t opcode;
bool send_to_stack;
uint16_t buf_len;
uint8_t buf[256];
struct completion comp;
};
struct btmtk_btif_dev {
/* BT state machine */
u_int8_t bt_state;
/* Power state */
struct bt_psm_ctrl psm;
/* Reset relative */
struct completion rst_comp;
enum bt_reset_level rst_level;
u_int8_t rst_count;
u_int8_t rst_flag;
wait_queue_head_t rst_onoff_waitq;
u_int8_t do_recal;
u_int8_t bt_precal_state;
struct bt_rf_cal_data_backup cal_data;
#ifdef SUPPORT_BT_THREAD
/* thread */
struct task_struct *tx_thread;
wait_queue_head_t tx_waitq;
/* Tx quque */
struct sk_buff_head tx_queue;
#endif
#if (USE_DEVICE_NODE == 1)
struct bt_ring_buffer_mgmt rx_buffer;
#endif
u_int8_t rx_ind; /* RX indication from Firmware */
u_int8_t bgf2ap_ind; /* FW log / reset indication */
u_int8_t bt_conn2ap_ind; /* BGF bus hang indication */
/* context for current pending command */
struct bt_internal_cmd internal_cmd;
/* For internal command (generated in driver) handling */
u_int8_t event_intercept;
#if (DRIVER_CMD_CHECK == 1)
/* command response queue */
struct bt_cmd_queue cmd_queue;
uint8_t cmd_timeout_count;
bool cmd_timeout_check;
#endif
/* driver dump queue*/
struct bt_dump_queue dump_queue;
/* cif info */
struct platform_device *pdev;
/* coredump handle */
void *coredump_handle;
/* state change callback */
BT_STATE_CHANGE_CB state_change_cb[MAX_STATE_MONITORS];
/* call back to notify upper layer RX data is available */
BT_RX_EVENT_CB rx_event_cb;
/* initernal trx function: send particular command,
get command complete event and run callback function */
struct internal_trx_st internal_trx;
/* DynamicAdjustTxPower function*/
struct bt_DyPwr_st dy_pwr;
/* sempaphore to control close */
struct semaphore halt_sem;
struct semaphore internal_cmd_sem;
struct semaphore cmd_tout_sem;
/* blank status */
int32_t blank_state;
/* btif deep idle ctrl */
struct btif_deepidle_ctrl btif_dpidle_ctrl;
};
#define BTMTK_GET_DEV(bdev) (&bdev->pdev->dev)
/* IRQ APIs */
int bt_request_irq(enum bt_irq_type irq_type);
void bt_enable_irq(enum bt_irq_type irq_type);
void bt_disable_irq(enum bt_irq_type irq_type);
void bt_free_irq(enum bt_irq_type irq_type);
void bt_trigger_reset(void);
int bt_chip_reset_flow(enum bt_reset_level rst_level,
enum consys_drv_type drv,
char *reason);
void bt_bgf2ap_irq_handler(void);
void bt_conn2ap_irq_handler(void);
/* external functions */
int BT_init(void);
void BT_exit(void);
int32_t btmtk_wcn_btif_open(void);
int32_t btmtk_wcn_btif_close(void);
int32_t btmtk_tx_thread(void * arg);
void btmtk_cif_dump_fw_no_rsp(unsigned int flag);
void btmtk_cif_dump_rxd_backtrace(void);
void btmtk_reset_init(void);
void bt_notify_state(void);
int32_t btmtk_intcmd_query_thermal(void);
static inline void bt_wake_lock_init(struct bt_wake_lock *plock)
{
if (plock) {
plock->ws = wakeup_source_register(NULL, plock->name);
if (!plock->ws)
BTMTK_ERR("ERROR NO MEM\n");
#if (PM_QOS_CONTROL == 1)
else
pm_qos_add_request(&plock->qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
#endif
}
}
static inline void bt_wake_lock_deinit(struct bt_wake_lock *plock)
{
if (plock && plock->ws) {
wakeup_source_unregister(plock->ws);
#if (PM_QOS_CONTROL == 1)
pm_qos_remove_request(&plock->qos_req);
#endif
}
}
static inline void bt_hold_wake_lock(struct bt_wake_lock *plock)
{
if (plock && plock->ws) {
__pm_stay_awake(plock->ws);
#if (PM_QOS_CONTROL == 1)
pm_qos_update_request(&plock->qos_req, 1000);
#endif
}
}
static inline void bt_hold_wake_lock_timeout(struct bt_wake_lock *plock, uint32_t ms)
{
if (plock && plock->ws) {
__pm_wakeup_event(plock->ws, ms);
#if (PM_QOS_CONTROL == 1)
//pm_qos_update_request_timeout(&plock->qos_req, 1000, ms * 1000);
#endif
}
}
static inline void bt_release_wake_lock(struct bt_wake_lock *plock)
{
if (plock && plock->ws) {
__pm_relax(plock->ws);
#if (PM_QOS_CONTROL == 1)
pm_qos_update_request(&plock->qos_req, PM_QOS_DEFAULT_VALUE);
#endif
}
}
static inline void bt_psm_init(struct bt_psm_ctrl *psm)
{
init_completion(&psm->comp);
strncpy(psm->wake_lock.name, "bt_psm", 6);
psm->wake_lock.name[6] = '\0';
bt_wake_lock_init(&psm->wake_lock);
}
static inline void bt_psm_deinit(struct bt_psm_ctrl *psm)
{
bt_wake_lock_deinit(&psm->wake_lock);
}
static inline int osal_strtol(const char *str, unsigned int adecimal, long *res)
{
if (sizeof(long) == 4)
return kstrtou32(str, adecimal, (unsigned int *) res);
else
return kstrtol(str, adecimal, res);
}
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
int32_t btmtk_set_power_on(struct hci_dev *hdev, u_int8_t for_precal);
int32_t btmtk_set_power_off(struct hci_dev *hdev, u_int8_t for_precal);
int btmtk_btif_internal_trx (uint8_t *buf, uint32_t count, BT_RX_EVT_HANDLER_CB cb, bool send_to_stack, bool is_blocking);
int btmtk_inttrx_DynamicAdjustTxPower_cb(uint8_t *buf, int len);
int btmtk_inttrx_DynamicAdjustTxPower(uint8_t mode, int8_t set_val, BT_RX_EVT_HANDLER_CB cb, bool is_blocking);
int32_t btmtk_intcmd_wmt_calibration(struct hci_dev *hdev);
int32_t btmtk_intcmd_wmt_blank_status(struct hci_dev *hdev, int32_t blank);
int32_t btmtk_intcmd_wmt_utc_sync(void);
int32_t btmtk_intcmd_set_fw_log(uint8_t flag);
int32_t btmtk_send_data(struct hci_dev *hdev, uint8_t *buf, uint32_t count);
bool bt_pwrctrl_support(void);
void bt_pwrctrl_pre_on(void);
void bt_pwrctrl_post_off(void);
int bt_dev_dbg_init(void);
int bt_dev_dbg_deinit(void);
void bthost_debug_print(void);
void btmtk_connsys_log_init(void);
void btmtk_connsys_log_register_event_cb(void (*func)(void));
void btmtk_connsys_log_deinit(void);
void btmtk_connsys_log_hold_sem(void);
void btmtk_connsys_log_release_sem(void);
ssize_t btmtk_connsys_log_read_to_user(char __user *buf, size_t count);
unsigned int btmtk_connsys_log_get_buf_size(void);
int btmtk_cif_send_calibration(struct btmtk_dev *bdev);
int btmtk_btif_send_cmd(struct btmtk_dev *bdev, struct sk_buff *skb, int delay,
int retry, int pkt_type);
#if (USE_DEVICE_NODE == 1)
uint8_t btmtk_rx_data_valid(void);
int32_t btmtk_receive_data(struct hci_dev *hdev, uint8_t *buf, uint32_t count);
void btmtk_rx_flush(void);
void btmtk_register_rx_event_cb(struct hci_dev *hdev, BT_RX_EVENT_CB cb);
int main_driver_init(void);
void main_driver_exit(void);
void rx_queue_initialize(void);
void rx_queue_destroy(void);
uint8_t is_rx_queue_empty(void);
int32_t rx_skb_enqueue(struct sk_buff *skb);
void rx_dequeue(uint8_t *buffer, uint32_t size, uint32_t *plen);
void rx_queue_flush(void);
#endif
#if (DRIVER_CMD_CHECK == 1)
void cmd_list_initialize(void);
bool cmd_list_check(uint16_t opcode);
bool cmd_list_remove(uint16_t opcode);
bool cmd_list_append (uint16_t opcode);
void cmd_list_destory(void);
bool cmd_list_isempty(void);
bool cmd_workqueue_init(void);
void cmd_workqueue_exit(void);
void update_command_response_workqueue(void);
#endif
void dump_queue_initialize(void);
void add_dump_packet(const uint8_t *buffer, const uint32_t length, enum bt_direction_type type);
void show_all_dump_packet(void);
#endif

View file

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM connsys_trace_event
#if !defined(_TRACE_BTMTK_DBG_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_BTMTK_DBG_EVENTS_H
#include <linux/tracepoint.h>
#define __GET_ENTRY_16_BYTES_LEN_BUFFER(__entry_data, __entry_data_len, data, data_len) \
do { \
unsigned int data_sz = (data_len <= 16) ? (data_len) : (16); \
char buf_str[32] = {""}; \
int i = 0; \
if (data_sz > 0 && data != NULL) { \
if (snprintf(__entry_data, __entry_data_len, "%s", "") < 0) \
pr_info("snprintf error in btmtk_dbg_tp_evt.h"); \
for (i = 0; i < data_sz; i++) { \
if (snprintf(buf_str, sizeof(buf_str), "%02x", data[i]) > 0) \
strncat(__entry_data, buf_str, strlen(buf_str)); \
} \
} else { \
if (snprintf(__entry_data, __entry_data_len, "%s", "null") < 0) \
pr_info("snprintf error in btmtk_dbg_tp_evt.h"); \
} \
} while (0)
#define __GET_ENTRY_STRING(__entry_data, __entry_data_len, data) \
do { \
if (strlen(data) == 0 || data == NULL){ \
if (snprintf(__entry_data, __entry_data_len, "%s", "null") < 0) \
pr_info("snprintf error in btmtk_dbg_tp_evt.h"); \
} else { \
if (snprintf(__entry_data, __entry_data_len, "%s", data) < 0) \
pr_info("snprintf error in btmtk_dbg_tp_evt.h"); \
} \
} while (0)
TRACE_EVENT(bt_evt,
TP_PROTO(unsigned int pkt_action,
unsigned int parameter,
unsigned int data_len,
char *data),
TP_ARGS(pkt_action, parameter, data_len, data),
TP_STRUCT__entry(
__field(unsigned int, pkt_action)
__field(unsigned int, parameter)
__field(unsigned int, data_len)
__dynamic_array(char, data, 256)
),
TP_fast_assign(
__entry->pkt_action = pkt_action;
__entry->parameter = parameter;
__entry->data_len = data_len;
__GET_ENTRY_16_BYTES_LEN_BUFFER(__get_str(data), __get_dynamic_array_len(data), data, data_len);
),
TP_printk("%d,%d,%d,%s",
__entry->pkt_action, __entry->parameter, __entry->data_len, __get_str(data))
);
#endif /* _TRACE_BTMTK_DBG_EVENTS_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH ./
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE btmtk_dbg_tp_evt
#include <trace/define_trace.h>

View file

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_DBG_EVENTS_IF_H_
#define _BTMTK_DBG_EVENTS_IF_H_
#define TP_ACT_PWR_ON 0
#define TP_ACT_PWR_OFF 1
#define TP_ACT_POLL 2
#define TP_ACT_WR_IN 3
#define TP_ACT_WR_OUT 4
#define TP_ACT_RD_IN 5
#define TP_ACT_RD_CB 6
#define TP_ACT_RD_OUT 7
#define TP_ACT_FWOWN_IN 8
#define TP_ACT_FWOWN_OUT 9
#define TP_ACT_DRVOWN_IN 10
#define TP_ACT_DRVOWN_OUT 11
#define TP_ACT_DPI_ENTER 12
#define TP_ACT_DPI_EXIT 13
#define TP_ACT_RST 14
#define TP_PAR_PASS 1
#define TP_PAR_FAIL 2
#define TP_PAR_RST_START 3
#define TP_PAR_RST_DUMP 4
#define TP_PAR_RST_OFF 5
void bt_dbg_tp_evt(unsigned int pkt_action,
unsigned int parameter,
unsigned int data_len,
char *data);
#endif

View file

@ -0,0 +1,254 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _PLATFORM_BASE_H
#define _PLATFORM_BASE_H
#include "conninfra.h"
#define BT_CR_DUMP_BUF_SIZE (1024)
#define FW_NAME_LEN (64)
#define PATCH_FILE_NUM 2
static uint8_t g_dump_cr_buffer[BT_CR_DUMP_BUF_SIZE];
#if (CUSTOMER_FW_UPDATE == 1)
extern uint8_t g_fwp_names[PATCH_FILE_NUM][2][FW_NAME_LEN];
#else
extern uint8_t g_fwp_names[PATCH_FILE_NUM][1][FW_NAME_LEN];
#endif
#define FLAVOR_NONE '0'
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
#ifndef BIT
#define BIT(n) (1UL << (n))
#endif /* BIT */
#ifndef BITS
/* bits range: for example BITS(16,23) = 0xFF0000
* ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000
* ==> (BIT(n+1)-1) = 0x00FFFFFF
*/
#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n)))
#endif /* BIT */
/*
* This macro returns the byte offset of a named field in a known structure
* type.
* _type - structure name,
* _field - field name of the structure
*/
#ifndef OFFSET_OF
#define OFFSET_OF(_type, _field) ((unsigned long)&(((_type *)0)->_field))
#endif /* OFFSET_OF */
/*
* This macro returns the base address of an instance of a structure
* given the type of the structure and the address of a field within the
* containing structure.
* _addr_of_field - address of a field within the structure,
* _type - structure name,
* _field - field name of the structure
*/
#ifndef ENTRY_OF
#define ENTRY_OF(_addr_of_field, _type, _field) \
((_type *)((unsigned char *)(_addr_of_field) - (unsigned char *)OFFSET_OF(_type, _field)))
#endif /* ENTRY_OF */
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
struct consys_reg_base_addr {
unsigned long vir_addr;
unsigned long phy_addr;
unsigned long long size;
};
enum bt_base_addr_index {
CONN_INFRA_RGU_BASE_INDEX = 0,
CONN_INFRA_CFG_BASE_INDEX = 1,
CONN_INFRA_SYS_BASE_INDEX = 2,
SPM_BASE_INDEX = 3,
BGFSYS_BASE_INDEX = 4,
BGFSYS_INFO_BASE_INDEX = 5,
INFRACFG_AO_BASE_INDEX = 6,
#if 0
CONN_INFRA_CFG_CCIF_BASE = 7,
BGF2MD_BASE_INDEX = 8,
#endif
CONSYS_BASE_ADDR_MAX
};
struct bt_base_addr {
struct consys_reg_base_addr reg_base_addr[CONSYS_BASE_ADDR_MAX];
};
extern struct bt_base_addr bt_reg;
#define CON_REG_INFRA_RGU_ADDR bt_reg.reg_base_addr[CONN_INFRA_RGU_BASE_INDEX].vir_addr /* 0x18000000 0x1000 */
#define CON_REG_INFRA_CFG_ADDR bt_reg.reg_base_addr[CONN_INFRA_CFG_BASE_INDEX].vir_addr /* 0x18001000 0x1000 */
#define CON_REG_INFRA_SYS_ADDR bt_reg.reg_base_addr[CONN_INFRA_SYS_BASE_INDEX].vir_addr /* 0x18050000 0x1000 */
#define CON_REG_SPM_BASE_ADDR bt_reg.reg_base_addr[SPM_BASE_INDEX].vir_addr /* 0x18060000 0x1000 */
#define BGF_REG_BASE_ADDR bt_reg.reg_base_addr[BGFSYS_BASE_INDEX].vir_addr /* 0x18800000 0x1000 */
#define BGF_REG_INFO_BASE_ADDR bt_reg.reg_base_addr[BGFSYS_INFO_BASE_INDEX].vir_addr /* 0x18812000 0x1000 */
#define CON_REG_INFRACFG_AO_ADDR bt_reg.reg_base_addr[INFRACFG_AO_BASE_INDEX].vir_addr /* 0x10001000 0x1000 */
#if 0
#define CON_REG_INFRA_CCIF_ADDR bt_reg.reg_base_addr[CONN_INFRA_CFG_CCIF_BASE].vir_addr
#define BGF2MD_BASE_ADDR bt_reg.reg_base_addr[BGF2MD_BASE_INDEX].vir_addr
#endif
#define SET_BIT(addr, bit) \
(*((volatile uint32_t *)(addr))) |= ((uint32_t)bit)
#define CLR_BIT(addr, bit) \
(*((volatile uint32_t *)(addr))) &= ~((uint32_t)bit)
#define REG_READL(addr) \
readl((volatile uint32_t *)(addr))
#define REG_WRITEL(addr, val) \
writel(val, (volatile uint32_t *)(addr))
#define CAN_DUMP_HOST_CSR(reason) \
(reason != CONNINFRA_INFRA_BUS_HANG && \
reason != CONNINFRA_AP2CONN_RX_SLP_PROT_ERR && \
reason != CONNINFRA_AP2CONN_TX_SLP_PROT_ERR && \
reason != CONNINFRA_AP2CONN_CLK_ERR)
#define POS_POLLING_RTY_LMT 100
#define IDLE_LOOP_RTY_LMT 100
#define CAL_READY_BIT_PATTERN 0x5AD02EA5
/*********************************************************************
*
* Global variable
*
**********************************************************************
*/
static uint32_t g_sw_irq_status = 0;
/*********************************************************************
*
* Utility APIs
*
**********************************************************************
*/
static uint32_t inline bt_read_cr(uint32_t addr)
{
uint32_t value = 0;
uint8_t *base = ioremap(addr, 0x10);
if (base == NULL) {
BTMTK_ERR("%s: remapping 0x%08x fail", addr);
} else {
value = REG_READL(base);
iounmap(base);
}
return value;
}
static void inline bt_write_cr(uint32_t addr, uint32_t value, bool is_set_bit)
{
uint32_t *base = ioremap(addr, 0x10);
if (base == NULL) {
BTMTK_ERR("%s: remapping 0x%08x fail", addr);
} else {
if (is_set_bit)
*base |= value; // set bit to CR
else
*base = value; // directly write value to CR
iounmap(base);
}
}
static void inline bt_dump_memory8(uint8_t *buf, uint32_t len)
{
uint32_t i = 0;
uint8_t *pos = NULL, *end = NULL;
int32_t ret = 0;
memset(g_dump_cr_buffer, 0, BT_CR_DUMP_BUF_SIZE);
pos = &g_dump_cr_buffer[0];
end = pos + BT_CR_DUMP_BUF_SIZE - 1;
BTMTK_INFO("%s: length = (%d)", __func__, len);
for (i = 0; i <= len; i++) {
ret = snprintf(pos, (end - pos + 1), "%02x ", buf[i]);
if (ret < 0 || ret >= (end - pos + 1))
break;
pos += ret;
if ((i & 0xF) == 0xF || i == len - 1) {
BTMTK_INFO("%s", g_dump_cr_buffer);
memset(g_dump_cr_buffer, 0, BT_CR_DUMP_BUF_SIZE);
pos = &g_dump_cr_buffer[0];
end = pos + BT_CR_DUMP_BUF_SIZE - 1;
}
}
}
static inline u_int8_t fwp_has_flavor_bin(uint8_t *flavor)
{
#define TARGET_KEY "flavor_bin"
u_int8_t ret = FALSE;
const char *str;
struct device_node *node = NULL;
node = of_find_compatible_node(NULL, NULL, "mediatek,bt");
if (node) {
if (of_property_read_string(node, TARGET_KEY, &str)) {
BTMTK_INFO("%s: get %s: fail", __func__, TARGET_KEY);
} else {
*flavor = *str;
BTMTK_INFO("%s: get %s: %c", __func__, TARGET_KEY, *flavor);
ret = TRUE;
}
} else
BTMTK_INFO("%s: get dts[mediatek,bt] fail!", __func__);
return ret;
}
static inline void compose_fw_name(u_int8_t has_flavor, uint8_t flavor,
const uint8_t *bin_mcu_name,
const uint8_t *bin_bt_name)
{
if (has_flavor) {
if (snprintf(g_fwp_names[0][0], FW_NAME_LEN, "%s%c_1_hdr.bin", bin_mcu_name, flavor) < 0)
BTMTK_ERR("%s: has_flavor[0][0]", __func__);
if (snprintf(g_fwp_names[1][0], FW_NAME_LEN, "%s%c_1_hdr.bin", bin_bt_name, flavor) < 0)
BTMTK_ERR("%s: has_flavor[1][0]", __func__);
} else {
if (snprintf(g_fwp_names[0][0], FW_NAME_LEN, "%s_1_hdr.bin", bin_mcu_name) < 0)
BTMTK_ERR("%s: no_flavor[0][0]", __func__);
if (snprintf(g_fwp_names[1][0], FW_NAME_LEN, "%s_1_hdr.bin", bin_bt_name) < 0)
BTMTK_ERR("%s: no_flavor[1][0]", __func__);
}
#if (CUSTOMER_FW_UPDATE == 1)
if (has_flavor) {
if (snprintf(g_fwp_names[0][1], FW_NAME_LEN, "%s%c_1_hdr-u.bin", bin_mcu_name, flavor) < 0)
BTMTK_ERR("%s: has_flavor[0][1]", __func__);
if (snprintf(g_fwp_names[1][1], FW_NAME_LEN, "%s%c_1_hdr-u.bin", bin_bt_name, flavor) < 0)
BTMTK_ERR("%s: has_flavor[1][1]", __func__);
} else {
if (snprintf(g_fwp_names[0][1], FW_NAME_LEN, "%s_1_hdr-u.bin", bin_mcu_name) < 0)
BTMTK_ERR("%s: no_flavor[0][1]", __func__);
if (snprintf(g_fwp_names[1][1], FW_NAME_LEN, "%s_1_hdr-u.bin", bin_bt_name) < 0)
BTMTK_ERR("%s: no_flavor[1][1]", __func__);
}
#endif
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_BUFFER_MODE_H__
#define __BTMTK_BUFFER_MODE_H__
#include "btmtk_main.h"
#define BUFFER_MODE_SWITCH_FILE "wifi.cfg"
#define BUFFER_MODE_SWITCH_FIELD "EfuseBufferModeCal"
#define BUFFER_MODE_CFG_FILE "EEPROM_MT%X_1.bin"
#define EFUSE_MODE 0
#define BIN_FILE_MODE 1
#define AUTO_MODE 2
#define SET_ADDRESS_CMD_LEN 10
#define SET_ADDRESS_EVT_LEN 7
#define SET_ADDRESS_CMD_PAYLOAD_OFFSET 4
#define SET_RADIO_CMD_LEN 12
#define SET_RADIO_EVT_LEN 7
#define SET_RADIO_CMD_EDR_DEF_OFFSET 4
#define SET_RADIO_CMD_BLE_OFFSET 8
#define SET_RADIO_CMD_EDR_MAX_OFFSET 9
#define SET_RADIO_CMD_EDR_MODE_OFFSET 11
#define SET_GRP_CMD_LEN 13
#define SET_GRP_EVT_LEN 7
#define SET_GRP_CMD_PAYLOAD_OFFSET 8
#define SET_PWR_OFFSET_CMD_LEN 14
#define SET_PWR_OFFSET_EVT_LEN 7
#define SET_PWR_OFFSET_CMD_PAYLOAD_OFFSET 8
#define BUFFER_MODE_MAC_LENGTH 6
#define BT0_MAC_OFFSET 0x139
#define BT1_MAC_OFFSET 0x13F
#define BUFFER_MODE_RADIO_LENGTH 4
#define BT0_RADIO_OFFSET 0x145
#define BT1_RADIO_OFFSET 0x149
#define BUFFER_MODE_GROUP_LENGTH 5
#define BT0_GROUP_ANT0_OFFSET 0x984
#define BT0_GROUP_ANT1_OFFSET 0x9BE
#define BT1_GROUP_ANT0_OFFSET 0x9A1
#define BT1_GROUP_ANT1_OFFSET 0x9DB
#define BUFFER_MODE_CAL_LENGTH 6
#define BT0_CAL_ANT0_OFFSET 0x96C
#define BT0_CAL_ANT1_OFFSET 0x9A6
#define BT1_CAL_ANT0_OFFSET 0x989
#define BT1_CAL_ANT1_OFFSET 0x9C3
struct btmtk_buffer_mode_radio_struct {
u8 radio_0; /* bit 0-5:edr_init_pwr, 6-7:edr_pwr_mode */
u8 radio_1; /* bit 0-5:edr_max_pwr, 6-7:reserved */
u8 radio_2; /* bit 0-5:ble_default_pwr, 6-7:reserved */
u8 radio_3; /* reserved */
};
struct btmtk_buffer_mode_struct {
struct btmtk_dev *bdev;
unsigned char file_name[MAX_BIN_FILE_NAME_LEN];
int efuse_mode;
u8 bt0_mac[BUFFER_MODE_MAC_LENGTH];
u8 bt1_mac[BUFFER_MODE_MAC_LENGTH];
struct btmtk_buffer_mode_radio_struct bt0_radio;
struct btmtk_buffer_mode_radio_struct bt1_radio;
u8 bt0_ant0_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt0_ant1_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt1_ant0_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt1_ant1_grp_boundary[BUFFER_MODE_GROUP_LENGTH];
u8 bt0_ant0_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt0_ant1_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt1_ant0_pwr_offset[BUFFER_MODE_CAL_LENGTH];
u8 bt1_ant1_pwr_offset[BUFFER_MODE_CAL_LENGTH];
};
int btmtk_buffer_mode_send(struct btmtk_buffer_mode_struct *buffer_mode);
void btmtk_buffer_mode_initialize(struct btmtk_dev *bdev, struct btmtk_buffer_mode_struct **buffer_mode);
#endif /* __BTMTK_BUFFER_MODE_H__ */

View file

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_CHIP_IF_H__
#define __BTMTK_CHIP_IF_H__
#ifdef CHIP_IF_USB
#include "btmtk_usb.h"
#elif defined(CHIP_IF_SDIO)
#include "btmtk_sdio.h"
#elif defined(CHIP_IF_UART)
#include "btmtk_uart.h"
#elif defined(CHIP_IF_BTIF)
#include "btmtk_btif.h"
#define CFG_SUPPORT_BT_DL_WIFI_PATCH 0
#define CFG_SUPPORT_DVT 0
#define CFG_SUPPORT_BLUEZ 0
#if (CONNAC20_CHIPID == 6885)
#include "platform_mt6885.h"
#elif (CONNAC20_CHIPID == 6893)
#include "platform_mt6893.h"
#elif (CONNAC20_CHIPID == 6877)
#include "platform_mt6877.h"
#elif (CONNAC20_CHIPID == 6983)
#include "platform_mt6983.h"
#elif (CONNAC20_CHIPID == 6879)
#include "platform_mt6879.h"
#elif (CONNAC20_CHIPID == 6895)
#include "platform_mt6895.h"
#endif
#endif
int btmtk_cif_register(void);
int btmtk_cif_deregister(void);
#endif /* __BTMTK_CHIP_IF_H__ */

View file

@ -0,0 +1,315 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_DEFINE_H__
#define __BTMTK_DEFINE_H__
#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <linux/cdev.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/device.h>
#include <asm/unaligned.h>
/* Define for proce node */
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
/* Define for whole chip reset */
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
/** Driver version */
#define VERSION "7.0.2020121701"
#define SUBVER ":turnkey"
#define ENABLESTP FALSE
#define BTMTKUART_TX_STATE_ACTIVE 1
#define BTMTKUART_TX_STATE_WAKEUP 2
#define BTMTK_TX_WAIT_VND_EVT 3
#define BTMTKUART_REQUIRED_WAKEUP 4
#define BTMTKUART_REQUIRED_DOWNLOAD 5
#define BTMTK_TX_SKIP_VENDOR_EVT 6
#define BTMTKUART_RX_STATE_ACTIVE 1
#define BTMTKUART_RX_STATE_WAKEUP 2
#define BTMTKUART_RX_STATE_RESET 3
/**
* Maximum rom patch file name length
*/
#define MAX_BIN_FILE_NAME_LEN 64
/**
* Type definition
*/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#ifndef ALIGN_4
#define ALIGN_4(_value) (((_value) + 3) & ~3u)
#endif /* ALIGN_4 */
#ifndef ALIGN_8
#define ALIGN_8(_value) (((_value) + 7) & ~7u)
#endif /* ALIGN_4 */
/* This macro check the DW alignment of the input value.
* _value - value of address need to check
*/
#ifndef IS_ALIGN_4
#define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE)
#endif /* IS_ALIGN_4 */
#ifndef IS_NOT_ALIGN_4
#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE)
#endif /* IS_NOT_ALIGN_4 */
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/**
* Log and level definition
*/
#define BTMTK_LOG_LVL_ERR 1
#define BTMTK_LOG_LVL_WARN 2
#define BTMTK_LOG_LVL_INFO 3
#define BTMTK_LOG_LVL_DBG 4
#define BTMTK_LOG_LVL_MAX BTMTK_LOG_LVL_DBG
#define BTMTK_LOG_LVL_DEF BTMTK_LOG_LVL_INFO /* default setting */
#define HCI_SNOOP_ENTRY_NUM 30
#define HCI_SNOOP_BUF_SIZE 32
#define HCI_SNOOP_MAX_BUF_SIZE 66
#define WMT_OVER_HCI_HEADER_SIZE 3
#define READ_ISO_PACKET_CMD_SIZE 4
extern uint8_t btmtk_log_lvl;
#define BTMTK_ERR(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_ERR) pr_info("[btmtk_err] ***"fmt"***\n", ##__VA_ARGS__); } while (0)
#define BTMTK_WARN(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_WARN) pr_info("[btmtk_warn] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_INFO(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) pr_info("[btmtk_info] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_DBG(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) pr_info("[btmtk_dbg] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_LIMIT(fmt, ...) \
do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) printk_ratelimited(KERN_INFO "[btmtk_info] "fmt"\n", ##__VA_ARGS__); } while (0)
#define BTMTK_INFO_RAW(p, l, fmt, ...) \
do { \
if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) { \
int cnt_ = 0; \
int len_ = (l <= HCI_SNOOP_MAX_BUF_SIZE ? l : HCI_SNOOP_MAX_BUF_SIZE); \
uint8_t raw_buf[HCI_SNOOP_MAX_BUF_SIZE * 5 + 10]; \
const unsigned char *ptr = p; \
for (cnt_ = 0; cnt_ < len_; ++cnt_) { \
if (snprintf(raw_buf+5*cnt_, 6, "0x%02X ", ptr[cnt_]) < 0) { \
pr_info("snprintf error\n"); \
break; \
} \
} \
raw_buf[5*cnt_] = '\0'; \
if (l <= HCI_SNOOP_MAX_BUF_SIZE) { \
pr_cont("[btmtk_info] "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
} else { \
pr_cont("[btmtk_info] "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
} \
} \
} while (0)
#define BTMTK_DBG_RAW(p, l, fmt, ...) \
do { \
if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) { \
int cnt_ = 0; \
int len_ = (l <= HCI_SNOOP_MAX_BUF_SIZE ? l : HCI_SNOOP_MAX_BUF_SIZE); \
uint8_t raw_buf[HCI_SNOOP_MAX_BUF_SIZE * 5 + 10]; \
const unsigned char *ptr = p; \
for (cnt_ = 0; cnt_ < len_; ++cnt_) { \
if (snprintf(raw_buf+5*cnt_, 6, "0x%02X ", ptr[cnt_]) < 0) { \
pr_info("snprintf error\n"); \
break; \
} \
} \
raw_buf[5*cnt_] = '\0'; \
if (l <= HCI_SNOOP_MAX_BUF_SIZE) { \
pr_cont("[btmtk_debug] "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
} else { \
pr_cont("[btmtk_debug] "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
} \
} \
} while (0)
#define BTMTK_CIF_IS_NULL(bdev, cif_event) \
(!bdev || !(&bdev->cif_state[cif_event]))
/**
*
* HCI packet type
*/
#define MTK_HCI_COMMAND_PKT 0x01
#define MTK_HCI_ACLDATA_PKT 0x02
#define MTK_HCI_SCODATA_PKT 0x03
#define MTK_HCI_EVENT_PKT 0x04
#define HCI_ISO_PKT 0x05
#define HCI_ISO_PKT_HEADER_SIZE 4
#define HCI_ISO_PKT_WITH_ACL_HEADER_SIZE 5
/**
* ROM patch related
*/
#define PATCH_HCI_HEADER_SIZE 4
#define PATCH_WMT_HEADER_SIZE 5
/*
* Enable STP
* HCI+WMT+STP = 4 + 5 + 1(phase) +(4=STP_HEADER + 2=CRC)
#define PATCH_HEADER_SIZE 16
*/
/*#ifdef ENABLESTP
* #define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE + 1 + 6)
* #define UPLOAD_PATCH_UNIT 916
* #define PATCH_INFO_SIZE 30
*#else
*/
#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE + 1)
/* TODO, If usb use 901 patch unit size, download patch will timeout
* because the timeout has been set to 1s
*/
#define UPLOAD_PATCH_UNIT 2048
#define PATCH_INFO_SIZE 30
/*#endif*/
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 7
#define IO_BUF_SIZE (HCI_MAX_EVENT_SIZE > 256 ? HCI_MAX_EVENT_SIZE : 256)
#define EVENT_COMPARE_SIZE 64
#define SECTION_SPEC_NUM 13
#define BD_ADDRESS_SIZE 6
#define PHASE1_WMT_CMD_COUNT 255
#define VENDOR_CMD_COUNT 255
#define BT_CFG_NAME "bt.cfg"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WOBLE_BY_EINT "SUPPORT_WOBLE_BY_EINT"
#define BT_DONGLE_RESET_PIN "BT_DONGLE_RESET_GPIO_PIN"
#define BT_RESET_DONGLE "SUPPORT_DONGLE_RESET"
#define BT_FULL_FW_DUMP "SUPPORT_FULL_FW_DUMP"
#define BT_WOBLE_WAKELOCK "SUPPORT_WOBLE_WAKELOCK"
#define BT_WOBLE_FOR_BT_DISABLE "SUPPORT_WOBLE_FOR_BT_DISABLE"
#define BT_RESET_STACK_AFTER_WOBLE "RESET_STACK_AFTER_WOBLE"
#define BT_AUTO_PICUS "SUPPORT_AUTO_PICUS"
#define BT_AUTO_PICUS_FILTER "PICUS_FILTER_COMMAND"
#define BT_AUTO_PICUS_ENABLE "PICUS_ENABLE_COMMAND"
#define BT_PICUS_TO_HOST "SUPPORT_PICUS_TO_HOST"
#define BT_PHASE1_WMT_CMD "PHASE1_WMT_CMD"
#define BT_VENDOR_CMD "VENDOR_CMD"
#define BT_SINGLE_SKU "SUPPORT_BT_SINGLE_SKU"
#define PM_KEY_BTW (0x0015) /* Notify PM the unify woble type */
/**
* Disable RESUME_RESUME
*/
#ifndef BT_DISABLE_RESET_RESUME
#define BT_DISABLE_RESET_RESUME 0
#endif
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
char *content; /* APCF content or radio off content */
u32 length; /* APCF content or radio off content of length */
};
struct bt_cfg_struct {
bool support_unify_woble; /* support unify woble or not */
bool support_woble_by_eint; /* support woble by eint or not */
bool support_dongle_reset; /* support chip reset or not */
bool support_full_fw_dump; /* dump full fw coredump or not */
bool support_woble_wakelock; /* support when woble error, do wakelock or not */
bool support_woble_for_bt_disable; /* when bt disable, support enter susend or not */
bool reset_stack_after_woble; /* support reset stack to re-connect IOT after resume */
bool support_auto_picus; /* support enable PICUS automatically */
struct fw_cfg_struct picus_filter; /* support on PICUS filter command customization */
struct fw_cfg_struct picus_enable; /* support on PICUS enable command customization */
bool support_picus_to_host; /* support picus log to host (boots/bluedroid) */
int dongle_reset_gpio_pin; /* BT_DONGLE_RESET_GPIO_PIN number */
unsigned int unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct phase1_wmt_cmd[PHASE1_WMT_CMD_COUNT];
struct fw_cfg_struct vendor_cmd[VENDOR_CMD_COUNT];
bool support_bt_single_sku;
};
#define WIFI_DOWNLOAD TRUE
#define BT_DOWNLOAD FALSE
#define SWAP32(x) \
((u32) (\
(((u32) (x) & (u32) 0x000000ffUL) << 24) | \
(((u32) (x) & (u32) 0x0000ff00UL) << 8) | \
(((u32) (x) & (u32) 0x00ff0000UL) >> 8) | \
(((u32) (x) & (u32) 0xff000000UL) >> 24)))
/* Endian byte swapping codes */
#ifdef __LITTLE_ENDIAN
#define cpu2le32(x) ((uint32_t)(x))
#define le2cpu32(x) ((uint32_t)(x))
#define cpu2be32(x) SWAP32((x))
#define be2cpu32(x) SWAP32((x))
#else
#define cpu2le32(x) SWAP32((x))
#define le2cpu32(x) SWAP32((x))
#define cpu2be32(x) ((uint32_t)(x))
#define be2cpu32(x) ((uint32_t)(x))
#endif
#define FW_VERSION 0x80021004
#define CHIP_ID 0x70010200
#define FLAVOR 0x70010020
#endif /* __BTMTK_DEFINE_H__ */

View file

@ -0,0 +1,149 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_DRV_H_
#define _BTMTK_DRV_H_
#include <linux/kthread.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <net/bluetooth/bluetooth.h>
#define SAVE_FW_DUMP_IN_KERNEL 1
#define SUPPORT_FW_DUMP 1
#define BTM_HEADER_LEN 5
#define BTM_UPLD_SIZE 2312
#define MTK_TXDATA_SIZE 2000
#define MTK_RXDATA_SIZE 2000
/* Time to wait until Host Sleep state change in millisecond */
#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000)
/* Time to wait for command response in millisecond */
#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000)
enum rdwr_status {
RDWR_STATUS_SUCCESS = 0,
RDWR_STATUS_FAILURE = 1,
RDWR_STATUS_DONE = 2
};
#define FW_DUMP_MAX_NAME_LEN 8
#define FW_DUMP_HOST_READY 0xEE
#define FW_DUMP_DONE 0xFF
#define FW_DUMP_READ_DONE 0xFE
struct memory_type_mapping {
u8 mem_name[FW_DUMP_MAX_NAME_LEN];
u8 *mem_ptr;
u32 mem_size;
u8 done_flag;
};
#define MTK_VENDOR_PKT 0xFE
/* Vendor specific Bluetooth commands */
#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03
#define BT_CMD_ROUTE_SCO_TO_HOST 0xFC1D
#define BT_CMD_SET_BDADDR 0xFC22
#define BT_CMD_AUTO_SLEEP_MODE 0xFC23
#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59
#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A
#define BT_CMD_MODULE_CFG_REQ 0xFC5B
#define BT_CMD_LOAD_CONFIG_DATA 0xFC61
/* Sub-commands: Module Bringup/Shutdown Request/Response */
#define MODULE_BRINGUP_REQ 0xF1
#define MODULE_BROUGHT_UP 0x00
#define MODULE_ALREADY_UP 0x0C
#define MODULE_SHUTDOWN_REQ 0xF2
/* Vendor specific Bluetooth events */
#define BT_EVENT_AUTO_SLEEP_MODE 0x23
#define BT_EVENT_HOST_SLEEP_CONFIG 0x59
#define BT_EVENT_HOST_SLEEP_ENABLE 0x5A
#define BT_EVENT_MODULE_CFG_REQ 0x5B
#define BT_EVENT_POWER_STATE 0x20
/* Bluetooth Power States */
#define BT_PS_ENABLE 0x02
#define BT_PS_DISABLE 0x03
#define BT_PS_SLEEP 0x01
/* Host Sleep states */
#define HS_ACTIVATED 0x01
#define HS_DEACTIVATED 0x00
/* Power Save modes */
#define PS_SLEEP 0x01
#define PS_AWAKE 0x00
#define BT_CAL_HDR_LEN 4
#define BT_CAL_DATA_SIZE 28
#define FW_DUMP_BUF_SIZE (1024*512)
#define FW_DUMP_FILE_NAME_SIZE 64
/* #define SAVE_FW_DUMP_IN_KERNEL 1 */
/* stpbt device node */
#define BT_NODE "stpbt"
#define BT_DRIVER_NAME "BT_chrdev"
struct btmtk_event {
u8 ec; /* event counter */
u8 length;
u8 data[4];
} __packed;
/* Prototype of global function */
struct btmtk_private *btmtk_add_card(void *card);
int btmtk_remove_card(struct btmtk_private *priv);
void btmtk_interrupt(struct btmtk_private *priv);
bool btmtk_check_evtpkt(struct btmtk_private *priv, struct sk_buff *skb);
int btmtk_process_event(struct btmtk_private *priv, struct sk_buff *skb);
int btmtk_send_module_cfg_cmd(struct btmtk_private *priv, u8 subcmd);
int btmtk_pscan_window_reporting(struct btmtk_private *priv, u8 subcmd);
int btmtk_send_hscfg_cmd(struct btmtk_private *priv);
int btmtk_enable_ps(struct btmtk_private *priv);
int btmtk_prepare_command(struct btmtk_private *priv);
int btmtk_enable_hs(struct btmtk_private *priv);
void btmtk_firmware_dump(struct btmtk_private *priv);
#define META_BUFFER_SIZE (1024*50)
struct _OSAL_UNSLEEPABLE_LOCK_ {
spinlock_t lock;
unsigned long flag;
};
struct ring_buffer {
struct _OSAL_UNSLEEPABLE_LOCK_ spin_lock;
u8 buffer[META_BUFFER_SIZE]; /* MTKSTP_BUFFER_SIZE:1024 */
u32 read_p; /* indicate the current read index */
u32 write_p; /* indicate the current write index */
};
#ifdef CONFIG_DEBUG_FS
#define FIXED_STPBT_MAJOR_DEV_ID 111
#define FW_DUMP_END_EVENT "coredump end"
#endif
#endif

View file

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_FW_LOG_H__
#define __BTMTK_FW_LOG_H__
#define BT_FWLOG_IOC_MAGIC (0xfc)
#define BT_FWLOG_IOC_ON_OFF _IOW(BT_FWLOG_IOC_MAGIC, 0, int)
#define BT_FWLOG_IOC_SET_LEVEL _IOW(BT_FWLOG_IOC_MAGIC, 1, int)
#define BT_FWLOG_IOC_GET_LEVEL _IOW(BT_FWLOG_IOC_MAGIC, 2, int)
#define BT_FWLOG_OFF 0x00
#define BT_FWLOG_ON 0xFF
/* bluetooth kpi */
#define KPI_WITHOUT_TYPE 0
/* Device node */
#define BT_FWLOG_DEV_NODE "fw_log_bt"
struct btmtk_fops_fwlog {
dev_t g_devIDfwlog;
struct cdev BT_cdevfwlog;
wait_queue_head_t fw_log_inq;
struct sk_buff_head fwlog_queue;
struct class *pBTClass;
struct device *pBTDevfwlog;
spinlock_t fwlog_lock;
u8 btmtk_bluetooth_kpi;
};
int btmtk_fops_initfwlog(void);
int btmtk_fops_exitfwlog(void);
void fw_log_bt_event_cb(void);
void fw_log_bt_state_cb(uint8_t state);
/** file_operations: stpbtfwlog */
int btmtk_fops_openfwlog(struct inode *inode, struct file *file);
int btmtk_fops_closefwlog(struct inode *inode, struct file *file);
ssize_t btmtk_fops_readfwlog(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t btmtk_fops_writefwlog(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
unsigned int btmtk_fops_pollfwlog(struct file *filp, poll_table *wait);
long btmtk_fops_unlocked_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg);
long btmtk_fops_compat_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg);
int btmtk_dispatch_fwlog(struct btmtk_dev *bdev, struct sk_buff *skb);
int btmtk_dispatch_fwlog_bluetooth_kpi(struct btmtk_dev *bdev, u8 *buf, int len, u8 type);
#endif /* __BTMTK_FW_LOG_H__ */

View file

@ -0,0 +1,680 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_MAIN_H__
#define __BTMTK_MAIN_H__
#include "btmtk_define.h"
#define DEFAULT_COUNTRY_TABLE_NAME "btPowerTable.dat"
//static inline struct sk_buff *mtk_add_stp(struct btmtk_dev *bdev, struct sk_buff *skb);
#define hci_dev_test_and_clear_flag(hdev, nr) test_and_clear_bit((nr), (hdev)->dev_flags)
/* h4_recv */
#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
#define hci_skb_expect(skb) bt_cb((skb))->expect
#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
#define HCI_SDIO 6
#define HCI_SPI 7
#define HCI_I2C 8
#define HCI_SMD 9
#define HCI_TYPE_SIZE 1
/* this for 7663 need download patch staus
* 0:
* patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1:
* patch download is complete
* 2:
* patch download is not complete/BT get patch semaphore success
*/
#define MT766X_PATCH_IS_DOWNLOAD_BY_OTHER 0
#define MT766X_PATCH_READY 1
#define MT766X_PATCH_NEED_DOWNLOAD 2
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define PATCH_ERR -1
#define PATCH_NEED_DOWNLOAD 0
#define PATCH_IS_DOWNLOAD_BY_OTHER 1
#define PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
/* * delay and retrey for main_send_cmd */
#define WMT_DELAY_TIMES 100
#define DELAY_TIMES 20
#define RETRY_TIMES 20
/* Expected minimum supported interface */
#define BT_MCU_MINIMUM_INTERFACE_NUM 4
/* Bus event */
#define HIF_EVENT_PROBE 0
#define HIF_EVENT_DISCONNECT 1
#define HIF_EVENT_SUSPEND 2
#define HIF_EVENT_RESUME 3
#define HIF_EVENT_STANDBY 4
#define HIF_EVENT_SUBSYS_RESET 5
#define HIF_EVENT_WHOLE_CHIP_RESET 6
#define HIF_EVENT_FW_DUMP 7
#define CHAR2HEX_SIZE 4
/**
* For chip reset pin
*/
#define RESET_PIN_SET_LOW_TIME 100
/* stpbtfwlog setting */
#define FWLOG_QUEUE_COUNT (400 * BT_MCU_MINIMUM_INTERFACE_NUM)
#define FWLOG_ASSERT_QUEUE_COUNT 45000
#define FWLOG_BLUETOOTH_KPI_QUEUE_COUNT 400
#define HCI_MAX_COMMAND_SIZE 255
#define HCI_MAX_COMMAND_BUF_SIZE (HCI_MAX_COMMAND_SIZE * 3)
//#define HCI_MAX_ISO_SIZE 340
/* fwlog information define */
#define FWLOG_TYPE 0xF0
#define FWLOG_LEN_SIZE 2
#define FWLOG_TL_SIZE (HCI_TYPE_SIZE + FWLOG_LEN_SIZE)
#define FWLOG_ATTR_TYPE_LEN 1
#define FWLOG_ATTR_LEN_LEN 1
#define FWLOG_ATTR_RX_LEN_LEN 2
#define FWLOG_ATTR_TL_SIZE (FWLOG_ATTR_TYPE_LEN + FWLOG_ATTR_LEN_LEN)
#define FWLOG_HCI_IDX 0x00
#define FWLOG_DONGLE_IDX 0x01
#define FWLOG_TX 0x10
#define FWLOG_RX 0x11
/* total fwlog info len */
#define FWLOG_PRSV_LEN 32
#define COUNTRY_CODE_LEN 2
#define EDR_MIN -32
#define EDR_MAX 20
#define EDR_MIN_LV9 13
#define BLE_MIN -29
#define BLE_MAX 20
#define EDR_MIN_R1 -64
#define EDR_MAX_R1 40
#define EDR_MIN_LV9_R1 26
#define BLE_MIN_R1 -58
#define BLE_MAX_R1 40
#define EDR_MIN_R2 -128
#define EDR_MAX_R2 80
#define EDR_MIN_LV9_R2 52
#define BLE_MIN_R2 -116
#define BLE_MAX_R2 80
#define ERR_PWR -9999
#define WAIT_POWERKEY_TIMEOUT 5000
#define SEPARATOR_LEN 2
#define STP_CRC_LEN 2
#define TEMP_LEN 260
#define SEARCH_LEN 32
#define TEXT_LEN 128
/* CMD&Event sent by driver */
#define READ_EFUSE_CMD_LEN 18
#define READ_EFUSE_EVT_HDR_LEN 9
#define READ_EFUSE_CMD_BLOCK_OFFSET 10
#define CHECK_LD_PATCH_CMD_LEN 9
#define CHECK_LD_PATCH_EVT_HDR_LEN 7
#define CHECK_LD_PATCH_EVT_RESULT_OFFSET 6 /* need confirm later */
#define HWERR_EVT_LEN 4
#define LD_PATCH_EVT_LEN 8
#define HCI_RESET_CMD_LEN 4
#define HCI_RESET_EVT_LEN 7
#define WMT_RESET_CMD_LEN 9
#define WMT_RESET_EVT_LEN 8
#define WMT_POWER_ON_CMD_LEN 10
#define WMT_POWER_ON_EVT_HDR_LEN 7
#define WMT_POWER_ON_EVT_RESULT_OFFSET 7
#define WMT_POWER_OFF_CMD_LEN 10
#define WMT_POWER_OFF_EVT_HDR_LEN 7
#define WMT_POWER_OFF_EVT_RESULT_OFFSET 7
#define PICUS_ENABLE_CMD_LEN 8
#define PICUS_ENABLE_EVT_HDR_LEN 9
#define PICUS_DISABLE_CMD_LEN 8
#define PICUS_DISABLE_EVT_HDR_LEN 9
#define RES_APCF_CMD_LEN 9
#define RES_APCF_EVT_LEN 5
#define READ_ADDRESS_CMD_LEN 4
#define READ_ADDRESS_EVT_HDR_LEN 7
#define WOBLE_ENABLE_DEFAULT_CMD_LEN 40
#define WOBLE_ENABLE_DEFAULT_EVT_LEN 5
#define WOBLE_DISABLE_DEFAULT_CMD_LEN 9
#define WOBLE_DISABLE_DEFAULT_EVT_LEN 5
#define RADIO_OFF_CMD_LEN 9
#define RADIO_OFF_EVT_LEN 5
#define RADIO_ON_CMD_LEN 9
#define RADIO_ON_EVT_LEN 5
#define APCF_FILTER_CMD_LEN 14
#define APCF_FILTER_EVT_HDR_LEN 8
#define APCF_CMD_LEN 43
#define APCF_EVT_HDR_LEN 7
#define APCF_DELETE_CMD_LEN 7
#define APCF_DELETE_EVT_HDR_LEN 8
#define APCF_RESUME_EVT_HDR_LEN 7
#define CHECK_WOBX_DEBUG_CMD_LEN 8
#define CHECK_WOBX_DEBUG_EVT_HDR_LEN 2
#define SET_STP_CMD_LEN 13
#define SET_STP_EVT_LEN 9
#define SET_STP1_CMD_LEN 16
#define SET_STP1_EVT_LEN 19
#define SET_SLEEP_CMD_LEN 11
#define SET_SLEEP_EVT_LEN 7
#define EVT_HDR_LEN 2
#define ASSERT_CMD_LEN 9
#define TXPOWER_CMD_LEN 16
#define TXPOWER_EVT_LEN 7
#define FW_COREDUMP_CMD_LEN 4
#define HCI_RESET_CMD_LEN 4
#define READ_ISO_PACKET_SIZE_CMD_HDR_LEN 4
#ifndef LD_PATCH_TIME
#define LD_PATCH_TIME 0
#endif
enum {
RES_1 = 0,
RES_DOT_5,
RES_DOT_25
};
enum {
CHECK_SINGLE_SKU_PWR_MODE = 0,
CHECK_SINGLE_SKU_EDR_MAX,
CHECK_SINGLE_SKU_BLE,
CHECK_SINGLE_SKU_BLE_2M,
CHECK_SINGLE_SKU_BLE_LR_S2,
CHECK_SINGLE_SKU_BLE_LR_S8,
CHECK_SINGLE_SKU_ALL
};
enum {
DISABLE_LV9 = 0,
ENABLE_LV9
};
enum {
DIFF_MODE_3DB = 0,
DIFF_MODE_0DB
};
struct btmtk_cif_state {
unsigned char ops_enter;
unsigned char ops_end;
unsigned char ops_error;
};
enum TX_TYPE {
BTMTK_TX_CMD_FROM_DRV = 0, /* send hci cmd and wmt cmd by driver */
BTMTK_TX_ACL_FROM_DRV, /* send acl pkt with load rompatch by driver */
BTMTK_TX_PKT_FROM_HOST, /* send pkt from host, include acl and hci */
};
enum bt_state {
FUNC_OFF = 0,
TURNING_ON = 1,
PRE_ON_AFTER_CAL = 2,
FUNC_ON = 3,
RESET_START = 4,
RESET_END = 5
};
struct bt_power_setting {
int8_t EDR_Max;
int8_t LV9;
int8_t DM;
int8_t IR;
int8_t BLE_1M;
int8_t BLE_2M;
int8_t BLE_LR_S2;
int8_t BLE_LR_S8;
char country_code[COUNTRY_CODE_LEN + 1];
};
enum {
BTMTK_DONGLE_STATE_UNKNOWN,
BTMTK_DONGLE_STATE_POWER_ON,
BTMTK_DONGLE_STATE_POWER_OFF,
BTMTK_DONGLE_STATE_ERROR,
};
enum {
HW_ERR_NONE = 0x00,
HW_ERR_CODE_CHIP_RESET = 0xF0,
HW_ERR_CODE_USB_DISC = 0xF1,
HW_ERR_CODE_CORE_DUMP = 0xF2,
HW_ERR_CODE_POWER_ON = 0xF3,
HW_ERR_CODE_POWER_OFF = 0xF4,
HW_ERR_CODE_SET_SLEEP_CMD = 0xF5,
HW_ERR_CODE_RESET_STACK_AFTER_WOBLE = 0xF6,
};
/* Please keep sync with btmtk_set_state function */
enum {
/* BTMTK_STATE_UNKNOWN = 0, */
BTMTK_STATE_INIT = 1,
BTMTK_STATE_DISCONNECT,
BTMTK_STATE_PROBE,
BTMTK_STATE_WORKING,
BTMTK_STATE_SUSPEND,
BTMTK_STATE_RESUME,
BTMTK_STATE_FW_DUMP,
BTMTK_STATE_STANDBY,
BTMTK_STATE_SUBSYS_RESET,
BTMTK_STATE_MSG_NUM
};
/* Please keep sync with btmtk_fops_set_state function */
enum {
/* BTMTK_FOPS_STATE_UNKNOWN = 0, */
BTMTK_FOPS_STATE_INIT = 1,
BTMTK_FOPS_STATE_OPENING, /* during opening */
BTMTK_FOPS_STATE_OPENED, /* open in fops_open */
BTMTK_FOPS_STATE_CLOSING, /* during closing */
BTMTK_FOPS_STATE_CLOSED, /* closed */
BTMTK_FOPS_STATE_MSG_NUM
};
enum {
BTMTK_EVENT_COMPARE_STATE_UNKNOWN,
BTMTK_EVENT_COMPARE_STATE_NOTHING_NEED_COMPARE,
BTMTK_EVENT_COMPARE_STATE_NEED_COMPARE,
BTMTK_EVENT_COMPARE_STATE_COMPARE_SUCCESS,
};
struct h4_recv_pkt {
u8 type; /* Packet type */
u8 hlen; /* Header length */
u8 loff; /* Data length offset in header */
u8 lsize; /* Data length field size */
u16 maxlen; /* Max overall packet length */
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
};
#pragma pack(1)
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 u4SecType;
u32 u4DLModeCrcType;
u32 u4Crc;
u32 reserved[6];
} bin_info_spec;
};
};
#pragma pack()
#define H4_RECV_ACL \
.type = HCI_ACLDATA_PKT, \
.hlen = HCI_ACL_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE \
#define H4_RECV_SCO \
.type = HCI_SCODATA_PKT, \
.hlen = HCI_SCO_HDR_SIZE, \
.loff = 2, \
.lsize = 1, \
.maxlen = HCI_MAX_SCO_SIZE
#define H4_RECV_EVENT \
.type = HCI_EVENT_PKT, \
.hlen = HCI_EVENT_HDR_SIZE, \
.loff = 1, \
.lsize = 1, \
.maxlen = HCI_MAX_EVENT_SIZE
/* yumin todo */
// TODO: replace by kernel constant if kernel support new spec
#define HCI_ISODATA_PKT 0x05
#define HCI_ISO_HDR_SIZE 4
#define H4_RECV_ISO \
.type = HCI_ISODATA_PKT, \
.hlen = HCI_ISO_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE
struct btmtk_dev {
struct hci_dev *hdev;
unsigned long hdev_flags;
unsigned long flags;
void *intf_dev;
void *cif_dev;
struct work_struct work;
struct work_struct waker;
struct work_struct reset_waker;
int recv_evt_len;
int tx_in_flight;
spinlock_t txlock;
spinlock_t rxlock;
struct sk_buff *evt_skb;
struct sk_buff *sco_skb;
/* For ble iso packet size */
int iso_threshold;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* For tx queue */
unsigned long tx_state;
/* For rx queue */
struct workqueue_struct *workqueue;
struct sk_buff_head rx_q;
struct work_struct rx_work;
struct sk_buff *rx_skb;
wait_queue_head_t p_wait_event_q;
unsigned int subsys_reset;
unsigned int chip_reset;
unsigned char *rom_patch_bin_file_name;
unsigned int chip_id;
unsigned int flavor;
unsigned int fw_version;
unsigned char dongle_index;
unsigned char power_state;
unsigned char fops_state;
unsigned char interface_state;
struct btmtk_cif_state *cif_state;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *setting_file;
unsigned char bdaddr[BD_ADDRESS_SIZE];
unsigned char *bt_cfg_file_name;
struct bt_cfg_struct bt_cfg;
/* single sku */
unsigned char *country_file_name;
u8 opcode_usr[2];
};
typedef int (*cif_bt_init_ptr)(void);
typedef void (*cif_bt_exit_ptr)(void);
typedef int (*cif_open_ptr)(struct hci_dev *hdev);
typedef int (*cif_close_ptr)(struct hci_dev *hdev);
typedef int (*cif_reg_read_ptr)(struct btmtk_dev *bdev, u32 reg, u32 *val);
typedef int (*cif_reg_write_ptr)(struct btmtk_dev *bdev, u32 reg, u32 val);
typedef int (*cif_send_cmd_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb,
int delay, int retry, int pkt_type);
typedef int (*cif_send_and_recv_ptr)(struct btmtk_dev *bdev,
struct sk_buff *skb,
const uint8_t *event, const int event_len,
int delay, int retry, int pkt_type);
typedef int (*cif_event_filter_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb);
typedef int (*cif_subsys_reset_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_whole_reset_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_chip_reset_notify_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_mutex_lock_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_mutex_unlock_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_flush_ptr)(struct btmtk_dev *bdev);
typedef void (*cif_log_init_ptr)(void);
typedef void (*cif_log_register_cb_ptr)(void (*func)(void));
typedef ssize_t (*cif_log_read_to_user_ptr)(char __user *buf, size_t count);
typedef unsigned int (*cif_log_get_buf_size_ptr)(void);
typedef void (*cif_log_deinit_ptr)(void);
typedef void (*cif_log_hold_sem_ptr)(void);
typedef void (*cif_log_release_sem_ptr)(void);
typedef void (*cif_open_done_ptr)(struct btmtk_dev *bdev);
typedef int (*cif_dl_dma_ptr)(struct btmtk_dev *bdev, u8 *image,
u8 *fwbuf, int section_dl_size, int section_offset);
struct hif_hook_ptr {
cif_bt_init_ptr init;
cif_bt_exit_ptr exit;
cif_open_ptr open;
cif_close_ptr close;
cif_reg_read_ptr reg_read;
cif_reg_write_ptr reg_write;
cif_send_cmd_ptr send_cmd;
cif_send_and_recv_ptr send_and_recv;
cif_event_filter_ptr event_filter;
cif_subsys_reset_ptr subsys_reset;
cif_whole_reset_ptr whole_reset;
cif_chip_reset_notify_ptr chip_reset_notify;
cif_mutex_lock_ptr cif_mutex_lock;
cif_mutex_unlock_ptr cif_mutex_unlock;
cif_flush_ptr flush;
cif_log_init_ptr log_init;
cif_log_register_cb_ptr log_register_cb;
cif_log_read_to_user_ptr log_read_to_user;
cif_log_get_buf_size_ptr log_get_buf_size;
cif_log_deinit_ptr log_deinit;
cif_log_hold_sem_ptr log_hold_sem;
cif_log_release_sem_ptr log_release_sem;
cif_open_done_ptr open_done;
cif_dl_dma_ptr dl_dma;
};
struct btmtk_main_info {
int whole_reset_flag;
u8 reset_stack_flag;
struct wakeup_source *fwdump_ws;
struct wakeup_source *woble_ws;
struct wakeup_source *eint_ws;
struct hif_hook_ptr hif_hook;
struct bt_power_setting PWS;
/* save Hci Snoop for debug*/
u8 hci_cmd_buf[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_MAX_BUF_SIZE];
u8 hci_cmd_len[HCI_SNOOP_ENTRY_NUM];
u16 hci_cmd_actual_len[HCI_SNOOP_ENTRY_NUM];
unsigned int hci_cmd_timestamp[HCI_SNOOP_ENTRY_NUM];
u8 hci_cmd_index;
u8 hci_event_buf[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_MAX_BUF_SIZE];
u8 hci_event_len[HCI_SNOOP_ENTRY_NUM];
u16 hci_event_actual_len[HCI_SNOOP_ENTRY_NUM];
unsigned int hci_event_timestamp[HCI_SNOOP_ENTRY_NUM];
u8 hci_event_index;
u8 hci_adv_event_buf[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_MAX_BUF_SIZE];
u8 hci_adv_event_len[HCI_SNOOP_ENTRY_NUM];
u16 hci_adv_event_actual_len[HCI_SNOOP_ENTRY_NUM];
unsigned int hci_adv_event_timestamp[HCI_SNOOP_ENTRY_NUM];
u8 hci_adv_event_index;
u8 hci_acl_buf[HCI_SNOOP_ENTRY_NUM][HCI_SNOOP_MAX_BUF_SIZE];
u8 hci_acl_len[HCI_SNOOP_ENTRY_NUM];
u16 hci_acl_actual_len[HCI_SNOOP_ENTRY_NUM];
unsigned int hci_acl_timestamp[HCI_SNOOP_ENTRY_NUM];
u8 hci_acl_index;
u8 wmt_over_hci_header[WMT_OVER_HCI_HEADER_SIZE];
u8 read_iso_packet_size_cmd[READ_ISO_PACKET_CMD_SIZE];
};
static inline int is_mt7922(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7922)
return 1;
return 0;
}
static inline int is_mt7961(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7961)
return 1;
return 0;
}
static inline int is_mt7663(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x7663)
return 1;
return 0;
}
static inline int is_mt66xx(u32 chip_id)
{
chip_id &= 0xFFFF;
if (chip_id == 0x6631 || chip_id == 0x6635)
return 1;
return 0;
}
unsigned char btmtk_get_chip_state(struct btmtk_dev *bdev);
void btmtk_set_chip_state(struct btmtk_dev *bdev, unsigned char new_state);
int btmtk_allocate_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
void btmtk_free_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
int btmtk_register_hci_device(struct btmtk_dev *bdev);
int btmtk_deregister_hci_device(struct btmtk_dev *bdev);
int btmtk_recv(struct hci_dev *hdev, const u8 *data, size_t count);
int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_recv_acl(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_recv_iso(struct hci_dev *hdev, struct sk_buff *skb);
int btmtk_send_init_cmds(struct btmtk_dev *hdev);
int btmtk_send_deinit_cmds(struct btmtk_dev *hdev);
int btmtk_send_wmt_reset(struct btmtk_dev *hdev);
int btmtk_load_rom_patch_766x(struct btmtk_dev *hdev);
int btmtk_load_rom_patch(struct btmtk_dev *bdev);
struct btmtk_dev *btmtk_get_dev(void);
void btmtk_reset_waker(struct work_struct *work);
int btmtk_cap_init(struct btmtk_dev *bdev);
struct btmtk_main_info *btmtk_get_main_info(void);
int btmtk_get_interface_num(void);
int btmtk_reset_power_on(struct btmtk_dev *bdev);
void btmtk_send_hw_err_to_host(struct btmtk_dev *bdev);
void btmtk_free_setting_file(struct btmtk_dev *bdev);
unsigned char btmtk_fops_get_state(struct btmtk_dev *bdev);
void btmtk_fops_set_state(struct btmtk_dev *bdev, unsigned char new_state);
void btmtk_hci_snoop_save_cmd(u32 len, u8 *buf);
void btmtk_hci_snoop_save_event(u32 len, u8 *buf);
void btmtk_hci_snoop_save_adv_event(u32 len, u8 *buf);
void btmtk_hci_snoop_save_acl(u32 len, u8 *buf);
void btmtk_hci_snoop_print(u32 len, const u8 *buf);
void btmtk_hci_snoop_print_to_log(void);
unsigned long btmtk_kallsyms_lookup_name(const char *name);
void btmtk_do_gettimeofday(struct timespec64 *tv);
void btmtk_reg_hif_hook(struct hif_hook_ptr *hook);
int btmtk_main_cif_initialize(struct btmtk_dev *bdev, int hci_bus);
void btmtk_main_cif_uninitialize(struct btmtk_dev *bdev, int hci_bus);
int btmtk_main_cif_disconnect_notify(struct btmtk_dev *bdev, int hci_bus);
int btmtk_load_code_from_bin(u8 **image, char *bin_name,
struct device *dev, u32 *code_len, u8 retry);
int btmtk_main_send_cmd(struct btmtk_dev *bdev, const uint8_t *cmd,
const int cmd_len, const uint8_t *event, const int event_len, int delay,
int retry, int pkt_type);
int btmtk_load_code_from_setting_files(char *setting_file_name,
struct device *dev, u32 *code_len, struct btmtk_dev *bdev);
int btmtk_load_fw_cfg_setting(char *block_name, struct fw_cfg_struct *save_content,
int counter, u8 *searchcontent, enum fw_cfg_index_len index_length);
int btmtk_send_assert_cmd(struct btmtk_dev *bdev);
void btmtk_free_fw_cfg_struct(struct fw_cfg_struct *fw_cfg, int count);
struct btmtk_dev **btmtk_get_pp_bdev(void);
int32_t btmtk_set_sleep(struct hci_dev *hdev, u_int8_t need_wait);
int32_t bgfsys_bt_patch_dl(void);
int btmtk_efuse_read(struct btmtk_dev *bdev, u16 addr, u8 *value);
void btmtk_set_country_code_from_wifi(char *code);
#endif /* __BTMTK_MAIN_H__ */

View file

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __BTMTK_WOBLE_H__
#define __BTMTK_WOBLE_H__
#include "btmtk_define.h"
#include "btmtk_main.h"
/* Define for WoBLE */
#define WOBLE_SETTING_COUNT 10
#define WOBLE_SETTING_FILE_NAME_7663 "woble_setting_7663.bin"
#define WOBLE_SETTING_FILE_NAME_7961 "woble_setting_7961.bin"
#define WOBLE_EVENT_INTERVAL_TIMO 500
#define WOBLE_COMP_EVENT_TIMO 5000
struct btmtk_woble {
unsigned char *woble_setting_file_name;
unsigned int woble_setting_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
struct fw_cfg_struct woble_setting_radio_off_status_event;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct fw_cfg_struct woble_setting_radio_on;
struct fw_cfg_struct woble_setting_radio_on_status_event;
struct fw_cfg_struct woble_setting_radio_on_comp_event;
/* set apcf after resume(radio on) */
struct fw_cfg_struct woble_setting_apcf_resume[WOBLE_SETTING_COUNT];
/* Foe Woble eint */
unsigned int wobt_irq;
int wobt_irqlevel;
atomic_t irq_enable_count;
struct input_dev *WoBLEInputDev;
void *bdev;
};
int btmtk_woble_suspend(struct btmtk_woble *bt_woble);
int btmtk_woble_resume(struct btmtk_woble *bt_woble);
int btmtk_woble_initialize(struct btmtk_dev *bdev, struct btmtk_woble *bt_woble);
void btmtk_woble_uninitialize(struct btmtk_woble *bt_woble);
void btmtk_woble_wake_unlock(struct btmtk_dev *bdev);
#endif /* __BTMTK_WOBLE_H__ */

View file

@ -0,0 +1,161 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_SDIO_H_
#define _BTMTK_SDIO_H_
/* It's for reset procedure */
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_woble.h"
#include "btmtk_buffer_mode.h"
#ifndef BTMTK_SDIO_DEBUG
#define BTMTK_SDIO_DEBUG 0
#endif
/**
* Card-relate definition.
*/
#define SDIO_VENDOR_ID_MEDIATEK 0x037A
#define HCI_HEADER_LEN 4
#define MTK_STP_TLR_SIZE 2
#define STP_HEADER_LEN 4
#define STP_HEADER_CRC_LEN 2
#define HCI_MAX_COMMAND_SIZE 255
#define URB_MAX_BUFFER_SIZE (4*1024)
#define BTMTK_SDIO_FUNC 2
/* common register address */
#define CCIR 0x0000
#define CHLPCR 0x0004
#define CSDIOCSR 0x0008
#define CHCR 0x000C
#define CHISR 0x0010
#define CHIER 0x0014
#define CTDR 0x0018
#define CRDR 0x001C
#define CTFSR 0x0020
#define CRPLR 0x0024
#define PD2HRM0R 0x00DC
#define SWPCDBGR 0x0154
/* CHLPCR */
#define C_FW_INT_EN_SET 0x00000001
#define C_FW_INT_EN_CLEAR 0x00000002
/* CHISR */
#define RX_PKT_LEN 0xFFFF0000
#define FIRMWARE_INT 0x0000FE00
/* PD2HRM0R */
#define PD2HRM0R_DRIVER_OWN 0x00000001
#define PD2HRM0R_FW_OWN 0x00000000
/* MCU notify host dirver for L0.5 reset */
#define FIRMWARE_INT_BIT31 0x80000000
/* MCU notify host driver for coredump */
#define FIRMWARE_INT_BIT15 0x00008000
#define TX_FIFO_OVERFLOW 0x00000100
#define FW_INT_IND_INDICATOR 0x00000080
#define TX_COMPLETE_COUNT 0x00000070
#define TX_UNDER_THOLD 0x00000008
#define TX_EMPTY 0x00000004
#define RX_DONE 0x00000002
#define FW_OWN_BACK_INT 0x00000001
/* MCU address offset */
#define MCU_ADDRESS_OFFSET_CMD 12
#define MCU_ADDRESS_OFFSET_EVT 16
/* wifi CR */
#define CONDBGCR 0x0034
#define CONDBGCR_SEL 0x0040
#define SDIO_CTRL_EN (1 << 31)
#define WM_MONITER_SEL (~(0x40000000))
#define PC_MONITER_SEL (~(0x20000000))
#define PC_IDX_SWH(val, idx) ((val & (~(0x3F << 16))) | ((0x3F & idx) << 16))
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define SDIO_BLOCK_SIZE 512
#define SDIO_RW_RETRY_COUNT 500
#define MTK_SDIO_PACKET_HEADER_SIZE 4
/* Driver & FW own related */
#define DRIVER_OWN 0
#define FW_OWN 1
#define SET_OWN_LOOP_COUNT 20
/* CMD&Event sent by driver */
#define READ_REGISTER_CMD_LEN 16
#define READ_REGISTER_EVT_HDR_LEN 11
#define FW_ASSERT_CMD_LEN 4
#define FW_ASSERT_CMD1_LEN 9
#define NOTIFY_ALT_EVT_LEN 7
#define READ_ADDRESS_EVT_HDR_LEN 7
#define READ_ADDRESS_EVT_PAYLOAD_OFFSET 7
#define WOBLE_DEBUG_EVT_TYPE 0xE8
#define LD_PATCH_CMD_LEN 10
#define LD_PATCH_EVT_LEN 8
struct btmtk_sdio_hdr {
/* For SDIO Header */
__le16 len;
__le16 reserved;
/* For hci type */
u8 bt_type;
} __packed;
struct btmtk_sdio_thread {
struct task_struct *task;
wait_queue_head_t wait_q;
void *priv;
u8 thread_status;
};
struct btmtk_sdio_dev {
struct sdio_func *func;
bool no_fw_own;
atomic_t int_count;
atomic_t tx_rdy;
/* TODO, need to confirm the max size of urb data, also need to confirm
* whether intr_complete and bulk_complete and soc_complete can all share
* this urb_transfer_buf
*/
unsigned char *transfer_buf;
unsigned char *sdio_packet;
struct sk_buff_head tx_queue;
struct btmtk_sdio_thread sdio_thread;
struct btmtk_woble bt_woble;
struct btmtk_buffer_mode_struct *buffer_mode;
};
int btmtk_sdio_read_bt_mcu_pc(u32 *val);
int btmtk_sdio_read_conn_infra_pc(u32 *val);
#endif

View file

@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_UART_H_
#define _BTMTK_UART_H_
#include "btmtk_define.h"
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/serial.h>
#define HCI_HEADER_LEN 4
struct mtk_stp_hdr {
u8 prefix;
__be16 dlen;
u8 cs;
} __packed;
#define MTK_STP_TLR_SIZE 2
#define STP_HEADER_LEN 4
#define STP_HEADER_CRC_LEN 2
struct btmtk_uart_dev {
struct hci_dev *hdev;
struct tty_struct *tty;
unsigned long hdev_flags;
/* For tx queue */
struct sk_buff *tx_skb;
unsigned long tx_state;
/* For rx queue */
struct sk_buff *rx_skb;
unsigned long rx_state;
struct sk_buff *evt_skb;
wait_queue_head_t p_wait_event_q;
unsigned int subsys_reset;
u8 stp_pad[6];
u8 stp_cursor;
u16 stp_dlen;
};
/**
* Maximum rom patch file name length
*/
#define MAX_BIN_FILE_NAME_LEN 32
#define N_MTK (15+1)
/**
* Upper layeard IOCTL
*/
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTSETBAUD _IOW('U', 201, int)
#define HCIUARTGETBAUD _IOW('U', 202, int)
#define HCIUARTSETSTP _IOW('U', 203, int)
#define HCIUARTLOADPATCH _IOW('U', 204, int)
#define HCIUARTSETWAKEUP _IOW('U', 205, int)
/**
* Send cmd dispatch evt
*/
#define RETRY_TIMES 10
#define HCI_EV_VENDOR 0xff
#define N_MTK (15+1)
int btmtk_cif_send_calibration(struct hci_dev *hdev);
#endif

View file

@ -0,0 +1,92 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _BTMTK_USB_H_
#define _BTMTK_USB_H_
#include <linux/usb.h>
#include "btmtk_define.h"
#include "btmtk_main.h"
#include "btmtk_woble.h"
#define HCI_MAX_COMMAND_SIZE 255
#define URB_MAX_BUFFER_SIZE (4*1024)
#define BT0_MCU_INTERFACE_NUM 0
#define BT1_MCU_INTERFACE_NUM 3
#define BT_MCU_INTERFACE_NUM_MAX 4
#define BT_MCU_NUM_MAX 2
typedef int (*pdwnc_func) (u8 fgReset);
typedef int (*reset_func_ptr2) (unsigned int gpio, int init_value);
typedef int (*set_gpio_low)(u8 gpio);
typedef int (*set_gpio_high)(u8 gpio);
/**
* Send cmd dispatch evt
*/
#define HCI_EV_VENDOR 0xff
#define HCI_USB_IO_BUF_SIZE 256
/* UHW CR mapping */
#define BT_MISC 0x70002510
#define BT_SUBSYS_RST 0x70002610
#define UDMA_INT_STA_BT 0x74000024
#define UDMA_INT_STA_BT1 0x74000308
#define BT_WDT_STATUS 0x740003A0
#define EP_RST_OPT 0x74011890
#define EP_RST_IN_OUT_OPT 0x00010001
struct btmtk_cif_chip_reset {
/* For Whole chip reset */
pdwnc_func pf_pdwndFunc;
reset_func_ptr2 pf_resetFunc2;
set_gpio_low pf_lowFunc;
set_gpio_high pf_highFunc;
};
struct btmtk_usb_dev {
struct usb_endpoint_descriptor *intr_ep;
/* EP10 OUT */
struct usb_endpoint_descriptor *intr_iso_tx_ep;
/* EP10 IN */
struct usb_endpoint_descriptor *intr_iso_rx_ep;
/* BULK CMD EP1 OUT or EP 11 OUT */
struct usb_endpoint_descriptor *bulk_cmd_tx_ep;
/* EP15 in for reset */
struct usb_endpoint_descriptor *reset_intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
struct usb_device *udev;
struct usb_interface *intf;
struct usb_interface *isoc;
struct usb_interface *iso_channel;
struct usb_anchor tx_anchor;
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
struct usb_anchor ctrl_anchor;
struct usb_anchor ble_isoc_anchor;
__u8 cmdreq_type;
__u8 cmdreq;
int new_isoc_altsetting;
int new_isoc_altsetting_interface;
unsigned char *o_usb_buf;
unsigned char *urb_intr_buf;
unsigned char *urb_bulk_buf;
unsigned char *urb_ble_isoc_buf;
struct btmtk_woble bt_woble;
};
#endif

View file

@ -0,0 +1,3 @@
# load btmtksdio
on boot
insmod /vendor/lib/modules/btmtk_sdio_unify.ko

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,311 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "btmtk_define.h"
#include "btmtk_uart.h"
#include "btmtk_main.h"
#define LOG TRUE
/*============================================================================*/
/* Global Variable */
/*============================================================================*/
static struct btmtk_dev *g_bdev;
/*============================================================================*/
/* Function Prototype */
/*============================================================================*/
static int btmtk_uart_allocate_memory(void);
unsigned long flagss;
/* Allocate Uart-Related memory */
static int btmtk_uart_allocate_memory(void)
{
if (g_bdev == NULL) {
g_bdev = kzalloc(sizeof(*g_bdev), GFP_KERNEL);
if (!g_bdev) {
BTMTK_ERR("%s: alloc memory fail (g_data)", __func__);
return -1;
}
}
return 0;
}
int btmtk_cif_send_calibration(struct hci_dev *hdev)
{
return 0;
}
/* Send cmd and Receive evt */
int btmtk_cif_send_cmd(struct hci_dev *hdev, const uint8_t *cmd,
const int cmd_len, int retry, int endpoint, unsigned long tx_state)
{
int ret = -1, len = 0;
struct btmtk_dev *bdev = hci_get_drvdata(hdev);
BTMTK_DBG_RAW(cmd, cmd_len, "%s, len = %d Send CMD : ", __func__, cmd_len);
/* BTMTK_INFO("%s: tty %p\n", __func__, bdev->tty); */
while (len != cmd_len) {
ret = bdev->tty->ops->write(bdev->tty, cmd, cmd_len);
len += ret;
BTMTK_DBG("%s, len = %d", __func__, len);
}
return ret;
}
static int btmtk_uart_send_query_uart_cmd(struct hci_dev *hdev)
{
u8 cmd[] = { 0x01, 0x6F, 0xFC, 0x05, 0x01, 0x04, 0x01, 0x00, 0x02};
/* To-Do, for event check */
/* u8 event[] = { 0x04, 0xE4, 0x0a, 0x02, 0x04, 0x06, 0x00, 0x00, 0x02}; */
btmtk_main_send_cmd(hdev, cmd, sizeof(cmd), BTMTK_TX_WAIT_VND_EVT);
BTMTK_INFO("%s done", __func__);
return 0;
}
/* ------ LDISC part ------ */
/* btmtk_uart_tty_open
*
* Called when line discipline changed to HCI_UART.
*
* Arguments:
* tty pointer to tty info structure
* Return Value:
* 0 if success, otherwise error code
*/
static int btmtk_uart_tty_open(struct tty_struct *tty)
{
BTMTK_INFO("%s: tty %p\n", __func__, tty);
/* Init tty-related operation */
tty->receive_room = 65536;
tty->port->low_latency = 1;
btmtk_uart_allocate_memory();
tty->disc_data = g_bdev;
g_bdev->tty = tty;
/* Flush any pending characters in the driver and line discipline. */
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
* open path is before the ldisc is referencable
*/
btmtk_allocate_hci_device(g_bdev, HCI_UART);
g_bdev->stp_cursor = 2;
g_bdev->stp_dlen = 0;
/* definition changed!! */
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
BTMTK_INFO("%s: tty done %p\n", __func__, tty);
return 0;
}
/* btmtk_uart_tty_close()
*
* Called when the line discipline is changed to something
* else, the tty is closed, or the tty detects a hangup.
*/
static void btmtk_uart_tty_close(struct tty_struct *tty)
{
btmtk_free_hci_device(g_bdev, HCI_UART);
BTMTK_INFO("%s: tty %p", __func__, tty);
}
/*
* We don't provide read/write/poll interface for user space.
*/
static ssize_t btmtk_uart_tty_read(struct tty_struct *tty, struct file *file,
unsigned char *buf, size_t count)
{
BTMTK_INFO("%s: tty %p", __func__, tty);
return 0;
}
static ssize_t btmtk_uart_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *data, size_t count)
{
BTMTK_INFO("%s: tty %p", __func__, tty);
return 0;
}
static unsigned int btmtk_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
if (g_bdev->subsys_reset == 1) {
mask |= POLLIN | POLLRDNORM; /* readable */
BTMTK_INFO("%s: tty %p", __func__, tty);
}
return mask;
}
/* btmtk_uart_tty_ioctl()
*
* Process IOCTL system call for the tty device.
*
* Arguments:
*
* tty pointer to tty instance data
* file pointer to open file object for device
* cmd IOCTL command code
* arg argument for IOCTL call (cmd dependent)
*
* Return Value: Command dependent
*/
static int btmtk_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
u32 err = 0;
BTMTK_INFO("%s: tty %p", __func__, tty);
switch (cmd) {
case HCIUARTSETPROTO:
pr_info("<!!> Set low_latency to TRUE <!!>\n");
tty->port->low_latency = 1;
break;
case HCIUARTSETBAUD:
pr_info("<!!> Set BAUDRATE <!!>\n");
btmtk_uart_send_set_uart_cmd(g_bdev->hdev);
msleep(100);
return 1;
case HCIUARTSETWAKEUP:
pr_info("<!!> Send Wakeup <!!>\n");
btmtk_uart_send_wakeup_cmd(g_bdev->hdev);
pr_info("<!!> Send Wakeup done, then wait 200ms for uart sleep <!!>\n");
msleep(200);
return 1;
case HCIUARTGETBAUD:
pr_info("<!!> Get BAUDRATE <!!>\n");
btmtk_uart_send_query_uart_cmd(g_bdev->hdev);
return 1;
case HCIUARTSETSTP:
pr_info("<!!> Set STP mandatory command <!!>\n");
return 1;
case HCIUARTLOADPATCH:
pr_info("<!!> Set HCIUARTLOADPATCH command <!!>\n");
btmtk_load_rom_patch_766x(g_bdev->hdev);
return 1;
default:
/* pr_info("<!!> n_tty_ioctl_helper <!!>\n"); */
err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
};
return err;
}
static void btmtk_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{
int ret = -1;
struct btmtk_dev *bdev = tty->disc_data;
BTMTK_DBG_RAW(data, count, "Receive");
/* add hci device part */
ret = btmtk_recv(bdev->hdev, data, count);
if (test_and_clear_bit(BTMTKUART_TX_SKIP_VENDOR_EVT, &bdev->tx_state)) {
BTMTK_DBG("%s clear bit BTMTKUART_TX_SKIP_VENDOR_EVT", __func__);
wake_up(&bdev->p_wait_event_q);
BTMTK_DBG("%s wake_up p_wait_event_q", __func__);
} else if (ret < 0) {
BTMTK_ERR("%s, ret = %d", __func__, ret);
}
}
/* btmtk_uart_tty_wakeup()
*
* Callback for transmit wakeup. Called when low level
* device driver can accept more send data.
*
* Arguments: tty pointer to associated tty instance data
* Return Value: None
*/
static void btmtk_uart_tty_wakeup(struct tty_struct *tty)
{
BTMTK_INFO("%s: tty %p", __func__, tty);
}
static int uart_register(void)
{
static struct tty_ldisc_ops btmtk_uart_ldisc;
u32 err = 0;
BTMTK_INFO("%s", __func__);
/* Register the tty discipline */
memset(&btmtk_uart_ldisc, 0, sizeof(btmtk_uart_ldisc));
btmtk_uart_ldisc.magic = TTY_LDISC_MAGIC;
btmtk_uart_ldisc.name = "n_mtk";
btmtk_uart_ldisc.open = btmtk_uart_tty_open;
btmtk_uart_ldisc.close = btmtk_uart_tty_close;
btmtk_uart_ldisc.read = btmtk_uart_tty_read;
btmtk_uart_ldisc.write = btmtk_uart_tty_write;
btmtk_uart_ldisc.ioctl = btmtk_uart_tty_ioctl;
btmtk_uart_ldisc.poll = btmtk_uart_tty_poll;
btmtk_uart_ldisc.receive_buf = btmtk_uart_tty_receive;
btmtk_uart_ldisc.write_wakeup = btmtk_uart_tty_wakeup;
btmtk_uart_ldisc.owner = THIS_MODULE;
err = tty_register_ldisc(N_MTK, &btmtk_uart_ldisc);
if (err) {
BTMTK_ERR("MTK line discipline registration failed. (%d)", err);
return err;
}
BTMTK_INFO("%s done", __func__);
return err;
}
static int uart_deregister(void)
{
u32 err = 0;
err = tty_unregister_ldisc(N_MTK);
if (err) {
BTMTK_ERR("line discipline registration failed. (%d)", err);
return err;
}
return 0;
}
int btmtk_cif_register(void)
{
int ret = -1;
BTMTK_INFO("%s", __func__);
ret = uart_register();
if (ret < 0) {
BTMTK_ERR("*** UART registration fail(%d)! ***", ret);
return ret;
}
BTMTK_INFO("%s: Done", __func__);
return 0;
}
int btmtk_cif_deregister(void)
{
int ret = -1;
BTMTK_INFO("%s", __func__);
ret = uart_deregister();
if (ret < 0) {
BTMTK_ERR("*** UART deregistration fail(%d)! ***", ret);
return ret;
}
BTMTK_INFO("%s: Done", __func__);
return 0;
}

View file

@ -0,0 +1,10 @@
LAUNCHER_SDIO=uart_launcher
LAUNCHER_SDIO_SRC=uart_launcher.c
all: $(LAUNCHER_SDIO)
$(LAUNCHER_SDIO):
$(CC) -o $(LAUNCHER_SDIO) $(LAUNCHER_SDIO_SRC)
clean:
rm $(LAUNCHER_UART) ${LAUNCHER_SDIO}

View file

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _LINUX_SERIAL_H
#define _LINUX_SERIAL_H
struct serial_struct {
int type;
int line;
unsigned int port;
int irq;
int flags;
int xmit_fifo_size;
int custom_divisor;
int baud_base;
unsigned short close_delay;
char io_type;
char reserved_char[1];
int hub6;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
unsigned int port_high;
unsigned long iomap_base;
};
#define ASYNCB_HUP_NOTIFY 0
#define ASYNCB_FOURPORT 1
#define ASYNCB_SAK 2
#define ASYNCB_SPLIT_TERMIOS 3
#define ASYNCB_SPD_HI 4
#define ASYNCB_SPD_VHI 5
#define ASYNCB_SKIP_TEST 6
#define ASYNCB_AUTO_IRQ 7
#define ASYNCB_SESSION_LOCKOUT 8
#define ASYNCB_PGRP_LOCKOUT 9
#define ASYNCB_CALLOUT_NOHUP 10
#define ASYNCB_HARDPPS_CD 11
#define ASYNCB_SPD_SHI 12
#define ASYNCB_LOW_LATENCY 13
#define ASYNCB_BUGGY_UART 14
#define ASYNCB_AUTOPROBE 15
#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED)
#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
#define ASYNC_SAK (1U << ASYNCB_SAK)
#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI)
#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI)
#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST)
#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ)
#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT)
#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT)
#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP)
#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD)
#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI)
#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE)
#define ASYNC_FLAGS ((1U << ASYNCB_LAST_USER) - 1)
#define ASYNC_USR_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI| \
ASYNC_CALLOUT_NOHUP|ASYNC_SPD_SHI|ASYNC_LOW_LATENCY)
#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI)
#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED)
#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE)
#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF)
#define ASYNC_CLOSING (1U << ASYNCB_CLOSING)
#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW)
#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD)
#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ)
#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW)
#define ASYNC_BOOT_ONLYMCA (1U << ASYNCB_BOOT_ONLYMCA)
#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1))
#endif /* _LINUX_SERIAL_H */

View file

@ -0,0 +1,545 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
/******************************************************************************
* C O M P I L E R F L A G S
*******************************************************************************
*/
/******************************************************************************
* E X T E R N A L R E F E R E N C E S
*******************************************************************************
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <linux/serial.h> /* struct serial_struct */
/******************************************************************************
* C O N S T A N T S
*******************************************************************************
*/
#ifndef N_MTKSTP
#define N_MTKSTP (15 + 1) /* MediaTek WCN Serial Transport Protocol */
#endif
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTSETBAUD _IOW('U', 201, int)
#define HCIUARTGETBAUD _IOW('U', 202, int)
#define HCIUARTSETSTP _IOW('U', 203, int)
#define HCIUARTLOADPATCH _IOW('U', 204, int)
#define HCIUARTSETWAKEUP _IOW('U', 205, int)
#define CUST_COMBO_WMT_DEV "/dev/stpwmt"
#define CUST_COMBO_STP_DEV "/dev/ttyUSB0"
#define CUST_COMBO_PATCH_PATH "/etc/firmware" //-- for ALPS
#define CUST_BAUDRATE_DFT (115200)
#define CUST_MULTI_PATCH (1)
#ifdef CFG_MTK_SOC_CONSYS_SUPPORT
#define CUST_MTK_SOC_CONSYS (1)
#else
#define CUST_MTK_SOC_CONSYS (0)
#endif
typedef enum {
STP_MIN = 0x0,
STP_UART_FULL = 0x1,
STP_UART_MAND = 0x2,
STP_BTIF_FULL = 0x3,
STP_SDIO = 0x4,
STP_MAX = 0x5,
}STP_MODE;
#define MAX_CMD_LEN (NAME_MAX+1)
typedef enum {
UART_DISABLE_FC = 0, /*NO flow control*/
UART_MTK_SW_FC = 1, /*MTK SW Flow Control, differs from Linux Flow Control*/
UART_LINUX_FC = 2, /*Linux SW Flow Control*/
UART_HW_FC = 3, /*HW Flow Control*/
} STP_UART_FC;
#ifdef ANDROID
typedef struct
{
const char *key;
const char *defValue;
char value[PROPERTY_VALUE_MAX];
}SYS_PROPERTY;
#endif
typedef struct {
STP_UART_FC fc;
int parity;
int stop_bit;
} STP_UART_CONFIG;
typedef struct {
STP_MODE eStpMode;
char *pPatchPath;
char *pPatchName;
char *gStpDev;
int iBaudrate;
STP_UART_CONFIG sUartConfig;
}STP_PARAMS_CONFIG, *P_STP_PARAMS_CONFIG;
#if CUST_MULTI_PATCH
typedef struct {
int dowloadSeq;
char addRess[4];
char patchName[256];
}STP_PATCH_INFO,*P_STP_PATCH_INFO;
#endif
typedef struct {
const char *pCfgItem;
char cfgItemValue[NAME_MAX + 1];
}CHIP_ANT_MODE_INFO, *P_CHIP_ANT_MODE_INFO;
typedef struct {
int chipId;
STP_MODE stpMode;
CHIP_ANT_MODE_INFO antMode;
}CHIP_MODE_INFO, *P_CHIP_MODE_INFO;
#ifdef ANDROID
#ifndef WMT_PLAT_APEX
CHIP_MODE_INFO gChipModeInfo[] = {
{0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}},
{0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}},
{0x6630, STP_UART_FULL, {"mt6630.defAnt", "mt6630_ant_m1.cfg"}},
};
#else
CHIP_MODE_INFO gChipModeInfo[] = {
{0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
{0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
{0x6630, STP_UART_FULL, {"mt6630.defAnt", "WMT.cfg"}},
};
#endif
#else
CHIP_MODE_INFO gChipModeInfo[] = {
{0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}},
{0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}},
{0x6630, STP_UART_FULL, {"mt6630.defAnt", "WMT.cfg"}},
};
#endif
/******************************************************************************
* D A T A T Y P E S
*******************************************************************************
*/
struct cmd_hdr{
char *pCmd;
int (*hdr_func)(P_STP_PARAMS_CONFIG pStpParamsConfig);
};
struct speed_map {
unsigned int baud;
speed_t speed;
};
/******************************************************************************
* M A C R O S
*******************************************************************************
*/
#define INIT_CMD(c, e, s) {.cmd= c, .cmd_sz=sizeof(c), .evt=e, .evt_sz=sizeof(e), .str=s}
/******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
*******************************************************************************
*/
static int set_speed(int fd, struct termios *ti, int speed);
int setup_uart_param (int hComPort, int iBaudrate, STP_UART_CONFIG *stp_uart);
int cmd_hdr_baud (P_STP_PARAMS_CONFIG pStpParamsConfig, int baudrate);
/*int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig);*/
int cmd_hdr_stp_open (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_stp_close (P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_stp_rst(P_STP_PARAMS_CONFIG pStpParamsConfig);
int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig);
static int wmt_cfg_item_parser(char *pItem);
static speed_t get_speed (int baudrate);
/******************************************************************************
* P U B L I C D A T A
*******************************************************************************
*/
/******************************************************************************
* P R I V A T E D A T A
*******************************************************************************
*/
static struct speed_map speeds[] = {
{115200, B115200},
{921600, B921600},
{1000000, B1000000},
{1152000, B1152000},
{2000000, B2000000},
{2500000, B2500000},
{3000000, B3000000},
{3500000, B3500000},
{4000000, B4000000},
};
static STP_UART_CONFIG g_stp_uart_config;
static volatile sig_atomic_t __io_canceled = 0;
static char gPatchName[NAME_MAX+1]= {0};
static char gPatchFolder[NAME_MAX+1]= {0};
static char gStpDev[NAME_MAX+1]= {0};
static int gStpMode = -1;
static char gWmtCfgName[NAME_MAX+1] = {0};
static int gWmtFd = -1;
static int gWmtBtFd = -1;
static int gTtyFd = -1;
static char gCmdStr[MAX_CMD_LEN]= {0};
static char gRespStr[MAX_CMD_LEN]= {0};
static int gFmMode = 2; /* 1: i2c, 2: comm I/F */
static const char *gUartName = NULL;
#if CUST_MULTI_PATCH
static unsigned int gPatchNum = 0;
static unsigned int gDwonSeq = 0;
static P_STP_PATCH_INFO pStpPatchInfo = NULL;
static STP_PATCH_INFO gStpPatchInfo;
#endif
/******************************************************************************
* F U N C T I O N S
*******************************************************************************
*/
/* Used as host uart param setup callback */
int setup_uart_param (
int hComPort,
int iBaudrate,
STP_UART_CONFIG *stpUartConfig)
{
struct termios ti;
int fd;
printf("setup_uart_param begin\n");
if(!stpUartConfig){
perror("Invalid stpUartConfig");
return -2;
}
printf("setup_uart_param %d %d\n", iBaudrate, stpUartConfig->fc);
fd = hComPort;
if (fd < 0) {
perror("Invalid serial port");
return -2;
}
tcflush(fd, TCIOFLUSH);
if (tcgetattr(fd, &ti) < 0) {
perror("Can't get port settings");
return -3;
}
cfmakeraw(&ti);
printf("ti.c_cflag = 0x%08x\n", ti.c_cflag);
ti.c_cflag |= CLOCAL;
printf("CLOCAL = 0x%x\n", CLOCAL);
printf("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag);
printf("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag);
printf("stpUartConfig->fc= %d (0:none,sw,hw,linux)\n", stpUartConfig->fc);
if(stpUartConfig->fc == UART_DISABLE_FC){
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag &= ~(0x80000000);
} else if(stpUartConfig->fc == UART_MTK_SW_FC){
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag |= 0x80000000; /*MTK Software FC*/
} else if(stpUartConfig->fc == UART_HW_FC){
printf("stpUartConfig->fc is UART_HW_FC\n");
ti.c_cflag |= CRTSCTS; /*RTS, Enable*/
ti.c_iflag &= ~(0x80000000);
} else if(stpUartConfig->fc == UART_LINUX_FC){
ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag &= ~(0x80000000);
}else {
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag &= ~(0x80000000);
}
printf("c_c CRTSCTS = 0x%16x\n", CRTSCTS);
printf("c_i IXON = 0x%08x\n", IXON);
printf("c_i IXOFF = 0x%08x\n", IXOFF);
printf("c_i IXANY = 0x%08x\n", IXANY);
printf("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag);
printf("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag);
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
perror("Can't set port settings");
return -4;
}
/* Set baudrate */
if (set_speed(fd, &ti, iBaudrate) < 0) {
perror("Can't set initial baud rate");
return -5;
}
tcflush(fd, TCIOFLUSH);
printf("%s done \n\n", __func__);
return 0;
}
static speed_t get_speed (int baudrate)
{
unsigned int idx;
for (idx = 0; idx < sizeof(speeds)/sizeof(speeds[0]); idx++) {
if (baudrate == (int)speeds[idx].baud) {
return speeds[idx].speed;
}
}
return CBAUDEX;
}
int set_speed(int fd, struct termios *ti, int speed)
{
struct serial_struct ss;
int baudenum = get_speed(speed);
if (speed != CBAUDEX) {
//printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) {
printf("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno));
return -1;
}
#ifdef ANDROID
ss.flags &= ~ASYNC_SPD_CUST;
#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/
memset(ss.reserved, 0x00, sizeof(ss.reserved));
#endif
ss.flags |= (1 << 13); /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/
/*set standard buadrate setting*/
if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) {
printf("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno));
return -2;
}
#endif
cfsetospeed(ti, baudenum);
cfsetispeed(ti, baudenum);
return tcsetattr(fd, TCSANOW, ti);
}
else {
printf("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum);
return -3;
}
}
int cmd_hdr_baud (P_STP_PARAMS_CONFIG pStpParamsConfig, int baudrate) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, baudrate, gStpUartConfig) : -1;
}
/*int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 115200, gStpUartConfig) : -1;
}
int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 921600, gStpUartConfig) : -1;
}
int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2000000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2500000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3000000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3200000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3250000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3500000, gStpUartConfig) : -1;
}
int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig) {
STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig;
return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 4000000, gStpUartConfig) : -1;
}*/
#define N_MTK (15+1)
int main(int argc, char *argv[])
{
printf("build date %s time %s\n",__DATE__,__TIME__);
FILE *fscript = 0;
int ld = 0;
unsigned char cmd[2] = {0};
struct pollfd fds;
int fd_num = 0;
int err = 0;
int opt;
int baudrate = 0;
int chang_baud_rate = 0;
int flow_control =0;
char *tty_path = "/dev/ttyUSB0";
STP_PARAMS_CONFIG sStpParaConfig;
memset(&sStpParaConfig, 0, sizeof(sStpParaConfig));
sStpParaConfig.sUartConfig.fc = flow_control;
while ((opt = getopt(argc, argv, "c:f:p:")) != -1) {
switch (opt) {
/* debug */
case 'c':
printf("baudrate = %d\n", baudrate);
baudrate = atoi(optarg);
printf("baudrate = %d\n", baudrate);
chang_baud_rate = 1;
printf("baudrate = %d\n", chang_baud_rate);
break;
/* command Usage */
case 'f':
flow_control = atoi(optarg);
printf("flow_control = %d\n", flow_control);
sStpParaConfig.sUartConfig.fc = flow_control;
break;
case 'p':
/* command Usage */
tty_path = optarg;
printf("Log path is %s\n", tty_path);
case '?':
default:
printf("uart_launcher -c baudrate\n");
}
}
/* open ttyUSB */
printf("Running...\n");
gTtyFd = open(tty_path, O_RDWR | O_NOCTTY | O_NONBLOCK);
printf("open done ttyfd %d\n", gTtyFd);
if (gTtyFd < 0) {
printf("ttyfd %d, error\n", gTtyFd);
return 0;
}
ld = N_MTK;
if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) {
printf("set TIOCSETD N_MTK error\n");
return 0;
}
restart:
/* Set default Baud rate */
sStpParaConfig.iBaudrate = CUST_BAUDRATE_DFT;
printf("set baudtate = %d\n", CUST_BAUDRATE_DFT);
cmd_hdr_baud(&sStpParaConfig, CUST_BAUDRATE_DFT);
fds.fd = gTtyFd;
fds.events = POLLIN;
++fd_num;
/*if (ioctl(gTtyFd, HCIUARTSETSTP, NULL) < 0) {
printf("set HCIUARTSETSTP error\n");
return 0;
}*/
ld = N_MTK;
/* chang baud rate */
if (chang_baud_rate) {
if (ioctl(gTtyFd, HCIUARTSETBAUD, NULL) < 0) {
printf("set HCIUARTSETBAUD error\n");
return 0;
}
sStpParaConfig.iBaudrate = baudrate;
printf("set baudtate %d\n", baudrate);
cmd_hdr_baud(&sStpParaConfig, baudrate);
}
//fds.fd = gTtyFd;
//fds.events = POLLERR | POLLHUP;
/*if (ioctl(gTtyFd, HCIUARTGETBAUD, NULL) < 0) {
printf("set HCIUARTSETBAUD error\n");
return 0;
}*/
if (ioctl(gTtyFd, HCIUARTSETWAKEUP, NULL) < 0) {
printf("set HCIUARTSETWAKEUP error\n");
return 0;
}
if (ioctl(gTtyFd, HCIUARTLOADPATCH, NULL) < 0) {
printf("set HCIUARTLOADPATCH error\n");
return 0;
}
/*write(gTtyFd, cmd , sizeof(cmd));*/
while (1) {
err = poll(&fds, fd_num, 2000);
if (err < 0) {
if (errno == EINTR) {
continue;
}
else {
printf("poll error:%d errno:%d, %s\n", err, errno, strerror(errno));
break;
}
} else if (!err) {
if (fds.revents & POLLIN) {
goto restart;
} else {
continue;
}
}
goto restart;
/*if (fds.revents & POLLIN) {
}*/
}
}

View file

@ -0,0 +1,30 @@
THIS_COMPONENT = usb3
ifdef LINUX_DRV_ROOT
export DRV_ROOT = $(LINUX_DRV_ROOT)
else
export DRV_ROOT = $(TARGET_OPEN_ROOT)
endif
SRC =
OBJ =
SUB_COMPONENTS = mt7668
OPTIONAL_SUB_COMPONENTS =
DEFINES +=
CC_INC +=
#############################################################################
#
# Include the makefile common to all components
#
#############################################################################
include $(DRV_ROOT)/driver.mak

View file

@ -0,0 +1,260 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_BTMTK_USB_H__
#define __LD_BTMTK_USB_H__
#include "LD_usbbt.h"
/* Memory map for MTK BT */
//#if 0
/* SYS Control */
#define SYSCTL 0x400000
/* WLAN */
#define WLAN 0x410000
/* MCUCTL */
#define CLOCK_CTL 0x0708
#define INT_LEVEL 0x0718
#define COM_REG0 0x0730
#define SEMAPHORE_00 0x07B0
#define SEMAPHORE_01 0x07B4
#define SEMAPHORE_02 0x07B8
#define SEMAPHORE_03 0x07BC
/* Chip definition */
#define CONTROL_TIMEOUT_JIFFIES (300)
#define DEVICE_VENDOR_REQUEST_OUT 0x40
#define DEVICE_VENDOR_REQUEST_IN 0xc0
#define DEVICE_CLASS_REQUEST_OUT 0x20
#define DEVICE_CLASS_REQUEST_IN 0xa0
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
/* ROM Patch */
#define PATCH_HCI_HEADER_SIZE 4
#define PATCH_WMT_HEADER_SIZE 5
#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE)
#define UPLOAD_PATCH_UNIT 2048
#define PATCH_INFO_SIZE 30
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
#define PATCH_LEN_ILM (192 * 1024)
#define BUZZARD_CHIP_ID 0x70010200
#define BUZZARD_FLAVOR 0x70010020
#define BUZZARD_FW_VERSION 0x80021004
/**
* 0: patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1: patch download is complete
* 2: patch download is not complete/BT get patch semaphore success
*/
#define PATCH_ERR -1
#define PATCH_IS_DOWNLOAD_BY_OTHER 0
#define PATCH_READY 1
#define PATCH_NEED_DOWNLOAD 2
#define MAX_BIN_FILE_NAME_LEN 64
#define LD_BT_MAX_EVENT_SIZE 260
#define BD_ADDR_LEN 6
#define WOBLE_SETTING_FILE_NAME_7961 "woble_setting_7961.bin"
#define WOBLE_SETTING_FILE_NAME_7668 "woble_setting_7668.bin"
#define WOBLE_SETTING_FILE_NAME_7663 "woble_setting_7663.bin"
#define WOBLE_SETTING_FILE_NAME "woble_setting.bin"
#define BT_CFG_NAME "bt.cfg"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WMT_CMD "WMT_CMD"
#define WMT_CMD_COUNT 255
#define WAKE_DEV_RECORD "wake_on_ble.conf"
#define WAKE_DEV_RECORD_PATH "misc/bluedroid"
#define APCF_SETTING_COUNT 10
#define WOBLE_SETTING_COUNT 10
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 6
#define SECTION_SPEC_NUM 13
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define BUZZARD_PATCH_ERR -1
#define BUZZARD_PATCH_NEED_DOWNLOAD 0
#define BUZZARD_PATCH_IS_DOWNLOAD_BY_OTHER 1
#define BUZZARD_PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
enum {
BTMTK_EP_TYPE_OUT_CMD = 0, /*EP type out for hci cmd and wmt cmd */
BTMTK_EP_TPYE_OUT_ACL, /* EP type out for acl pkt with load rompatch */
};
typedef enum {
TYPE_APCF_CMD,
} woble_setting_type;
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
u8 *content; /* APCF content or radio off content */
int length; /* APCF content or radio off content of length */
};
struct bt_cfg_struct {
u8 support_unify_woble; /* support unify woble or not */
u8 unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct wmt_cmd[WMT_CMD_COUNT];
};
struct LD_btmtk_usb_data {
mtkbt_dev_t *udev; /* store the usb device informaiton */
unsigned long flags;
int meta_tx;
HC_IF *hcif;
u8 cmdreq_type;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* request for different io operation */
u8 w_request;
u8 r_request;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *fw_image;
unsigned char *fw_header_image;
unsigned char *rom_patch;
unsigned char *rom_patch_header_image;
unsigned char *rom_patch_bin_file_name;
u32 chip_id;
unsigned int flavor;
unsigned int fw_version;
u8 need_load_fw;
u8 need_load_rom_patch;
u32 rom_patch_offset;
u32 rom_patch_len;
u32 fw_len;
int recv_evt_len;
u8 local_addr[BD_ADDR_LEN];
char *woble_setting_file_name;
u8 *setting_file;
u32 setting_file_len;
u8 *wake_dev; /* ADDR:NAP-UAP-LAP, VID/PID:Both Little endian */
u32 wake_dev_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct bt_cfg_struct bt_cfg;
};
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 reserved[9];
}bin_info_spec;
};
};
u8 LD_btmtk_usb_getWoBTW(void);
int LD_btmtk_usb_probe(mtkbt_dev_t *dev,int flag);
void LD_btmtk_usb_disconnect(mtkbt_dev_t *dev);
void LD_btmtk_usb_SetWoble(mtkbt_dev_t *dev);
int Ldbtusb_getBtWakeT(struct LD_btmtk_usb_data *data);
#define REV_MT76x2E3 0x0022
#define MT_REV_LT(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) < (_rev))
#define MT_REV_GTE(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) >= (_rev))
/*
* Load code method
*/
enum LOAD_CODE_METHOD {
BIN_FILE_METHOD,
HEADER_METHOD,
};
#endif

View file

@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _GENERIC_ERRNO_H
#define _GENERIC_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#endif

View file

@ -0,0 +1,473 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
//#include <command.h>
//#include <common.h>
//#include <ShareType.h>
//#include <CusConfig.h>
//#include <MsVfs.h>
//#include <MsDebug.h>
//#include "usb_def.h"
//#include <MsSystem.h>
#include <stdio.h>
#include "LD_usbbt.h"
#include "LD_btmtk_usb.h"
//#include "hal_usb.h"
usb_vid_pid array_mtk_vid_pid[] = {
{0x0E8D, 0x7668, "MTK7668"}, // 7668
{0x0E8D, 0x76A0, "MTK7662T"}, // 7662T
{0x0E8D, 0x76A1, "MTK7632T"}, // 7632T
{0x0E8D, 0x7663, "MTK7663"}, //7663
{0x0E8D, 0x7961, "MTK7961"}, //7961
};
int max_mtk_wifi_id = (sizeof(array_mtk_vid_pid) / sizeof(array_mtk_vid_pid[0]));
usb_vid_pid *pmtk_wifi = &array_mtk_vid_pid[0];
static mtkbt_dev_t *g_DrvData = NULL;
extern void LDR_Mount(void);
extern UINT32 FAT_getsize(const char* filename);
extern UINT8 FAT_Read(const char* filename, char *buffer,UINT32 filesize);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len)
{
return x_memcpy(dst, src, len);
}
VOID *os_memmove(VOID *dest, const void *src,UINT32 len)
{
return x_memcpy(dest, src, len);
}
VOID *os_memset(VOID *s, int c, size_t n)
{
return x_memset(s,c,n);
}
VOID *os_kzalloc(size_t size, unsigned int flags)
{
VOID *ptr = x_mem_alloc(size);
os_memset(ptr, 0, size);
return ptr;
}
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev, u32 *code_len)
{
int size;
size = FAT_getsize(bin_name);
if (size == -1){
usb_debug("Get file size fail\n");
return;
}
*code_len = size;
*image = x_mem_alloc(size);
FAT_Read(bin_name, (char *)(*image),size);
return;
}
static int usb_bt_bulk_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* not used */
)
{
int ret =0 ;
if(dev == NULL || dev->idev == NULL || dev->bulk_tx_ep == NULL)
{
usb_debug("bulk out error 00\n");
return -1;
}
//usb_debug("[usb_bt_bulk_msg]ep_addr:%x\n", dev->bulk_tx_ep->bEndpointAddress);
//usb_debug("[usb_bt_bulk_msg]ep_maxpkt:%x\n", dev->bulk_tx_ep->wMaxPacketSize);
if(epType == MTKBT_BULK_TX_EP)
{
ret = dev->idev->controller->bulk(dev->bulk_tx_ep, size, data,0);
*realsize = ret;
if(ret<0)
{
usb_debug("bulk out error 01\n");
return -1;
}
if(*realsize == size)
{
//usb_debug("bulk out success 01,size =0x%x\n",size);
return 0;
}
else
{
usb_debug("bulk out fail 02,size =0x%x,realsize =0x%x\n",size,*realsize);
}
}
return -1;
}
static int usb_bt_control_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 request,
u8 requesttype,
u16 value,
u16 index,
u8 *data,
int data_length,
int timeout /* not used */
)
{
int ret = -1;
dev_req_t dr;
dr.bmRequestType = requesttype;
dr.bRequest = request;
dr.wValue = value;
dr.wIndex = index;
dr.wLength = data_length;
if(epType == MTKBT_CTRL_TX_EP)
{
ret = dev->idev->controller->control(dev->idev, OUT, sizeof (dr), &dr, data_length, data);
}
else if (epType == MTKBT_CTRL_RX_EP)
{
ret = dev->idev->controller->control(dev->idev, IN, sizeof (dr), &dr, data_length, data);
}
else
{
usb_debug("control message wrong Type =0x%x\n",epType);
}
if (ret < 0)
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
return ret;
}
static int usb_bt_interrupt_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* unit of 1ms */
)
{
int ret = -1;
usb_debug("epType = 0x%x\n",epType);
if(epType == MTKBT_INTR_EP)
{
ret = dev->idev->controller->intr(dev->intr_ep, size, realsize,data, 2000);
}
usb_debug("realsize=%d reqdata 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",*realsize,data[0],data[1],data[2],data[3],data[4],data[5]);
if(ret < 0 )
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
//usb_debug("ret = 0x%x\n",ret);
return ret;
}
static HC_IF usbbt_host_interface =
{
usb_bt_bulk_msg,
usb_bt_control_msg,
usb_bt_interrupt_msg,
};
static void Ldbtusb_diconnect (btusbdev_t *dev)
{
LD_btmtk_usb_disconnect(g_DrvData);
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
}
static int Ldbtusb_SetWoble(btusbdev_t *dev)
{
if(!g_DrvData)
{
usb_debug("usb set woble fail ,because no drv data\n");
return -1;
}
else
{
LD_btmtk_usb_SetWoble(g_DrvData);
usb_debug("usb set woble end\n");
}
return 0;
}
int Ldbtusb_connect (btusbdev_t *dev, int flag)
{
int ret = 0;
// For Mstar
//struct usb_endpoint_descriptor *ep_desc;
//struct usb_interface *iface;
int i;
//iface = &dev->config.if_desc[0];
if(g_DrvData == NULL)
{
g_DrvData = os_kmalloc(sizeof(mtkbt_dev_t),MTK_GFP_ATOMIC);
if(!g_DrvData)
{
usb_debug("Not enough memory for mtkbt virtual usb device.\n");
return -1;
}
else
{
os_memset(g_DrvData,0,sizeof(mtkbt_dev_t));
g_DrvData->idev = dev;
g_DrvData->connect = Ldbtusb_connect;
g_DrvData->disconnect = Ldbtusb_diconnect;
g_DrvData->SetWoble = Ldbtusb_SetWoble;
}
}
else
{
return -1;
}
for (i = 1; i <= dev->num_endp; i++) {
usb_debug("dev->endpoints[%d].type = %d\n", i, dev->endpoints[i].type);
usb_debug("dev->endpoints[%d].endpoint = %d\n", i, dev->endpoints[i].endpoint);
usb_debug("dev->endpoints[%d].direction = %d\n", i, dev->endpoints[i].direction);
if (dev->endpoints[i].type == BULK)
{
if (dev->endpoints[i].direction == IN)
{
g_DrvData->bulk_rx_ep = &dev->endpoints[i];
}
else if (dev->endpoints[i].direction == OUT &&
dev->endpoints[i].endpoint != 0x01)
{
g_DrvData->bulk_tx_ep = &dev->endpoints[i];
}
continue;
}
if (dev->endpoints[i].type == INTERRUPT &&
dev->endpoints[i].endpoint != 0x8f)
{
g_DrvData->intr_ep = &dev->endpoints[i];
continue;
}
}
if (!g_DrvData->intr_ep || !g_DrvData->bulk_tx_ep || !g_DrvData->bulk_rx_ep)
{
os_kfree(g_DrvData);
g_DrvData = NULL;
usb_debug("btmtk_usb_probe end Error 3\n");
return -1;
}
/* Init HostController interface */
g_DrvData->hci_if = &usbbt_host_interface;
/* btmtk init */
ret = LD_btmtk_usb_probe(g_DrvData, flag);
if (ret != 0)
{
usb_debug("usb probe fail\n");
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
return -1;
}
else
{
usb_debug("usbbt probe success\n");
}
return ret;
}
u8 LDbtusb_getWoBTW(void)
{
return LD_btmtk_usb_getWoBTW();
}
#if 0
static int checkUsbDevicePort(struct usb_device* udev, u16 vendorID, u16 productID, u8 port)
{
struct usb_device* pdev = NULL;
/*#if defined (CONFIG_USB_PREINIT)
usb_stop(port);
if (usb_post_init(port) == 0)
#else
if (usb_init(port) == 0)
#endif*/
#if 0
{
/* get device */
//pdev = usb_get_dev_index(0);
if ((pdev != NULL) && (pdev->descriptor.idVendor == vendorID) && (pdev->descriptor.idProduct == productID)) // MTK 7662
{
Printf("OK\n");
x_memcpy(udev, pdev, sizeof(struct usb_device));
return 0 ;
}
}
#endif
return -1;
}
#endif
#if 0
static int findUsbDevice(struct usb_device* udev)
{
int ret = -1;
u8 idx = 0;
u8 i = 0;
char portNumStr[10] = "\0";
char* pBTUsbPort = NULL;
Printf("IN\n");
if(udev == NULL)
{
Printf("udev can not be NULL\n");
return -1;
}
//use the usb poll function replace----lining
//keys add:find usb port idx
/*#define BT_USB_PORT "bt_usb_port"
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
i = 0;
// search mtk bt usb port
idx = atoi(pBTUsbPort);
usb_debug("find mtk bt usb device from usb prot[%d]\n", idx);
while (i < max_mtk_wifi_id) {
ret = checkUsbDevicePort(udev, (pmtk_wifi + i)->vid, (pmtk_wifi + i)->pid, idx);
if (ret == 0) break;
i++;
#if defined(NEW_RC_CON) && (NEW_RC_CON == TRUE)
usb_debug("fengchen 7668 error");
return -1;
#endif
}
if(ret == 0)
{
return 0;
}
}*/
//keys add:find usb port idx end!!!
// not find mt bt usb device from given usb port, so poll every usb port.
/*#if defined(ENABLE_FIFTH_EHC)
const char u8UsbPortCount = 5;
#elif defined(ENABLE_FOURTH_EHC)
const char u8UsbPortCount = 4;
#elif defined(ENABLE_THIRD_EHC)
const char u8UsbPortCount = 3;
#elif defined(ENABLE_SECOND_EHC)
const char u8UsbPortCount = 2;
#else
const char u8UsbPortCount = 1;
#endif
for(idx = 0; idx < u8UsbPortCount; idx++)
{
i = 0;
while (i < max_mtk_wifi_id) {
ret = checkUsbDevicePort(udev, (pmtk_wifi + i)->vid, (pmtk_wifi + i)->pid, idx);
if (ret == 0) break;
i++;
}
if(ret == 0)
{
// set bt_usb_port to store mt bt usb device port
snprintf(portNumStr, sizeof(portNumStr), "%d", idx);
setenv(BT_USB_PORT, portNumStr);
saveenv();
return 0;
}
}
if(pBTUsbPort != NULL)
{
// env BT_USB_PORT is involid, so delete it
setenv(BT_USB_PORT, NULL);
saveenv();
}*/
Printf("Not find usb device\n");
return -1;
}
#endif
void do_setMtkBT(usbdev_t *dev)
{
int ret = 0;
Printf("IN\n");
LDR_Mount(); //16566
// MTK USB controller
/*ret = findUsbDevice(&udev);
if (ret != 0)
{
Printf("find bt usb device failed\n");
return -1;
}*/
ret = Ldbtusb_connect(dev,0);
if(ret != 0){
Printf("connect to bt usb device failed\n");
return;
}
ret = Ldbtusb_SetWoble(NULL);
if(ret != 0)
{
Printf("set bt usb device woble cmd failed\n");
return;
}
Printf("OK\n");
}
int getMtkBTWakeT(void)
{
int ret = 0;
#if 0
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
Printf("IN\n");
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
Printf("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 1);
if(ret != 0)
{
Printf("connect to bt usb device failed\n");
return -1;
}
if(ret != 0)
{
Printf("set bt usb device woble cmd failed\n");
return -1;
}
Printf("OK\n");
#endif
return ret;
}

View file

@ -0,0 +1,115 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_USBBT_H__
#define __LD_USBBT_H__
//#include <common.h>
//#include "usb_def.h"
//#include <MsTypes.h>
#include "types.h"
#include "loader_if.h"
#include "usb_type.h"
struct _usb_vid_pid_
{
unsigned short vid;
unsigned short pid;
char name[10];
};
typedef struct _usb_vid_pid_ usb_vid_pid;
#define MTKBT_CTRL_TX_EP 0
#define MTKBT_CTRL_RX_EP 1
#define MTKBT_INTR_EP 2
#define MTKBT_BULK_TX_EP 3
#define MTKBT_BULK_RX_EP 4
#define MTK_GFP_ATOMIC 1
#define CRC_CHECK 0
#define BTLDER "[BT-LOADER] "
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define usb_debug(fmt,...) Printf("%s: "fmt, __func__, ##__VA_ARGS__)
#define usb_debug_raw(p, l, fmt, ...) \
do { \
int raw_count = 0; \
const unsigned char *ptr = p; \
Printf("%s: "fmt, __func__, ##__VA_ARGS__); \
for (raw_count = 0; raw_count < l; ++raw_count) \
Printf(" %02X", ptr[raw_count]); \
Printf("\n"); \
} while (0)
#define os_kmalloc(size,flags) x_mem_alloc(size)
#define os_kfree(ptr) x_mem_free(ptr)
#define MTK_UDELAY(x) HAL_Delay_us(x)
#define MTK_MDELAY(x) HAL_Delay_us(x*1000)
//#define btusbdev_t struct usb_interface
#define btusbdev_t struct usbdev
#undef NULL
#define NULL ((void *)0)
#define s32 signed int
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned int UINT32;
typedef signed int INT32;
typedef unsigned char UINT8;
typedef unsigned long ULONG;
typedef unsigned char BOOL;
typedef struct __USBBT_DEVICE__ mtkbt_dev_t;
typedef struct {
int (*usb_bulk_msg) (mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
int (*usb_control_msg) (mtkbt_dev_t *dev, u32 epType, u8 request, u8 requesttype, u16 value, u16 index,
u8 *data, int data_length, int timeout);
int (*usb_interrupt_msg)(mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
} HC_IF;
struct __USBBT_DEVICE__
{
void *priv_data;
btusbdev_t* intf;
struct usbdev *idev;
endpoint_t *intr_ep;
endpoint_t *bulk_tx_ep;
endpoint_t *bulk_rx_ep;
endpoint_t *isoc_tx_ep;
endpoint_t *isoc_rx_ep;
HC_IF *hci_if;
int (*connect)(btusbdev_t *dev, int flag);
void (*disconnect)(btusbdev_t *dev);
int (*SetWoble)(btusbdev_t *dev);
};//mtkbt_dev_t;
#define BT_INST(dev) (dev)
u8 LDbtusb_getWoBTW(void);
int Ldbtusb_connect (btusbdev_t *dev,int falg);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len);
VOID *os_memmove(VOID *dest, const void *src,UINT32 len);
VOID *os_memset(VOID *s, int c, size_t n);
VOID *os_kzalloc(size_t size, unsigned int flags);
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev,u32 *code_len);
void do_setMtkBT(usbdev_t *dev);
int getMtkBTWakeT(void);
#endif

View file

@ -0,0 +1,82 @@
###########################################################################
# $RCSfile: Makefile,v $
# $Revision: #2 $
# $Date: 2009/04/08 $
# $Author: allen.kao $
#
# Description:
# Leave-level makefile to build the subcomponent of driver library.
#
# Specify the source files to be compile in SRC.
#############################################################################
THIS_COMPONENT = usb3
ifeq "$(UBOOT_LIBRARY)" "y"
include $(TOPDIR)/config.mk
CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/drv_inc -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/inc
CFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/drv_inc -I$(TOPDIR)/board/$(BOARDDIR)/drv_lib/inc
CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/include -I$(OSAI_INC)
CFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)/include -I$(OSAI_INC)
LIB = lib$(THIS_COMPONENT).a
OBJS := LD_btmtk_usb.o LD_usbbt.o
$(LIB): $(OBJS) $(SOBJS)
$(AR) crv $@ $^
clean:
rm -f $(SOBJS) $(OBJS)
distclean: clean
rm -f $(LIB) core *.bak .depend
#########################################################################
.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
$(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
-include .depend
else # UBOOT_LIBRARY
ifdef LINUX_DRV_ROOT
export DRV_ROOT = $(LINUX_DRV_ROOT)
else
export DRV_ROOT = $(TARGET_OPEN_ROOT)
endif
SRC = LD_btmtk_usb.c LD_usbbt.c
ifeq "$(USRDRV)" "true"
ifeq "$(BUILD_LINUX_LOADER)" ""
SRC += kcu_graphic.c
endif
endif
OBJ =
SUB_COMPONENTS =
OPTIONAL_SUB_COMPONENTS =
DEFINES +=
CC_INC += -I$(KERNEL_ROOT)/$(KERNEL_VER)/include -I$(DRV_ROOT)/usb3/libpayload_usb/
#############################################################################
#
# Include the makefile common to all components
#
include $(DRV_ROOT)/driver.mak
endif # UBOOT_LIBRARY

View file

@ -0,0 +1,266 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_BTMTK_USB_H__
#define __LD_BTMTK_USB_H__
#include <mtk-bt/LD_usbbt.h>
/* Memory map for MTK BT */
//#if 0
/* SYS Control */
#define SYSCTL 0x400000
/* WLAN */
#define WLAN 0x410000
/* MCUCTL */
#define CLOCK_CTL 0x0708
#define INT_LEVEL 0x0718
#define COM_REG0 0x0730
#define SEMAPHORE_00 0x07B0
#define SEMAPHORE_01 0x07B4
#define SEMAPHORE_02 0x07B8
#define SEMAPHORE_03 0x07BC
/* Chip definition */
#define CONTROL_TIMEOUT_JIFFIES (300)
#define DEVICE_VENDOR_REQUEST_OUT 0x40
#define DEVICE_VENDOR_REQUEST_IN 0xc0
#define DEVICE_CLASS_REQUEST_OUT 0x20
#define DEVICE_CLASS_REQUEST_IN 0xa0
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
/* ROM Patch */
#define PATCH_HCI_HEADER_SIZE_BULK_EP 4
#define PATCH_HCI_HEADER_SIZE_CTRL_EP 3
#define PATCH_WMT_HEADER_SIZE 5
#define PATCH_HEADER_SIZE_BULK_EP (PATCH_WMT_HEADER_SIZE + PATCH_HCI_HEADER_SIZE_BULK_EP)
#define PATCH_HEADER_SIZE_CTRL_EP (PATCH_WMT_HEADER_SIZE + PATCH_HCI_HEADER_SIZE_CTRL_EP)
#define UPLOAD_PATCH_UNIT 512
#define PATCH_INFO_SIZE 30
#define PATCH_PHASE1 1
#define PATCH_PHASE2 2
#define PATCH_PHASE3 3
#define PATCH_LEN_ILM (192 * 1024)
#define BUZZARD_CHIP_ID 0x70010200
#define BUZZARD_FLAVOR 0x70010020
#define BUZZARD_FW_VERSION 0x80021004
/**
* 0: patch download is not complete/BT get patch semaphore fail (WiFi get semaphore success)
* 1: patch download is complete
* 2: patch download is not complete/BT get patch semaphore success
*/
#define PATCH_ERR -1
#define PATCH_IS_DOWNLOAD_BY_OTHER 0
#define PATCH_READY 1
#define PATCH_NEED_DOWNLOAD 2
#define MAX_BIN_FILE_NAME_LEN 64
#define LD_BT_MAX_EVENT_SIZE 260
#define BD_ADDR_LEN 6
#define WOBLE_SETTING_FILE_NAME_7961 "woble_setting_7961.bin"
#define WOBLE_SETTING_FILE_NAME_7668 "woble_setting_7668.bin"
#define WOBLE_SETTING_FILE_NAME_7663 "woble_setting_7663.bin"
#define WOBLE_SETTING_FILE_NAME "woble_setting.bin"
#define BT_CFG_NAME "bt.cfg"
#define BT_UNIFY_WOBLE "SUPPORT_UNIFY_WOBLE"
#define BT_UNIFY_WOBLE_TYPE "UNIFY_WOBLE_TYPE"
#define BT_WMT_CMD "WMT_CMD"
#define WMT_CMD_COUNT 255
#define WAKE_DEV_RECORD "wake_on_ble.conf"
#define WAKE_DEV_RECORD_PATH "misc/bluedroid"
#define APCF_SETTING_COUNT 10
#define WOBLE_SETTING_COUNT 10
/* It is for mt7961 download rom patch*/
#define FW_ROM_PATCH_HEADER_SIZE 32
#define FW_ROM_PATCH_GD_SIZE 64
#define FW_ROM_PATCH_SEC_MAP_SIZE 64
#define SEC_MAP_NEED_SEND_SIZE 52
#define PATCH_STATUS 6
#define SECTION_SPEC_NUM 13
#define WMT_HEADER_LEN 4
#define LOAD_PATCH_PHASE_LEN 1
/* this for 79XX need download patch staus
* 0:
* patch download is not complete, BT driver need to download patch
* 1:
* patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
* 2:
* patch download is complete, BT driver no need to download patch
*/
#define BUZZARD_PATCH_ERR -1
#define BUZZARD_PATCH_NEED_DOWNLOAD 0
#define BUZZARD_PATCH_IS_DOWNLOAD_BY_OTHER 1
#define BUZZARD_PATCH_READY 2
/* 0:
* using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
* 1:
* using DMA to download fw patch
*/
#define PATCH_DOWNLOAD_USING_WMT 0
#define PATCH_DOWNLOAD_USING_DMA 1
#define PATCH_DOWNLOAD_CMD_DELAY_TIME 5
#define PATCH_DOWNLOAD_CMD_RETRY 0
#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
#define PATCH_DOWNLOAD_PHASE3_RETRY 20
enum {
BTMTK_EP_TYPE_OUT_CMD = 0, /*EP type out for hci cmd and wmt cmd */
BTMTK_EP_TPYE_OUT_ACL, /* EP type out for acl pkt with load rompatch */
};
typedef enum {
TYPE_APCF_CMD,
} woble_setting_type;
enum fw_cfg_index_len {
FW_CFG_INX_LEN_NONE = 0,
FW_CFG_INX_LEN_2 = 2,
FW_CFG_INX_LEN_3 = 3,
};
struct fw_cfg_struct {
u8 *content; /* APCF content or radio off content */
int length; /* APCF content or radio off content of length */
};
#define UNIFY_WOBLE_LEGACY 0
#define UNIFY_WOBLE_WAVEFORM 1
struct bt_cfg_struct {
u8 support_unify_woble; /* support unify woble or not */
u8 unify_woble_type; /* 0: legacy. 1: waveform. 2: IR */
struct fw_cfg_struct wmt_cmd[WMT_CMD_COUNT];
};
struct LD_btmtk_usb_data {
mtkbt_dev_t *udev; /* store the usb device informaiton */
unsigned long flags;
int meta_tx;
HC_IF *hcif;
u8 cmdreq_type;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
/* request for different io operation */
u8 w_request;
u8 r_request;
/* io buffer for usb control transfer */
unsigned char *io_buf;
unsigned char *fw_image;
unsigned char *fw_header_image;
unsigned char *fw_bin_file_name;
unsigned char *rom_patch;
unsigned char *rom_patch_header_image;
unsigned char *rom_patch_bin_file_name;
u32 chip_id;
unsigned int flavor;
unsigned int fw_version;
u8 need_load_fw;
u8 need_load_rom_patch;
u32 rom_patch_offset;
u32 rom_patch_len;
u32 fw_len;
int recv_evt_len;
u8 local_addr[BD_ADDR_LEN];
char *woble_setting_file_name;
u8 *setting_file;
u32 setting_file_len;
u8 *wake_dev; /* ADDR:NAP-UAP-LAP, VID/PID:Both Little endian */
u32 wake_dev_len;
struct fw_cfg_struct woble_setting_apcf[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT];
struct fw_cfg_struct woble_setting_radio_off;
struct fw_cfg_struct woble_setting_wakeup_type;
/* complete event */
struct fw_cfg_struct woble_setting_radio_off_comp_event;
struct bt_cfg_struct bt_cfg;
};
struct _PATCH_HEADER {
u8 ucDateTime[16];
u8 ucPlatform[4];
u16 u2HwVer;
u16 u2SwVer;
u32 u4MagicNum;
};
struct _Global_Descr {
u32 u4PatchVer;
u32 u4SubSys;
u32 u4FeatureOpt;
u32 u4SectionNum;
};
struct _Section_Map {
u32 u4SecType;
u32 u4SecOffset;
u32 u4SecSize;
union {
u32 u4SecSpec[SECTION_SPEC_NUM];
struct {
u32 u4DLAddr;
u32 u4DLSize;
u32 u4SecKeyIdx;
u32 u4AlignLen;
u32 reserved[9];
}bin_info_spec;
};
};
u8 LD_btmtk_usb_getWoBTW(void);
int LD_btmtk_usb_probe(mtkbt_dev_t *dev, int flag);
void LD_btmtk_usb_disconnect(mtkbt_dev_t *dev);
void LD_btmtk_usb_SetWoble(mtkbt_dev_t *dev);
int Ldbtusb_getBtWakeT(struct LD_btmtk_usb_data *data);
#define REV_MT76x2E3 0x0022
#define MT_REV_LT(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) < (_rev))
#define MT_REV_GTE(_data, _chip, _rev) \
is_##_chip(_data) && (((_data)->chip_id & 0x0000ffff) >= (_rev))
/*
* Load code method
*/
enum LOAD_CODE_METHOD {
BIN_FILE_METHOD,
HEADER_METHOD,
};
#endif

View file

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __LD_USBBT_H__
#define __LD_USBBT_H__
#include <common.h>
#include <malloc.h>
#include <usb.h>
#include <MsTypes.h>
#define MTKBT_CTRL_TX_EP 0
#define MTKBT_CTRL_RX_EP 1
#define MTKBT_INTR_EP 2
#define MTKBT_BULK_TX_EP 3
#define MTKBT_BULK_RX_EP 4
#define USB_INTR_MSG_TIMO 2000
#define MTK_GFP_ATOMIC 1
#define CRC_CHECK 0
#define BT_USB_PORT "bt_usb_port"
#define BTLDER "[BT-LOADER] "
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define usb_debug(fmt,...) printf("%s: "fmt, __func__, ##__VA_ARGS__)
#define usb_debug_raw(p, l, fmt, ...) \
do { \
int raw_count = 0; \
const unsigned char *ptr = p; \
printf("%s: "fmt, __func__, ##__VA_ARGS__); \
for (raw_count = 0; raw_count < l; ++raw_count) \
printf(" %02X", ptr[raw_count]); \
printf("\n"); \
} while (0)
#define os_kmalloc(size,flags) malloc(size)
#define os_kfree(ptr) free(ptr)
#define MTK_UDELAY(x) udelay(x)
#define MTK_MDELAY(x) mdelay(x)
//#define btusbdev_t struct usb_interface
#define btusbdev_t struct usb_device
#undef NULL
#define NULL ((void *)0)
#define s32 signed int
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef unsigned int UINT32;
typedef signed int INT32;
typedef unsigned char UINT8;
typedef unsigned long ULONG;
typedef unsigned char BOOL;
typedef struct __USBBT_DEVICE__ mtkbt_dev_t;
typedef struct {
int (*usb_bulk_msg) (mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
int (*usb_control_msg) (mtkbt_dev_t *dev, u32 epType, u8 request, u8 requesttype, u16 value, u16 index,
u8 *data, int data_length, int timeout);
int (*usb_interrupt_msg)(mtkbt_dev_t *dev, u32 epType, u8 *data, int size, int* realsize, int timeout);
} HC_IF;
struct __USBBT_DEVICE__
{
void *priv_data;
btusbdev_t* intf;
struct usb_device *udev;
struct usb_endpoint_descriptor *intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
HC_IF *hci_if;
int (*connect)(btusbdev_t *dev, int flag);
void (*disconnect)(btusbdev_t *dev);
int (*SetWoble)(btusbdev_t *dev);
u32 chipid;
};//mtkbt_dev_t;
#define BT_INST(dev) (dev)
u8 LDbtusb_getWoBTW(void);
int Ldbtusb_connect (btusbdev_t *dev, int falg);
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len);
VOID *os_memmove(VOID *dest, const void *src,UINT32 len);
VOID *os_memset(VOID *s, int c, size_t n);
VOID *os_kzalloc(size_t size, unsigned int flags);
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev,u32 *code_len);
int do_setMtkBT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_getMtkBTWakeT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif

View file

@ -0,0 +1,137 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef _GENERIC_ERRNO_H
#define _GENERIC_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#endif

View file

@ -0,0 +1,543 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <command.h>
#include <common.h>
#include <ShareType.h>
#include <CusConfig.h>
#include <MsVfs.h>
#include <MsDebug.h>
#include <usb.h>
#include <MsSystem.h>
#include <stdio.h>
#include <mtk-bt/LD_usbbt.h>
#include <mtk-bt/LD_btmtk_usb.h>
usb_vid_pid array_mtk_vid_pid[] = {
{0x0E8D, 0x7668, "MTK7668"}, // 7668
{0x0E8D, 0x76A0, "MTK7662T"}, // 7662T
{0x0E8D, 0x76A1, "MTK7632T"}, // 7632T
{0x0E8D, 0x7663, "MTK7663"}, //7663
{0x0E8D, 0x7961, "MTK7961"}, //7961
};
int max_mtk_wifi_id = (sizeof(array_mtk_vid_pid) / sizeof(array_mtk_vid_pid[0]));
usb_vid_pid *pmtk_wifi = &array_mtk_vid_pid[0];
static mtkbt_dev_t *g_DrvData = NULL;
VOID *os_memcpy(VOID *dst, const VOID *src, UINT32 len)
{
return memcpy(dst, src, len);
}
VOID *os_memmove(VOID *dest, const void *src,UINT32 len)
{
return memmove(dest, src, len);
}
VOID *os_memset(VOID *s, int c, size_t n)
{
return memset(s,c,n);
}
VOID *os_kzalloc(size_t size, unsigned int flags)
{
VOID *ptr = malloc(size);
os_memset(ptr, 0, size);
return ptr;
}
int LD_load_code(unsigned char **image, char *partition, char *file, mtkbt_dev_t *dev, u32 *code_len)
{
if (vfs_mount(partition) != 0) {
usb_debug("vfs_mount %s fail\n", partition);
return -1;
}
*code_len = vfs_getsize(file);
if (*code_len == 0) {
usb_debug("Get file size fail\n");
return -1;
}
// malloc buffer to store bt patch file data
*image = malloc(*code_len);
if (*image == NULL) {
usb_debug("malloc fail\n");
return -1;
}
if (vfs_read(*image, file, 0, *code_len) != 0) {
usb_debug("vfs_read %s fail\n", file);
free(*image);
return -1;
}
UBOOT_DEBUG("Load file(%s:%s) OK\n", partition, file);
UBOOT_DUMP((unsigned int)*image, 0x200);
return 0;
}
void LD_load_code_from_bin(unsigned char **image, char *bin_name, char *path, mtkbt_dev_t *dev, u32 *code_len)
{
#define ENV_BT_FW_PATH "BTFWBinPath"
char mtk_patch_bin_patch[128] = "\0";
char *bt_env;
char *partition[5] = {"tvconfig", "vendor", "userdata", "system", "APP"};
int i = 0;
/** implement by mstar/MTK
* path: /system/etc/firmware/mt76XX_patch_eX_hdr.bin
* If argument "path" is NULL, access "/etc/firmware" directly like as request_firmware
* if argument "path" is not NULL, so far only support directory "userdata"
* NOTE: latest vfs_mount seems decided this time access directory
*/
if (path) {
snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", path, bin_name);
printf("File: %s\n", mtk_patch_bin_patch);
} else {
#if (ENABLE_MODULE_ANDROID_BOOT == 1)
snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", "/firmware", bin_name);
#else
snprintf(mtk_patch_bin_patch, sizeof(mtk_patch_bin_patch), "%s/%s", "/krl/wifi/ralink/firmware", bin_name);
#endif
printf("mtk_patch_bin_patch: %s\n", mtk_patch_bin_patch);
}
bt_env = getenv(ENV_BT_FW_PATH);
if (bt_env == NULL) {
/* get PATH failed */
printf("bt_env is NULL\n");
for (i = 0; i < 5; i++) {
if (LD_load_code(image, partition[i], mtk_patch_bin_patch, dev, code_len) == 0)
return;
}
} else {
printf("bt_env: %s\n", bt_env);
LD_load_code(image, bt_env, mtk_patch_bin_patch, dev, code_len);
}
return;
}
static int usb_bt_bulk_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* not used */
)
{
int ret =0 ;
if(dev == NULL || dev->udev == NULL || dev->bulk_tx_ep == NULL)
{
usb_debug("bulk out error 00\n");
return -1;
}
if(epType == MTKBT_BULK_TX_EP)
{
// usb_debug_raw(data, size, "%s: usb_bulk_msg:", __func__);
ret = usb_bulk_msg(dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_tx_ep->bEndpointAddress),data,size,realsize,2000);
if(ret)
{
usb_debug("bulk out error 01, ret = %d\n", ret);
return -1;
}
if(*realsize == size)
{
//usb_debug("bulk out success 01,size =0x%x\n",size);
return 0;
}
else
{
usb_debug("bulk out fail 02,size =0x%x,realsize =0x%x\n",size,*realsize);
}
}
return -1;
}
static int usb_bt_control_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 request,
u8 requesttype,
u16 value,
u16 index,
u8 *data,
int data_length,
int timeout /* not used */
)
{
int ret = -1;
if(epType == MTKBT_CTRL_TX_EP)
{
// usb_debug_raw(data, data_length, "%s: usb_control_msg:", __func__);
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), request,
requesttype, value, index, data, data_length,timeout);
}
else if (epType == MTKBT_CTRL_RX_EP)
{
ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), request,
requesttype, value, index, data, data_length,timeout);
}
else
{
usb_debug("control message wrong Type =0x%x\n",epType);
}
if (ret < 0)
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
return ret;
}
static int usb_bt_interrupt_msg(
mtkbt_dev_t *dev,
u32 epType,
u8 *data,
int size,
int* realsize,
int timeout /* unit of 1ms */
)
{
int ret = -1;
usb_debug("epType = 0x%x\n",epType);
if(epType == MTKBT_INTR_EP)
{
ret = usb_submit_int_msg(dev->udev,usb_rcvintpipe(dev->udev,dev->intr_ep->bEndpointAddress),data,size,realsize,timeout);
}
if(ret < 0 )
{
usb_debug("Err1(%d)\n", ret);
return ret;
}
usb_debug("ret = 0x%x\n",ret);
return ret;
}
static HC_IF usbbt_host_interface =
{
usb_bt_bulk_msg,
usb_bt_control_msg,
usb_bt_interrupt_msg,
};
static void Ldbtusb_diconnect (btusbdev_t *dev)
{
LD_btmtk_usb_disconnect(g_DrvData);
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
}
static int Ldbtusb_SetWoble(btusbdev_t *dev)
{
if(!g_DrvData)
{
usb_debug("usb set woble fail ,because no drv data\n");
return -1;
}
else
{
LD_btmtk_usb_SetWoble(g_DrvData);
usb_debug("usb set woble end\n");
}
return 0;
}
static u32 chipid;
int Ldbtusb_connect (btusbdev_t *dev, int flag)
{
int ret = 0;
// For Mstar
struct usb_endpoint_descriptor *ep_desc;
struct usb_interface *iface;
int i;
iface = &dev->config.if_desc[0];
if(g_DrvData == NULL)
{
g_DrvData = os_kmalloc(sizeof(mtkbt_dev_t),MTK_GFP_ATOMIC);
if(!g_DrvData)
{
usb_debug("Not enough memory for mtkbt virtual usb device.\n");
return -1;
}
else
{
os_memset(g_DrvData,0,sizeof(mtkbt_dev_t));
g_DrvData->udev = dev;
g_DrvData->connect = Ldbtusb_connect;
g_DrvData->disconnect = Ldbtusb_diconnect;
g_DrvData->SetWoble = Ldbtusb_SetWoble;
}
}
else
{
return -1;
}
// For Mstar
for (i = 0; i < iface->desc.bNumEndpoints; i++)
{
ep_desc = &iface->ep_desc[i];
usb_debug("dev->endpoints[%d].bmAttributes = 0x%x\n", i, ep_desc->bmAttributes);
usb_debug("dev->endpoints[%d].bEndpointAddress = 0x%x\n", i, ep_desc->bEndpointAddress);
if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
{
if (ep_desc->bEndpointAddress & USB_DIR_IN)
{
usb_debug("set endpoints[%d] to bulk_rx_ep\n", i);
g_DrvData->bulk_rx_ep = ep_desc;
}
else
{
if (ep_desc->bEndpointAddress != 0x1) {
usb_debug("set endpoints[%d] to bulk_tx_ep\n", i);
g_DrvData->bulk_tx_ep = ep_desc;
}
}
continue;
}
/* is it an interrupt endpoint? */
if (((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
&& ep_desc->bEndpointAddress != 0x8f)
{
usb_debug("set endpoints[%d] to intr_ep\n", i);
g_DrvData->intr_ep = ep_desc;
continue;
}
}
if (!g_DrvData->intr_ep || !g_DrvData->bulk_tx_ep || !g_DrvData->bulk_rx_ep)
{
os_kfree(g_DrvData);
g_DrvData = NULL;
usb_debug("btmtk_usb_probe end Error 3\n");
return -1;
}
/* Init HostController interface */
g_DrvData->hci_if = &usbbt_host_interface;
g_DrvData->chipid = chipid;
/* btmtk init */
ret = LD_btmtk_usb_probe(g_DrvData, flag);
if (ret != 0)
{
usb_debug("usb probe fail\n");
if(g_DrvData)
{
os_kfree(g_DrvData);
}
g_DrvData = NULL;
return -1;
}
else
{
usb_debug("usbbt probe success\n");
}
return ret;
}
u8 LDbtusb_getWoBTW(void)
{
return LD_btmtk_usb_getWoBTW();
}
static int checkUsbDevicePort(struct usb_device *udev, usb_vid_pid *pmtk_dongle, u8 port)
{
struct usb_device *pdev = NULL;
int i;
int dongleCount = 0;
#if defined (CONFIG_USB_PREINIT)
usb_stop(port);
if (usb_post_init(port) == 0)
#else
if (usb_init(port) == 0)
#endif
{
for (i = 0; i < usb_get_dev_num(); i++) {
pdev = usb_get_dev_index(i); // get device
if (pdev != NULL) {
for (dongleCount = 0; dongleCount < max_mtk_wifi_id; dongleCount++) {
if ((pdev->descriptor.idVendor == pmtk_dongle[dongleCount].vid)
&& (pdev->descriptor.idProduct == pmtk_dongle[dongleCount].pid)) {
UBOOT_TRACE("OK\n");
memcpy(udev, pdev, sizeof(struct usb_device));
chipid = pmtk_dongle[dongleCount].pid;
return 0;
}
}
}
}
}
return -1;
}
static int findUsbDevice(struct usb_device* udev)
{
int ret = -1;
u8 idx = 0;
char portNumStr[10] = "\0";
char* pBTUsbPort = NULL;
UBOOT_TRACE("IN\n");
if(udev == NULL)
{
UBOOT_ERROR("udev can not be NULL\n");
return -1;
}
#define BT_USB_PORT "bt_usb_port"
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
// search mtk bt usb port
idx = atoi(pBTUsbPort);
usb_debug("find mtk bt usb device from usb prot[%d]\n", idx);
ret = checkUsbDevicePort(udev, pmtk_wifi, idx);
if(ret == 0)
{
return 0;
}
}
// not find mt bt usb device from given usb port, so poll every usb port.
#if defined(ENABLE_FIFTH_EHC)
const char u8UsbPortCount = 5;
#elif defined(ENABLE_FOURTH_EHC)
const char u8UsbPortCount = 4;
#elif defined(ENABLE_THIRD_EHC)
const char u8UsbPortCount = 3;
#elif defined(ENABLE_SECOND_EHC)
const char u8UsbPortCount = 2;
#else
const char u8UsbPortCount = 1;
#endif
for(idx = 0; idx < u8UsbPortCount; idx++)
{
ret = checkUsbDevicePort(udev, pmtk_wifi, idx);
if(ret == 0)
{
// set bt_usb_port to store mt bt usb device port
snprintf(portNumStr, sizeof(portNumStr), "%d", idx);
setenv(BT_USB_PORT, portNumStr);
saveenv();
return 0;
}
}
if(pBTUsbPort != NULL)
{
// env BT_USB_PORT is involid, so delete it
setenv(BT_USB_PORT, NULL);
saveenv();
}
UBOOT_ERROR("Not find usb device\n");
return -1;
}
int do_setMtkBT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int ret = 0;
char* pBTUsbPort = NULL;
int usbPort = 0;
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
UBOOT_TRACE("IN\n");
if (argc < 1)
{
cmd_usage(cmdtp);
return -1;
}
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
UBOOT_ERROR("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 0);
if(ret != 0){
UBOOT_ERROR("connect to bt usb device failed\n");
return -1;
}
ret = Ldbtusb_SetWoble(&udev);
if(ret != 0)
{
UBOOT_ERROR("set bt usb device woble cmd failed\n");
return -1;
}
usb_debug("ready to do usb_stop\n");
pBTUsbPort = getenv(BT_USB_PORT);
if(pBTUsbPort != NULL)
{
// search mtk bt usb port
usbPort = atoi(pBTUsbPort);
usb_debug("stop usb port: %d\n",usbPort);
if(usb_stop(usbPort) != 0){
usb_debug("usb_stop fail\n");
}
}else{
usb_debug("no BT_USB_PORT\n");
}
UBOOT_TRACE("OK\n");
return ret;
}
int do_getMtkBTWakeT(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int ret = 0;
struct usb_device udev;
memset(&udev, 0, sizeof(struct usb_device));
UBOOT_TRACE("IN\n");
if (argc < 1)
{
cmd_usage(cmdtp);
return -1;
}
// MTK USB controller
ret = findUsbDevice(&udev);
if (ret != 0)
{
UBOOT_ERROR("find bt usb device failed\n");
return -1;
}
ret = Ldbtusb_connect(&udev, 1);
if(ret != 0)
{
UBOOT_ERROR("connect to bt usb device failed\n");
return -1;
}
if(ret != 0)
{
UBOOT_ERROR("set bt usb device woble cmd failed\n");
return -1;
}
UBOOT_TRACE("OK\n");
return ret;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
acpi_dock_ops
address_space_operations
backlight_ops
block_device_operations
clk_ops
comedi_lrange
component_ops
dentry_operations
dev_pm_ops
dma_map_ops
driver_info
drm_connector_funcs
drm_encoder_funcs
drm_encoder_helper_funcs
ethtool_ops
extent_io_ops
file_lock_operations
file_operations
hv_ops
ide_dma_ops
ide_port_ops
inode_operations
intel_dvo_dev_ops
irq_domain_ops
item_operations
iwl_cfg
iwl_ops
kgdb_arch
kgdb_io
kset_uevent_ops
lock_manager_operations
machine_desc
microcode_ops
mlxsw_reg_info
mtrr_ops
neigh_ops
net_device_ops
nlmsvc_binding
nvkm_device_chip
of_device_id
pci_raw_ops
pipe_buf_operations
platform_hibernation_ops
platform_suspend_ops
proto_ops
regmap_access_table
rpc_pipe_ops
rtc_class_ops
sd_desc
seq_operations
sirfsoc_padmux
snd_ac97_build_ops
snd_soc_component_driver
soc_pcmcia_socket_ops
stacktrace_ops
sysfs_ops
tty_operations
uart_ops
usb_mon_operations
v4l2_ctrl_ops
v4l2_ioctl_ops
vm_operations_struct
wacom_features
wd_ops

Some files were not shown because too many files have changed in this diff Show more