diff --git a/drivers/misc/mediatek/Makefile b/drivers/misc/mediatek/Makefile
index be95574a6ae82d4d0d994379f41e52c9f78705aa..f216172c1b3b8949e52bea489ed9a5acfb35146e 100644
--- a/drivers/misc/mediatek/Makefile
+++ b/drivers/misc/mediatek/Makefile
@@ -6,6 +6,7 @@ subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/
subdir-ccflags-y += -I$(srctree)/drivers/mmc/host/mediatek/$(MTK_PLATFORM)
obj-$(CONFIG_MTK_MET) += met_drv/
+obj-y += met_drv_v2/
obj-$(CONFIG_MTK_BASE_POWER) += base/
obj-$(CONFIG_MTK_PWM) += pwm/
obj-$(CONFIG_MTK_IRTX_PWM_SUPPORT) += irtx/
@@ -119,3 +120,4 @@ obj-$(CONFIG_MTK_GIC_EXT) += ext_gic/
obj-$(CONFIG_MTK_SYS_CIRQ) += cirq/
obj-$(CONFIG_MTK_SECURITY_SW_SUPPORT) += masp/
obj-y += rps/
+obj-$(CONFIG_MTK_FPSGO_V3) += fpsgo_cus/
diff --git a/drivers/misc/mediatek/connectivity/Makefile b/drivers/misc/mediatek/connectivity/Makefile
index 1db2b3532be421020b844613b0f877b40e956760..387dd83709ac5df41e4993fc21f80c2ab140cb6e 100644
--- a/drivers/misc/mediatek/connectivity/Makefile
+++ b/drivers/misc/mediatek/connectivity/Makefile
@@ -37,6 +37,13 @@ ifneq ($(KERNELRELEASE),)
ifeq ($(CONFIG_MTK_COMBO), y)
ccflags-y += -D CFG_CONNADP_BUILD_IN
endif
+
+ # for gen4m options
+ export CONFIG_MTK_COMBO_WIFI_HIF=axi
+ export MTK_COMBO_CHIP=CONNAC
+ export WLAN_CHIP_ID=6765
+ export MTK_ANDROID_WMT=y
+
# Do build-in for Makefile checking
# export CONFIG_WLAN_DRV_BUILD_IN=y
@@ -72,12 +79,6 @@ ifneq ($(KERNELRELEASE),)
$(shell ln -s $(ABS_PATH_TO_WLAN_CHR_DRV) $(srctree)/$(src)/wmt_chrdev_wifi)
$(shell ln -s $(ABS_PATH_TO_WLAN_DRV) $(srctree)/$(src)/wlan_drv_gen4m)
- # for gen4m options
- export CONFIG_MTK_COMBO_WIFI_HIF=axi
- export MTK_COMBO_CHIP=CONNAC
- export WLAN_CHIP_ID=6765
- export MTK_ANDROID_WMT=y
-
# Do build-in for xxx.c checking
subdir-ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE
subdir-ccflags-y += -D MTK_WCN_BUILT_IN_DRIVER
@@ -86,6 +87,13 @@ ifneq ($(KERNELRELEASE),)
obj-y += wlan_drv_gen4m/
endif
+ obj-$(CONFIG_MTK_COMBO) += common/
+ obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/adaptor/
+ obj-$(CONFIG_MTK_COMBO_CHIP_CONSYS_6765) += wlan/core/gen4m/
+ obj-$(CONFIG_MTK_BTIF) += bt/mt66xx/legacy/
+ obj-$(CONFIG_MTK_COMBO_GPS) += gps/
+ obj-$(CONFIG_MTK_FMRADIO) += fmradio/
+
# Otherwise we were called directly from the command line;
# invoke the kernel build system.
else
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/Makefile b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..21d897d14398f29fc8edc7a9e67aef394e904c29
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/Makefile
@@ -0,0 +1,49 @@
+MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM))
+###############################################################################
+# Bluetooth character device driver
+
+ifneq ($(CFG_BT_PM_QOS_CONTROL),)
+ $(warning set PM_QOS_CONTROL=1)
+ ccflags-y += -D PM_QOS_CONTROL=1
+else
+ ccflags-y += -D PM_QOS_CONTROL=0
+endif
+
+# Force build fail on modpost warning
+KBUILD_MODPOST_FAIL_ON_WARNINGS := y
+###############################################################################
+# To add WMT dependent Macro and header file, will be removed later
+
+ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include
+
+ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y)
+ ccflags-y += -D WMT_IDC_SUPPORT=1
+else
+ ccflags-y += -D WMT_IDC_SUPPORT=0
+endif
+
+###############################################################################
+# To include BT driver dependent header file
+
+WMT_SRC_FOLDER := $(srctree)/drivers/misc/mediatek/connectivity/common
+ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/include
+ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/linux/include
+ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),)
+ccflags-y += -I$(WMT_SRC_FOLDER)/debug_utility
+endif
+
+###############################################################################
+
+MODULE_NAME := bt_drv
+obj-m += $(MODULE_NAME).o
+
+ccflags-y += -D CREATE_NODE_DYNAMIC=1
+
+$(MODULE_NAME)-objs += stp_chrdev_bt.o
+$(MODULE_NAME)-objs += dbg_bt.o
+ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),)
+$(MODULE_NAME)-objs += fw_log_bt.o
+endif
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/bt.h b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/bt.h
new file mode 100644
index 0000000000000000000000000000000000000000..febe31c2dba447823321e791d83cfdeecf2ff630
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/bt.h
@@ -0,0 +1,138 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _BT_EXP_H_
+#define _BT_EXP_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "wmt_exp.h"
+#include "stp_exp.h"
+
+
+#define TRUE 1
+#define FALSE 0
+
+/* Flags to control BT FW log flow */
+#define OFF 0x00
+#define ON 0xff
+
+#define PFX "[MTK-BT]"
+#define BT_LOG_DBG 4
+#define BT_LOG_INFO 3
+#define BT_LOG_WARN 2
+#define BT_LOG_ERR 1
+#define RAW_MAX_BYTES 30
+
+static uint8_t raw_buf[RAW_MAX_BYTES * 5 + 10];
+extern UINT32 gBtDbgLevel;
+
+#define BT_LOG_PRT_DBG(fmt, arg...) \
+ do { if (gBtDbgLevel >= BT_LOG_DBG) pr_info(PFX "%s: " fmt, __func__, ##arg); } while (0)
+#define BT_LOG_PRT_INFO(fmt, arg...) \
+ do { if (gBtDbgLevel >= BT_LOG_INFO) pr_info(PFX "%s: " fmt, __func__, ##arg); } while (0)
+#define BT_LOG_PRT_WARN(fmt, arg...) \
+ do { if (gBtDbgLevel >= BT_LOG_WARN) pr_info(PFX "%s: " fmt, __func__, ##arg); } while (0)
+#define BT_LOG_PRT_ERR(fmt, arg...) \
+ do { if (gBtDbgLevel >= BT_LOG_ERR) pr_info(PFX "%s: " fmt, __func__, ##arg); } while (0)
+#define BT_LOG_PRT_INFO_RATELIMITED(fmt, arg...) \
+ do { if (gBtDbgLevel >= BT_LOG_ERR) pr_info_ratelimited(PFX "%s: " fmt, __func__, ##arg); } while (0)
+
+#define BT_LOG_PRT_DBG_RAW(p, l, fmt, ...) \
+ do { \
+ if (gBtDbgLevel >= BT_LOG_DBG) { \
+ int cnt_ = 0; \
+ int len_ = (l <= RAW_MAX_BYTES ? l : RAW_MAX_BYTES); \
+ 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 <= RAW_MAX_BYTES) { \
+ pr_info(PFX" "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
+ } else { \
+ pr_info(PFX" "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
+ } \
+ } \
+ } while (0)
+
+#define BT_LOG_PRT_INFO_RAW(p, l, fmt, ...) \
+ do { \
+ if (gBtDbgLevel >= BT_LOG_INFO) { \
+ int cnt_ = 0; \
+ int len_ = (l <= RAW_MAX_BYTES ? l : RAW_MAX_BYTES); \
+ 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 <= RAW_MAX_BYTES) { \
+ pr_info(PFX" "fmt"%s\n", ##__VA_ARGS__, raw_buf); \
+ } else { \
+ pr_info(PFX" "fmt"%s (prtail)\n", ##__VA_ARGS__, raw_buf); \
+ } \
+ } \
+ } while (0)
+
+struct bt_dbg_st {
+ bool trx_enable;
+ uint16_t trx_opcode;
+ struct completion trx_comp;
+ void(*trx_cb) (char *buf, int len);
+ int rx_len;
+ char rx_buf[64];
+};
+
+struct pm_qos_ctrl {
+ struct semaphore sem;
+ struct workqueue_struct *task;
+ struct delayed_work work;
+ u_int8_t is_hold;
+};
+
+/* *****************************************************************************************
+ * BT Logger Tool will send 3 levels(Low, SQC and Debug)
+ * Driver will not check its range so we can provide capability of extention.
+ ******************************************************************************************/
+#define DEFAULT_LEVEL 0x02 /* 0x00:OFF, 0x01: LOW POWER, 0x02: SQC, 0x03: DEBUG */
+
+extern int fw_log_bt_init(void);
+extern void fw_log_bt_exit(void);
+extern void bt_state_notify(UINT32 on_off);
+extern ssize_t send_hci_frame(const PUINT8 buf, size_t count);
+
+#endif
+
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/dbg_bt.c b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/dbg_bt.c
new file mode 100755
index 0000000000000000000000000000000000000000..313ffe747bc3095c9f9bf0a363b902f9e36bcdfb
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/dbg_bt.c
@@ -0,0 +1,367 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+#include
+#include
+#include
+#include "bt.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
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+static int bt_dbg_get_bt_state(int par1, int par2, int par3);
+static int bt_dbg_setlog_level(int par1, int par2, int par3);
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+extern struct bt_dbg_st g_bt_dbg_st;
+extern UINT32 gBtDbgLevel;
+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_turn_on = FALSE;
+static bool g_bt_dbg_enable = FALSE;
+
+static const tBT_DEV_DBG_STRUCT bt_dev_dbg_struct[] = {
+ [0xb] = {bt_dbg_setlog_level, TRUE},
+ [0xe] = {bt_dbg_get_bt_state, TRUE},
+};
+
+/*******************************************************************************
+* 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_get_bt_state(int par1, int par2, int par3)
+{
+ // 0x01: bt on, 0x00: bt off
+ BT_LOG_PRT_INFO("g_bt_turn_on[%d]\n", g_bt_turn_on);
+ _bt_dbg_reset_dump_buf();
+ g_bt_dump_buf[0] = g_bt_turn_on;
+ g_bt_dump_buf[1] = '\0';
+ g_bt_dump_buf_len = 2;
+ return 0;
+}
+
+int bt_dbg_setlog_level(int par1, int par2, int par3)
+{
+ if (par2 < BT_LOG_ERR || par2 > BT_LOG_DBG) {
+ gBtDbgLevel = BT_LOG_INFO;
+ } else {
+ gBtDbgLevel = par2;
+ }
+ BT_LOG_PRT_INFO("gBtDbgLevel = %d\n", gBtDbgLevel);
+ 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;
+
+ ret = mutex_lock_killable(&g_bt_lock);
+ if (ret) {
+ BT_LOG_PRT_ERR("dump_lock fail!!\n");
+ 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) {
+ BT_LOG_PRT_ERR("copy to dump info buffer failed, ret:%d\n", ret);
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ *f_pos += dump_len;
+ g_bt_dump_buf_len -= dump_len;
+ g_bt_dump_buf_ptr += dump_len;
+ BT_LOG_PRT_INFO("after read, wmt for dump info buffer len(%d)\n", g_bt_dump_buf_len);
+
+ ret = dump_len;
+exit:
+
+ mutex_unlock(&g_bt_lock);
+ return ret;
+}
+
+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);
+}
+
+void bt_dbg_user_trx_cb(char *buf, int len)
+{
+ unsigned char *ptr = g_bt_dbg_st.rx_buf;
+ unsigned int i = 0, evt_len = 0;
+ int ret = 0;
+
+ /* 1. bluedroid use partial read, this callback will enter several times
+ 2. this function read and parse the command_complete event */
+ memcpy(&g_bt_dbg_st.rx_buf[g_bt_dbg_st.rx_len], buf, len);
+ g_bt_dbg_st.rx_len += len;
+
+ // check the complete packet is read out by bluedroid
+ if(g_bt_dbg_st.rx_len != (g_bt_dbg_st.rx_buf[2] + 3))
+ return;
+
+ // if this event is not the desire one, skip and reset buffer
+ if((g_bt_dbg_st.rx_buf[4] + (g_bt_dbg_st.rx_buf[5] << 8)) != g_bt_dbg_st.trx_opcode) {
+ g_bt_dbg_st.rx_len = 0;
+ memset(g_bt_dbg_st.rx_buf, 0, sizeof(g_bt_dbg_st.rx_buf));
+ return;
+ }
+
+ // desire rx event is received, write to read buffer as string
+ evt_len = g_bt_dbg_st.rx_len;
+ BT_LOG_PRT_INFO_RAW(g_bt_dbg_st.rx_buf, evt_len, "%s: len[%ud], RxEvt: ", __func__, evt_len);
+ if(evt_len * 5 + 2 > BT_DBG_DUMP_BUF_SIZE)
+ return;
+
+ _bt_dbg_reset_dump_buf();
+ for (i = 0; i < evt_len; i++) {
+ ret = snprintf(g_bt_dump_buf + 5*i, 6, "0x%02X ", ptr[i]);
+ if (ret < 0) {
+ BT_LOG_PRT_ERR("error snprintf return value = [%d]\n", ret);
+ return;
+ }
+ }
+
+ g_bt_dump_buf[5*evt_len] = '\n';
+ g_bt_dump_buf[5*evt_len + 1] = '\0';
+ g_bt_dump_buf_len = 5*evt_len + 1;
+
+ // complete trx process
+ complete(&g_bt_dbg_st.trx_comp);
+}
+
+void bt_dbg_user_trx_proc(char *cmd_raw)
+{
+#define LEN_64 64
+ unsigned char hci_cmd[LEN_64];
+ unsigned 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) {
+ BT_LOG_PRT_INFO("%s: skip since cmd length exceed!", __func__);
+ return;
+ }
+ ptr = strsep(&pRaw, " ");
+ if (ptr != NULL) {
+ _osal_strtol(ptr, 16, &tmp);
+ hci_cmd[len++] = (unsigned char)tmp;
+ }
+ }
+
+ // Initialize rx variables
+ g_bt_dbg_st.rx_len = 0;
+ g_bt_dbg_st.trx_opcode = hci_cmd[1] + (hci_cmd[2] << 8);
+ memset(g_bt_dbg_st.rx_buf, 0, sizeof(g_bt_dbg_st.rx_buf));
+ BT_LOG_PRT_INFO_RAW(hci_cmd, len, "%s: len[%ud], TxCmd: ", __func__, len);
+
+ // Send command and wait for command_complete event
+ g_bt_dbg_st.trx_enable = TRUE;
+ send_hci_frame(hci_cmd, len);
+ if (!wait_for_completion_timeout(&g_bt_dbg_st.trx_comp, msecs_to_jiffies(2000)))
+ BT_LOG_PRT_ERR("%s: wait event timeout!", __func__);
+ g_bt_dbg_st.trx_enable = FALSE;
+}
+
+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";
+
+ if (len <= 0 || len >= sizeof(buf)) {
+ BT_LOG_PRT_ERR("input handling fail!\n");
+ len = sizeof(buf) - 1;
+ return -1;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, buffer, len))
+ return -EFAULT;
+ buf[len] = '\0';
+ BT_LOG_PRT_INFO("g_bt_turn_on[%d], dbg_enable[%d], len[%d], data = %s\n",
+ g_bt_turn_on, g_bt_dbg_enable, (int)len, buf);
+
+ /* 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(!g_bt_turn_on) // 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) {
+ _osal_strtol(pToken, 16, &res);
+ x = (int)res;
+ } else {
+ x = 0;
+ }
+
+ pToken = strsep(&pBuf, "\t\n ");
+ if (pToken != NULL) {
+ _osal_strtol(pToken, 16, &res);
+ y = (int)res;
+ BT_LOG_PRT_INFO("y = 0x%08x\n", 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) {
+ _osal_strtol(pToken, 16, &res);
+ z = (int)res;
+ } else {
+ z = 10;
+ /*efuse, register read write default value */
+ if (0x5 == x || 0x6 == x)
+ z = 0xffffffff;
+ }
+
+ BT_LOG_PRT_INFO("x(0x%08x), y(0x%08x), z(0x%08x)\n", x, y, z);
+ if (ARRAY_SIZE(bt_dev_dbg_struct) > x && NULL != bt_dev_dbg_struct[x].func) {
+ if(!g_bt_turn_on && !bt_dev_dbg_struct[x].turn_off_availavle) {
+ BT_LOG_PRT_WARN("command id(0x%08x) only work when bt on!\n", x);
+ } else {
+ (*bt_dev_dbg_struct[x].func) (x, y, z);
+ }
+ } else {
+ BT_LOG_PRT_WARN("command id(0x%08x) no handler defined!\n", x);
+ }
+
+ return len;
+}
+
+int bt_dev_dbg_init(void)
+{
+ int i_ret = 0;
+ static const struct file_operations bt_dbg_fops = {
+ .owner = THIS_MODULE,
+ .read = bt_dbg_read,
+ .write = bt_dbg_write,
+ };
+
+ // initialize debug function struct
+ g_bt_dbg_st.trx_enable = FALSE;
+ g_bt_dbg_st.trx_opcode = 0;
+ g_bt_dbg_st.trx_cb = bt_dbg_user_trx_cb;
+ init_completion(&g_bt_dbg_st.trx_comp);
+
+ g_bt_dbg_entry = proc_create(BT_DBG_PROCNAME, 0664, NULL, &bt_dbg_fops);
+ if (g_bt_dbg_entry == NULL) {
+ BT_LOG_PRT_ERR("Unable to create [%s] bt proc entry\n", BT_DBG_PROCNAME);
+ i_ret = -1;
+ }
+
+ mutex_init(&g_bt_lock);
+
+ BT_LOG_PRT_INFO("create [%s] done\n", BT_DBG_PROCNAME);
+ 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;
+}
+
+
+int bt_dev_dbg_set_state(bool turn_on)
+{
+ g_bt_turn_on = turn_on;
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/fw_log_bt.c b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/fw_log_bt.c
new file mode 100644
index 0000000000000000000000000000000000000000..de10bf7c6f1461cd5f62462a0a50cf49db14f59c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/fw_log_bt.c
@@ -0,0 +1,347 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+#include "bt.h"
+#include "connsys_debug_utility.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define BT_LOG_NODE_NAME "fw_log_bt"
+
+#define BT_FW_LOG_IOC_MAGIC (0xfc)
+#define BT_FW_LOG_IOCTL_ON_OFF _IOW(BT_FW_LOG_IOC_MAGIC, 0, int)
+#define BT_FW_LOG_IOCTL_SET_LEVEL _IOW(BT_FW_LOG_IOC_MAGIC, 1, int)
+#define BT_FW_LOG_IOCTL_GET_LEVEL _IOW(BT_FW_LOG_IOC_MAGIC, 2, int)
+
+static unsigned char g_bt_on = OFF;
+static unsigned char g_log_on = OFF;
+static unsigned char g_log_level = DEFAULT_LEVEL;
+static unsigned char g_log_current = OFF;
+
+#define BT_LOG_BUFFER_SIZE 512
+
+static struct cdev log_cdev;
+#if CREATE_NODE_DYNAMIC
+static struct class *log_class;
+static struct device *log_dev;
+#endif
+static dev_t devno;
+
+wait_queue_head_t BT_log_wq;
+
+static struct semaphore ioctl_mtx;
+
+static int ascii_to_hex(unsigned char ascii, unsigned char *hex)
+{
+ int ret = 0;
+
+ if('0' <= ascii && ascii <= '9')
+ *hex = ascii - '0';
+ else if ('a' <= ascii && ascii <= 'f')
+ *hex = ascii - 'a' + 10;
+ else if ('A' <= ascii && ascii <= 'F')
+ *hex = ascii - 'A' + 10;
+ else
+ ret = -1;
+
+ return ret;
+}
+
+static int set_fw_log(unsigned char flag)
+{
+ ssize_t retval = 0;
+
+ /* Opcode 0xfc5d TCI_MTK_DEBUG_VERSION_INFO */
+ unsigned char HCI_CMD_FW_LOG_DEBUG[] = {0x01, 0x5d, 0xfc, 0x04, 0x02, 0x00, 0x01, 0xff}; // Via EMI
+
+ HCI_CMD_FW_LOG_DEBUG[7] = flag;
+ BT_LOG_PRT_INFO("hci_cmd: %02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n",
+ HCI_CMD_FW_LOG_DEBUG[0], HCI_CMD_FW_LOG_DEBUG[1],
+ HCI_CMD_FW_LOG_DEBUG[2], HCI_CMD_FW_LOG_DEBUG[3],
+ HCI_CMD_FW_LOG_DEBUG[4], HCI_CMD_FW_LOG_DEBUG[5],
+ HCI_CMD_FW_LOG_DEBUG[6], HCI_CMD_FW_LOG_DEBUG[7]);
+
+ retval = send_hci_frame(HCI_CMD_FW_LOG_DEBUG, sizeof(HCI_CMD_FW_LOG_DEBUG));
+
+ if (likely(retval == sizeof(HCI_CMD_FW_LOG_DEBUG)))
+ return 0;
+ else if (retval < 0)
+ return retval;
+ else {
+ BT_LOG_PRT_ERR("Only partial sent %zu bytes, but hci cmd has %zu bytes", retval, sizeof(HCI_CMD_FW_LOG_DEBUG));
+ return -EFAULT;
+ }
+}
+
+void bt_state_notify(UINT32 on_off)
+{
+ BT_LOG_PRT_INFO("g_bt_on %d, on_off %d\n", g_bt_on, on_off);
+
+ if (g_bt_on == on_off) {
+ // no change.
+ } else {
+ // changed.
+ if (on_off == OFF) { // should turn off.
+ g_bt_on = OFF;
+ BT_LOG_PRT_INFO("BT func off, no need to send hci cmd\n");
+ } else {
+ g_bt_on = ON;
+ if(g_log_current)
+ set_fw_log(g_log_current);
+ }
+ }
+}
+
+long fw_log_bt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ long retval = 0;
+ unsigned char log_tmp = OFF;
+
+ down(&ioctl_mtx);
+ switch (cmd) {
+ case BT_FW_LOG_IOCTL_ON_OFF:
+ /* connsyslogger daemon dynamically enable/disable Picus log */
+ BT_LOG_PRT_INFO("BT_FW_LOG_IOCTL_ON_OFF: arg(%lu), g_bt_on(0x%02x), g_log_on(0x%02x), g_log_level(0x%02x), g_log_current(0x%02x)\n",
+ arg, g_bt_on, g_log_on, g_log_level, g_log_current);
+ log_tmp = (arg == 0 ? OFF: ON);
+ if (log_tmp == g_log_on) // no change
+ break;
+ else { // changed
+ g_log_on = log_tmp;
+ g_log_current = g_log_on & g_log_level;
+ if (g_bt_on)
+ retval = set_fw_log(g_log_current);
+ }
+ break;
+ case BT_FW_LOG_IOCTL_SET_LEVEL:
+ /* connsyslogger daemon dynamically set Picus log level */
+ BT_LOG_PRT_INFO("BT_FW_LOG_IOCTL_SET_LEVEL: arg(%lu), g_bt_on(0x%02x), g_log_on(0x%02x), g_log_level(0x%02x), g_log_current(0x%02x)\n",
+ arg, g_bt_on, g_log_on, g_log_level, g_log_current);
+ log_tmp = (unsigned char)arg;
+ if(log_tmp == g_log_level) // no change
+ break;
+ else {
+ 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 = set_fw_log(g_log_current);
+ }
+ break;
+ case BT_FW_LOG_IOCTL_GET_LEVEL:
+ retval = g_log_level;
+ BT_LOG_PRT_INFO("BT_FW_LOG_IOCTL_GET_LEVEL: %ld\n", retval);
+ break;
+ default:
+ BT_LOG_PRT_ERR("Unknown cmd: 0x%08x\n", cmd);
+ retval = -EOPNOTSUPP;
+ break;
+ }
+
+ up(&ioctl_mtx);
+ return retval;
+}
+
+long fw_log_bt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ return fw_log_bt_unlocked_ioctl(filp, cmd, arg);
+}
+
+static void fw_log_bt_event_cb(void)
+{
+ BT_LOG_PRT_DBG("fw_log_bt_event_cb");
+ wake_up_interruptible(&BT_log_wq);
+}
+
+static unsigned int fw_log_bt_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ poll_wait(file, &BT_log_wq, wait);
+ if (connsys_log_get_buf_size(CONNLOG_TYPE_BT) > 0) {
+ mask = (POLLIN | POLLRDNORM);
+ }
+ return mask;
+}
+
+static ssize_t fw_log_bt_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ ssize_t retval = 0;
+ UINT8 tmp_buf[BT_LOG_BUFFER_SIZE] = {0};
+ UINT8 hci_cmd[BT_LOG_BUFFER_SIZE] = {0};
+ UINT8 tmp = 0, tmp_h = 0;
+ size_t i = 0, j = 0, k = 0;
+
+ if(count >= BT_LOG_BUFFER_SIZE) {
+ BT_LOG_PRT_ERR("write count %zd exceeds max buffer size %d", count, BT_LOG_BUFFER_SIZE);
+ retval = -EINVAL;
+ goto OUT;
+ }
+
+ if (copy_from_user(tmp_buf, buf, count)) {
+ BT_LOG_PRT_ERR("copy_from_user failed!\n");
+ retval = -EFAULT;
+ } else {
+ BT_LOG_PRT_INFO("adb input: %s, len %zd\n", tmp_buf, strlen(tmp_buf));
+ if (0 == memcmp(tmp_buf, "raw-hex,", strlen("raw-hex,"))) {
+ // Skip prefix
+ for(i = strlen("raw-hex,"); i < strlen(tmp_buf); i++) {
+ if(tmp_buf[i] == ' ') // get space
+ continue;
+ else if(tmp_buf[i] == '\r' || tmp_buf[i] =='\n') // get 0x0a('\n') or 0x0d('\r')
+ break;
+ // Two input char should turn to one byte
+ if (ascii_to_hex(tmp_buf[i], &tmp) == 0) {
+ if (j%2 == 0)
+ tmp_h = tmp;
+ else {
+ hci_cmd[k] = tmp_h * 16 + tmp;
+ BT_LOG_PRT_DBG("hci_cmd[%zd] = 0x%02x\n", k, hci_cmd[k]);
+ k++;
+ }
+ } else {
+ BT_LOG_PRT_ERR("get unexpected char %c\n", tmp_buf[i]);
+ retval = -EINVAL;
+ goto OUT;
+ }
+ j++;
+ }
+ }
+ // ONLY send hci cmd when BT func on
+ if (!g_bt_on) {
+ retval = -EIO;
+ BT_LOG_PRT_ERR("BT func off, skip to send hci cmd\n");
+ } else
+ retval = send_hci_frame(hci_cmd, k);
+
+ }
+OUT:
+
+ return retval;
+}
+
+static ssize_t fw_log_bt_read(struct file *filp, char __user *buf, size_t len, loff_t *f_pos)
+{
+ size_t ret = 0;
+
+ ret = connsys_log_read_to_user(CONNLOG_TYPE_BT, buf, len);
+ BT_LOG_PRT_DBG("BT F/W log from connsys len %zd\n", ret);
+ return ret;
+}
+
+static int fw_log_bt_open(struct inode *inode, struct file *file)
+{
+ BT_LOG_PRT_INFO("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+ return 0;
+}
+
+static int fw_log_bt_close(struct inode *inode, struct file *file)
+{
+ BT_LOG_PRT_INFO("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+ return 0;
+}
+
+struct file_operations log_fops = {
+ .open = fw_log_bt_open,
+ .release = fw_log_bt_close,
+ .read = fw_log_bt_read,
+ .write = fw_log_bt_write,
+ .unlocked_ioctl = fw_log_bt_unlocked_ioctl,
+ .compat_ioctl = fw_log_bt_compat_ioctl,
+ .poll = fw_log_bt_poll
+};
+
+int fw_log_bt_init(void)
+{
+ INT32 alloc_ret = 0;
+ INT32 cdv_err = 0;
+
+ connsys_log_init(CONNLOG_TYPE_BT);
+
+ init_waitqueue_head(&BT_log_wq);
+ connsys_log_register_event_cb(CONNLOG_TYPE_BT, fw_log_bt_event_cb);
+ sema_init(&ioctl_mtx, 1);
+
+ /* Allocate char device */
+ alloc_ret = alloc_chrdev_region(&devno, 0, 1, BT_LOG_NODE_NAME);
+ if (alloc_ret) {
+ BT_LOG_PRT_ERR("Failed to register device numbers\n");
+ return alloc_ret;
+ }
+
+ cdev_init(&log_cdev, &log_fops);
+ log_cdev.owner = THIS_MODULE;
+
+ cdv_err = cdev_add(&log_cdev, devno, 1);
+ if (cdv_err)
+ goto error;
+
+#if CREATE_NODE_DYNAMIC /* mknod replace */
+ log_class = class_create(THIS_MODULE, BT_LOG_NODE_NAME);
+ if (IS_ERR(log_class))
+ goto error;
+
+ log_dev = device_create(log_class, NULL, devno, NULL, BT_LOG_NODE_NAME);
+ if (IS_ERR(log_dev))
+ goto error;
+#endif
+
+ BT_LOG_PRT_INFO("%s driver(major %d, minor %d) installed\n", BT_LOG_NODE_NAME, MAJOR(devno), MINOR(devno));
+ return 0;
+
+error:
+
+#if CREATE_NODE_DYNAMIC
+ if (log_dev && !IS_ERR(log_dev)) {
+ device_destroy(log_class, devno);
+ log_dev = NULL;
+ }
+ if (log_class && !IS_ERR(log_class)) {
+ class_destroy(log_class);
+ log_class = NULL;
+ }
+#endif
+ if (cdv_err == 0)
+ cdev_del(&log_cdev);
+
+ if (alloc_ret == 0)
+ unregister_chrdev_region(devno, 1);
+
+ return -1;
+}
+
+void fw_log_bt_exit(void)
+{
+ connsys_log_deinit(CONNLOG_TYPE_BT);
+
+ cdev_del(&log_cdev);
+ unregister_chrdev_region(devno, 1);
+
+#if CREATE_NODE_DYNAMIC
+ if (log_dev && !IS_ERR(log_dev)) {
+ device_destroy(log_class, devno);
+ log_dev = NULL;
+ }
+ if (log_class && !IS_ERR(log_class)) {
+ class_destroy(log_class);
+ log_class = NULL;
+ }
+#endif
+ BT_LOG_PRT_INFO("%s driver removed\n", BT_LOG_NODE_NAME);
+}
+#endif
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/init.bt_drv.rc b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/init.bt_drv.rc
new file mode 100644
index 0000000000000000000000000000000000000000..b857ffba811c51c9c73f506a19fce8719edec8d7
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/init.bt_drv.rc
@@ -0,0 +1,4 @@
+# load bt_drv
+on property:vendor.connsys.driver.ready=yes
+ insmod /vendor/lib/modules/bt_drv.ko
+ chown bluetooth bluetooth /proc/driver/bt_dbg
\ No newline at end of file
diff --git a/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/stp_chrdev_bt.c
new file mode 100644
index 0000000000000000000000000000000000000000..9cf910b731a263c8e73a12153aec34af8e6abbc6
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/bt/mt66xx/legacy/stp_chrdev_bt.c
@@ -0,0 +1,891 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#include "bt.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define BT_DRIVER_NAME "mtk_stp_bt_chrdev"
+#define BT_DEV_MAJOR 192
+
+#define VERSION "2.0"
+
+#define COMBO_IOC_MAGIC 0xb0
+#define COMBO_IOCTL_FW_ASSERT _IOW(COMBO_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_BT_SET_PSM _IOW(COMBO_IOC_MAGIC, 1, bool)
+#define COMBO_IOCTL_BT_IC_HW_VER _IOR(COMBO_IOC_MAGIC, 2, void*)
+#define COMBO_IOCTL_BT_IC_FW_VER _IOR(COMBO_IOC_MAGIC, 3, void*)
+
+#define BT_BUFFER_SIZE 2048
+#define FTRACE_STR_LOG_SIZE 256
+#define REG_READL(addr) readl((volatile uint32_t *)(addr))
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+static INT32 BT_devs = 1;
+static INT32 BT_major = BT_DEV_MAJOR;
+module_param(BT_major, uint, 0);
+static struct cdev BT_cdev;
+#if CREATE_NODE_DYNAMIC
+static struct class *stpbt_class;
+static struct device *stpbt_dev;
+#endif
+
+static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer for read */
+static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer for write */
+
+static struct semaphore wr_mtx, rd_mtx;
+static struct wakeup_source *bt_wakelock;
+/* Wait queue for poll and read */
+static wait_queue_head_t inq;
+static DECLARE_WAIT_QUEUE_HEAD(BT_wq);
+static INT32 flag;
+static INT32 bt_ftrace_flag;
+static bool btonflag = 0;
+UINT32 gBtDbgLevel = BT_LOG_INFO;
+struct bt_dbg_st g_bt_dbg_st;
+#if (PM_QOS_CONTROL == 1)
+static struct pm_qos_request qos_req;
+static struct pm_qos_ctrl qos_ctrl;
+#endif
+
+/*
+ * 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 rstflag;
+static UINT8 HCI_EVT_HW_ERROR[] = {0x04, 0x10, 0x01, 0x00};
+static loff_t rd_offset;
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+extern int bt_dev_dbg_init(void);
+extern int bt_dev_dbg_deinit(void);
+extern int bt_dev_dbg_set_state(bool turn_on);
+
+static INT32 ftrace_print(const PINT8 str, ...)
+{
+#ifdef CONFIG_TRACING
+ va_list args;
+ int ret = 0;
+ INT8 temp_string[FTRACE_STR_LOG_SIZE];
+
+ if (bt_ftrace_flag) {
+ va_start(args, str);
+ ret = vsnprintf(temp_string, FTRACE_STR_LOG_SIZE, str, args);
+ va_end(args);
+ if (ret < 0) {
+ BT_LOG_PRT_ERR("error return value in vsnprintf ret = [%d]\n", ret);
+ return 0;
+ }
+ trace_printk("%s\n", temp_string);
+ }
+#endif
+ return 0;
+}
+
+static size_t bt_report_hw_error(char *buf, size_t count, loff_t *f_pos)
+{
+ size_t bytes_rest, bytes_read;
+
+ if (*f_pos == 0)
+ BT_LOG_PRT_INFO("Send Hardware Error event to stack to restart Bluetooth\n");
+
+ 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 uint32_t inline bt_read_cr(unsigned char *cr_name, uint32_t addr)
+{
+ uint32_t value = 0;
+ uint8_t *base = ioremap_nocache(addr, 0x10);
+
+ if (base == NULL) {
+ BT_LOG_PRT_WARN("remapping 0x%08x fail\n", addr);
+ } else {
+ value = REG_READL(base);
+ iounmap(base);
+ BT_LOG_PRT_INFO("%s[0x%08x], read[0x%08x]\n", cr_name, addr, value);
+ }
+ return value;
+}
+
+/*
+static struct notifier_block bt_fb_notifier;
+static int bt_fb_notifier_callback(struct notifier_block
+ *self, unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int32_t blank = 0;
+
+ if ((event != FB_EVENT_BLANK))
+ return 0;
+
+ blank = *(int32_t *)evdata->data;
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ case FB_BLANK_POWERDOWN:
+ if(btonflag == 1 && rstflag == 0) {
+ BT_LOG_PRT_INFO("blank state [%ld]", blank);
+ bt_read_cr("HOST_MAILBOX_BT_ADDR", 0x18007124);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int bt_fb_notify_register(void)
+{
+ int32_t ret;
+
+ bt_fb_notifier.notifier_call = bt_fb_notifier_callback;
+
+ ret = fb_register_client(&bt_fb_notifier);
+ if (ret)
+ BT_LOG_PRT_WARN("Register bt_fb_notifier failed:%d\n", ret);
+ else
+ BT_LOG_PRT_DBG("Register bt_fb_notifier succeed\n");
+
+ return ret;
+}
+
+static void bt_fb_notify_unregister(void)
+{
+ fb_unregister_client(&bt_fb_notifier);
+}
+*/
+
+static struct notifier_block bt_pm_notifier;
+static int bt_pm_notifier_callback(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ BT_LOG_PRT_INFO("%s: btonflag[%d], event[%ld]", __func__, btonflag, event);
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ case PM_POST_SUSPEND:
+ if(btonflag == 1 && rstflag == 0) {
+ // for fw debug power issue
+ bt_read_cr("HOST_MAILBOX_BT_ADDR", 0x18007124);
+ }
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static int bt_pm_notify_register(void)
+{
+ int32_t ret;
+
+ bt_pm_notifier.notifier_call = bt_pm_notifier_callback;
+
+ ret = register_pm_notifier(&bt_pm_notifier);
+ if (ret)
+ BT_LOG_PRT_ERR("Register bt_pm_notifier failed:%d\n", ret);
+ else
+ BT_LOG_PRT_INFO("Register bt_pm_notifier succeed\n");
+
+ return ret;
+}
+
+static void bt_pm_notify_unregister(void)
+{
+ unregister_pm_notifier(&bt_pm_notifier);
+}
+
+/*******************************************************************
+* WHOLE CHIP RESET message handler
+********************************************************************
+*/
+static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src,
+ ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz)
+{
+ ENUM_WMTRSTMSG_TYPE_T rst_msg;
+
+ if (sz > sizeof(ENUM_WMTRSTMSG_TYPE_T)) {
+ BT_LOG_PRT_WARN("Invalid message format!\n");
+ return;
+ }
+
+ memcpy((PINT8)&rst_msg, (PINT8)buf, sz);
+ BT_LOG_PRT_DBG("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n",
+ src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX);
+ if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) && (type == WMTMSG_TYPE_RESET)) {
+ switch (rst_msg) {
+ case WMTRSTMSG_RESET_START:
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ bt_state_notify(OFF);
+#endif
+ BT_LOG_PRT_INFO("Whole chip reset start!\n");
+ rstflag = 1;
+ break;
+
+ case WMTRSTMSG_RESET_END:
+ case WMTRSTMSG_RESET_END_FAIL:
+ if (rst_msg == WMTRSTMSG_RESET_END)
+ BT_LOG_PRT_INFO("Whole chip reset end!\n");
+ else
+ BT_LOG_PRT_INFO("Whole chip reset fail!\n");
+ rd_offset = 0;
+ rstflag = 2;
+ flag = 1;
+ wake_up_interruptible(&inq);
+ wake_up(&BT_wq);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static VOID BT_event_cb(VOID)
+{
+ BT_LOG_PRT_DBG("BT_event_cb\n");
+ 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.
+ */
+ __pm_wakeup_event(bt_wakelock, 100);
+
+#if (PM_QOS_CONTROL == 1)
+ /* pm qos control:
+ * Set pm_qos to higher level for mass data transfer.
+ * When rx packet reveived, schedule a work to restore pm_qos setting after 500ms.
+ * If next packet is receiving before 500ms, this work will be cancel & re-schedule.
+ * (500ms: better power performance after experiment)
+ */
+ down(&qos_ctrl.sem);
+ if(qos_ctrl.task != NULL ) {
+ cancel_delayed_work(&qos_ctrl.work);
+ if(qos_ctrl.is_hold == FALSE) {
+ pm_qos_update_request(&qos_req, 1000);
+ qos_ctrl.is_hold = TRUE;
+ BT_LOG_PRT_INFO("[qos] is_hold[%d]\n", qos_ctrl.is_hold);
+ }
+ queue_delayed_work(qos_ctrl.task, &qos_ctrl.work, (500 * HZ) >> 10);
+ }
+ up(&qos_ctrl.sem);
+#endif
+
+ /*
+ * 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__);
+}
+
+unsigned int BT_poll(struct file *filp, poll_table *wait)
+{
+ UINT32 mask = 0;
+
+ if ((mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) && rstflag == 0) ||
+ (rstflag == 1) || (rstflag == 3)) {
+ /*
+ * 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 (!((mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) && rstflag == 0) ||
+ (rstflag == 1) || (rstflag == 3)))
+ 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(const PUINT8 buffer, size_t count)
+{
+ INT32 retval = 0;
+
+ retval = mtk_wcn_stp_send_data(buffer, count, BT_TASK_INDX);
+
+ if (retval < 0)
+ BT_LOG_PRT_ERR("mtk_wcn_stp_send_data fail, retval %d\n", retval);
+ else if (retval == 0) {
+ /* Device cannot process data in time, STP queue is full and no space is available for write,
+ * native program should not call writev with no delay.
+ */
+ BT_LOG_PRT_INFO_RATELIMITED("write count %zd, sent bytes %d, no space is available!\n", count, retval);
+ retval = -EAGAIN;
+ } else
+ BT_LOG_PRT_DBG("write count %zd, sent bytes %d\n", count, retval);
+
+ return retval;
+}
+
+ssize_t send_hci_frame(const PUINT8 buff, size_t count)
+{
+ ssize_t retval = 0;
+ int retry = 0;
+
+ down(&wr_mtx);
+
+ do {
+ if (retry > 0) {
+ msleep(30);
+ BT_LOG_PRT_ERR("Send hci cmd failed, retry %d time(s)\n", retry);
+ }
+ retval = __bt_write(buff, count);
+ retry++;
+ } while (retval == -EAGAIN && retry < 3);
+
+ up(&wr_mtx);
+
+ return retval;
+}
+
+ssize_t BT_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+ INT32 retval = 0;
+ size_t count = iov_iter_count(from);
+
+ ftrace_print("%s get called, count %zu", __func__, count);
+ down(&wr_mtx);
+
+ BT_LOG_PRT_DBG("count %zd\n", count);
+
+ if (rstflag) {
+ BT_LOG_PRT_ERR("whole chip reset occurs! rstflag=%d\n", rstflag);
+ retval = -EIO;
+ goto OUT;
+ }
+
+ if (count > 0) {
+ if (count > BT_BUFFER_SIZE) {
+ BT_LOG_PRT_ERR("write count %zd exceeds max buffer size %d", count, BT_BUFFER_SIZE);
+ retval = -EINVAL;
+ goto OUT;
+ }
+
+ if (copy_from_iter(o_buf, count, from) != count) {
+ retval = -EFAULT;
+ goto OUT;
+ }
+
+ BT_LOG_PRT_DBG_RAW(o_buf, count, "%s: len[%d], TX: ", __func__, count);
+ retval = __bt_write(o_buf, count);
+ }
+
+OUT:
+ up(&wr_mtx);
+ return retval;
+}
+
+ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ INT32 retval = 0;
+
+ ftrace_print("%s get called, count %zu", __func__, count);
+ down(&wr_mtx);
+
+ BT_LOG_PRT_DBG("count %zd pos %lld\n", count, *f_pos);
+
+ if (rstflag) {
+ BT_LOG_PRT_ERR("whole chip reset occurs! rstflag=%d\n", rstflag);
+ retval = -EIO;
+ goto OUT;
+ }
+
+ if (count > 0) {
+ if (count > BT_BUFFER_SIZE) {
+ BT_LOG_PRT_ERR("write count %zd exceeds max buffer size %d", count, BT_BUFFER_SIZE);
+ retval = -EINVAL;
+ goto OUT;
+ }
+
+ if (copy_from_user(o_buf, buf, count)) {
+ retval = -EFAULT;
+ goto OUT;
+ }
+
+ BT_LOG_PRT_DBG_RAW(o_buf, count, "%s: len[%d], TX: ", __func__, count);
+ retval = __bt_write(o_buf, count);
+ }
+
+OUT:
+ up(&wr_mtx);
+ return retval;
+}
+
+ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ INT32 retval = 0;
+
+ ftrace_print("%s get called, count %zu", __func__, count);
+ down(&rd_mtx);
+
+ BT_LOG_PRT_DBG("count %zd pos %lld\n", count, *f_pos);
+
+ if (rstflag) {
+ while (rstflag != 2) {
+ /*
+ * If nonblocking mode, return directly.
+ * O_NONBLOCK is specified during open()
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ BT_LOG_PRT_ERR("Non-blocking read, whole chip reset occurs! rstflag=%d\n", 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 = 3;
+ }
+
+ if (copy_to_user(buf, i_buf, retval)) {
+ retval = -EFAULT;
+ if (rstflag == 3)
+ rstflag = 2;
+ }
+
+ goto OUT;
+ }
+
+ if (count > BT_BUFFER_SIZE) {
+ count = BT_BUFFER_SIZE;
+ BT_LOG_PRT_WARN("Shorten read count from %zd to %d\n", count, BT_BUFFER_SIZE);
+ }
+
+ do {
+ retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX);
+ if (retval < 0) {
+ BT_LOG_PRT_ERR("mtk_wcn_stp_receive_data fail, retval %d\n", retval);
+ goto OUT;
+ } else if (retval == 0) { /* Got nothing, wait for STP's signal */
+ /*
+ * If nonblocking mode, return directly.
+ * O_NONBLOCK is specified during open()
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ BT_LOG_PRT_ERR("Non-blocking read, no data is available!\n");
+ retval = -EAGAIN;
+ goto OUT;
+ }
+
+ wait_event(BT_wq, flag != 0);
+ flag = 0;
+ } else { /* Got something from STP driver */
+ // for bt_dbg user trx function
+ if (g_bt_dbg_st.trx_enable) {
+ g_bt_dbg_st.trx_cb(i_buf, retval);
+ }
+ //BT_LOG_PRT_DBG("Read bytes %d\n", retval);
+ BT_LOG_PRT_DBG_RAW(i_buf, retval, "%s: len[%d], RX: ", __func__, retval);
+ break;
+ }
+ } while (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) && rstflag == 0);
+
+ if (retval == 0) {
+ if (rstflag != 2) { /* Should never happen */
+ WARN(1, "Blocking read is waken up with no data but rstflag=%d\n", 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 = 3;
+ }
+ }
+ }
+
+ if (copy_to_user(buf, i_buf, retval)) {
+ retval = -EFAULT;
+ if (rstflag == 3)
+ rstflag = 2;
+ }
+
+OUT:
+ up(&rd_mtx);
+ return retval;
+}
+
+/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */
+long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ INT32 retval = 0;
+ UINT32 reason;
+ UINT32 ver = 0;
+
+ BT_LOG_PRT_DBG("cmd: 0x%08x\n", cmd);
+
+ switch (cmd) {
+ case COMBO_IOCTL_FW_ASSERT:
+ /* Trigger FW assert for debug */
+ reason = (UINT32)arg & 0xFFFF;
+ BT_LOG_PRT_INFO("Host trigger FW assert......, reason:%d\n", reason);
+ if (reason == 31) /* HCI command timeout */
+ BT_LOG_PRT_INFO("HCI command timeout OpCode 0x%04x\n", ((UINT32)arg >> 16) & 0xFFFF);
+
+ if (mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, reason) == MTK_WCN_BOOL_TRUE) {
+ BT_LOG_PRT_INFO("Host trigger FW assert succeed\n");
+ retval = 0;
+ } else {
+ BT_LOG_PRT_ERR("Host trigger FW assert failed\n");
+ retval = -EBUSY;
+ }
+ break;
+ case COMBO_IOCTL_BT_SET_PSM:
+ /* BT stack may need to dynamically enable/disable Power Saving Mode
+ * in some scenarios for performance, e.g. A2DP chopping.
+ */
+ BT_LOG_PRT_INFO("BT stack change PSM setting: %lu\n", arg);
+ retval = mtk_wcn_wmt_psm_ctrl((MTK_WCN_BOOL)arg);
+ break;
+ case COMBO_IOCTL_BT_IC_HW_VER:
+ ver = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER);
+ BT_LOG_PRT_INFO("HW ver: 0x%x\n", ver);
+ if (copy_to_user((UINT32 __user *)arg, &ver, sizeof(ver)))
+ retval = -EFAULT;
+ break;
+ case COMBO_IOCTL_BT_IC_FW_VER:
+ ver = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER);
+ BT_LOG_PRT_INFO("FW ver: 0x%x\n", ver);
+ if (copy_to_user((UINT32 __user *)arg, &ver, sizeof(ver)))
+ retval = -EFAULT;
+ break;
+ default:
+ BT_LOG_PRT_ERR("Unknown cmd: 0x%08x\n", cmd);
+ retval = -EOPNOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ return BT_unlocked_ioctl(filp, cmd, arg);
+}
+
+#if (PM_QOS_CONTROL == 1)
+static void pm_qos_release(struct work_struct *pwork)
+{
+ pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
+ qos_ctrl.is_hold = FALSE;
+ BT_LOG_PRT_INFO("[qos] is_hold[%d]\n", qos_ctrl.is_hold);
+}
+#endif
+
+static int BT_open(struct inode *inode, struct file *file)
+{
+ if(btonflag) {
+ BT_LOG_PRT_WARN("BT already on!\n");
+ return -EIO;
+ }
+ BT_LOG_PRT_INFO("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+
+ /* Turn on BT */
+ if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT) == MTK_WCN_BOOL_FALSE) {
+ BT_LOG_PRT_WARN("WMT turn on BT fail!\n");
+ return -EIO;
+ }
+
+ BT_LOG_PRT_INFO("WMT turn on BT OK!\n");
+
+ if (mtk_wcn_stp_is_ready() == MTK_WCN_BOOL_FALSE) {
+
+ BT_LOG_PRT_ERR("STP is not ready!\n");
+ mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT);
+ return -EIO;
+ }
+
+ mtk_wcn_stp_set_bluez(0);
+
+ BT_LOG_PRT_INFO("Now it's in MTK Bluetooth Mode\n");
+ BT_LOG_PRT_INFO("STP is ready!\n");
+
+ BT_LOG_PRT_DBG("Register BT event callback!\n");
+ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb);
+
+ BT_LOG_PRT_DBG("Register BT reset callback!\n");
+ mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb);
+
+ rstflag = 0;
+ bt_ftrace_flag = 1;
+ btonflag = 1;
+
+ sema_init(&wr_mtx, 1);
+ sema_init(&rd_mtx, 1);
+
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ bt_state_notify(ON);
+#endif
+ bt_dev_dbg_set_state(TRUE);
+
+#if (PM_QOS_CONTROL == 1)
+ down(&qos_ctrl.sem);
+ pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
+ qos_ctrl.is_hold = FALSE;
+ qos_ctrl.task = create_singlethread_workqueue("pm_qos_task");
+ if (!qos_ctrl.task){
+ BT_LOG_PRT_ERR("fail to create pm_qos_task");
+ return -EIO;
+ }
+ INIT_DELAYED_WORK(&qos_ctrl.work, pm_qos_release);
+ up(&qos_ctrl.sem);
+#endif
+ bt_pm_notify_register();
+
+ return 0;
+}
+
+static int BT_close(struct inode *inode, struct file *file)
+{
+ BT_LOG_PRT_INFO("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+
+ bt_pm_notify_unregister();
+ bt_dev_dbg_set_state(FALSE);
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ bt_state_notify(OFF);
+#endif
+
+ rstflag = 0;
+ bt_ftrace_flag = 0;
+ btonflag = 0;
+
+ mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT);
+ mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL);
+
+#if (PM_QOS_CONTROL == 1)
+ down(&qos_ctrl.sem);
+ if(qos_ctrl.task != NULL) {
+ BT_LOG_PRT_INFO("[qos] cancel delayed work\n");
+ cancel_delayed_work(&qos_ctrl.work);
+ flush_workqueue(qos_ctrl.task);
+ destroy_workqueue(qos_ctrl.task);
+ qos_ctrl.task = NULL;
+ }
+ pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
+ qos_ctrl.is_hold = FALSE;
+ up(&qos_ctrl.sem);
+#endif
+
+ if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT) == MTK_WCN_BOOL_FALSE) {
+ BT_LOG_PRT_ERR("WMT turn off BT fail!\n");
+ return -EIO; /* Mostly, native program will not check this return value. */
+ }
+
+ BT_LOG_PRT_INFO("WMT turn off BT OK!\n");
+ 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
+};
+
+static int BT_init(void)
+{
+ dev_t dev;
+ INT32 alloc_ret = 0;
+ INT32 cdv_err = 0;
+ dev = MKDEV(BT_major, 0);
+
+ /* Initialize wait queue */
+ init_waitqueue_head(&(inq));
+ /* Initialize wake lock */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 149)
+ BT_LOG_PRT_INFO("wakeup_source_register() with kernel-4.14.149\n");
+ bt_wakelock = wakeup_source_register(NULL, "bt_drv");
+#else
+ bt_wakelock = wakeup_source_register("bt_drv");
+#endif
+ if(!bt_wakelock) {
+ BT_LOG_PRT_ERR("%s: init bt_wakelock failed!\n", __func__);
+ }
+
+ /* Allocate char device */
+ alloc_ret = register_chrdev_region(dev, BT_devs, BT_DRIVER_NAME);
+ if (alloc_ret) {
+ BT_LOG_PRT_ERR("Failed to register device numbers\n");
+ return alloc_ret;
+ }
+
+ cdev_init(&BT_cdev, &BT_fops);
+ BT_cdev.owner = THIS_MODULE;
+
+ cdv_err = cdev_add(&BT_cdev, dev, BT_devs);
+ if (cdv_err)
+ goto error;
+
+#if CREATE_NODE_DYNAMIC /* mknod replace */
+ stpbt_class = class_create(THIS_MODULE, "stpbt");
+ if (IS_ERR(stpbt_class))
+ goto error;
+ stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt");
+ if (IS_ERR(stpbt_dev))
+ goto error;
+#endif
+
+ BT_LOG_PRT_INFO("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major);
+
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ fw_log_bt_init();
+#endif
+ bt_dev_dbg_init();
+
+#if (PM_QOS_CONTROL == 1)
+ pm_qos_add_request(&qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+ sema_init(&qos_ctrl.sem, 1);
+#endif
+
+ return 0;
+
+error:
+#if CREATE_NODE_DYNAMIC
+ if (stpbt_dev && !IS_ERR(stpbt_dev)) {
+ device_destroy(stpbt_class, dev);
+ stpbt_dev = NULL;
+ }
+ if (stpbt_class && !IS_ERR(stpbt_class)) {
+ class_destroy(stpbt_class);
+ stpbt_class = NULL;
+ }
+#endif
+ if (cdv_err == 0)
+ cdev_del(&BT_cdev);
+
+ if (alloc_ret == 0)
+ unregister_chrdev_region(dev, BT_devs);
+
+ return -1;
+}
+
+static void BT_exit(void)
+{
+ dev_t dev;
+
+#if (PM_QOS_CONTROL == 1)
+ pm_qos_remove_request(&qos_req);
+#endif
+
+ bt_dev_dbg_deinit();
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ fw_log_bt_exit();
+#endif
+
+ dev = MKDEV(BT_major, 0);
+ /* Destroy wake lock*/
+ wakeup_source_unregister(bt_wakelock);
+
+#if CREATE_NODE_DYNAMIC
+ if (stpbt_dev && !IS_ERR(stpbt_dev)) {
+ device_destroy(stpbt_class, dev);
+ stpbt_dev = NULL;
+ }
+ if (stpbt_class && !IS_ERR(stpbt_class)) {
+ class_destroy(stpbt_class);
+ stpbt_class = NULL;
+ }
+#endif
+
+ cdev_del(&BT_cdev);
+ unregister_chrdev_region(dev, BT_devs);
+
+ BT_LOG_PRT_INFO("%s driver removed\n", BT_DRIVER_NAME);
+}
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+
+int mtk_wcn_stpbt_drv_init(void)
+{
+ return BT_init();
+}
+EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init);
+
+void mtk_wcn_stpbt_drv_exit(void)
+{
+ return BT_exit();
+}
+EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit);
+
+#else
+
+module_init(BT_init);
+module_exit(BT_exit);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/Makefile b/drivers/misc/mediatek/connectivity/common/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f390aff160e6d781f5a162e8484651eecdbb94fa
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/Makefile
@@ -0,0 +1,290 @@
+ifeq ($(MTK_PLATFORM),)
+ifneq ($(MTK_PLATFORM_WMT),)
+MTK_PLATFORM := $(shell echo $(MTK_PLATFORM_WMT) | tr A-Z a-z)
+endif
+endif
+
+ifeq ($(MTK_PLATFORM),)
+ifneq ($(CONFIG_MTK_PLATFORM),)
+MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM))
+endif
+endif
+
+CONNSYS_PLATFORM := $(TARGET_BOARD_PLATFORM_WMT)
+PRIORITY_TABLE_MTK_PLATFORM := mt6735
+
+ifeq ($(CONNSYS_PLATFORM),)
+CONNSYS_PLATFORM := $(MTK_PLATFORM)
+else
+ifneq ($(filter $(PRIORITY_TABLE_MTK_PLATFORM), $(MTK_PLATFORM)),)
+CONNSYS_PLATFORM := $(MTK_PLATFORM)
+endif
+endif
+
+ifneq ($(CONFIG_MTK_COMBO),)
+
+ifeq ($(CONFIG_MTK_COMBO_CHIP),)
+ $(error CONFIG_MTK_COMBO_CHIP not defined)
+endif
+
+# Force build fail on modpost warning
+KBUILD_MODPOST_FAIL_ON_WARNINGS := y
+###############################################################################
+
+#ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE
+ifeq ($(CONFIG_ARM64), y)
+ ccflags-y += -D CONFIG_MTK_WCN_ARM64
+endif
+
+ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y)
+ ccflags-y += -D WMT_IDC_SUPPORT=1
+else
+ ccflags-y += -D WMT_IDC_SUPPORT=0
+endif
+ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM)
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1/$(MTK_PLATFORM)
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/btif/common/inc
+ifeq ($(strip $(MTK_PLATFORM)), mt6735)
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci1
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci1/$(MTK_PLATFORM)
+else
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM)
+endif
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/submodule
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/$(MTK_PLATFORM)
+ifeq ($(CONFIG_MTK_PMIC_CHIP_MT6359),y)
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/pmic/include/mt6359
+endif
+ifeq ($(CONFIG_MTK_PMIC_CHIP_MT6359P),y)
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/pmic/include/mt6359p
+endif
+ccflags-y += -I$(srctree)/drivers/mmc/core
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/common
+ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat
+###############################################################################
+
+
+ccflags-y += -Werror
+
+ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MT6628
+ ccflags-y += -D MERGE_INTERFACE_SUPPORT
+endif
+ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MT6630
+ifneq ($(CONFIG_ARCH_MT2601),y)
+ ccflags-y += -D MERGE_INTERFACE_SUPPORT
+endif
+endif
+
+ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MT6632
+ ccflags-y += -D MERGE_INTERFACE_SUPPORT
+endif
+
+#obj-y += common_main/
+#obj-y += common_detect/
+
+ifneq ($(filter MT6631,$(MTK_CONSYS_ADIE)),)
+ ccflags-y += -D CONSYS_PMIC_CTRL_6635=0
+else
+ ccflags-y += -D CONSYS_PMIC_CTRL_6635=1
+endif
+
+###############################################################################
+MODULE_NAME := wmt_drv
+ifeq ($(CONFIG_WLAN_DRV_BUILD_IN),y)
+$(warning $(MODULE_NAME) build-in boot.img)
+obj-y += $(MODULE_NAME).o
+else
+$(warning $(MODULE_NAME) is kernel module)
+obj-m += $(MODULE_NAME).o
+endif
+
+###############################################################################
+# common_detect
+###############################################################################
+ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/$(ARCH_MTK_PROJECT)/dct/dct
+ccflags-y += -DWMT_PLAT_ALPS=1
+
+COMBO_CHIP_SUPPORT := false
+ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),)
+ COMBO_CHIP_SUPPORT := true
+endif
+ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),)
+ COMBO_CHIP_SUPPORT := true
+endif
+ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),)
+ COMBO_CHIP_SUPPORT := true
+endif
+ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),)
+ COMBO_CHIP_SUPPORT := true
+endif
+ifeq ($(COMBO_CHIP_SUPPORT), true)
+ ccflags-y += -D MTK_WCN_COMBO_CHIP_SUPPORT
+endif
+
+ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MTK_WCN_SOC_CHIP_SUPPORT
+endif
+
+ccflags-y += -I$(src)/common_main/linux/include
+ccflags-y += -I$(src)/common_detect/drv_init/inc
+ccflags-y += -I$(src)/common_detect
+ccflags-y += -I$(src)/debug_utility
+
+$(MODULE_NAME)-objs += common_detect/wmt_detect_pwr.o
+$(MODULE_NAME)-objs += common_detect/wmt_detect.o
+$(MODULE_NAME)-objs += common_detect/sdio_detect.o
+$(MODULE_NAME)-objs += common_detect/mtk_wcn_stub_alps.o
+$(MODULE_NAME)-objs += common_detect/wmt_gpio.o
+
+
+ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MTK_WCN_WLAN_GEN3
+endif
+
+ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MTK_WCN_WLAN_GEN4
+endif
+
+ifneq ($(filter "CONSYS_6797" "CONSYS_6759" "CONSYS_6758" "CONSYS_6771" "CONSYS_6775",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MTK_WCN_WLAN_GEN3
+else ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),)
+ ccflags-y += -D MTK_WCN_WLAN_GEN2
+endif
+
+$(MODULE_NAME)-objs += common_detect/drv_init/fm_drv_init.o
+$(MODULE_NAME)-objs += common_detect/drv_init/conn_drv_init.o
+$(MODULE_NAME)-objs += common_detect/drv_init/bluetooth_drv_init.o
+$(MODULE_NAME)-objs += common_detect/drv_init/wlan_drv_init.o
+$(MODULE_NAME)-objs += common_detect/drv_init/common_drv_init.o
+$(MODULE_NAME)-objs += common_detect/drv_init/gps_drv_init.o
+
+
+###############################################################################
+# common_main
+###############################################################################
+ccflags-y += -I$(src)/common_main/linux/include
+ccflags-y += -I$(src)/common_main/linux/pri/include
+ccflags-y += -I$(src)/common_main/platform/include
+ccflags-y += -I$(src)/common_main/core/include
+ccflags-y += -I$(src)/common_main/include
+
+ccflags-y += -D WMT_PLAT_ALPS=1
+ccflags-y += -D WMT_UART_RX_MODE_WORK=0 # 1. work thread 0. tasklet
+ccflags-y += -D WMT_SDIO_MODE=1
+ccflags-y += -D WMT_CREATE_NODE_DYNAMIC=1
+
+ifneq ($(TARGET_BUILD_VARIANT),eng)
+ifeq ($(CONFIG_EXTREME_LOW_RAM), y)
+ccflags-y += -DLOG_STP_DEBUG_DISABLE
+endif
+endif
+
+ifneq ($(TARGET_BUILD_VARIANT), user)
+ ccflags-y += -D WMT_DBG_SUPPORT=1
+else
+ ccflags-y += -D WMT_DBG_SUPPORT=0
+endif
+
+ifeq ($(CONFIG_MTK_DEVAPC),y)
+ ccflags-y += -D WMT_DEVAPC_DBG_SUPPORT=1
+else
+ ccflags-y += -D WMT_DEVAPC_DBG_SUPPORT=0
+endif
+
+ifeq ($(CONFIG_ARCH_MT6580), y)
+ccflags-y += -D CFG_WMT_READ_EFUSE_VCN33
+endif
+
+# STEP: (Support Connac)
+# MTK eng/userdebug/user load: Support
+# Customer eng/userdebug load: Support
+# Customer user load: Not support
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+ ccflags-y += -D CFG_WMT_STEP
+endif
+
+ifeq ($(findstring evb, $(MTK_PROJECT)), evb)
+ccflags-y += -D CFG_WMT_EVB
+endif
+
+ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),)
+$(MODULE_NAME)-objs += common_main/platform/$(CONNSYS_PLATFORM).o
+endif
+
+#$(MODULE_NAME)-objs += common_main/platform/wmt_plat_stub.o
+$(MODULE_NAME)-objs += common_main/platform/wmt_plat_alps.o
+$(MODULE_NAME)-objs += common_main/platform/mtk_wcn_consys_hw.o
+$(MODULE_NAME)-objs += common_main/platform/mtk_wcn_cmb_hw.o
+
+$(MODULE_NAME)-objs += common_main/core/wmt_ic_6628.o
+$(MODULE_NAME)-objs += common_main/core/wmt_conf.o
+$(MODULE_NAME)-objs += common_main/core/stp_core.o
+$(MODULE_NAME)-objs += common_main/core/wmt_ctrl.o
+$(MODULE_NAME)-objs += common_main/core/wmt_func.o
+$(MODULE_NAME)-objs += common_main/core/wmt_core.o
+$(MODULE_NAME)-objs += common_main/core/psm_core.o
+$(MODULE_NAME)-objs += common_main/core/wmt_ic_soc.o
+$(MODULE_NAME)-objs += common_main/core/wmt_lib.o
+$(MODULE_NAME)-objs += common_main/core/wmt_ic_6620.o
+$(MODULE_NAME)-objs += common_main/core/stp_exp.o
+$(MODULE_NAME)-objs += common_main/core/wmt_ic_6632.o
+$(MODULE_NAME)-objs += common_main/core/wmt_exp.o
+$(MODULE_NAME)-objs += common_main/core/btm_core.o
+$(MODULE_NAME)-objs += common_main/core/wmt_ic_6630.o
+
+$(MODULE_NAME)-objs += common_main/linux/hif_sdio.o
+$(MODULE_NAME)-objs += common_main/linux/stp_dbg_soc.o
+$(MODULE_NAME)-objs += common_main/linux/stp_dbg_combo.o
+$(MODULE_NAME)-objs += common_main/linux/osal.o
+$(MODULE_NAME)-objs += common_main/linux/wmt_dev.o
+$(MODULE_NAME)-objs += common_main/linux/stp_sdio.o
+$(MODULE_NAME)-objs += common_main/linux/bgw_desense.o
+$(MODULE_NAME)-objs += common_main/linux/wmt_idc.o
+$(MODULE_NAME)-objs += common_main/linux/stp_uart.o
+$(MODULE_NAME)-objs += common_main/linux/wmt_dbg.o
+$(MODULE_NAME)-objs += common_main/linux/stp_dbg.o
+$(MODULE_NAME)-objs += common_main/linux/wmt_user_proc.o
+
+$(MODULE_NAME)-objs += common_main/linux/wmt_proc_dbg.o
+$(MODULE_NAME)-objs += common_main/linux/wmt_alarm.o
+
+ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),)
+$(MODULE_NAME)-objs += common_main/linux/fw_log_wmt.o
+endif
+$(MODULE_NAME)-objs += common_main/linux/wmt_step.o
+
+ifeq ($(CONFIG_MTK_BTIF),$(filter $(CONFIG_MTK_BTIF),y m))
+$(MODULE_NAME)-objs += common_main/linux/stp_btif.o
+endif
+
+$(MODULE_NAME)-objs += debug_utility/ring.o
+$(MODULE_NAME)-objs += debug_utility/ring_emi.o
+$(MODULE_NAME)-objs += debug_utility/connsys_debug_utility.o
+###############################################################################
+# test
+###############################################################################
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+ccflags-y += -I$(src)/test/include
+endif
+
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+$(MODULE_NAME)-objs += test/wmt_step_test.o
+endif
+
+endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..d89d5da4357b61fdb983aab7219504fb00e0fdde
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c
@@ -0,0 +1,43 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[BT-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "bluetooth_drv_init.h"
+
+#ifdef CONFIG_MTK_COMBO_BT
+int __attribute__((weak)) mtk_wcn_stpbt_drv_init()
+{
+ WMT_DETECT_PR_INFO("Not implement mtk_wcn_stpbt_drv_init\n");
+ return 0;
+}
+#endif
+
+int do_bluetooth_drv_init(int chip_id)
+{
+ int i_ret = -1;
+
+#ifdef CONFIG_MTK_COMBO_BT
+ WMT_DETECT_PR_INFO("start to do bluetooth driver init\n");
+ i_ret = mtk_wcn_stpbt_drv_init();
+ WMT_DETECT_PR_INFO("finish bluetooth driver init, i_ret:%d\n", i_ret);
+#else
+ WMT_DETECT_PR_INFO("CONFIG_MTK_COMBO_BT is not defined\n");
+#endif
+ return i_ret;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6c64529eaff714bf2d23cd03ef70c8b71a87d58
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "common_drv_init.h"
+
+
+#if (MTK_WCN_REMOVE_KO)
+int do_common_drv_init(int chip_id)
+{
+ int i_ret = 0;
+ int i_ret_tmp = 0;
+
+ WMT_DETECT_PR_INFO("start to do common driver init, chipid:0x%08x\n", chip_id);
+
+ wmt_detect_set_chip_type(chip_id);
+
+ /* HIF-SDIO driver init */
+ i_ret_tmp = mtk_wcn_hif_sdio_drv_init();
+ i_ret += i_ret_tmp;
+ WMT_DETECT_PR_DBG("HIF-SDIO driver init, i_ret:%d\n", i_ret);
+
+ /* WMT driver init */
+ i_ret_tmp = mtk_wcn_common_drv_init();
+ i_ret += i_ret_tmp;
+ WMT_DETECT_PR_DBG("COMBO COMMON driver init, i_ret:%d\n", i_ret);
+
+ /* STP-UART driver init */
+ i_ret_tmp = mtk_wcn_stp_uart_drv_init();
+ i_ret += i_ret_tmp;
+ WMT_DETECT_PR_DBG("STP-UART driver init, i_ret:%d\n", i_ret);
+
+ /* STP-SDIO driver init */
+ i_ret_tmp = mtk_wcn_stp_sdio_drv_init();
+ i_ret += i_ret_tmp;
+ WMT_DETECT_PR_DBG("STP-SDIO driver init, i_ret:%d\n", i_ret);
+
+ WMT_DETECT_PR_INFO("common driver init finish:%d\n", i_ret);
+ return i_ret;
+
+}
+#endif
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab03a5b14fe788b7fc9c5c0e58ce1bfe64f89b43
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c
@@ -0,0 +1,70 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WCN-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "conn_drv_init.h"
+#include "common_drv_init.h"
+#include "fm_drv_init.h"
+#include "wlan_drv_init.h"
+#include "bluetooth_drv_init.h"
+#include "gps_drv_init.h"
+
+#if (MTK_WCN_REMOVE_KO)
+int do_connectivity_driver_init(int chip_id)
+{
+ int i_ret = 0;
+ int tmp_ret = 0;
+ static int init_before;
+
+ /* To avoid invoking more than once.*/
+ if (init_before)
+ return 0;
+ init_before = 1;
+
+ tmp_ret = do_common_drv_init(chip_id);
+ i_ret += tmp_ret;
+ if (tmp_ret) {
+ WMT_DETECT_PR_ERR("do common driver not ready, ret:%d\n abort!\n", tmp_ret);
+ return i_ret;
+ }
+
+ tmp_ret = do_bluetooth_drv_init(chip_id);
+ i_ret += tmp_ret;
+ if (tmp_ret)
+ WMT_DETECT_PR_ERR("do common driver init failed, ret:%d\n", tmp_ret);
+
+ tmp_ret = do_gps_drv_init(chip_id);
+ i_ret += tmp_ret;
+ if (tmp_ret)
+ WMT_DETECT_PR_ERR("do common driver init failed, ret:%d\n", tmp_ret);
+
+ tmp_ret = do_fm_drv_init(chip_id);
+ i_ret += tmp_ret;
+ if (tmp_ret)
+ WMT_DETECT_PR_ERR("do fm module init failed, ret:%d\n", tmp_ret);
+
+ tmp_ret = do_wlan_drv_init(chip_id);
+ i_ret += tmp_ret;
+ if (tmp_ret)
+ WMT_DETECT_PR_ERR("do wlan module init failed, ret:%d\n", tmp_ret);
+
+ return i_ret;
+}
+#endif
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ec149e77046a6a1f1e78a752442e9029fc01f80
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c
@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[FM-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "fm_drv_init.h"
+
+#ifdef CONFIG_MTK_FMRADIO
+int __attribute__((weak)) mtk_wcn_fm_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_fm_init\n");
+ return 0;
+}
+#endif
+
+int do_fm_drv_init(int chip_id)
+{
+ WMT_DETECT_PR_INFO("start to do fm module init\n");
+
+#ifdef CONFIG_MTK_FMRADIO
+ mtk_wcn_fm_init();
+#endif
+
+ WMT_DETECT_PR_INFO("finish fm module init\n");
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac48b231a3d0e8a8cbfa22ed63d62e8c0821abed
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c
@@ -0,0 +1,43 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[GPS-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "gps_drv_init.h"
+
+#ifdef CONFIG_MTK_COMBO_GPS
+int __attribute__((weak)) mtk_wcn_stpgps_drv_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_stpgps_drv_init\n");
+ return 0;
+}
+#endif
+
+int do_gps_drv_init(int chip_id)
+{
+ int i_ret = -1;
+#ifdef CONFIG_MTK_COMBO_GPS
+ WMT_DETECT_PR_INFO("start to do gps driver init\n");
+ i_ret = mtk_wcn_stpgps_drv_init();
+ WMT_DETECT_PR_INFO("finish gps driver init, i_ret:%d\n", i_ret);
+#else
+ WMT_DETECT_PR_INFO("CONFIG_MTK_COMBO_GPS is not defined\n");
+#endif
+ return i_ret;
+
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a847d361fc8c66158a07b328133906e87480ee6
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h
@@ -0,0 +1,20 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _BLUETOOTH_DRIVER_INIT_H_
+#define _BLUETOOTH_DRIVER_INIT_H_
+
+extern int do_bluetooth_drv_init(int chip_id);
+extern int mtk_wcn_stpbt_drv_init(void);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..dae155e1d4039c8b699b2704bba6a4b158083abb
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h
@@ -0,0 +1,25 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _COMMON_DRV_INIT_H_
+#define _COMMON_DRV_INIT_H_
+extern int do_common_drv_init(int chip_id);
+
+extern int mtk_wcn_common_drv_init(void);
+extern int mtk_wcn_hif_sdio_drv_init(void);
+extern int mtk_wcn_stp_uart_drv_init(void);
+extern int mtk_wcn_stp_sdio_drv_init(void);
+
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..971193eade9e9b5226f49cf0145809f0556f06e2
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h
@@ -0,0 +1,18 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _CONNECTIVITY_DRV_INIT_H_
+#define _CONNECTIVITY_DRV_INIT_H_
+extern int do_connectivity_driver_init(int chip_id);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6ea30addc5da1f231e2bb0e0213e209b7ea80fc
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h
@@ -0,0 +1,20 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _FM_DRV_INIT_H_
+#define _FM_DRV_INIT_H_
+extern int do_fm_drv_init(int chip_id);
+extern int mtk_wcn_fm_init(void);
+extern void mtk_wcn_fm_exit(void);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..006ce072c53b6680b79e3f73c8689c06950aa352
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _GPS_DRIVER_INIT_H_
+#define _GPS_DRIVER_INIT_H_
+extern int do_gps_drv_init(int chip_id);
+extern int mtk_wcn_stpgps_drv_init(void);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ed7d4e458d1e824240300b0aef5a6f6faac3943
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _WLAN_DRV_INIT_H_
+#define _WLAN_DRV_INIT_H_
+
+
+extern int do_wlan_drv_init(int chip_id);
+
+extern int mtk_wcn_wmt_wifi_init(void);
+
+extern int mtk_wcn_wlan_gen2_init(void);
+
+extern int mtk_wcn_wlan_gen3_init(void);
+
+extern int mtk_wcn_wlan_gen4_init(void);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b28ad934f83f4ea0f5654254a27e462a2855a2a
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c
@@ -0,0 +1,89 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WLAN-MOD-INIT]"
+
+#include "wmt_detect.h"
+#include "wlan_drv_init.h"
+
+int __attribute__((weak)) mtk_wcn_wlan_gen4_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen4_init\n");
+ return 0;
+}
+
+int __attribute__((weak)) mtk_wcn_wlan_gen3_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen3_init\n");
+ return 0;
+}
+
+int __attribute__((weak)) mtk_wcn_wlan_gen2_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen2_init\n");
+ return 0;
+}
+
+int __attribute__((weak)) mtk_wcn_wmt_wifi_init()
+{
+ WMT_DETECT_PR_INFO("no impl. mtk_wcn_wmt_wifi_init\n");
+ return 0;
+}
+
+int do_wlan_drv_init(int chip_id)
+{
+ int i_ret = 0;
+ int ret = 0;
+
+ WMT_DETECT_PR_INFO("start to do wlan module init 0x%x\n", chip_id);
+
+ /* WMT-WIFI char dev init */
+ ret = mtk_wcn_wmt_wifi_init();
+ WMT_DETECT_PR_INFO("WMT-WIFI char dev init, ret:%d\n", ret);
+ i_ret += ret;
+
+ switch (chip_id) {
+ case 0x6580:
+ case 0x6739:
+ ret = mtk_wcn_wlan_gen2_init();
+ WMT_DETECT_PR_INFO("WLAN-GEN2 driver init, ret:%d\n", ret);
+ break;
+
+ case 0x6630:
+ case 0x6797:
+ case 0x6758:
+ case 0x6759:
+ case 0x6775:
+ case 0x6771:
+ /* WLAN driver init */
+ ret = mtk_wcn_wlan_gen3_init();
+ WMT_DETECT_PR_INFO("WLAN-GEN3 driver init, ret:%d\n", ret);
+ break;
+
+ default:
+ /* WLAN driver init */
+ ret = mtk_wcn_wlan_gen4_init();
+ WMT_DETECT_PR_INFO("WLAN-GEN4 driver init, ret:%d\n", ret);
+ break;
+ }
+
+ i_ret += ret;
+
+ WMT_DETECT_PR_INFO("finish wlan module init\n");
+
+ return i_ret;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c
new file mode 100644
index 0000000000000000000000000000000000000000..cf281b416d85875c155256d170a985a3815d482d
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c
@@ -0,0 +1,621 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+/*
+ * ! \file
+ * \brief Declaration of library functions
+ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+
+/* kernel wmt_build_in_adapter.c already has these, so always ignored */
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+#undef MTK_WCN_REMOVE_KERNEL_MODULE
+#endif
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define CMB_STUB_DBG_LOG 3
+#define CMB_STUB_INFO_LOG 2
+#define CMB_STUB_WARN_LOG 1
+
+int gCmbStubLogLevel = CMB_STUB_INFO_LOG;
+
+#define CMB_STUB_LOG_PR_INFO(fmt, arg...) \
+do { \
+ if (gCmbStubLogLevel >= CMB_STUB_INFO_LOG) \
+ pr_info(fmt, ##arg); \
+} while (0)
+#define CMB_STUB_LOG_PR_WARN(fmt, arg...) \
+do { \
+ if (gCmbStubLogLevel >= CMB_STUB_WARN_LOG) \
+ pr_warn(fmt, ##arg); \
+} while (0)
+#define CMB_STUB_LOG_PR_DBG(fmt, arg...) \
+do { \
+ if (gCmbStubLogLevel >= CMB_STUB_DBG_LOG) \
+ pr_info(fmt, ##arg); \
+} while (0)
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "wmt_detect.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
+********************************************************************************
+*/
+
+int gConnectivityChipId = -1;
+
+/*
+* current used uart port name, default is "ttyMT2",
+* will be changed when wmt driver init
+*/
+char *wmt_uart_port_desc = "ttyMT2";
+EXPORT_SYMBOL(wmt_uart_port_desc);
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data);
+static void mtk_wcn_cmb_sdio_enable_eirq(void);
+static void mtk_wcn_cmb_sdio_disable_eirq(void);
+static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data);
+
+struct sdio_ops mt_sdio_ops[4] = {
+ {NULL, NULL, NULL, NULL},
+ {NULL, NULL, NULL, NULL},
+ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq,
+ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm},
+ {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq,
+ mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}
+};
+#endif
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb;
+static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb;
+static wmt_thermal_query_cb cmb_stub_thermal_ctrl_cb;
+static wmt_trigger_assert_cb cmb_stub_trigger_assert_cb;
+static enum CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0;
+static wmt_deep_idle_ctrl_cb cmb_stub_deep_idle_ctrl_cb;
+static wmt_func_do_reset cmb_stub_do_reset_cb;
+static wmt_clock_fail_dump_cb cmb_stub_clock_fail_dump_cb;
+/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X.
+ * This is used for ALPS backward compatible ONLY!!! Remove this table, related
+ * functions, and type definition after modifying other kernel built-in modules,
+ * such as AUDIO. [FixMe][GeorgeKuo]
+ */
+#if 0
+static enum CMB_STUB_AIF_X audio2aif[] = {
+ [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0,
+ [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1,
+ [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2,
+ [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3,
+};
+#endif
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler;
+static atomic_t sdio_claim_irq_enable_flag;
+static atomic_t irq_enable_flag;
+static pm_callback_t mtk_wcn_cmb_sdio_pm_cb;
+static void *mtk_wcn_cmb_sdio_pm_data;
+static void *mtk_wcn_cmb_sdio_eirq_data;
+
+static u32 wifi_irq = 0xffffffff;
+#endif
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+#ifndef MTK_WCN_REMOVE_KERNEL_MODULE
+static int _mtk_wcn_cmb_stub_query_ctrl(void);
+static int _mtk_wcn_cmb_stub_trigger_assert(void);
+static void _mtk_wcn_cmb_stub_clock_fail_dump(void);
+#endif /* MTK_WCN_REMOVE_KERNEL_MODULE */
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+/*!
+ * \brief A registration function for WMT-PLAT to register itself to CMB-STUB.
+ *
+ * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register
+ * itself and related callback functions when driver being loaded into kernel.
+ *
+ * \param p_stub_cb a pointer carrying CMB_STUB_CB information
+ *
+ * \retval 0 operation success
+ * \retval -1 invalid parameters
+ */
+int mtk_wcn_cmb_stub_reg(struct _CMB_STUB_CB_ *p_stub_cb)
+{
+#ifndef MTK_WCN_REMOVE_KERNEL_MODULE
+ struct wmt_platform_bridge pbridge;
+
+ memset(&pbridge, 0, sizeof(struct wmt_platform_bridge));
+#endif
+
+ if ((!p_stub_cb)
+ || (p_stub_cb->size != sizeof(struct _CMB_STUB_CB_))) {
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n",
+ p_stub_cb, (p_stub_cb) ? p_stub_cb->size : 0);
+ return -1;
+ }
+
+ CMB_STUB_LOG_PR_DBG("[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n",
+ p_stub_cb, p_stub_cb->size);
+
+ cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb;
+ cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb;
+ cmb_stub_thermal_ctrl_cb = p_stub_cb->thermal_query_cb;
+ cmb_stub_trigger_assert_cb = p_stub_cb->trigger_assert_cb;
+ cmb_stub_deep_idle_ctrl_cb = p_stub_cb->deep_idle_ctrl_cb;
+ cmb_stub_do_reset_cb = p_stub_cb->wmt_do_reset_cb;
+ cmb_stub_clock_fail_dump_cb = p_stub_cb->clock_fail_dump_cb;
+
+#ifndef MTK_WCN_REMOVE_KERNEL_MODULE
+ pbridge.thermal_query_cb = _mtk_wcn_cmb_stub_query_ctrl;
+ pbridge.trigger_assert_cb = _mtk_wcn_cmb_stub_trigger_assert;
+ pbridge.clock_fail_dump_cb = _mtk_wcn_cmb_stub_clock_fail_dump;
+ wmt_export_platform_bridge_register(&pbridge);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg);
+/*!
+ * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB.
+ *
+ * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to
+ * unregister itself and clear callback function references.
+ *
+ * \retval 0 operation success
+ */
+int mtk_wcn_cmb_stub_unreg(void)
+{
+#ifndef MTK_WCN_REMOVE_KERNEL_MODULE
+ wmt_export_platform_bridge_unregister();
+#endif
+
+ cmb_stub_aif_ctrl_cb = NULL;
+ cmb_stub_func_ctrl_cb = NULL;
+ cmb_stub_thermal_ctrl_cb = NULL;
+ cmb_stub_deep_idle_ctrl_cb = NULL;
+ cmb_stub_do_reset_cb = NULL;
+ cmb_stub_clock_fail_dump_cb = NULL;
+ CMB_STUB_LOG_PR_INFO("[cmb_stub] unregistered\n"); /* KERN_DEBUG */
+
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg);
+
+/* stub functions for kernel to control audio path pin mux */
+int mtk_wcn_cmb_stub_aif_ctrl(enum CMB_STUB_AIF_X state, enum CMB_STUB_AIF_CTRL ctrl)
+{
+ int ret;
+
+ if ((state >= CMB_STUB_AIF_MAX)
+ || (ctrl >= CMB_STUB_AIF_CTRL_MAX)) {
+
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n",
+ state, ctrl);
+ return -1;
+ }
+
+ /* avoid the early interrupt before we register the eirq_handler */
+ if (cmb_stub_aif_ctrl_cb) {
+ ret = (*cmb_stub_aif_ctrl_cb) (state, ctrl);
+ CMB_STUB_LOG_PR_INFO("aif state(%d->%d) ctrl(%d) ret(%d)\n",
+ cmb_stub_aif_stat, state, ctrl, ret); /* KERN_DEBUG */
+
+ cmb_stub_aif_stat = state;
+ } else {
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] aif_ctrl_cb null\n");
+ ret = -2;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl);
+
+/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X
+ * for ALPS backward compatible ONLY!!! Remove this table, related functions,
+ * and type definition after modifying other kernel built-in modules, such as
+ * AUDIO. [FixMe][GeorgeKuo]
+ */
+
+void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on)
+{
+ if (cmb_stub_func_ctrl_cb)
+ (*cmb_stub_func_ctrl_cb) (type, on);
+ else
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] func_ctrl_cb null\n");
+}
+EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl);
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+int mtk_wcn_cmb_stub_query_ctrl(void)
+#else
+static int _mtk_wcn_cmb_stub_query_ctrl(void)
+#endif
+{
+ signed long temp = 0;
+
+ if (cmb_stub_thermal_ctrl_cb)
+ temp = (*cmb_stub_thermal_ctrl_cb) ();
+ else
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] thermal_ctrl_cb null\n");
+
+ return temp;
+}
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+int mtk_wcn_cmb_stub_trigger_assert(void)
+#else
+static int _mtk_wcn_cmb_stub_trigger_assert(void)
+#endif
+{
+ int ret = 0;
+
+ if (cmb_stub_trigger_assert_cb)
+ ret = (*cmb_stub_trigger_assert_cb) ();
+ else
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] trigger_assert_cb null\n");
+
+ return ret;
+}
+
+#ifndef MTK_WCN_REMOVE_KERNEL_MODULE
+void _mtk_wcn_cmb_stub_clock_fail_dump(void)
+{
+ if (cmb_stub_clock_fail_dump_cb)
+ (*cmb_stub_clock_fail_dump_cb) ();
+ else
+ CMB_STUB_LOG_PR_WARN("[cmb_stub] clock_fail_dump_cb null\n");
+}
+#endif
+
+/*platform-related APIs*/
+/* void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); */
+/* void set_device_working_ability(UINT32 clockId, MT6573_STATE state); */
+
+static int _mt_combo_plt_do_deep_idle(enum COMBO_IF src, int enter)
+{
+ int ret = -1;
+
+#if 0
+ if (src != COMBO_IF_UART && src != COMBO_IF_MSDC && src != COMBO_IF_BTIF) {
+ CMB_STUB_LOG_PR_WARN("src = %d is error\n", src);
+ return ret;
+ }
+ if (src >= 0 && src < COMBO_IF_MAX)
+ CMB_STUB_LOG_PR_INFO("src = %s, to enter deep idle? %d\n",
+ combo_if_name[src], enter);
+#endif
+ /*
+ * TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI
+ * to decide if the msdc will enter deep idle safely
+ */
+
+ switch (src) {
+ case COMBO_IF_UART:
+ if (enter == 0) {
+ /* clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */
+ /* disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+#if 0
+ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 0);
+ if (ret < 0)
+ CMB_STUB_LOG_PR_WARN("%s exit deepidle failed",
+ wmt_uart_port_desc);
+#endif
+#endif
+ } else {
+ /* set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */
+ /* enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+#if 0
+ ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 1);
+ if (ret < 0)
+ CMB_STUB_LOG_PR_WARN("%s enter deepidle failed",
+ wmt_uart_port_desc);
+#endif
+#endif
+ }
+ ret = 0;
+ break;
+
+ case COMBO_IF_MSDC:
+ if (enter == 0) {
+ /* for common sdio hif */
+ /* clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */
+ } else {
+ /* for common sdio hif */
+ /* set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */
+ }
+ ret = 0;
+ break;
+
+ case COMBO_IF_BTIF:
+ if (cmb_stub_deep_idle_ctrl_cb)
+ ret = (*cmb_stub_deep_idle_ctrl_cb) (enter);
+ else
+ CMB_STUB_LOG_PR_WARN("NULL function pointer\n");
+
+ if (ret)
+ CMB_STUB_LOG_PR_WARN("%s deep idle fail(%d)\n",
+ enter == 1 ? "enter" : "exit", ret);
+ else
+ CMB_STUB_LOG_PR_DBG("%s deep idle ok(%d)\n",
+ enter == 1 ? "enter" : "exit", ret);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int mt_combo_plt_enter_deep_idle(enum COMBO_IF src)
+{
+ /* return 0; */
+ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */
+ return _mt_combo_plt_do_deep_idle(src, 1);
+}
+EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle);
+
+int mt_combo_plt_exit_deep_idle(enum COMBO_IF src)
+{
+ /* return 0; */
+ /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */
+ return _mt_combo_plt_do_deep_idle(src, 0);
+}
+EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle);
+
+int mtk_wcn_wmt_chipid_query(void)
+{
+ CMB_STUB_LOG_PR_INFO("query current consys chipid (0x%x)\n",
+ gConnectivityChipId);
+ return gConnectivityChipId;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query);
+
+void mtk_wcn_wmt_set_chipid(int chipid)
+{
+ CMB_STUB_LOG_PR_INFO("set current consys chipid (0x%x)\n", chipid);
+ gConnectivityChipId = chipid;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_set_chipid);
+
+int mtk_wcn_cmb_stub_do_reset(unsigned int type)
+{
+ if (cmb_stub_do_reset_cb)
+ return (*cmb_stub_do_reset_cb) (type);
+ else
+ return -1;
+}
+EXPORT_SYMBOL(mtk_wcn_cmb_stub_do_reset);
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+static void mtk_wcn_cmb_sdio_enable_eirq(void)
+{
+ if (atomic_read(&irq_enable_flag))
+ CMB_STUB_LOG_PR_DBG("wifi eint has been enabled\n");
+ else {
+ atomic_set(&irq_enable_flag, 1);
+ if (wifi_irq != 0xffffffff) {
+ enable_irq(wifi_irq);
+ CMB_STUB_LOG_PR_DBG(" enable WIFI EINT irq %d !!\n",
+ wifi_irq);
+ }
+ }
+}
+
+static void mtk_wcn_cmb_sdio_disable_eirq(void)
+{
+ if (!atomic_read(&irq_enable_flag))
+ CMB_STUB_LOG_PR_DBG("wifi eint has been disabled!\n");
+ else {
+ if (wifi_irq != 0xffffffff) {
+ disable_irq_nosync(wifi_irq);
+ CMB_STUB_LOG_PR_DBG("disable WIFI EINT irq %d !!\n",
+ wifi_irq);
+ }
+ atomic_set(&irq_enable_flag, 0);
+ }
+}
+
+irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data)
+{
+ if ((mtk_wcn_cmb_sdio_eirq_handler != NULL) && (atomic_read(&sdio_claim_irq_enable_flag) != 0))
+ mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data);
+ return IRQ_HANDLED;
+}
+
+static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data)
+{
+ struct device_node *node;
+ int ret = -EINVAL;
+#if 0
+ unsigned int gpio_wifi_eint_pin;
+#endif
+
+ CMB_STUB_LOG_PR_INFO("enter %s\n", __func__);
+ mtk_wcn_sdio_irq_flag_set(0);
+ atomic_set(&irq_enable_flag, 1);
+ mtk_wcn_cmb_sdio_eirq_data = data;
+ mtk_wcn_cmb_sdio_eirq_handler = irq_handler;
+
+ node = (struct device_node *)of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo");
+ if (node) {
+#if 0
+ gpio_wifi_eint_pin = of_get_gpio(node, 5);
+ CMB_STUB_LOG_PR_INFO("WIFI EINT pin %d !!\n",
+ gpio_wifi_eint_pin);
+ wifi_irq = gpio_to_irq(gpio_wifi_eint_pin);
+#else
+ wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */
+#endif
+#if 1
+ ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW,
+ "WIFI-eint", NULL);
+ CMB_STUB_LOG_PR_DBG("WIFI EINT irq %d !!\n", wifi_irq);
+#endif
+
+ if (ret)
+ CMB_STUB_LOG_PR_WARN("EINT IRQ LINE NOT AVAILABLE!!\n");
+ else
+ mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/
+ } else
+ CMB_STUB_LOG_PR_WARN("[%s] can't find device node\n", __func__);
+
+ CMB_STUB_LOG_PR_INFO("exit %s\n", __func__);
+}
+
+static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data)
+{
+ CMB_STUB_LOG_PR_DBG("mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n",
+ pm_cb, data);
+ /* register pm change callback */
+ mtk_wcn_cmb_sdio_pm_cb = pm_cb;
+ mtk_wcn_cmb_sdio_pm_data = data;
+}
+#endif /* MTK_WCN_REMOVE_KERNEL_MODULE */
+
+static void mtk_wcn_cmb_sdio_on(int sdio_port_num)
+{
+ pm_message_t state = {.event = PM_EVENT_USER_RESUME };
+
+ CMB_STUB_LOG_PR_INFO("mtk_wcn_cmb_sdio_on (%d)\n", sdio_port_num);
+
+ /* 1. disable sdio eirq */
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+ mtk_wcn_cmb_sdio_disable_eirq();
+#else
+ wmt_export_mtk_wcn_cmb_sdio_disable_eirq();
+#endif
+
+ /* 2. call sd callback */
+ if (mtk_wcn_cmb_sdio_pm_cb) {
+ /* pr_warn("mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p)\n",
+ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
+ */
+ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
+ } else
+ CMB_STUB_LOG_PR_WARN("mtk_wcn_cmb_sdio_on no sd callback!!\n");
+}
+
+static void mtk_wcn_cmb_sdio_off(int sdio_port_num)
+{
+ pm_message_t state = {.event = PM_EVENT_USER_SUSPEND };
+
+ CMB_STUB_LOG_PR_INFO("mtk_wcn_cmb_sdio_off (%d)\n", sdio_port_num);
+
+ /* 1. call sd callback */
+ if (mtk_wcn_cmb_sdio_pm_cb) {
+ /* pr_warn("mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p)\n",
+ * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
+ */
+ mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
+ } else
+ CMB_STUB_LOG_PR_WARN("mtk_wcn_cmb_sdio_off no sd callback!!\n");
+
+ /* 2. disable sdio eirq */
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+ mtk_wcn_cmb_sdio_disable_eirq();
+#else
+ wmt_export_mtk_wcn_cmb_sdio_disable_eirq();
+#endif
+}
+
+int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on)
+{
+ CMB_STUB_LOG_PR_DBG("mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n",
+ sdio_port_num, on);
+ if (on) {
+#if 1
+ CMB_STUB_LOG_PR_DBG("board_sdio_ctrl force off before on\n");
+ mtk_wcn_cmb_sdio_off(sdio_port_num);
+#else
+ CMB_STUB_LOG_PR_WARN("skip sdio off before on\n");
+#endif
+ /* off -> on */
+ mtk_wcn_cmb_sdio_on(sdio_port_num);
+ if (wifi_irq != 0xffffffff)
+ irq_set_irq_wake(wifi_irq, 1);
+ else
+ CMB_STUB_LOG_PR_WARN("wifi_irq is not available\n");
+ } else {
+ if (wifi_irq != 0xffffffff)
+ irq_set_irq_wake(wifi_irq, 0);
+ else
+ CMB_STUB_LOG_PR_WARN("wifi_irq is not available\n");
+ /* on -> off */
+ mtk_wcn_cmb_sdio_off(sdio_port_num);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(board_sdio_ctrl);
+
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+int mtk_wcn_sdio_irq_flag_set(int flag)
+{
+ if (flag != 0)
+ atomic_set(&sdio_claim_irq_enable_flag, 1);
+ else
+ atomic_set(&sdio_claim_irq_enable_flag, 0);
+
+ CMB_STUB_LOG_PR_DBG("sdio_claim_irq_enable_flag:%d\n",
+ atomic_read(&sdio_claim_irq_enable_flag));
+
+ return atomic_read(&sdio_claim_irq_enable_flag);
+}
+EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c
new file mode 100644
index 0000000000000000000000000000000000000000..42dbafecd265d0cca0cf1741c00cc0d462938d62
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c
@@ -0,0 +1,249 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[SDIO-DETECT]"
+
+#include "wmt_detect.h"
+
+unsigned int gComboChipId = -1;
+struct sdio_func *g_func;
+unsigned int gDrvRegistered;
+
+MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = {
+ /* MT6620 *//* Not an SDIO standard class device */
+ {{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620}, /* SDIO1:FUNC1:WIFI */
+ {{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620}, /* SDIO2:FUNC1:BT+FM+GPS */
+ {{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
+
+ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628},
+
+ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630},
+
+ /* MT6632 *//* SDIO1: Wi-Fi */
+ {{SDIO_DEVICE(0x037A, 0x6602)}, 0x6632},
+
+ /* MT6632 *//* SDIO2: BGF */
+ {{SDIO_DEVICE(0x037A, 0x6632)}, 0x6632},
+
+};
+
+/* Supported SDIO device table */
+static const struct sdio_device_id mtk_sdio_id_tbl[] = {
+ /* MT6618 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */
+ {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */
+ {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */
+
+ /* MT6619 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */
+
+ /* MT6620 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */
+ {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */
+ {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
+
+ /* MT5921 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x5921)},
+
+ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6628)},
+
+ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6630)},
+
+ /* MT6632 *//* SDIO1: Wi-Fi */
+ {SDIO_DEVICE(0x037A, 0x6602)},
+
+ /* MT6632 *//* SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6632)},
+ { /* end: all zeroes */ },
+};
+
+static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id);
+
+static void sdio_detect_remove(struct sdio_func *func);
+
+static struct sdio_driver mtk_sdio_client_drv = {
+ .name = "mtk_sdio_client", /* MTK SDIO Client Driver */
+ .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */
+ .probe = sdio_detect_probe,
+ .remove = sdio_detect_remove,
+};
+
+static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id);
+
+int hif_sdio_is_chipid_valid(int chipId)
+{
+ int index = -1;
+
+ int left = 0;
+ int middle = 0;
+ int right = ARRAY_SIZE(gChipInfoArray) - 1;
+
+ if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId))
+ return index;
+
+ middle = (left + right) / 2;
+
+ while (left <= right) {
+ if (chipId > gChipInfoArray[middle].chipId) {
+ left = middle + 1;
+ } else if (chipId < gChipInfoArray[middle].chipId) {
+ right = middle - 1;
+ } else {
+ index = middle;
+ break;
+ }
+ middle = (left + right) / 2;
+ }
+
+ if (index < 0)
+ WMT_DETECT_PR_ERR("no supported chipid found\n");
+ else
+ WMT_DETECT_PR_INFO("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId);
+
+ return index;
+}
+
+int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id)
+{
+ int maxIndex = ARRAY_SIZE(gChipInfoArray);
+ int index = 0;
+ struct sdio_device_id *localId = NULL;
+ int chipId = -1;
+
+ for (index = 0; index < maxIndex; index++) {
+ localId = &(gChipInfoArray[index].deviceId);
+ if ((localId->vendor == id->vendor) && (localId->device == id->device)) {
+ chipId = gChipInfoArray[index].chipId;
+ WMT_DETECT_PR_INFO
+ ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index,
+ localId->vendor, localId->device, chipId);
+ mtk_wcn_wmt_set_chipid(chipId);
+ gComboChipId = chipId;
+ break;
+ }
+ }
+ if (chipId < 0) {
+ WMT_DETECT_PR_ERR("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor,
+ id->device);
+ }
+
+ return chipId;
+}
+
+int sdio_detect_query_chipid(int waitFlag)
+{
+ unsigned int timeSlotMs = 200;
+ unsigned int maxTimeSlot = 30;
+ unsigned int counter = 0;
+ /* gComboChipId = 0x6628; */
+ if (waitFlag == 0)
+ return gComboChipId;
+ if (hif_sdio_is_chipid_valid(gComboChipId) >= 0)
+ return gComboChipId;
+
+ while (counter < maxTimeSlot) {
+ if (hif_sdio_is_chipid_valid(gComboChipId) >= 0)
+ break;
+ msleep(timeSlotMs);
+ counter++;
+ }
+
+ return gComboChipId;
+}
+
+int sdio_detect_do_autok(int chipId)
+{
+ int i_ret = 0;
+
+ WMT_DETECT_PR_INFO("autok was move to sdio driver\n");
+ return i_ret;
+}
+
+/*!
+ * \brief hif_sdio probe function
+ *
+ * hif_sdio probe function called by mmc driver when any matched SDIO function
+ * is detected by it.
+ *
+ * \param func
+ * \param id
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int chipId = 0;
+
+ WMT_DETECT_PR_INFO("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num);
+ chipId = hif_sdio_match_chipid_by_dev_id(id);
+
+ if ((chipId == 0x6630 || chipId == 0x6632) && (func->num == 1)) {
+ int ret = 0;
+
+ g_func = func;
+ WMT_DETECT_PR_INFO("autok function detected, func:0x%p\n", g_func);
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ sdio_release_host(func);
+ if (ret)
+ WMT_DETECT_PR_ERR("sdio_enable_func failed!\n");
+ }
+
+ return 0;
+}
+
+static void sdio_detect_remove(struct sdio_func *func)
+{
+ if (g_func == func) {
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ g_func = NULL;
+ }
+ WMT_DETECT_PR_INFO("do sdio remove\n");
+}
+
+int sdio_detect_init(void)
+{
+ int ret = 0;
+ /* register to mmc driver */
+ if (gDrvRegistered == 0) {
+ ret = sdio_register_driver(&mtk_sdio_client_drv);
+ if (ret == 0)
+ gDrvRegistered = 1;
+ }
+ WMT_DETECT_PR_INFO("sdio_register_driver() ret=%d\n", ret);
+ return ret;
+}
+
+int sdio_detect_exit(void)
+{
+ g_func = NULL;
+ /* unregister to mmc driver */
+ if (gDrvRegistered == 1) {
+ sdio_unregister_driver(&mtk_sdio_client_drv);
+ gDrvRegistered = 0;
+ }
+ WMT_DETECT_PR_INFO("sdio_unregister_driver\n");
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h
new file mode 100644
index 0000000000000000000000000000000000000000..274261d6075d1c04c02c77aeb89cfe0da6ff60b7
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h
@@ -0,0 +1,36 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _SDIO_DETECT_H_
+#define _SDIO_DETECT_H_
+
+#include
+#include
+#include
+#include
+#include
+
+typedef struct _MTK_WCN_HIF_SDIO_CHIP_INFO_ {
+ struct sdio_device_id deviceId;
+ unsigned int chipId;
+} MTK_WCN_HIF_SDIO_CHIP_INFO, *P_MTK_WCN_HIF_SDIO_CHIP_INFO;
+
+extern int sdio_detect_exit(void);
+extern int sdio_detect_init(void);
+extern int sdio_detect_query_chipid(int waitFlag);
+extern int hif_sdio_is_chipid_valid(int chipId);
+
+extern int sdio_detect_do_autok(int chipId);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c
new file mode 100644
index 0000000000000000000000000000000000000000..ade16a12be1c8f772ba6ccb999c6d4d986a1fe56
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c
@@ -0,0 +1,407 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#include
+#include
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-DETECT]"
+
+#include "wmt_detect.h"
+#include "wmt_gpio.h"
+#include "wmt_dev.h"
+
+#if MTK_WCN_REMOVE_KO
+#include "conn_drv_init.h"
+#endif
+#ifdef CONFIG_COMPAT
+#include
+#endif
+
+#define WMT_DETECT_MAJOR 154
+#define WMT_DETECT_DEV_NUM 1
+#define WMT_DETECT_DRVIER_NAME "mtk_wcn_detect"
+#define WMT_DETECT_DEVICE_NAME "wmtdetect"
+
+struct class *pDetectClass;
+struct device *pDetectDev;
+static int gWmtDetectMajor = WMT_DETECT_MAJOR;
+static struct cdev gWmtDetectCdev;
+int gWmtDetectDbgLvl = WMT_DETECT_LOG_INFO;
+static ENUM_WMT_CHIP_TYPE g_chip_type = WMT_CHIP_TYPE_INVALID;
+
+static int wmt_detect_open(struct inode *inode, struct file *file)
+{
+ WMT_DETECT_PR_INFO("open major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+
+ return 0;
+}
+
+static int wmt_detect_close(struct inode *inode, struct file *file)
+{
+ WMT_DETECT_PR_INFO("close major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
+
+ return 0;
+}
+
+static ssize_t wmt_detect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ WMT_DETECT_PR_INFO(" ++\n");
+ WMT_DETECT_PR_INFO(" --\n");
+
+ return 0;
+}
+
+ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ WMT_DETECT_PR_INFO(" ++\n");
+ WMT_DETECT_PR_INFO(" --\n");
+
+ return 0;
+}
+
+static long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ WMT_DETECT_PR_INFO("cmd (%d),arg(%ld)\n", cmd, arg);
+
+ switch (cmd) {
+ case COMBO_IOCTL_GET_CHIP_ID:
+ /*just get chipid from sdio-detect module */
+ /*check if external combo chip exists or not */
+ /*if yes, just return combo chip id */
+ /*if no, get soc chipid */
+ retval = mtk_wcn_wmt_chipid_query();
+ break;
+
+ case COMBO_IOCTL_SET_CHIP_ID:
+ WMT_DETECT_PR_INFO("chipid(%ld)\n", arg);
+ mtk_wcn_wmt_set_chipid(arg);
+ wmt_detect_set_chip_type(arg);
+ break;
+
+ case COMBO_IOCTL_EXT_CHIP_PWR_ON:
+ retval = wmt_detect_ext_chip_pwr_on();
+ break;
+
+ case COMBO_IOCTL_EXT_CHIP_DETECT:
+ retval = wmt_detect_ext_chip_detect();
+ break;
+
+ case COMBO_IOCTL_EXT_CHIP_PWR_OFF:
+ retval = wmt_detect_ext_chip_pwr_off();
+ break;
+
+ case COMBO_IOCTL_DO_SDIO_AUDOK:
+ retval = sdio_detect_do_autok(arg);
+ break;
+
+ case COMBO_IOCTL_GET_SOC_CHIP_ID:
+ retval = wmt_plat_get_soc_chipid();
+ /*get soc chipid by HAL interface */
+ break;
+
+ case COMBO_IOCTL_GET_ADIE_CHIP_ID:
+ retval = wmt_plat_get_adie_chipid();
+ break;
+
+ case COMBO_IOCTL_MODULE_CLEANUP:
+ retval = sdio_detect_exit();
+ break;
+
+ case COMBO_IOCTL_DO_MODULE_INIT:
+#if (MTK_WCN_REMOVE_KO)
+ /*deinit SDIO-DETECT module */
+ WMT_DETECT_PR_INFO("built-in mode\n");
+ retval = do_connectivity_driver_init(arg);
+#else
+ WMT_DETECT_PR_INFO("kernel object mode\n");
+ retval = mtk_wcn_common_drv_init();
+#endif
+ break;
+
+ default:
+ WMT_DETECT_PR_WARN("unknown cmd (%d)\n", cmd);
+ retval = 0;
+ break;
+ }
+ return retval;
+}
+#ifdef CONFIG_COMPAT
+static long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ long ret;
+
+ WMT_DETECT_PR_INFO("cmd (%d)\n", cmd);
+ ret = wmt_detect_unlocked_ioctl(filp, cmd, arg);
+ return ret;
+}
+#endif
+const struct file_operations gWmtDetectFops = {
+ .open = wmt_detect_open,
+ .release = wmt_detect_close,
+ .read = wmt_detect_read,
+ .write = wmt_detect_write,
+ .unlocked_ioctl = wmt_detect_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = WMT_compat_detect_ioctl,
+#endif
+};
+
+int wmt_detect_ext_chip_pwr_on(void)
+{
+ /*pre power on external chip */
+ /* wmt_plat_pwr_ctrl(FUNC_ON); */
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ WMT_DETECT_PR_INFO("++\n");
+ if (wmt_detect_chip_pwr_ctrl(1) != 0)
+ return -2;
+ if (wmt_detect_sdio_pwr_ctrl(1) != 0)
+ return -3;
+ return 0;
+#else
+ WMT_DETECT_PR_INFO("combo chip is not supported\n");
+ return -1;
+#endif
+}
+
+int wmt_detect_ext_chip_pwr_off(void)
+{
+ /*pre power off external chip */
+ /* wmt_plat_pwr_ctrl(FUNC_OFF); */
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ WMT_DETECT_PR_INFO("--\n");
+ wmt_detect_sdio_pwr_ctrl(0);
+ return wmt_detect_chip_pwr_ctrl(0);
+#else
+ WMT_DETECT_PR_INFO("combo chip is not supported\n");
+ return 0;
+#endif
+}
+
+int wmt_detect_ext_chip_detect(void)
+{
+ int iRet = -1;
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ unsigned int chipId = -1;
+ /*if there is no external combo chip, return -1 */
+ int bgfEintStatus = -1;
+
+ WMT_DETECT_PR_INFO("++\n");
+ /*wait for a stable time */
+ msleep(20);
+
+ /*read BGF_EINT_PIN status */
+ bgfEintStatus = wmt_detect_read_ext_cmb_status();
+
+ if (bgfEintStatus == 0) {
+ /*external chip does not exist */
+ WMT_DETECT_PR_INFO("external combo chip not detected\n");
+ iRet = -2;
+ } else if (bgfEintStatus == 1) {
+ /*combo chip exists */
+ WMT_DETECT_PR_INFO("external combo chip detected\n");
+
+ /*detect chipid by sdio_detect module */
+ chipId = sdio_detect_query_chipid(1);
+ if (hif_sdio_is_chipid_valid(chipId) >= 0)
+ WMT_DETECT_PR_INFO("valid external combo chip id (0x%x)\n", chipId);
+ else
+ WMT_DETECT_PR_INFO("invalid external combo chip id (0x%x)\n", chipId);
+ iRet = 0;
+ } else {
+ /*Error exists */
+ WMT_DETECT_PR_ERR("error happens when detecting combo chip\n");
+ iRet = -3;
+ }
+ WMT_DETECT_PR_INFO("--\n");
+ /*return 0 */
+#endif
+ return iRet;
+ /*todo: if there is external combo chip, power on chip return 0 */
+}
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+static int wmt_detect_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ WMT_DETECT_PR_INFO("platform name: %s\n", pdev->name);
+ ret = wmt_gpio_init(pdev);
+ if (-1 == ret)
+ WMT_DETECT_PR_ERR("gpio init fail ret:%d\n", ret);
+ return ret;
+}
+
+static int wmt_detect_remove(struct platform_device *pdev)
+{
+ wmt_gpio_deinit();
+ return 0;
+}
+#endif
+
+int wmt_detect_set_chip_type(int chip_id)
+{
+ switch (chip_id) {
+ case 0x6620:
+ case 0x6628:
+ case 0x6630:
+ case 0x6632:
+ g_chip_type = WMT_CHIP_TYPE_COMBO;
+ break;
+ case -1:
+ break;
+ default:
+ g_chip_type = WMT_CHIP_TYPE_SOC;
+ break;
+ }
+ return 0;
+}
+ENUM_WMT_CHIP_TYPE wmt_detect_get_chip_type(void)
+{
+ return g_chip_type;
+}
+
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+static const struct of_device_id wmt_detect_match[] = {
+ { .compatible = "mediatek,connectivity-combo", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wmt_detect_match);
+
+static struct platform_driver wmt_detect_driver = {
+ .probe = wmt_detect_probe,
+ .remove = wmt_detect_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mediatek,connectivity-combo",
+ .of_match_table = wmt_detect_match,
+ },
+};
+#endif
+
+/*module_platform_driver(wmt_detect_driver);*/
+static int wmt_detect_driver_init(void)
+{
+ dev_t devID = MKDEV(gWmtDetectMajor, 0);
+ int cdevErr = -1;
+ int ret = -1;
+
+ /*init SDIO-DETECT module */
+ sdio_detect_init();
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ ret = platform_driver_register(&wmt_detect_driver);
+ if (ret)
+ WMT_DETECT_PR_ERR("platform driver register fail ret:%d\n", ret);
+#endif
+
+ ret = register_chrdev_region(devID, WMT_DETECT_DEV_NUM, WMT_DETECT_DRVIER_NAME);
+ if (ret) {
+ WMT_DETECT_PR_ERR("fail to register chrdev\n");
+ goto err0;
+ }
+
+ cdev_init(&gWmtDetectCdev, &gWmtDetectFops);
+ gWmtDetectCdev.owner = THIS_MODULE;
+
+ cdevErr = cdev_add(&gWmtDetectCdev, devID, WMT_DETECT_DEV_NUM);
+ if (cdevErr) {
+ WMT_DETECT_PR_ERR("cdev_add() fails (%d)\n", cdevErr);
+ goto err1;
+ }
+
+ pDetectClass = class_create(THIS_MODULE, WMT_DETECT_DEVICE_NAME);
+ if (IS_ERR(pDetectClass)) {
+ WMT_DETECT_PR_ERR("class create fail, error code(%ld)\n", PTR_ERR(pDetectClass));
+ goto err1;
+ }
+
+ pDetectDev = device_create(pDetectClass, NULL, devID, NULL, WMT_DETECT_DEVICE_NAME);
+ if (IS_ERR(pDetectDev)) {
+ WMT_DETECT_PR_ERR("device create fail, error code(%ld)\n", PTR_ERR(pDetectDev));
+ goto err2;
+ }
+
+ WMT_DETECT_PR_INFO("driver(major %d) installed success\n", gWmtDetectMajor);
+
+ return 0;
+
+err2:
+
+ if (pDetectClass) {
+ class_destroy(pDetectClass);
+ pDetectClass = NULL;
+ }
+
+err1:
+
+ if (cdevErr == 0)
+ cdev_del(&gWmtDetectCdev);
+
+ if (ret == 0) {
+ unregister_chrdev_region(devID, WMT_DETECT_DEV_NUM);
+ gWmtDetectMajor = -1;
+ }
+
+err0:
+ sdio_detect_exit();
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ platform_driver_unregister(&wmt_detect_driver);
+#endif
+
+ return ret ? ret : -1;
+}
+
+static void wmt_detect_driver_exit(void)
+{
+ dev_t dev = MKDEV(gWmtDetectMajor, 0);
+
+ mtk_wcn_common_drv_exit();
+
+ if (pDetectDev) {
+ device_destroy(pDetectClass, dev);
+ pDetectDev = NULL;
+ }
+
+ if (pDetectClass) {
+ class_destroy(pDetectClass);
+ pDetectClass = NULL;
+ }
+
+ cdev_del(&gWmtDetectCdev);
+ unregister_chrdev_region(dev, WMT_DETECT_DEV_NUM);
+
+ sdio_detect_exit();
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ if (wmt_detect_driver.driver.p)
+ platform_driver_unregister(&wmt_detect_driver);
+#endif
+
+ WMT_DETECT_PR_INFO("done\n");
+}
+
+module_init(wmt_detect_driver_init);
+module_exit(wmt_detect_driver_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhiguo.Niu & Chaozhong.Liang @ MBJ/WCNSE/SS1");
+
+module_param(gWmtDetectMajor, uint, 0);
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6ca8857beab2bacac9dde90bd5f72821a300075
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h
@@ -0,0 +1,120 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _WMT_DETECT_H_
+#define _WMT_DETECT_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+#ifdef MTK_WCN_REMOVE_KERNEL_MODULE
+#define MTK_WCN_REMOVE_KO 1
+#else
+#define MTK_WCN_REMOVE_KO 0
+#endif
+
+#include "sdio_detect.h"
+#include "wmt_detect_pwr.h"
+#include
+
+#define WMT_DETECT_LOG_LOUD 4
+#define WMT_DETECT_LOG_DBG 3
+#define WMT_DETECT_LOG_INFO 2
+#define WMT_DETECT_LOG_WARN 1
+#define WMT_DETECT_LOG_ERR 0
+
+extern int gWmtDetectDbgLvl;
+
+#define WMT_DETECT_PR_LOUD(fmt, arg...) \
+do { \
+ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_LOUD) \
+ pr_info(DFT_TAG"[L]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_DETECT_PR_DBG(fmt, arg...) \
+do { \
+ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_DBG) \
+ pr_info(DFT_TAG"[D]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_DETECT_PR_INFO(fmt, arg...) \
+do { \
+ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_INFO) \
+ pr_info(DFT_TAG"[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_DETECT_PR_WARN(fmt, arg...) \
+do { \
+ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_WARN) \
+ pr_warn(DFT_TAG"[W]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+#define WMT_DETECT_PR_ERR(fmt, arg...) \
+do { \
+ if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_ERR) \
+ pr_err(DFT_TAG"[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+#define WMT_DETECT_IOC_MAGIC 'w'
+#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 0, int)
+#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_DETECT_IOC_MAGIC, 1, int)
+#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_DETECT_IOC_MAGIC, 2, int)
+#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 3, int)
+#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_DETECT_IOC_MAGIC, 4, int)
+#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_DETECT_IOC_MAGIC, 5, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_DETECT_IOC_MAGIC, 6, int)
+#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_DETECT_IOC_MAGIC, 7, int)
+#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_DETECT_IOC_MAGIC, 8, int)
+#define COMBO_IOCTL_GET_ADIE_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 9, int)
+
+typedef enum _ENUM_WMT_CHIP_TYPE_T {
+ WMT_CHIP_TYPE_COMBO,
+ WMT_CHIP_TYPE_SOC,
+ WMT_CHIP_TYPE_INVALID
+} ENUM_WMT_CHIP_TYPE;
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************/
+extern int wmt_detect_ext_chip_detect(void);
+extern int wmt_detect_ext_chip_pwr_on(void);
+extern int wmt_detect_ext_chip_pwr_off(void);
+
+extern unsigned int wmt_plat_get_soc_chipid(void);
+extern int wmt_plat_get_adie_chipid(void);
+
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver
+ *
+ * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2"
+ * @ enable - "1", enable deep idle; "0", disable deep idle
+ *
+ * Return 0 if success, else -1
+ */
+extern unsigned int mtk_uart_pdn_enable(char *port, int enable);
+#endif
+extern int wmt_detect_set_chip_type(int chip_id);
+extern ENUM_WMT_CHIP_TYPE wmt_detect_get_chip_type(void);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d26c2df4f21048be73c99be8fdceea6321d9119
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c
@@ -0,0 +1,259 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+/* ALPS header files */
+#include
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
+#ifndef CONFIG_RTC_DRV_MT6397
+#include
+#else
+#include
+#endif
+#endif
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-DETECT]"
+
+#include "wmt_detect.h"
+#include "wmt_gpio.h"
+
+#define INVALID_PIN_ID (0xFFFFFFFF)
+
+/*copied form WMT module*/
+static int wmt_detect_dump_pin_conf(void)
+{
+ WMT_DETECT_PR_DBG("[WMT-DETECT]=>dump wmt pin configuration start<=\n");
+
+ WMT_DETECT_PR_INFO("LDO(GPIO%d), PMU(GPIO%d), PMUV28(GPIO%d)\n",
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num);
+
+ WMT_DETECT_PR_INFO("RST(GPIO%d), BGF_EINT(GPIO%d), BGF_EINT_NUM(%d)\n",
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num,
+ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num));
+
+ WMT_DETECT_PR_INFO("WIFI_EINT(GPIO%d), WIFI_EINT_NUM(%d)\n",
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num,
+ gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num));
+
+ WMT_DETECT_PR_DBG("[WMT-PLAT]=>dump wmt pin configuration ends<=\n");
+
+ return 0;
+}
+
+int _wmt_detect_output_low(unsigned int id)
+{
+ if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 0);
+ WMT_DETECT_PR_INFO("WMT-DETECT: set GPIO%d to output %d\n",
+ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num-280,
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num));
+ }
+
+ return 0;
+}
+
+int _wmt_detect_output_high(unsigned int id)
+{
+ if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 1);
+ WMT_DETECT_PR_INFO("WMT-DETECT: set GPIO%d to output %d\n",
+ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num-280,
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num));
+ }
+
+ return 0;
+}
+
+int _wmt_detect_read_gpio_input(unsigned int id)
+{
+ int retval = 0;
+
+ if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) {
+ retval = gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num);
+ WMT_DETECT_PR_DBG("WMT-DETECT: get GPIO%d val%d\n",
+ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, retval);
+ } else
+ WMT_DETECT_PR_ERR("WMT-DETECT: GPIO%d invalid\n",
+ gpio_ctrl_info.gpio_ctrl_state[id].gpio_num);
+
+ return retval;
+}
+
+/*This power on sequence must support all combo chip's basic power on sequence
+ * 1. LDO control is a must, if external LDO exist
+ * 2. PMU control is a must
+ * 3. RST control is a must
+ * 4. WIFI_EINT pin control is a must, used for GPIO mode for EINT status checkup
+ * 5. RTC32k clock control is a must
+ *
+ */
+static int wmt_detect_chip_pwr_on(void)
+{
+ int retval = -1;
+
+ /*setting validiation check*/
+ if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num == INVALID_PIN_ID) ||
+ (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num == INVALID_PIN_ID)) {
+ WMT_DETECT_PR_ERR("WMT-DETECT: either PMU(%d) or WIFI_EINT(%d) is not set\n",
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num);
+
+ return retval;
+ }
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num == INVALID_PIN_ID) {
+ WMT_DETECT_PR_WARN("WMT-DETECT: RST(%d) is not set, if it`s not 6632 project, please check it\n",
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num);
+
+ }
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_COMBO_URXD_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ WMT_DETECT_PR_DBG("WMT-DETECT: GPIO_COMBO_URXD_PIN out 0\n");
+ _wmt_detect_output_low(GPIO_COMBO_URXD_PIN);
+
+ /*set LDO/PMU/RST to output 0, no pull*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID)
+ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN);
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]);
+ WMT_DETECT_PR_INFO("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n");
+ } else
+ WMT_DETECT_PR_ERR("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN);
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]);
+ WMT_DETECT_PR_INFO("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n");
+ } else
+ WMT_DETECT_PR_ERR("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+ _wmt_detect_output_low(GPIO_COMBO_RST_PIN);
+
+#if 0
+ _wmt_detect_output_high(GPIO_WIFI_EINT_PIN);
+#endif
+
+ /*pull high LDO*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID)
+ _wmt_detect_output_high(GPIO_COMBO_LDO_EN_PIN);
+ /*sleep for LDO stable time*/
+ msleep(MAX_LDO_STABLE_TIME);
+
+ /*export RTC clock, sleep for RTC stable time*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
+ rtc_gpio_enable_32k(RTC_GPIO_USER_GPS);
+#endif
+ msleep(MAX_RTC_STABLE_TIME);
+ /*PMU output low, RST output low, to make chip power off completely*/
+ /*always done*/
+ /*sleep for power off stable time*/
+ msleep(MAX_OFF_STABLE_TIME);
+ /*PMU output high, and sleep for reset stable time*/
+ _wmt_detect_output_high(GPIO_COMBO_PMU_EN_PIN);
+#ifdef CONFIG_MTK_COMBO_COMM_NPWR
+ if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != INVALID_PIN_ID) &&
+ (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != INVALID_PIN_ID)) {
+ msleep(20);
+ _wmt_detect_output_high(GPIO_PCM_DAISYNC_PIN);
+
+ msleep(20);
+ _wmt_detect_output_high(GPIO_COMBO_I2S_DAT_PIN);
+
+ msleep(20);
+ _wmt_detect_output_low(GPIO_COMBO_I2S_DAT_PIN);
+
+ msleep(20);
+ _wmt_detect_output_low(GPIO_PCM_DAISYNC_PIN);
+
+ msleep(20);
+ }
+#endif
+ msleep(MAX_RST_STABLE_TIME);
+ /*RST output high, and sleep for power on stable time */
+ _wmt_detect_output_high(GPIO_COMBO_RST_PIN);
+ msleep(MAX_ON_STABLE_TIME);
+ retval = 0;
+ return retval;
+}
+
+static int wmt_detect_chip_pwr_off(void)
+{
+
+ /*set RST pin to input low status*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID)
+ _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN);
+ /*set RST pin to input low status*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num != INVALID_PIN_ID)
+ _wmt_detect_output_low(GPIO_COMBO_RST_PIN);
+ /*set PMU pin to input low status*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num != INVALID_PIN_ID)
+ _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN);
+ return 0;
+}
+
+int wmt_detect_read_ext_cmb_status(void)
+{
+ int retval = 0;
+ /*read WIFI_EINT pin status*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num == INVALID_PIN_ID) {
+ retval = 0;
+ WMT_DETECT_PR_ERR("WMT-DETECT: no WIFI_EINT pin set\n");
+ } else {
+ retval = _wmt_detect_read_gpio_input(GPIO_WIFI_EINT_PIN);
+ WMT_DETECT_PR_INFO("WMT-DETECT: WIFI_EINT input status:%d\n", retval);
+ }
+ return retval;
+}
+
+int wmt_detect_chip_pwr_ctrl(int on)
+{
+ int retval = -1;
+
+ if (on == 0) {
+ /*power off combo chip */
+ retval = wmt_detect_chip_pwr_off();
+ } else {
+ wmt_detect_dump_pin_conf();
+ /*power on combo chip */
+ retval = wmt_detect_chip_pwr_on();
+ }
+ return retval;
+}
+
+int wmt_detect_sdio_pwr_ctrl(int on)
+{
+ int retval = -1;
+#ifdef MTK_WCN_COMBO_CHIP_SUPPORT
+ if (on == 0) {
+ /*power off SDIO slot */
+ retval = board_sdio_ctrl(1, 0);
+ } else {
+ /*power on SDIO slot */
+ retval = board_sdio_ctrl(1, 1);
+ }
+#else
+ WMT_DETECT_PR_WARN("WMT-DETECT: MTK_WCN_COMBO_CHIP_SUPPORT is not set\n");
+#endif
+ return retval;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h
new file mode 100644
index 0000000000000000000000000000000000000000..32e661520fd0d09ac92244c950258df291cf695e
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef __WMT_DETECT_PWR_H_
+#define __WMT_DETECT_PWR_H_
+
+#define MAX_RTC_STABLE_TIME 100
+#define MAX_LDO_STABLE_TIME 100
+#define MAX_RST_STABLE_TIME 30
+#define MAX_OFF_STABLE_TIME 10
+#define MAX_ON_STABLE_TIME 30
+
+extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on);
+extern int wmt_detect_chip_pwr_ctrl(int on);
+extern int wmt_detect_sdio_pwr_ctrl(int on);
+extern int wmt_detect_read_ext_cmb_status(void);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c
new file mode 100644
index 0000000000000000000000000000000000000000..55a483895f8faae045b2dd7d3f1d210d30bc6b0d
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c
@@ -0,0 +1,496 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#include "wmt_gpio.h"
+#if (LINUX_VERSION_CODE >> 8) == 0x40E
+#include
+#endif
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX] = {{"gpio_ldo_en_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_ldo_en_in_pulldown",
+ ""},
+ {"gpio_pmuv28_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_pmuv28_in_pulldown",
+ ""},
+ {"gpio_pmu_en_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_pmu_en_in_pulldown",
+ ""},
+ {"gpio_rst_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_rst_in_pulldown",
+ ""},
+ {"",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_bgf_eint_in_pull_dis",
+ "gpio_bgf_eint_in_pulldown",
+ "gpio_bgf_eint_in_pullup"},
+ {"",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_wifi_eint_in_pull_dis",
+ "",
+ "gpio_wifi_eint_in_pullup"},
+ {"",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "gpio_all_eint_in_pulldown",
+ "gpio_all_eint_in_pullup"},
+ {"gpio_urxd_uart_pull_dis",
+ "",
+ "",
+ "gpio_urxd_uart_out_low",
+ "",
+ "",
+ "",
+ "gpio_urxd_gpio_in_pull_dis",
+ "",
+ "gpio_urxd_gpio_in_pullup"},
+ {"gpio_utxd_uart_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_pcm_daiclk_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_pcm_daipcmin_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_pcm_daipcmout_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_pcm_daisync_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_i2s_ck_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_i2s_ws_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_i2s_dat_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_gps_sync_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"gpio_gps_lna_pull_dis",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""},
+ {"",
+ "",
+ "",
+ "",
+ "",
+ "gpio_chip_deep_sleep_in_pull_dis",
+ "",
+ "",
+ "",
+ ""},
+ {"",
+ "",
+ "gpio_chip_wake_up_pullup",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""}
+};
+
+const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX] = {"gpio_combo_ldo_en_pin",
+ "gpio_combo_pmuv28_en_pin",
+ "gpio_combo_pmu_en_pin",
+ "gpio_combo_rst_pin",
+ "gpio_combo_bgf_eint_pin",
+ "gpio_wifi_eint_pin",
+ "gpio_all_eint_pin",
+ "gpio_combo_urxd_pin",
+ "gpio_combo_utxd_pin",
+ "gpio_pcm_daiclk_pin",
+ "gpio_pcm_daipcmin_pin",
+ "gpio_pcm_daipcmout_pin",
+ "gpio_pcm_daisync_pin",
+ "gpio_combo_i2s_ck_pin",
+ "gpio_combo_i2s_ws_pin",
+ "gpio_combo_i2s_dat_pin",
+ "gpio_gps_sync_pin",
+ "gpio_gps_lna_pin",
+ "gpio_chip_deep_sleep_pin",
+ "gpio_chip_wake_up_pin"
+ };
+
+GPIO_CTRL_INFO gpio_ctrl_info;
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+int __weak mt_get_gpio_mode_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_pull_select_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_in_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_out_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_pull_enable_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_dir_base(unsigned long pin)
+{
+ return 0;
+}
+
+int __weak mt_get_gpio_ies_base(unsigned long pin)
+{
+ return 0;
+}
+
+INT32 wmt_gpio_init(struct platform_device *pdev)
+{
+ INT32 iret = 0;
+ UINT32 i, j;
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo");
+ if (!node) {
+ for (i = 0; i < GPIO_PIN_ID_MAX; i++)
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID;
+ pr_err("wmt_gpio:can't find device tree node!\n");
+ iret = -1;
+ goto err;
+ }
+
+ gpio_ctrl_info.pinctrl_info = devm_pinctrl_get(&pdev->dev);
+ if (gpio_ctrl_info.pinctrl_info) {
+ for (i = 0; i < GPIO_PIN_ID_MAX; i++) {
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = of_get_named_gpio(node,
+ gpio_pin_name[i], 0);
+ if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num < 0)
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID;
+ if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num != DEFAULT_PIN_ID) {
+ for (j = 0; j < GPIO_STATE_MAX; j++) {
+ if (strlen(gpio_state_name[i][j]) != 0) {
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] =
+ pinctrl_lookup_state(gpio_ctrl_info.pinctrl_info,
+ gpio_state_name[i][j]);
+ } else
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL;
+ }
+ } else {
+ for (j = 0; j < GPIO_STATE_MAX; j++)
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL;
+ }
+ }
+
+ pr_info("wmt_gpio: gpio init start!\n");
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_COMBO_URXD_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_COMBO_UTXD_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num != DEFAULT_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num,
+ 0);
+ pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN out to 0: %d!\n",
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num));
+ }
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num != DEFAULT_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num,
+ 0);
+ pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN out to 0: %d!\n",
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num));
+ }
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]);
+ } else
+ pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].
+ gpio_state[GPIO_PULL_DIS]);
+ } else
+ pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS fail, is NULL!\n");
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_state[GPIO_IN_DIS]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].
+ gpio_state[GPIO_IN_DIS]);
+ } else
+ pr_warn("wmt_gpio:it may not be 6632 project, GPIO_CHIP_DEEP_SLEEP_PIN no need config!\n");
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_state[GPIO_PULL_UP]) {
+ pinctrl_select_state(gpio_ctrl_info.pinctrl_info,
+ gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].
+ gpio_state[GPIO_PULL_UP]);
+ } else
+ pr_warn("wmt_gpio:it may not be 6632 project, GPIO_CHIP_WAKE_UP_PIN no need config!\n");
+
+ pr_info("wmt_gpio: gpio init done!\n");
+ } else {
+ pr_err("wmt_gpio:can't find pinctrl dev!\n");
+ iret = -1;
+ }
+
+#if (LINUX_VERSION_CODE >> 8) == 0x40E
+ KERNEL_mtk_wcn_cmb_sdio_request_eirq();
+#endif
+err:
+ return iret;
+}
+
+INT32 wmt_gpio_deinit(VOID)
+{
+ INT32 iret = 0;
+ UINT32 i;
+ UINT32 j;
+
+ for (i = 0; i < GPIO_PIN_ID_MAX; i++) {
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID;
+ if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num != DEFAULT_PIN_ID) {
+ for (j = 0; j < GPIO_STATE_MAX; j++) {
+ if (strlen(gpio_state_name[i][j]) != 0)
+ gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL;
+ }
+ }
+ }
+ if (gpio_ctrl_info.pinctrl_info) {
+ devm_pinctrl_put(gpio_ctrl_info.pinctrl_info);
+ gpio_ctrl_info.pinctrl_info = NULL;
+ }
+
+ return iret;
+}
+
+VOID _wmt_dump_gpio_regs(INT32 idx)
+{
+ ULONG idxl = (ULONG)idx;
+
+ pr_info("PIN: [MODE] [PULL_SEL] [DIN] [DOUT] [PULL EN] [DIR] [IES]\n");
+ pr_info("idx = %3d: %d %d %d %d %d %d %d\n",
+ idx, mt_get_gpio_mode_base(idxl),
+ mt_get_gpio_pull_select_base(idxl),
+ mt_get_gpio_in_base(idxl),
+ mt_get_gpio_out_base(idxl),
+ mt_get_gpio_pull_enable_base(idxl),
+ mt_get_gpio_dir_base(idxl),
+ mt_get_gpio_ies_base(idxl));
+}
+
+VOID _wmt_gpio_pre_regs(INT32 num, WMT_GPIO_STATE_INFO *gpio_state)
+{
+ gpio_state->gpio_num = num;
+ gpio_state->mode = mt_get_gpio_mode_base(num);
+ gpio_state->pull_sel = mt_get_gpio_pull_select_base(num);
+ gpio_state->in = mt_get_gpio_in_base(num);
+ gpio_state->out = mt_get_gpio_out_base(num);
+ gpio_state->pull_en = mt_get_gpio_pull_enable_base(num);
+ gpio_state->dir = mt_get_gpio_dir_base(num);
+ gpio_state->ies = mt_get_gpio_ies_base(num);
+
+}
+
+VOID _wmt_dump_gpio_pre_regs(WMT_GPIO_STATE_INFO gpio_state)
+{
+ pr_info("PIN: [MODE] [PULL_SEL] [DIN] [DOUT] [PULL EN] [DIR] [IES]\n");
+ pr_info("idx = %3d: %d %d %d %d %d %d %d\n",
+ gpio_state.gpio_num, gpio_state.mode,
+ gpio_state.pull_sel, gpio_state.in,
+ gpio_state.out, gpio_state.pull_en,
+ gpio_state.dir, gpio_state.ies);
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e42dba212a15ef16b6a2a4fec379e3100f60fec
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h
@@ -0,0 +1,127 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef _WMT_GPIO_H_
+#define _WMT_GPIO_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "osal.h"
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define DEFAULT_PIN_ID (0xffffffff)
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef enum _ENUM_GPIO_PIN_ID {
+ GPIO_COMBO_LDO_EN_PIN = 0,
+ GPIO_COMBO_PMUV28_EN_PIN,
+ GPIO_COMBO_PMU_EN_PIN,
+ GPIO_COMBO_RST_PIN,
+ GPIO_COMBO_BGF_EINT_PIN,
+ GPIO_WIFI_EINT_PIN,
+ GPIO_COMBO_ALL_EINT_PIN,
+ GPIO_COMBO_URXD_PIN,
+ GPIO_COMBO_UTXD_PIN,
+ GPIO_PCM_DAICLK_PIN,
+ GPIO_PCM_DAIPCMIN_PIN,
+ GPIO_PCM_DAIPCMOUT_PIN,
+ GPIO_PCM_DAISYNC_PIN,
+ GPIO_COMBO_I2S_CK_PIN,
+ GPIO_COMBO_I2S_WS_PIN,
+ GPIO_COMBO_I2S_DAT_PIN,
+ GPIO_GPS_SYNC_PIN,
+ GPIO_GPS_LNA_PIN,
+ GPIO_CHIP_DEEP_SLEEP_PIN,
+ GPIO_CHIP_WAKE_UP_PIN,
+ GPIO_PIN_ID_MAX
+} ENUM_GPIO_PIN_ID, *P_ENUM_GPIO_PIN_ID;
+
+typedef enum _ENUM_GPIO_STATE_ID {
+ GPIO_PULL_DIS = 0,
+ GPIO_PULL_DOWN,
+ GPIO_PULL_UP,
+ GPIO_OUT_LOW,
+ GPIO_OUT_HIGH,
+ GPIO_IN_DIS,
+ GPIO_IN_EN,
+ GPIO_IN_PULL_DIS,
+ GPIO_IN_PULLDOWN,
+ GPIO_IN_PULLUP,
+ GPIO_STATE_MAX,
+} ENUM_GPIO_STATE_ID, *P_ENUM_GPIO_STATE_ID;
+
+typedef struct _GPIO_CTRL_STATE {
+ INT32 gpio_num;
+ struct pinctrl_state *gpio_state[GPIO_STATE_MAX];
+} GPIO_CTRL_STATE, *P_GPIO_CTRL_STATE;
+
+typedef struct _WMT_GPIO_STATE_INFO {
+ INT32 gpio_num;
+ INT32 mode;
+ INT32 pull_sel;
+ INT32 in;
+ INT32 out;
+ INT32 pull_en;
+ INT32 dir;
+ INT32 ies;
+} WMT_GPIO_STATE_INFO;
+
+typedef struct _GPIO_CTRL_INFO {
+ struct pinctrl *pinctrl_info;
+ GPIO_CTRL_STATE gpio_ctrl_state[GPIO_PIN_ID_MAX];
+} GPIO_CTRL_INFO, *P_GPIO_CTRL_INFO;
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+extern const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX];
+extern const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX];
+extern GPIO_CTRL_INFO gpio_ctrl_info;
+
+extern int mt_get_gpio_mode_base(unsigned long pin);
+extern int mt_get_gpio_pull_select_base(unsigned long pin);
+extern int mt_get_gpio_in_base(unsigned long pin);
+extern int mt_get_gpio_out_base(unsigned long pin);
+extern int mt_get_gpio_pull_enable_base(unsigned long pin);
+extern int mt_get_gpio_dir_base(unsigned long pin);
+extern int mt_get_gpio_ies_base(unsigned long pin);
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+INT32 wmt_gpio_init(struct platform_device *pdev);
+VOID _wmt_dump_gpio_regs(INT32 idx);
+VOID _wmt_gpio_pre_regs(INT32 num, WMT_GPIO_STATE_INFO *gpio_state);
+VOID _wmt_dump_gpio_pre_regs(WMT_GPIO_STATE_INFO gpio_state);
+INT32 wmt_gpio_deinit(VOID);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..162fb765bf0248b3cca911ecf56ac19cff16f619
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c
@@ -0,0 +1,779 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#include
+#include "osal_typedef.h"
+#include "osal.h"
+#include "stp_dbg.h"
+#include "stp_core.h"
+#include "btm_core.h"
+#include "wmt_plat.h"
+#include "wmt_step.h"
+#include "wmt_detect.h"
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+#include "connsys_debug_utility.h"
+#endif
+#include
+
+#define PFX_BTM "[STP-BTM] "
+#define STP_BTM_LOG_LOUD 4
+#define STP_BTM_LOG_DBG 3
+#define STP_BTM_LOG_INFO 2
+#define STP_BTM_LOG_WARN 1
+#define STP_BTM_LOG_ERR 0
+
+INT32 gBtmDbgLevel = STP_BTM_LOG_INFO;
+
+#define STP_BTM_PR_LOUD(fmt, arg...) \
+do { \
+ if (gBtmDbgLevel >= STP_BTM_LOG_LOUD) \
+ pr_info(PFX_BTM "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_BTM_PR_DBG(fmt, arg...) \
+do { \
+ if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \
+ pr_info(PFX_BTM "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_BTM_PR_INFO(fmt, arg...) \
+do { \
+ if (gBtmDbgLevel >= STP_BTM_LOG_INFO) \
+ pr_info(PFX_BTM "[I]%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_BTM_PR_WARN(fmt, arg...) \
+do { \
+ if (gBtmDbgLevel >= STP_BTM_LOG_WARN) \
+ pr_warn(PFX_BTM "[W]%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_BTM_PR_ERR(fmt, arg...) \
+do { \
+ if (gBtmDbgLevel >= STP_BTM_LOG_ERR) \
+ pr_err(PFX_BTM "[E]%s(%d):ERROR! " fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+#define ASSERT(expr)
+
+MTKSTP_BTM_T stp_btm_i;
+MTKSTP_BTM_T *stp_btm = &stp_btm_i;
+
+const PINT8 g_btm_op_name[] = {
+ [0x0] = "STP_OPID_BTM_RETRY",
+ [0x1] = "STP_OPID_BTM_RST",
+ [0x2] = "STP_OPID_BTM_DBG_DUMP",
+ [0x3] = "STP_OPID_BTM_DUMP_TIMEOUT",
+ [0x4] = "STP_OPID_BTM_POLL_CPUPCR",
+ [0x5] = "STP_OPID_BTM_PAGED_DUMP",
+ [0x6] = "STP_OPID_BTM_FULL_DUMP",
+ [0x7] = "STP_OPID_BTM_PAGED_TRACE",
+ [0x8] = "STP_OPID_BTM_FORCE_FW_ASSERT",
+#if CFG_WMT_LTE_COEX_HANDLING
+ [0x9] = "STP_OPID_BTM_WMT_LTE_COEX",
+#endif
+ [0xa] = "STP_OPID_BTM_ASSERT_TIMEOUT",
+ [0xb] = "STP_OPID_BTM_EMI_DUMP_END",
+ [0xc] = "STP_OPID_BTM_EXIT"
+};
+
+static VOID stp_btm_trigger_assert_timeout_handler(timer_handler_arg arg)
+{
+ ULONG data;
+
+ GET_HANDLER_DATA(arg, data);
+ if (mtk_wcn_stp_coredump_start_get() == 0)
+ stp_btm_notify_assert_timeout_wq((MTKSTP_BTM_T *)data);
+}
+
+static INT32 _stp_btm_handler(MTKSTP_BTM_T *stp_btm, P_STP_BTM_OP pStpOp)
+{
+ INT32 ret = -1;
+ /* core dump target, 0: aee; 1: netlink */
+ INT32 dump_sink = mtk_wcn_stp_coredump_flag_get();
+
+ if (pStpOp == NULL)
+ return -1;
+
+ switch (pStpOp->opId) {
+ case STP_OPID_BTM_EXIT:
+ /* TODO: clean all up? */
+ ret = 0;
+ break;
+
+ /*tx timeout retry */
+ case STP_OPID_BTM_RETRY:
+ if (mtk_wcn_stp_coredump_start_get() == 0)
+ stp_do_tx_timeout();
+ ret = 0;
+ break;
+
+ /*whole chip reset */
+ case STP_OPID_BTM_RST:
+ STP_BTM_PR_INFO("whole chip reset start!\n");
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC &&
+ mtk_wcn_stp_coredump_flag_get() != 0 && chip_reset_only == 0) {
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ connsys_dedicated_log_flush_emi();
+#endif
+ stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_FALSE);
+ }
+ STP_BTM_PR_INFO("....+\n");
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_CHIP_RESET);
+ if (stp_btm->wmt_notify) {
+ stp_btm->wmt_notify(BTM_RST_OP);
+ ret = 0;
+ } else {
+ STP_BTM_PR_ERR("stp_btm->wmt_notify is NULL.");
+ ret = -1;
+ }
+
+ STP_BTM_PR_INFO("whole chip reset end!\n");
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_CHIP_RESET);
+ break;
+
+ case STP_OPID_BTM_DBG_DUMP:
+ /*Notify the wmt to get dump data */
+ STP_BTM_PR_DBG("wmt dmp notification\n");
+ set_user_nice(stp_btm->BTMd.pThread, -20);
+ ret = stp_dbg_core_dump(dump_sink);
+ set_user_nice(stp_btm->BTMd.pThread, 0);
+ break;
+
+ case STP_OPID_BTM_DUMP_TIMEOUT:
+ /* append fake coredump end message */
+ if (dump_sink == 2 && wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) {
+ stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING);
+ STP_BTM_PR_WARN("generate fake coredump message\n");
+ stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND));
+ }
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) {
+ /* Flush dump data, and reset compressor */
+ STP_BTM_PR_INFO("Flush dump data\n");
+ stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_TRUE);
+ }
+ ret = mtk_wcn_stp_coredump_timeout_handle();
+ break;
+#if CFG_WMT_LTE_COEX_HANDLING
+ case STP_OPID_BTM_WMT_LTE_COEX:
+ ret = wmt_idc_msg_to_lte_handing();
+ break;
+#endif
+ case STP_OPID_BTM_ASSERT_TIMEOUT:
+ mtk_wcn_stp_assert_timeout_handle();
+ ret = 0;
+ break;
+ case STP_OPID_BTM_EMI_DUMP_END:
+ STP_BTM_PR_INFO("emi dump end notification.\n");
+ stp_dbg_stop_emi_dump();
+ mtk_wcn_stp_ctx_restore();
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ)
+{
+ P_OSAL_OP pOp;
+ /* INT32 ret = 0; */
+
+ if (!pOpQ) {
+ STP_BTM_PR_WARN("!pOpQ\n");
+ return NULL;
+ }
+
+ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ /* acquire lock success */
+ RB_GET(pOpQ, pOp);
+ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock));
+
+ if (!pOp)
+ STP_BTM_PR_DBG("RB_GET fail\n");
+ return pOp;
+}
+
+static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp)
+{
+ INT32 ret;
+ P_OSAL_OP pOp_latest = NULL;
+ P_OSAL_OP pOp_current = NULL;
+ INT32 flag_latest = 1;
+ INT32 flag_current = 1;
+
+ if (!pOpQ || !pOp) {
+ STP_BTM_PR_WARN("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp);
+ return 0; /* ;MTK_WCN_BOOL_FALSE; */
+ }
+ ret = 0;
+
+ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ /* acquire lock success */
+ if (&stp_btm->rFreeOpQ == pOpQ) {
+ if (!RB_FULL(pOpQ))
+ RB_PUT(pOpQ, pOp);
+ else
+ ret = -1;
+ } else if (pOp->op.opId == STP_OPID_BTM_RST ||
+ pOp->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT ||
+ pOp->op.opId == STP_OPID_BTM_DUMP_TIMEOUT ||
+ pOp->op.opId == STP_OPID_BTM_EMI_DUMP_END) {
+ if (!RB_FULL(pOpQ)) {
+ RB_PUT(pOpQ, pOp);
+ STP_BTM_PR_DBG("RB_PUT: 0x%x\n", pOp->op.opId);
+ } else
+ ret = -1;
+ } else {
+ pOp_current = stp_btm_get_current_op(stp_btm);
+ if (pOp_current) {
+ if (pOp_current->op.opId == STP_OPID_BTM_RST ||
+ pOp_current->op.opId == STP_OPID_BTM_DUMP_TIMEOUT ||
+ (pOp_current->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT &&
+ pOp->op.opId != STP_OPID_BTM_DBG_DUMP)) {
+ STP_BTM_PR_DBG("current: 0x%x\n", pOp_current->op.opId);
+ flag_current = 0;
+ }
+ }
+
+ RB_GET_LATEST(pOpQ, pOp_latest);
+ if (pOp_latest) {
+ if (pOp_latest->op.opId == STP_OPID_BTM_RST ||
+ pOp_latest->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT ||
+ pOp_latest->op.opId == STP_OPID_BTM_DUMP_TIMEOUT) {
+ STP_BTM_PR_DBG("latest: 0x%x\n", pOp_latest->op.opId);
+ flag_latest = 0;
+ }
+ if (pOp_latest->op.opId == pOp->op.opId
+#if CFG_WMT_LTE_COEX_HANDLING
+ && pOp->op.opId != STP_OPID_BTM_WMT_LTE_COEX
+#endif
+ ) {
+ flag_latest = 0;
+ STP_BTM_PR_DBG("With the latest a command repeat: latest 0x%x,current 0x%x\n",
+ pOp_latest->op.opId, pOp->op.opId);
+ }
+ }
+ if (flag_current && flag_latest) {
+ if (!RB_FULL(pOpQ)) {
+ RB_PUT(pOpQ, pOp);
+ STP_BTM_PR_DBG("RB_PUT: 0x%x\n", pOp->op.opId);
+ } else
+ ret = -1;
+ } else
+ ret = 0;
+
+ }
+
+ if (ret) {
+ STP_BTM_PR_DBG("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n",
+ pOpQ, RB_COUNT(pOpQ), &stp_btm->rFreeOpQ, &stp_btm->rActiveOpQ);
+ osal_opq_dump_locked("FreeOpQ", &stp_btm->rFreeOpQ);
+ osal_opq_dump_locked("ActiveOpQ", &stp_btm->rActiveOpQ);
+ }
+
+ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ return ret ? 0 : 1;
+}
+
+P_OSAL_OP _stp_btm_get_free_op(MTKSTP_BTM_T *stp_btm)
+{
+ P_OSAL_OP pOp;
+
+ if (stp_btm) {
+ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rFreeOpQ);
+ if (pOp) {
+ osal_memset(pOp, 0, osal_sizeof(OSAL_OP));
+ }
+
+ return pOp;
+ } else
+ return NULL;
+}
+
+INT32 _stp_btm_put_act_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp)
+{
+ INT32 bRet = 0;
+ INT32 wait_ret = -1;
+
+ P_OSAL_SIGNAL pSignal = NULL;
+
+ if (!stp_btm || !pOp) {
+ STP_BTM_PR_ERR("Input NULL pointer\n");
+ return bRet;
+ }
+ do {
+ pSignal = &pOp->signal;
+
+ if (pSignal->timeoutValue) {
+ pOp->result = -9;
+ osal_signal_init(&pOp->signal);
+ }
+
+ /* Init ref_count to 2, as one is held by current thread, the second by btm thread */
+ atomic_set(&pOp->ref_count, 2);
+
+ /* put to active Q */
+ bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp);
+ if (bRet == 0) {
+ STP_BTM_PR_DBG("put active queue fail\n");
+ atomic_dec(&pOp->ref_count);
+ break;
+ }
+ /* wake up wmtd */
+ osal_trigger_event(&stp_btm->STPd_event);
+
+ if (pSignal->timeoutValue == 0) {
+ bRet = 1; /* MTK_WCN_BOOL_TRUE; */
+ break;
+ }
+
+ /* check result */
+ wait_ret = osal_wait_for_signal_timeout(&pOp->signal, &stp_btm->BTMd);
+
+ STP_BTM_PR_DBG("wait completion:%d\n", wait_ret);
+ if (!wait_ret) {
+ STP_BTM_PR_ERR("wait completion timeout\n");
+ /* TODO: how to handle it? retry? */
+ } else {
+ if (pOp->result)
+ STP_BTM_PR_WARN("op(%d) result:%d\n", pOp->op.opId, pOp->result);
+ bRet = (pOp->result) ? 0 : 1;
+ }
+ } while (0);
+
+ if (pOp && atomic_dec_and_test(&pOp->ref_count)) {
+ /* put Op back to freeQ */
+ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp);
+ }
+
+ return bRet;
+}
+
+static INT32 _stp_btm_wait_for_msg(PVOID pvData)
+{
+ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData;
+
+ return (!RB_EMPTY(&stp_btm->rActiveOpQ)) || osal_thread_should_stop(&stp_btm->BTMd);
+}
+
+static INT32 _stp_btm_proc(PVOID pvData)
+{
+ MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData;
+ P_OSAL_OP pOp;
+ INT32 id;
+ INT32 result;
+
+ if (!stp_btm) {
+ STP_BTM_PR_WARN("!stp_btm\n");
+ return -1;
+ }
+
+ for (;;) {
+ pOp = NULL;
+
+ osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (PVOID) stp_btm);
+
+ if (osal_thread_should_stop(&stp_btm->BTMd)) {
+ STP_BTM_PR_INFO("should stop now...\n");
+ /* TODO: clean up active opQ */
+ break;
+ }
+
+ if (stp_btm->gDumplogflag) {
+ /* pr_warn("enter place1\n"); */
+ stp_btm->gDumplogflag = 0;
+ continue;
+ }
+
+ /* get Op from activeQ */
+ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ);
+
+ if (!pOp) {
+ STP_BTM_PR_WARN("get_lxop activeQ fail\n");
+ continue;
+ }
+ osal_op_history_save(&stp_btm->op_history, pOp);
+
+ id = osal_op_get_id(pOp);
+
+ if ((id >= STP_OPID_BTM_NUM) || (id < 0)) {
+ STP_BTM_PR_WARN("abnormal opid id: 0x%x\n", id);
+ result = -1;
+ goto handler_done;
+ }
+
+ STP_BTM_PR_DBG("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", id,
+ g_btm_op_name[id], RB_COUNT(&stp_btm->rActiveOpQ));
+
+ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ stp_btm_set_current_op(stp_btm, pOp);
+ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ result = _stp_btm_handler(stp_btm, &pOp->op);
+ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ stp_btm_set_current_op(stp_btm, NULL);
+ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock));
+
+ if (result) {
+ STP_BTM_PR_WARN("opid id(0x%x)(%s) error(%d)\n", id,
+ g_btm_op_name[id], result);
+ }
+
+handler_done:
+
+ if (atomic_dec_and_test(&pOp->ref_count)) {
+ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp);
+ } else if (osal_op_is_wait_for_signal(pOp)) {
+ osal_op_raise_signal(pOp, result);
+ }
+
+ if (id == STP_OPID_BTM_EXIT) {
+ break;
+ } else if (id == STP_OPID_BTM_RST) {
+ /* prevent multi reset case */
+ stp_btm_reset_btm_wq(stp_btm);
+ }
+ }
+
+ STP_BTM_PR_INFO("exits\n");
+
+ return 0;
+}
+
+static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid)
+{
+ P_OSAL_OP pOp;
+ INT32 bRet;
+ INT32 retval;
+
+ pOp = _stp_btm_get_free_op(stp_btm);
+ if (!pOp) {
+ STP_BTM_PR_WARN("get_free_lxop fail\n");
+ return -1; /* break; */
+ }
+
+ pOp->op.opId = opid;
+ pOp->signal.timeoutValue = 0;
+ bRet = _stp_btm_put_act_op(stp_btm, pOp);
+ STP_BTM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet);
+ retval = (bRet == 0) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS;
+
+ return retval;
+}
+
+static inline INT32 _stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (stp_btm == NULL)
+ return STP_BTM_OPERATION_FAIL;
+
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_RST);
+ return retval;
+}
+
+static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (stp_btm == NULL)
+ return STP_BTM_OPERATION_FAIL;
+
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_RETRY);
+ return retval;
+}
+
+
+static inline INT32 _stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (!stp_btm)
+ return STP_BTM_OPERATION_FAIL;
+
+ stp_btm_reset_btm_wq(stp_btm);
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DUMP_TIMEOUT);
+ return retval;
+}
+
+static inline INT32 _stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (!stp_btm)
+ return STP_BTM_OPERATION_FAIL;
+
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_ASSERT_TIMEOUT);
+ return retval;
+}
+
+static inline INT32 _stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm)
+{
+
+ INT32 retval;
+
+ if (stp_btm == NULL)
+ return STP_BTM_OPERATION_FAIL;
+
+ /* Paged dump */
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DBG_DUMP);
+
+ return retval;
+}
+
+static inline INT32 _stp_btm_notify_emi_dump_end_wq(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (!stp_btm)
+ return STP_BTM_OPERATION_FAIL;
+
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_EMI_DUMP_END);
+ return retval;
+}
+
+INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_wmt_rst_wq(stp_btm);
+}
+
+INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_stp_retry_wq(stp_btm);
+}
+
+INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_coredump_timeout_wq(stp_btm);
+}
+
+INT32 stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_assert_timeout_wq(stp_btm);
+}
+
+INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_wmt_dmp_wq(stp_btm);
+}
+
+INT32 stp_btm_notify_emi_dump_end(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_notify_emi_dump_end_wq(stp_btm);
+}
+
+INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en)
+{
+ return stp_dbg_poll_cpupcr_ctrl(en);
+}
+
+
+#if CFG_WMT_LTE_COEX_HANDLING
+
+static inline INT32 _stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 retval;
+
+ if (stp_btm == NULL)
+ return STP_BTM_OPERATION_FAIL;
+
+ retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_WMT_LTE_COEX);
+ return retval;
+}
+
+INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_notify_btm_handle_wmt_lte_coex(stp_btm);
+}
+
+#endif
+MTKSTP_BTM_T *stp_btm_init(VOID)
+{
+ INT32 i = 0x0;
+ INT32 ret = -1;
+
+ osal_unsleepable_lock_init(&stp_btm->wq_spinlock);
+ osal_event_init(&stp_btm->STPd_event);
+ stp_btm->wmt_notify = wmt_lib_btm_cb;
+
+ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE);
+ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE);
+
+ /* Put all to free Q */
+ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) {
+ osal_signal_init(&(stp_btm->arQue[i].signal));
+ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i]));
+ }
+
+ stp_btm_init_trigger_assert_timer(stp_btm);
+ osal_op_history_init(&stp_btm->op_history, 16);
+
+ /*Generate PSM thread, to servie STP-CORE for packet retrying and core dump receiving */
+ stp_btm->BTMd.pThreadData = (PVOID) stp_btm;
+ stp_btm->BTMd.pThreadFunc = (PVOID) _stp_btm_proc;
+ osal_memcpy(stp_btm->BTMd.threadName, BTM_THREAD_NAME, osal_strlen(BTM_THREAD_NAME));
+
+ ret = osal_thread_create(&stp_btm->BTMd);
+ if (ret < 0) {
+ STP_BTM_PR_ERR("osal_thread_create fail...\n");
+ goto ERR_EXIT1;
+ }
+
+ /* Start STPd thread */
+ ret = osal_thread_run(&stp_btm->BTMd);
+ if (ret < 0) {
+ STP_BTM_PR_ERR("osal_thread_run FAILS\n");
+ goto ERR_EXIT1;
+ }
+
+ return stp_btm;
+
+ERR_EXIT1:
+
+ return NULL;
+
+}
+
+INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm)
+{
+
+ INT32 ret = -1;
+
+ STP_BTM_PR_INFO("btm deinit\n");
+
+ if (!stp_btm)
+ return STP_BTM_OPERATION_FAIL;
+
+ ret = osal_thread_destroy(&stp_btm->BTMd);
+ if (ret < 0) {
+ STP_BTM_PR_ERR("osal_thread_destroy FAILS\n");
+ return STP_BTM_OPERATION_FAIL;
+ }
+
+ return STP_BTM_OPERATION_SUCCESS;
+}
+
+
+INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm)
+{
+ UINT32 i = 0;
+
+ osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE);
+ RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE);
+ osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock));
+ /* Put all to free Q */
+ for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) {
+ osal_signal_init(&(stp_btm->arQue[i].signal));
+ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i]));
+ }
+
+ return 0;
+}
+
+
+INT32 stp_notify_btm_dump(MTKSTP_BTM_T *stp_btm)
+{
+ /* pr_warn("%s:enter++\n",__func__); */
+ if (stp_btm == NULL) {
+ osal_dbg_print("%s: NULL POINTER\n", __func__);
+ return -1;
+ }
+ stp_btm->gDumplogflag = 1;
+ osal_trigger_event(&stp_btm->STPd_event);
+ return 0;
+}
+
+static inline INT32 _stp_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm)
+{
+ INT32 status = -1;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+
+ /* send assert command */
+ STP_BTM_PR_INFO("trigger stp assert process\n");
+ if (mtk_wcn_stp_is_sdio_mode()) {
+ bRet = stp_btm->wmt_notify(BTM_TRIGGER_STP_ASSERT_OP);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ STP_BTM_PR_INFO("trigger stp assert failed\n");
+ return status;
+ }
+ status = 0;
+ } else if (mtk_wcn_stp_is_btif_fullset_mode()) {
+#if BTIF_RXD_BE_BLOCKED_DETECT
+ stp_dbg_is_btif_rxd_be_blocked();
+#endif
+ status = wmt_plat_force_trigger_assert(STP_FORCE_TRG_ASSERT_DEBUG_PIN);
+ }
+
+ stp_btm_start_trigger_assert_timer(stp_btm);
+
+ if (status == 0)
+ STP_BTM_PR_INFO("trigger stp assert succeed\n");
+
+ return status;
+}
+
+
+INT32 stp_notify_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm)
+{
+ return _stp_btm_do_fw_assert(stp_btm);
+}
+
+INT32 wmt_btm_trigger_reset(VOID)
+{
+ return stp_btm_notify_wmt_rst_wq(stp_btm);
+}
+
+INT32 stp_btm_set_current_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp)
+{
+ if (stp_btm) {
+ stp_btm->pCurOP = pOp;
+ STP_BTM_PR_DBG("pOp=0x%p\n", pOp);
+ return 0;
+ }
+ STP_BTM_PR_ERR("Invalid pointer\n");
+ return -1;
+}
+
+P_OSAL_OP stp_btm_get_current_op(MTKSTP_BTM_T *stp_btm)
+{
+ if (stp_btm)
+ return stp_btm->pCurOP;
+ STP_BTM_PR_ERR("Invalid pointer\n");
+ return NULL;
+}
+
+INT32 stp_btm_init_trigger_assert_timer(MTKSTP_BTM_T *stp_btm)
+{
+ stp_btm->trigger_assert_timer.timeoutHandler = stp_btm_trigger_assert_timeout_handler;
+ stp_btm->trigger_assert_timer.timeroutHandlerData = (ULONG)stp_btm;
+ stp_btm->timeout = 1000;
+
+ return osal_timer_create(&stp_btm->trigger_assert_timer);
+}
+
+INT32 stp_btm_start_trigger_assert_timer(MTKSTP_BTM_T *stp_btm)
+{
+ return osal_timer_start(&stp_btm->trigger_assert_timer, stp_btm->timeout);
+}
+
+INT32 stp_btm_stop_trigger_assert_timer(MTKSTP_BTM_T *stp_btm)
+{
+ return osal_timer_stop(&stp_btm->trigger_assert_timer);
+}
+
+VOID stp_btm_print_op_history(VOID)
+{
+ osal_op_history_print(&stp_btm->op_history, "_stp_btm_proc");
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..305e46cc76f5cd7e1bac99652f789678ede08446
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h
@@ -0,0 +1,154 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+
+#ifndef _BTM_CORE_H
+#define _BTM_CORE_H
+
+#include "osal_typedef.h"
+#include "osal.h"
+#include "stp_wmt.h"
+#include "wmt_plat.h"
+#include "wmt_idc.h"
+#include "osal.h"
+#include "mtk_btif_exp.h"
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define STP_BTM_OPERATION_FAIL (-1)
+#define STP_BTM_OPERATION_SUCCESS (0)
+
+#define STP_BTM_OP_BUF_SIZE (64)
+
+#define BTM_THREAD_NAME "mtk_stp_btm"
+#define STP_PAGED_DUMP_TIME_LIMIT 3500
+#define STP_FULL_DUMP_TIME 3
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef enum _ENUM_STP_BTM_OPID_T {
+ STP_OPID_BTM_RETRY = 0x0,
+ STP_OPID_BTM_RST = 0x1,
+ STP_OPID_BTM_DBG_DUMP = 0x2,
+ STP_OPID_BTM_DUMP_TIMEOUT = 0x3,
+ STP_OPID_BTM_POLL_CPUPCR = 0x4,
+ STP_OPID_BTM_PAGED_DUMP = 0x5,
+ STP_OPID_BTM_FULL_DUMP = 0x6,
+ STP_OPID_BTM_PAGED_TRACE = 0x7,
+ STP_OPID_BTM_FORCE_FW_ASSERT = 0x8,
+#if CFG_WMT_LTE_COEX_HANDLING
+ STP_OPID_BTM_WMT_LTE_COEX = 0x9,
+#endif
+ STP_OPID_BTM_ASSERT_TIMEOUT = 0xa,
+ STP_OPID_BTM_EMI_DUMP_END = 0xb,
+ STP_OPID_BTM_EXIT = 0xc,
+ STP_OPID_BTM_NUM
+} ENUM_STP_BTM_OPID_T, *P_ENUM_STP_BTM_OPID_T;
+
+typedef OSAL_OP_DAT STP_BTM_OP;
+typedef P_OSAL_OP_DAT P_STP_BTM_OP;
+
+typedef struct mtk_stp_btm {
+ OSAL_THREAD BTMd; /* main thread (wmtd) handle */
+ OSAL_EVENT STPd_event;
+ OSAL_UNSLEEPABLE_LOCK wq_spinlock;
+
+ OSAL_OP_Q rFreeOpQ; /* free op queue */
+ OSAL_OP_Q rActiveOpQ; /* active op queue */
+ OSAL_OP arQue[STP_BTM_OP_BUF_SIZE]; /* real op instances */
+ P_OSAL_OP pCurOP; /* current op */
+ INT32 gDumplogflag;
+
+ /*wmt_notify */
+ INT32 (*wmt_notify)(MTKSTP_BTM_WMT_OP_T);
+
+ OSAL_TIMER trigger_assert_timer;
+ UINT32 timeout;
+ struct osal_op_history op_history;
+} MTKSTP_BTM_T;
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_notify_emi_dump_end(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep);
+INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en);
+INT32 stp_btm_sort_btm_wq(MTKSTP_BTM_T *stp_btm);
+INT32 stp_notify_btm_dump(MTKSTP_BTM_T *stp_btm);
+INT32 stp_notify_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm);
+INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm);
+INT32 wcn_psm_flag_trigger_collect_ftrace(void);
+#if BTIF_RXD_BE_BLOCKED_DETECT
+INT32 wcn_btif_rxd_blocked_collect_ftrace(void);
+MTK_WCN_BOOL is_btif_rxd_be_blocked(void);
+#endif
+
+INT32 wmt_btm_trigger_reset(VOID);
+INT32 stp_btm_init_trigger_assert_timer(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_start_trigger_assert_timer(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_stop_trigger_assert_timer(MTKSTP_BTM_T *stp_btm);
+INT32 stp_btm_set_current_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp);
+P_OSAL_OP stp_btm_get_current_op(MTKSTP_BTM_T *stp_btm);
+
+MTKSTP_BTM_T *stp_btm_init(VOID);
+extern unsigned int chip_reset_only;
+
+VOID stp_btm_print_op_history(VOID);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..d57740edfeae698c785424dc1471a23fab9f6a98
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+#ifndef _DBG_CORE_H
+#define _DBG_CORE_H
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..393d0f41227dd99fa35472edda341ab2b82d5993
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+#ifndef _PSM_CORE_H
+#define _PSM_CORE_H
+
+#include "osal_typedef.h"
+#include "stp_wmt.h"
+#include "osal.h"
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define PFX_PSM "[STP-PSM] "
+#define STP_PSM_LOG_LOUD 4
+#define STP_PSM_LOG_DBG 3
+#define STP_PSM_LOG_INFO 2
+#define STP_PSM_LOG_WARN 1
+#define STP_PSM_LOG_ERR 0
+
+#define ASSERT(expr)
+#define STP_PSM_FIFO_SIZE 0x2000 /* 8kbytes */
+#define STP_PSM_TX_SIZE 0x800 /* 2kbytes */
+
+#define STP_PSM_OPERATION_FAIL (-1)
+#define STP_PSM_OPERATION_SUCCESS (0)
+
+#define STP_PSM_PACKET_SIZE_MAX (2000)
+#if (WMT_UART_RX_MODE_WORK || WMT_SDIO_MODE)
+#define CFG_PSM_CORE_FIFO_SPIN_LOCK 0
+#else
+#define CFG_PSM_CORE_FIFO_SPIN_LOCK 1
+#endif
+
+
+#define PSM_HANDLING 127
+
+#define STP_PSM_WMT_PS_TASK_HANDLING_TIME 30 /* 20 milli-seconds */
+#define STP_PSM_IDLE_TIME_SLEEP 30 /* temporary for stress testing */
+#define STP_PSM_IDLE_TIME_SLEEP_1000 1000 /* for high speed transmission e.g. BT OPP*/
+#define STP_PSM_SDIO_IDLE_TIME_SLEEP 100 /* temporary for SDIO stress testing */
+#define STP_PSM_WAIT_EVENT_TIMEOUT 18500 /* set same as MAX_FUNC_ON_TIME */
+
+#if 0
+#define STP_PSM_WMT_EVENT_SLEEP_EN (0x1UL << 0)
+#define STP_PSM_WMT_EVENT_WAKEUP_EN (0x1UL << 1)
+#define STP_PSM_BLOCK_DATA_EN (0x1UL << 2)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (0x1UL << 3)
+#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (0x1UL << 4)
+#define STP_PSM_RESET_EN (0x1UL << 5)
+#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (0x1UL << 6)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (0x1UL << 7)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (0x1UL << 8)
+#endif
+
+#define STP_PSM_WMT_EVENT_SLEEP_EN (0)
+#define STP_PSM_WMT_EVENT_WAKEUP_EN (1)
+#define STP_PSM_BLOCK_DATA_EN (2)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (3)
+#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (4)
+#define STP_PSM_RESET_EN (5)
+#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (6)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (7)
+#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (8)
+
+#define STP_PSM_DBG_SIZE (48)
+
+/* OP command ring buffer : must be power of 2 */
+#define STP_OP_BUF_SIZE (16)
+
+#define PSM_THREAD_NAME "mtk_stp_psm"
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef enum {
+ ACT = 0,
+ ACT_INACT = 1,
+ INACT = 2,
+ INACT_ACT = 3,
+ STP_PSM_MAX_STATE = 4,
+} MTKSTP_PSM_STATE_T;
+
+typedef enum _ENUM_STP_OPID_T {
+ STP_OPID_PSM_SLEEP = 0,
+ STP_OPID_PSM_WAKEUP,
+ STP_OPID_PSM_HOST_AWAKE,
+ STP_OPID_PSM_EXIT,
+ STP_OPID_PSM_NUM,
+ STP_OPID_PSM_INALID = STP_OPID_PSM_NUM,
+} ENUM_STP_OPID_T, *P_ENUM_STP_OPID_T;
+
+typedef enum {
+ MON = 0,
+ UNMON,
+} MTKSTP_PSM_MONSTATE_T;
+
+typedef INT32(*wmt_notify_t) (MTKSTP_PSM_ACTION_T action);
+typedef INT32(*stp_tx_cb_t) (PUINT8 buffer, UINT32 length, UINT8 type);
+
+typedef OSAL_OP_DAT STP_OP;
+typedef P_OSAL_OP_DAT P_STP_OP;
+#if 0
+#if CFG_PSM_CORE_FIFO_SPIN_LOCK
+typedef OSAL_UNSLEEPABLE_LOCK PSM_FIFO_LOCK, *PPSM_FIFO_LOCK;
+#else
+typedef OSAL_SLEEPABLE_LOCK PSM_FIFO_LOCK, *PPSM_FIFO_LOCK;
+#endif
+#endif
+typedef struct mtk_stp_psm {
+ OSAL_THREAD PSMd; /* main thread (wmtd) handle */
+ OSAL_EVENT STPd_event;
+
+ OSAL_OP_Q rFreeOpQ; /* free op queue */
+ OSAL_OP_Q rActiveOpQ; /* active op queue */
+ OSAL_OP arQue[STP_OP_BUF_SIZE]; /* real op instances */
+
+ /* OSAL_OP current_active_op; */
+ /* P_OSAL_OP current_active_op; */
+ UINT32 last_active_opId;
+ MTKSTP_PSM_STATE_T work_state; /*working state */
+ OSAL_BIT_OP_VAR flag;
+
+ /* in normal cases, sleep op is always enabled; but in error cases, we can't execute sleep cmd,
+ * Eg: FW assert, core dump
+ */
+ INT32 sleep_en;
+
+/* OSAL_UNSLEEPABLE_LOCK flagSpinlock; */
+ INT32 idle_time_to_sleep;
+ OSAL_WAKE_LOCK wake_lock;
+ OSAL_TIMER psm_timer; /*monitor if active */
+ OSAL_EVENT wait_wmt_q;
+ OSAL_FIFO hold_fifo;
+
+ /* PSM_FIFO_LOCK hold_fifo_lock; */
+ OSAL_SLEEPABLE_LOCK hold_fifo_spinlock_global;
+
+ OSAL_UNSLEEPABLE_LOCK wq_spinlock;
+ OSAL_SLEEPABLE_LOCK user_lock;
+ OSAL_SLEEPABLE_LOCK stp_psm_lock;
+ INT32 (*wmt_notify)(MTKSTP_PSM_ACTION_T action);
+ INT32 (*stp_tx_cb)(PUINT8 buffer, UINT32 length, UINT8 type);
+ MTK_WCN_BOOL (*is_wmt_quick_ps_support)(VOID);
+ INT32 (*update_wmt_fw_patch_chip_rst)(VOID);
+ UINT8 out_buf[STP_PSM_TX_SIZE];
+ struct osal_op_history op_history;
+} MTKSTP_PSM_T;
+
+typedef struct {
+ UINT32 prev_flag;
+ UINT32 cur_flag;
+ UINT32 line_num;
+ UINT32 package_no;
+ UINT32 sec;
+ UINT32 usec;
+ UINT32 pid;
+ UINT64 l_sec;
+ ULONG l_nsec;
+} STP_PSM_ENTRY_T;
+
+typedef struct stp_psm_record {
+ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE];
+ UINT32 in;
+ UINT32 out;
+ UINT32 size;
+ OSAL_UNSLEEPABLE_LOCK lock;
+} STP_PSM_RECORD_T;
+
+typedef struct stp_psm_opid_record {
+ STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE];
+ UINT32 in;
+ UINT32 out;
+ UINT32 size;
+ OSAL_UNSLEEPABLE_LOCK lock;
+} STP_PSM_OPID_RECORD, *P_STP_PSM_OPID_RECORD;
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+#define PSM_USE_COUNT_PACKAGE 0
+
+#if PSM_USE_COUNT_PACKAGE
+#define MTK_COMBO_PSM_RX_TH_DEFAULT (1600)
+#define MTK_COMBO_PSM_TX_TH_DEFAULT (300)
+INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir);
+#else
+#define SAMPLE_DURATION 1 /*1 second */
+#define RTX_SPEED_THRESHOLD 50000 /*50KB/s */
+INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length);
+#endif
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+/*stp-psm external function*/
+INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action);
+INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm);
+
+INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm,
+ const PUINT8 buffer, const UINT32 len, const UINT8 type);
+INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep);
+struct mtk_stp_psm *stp_psm_init(void);
+INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm);
+MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(INT32 dbglevel);
+INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state);
+MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID);
+
+INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm);
+INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm);
+
+VOID stp_psm_print_op_history(VOID);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..2099131738bedde3c361eec1a523dcefcabb8710
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _STP_CORE_H
+#define _STP_CORE_H
+#include "osal_typedef.h"
+#include "osal.h"
+#include "stp_exp.h"
+#include "psm_core.h"
+#include "btm_core.h"
+#include "stp_btif.h"
+#include "stp_wmt.h"
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+#define WMT_LTE_COEX_FLAG (0x16)
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#define CONFIG_POWER_SAVING_SUPPORT
+#if (WMT_UART_RX_MODE_WORK || WMT_SDIO_MODE)
+#define CFG_STP_CORE_CTX_SPIN_LOCK 0
+#else
+#define CFG_STP_CORE_CTX_SPIN_LOCK 1
+#endif
+
+
+
+#define PFX "[STP] "
+#define STP_LOG_DBG 4
+#define STP_LOG_PKHEAD 3
+#define STP_LOG_INFO 2
+#define STP_LOG_WARN 1
+#define STP_LOG_ERR 0
+
+extern INT32 gStpDbgLvl;
+
+#define STP_DBG_FUNC(fmt, arg...) do {\
+ if (gStpDbgLvl >= STP_LOG_DBG)\
+ osal_warn_print(PFX "%s: " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_INFO_FUNC(fmt, arg...) do {\
+ if (gStpDbgLvl >= STP_LOG_INFO)\
+ osal_warn_print(PFX "%s:[I] " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_WARN_RATELIMITED_FUNC(fmt, arg...) do {\
+ static DEFINE_RATELIMIT_STATE(_rs, HZ, 5);\
+ if (gStpDbgLvl >= STP_LOG_WARN && __ratelimit(&_rs))\
+ osal_warn_print(PFX "%s:[W] " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_WARN_FUNC(fmt, arg...) do {\
+ if (gStpDbgLvl >= STP_LOG_WARN)\
+ osal_warn_print(PFX "%s:[W] " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_ERR_FUNC(fmt, arg...) do {\
+ if (gStpDbgLvl >= STP_LOG_ERR)\
+ osal_err_print(PFX "%s:[E] " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_TRC_FUNC(f) do {\
+ if (gStpDbgLvl >= STP_LOG_DBG)\
+ osal_warn_print(PFX "<%s> <%d>\n", __func__, __LINE__);\
+} while (0)
+
+#define STP_DUMP_PACKET_HEAD(a, b, c) do {\
+ if (gStpDbgLvl >= STP_LOG_PKHEAD)\
+ stp_dump_data(a, b, c);\
+} while (0)
+
+#define STP_TRACE_FUNC(fmt, arg...) do {\
+ if (gStpDbgLvl >= STP_LOG_DBG)\
+ osal_warn_print(PFX "%s: " fmt, __func__, ##arg);\
+} while (0)
+
+#define STP_MODE_BIT(x) (0x1UL << x)
+#define MTKSTP_UART_FULL_MODE STP_MODE_BIT(0)
+#define MTKSTP_UART_MAND_MODE STP_MODE_BIT(1)
+#define MTKSTP_BTIF_FULL_MODE STP_MODE_BIT(2)
+#define MTKSTP_BTIF_MAND_MODE STP_MODE_BIT(3)
+#define MTKSTP_SDIO_MODE STP_MODE_BIT(4)
+
+#define MTKSTP_BUFFER_SIZE (16384)
+#define PARSER_CORE_DUMP_NUM 200
+#define CORE_DUMP_NUM 100
+/*To check function driver's status by the the interface*/
+/*Operation definition*/
+#define OP_FUNCTION_ACTIVE 0
+
+/*Driver's status*/
+#define STATUS_OP_INVALID 0
+#define STATUS_FUNCTION_INVALID 1
+
+#define STATUS_FUNCTION_ACTIVE 31
+#define STATUS_FUNCTION_INACTIVE 32
+
+#define MTKSTP_CRC_SIZE (2)
+#define MTKSTP_HEADER_SIZE (4)
+#define MTKSTP_SEQ_SIZE (8)
+
+/*#define MTKSTP_WINSIZE (4)*/
+#define MTKSTP_WINSIZE (7)
+#define MTKSTP_TX_TIMEOUT (180) /*TODO: Baudrate to decide this */
+#define MTKSTP_RETRY_LIMIT (10)
+
+#define INDEX_INC(idx) \
+{ \
+ idx++; \
+ idx &= 0x7; \
+}
+
+#define INDEX_DEC(idx) \
+{ \
+ idx--; \
+ idx &= 0x7; \
+}
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef INT32(*IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size);
+typedef INT32(*RX_HAS_PENDING_DATA) (VOID);
+typedef INT32(*TX_HAS_PENDING_DATA) (VOID);
+typedef P_OSAL_THREAD(*RX_THREAD_GET) (VOID);
+/* event/signal */
+typedef INT32(*EVENT_SET) (UINT8 function_type);
+typedef INT32(*EVENT_TX_RESUME) (UINT8 winspace);
+typedef INT32(*FUNCTION_STATUS) (UINT8 type, UINT8 op);
+typedef INT32(*WMT_NOTIFY_FUNC_T) (UINT32 action);
+typedef INT32(*BTM_NOTIFY_WMT_FUNC_T) (INT32);
+
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+typedef OSAL_UNSLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK;
+#else
+typedef OSAL_SLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK;
+#endif
+
+typedef struct {
+ /* common interface */
+ IF_TX cb_if_tx;
+ RX_HAS_PENDING_DATA cb_rx_has_pending_data;
+ TX_HAS_PENDING_DATA cb_tx_has_pending_data;
+ RX_THREAD_GET cb_rx_thread_get;
+ /* event/signal */
+ EVENT_SET cb_event_set;
+ EVENT_TX_RESUME cb_event_tx_resume;
+ FUNCTION_STATUS cb_check_funciton_status;
+} mtkstp_callback;
+
+typedef enum {
+ MTKSTP_SYNC = 0,
+ MTKSTP_SEQ,
+ MTKSTP_ACK,
+ MTKSTP_NAK,
+ MTKSTP_TYPE,
+ MTKSTP_LENGTH,
+ MTKSTP_CHECKSUM,
+ MTKSTP_DATA,
+ MTKSTP_CRC1,
+ MTKSTP_CRC2,
+ MTKSTP_RESYNC1,
+ MTKSTP_RESYNC2,
+ MTKSTP_RESYNC3,
+ MTKSTP_RESYNC4,
+ MTKSTP_FW_MSG,
+} mtkstp_parser_state;
+
+typedef struct {
+ mtkstp_parser_state state;
+ UINT8 seq;
+ UINT8 ack;
+ UINT8 nak;
+ UINT8 type;
+ UINT16 length;
+ UINT8 checksum;
+ UINT16 crc;
+} mtkstp_parser_context_struct;
+
+typedef struct {
+ UINT8 txseq; /* last tx pkt's seq + 1 */
+ UINT8 txack; /* last tx pkt's ack */
+ UINT8 rxack; /* last rx pkt's ack */
+ UINT8 winspace; /* current sliding window size */
+ UINT8 expected_rxseq; /* last rx pkt's seq + 1 */
+ UINT8 retry_times;
+ UINT8 tx_timeout_loop; /* for extend tx timeout */
+ UINT8 rx_resync; /* num of 7f7f7f7f before expected_rxseq pkt, indicates if recv series of resync pkt */
+ UINT8 rx_resync_seq; /* last resync pkg's seq (0xFF if not set), only valid if rx_resync != 0 */
+} mtkstp_sequence_context_struct;
+
+typedef struct {
+ /* MTK_WCN_MUTEX mtx; */
+ OSAL_UNSLEEPABLE_LOCK mtx;
+ UINT8 buffer[MTKSTP_BUFFER_SIZE];
+ UINT32 read_p;
+ UINT32 write_p;
+} mtkstp_ring_buffer_struct;
+
+typedef struct {
+ UINT8 inband_rst_set;
+ UINT32 assert_info_cnt;
+ UINT32 rx_counter; /* size of current processing pkt in rx_buf[] */
+ UINT8 rx_buf[MTKSTP_BUFFER_SIZE]; /* input buffer of STP, room for current processing pkt */
+ UINT32 tx_read; /* read ptr of tx_buf[] */
+ UINT32 tx_write; /* write ptr of tx_buf[] */
+ UINT8 tx_buf[MTKSTP_BUFFER_SIZE]; /* output buffer of STP */
+ UINT32 tx_start_addr[MTKSTP_SEQ_SIZE]; /* ptr of each pkt in tx_buf[] */
+ UINT32 tx_length[MTKSTP_SEQ_SIZE]; /* length of each pkt in tx_buf[] */
+ mtkstp_ring_buffer_struct ring[MTKSTP_MAX_TASK_NUM]; /* ring buffers for each function driver */
+ mtkstp_parser_context_struct parser; /* current rx pkt's content */
+ mtkstp_sequence_context_struct sequence; /* state machine's current status */
+ /* MTK_WCN_MUTEX stp_mutex; */
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+ OSAL_UNSLEEPABLE_LOCK stp_mutex;
+#else
+ OSAL_SLEEPABLE_LOCK stp_mutex;
+#endif
+ /* MTK_WCN_TIMER tx_timer; // timer for tx timeout handling */
+ OSAL_TIMER tx_timer;
+
+ MTKSTP_PSM_T *psm;
+ MTKSTP_BTM_T *btm;
+ UINT8 f_enable; /* default disabled */
+ UINT8 f_ready; /* default non-ready */
+ UINT8 f_pending_type;
+ UINT8 f_coredump; /*block tx flag, for now, only when f/w assert happens, we will set this bit on */
+ UINT8 en_coredump;
+ UINT8 f_emidump;
+ /* Flag to identify Blueztooth is Bluez/or MTK Stack */
+ MTK_WCN_BOOL f_bluez;
+ MTK_WCN_BOOL f_dbg_en;
+ MTK_WCN_BOOL f_autorst_en;
+
+
+
+ /* Flag to identify STP by SDIO or UART */
+ UINT32 f_mode;
+
+ /* Flag to indicate the last WMT CLOSE */
+ UINT32 f_wmt_last_close;
+ /* Flag to indicate evt err has triggered assert or not */
+ UINT32 f_evt_err_assert;
+ /* Flag to indicate assert process is ongoing or not */
+ UINT32 f_assert_in_progress;
+
+ /* Flag to identify support GPSL5 */
+ MTK_WCN_BOOL f_gpsl5_en;
+} mtkstp_context_struct;
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+INT32 stp_send_data_no_ps(PUINT8 buffer, UINT32 length, UINT8 type);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_init
+* DESCRIPTION
+* init STP kernel
+* PARAMETERS
+* cb_func [IN] function pointers of system APIs
+* RETURNS
+* INT32 0 = success, others = failure
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_deinit
+* DESCRIPTION
+* deinit STP kernel
+* PARAMETERS
+* void
+* RETURNS
+* INT32 0 = success, others = failure
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_deinit(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_enable
+* DESCRIPTION
+* enable/disable STP
+* PARAMETERS
+* value [IN] 0 = disable, others = enable
+* RETURNS
+* INT32 0 = success, others = error
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_enable(INT32 value);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_enable
+* DESCRIPTION
+* get STP enable/disable status
+* PARAMETERS
+* none.
+* RETURNS
+* INT32 0 = disable, 1 = enable
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_is_enable(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_ready
+* DESCRIPTION
+* ready/non-ready STP
+* PARAMETERS
+* value [IN] 0 = non-ready, others = ready
+* RETURNS
+* INT32 0 = success, others = error
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_ready(INT32 value);
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_coredump_start_ctrl
+* DESCRIPTION
+* set f/w assert flag in STP context
+* PARAMETERS
+* value [IN] 0=assert end, others=assert begins
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_coredump_start_get
+* DESCRIPTION
+* get f/w assert flag in STP context
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0= f/w assert flag is not set, others=f/w assert flag is set
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_coredump_start_get(VOID);
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_send_data_raw
+* DESCRIPTION
+* send raw data to common interface, bypass STP
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] subfunction type
+* RETURNS
+* INT32 length transmitted
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_set_sdio_mode
+* DESCRIPTION
+* Set stp for SDIO mode
+* PARAMETERS
+* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode)
+* RETURNS
+* void
+*****************************************************************************/
+extern VOID mtk_wcn_stp_set_mode(UINT32 sdio_flag);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_uart_fullset_mode
+* DESCRIPTION
+* Is stp use UART Fullset mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:UART Fullset, FALSE:UART Fullset
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_uart_mand_mode
+* DESCRIPTION
+* Is stp use UART Mandatory mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:UART Mandatory, FALSE:UART Mandatory
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID);
+
+extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID);
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_btif_fullset_mode
+* DESCRIPTION
+* Is stp use BTIF Fullset mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:BTIF Fullset, FALSE:BTIF Fullset
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_btif_mand_mode
+* DESCRIPTION
+* Is stp use BTIF Mandatory mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:BTIF Mandatory, FALSE:BTIF Mandatory
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_sdio_mode
+* DESCRIPTION
+* Is stp use SDIO mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(VOID);
+
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_inband_reset
+* DESCRIPTION
+* To sync to oringnal stp state with f/w stp
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+extern VOID mtk_wcn_stp_inband_reset(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_inband_reset
+* DESCRIPTION
+* To send testing command to chip
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+extern VOID mtk_wcn_stp_test_cmd(INT32 no);
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_inband_reset
+* DESCRIPTION
+* To control STP debugging mechanism
+* PARAMETERS
+* func_no: function control, func_op: dumpping filer, func_param: dumpping parameter
+* RETURNS
+* none
+*****************************************************************************/
+extern VOID mtk_wcn_stp_debug_ctrl(INT32 func_no, INT32 func_op, INT32 func_param);
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_flush
+* DESCRIPTION
+* flush all stp context
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+extern VOID mtk_wcn_stp_flush_context(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_rx_queue
+* DESCRIPTION
+* flush all stp rx queue
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+extern VOID mtk_wcn_stp_flush_rx_queue(UINT32 type);
+
+/*****************************************************************************
+* FUNCTION
+* set stp debugging mdoe
+* DESCRIPTION
+* set stp debugging mdoe
+* PARAMETERS
+* dbg_mode: switch to dbg mode ?
+* RETURNS
+* void
+*****************************************************************************/
+extern VOID mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode);
+
+/*****************************************************************************
+* FUNCTION
+* set stp auto reset mdoe
+* DESCRIPTION
+* set stp auto reset mdoe
+* PARAMETERS
+* auto_rst: switch to auto reset mode ?
+* RETURNS
+* void
+*****************************************************************************/
+extern VOID mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst);
+
+/*stp_psm support*/
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_notify_stp
+* DESCRIPTION
+* WMT notification to STP that power saving job is done or not
+* PARAMETERS
+*
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action);
+
+extern INT32 mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_enabla
+* DESCRIPTION
+* enable STP PSM
+* PARAMETERS
+* int idle_time_to_sleep: IDLE time to sleep
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_disable
+* DESCRIPTION
+* disable STP PSM
+* PARAMETERS
+* void
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_psm_disable(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_reset
+* DESCRIPTION
+* reset STP PSM (used on whole chip reset)
+* PARAMETERS
+* void
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_psm_reset(VOID);
+extern VOID stp_do_tx_timeout(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_btm_get_dmp
+* DESCRIPTION
+* get stp dump related information
+* PARAMETERS
+* buffer: dump placement, len: dump size
+* RETURNS
+* 0: Success Negative Value: Fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_btm_get_dmp(PINT8 buf, PINT32 len);
+
+extern INT32 mtk_wcn_stp_dbg_enable(VOID);
+
+extern INT32 mtk_wcn_stp_dbg_disable(VOID);
+
+extern VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type);
+
+extern INT32 mtk_wcn_sys_if_rx(PUINT8 data, INT32 size);
+
+extern MTK_WCN_BOOL mtk_wcn_stp_dbg_level(INT32 dbglevel);
+
+extern INT32 mtk_wcn_stp_dbg_dump_package(VOID);
+
+extern INT32 stp_drv_init(VOID);
+
+extern VOID stp_drv_exit(VOID);
+
+extern INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on);
+
+extern INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on);
+
+extern INT32 mtk_wcn_stp_coredump_flag_get(VOID);
+extern INT32 mtk_wcn_stp_notify_sleep_for_thermal(VOID);
+extern INT32 mtk_wcn_stp_emi_dump_flag_ctrl(UINT32 on);
+extern INT32 mtk_wcn_stp_emi_dump_flag_get(VOID);
+
+extern INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value);
+extern INT32 mtk_wcn_stp_is_wmt_last_close(VOID);
+
+/*stp btif API declared*/
+extern INT32 mtk_wcn_stp_open_btif(VOID);
+extern INT32 mtk_wcn_stp_close_btif(VOID);
+extern INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb);
+extern INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len);
+extern INT32 mtk_wcn_stp_wakeup_consys(VOID);
+extern INT32 mtk_wcn_stp_dpidle_ctrl(UINT32 en_flag);
+extern INT32 mtk_wcn_stp_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode);
+extern INT32 mtk_wcn_stp_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag);
+extern VOID mtk_wcn_stp_ctx_save(VOID);
+extern VOID mtk_wcn_stp_ctx_restore(VOID);
+
+extern INT32 mtk_wcn_stp_wmt_trg_assert(VOID);
+extern UINT32 mtk_wcn_stp_get_wmt_trg_assert(VOID);
+extern VOID mtk_wcn_stp_set_wmt_trg_assert(UINT32 value);
+extern INT32 mtk_wcn_stp_assert_timeout_handle(VOID);
+extern INT32 mtk_wcn_stp_coredump_timeout_handle(VOID);
+extern VOID mtk_wcn_stp_dbg_pkt_log(INT32 type, INT32 dir);
+
+extern INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size);
+
+/*
+ * API to get/set assert process is ongoing.
+ * It includes assert, coredump and chip reset process.
+ */
+extern VOID mtk_wcn_stp_assert_flow_ctrl(UINT32 on);
+extern UINT32 mtk_wcn_stp_assert_flow_get(VOID);
+
+extern VOID mtk_wcn_stp_set_support_gpsl5(MTK_WCN_BOOL support_gpsl5);
+extern INT32 mtk_wcn_stp_is_support_gpsl5(VOID);
+
+VOID mtk_stp_sdio_retry_flag_ctrl(INT32 flag);
+VOID mtk_stp_dbg_sdio_retry_flag_ctrl(INT32 flag);
+INT32 mtk_stp_sdio_retry_flag_get(VOID);
+VOID mtk_stp_dump_sdio_register(VOID);
+VOID mtk_stp_notify_emi_dump_end(VOID);
+INT32 mtk_stp_check_rx_has_pending_data(VOID);
+INT32 mtk_stp_dbg_dmp_append(PUINT8 buf, INT32 max_len);
+P_OSAL_THREAD mtk_stp_rx_thread_get(VOID);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif /* _STP_CORE_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h
new file mode 100644
index 0000000000000000000000000000000000000000..63d237a058b22886abb12b320972b6cb79fe0ea2
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _STP_WMT_H
+#define _STP_WMT_H
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef enum {
+ BTM_RST_OP = 0,
+ BTM_DMP_OP = 1,
+ BTM_GET_AEE_SUPPORT_FLAG = 2,
+ BTM_TRIGGER_STP_ASSERT_OP = 3,
+ BTM_MAX_OP,
+} MTKSTP_BTM_WMT_OP_T;
+
+typedef enum {
+ SLEEP = 0,
+ HOST_AWAKE,
+ WAKEUP,
+ EIRQ,
+ ROLL_BACK,
+ STP_PSM_MAX_ACTION
+} MTKSTP_PSM_ACTION_T;
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+extern MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op);
+
+extern INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action);
+extern MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID);
+
+extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime);
+
+extern INT32 wmt_lib_update_fw_patch_chip_rst(VOID);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif /* _STP_WMT_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..99788d3d2c63ac14f8ba5cf7fc27da5e10d70850
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _WMT_CONF_H_
+#define _WMT_CONF_H_
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define CUST_CFG_WMT "WMT.cfg"
+#define CUST_CFG_WMT_SOC "WMT_SOC.cfg"
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+
+
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+INT32 wmt_conf_read_file(VOID);
+P_WMT_GEN_CONF wmt_conf_get_cfg(VOID);
+INT32 wmt_conf_set_cfg_file(const PINT8 name);
+INT32 wmt_conf_deinit(VOID);
+
+#endif /* _WMT_CONF_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ac2b51cdb6b61ec4eb7445f4100b3886c8cdd25
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+#ifndef _WMT_CORE_H_
+#define _WMT_CORE_H_
+
+#include "wmt_ctrl.h"
+#include "wmt_exp.h"
+#include "wmt_plat.h"
+#include "osal.h"
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+#if defined(MT6620E3) || defined(MT6620E6) /* need modify this part */
+#define CFG_CORE_MT6620_SUPPORT 1 /* whether MT6620 is supported or not */
+#else
+#define CFG_CORE_MT6620_SUPPORT 1 /* whether MT6620 is supported or not */
+#endif
+
+#if defined(MT6628)
+#define CFG_CORE_MT6628_SUPPORT 1 /* whether MT6628 is supported or not */
+#else
+#define CFG_CORE_MT6628_SUPPORT 1 /* whether MT6628 is supported or not */
+#endif
+
+#if defined(MT6630)
+#define CFG_CORE_MT6630_SUPPORT 1 /* whether MT6630 is supported or not */
+#else
+#define CFG_CORE_MT6630_SUPPORT 1 /* whether MT6630 is supported or not */
+#endif
+
+#if defined(MT6632)
+#define CFG_CORE_MT6632_SUPPORT 1 /* whether MT6632 is supported or not */
+#else
+#define CFG_CORE_MT6632_SUPPORT 1 /* whether MT6632 is supported or not */
+#endif
+
+#define CFG_CORE_SOC_SUPPORT 1
+/* TODO:[ChangeFeature][George] move this definition outside so that wmt_dev can remove wmt_core.h inclusion. */
+#define defaultPatchName "mt66xx_patch_hdr.bin"
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#define BCNT_PATCH_BUF_HEADROOM (8)
+
+#define BCNT_PATCH_BUF_CHECKSUM (2)
+
+#define DWCNT_HIF_CONF (4)
+#define DWCNT_STRAP_CONF (4)
+#define DWCNT_RESERVED (8)
+#define DWCNT_CTRL_DATA (16)
+
+
+#if 0 /* TODO: [obsolete][GeorgeKuo]: remove ubsolete definitions */
+#define WMT_SET (1)
+#define WMT_QUERY (0)
+#define WMT_PKT_FMT_RAW (1)
+#define WMT_PKT_FMT_STP (0)
+#endif
+
+#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE)
+#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE)
+
+#define WMT_HDR_LEN (4) /* header length */
+#define WMT_STS_LEN (1) /* status length */
+#define WMT_FLAG_LEN (1)
+#define WMT_HIF_UART_INFO_LEN (4)
+#define WMT_FUNC_CTRL_PARAM_LEN (1)
+#define WMT_LPBK_CMD_LEN (5)
+#define WMT_LPBK_BUF_LEN (1024+WMT_LPBK_CMD_LEN)
+#define WMT_DEFAULT_BAUD_RATE (115200)
+
+#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s}
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef enum _ENUM_WMT_FM_T {
+ WMT_FM_INVALID = 0,
+ WMT_FM_I2C = 1,
+ WMT_FM_COMM = 2,
+ WMT_FM_MAX
+} ENUM_WMT_FM_T, *P_ENUM_WMT_FM_T;
+
+typedef enum _ENUM_WMT_HIF_T {
+ WMT_HIF_UART = 0,
+ WMT_HIF_SDIO = 1,
+ WMT_HIF_BTIF = 2,
+ WMT_HIF_MAX
+} ENUM_WMT_HIF_T, *P_ENUM_WMT_HIF_T;
+
+#if 0 /* [George] moved to wmt_exp.h for hif_sdio's use */
+typedef enum {
+ WMT_SDIO_SLOT_INVALID = 0,
+ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */
+ WMT_SDIO_SLOT_SDIO2 = 2,
+ WMT_SDIO_SLOT_MAX
+} WMT_SDIO_SLOT_NUM;
+
+typedef enum {
+ WMT_SDIO_FUNC_STP = 0,
+ WMT_SDIO_FUNC_WIFI = 1,
+ WMT_SDIO_FUNC_MAX
+} WMT_SDIO_FUNC_TYPE;
+#endif
+
+typedef enum _ENUM_WMT_OPID_T {
+ WMT_OPID_HIF_CONF = 0,
+ WMT_OPID_PWR_ON = 1,
+ WMT_OPID_PWR_OFF = 2,
+ WMT_OPID_FUNC_ON = 3,
+ WMT_OPID_FUNC_OFF = 4,
+ WMT_OPID_REG_RW = 5, /* TODO:[ChangeFeature][George] is this OP obsoleted? */
+ WMT_OPID_EXIT = 6,
+ WMT_OPID_PWR_SV = 7,
+ WMT_OPID_DSNS = 8,
+ WMT_OPID_LPBK = 9,
+ WMT_OPID_CMD_TEST = 10,
+ WMT_OPID_HW_RST = 11,
+ WMT_OPID_SW_RST = 12,
+ WMT_OPID_BAUD_RST = 13,
+ WMT_OPID_STP_RST = 14,
+ WMT_OPID_THERM_CTRL = 15,
+ WMT_OPID_EFUSE_RW = 16,
+ WMT_OPID_GPIO_CTRL = 17,
+ WMT_OPID_SDIO_CTRL = 18,
+ WMT_OPID_FW_COREDMP = 19,
+ WMT_OPID_GPIO_STATE = 20,
+ WMT_OPID_BGW_DS = 21,
+ WMT_OPID_SET_MCU_CLK = 22,
+ WMT_OPID_ADIE_LPBK_TEST = 23,
+#ifdef CONFIG_MTK_COMBO_ANT
+ WMT_OPID_ANT_RAM_DOWN = 24,
+ WMT_OPID_ANT_RAM_STA_GET = 25,
+#endif
+#if CFG_WMT_LTE_COEX_HANDLING
+ WMT_OPID_IDC_MSG_HANDLING = 26,
+#endif
+ WMT_OPID_TRIGGER_STP_ASSERT = 27,
+ WMT_OPID_FLASH_PATCH_DOWN = 28,
+ WMT_OPID_FLASH_PATCH_VER_GET = 29,
+ WMT_OPID_UTC_TIME_SYNC = 30,
+ WMT_OPID_FW_LOG_CTRL = 31,
+ WMT_OPID_WLAN_PROBE = 32,
+ WMT_OPID_WLAN_REMOVE = 33,
+ WMT_OPID_GPS_MCU_CTRL = 34,
+ WMT_OPID_TRY_PWR_OFF = 35,
+ WMT_OPID_BLANK_STATUS_CTRL = 36,
+ WMT_OPID_MET_CTRL = 37,
+ WMT_OPID_GPS_SUSPEND = 38,
+ WMT_OPID_GET_CONSYS_STATE = 39,
+ WMT_OPID_MAX
+} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T;
+
+typedef OSAL_OP_DAT WMT_OP;
+typedef P_OSAL_OP_DAT P_WMT_OP;
+
+typedef enum _ENUM_WMT_UART_FC_T {
+ WMT_UART_NO_FC = 0,
+ WMT_UART_MTK_SW_FC = 1,
+ WMT_UART_LUX_SW_FC = 2,
+ WMT_UART_HW_FC = 3,
+ WMT_UART_MAX
+} ENUM_WMT_UART_FC_T, *P_ENUM_UART_FC_T;
+
+
+typedef struct _WMT_HIF_CONF {
+ UINT32 hifType; /* HIF Type */
+ UINT32 uartFcCtrl; /* UART FC config */
+ UINT32 au4HifConf[DWCNT_HIF_CONF]; /* HIF Config */
+ UINT32 au4StrapConf[DWCNT_STRAP_CONF]; /* Strap Config */
+} WMT_HIF_CONF, *P_WMT_HIF_CONF;
+
+typedef INT32(*WMT_OPID_FUNC) (P_WMT_OP);
+
+struct WMT_BYTE_ARRAY {
+ UINT32 size;
+ PUINT8 data;
+};
+
+typedef struct _WMT_GEN_CONF {
+ UINT8 cfgExist;
+
+ UINT8 coex_wmt_ant_mode;
+ UINT8 coex_wmt_ant_mode_ex;
+ UINT8 coex_wmt_ext_component;
+ UINT8 coex_wmt_wifi_time_ctl;
+ UINT8 coex_wmt_ext_pta_dev_on;
+ /*combo chip and LTE coex filter mode setting */
+ UINT8 coex_wmt_filter_mode;
+
+ UINT8 coex_bt_rssi_upper_limit;
+ UINT8 coex_bt_rssi_mid_limit;
+ UINT8 coex_bt_rssi_lower_limit;
+ UINT8 coex_bt_pwr_high;
+ UINT8 coex_bt_pwr_mid;
+ UINT8 coex_bt_pwr_low;
+
+ UINT8 coex_wifi_rssi_upper_limit;
+ UINT8 coex_wifi_rssi_mid_limit;
+ UINT8 coex_wifi_rssi_lower_limit;
+ UINT8 coex_wifi_pwr_high;
+ UINT8 coex_wifi_pwr_mid;
+ UINT8 coex_wifi_pwr_low;
+
+ UINT8 coex_ext_pta_hi_tx_tag;
+ UINT8 coex_ext_pta_hi_rx_tag;
+ UINT8 coex_ext_pta_lo_tx_tag;
+ UINT8 coex_ext_pta_lo_rx_tag;
+ UINT16 coex_ext_pta_sample_t1;
+ UINT16 coex_ext_pta_sample_t2;
+ UINT8 coex_ext_pta_wifi_bt_con_trx;
+
+ UINT32 coex_misc_ext_pta_on;
+ UINT32 coex_misc_ext_feature_set;
+ /*GPS LNA setting */
+ UINT8 wmt_gps_lna_pin;
+ UINT8 wmt_gps_lna_enable;
+ /*GPS HW suspend setting */
+ UINT8 wmt_gps_suspend_ctrl;
+ /*Power on sequence */
+ UINT8 pwr_on_rtc_slot;
+ UINT8 pwr_on_ldo_slot;
+ UINT8 pwr_on_rst_slot;
+ UINT8 pwr_on_off_slot;
+ UINT8 pwr_on_on_slot;
+ UINT8 co_clock_flag;
+
+ /*deep sleep feature flag*/
+ UINT8 disable_deep_sleep_cfg;
+
+ /* Combo chip side SDIO driving setting */
+ UINT32 sdio_driving_cfg;
+
+ /* Combo chip WiFi path setting */
+ UINT16 coex_wmt_wifi_path;
+ /* Combo chip WiFi eLAN gain setting */
+ UINT8 coex_wmt_ext_elna_gain_p1_support;
+ UINT32 coex_wmt_ext_elna_gain_p1_D0;
+ UINT32 coex_wmt_ext_elna_gain_p1_D1;
+ UINT32 coex_wmt_ext_elna_gain_p1_D2;
+ UINT32 coex_wmt_ext_elna_gain_p1_D3;
+ PINT8 coex_wmt_antsel_invert_support;
+ UINT8 coex_wmt_ext_epa_mode;
+
+ struct WMT_BYTE_ARRAY *coex_wmt_epa_elna;
+
+ UINT8 bt_tssi_from_wifi;
+ UINT16 bt_tssi_target;
+
+ UINT8 coex_config_bt_ctrl;
+ UINT8 coex_config_bt_ctrl_mode;
+ UINT8 coex_config_bt_ctrl_rw;
+
+ UINT8 coex_config_addjust_opp_time_ratio;
+ UINT8 coex_config_addjust_opp_time_ratio_bt_slot;
+ UINT8 coex_config_addjust_opp_time_ratio_wifi_slot;
+
+ UINT8 coex_config_addjust_ble_scan_time_ratio;
+ UINT8 coex_config_addjust_ble_scan_time_ratio_bt_slot;
+ UINT8 coex_config_addjust_ble_scan_time_ratio_wifi_slot;
+
+ /* wifi ant swap feature */
+ UINT8 wifi_ant_swap_mode;
+ UINT8 wifi_main_ant_polarity;
+ UINT8 wifi_ant_swap_ant_sel_gpio;
+
+ struct WMT_BYTE_ARRAY *wifi_config;
+} WMT_GEN_CONF, *P_WMT_GEN_CONF;
+
+typedef enum _ENUM_DRV_STS_ {
+#if 0
+ DRV_STS_INVALID = 0,
+ DRV_STS_UNREG = 1, /* Initial State */
+#endif
+ DRV_STS_POWER_OFF = 0, /* initial state */
+ DRV_STS_POWER_ON = 1, /* powered on, only WMT */
+ DRV_STS_FUNC_ON = 2, /* FUNC ON */
+ DRV_STS_MAX
+} ENUM_DRV_STS, *P_ENUM_DRV_STS;
+
+typedef enum _WMT_IC_PIN_ID_ {
+ WMT_IC_PIN_AUDIO = 0,
+ WMT_IC_PIN_EEDI = 1,
+ WMT_IC_PIN_EEDO = 2,
+ WMT_IC_PIN_GSYNC = 3,
+ WMT_IC_PIN_MAX
+} WMT_IC_PIN_ID, *P_WMT_IC_PIN_ID;
+
+
+typedef enum _WMT_IC_PIN_STATE_ {
+ WMT_IC_PIN_EN = 0,
+ WMT_IC_PIN_DIS = 1,
+ WMT_IC_AIF_0 = 2, /* = CMB_STUB_AIF_0, */
+ WMT_IC_AIF_1 = 3, /* = CMB_STUB_AIF_1, */
+ WMT_IC_AIF_2 = 4, /* = CMB_STUB_AIF_2, */
+ WMT_IC_AIF_3 = 5, /* = CMB_STUB_AIF_3, */
+ WMT_IC_PIN_MUX = 6,
+ WMT_IC_PIN_GPIO = 7,
+ WMT_IC_PIN_GPIO_HIGH = 8,
+ WMT_IC_PIN_GPIO_LOW = 9,
+ WMT_IC_PIN_STATE_MAX
+} WMT_IC_PIN_STATE, *P_WMT_IC_PIN_STATE;
+
+typedef enum _WMT_CO_CLOCK_ {
+ WMT_CO_CLOCK_DIS = 0,
+ WMT_CO_CLOCK_EN = 1,
+ WMT_CO_CLOCK_DCXO = 2,
+ WMT_CO_CLOCK_MAX
+} WMT_CO_CLOCK, *P_WMT_CO_CLOCK;
+
+
+typedef INT32(*SW_INIT) (P_WMT_HIF_CONF pWmtHifConf);
+typedef INT32(*SW_DEINIT) (P_WMT_HIF_CONF pWmtHifConf);
+typedef INT32(*IC_PIN_CTRL) (WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+typedef INT32(*IC_VER_CHECK) (VOID);
+typedef INT32(*CO_CLOCK_CTRL) (WMT_CO_CLOCK on);
+typedef MTK_WCN_BOOL(*IS_QUICK_SLEEP_SUPPORT) (VOID);
+typedef MTK_WCN_BOOL(*IS_AEE_DUMP_SUPPORT) (VOID);
+typedef MTK_WCN_BOOL(*TRIGGER_STP_ASSERT) (VOID);
+typedef MTK_WCN_BOOL(*DEEP_SLEEP_CONTROL) (INT32 value);
+
+
+typedef struct _WMT_IC_OPS_ {
+ UINT32 icId;
+ UINT64 options;
+ SW_INIT sw_init;
+ SW_DEINIT sw_deinit;
+ IC_PIN_CTRL ic_pin_ctrl;
+ IC_VER_CHECK ic_ver_check;
+ CO_CLOCK_CTRL co_clock_ctrl;
+ IS_QUICK_SLEEP_SUPPORT is_quick_sleep;
+ IS_AEE_DUMP_SUPPORT is_aee_dump_support;
+ TRIGGER_STP_ASSERT trigger_stp_assert;
+ DEEP_SLEEP_CONTROL deep_sleep_ctrl;
+} WMT_IC_OPS, *P_WMT_IC_OPS;
+
+typedef struct _WMT_CTX_ {
+ ENUM_DRV_STS eDrvStatus[WMTDRV_TYPE_MAX]; /* Controlled driver status */
+ UINT32 wmtInfoBit; /* valid info bit */
+ WMT_HIF_CONF wmtHifConf; /* HIF information */
+
+ /* Pointer to WMT_IC_OPS. Shall be assigned to a correct table in stp_init
+ * if and only if getting chip id successfully. hwver and fwver are kept in
+ * WMT-IC module only.
+ */
+ P_WMT_IC_OPS p_ic_ops;
+ UINT32 wmtBlankStatus; /* Controlled blank status */
+} WMT_CTX, *P_WMT_CTX;
+
+/* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */
+/* Using this struct relies on compiler's implementation and pack() settings */
+typedef struct _WMT_PKT_ {
+ UINT8 eType; /* WMT_PKT_TYPE_* */
+ UINT8 eOpCode; /* OPCODE_* */
+ UINT16 u2SduLen; /* 2 bytes length, little endian */
+ UINT8 aucParam[32];
+} WMT_PKT, *P_WMT_PKT;
+
+/* WMT Packet Format */
+typedef enum _ENUM_WMT_PKT_TYPE {
+ WMT_PKT_TYPE_INVALID = 0,
+ WMT_PKT_TYPE_CMD = 1,
+ WMT_PKT_TYPE_EVENT = 2,
+ WMT_PKT_TYPE_MAX
+} ENUM_WMT_PKT_TYPE, *P_ENUM_WMT_PKT_TYPE;
+
+typedef enum _ENUM_OPCODE {
+ OPCODE_INVALID = 0,
+ OPCODE_PATCH = 1,
+ OPCODE_TEST = 2,
+ OPCODE_WAKEUP = 3,
+ OPCODE_HIF = 4,
+ OPCODE_STRAP_CONF = 5,
+ OPCODE_FUNC_CTRL = 6,
+ OPCODE_RESET = 7,
+ OPCODE_INT = 8,
+ OPCODE_MAX
+} ENUM_OPCODE, *P_ENUM_OPCODE;
+
+typedef enum {
+ WMT_STP_CONF_EN = 0,
+ WMT_STP_CONF_RDY = 1,
+ WMT_STP_CONF_MODE = 2,
+ WMT_STP_CONF_MAX
+} WMT_STP_CONF_TYPE;
+
+struct init_script {
+ PUINT8 cmd;
+ UINT32 cmdSz;
+ PUINT8 evt;
+ UINT32 evtSz;
+ PUINT8 str;
+};
+
+typedef struct _WMT_PATCH {
+ UINT8 ucDateTime[16];
+ UINT8 ucPLat[4];
+ UINT16 u2HwVer;
+ UINT16 u2SwVer;
+ UINT32 u4PatchVer;
+} WMT_PATCH, *P_WMT_PATCH;
+
+struct wmt_rom_patch {
+ UINT8 ucDateTime[16];
+ UINT8 ucPLat[4];
+ UINT16 u2HwVer;
+ UINT16 u2SwVer;
+ UINT32 u4PatchAddr;
+ UINT32 u4PatchType;
+ UINT32 u4CRC[4];
+};
+
+
+#define WMT_CORE_DMP_CPUPCR_NUM 10
+enum wmt_consys_dump_status {
+ WMT_DUMP_STATE_NONE = 0,
+ WMT_DUMP_STATE_SCHEDULED = 1,
+ WMT_DUMP_STATE_ONGOING = 2
+};
+
+typedef struct consys_state_dmp_info {
+ UINT32 cpu_pcr[WMT_CORE_DMP_CPUPCR_NUM];
+ CONSYS_STATE state;
+} CONSYS_STATE_DMP_INFO, *P_CONSYS_STATE_DMP_INFO;
+
+typedef struct consys_state_dmp_op {
+ enum wmt_consys_dump_status status;
+ OSAL_SLEEPABLE_LOCK lock;
+ UINT32 times;
+ UINT32 cpu_sleep_ms;
+ CONSYS_STATE_DMP_INFO dmp_info;
+ ULONG version;
+} CONSYS_STATE_DMP_OP, *P_CONSYS_STATE_DMP_OP;
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+extern INT32 wmt_core_init(VOID);
+extern INT32 wmt_core_deinit(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_wmtd
+* DESCRIPTION
+* deinit STP kernel
+* PARAMETERS
+* void
+* RETURNS
+* INT32 0 = success, others = failure
+*****************************************************************************/
+extern INT32 wmt_core_opid(P_WMT_OP pWmtOp);
+
+extern INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, PULONG pPa1, PULONG pPa2);
+
+extern INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn);
+
+extern INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask);
+
+extern VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len);
+
+extern MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer);
+
+extern INT32 wmt_core_init_script_retry(struct init_script *script, INT32 count, INT32 retry, INT32 dump_err_log);
+
+extern INT32 wmt_core_init_script(struct init_script *script, INT32 count);
+
+extern INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, PUINT32 readSize);
+
+extern INT32
+wmt_core_tx(const PUINT8 pData, UINT32 size, PUINT32 writtenSize, MTK_WCN_BOOL bRawFlag);
+extern MTK_WCN_BOOL wmt_core_is_quick_ps_support(VOID);
+
+extern MTK_WCN_BOOL wmt_core_get_aee_dump_flag(VOID);
+extern MTK_WCN_BOOL wmt_core_trigger_stp_assert(VOID);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+extern MTK_WCN_BOOL wmt_core_deep_sleep_ctrl(INT32 value);
+#endif
+extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state);
+
+#if CFG_CORE_INTERNAL_TXRX
+extern INT32 wmt_core_lpbk_do_stp_init(void);
+extern INT32 wmt_core_lpbk_do_stp_deinit(void);
+#endif
+
+extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state);
+extern ENUM_DRV_STS wmt_core_get_drv_status(ENUM_WMTDRV_TYPE_T type);
+#if CFG_WMT_LTE_COEX_HANDLING
+extern VOID wmt_core_set_flag_for_test(UINT32 enable);
+extern UINT32 wmt_core_get_flag_for_test(VOID);
+#endif
+
+#if CFG_CORE_MT6620_SUPPORT
+extern WMT_IC_OPS wmt_ic_ops_mt6620;
+#endif
+
+#if CFG_CORE_MT6628_SUPPORT
+extern WMT_IC_OPS wmt_ic_ops_mt6628;
+#endif
+
+#if CFG_CORE_MT6630_SUPPORT
+extern WMT_IC_OPS wmt_ic_ops_mt6630;
+#endif
+
+#if CFG_CORE_MT6632_SUPPORT
+extern WMT_IC_OPS wmt_ic_ops_mt6632;
+#endif
+
+#if CFG_CORE_SOC_SUPPORT
+extern WMT_IC_OPS wmt_ic_ops_soc;
+#endif
+
+extern P_WMT_GEN_CONF wmt_get_gen_conf_pointer(VOID);
+
+VOID wmt_core_set_blank_status(UINT32 on_off_flag);
+extern UINT32 wmt_core_get_blank_status(VOID);
+
+INT32 wmt_blank_status_ctrl(UINT32 on_off_flag);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static _osal_inline_ MTK_WCN_BOOL wmt_core_ic_ops_check(P_WMT_IC_OPS p_ops)
+{
+ if (!p_ops)
+ return MTK_WCN_BOOL_FALSE;
+ if ((p_ops->sw_init == NULL)
+ || (p_ops->sw_deinit == NULL)
+ || (p_ops->ic_ver_check == NULL)
+ || (p_ops->ic_pin_ctrl == NULL)) {
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return MTK_WCN_BOOL_TRUE;
+}
+
+#endif /* _WMT_CORE_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h
new file mode 100644
index 0000000000000000000000000000000000000000..6bb71ba0e2fd3f76989fb2f71c408fa3b607a1d3
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _WMT_CTRL_H_
+#define _WMT_CTRL_H_
+
+#include "osal.h"
+#include "stp_exp.h"
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#define DWCNT_CTRL_DATA (16)
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+
+
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef struct _WMT_CTRL_DATA_ {
+ UINT32 ctrlId;
+ SIZE_T au4CtrlData[DWCNT_CTRL_DATA];
+} WMT_CTRL_DATA, *P_WMT_CTRL_DATA;
+
+typedef enum _ENUM_WMT_CTRL_T {
+ WMT_CTRL_HW_PWR_OFF = 0, /* whole chip power off */
+ WMT_CTRL_HW_PWR_ON = 1, /* whole chip power on */
+ WMT_CTRL_HW_RST = 2, /* whole chip reset */
+ WMT_CTRL_STP_CLOSE = 3,
+ WMT_CTRL_STP_OPEN = 4,
+ WMT_CTRL_STP_CONF = 5,
+ WMT_CTRL_FREE_PATCH = 6,
+ WMT_CTRL_GET_PATCH = 7,
+ WMT_CTRL_GET_PATCH_NAME = 8,
+ WMT_CTRL_HOST_BAUDRATE_SET = 9,
+ WMT_CTRL_SDIO_HW = 10, /* enable/disable SDIO1/2 of combo chip */
+ WMT_CTRL_SDIO_FUNC = 11, /* probe/remove STP/Wi-Fi driver in SDIO1/2 of combo chip */
+ WMT_CTRL_HWIDVER_SET = 12, /* TODO: rename this and add chip id information in addition to chip version */
+ WMT_CTRL_HWVER_GET = 13, /* TODO: [FixMe][GeorgeKuo] remove unused functions */
+ WMT_CTRL_STP_RST = 14,
+ WMT_CTRL_GET_WMT_CONF = 15,
+ WMT_CTRL_TX = 16, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */
+ WMT_CTRL_RX = 17, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */
+ WMT_CTRL_RX_FLUSH = 18, /* [FixMe][SeanWang]: to be removed by Sean's stp integration */
+ WMT_CTRL_GPS_SYNC_SET = 19,
+ WMT_CTRL_GPS_LNA_SET = 20,
+ WMT_CTRL_PATCH_SEARCH = 21,
+ WMT_CTRL_CRYSTAL_TRIMING_GET = 22,
+ WMT_CTRL_CRYSTAL_TRIMING_PUT = 23,
+ WMT_CTRL_HW_STATE_DUMP = 24,
+ WMT_CTRL_GET_PATCH_NUM = 25,
+ WMT_CTRL_GET_PATCH_INFO = 26,
+ WMT_CTRL_SOC_PALDO_CTRL = 27,
+ WMT_CTRL_SOC_WAKEUP_CONSYS = 28,
+ WMT_CTRL_SET_STP_DBG_INFO = 29,
+ WMT_CTRL_BGW_DESENSE_CTRL = 30,
+ WMT_CTRL_TRG_ASSERT = 31,
+#if CFG_WMT_LTE_COEX_HANDLING
+ WMT_CTRL_GET_TDM_REQ_ANTSEL = 32,
+#endif
+ WMT_CTRL_EVT_PARSER = 33,
+ WMT_CTRL_GET_ROM_PATCH_INFO = 34,
+ WMT_CTRL_UPDATE_PATCH_VERSION = 35,
+ WMT_CTRL_MAX
+} ENUM_WMT_CTRL_T, *P_ENUM_WMT_CTRL_T;
+
+typedef INT32(*WMT_CTRL_FUNC) (P_WMT_CTRL_DATA);
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+extern INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData);
+
+extern INT32
+wmt_ctrl_tx_ex(const PUINT8 pData,
+ const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag);
+
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+
+
+#endif /* _WMT_CTRL_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h
new file mode 100644
index 0000000000000000000000000000000000000000..9145bb205ba8c887f876734c585950d7f114e38c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+#ifndef _WMT_FUNC_H_
+#define _WMT_FUNC_H_
+
+#include "wmt_core.h"
+#include "wmt_plat.h"
+#include "osal.h"
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#if 1 /* defined(CONFIG_MTK_COMBO_HCI_DRIVER) || defined(CONFIG_MTK_COMBO_BT) */
+#define CFG_FUNC_BT_SUPPORT 1
+#else
+#define CFG_FUNC_BT_SUPPORT 0
+#endif
+
+
+#if IS_ENABLED(CONFIG_MTK_FMRADIO)
+#define CFG_FUNC_FM_SUPPORT 1
+#else
+#define CFG_FUNC_FM_SUPPORT 0
+#endif
+
+#if IS_ENABLED(CONFIG_MTK_COMBO_GPS)
+#define CFG_FUNC_GPS_SUPPORT 1
+#define CFG_FUNC_GPSL5_SUPPORT 1
+#else
+#define CFG_FUNC_GPS_SUPPORT 0
+#define CFG_FUNC_GPSL5_SUPPORT 0
+#endif
+
+#if 1 /* IS_ENABLED(CONFIG_MTK_COMBO_WIFI) */
+#define CFG_FUNC_WIFI_SUPPORT 1
+#else
+#define CFG_FUNC_WIFI_SUPPORT 0
+#endif
+
+#if 1
+#define CFG_FUNC_ANT_SUPPORT 1
+#else
+#define CFG_FUNC_ANT_SUPPORT 0
+#endif
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef INT32 (*SUBSYS_FUNC_ON)(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+typedef INT32 (*SUBSYS_FUNC_OFF)(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+typedef struct _WMT_FUNC_OPS_ {
+ SUBSYS_FUNC_ON func_on;
+ SUBSYS_FUNC_OFF func_off;
+} WMT_FUNC_OPS, *P_WMT_FUNC_OPS;
+
+typedef struct _CMB_PIN_CTRL_REG_ {
+ UINT32 regAddr;
+ UINT32 regValue;
+ UINT32 regMask;
+
+} CMB_PIN_CTRL_REG, *P_CMB_PIN_CTRL_REG;
+
+typedef struct _CMB_PIN_CTRL_ {
+ UINT32 pinId;
+ UINT32 regNum;
+ P_CMB_PIN_CTRL_REG pFuncOnArray;
+ P_CMB_PIN_CTRL_REG pFuncOffArray;
+
+} CMB_PIN_CTRL, *P_CMB_PIN_CTRL;
+
+typedef enum _ENUM_CMP_PIN_ID_ {
+ CMB_PIN_EEDI_ID = 0,
+ CMB_PIN_EEDO_ID = 1,
+ CMB_PIN_GSYNC_ID = 2,
+} ENUM_CMP_PIN_ID, *P_ENUM_CMP_PIN_ID;
+
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+#if CFG_FUNC_BT_SUPPORT
+extern WMT_FUNC_OPS wmt_func_bt_ops;
+#endif
+
+#if CFG_FUNC_FM_SUPPORT
+extern WMT_FUNC_OPS wmt_func_fm_ops;
+#endif
+
+#if CFG_FUNC_GPS_SUPPORT
+extern WMT_FUNC_OPS wmt_func_gps_ops;
+#endif
+
+#if CFG_FUNC_GPSL5_SUPPORT
+extern WMT_FUNC_OPS wmt_func_gpsl5_ops;
+#endif
+
+#if CFG_FUNC_WIFI_SUPPORT
+extern WMT_FUNC_OPS wmt_func_wifi_ops;
+#endif
+
+#if CFG_FUNC_ANT_SUPPORT
+extern WMT_FUNC_OPS wmt_func_ant_ops;
+#endif
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+
+
+
+
+
+
+#endif /* _WMT_FUNC_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h
new file mode 100644
index 0000000000000000000000000000000000000000..aa44dff600b4831ddad6cc9f66a4ac5d98af211c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _WMT_IC_H_
+#define _WMT_IC_H_
+
+/*******************************************************************************
+* 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 "wmt_core.h"
+#include "wmt_exp.h"
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define WMT_IC_NAME_MT6620 "MT6620"
+#define WMT_IC_NAME_MT6628 "MT6628"
+#define WMT_IC_NAME_MT6630 "MT6630"
+#define WMT_IC_NAME_MT6632 "MT6632"
+#define WMT_IC_NAME_DEFAULT "SOC_CONSYS"
+
+#define WMT_IC_VER_E1 "E1"
+#define WMT_IC_VER_E2 "E2"
+#define WMT_IC_VER_E3 "E3"
+#define WMT_IC_VER_E4 "E4"
+#define WMT_IC_VER_E5 "E5"
+#define WMT_IC_VER_E6 "E6"
+#define WMT_IC_VER_E7 "E7"
+
+#define WMT_IC_PATCH_DUMMY_EXT "_ex"
+#define WMT_IC_PATCH_NO_EXT ""
+#define WMT_IC_PATCH_E1_EXT "_e1"
+#define WMT_IC_PATCH_E2_EXT "_e2"
+#define WMT_IC_PATCH_E3_EXT "_e3"
+#define WMT_IC_PATCH_E4_EXT "_e4"
+#define WMT_IC_PATCH_E5_EXT "_e5"
+#define WMT_IC_PATCH_E6_EXT "_e6"
+
+#define WMT_IC_PATCH_TAIL "_hdr.bin"
+
+#define WMT_IC_INVALID_CHIP_ID 0xFFFF
+
+#define MAJORNUM(x) (x & 0x00F0)
+#define MINORNUM(x) (x & 0x000F)
+
+/*******************************************************************************
+* R E G I S T E R M A P
+********************************************************************************
+*/
+/* General definition used for ALL/UNKNOWN CHIPS */
+/* Now MT6620 uses these definitions */
+#define GEN_CONFG_BASE (0x80000000UL)
+#define GEN_HVR (GEN_CONFG_BASE + 0x0UL) /* HW_VER */
+#define GEN_FVR (GEN_CONFG_BASE + 0x4UL) /* FW_VER */
+#define GEN_VER_MASK (0x0000FFFFUL) /* HW_VER and FW_VER valid bits mask */
+#define GEN_HCR (GEN_CONFG_BASE + 0x8UL) /* HW_CODE, chip id */
+#define GEN_HCR_MASK (0x0000FFFFUL) /* HW_CODE valid bits mask */
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef struct _WMT_IC_INFO_S {
+ UINT32 u4HwVer; /* u4HwId */
+ PUINT8 cChipName;
+ PUINT8 cChipVersion;
+ PUINT8 cPatchNameExt;
+ MTK_WCN_BOOL bPsmSupport;
+ MTK_WCN_BOOL bWorkWithoutPatch;
+} WMT_IC_INFO_S, *P_WMT_IC_INFO_S;
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+INT32 mtk_wcn_soc_rom_patch_dwn(UINT32 ip_ver, UINT32 fw_ver);
+VOID mtk_wcn_soc_restore_wifi_cal_result(VOID);
+
+#endif /* _WMT_IC_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h
new file mode 100644
index 0000000000000000000000000000000000000000..afec898f8d5318109dd6b47b25f5f8f532314bb2
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _WMT_LIB_H_
+#define _WMT_LIB_H_
+
+
+#include "wmt_core.h"
+#include "wmt_exp.h"
+#include
+#include "stp_wmt.h"
+#include "wmt_plat.h"
+#include "wmt_idc.h"
+#include "osal.h"
+#include "mtk_wcn_consys_hw.h"
+
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+#define USE_NEW_PROC_FS_FLAG 1
+
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#define WMT_OP_BUF_SIZE (16)
+#if 0 /* moved to wmt_exp.h */
+#define WMT_LOG_LOUD 4
+#define WMT_LOG_DBG 3
+#define WMT_LOG_INFO 2
+#define WMT_LOG_WARN 1
+#define WMT_LOG_ERR 0
+#endif
+typedef enum _ENUM_WMTRSTRET_TYPE_T {
+ WMTRSTRET_SUCCESS = 0x0,
+ WMTRSTRET_FAIL = 0x1,
+ WMTRSTRET_ONGOING = 0x2,
+ WMTRSTRET_RETRY = 0x3,
+ WMTRSTRET_MAX
+} ENUM_WMTRSTRET_TYPE_T, *P_ENUM_WMTRSTRET_TYPE_T;
+
+#define MAX_ANT_RAM_CODE_DOWN_TIME 3000
+/*
+*3(retry times) * 180 (STP retry time out)
+*+ 10 (firmware process time) +
+*10 (transmit time) +
+*10 (uart process -> WMT response pool) +
+*230 (others)
+*/
+#define WMT_LIB_RX_TIMEOUT 2000 /*800-->cover v1.2phone BT function on time (~830ms) */
+/* Since GPS timeout is 6 seconds */
+#define WMT_LIB_RX_EXTEND_TIMEOUT 4000
+/*
+*open wifi during wifi power on procedure
+*(because wlan is insert to system after mtk_hif_sdio module,
+*so wifi card is not registered to hif module
+*when mtk_wcn_wmt_func_on is called by wifi through rfkill)
+*/
+#define MAX_WIFI_ON_TIME 5500
+
+#define WMT_PWRON_RTY_DFT 2
+#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT)
+#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY WMT_LIB_RX_TIMEOUT /*each WMT command */
+#define MAX_FUNC_ON_TIME (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT +\
+ MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3 + MAX_ANT_RAM_CODE_DOWN_TIME)
+
+/*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */
+#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000)
+#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4)
+
+/*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */
+#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000)
+
+/* For WMT OP who will have trouble if timeout really happens */
+#define MAX_WMT_OP_TIMEOUT (30000)
+
+#define MAX_GPIO_CTRL_TIME (2000) /* [FixMe][GeorgeKuo] a temp value */
+
+#define UTC_SYNC_TIME (60 * 60 * 1000)
+
+#define WMT_IDC_MSG_BUFFER 2048
+#define WMT_IDC_MSG_MAX_SIZE (WMT_IDC_MSG_BUFFER - 7) /* Subtract STP payload cmd size */
+
+#define MAX_PATCH_NUM (10)
+
+#define WMT_FIRMWARE_VERSION_LENGTH (14)
+#define WMT_FIRMWARE_MAX_FILE_NAME_LENGTH (50)
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/* AIF FLAG definition */
+/* bit(0): share pin or not */
+#define WMT_LIB_AIF_FLAG_MASK (0x1UL)
+#define WMT_LIB_AIF_FLAG_SHARE (0x1UL << 0)
+#define WMT_LIB_AIF_FLAG_SEPARATE (0x0UL << 0)
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/* bit field offset definition */
+typedef enum {
+ WMT_STAT_PWR = 0, /* is powered on */
+ WMT_STAT_STP_REG = 1, /* is STP driver registered: */
+ WMT_STAT_STP_OPEN = 2, /* is STP opened: default FALSE */
+ WMT_STAT_STP_EN = 3, /* is STP enabled: default FALSE */
+ WMT_STAT_STP_RDY = 4, /* is STP ready for client: default FALSE */
+ WMT_STAT_RX = 5, /* is rx data available */
+ WMT_STAT_CMD = 6, /* is cmd string to be read */
+ WMT_STAT_SDIO1_ON = 7, /* is SDIO1 on */
+ WMT_STAT_SDIO2_ON = 8, /* is SDIO2 on */
+ WMT_STAT_SDIO_WIFI_ON = 9, /* is Wi-Fi SDIO function on */
+ WMT_STAT_SDIO_STP_ON = 10, /* is STP SDIO function on */
+ WMT_STAT_RST_ON = 11,
+ WMT_STAT_MAX
+} WMT_STAT;
+
+typedef enum _ENUM_WMTRSTSRC_TYPE_T {
+ WMTRSTSRC_RESET_BT = 0x0,
+ WMTRSTSRC_RESET_FM = 0x1,
+ WMTRSTSRC_RESET_GPS = 0x2,
+ WMTRSTSRC_RESET_WIFI = 0x3,
+ WMTRSTSRC_RESET_STP = 0x4,
+ WMTRSTSRC_RESET_TEST = 0x5,
+ WMTRSTSRC_RESET_MAX
+} ENUM_WMTRSTSRC_TYPE_T, *P_ENUM_WMTRSTSRC_TYPE_T;
+
+enum wmt_fw_log_type {
+ WMT_FWLOG_MCU = 0,
+ WMT_FWLOG_MAX
+};
+
+typedef struct {
+ PF_WMT_CB fDrvRst[WMTDRV_TYPE_MAX];
+} WMT_FDRV_CB, *P_WMT_FDRV_CB;
+
+
+typedef struct {
+ UINT32 dowloadSeq;
+ UINT8 addRess[4];
+ UINT8 patchName[256];
+} WMT_PATCH_INFO, *P_WMT_PATCH_INFO;
+
+struct wmt_rom_patch_info {
+ UINT32 type;
+ UINT8 addRess[4];
+ UINT8 patchName[256];
+};
+
+struct wmt_vendor_patch {
+ union {
+ INT32 id;
+ INT32 type;
+ };
+ UINT8 file_name[WMT_FIRMWARE_MAX_FILE_NAME_LENGTH + 1];
+ UINT8 version[WMT_FIRMWARE_VERSION_LENGTH + 1];
+};
+
+struct vendor_patch_table {
+ UINT32 capacity;
+ UINT32 num;
+ INT8 status;
+ INT8 need_update;
+ PUINT8 *active_version;
+ struct wmt_vendor_patch *patch;
+};
+
+enum wmt_patch_type {
+ WMT_PATCH_TYPE_ROM = 0,
+ WMT_PATCH_TYPE_RAM,
+ WMT_PATCH_TYPE_WIFI
+};
+
+enum wmt_cp_status {
+ WMT_CP_INIT = 0,
+ WMT_CP_READY_TO_CHECK,
+ WMT_CP_CHECK_DONE
+};
+
+#define WMT_LIB_DMP_SLOT 2
+struct consys_state_dmp_req {
+ struct consys_state_dmp_op consys_ops[WMT_LIB_DMP_SLOT];
+ atomic_t version;
+};
+
+/* OS independent wrapper for WMT_OP */
+typedef struct _DEV_WMT_ {
+
+ OSAL_SLEEPABLE_LOCK psm_lock;
+ OSAL_SLEEPABLE_LOCK idc_lock;
+ OSAL_SLEEPABLE_LOCK wlan_lock;
+ OSAL_SLEEPABLE_LOCK assert_lock;
+ OSAL_SLEEPABLE_LOCK mpu_lock;
+ OSAL_SLEEPABLE_LOCK power_lock;
+ /* WMTd thread information */
+ /* struct task_struct *pWmtd; *//* main thread (wmtd) handle */
+ OSAL_THREAD thread;
+ /* wait_queue_head_t rWmtdWq; *//*WMTd command wait queue */
+ OSAL_EVENT rWmtdWq; /* rename */
+ OSAL_THREAD worker_thread;
+ OSAL_EVENT rWmtdWorkerWq;
+ /* ULONG state; *//* bit field of WMT_STAT */
+ OSAL_BIT_OP_VAR state;
+
+ /* STP context information */
+ /* wait_queue_head_t rWmtRxWq; *//* STP Rx wait queue */
+ OSAL_EVENT rWmtRxWq; /* rename */
+ /* WMT_STP_FUNC rStpFunc; *//* STP functions */
+ WMT_FDRV_CB rFdrvCb;
+
+ /* WMT Configurations */
+ WMT_HIF_CONF rWmtHifConf;
+ WMT_GEN_CONF rWmtGenConf;
+
+ /* Patch information */
+ UINT8 cPatchName[NAME_MAX + 1];
+ UINT8 cFullPatchName[NAME_MAX + 1];
+ UINT32 patchNum;
+
+ const osal_firmware *pPatch;
+
+ UINT8 cWmtcfgName[NAME_MAX + 1];
+
+ const osal_firmware *pWmtCfg;
+
+ const osal_firmware *pNvram;
+
+ /* Current used UART port description */
+ INT8 cUartName[NAME_MAX + 1];
+
+ OSAL_OP_Q rFreeOpQ; /* free op queue */
+ OSAL_OP_Q rActiveOpQ; /* active op queue */
+ OSAL_OP_Q rWorkerOpQ;
+ OSAL_OP arQue[WMT_OP_BUF_SIZE]; /* real op instances */
+ P_OSAL_OP pCurOP; /* current op */
+ P_OSAL_OP pWorkerOP; /* current op on worker thread */
+
+ /* cmd str buffer */
+ UINT8 cCmd[NAME_MAX + 1];
+ INT32 cmdResult;
+/* struct completion cmd_comp; */
+ /* wait_queue_head_t cmd_wq; *//* read command queues */
+ OSAL_SIGNAL cmdResp;
+ OSAL_EVENT cmdReq;
+
+ /* WMT loopback Thread Information */
+/* WMT_CMB_VER combo_ver; */
+ /* P_WMT_CMB_CHIP_INFO_S pChipInfo; */
+ UINT32 chip_id;
+ UINT32 hw_ver;
+ UINT32 fw_ver;
+ UINT32 ip_ver;
+
+ UINT32 ext_ldo_flag;
+ P_WMT_PATCH_INFO pWmtPatchInfo;
+ struct wmt_rom_patch_info *pWmtRomPatchInfo[WMTDRV_TYPE_ANT];
+ /* MET thread information */
+ OSAL_THREAD met_thread;
+ INT32 met_log_ctrl;
+ /* Timer to sync UTC time with connsys */
+ OSAL_TIMER utc_sync_timer;
+ struct work_struct utcSyncWorker;
+ /* Timer for wmt_worker_thread */
+ OSAL_TIMER worker_timer;
+ struct work_struct wmtd_worker_thread_work;
+ struct osal_op_history wmtd_op_history;
+ struct osal_op_history worker_op_history;
+ UINT8 msg_local_buffer[WMT_IDC_MSG_BUFFER];
+ struct vendor_patch_table patch_table;
+
+ struct consys_state_dmp_req state_dmp_req;
+
+} DEV_WMT, *P_DEV_WMT;
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+extern DEV_WMT gDevWmt;
+extern INT32 wmt_lib_init(VOID);
+extern INT32 wmt_lib_deinit(VOID);
+extern INT32 wmt_lib_tx(PUINT8 data, UINT32 size, PUINT32 writtenSize);
+extern INT32 wmt_lib_tx_raw(PUINT8 data, UINT32 size, PUINT32 writtenSize);
+extern INT32 wmt_lib_rx(PUINT8 buff, UINT32 buffLen, PUINT32 readSize);
+extern VOID wmt_lib_flush_rx(VOID);
+extern UINT32 wmt_lib_co_clock_flag_get(VOID);
+extern INT32 wmt_lib_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value);
+
+
+#if WMT_PLAT_ALPS
+extern PINT8 wmt_uart_port_desc; /* defined in mtk_wcn_cmb_stub_alps.cpp */
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime);
+extern INT32 wmt_lib_ps_init(VOID);
+extern INT32 wmt_lib_ps_deinit(VOID);
+extern INT32 wmt_lib_ps_enable(VOID);
+extern INT32 wmt_lib_ps_ctrl(UINT32 state);
+
+extern INT32 wmt_lib_ps_disable(VOID);
+extern VOID wmt_lib_ps_irq_cb(VOID);
+#endif
+extern VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+extern VOID wmt_lib_sdio_deep_sleep_flag_set_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb);
+#endif
+extern VOID wmt_lib_sdio_reg_rw_cb(PF_WMT_SDIO_DEBUG reg_rw_cb);
+extern INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl);
+extern INT32 wmt_lib_register_trigger_assert_cb(trigger_assert_cb trigger_assert);
+
+/* LXOP functions: */
+extern P_OSAL_OP wmt_lib_get_free_op(VOID);
+extern INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp);
+extern MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp);
+extern MTK_WCN_BOOL wmt_lib_put_worker_op(P_OSAL_OP pOp);
+
+/* extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); */
+extern UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T type);
+
+extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(ENUM_WMTTHERM_TYPE_T eType);
+extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID);
+extern INT32 wmt_lib_trigger_cmd_signal(INT32 result);
+extern PUINT8 wmt_lib_get_cmd(VOID);
+extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID);
+extern INT32 wmt_lib_set_patch_name(PUINT8 cPatchName);
+extern INT32 wmt_lib_set_uart_name(PINT8 cUartName);
+extern INT32 wmt_lib_set_hif(ULONG hifconf);
+extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID);
+extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID);
+
+/* GeorgeKuo: replace set_chip_gpio() with more specific ones */
+#if 0 /* moved to wmt_exp.h */
+extern INT32 wmt_lib_set_aif(enum CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */
+#endif
+extern INT32 wmt_lib_host_awake_get(VOID);
+extern INT32 wmt_lib_host_awake_put(VOID);
+extern UINT32 wmt_lib_dbg_level_set(UINT32 level);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+extern INT32 wmt_lib_deep_sleep_ctrl(INT32 value);
+extern MTK_WCN_BOOL wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL flag);
+#endif
+extern INT32 wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb);
+
+extern INT32 wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType);
+ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src);
+MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst);
+MTK_WCN_BOOL wmt_lib_hw_rst(VOID);
+INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask);
+INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask);
+INT32 wmt_lib_sdio_ctrl(UINT32 on);
+INT32 wmt_lib_met_ctrl(INT32 met_ctrl, INT32 log_ctrl);
+INT32 wmt_lib_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf,
+ UINT32 rx_data_buf_len, PUINT32 p_rx_data_len);
+VOID wmt_lib_set_ext_ldo(UINT32 flag);
+UINT32 wmt_lib_get_ext_ldo(VOID);
+INT32 wmt_lib_try_pwr_off(VOID);
+P_WMT_PATCH_INFO wmt_lib_get_patch_info(VOID);
+INT32 wmt_lib_met_cmd(UINT32 value);
+
+INT32 wmt_lib_blank_status_ctrl(UINT32 on_off_flag);
+VOID wmt_lib_set_blank_status(UINT32 on_off_flag);
+extern UINT32 wmt_lib_get_blank_status(VOID);
+
+extern INT32 DISABLE_PSM_MONITOR(VOID);
+extern VOID ENABLE_PSM_MONITOR(VOID);
+extern INT32 wmt_lib_notify_stp_sleep(VOID);
+extern VOID wmt_lib_psm_lock_release(VOID);
+extern INT32 wmt_lib_psm_lock_aquire(VOID);
+extern INT32 wmt_lib_psm_lock_trylock(VOID);
+extern VOID wmt_lib_idc_lock_release(VOID);
+extern INT32 wmt_lib_idc_lock_aquire(VOID);
+extern VOID wmt_lib_wlan_lock_release(VOID);
+extern INT32 wmt_lib_wlan_lock_trylock(VOID);
+extern INT32 wmt_lib_wlan_lock_aquire(VOID);
+extern VOID wmt_lib_assert_lock_release(VOID);
+extern INT32 wmt_lib_assert_lock_trylock(VOID);
+extern INT32 wmt_lib_assert_lock_aquire(VOID);
+extern VOID wmt_lib_mpu_lock_release(VOID);
+extern INT32 wmt_lib_mpu_lock_aquire(VOID);
+extern VOID wmt_lib_power_lock_release(VOID);
+extern INT32 wmt_lib_power_lock_trylock(VOID);
+extern INT32 wmt_lib_power_lock_aquire(VOID);
+extern INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value);
+
+extern VOID wmt_lib_set_patch_num(UINT32 num);
+extern VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo);
+extern VOID wmt_lib_set_rom_patch_info(struct wmt_rom_patch_info *PatchInfo, ENUM_WMTDRV_TYPE_T type);
+extern MTK_WCN_BOOL wmt_lib_stp_is_btif_fullset_mode(VOID);
+
+extern INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp);
+extern P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev);
+extern INT32 wmt_lib_set_worker_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp);
+extern P_OSAL_OP wmt_lib_get_worker_op(P_DEV_WMT pWmtDev);
+extern PUINT8 wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, PUINT8 buff, UINT32 len);
+extern INT32 wmt_lib_merge_if_flag_ctrl(UINT32 enable);
+extern INT32 wmt_lib_merge_if_flag_get(UINT32 enable);
+
+extern PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 len);
+extern PUINT8 wmt_lib_get_cpupcr_reg_info(PUINT32 len, PUINT32 consys_reg);
+extern UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en);
+extern INT8 wmt_lib_co_clock_get(VOID);
+extern UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver);
+extern VOID wmt_lib_dump_wmtd_backtrace(VOID);
+
+#if CFG_WMT_LTE_COEX_HANDLING
+extern MTK_WCN_BOOL wmt_lib_handle_idc_msg(conn_md_ipc_ilm_t *idc_infor);
+#endif
+extern UINT32 wmt_lib_get_drv_status(UINT32 type);
+extern INT32 wmt_lib_tm_temp_query(VOID);
+extern INT32 wmt_lib_trigger_reset(VOID);
+extern INT32 wmt_lib_trigger_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason);
+extern INT32 wmt_lib_trigger_assert_keyword(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword);
+extern VOID wmt_lib_trigger_assert_keyword_delay(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword);
+extern INT32 wmt_lib_wifi_fem_cfg_report(PVOID pvInfoBuf);
+#if CFG_WMT_PS_SUPPORT
+extern UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en);
+#endif
+extern UINT32 wmt_lib_fw_patch_update_rst_ctrl(UINT32 en);
+#if CONSYS_ENALBE_SET_JTAG
+extern UINT32 wmt_lib_jtag_flag_set(UINT32 en);
+#endif
+
+UINT32 wmt_lib_get_gps_lna_pin_num(VOID);
+extern INT32 wmt_lib_fw_log_ctrl(enum wmt_fw_log_type type, UINT8 onoff, UINT8 level);
+VOID wmt_lib_print_wmtd_op_history(VOID);
+VOID wmt_lib_print_worker_op_history(VOID);
+extern INT32 wmt_lib_get_vendor_patch_num(VOID);
+extern INT32 wmt_lib_set_vendor_patch_version(struct wmt_vendor_patch *p);
+extern INT32 wmt_lib_get_vendor_patch_version(struct wmt_vendor_patch *p);
+extern INT32 wmt_lib_set_check_patch_status(INT32 status);
+extern INT32 wmt_lib_get_check_patch_status(VOID);
+extern INT32 wmt_lib_set_active_patch_version(struct wmt_vendor_patch *p);
+extern INT32 wmt_lib_get_active_patch_version(struct wmt_vendor_patch *p);
+extern INT32 wmt_lib_get_need_update_patch_version(VOID);
+extern INT32 wmt_lib_set_need_update_patch_version(INT32 need);
+extern VOID wmt_lib_set_bt_link_status(INT32 type, INT32 value);
+VOID mtk_lib_set_mcif_mpu_protection(MTK_WCN_BOOL enable);
+INT32 wmt_lib_dmp_consys_state(P_CONSYS_STATE_DMP_INFO dmp_info,
+ UINT32 cpupcr_times, UINT32 slp_ms);
+
+extern INT32 wmt_lib_reg_readable(VOID);
+extern INT32 wmt_lib_reg_readable_by_addr(SIZE_T addr);
+extern INT32 wmt_lib_utc_time_sync(VOID);
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif /* _WMT_LIB_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..5e7220c86fcbf21e956ee5be848fb1333cfea9b9
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c
@@ -0,0 +1,2080 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include "osal_typedef.h"
+#include "osal.h"
+#include "psm_core.h"
+#include "stp_core.h"
+#include "stp_dbg.h"
+#include "wmt_detect.h"
+#include "wmt_exp.h"
+#include
+#include
+
+INT32 gPsmDbgLevel = STP_PSM_LOG_INFO;
+MTKSTP_PSM_T stp_psm_i;
+MTKSTP_PSM_T *stp_psm = &stp_psm_i;
+
+STP_PSM_RECORD_T *g_stp_psm_dbg;
+static UINT32 g_record_num;
+
+P_STP_PSM_OPID_RECORD g_stp_psm_opid_dbg;
+static UINT32 g_opid_record_num;
+
+static UINT32 stp_traffic_start;
+static UINT32 stp_traffic_current;
+
+#define STP_PSM_PR_LOUD(fmt, arg...) \
+do { \
+ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) \
+ pr_info(PFX_PSM "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_PSM_PR_DBG(fmt, arg...) \
+do { \
+ if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \
+ pr_info(PFX_PSM "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_PSM_PR_INFO(fmt, arg...) \
+do { \
+ if (gPsmDbgLevel >= STP_PSM_LOG_INFO) \
+ pr_info(PFX_PSM "[I]%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_PSM_PR_WARN(fmt, arg...) \
+do { \
+ if (gPsmDbgLevel >= STP_PSM_LOG_WARN) \
+ pr_warn(PFX_PSM "[W]%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_PSM_PR_ERR(fmt, arg...) \
+do { \
+ if (gPsmDbgLevel >= STP_PSM_LOG_ERR) \
+ pr_err(PFX_PSM "[E]%s(%d):ERROR! " fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+
+static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action);
+static INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm);
+static INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm);
+static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num);
+static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg);
+static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num);
+static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg);
+
+
+static const PINT8 g_psm_state[STP_PSM_MAX_STATE] = {
+ "ACT",
+ "ACT_INACT",
+ "INACT",
+ "INACT_ACT"
+};
+
+static const PINT8 g_psm_action[STP_PSM_MAX_ACTION] = {
+ "SLEEP",
+ "HOST_AWAKE",
+ "WAKEUP",
+ "EIRQ",
+ "ROLL_BACK"
+};
+
+static const PINT8 g_psm_op_name[STP_OPID_PSM_NUM] = {
+ "STP_OPID_PSM_SLEEP",
+ "STP_OPID_PSM_WAKEUP",
+ "STP_OPID_PSM_HOST_AWAKE",
+ "STP_OPID_PSM_EXIT"
+};
+
+static INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm);
+
+static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm);
+
+static INT32 _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ);
+
+static INT32 _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ);
+static MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID);
+
+ENUM_STP_TX_IF_TYPE __weak wmt_plat_get_comm_if_type(VOID)
+{
+ return STP_MAX_IF_TX;
+}
+
+MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(INT32 dbglevel)
+{
+ if (dbglevel >= 0 && dbglevel <= 4) {
+ gPsmDbgLevel = dbglevel;
+ STP_PSM_PR_INFO("gPsmDbgLevel = %d\n", gPsmDbgLevel);
+ return true;
+ }
+ STP_PSM_PR_INFO("invalid psm debug level. gPsmDbgLevel = %d\n", gPsmDbgLevel);
+ return false;
+}
+#if 0
+/* change from macro to static function to enforce type checking on parameters. */
+static INT32 psm_fifo_lock_init(MTKSTP_PSM_T *psm)
+{
+
+
+#if CFG_PSM_CORE_FIFO_SPIN_LOCK
+#if defined(CONFIG_PROVE_LOCKING)
+ osal_unsleepable_lock_init(&(psm->hold_fifo_lock));
+ return 0;
+#else
+ return osal_unsleepable_lock_init(&(psm->hold_fifo_lock));
+#endif
+#else
+#if defined(CONFIG_PROVE_LOCKING)
+ osal_sleepable_lock_init(&(psm->hold_fifo_lock));
+ return 0;
+#else
+ return osal_sleepable_lock_init(&(psm->hold_fifo_lock));
+#endif
+#endif
+}
+
+static INT32 psm_fifo_lock_deinit(MTKSTP_PSM_T *psm)
+{
+#if CFG_PSM_CORE_FIFO_SPIN_LOCK
+ return osal_unsleepable_lock_deinit(&(psm->hold_fifo_lock));
+#else
+ return osal_sleepable_lock_deinit(&(psm->hold_fifo_lock));
+#endif
+}
+
+static INT32 psm_fifo_lock(MTKSTP_PSM_T *psm)
+{
+
+
+#if CFG_PSM_CORE_FIFO_SPIN_LOCK
+ return osal_lock_unsleepable_lock(&(psm->hold_fifo_lock));
+#else
+ return osal_lock_sleepable_lock(&(psm->hold_fifo_lock));
+#endif
+}
+
+static INT32 psm_fifo_unlock(MTKSTP_PSM_T *psm)
+{
+
+
+#if CFG_PSM_CORE_FIFO_SPIN_LOCK
+ return osal_unlock_unsleepable_lock(&(psm->hold_fifo_lock));
+#else
+ return osal_unlock_sleepable_lock(&(psm->hold_fifo_lock));
+#endif
+}
+#endif
+static INT32 _stp_psm_handler(MTKSTP_PSM_T *stp_psm, P_STP_OP pStpOp)
+{
+ INT32 ret = -1;
+
+ /* if (NULL == pStpOp) */
+ /* { */
+ /* return -1; */
+ /* } */
+ ret = _stp_psm_thread_lock_aquire(stp_psm);
+ if (ret) {
+ STP_PSM_PR_ERR("--->lock psm_thread_lock failed ret=%d\n", ret);
+ return ret;
+ }
+
+ switch (pStpOp->opId) {
+ case STP_OPID_PSM_EXIT:
+ /* TODO: clean all up? */
+ ret = 0;
+ break;
+
+ case STP_OPID_PSM_SLEEP:
+ if (stp_psm_check_sleep_enable(stp_psm) > 0)
+ ret = _stp_psm_notify_wmt(stp_psm, SLEEP);
+ else
+ STP_PSM_PR_INFO("cancel sleep request\n");
+ break;
+
+ case STP_OPID_PSM_WAKEUP:
+ ret = _stp_psm_notify_wmt(stp_psm, WAKEUP);
+ break;
+
+ case STP_OPID_PSM_HOST_AWAKE:
+ ret = _stp_psm_notify_wmt(stp_psm, HOST_AWAKE);
+ break;
+
+ default:
+ STP_PSM_PR_ERR("invalid operation id (%d)\n", pStpOp->opId);
+ ret = -1;
+ break;
+ }
+ _stp_psm_thread_lock_release(stp_psm);
+ return ret;
+}
+
+static P_OSAL_OP _stp_psm_get_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ)
+{
+ P_OSAL_OP pOp;
+
+ if (!pOpQ) {
+ STP_PSM_PR_WARN("pOpQ == NULL\n");
+ return NULL;
+ }
+
+ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ /* acquire lock success */
+ RB_GET(pOpQ, pOp);
+
+ if ((pOpQ == &stp_psm->rActiveOpQ) && (pOp != NULL)) {
+ /* stp_psm->current_active_op = pOp; */
+ stp_psm->last_active_opId = pOp->op.opId;
+ }
+ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock));
+
+ if ((pOpQ == &stp_psm->rActiveOpQ) && (pOp != NULL))
+ STP_PSM_PR_DBG("last_active_opId(%d)\n", stp_psm->last_active_opId);
+
+ if (!pOp)
+ STP_PSM_PR_WARN("RB_GET fail\n");
+
+ return pOp;
+}
+
+static INT32 _stp_psm_dump_active_q(P_OSAL_OP_Q pOpQ)
+{
+ UINT32 read_idx;
+ UINT32 write_idx;
+ UINT32 opId;
+
+ if (pOpQ == &stp_psm->rActiveOpQ) {
+ read_idx = stp_psm->rActiveOpQ.read;
+ write_idx = stp_psm->rActiveOpQ.write;
+
+ STP_PSM_PR_DBG("Active op list:++\n");
+ while ((read_idx & RB_MASK(pOpQ)) != (write_idx & RB_MASK(pOpQ))) {
+ opId = pOpQ->queue[read_idx & RB_MASK(pOpQ)]->op.opId;
+ if (opId < STP_OPID_PSM_NUM)
+ STP_PSM_PR_DBG("%s\n", g_psm_op_name[opId]);
+ else
+ STP_PSM_PR_WARN("Unknown OP Id\n");
+ ++read_idx;
+ }
+ STP_PSM_PR_DBG("Active op list:--\n");
+ } else
+ STP_PSM_PR_DBG("%s: not active queue, dont dump\n", __func__);
+
+ return 0;
+}
+
+static INT32 _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ)
+{
+ UINT32 opId = 0;
+ UINT32 prev_opId = 0;
+
+ /* if((pOpQ == &stp_psm->rActiveOpQ) && (NULL != stp_psm->current_active_op)) */
+ if ((pOpQ == &stp_psm->rActiveOpQ) && (stp_psm->last_active_opId != STP_OPID_PSM_INALID)) {
+ opId = pOp->op.opId;
+
+ if (opId == STP_OPID_PSM_SLEEP) {
+ if (RB_EMPTY(pOpQ)) {
+ /* prev_opId = stp_psm->current_active_op->op.opId; */
+ prev_opId = stp_psm->last_active_opId;
+ } else {
+ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId;
+ }
+
+ if (prev_opId == STP_OPID_PSM_SLEEP) {
+ STP_PSM_PR_DBG("redundant sleep opId found\n");
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ if (RB_EMPTY(pOpQ)) {
+ /* prev_opId = stp_psm->current_active_op->op.opId; */
+ prev_opId = stp_psm->last_active_opId;
+ } else {
+ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId;
+ }
+
+ if (((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_WAKEUP)) ||
+ ((opId == STP_OPID_PSM_HOST_AWAKE)
+ && (prev_opId == STP_OPID_PSM_WAKEUP))
+ || ((opId == STP_OPID_PSM_HOST_AWAKE)
+ && (prev_opId == STP_OPID_PSM_HOST_AWAKE))
+ || ((opId == STP_OPID_PSM_WAKEUP)
+ && (prev_opId == STP_OPID_PSM_HOST_AWAKE))
+ ) {
+ STP_PSM_PR_DBG("redundant opId found, opId(%d), preOpid(%d)\n",
+ opId, prev_opId);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ } else {
+ return 0;
+ }
+
+}
+
+static INT32 _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ)
+{
+ UINT32 prev_opId = 0;
+ UINT32 prev_prev_opId = 0;
+
+ P_OSAL_OP pOp;
+ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ;
+
+ if (pOpQ == &stp_psm->rActiveOpQ) {
+ /* sleep , wakeup | sleep, --> null | sleep (x) */
+ /* wakeup , sleep , wakeup | sleep --> wakeup | sleep (v) */
+ /* sleep , wakeup , sleep | wakeup --> sleep | wakeup (v) */
+ /* xxx, sleep | sleep --> xxx, sleep (v) */
+ /* xxx, wakeup | wakeup --> xxx, wakeup (v) */
+ /* xxx, awake | awake --> xxx, awake (v) --> should never happen */
+ while (RB_COUNT(pOpQ) > 2) {
+ prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId;
+ prev_prev_opId = pOpQ->queue[(pOpQ->write - 2) & RB_MASK(pOpQ)]->op.opId;
+
+ if ((prev_opId == STP_OPID_PSM_SLEEP
+ && prev_prev_opId == STP_OPID_PSM_WAKEUP)
+ || (prev_opId == STP_OPID_PSM_SLEEP
+ && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE)
+ || (prev_opId == STP_OPID_PSM_WAKEUP
+ && prev_prev_opId == STP_OPID_PSM_SLEEP)
+ || (prev_opId == STP_OPID_PSM_HOST_AWAKE
+ && prev_prev_opId == STP_OPID_PSM_SLEEP)
+ ) {
+ RB_GET(pOpQ, pOp);
+ RB_PUT(pFreeOpQ, pOp);
+ RB_GET(pOpQ, pOp);
+ RB_PUT(pFreeOpQ, pOp);
+ } else if (prev_opId == prev_prev_opId) {
+ RB_GET(pOpQ, pOp);
+ if (!pOp) {
+ STP_PSM_PR_DBG("RB_GET pOp == NULL\n");
+ } else {
+ STP_PSM_PR_DBG("redundant opId(%d) found, remove it\n",
+ pOp->op.opId);
+ }
+ RB_PUT(pFreeOpQ, pOp);
+ } else
+ if ((prev_opId == STP_OPID_PSM_WAKEUP
+ && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE)
+ || (prev_opId == STP_OPID_PSM_HOST_AWAKE
+ && prev_prev_opId == STP_OPID_PSM_WAKEUP)) {
+ STP_PSM_PR_WARN("prev_opId(%d), prev_prev_opId(%d)\n", prev_opId,
+ prev_prev_opId);
+ RB_GET(pOpQ, pOp);
+ RB_PUT(pFreeOpQ, pOp);
+ } else {
+ STP_PSM_PR_ERR
+ ("prev_opId(%d), prev_prev_opId(%d), this should never happen!!!\n",
+ prev_opId, prev_prev_opId);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static INT32 _stp_psm_put_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp)
+{
+ INT32 ret;
+
+ /* if (!pOpQ || !pOp) */
+ /* { */
+ /* STP_PSM_PR_WARN("pOpQ = 0x%p, pLxOp = 0x%p\n", pOpQ, pOp); */
+ /* return 0; */
+ /* } */
+ ret = 0;
+
+ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ /* acquire lock success */
+ if (pOpQ == &stp_psm->rActiveOpQ) {
+ if (!_stp_psm_is_redundant_active_op(pOp, pOpQ)) {
+ /* acquire lock success */
+ if (!RB_FULL(pOpQ)) {
+ RB_PUT(pOpQ, pOp);
+ STP_PSM_PR_DBG("opId(%d) enqueue\n", pOp->op.opId);
+ } else {
+ STP_PSM_PR_INFO("************ Active Queue Full ************\n");
+ ret = -1;
+ }
+
+ _stp_psm_clean_up_redundant_active_op(pOpQ);
+ } else {
+ /*redundant opId, mark ret as success */
+ P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ;
+
+ if (!RB_FULL(pFreeOpQ))
+ RB_PUT(pFreeOpQ, pOp);
+ else
+ osal_assert(!RB_FULL(pFreeOpQ));
+ ret = 0;
+ }
+ } else {
+ if (!RB_FULL(pOpQ))
+ RB_PUT(pOpQ, pOp);
+ else
+ ret = -1;
+ }
+
+ if (pOpQ == &stp_psm->rActiveOpQ)
+ _stp_psm_dump_active_q(&stp_psm->rActiveOpQ);
+
+
+ if (ret) {
+ STP_PSM_PR_WARN("RB_FULL, RB_COUNT=%d , RB_SIZE=%d\n", RB_COUNT(pOpQ),
+ RB_SIZE(pOpQ));
+ osal_opq_dump_locked("FreeOpQ", &stp_psm->rFreeOpQ);
+ osal_opq_dump_locked("ActiveOpQ", &stp_psm->rActiveOpQ);
+ }
+
+ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ return ret ? 0 : 1;
+}
+
+P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm)
+{
+ P_OSAL_OP pOp;
+
+ if (stp_psm) {
+ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rFreeOpQ);
+ if (pOp) {
+ osal_memset(pOp, 0, osal_sizeof(OSAL_OP));
+ }
+ return pOp;
+ }
+ return NULL;
+}
+
+INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp)
+{
+ INT32 bRet = 0; /* MTK_WCN_BOOL_FALSE; */
+ INT32 wait_ret = -1;
+ P_OSAL_SIGNAL pSignal = NULL;
+ INT32 ret = 0;
+
+ do {
+ if (!stp_psm || !pOp) {
+ STP_PSM_PR_ERR("stp_psm = %p, pOp = %p\n", stp_psm, pOp);
+ break;
+ }
+
+ pSignal = &pOp->signal;
+
+ if (pSignal->timeoutValue) {
+ pOp->result = -9;
+ osal_signal_init(&pOp->signal);
+ }
+
+ /* Init ref_count to 2, as one is held by current thread, the second by psm thread */
+ atomic_set(&pOp->ref_count, 2);
+
+ /* put to active Q */
+ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rActiveOpQ, pOp);
+
+ if (bRet == 0) {
+ STP_PSM_PR_WARN("+++++++++++ Put op Active queue Fail\n");
+ atomic_dec(&pOp->ref_count);
+ break;
+ }
+ _stp_psm_opid_dbg_dmp_in(g_stp_psm_opid_dbg, pOp->op.opId, __LINE__);
+ /* wake up wmtd */
+ ret = osal_trigger_event(&stp_psm->STPd_event);
+
+ if (pSignal->timeoutValue == 0) {
+ bRet = 1; /* MTK_WCN_BOOL_TRUE; */
+ break;
+ }
+
+ /* check result */
+ wait_ret = osal_wait_for_signal_timeout(&pOp->signal, &stp_psm->PSMd);
+ STP_PSM_PR_DBG("wait completion:%d\n", wait_ret);
+ if (!wait_ret) {
+ STP_PSM_PR_ERR("wait completion timeout\n");
+ /* TODO: how to handle it? retry? */
+ } else {
+ if (pOp->result)
+ STP_PSM_PR_WARN("op(%d) result:%d\n", pOp->op.opId, pOp->result);
+ /* op completes, check result */
+ bRet = (pOp->result) ? 0 : 1;
+ }
+ } while (0);
+
+ if (pOp && atomic_dec_and_test(&pOp->ref_count)) {
+ /* put Op back to freeQ */
+ bRet = _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp);
+ if (bRet == 0)
+ STP_PSM_PR_WARN("+++++++++++ Put op active free fail, maybe disable/enable psm\n");
+ }
+
+ return bRet;
+}
+
+static INT32 _stp_psm_wait_for_msg(PVOID pvData)
+{
+ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *)pvData;
+
+ STP_PSM_PR_DBG("%s: stp_psm->rActiveOpQ = %d\n", __func__,
+ RB_COUNT(&stp_psm->rActiveOpQ));
+
+ return (!RB_EMPTY(&stp_psm->rActiveOpQ)) || osal_thread_should_stop(&stp_psm->PSMd);
+}
+
+static INT32 _stp_psm_proc(PVOID pvData)
+{
+ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData;
+ P_OSAL_OP pOp;
+ UINT32 id;
+ INT32 result;
+
+ if (!stp_psm) {
+ STP_PSM_PR_WARN("!stp_psm\n");
+ return -1;
+ }
+/* STP_PSM_PR_INFO("wmtd starts running: pWmtDev(0x%p) [pol, rt_pri, n_pri, pri]=[%d, %d, %d, %d]\n", */
+/* stp_psm, current->policy, current->rt_priority, current->normal_prio, current->prio); */
+
+ for (;;) {
+
+ pOp = NULL;
+ osal_wait_for_event(&stp_psm->STPd_event, _stp_psm_wait_for_msg, (PVOID) stp_psm);
+
+ /* we set reset flag when calling stp_reset after cleanup all op. */
+ if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) {
+ osal_clear_bit(STP_PSM_RESET_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ }
+ if (osal_thread_should_stop(&stp_psm->PSMd)) {
+ STP_PSM_PR_INFO("should stop now...\n");
+ /* TODO: clean up active opQ */
+ break;
+ }
+
+ /* get Op from activeQ */
+ pOp = _stp_psm_get_op(stp_psm, &stp_psm->rActiveOpQ);
+ if (!pOp) {
+ STP_PSM_PR_WARN
+ ("+++++++++++ Get op from activeQ fail, maybe disable/enable psm\n");
+ continue;
+ }
+ osal_op_history_save(&stp_psm->op_history, pOp);
+
+ id = osal_op_get_id(pOp);
+
+ if (id >= STP_OPID_PSM_NUM) {
+ STP_PSM_PR_WARN("abnormal opid id: 0x%x\n", id);
+ result = -1;
+ goto handler_done;
+ }
+
+ result = _stp_psm_handler(stp_psm, &pOp->op);
+
+
+handler_done:
+
+ if (result)
+ STP_PSM_PR_WARN("opid id(0x%x)(%s) error(%d)\n", id,
+ (id >= 4) ? ("???") : (g_psm_op_name[id]), result);
+
+ if (atomic_dec_and_test(&pOp->ref_count)) {
+ /* put Op back to freeQ */
+ if (_stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp) == 0)
+ STP_PSM_PR_WARN
+ ("+++++++++++ Put op to FreeOpQ fail, maybe disable/enable psm\n");
+ } else if (osal_op_is_wait_for_signal(pOp)) {
+ osal_op_raise_signal(pOp, result);
+ }
+
+ if (id == STP_OPID_PSM_EXIT)
+ break;
+ }
+ STP_PSM_PR_INFO("exits\n");
+
+ return 0;
+};
+
+static inline INT32 _stp_psm_get_time(VOID)
+{
+ if (gPsmDbgLevel >= STP_PSM_LOG_LOUD)
+ osal_printtimeofday(">>>");
+
+ return 0;
+}
+
+static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm)
+{
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ if (stp_psm->work_state < STP_PSM_MAX_STATE)
+ return stp_psm->work_state;
+ STP_PSM_PR_ERR("work_state = %d, invalid\n", stp_psm->work_state);
+ return -STP_PSM_OPERATION_FAIL;
+}
+
+static inline INT32 _stp_psm_set_state(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_STATE_T state)
+{
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ if (stp_psm->work_state < STP_PSM_MAX_STATE) {
+ _stp_psm_get_time();
+ /* STP_PSM_PR_INFO("work_state = %s --> %s\n",
+ * g_psm_state[stp_psm->work_state], g_psm_state[state]);
+ */
+ stp_psm->work_state = state;
+ if (stp_psm->work_state != ACT) {
+ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ osal_set_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag);
+ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ }
+ } else
+ STP_PSM_PR_ERR("work_state = %d, invalid\n", stp_psm->work_state);
+
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm)
+{
+
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) {
+ STP_PSM_PR_DBG("STP-PSM DISABLE, DONT restart monitor!\n\r");
+ return STP_PSM_OPERATION_SUCCESS;
+ }
+
+
+ STP_PSM_PR_LOUD("start monitor\n");
+ stp_traffic_start = stp_traffic_current;
+ osal_timer_modify(&stp_psm->psm_timer, stp_psm->idle_time_to_sleep);
+
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_stop_monitor(MTKSTP_PSM_T *stp_psm)
+{
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+ STP_PSM_PR_DBG("stop monitor\n");
+ osal_timer_stop_sync(&stp_psm->psm_timer);
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+INT32
+_stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const PUINT8 buffer, const UINT32 len, const UINT8 type)
+{
+ INT32 available_space = 0;
+ INT32 needed_space = 0;
+ UINT8 delimiter[] = { 0xbb, 0xbb };
+
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+ /*psm_fifo_lock(stp_psm);*/
+ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+ available_space = STP_PSM_FIFO_SIZE - osal_fifo_len(&stp_psm->hold_fifo);
+ needed_space = len + sizeof(UINT8) + sizeof(UINT32) + 2;
+ /* STP_PSM_PR_INFO("*******FIFO Available(%d), Need(%d)\n",
+ * available_space, needed_space);
+ */
+ if (available_space < needed_space) {
+ STP_PSM_PR_ERR("FIFO Available!! Reset FIFO\n");
+ osal_fifo_reset(&stp_psm->hold_fifo);
+ }
+ /* type */
+ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8));
+ /* length */
+ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32));
+ /* buffer */
+ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) buffer, len);
+ /* delimiter */
+ osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) delimiter, 2);
+ /*psm_fifo_unlock(stp_psm);*/
+ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+ return len;
+}
+
+INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm)
+{
+ return osal_fifo_len(&stp_psm->hold_fifo);
+}
+
+INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm)
+{
+
+ INT32 i = 20; /*Max buffered packet number */
+ INT32 ret = 0;
+ UINT8 type = 0;
+ UINT32 len = 0;
+ UINT8 delimiter[2] = {0};
+ INT32 winspace_flag = 0;
+
+ /* STP_PSM_PR_ERR("++++++++++release data++len=%d\n", osal_fifo_len(&stp_psm->hold_fifo)); */
+ while ((osal_fifo_len(&stp_psm->hold_fifo) && i > 0) || winspace_flag > 0) {
+ /* acquire spinlock */
+ /* psm_fifo_lock(stp_psm); */
+ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+
+ if (winspace_flag == 0) {
+ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)&type, sizeof(UINT8));
+ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)&len, sizeof(UINT32));
+
+ if (len > STP_PSM_PACKET_SIZE_MAX) {
+ STP_PSM_PR_ERR("***psm packet's length too Long!****\n");
+ STP_PSM_PR_INFO("***reset psm's fifo***\n");
+ } else {
+ osal_memset(stp_psm->out_buf, 0, STP_PSM_TX_SIZE);
+ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) stp_psm->out_buf, len);
+ }
+
+ ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)delimiter, 2);
+ }
+
+ if (delimiter[0] == 0xbb && delimiter[1] == 0xbb) {
+ /* osal_buffer_dump(stp_psm->out_buf, "psm->out_buf", len, 32); */
+ ret = stp_send_data_no_ps(stp_psm->out_buf, len, type);
+ if (ret == 0)
+ winspace_flag++;
+ else
+ winspace_flag = 0;
+ } else {
+ STP_PSM_PR_ERR("***psm packet fifo parsing fail****\n");
+ STP_PSM_PR_INFO("***reset psm's fifo***\n");
+
+ osal_fifo_reset(&stp_psm->hold_fifo);
+ }
+
+ if (winspace_flag == 0)
+ i--;
+ /* psm_fifo_unlock(stp_psm); */
+ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+
+ if (winspace_flag > 0 && winspace_flag < 10)
+ osal_sleep_ms(2);
+ else if (winspace_flag >= 10) {
+ STP_PSM_PR_ERR("***More than 20ms no winspace available***\n");
+ break;
+ }
+ }
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_notify_wmt_host_awake_wq(MTKSTP_PSM_T *stp_psm)
+{
+
+ P_OSAL_OP pOp;
+ INT32 bRet;
+ INT32 retval;
+
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ pOp = _stp_psm_get_free_op(stp_psm);
+ if (!pOp) {
+ STP_PSM_PR_DBG("get_free_lxop fail\n");
+ return -1; /* break; */
+ }
+ pOp->op.opId = STP_OPID_PSM_HOST_AWAKE;
+ pOp->signal.timeoutValue = 0;
+ bRet = _stp_psm_put_act_op(stp_psm, pOp);
+ STP_PSM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet);
+ retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : 0;
+ return retval;
+}
+
+static inline INT32 _stp_psm_notify_wmt_wakeup_wq(MTKSTP_PSM_T *stp_psm)
+{
+ P_OSAL_OP pOp;
+ INT32 bRet;
+ INT32 retval;
+
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ pOp = _stp_psm_get_free_op(stp_psm);
+ if (!pOp) {
+ STP_PSM_PR_DBG("get_free_lxop fail\n");
+ return -1; /* break; */
+ }
+ pOp->op.opId = STP_OPID_PSM_WAKEUP;
+ pOp->signal.timeoutValue = 0;
+ bRet = _stp_psm_put_act_op(stp_psm, pOp);
+ if (bRet == 0) {
+ STP_PSM_PR_WARN("OPID(%d) type(%zd) bRet(%s)\n\n",
+ pOp->op.opId, pOp->op.au4OpData[0], "fail");
+ }
+ retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : (STP_PSM_OPERATION_SUCCESS);
+ return retval;
+}
+
+static inline INT32 _stp_psm_notify_wmt_sleep_wq(MTKSTP_PSM_T *stp_psm)
+{
+ P_OSAL_OP pOp;
+ INT32 bRet;
+ INT32 retval;
+
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag))
+ return 0;
+#if PSM_USE_COUNT_PACKAGE
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag))
+ return 0;
+#endif
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag))
+ return 0;
+ pOp = _stp_psm_get_free_op(stp_psm);
+ if (!pOp) {
+ STP_PSM_PR_DBG("get_free_lxop fail\n");
+ return -1; /* break; */
+ }
+ pOp->op.opId = STP_OPID_PSM_SLEEP;
+ pOp->signal.timeoutValue = 0;
+ bRet = _stp_psm_put_act_op(stp_psm, pOp);
+ STP_PSM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet);
+ retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : 1;
+ return retval;
+}
+
+/*internal function*/
+
+static inline INT32 _stp_psm_reset(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 i = 0;
+ P_OSAL_OP_Q pOpQ;
+ P_OSAL_OP pOp;
+ INT32 ret = 0;
+
+ STP_PSM_PR_DBG("PSM MODE RESET=============================>\n\r");
+ STP_PSM_PR_DBG("_stp_psm_reset\n");
+ STP_PSM_PR_DBG("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock));
+ osal_wake_unlock(&stp_psm->wake_lock);
+ STP_PSM_PR_DBG("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock));
+ /* --> serialized the request from wmt <--// */
+ ret = osal_lock_sleepable_lock(&stp_psm->user_lock);
+ if (ret) {
+ STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+ /* --> disable psm <--// */
+ stp_psm->flag.data = 0;
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ _stp_psm_stop_monitor(stp_psm);
+ /* --> prepare the op list <--// */
+ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE);
+ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE);
+ /* stp_psm->current_active_op = NULL; */
+ stp_psm->last_active_opId = STP_OPID_PSM_INALID;
+ pOpQ = &stp_psm->rFreeOpQ;
+ for (i = 0; i < STP_OP_BUF_SIZE; i++) {
+ if (!RB_FULL(pOpQ)) {
+ pOp = &stp_psm->arQue[i];
+ RB_PUT(pOpQ, pOp);
+ }
+ }
+ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ /* --> clean up interal data structure<--// */
+ _stp_psm_set_state(stp_psm, ACT);
+ /*psm_fifo_lock(stp_psm);*/
+ osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+ osal_fifo_reset(&stp_psm->hold_fifo);
+ /*psm_fifo_unlock(stp_psm);*/
+ osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global);
+ /* --> stop psm thread wait <--*/
+ osal_set_bit(STP_PSM_RESET_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ osal_unlock_sleepable_lock(&stp_psm->user_lock);
+ STP_PSM_PR_DBG("PSM MODE RESET<============================\n\r");
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static INT32 _stp_psm_wait_wmt_event(PVOID pvData)
+{
+ MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData;
+
+ STP_PSM_PR_DBG("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data);
+ osal_ftrace_print("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data);
+
+ return (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) ||
+ (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) ||
+ (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) ||
+ (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag));
+
+}
+
+
+static inline INT32 _stp_psm_wait_wmt_event_wq(MTKSTP_PSM_T *stp_psm)
+{
+
+ INT32 retval = 0;
+ PUINT8 pbuf = NULL;
+ INT32 len = 0;
+
+ if (stp_psm == NULL)
+ return STP_PSM_OPERATION_FAIL;
+ osal_wait_for_event_timeout(&stp_psm->wait_wmt_q, _stp_psm_wait_wmt_event, (PVOID) stp_psm);
+
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 1 || mtk_wcn_stp_coredump_start_get() == 1) {
+ STP_PSM_PR_INFO("Host/Fw already triggered assert. Skip psm operation.\n");
+ return STP_PSM_OPERATION_FAIL;
+ }
+
+ if (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) {
+ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ /* STP send data here: STP enqueue data to psm buffer. */
+ _stp_psm_release_data(stp_psm);
+ /* STP send data here: STP enqueue data to psm buffer. We release packet by the next one. */
+ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* STP send data here: STP sends data directly without PSM. */
+ _stp_psm_set_state(stp_psm, ACT);
+ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ if (stp_psm_is_quick_ps_support())
+ stp_psm_notify_wmt_sleep(stp_psm);
+ else
+ _stp_psm_start_monitor(stp_psm);
+ } else if (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) {
+ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ _stp_psm_set_state(stp_psm, INACT);
+ STP_PSM_PR_DBG("mt_combo_plt_enter_deep_idle++\n");
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC)
+ mt_combo_plt_enter_deep_idle(COMBO_IF_BTIF);
+ else {
+ switch (wmt_plat_get_comm_if_type()) {
+ case STP_UART_IF_TX:
+ mt_combo_plt_enter_deep_idle(COMBO_IF_UART);
+ break;
+ case STP_SDIO_IF_TX:
+ mt_combo_plt_enter_deep_idle(COMBO_IF_MSDC);
+ break;
+ default:
+ break;
+ }
+ }
+ STP_PSM_PR_DBG("mt_combo_plt_enter_deep_idle--\n");
+ STP_PSM_PR_DBG("sleep-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock));
+ osal_wake_unlock(&stp_psm->wake_lock);
+ STP_PSM_PR_DBG("sleep-wake_lock#(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock));
+
+ if (osal_wake_lock_count(&stp_psm->wake_lock) == 0 && stp_psm->update_wmt_fw_patch_chip_rst != NULL)
+ stp_psm->update_wmt_fw_patch_chip_rst();
+ } else if (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) {
+ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ if (_stp_psm_get_state(stp_psm) == ACT_INACT) {
+ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ _stp_psm_release_data(stp_psm);
+ osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ _stp_psm_set_state(stp_psm, ACT);
+ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ } else if (_stp_psm_get_state(stp_psm) == INACT_ACT) {
+ _stp_psm_set_state(stp_psm, INACT);
+ STP_PSM_PR_INFO("[WARNING]PSM state rollback due too wakeup fail\n");
+ }
+ } else if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) {
+ osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ } else {
+ STP_PSM_PR_ERR("state = %d, flag = %ld<== Abnormal flag be set!!\n\r",
+ stp_psm->work_state, stp_psm->flag.data);
+ mtk_wcn_wmt_dump_wmtd_backtrace();
+ /* wcn_psm_flag_trigger_collect_ftrace(); */ /* trigger collect SYS_FTRACE */
+ pbuf = "Abnormal PSM flag be set, just collect SYS_FTRACE to DB";
+ len = osal_strlen(pbuf);
+ stp_dbg_trigger_collect_ftrace(pbuf, len);
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ }
+ retval = STP_PSM_OPERATION_SUCCESS;
+ return retval;
+}
+
+static inline INT32 _stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action)
+{
+
+ INT32 retval = STP_PSM_OPERATION_SUCCESS;
+
+ if (action < 0 || action >= STP_PSM_MAX_ACTION)
+ return STP_PSM_OPERATION_FAIL;
+
+ if (action == EIRQ) {
+ STP_PSM_PR_DBG("Call _stp_psm_notify_wmt_host_awake_wq\n\r");
+ _stp_psm_notify_wmt_host_awake_wq(stp_psm);
+ return STP_PSM_OPERATION_FAIL;
+ }
+ if ((_stp_psm_get_state(stp_psm) < STP_PSM_MAX_STATE) && (_stp_psm_get_state(stp_psm) >= 0)) {
+ STP_PSM_PR_DBG("state = %s, action=%s\n\r",
+ g_psm_state[_stp_psm_get_state(stp_psm)], g_psm_action[action]);
+ }
+ /* If STP trigger WAKEUP and SLEEP, to do the job below */
+ switch (_stp_psm_get_state(stp_psm)) {
+ /* stp trigger */
+ case ACT_INACT:
+ if (action == SLEEP) {
+ STP_PSM_PR_LOUD("Action = %s, ACT_INACT state, ready to INACT\n\r",
+ g_psm_action[action]);
+ osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ osal_set_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* wake_up(&stp_psm->wait_wmt_q); */
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ } else if (action == ROLL_BACK) {
+ STP_PSM_PR_LOUD("Action = %s, ACT_INACT state, back to ACT\n\r",
+ g_psm_action[action]);
+ /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */
+ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* wake_up(&stp_psm->wait_wmt_q); */
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ } else {
+ if (action < STP_PSM_MAX_ACTION) {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ } else {
+ STP_PSM_PR_ERR("Invalid Action!!\n\r");
+ }
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+
+ retval = STP_PSM_OPERATION_FAIL;
+ }
+ break;
+ /* stp trigger */
+ case INACT_ACT:
+ if (action == WAKEUP) {
+ STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, ready to ACT\n\r",
+ g_psm_action[action]);
+ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* wake_up(&stp_psm->wait_wmt_q); */
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ } else if (action == HOST_AWAKE) {
+ STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, ready to ACT\n\r",
+ g_psm_action[action]);
+ osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* wake_up(&stp_psm->wait_wmt_q); */
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ } else if (action == ROLL_BACK) {
+ STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, back to INACT\n\r",
+ g_psm_action[action]);
+ /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */
+ osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ /* wake_up(&stp_psm->wait_wmt_q); */
+ osal_trigger_event(&stp_psm->wait_wmt_q);
+ } else {
+ if (action < STP_PSM_MAX_ACTION) {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ } else {
+ STP_PSM_PR_ERR("Invalid Action!!\n\r");
+ }
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ retval = STP_PSM_OPERATION_FAIL;
+ }
+ break;
+ case INACT:
+ if (action < STP_PSM_MAX_ACTION) {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ } else {
+ STP_PSM_PR_ERR("Invalid Action!!\n\r");
+ }
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ retval = -1;
+ break;
+ case ACT:
+ if (action < STP_PSM_MAX_ACTION) {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ } else {
+ STP_PSM_PR_ERR("Invalid Action!!\n\r");
+ }
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+
+ retval = STP_PSM_OPERATION_FAIL;
+ break;
+ default:
+ /*invalid */
+ if (action < STP_PSM_MAX_ACTION) {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ } else {
+ STP_PSM_PR_ERR("Invalid Action!!\n\r");
+ }
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+
+ retval = STP_PSM_OPERATION_FAIL;
+ break;
+ }
+ return retval;
+}
+
+static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action)
+{
+ INT32 ret = STP_PSM_OPERATION_SUCCESS;
+
+ if (stp_psm == NULL || action < 0 || action >= STP_PSM_MAX_ACTION)
+ return STP_PSM_OPERATION_FAIL;
+
+ switch (_stp_psm_get_state(stp_psm)) {
+ case ACT:
+
+ if (action == SLEEP) {
+ osal_lock_sleepable_lock(&stp_psm->user_lock);
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) {
+ STP_PSM_PR_ERR("psm monitor disabled, can't do sleep op\n");
+ osal_unlock_sleepable_lock(&stp_psm->user_lock);
+ return STP_PSM_OPERATION_FAIL;
+ }
+
+ _stp_psm_set_state(stp_psm, ACT_INACT);
+ osal_unlock_sleepable_lock(&stp_psm->user_lock);
+ _stp_psm_release_data(stp_psm);
+
+ if (stp_psm->wmt_notify) {
+ ret = stp_psm->wmt_notify(SLEEP);
+ if (!ret)
+ _stp_psm_wait_wmt_event_wq(stp_psm);
+ else
+ STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n");
+
+ } else {
+ STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n");
+ ret = STP_PSM_OPERATION_FAIL;
+ }
+ } else if (action == WAKEUP || action == HOST_AWAKE) {
+ STP_PSM_PR_DBG("In ACT state, dont do WAKEUP/HOST_AWAKE again\n");
+ _stp_psm_release_data(stp_psm);
+ } else {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ ret = STP_PSM_OPERATION_FAIL;
+
+ }
+
+ break;
+
+ case INACT:
+
+ if (action == WAKEUP) {
+ _stp_psm_set_state(stp_psm, INACT_ACT);
+
+ if (stp_psm->wmt_notify) {
+ STP_PSM_PR_DBG("wakeup +wake_lock(%d)\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+ osal_wake_lock(&stp_psm->wake_lock);
+ STP_PSM_PR_DBG("wakeup +wake_lock(%d)#\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+
+ STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle++\n");
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC)
+ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF);
+ else {
+ switch (wmt_plat_get_comm_if_type()) {
+ case STP_UART_IF_TX:
+ mt_combo_plt_exit_deep_idle(COMBO_IF_UART);
+ break;
+ case STP_SDIO_IF_TX:
+ mt_combo_plt_exit_deep_idle(COMBO_IF_MSDC);
+ break;
+ default:
+ break;
+ }
+ }
+ STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle--\n");
+
+ ret = stp_psm->wmt_notify(WAKEUP);
+ if (!ret)
+ _stp_psm_wait_wmt_event_wq(stp_psm);
+ else
+ STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n");
+ } else {
+ STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n");
+ ret = STP_PSM_OPERATION_FAIL;
+ }
+ } else if (action == HOST_AWAKE) {
+ _stp_psm_set_state(stp_psm, INACT_ACT);
+
+ if (stp_psm->wmt_notify) {
+ STP_PSM_PR_DBG("host awake +wake_lock(%d)\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+ osal_wake_lock(&stp_psm->wake_lock);
+ STP_PSM_PR_DBG("host awake +wake_lock(%d)#\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+
+ STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle++\n");
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC)
+ mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF);
+ else {
+ switch (wmt_plat_get_comm_if_type()) {
+ case STP_UART_IF_TX:
+ mt_combo_plt_exit_deep_idle(COMBO_IF_UART);
+ break;
+ case STP_SDIO_IF_TX:
+ mt_combo_plt_exit_deep_idle(COMBO_IF_MSDC);
+ break;
+ default:
+ break;
+ }
+ }
+ STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle--\n");
+
+ ret = stp_psm->wmt_notify(HOST_AWAKE);
+ if (!ret)
+ _stp_psm_wait_wmt_event_wq(stp_psm);
+ else
+ STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n");
+ } else {
+ STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n");
+ ret = STP_PSM_OPERATION_FAIL;
+ }
+ } else if (action == SLEEP) {
+ STP_PSM_PR_INFO("In INACT state, dont do SLEEP again\n");
+ } else {
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ ret = STP_PSM_OPERATION_FAIL;
+ }
+
+ break;
+
+ default:
+
+ /*invalid */
+ STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n",
+ g_psm_action[action],
+ stp_psm->work_state, stp_psm->flag.data);
+ _stp_psm_dbg_out_printk(g_stp_psm_dbg);
+ ret = STP_PSM_OPERATION_FAIL;
+
+ break;
+ }
+ return ret;
+}
+
+static inline VOID _stp_psm_stp_is_idle(timer_handler_arg arg)
+{
+ ULONG data;
+ MTKSTP_PSM_T *stp_psm;
+
+ GET_HANDLER_DATA(arg, data);
+ stp_psm = (MTKSTP_PSM_T *) data;
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) {
+ STP_PSM_PR_DBG("STP-PSM DISABLE!\n");
+ return;
+ }
+
+ if (stp_traffic_start != stp_traffic_current) {
+ STP_PSM_PR_DBG("Timer extension due to ongoing traffic (%d, %d)\n",
+ stp_traffic_start, stp_traffic_current);
+ stp_psm_start_monitor(stp_psm);
+ return;
+ }
+
+ STP_PSM_PR_DBG("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep);
+ osal_ftrace_print("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep);
+ _stp_psm_notify_wmt_sleep_wq(stp_psm);
+}
+
+static inline INT32 _stp_psm_init_monitor(MTKSTP_PSM_T *stp_psm)
+{
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+ STP_PSM_PR_DBG("init monitor\n");
+ stp_psm->psm_timer.timeoutHandler = _stp_psm_stp_is_idle;
+ stp_psm->psm_timer.timeroutHandlerData = (ULONG)stp_psm;
+ osal_timer_create(&stp_psm->psm_timer);
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_deinit_monitor(MTKSTP_PSM_T *stp_psm)
+{
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+ STP_PSM_PR_INFO("deinit monitor\n");
+ osal_timer_stop_sync(&stp_psm->psm_timer);
+ return 0;
+}
+static inline INT32 _stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 iRet = -1;
+ /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ if (osal_test_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag))
+ iRet = 1;
+ else
+ iRet = 0;
+ /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */
+ return iRet;
+}
+
+static inline INT32 _stp_psm_is_disable(MTKSTP_PSM_T *stp_psm)
+{
+ if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag))
+ return 1;
+ return 0;
+}
+
+static inline INT32 _stp_psm_do_wait(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state)
+{
+#define POLL_WAIT 20 /* 200 */
+#define POLL_WAIT_TIME 2000
+ INT32 i = 0;
+ INT32 limit = POLL_WAIT_TIME / POLL_WAIT;
+ UINT64 sec = 0;
+ ULONG usec = 0;
+
+ if (state < 0 || state >= STP_PSM_MAX_STATE)
+ return STP_PSM_OPERATION_FAIL;
+
+ osal_get_local_time(&sec, &usec);
+ while (_stp_psm_get_state(stp_psm) != state && i < limit && mtk_wcn_stp_is_enable()) {
+ i++;
+ if (i < 3)
+ STP_PSM_PR_INFO("STP is waiting state for %s, i=%d, state = %d\n",
+ g_psm_state[state], i, _stp_psm_get_state(stp_psm));
+ osal_sleep_ms(POLL_WAIT);
+ if (i == 10) {
+ STP_PSM_PR_WARN("-Wait for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT);
+ _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg);
+ }
+ }
+ if (mtk_wcn_stp_is_enable() == 0) {
+ STP_PSM_PR_INFO("STP disable, maybe do chip reset");
+ return STP_PSM_OPERATION_FAIL;
+ }
+
+ if (i == limit) {
+ STP_PSM_PR_WARN("-Wait for %s takes %llu usec\n", g_psm_state[state], osal_elapsed_us(sec, usec));
+ mtk_wcn_wmt_dump_wmtd_backtrace();
+ _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg);
+ return STP_PSM_OPERATION_FAIL;
+ }
+ if (i > 0)
+ STP_PSM_PR_INFO("+Total waits for %s takes %llu usec\n",
+ g_psm_state[state], osal_elapsed_us(sec, usec));
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = 0;
+ INT32 retry = 10;
+ P_OSAL_OP_Q pOpQ;
+ P_OSAL_OP pOp;
+
+ STP_PSM_PR_LOUD("*** Do Force Wakeup!***\n\r");
+ /* <1>If timer is active, we will stop it. */
+ _stp_psm_stop_monitor(stp_psm);
+ osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ pOpQ = &stp_psm->rFreeOpQ;
+ while (!RB_EMPTY(&stp_psm->rActiveOpQ)) {
+ RB_GET(&stp_psm->rActiveOpQ, pOp);
+ if (pOp != NULL && !RB_FULL(pOpQ))
+ RB_PUT(pOpQ, pOp);
+ else
+ STP_PSM_PR_ERR("clear up active queue fail, freeQ full\n");
+ }
+ osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock));
+ /* <5>We issue wakeup request into op queue. and wait for active. */
+ do {
+ ret = _stp_psm_notify_wmt_wakeup_wq(stp_psm);
+ if (ret == STP_PSM_OPERATION_SUCCESS) {
+ ret = _stp_psm_do_wait(stp_psm, ACT);
+ /* STP_PSM_PR_INFO("<< wait ret = %d, num of activeQ = %d\n", ret,
+ * RB_COUNT(&stp_psm->rActiveOpQ));
+ */
+ if (ret == STP_PSM_OPERATION_SUCCESS)
+ break;
+ } else
+ STP_PSM_PR_ERR("_stp_psm_notify_wmt_wakeup_wq fail, retry = %d !!\n", retry);
+ /* STP_PSM_PR_INFO("retry = %d\n", retry); */
+ retry--;
+ if (retry == 0)
+ break;
+ } while (1);
+ if (retry == 0)
+ return STP_PSM_OPERATION_FAIL;
+ return STP_PSM_OPERATION_SUCCESS;
+}
+
+static inline INT32 _stp_psm_disable(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = STP_PSM_OPERATION_FAIL;
+ P_OSAL_THREAD psm_thread;
+
+ STP_PSM_PR_DBG("PSM Disable start\n\r");
+ ret = osal_lock_sleepable_lock(&stp_psm->user_lock);
+ if (ret) {
+ STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ ret = _stp_psm_do_wakeup(stp_psm);
+ osal_unlock_sleepable_lock(&stp_psm->user_lock);
+ if (ret == STP_PSM_OPERATION_SUCCESS)
+ STP_PSM_PR_DBG("PSM Disable Success\n");
+ else {
+ STP_PSM_PR_ERR("***PSM Disable Fail***\n");
+ psm_thread = &stp_psm_i.PSMd;
+ osal_thread_show_stack(psm_thread);
+ }
+ return ret;
+}
+
+static inline INT32 _stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep)
+{
+ INT32 ret = STP_PSM_OPERATION_FAIL;
+
+ STP_PSM_PR_LOUD("PSM Enable start\n\r");
+ ret = osal_lock_sleepable_lock(&stp_psm->user_lock);
+ if (ret) {
+ STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ ret = _stp_psm_do_wakeup(stp_psm);
+ if (ret == STP_PSM_OPERATION_SUCCESS) {
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ stp_psm->idle_time_to_sleep = idle_time_to_sleep;
+ if (osal_wake_lock_count(&stp_psm->wake_lock) == 0) {
+ STP_PSM_PR_DBG("psm_en+wake_lock(%d)\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+ osal_wake_lock(&stp_psm->wake_lock);
+ STP_PSM_PR_DBG("psm_en+wake_lock(%d)#\n",
+ osal_wake_lock_count(&stp_psm->wake_lock));
+ }
+ _stp_psm_start_monitor(stp_psm);
+ STP_PSM_PR_DBG("PSM Enable succeed\n\r");
+ } else
+ STP_PSM_PR_ERR("***PSM Enable Fail***\n");
+ osal_unlock_sleepable_lock(&stp_psm->user_lock);
+ return ret;
+}
+
+INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm)
+{
+ return osal_lock_sleepable_lock(&stp_psm->stp_psm_lock);
+}
+
+INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm)
+{
+ osal_unlock_sleepable_lock(&stp_psm->stp_psm_lock);
+ return 0;
+}
+
+MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID)
+{
+ if (stp_psm->is_wmt_quick_ps_support)
+ return (*(stp_psm->is_wmt_quick_ps_support)) ();
+ STP_PSM_PR_DBG("stp_psm->is_wmt_quick_ps_support is NULL, return false\n\r");
+ return MTK_WCN_BOOL_FALSE;
+}
+
+
+MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID)
+{
+ return _stp_psm_is_quick_ps_support();
+}
+
+#if PSM_USE_COUNT_PACKAGE
+INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir)
+{
+ /* easy the variable maintain beween stp tx, rx thread. */
+ /* so we create variable for tx, rx respectively. */
+ static INT32 tx_cnt;
+ static INT32 rx_cnt;
+ INT32 tx_cnt_th = MTK_COMBO_PSM_TX_TH_DEFAULT;
+ INT32 rx_cnt_th = MTK_COMBO_PSM_RX_TH_DEFAULT;
+ static INT32 is_tx_first = 1;
+ static INT32 is_rx_first = 1;
+ static ULONG tx_end_time;
+ static ULONG rx_end_time;
+ long res;
+
+ /* */
+ /* BT A2DP TX CNT = 220, RX CNT = 843 */
+ /* BT FTP Transferring TX CNT = 574, RX CNT = 2233 (1228~1588) */
+ /* BT FTP Receiving TX CNT = 204, RX CNT = 3301 (2072~2515) */
+ /* BT OPP Tx TX_CNT= 330, RX CNT = 1300~1800 */
+ /* BT OPP Rx TX_CNT= (109~157), RX CNT = 1681~2436 */
+/* #if defined(MTK_COMBO_PSM_RX_TH)
+* osal_strtol(MTK_COMBO_PSM_RX_TH, 10, &res);
+* rx_cnt_th = (INT32)res;
+* #endif
+* #if defined(MTK_COMBO_PSM_TX_TH)
+* osal_strtol(MTK_COMBO_PSM_TX_TH, 10, &res);
+* tx_cnt_th = (INT32)res;
+* #endif
+*/
+ STP_PSM_PR_DBG("RX TH:%d; TX TH:%d\n\r", rx_cnt_th, tx_cnt_th);
+ stp_traffic_current++;
+ if (dir == 0) { /* tx */
+ tx_cnt++;
+ if (((long)jiffies - (long)tx_end_time >= 0) || (is_tx_first)) {
+ tx_end_time = jiffies + (3 * HZ);
+ STP_PSM_PR_INFO("tx cnt = %d in the previous 3 sec,tx_th = %d\n", tx_cnt,
+ tx_cnt_th);
+ /* if(tx_cnt > 400)//for high traffic , not to do sleep. */
+ if (tx_cnt > tx_cnt_th) {
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY,
+ &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ stp_psm_start_monitor(stp_psm);
+ } else {
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY,
+ &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ }
+ tx_cnt = 0;
+ if (is_tx_first)
+ is_tx_first = 0;
+ }
+ } else {
+ rx_cnt++;
+
+ if (((long)jiffies - (long)rx_end_time >= 0) || (is_rx_first)) {
+ rx_end_time = jiffies + (3 * HZ);
+ STP_PSM_PR_INFO("rx cnt = %d in the previous 3 sec, rx_th = %d\n", rx_cnt,
+ rx_cnt_th);
+
+ /* if(rx_cnt > 2000)//for high traffic , not to do sleep. */
+ if (rx_cnt > rx_cnt_th) { /* for high traffic , not to do sleep. */
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY,
+ &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ stp_psm_start_monitor(stp_psm);
+ } else {
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY,
+ &stp_psm->flag);
+ _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__);
+ }
+ rx_cnt = 0;
+ if (is_rx_first)
+ is_rx_first = 0;
+ }
+ }
+
+ return 0;
+}
+#else
+static struct timeval tv_now, tv_end;
+static INT32 sample_start;
+static INT32 tx_sum_len;
+static INT32 rx_sum_len;
+
+INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length)
+{
+ stp_traffic_current++;
+ if (sample_start) {
+ if (dir)
+ rx_sum_len += length;
+ else
+ tx_sum_len += length;
+
+ osal_do_gettimeofday(&tv_now);
+ /* STP_PSM_PR_INFO("tv_now:%d.%d tv_end:%d.%d\n", tv_now.tv_sec, tv_now.tv_usec,
+ * tv_end.tv_sec,tv_end.tv_usec);
+ */
+ if (((tv_now.tv_sec == tv_end.tv_sec) && (tv_now.tv_usec > tv_end.tv_usec)) ||
+ (tv_now.tv_sec > tv_end.tv_sec)) {
+ STP_PSM_PR_INFO("STP speed rx:%d tx:%d\n", rx_sum_len, tx_sum_len);
+ if ((rx_sum_len + tx_sum_len) > RTX_SPEED_THRESHOLD) {
+ STP_PSM_PR_INFO("High speed,Disable monitor\n");
+ osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag);
+ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP_1000;
+ stp_psm_start_monitor(stp_psm);
+ } else {
+ STP_PSM_PR_INFO("Low speed,Enable monitor\n");
+ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP;
+ osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag);
+ }
+ wmt_lib_ps_set_idle_time(stp_psm->idle_time_to_sleep);
+ sample_start = 0;
+ rx_sum_len = 0;
+ tx_sum_len = 0;
+ }
+ } else {
+ sample_start = 1;
+ osal_do_gettimeofday(&tv_now);
+ tv_end = tv_now;
+ tv_end.tv_sec += SAMPLE_DURATION;
+ }
+
+ return 0;
+}
+#endif
+
+/*external function for WMT module to do sleep/wakeup*/
+INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state)
+{
+ return _stp_psm_set_state(stp_psm, state);
+}
+
+
+INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_thread_lock_aquire(stp_psm);
+}
+
+
+INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_thread_lock_release(stp_psm);
+}
+
+
+
+INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_do_wakeup(stp_psm);
+}
+
+INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action)
+{
+
+ return _stp_psm_notify_stp(stp_psm, action);
+}
+
+INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_notify_wmt_wakeup_wq(stp_psm);
+}
+
+INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm)
+{
+
+ return _stp_psm_notify_wmt_sleep_wq(stp_psm);
+}
+
+INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_start_monitor(stp_psm);
+}
+
+INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_is_to_block_traffic(stp_psm);
+}
+
+INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_is_disable(stp_psm);
+}
+
+INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_has_pending_data(stp_psm);
+}
+
+INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_release_data(stp_psm);
+}
+
+INT32
+stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const PUINT8 buffer, const UINT32 len, const UINT8 type)
+{
+ return _stp_psm_hold_data(stp_psm, buffer, len, type);
+}
+
+INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_disable(stp_psm);
+}
+
+INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep)
+{
+ return _stp_psm_enable(stp_psm, idle_time_to_sleep);
+}
+
+INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm)
+{
+ stp_psm_set_sleep_enable(stp_psm);
+
+ return _stp_psm_reset(stp_psm);
+}
+
+INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm)
+{
+ return _stp_psm_notify_wmt_sleep_wq(stp_psm);
+}
+
+
+INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = 0;
+
+ if (stp_psm) {
+ stp_psm->sleep_en = 1;
+ STP_PSM_PR_DBG("\n");
+ ret = 0;
+ } else {
+ STP_PSM_PR_INFO("Null pointer\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = 0;
+
+ if (stp_psm) {
+ stp_psm->sleep_en = 0;
+ STP_PSM_PR_DBG("\n");
+ ret = 0;
+ } else {
+ STP_PSM_PR_INFO("Null pointer\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/* stp_psm_check_sleep_enable - to check if sleep cmd is enabled or not
+ * @ stp_psm - pointer of psm
+ *
+ * return 1 if sleep is enabled; else return 0 if disabled; else error code
+ */
+INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = 0;
+
+ if (stp_psm) {
+ ret = stp_psm->sleep_en;
+ STP_PSM_PR_DBG("%s\n", ret ? "enabled" : "disabled");
+ } else {
+ STP_PSM_PR_INFO("Null pointer\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num)
+{
+ INT32 index = 0;
+ struct timeval now;
+
+ if (stp_psm_dbg) {
+ osal_lock_unsleepable_lock(&stp_psm_dbg->lock);
+ osal_do_gettimeofday(&now);
+ index = stp_psm_dbg->in - 1;
+ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE;
+ STP_PSM_PR_DBG("index(%d)\n", index);
+ stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag = stp_psm_dbg->queue[index].cur_flag;
+ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag = flag;
+ stp_psm_dbg->queue[stp_psm_dbg->in].line_num = line_num;
+ stp_psm_dbg->queue[stp_psm_dbg->in].package_no = g_record_num++;
+ stp_psm_dbg->queue[stp_psm_dbg->in].sec = now.tv_sec;
+ stp_psm_dbg->queue[stp_psm_dbg->in].usec = now.tv_usec;
+ stp_psm_dbg->size++;
+ STP_PSM_PR_DBG("pre_Flag = %d, cur_flag = %d\n", stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag,
+ stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag);
+ stp_psm_dbg->size = (stp_psm_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : stp_psm_dbg->size;
+ stp_psm_dbg->in = (stp_psm_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (stp_psm_dbg->in + 1);
+ STP_PSM_PR_DBG("record size = %d, in = %d num = %d\n", stp_psm_dbg->size, stp_psm_dbg->in, line_num);
+
+ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock);
+ }
+ return 0;
+}
+
+static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg)
+{
+
+ UINT32 dumpSize = 0;
+ UINT32 inIndex = 0;
+ UINT32 outIndex = 0;
+
+ if (!stp_psm_dbg) {
+ STP_PSM_PR_ERR("NULL g_stp_psm_dbg reference\n");
+ return -1;
+ }
+ osal_lock_unsleepable_lock(&stp_psm_dbg->lock);
+
+ inIndex = stp_psm_dbg->in;
+ dumpSize = stp_psm_dbg->size;
+ if (dumpSize == STP_PSM_DBG_SIZE)
+ outIndex = inIndex;
+ else
+ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE;
+
+ STP_PSM_PR_INFO("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex);
+ while (dumpSize > 0) {
+
+ pr_info("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d)\n",
+ stp_psm_dbg->queue[outIndex].sec,
+ stp_psm_dbg->queue[outIndex].usec,
+ stp_psm_dbg->queue[outIndex].package_no,
+ stp_psm_dbg->queue[outIndex].prev_flag,
+ stp_psm_dbg->queue[outIndex].cur_flag, stp_psm_dbg->queue[outIndex].line_num);
+
+ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1);
+ dumpSize--;
+
+ }
+
+ osal_unlock_unsleepable_lock(&stp_psm_dbg->lock);
+
+ return 0;
+}
+
+static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num)
+{
+ INT32 index = 0;
+ struct timeval now;
+ UINT64 ts;
+ ULONG nsec;
+
+ osal_get_local_time(&ts, &nsec);
+ if (p_opid_dbg) {
+ osal_lock_unsleepable_lock(&p_opid_dbg->lock);
+ osal_do_gettimeofday(&now);
+ index = p_opid_dbg->in - 1;
+ index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE;
+ STP_PSM_PR_DBG("index(%d)\n", index);
+ p_opid_dbg->queue[p_opid_dbg->in].prev_flag = p_opid_dbg->queue[index].cur_flag;
+ p_opid_dbg->queue[p_opid_dbg->in].cur_flag = opid;
+ p_opid_dbg->queue[p_opid_dbg->in].line_num = line_num;
+ p_opid_dbg->queue[p_opid_dbg->in].package_no = g_opid_record_num++;
+ p_opid_dbg->queue[p_opid_dbg->in].sec = now.tv_sec;
+ p_opid_dbg->queue[p_opid_dbg->in].usec = now.tv_usec;
+ p_opid_dbg->queue[p_opid_dbg->in].pid = current->pid;
+ p_opid_dbg->queue[p_opid_dbg->in].l_sec = ts;
+ p_opid_dbg->queue[p_opid_dbg->in].l_nsec = nsec;
+ p_opid_dbg->size++;
+ STP_PSM_PR_DBG("pre_opid = %d, cur_opid = %d\n", p_opid_dbg->queue[p_opid_dbg->in].prev_flag,
+ p_opid_dbg->queue[p_opid_dbg->in].cur_flag);
+ p_opid_dbg->size = (p_opid_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : p_opid_dbg->size;
+ p_opid_dbg->in = (p_opid_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (p_opid_dbg->in + 1);
+ STP_PSM_PR_DBG("opid record size = %d, in = %d num = %d\n", p_opid_dbg->size, p_opid_dbg->in,
+ line_num);
+
+ osal_unlock_unsleepable_lock(&p_opid_dbg->lock);
+ }
+ return 0;
+
+}
+
+static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg)
+{
+ UINT32 dumpSize = 0;
+ UINT32 inIndex = 0;
+ UINT32 outIndex = 0;
+
+ if (!p_opid_dbg) {
+ STP_PSM_PR_ERR("NULL p_opid_dbg reference\n");
+ return -1;
+ }
+ osal_lock_unsleepable_lock(&p_opid_dbg->lock);
+
+ inIndex = p_opid_dbg->in;
+ dumpSize = p_opid_dbg->size;
+ if (dumpSize == STP_PSM_DBG_SIZE)
+ outIndex = inIndex;
+ else
+ outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE;
+
+ STP_PSM_PR_INFO("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex);
+ while (dumpSize > 0) {
+
+ pr_info("STP-PSM:%d.%ds, time[%llu.%06lu], n(%d)pre_flag(%d)cur_flag(%d)line_no(%d) pid(%d)\n",
+ p_opid_dbg->queue[outIndex].sec,
+ p_opid_dbg->queue[outIndex].usec,
+ p_opid_dbg->queue[outIndex].l_sec,
+ p_opid_dbg->queue[outIndex].l_nsec,
+ p_opid_dbg->queue[outIndex].package_no,
+ p_opid_dbg->queue[outIndex].prev_flag,
+ p_opid_dbg->queue[outIndex].cur_flag,
+ p_opid_dbg->queue[outIndex].line_num, p_opid_dbg->queue[outIndex].pid);
+
+ outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1);
+ dumpSize--;
+
+ }
+
+ osal_unlock_unsleepable_lock(&p_opid_dbg->lock);
+
+ return 0;
+
+}
+
+VOID stp_psm_print_op_history(VOID)
+{
+ osal_op_history_print(&stp_psm->op_history, "_stp_psm_proc");
+}
+
+MTKSTP_PSM_T *stp_psm_init(VOID)
+{
+ INT32 err = 0;
+ INT32 i = 0;
+ INT32 ret = -1;
+
+ STP_PSM_PR_DBG("psm init\n");
+
+ stp_psm->work_state = ACT;
+ stp_psm->wmt_notify = wmt_lib_ps_stp_cb;
+ stp_psm->is_wmt_quick_ps_support = wmt_lib_is_quick_ps_support;
+ stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP;
+ stp_psm->update_wmt_fw_patch_chip_rst = wmt_lib_update_fw_patch_chip_rst;
+ stp_psm->flag.data = 0;
+ stp_psm->stp_tx_cb = NULL;
+ stp_psm_set_sleep_enable(stp_psm);
+
+ ret = osal_fifo_init(&stp_psm->hold_fifo, NULL, STP_PSM_FIFO_SIZE);
+ if (ret < 0) {
+ STP_PSM_PR_ERR("FIFO INIT FAILS\n");
+ goto ERR_EXIT4;
+ }
+
+ osal_fifo_reset(&stp_psm->hold_fifo);
+ osal_sleepable_lock_init(&stp_psm->user_lock);
+ /*psm_fifo_lock_init(stp_psm);*/
+ osal_sleepable_lock_init(&stp_psm->hold_fifo_spinlock_global);
+ osal_unsleepable_lock_init(&stp_psm->wq_spinlock);
+ osal_sleepable_lock_init(&stp_psm->stp_psm_lock);
+
+/* osal_unsleepable_lock_init(&stp_psm->flagSpinlock); */
+
+ osal_memcpy(stp_psm->wake_lock.name, "MT662x", 6);
+ stp_psm->wake_lock.init_flag = 0;
+ osal_wake_lock_init(&stp_psm->wake_lock);
+ osal_event_init(&stp_psm->STPd_event);
+ RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE);
+ RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE);
+ /* Put all to free Q */
+ for (i = 0; i < STP_OP_BUF_SIZE; i++) {
+ osal_signal_init(&(stp_psm->arQue[i].signal));
+ _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, &(stp_psm->arQue[i]));
+ }
+ /* stp_psm->current_active_op = NULL; */
+ stp_psm->last_active_opId = STP_OPID_PSM_INALID;
+ osal_op_history_init(&stp_psm->op_history, 16);
+ /*Generate PSM thread, to servie STP-CORE and WMT-CORE for sleeping, waking up and host awake */
+ stp_psm->PSMd.pThreadData = (PVOID) stp_psm;
+ stp_psm->PSMd.pThreadFunc = (PVOID) _stp_psm_proc;
+ osal_memcpy(stp_psm->PSMd.threadName, PSM_THREAD_NAME, osal_strlen(PSM_THREAD_NAME));
+
+ ret = osal_thread_create(&stp_psm->PSMd);
+ if (ret < 0) {
+ STP_PSM_PR_ERR("osal_thread_create fail...\n");
+ goto ERR_EXIT5;
+ }
+ /* init_waitqueue_head(&stp_psm->wait_wmt_q); */
+ stp_psm->wait_wmt_q.timeoutValue = STP_PSM_WAIT_EVENT_TIMEOUT;
+ osal_event_init(&stp_psm->wait_wmt_q);
+
+ err = _stp_psm_init_monitor(stp_psm);
+ if (err) {
+ STP_PSM_PR_ERR("__stp_psm_init ERROR\n");
+ goto ERR_EXIT6;
+ }
+ /* Start STPd thread */
+ ret = osal_thread_run(&stp_psm->PSMd);
+ if (ret < 0) {
+ STP_PSM_PR_ERR("osal_thread_run FAILS\n");
+ goto ERR_EXIT6;
+ }
+
+ g_stp_psm_dbg = (STP_PSM_RECORD_T *) osal_malloc(osal_sizeof(STP_PSM_RECORD_T));
+ if (!g_stp_psm_dbg) {
+ STP_PSM_PR_ERR("stp psm dbg allocate memory fail!\n");
+ return NULL;
+ }
+ osal_memset(g_stp_psm_dbg, 0, osal_sizeof(STP_PSM_RECORD_T));
+ osal_unsleepable_lock_init(&g_stp_psm_dbg->lock);
+
+ g_stp_psm_opid_dbg = (STP_PSM_OPID_RECORD *) osal_malloc(osal_sizeof(STP_PSM_OPID_RECORD));
+ if (!g_stp_psm_opid_dbg) {
+ STP_PSM_PR_ERR("stp psm dbg allocate memory fail!\n");
+ return NULL;
+ }
+ osal_memset(g_stp_psm_opid_dbg, 0, osal_sizeof(STP_PSM_OPID_RECORD));
+ osal_unsleepable_lock_init(&g_stp_psm_opid_dbg->lock);
+
+ return stp_psm;
+
+ERR_EXIT6:
+
+ ret = osal_thread_destroy(&stp_psm->PSMd);
+ if (ret < 0) {
+ STP_PSM_PR_ERR("osal_thread_destroy FAILS\n");
+ goto ERR_EXIT5;
+ }
+ERR_EXIT5:
+ osal_fifo_deinit(&stp_psm->hold_fifo);
+ERR_EXIT4:
+
+ return NULL;
+}
+
+INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm)
+{
+ INT32 ret = -1;
+
+ STP_PSM_PR_INFO("psm deinit\n");
+ if (g_stp_psm_dbg) {
+ osal_unsleepable_lock_deinit(&g_stp_psm_dbg->lock);
+ osal_free(g_stp_psm_dbg);
+ g_stp_psm_dbg = NULL;
+ }
+
+ if (!stp_psm)
+ return STP_PSM_OPERATION_FAIL;
+
+ ret = osal_thread_destroy(&stp_psm->PSMd);
+ if (ret < 0)
+ STP_PSM_PR_ERR("osal_thread_destroy FAILS\n");
+
+ ret = _stp_psm_deinit_monitor(stp_psm);
+ if (ret < 0)
+ STP_PSM_PR_ERR("_stp_psm_deinit_monitor ERROR\n");
+
+ osal_wake_lock_deinit(&stp_psm->wake_lock);
+ osal_fifo_deinit(&stp_psm->hold_fifo);
+ osal_sleepable_lock_deinit(&stp_psm->user_lock);
+ /*psm_fifo_lock_deinit(stp_psm);*/
+ osal_sleepable_lock_deinit(&stp_psm->hold_fifo_spinlock_global);
+ osal_unsleepable_lock_deinit(&stp_psm->wq_spinlock);
+ osal_sleepable_lock_deinit(&stp_psm->stp_psm_lock);
+/* osal_unsleepable_lock_deinit(&stp_psm->flagSpinlock); */
+
+ return STP_PSM_OPERATION_SUCCESS;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..198e7393b924da7c1637705bd7ae0c49a7c526b7
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c
@@ -0,0 +1,3591 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include "osal_typedef.h"
+#include "stp_core.h"
+#include "psm_core.h"
+#include "btm_core.h"
+#include "stp_dbg.h"
+#include "stp_sdio.h"
+#include "stp_btif.h"
+#include "wmt_lib.h"
+#include "wmt_step.h"
+#include "wmt_detect.h"
+
+#define PFX "[STP] "
+#define STP_LOG_DBG 4
+#define STP_LOG_PKHEAD 3
+#define STP_LOG_INFO 2
+#define STP_LOG_WARN 1
+#define STP_LOG_ERR 0
+
+#define STP_DEL_SIZE 2 /* STP delimiter length */
+#define STP_MAX_TX_TIMEOUT_LOOP 3
+
+INT32 gStpDbgLvl = STP_LOG_INFO;
+unsigned int chip_reset_only;
+INT32 wmt_dbg_sdio_retry_ctrl = 1;
+INT32 gCrcErrorCount;
+
+#define STP_POLL_CPUPCR_NUM 5
+#define STP_POLL_CPUPCR_DELAY 1
+
+/* global variables */
+static const UINT8 stp_delimiter[STP_DEL_SIZE] = { 0x55, 0x55 };
+
+static INT32 fgEnableNak; /* 0=enable NAK; 1=disable NAK */
+static INT32 fgEnableDelimiter; /* 0=disable Delimiter; 1=enable Delimiter */
+/* common interface */
+static IF_TX sys_if_tx;
+static RX_HAS_PENDING_DATA sys_rx_has_pending_data;
+static TX_HAS_PENDING_DATA sys_tx_has_pending_data;
+static RX_THREAD_GET sys_rx_thread_get;
+/* event/signal */
+static EVENT_SET sys_event_set;
+static EVENT_TX_RESUME sys_event_tx_resume;
+static FUNCTION_STATUS sys_check_function_status;
+/* kernel lib */
+/* INT32 g_block_tx = 0; */
+static mtkstp_context_struct stp_core_ctx = { 0 };
+
+#define STP_PSM_CORE(x) ((x).psm)
+#define STP_SET_PSM_CORE(x, v) ((x).psm = (v))
+
+#define STP_BTM_CORE(x) ((x).btm)
+#define STP_SET_BTM_CORE(x, v) ((x).btm = (v))
+
+#define STP_IS_ENABLE(x) ((x).f_enable != 0)
+#define STP_NOT_ENABLE(x) ((x).f_enable == 0)
+#define STP_SET_ENABLE(x, v) ((x).f_enable = (v))
+
+#define STP_IS_READY(x) ((x).f_ready != 0)
+#define STP_NOT_READY(x) ((x).f_ready == 0)
+#define STP_SET_READY(x, v) ((x).f_ready = (v))
+
+#define STP_PENDING_TYPE(x) ((x).f_pending_type)
+#define STP_SET_PENDING_TYPE(x, v) ((x).f_pending_type = (v))
+
+#define STP_BLUE_ANGEL (0)
+#define STP_BLUE_Z (1)
+#define STP_BT_STK(x) ((x).f_bluez)
+#define STP_BT_STK_IS_BLUEZ(x) ((x).f_bluez == (STP_BLUE_Z))
+#define STP_SET_BT_STK(x, v) ((x).f_bluez = (v))
+
+#define STP_IS_ENABLE_DBG(x) ((x).f_dbg_en != 0)
+#define STP_NOT_ENABLE_DBG(x) ((x).f_dbg_en == 0)
+#define STP_SET_ENABLE_DBG(x, v) ((x).f_dbg_en = (v))
+
+#define STP_IS_ENABLE_RST(x) ((x).f_autorst_en != 0)
+#define STP_NOT_ENABLE_RST(x) ((x).f_autorst_en == 0)
+#define STP_SET_ENABLE_RST(x, v) ((x).f_autorst_en = (v))
+
+#define STP_SUPPORT_PROTOCOL(x) ((x).f_mode)
+#define STP_SET_SUPPORT_PROTOCOL(x, v) ((x).f_mode = (v))
+
+#define STP_FW_COREDUMP_FLAG(x) ((x).f_coredump)
+#define STP_SET_FW_COREDUMP_FLAG(x, v) ((x).f_coredump = (v))
+#define STP_ENABLE_FW_COREDUMP(x, v) ((x).en_coredump = (v))
+#define STP_ENABLE_FW_COREDUMP_FLAG(x) ((x).en_coredump)
+#define STP_EMI_DUMP_FLAG(x) ((x).f_emidump)
+#define STP_SET_EMI_DUMP_FLAG(x, v) ((x).f_emidump = (v))
+
+#define STP_WMT_LAST_CLOSE(x) ((x).f_wmt_last_close)
+#define STP_SET_WMT_LAST_CLOSE(x, v) ((x).f_wmt_last_close = (v))
+
+#define STP_ASSERT(x) ((x).f_evt_err_assert)
+#define STP_SET_ASSERT(x, v) ((x).f_evt_err_assert = (v))
+
+#define STP_ASSERT_IN_PROGRESS(x) ((x).f_assert_in_progress)
+#define STP_SET_ASSERT_IN_PROGRESS(x, v) ((x).f_assert_in_progress = (v))
+
+#define STP_IS_SUPPORT_GPSL5(x) ((x).f_gpsl5_en != 0)
+#define STP_NOT_SUPPORT_GPSL5(x) ((x).f_gpsl5_en == 0)
+#define STP_SET_SUPPORT_GPSL5(x, v) ((x).f_gpsl5_en = (v))
+
+
+/*[PatchNeed]Need to calculate the timeout value*/
+static UINT32 mtkstp_tx_timeout = MTKSTP_TX_TIMEOUT;
+static mtkstp_parser_state prev_state = -1;
+
+
+#define CONFIG_DEBUG_STP_TRAFFIC_SUPPORT
+#ifdef CONFIG_DEBUG_STP_TRAFFIC_SUPPORT
+static MTKSTP_DBG_T *g_mtkstp_dbg;
+#endif
+static VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir,
+ const PUINT8 pBuf, INT32 len);
+static MTK_WCN_BOOL stp_check_crc(PUINT8 buffer, UINT32 length, UINT16 crc);
+static VOID stp_update_tx_queue(UINT32 txseq);
+static VOID stp_rest_ctx_state(VOID);
+static VOID stp_change_rx_state(mtkstp_parser_state next);
+static void stp_tx_timeout_handler(timer_handler_arg arg);
+static VOID stp_dump_data(const PUINT8 buf, const PUINT8 title, const UINT32 len);
+static VOID stp_dump_tx_queue(UINT32 txseq);
+static INT32 stp_is_apply_powersaving(VOID);
+#if 0
+static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type);
+#endif
+static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length);
+static VOID stp_add_to_tx_queue(const PUINT8 buffer, UINT32 length);
+static INT32 stp_add_to_rx_queue(PUINT8 buffer, UINT32 length, UINT8 type);
+static VOID stp_send_tx_queue(UINT32 txseq);
+static VOID stp_send_ack(UINT8 txAck, UINT8 nak);
+static INT32 stp_process_rxack(VOID);
+static VOID stp_process_packet(VOID);
+static VOID stp_process_header_only_packet(VOID);
+static VOID stp_sdio_process_packet(VOID);
+static VOID stp_trace32_dump(VOID);
+static VOID stp_sdio_trace32_dump(VOID);
+static LONG stp_parser_dmp_num(PUINT8 str);
+static INT32 wmt_parser_data(PUINT8 buffer, UINT32 length, UINT8 type);
+static MTK_WCN_BOOL mtk_wcn_stp_is_info_task(VOID);
+
+INT32 __weak mtk_wcn_consys_stp_btif_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_logger_ctrl is not define!!\n");
+ return 0;
+}
+INT32 __weak mtk_wcn_consys_stp_btif_open(VOID)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_open is not define!!\n");
+
+ return 0;
+}
+
+INT32 __weak mtk_wcn_consys_stp_btif_close(VOID)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_close is not define!!\n");
+
+ return 0;
+}
+
+INT32 __weak mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_rx_cb_register is not define!!\n");
+ return 0;
+}
+
+INT32 __weak mtk_wcn_consys_stp_btif_tx(const PUINT8 pBuf, const UINT32 len, PUINT32 written_len)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_tx is not define!!\n");
+
+ return 0;
+}
+
+INT32 __weak mtk_wcn_consys_stp_btif_wakeup(VOID)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_wakeup is not define!!\n");
+
+ return 0;
+}
+
+INT32 __weak mtk_wcn_consys_stp_btif_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode)
+{
+ STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_lpbk_ctrl is not define!!\n");
+
+ return 0;
+}
+
+static INT32 stp_ctx_lock_init(mtkstp_context_struct *pctx)
+{
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+#if defined(CONFIG_PROVE_LOCKING)
+ osal_unsleepable_lock_init(&((pctx)->stp_mutex));
+ return 0;
+#else
+ return osal_unsleepable_lock_init(&((pctx)->stp_mutex));
+#endif
+#else
+#if defined(CONFIG_PROVE_LOCKING)
+ osal_sleepable_lock_init(&((pctx)->stp_mutex));
+ return 0;
+#else
+ return osal_sleepable_lock_init(&((pctx)->stp_mutex));
+#endif
+#endif
+}
+
+static INT32 stp_ctx_lock_deinit(mtkstp_context_struct *pctx)
+{
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+ return osal_unsleepable_lock_deinit(&((pctx)->stp_mutex));
+#else
+ return osal_sleepable_lock_deinit(&((pctx)->stp_mutex));
+#endif
+}
+
+static INT32 stp_ctx_lock(mtkstp_context_struct *pctx)
+{
+ /* dump_stack(); */
+ /* pr_debug("stp_lock\n\r"); */
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+ return osal_lock_unsleepable_lock(&((pctx)->stp_mutex));
+#else
+ return osal_lock_sleepable_lock(&((pctx)->stp_mutex));
+#endif
+}
+
+static INT32 stp_ctx_unlock(mtkstp_context_struct *pctx)
+{
+ /* dump_stack(); */
+ /* pr_debug("stp_unlock\n\r"); */
+
+#if CFG_STP_CORE_CTX_SPIN_LOCK
+ return osal_unlock_unsleepable_lock(&((pctx)->stp_mutex));
+#else
+ return osal_unlock_sleepable_lock(&((pctx)->stp_mutex));
+#endif
+}
+
+
+MTK_WCN_BOOL mtk_wcn_stp_dbg_level(INT32 dbglevel)
+{
+ if (dbglevel >= 0 && dbglevel <= 4) {
+ gStpDbgLvl = dbglevel;
+ STP_INFO_FUNC("gStpDbgLvl = %d\n", gStpDbgLvl);
+ return MTK_WCN_BOOL_TRUE;
+ }
+ STP_INFO_FUNC("invalid stp debug level. gStpDbgLvl = %d\n", gStpDbgLvl);
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static VOID stp_sdio_process_packet(VOID)
+{
+ MTK_WCN_BOOL is_function_active = 0;
+
+ if ((stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) {
+ INT32 b;
+ /*Indicate packet to hci_stp */
+ if (gStpDbgLvl >= STP_LOG_DBG)
+ stp_dump_data(stp_core_ctx.rx_buf, "indicate_to_bt_core", stp_core_ctx.rx_counter);
+ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter);
+ if (b)
+ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n");
+ } else {
+ is_function_active = ((*sys_check_function_status)(stp_core_ctx.parser.type,
+ OP_FUNCTION_ACTIVE) == STATUS_FUNCTION_ACTIVE);
+ /*check type and function if active? */
+ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) &&
+ (is_function_active == MTK_WCN_BOOL_TRUE)) {
+ if (stp_core_ctx.parser.type == WMT_TASK_INDX)
+ wmt_parser_data(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type);
+ else {
+ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type);
+
+ /*notify corresponding subfunction of incoming data */
+ (*sys_event_set)(stp_core_ctx.parser.type);
+ }
+ } else {
+ if (is_function_active == MTK_WCN_BOOL_FALSE) {
+ STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n",
+ stp_core_ctx.parser.type);
+ } else {
+ STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n",
+ stp_core_ctx.parser.type);
+ }
+ }
+ }
+}
+
+static MTK_WCN_BOOL mtk_wcn_stp_is_info_task(VOID)
+{
+ if (STP_NOT_SUPPORT_GPSL5(stp_core_ctx) && (stp_core_ctx.parser.type == INFO_TASK_INDX))
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static VOID stp_trace32_dump(VOID)
+{
+ if (STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX)) {
+ STP_INFO_FUNC("[len=%d][type=%d]%s\n", stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type, stp_core_ctx.rx_buf);
+ }
+ /*Runtime FW Log */
+ else if (STP_IS_ENABLE_DBG(stp_core_ctx) && mtk_wcn_stp_is_info_task()) {
+ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0,
+ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf);
+ mtk_wcn_stp_dbg_dump_package();
+ }
+ /*Normal mode: whole chip reset */
+ else {
+ /*Aee Kernel Warning Message Shown First */
+ /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */
+ mtk_wcn_stp_dbg_dump_package();
+
+ osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf);
+ /*Whole Chip Reset Procedure Invoke */
+ if (STP_IS_ENABLE_RST(stp_core_ctx)) {
+ STP_SET_READY(stp_core_ctx, 0);
+ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx));
+ } else
+ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n");
+ }
+}
+
+static LONG stp_parser_dmp_num(PUINT8 str)
+{
+ PUINT8 pParserDmpStr = "Dump=";
+ PUINT8 pStr = NULL;
+ PUINT8 pDtr = NULL;
+ PUINT8 pTemp = NULL;
+ INT32 ret = -1;
+ UINT32 len = 0;
+ UINT8 tempBuf[64] = {0};
+ LONG res;
+
+
+ if (!str) {
+ STP_DBG_PR_ERR("NULL string source\n");
+ return -1;
+ }
+
+ pStr = str;
+ pDtr = osal_strstr(pStr, pParserDmpStr);
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(pParserDmpStr);
+ pTemp = pDtr;
+ while (*pTemp >= '0' && *pTemp <= '9')
+ pTemp++;
+ } else {
+ STP_DBG_PR_WARN("parser string 'Dump=' is not found\n");
+ return -2;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+ ret = osal_strtol(tempBuf, 10, &res);
+ if (ret) {
+ STP_DBG_PR_ERR(" get 'Dump=' from firmware failed (%d)", ret);
+ return -4;
+ }
+
+ return res;
+}
+
+static VOID stp_sdio_trace32_dump(VOID)
+{
+ LONG dmp_num = 0;
+ int coredump_end_str_len = osal_strlen("coredump end");
+ int len;
+
+ if (STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX) &&
+ (mtk_wcn_stp_coredump_flag_get() != 0)) {
+ if (stp_core_ctx.rx_counter != 0) {
+ STP_SET_READY(stp_core_ctx, 0);
+ mtk_wcn_stp_ctx_save();
+ if (stp_core_ctx.assert_info_cnt == 0) {
+ dmp_num = stp_parser_dmp_num(stp_core_ctx.rx_buf);
+ if (dmp_num > 0 && dmp_num < PARSER_CORE_DUMP_NUM) {
+ STP_INFO_FUNC("parser dmp_num is %ld\n", dmp_num);
+ stp_dbg_dump_num(dmp_num);
+ } else if (dmp_num > PARSER_CORE_DUMP_NUM) {
+ STP_INFO_FUNC("parser dmp_num is out of range %ld\n",
+ dmp_num);
+ stp_dbg_dump_num(PARSER_CORE_DUMP_NUM);
+ } else {
+ STP_INFO_FUNC("parser dmp_num not found %ld\n", dmp_num);
+ stp_dbg_dump_num(CORE_DUMP_NUM);
+ }
+ }
+ /*STP_DBG_FW_ASSERT */
+ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_DMP, STP_TASK_INDX, 0, 0, 0, 0,
+ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf);
+ }
+ stp_core_ctx.assert_info_cnt++;
+ if (stp_core_ctx.assert_info_cnt == 20)
+ STP_INFO_FUNC("only dump 20 packages from the beginning\n");
+ else if (stp_core_ctx.assert_info_cnt < 20)
+ osal_err_print("[len=%d][type=%d]counter[%d]\n%s\n", stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type, stp_core_ctx.assert_info_cnt, stp_core_ctx.rx_buf);
+
+ len = stp_core_ctx.rx_counter - coredump_end_str_len - 2;
+ if ((len >= 0) &&
+ (stp_core_ctx.rx_counter < MTKSTP_BUFFER_SIZE) &&
+ (osal_strncmp("coredump end", stp_core_ctx.rx_buf
+ + len, coredump_end_str_len) == 0)) {
+ STP_INFO_FUNC("%d coredump packets received\n", stp_core_ctx.assert_info_cnt);
+ STP_ERR_FUNC("coredump end\n");
+ mtk_wcn_stp_ctx_restore();
+ }
+ }
+ /*Runtime FW Log */
+ else if (STP_IS_ENABLE_DBG(stp_core_ctx) && mtk_wcn_stp_is_info_task()) {
+ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0,
+ (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf);
+ mtk_wcn_stp_dbg_dump_package();
+ }
+ /*Normal mode: whole chip reset */
+ else {
+ /*Aee Kernel Warning Message Shown First */
+ /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */
+ mtk_wcn_stp_dbg_dump_package();
+ if (mtk_wcn_stp_coredump_flag_get() == 0) {
+ osal_err_print("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type, stp_core_ctx.rx_buf);
+ STP_ERR_FUNC("fw error happened but coredump disabled\n");
+ } else
+ osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf);
+ /*Whole Chip Reset Procedure Invoke */
+ if (STP_IS_ENABLE_RST(stp_core_ctx)) {
+ STP_SET_READY(stp_core_ctx, 0);
+ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx));
+ } else
+ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n");
+ }
+}
+
+static VOID stp_process_header_only_packet(VOID)
+{
+ if (stp_core_ctx.parser.length == 0) {
+ INT32 fgTriggerResume = (-1);
+ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+ stp_ctx_lock(&stp_core_ctx);
+ if (stp_core_ctx.inband_rst_set == 0) {
+ stp_dbg_pkt_log(STP_TASK_INDX,
+ stp_core_ctx.parser.ack,
+ stp_core_ctx.parser.seq,
+ 5, /* STP type id */
+ PKT_DIR_RX,
+ NULL,
+ 0);
+ fgTriggerResume = stp_process_rxack();
+ } else {
+ STP_WARN_FUNC
+ ("Now it's inband reset process and drop ACK packet.\n");
+ }
+ if (fgTriggerResume == 0) {
+ /* notify adaptation layer for
+ * possible tx resume mechanism
+ */
+ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace);
+ }
+ stp_ctx_unlock(&stp_core_ctx);
+ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.rx_counter = 0;
+ } else {
+ stp_change_rx_state(MTKSTP_DATA);
+ stp_core_ctx.rx_counter = 0;
+ }
+}
+
+#if 0
+/*****************************************************************************
+* FUNCTION
+* crc16
+* DESCRIPTION
+* Compute the CRC-16 for the data buffer
+* PARAMETERS
+* crc [IN] previous CRC value
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* the updated CRC value
+*****************************************************************************/
+static UINT16 crc16(const UINT8 *buffer, const UINT32 length)
+{
+ UINT32 crc, i;
+
+ /* FIXME: Add STP checksum feature */
+ crc = 0;
+ for (i = 0; i < length; i++, buffer++)
+ crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff];
+ return crc;
+}
+
+#endif
+
+
+VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const PUINT8 pBuf,
+ INT32 len)
+{
+
+#ifndef CONFIG_LOG_STP_INTERNAL
+ return;
+#endif
+
+ if (STP_IS_ENABLE_DBG(stp_core_ctx)) {
+ if (STP_IS_READY(stp_core_ctx) ||
+ (!STP_IS_READY(stp_core_ctx) && (type > WIFI_TASK_INDX)
+ && (type != ANT_TASK_INDX) && (len != 0)))
+ stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_PKT, type, /* type */
+ txAck, /* ack */
+ seq, /* seq */
+ crc, /* crc */
+ dir, /* dir */
+ len, /* len */
+ pBuf); /* body */
+ } else {
+ STP_DBG_FUNC("stp_dbg not enabled or not ready or len is 0\n");
+ }
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_check_crc
+* DESCRIPTION
+* check the check sum of packet payload
+* PARAMETERS
+* pdata [IN] the data want to check
+* length [IN] the length of pdata
+* crc [IN] the crc of pdata
+* RETURNS
+* KAL_TRUE crc is ok
+* KAL_FALSE crc is wrong
+*****************************************************************************/
+static MTK_WCN_BOOL stp_check_crc(PUINT8 buffer, UINT32 length, UINT16 crc)
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+ UINT16 checksum;
+
+ /*----------------------------------------------------------------*/
+ /* Code Body */
+ /*----------------------------------------------------------------*/
+
+ /* FIXME: Add STP feature: check or skip crc */
+
+ checksum = osal_crc16(buffer, length);
+ if (checksum == crc)
+ return MTK_WCN_BOOL_TRUE;
+ STP_ERR_FUNC("CRC fail, length = %d, rx = %x, calc = %x \r\n", length, crc, checksum);
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_update_tx_queue
+* DESCRIPTION
+* update packet's ACK field
+* PARAMETERS
+* txseq [IN] index of the tx packet which we want to update
+* RETURNS
+* void
+*****************************************************************************/
+static void stp_update_tx_queue(UINT32 txseq)
+{
+ INT32 tx_read, i;
+ UINT8 checksum = 0;
+
+ tx_read = stp_core_ctx.tx_start_addr[txseq];
+ if (tx_read < 0)
+ return;
+
+ stp_core_ctx.tx_buf[tx_read] &= 0xf8;
+ stp_core_ctx.tx_buf[tx_read] |= stp_core_ctx.sequence.txack;
+
+ for (i = 0; i < 3; i++) {
+ checksum += stp_core_ctx.tx_buf[tx_read];
+ tx_read++;
+ if (tx_read >= MTKSTP_BUFFER_SIZE)
+ tx_read -= MTKSTP_BUFFER_SIZE;
+ }
+
+ stp_core_ctx.tx_buf[tx_read] = checksum;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_rest_ctx_state
+* DESCRIPTION
+* Reset stp context state variables only. Mutex and timer resources are not touched.
+*
+* PARAMETERS
+* void
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_rest_ctx_state(VOID)
+{
+ INT32 i;
+
+ stp_ctx_lock(&stp_core_ctx);
+ stp_core_ctx.rx_counter = 0;
+
+ /*reset rx buffer pointer */
+ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) {
+ stp_core_ctx.ring[i].read_p = 0;
+ stp_core_ctx.ring[i].write_p = 0;
+ }
+
+ /*reset tx buffer pointer */
+ stp_core_ctx.tx_write = 0;
+ stp_core_ctx.tx_read = 0;
+
+ /*reset STP protocol context */
+ stp_core_ctx.parser.state = MTKSTP_SYNC;
+ stp_core_ctx.sequence.txseq = 0;
+ stp_core_ctx.sequence.txack = 7;
+ stp_core_ctx.sequence.rxack = 7;
+ stp_core_ctx.sequence.winspace = MTKSTP_WINSIZE;
+ stp_core_ctx.sequence.expected_rxseq = 0;
+ stp_core_ctx.sequence.retry_times = 0;
+ stp_core_ctx.sequence.tx_timeout_loop = 0;
+ stp_core_ctx.sequence.rx_resync = 0;
+ stp_core_ctx.sequence.rx_resync_seq = 0xFF;
+ stp_core_ctx.inband_rst_set = 0;
+
+ stp_ctx_unlock(&stp_core_ctx);
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_change_rx_state
+* DESCRIPTION
+* change the rx fsm of STP to "next"
+* PARAMETERS
+* next [IN] the next state of rx fsm
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_change_rx_state(mtkstp_parser_state next)
+{
+ prev_state = stp_core_ctx.parser.state;
+ stp_core_ctx.parser.state = next;
+}
+
+/* static void stp_tx_timeout_handler(void){ */
+static void stp_tx_timeout_handler(timer_handler_arg arg)
+{
+ if (mtk_wcn_stp_coredump_start_get() == 1) {
+ STP_WARN_FUNC("Starting coredump, skip tx retry.\n");
+ return;
+ }
+ STP_WARN_FUNC("call retry btm retry wq ...\n");
+ /*shorten the softirq lattency */
+ stp_btm_notify_stp_retry_wq(STP_BTM_CORE(stp_core_ctx));
+}
+
+VOID stp_do_tx_timeout(VOID)
+{
+ UINT32 seq;
+ UINT32 ret;
+ UINT8 resync[4];
+ INT32 tx_pending_state;
+ INT32 rx_pending_state;
+
+ STP_WARN_FUNC
+ ("==============================================================================\n");
+ osal_dump_thread_state("btif_rxd");
+ if (!mtk_wcn_stp_is_sdio_mode())
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_IRQ);
+
+ tx_pending_state = sys_tx_has_pending_data();
+ /* Sys_rx_has_pending_data cannot be called after stp_ctx_lock(&stp_core_ctx),
+ * there will be a deadlock problem, because sys_rx_has_pending_data will take
+ * the mutex of btif_rxd, and btif_rxd may need to return TX ack during parsing
+ * data process. This will take stp_ctx_lock(&stp_core_ctx), causing deadlock
+ */
+ rx_pending_state = sys_rx_has_pending_data();
+ STP_INFO_FUNC("check tx/rx has pending data(%d/%d).\n", tx_pending_state, rx_pending_state);
+ stp_ctx_lock(&stp_core_ctx);
+
+ if (stp_core_ctx.sequence.retry_times > (MTKSTP_RETRY_LIMIT)) {
+ STP_INFO_FUNC("STP retry times(%d) have reached retry limit,stop it\n",
+ stp_core_ctx.sequence.retry_times);
+ stp_ctx_unlock(&stp_core_ctx);
+ return;
+ }
+
+ seq = stp_core_ctx.sequence.rxack;
+ INDEX_INC(seq);
+
+ if (seq != stp_core_ctx.sequence.txseq) {
+ osal_memset(&resync[0], 0x7f, 4);
+ (*sys_if_tx) (&resync[0], 4, &ret);
+ if (ret != 4) {
+ STP_ERR_FUNC("mtkstp_tx_timeout_handler: send resync fail\n");
+ osal_assert(0);
+ }
+
+ do {
+ /* rxack (=last rx ack), txack (=last rx seq), txseq (=next tx seq) */
+ STP_WARN_FUNC("[stp.ctx]rxack/txack/txseq=%d/%d/%d(Resend from%d->%d)\n",
+ stp_core_ctx.sequence.rxack,
+ stp_core_ctx.sequence.txack,
+ stp_core_ctx.sequence.txseq,
+ seq,
+ (stp_core_ctx.sequence.txseq <= 0) ? (7) :
+ (stp_core_ctx.sequence.txseq - 1));
+ stp_dump_tx_queue(seq);
+
+ stp_send_tx_queue(seq);
+ INDEX_INC(seq);
+ } while (seq != stp_core_ctx.sequence.txseq);
+
+ }
+
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout);
+
+ if (stp_core_ctx.sequence.winspace == MTKSTP_WINSIZE) {
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n");
+ } else {
+ stp_core_ctx.sequence.retry_times++;
+ STP_ERR_FUNC("mtkstp_tx_timeout_handler, retry = %d\n",
+ stp_core_ctx.sequence.retry_times);
+
+ /*If retry too much, try to recover STP by return back to initializatin state */
+ /*And not to retry again */
+ if (stp_core_ctx.sequence.retry_times > MTKSTP_RETRY_LIMIT) {
+ do {
+ int reason = 42;
+
+ if (tx_pending_state > 0 || (tx_pending_state == 0 && rx_pending_state > 0)) {
+ if (stp_core_ctx.sequence.tx_timeout_loop < STP_MAX_TX_TIMEOUT_LOOP) {
+ stp_core_ctx.sequence.retry_times = 0;
+ stp_core_ctx.sequence.tx_timeout_loop++;
+ STP_INFO_FUNC("extend tx retry only.\n");
+ break;
+ }
+
+ STP_ERR_FUNC("there are still some data in tx/rx buffer.\n");
+ /* Reason number 45 means that stp data path still has data,
+ * possibly a driver problem
+ */
+ reason = 45;
+ }
+
+ WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP TX no ack timeout");
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ stp_ctx_unlock(&stp_core_ctx);
+
+ STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n");
+
+ STP_ERR_FUNC("TX retry limit = %d\n", MTKSTP_RETRY_LIMIT);
+ osal_assert(0);
+ stp_notify_btm_dump(STP_BTM_CORE(stp_core_ctx));
+
+ /*Whole Chip Reset Procedure Invoke */
+ stp_psm_disable(STP_PSM_CORE(stp_core_ctx));
+ STP_INFO_FUNC("**STP NoAck trigger firmware assert**\n");
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 42);
+ return;
+ } while (0);
+ }
+ }
+
+ stp_ctx_unlock(&stp_core_ctx);
+ /*polling cpupcr when no ack occurs at first retry */
+ stp_dbg_poll_cpupcr(STP_POLL_CPUPCR_NUM, STP_POLL_CPUPCR_DELAY, 1);
+ STP_WARN_FUNC
+ ("==============================================================================#\n");
+}
+
+static VOID stp_dump_data(const PUINT8 buf, const PUINT8 title, const UINT32 len)
+{
+ osal_buffer_dump(buf, title, len, 32);
+}
+
+/*****************************************************************************
+ * FUNCTION
+ * stp_tx_timeout_handler
+ * DESCRIPTION
+ * tx timeout handler, send resync & retransmitt
+ * PARAMETERS
+ * void
+ * RETURNS
+ * void
+ *****************************************************************************/
+static VOID stp_dump_tx_queue(UINT32 txseq)
+{
+ INT32 tx_read, tx_length, last_len;
+
+ tx_read = stp_core_ctx.tx_start_addr[txseq];
+ tx_length = stp_core_ctx.tx_length[txseq];
+
+ STP_ERR_FUNC("tx_seq=%d ..", txseq);
+
+ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE)
+ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q", (tx_length >= 8) ? (8) : (tx_length));
+ else {
+ last_len = MTKSTP_BUFFER_SIZE - tx_read;
+ stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q_0", (last_len >= 8) ? (8) : (last_len));
+ stp_dump_data(&stp_core_ctx.tx_buf[0], "tx_q_0",
+ ((tx_length - last_len) ? (8) : (tx_length - last_len)));
+ }
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_is_apply_powersaving
+* DESCRIPTION
+* Check if STP support power saving mode.
+* PARAMETERS
+*
+* RETURNS
+* True: support power saving False: not support power saving
+*****************************************************************************/
+static INT32 stp_is_apply_powersaving(VOID)
+{
+
+ if (STP_IS_READY(stp_core_ctx) && !stp_psm_is_disable(STP_PSM_CORE(stp_core_ctx))) {
+ /* osal_dbg_print("apply power saving\n"); */
+ return MTK_WCN_BOOL_TRUE;
+ }
+ if (mtk_wcn_stp_is_sdio_mode())
+ return MTK_WCN_BOOL_FALSE;
+ STP_DBG_FUNC("not apply power saving\n");
+ return MTK_WCN_BOOL_FALSE;
+}
+
+#if 0
+/*****************************************************************************
+* FUNCTION
+* stp_is_privileges_cmd
+* DESCRIPTION
+* Check if the data is privilege command
+* PARAMETERS
+*
+* RETURNS
+* True/False
+*****************************************************************************/
+
+static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type)
+{
+ typedef struct privileges_cmd {
+ UINT32 length;
+ UINT8 type;
+ UINT8 buf[7]; /* MAX length of target command is only 5 currently */
+ } p_cmd_t;
+
+ p_cmd_t p_cmd_table[] = {
+ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x01} }, /* sleep command */
+ {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x02} }, /* host_awake command */
+ };
+
+ UINT32 i;
+ UINT32 size = ARRAY_SIZE(p_cmd_table));
+
+ for (i = 0; i < size; i++) {
+ if (type != p_cmd_table[i].type)
+ continue;
+
+ if (length != p_cmd_table[i].length)
+ continue;
+
+ if (osal_memcmp(p_cmd_table[i].buf, buffer, length))
+ continue;
+ /* matched entry is found */
+ STP_DBG_FUNC("It's p_cmd_t\n");
+ return MTK_WCN_BOOL_TRUE;
+ }
+
+ return MTK_WCN_BOOL_FALSE;
+}
+#endif
+/*****************************************************************************
+* FUNCTION
+* tx_queue_room_available
+* DESCRIPTION
+* check room if available,
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* void
+*****************************************************************************/
+static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length)
+{
+ UINT32 roomLeft;
+
+ /*
+ * Get available space of TX Queue
+ */
+ if (stp_core_ctx.tx_read <= stp_core_ctx.tx_write)
+ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write + stp_core_ctx.tx_read - 1;
+ else
+ roomLeft = stp_core_ctx.tx_read - stp_core_ctx.tx_write - 1;
+ if (roomLeft < length) {
+ STP_ERR_FUNC("%s: tx queue room shortage\n", __func__);
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return MTK_WCN_BOOL_TRUE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_add_to_tx_queue
+* DESCRIPTION
+* put data to tx queue
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_add_to_tx_queue(const PUINT8 buffer, UINT32 length)
+{
+ UINT32 last_len;
+
+ /* Get available space of TX Queue */
+ if (length + stp_core_ctx.tx_write < MTKSTP_BUFFER_SIZE) {
+ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, length);
+ stp_core_ctx.tx_write += length;
+ } else {
+ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write;
+ osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, last_len);
+ osal_memcpy(stp_core_ctx.tx_buf, buffer + last_len, length - last_len);
+ stp_core_ctx.tx_write = length - last_len;
+ }
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_add_to_rx_queue
+* DESCRIPTION
+* put data to corresponding task's rx queue and notify corresponding task
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] corresponding task index
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type)
+{
+ UINT32 roomLeft, last_len;
+
+ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+
+ if (stp_core_ctx.ring[type].read_p <= stp_core_ctx.ring[type].write_p)
+ roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p + stp_core_ctx.ring[type].read_p - 1;
+ else
+ roomLeft = stp_core_ctx.ring[type].read_p - stp_core_ctx.ring[type].write_p - 1;
+
+ if (roomLeft < length) {
+ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+ STP_WARN_RATELIMITED_FUNC(
+ "Queue full, type(%d), remain buf(%d), len(%d), w_p(%d), r_p(%d)\n",
+ type, roomLeft, length,
+ stp_core_ctx.ring[type].write_p,
+ stp_core_ctx.ring[type].read_p);
+ osal_assert(0);
+ return -1;
+ }
+
+ if (length + stp_core_ctx.ring[type].write_p < MTKSTP_BUFFER_SIZE) {
+ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, length);
+ stp_core_ctx.ring[type].write_p += length;
+ } else {
+ last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p;
+ osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, last_len);
+ osal_memcpy(stp_core_ctx.ring[type].buffer, buffer + last_len, length - last_len);
+ stp_core_ctx.ring[type].write_p = length - last_len;
+ }
+
+ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+
+ return 0;
+}
+
+/*****************************************************************************
+* FUNCTION
+* wmt_parser_data
+* DESCRIPTION
+* push data to wmt parser engine
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] corresponding task index
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+static INT32 wmt_parser_data(PUINT8 buffer, UINT32 length, UINT8 type)
+{
+ UINT8 wmtsubtype;
+ INT32 fgRxOk = -1;
+ UINT32 parser_length = 0;
+ UINT32 packet_length = 0;
+
+ while (parser_length < length) {
+ wmtsubtype = buffer[parser_length + 1];
+ packet_length = buffer[parser_length + 3] << 8;
+ packet_length += buffer[parser_length + 2];
+ STP_DBG_FUNC("wmt sub type (%d)\n", wmtsubtype);
+ if (wmtsubtype == WMT_LTE_COEX_FLAG) {
+#if CFG_WMT_LTE_COEX_HANDLING
+ fgRxOk = stp_add_to_rx_queue(buffer + parser_length, packet_length + 4, COEX_TASK_INDX);
+ if (fgRxOk == 0) {
+ STP_DBG_FUNC("wmt/lte coex package!\n");
+ stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx));
+ } else
+ osal_buffer_dump(buffer, "coex_packet_print", length, 128);
+#else
+ STP_WARN_FUNC("BT/WIFI & LTE coex in non-LTE projects,drop it...\n");
+#endif
+ } else {
+ fgRxOk = stp_add_to_rx_queue(buffer + parser_length, packet_length + 4, type);
+ if (fgRxOk == 0) {
+ STP_DBG_FUNC("wmt package!\n");
+ (*sys_event_set)(type);
+ } else
+ osal_buffer_dump(buffer, "wmt_packet_print", length, 128);
+ }
+ parser_length += packet_length + 4;
+ }
+
+ return fgRxOk;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_tx_queue
+* DESCRIPTION
+* send data in tx buffer to common interface
+* PARAMETERS
+* txseq [IN] sequence number of outgoing packet in tx buffer
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_send_tx_queue(UINT32 txseq)
+{
+ UINT32 ret;
+ INT32 tx_read, tx_length, last_len;
+
+ tx_read = stp_core_ctx.tx_start_addr[txseq];
+ tx_length = stp_core_ctx.tx_length[txseq];
+
+ stp_update_tx_queue(txseq);
+
+ if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) {
+
+ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], tx_length, &ret);
+
+ if (ret != tx_length) {
+ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length, ret);
+ osal_assert(0);
+ }
+ } else {
+ last_len = MTKSTP_BUFFER_SIZE - tx_read;
+ (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], last_len, &ret);
+
+ if (ret != last_len) {
+ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", last_len, ret);
+ osal_assert(0);
+ }
+
+ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], tx_length - last_len, &ret);
+
+ if (ret != tx_length - last_len) {
+ STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length - last_len, ret);
+ osal_assert(0);
+ }
+ }
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_ack
+* DESCRIPTION
+* send ack packet to the peer
+* PARAMETERS
+* txAck [IN] Ack number
+* nak [IN] 0 = ack; !0 = NAK
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_send_ack(UINT8 txAck, UINT8 nak)
+{
+ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE];
+ UINT32 ret;
+ INT32 iStatus;
+
+ mtkstp_header[0] = 0x80 + (0 << 3) + txAck; /* stp_core_ctx.sequence.txack; */
+
+ if (fgEnableNak == 0)
+ mtkstp_header[1] = 0x00; /* disable NAK */
+ else
+ mtkstp_header[1] = ((nak == 0) ? 0x00 : 0x80);
+
+ mtkstp_header[2] = 0;
+ mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff;
+
+ stp_dbg_pkt_log(STP_TASK_INDX, txAck, 0, 0, PKT_DIR_TX, NULL, 0);
+
+ if (fgEnableDelimiter == 1) {
+ iStatus = (*sys_if_tx) ((const PUINT8)(&stp_delimiter[0]), STP_DEL_SIZE, &ret);
+ STP_DUMP_PACKET_HEAD((PUINT8)(&stp_delimiter[0]), "tx del", STP_DEL_SIZE);
+ if (ret != STP_DEL_SIZE) {
+ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", STP_DEL_SIZE, ret, iStatus);
+ osal_assert(0);
+ }
+ }
+
+ iStatus = (*sys_if_tx) (&mtkstp_header[0], MTKSTP_HEADER_SIZE, &ret);
+
+ if (ret != MTKSTP_HEADER_SIZE) {
+ STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", MTKSTP_HEADER_SIZE, ret, iStatus);
+ osal_assert(0);
+ }
+}
+
+
+
+INT32 stp_send_data_no_ps(PUINT8 buffer, UINT32 length, UINT8 type)
+{
+ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2];
+ PUINT8 p_tx_buf = NULL;
+ UINT16 crc;
+ INT32 ret = 0;
+
+ stp_ctx_lock(&stp_core_ctx);
+
+ /*Only WMT can set raw data */
+ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) {
+ /* no op */
+ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) {
+ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */
+ } else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() ||
+ mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) {
+ /* STP over SDIO */
+ /* osal_printtimeofday("[ STP][SDIO][ B][W]"); */
+
+ mtkstp_header[0] = 0x80;
+ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f);
+ mtkstp_header[2] = (length) & 0xff;
+ mtkstp_header[3] = 0x00;
+
+ p_tx_buf = &stp_core_ctx.tx_buf[0];
+ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE);
+ p_tx_buf += MTKSTP_HEADER_SIZE;
+
+ osal_memcpy(p_tx_buf, buffer, length);
+ p_tx_buf += length;
+
+ temp[0] = 0x00;
+ temp[1] = 0x00;
+ osal_memcpy(p_tx_buf, temp, 2);
+ stp_dbg_pkt_log(type,
+ stp_core_ctx.sequence.txack,
+ stp_core_ctx.sequence.txseq, 0, PKT_DIR_TX, buffer, length);
+ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret);
+ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) {
+ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret);
+ osal_assert(0);
+ ret = 0;
+ } else
+ ret = (INT32) length;
+ /* osal_printtimeofday("[ STP][SDIO][ E][W]"); */
+ } else if ((mtk_wcn_stp_is_uart_fullset_mode() || mtk_wcn_stp_is_btif_fullset_mode())
+ && STP_IS_ENABLE(stp_core_ctx)) {
+ /* STP over UART OR BTIF*/
+ if ((stp_core_ctx.sequence.winspace > 0) &&
+ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) {
+ mtkstp_header[0] =
+ 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack;
+ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8);
+ mtkstp_header[2] = length & 0xff;
+ mtkstp_header[3] =
+ (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff;
+
+ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] =
+ stp_core_ctx.tx_write;
+ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] =
+ MTKSTP_HEADER_SIZE + length + 2;
+
+ if (fgEnableDelimiter == 1) {
+ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE;
+ stp_add_to_tx_queue((const PUINT8)(&stp_delimiter[0]),
+ STP_DEL_SIZE);
+ }
+
+ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE);
+
+ /*Make Payload */
+ stp_add_to_tx_queue(buffer, length);
+
+ /*Make CRC */
+ crc = osal_crc16(buffer, length);
+ temp[0] = crc & 0xff;
+ temp[1] = (crc & 0xff00) >> 8;
+ stp_add_to_tx_queue(temp, 2);
+
+ stp_dbg_pkt_log(type,
+ stp_core_ctx.sequence.txack,
+ stp_core_ctx.sequence.txseq,
+ crc, PKT_DIR_TX, buffer, length);
+
+ /*Kick to UART */
+ stp_send_tx_queue(stp_core_ctx.sequence.txseq);
+ INDEX_INC(stp_core_ctx.sequence.txseq);
+ stp_core_ctx.sequence.winspace--;
+
+ /*Setup the Retry Timer */
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE)
+ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout);
+ else
+ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n");
+ ret = (INT32) length;
+ } else {
+ /* No winspace to send. Let caller retry */
+ STP_ERR_FUNC("%s: There is no winspace/txqueue to send !!!\n",
+ __func__);
+ ret = 0;
+ }
+ }
+
+ stp_ctx_unlock(&stp_core_ctx);
+
+ return ret;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_process_rxack
+* DESCRIPTION
+* process ack packet
+* PARAMETERS
+* void
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+static INT32 stp_process_rxack(VOID)
+{
+ INT32 j, k;
+ UINT8 rxack;
+ INT32 fgResult = -1;
+
+ if (stp_core_ctx.sequence.rxack != stp_core_ctx.parser.ack) {
+ j = k = 0;
+ rxack = stp_core_ctx.sequence.rxack;
+ INDEX_INC(rxack);
+ while (rxack != stp_core_ctx.sequence.txseq) {
+ j++;
+ if (rxack == stp_core_ctx.parser.ack) {
+ k = 1;
+ break;
+ }
+ INDEX_INC(rxack);
+ }
+ if (k == 1) {
+ stp_core_ctx.sequence.rxack = stp_core_ctx.parser.ack;
+ stp_core_ctx.tx_read =
+ stp_core_ctx.tx_start_addr[rxack] + stp_core_ctx.tx_length[rxack];
+ if (stp_core_ctx.tx_read >= MTKSTP_BUFFER_SIZE)
+ stp_core_ctx.tx_read -= MTKSTP_BUFFER_SIZE;
+ stp_core_ctx.sequence.winspace += j;
+ stp_core_ctx.sequence.retry_times = 0;
+ stp_core_ctx.sequence.tx_timeout_loop = 0;
+
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE)
+ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout);
+ fgResult = 0;
+ }
+ }
+
+ return fgResult;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_process_packet
+* DESCRIPTION
+* process STP packet
+* PARAMETERS
+* void
+* RETURNS
+* void
+*****************************************************************************/
+static VOID stp_process_packet(VOID)
+{
+ INT32 fgTriggerResume = (-1);
+ UINT8 txAck = 0;
+ static INT32 fgRxOk;
+ MTK_WCN_BOOL b;
+ MTK_WCN_BOOL is_function_active = 0;
+ static INT32 stp_process_packet_fail_count;
+
+ stp_dbg_pkt_log(stp_core_ctx.parser.type,
+ stp_core_ctx.parser.ack,
+ stp_core_ctx.parser.seq,
+ stp_core_ctx.parser.crc, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.parser.length);
+ /*Optimization */
+ /*If bluez, direct send packet to hci_core not through RX buffer! */
+ if ((stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) &&
+ (stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) {
+ stp_core_ctx.sequence.rx_resync = 0;
+
+ /*Indicate packet to hci_stp */
+ STP_DBG_FUNC("Send Packet to BT_SUBFUCTION, len = %d\n", stp_core_ctx.rx_counter);
+
+ b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter);
+ if (b)
+ STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n");
+
+ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+ stp_ctx_lock(&stp_core_ctx);
+ /*Process rx ack */
+ fgTriggerResume = stp_process_rxack();
+ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq;
+ INDEX_INC(stp_core_ctx.sequence.expected_rxseq);
+ txAck = stp_core_ctx.sequence.txack;
+
+ /*Send ack back */
+ stp_send_ack(txAck, 0);
+
+ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+ stp_ctx_unlock(&stp_core_ctx);
+ fgRxOk = 0;
+ }
+ /* sequence matches expected, enqueue packet */
+ else if (stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) {
+ stp_core_ctx.sequence.rx_resync = 0;
+
+ is_function_active =
+ ((*sys_check_function_status) (stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) ==
+ STATUS_FUNCTION_ACTIVE);
+ /*If type is valid and function works, then try to enqueue */
+ if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && (is_function_active == MTK_WCN_BOOL_TRUE)) {
+
+ stp_ctx_lock(&stp_core_ctx);
+
+ fgTriggerResume = stp_process_rxack();
+ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq;
+ INDEX_INC(stp_core_ctx.sequence.expected_rxseq);
+
+ /*Send tx ack */
+ txAck = stp_core_ctx.sequence.txack;
+ stp_send_ack(txAck, 0);
+
+ stp_ctx_unlock(&stp_core_ctx);
+
+ if (stp_core_ctx.parser.type == WMT_TASK_INDX)
+ fgRxOk =
+ wmt_parser_data(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type);
+ else
+ fgRxOk =
+ stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter,
+ stp_core_ctx.parser.type);
+ } else {
+ if (is_function_active == MTK_WCN_BOOL_FALSE) {
+ STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n",
+ stp_core_ctx.parser.type);
+ fgRxOk = 0; /*drop packet */
+ } else {
+ STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n",
+ stp_core_ctx.parser.type);
+ fgRxOk = 0; /*drop packet */
+ }
+ stp_ctx_lock(&stp_core_ctx);
+
+ fgTriggerResume = stp_process_rxack();
+ stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq;
+ INDEX_INC(stp_core_ctx.sequence.expected_rxseq);
+
+ /*Send tx ack */
+ txAck = stp_core_ctx.sequence.txack;
+ stp_send_ack(txAck, 0);
+
+ stp_ctx_unlock(&stp_core_ctx);
+ }
+
+ /* enqueue successfully */
+ if (fgRxOk == 0) {
+ stp_process_packet_fail_count = 0;
+ /*notify corresponding subfunction of incoming data */
+ if (stp_core_ctx.parser.type != WMT_TASK_INDX)
+ (*sys_event_set) (stp_core_ctx.parser.type);
+ } else {
+ /*Queue is full */
+ switch (stp_core_ctx.parser.type) {
+ case GPS_TASK_INDX:
+ /*Clear Rx Queue if GPS */
+ mtk_wcn_stp_flush_rx_queue(GPS_TASK_INDX);
+ break;
+ case BT_TASK_INDX:
+ /* just ignore this case */
+ /*notify corresponding subfunction of incoming data */
+ (*sys_event_set) (stp_core_ctx.parser.type);
+ break;
+ default:
+ stp_process_packet_fail_count++;
+ /*notify corresponding subfunction of incoming data */
+ (*sys_event_set) (stp_core_ctx.parser.type);
+ break;
+ }
+ /*enqueue fail, don't send ack and wait for peer retry */
+ STP_WARN_RATELIMITED_FUNC("%s %d queue is full\n",
+ "Enqueue to Rx queue fail, maybe function",
+ stp_core_ctx.parser.type);
+ }
+ }
+ /*sequence not match && previous packet enqueue successfully, send the previous ACK */
+ else if (fgRxOk == 0) {
+ STP_ERR_FUNC("mtkstp_process_packet: expected_rxseq = %d, parser.seq = %d, rx_resync = %d\n",
+ stp_core_ctx.sequence.expected_rxseq,
+ stp_core_ctx.parser.seq,
+ stp_core_ctx.sequence.rx_resync);
+
+ stp_ctx_lock(&stp_core_ctx);
+ /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+ txAck = stp_core_ctx.sequence.txack;
+ stp_send_ack(txAck, 1);
+ stp_ctx_unlock(&stp_core_ctx);
+ /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */
+
+ if (stp_core_ctx.sequence.rx_resync) {
+ STP_ERR_FUNC("resync'd packets, discard and send the previous (ack no =%d)\n", txAck);
+ if (stp_core_ctx.sequence.rx_resync_seq == 0xFF)
+ stp_core_ctx.sequence.rx_resync_seq = stp_core_ctx.parser.seq;
+ else {
+ INDEX_INC(stp_core_ctx.sequence.rx_resync_seq);
+ if (stp_core_ctx.sequence.rx_resync_seq != stp_core_ctx.parser.seq) {
+ STP_ERR_FUNC("resync'd packet seq not match, %d expected\n",
+ stp_core_ctx.sequence.rx_resync_seq);
+ stp_process_packet_fail_count++;
+ stp_core_ctx.sequence.rx_resync = 0;
+ }
+ }
+ } else {
+ stp_process_packet_fail_count++;
+ STP_ERR_FUNC
+ ("seq not match && previous packet enqueue success, send the previous (ack no =%d)\n",
+ txAck);
+ }
+ }
+ /*sequence not match && previous packet enqueue failed, do nothing, make the other side timeout */
+ else {
+ stp_process_packet_fail_count++;
+ STP_ERR_FUNC
+ ("seq not match && previous packet enqueue failed, make the other side timeout\n");
+ }
+
+ if (fgTriggerResume == 0) {
+ /*[PatchNeed]Just Notificaiton, not blocking call */
+ /* notify adaptation layer for possible tx resume mechanism */
+ (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace);
+ }
+
+ if (stp_process_packet_fail_count > MTKSTP_RETRY_LIMIT) {
+ stp_process_packet_fail_count = 0;
+ STP_ERR_FUNC("The process packet fail count > 10 lastly, host trigger assert\n");
+ /*Whole Chip Reset Procedure Invoke */
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 43);
+ }
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_init
+* DESCRIPTION
+* init STP kernel
+* PARAMETERS
+* cb_func [IN] function pointers of system APIs
+* RETURNS
+* INT32 0 = success, others = failure
+*****************************************************************************/
+INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func)
+{
+ INT32 ret = 0;
+ INT32 i = 0;
+
+ /* Function pointer to point to the currently used transmission interface
+ */
+ sys_if_tx = cb_func->cb_if_tx;
+
+ /* Used to check tx/rx has pending data*/
+ sys_rx_has_pending_data = cb_func->cb_rx_has_pending_data;
+ sys_tx_has_pending_data = cb_func->cb_tx_has_pending_data;
+
+ /* Used to get rx thread */
+ sys_rx_thread_get = cb_func->cb_rx_thread_get;
+
+ /* Used to inform the function driver has received the corresponding type of information */
+ sys_event_set = cb_func->cb_event_set;
+
+ /* Used to inform the function driver can continue to send information and
+ * STP has resources to deal with
+ */
+ sys_event_tx_resume = cb_func->cb_event_tx_resume;
+
+ /* STP driver determines whether the function is enable. If not enable and
+ * STP has received the kind of information, and STP have the right to put it away.
+ */
+ sys_check_function_status = cb_func->cb_check_funciton_status;
+
+ stp_ctx_lock_init(&stp_core_ctx);
+
+ /* Setup timer to be used to check if f/w receive the data in the specific time
+ * interval after being sent
+ */
+ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++)
+ osal_unsleepable_lock_init(&stp_core_ctx.ring[i].mtx);
+ stp_core_ctx.tx_timer.timeoutHandler = stp_tx_timeout_handler;
+ stp_core_ctx.tx_timer.timeroutHandlerData = 0;
+ osal_timer_create(&stp_core_ctx.tx_timer);
+
+ STP_SET_BT_STK(stp_core_ctx, 0);
+ STP_SET_ENABLE(stp_core_ctx, 0);
+ STP_SET_ENABLE_DBG(stp_core_ctx, 0);
+ STP_SET_ENABLE_RST(stp_core_ctx, 0);
+ STP_SET_PENDING_TYPE(stp_core_ctx, 0);
+ STP_SET_READY(stp_core_ctx, 0);
+ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, 0);
+ STP_SET_PSM_CORE(stp_core_ctx, stp_psm_init());
+ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, 0);
+ STP_ENABLE_FW_COREDUMP(stp_core_ctx, 0);
+ STP_SET_WMT_LAST_CLOSE(stp_core_ctx, 0);
+ STP_SET_EMI_DUMP_FLAG(stp_core_ctx, 0);
+ STP_SET_ASSERT(stp_core_ctx, 0);
+ STP_SET_ASSERT_IN_PROGRESS(stp_core_ctx, 0);
+ STP_SET_SUPPORT_GPSL5(stp_core_ctx, 0);
+
+ if (!STP_PSM_CORE(stp_core_ctx)) {
+ ret = (-3);
+ goto ERROR;
+ }
+
+ STP_SET_BTM_CORE(stp_core_ctx, stp_btm_init());
+ if (!STP_BTM_CORE(stp_core_ctx)) {
+ STP_ERR_FUNC("STP_BTM_CORE(stp_core_ctx) initialization fail!\n");
+ ret = (-3);
+ goto ERROR;
+ }
+
+ if (STP_BTM_CORE(stp_core_ctx) != NULL)
+ g_mtkstp_dbg = stp_dbg_init(STP_BTM_CORE(stp_core_ctx));
+ else
+ g_mtkstp_dbg = stp_dbg_init(NULL);
+
+ if (!g_mtkstp_dbg) {
+ STP_ERR_FUNC("g_mtkstp_dbg initialization fail!\n");
+ ret = (-3);
+ goto ERROR;
+ }
+ STP_SET_ENABLE_RST(stp_core_ctx, 1);
+
+ mtk_wcn_stp_dbg_enable();
+
+ /* set coredump flag for debugging earlier */
+ mtk_wcn_stp_coredump_flag_ctrl(1);
+
+ goto RETURN;
+
+ERROR:
+ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx));
+
+RETURN:
+ return ret;
+
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_deinit
+* DESCRIPTION
+* deinit STP kernel
+* PARAMETERS
+* void
+* RETURNS
+* INT32 0 = success, others = failure
+*****************************************************************************/
+INT32 mtk_wcn_stp_deinit(VOID)
+{
+ INT32 i = 0;
+
+ sys_if_tx = NULL;
+ sys_event_set = NULL;
+ sys_event_tx_resume = NULL;
+ sys_check_function_status = NULL;
+
+ stp_dbg_deinit(g_mtkstp_dbg);
+ stp_btm_deinit(STP_BTM_CORE(stp_core_ctx));
+ stp_psm_deinit(STP_PSM_CORE(stp_core_ctx));
+
+ for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++)
+ osal_unsleepable_lock_deinit(&stp_core_ctx.ring[i].mtx);
+
+ stp_ctx_lock_deinit(&stp_core_ctx);
+ return 0;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_btm_get_dmp
+* DESCRIPTION
+* get stp dump related information
+* PARAMETERS
+* buffer: dump placement, len: dump size
+* RETURNS
+* 0: Success Negative Value: Fail
+*****************************************************************************/
+
+INT32 mtk_wcn_stp_btm_get_dmp(PINT8 buf, PINT32 len)
+{
+ return stp_dbg_dmp_out(g_mtkstp_dbg, buf, len);
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_notify_stp
+* DESCRIPTION
+* WMT notification to STP that power saving job is done or not
+* PARAMETERS
+*
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+INT32 mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action)
+{
+ return stp_psm_notify_stp(STP_PSM_CORE(stp_core_ctx), action);
+}
+
+INT32 mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state)
+{
+ return stp_psm_set_state(STP_PSM_CORE(stp_core_ctx), state);
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_enable
+* DESCRIPTION
+* enable STP sleep/wakeup support
+* PARAMETERS
+* void
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep)
+{
+ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_enable() && (mtk_wcn_stp_is_uart_fullset_mode()
+ || mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_fullset_mode()))
+ return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep);
+
+ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n");
+ return -1;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_psm_disable
+* DESCRIPTION
+* disable STP sleep/wakeup support
+* PARAMETERS
+* void
+* RETURNS
+* 0: Sccuess Negative value: Fail
+*****************************************************************************/
+INT32 mtk_wcn_stp_psm_disable(VOID)
+{
+ if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_enable() && (mtk_wcn_stp_is_uart_fullset_mode()
+ || mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_fullset_mode()))
+ return stp_psm_disable(STP_PSM_CORE(stp_core_ctx));
+
+ STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n");
+ return 0;
+}
+
+INT32 mtk_wcn_stp_psm_reset(VOID)
+{
+ return stp_psm_reset(STP_PSM_CORE(stp_core_ctx));
+}
+
+INT32 mtk_wcn_stp_dbg_disable(VOID)
+{
+ if (STP_IS_ENABLE_DBG(stp_core_ctx)) {
+ STP_INFO_FUNC("STP dbg mode is turned off\n");
+ STP_SET_ENABLE_DBG(stp_core_ctx, 0);
+ stp_dbg_disable(g_mtkstp_dbg);
+ } else
+ STP_WARN_FUNC("STP dbg mode has been turned off\n");
+
+ return 0;
+}
+
+INT32 mtk_wcn_stp_dbg_enable(VOID)
+{
+ if (STP_NOT_ENABLE_DBG(stp_core_ctx)) {
+ STP_DBG_FUNC("STP dbg mode is turned on\n");
+ STP_SET_ENABLE_DBG(stp_core_ctx, 1);
+ stp_dbg_enable(g_mtkstp_dbg);
+ } else
+ STP_WARN_FUNC("STP dbg mode has been turned on\n");
+
+ return 0;
+}
+
+INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on)
+{
+ stp_dbg_log_ctrl(on);
+ return 0;
+}
+
+INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on)
+{
+ static INT32 pre_coredump_mode;
+
+ STP_ENABLE_FW_COREDUMP(stp_core_ctx, on);
+ STP_INFO_FUNC("%s coredump function.\n", 0 == on ? "disable" : "enable");
+ if (pre_coredump_mode != on) {
+ if (on == 1 || on == 2)
+ stp_dbg_nl_init();
+ else
+ stp_dbg_nl_deinit();
+ }
+ pre_coredump_mode = on;
+ return 0;
+}
+
+INT32 mtk_wcn_stp_coredump_flag_get(VOID)
+{
+ return STP_ENABLE_FW_COREDUMP_FLAG(stp_core_ctx);
+}
+
+INT32 mtk_wcn_stp_emi_dump_flag_ctrl(UINT32 on)
+{
+ STP_SET_EMI_DUMP_FLAG(stp_core_ctx, on);
+ return 0;
+}
+
+INT32 mtk_wcn_stp_emi_dump_flag_get(VOID)
+{
+ return STP_EMI_DUMP_FLAG(stp_core_ctx);
+}
+
+static INT32 stp_parser_data_in_mand_mode(UINT32 length, UINT8 *p_data)
+{
+ UINT8 padding_len = 0;
+ INT32 remain_length = 0;
+ INT32 i = 0;
+ INT32 i_ret = 0;
+
+ i = length;
+ while (i > 0) {
+ switch (stp_core_ctx.parser.state) {
+ case MTKSTP_SYNC: /* b'10 */
+ /* Must be 0x80 */
+ if (*p_data == 0x80) {
+ stp_change_rx_state(MTKSTP_NAK);
+ stp_core_ctx.rx_counter++;
+ } else {
+ STP_WARN_FUNC("non-0x80 (0x%x) detected, discard %d bytes\n",
+ *p_data, i);
+ osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0);
+ i = 0;
+ /* Drop them and keep at MTKSTP_SYNC state */
+ continue;
+ }
+ break;
+
+ case MTKSTP_NAK:
+ stp_change_rx_state(MTKSTP_LENGTH);
+ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4;
+ if (stp_core_ctx.parser.type <= MTKSTP_MAX_TASK_NUM) {
+ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8;
+ stp_core_ctx.rx_counter++;
+ } else {
+ STP_WARN_FUNC("abnormal type (0x%x) detected, discard %d bytes\n",
+ stp_core_ctx.parser.type, i);
+ osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0);
+
+ /* Drop them and back to MTKSTP_SYNC state */
+ i = 0;
+ STP_WARN_FUNC("nak to sync\n");
+ stp_change_rx_state(MTKSTP_SYNC);
+ continue;
+ }
+ break;
+
+ case MTKSTP_LENGTH:
+ stp_change_rx_state(MTKSTP_CHECKSUM);
+ stp_core_ctx.parser.length += *p_data;
+
+ /*Valid length checking */
+ if (stp_core_ctx.parser.length < 2000)
+ stp_core_ctx.rx_counter++;
+ else {
+ STP_WARN_FUNC("abnormal length (0x%x) detected, discard %d bytes\n",
+ stp_core_ctx.parser.length, i);
+ osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0);
+
+ /* Drop them and back to MTKSTP_SYNC state */
+ i = 0;
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.rx_counter = 0;
+ continue;
+ }
+ break;
+
+ case MTKSTP_CHECKSUM:
+ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || mtk_wcn_stp_is_info_task()) {
+ stp_change_rx_state(MTKSTP_FW_MSG);
+ stp_core_ctx.rx_counter = 0;
+ i -= 1;
+ if (i != 0)
+ p_data += 1;
+ continue;
+ }
+ if (stp_core_ctx.parser.length == 0) {
+ STP_WARN_FUNC("checksum to sync\n");
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.rx_counter = 0;
+ } else {
+ stp_change_rx_state(MTKSTP_DATA);
+ stp_core_ctx.rx_counter = 0;
+ }
+ break;
+
+ case MTKSTP_DATA:
+ /* block copy instead of byte copy */
+ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) {
+ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n",
+ stp_core_ctx.parser.length, stp_core_ctx.rx_counter);
+ osal_assert(0);
+ }
+ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter;
+ if (i >= remain_length) {
+ /*boundary checking */
+ if (stp_core_ctx.rx_counter + remain_length >= MTKSTP_BUFFER_SIZE) {
+ STP_ERR_FUNC("Abnormal!! Memory operation over boundary!!\n");
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.rx_counter = 0;
+ return -1;
+ }
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length);
+ i -= remain_length;
+ p_data += remain_length;
+ stp_core_ctx.rx_counter = stp_core_ctx.parser.length;
+ stp_core_ctx.parser.state = MTKSTP_CRC1;
+ continue;
+
+ } else { /* only copy by data length */
+ /*fixed klocwork insight issue */
+ /*boundary checking */
+ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) {
+ STP_ERR_FUNC("Abnormal!! Memory operation over boundary 2!!\n");
+ stp_core_ctx.rx_counter = 0;
+ return -1;
+ }
+
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i);
+ stp_core_ctx.rx_counter += i; /* all remain buffer are data */
+ i = 0;
+ p_data += i;
+ continue;
+ }
+ break;
+
+ case MTKSTP_CRC1:
+ stp_change_rx_state(MTKSTP_CRC2);
+ stp_core_ctx.parser.crc = *p_data;
+ break;
+
+ case MTKSTP_CRC2:
+ stp_core_ctx.parser.crc += (*p_data) << 8;
+ if (stp_core_ctx.parser.crc != 0x00)
+ STP_ERR_FUNC
+ ("CRC (0x%x) is not 0 under SDIO/MAND mode, maybe something is wrong.\n",
+ stp_core_ctx.parser.crc);
+ /*SDIO mode do it. */
+ if (mtk_wcn_stp_is_sdio_mode()) {
+ /*STP packet 4-bytes alignment */
+ /*Discard padding bytes , otherwise make parser state machine disorder */
+ if (i <= 4) {
+ p_data += (i - 1);
+ i -= (i - 1);
+ } else {
+ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03;
+ p_data += padding_len;
+ i -= padding_len;
+ }
+ }
+ stp_dbg_pkt_log(stp_core_ctx.parser.type,
+ 0,
+ 0,
+ 0,
+ PKT_DIR_RX,
+ stp_core_ctx.rx_buf, stp_core_ctx.rx_counter);
+ stp_sdio_process_packet();
+
+ stp_core_ctx.rx_counter = 0;
+ stp_change_rx_state(MTKSTP_SYNC);
+
+ break;
+
+ case MTKSTP_FW_MSG:
+ i_ret = -2;
+ if (stp_core_ctx.parser.length == 0) {
+ STP_INFO_FUNC("FW Assert len = 0, ignore this pkg\n");
+ /*discard CRC */
+ if (i > 2) {
+ STP_DBG_FUNC("crc discard.. i = %d\n", i);
+ i -= 2;
+ p_data += 2;
+ } else if (i == 2) {
+ STP_DBG_FUNC("crc discard.. i = %d\n", i);
+ i -= 2;
+ }
+ /*STP packet 4-bytes alignment */
+ /*Discard padding bytes , otherwise make parser state machine disorder */
+ if (i == 0) {
+ /*STP_DBG_FUNC("\n[STP]FW_EVENT======= no padding byte =======\n"); */
+ /*do nothing */
+ } else if (i <= 4) {
+ STP_INFO_FUNC
+ ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", i);
+ p_data += i;
+ i -= i;
+ } else {
+ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03;
+ p_data += padding_len;
+ i -= padding_len;
+ STP_INFO_FUNC
+ ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n",
+ padding_len);
+ }
+ continue;
+ }
+ mtk_wcn_stp_assert_flow_ctrl(1);
+ mtk_wcn_stp_coredump_start_ctrl(1);
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 1)
+ stp_btm_stop_trigger_assert_timer(STP_BTM_CORE(stp_core_ctx));
+ if (STP_IS_READY(stp_core_ctx)) {
+ mtk_wcn_stp_dbg_dump_package();
+ stp_notify_btm_dump(STP_BTM_CORE(stp_core_ctx));
+ }
+ STP_SET_READY(stp_core_ctx, 0);
+ /*stp inband reset */
+ if (stp_core_ctx.parser.type == STP_TASK_INDX &&
+ stp_core_ctx.parser.seq == 0 &&
+ stp_core_ctx.parser.ack == 0 &&
+ stp_core_ctx.parser.length == 0 &&
+ stp_core_ctx.inband_rst_set == 1) {
+ STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r");
+ stp_rest_ctx_state();
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.inband_rst_set = 0;
+ STP_TRACE_FUNC("--\n");
+ return 0;
+ }
+ /*f/w assert and exception information */
+ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) {
+ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n",
+ stp_core_ctx.parser.length, stp_core_ctx.rx_counter);
+ osal_assert(0);
+ }
+
+ remain_length =
+ stp_core_ctx.parser.length - stp_core_ctx.rx_counter;
+ if (i >= remain_length) {
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length);
+ i -= remain_length;
+ p_data += remain_length;
+ stp_core_ctx.rx_counter = stp_core_ctx.parser.length;
+ stp_change_rx_state(MTKSTP_SYNC);
+ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0';
+ /* STP_ERR_FUNC("%s [%d]\n", stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); */
+
+ /*Trace32 Dump */
+ stp_sdio_trace32_dump();
+
+ /*discard CRC */
+ if (i > 2) {
+ STP_DBG_FUNC("crc discard.. i = %d\n", i);
+ i -= 2;
+ p_data += 2;
+ } else if (i == 2) {
+ STP_DBG_FUNC("crc discard.. i = %d\n", i);
+ i -= 2;
+ }
+ /*STP packet 4-bytes alignment */
+ /*Discard padding bytes , otherwise make parser state machine disorder */
+ if (i == 0)
+ STP_DBG_FUNC
+ ("\n[STP]FW_EVENT========= no padding byte =========\n");
+ else if (i <= 4) {
+ STP_DBG_FUNC
+ ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", i);
+ p_data += i;
+ i -= i;
+ } else {
+ padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03;
+ p_data += padding_len;
+ i -= padding_len;
+ STP_DBG_FUNC
+ ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n",
+ padding_len);
+ }
+ continue;
+ } else { /* only copy by data length */
+
+ /*fixed klocwork insight issue */
+ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) {
+ STP_ERR_FUNC
+ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n");
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.rx_counter = 0;
+ return -1;
+ }
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i);
+ stp_core_ctx.rx_counter += i; /* all remain buffer are data */
+ i = 0;
+ p_data += i;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ p_data++;
+ i--;
+ }
+ return 0;
+}
+
+static INT32 stp_parser_data_in_full_mode(UINT32 length, UINT8 *p_data)
+{
+ INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */
+ INT32 i = length;
+ static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 1);
+
+ while (i > 0) {
+ switch (stp_core_ctx.parser.state) {
+
+ case MTKSTP_RESYNC1: /* RESYNC must be 4 _continuous_ 0x7f */
+ if (*p_data == 0x7f)
+ stp_change_rx_state(MTKSTP_RESYNC2);
+ else
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ break;
+ case MTKSTP_RESYNC2:
+ if (*p_data == 0x7f)
+ stp_change_rx_state(MTKSTP_RESYNC3);
+ else
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ break;
+ case MTKSTP_RESYNC3:
+ if (*p_data == 0x7f)
+ stp_change_rx_state(MTKSTP_RESYNC4);
+ else
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ break;
+ case MTKSTP_RESYNC4:
+ if (*p_data == 0x7f) {
+ stp_change_rx_state(MTKSTP_SYNC);
+ if (stp_core_ctx.sequence.rx_resync < 0xFF)
+ stp_core_ctx.sequence.rx_resync++;
+ stp_core_ctx.sequence.rx_resync_seq = 0xFF;
+ } else
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ break;
+ case MTKSTP_SYNC: /* b'10 */
+ STP_DUMP_PACKET_HEAD(p_data, "rx (uart):", length > 4 ? 4 : length);
+ if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) {
+ stp_change_rx_state(MTKSTP_NAK);
+ stp_core_ctx.parser.seq = (*p_data & 0x38) >> 3;
+ stp_core_ctx.parser.ack = *p_data & 0x07;
+ stp_core_ctx.rx_buf[0] = *p_data;
+ } else if ((*p_data == 0x7f) && (prev_state == MTKSTP_RESYNC4)) {
+ /* if this 0x7f is continuous to resync pattern */
+ /* skip this continuous 0x7f, remain current & prev state */
+ STP_ERR_FUNC("MTKSTP_SYNC: continuous resync pattern, buff = %x\n", *p_data);
+ } else if (*p_data == 0x7f) { /* a start of 0x7f, maybe this is resync pattern */
+ stp_change_rx_state(MTKSTP_RESYNC2);
+ STP_ERR_FUNC("MTKSTP_SYNC: go to MTKSTP_RESYNC2, buff = %x\n", *p_data);
+ } else if (*p_data == 0x55) { /* STP delimiter */
+ /* do nothing for delimiter */
+ } else { /* unexpected, drop them */
+ osal_assert(0);
+ if (__ratelimit(&_rs)) {
+ STP_WARN_FUNC("error header(0x%x) detected, discard %d bytes\n",
+ *p_data, i);
+ osal_buffer_dump(p_data, "full mode unexpected header", i, 0);
+ }
+ i = 0;
+ continue;
+ }
+ break;
+
+ case MTKSTP_NAK:
+ if (fgEnableNak == 0)
+ stp_core_ctx.parser.nak = 0; /* disable NAK */
+ else
+ stp_core_ctx.parser.nak = (*p_data & 0x80) >> 7;
+ stp_core_ctx.parser.type = (*p_data & 0x70) >> 4;
+ stp_core_ctx.parser.length = (*p_data & 0x0f) << 8;
+ stp_core_ctx.rx_buf[1] = *p_data;
+ if (stp_core_ctx.parser.nak)
+ STP_ERR_FUNC("MTKSTP_NAK TRUE: buff = %x\n", *p_data);
+
+ if (stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM)
+ stp_change_rx_state(MTKSTP_LENGTH);
+ else
+ stp_change_rx_state(MTKSTP_SYNC);
+ break;
+
+ case MTKSTP_LENGTH:
+ stp_change_rx_state(MTKSTP_CHECKSUM);
+ stp_core_ctx.parser.length += *p_data;
+ /* Valid length checking */
+ if (stp_core_ctx.parser.length > 2048) {
+ STP_ERR_FUNC("The length of STP packet is not valid !!! length = %d\n",
+ stp_core_ctx.parser.length);
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.rx_counter = 0;
+ STP_WARN_FUNC("error length(0x%x) detected, discard %d bytes\n",
+ stp_core_ctx.parser.length, i);
+ osal_buffer_dump(p_data, "full mode unexpected length", i, 0);
+ i = 0;
+ continue;
+ }
+ stp_core_ctx.rx_buf[2] = *p_data;
+ break;
+
+ case MTKSTP_CHECKSUM:
+ if (((stp_core_ctx.rx_buf[0] +
+ stp_core_ctx.rx_buf[1] + stp_core_ctx.rx_buf[2]) & 0xff) == *p_data) {
+ if ((stp_core_ctx.parser.type == STP_TASK_INDX) || mtk_wcn_stp_is_info_task()) {
+ stp_change_rx_state(MTKSTP_FW_MSG);
+ stp_core_ctx.rx_counter = 0;
+ i -= 1;
+ if (i != 0)
+ p_data += 1;
+ continue;
+ }
+ /* header only packet */
+ stp_process_header_only_packet();
+ } else {
+ STP_ERR_FUNC("The checksum of header is error !!! %02x %02x %02x %02x\n",
+ stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1],
+ stp_core_ctx.rx_buf[2], *p_data);
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.rx_counter = 0;
+ /* since checksum error is usually related to interface
+ * buffer overflow, so we just let timeout mechanism to
+ * handle such error.
+ */
+ /*stp_send_ack(1); NAK mechanism is removed */
+ osal_buffer_dump(p_data, "full mode unexpected checksum", i, 0);
+ i = 0;
+ continue;
+ }
+ break;
+
+ case MTKSTP_DATA:
+ /* block copy instead of byte copy */
+ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) {
+ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n",
+ stp_core_ctx.parser.length, stp_core_ctx.rx_counter);
+ osal_assert(0);
+ }
+ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter;
+ if (i >= remain_length) {
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length);
+ i -= remain_length;
+ p_data += remain_length;
+ stp_core_ctx.rx_counter = stp_core_ctx.parser.length;
+ stp_core_ctx.parser.state = MTKSTP_CRC1;
+ continue;
+ } else { /* only copy by data length */
+ /*fixed klocwork insight issue */
+ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) {
+ STP_ERR_FUNC
+ ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n");
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.rx_counter = 0;
+ STP_TRACE_FUNC("--\n");
+ return -1;
+ }
+
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i);
+ stp_core_ctx.rx_counter += i; /* all remain buffer are data */
+ i = 0;
+ p_data += i;
+ continue;
+ }
+ break;
+
+ case MTKSTP_CRC1:
+ stp_change_rx_state(MTKSTP_CRC2);
+ stp_core_ctx.parser.crc = *p_data;
+ break;
+ case MTKSTP_CRC2:
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.parser.crc += (*p_data) << 8;
+ if (stp_check_crc(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, stp_core_ctx.parser.crc)
+ == MTK_WCN_BOOL_TRUE) {
+ if (stp_core_ctx.inband_rst_set == 0)
+ stp_process_packet();
+ else
+ STP_WARN_FUNC("inband reset state,drop the packet\n");
+ } else {
+ STP_ERR_FUNC("[%d]CRC error, drop the packet\n", gCrcErrorCount++);
+ osal_buffer_dump(&stp_core_ctx.rx_buf[0], "CRC data", stp_core_ctx.rx_counter, 0);
+ stp_change_rx_state(MTKSTP_SYNC);
+ stp_core_ctx.rx_counter = 0;
+
+ /* since checksum error is usually related to interface
+ * buffer overflow, so we just let timeout mechanism to
+ * handle such error.
+ */
+ STP_TRACE_FUNC("--\n");
+ /* return and purge COMM port */
+ return -1;
+ /*stp_send_ack(1); NAK mechanism is removed */
+ }
+ break;
+
+ case MTKSTP_FW_MSG:
+ if (((length > 11) && (osal_strncmp(p_data, "{reset}", 7) == 0)) ||
+ (stp_core_ctx.parser.length == 7)) {
+ STP_INFO_FUNC("MCU need chip reset only! len=%d,pkt_len=%d!\n",
+ length, stp_core_ctx.parser.length);
+ chip_reset_only = 1;
+ }
+#if CFG_WMT_DUMP_INT_STATUS
+ if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE)
+ wmt_plat_BGF_irq_dump_status();
+#endif
+
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 1)
+ stp_btm_stop_trigger_assert_timer(STP_BTM_CORE(stp_core_ctx));
+ if (STP_IS_READY(stp_core_ctx))
+ mtk_wcn_stp_dbg_dump_package();
+
+ STP_SET_READY(stp_core_ctx, 0);
+ /*stp inband reset */
+ if (stp_core_ctx.parser.type == STP_TASK_INDX &&
+ stp_core_ctx.parser.seq == 0 &&
+ stp_core_ctx.parser.ack == 0 &&
+ stp_core_ctx.parser.length == 0 && stp_core_ctx.inband_rst_set == 1) {
+ STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r");
+ stp_rest_ctx_state();
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.inband_rst_set = 0;
+ STP_TRACE_FUNC("--\n");
+ return 0;
+ }
+
+ /*f/w assert and exception information */
+ if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) {
+ STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n",
+ stp_core_ctx.parser.length, stp_core_ctx.rx_counter);
+ osal_assert(0);
+ }
+
+ mtk_wcn_stp_assert_flow_ctrl(1);
+ if (mtk_wcn_stp_coredump_start_get() == 0 && stp_core_ctx.rx_counter == 0 &&
+ STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX)) {
+ mtk_wcn_stp_coredump_start_ctrl(1);
+ mtk_wcn_stp_ctx_save();
+ STP_INFO_FUNC("++ start to read paged dump and paged trace ++\n");
+ stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm);
+ STP_INFO_FUNC("++ start to read paged dump and paged trace --\n");
+ /* Dump CRC error count for debug only */
+ STP_INFO_FUNC("gCrcErrorCount = %d\n", gCrcErrorCount);
+ }
+
+ remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter;
+ if (i >= remain_length) {
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data,
+ remain_length);
+ i -= remain_length;
+ p_data += remain_length;
+ stp_core_ctx.rx_counter = stp_core_ctx.parser.length;
+ stp_change_rx_state(MTKSTP_SYNC);
+ *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0';
+ /*Trace32 Dump */
+ stp_trace32_dump();
+ /*discard CRC */
+ if (i >= 2) {
+ STP_DBG_FUNC("crc discard.. i = %d\n", i);
+ i -= 2;
+ if (i > 0)
+ p_data += 2;
+ }
+ continue;
+ } else { /* only copy by data length */
+
+ /*fixed klocwork insight issue */
+ if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) {
+ STP_ERR_FUNC
+ ("Fail to handle Packet, it doesn't follow STP protocol.\n");
+ stp_change_rx_state(MTKSTP_RESYNC1);
+ stp_core_ctx.rx_counter = 0;
+ return -1;
+ }
+ osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i);
+ stp_core_ctx.rx_counter += i; /* all remain buffer are data */
+ i = 0;
+ p_data += i;
+ continue;
+ }
+
+ break;
+ default:
+ break;
+ }
+ p_data++;
+ i--;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_parser_data
+* DESCRIPTION
+* push data to serial transport protocol parser engine
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* INT32 0 = success; -1 = crc/checksum error
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length)
+#else
+INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length)
+#endif
+{
+ /*----------------------------------------------------------------*/
+ /* Local Variables */
+ /*----------------------------------------------------------------*/
+ INT32 i;
+ PUINT8 p_data;
+ INT32 ret = 0;
+#ifdef DEBUG_DUMP_PACKET_HEAD
+ static UINT32 counter;
+
+ STP_TRACE_FUNC("++, rx (cnt=%d,len=%d)\n", ++counter, length);
+#endif
+
+ i = length;
+ p_data = (PUINT8) buffer;
+
+ /* STP is not enabled and only WMT can use Raw data path */
+ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == STP_PENDING_TYPE(stp_core_ctx)) {
+ stp_add_to_rx_queue(buffer, i, STP_PENDING_TYPE(stp_core_ctx));
+
+ /* mike: notify corresponding subfunction of incoming data */
+ (*sys_event_set) (STP_PENDING_TYPE(stp_core_ctx));
+ }
+ /* Mandatory or SDIO mode */
+ else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() ||
+ mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) {
+ ret = stp_parser_data_in_mand_mode(i, p_data);
+ }
+ /* Full mode */
+ else if ((mtk_wcn_stp_is_btif_fullset_mode() || mtk_wcn_stp_is_uart_fullset_mode())
+ && STP_IS_ENABLE(stp_core_ctx)) {
+ ret = stp_parser_data_in_full_mode(i, p_data);
+ }
+ STP_TRACE_FUNC("--\n");
+ return ret;
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_parser_data);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_enable
+* DESCRIPTION
+* enable/disable STP
+* PARAMETERS
+* value [IN] 0=disable, others=enable
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+INT32 mtk_wcn_stp_enable(INT32 value)
+{
+ STP_DBG_FUNC("%s: set the current enable = (%d)\n", __func__, value);
+
+ stp_rest_ctx_state();
+ STP_SET_ENABLE(stp_core_ctx, value);
+ if (!value)
+ mtk_wcn_stp_psm_reset();
+ else {
+/* g_block_tx = 0; */
+ mtk_wcn_stp_coredump_start_ctrl(0);
+ mtk_wcn_stp_set_wmt_trg_assert(0);
+ }
+ return 0;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_enable
+* DESCRIPTION
+* get STP enable/disable status
+* PARAMETERS
+* none.
+* RETURNS
+* INT32 0 = disable, 1 = enable
+*****************************************************************************/
+INT32 mtk_wcn_stp_is_enable(VOID)
+{
+ return STP_IS_ENABLE(stp_core_ctx);
+}
+
+INT32 mtk_wcn_stp_dbg_dump_package(VOID)
+{
+ if (STP_NOT_ENABLE(stp_core_ctx))
+ STP_INFO_FUNC("STP dbg mode is off\n");
+ else {
+ STP_INFO_FUNC("STP dbg mode is on\n");
+ wmt_lib_print_wmtd_op_history();
+ wmt_lib_print_worker_op_history();
+ stp_psm_print_op_history();
+ stp_btm_print_op_history();
+
+ if (mtk_wcn_stp_coredump_start_get() == 0 &&
+ mtk_wcn_stp_get_wmt_trg_assert() == 0) {
+ if (mtk_wcn_stp_is_sdio_mode()) {
+ stp_dbg_dmp_print(g_mtkstp_dbg);
+ STP_INFO_FUNC("STP_SDIO TX data dump start\n");
+ stp_sdio_txdbg_dump();
+ } else {
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG);
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG);
+ stp_dbg_dmp_print(g_mtkstp_dbg);
+ }
+ } else
+ STP_INFO_FUNC("assert start flag is set, disable packet dump function\n");
+ }
+ return 0;
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_ready
+* DESCRIPTION
+* ready/un-ready STP
+* PARAMETERS
+* value [IN] 0=un-ready, others=ready
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+INT32 mtk_wcn_stp_ready(INT32 value)
+{
+ STP_DBG_FUNC("set ready (%d)\n", value);
+
+ STP_SET_READY(stp_core_ctx, value);
+ /*if whole chip reset, reset the debuggine mode */
+#ifndef CONFIG_LOG_STP_INTERNAL
+ /* mtk_wcn_stp_dbg_disable(); */
+#endif
+
+ if (stp_is_apply_powersaving()) {
+ STP_INFO_FUNC("Restart the stp-psm monitor !!\n");
+ stp_psm_disable(STP_PSM_CORE(stp_core_ctx));
+ }
+
+ return 0;
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_coredump_start_ctrl
+* DESCRIPTION
+* set f/w assert flag in STP context
+* PARAMETERS
+* value [IN] 0=assert end, others=assert begins
+* RETURNS
+* INT32 0=success, others=error
+*****************************************************************************/
+INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value)
+{
+ if (value != STP_FW_COREDUMP_FLAG(stp_core_ctx)) {
+ STP_INFO_FUNC("set f/w assert (%d)\n", value);
+ STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, value);
+ }
+ return 0;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_coredump_start_get
+* DESCRIPTION
+* get f/w assert flag in STP context
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0= f/w assert flag is not set, others=f/w assert flag is set
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_coredump_start_get(VOID)
+#else
+INT32 mtk_wcn_stp_coredump_start_get(VOID)
+#endif
+{
+ return STP_FW_COREDUMP_FLAG(stp_core_ctx);
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get);
+#endif
+
+/* mtk_wcn_stp_set_wmt_last_close -- set the state of link(UART or SDIO)
+ * @ value - 1, link already be closed; 0, link is open
+ *
+ * Return 0 if success; else error code
+ */
+INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value)
+{
+ STP_INFO_FUNC("set wmt_last_close flag (%d)\n", value);
+
+ /* test whether last_close can be removed safely */
+ /* STP_SET_WMT_LAST_CLOSE(stp_core_ctx, value); */
+
+ return 0;
+}
+
+INT32 mtk_wcn_stp_is_wmt_last_close(VOID)
+{
+ return STP_WMT_LAST_CLOSE(stp_core_ctx);
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_send_data
+* DESCRIPTION
+* subfunction send data through STP
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] subfunction type
+* RETURNS
+* INT32 > 0: length transmitted; = 0: error
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type)
+#else
+INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type)
+#endif
+{
+ UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2];
+ PUINT8 p_tx_buf = NULL;
+ UINT16 crc;
+ INT32 ret = 0;
+
+ /* osal_buffer_dump(buffer,"tx", length, 32); */
+ osal_ftrace_print("%s|S|T%d|L%d\n", __func__, type, length);
+
+ if (STP_WMT_LAST_CLOSE(stp_core_ctx) != 0) {
+ STP_ERR_FUNC("WMT lats close,should not have tx request!\n");
+ return length;
+ }
+ /* if(g_block_tx) */
+ if (mtk_wcn_stp_coredump_start_get() != 0) {
+ STP_WARN_RATELIMITED_FUNC("STP fw coredump start flag set...\n");
+ return length;
+ }
+#ifdef CONFIG_POWER_SAVING_SUPPORT
+ if (type != WMT_TASK_INDX) {
+#if PSM_USE_COUNT_PACKAGE
+ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0);
+#else
+ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0, length);
+#endif
+ }
+
+ if (type == WMT_TASK_INDX)
+ goto DONT_MONITOR;
+ if ((type == BT_TASK_INDX) && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX)) {
+ if (stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx)))
+ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx));
+ goto DONT_MONITOR;
+ }
+ /*-----------------------------STP_PSM_Lock----------------------------------------*/
+ ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx));
+ if (ret) {
+ STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret);
+ return ret;
+ }
+
+ if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) {
+ if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) {
+ STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n");
+ stp_psm_release_data(STP_PSM_CORE(stp_core_ctx));
+ }
+ } else {
+ ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type);
+ stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx));
+ /*-----------------------------STP_PSM_UnLock-----------------------------------*/
+ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx));
+ return ret;
+ }
+DONT_MONITOR:
+#endif
+
+ ret = stp_ctx_lock(&stp_core_ctx);
+ if (ret) {
+ STP_ERR_FUNC("stp context lock failed, ret=%d\n", ret);
+ ret = 0;
+ goto STP_LOCK_FAIL;
+ }
+ /*Only WMT can set raw data */
+ if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) {
+ /* no-op */
+ } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) {
+ /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */
+ } else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() || mtk_wcn_stp_is_btif_mand_mode())
+ && STP_IS_ENABLE(stp_core_ctx)) {
+
+ /*mtkstp_header[0] = 0x80;*/
+ mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3); /* for debug purpose */
+ mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f);
+ mtkstp_header[2] = (length) & 0xff;
+ mtkstp_header[3] = 0x00;
+
+ /* HEADER */
+ p_tx_buf = &stp_core_ctx.tx_buf[0];
+ osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE);
+ p_tx_buf += MTKSTP_HEADER_SIZE;
+
+ /* PAYLOAD */
+ osal_memcpy(p_tx_buf, buffer, length);
+ p_tx_buf += length;
+
+ /* CRC */
+ temp[0] = 0x00;
+ temp[1] = 0x00;
+ osal_memcpy(p_tx_buf, temp, 2);
+ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length);
+ (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret);
+
+ if ((MTKSTP_HEADER_SIZE + length + 2) != ret) {
+ STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret);
+ osal_assert(0);
+ ret = 0;
+ } else
+ ret = (INT32) length;
+ }
+ else if ((mtk_wcn_stp_is_uart_fullset_mode() || mtk_wcn_stp_is_btif_fullset_mode())
+ && STP_IS_ENABLE(stp_core_ctx)) {
+
+ if ((stp_core_ctx.sequence.winspace > 0) &&
+ (stp_core_ctx.inband_rst_set == 0) &&
+ (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) {
+ /*Make Header */
+ mtkstp_header[0] =
+ 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack;
+ mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8);
+ mtkstp_header[2] = length & 0xff;
+ mtkstp_header[3] =
+ (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff;
+ stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] =
+ stp_core_ctx.tx_write;
+ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] =
+ MTKSTP_HEADER_SIZE + length + 2;
+ if (fgEnableDelimiter == 1) {
+ stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE;
+ stp_add_to_tx_queue((const PUINT8)(&stp_delimiter[0]),
+ STP_DEL_SIZE);
+ }
+ stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE);
+
+ /*Make Payload */
+ stp_add_to_tx_queue(buffer, length);
+
+ /*Make CRC */
+ crc = osal_crc16(buffer, length);
+ temp[0] = crc & 0xff;
+ temp[1] = (crc & 0xff00) >> 8;
+ stp_add_to_tx_queue(temp, 2);
+ stp_dbg_pkt_log(type,
+ stp_core_ctx.sequence.txack,
+ stp_core_ctx.sequence.txseq,
+ crc, PKT_DIR_TX, buffer, length);
+
+ /*Kick to BUS */
+ stp_send_tx_queue(stp_core_ctx.sequence.txseq);
+
+ INDEX_INC(stp_core_ctx.sequence.txseq);
+ stp_core_ctx.sequence.winspace--;
+
+ /*Setup the Retry Timer */
+ osal_timer_stop(&stp_core_ctx.tx_timer);
+ if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE)
+ osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout);
+ else
+ STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n");
+ ret = (INT32) length;
+ } else {
+ /*
+ * No winspace to send. Let caller retry
+ */
+ if (stp_core_ctx.inband_rst_set == 1)
+ STP_WARN_RATELIMITED_FUNC
+ ("Now it's inband reset process and drop sent packet.\n");
+ else
+ STP_WARN_RATELIMITED_FUNC("%s: There is no winspace/txqueue to send !!!\n",
+ __func__);
+ ret = 0;
+ }
+ }
+ stp_ctx_unlock(&stp_core_ctx);
+STP_LOCK_FAIL:
+#ifdef CONFIG_POWER_SAVING_SUPPORT
+
+ if (stp_psm_is_quick_ps_support() == MTK_WCN_BOOL_TRUE) {
+ stp_psm_notify_wmt_sleep(STP_PSM_CORE(stp_core_ctx));
+ }
+ /*-----------------------------STP_PSM_UnLock----------------------------------------*/
+ if (type != WMT_TASK_INDX) {
+ if (!((type == BT_TASK_INDX) && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX)))
+ stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx));
+ }
+#endif
+
+ osal_ftrace_print("%s|E|T|%d|L|%d\n", __func__, type, length);
+ return ret;
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_send_data);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_send_data_raw
+* DESCRIPTION
+* send raw data to common interface, bypass STP
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] subfunction type
+* RETURNS
+* INT32 >= 0: length transmitted; < 0: error
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type)
+#else
+INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type)
+#endif
+{
+ UINT32 written = 0;
+ INT32 ret = 0;
+
+ if (STP_WMT_LAST_CLOSE(stp_core_ctx) != 0) {
+ STP_ERR_FUNC("WMT lats close, should not have tx request!");
+ return length;
+ }
+
+ if (length >= 6)
+ STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d data = %x %x %x %x %x %x ", type,
+ buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+ else if (length > 0)
+ STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d data = %x", type, buffer[0]);
+
+ /* remember tx type, forward following rx to this type */
+ STP_SET_PENDING_TYPE(stp_core_ctx, type);
+
+ stp_ctx_lock(&stp_core_ctx);
+ stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length);
+ (*sys_if_tx) (&buffer[0], length, &written);
+ stp_ctx_unlock(&stp_core_ctx);
+
+ if (written == 0)
+ stp_dump_data(&buffer[0], "tx raw failed:", length);
+
+ if (written == length)
+ ret = (INT32) written;
+ else
+ ret = (-1);
+
+ return ret;
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_receive_data
+* DESCRIPTION
+* receive data from serial protocol engine
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] subfunction type
+* RETURNS
+* INT32 >= 0: size of data received; < 0: error
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type)
+#else
+INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type)
+#endif
+{
+ /* GeorgeKuo modify: reduce "if" branch */
+ UINT16 copyLen = 0;
+ UINT16 tailLen = 0;
+
+ osal_ftrace_print("%s|S|T|%d|L|%d\n", __func__, type, length);
+ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+ while (stp_core_ctx.ring[type].read_p != stp_core_ctx.ring[type].write_p) {
+ /* GeorgeKuo modify: reduce if branch */
+ if (stp_core_ctx.ring[type].write_p > stp_core_ctx.ring[type].read_p) {
+ copyLen = stp_core_ctx.ring[type].write_p - stp_core_ctx.ring[type].read_p;
+ if (copyLen > length)
+ copyLen = length;
+ osal_memcpy(buffer,
+ stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p,
+ copyLen);
+ stp_core_ctx.ring[type].read_p += copyLen;
+ break;
+ }
+ tailLen = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].read_p;
+ if (tailLen > length) { /* exclude equal case to skip wrap check */
+ copyLen = length;
+ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer +
+ stp_core_ctx.ring[type].read_p, copyLen);
+ stp_core_ctx.ring[type].read_p += copyLen;
+ } else {
+ /* part 1: copy tailLen */
+ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer +
+ stp_core_ctx.ring[type].read_p, tailLen);
+ buffer += tailLen; /* update buffer offset */
+ /* part 2: check if head length is enough */
+ copyLen = length - tailLen;
+ copyLen = (stp_core_ctx.ring[type].write_p <
+ copyLen) ? stp_core_ctx.ring[type].write_p : copyLen;
+ if (copyLen)
+ osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + 0, copyLen);
+ /* Update read_p final position */
+ stp_core_ctx.ring[type].read_p = copyLen;
+ /* update return length: head + tail */
+ copyLen += tailLen;
+ }
+ break;
+ }
+
+ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+
+ if ((stp_psm_is_quick_ps_support() == MTK_WCN_BOOL_TRUE) && (type != WMT_TASK_INDX)) {
+#if PSM_USE_COUNT_PACKAGE
+ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1);
+#else
+ stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1, copyLen);
+#endif
+ }
+
+ osal_ftrace_print("%s|E|T|%d|L|%d\n", __func__, type, copyLen);
+ return copyLen;
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_receive_data);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_rxqueue_empty
+* DESCRIPTION
+* Is certain rx queue empty?
+* PARAMETERS
+* type [IN] subfunction type
+* RETURNS
+* INT32 0: queue is NOT empyt; !0: queue is empty
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_is_rxqueue_empty(UINT8 type)
+#else
+INT32 mtk_wcn_stp_is_rxqueue_empty(UINT8 type)
+#endif
+{
+ INT32 ret;
+
+ osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+
+ if (stp_core_ctx.ring[type].read_p == stp_core_ctx.ring[type].write_p)
+ ret = 1; /* queue is empty */
+ else
+ ret = 0; /* queue is not empty */
+
+ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+
+ return ret;
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_set_sdio_mode
+* DESCRIPTION
+* Set stp for SDIO mode
+* PARAMETERS
+* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode)
+* RETURNS
+* void
+*****************************************************************************/
+
+void mtk_wcn_stp_set_mode(UINT32 mode)
+{
+ STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, mode);
+ STP_DBG_FUNC("STP_SUPPORT_PROTOCOL = %08x\n", STP_SUPPORT_PROTOCOL(stp_core_ctx));
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_uart_fullset_mode
+* DESCRIPTION
+* Is stp use UART fullset mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:Uart Fullset mode, FALSE:Not UART Fullset mode
+*****************************************************************************/
+MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(VOID)
+{
+ /*
+ * bit 0: uart fullset mode
+ * bit 1: uart mandatory mode
+ * bit 2: sdio mode
+ */
+ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_FULL_MODE)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_uart_mand_mode
+* DESCRIPTION
+* Is stp use UART mandatory mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:Uart Mandatory mode, FALSE:Not UART Mandotary mode
+*****************************************************************************/
+MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID)
+{
+ /*
+ * bit 0: uart fullset mode
+ * bit 1: uart mandatory mode
+ * bit 2: sdio mode
+ */
+ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_MAND_MODE)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_sdio_mode
+* DESCRIPTION
+* Is stp use SDIO mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode
+*****************************************************************************/
+MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(VOID)
+{
+ /*
+ * bit 0: uart fullset mode
+ * bit 1: uart mandatory mode
+ * bit 2: sdio mode
+ */
+ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_SDIO_MODE)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_btif_fullset_mode
+* DESCRIPTION
+* Is stp use BTIF fullset mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:BTIF Fullset mode, FALSE:Not BTIF Fullset mode
+*****************************************************************************/
+MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(VOID)
+{
+
+ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_FULL_MODE)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_btif_mand_mode
+* DESCRIPTION
+* Is stp use BTIF mandatory mode?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:BTIF Mandatory mode, FALSE:Not BTIF Mandotary mode
+*****************************************************************************/
+
+MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void)
+{
+
+ if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_MAND_MODE)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+/*****************************************************************************
+* FUNCTION
+* stp_send_inband_reset
+* DESCRIPTION
+* To sync to oringnal stp state with f/w stp
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+VOID mtk_wcn_stp_inband_reset(VOID)
+{
+ UINT8 inband_reset_packet[64];
+ UINT32 txseq = 0;
+ UINT32 txack = 0;
+ UINT32 crc = 0;
+ UINT32 ret = 0;
+ UINT32 reset_payload_len = 0;
+
+ /*512 bytes */
+ UINT8 reset_payload[] = {
+ 0xc0, 0x01, 0xc0, 0xde, 0x3e, 0xd1, 0xa7, 0xef
+ };
+
+ stp_ctx_lock(&stp_core_ctx);
+
+ /*RESYNC*/ inband_reset_packet[0] = 0x7f;
+ inband_reset_packet[1] = 0x7f;
+ inband_reset_packet[2] = 0x7f;
+ inband_reset_packet[3] = 0x7f;
+ inband_reset_packet[4] = 0x7f;
+ inband_reset_packet[5] = 0x7f;
+ inband_reset_packet[6] = 0x7f;
+ inband_reset_packet[7] = 0x7f;
+
+ /*header */
+ reset_payload_len = ARRAY_SIZE(reset_payload);
+ inband_reset_packet[8] = 0x80 + (txseq << 3) + txack;
+ inband_reset_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8);
+ inband_reset_packet[10] = reset_payload_len & 0xff;
+ inband_reset_packet[11] =
+ (inband_reset_packet[8] + inband_reset_packet[9] + inband_reset_packet[10]) & 0xff;
+
+ /*payload */
+ osal_memcpy(&inband_reset_packet[12], reset_payload, reset_payload_len);
+
+ /*crc */
+ crc = osal_crc16(&reset_payload[0], reset_payload_len);
+ inband_reset_packet[12 + reset_payload_len] = crc & 0xff;
+ inband_reset_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8;
+
+ (*sys_if_tx)(&inband_reset_packet[0], 14 + reset_payload_len, &ret);
+
+ if (ret != (14 + reset_payload_len))
+ STP_ERR_FUNC("Inband sending error, sending %d , but ret = %d\n",
+ 10 + reset_payload_len, ret);
+
+ stp_core_ctx.inband_rst_set = 1;
+ stp_ctx_unlock(&stp_core_ctx);
+}
+
+void mtk_wcn_stp_debug_ctrl(INT32 op, INT32 filter, INT32 filter_param)
+{
+}
+
+void mtk_wcn_stp_test_cmd(INT32 cmd_no)
+{
+ UINT8 test_packet[64];
+ UINT32 txseq = 0;
+ UINT32 txack = 0;
+ UINT32 crc = 0;
+ UINT32 ret = 0;
+ UINT32 reset_payload_len = 0;
+
+ UINT8 test_payload[] = {
+ 0xAA, 0xAA, 0xC0, 0xDE, 0x3E, 0xD1, 0xA7, 0xEF
+ };
+/* */
+/* select your test command by cmd_no */
+/* */
+ if (cmd_no == 0) {
+ /* to test new command to chip */
+ stp_ctx_lock(&stp_core_ctx);
+
+ /*RESYNC*/ test_packet[0] = 0x7f;
+ test_packet[1] = 0x7f;
+ test_packet[2] = 0x7f;
+ test_packet[3] = 0x7f;
+ test_packet[4] = 0x7f;
+ test_packet[5] = 0x7f;
+ test_packet[6] = 0x7f;
+ test_packet[7] = 0x7f;
+
+ /*header */
+ reset_payload_len = ARRAY_SIZE(test_payload);
+ test_packet[8] = 0x80 + (txseq << 3) + txack;
+ test_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8);
+ test_packet[10] = reset_payload_len & 0xff;
+ test_packet[11] = (test_packet[8] + test_packet[9] + test_packet[10]) & 0xff;
+
+ /*payload */
+ osal_memcpy(&test_packet[12], test_payload, reset_payload_len);
+
+ /*crc */
+ crc = osal_crc16(&test_payload[0], reset_payload_len);
+ test_packet[12 + reset_payload_len] = crc & 0xff;
+ test_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8;
+
+ (*sys_if_tx)(&test_packet[0], 14 + reset_payload_len, &ret);
+ if (ret != (14 + reset_payload_len))
+ STP_ERR_FUNC("stp test sending error, sending %d , but ret = %d\n",
+ 10 + reset_payload_len, ret);
+
+ stp_ctx_unlock(&stp_core_ctx);
+ }
+
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_flush_context
+* DESCRIPTION
+* Flush STP Context
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+VOID mtk_wcn_stp_flush_context(VOID)
+{
+ stp_rest_ctx_state();
+}
+
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_flush_rx_queue
+* DESCRIPTION
+* Flush STP Rx Queue
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+
+VOID mtk_wcn_stp_flush_rx_queue(UINT32 type)
+{
+ INT32 ret = 0;
+
+ if (type < MTKSTP_MAX_TASK_NUM) {
+ ret = osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+ if (ret != 0) {
+ STP_WARN_FUNC("stp context lock failed, ret=%d\n", ret);
+ return;
+ }
+ stp_core_ctx.ring[type].read_p = 0;
+ stp_core_ctx.ring[type].write_p = 0;
+ osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx);
+ }
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_enable
+* DESCRIPTION
+* STP is ready?
+* PARAMETERS
+* none.
+* RETURNS
+* none
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+MTK_WCN_BOOL _mtk_wcn_stp_is_ready(VOID)
+#else
+MTK_WCN_BOOL mtk_wcn_stp_is_ready(VOID)
+#endif
+{
+ return STP_IS_READY(stp_core_ctx);
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_is_ready);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* set_bluetooth_rx_interface
+* DESCRIPTION
+* Set bluetooth rx interface
+* PARAMETERS
+* rx interface type
+* RETURNS
+* void
+*****************************************************************************/
+#if STP_EXP_HID_API_EXPORT
+VOID _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag)
+#else
+VOID mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag)
+#endif
+{
+ /* g_mtkstp_bluez_flag = bluez_flag; */
+ STP_SET_BT_STK(stp_core_ctx, bluez_flag);
+}
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+EXPORT_SYMBOL(mtk_wcn_stp_set_bluez);
+#endif
+
+/*****************************************************************************
+* FUNCTION
+* set stp debugging mdoe
+* DESCRIPTION
+* set stp debugging mdoe
+* PARAMETERS
+* dbg_mode: switch to dbg mode ?
+* RETURNS
+* void
+*****************************************************************************/
+VOID mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode)
+{
+ STP_SET_ENABLE_DBG(stp_core_ctx, dbg_mode);
+}
+
+/*****************************************************************************
+* FUNCTION
+* set stp auto reset mdoe
+* DESCRIPTION
+* set stp auto reset mdoe
+* PARAMETERS
+* auto_rst: switch to auto reset mode ?
+* RETURNS
+* void
+*****************************************************************************/
+VOID mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst)
+{
+ STP_SET_ENABLE_RST(stp_core_ctx, auto_rst);
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_open_btif
+* DESCRIPTION
+* init btif hw & sw by owner stp
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_open_btif(VOID)
+{
+ return mtk_wcn_consys_stp_btif_open();
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_open_close
+* DESCRIPTION
+* close btif hw & sw by owner stp
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_close_btif(VOID)
+{
+ return mtk_wcn_consys_stp_btif_close();
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_rx_cb_register
+* DESCRIPTION
+* register stp rx cb to btif
+* PARAMETERS
+* MTK_WCN_BTIF_RX_CB stp rx handle function
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb)
+{
+ return mtk_wcn_consys_stp_btif_rx_cb_register(rx_cb);
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_tx
+* DESCRIPTION
+* send stp package by btif
+* PARAMETERS
+* pBuf:package buffer pointer,len:package length
+* written_len:package written length
+* RETURNS
+* INT32 package length-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len)
+{
+ INT32 iRet = -1;
+
+ iRet = mtk_wcn_consys_stp_btif_tx(pBuf, len, written_len);
+ return iRet;
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_wakeup_consys
+* DESCRIPTION
+* STP wakeup consys by btif
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_wakeup_consys(VOID)
+{
+ /*log wakeup int for debug */
+ stp_dbg_pkt_log(7, 0, 0, 0, PKT_DIR_TX, NULL, 0);
+ return mtk_wcn_consys_stp_btif_wakeup();
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_dpidle_ctrl
+* DESCRIPTION
+* decide AP enter or exit deep idle
+* PARAMETERS
+* en_flag:1,enter,0,exit
+* RETURNS
+* always 0
+*****************************************************************************/
+INT32 mtk_wcn_stp_dpidle_ctrl(UINT32 en_flag)
+{
+ mtk_wcn_consys_stp_btif_dpidle_ctrl(en_flag);
+
+ return 0;
+}
+
+INT32 mtk_wcn_stp_notify_sleep_for_thermal(VOID)
+{
+ return stp_psm_sleep_for_thermal(STP_PSM_CORE(stp_core_ctx));
+}
+
+VOID mtk_wcn_stp_set_wmt_trg_assert(UINT32 value)
+{
+ STP_DBG_FUNC("set evt err tigger assert flag to %d\n", value);
+ STP_SET_ASSERT(stp_core_ctx, value);
+}
+
+UINT32 mtk_wcn_stp_get_wmt_trg_assert(VOID)
+{
+ return STP_ASSERT(stp_core_ctx);
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_lpbk_ctrl
+* DESCRIPTION
+* enable stp internal lpbk test or not
+* PARAMETERS
+* mode:1,enable,0,disabel
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode)
+{
+ return mtk_wcn_consys_stp_btif_lpbk_ctrl(mode);
+}
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_logger_ctrl
+* DESCRIPTION
+* dump btif buffer or register status when No ACK or assert occurs
+* PARAMETERS
+* flag:see enum value in enum _ENUM_BTIF_DBG_ID_
+* RETURNS
+* INT32 0-success,other fail.
+*****************************************************************************/
+INT32 mtk_wcn_stp_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag)
+{
+ return mtk_wcn_consys_stp_btif_logger_ctrl(flag);
+}
+
+VOID mtk_wcn_stp_ctx_save(void)
+{
+ STP_DBG_FUNC("start ++\n");
+ stp_psm_set_sleep_disable(stp_core_ctx.psm);
+ STP_DBG_FUNC("exit --\n");
+}
+
+VOID mtk_wcn_stp_ctx_restore(void)
+{
+ stp_core_ctx.assert_info_cnt = 0;
+
+ stp_psm_set_sleep_enable(stp_core_ctx.psm);
+ stp_btm_reset_btm_wq(STP_BTM_CORE(stp_core_ctx));
+
+ if (STP_IS_ENABLE_RST(stp_core_ctx))
+ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx));
+ else
+ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n");
+}
+
+INT32 mtk_wcn_stp_wmt_trg_assert(VOID)
+{
+ INT32 ret = -1;
+
+ if (mtk_wcn_stp_coredump_start_get() != 0) {
+ STP_INFO_FUNC("firmware assert has been triggered\n");
+ return 1;
+ }
+ ret = stp_notify_btm_do_fw_assert(STP_BTM_CORE(stp_core_ctx));
+
+ if (ret) {
+ STP_ERR_FUNC("trigger assert fail,do chip reset to recovery\n");
+ if (STP_IS_ENABLE_RST(stp_core_ctx))
+ stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx));
+ else
+ STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n");
+ }
+
+ return ret;
+}
+
+INT32 mtk_wcn_stp_assert_timeout_handle(VOID)
+{
+ INT32 ret = 0;
+ P_CONSYS_EMI_ADDR_INFO p_ecsi;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) {
+ mtk_wcn_stp_ctx_restore();
+ return ret;
+ }
+
+ p_ecsi = wmt_plat_get_emi_phy_add();
+ /* dump btif data */
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG);
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG);
+ mtk_wcn_stp_coredump_start_ctrl(1);
+ if (p_ecsi != NULL && wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_assert_flag)) {
+ STP_INFO_FUNC("EMI assert flag was set. To do coredump.\n");
+ mtk_wcn_stp_ctx_save();
+ ret = stp_btm_notify_wmt_dmp_wq(STP_BTM_CORE(stp_core_ctx));
+ } else {
+ /*host trigger assert timeout and no coredump packet. To dump EMI data*/
+ STP_INFO_FUNC("host trigger fw assert timeout!\n");
+ WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("Trigger assert timeout");
+ if (mtk_wcn_stp_coredump_flag_get() != 0)
+ ret = stp_dbg_start_emi_dump();
+ else
+ mtk_wcn_stp_ctx_restore();
+ }
+ return ret;
+}
+
+INT32 mtk_wcn_stp_coredump_timeout_handle(VOID)
+{
+ /* dump btif data */
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG);
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG);
+
+ WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("Coredump timeout");
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ mtk_wcn_stp_ctx_restore();
+ return 0;
+}
+
+VOID mtk_wcn_stp_dbg_pkt_log(INT32 type, INT32 dir)
+{
+ stp_dbg_pkt_log(type, 0, 0, 0, dir, NULL, 0);
+}
+
+VOID mtk_stp_sdio_retry_flag_ctrl(INT32 flag)
+{
+ if (flag) {
+ if (flag != wmt_dbg_sdio_retry_ctrl)
+ flag = wmt_dbg_sdio_retry_ctrl;
+ }
+ stp_sdio_retry_flag_ctrl(flag == 0 ? 0 : 1);
+}
+
+VOID mtk_stp_dbg_sdio_retry_flag_ctrl(INT32 flag)
+{
+ wmt_dbg_sdio_retry_ctrl = flag == 0 ? 0 : 1;
+}
+
+INT32 mtk_stp_sdio_retry_flag_get(VOID)
+{
+ return stp_sdio_retry_flag_get();
+}
+
+VOID mtk_stp_dump_sdio_register(VOID)
+{
+ stp_sdio_dump_register();
+}
+
+INT32 mtk_stp_dbg_dmp_append(PUINT8 buf, INT32 max_len)
+{
+ return stp_dbg_dmp_append(g_mtkstp_dbg, buf, max_len);
+}
+
+VOID mtk_stp_notify_emi_dump_end(VOID)
+{
+ stp_btm_notify_emi_dump_end(STP_BTM_CORE(stp_core_ctx));
+}
+
+INT32 mtk_stp_check_rx_has_pending_data(VOID)
+{
+ return sys_rx_has_pending_data();
+}
+
+P_OSAL_THREAD mtk_stp_rx_thread_get(VOID)
+{
+ return sys_rx_thread_get();
+}
+
+VOID mtk_wcn_stp_assert_flow_ctrl(UINT32 on)
+{
+ STP_DBG_FUNC("Set assert progress flag to %d\n", on);
+ STP_SET_ASSERT_IN_PROGRESS(stp_core_ctx, on);
+}
+
+UINT32 mtk_wcn_stp_assert_flow_get(VOID)
+{
+ return STP_ASSERT_IN_PROGRESS(stp_core_ctx);
+}
+
+VOID mtk_wcn_stp_set_support_gpsl5(MTK_WCN_BOOL support_gpsl5)
+{
+ STP_SET_SUPPORT_GPSL5(stp_core_ctx, support_gpsl5);
+}
+
+INT32 mtk_wcn_stp_is_support_gpsl5(VOID)
+{
+ return STP_IS_SUPPORT_GPSL5(stp_core_ctx);
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c
new file mode 100644
index 0000000000000000000000000000000000000000..f695778f328f12919b7b1ad7864a2405f32fce49
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#if 0 /* to do---- need check why need this header file */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include /* udelay() */
+
+#include
+#include
+#endif
+#include "osal_typedef.h"
+#include "stp_core.h"
+#include "stp_exp.h"
+#include "hif_sdio.h"
+#include "stp_sdio.h"
+#include "stp_dbg.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
+********************************************************************************
+*/
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+static MTK_WCN_STP_IF_TX stp_uart_if_tx;
+static MTK_WCN_STP_IF_TX stp_sdio_if_tx;
+static MTK_WCN_STP_IF_TX stp_btif_if_tx;
+static MTK_WCN_STP_RX_HAS_PENDING_DATA stp_btif_rx_has_pending_data;
+static MTK_WCN_STP_TX_HAS_PENDING_DATA stp_btif_tx_has_pending_data;
+static MTK_WCN_STP_RX_THREAD_GET stp_btif_rx_thread_get;
+static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX;
+static MTK_WCN_STP_IF_RX stp_if_rx;
+static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 };
+static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 };
+
+/******************************************************************************
+* 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
+********************************************************************************
+*/
+
+INT32 mtk_wcn_sys_if_rx(PUINT8 data, INT32 size)
+{
+ if (stp_if_rx == 0x0)
+ return -1;
+ (*stp_if_rx)(data, size);
+ return 0;
+}
+
+static INT32 mtk_wcn_sys_if_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size)
+{
+ if (g_stp_if_type == STP_UART_IF_TX)
+ return stp_uart_if_tx != NULL ? (*stp_uart_if_tx)(data, size, written_size) : -1;
+ else if (g_stp_if_type == STP_SDIO_IF_TX)
+ return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx)(data, size, written_size) : -1;
+ else if (g_stp_if_type == STP_BTIF_IF_TX)
+ return stp_btif_if_tx != NULL ? (*stp_btif_if_tx) (data, size, written_size) : -1;
+ /*if (g_stp_if_type >= STP_MAX_IF_TX) *//* George: remove ALWAYS TRUE condition */
+ return -1;
+}
+
+static INT32 mtk_wcn_sys_rx_has_pending_data(VOID)
+{
+ if (g_stp_if_type == STP_BTIF_IF_TX)
+ return stp_btif_rx_has_pending_data != NULL ? (*stp_btif_rx_has_pending_data) () : -1;
+ return -1;
+}
+
+static INT32 mtk_wcn_sys_tx_has_pending_data(VOID)
+{
+ if (g_stp_if_type == STP_BTIF_IF_TX)
+ return stp_btif_tx_has_pending_data != NULL ? (*stp_btif_tx_has_pending_data) () : -1;
+ return -1;
+}
+
+static P_OSAL_THREAD mtk_wcn_sys_rx_thread_get(VOID)
+{
+ if (g_stp_if_type == STP_BTIF_IF_TX)
+ return stp_btif_rx_thread_get != NULL ? (*stp_btif_rx_thread_get) () : NULL;
+ return NULL;
+}
+
+static INT32 mtk_wcn_sys_event_set(UINT8 function_type)
+{
+ if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0))
+ (*event_callback_tbl[function_type])();
+ else {
+ /* FIXME: error handling */
+ osal_dbg_print("[%s] STP set event fail. It seems the function is not active.\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace)
+{
+ int type = 0;
+
+ for (type = 0; type < MTKSTP_MAX_TASK_NUM; type++) {
+ if (tx_event_callback_tbl[type])
+ tx_event_callback_tbl[type]();
+ }
+
+ return 0;
+}
+
+static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op)
+{
+
+ /*op == FUNCTION_ACTIVE, to check if funciton[type] is active ? */
+ if (type >= MTKSTP_MAX_TASK_NUM)
+ return STATUS_FUNCTION_INVALID;
+
+ if (op == OP_FUNCTION_ACTIVE) {
+ if (event_callback_tbl[type] != 0x0)
+ return STATUS_FUNCTION_ACTIVE;
+ return STATUS_FUNCTION_INACTIVE;
+ }
+ /*you can define more operation here ..., to queury function's status/information */
+
+ return STATUS_OP_INVALID;
+}
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func)
+#else
+INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func)
+#endif
+{
+ stp_if_rx = func;
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx);
+#endif
+
+VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type)
+{
+ g_stp_if_type = stp_if_type;
+ osal_dbg_print("[%s] set STP_IF_TX to %s.\n",
+ __func__,
+ (STP_UART_IF_TX ==
+ stp_if_type) ? "UART" : ((STP_SDIO_IF_TX ==
+ stp_if_type) ? "SDIO" : "NULL"));
+}
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func)
+#else
+INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func)
+#endif
+{
+ if (stp_if == STP_UART_IF_TX)
+ stp_uart_if_tx = func;
+ else if (stp_if == STP_SDIO_IF_TX)
+ stp_sdio_if_tx = func;
+ else if (stp_if == STP_BTIF_IF_TX)
+ stp_btif_if_tx = func;
+ else {
+ osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if);
+ return -1;
+ }
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx);
+#endif
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func)
+#else
+INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func)
+#endif
+{
+ if ((type < MTKSTP_MAX_TASK_NUM) && (type >= BT_TASK_INDX)) {
+ event_callback_tbl[type] = func;
+
+ /*clear rx queue */
+ mtk_wcn_stp_flush_rx_queue(type);
+ }
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb);
+#endif
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func)
+#else
+INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func)
+#endif
+{
+ if ((type < MTKSTP_MAX_TASK_NUM) && (type >= BT_TASK_INDX))
+ tx_event_callback_tbl[type] = func;
+ else
+ osal_bug_on(0);
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb);
+#endif
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func)
+#else
+INT32 mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func)
+#endif
+{
+ if (stp_if == STP_BTIF_IF_TX)
+ stp_btif_rx_has_pending_data = func;
+ else {
+ osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if);
+ return -1;
+ }
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_rx_has_pending_data);
+#endif
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func)
+#else
+INT32 mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func)
+#endif
+{
+ if (stp_if == STP_BTIF_IF_TX)
+ stp_btif_tx_has_pending_data = func;
+ else {
+ osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if);
+ return -1;
+ }
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_tx_has_pending_data);
+#endif
+
+#if STP_EXP_HID_API_EXPORT
+INT32 _mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func)
+#else
+INT32 mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func)
+#endif
+{
+ if (stp_if == STP_BTIF_IF_TX)
+ stp_btif_rx_thread_get = func;
+ else {
+ osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if);
+ return -1;
+ }
+
+ return 0;
+}
+#if !STP_EXP_HID_API_EXPORT
+EXPORT_SYMBOL(mtk_wcn_stp_register_rx_thread_get);
+#endif
+
+INT32 stp_drv_init(VOID)
+{
+ INT32 ret = 0;
+
+ mtkstp_callback cb = {
+ .cb_if_tx = mtk_wcn_sys_if_tx,
+ .cb_rx_has_pending_data = mtk_wcn_sys_rx_has_pending_data,
+ .cb_tx_has_pending_data = mtk_wcn_sys_tx_has_pending_data,
+ .cb_rx_thread_get = mtk_wcn_sys_rx_thread_get,
+ .cb_event_set = mtk_wcn_sys_event_set,
+ .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume,
+ .cb_check_funciton_status = mtk_wcn_sys_check_function_status
+ };
+#if 0
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+ MTK_WCN_STP_EXP_CB_INFO stpExpCb = {
+ .stp_send_data_cb = _mtk_wcn_stp_send_data,
+ .stp_send_data_raw_cb = _mtk_wcn_stp_send_data_raw,
+ .stp_parser_data_cb = _mtk_wcn_stp_parser_data,
+ .stp_receive_data_cb = _mtk_wcn_stp_receive_data,
+ .stp_is_rxqueue_empty_cb = _mtk_wcn_stp_is_rxqueue_empty,
+ .stp_is_ready_cb = _mtk_wcn_stp_is_ready,
+ .stp_set_bluez_cb = _mtk_wcn_stp_set_bluez,
+ .stp_if_tx_cb = _mtk_wcn_stp_register_if_tx,
+ .stp_if_rx_cb = _mtk_wcn_stp_register_if_rx,
+ .stp_reg_event_cb = _mtk_wcn_stp_register_event_cb,
+ .stp_reg_tx_event_cb = _mtk_wcn_stp_register_tx_event_cb,
+ .stp_coredump_start_get_cb = _mtk_wcn_stp_coredump_start_get
+ };
+ mtk_wcn_stp_exp_cb_reg(&stpExpCb);
+
+#endif
+#endif
+ ret = mtk_wcn_stp_init(&cb);
+
+ return ret;
+}
+
+VOID stp_drv_exit(VOID)
+{
+ mtk_wcn_stp_deinit();
+#if 0
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+ mtk_wcn_stp_exp_cb_unreg();
+#endif
+#endif
+}
+
+INT32 mtk_wcn_stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ stp_sdio_wake_up_ctrl(ctx);
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_stp_sdio_wake_up_ctrl);
+
+INT32 mtk_stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd)
+{
+ return stp_dbg_poll_cpupcr(times, sleep, cmd);
+}
+EXPORT_SYMBOL(mtk_stp_dbg_poll_cpupcr);
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c
new file mode 100644
index 0000000000000000000000000000000000000000..5d1d387c7a8a7623941fc251742345ea8b42bc7b
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-CONF]"
+
+
+#include "osal_typedef.h"
+/* #include "osal.h" */
+#include "wmt_lib.h"
+#include "wmt_dev.h"
+#include "wmt_conf.h"
+#include "wmt_detect.h"
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+struct parse_data {
+ PINT8 name;
+ INT32 (*parser)(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 value);
+ PINT8 (*writer)(P_DEV_WMT pWmtDev, const struct parse_data *data);
+ /*PCHAR param1, *param2, *param3; */
+ /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */
+ PINT8 param1;
+ PINT8 param2;
+ PINT8 param3;
+};
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+
+/******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+*******************************************************************************
+*/
+static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos);
+
+static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data);
+
+static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev,
+ const struct parse_data *data, const PINT8 pos);
+
+static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data);
+
+static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos);
+
+static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data);
+
+static INT32 wmt_conf_parse_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data,
+ const PINT8 pos);
+
+static PINT8 wmt_conf_write_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data);
+
+static INT32 wmt_conf_parse_string(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos);
+
+static PINT8 wmt_conf_write_string(P_DEV_WMT pWmtDev, const struct parse_data *data);
+
+static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal);
+
+static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size);
+
+#define OFFSET(v) ((void *) &((P_DEV_WMT) 0)->v)
+
+#define CHAR(f) {#f, wmt_conf_parse_char, wmt_conf_write_char, OFFSET(rWmtGenConf.f), NULL, NULL}
+
+#define SHORT(f) {#f, wmt_conf_parse_short, wmt_conf_write_short, OFFSET(rWmtGenConf.f), NULL, NULL}
+
+#define INT(f) {#f, wmt_conf_parse_int, wmt_conf_write_int, OFFSET(rWmtGenConf.f), NULL, NULL}
+
+#define BYTE_ARRAY(f) {#f, wmt_conf_parse_byte_array, wmt_conf_write_byte_array, \
+ OFFSET(rWmtGenConf.f), NULL, NULL}
+
+#define STRING(f) {#f, wmt_conf_parse_string, wmt_conf_write_string, OFFSET(rWmtGenConf.f), NULL, NULL}
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static const struct parse_data wmtcfg_fields[] = {
+ CHAR(coex_wmt_ant_mode),
+ CHAR(coex_wmt_ant_mode_ex),
+ CHAR(coex_wmt_ext_component),
+ CHAR(coex_wmt_wifi_time_ctl),
+ CHAR(coex_wmt_ext_pta_dev_on),
+ CHAR(coex_wmt_filter_mode),
+
+ CHAR(coex_bt_rssi_upper_limit),
+ CHAR(coex_bt_rssi_mid_limit),
+ CHAR(coex_bt_rssi_lower_limit),
+ CHAR(coex_bt_pwr_high),
+ CHAR(coex_bt_pwr_mid),
+ CHAR(coex_bt_pwr_low),
+
+ CHAR(coex_wifi_rssi_upper_limit),
+ CHAR(coex_wifi_rssi_mid_limit),
+ CHAR(coex_wifi_rssi_lower_limit),
+ CHAR(coex_wifi_pwr_high),
+ CHAR(coex_wifi_pwr_mid),
+ CHAR(coex_wifi_pwr_low),
+
+ CHAR(coex_ext_pta_hi_tx_tag),
+ CHAR(coex_ext_pta_hi_rx_tag),
+ CHAR(coex_ext_pta_lo_tx_tag),
+ CHAR(coex_ext_pta_lo_rx_tag),
+ SHORT(coex_ext_pta_sample_t1),
+ SHORT(coex_ext_pta_sample_t2),
+ CHAR(coex_ext_pta_wifi_bt_con_trx),
+
+ INT(coex_misc_ext_pta_on),
+ INT(coex_misc_ext_feature_set),
+
+ CHAR(wmt_gps_lna_pin),
+ CHAR(wmt_gps_lna_enable),
+
+ CHAR(pwr_on_rtc_slot),
+ CHAR(pwr_on_ldo_slot),
+ CHAR(pwr_on_rst_slot),
+ CHAR(pwr_on_off_slot),
+ CHAR(pwr_on_on_slot),
+ CHAR(co_clock_flag),
+
+ CHAR(disable_deep_sleep_cfg),
+
+ INT(sdio_driving_cfg),
+
+ SHORT(coex_wmt_wifi_path),
+
+ CHAR(coex_wmt_ext_elna_gain_p1_support),
+ INT(coex_wmt_ext_elna_gain_p1_D0),
+ INT(coex_wmt_ext_elna_gain_p1_D1),
+ INT(coex_wmt_ext_elna_gain_p1_D2),
+ INT(coex_wmt_ext_elna_gain_p1_D3),
+ STRING(coex_wmt_antsel_invert_support),
+ CHAR(coex_wmt_ext_epa_mode),
+
+ BYTE_ARRAY(coex_wmt_epa_elna),
+
+ CHAR(bt_tssi_from_wifi),
+ SHORT(bt_tssi_target),
+
+ CHAR(coex_config_bt_ctrl),
+ CHAR(coex_config_bt_ctrl_mode),
+ CHAR(coex_config_bt_ctrl_rw),
+
+ CHAR(coex_config_addjust_opp_time_ratio),
+ CHAR(coex_config_addjust_opp_time_ratio_bt_slot),
+ CHAR(coex_config_addjust_opp_time_ratio_wifi_slot),
+
+ CHAR(coex_config_addjust_ble_scan_time_ratio),
+ CHAR(coex_config_addjust_ble_scan_time_ratio_bt_slot),
+ CHAR(coex_config_addjust_ble_scan_time_ratio_wifi_slot),
+
+ CHAR(wifi_ant_swap_mode),
+ CHAR(wifi_main_ant_polarity),
+ CHAR(wifi_ant_swap_ant_sel_gpio),
+
+ /* This is an open config whose actual purpose is decided by WIFI. */
+ BYTE_ARRAY(wifi_config),
+};
+
+#define NUM_WMTCFG_FIELDS (osal_sizeof(wmtcfg_fields) / osal_sizeof(wmtcfg_fields[0]))
+
+static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos)
+{
+ PUINT8 dst;
+ long res = 0;
+
+ dst = (PINT8)(((PUINT8) pWmtDev) + (long)data->param1);
+
+ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) {
+ osal_strtol(pos + 2, 16, &res);
+ *dst = (UINT8)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst);
+ } else {
+ osal_strtol(pos, 10, &res);
+ *dst = (UINT8)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst);
+ }
+ return 0;
+}
+
+static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data)
+{
+ PINT8 src;
+ INT32 res;
+ PINT8 value;
+
+ src = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1);
+
+ value = osal_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = osal_snprintf(value, 20, "0x%x", *src);
+ if (res < 0 || res >= 20) {
+ osal_free(value);
+ return NULL;
+ }
+ value[20 - 1] = '\0';
+ return value;
+}
+
+static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos)
+{
+ PUINT16 dst;
+ long res = 0;
+
+ dst = (PINT16)(((PUINT8) pWmtDev) + (long)data->param1);
+
+ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */
+
+ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) {
+ osal_strtol(pos + 2, 16, &res);
+ *dst = (UINT16)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst);
+ } else {
+ osal_strtol(pos, 10, &res);
+ *dst = (UINT16)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst);
+ }
+
+ return 0;
+}
+
+static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data)
+{
+ PINT16 src;
+ INT32 res;
+ PINT8 value;
+
+ /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */
+ src = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1);
+
+ value = osal_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = osal_snprintf(value, 20, "0x%x", *src);
+ if (res < 0 || res >= 20) {
+ osal_free(value);
+ return NULL;
+ }
+ value[20 - 1] = '\0';
+ return value;
+}
+
+static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos)
+{
+ PUINT32 dst;
+ long res = 0;
+
+ dst = (PINT32)(((PUINT8) pWmtDev) + (long)data->param1);
+
+ /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */
+
+ if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) {
+ osal_strtol(pos + 2, 16, &res);
+ *dst = (UINT32)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst);
+ } else {
+ osal_strtol(pos, 10, &res);
+ *dst = (UINT32)res;
+ WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst);
+ }
+
+ return 0;
+}
+
+static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data)
+{
+ PINT32 src;
+ INT32 res;
+ PINT8 value;
+
+ src = (PUINT32) (((PUINT8) pWmtDev) + (long) data->param1);
+
+ value = osal_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = osal_snprintf(value, 20, "0x%x", *src);
+ if (res < 0 || res >= 20) {
+ osal_free(value);
+ return NULL;
+ }
+ value[20 - 1] = '\0';
+ return value;
+}
+
+static INT32 wmt_conf_parse_string(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos)
+{
+ PUINT8 *dst = NULL;
+ PUINT8 buffer;
+
+ buffer = osal_malloc(osal_strlen(pos)+1);
+ if (buffer == NULL) {
+ WMT_ERR_FUNC("wmtcfg==> %s malloc fail, size %d\n", data->name, osal_strlen(pos)+1);
+ return -1;
+ }
+
+ osal_strcpy(buffer, pos);
+ dst = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1);
+ *dst = (PUINT8)buffer;
+ WMT_DBG_FUNC("wmtcfg==> %s=%s\n", data->name, *dst);
+
+ return 0;
+}
+
+static PINT8 wmt_conf_write_string(P_DEV_WMT pWmtDev, const struct parse_data *data)
+{
+ PUINT8 *src;
+ INT32 res;
+ PINT8 value;
+ UINT32 str_size;
+
+ src = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1);
+ if (*src == NULL)
+ return NULL;
+
+ str_size = osal_strlen(*src) + 1;
+ value = osal_malloc(str_size);
+ if (value == NULL)
+ return NULL;
+
+ res = osal_snprintf(value, str_size, "%s", *src);
+ if (res < 0 || res >= str_size) {
+ osal_free(value);
+ return NULL;
+ }
+
+ value[str_size - 1] = '\0';
+ return value;
+}
+
+static INT32 wmt_conf_parse_byte_array(P_DEV_WMT pWmtDev,
+ const struct parse_data *data, const PINT8 pos)
+{
+ PUINT8 *dst = NULL;
+ struct WMT_BYTE_ARRAY *ba = NULL;
+ PUINT8 buffer;
+ INT32 size = osal_strlen(pos) / 2;
+ UINT8 temp[3];
+ INT32 i;
+ long value;
+
+ if (size <= 1) {
+ WMT_ERR_FUNC("wmtcfg==> %s has no value assigned\n",
+ data->name);
+ return -1;
+ } else if (size & 0x1) {
+ WMT_ERR_FUNC("wmtcfg==> %s, length should be even\n", data->name);
+ return -1;
+ }
+
+ ba = (struct WMT_BYTE_ARRAY *)osal_malloc(sizeof(struct WMT_BYTE_ARRAY));
+ if (ba == NULL) {
+ WMT_ERR_FUNC("wmtcfg==> %s malloc fail\n", data->name);
+ return -1;
+ }
+
+ buffer = osal_malloc(size);
+ if (buffer == NULL) {
+ osal_free(ba);
+ WMT_ERR_FUNC("wmtcfg==> %s malloc fail, size %d\n", data->name, size);
+ return -1;
+ }
+
+ temp[2] = '\0';
+ for (i = 0; i < size; i++) {
+ osal_memcpy(temp, &pos[i * 2], 2);
+ if (osal_strtol(temp, 16, &value) < 0) {
+ WMT_ERR_FUNC("wmtcfg==> %s should be hexadecimal format\n", data->name);
+ osal_free(ba);
+ osal_free(buffer);
+ return -1;
+ }
+ buffer[i] = (UINT8)value;
+ }
+ ba->data = buffer;
+ ba->size = size;
+
+ dst = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1);
+ *dst = (PUINT8)ba;
+
+ return 0;
+}
+
+static PINT8 wmt_conf_write_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data)
+{
+ PUINT8 *src = NULL;
+ PINT8 value;
+ struct WMT_BYTE_ARRAY *ba = NULL;
+ INT32 i;
+
+ src = (PUINT8 *) (((PUINT8) pWmtDev) + (long)data->param1);
+ if (*src == NULL)
+ return NULL;
+
+ ba = (struct WMT_BYTE_ARRAY *)*src;
+
+ value = osal_malloc(ba->size * 2 + 1);
+ if (value == NULL)
+ return NULL;
+
+ for (i = 0; i < ba->size; i++)
+ osal_snprintf(&value[i * 2], 3, "%x", ba->data[i]);
+
+ return value;
+}
+
+static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal)
+{
+ INT32 i = 0;
+ INT32 ret = 0;
+
+ /* WMT_INFO_FUNC( DBG_NAME "cfg(%s) val(%s)\n", pKey, pVal); */
+
+ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) {
+ const struct parse_data *field = &wmtcfg_fields[i];
+
+ if (osal_strcmp(pKey, field->name) != 0)
+ continue;
+ if (field->parser(pWmtDev, field, pVal)) {
+ WMT_ERR_FUNC("failed to parse %s '%s'.\n", pKey, pVal);
+ ret = -1;
+ }
+ break;
+ }
+ if (i == NUM_WMTCFG_FIELDS) {
+ WMT_ERR_FUNC("unknown field '%s'.\n", pKey);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size)
+{
+ PINT8 pch;
+ PINT8 pBuf;
+ PINT8 pLine;
+ PINT8 pKey;
+ PINT8 pVal;
+ PINT8 pPos;
+ INT32 ret = 0;
+ INT32 i = 0;
+ PINT8 pa = NULL;
+
+ pBuf = osal_malloc(size+1);
+ if (!pBuf)
+ return -1;
+
+ osal_memcpy(pBuf, pInBuf, size);
+ pBuf[size] = '\0';
+
+ pch = pBuf;
+ /* pch is to be updated by strsep(). Keep pBuf unchanged!! */
+
+#if 0
+ {
+ PINT8 buf_ptr = pBuf;
+ INT32 k = 0;
+
+ WMT_INFO_FUNC("%s len=%d", "wmcfg.content:", size);
+ for (k = 0; k < size; k++) {
+ /* if(k%16 == 0) WMT_INFO_FUNC("\n"); */
+ WMT_INFO_FUNC("%c", buf_ptr[k]);
+ }
+ WMT_INFO_FUNC("--end\n");
+ }
+#endif
+
+ while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) {
+ /* pch is updated to the end of pLine by strsep() and updated to '\0' */
+ /*WMT_INFO_FUNC("strsep offset(%d), char(%d, '%c' )\n", pLine-pBuf, *pLine, *pLine); */
+ /* parse each line */
+
+ /* WMT_INFO_FUNC("==> Line = (%s)\n", pLine); */
+
+ if (!*pLine)
+ continue;
+
+ pVal = osal_strchr(pLine, '=');
+ if (!pVal) {
+ WMT_WARN_FUNC("mal-format cfg string(%s)\n", pLine);
+ continue;
+ }
+
+ /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */
+ *pVal = '\0'; /* replace '=' with '\0' to get key */
+ /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */
+ pKey = pLine;
+
+ if ((pVal - pBuf) < size)
+ pVal++;
+
+ /*key handling */
+ pPos = pKey;
+ /*skip space characeter */
+ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) {
+ if ((pPos - pBuf) >= size)
+ break;
+ pPos++;
+ }
+ /*key head */
+ pKey = pPos;
+ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0')
+ && ((*pPos) != '\n')) {
+ if ((pPos - pBuf) >= size)
+ break;
+ pPos++;
+ }
+ /*key tail */
+ (*pPos) = '\0';
+
+ /*value handling */
+ pPos = pVal;
+ /*skip space characeter */
+ while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) {
+ if ((pPos - pBuf) >= size)
+ break;
+ pPos++;
+ }
+ /*value head */
+ pVal = pPos;
+ while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0')
+ && ((*pPos) != '\n')) {
+ if ((pPos - pBuf) >= size)
+ break;
+ pPos++;
+ }
+ /*value tail */
+ (*pPos) = '\0';
+
+ /* WMT_DBG_FUNC("parse (key: #%s#, value: #%s#)\n", pKey, pVal); */
+ ret = wmt_conf_parse_pair(pWmtDev, pKey, pVal);
+ WMT_DBG_FUNC("parse (%s, %s, %d)\n", pKey, pVal, ret);
+ if (ret)
+ WMT_WARN_FUNC("parse fail (%s, %s, %d)\n", pKey, pVal, ret);
+ }
+
+ for (i = 0; i < NUM_WMTCFG_FIELDS; i++) {
+ const struct parse_data *field = &wmtcfg_fields[i];
+
+ pa = field->writer(pWmtDev, field);
+ if (pa) {
+ WMT_DBG_FUNC("#%d(%s)=>%s\n", i, field->name, pa);
+ osal_free(pa);
+ } else
+ WMT_ERR_FUNC("failed to parse '%s'.\n", field->name);
+ }
+ osal_free(pBuf);
+ return 0;
+}
+
+
+INT32 wmt_conf_set_cfg_file(const PINT8 name)
+{
+ if (name == NULL) {
+ WMT_ERR_FUNC("name is NULL\n");
+ return -1;
+ }
+ if (osal_strlen(name) >= osal_sizeof(gDevWmt.cWmtcfgName)) {
+ WMT_ERR_FUNC("name is too long, length=%d, expect to < %zu\n", osal_strlen(name),
+ osal_sizeof(gDevWmt.cWmtcfgName));
+ return -2;
+ }
+ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName));
+ osal_strcpy(&(gDevWmt.cWmtcfgName[0]), name);
+ WMT_ERR_FUNC("WMT config file is set to (%s)\n", &(gDevWmt.cWmtcfgName[0]));
+
+ return 0;
+}
+
+
+INT32 wmt_conf_read_file(VOID)
+{
+ INT32 ret = -1;
+ ENUM_WMT_CHIP_TYPE chip_type;
+
+ osal_memset(&gDevWmt.rWmtGenConf, 0, osal_sizeof(gDevWmt.rWmtGenConf));
+ osal_memset(&gDevWmt.pWmtCfg, 0, osal_sizeof(gDevWmt.pWmtCfg));
+ chip_type = wmt_detect_get_chip_type();
+ if (chip_type == WMT_CHIP_TYPE_SOC) {
+ osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName));
+
+ osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT_SOC, osal_sizeof(CUST_CFG_WMT_SOC));
+ }
+
+ if (!osal_strlen(&(gDevWmt.cWmtcfgName[0]))) {
+ WMT_ERR_FUNC("empty Wmtcfg name\n");
+ osal_assert(0);
+ return ret;
+ }
+ WMT_DBG_FUNC("WMT config file:%s\n", &(gDevWmt.cWmtcfgName[0]));
+ if (0 ==
+ wmt_dev_patch_get(&gDevWmt.cWmtcfgName[0], (osal_firmware **) &gDevWmt.pWmtCfg)) {
+ /*get full name patch success */
+ WMT_DBG_FUNC("get full file name(%s) buf(0x%p) size(%zu)\n",
+ &gDevWmt.cWmtcfgName[0], gDevWmt.pWmtCfg->data,
+ gDevWmt.pWmtCfg->size);
+ if (0 ==
+ wmt_conf_parse(&gDevWmt, (const PINT8)gDevWmt.pWmtCfg->data,
+ gDevWmt.pWmtCfg->size)) {
+ /*config file exists */
+ gDevWmt.rWmtGenConf.cfgExist = 1;
+ WMT_DBG_FUNC("&gDevWmt.rWmtGenConf=%p\n", &gDevWmt.rWmtGenConf);
+ ret = 0;
+ } else {
+ WMT_ERR_FUNC("wmt conf parsing fail\n");
+ osal_assert(0);
+ ret = -1;
+ }
+ wmt_dev_patch_put((osal_firmware **) &gDevWmt.pWmtCfg);
+/*
+* if (gDevWmt.pWmtCfg)
+* {
+* if (gDevWmt.pWmtCfg->data)
+* {
+* osal_free(gDevWmt.pWmtCfg->data);
+* }
+* osal_free(gDevWmt.pWmtCfg);
+* gDevWmt.pWmtCfg = 0;
+* }
+*/
+ return ret;
+ }
+ WMT_ERR_FUNC("read %s file fails\n", &(gDevWmt.cWmtcfgName[0]));
+ osal_assert(0);
+ gDevWmt.rWmtGenConf.cfgExist = 0;
+ return ret;
+}
+
+P_WMT_GEN_CONF wmt_conf_get_cfg(VOID)
+{
+ if (gDevWmt.rWmtGenConf.cfgExist == 0)
+ return NULL;
+
+ return &gDevWmt.rWmtGenConf;
+}
+
+INT32 wmt_conf_deinit(VOID)
+{
+ P_WMT_GEN_CONF pWmtGenConf = wmt_conf_get_cfg();
+
+ if (pWmtGenConf == NULL)
+ return -1;
+
+ if (pWmtGenConf->coex_wmt_epa_elna != NULL) {
+ if (pWmtGenConf->coex_wmt_epa_elna->data != NULL) {
+ osal_free(pWmtGenConf->coex_wmt_epa_elna->data);
+ pWmtGenConf->coex_wmt_epa_elna->data = NULL;
+ }
+ osal_free(pWmtGenConf->coex_wmt_epa_elna);
+ pWmtGenConf->coex_wmt_epa_elna = NULL;
+ }
+
+ if (pWmtGenConf->coex_wmt_antsel_invert_support != NULL) {
+ osal_free(pWmtGenConf->coex_wmt_antsel_invert_support);
+ pWmtGenConf->coex_wmt_antsel_invert_support = NULL;
+ }
+
+ if (pWmtGenConf->wifi_config != NULL) {
+ if (pWmtGenConf->wifi_config->data != NULL) {
+ osal_free(pWmtGenConf->wifi_config->data);
+ pWmtGenConf->wifi_config->data = NULL;
+ }
+ osal_free(pWmtGenConf->wifi_config);
+ pWmtGenConf->wifi_config = NULL;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..382905526a537cd808e5a87085b8944d56ed096b
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c
@@ -0,0 +1,3820 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-CORE]"
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include
+#include "osal_typedef.h"
+#include "connsys_debug_utility.h"
+#include "wmt_lib.h"
+#include "wmt_core.h"
+#include "wmt_ctrl.h"
+#include "wmt_ic.h"
+#include "wmt_conf.h"
+
+#include "wmt_func.h"
+#include "stp_core.h"
+#include "psm_core.h"
+#include "wmt_exp.h"
+#include "wmt_detect.h"
+#include "wmt_plat.h"
+#include "wmt_dev.h"
+
+P_WMT_FUNC_OPS gpWmtFuncOps[WMTDRV_TYPE_MAX] = {
+#if CFG_FUNC_BT_SUPPORT
+ [WMTDRV_TYPE_BT] = &wmt_func_bt_ops,
+#else
+ [WMTDRV_TYPE_BT] = NULL,
+#endif
+
+#if CFG_FUNC_FM_SUPPORT
+ [WMTDRV_TYPE_FM] = &wmt_func_fm_ops,
+#else
+ [WMTDRV_TYPE_FM] = NULL,
+#endif
+
+#if CFG_FUNC_GPS_SUPPORT
+ [WMTDRV_TYPE_GPS] = &wmt_func_gps_ops,
+#else
+ [WMTDRV_TYPE_GPS] = NULL,
+#endif
+
+#if CFG_FUNC_GPSL5_SUPPORT
+ [WMTDRV_TYPE_GPSL5] = &wmt_func_gpsl5_ops,
+#else
+ [WMTDRV_TYPE_GPSL5] = NULL,
+#endif
+
+#if CFG_FUNC_WIFI_SUPPORT
+ [WMTDRV_TYPE_WIFI] = &wmt_func_wifi_ops,
+#else
+ [WMTDRV_TYPE_WIFI] = NULL,
+#endif
+
+#if CFG_FUNC_ANT_SUPPORT
+ [WMTDRV_TYPE_ANT] = &wmt_func_ant_ops,
+#else
+ [WMTDRV_TYPE_ANT] = NULL,
+#endif
+
+
+};
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+/* TODO:[FixMe][GeorgeKuo]: is it an MT6620 only or general general setting?
+ * move to wmt_ic_6620 temporarily.
+ */
+/* #define CFG_WMT_BT_PORT2 (1) *//* BT Port 2 Feature. */
+#define CFG_CHECK_WMT_RESULT (1)
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+static WMT_CTX gMtkWmtCtx;
+static UINT8 gLpbkBuf[WMT_LPBK_BUF_LEN] = { 0 };
+#ifdef CONFIG_MTK_COMBO_ANT
+static UINT8 gAntBuf[1024] = { 0 };
+#endif
+#if CFG_WMT_LTE_COEX_HANDLING
+static UINT32 g_open_wmt_lte_flag;
+#endif
+static UINT8 gFlashBuf[1024] = { 0 };
+#if CFG_WMT_LTE_COEX_HANDLING
+static UINT8 msg_local_buffer[WMT_IDC_MSG_BUFFER] = { 0 };
+#endif
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp);
+static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp);
+static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp);
+static INT32 opfunc_func_on(P_WMT_OP pWmtOp);
+static INT32 opfunc_func_off(P_WMT_OP pWmtOp);
+static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp);
+static INT32 opfunc_exit(P_WMT_OP pWmtOp);
+static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp);
+static INT32 opfunc_dsns(P_WMT_OP pWmtOp);
+static INT32 opfunc_lpbk(P_WMT_OP pWmtOp);
+static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp);
+static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp);
+static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp);
+static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp);
+static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp);
+static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_sdio_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_pin_state(P_WMT_OP pWmtOp);
+static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp);
+static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp);
+static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp);
+static INT32 wmt_core_gen2_set_mcu_clk(UINT32 kind);
+static INT32 wmt_core_gen3_set_mcu_clk(UINT32 kind);
+static INT32 wmt_core_set_mcu_clk(UINT32 kind);
+static VOID wmt_core_dump_func_state(PINT8 pSource);
+static INT32 wmt_core_stp_init(VOID);
+static INT32 wmt_core_trigger_assert(VOID);
+static INT32 wmt_core_stp_deinit(VOID);
+static INT32 wmt_core_hw_check(VOID);
+#ifdef CONFIG_MTK_COMBO_ANT
+static INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp);
+static INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp);
+#endif
+#if CFG_WMT_LTE_COEX_HANDLING
+static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp);
+#endif
+static INT32 opfunc_trigger_stp_assert(P_WMT_OP pWmtOp);
+static INT32 opfunc_flash_patch_down(P_WMT_OP pWmtOp);
+static INT32 opfunc_flash_patch_ver_get(P_WMT_OP pWmtOp);
+static INT32 opfunc_utc_time_sync(P_WMT_OP pWmtOp);
+static INT32 opfunc_fw_log_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_wlan_probe(P_WMT_OP pWmtOp);
+static INT32 opfunc_wlan_remove(P_WMT_OP pWmtOp);
+static INT32 opfunc_try_pwr_off(P_WMT_OP pWmtOp);
+static INT32 opfunc_gps_mcu_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_blank_status_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_met_ctrl(P_WMT_OP pWmtOp);
+static INT32 opfunc_gps_suspend(P_WMT_OP pWmtOp);
+static INT32 opfunc_get_consys_state(P_WMT_OP pWmtOp);
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static const UINT8 WMT_SLEEP_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x01 };
+static const UINT8 WMT_SLEEP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 };
+
+static const UINT8 WMT_HOST_AWAKE_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x02 };
+static const UINT8 WMT_HOST_AWAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 };
+
+static const UINT8 WMT_WAKEUP_CMD[] = { 0xFF };
+static const UINT8 WMT_WAKEUP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+
+static UINT8 WMT_THERM_CMD[] = { 0x01, 0x11, 0x01, 0x00,
+ 0x00 /*thermal sensor operation */
+};
+static UINT8 WMT_THERM_CTRL_EVT[] = { 0x02, 0x11, 0x01, 0x00, 0x00 };
+static UINT8 WMT_THERM_READ_EVT[] = { 0x02, 0x11, 0x02, 0x00, 0x00, 0x00 };
+
+static UINT8 WMT_EFUSE_CMD[] = { 0x01, 0x0D, 0x08, 0x00,
+ 0x01, /*[4]operation, 0:init, 1:write 2:read */
+ 0x01, /*[5]Number of register setting */
+ 0xAA, 0xAA, /*[6-7]Address */
+ 0xBB, 0xBB, 0xBB, 0xBB /*[8-11] Value */
+};
+
+static UINT8 WMT_EFUSE_EVT[] = { 0x02, 0x0D, 0x08, 0x00,
+ 0xAA, /*[4]operation, 0:init, 1:write 2:read */
+ 0xBB, /*[5]Number of register setting */
+ 0xCC, 0xCC, /*[6-7]Address */
+ 0xDD, 0xDD, 0xDD, 0xDD /*[8-11] Value */
+};
+
+static UINT8 WMT_DSNS_CMD[] = { 0x01, 0x0E, 0x02, 0x00, 0x01,
+ 0x00 /*desnse type */
+};
+static UINT8 WMT_DSNS_EVT[] = { 0x02, 0x0E, 0x01, 0x00, 0x00 };
+
+/* TODO:[NewFeature][GeorgeKuo] Update register group in ONE CMD/EVT */
+static UINT8 WMT_SET_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x00 /*op: w(1) & r(2) */
+ , 0x01 /*type: reg */
+ , 0x00 /*res */
+ , 0x01 /*1 register */
+ , 0x00, 0x00, 0x00, 0x00 /* addr */
+ , 0x00, 0x00, 0x00, 0x00 /* value */
+ , 0xFF, 0xFF, 0xFF, 0xFF /*mask */
+};
+
+static UINT8 WMT_SET_REG_WR_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 register */
+ /* , 0x00, 0x00, 0x00, 0x00 *//* addr */
+ /* , 0x00, 0x00, 0x00, 0x00 *//* value */
+};
+
+static UINT8 WMT_SET_REG_RD_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 register */
+ , 0x00, 0x00, 0x00, 0x00 /* addr */
+ , 0x00, 0x00, 0x00, 0x00 /* value */
+};
+
+#ifdef CONFIG_MTK_COMBO_ANT
+static UINT8 WMT_ANT_RAM_STA_GET_CMD[] = { 0x01, 0x06, 0x02, 0x00, 0x05, 0x02
+};
+static UINT8 WMT_ANT_RAM_STA_GET_EVT[] = { 0x02, 0x06, 0x03, 0x00 /*length */
+ , 0x05, 0x02, 0x00 /*S: result */
+};
+static UINT8 WMT_ANT_RAM_DWN_CMD[] = { 0x01, 0x15, 0x00, 0x00, 0x01
+};
+static UINT8 WMT_ANT_RAM_DWN_EVT[] = { 0x02, 0x15, 0x01, 0x00 /*length */
+ , 0x00
+};
+#endif
+
+static UINT8 WMT_FLASH_PATCH_VER_GET_CMD[] = { 0x01, 0x01, 0x05, 0x00 /*length*/
+ , 0x06, 0x00, 0x00, 0x00, 0x00 /*flash patch type*/
+};
+
+static UINT8 WMT_FLASH_PATCH_VER_GET_EVT[] = { 0x02, 0x01, 0x09, 0x00 /*length */
+ , 0x06, 0x00, 0x00, 0x00, 0x00 /*flash patch type*/
+ , 0x00, 0x00, 0x00, 0x00 /*flash patch version*/
+};
+
+static UINT8 WMT_FLASH_PATCH_DWN_CMD[] = { 0x01, 0x01, 0x0d, 0x00, 0x05
+};
+
+static UINT8 WMT_FLASH_PATCH_DWN_EVT[] = { 0x02, 0x01, 0x01, 0x00 /*length */
+ , 0x00
+};
+
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+static UINT8 WMT_UTC_SYNC_CMD[] = { 0x01, 0xF0, 0x09, 0x00, 0x02
+ , 0x00, 0x00, 0x00, 0x00 /*UTC time second unit*/
+ , 0x00, 0x00, 0x00, 0x00 /*UTC time microsecond unit*/
+};
+static UINT8 WMT_UTC_SYNC_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x02, 0x00
+};
+
+static UINT8 WMT_BLANK_STATUS_CMD[] = { 0x01, 0xF0, 0x02, 0x00, 0x03, 0x00 };
+static UINT8 WMT_BLANK_STATUS_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x03, 0x00 };
+#endif
+
+static UINT8 WMT_FW_LOG_CTRL_CMD[] = { 0x01, 0xF0, 0x04, 0x00, 0x01
+ , 0x00 /* subsys type */
+ , 0x00 /* on/off */
+ , 0x00 /* level (subsys-specific) */
+};
+static UINT8 WMT_FW_LOG_CTRL_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x01, 0x00 };
+
+/* GeorgeKuo: Use designated initializers described in
+ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html
+ */
+
+static const WMT_OPID_FUNC wmt_core_opfunc[] = {
+ [WMT_OPID_HIF_CONF] = opfunc_hif_conf,
+ [WMT_OPID_PWR_ON] = opfunc_pwr_on,
+ [WMT_OPID_PWR_OFF] = opfunc_pwr_off,
+ [WMT_OPID_FUNC_ON] = opfunc_func_on,
+ [WMT_OPID_FUNC_OFF] = opfunc_func_off,
+ [WMT_OPID_REG_RW] = opfunc_reg_rw, /* TODO:[ChangeFeature][George] is this OP obsoleted? */
+ [WMT_OPID_EXIT] = opfunc_exit,
+ [WMT_OPID_PWR_SV] = opfunc_pwr_sv,
+ [WMT_OPID_DSNS] = opfunc_dsns,
+ [WMT_OPID_LPBK] = opfunc_lpbk,
+ [WMT_OPID_CMD_TEST] = opfunc_cmd_test,
+ [WMT_OPID_HW_RST] = opfunc_hw_rst,
+ [WMT_OPID_SW_RST] = opfunc_sw_rst,
+ [WMT_OPID_STP_RST] = opfunc_stp_rst,
+ [WMT_OPID_THERM_CTRL] = opfunc_therm_ctrl,
+ [WMT_OPID_EFUSE_RW] = opfunc_efuse_rw,
+ [WMT_OPID_GPIO_CTRL] = opfunc_gpio_ctrl,
+ [WMT_OPID_SDIO_CTRL] = opfunc_sdio_ctrl,
+ [WMT_OPID_GPIO_STATE] = opfunc_pin_state,
+ [WMT_OPID_BGW_DS] = opfunc_bgw_ds,
+ [WMT_OPID_SET_MCU_CLK] = opfunc_set_mcu_clk,
+ [WMT_OPID_ADIE_LPBK_TEST] = opfunc_adie_lpbk_test,
+#ifdef CONFIG_MTK_COMBO_ANT
+ [WMT_OPID_ANT_RAM_DOWN] = opfunc_ant_ram_down,
+ [WMT_OPID_ANT_RAM_STA_GET] = opfunc_ant_ram_stat_get,
+#endif
+#if CFG_WMT_LTE_COEX_HANDLING
+ [WMT_OPID_IDC_MSG_HANDLING] = opfunc_idc_msg_handling,
+#endif
+ [WMT_OPID_TRIGGER_STP_ASSERT] = opfunc_trigger_stp_assert,
+ [WMT_OPID_FLASH_PATCH_DOWN] = opfunc_flash_patch_down,
+ [WMT_OPID_FLASH_PATCH_VER_GET] = opfunc_flash_patch_ver_get,
+ [WMT_OPID_UTC_TIME_SYNC] = opfunc_utc_time_sync,
+ [WMT_OPID_FW_LOG_CTRL] = opfunc_fw_log_ctrl,
+ [WMT_OPID_WLAN_PROBE] = opfunc_wlan_probe,
+ [WMT_OPID_WLAN_REMOVE] = opfunc_wlan_remove,
+ [WMT_OPID_GPS_MCU_CTRL] = opfunc_gps_mcu_ctrl,
+ [WMT_OPID_TRY_PWR_OFF] = opfunc_try_pwr_off,
+ [WMT_OPID_BLANK_STATUS_CTRL] = opfunc_blank_status_ctrl,
+ [WMT_OPID_MET_CTRL] = opfunc_met_ctrl,
+ [WMT_OPID_GPS_SUSPEND] = opfunc_gps_suspend,
+ [WMT_OPID_GET_CONSYS_STATE] = opfunc_get_consys_state,
+};
+
+atomic_t g_wifi_on_off_ready;
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+INT32 wmt_core_init(VOID)
+{
+ INT32 i = 0;
+
+ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx));
+ /* gMtkWmtCtx.p_ops is cleared to NULL */
+
+ /* default FUNC_OFF state */
+ for (i = 0; i < WMTDRV_TYPE_MAX; ++i) {
+ /* WinMo is default to DRV_STS_UNREG; */
+ gMtkWmtCtx.eDrvStatus[i] = DRV_STS_POWER_OFF;
+ }
+
+ atomic_set(&g_wifi_on_off_ready, 0);
+
+ return 0;
+}
+
+INT32 wmt_core_deinit(VOID)
+{
+ /* return to init state */
+ osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx));
+ /* gMtkWmtCtx.p_ops is cleared to NULL */
+ return 0;
+}
+
+/* TODO: [ChangeFeature][George] Is wmt_ctrl a good interface? maybe not...... */
+/* parameters shall be copied in/from ctrl buffer, which is also a size-wasting buffer. */
+INT32
+wmt_core_tx(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag)
+{
+ INT32 iRet = 0;
+ INT32 retry_times = 0;
+ INT32 max_retry_times = 0;
+ INT32 retry_delay_ms = 0;
+ ENUM_WMT_CHIP_TYPE chip_type;
+
+ chip_type = wmt_detect_get_chip_type();
+ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag);
+ if (*writtenSize == 0 && (chip_type == WMT_CHIP_TYPE_SOC)) {
+ retry_times = 0;
+ max_retry_times = 3;
+ retry_delay_ms = 360;
+ WMT_WARN_FUNC("WMT-CORE: wmt_ctrl_tx_ex failed and written ret:%d, maybe no winspace in STP layer\n",
+ *writtenSize);
+ while ((*writtenSize == 0) && (retry_times < max_retry_times)) {
+ WMT_ERR_FUNC("WMT-CORE: retrying, wait for %d ms\n", retry_delay_ms);
+ osal_sleep_ms(retry_delay_ms);
+
+ iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag);
+ retry_times++;
+ }
+ }
+ return iRet;
+}
+
+INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, PUINT32 readSize)
+{
+ INT32 iRet;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_RX;
+ ctrlData.au4CtrlData[0] = (SIZE_T) pBuf;
+ ctrlData.au4CtrlData[1] = bufLen;
+ ctrlData.au4CtrlData[2] = (SIZE_T) readSize;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /* ERROR */
+ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX, iRet:%d\n", iRet);
+ osal_assert(0);
+ }
+ return iRet;
+}
+
+INT32 wmt_core_rx_flush(UINT32 type)
+{
+ INT32 iRet;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_RX_FLUSH;
+ ctrlData.au4CtrlData[0] = (UINT32) type;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /* ERROR */
+ WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX_FLUSH, iRet:%d\n", iRet);
+ osal_assert(0);
+ }
+ return iRet;
+}
+
+INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn)
+{
+ INT32 iRet = 0;
+ UINT32 u4WmtCmdPduLen;
+ UINT32 u4WmtEventPduLen;
+ UINT32 u4ReadSize;
+ UINT32 u4WrittenSize;
+ WMT_PKT rWmtPktCmd;
+ WMT_PKT rWmtPktEvent;
+ MTK_WCN_BOOL fgFail;
+
+ /* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */
+ /* Using this struct relies on compiler's implementation and pack() settings */
+ osal_memset(&rWmtPktCmd, 0, osal_sizeof(rWmtPktCmd));
+ osal_memset(&rWmtPktEvent, 0, osal_sizeof(rWmtPktEvent));
+
+ rWmtPktCmd.eType = (UINT8) WMT_PKT_TYPE_CMD;
+ rWmtPktCmd.eOpCode = (UINT8) OPCODE_FUNC_CTRL;
+
+ /* Flag field: driver type */
+ rWmtPktCmd.aucParam[0] = (UINT8) type;
+ /* Parameter field: ON/OFF */
+ rWmtPktCmd.aucParam[1] = (fgEn == WMT_FUNC_CTRL_ON) ? 1 : 0;
+ rWmtPktCmd.u2SduLen = WMT_FLAG_LEN + WMT_FUNC_CTRL_PARAM_LEN; /* (2) */
+
+ /* WMT Header + WMT SDU */
+ u4WmtCmdPduLen = WMT_HDR_LEN + rWmtPktCmd.u2SduLen; /* (6) */
+ u4WmtEventPduLen = WMT_HDR_LEN + WMT_STS_LEN; /* (5) */
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+/* iRet = (*kal_stp_tx)((PUINT8)&rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize); */
+ iRet =
+ wmt_core_tx((PUINT8) &rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_tx failed\n");
+ break;
+ }
+
+ iRet = wmt_core_rx((PUINT8) &rWmtPktEvent, u4WmtEventPduLen, &u4ReadSize);
+ if (iRet) {
+ WMT_ERR_FUNC
+ ("WMT firwmare no rx event, trigger f/w assert. sub-driver type:%d, state(%d)\n",
+ type, fgEn);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 32);
+ break;
+ }
+
+ /* Error Checking */
+ if (rWmtPktEvent.eType != WMT_PKT_TYPE_EVENT) {
+ WMT_ERR_FUNC
+ ("WMT-CORE: wmt_func_ctrl_cmd WMT_PKT_TYPE_EVENT != rWmtPktEvent.eType %d\n",
+ rWmtPktEvent.eType);
+ break;
+ }
+
+ if (rWmtPktCmd.eOpCode != rWmtPktEvent.eOpCode) {
+ WMT_ERR_FUNC
+ ("WMT-CORE: wmt_func_ctrl_cmd rWmtPktCmd.eOpCode(0x%x) != rWmtPktEvent.eType(0x%x)\n",
+ rWmtPktCmd.eOpCode, rWmtPktEvent.eOpCode);
+ break;
+ }
+
+ if (u4WmtEventPduLen != (rWmtPktEvent.u2SduLen + WMT_HDR_LEN)) {
+ WMT_ERR_FUNC
+ ("WMT-CORE: wmt_func_ctrl_cmd u4WmtEventPduLen(0x%x) != rWmtPktEvent.u2SduLen(0x%x)+4\n",
+ u4WmtEventPduLen, rWmtPktEvent.u2SduLen);
+ break;
+ }
+ /* Status field of event check */
+ if (rWmtPktEvent.aucParam[0] != 0) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd, 0 != status(%d)\n",
+ rWmtPktEvent.aucParam[0]);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+ } while (0);
+
+ if (fgFail == MTK_WCN_BOOL_FALSE) {
+ /* WMT_INFO_FUNC("WMT-CORE: wmt_func_ctrl_cmd OK!\n"); */
+ return 0;
+ }
+ WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd 0x%x FAIL\n", rWmtPktCmd.aucParam[0]);
+ return -2;
+}
+
+INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp)
+{
+ UINT32 opId;
+ INT32 ret;
+
+ opId = pWmtOp->opId;
+
+ if (wmt_core_opfunc[opId]) {
+ ret = (*(wmt_core_opfunc[opId])) (pWmtOp); /*wmtCoreOpidHandlerPack[].opHandler */
+ return ret;
+ }
+ WMT_ERR_FUNC("WMT-CORE: null handler (%d)\n", pWmtOp->opId);
+ return -2;
+}
+
+INT32 wmt_core_opid(P_WMT_OP pWmtOp)
+{
+
+ /*sanity check */
+ if (pWmtOp == NULL) {
+ WMT_ERR_FUNC("null pWmtOP\n");
+ /*print some message with error info */
+ return -1;
+ }
+
+ if (pWmtOp->opId >= WMT_OPID_MAX) {
+ WMT_ERR_FUNC("WMT-CORE: invalid OPID(%d)\n", pWmtOp->opId);
+ return -2;
+ }
+ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */
+ return wmt_core_opid_handler(pWmtOp);
+}
+
+INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, PULONG pPa1, PULONG pPa2)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+ SIZE_T val1 = (pPa1) ? *pPa1 : 0;
+ SIZE_T val2 = (pPa2) ? *pPa2 : 0;
+
+ ctrlData.ctrlId = (SIZE_T) ctrId;
+ ctrlData.au4CtrlData[0] = val1;
+ ctrlData.au4CtrlData[1] = val2;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /* ERROR */
+ WMT_ERR_FUNC
+ ("WMT-CORE: wmt_core_ctrl failed: id(%d), type(%zu), value(%zu) iRet:(%d)\n",
+ ctrId, val1, val2, iRet);
+ osal_assert(0);
+ } else {
+ if (pPa1)
+ *pPa1 = ctrlData.au4CtrlData[0];
+ if (pPa2)
+ *pPa2 = ctrlData.au4CtrlData[1];
+ }
+ return iRet;
+}
+
+
+VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len)
+{
+ PUINT8 ptr = pData;
+ INT32 k = 0;
+
+ WMT_INFO_FUNC("%s len=%d\n", pTitle, len);
+ for (k = 0; k < len; k++) {
+ if (k % 16 == 0)
+ WMT_INFO_FUNC("\n");
+ WMT_INFO_FUNC("0x%02x ", *ptr);
+ ptr++;
+ }
+ WMT_INFO_FUNC("--end\n");
+}
+
+/*!
+ * \brief An WMT-CORE function to support read, write, and read after write to
+ * an internal register.
+ *
+ * Detailed description.
+ *
+ * \param isWrite 1 for write, 0 for read
+ * \param offset of register to be written or read
+ * \param pVal a pointer to the 32-bit value to be writtern or read
+ * \param mask a 32-bit mask to be applied for the read or write operation
+ *
+ * \retval 0 operation success
+ * \retval -1 invalid parameters
+ * \retval -2 tx cmd fail
+ * \retval -3 rx event fail
+ * \retval -4 read check error
+ */
+INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask)
+{
+ INT32 iRet;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+
+ WMT_SET_REG_CMD[4] = (isWrite) ? 0x1 : 0x2; /* w:1, r:2 */
+ osal_memcpy(&WMT_SET_REG_CMD[8], &offset, 4); /* offset */
+ osal_memcpy(&WMT_SET_REG_CMD[12], pVal, 4); /* [2] is var addr */
+ osal_memcpy(&WMT_SET_REG_CMD[16], &mask, 4); /* mask */
+
+ /* send command */
+ iRet = wmt_core_tx(WMT_SET_REG_CMD, sizeof(WMT_SET_REG_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if ((iRet) || (u4Res != sizeof(WMT_SET_REG_CMD))) {
+ WMT_ERR_FUNC("Tx REG_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res,
+ sizeof(WMT_SET_REG_CMD));
+ return -2;
+ }
+
+ /* receive event */
+ evtLen = (isWrite) ? sizeof(WMT_SET_REG_WR_EVT) : sizeof(WMT_SET_REG_RD_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if ((iRet) || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("Rx REG_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen);
+ if (isWrite)
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ WMT_SET_REG_WR_EVT[0], WMT_SET_REG_WR_EVT[1],
+ WMT_SET_REG_WR_EVT[2], WMT_SET_REG_WR_EVT[3],
+ WMT_SET_REG_WR_EVT[4]);
+ else
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ WMT_SET_REG_RD_EVT[0], WMT_SET_REG_RD_EVT[1],
+ WMT_SET_REG_RD_EVT[2], WMT_SET_REG_RD_EVT[3],
+ WMT_SET_REG_RD_EVT[4]);
+ mtk_wcn_stp_dbg_dump_package();
+ wmt_core_trigger_assert();
+ return -3;
+ }
+
+ if (!isWrite) {
+ UINT32 rxEvtAddr;
+ UINT32 txCmdAddr;
+
+ osal_memcpy(&txCmdAddr, &WMT_SET_REG_CMD[8], 4);
+ osal_memcpy(&rxEvtAddr, &evtBuf[8], 4);
+
+ /* check read result */
+ if (txCmdAddr != rxEvtAddr) {
+ WMT_ERR_FUNC("Check read addr fail (0x%08x, 0x%08x)\n", rxEvtAddr,
+ txCmdAddr);
+ return -4;
+ }
+ WMT_DBG_FUNC("Check read addr(0x%08x) ok\n", rxEvtAddr);
+ osal_memcpy(pVal, &evtBuf[12], 4);
+ }
+
+ /* no error here just return 0 */
+ return 0;
+}
+
+INT32 wmt_core_init_script_retry(struct init_script *script, INT32 count, INT32 retry, INT32 dump_err_log)
+{
+ UINT8 evtBuf[256];
+ UINT32 u4Res;
+ INT32 i = 0;
+ INT32 iRet;
+ INT32 err = 0;
+
+ do {
+ err = 0;
+ for (i = 0; i < count; i++) {
+ WMT_DBG_FUNC("WMT-CORE: init_script operation %s start\n", script[i].str);
+ /* CMD */
+ /* iRet = (*kal_stp_tx)(script[i].cmd, script[i].cmdSz, &u4Res); */
+ iRet = wmt_core_tx(script[i].cmd, script[i].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != script[i].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ script[i].str, iRet, u4Res, script[i].cmdSz);
+
+ err = -1;
+ break;
+ }
+ /* EVENT BUF */
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, script[i].evtSz, &u4Res);
+ if (iRet || (u4Res != script[i].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ script[i].str, iRet, u4Res, script[i].evtSz);
+ if (dump_err_log == 1)
+ mtk_wcn_stp_dbg_dump_package();
+
+ err = -1;
+ break;
+ }
+ /* RESULT */
+ if (evtBuf[1] != 0x14) { /*workaround RF calibration data EVT, do not care this EVT*/
+ if (osal_memcmp(evtBuf, script[i].evt, script[i].evtSz) != 0) {
+ WMT_ERR_FUNC("WMT-CORE:compare %s result error\n", script[i].str);
+ WMT_ERR_FUNC
+ ("WMT-CORE:rx(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4]);
+ WMT_ERR_FUNC
+ ("WMT-CORE:exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ script[i].evtSz, script[i].evt[0], script[i].evt[1], script[i].evt[2],
+ script[i].evt[3], script[i].evt[4]);
+ if (dump_err_log == 1)
+ mtk_wcn_stp_dbg_dump_package();
+
+ err = -1;
+ break;
+ }
+ }
+ WMT_DBG_FUNC("init_script operation %s ok\n", script[i].str);
+ }
+ retry--;
+ } while (retry >= 0 && err < 0);
+
+ return (i == count) ? 0 : -1;
+}
+
+
+INT32 wmt_core_init_script(struct init_script *script, INT32 count)
+{
+ return wmt_core_init_script_retry(script, count, 0, 1);
+}
+
+static INT32 wmt_core_trigger_assert(VOID)
+{
+ INT32 ret = 0;
+ UINT32 u4Res;
+ UINT32 tstCmdSz = 0;
+ UINT32 tstEvtSz = 0;
+ UINT8 tstCmd[64];
+ UINT8 tstEvt[64];
+ UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 };
+ UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+
+ WMT_INFO_FUNC("Send Assert command !\n");
+ tstCmdSz = osal_sizeof(WMT_ASSERT_CMD);
+ tstEvtSz = osal_sizeof(WMT_ASSERT_EVT);
+ osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz);
+
+ ret = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (ret || (u4Res != tstCmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", ret, u4Res,
+ tstCmdSz);
+ ret = -1;
+ }
+ return ret;
+}
+
+static INT32 wmt_core_stp_init(VOID)
+{
+ INT32 iRet = 0;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ UINT8 co_clock_type;
+ P_WMT_CTX pctx = &gMtkWmtCtx;
+ P_WMT_GEN_CONF pWmtGenConf = NULL;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ wmt_conf_read_file();
+ gDevWmt.rWmtGenConf.co_clock_flag = wmt_lib_co_clock_flag_get();
+
+ pWmtGenConf = wmt_conf_get_cfg();
+ if (pWmtGenConf == NULL)
+ WMT_ERR_FUNC("WMT-CORE: wmt_conf_get_cfg return NULL!!\n");
+ if (!(pctx->wmtInfoBit & WMT_OP_HIF_BIT)) {
+ WMT_ERR_FUNC("WMT-CORE: no hif info!\n");
+ osal_assert(0);
+ return -WMT_ERRCODE_NO_HIF_INFO;
+ }
+
+ /* 4 <0> turn on SDIO2 for common SDIO */
+ if (pctx->wmtHifConf.hifType == WMT_HIF_SDIO) {
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO2;
+ ctrlPa2 = 1; /* turn on SDIO2 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn on SLOT_SDIO2 fail (%d)\n", iRet);
+ osal_assert(0);
+
+ return -WMT_ERRCODE_SDIO_SLOT_SDIO2_FAIL;
+ }
+ pctx->eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_FUNC_ON;
+
+ ctrlPa1 = WMT_SDIO_FUNC_STP;
+ ctrlPa2 = 1; /* turn on STP driver */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn on SDIO_FUNC_STP func fail (%d)\n", iRet);
+
+ /* check all sub-func and do power off */
+ return -WMT_ERRCODE_SDIO_FUNC_STP_FAIL;
+ }
+ }
+ /* 4 <1> open stp */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt open stp failed.\n");
+ return -WMT_ERRCODE_OPEN_STP_FAIL;
+ }
+
+ if (pctx->wmtHifConf.hifType == WMT_HIF_UART) {
+ ctrlPa1 = WMT_DEFAULT_BAUD_RATE;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: change host baudrate(%d) fails\n",
+ pctx->wmtHifConf.au4HifConf[0]);
+ return -WMT_ERRCODE_UART_BAUDRATE_FAIL;
+ }
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: change host baudrate(%d) ok\n", gMtkWmtCtx.wmtHifConf.au4HifConf[0]); */
+
+ /* 4 <1.5> disable and un-ready stp */
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("disable WMT_STP_CONF_EN fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+
+ ctrlPa1 = WMT_STP_CONF_RDY;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("un-ready WMT_STP_CONF_RDY fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+
+ /* 4 <2> set mode and enable */
+ if (pctx->wmtHifConf.hifType == WMT_HIF_UART) {
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_MAND_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("config MTKSTP_UART_MAND_MODE fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ } else if (pctx->wmtHifConf.hifType == WMT_HIF_SDIO) {
+
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_SDIO_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("config MTKSTP_SDIO_MODE fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ } else if (pctx->wmtHifConf.hifType == WMT_HIF_BTIF) {
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_BTIF_MAND_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("config MTKSTP_BTIF_MAND_MODE fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ }
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("enable WMT_STP_CONF_EN fail:%d\n", iRet);
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ /* TODO: [ChangeFeature][GeorgeKuo] can we apply raise UART baud rate firstly for ALL supported chips??? */
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ WMT_DBG_FUNC("disable deep sleep featrue before the first command to firmware\n");
+ wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE);
+#endif
+
+ iRet = wmt_core_hw_check();
+ if (iRet) {
+ WMT_ERR_FUNC("hw_check fail:%d\n", iRet);
+ return iRet;
+ }
+ /* mtkWmtCtx.p_ic_ops is identified and checked ok */
+ if ((pctx->p_ic_ops->co_clock_ctrl != NULL) && (pWmtGenConf != NULL)) {
+ co_clock_type = (pWmtGenConf->co_clock_flag & 0x0f);
+ (*(pctx->p_ic_ops->co_clock_ctrl)) (co_clock_type == 0 ? WMT_CO_CLOCK_DIS : WMT_CO_CLOCK_EN);
+ } else {
+ WMT_WARN_FUNC("pctx->p_ic_ops->co_clock_ctrl(%p), pWmtGenConf(%p)\n", pctx->p_ic_ops->co_clock_ctrl,
+ pWmtGenConf);
+ }
+ osal_assert(pctx->p_ic_ops->sw_init != NULL);
+ if (pctx->p_ic_ops->sw_init != NULL) {
+ iRet = (*(pctx->p_ic_ops->sw_init)) (&pctx->wmtHifConf);
+ } else {
+ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n");
+ return -WMT_ERRCODE_NULL_FUNC_POINTER;
+ }
+ if (iRet) {
+ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init fail:%d\n", iRet);
+ return iRet;
+ }
+
+ /* send UTC time sync command after connsys power on or chip reset */
+ opfunc_utc_time_sync(NULL);
+
+ /* 4 <10> set stp ready */
+ ctrlPa1 = WMT_STP_CONF_RDY;
+ ctrlPa2 = 1;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("set WMT_STP_CONF_RDY fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+
+ return 0;
+}
+
+static INT32 wmt_core_stp_deinit(VOID)
+{
+ INT32 iRet;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ WMT_DBG_FUNC(" start\n");
+
+ if (gMtkWmtCtx.p_ic_ops == NULL) {
+ WMT_WARN_FUNC("gMtkWmtCtx.p_ic_ops is NULL\n");
+ goto deinit_ic_ops_done;
+ }
+ if (gMtkWmtCtx.p_ic_ops->sw_deinit != NULL) {
+ iRet = (*(gMtkWmtCtx.p_ic_ops->sw_deinit)) (&gMtkWmtCtx.wmtHifConf);
+ /* unbind WMT-IC */
+ gMtkWmtCtx.p_ic_ops = NULL;
+ } else {
+ WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n");
+ }
+
+deinit_ic_ops_done:
+
+ /* 4 <1> un-ready, disable, and close stp. */
+ ctrlPa1 = WMT_STP_CONF_RDY;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 0;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2);
+
+ /* 4 <1.1> turn off SDIO2 for common SDIO */
+ if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) {
+ ctrlPa1 = WMT_SDIO_FUNC_STP;
+ ctrlPa2 = 0; /* turn off STP driver */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_WARN_FUNC("turn off SDIO_FUNC_STP fail (%d)\n", iRet);
+ /* Anyway, continue turning SDIO HW off */
+ } else {
+ WMT_DBG_FUNC("turn off SDIO_FUNC_STP ok\n");
+ }
+
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO2;
+ ctrlPa2 = 0; /* turn off SDIO2 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_WARN_FUNC("turn off SDIO2 HW fail (%d)\n", iRet);
+ /* Anyway, continue turning STP SDIO to POWER OFF state */
+ } else
+ WMT_DBG_FUNC("turn off SDIO2 HW ok\n");
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_POWER_OFF;
+ }
+
+ if (iRet)
+ WMT_WARN_FUNC("end with fail:%d\n", iRet);
+
+ return iRet;
+}
+
+static VOID wmt_core_dump_func_state(PINT8 pSource)
+{
+ WMT_INFO_FUNC
+ ("[%s]status(b:%d f:%d g:%d gl5:%d w:%d lpbk:%d coredump:%d wmt:%d ant:%d sd1:%d sd2:%d stp:%d)\n",
+ (pSource == NULL ? (PINT8) "CORE" : pSource), gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPSL5],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1],
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP]
+ );
+ return;
+
+}
+
+ENUM_DRV_STS wmt_core_get_drv_status(ENUM_WMTDRV_TYPE_T type)
+{
+ if ((type < WMTDRV_TYPE_BT) || (type >= WMTDRV_TYPE_MAX))
+ return DRV_STS_POWER_OFF;
+ return gMtkWmtCtx.eDrvStatus[type];
+}
+
+MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer)
+{
+ if (MAJORNUM(u4HwVer) != MAJORNUM(u4PatchVer)) {
+ /*major no. does not match */
+ WMT_ERR_FUNC("WMT-CORE: chip version(0x%x) does not match patch version(0x%x)\n",
+ u4HwVer, u4PatchVer);
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return MTK_WCN_BOOL_TRUE;
+}
+
+static INT32 wmt_core_hw_check(VOID)
+{
+ UINT32 chipid;
+ P_WMT_IC_OPS p_ops;
+ INT32 iret;
+
+ /* 1. get chip id */
+ chipid = 0;
+ WMT_LOUD_FUNC("before read hwcode (chip id)\n");
+ iret = wmt_core_reg_rw_raw(0, GEN_HCR, &chipid, GEN_HCR_MASK); /* read 0x80000008 */
+ if (iret) {
+#if defined(KERNEL_clk_buf_show_status_info)
+ KERNEL_clk_buf_show_status_info(); /* dump clock buffer */
+#endif
+ WMT_ERR_FUNC("get hwcode (chip id) fail (%d)\n", iret);
+ return -WMT_ERRCODE_HW_CHECK_FAIL;
+ }
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (wmt_lib_get_icinfo(WMTCHIN_IPVER))
+ chipid = wmt_plat_get_soc_chipid();
+ }
+ WMT_INFO_FUNC("get hwcode (chip id) (0x%x)\n", chipid);
+
+ /* TODO:[ChangeFeature][George]: use a better way to select a correct ops table based on chip id */
+ switch (chipid) {
+#if CFG_CORE_MT6620_SUPPORT
+ case 0x6620:
+ p_ops = &wmt_ic_ops_mt6620;
+ break;
+#endif
+#if CFG_CORE_MT6628_SUPPORT
+ case 0x6628:
+ p_ops = &wmt_ic_ops_mt6628;
+ break;
+#endif
+
+#if CFG_CORE_MT6630_SUPPORT
+ case 0x6630:
+ p_ops = &wmt_ic_ops_mt6630;
+ break;
+#endif
+
+#if CFG_CORE_MT6632_SUPPORT
+ case 0x6632:
+ p_ops = &wmt_ic_ops_mt6632;
+ break;
+#endif
+#if CFG_CORE_SOC_SUPPORT
+ case 0x0690:
+ case 0x6572:
+ case 0x6582:
+ case 0x6592:
+ case 0x8127:
+ case 0x6571:
+ case 0x6752:
+ case 0x0279:
+ case 0x0326:
+ case 0x0321:
+ case 0x0335:
+ case 0x0337:
+ case 0x8163:
+ case 0x6580:
+ case 0x0551:
+ case 0x8167:
+ case 0x0507:
+ case 0x0688:
+ case 0x0699:
+ case 0x0633:
+ case 0x0713:
+ case 0x0788:
+ case 0x6765:
+ case 0x6761:
+ case 0x6779:
+ case 0x6768:
+ case 0x6785:
+ case 0x6833:
+ case 0x6853:
+ case 0x6873:
+ case 0x8168:
+ p_ops = &wmt_ic_ops_soc;
+ break;
+#endif
+
+ default:
+ p_ops = (P_WMT_IC_OPS) NULL;
+#if CFG_CORE_SOC_SUPPORT
+ if (chipid - 0x600 == 0x7f90) {
+ p_ops = &wmt_ic_ops_soc;
+ chipid -= 0xf6d;
+ }
+#endif
+ break;
+ }
+
+ if (p_ops == NULL) {
+ WMT_ERR_FUNC("unsupported chip id (hw_code): 0x%x\n", chipid);
+ return -WMT_ERRCODE_CHIPID_NOT_SUPPORT;
+ } else if (wmt_core_ic_ops_check(p_ops) == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC
+ ("chip id(0x%x) with null operation fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n",
+ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl,
+ p_ops->ic_ver_check);
+ return -WMT_ERRCODE_NULL_FUNC_POINTER;
+ }
+ WMT_DBG_FUNC("chip id(0x%x) fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n",
+ chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl,
+ p_ops->ic_ver_check);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ wmt_ic_ops_soc.icId = chipid;
+ wmt_ic_ops_soc.options = mtk_wcn_consys_get_options();
+ WMT_INFO_FUNC("options = %llx", wmt_ic_ops_soc.options);
+ }
+ iret = p_ops->ic_ver_check();
+ if (iret) {
+ WMT_ERR_FUNC("chip id(0x%x) ver_check error:%d\n", chipid, iret);
+ return -WMT_ERRCODE_VER_CHECK_FAIL;
+ }
+
+ WMT_DBG_FUNC("chip id(0x%x) ver_check ok\n", chipid);
+ gMtkWmtCtx.p_ic_ops = p_ops;
+ return 0;
+}
+
+static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp)
+{
+ if (!(pWmtOp->u4InfoBit & WMT_OP_HIF_BIT)) {
+ WMT_ERR_FUNC("WMT-CORE: no HIF_BIT in WMT_OP!\n");
+ return -1;
+ }
+
+ if (gMtkWmtCtx.wmtInfoBit & WMT_OP_HIF_BIT) {
+ WMT_ERR_FUNC("WMT-CORE: WMT HIF already exist. Just return\n");
+ return 0;
+ } else {
+ gMtkWmtCtx.wmtInfoBit |= WMT_OP_HIF_BIT;
+ WMT_ERR_FUNC("WMT-CORE: WMT HIF info added\n");
+ }
+
+ osal_memcpy(&gMtkWmtCtx.wmtHifConf,
+ &pWmtOp->au4OpData[0], osal_sizeof(gMtkWmtCtx.wmtHifConf));
+ return 0;
+
+}
+
+static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp)
+{
+ INT32 iRet;
+ INT32 iErrHandle = 0;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_POWER_OFF) {
+ WMT_ERR_FUNC("WMT-CORE: already powered on, WMT DRV_STS_[0x%x]\n",
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]);
+ osal_assert(0);
+ return -WMT_ERRCODE_ALREADY_ON;
+ }
+
+ /* power on control */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet);
+ iErrHandle = opfunc_pwr_off(pWmtOp);
+ if (iErrHandle)
+ WMT_ERR_FUNC("opfunc_pwr_off fail\n");
+ return (iErrHandle) ? iErrHandle : iRet;
+ }
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON;
+
+ /* init stp */
+ iRet = wmt_core_stp_init();
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_init fail (%d)\n", iRet);
+ osal_assert(0);
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 0) {
+ iErrHandle = wmt_core_stp_deinit();
+ if (iErrHandle)
+ WMT_ERR_FUNC("wmt_core_stp_deinit() failed, Err=%d\n", iErrHandle);
+ iErrHandle = opfunc_pwr_off(pWmtOp);
+ if (iErrHandle)
+ WMT_ERR_FUNC("opfunc_pwr_off fail, Err=%d\n", iErrHandle);
+ }
+ return (iErrHandle) ? iErrHandle : iRet;
+ }
+
+ WMT_DBG_FUNC("WMT-CORE: WMT [FUNC_ON]\n");
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON;
+
+ /* update blank status when ConnSys power on */
+ wmt_blank_status_ctrl(wmt_dev_get_blank_state());
+
+ mtk_wcn_consys_sleep_info_restore();
+
+ /* What to do when state is changed from POWER_OFF to POWER_ON?
+ * 1. STP driver does s/w reset
+ * 2. UART does 0xFF wake up
+ * 3. SDIO does re-init command(changed to trigger by host)
+ */
+ return 0;
+}
+
+static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_POWER_OFF) {
+ WMT_WARN_FUNC("WMT-CORE: WMT already off, WMT DRV_STS_[0x%x]\n",
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]);
+ osal_assert(0);
+ return -WMT_ERRCODE_ALREADY_OFF;
+ }
+ if (g_pwr_off_flag == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("CONNSYS power off be disabled, maybe need trigger core dump!\n");
+ osal_assert(0);
+ return -WMT_ERRCODE_READYTO_OFF;
+ }
+ /* wmt and stp are initialized successfully */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_FUNC_ON) {
+ iRet = wmt_core_stp_deinit();
+ if (iRet) {
+ WMT_WARN_FUNC("wmt_core_stp_deinit fail (%d)\n", iRet);
+ /*should let run to power down chip */
+ }
+ }
+
+ if (wmt_lib_power_lock_aquire() == 0) {
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF;
+ wmt_lib_power_lock_release();
+ } else {
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF;
+ WMT_INFO_FUNC("wmt_lib_power_lock_aquire failed\n");
+ }
+
+ /* power off control */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_OFF, &ctrlPa1, &ctrlPa2);
+ if (iRet)
+ WMT_WARN_FUNC("HW_PWR_OFF fail (%d)\n", iRet);
+ else
+ WMT_DBG_FUNC("HW_PWR_OFF ok\n");
+
+ return iRet;
+
+}
+
+static INT32 opfunc_func_on(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ UINT32 drvType = pWmtOp->au4OpData[0];
+
+ /* Check abnormal type */
+ if (drvType >= WMTDRV_TYPE_MAX) {
+ WMT_ERR_FUNC("abnormal Fun(%d)\n", drvType);
+ osal_assert(0);
+ return -1;
+ }
+
+ /* Check abnormal state */
+ if ((gMtkWmtCtx.eDrvStatus[drvType] < DRV_STS_POWER_OFF)
+ || (gMtkWmtCtx.eDrvStatus[drvType] >= DRV_STS_MAX)) {
+ WMT_ERR_FUNC("func(%d) status[0x%x] abnormal\n",
+ drvType, gMtkWmtCtx.eDrvStatus[drvType]);
+ osal_assert(0);
+ return -2;
+ }
+
+ if (WMTDRV_TYPE_GPSL5 == drvType)
+ mtk_wcn_stp_set_support_gpsl5(1);
+
+ /* check if func already on */
+ if (gMtkWmtCtx.eDrvStatus[drvType] == DRV_STS_FUNC_ON) {
+ WMT_WARN_FUNC("func(%d) already on\n", drvType);
+ return 0;
+ }
+ /*enable power off flag, if flag=0, power off connsys will not be executed */
+ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE);
+ /* check if chip power on is needed */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ iRet = opfunc_pwr_on(pWmtOp);
+ if (iRet) {
+ WMT_ERR_FUNC("func(%d) pwr_on fail(%d)\n", drvType, iRet);
+ osal_assert(0);
+
+ /* check all sub-func and do power off */
+ return -3;
+ }
+ }
+
+ if (WMTDRV_TYPE_WMT > drvType || WMTDRV_TYPE_ANT == drvType || WMTDRV_TYPE_GPSL5 == drvType) {
+ if (gpWmtFuncOps[drvType] && gpWmtFuncOps[drvType]->func_on) {
+
+ /* special handling for Wi-Fi */
+ if (drvType == WMTDRV_TYPE_WIFI) {
+ P_OSAL_OP pOp = wmt_lib_get_current_op(&gDevWmt);
+ atomic_set(&g_wifi_on_off_ready, 1);
+
+ pOp->op.opId = WMT_OPID_WLAN_PROBE;
+ if (wmt_lib_put_worker_op(pOp) == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("put to activeWorker queue fail\n");
+ atomic_set(&g_wifi_on_off_ready, 0);
+ return -4;
+ }
+ return 0;
+ }
+
+ iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+ if (iRet != 0)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+ else
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON;
+ } else {
+ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType);
+ iRet = -5;
+ }
+ } else {
+ if (drvType == WMTDRV_TYPE_LPBK)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON;
+ else if (drvType == WMTDRV_TYPE_COREDUMP)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON;
+ iRet = 0;
+ }
+
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet);
+ opfunc_try_pwr_off(pWmtOp);
+ return iRet;
+ }
+
+ /* send UTC time sync command after function on */
+ opfunc_utc_time_sync(NULL);
+ wmt_core_dump_func_state("AF FUNC ON");
+
+ return 0;
+}
+
+static INT32 opfunc_func_off(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ UINT32 drvType = pWmtOp->au4OpData[0];
+
+ /* Check abnormal type */
+ if (drvType >= WMTDRV_TYPE_MAX) {
+ WMT_ERR_FUNC("WMT-CORE: abnormal Fun(%d) in wmt_func_off\n", drvType);
+ osal_assert(0);
+ return -1;
+ }
+
+ /* Check abnormal state */
+ if (gMtkWmtCtx.eDrvStatus[drvType] >= DRV_STS_MAX) {
+ WMT_ERR_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] abnormal in wmt_func_off\n",
+ drvType, gMtkWmtCtx.eDrvStatus[drvType]);
+ osal_assert(0);
+ return -2;
+ }
+
+ if (gMtkWmtCtx.eDrvStatus[drvType] != DRV_STS_FUNC_ON) {
+ WMT_WARN_FUNC
+ ("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n",
+ drvType, gMtkWmtCtx.eDrvStatus[drvType]);
+ /* needs to check 4 subsystem's state? */
+ return 0;
+ } else if (WMTDRV_TYPE_WMT > drvType || WMTDRV_TYPE_ANT == drvType || WMTDRV_TYPE_GPSL5 == drvType) {
+ if (gpWmtFuncOps[drvType] && gpWmtFuncOps[drvType]->func_off) {
+ /* special handling for Wi-Fi */
+ if (drvType == WMTDRV_TYPE_WIFI) {
+ P_OSAL_OP pOp = wmt_lib_get_current_op(&gDevWmt);
+ atomic_set(&g_wifi_on_off_ready, 1);
+
+ pOp->op.opId = WMT_OPID_WLAN_REMOVE;
+ if (wmt_lib_put_worker_op(pOp) == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("put to activeWorker queue fail\n");
+ atomic_set(&g_wifi_on_off_ready, 0);
+ return -4;
+ }
+ return 0;
+ }
+ iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+ } else {
+ WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType);
+ iRet = -3;
+ }
+ } else {
+ if (drvType == WMTDRV_TYPE_LPBK)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+ else if (drvType == WMTDRV_TYPE_COREDUMP)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+ iRet = 0;
+ }
+
+ if (drvType != WMTDRV_TYPE_WMT)
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet);
+ osal_assert(0);
+ /* no matter subsystem function control fail or not, chip should be powered off
+ * when no subsystem is active
+ * return iRet;
+ */
+ }
+
+ /* check all sub-func and do power off */
+ opfunc_try_pwr_off(pWmtOp);
+ wmt_core_dump_func_state("AF FUNC OFF");
+ return iRet;
+}
+
+static INT32 opfunc_gps_suspend_by_type(ENUM_WMTDRV_TYPE_T type, P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ P_WMT_GEN_CONF pWmtGenConf = NULL;
+ MTK_WCN_BOOL suspend = (pWmtOp->au4OpData[0] != 0);
+ UINT32 suspend_flag = WMT_GPS_SUSPEND;
+
+ if (WMTDRV_TYPE_GPS != type && WMTDRV_TYPE_GPSL5 != type)
+ return 0;
+
+ if (WMTDRV_TYPE_GPSL5 == type)
+ suspend_flag = WMT_GPSL5_SUSPEND;
+
+ pWmtGenConf = wmt_conf_get_cfg();
+
+ if (gMtkWmtCtx.eDrvStatus[type] != DRV_STS_FUNC_ON) {
+ WMT_WARN_FUNC("WMT-CORE: GPS(%d) driver non-FUN_ON in opfunc_gps_suspend\n", type);
+ return 0;
+ }
+
+ if (MTK_WCN_BOOL_TRUE == suspend) {
+ if (osal_test_bit(suspend_flag, &gGpsFmState)) {
+ WMT_WARN_FUNC("WMT-CORE: GPS(%d) already suspend\n", type);
+ return 0;
+ }
+ } else {
+ if (!osal_test_bit(suspend_flag, &gGpsFmState)) {
+ WMT_WARN_FUNC("WMT-CORE: GPS(%d) already resume on\n", type);
+ return 0;
+ }
+ }
+
+ if (MTK_WCN_BOOL_TRUE == suspend) {
+ if (gpWmtFuncOps[type] && gpWmtFuncOps[type]->func_off) {
+ if (pWmtGenConf != NULL)
+ pWmtGenConf->wmt_gps_suspend_ctrl = 1;
+ iRet = (*(gpWmtFuncOps[type]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+ if (pWmtGenConf != NULL)
+ pWmtGenConf->wmt_gps_suspend_ctrl = 0;
+ } else {
+ WMT_WARN_FUNC("WMT-CORE: GPS(%d) suspend ops not found\n", type);
+ iRet = -3;
+ }
+ } else {
+ /*enable power off flag, if flag=0, power off connsys will not be executed */
+ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE);
+ /* check if chip power on is needed */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ iRet = opfunc_pwr_on(pWmtOp);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: func(%d) hw resume fail(%d)\n", type, iRet);
+ osal_assert(0);
+
+ /* check all sub-func and do power off */
+ return -5;
+ }
+ }
+
+ if (gpWmtFuncOps[type] && gpWmtFuncOps[type]->func_on) {
+ if (pWmtGenConf != NULL)
+ pWmtGenConf->wmt_gps_suspend_ctrl = 1;
+ iRet = (*(gpWmtFuncOps[type]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+ if (pWmtGenConf != NULL)
+ pWmtGenConf->wmt_gps_suspend_ctrl = 0;
+ } else {
+ WMT_WARN_FUNC("WMT-CORE: GPS(%d) resume ops not found\n", type);
+ iRet = -7;
+ }
+ }
+
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: gps(%d) %s function failed, ret(%d)\n",
+ type, ((pWmtOp->au4OpData[0] != 0) ? "suspend" : "resume"), iRet);
+ osal_assert(0);
+ }
+
+ if (MTK_WCN_BOOL_FALSE == suspend)
+ opfunc_utc_time_sync(NULL);
+
+ return iRet;
+}
+
+static INT32 opfunc_gps_suspend(P_WMT_OP pWmtOp)
+{
+ if (pWmtOp->au4OpData[1] == 1)
+ opfunc_gps_suspend_by_type(WMTDRV_TYPE_GPS, pWmtOp);
+
+ if (pWmtOp->au4OpData[2] == 1)
+ opfunc_gps_suspend_by_type(WMTDRV_TYPE_GPSL5, pWmtOp);
+
+ return 0;
+}
+
+/* TODO:[ChangeFeature][George] is this OP obsoleted? */
+static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp)
+{
+ INT32 iret;
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ WMT_ERR_FUNC("reg_rw when WMT is powered off\n");
+ return -1;
+ }
+ iret = wmt_core_reg_rw_raw(pWmtOp->au4OpData[0],
+ pWmtOp->au4OpData[1],
+ (PUINT32) pWmtOp->au4OpData[2], pWmtOp->au4OpData[3]);
+
+ return iret;
+}
+
+static INT32 opfunc_exit(P_WMT_OP pWmtOp)
+{
+ /* TODO: [FixMe][George] is ok to leave this function empty??? */
+ WMT_WARN_FUNC("EMPTY FUNCTION\n");
+ return 0;
+}
+
+static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp)
+{
+ INT32 ret = -1;
+ UINT32 u4_result = 0;
+ UINT32 evt_len;
+ UINT8 evt_buf[16] = { 0 };
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+
+ typedef INT32(*STP_PSM_CB) (const MTKSTP_PSM_ACTION_T);
+ STP_PSM_CB psm_cb = NULL;
+
+ if (pWmtOp->au4OpData[0] == SLEEP) {
+ WMT_DBG_FUNC("**** Send sleep command\n");
+ /* mtk_wcn_stp_set_psm_state(ACT_INACT); */
+ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */
+ ret =
+ wmt_core_tx((const PUINT8)(&WMT_SLEEP_CMD[0]), sizeof(WMT_SLEEP_CMD),
+ &u4_result, 0);
+ if (ret || (u4_result != sizeof(WMT_SLEEP_CMD))) {
+ WMT_ERR_FUNC("wmt_core: SLEEP_CMD ret(%d) cmd len err(%d, %zu) ", ret,
+ u4_result, sizeof(WMT_SLEEP_CMD));
+ goto pwr_sv_done;
+ }
+
+ evt_len = sizeof(WMT_SLEEP_EVT);
+ ret = wmt_core_rx(evt_buf, evt_len, &u4_result);
+ if (ret || (u4_result != evt_len)) {
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC
+ ("wmt_core: read SLEEP_EVT fail(%d) len(%d, %d), host trigger firmware assert\n",
+ ret, u4_result, evt_len);
+
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 33);
+ goto pwr_sv_done;
+ }
+
+ if (osal_memcmp(evt_buf, (const PVOID)WMT_SLEEP_EVT, sizeof(WMT_SLEEP_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_SLEEP_EVT error\n");
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n",
+ u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4],
+ evt_buf[5], sizeof(WMT_SLEEP_EVT), WMT_SLEEP_EVT[0], WMT_SLEEP_EVT[1],
+ WMT_SLEEP_EVT[2], WMT_SLEEP_EVT[3], WMT_SLEEP_EVT[4],
+ WMT_SLEEP_EVT[5]);
+ mtk_wcn_stp_dbg_dump_package();
+ goto pwr_sv_done;
+ }
+ WMT_DBG_FUNC("Send sleep command OK!\n");
+ } else if (pWmtOp->au4OpData[0] == WAKEUP) {
+ if (mtk_wcn_stp_is_btif_fullset_mode()) {
+ WMT_DBG_FUNC("wakeup connsys by btif");
+ ret = wmt_core_ctrl(WMT_CTRL_SOC_WAKEUP_CONSYS, &ctrlPa1, &ctrlPa2);
+ if (ret) {
+ WMT_ERR_FUNC("wmt-core:WAKEUP_CONSYS by BTIF fail(%d)", ret);
+ goto pwr_sv_done;
+ }
+ } else if (mtk_wcn_stp_is_sdio_mode()) {
+ WMT_DBG_FUNC("**** Send wakeup command\n");
+ ret =
+ wmt_core_tx((const PUINT8)WMT_WAKEUP_CMD, sizeof(WMT_WAKEUP_CMD), &u4_result, 1);
+ if (ret || (u4_result != sizeof(WMT_WAKEUP_CMD))) {
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC("wmt_core: WAKEUP_CMD ret(%d) cmd len err(%d, %zu)\n",
+ ret, u4_result, sizeof(WMT_WAKEUP_CMD));
+ goto pwr_sv_done;
+ }
+ }
+ evt_len = sizeof(WMT_WAKEUP_EVT);
+ ret = wmt_core_rx(evt_buf, evt_len, &u4_result);
+ if (ret || (u4_result != evt_len)) {
+ WMT_ERR_FUNC
+ ("wmt_core: read WAKEUP_EVT fail(%d) len(%d, %d), host grigger firmaware assert\n",
+ ret, u4_result, evt_len);
+
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 34);
+ goto pwr_sv_done;
+ }
+
+ if (osal_memcmp(evt_buf, (const PVOID)WMT_WAKEUP_EVT, sizeof(WMT_WAKEUP_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_WAKEUP_EVT error\n");
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n",
+ u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4],
+ evt_buf[5], sizeof(WMT_WAKEUP_EVT), WMT_WAKEUP_EVT[0],
+ WMT_WAKEUP_EVT[1], WMT_WAKEUP_EVT[2], WMT_WAKEUP_EVT[3],
+ WMT_WAKEUP_EVT[4], WMT_WAKEUP_EVT[5]);
+ mtk_wcn_stp_dbg_dump_package();
+ goto pwr_sv_done;
+ }
+ WMT_DBG_FUNC("Send wakeup command OK!\n");
+ } else if (pWmtOp->au4OpData[0] == HOST_AWAKE) {
+
+ WMT_DBG_FUNC("**** Send host awake command\n");
+
+ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1];
+ /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */
+ ret =
+ wmt_core_tx((const PUINT8)WMT_HOST_AWAKE_CMD, sizeof(WMT_HOST_AWAKE_CMD),
+ &u4_result, 0);
+ if (ret || (u4_result != sizeof(WMT_HOST_AWAKE_CMD))) {
+ WMT_ERR_FUNC("wmt_core: HOST_AWAKE_CMD ret(%d) cmd len err(%d, %zu) ", ret,
+ u4_result, sizeof(WMT_HOST_AWAKE_CMD));
+ goto pwr_sv_done;
+ }
+
+ evt_len = sizeof(WMT_HOST_AWAKE_EVT);
+ ret = wmt_core_rx(evt_buf, evt_len, &u4_result);
+ if (ret || (u4_result != evt_len)) {
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC
+ ("wmt_core:read HOST_AWAKE_EVT fail(%d) len(%d, %d), host trigger f/w assert\n",
+ ret, u4_result, evt_len);
+
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 35);
+ goto pwr_sv_done;
+ }
+
+ if (osal_memcmp
+ (evt_buf, (const PVOID)WMT_HOST_AWAKE_EVT, sizeof(WMT_HOST_AWAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_HOST_AWAKE_EVT error\n");
+ wmt_core_rx_flush(WMT_TASK_INDX);
+ WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n",
+ u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4],
+ evt_buf[5], sizeof(WMT_HOST_AWAKE_EVT), WMT_HOST_AWAKE_EVT[0],
+ WMT_HOST_AWAKE_EVT[1], WMT_HOST_AWAKE_EVT[2], WMT_HOST_AWAKE_EVT[3],
+ WMT_HOST_AWAKE_EVT[4], WMT_HOST_AWAKE_EVT[5]);
+ mtk_wcn_stp_dbg_dump_package();
+ /* goto pwr_sv_done; */
+ } else {
+ WMT_DBG_FUNC("Send host awake command OK!\n");
+ }
+ }
+pwr_sv_done:
+
+ if (pWmtOp->au4OpData[0] < STP_PSM_MAX_ACTION) {
+ psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1];
+ WMT_DBG_FUNC("Do STP-CB! %zu %p\n", pWmtOp->au4OpData[0],
+ (PVOID) pWmtOp->au4OpData[1]);
+ if (psm_cb != NULL) {
+ psm_cb(pWmtOp->au4OpData[0]);
+ } else {
+ WMT_ERR_FUNC
+ ("fatal error !!!, psm_cb = %p, god, someone must have corrupted our memory.\n",
+ psm_cb);
+ }
+ }
+
+ return ret;
+}
+
+static INT32 opfunc_dsns(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet = -1;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+
+ WMT_DSNS_CMD[4] = pWmtOp->au4OpData[0];
+ WMT_DSNS_CMD[5] = pWmtOp->au4OpData[1];
+
+ /* send command */
+ /* iRet = (*kal_stp_tx)(WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8) WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != osal_sizeof(WMT_DSNS_CMD))) {
+ WMT_ERR_FUNC("WMT-CORE: DSNS_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet, u4Res,
+ osal_sizeof(WMT_DSNS_CMD));
+ return iRet;
+ }
+
+ evtLen = osal_sizeof(WMT_DSNS_EVT);
+
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("WMT-CORE: read DSNS_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen);
+ mtk_wcn_stp_dbg_dump_package();
+ return iRet;
+ }
+
+ if (osal_memcmp(evtBuf, WMT_DSNS_EVT, osal_sizeof(WMT_DSNS_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: compare WMT_DSNS_EVT error\n");
+ WMT_ERR_FUNC
+ ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ osal_sizeof(WMT_DSNS_EVT), WMT_DSNS_EVT[0], WMT_DSNS_EVT[1], WMT_DSNS_EVT[2],
+ WMT_DSNS_EVT[3], WMT_DSNS_EVT[4]);
+ } else {
+ WMT_INFO_FUNC("Send WMT_DSNS_CMD command OK!\n");
+ }
+
+ return iRet;
+}
+
+#if CFG_CORE_INTERNAL_TXRX
+INT32 wmt_core_lpbk_do_stp_init(void)
+{
+ INT32 iRet = 0;
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n");
+ return -1;
+ }
+
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_BTIF_MAND_MODE;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet);
+ return -2;
+ }
+}
+
+INT32 wmt_core_lpbk_do_stp_deinit(void)
+{
+ INT32 iRet = 0;
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt open stp\n");
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+
+static INT32 opfunc_lpbk(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ UINT32 buf_length = 0;
+ PUINT32 pbuffer = NULL;
+ UINT16 len_in_cmd;
+ /* UINT32 offset; */
+ UINT8 WMT_TEST_LPBK_CMD[] = { 0x1, 0x2, 0x0, 0x0, 0x7 };
+ UINT8 WMT_TEST_LPBK_EVT[] = { 0x2, 0x2, 0x0, 0x0, 0x0 };
+ /* UINT8 lpbk_buf[1024 + 5] = {0}; */
+ MTK_WCN_BOOL fgFail;
+
+ buf_length = pWmtOp->au4OpData[0]; /* packet length */
+ pbuffer = (PUINT32) pWmtOp->au4OpData[1]; /* packet buffer pointer */
+ WMT_DBG_FUNC("WMT-CORE: -->wmt_do_lpbk\n");
+ /*check if WMTDRV_TYPE_LPBK function is already on */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] != DRV_STS_FUNC_ON
+ || buf_length + osal_sizeof(WMT_TEST_LPBK_CMD) > osal_sizeof(gLpbkBuf)) {
+ WMT_ERR_FUNC("WMT-CORE: abnormal LPBK in wmt_do_lpbk\n");
+ osal_assert(0);
+ return -2;
+ }
+ /*package loopback for STP */
+
+ /* init buffer */
+ osal_memset(gLpbkBuf, 0, osal_sizeof(gLpbkBuf));
+
+ len_in_cmd = buf_length + 1; /* add flag field */
+
+ osal_memcpy(&WMT_TEST_LPBK_CMD[2], &len_in_cmd, 2);
+ osal_memcpy(&WMT_TEST_LPBK_EVT[2], &len_in_cmd, 2);
+
+ /* wmt cmd */
+ osal_memcpy(gLpbkBuf, WMT_TEST_LPBK_CMD, osal_sizeof(WMT_TEST_LPBK_CMD));
+ osal_memcpy(gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), pbuffer, buf_length);
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+ /*send packet through STP */
+ /* iRet = (*kal_stp_tx)((PUINT8)gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_CMD) +
+ * buf_length, &u4WrittenSize);
+ */
+ iRet =
+ wmt_core_tx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length),
+ &u4WrittenSize, MTK_WCN_BOOL_FALSE);
+ if (iRet) {
+ WMT_ERR_FUNC("opfunc_lpbk wmt_core_tx failed\n");
+ break;
+ }
+ /*receive firmware response from STP */
+ iRet =
+ wmt_core_rx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_EVT) + buf_length),
+ &u4ReadSize);
+ if (iRet) {
+ WMT_ERR_FUNC("opfunc_lpbk wmt_core_rx failed\n");
+ break;
+ }
+ /*check if loopback response ok or not */
+ if (u4ReadSize != (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)) {
+ WMT_ERR_FUNC("lpbk event read size wrong(%d, %zu)\n", u4ReadSize,
+ (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length));
+ break;
+ }
+ if (osal_memcmp(WMT_TEST_LPBK_EVT, gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_EVT))) {
+ WMT_ERR_FUNC
+ ("WMT-CORE WMT_TEST_LPBK_EVT error! read len %d [%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4ReadSize, gLpbkBuf[0], gLpbkBuf[1], gLpbkBuf[2], gLpbkBuf[3],
+ gLpbkBuf[4]
+ );
+ break;
+ }
+ pWmtOp->au4OpData[0] = u4ReadSize - osal_sizeof(WMT_TEST_LPBK_EVT);
+ osal_memcpy((PVOID) pWmtOp->au4OpData[1],
+ gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), buf_length);
+ fgFail = MTK_WCN_BOOL_FALSE;
+ } while (0);
+ /*return result */
+ /* WMT_DBG_FUNC("WMT-CORE: <--wmt_do_lpbk, fgFail = %d\n", fgFail); */
+ if (fgFail == MTK_WCN_BOOL_TRUE) {
+ WMT_ERR_FUNC("LPBK fail and trigger assert\n");
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 37);
+ }
+ return fgFail;
+
+}
+
+static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet = 0;
+ UINT32 cmdNo = 0;
+ UINT32 cmdNoPa = 0;
+
+ UINT8 tstCmd[64];
+ UINT8 tstEvt[64];
+ UINT8 tstEvtTmp[64];
+ UINT32 u4Res;
+ UINT32 tstCmdSz = 0;
+ UINT32 tstEvtSz = 0;
+
+ PUINT8 pRes = NULL;
+ UINT32 resBufRoom = 0;
+ /*test command list */
+ /*1 */
+ UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 };
+ UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+ UINT8 WMT_NOACK_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0A };
+ UINT8 WMT_NOACK_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+ UINT8 WMT_WARNRST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0B };
+ UINT8 WMT_WARNRST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+ UINT8 WMT_FWLOGTST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0C };
+ UINT8 WMT_FWLOGTST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+
+ UINT8 WMT_EXCEPTION_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x09 };
+ UINT8 WMT_EXCEPTION_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+ /*2 */
+ UINT8 WMT_COEXDBG_CMD[] = { 0x01, 0x10, 0x02, 0x00,
+ 0x08,
+ 0xAA /*Debugging Parameter */
+ };
+ UINT8 WMT_COEXDBG_1_EVT[] = { 0x02, 0x10, 0x05, 0x00,
+ 0x00,
+ 0xAA, 0xAA, 0xAA, 0xAA /*event content */
+ };
+ UINT8 WMT_COEXDBG_2_EVT[] = { 0x02, 0x10, 0x07, 0x00,
+ 0x00,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB /*event content */
+ };
+ UINT8 WMT_COEXDBG_3_EVT[] = { 0x02, 0x10, 0x0B, 0x00,
+ 0x00,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB /*event content */
+ };
+ /*test command list -end */
+
+ cmdNo = pWmtOp->au4OpData[0];
+
+ WMT_INFO_FUNC("Send Test command %d!\n", cmdNo);
+ if (cmdNo == 0) {
+ /*dead command */
+ WMT_INFO_FUNC("Send Assert command !\n");
+ tstCmdSz = osal_sizeof(WMT_ASSERT_CMD);
+ tstEvtSz = osal_sizeof(WMT_ASSERT_EVT);
+ osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz);
+ } else if (cmdNo == 1) {
+ /*dead command */
+ WMT_INFO_FUNC("Send Exception command !\n");
+ tstCmdSz = osal_sizeof(WMT_EXCEPTION_CMD);
+ tstEvtSz = osal_sizeof(WMT_EXCEPTION_EVT);
+ osal_memcpy(tstCmd, WMT_EXCEPTION_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_EXCEPTION_EVT, tstEvtSz);
+ } else if (cmdNo == 2) {
+ cmdNoPa = pWmtOp->au4OpData[1];
+ pRes = (PUINT8) pWmtOp->au4OpData[2];
+ resBufRoom = pWmtOp->au4OpData[3];
+ if (cmdNoPa <= 0xf) {
+ WMT_INFO_FUNC("Send Coexistence Debug command [0x%x]!\n", cmdNoPa);
+ tstCmdSz = osal_sizeof(WMT_COEXDBG_CMD);
+ osal_memcpy(tstCmd, WMT_COEXDBG_CMD, tstCmdSz);
+ if (tstCmdSz > 5)
+ tstCmd[5] = cmdNoPa;
+
+ /*setup the expected event length */
+ if (cmdNoPa <= 0x4) {
+ tstEvtSz = osal_sizeof(WMT_COEXDBG_1_EVT);
+ osal_memcpy(tstEvt, WMT_COEXDBG_1_EVT, tstEvtSz);
+ } else if (cmdNoPa == 0x5) {
+ tstEvtSz = osal_sizeof(WMT_COEXDBG_2_EVT);
+ osal_memcpy(tstEvt, WMT_COEXDBG_2_EVT, tstEvtSz);
+ } else if (cmdNoPa >= 0x6 && cmdNoPa <= 0xf) {
+ tstEvtSz = osal_sizeof(WMT_COEXDBG_3_EVT);
+ osal_memcpy(tstEvt, WMT_COEXDBG_3_EVT, tstEvtSz);
+ } else {
+
+ }
+ } else {
+ WMT_ERR_FUNC("cmdNoPa is wrong\n");
+ return iRet;
+ }
+ } else if (cmdNo == 3) {
+ /*dead command */
+ WMT_INFO_FUNC("Send No Ack command !\n");
+ tstCmdSz = osal_sizeof(WMT_NOACK_CMD);
+ tstEvtSz = osal_sizeof(WMT_NOACK_EVT);
+ osal_memcpy(tstCmd, WMT_NOACK_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_NOACK_EVT, tstEvtSz);
+ } else if (cmdNo == 4) {
+ /*dead command */
+ WMT_INFO_FUNC("Send Warm reset command !\n");
+ tstCmdSz = osal_sizeof(WMT_WARNRST_CMD);
+ tstEvtSz = osal_sizeof(WMT_WARNRST_EVT);
+ osal_memcpy(tstCmd, WMT_WARNRST_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_WARNRST_EVT, tstEvtSz);
+ } else if (cmdNo == 5) {
+ /*dead command */
+ WMT_INFO_FUNC("Send f/w log test command !\n");
+ tstCmdSz = osal_sizeof(WMT_FWLOGTST_CMD);
+ tstEvtSz = osal_sizeof(WMT_FWLOGTST_EVT);
+ osal_memcpy(tstCmd, WMT_FWLOGTST_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_FWLOGTST_EVT, tstEvtSz);
+ }
+
+ /* send command */
+ /* iRet = (*kal_stp_tx)(tstCmd, tstCmdSz, &u4Res); */
+ iRet = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != tstCmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res,
+ tstCmdSz);
+ return -1;
+ }
+
+ if ((cmdNo == 0) || (cmdNo == 1) || cmdNo == 3) {
+ WMT_INFO_FUNC("WMT-CORE: not to rx event for assert command\n");
+ return 0;
+ }
+
+ iRet = wmt_core_rx(tstEvtTmp, tstEvtSz, &u4Res);
+
+ /*Event Post Handling */
+ if (cmdNo == 2) {
+ WMT_INFO_FUNC("#=========================================================#\n");
+ WMT_INFO_FUNC("coext debugging id = %d", cmdNoPa);
+ if (tstEvtSz > 5)
+ wmt_core_dump_data(&tstEvtTmp[5], "coex debugging ", tstEvtSz - 5);
+ else
+ WMT_ERR_FUNC("error coex debugging event\n");
+ /*put response to buffer for shell to read */
+ if (pRes != NULL && resBufRoom > 0) {
+ pWmtOp->au4OpData[3] =
+ resBufRoom < tstEvtSz - 5 ? resBufRoom : tstEvtSz - 5;
+ osal_memcpy(pRes, &tstEvtTmp[5], pWmtOp->au4OpData[3]);
+ } else
+ pWmtOp->au4OpData[3] = 0;
+ WMT_INFO_FUNC("#=========================================================#\n");
+ }
+
+ return iRet;
+
+}
+
+static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet = -1;
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+
+ wmt_core_dump_func_state("BE HW RST");
+ /*-->Reset WMT data structure*/
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] = DRV_STS_POWER_OFF;
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT] = DRV_STS_POWER_OFF;
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = DRV_STS_POWER_OFF;
+ /*enable power off flag, if flag=0, power off connsys will not be executed */
+ mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE);
+
+ /* if wmt is poweroff, we need poweron chip first */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_POWER_OFF) {
+ WMT_WARN_FUNC("WMT-CORE: WMT is off, need re-poweron\n");
+ /* power on control */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet);
+ return -1;
+ }
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON;
+ }
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_FUNC_ON) {
+ if (mtk_wcn_stp_is_btif_fullset_mode()) {
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ if (iRet)
+ WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%lu)(%lu)\n",
+ iRet, ctrlPa1, ctrlPa2);
+ }
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF;
+ }
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] == DRV_STS_FUNC_ON ||
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPSL5] == DRV_STS_FUNC_ON ||
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] == DRV_STS_FUNC_ON) {
+ if (mtk_wcn_stp_is_btif_fullset_mode()) {
+ ctrlPa1 = GPS_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ if (iRet)
+ WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%lu)(%lu)\n",
+ iRet, ctrlPa1, ctrlPa2);
+ }
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] = DRV_STS_POWER_OFF;
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] = DRV_STS_POWER_OFF;
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPSL5] = DRV_STS_POWER_OFF;
+ }
+
+ iRet = wmt_lib_wlan_lock_aquire();
+ if (iRet) {
+ WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet);
+ return iRet;
+ }
+
+ /*--> reset SDIO function/slot additionally if wifi ON*/
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_FUNC_ON) {
+ if (mtk_wcn_stp_is_sdio_mode()) {
+ ctrlPa1 = WMT_SDIO_FUNC_WIFI;
+ ctrlPa2 = 0; /* turn off Wi-Fi driver */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn off SDIO_WIFI func fail (%d)\n", iRet);
+ /* check all sub-func and do power off */
+ } else
+ WMT_INFO_FUNC("wmt core: turn off SDIO WIFI func ok!!\n");
+ /* Anyway, turn off Wi-Fi Function */
+ } else if (mtk_wcn_stp_is_btif_fullset_mode()) {
+ if (gpWmtFuncOps[WMTDRV_TYPE_WIFI] != NULL &&
+ gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off != NULL) {
+ iRet = gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off(gMtkWmtCtx.p_ic_ops,
+ wmt_conf_get_cfg());
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn off WIFI func fail (%d)\n", iRet);
+
+ /* check all sub-func and do power off */
+ } else {
+ WMT_INFO_FUNC("wmt core: turn off WIFI func ok!!\n");
+ }
+ }
+ }
+ /* Anyway, turn off Wi-Fi Function */
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF;
+
+ if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_UART) {
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO1;
+ ctrlPa2 = 0; /* turn off SDIO1 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn off SLOT_SDIO1 fail (%d)\n", iRet);
+ osal_assert(0);
+
+ /* check all sub-func and do power off */
+ } else
+ WMT_INFO_FUNC("WMT-CORE: turn off SLOT_SDIO1 successfully (%d)\n", iRet);
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF;
+ }
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF;
+ }
+ wmt_lib_wlan_lock_release();
+
+ mtk_wcn_wmt_system_state_reset();
+
+ if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) {
+ ctrlPa1 = WMT_SDIO_FUNC_STP;
+ ctrlPa2 = 0; /* turn off STP driver */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn off SDIO_FUNC_STP func fail (%d)\n", iRet);
+
+ /* check all sub-func and do power off */
+ /* goto stp_deinit_done; */
+ } else
+ WMT_INFO_FUNC("WMT-CORE: turn off SDIO_FUNC_STP func successfully (%d)\n", iRet);
+
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO2;
+ ctrlPa2 = 0; /* turn off SDIO2 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn off SLOT_SDIO2 fail (%d)\n", iRet);
+ osal_assert(0);
+
+ /* check all sub-func and do power off */
+ /* goto stp_deinit_done; */
+ } else
+ WMT_INFO_FUNC("WMT-CORE: turn off SLOT_SDIO2 successfully (%d)\n", iRet);
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_POWER_OFF;
+ }
+#if 0
+ /*<4>Power off Combo chip */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2);
+ if (iRet)
+ WMT_ERR_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF fail (%d)", iRet);
+ else
+ WMT_INFO_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF ok (%d)", iRet);
+#endif
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF;
+
+ /*-->PesetCombo chip*/
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2);
+ if (iRet)
+ WMT_ERR_FUNC("WMT-CORE: -->[HW RST] fail iRet(%d)\n", iRet);
+ else
+ WMT_INFO_FUNC("WMT-CORE: -->[HW RST] ok\n");
+
+ /* 4 close stp */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt close stp failed\n");
+ return -1;
+ }
+
+ wmt_core_dump_func_state("AF HW RST");
+ return iRet;
+}
+
+static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+
+ iRet = wmt_core_stp_init();
+ if (iRet == 0) {
+ WMT_INFO_FUNC("WMT-CORE: SW Rst succeed\n");
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON;
+ } else {
+ WMT_ERR_FUNC("WMT-CORE: SW Rst failed\n");
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF;
+ }
+
+ return iRet;
+}
+
+static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp)
+{
+
+ return 0;
+}
+
+static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet = -1;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+
+ WMT_THERM_CMD[4] = pWmtOp->au4OpData[0]; /*CMD type, refer to ENUM_WMTTHERM_TYPE_T */
+
+ /* send command */
+ /* iRet = (*kal_stp_tx)(WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8) WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != osal_sizeof(WMT_THERM_CMD))) {
+ WMT_ERR_FUNC("WMT-CORE: THERM_CTRL_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet,
+ u4Res, osal_sizeof(WMT_THERM_CMD));
+ return iRet;
+ }
+
+ evtLen = 16;
+
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || ((u4Res != osal_sizeof(WMT_THERM_CTRL_EVT)) && (u4Res != osal_sizeof(WMT_THERM_READ_EVT)))) {
+ WMT_ERR_FUNC("WMT-CORE: read THERM_CTRL_EVT/THERM_READ_EVENT fail(%d) len(%d)\n", iRet, u4Res);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 36);
+ return iRet;
+ }
+ if (u4Res == osal_sizeof(WMT_THERM_CTRL_EVT)) {
+ if (osal_memcmp(evtBuf, WMT_THERM_CTRL_EVT, osal_sizeof(WMT_THERM_CTRL_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_CTRL_EVT error\n");
+ WMT_ERR_FUNC
+ ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ osal_sizeof(WMT_THERM_CTRL_EVT), WMT_THERM_CTRL_EVT[0],
+ WMT_THERM_CTRL_EVT[1], WMT_THERM_CTRL_EVT[2], WMT_THERM_CTRL_EVT[3],
+ WMT_THERM_CTRL_EVT[4]);
+ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_FALSE; /*will return to function driver */
+ mtk_wcn_stp_dbg_dump_package();
+ } else {
+ WMT_DBG_FUNC("Send WMT_THERM_CTRL_CMD command OK!\n");
+ pWmtOp->au4OpData[1] = MTK_WCN_BOOL_TRUE; /*will return to function driver */
+ }
+ } else {
+ /*no need to judge the real thermal value */
+ if (osal_memcmp(evtBuf, WMT_THERM_READ_EVT, osal_sizeof(WMT_THERM_READ_EVT) - 1) !=
+ 0) {
+ WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_READ_EVT error\n");
+ WMT_ERR_FUNC
+ ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5], osal_sizeof(WMT_THERM_READ_EVT), WMT_THERM_READ_EVT[0],
+ WMT_THERM_READ_EVT[1], WMT_THERM_READ_EVT[2], WMT_THERM_READ_EVT[3]);
+ pWmtOp->au4OpData[1] = 0xFF; /*will return to function driver */
+ mtk_wcn_stp_dbg_dump_package();
+ } else {
+ WMT_DBG_FUNC("Send WMT_THERM_READ_CMD command OK!\n");
+ pWmtOp->au4OpData[1] = evtBuf[5]; /*will return to function driver */
+ }
+ }
+
+ return iRet;
+
+}
+
+static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp)
+{
+
+ INT32 iRet = -1;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_efuse_rw fail: chip is powered off\n");
+ return -1;
+ }
+
+ WMT_EFUSE_CMD[4] = (pWmtOp->au4OpData[0]) ? 0x1 : 0x2; /* w:2, r:1 */
+ osal_memcpy(&WMT_EFUSE_CMD[6], (PUINT8) &pWmtOp->au4OpData[1], 2); /* address */
+ osal_memcpy(&WMT_EFUSE_CMD[8], (PUINT32) pWmtOp->au4OpData[2], 4); /* value */
+
+ wmt_core_dump_data(&WMT_EFUSE_CMD[0], "efuse_cmd", osal_sizeof(WMT_EFUSE_CMD));
+
+ /* send command */
+ /* iRet = (*kal_stp_tx)(WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8) WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != osal_sizeof(WMT_EFUSE_CMD))) {
+ WMT_ERR_FUNC("WMT-CORE: EFUSE_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet, u4Res,
+ osal_sizeof(WMT_EFUSE_CMD));
+ return iRet;
+ }
+
+ evtLen = osal_sizeof(WMT_EFUSE_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("WMT-CORE: read REG_EVB fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ WMT_EFUSE_EVT[0], WMT_EFUSE_EVT[1], WMT_EFUSE_EVT[2],
+ WMT_EFUSE_EVT[3], WMT_EFUSE_EVT[4]);
+ }
+ wmt_core_dump_data(&evtBuf[0], "efuse_evt", osal_sizeof(evtBuf));
+
+ return iRet;
+}
+
+static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ WMT_IC_PIN_ID id;
+ WMT_IC_PIN_STATE stat;
+ UINT32 flag;
+
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_gpio_ctrl fail: chip is powered off\n");
+ return -1;
+ }
+
+ if (!gMtkWmtCtx.p_ic_ops->ic_pin_ctrl) {
+ WMT_ERR_FUNC("WMT-CORE: error, gMtkWmtCtx.p_ic_ops->ic_pin_ctrl(NULL)\n");
+ return -1;
+ }
+
+ id = pWmtOp->au4OpData[0];
+ stat = pWmtOp->au4OpData[1];
+ flag = pWmtOp->au4OpData[2];
+
+ WMT_INFO_FUNC("ic pin id:%d, stat:%d, flag:0x%x\n", id, stat, flag);
+
+ iRet = (*(gMtkWmtCtx.p_ic_ops->ic_pin_ctrl)) (id, stat, flag);
+
+ return iRet;
+}
+
+/* turn on/off sdio function */
+INT32 opfunc_sdio_ctrl(P_WMT_OP pWmtOp)
+{
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+ UINT32 iRet = 0;
+
+ ctrlPa1 =
+ WMT_HIF_SDIO ==
+ gMtkWmtCtx.wmtHifConf.hifType ? WMT_SDIO_SLOT_SDIO2 : WMT_SDIO_SLOT_SDIO1;
+ ctrlPa2 = pWmtOp->au4OpData[0]; /* turn off/on SDIO slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_WARN_FUNC("SDIO hw ctrl fail ret(%d)\n", iRet);
+ /* Anyway, continue turning STP SDIO to POWER OFF/ON state */
+ gMtkWmtCtx.eDrvStatus[ctrlPa1] = DRV_STS_POWER_OFF;
+ } else {
+ WMT_INFO_FUNC("SDIO hw ctrl succeed\n");
+ gMtkWmtCtx.eDrvStatus[ctrlPa1] =
+ ctrlPa2 == 0 ? DRV_STS_POWER_OFF : DRV_STS_POWER_ON;
+ }
+
+ return 0;
+
+}
+
+INT32 opfunc_trigger_stp_assert(P_WMT_OP pWmtOp)
+{
+ if (wmt_core_trigger_stp_assert() == MTK_WCN_BOOL_TRUE) {
+ WMT_INFO_FUNC("trigger STP assert succeed\n");
+ return 0;
+ }
+ WMT_WARN_FUNC("trigger STP assert failed\n");
+ return -1;
+}
+
+MTK_WCN_BOOL wmt_core_is_quick_ps_support(VOID)
+{
+ P_WMT_CTX pctx = &gMtkWmtCtx;
+
+ if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->is_quick_sleep != NULL))
+ return (*(pctx->p_ic_ops->is_quick_sleep))();
+ return MTK_WCN_BOOL_FALSE;
+}
+
+MTK_WCN_BOOL wmt_core_get_aee_dump_flag(VOID)
+{
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_WMT_CTX pctx = &gMtkWmtCtx;
+
+ if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->is_aee_dump_support != NULL))
+ bRet = (*(pctx->p_ic_ops->is_aee_dump_support))();
+ else
+ bRet = MTK_WCN_BOOL_FALSE;
+
+ return bRet;
+}
+
+static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ UINT32 buf_len = 0;
+ UINT8 *buffer = NULL;
+ UINT8 evt_buffer[8] = { 0 };
+ MTK_WCN_BOOL fgFail;
+
+ UINT8 WMT_BGW_DESENSE_CMD[] = {
+ 0x01, 0x0e, 0x0f, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+ UINT8 WMT_BGW_DESENSE_EVT[] = { 0x02, 0x0e, 0x01, 0x00, 0x00 };
+
+ buf_len = pWmtOp->au4OpData[0];
+ buffer = (PUINT8) pWmtOp->au4OpData[1];
+
+ osal_memcpy(&WMT_BGW_DESENSE_CMD[5], buffer, buf_len);
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ iRet =
+ wmt_core_tx(&WMT_BGW_DESENSE_CMD[0], osal_sizeof(WMT_BGW_DESENSE_CMD), &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4WrittenSize != osal_sizeof(WMT_BGW_DESENSE_CMD))) {
+ WMT_ERR_FUNC("bgw desense tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize);
+ break;
+ }
+
+ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_BGW_DESENSE_EVT), &u4ReadSize);
+ if (iRet || (u4ReadSize != osal_sizeof(WMT_BGW_DESENSE_EVT))) {
+ WMT_ERR_FUNC("bgw desense rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize);
+ break;
+ }
+
+ if (osal_memcmp(evt_buffer, WMT_BGW_DESENSE_EVT, osal_sizeof(WMT_BGW_DESENSE_EVT)) != 0) {
+ WMT_ERR_FUNC
+ ("bgw desense WMT_BGW_DESENSE_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4]);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ return fgFail;
+}
+
+static INT32 wmt_core_gen2_set_mcu_clk(UINT32 kind)
+{
+ INT32 iRet = -1;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ UINT8 evt_buffer[12] = { 0 };
+ MTK_WCN_BOOL fgFail;
+ PUINT8 set_mcu_clk_str[] = {
+ "Enable GEN2 MCU PLL",
+ "SET GEN2 MCU CLK to 26M",
+ "SET GEN2 MCU CLK to 37M",
+ "SET GEN2 MCU CLK to 64M",
+ "SET GEN2 MCU CLK to 69M",
+ "SET GEN2 MCU CLK to 104M",
+ "SET GEN2 MCU CLK to 118.857M",
+ "SET GEN2 MCU CLK to 138.67M",
+ "Disable GEN2 MCU PLL"
+ };
+ UINT8 WMT_SET_MCU_CLK_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+ };
+ UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+ UINT8 WMT_EN_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00 }; /* enable pll clk */
+ UINT8 WMT_26_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x00, 0x4d, 0x84, 0x00 }; /* set 26M */
+ UINT8 WMT_37_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1e, 0x4d, 0x84, 0x00 }; /* set 37.8M */
+ UINT8 WMT_64_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1d, 0x4d, 0x84, 0x00 }; /* set 64M */
+ UINT8 WMT_69_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1c, 0x4d, 0x84, 0x00 }; /* set 69M */
+ UINT8 WMT_104_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5b, 0x4d, 0x84, 0x00 }; /* set 104M */
+ UINT8 WMT_108_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5a, 0x4d, 0x84, 0x00 }; /* set 118.857M */
+ UINT8 WMT_138_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x59, 0x4d, 0x84, 0x00 }; /* set 138.67M */
+ UINT8 WMT_DIS_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 }; /* disable pll clk */
+
+ WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]);
+
+ switch (kind) {
+ case 0:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_EN_MCU_CLK_CMD[0], osal_sizeof(WMT_EN_MCU_CLK_CMD));
+ break;
+ case 1:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_26_MCU_CLK_CMD[0], osal_sizeof(WMT_26_MCU_CLK_CMD));
+ break;
+ case 2:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_37_MCU_CLK_CMD[0], osal_sizeof(WMT_37_MCU_CLK_CMD));
+ break;
+ case 3:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_64_MCU_CLK_CMD[0], osal_sizeof(WMT_64_MCU_CLK_CMD));
+ break;
+ case 4:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_69_MCU_CLK_CMD[0], osal_sizeof(WMT_69_MCU_CLK_CMD));
+ break;
+ case 5:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_104_MCU_CLK_CMD[0], osal_sizeof(WMT_104_MCU_CLK_CMD));
+ break;
+ case 6:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_108_MCU_CLK_CMD[0], osal_sizeof(WMT_108_MCU_CLK_CMD));
+ break;
+ case 7:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_138_MCU_CLK_CMD[0], osal_sizeof(WMT_138_MCU_CLK_CMD));
+ break;
+ case 8:
+ osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_DIS_MCU_CLK_CMD[0], osal_sizeof(WMT_DIS_MCU_CLK_CMD));
+ break;
+ default:
+ WMT_ERR_FUNC("unknown kind\n");
+ break;
+ }
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ iRet =
+ wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize);
+ break;
+ }
+
+ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize);
+ if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize);
+ mtk_wcn_stp_dbg_dump_package();
+ break;
+ }
+
+ if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]);
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ if (fgFail == MTK_WCN_BOOL_FALSE)
+ WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]);
+ else
+ WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]);
+
+ return fgFail;
+}
+
+static INT32 wmt_core_gen3_set_mcu_clk(UINT32 kind)
+{
+ INT32 iRet = -1;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ UINT8 evt_buffer[12] = { 0 };
+ MTK_WCN_BOOL fgFail;
+ PUINT8 set_mcu_clk_str[] = {
+ "SET GEN3 MCU CLK to 26M",
+ "SET GEN3 MCU CLK to 46M",
+ "SET GEN3 MCU CLK to 97M",
+ "SET GEN3 MCU CLK to 104M",
+ "SET GEN3 MCU CLK to 184M",
+ "SET GEN3 MCU CLK to 208M",
+ };
+ UINT8 set_mcu_clk_vel[] = {
+ 0x1a, /* set 26M*/
+ 0x2e, /* set 46M*/
+ 0x61, /* set 97M*/
+ 0x68, /* set 104M */
+ 0xb8, /* set 184M */
+ 0xd0, /* set 208M */
+ };
+ UINT8 WMT_SET_MCU_CLK_CMD[] = { 0x01, 0x0a, 0x04, 0x00, 0x09, 0x03, 0x00, 0x00 };
+ UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x0a, 0x01, 0x00, 0x00 };
+
+
+ if (kind < osal_sizeof(set_mcu_clk_vel)) {
+ WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]);
+ WMT_SET_MCU_CLK_CMD[6] = set_mcu_clk_vel[kind];
+ } else {
+ WMT_ERR_FUNC("unknown kind(%d)!\n", kind);
+ return MTK_WCN_BOOL_TRUE;
+ }
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ iRet = wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize);
+ break;
+ }
+
+ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize);
+ if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize);
+ mtk_wcn_stp_dbg_dump_package();
+ break;
+ }
+
+ if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]);
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ if (fgFail == MTK_WCN_BOOL_FALSE)
+ WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]);
+ else
+ WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]);
+
+ return fgFail;
+}
+
+static INT32 wmt_core_set_mcu_clk(UINT32 kind)
+{
+ INT32 iRet = -1;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ UINT8 evt_buffer[12] = { 0 };
+ MTK_WCN_BOOL fgFail;
+
+ UINT8 WMT_SET_MCU_CLK_CMD[] = { 0x01, 0x0a, 0x04, 0x00, 0x09, 0x01, 0x00, 0x00 };
+ UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x0a, 0x01, 0x00, 0x00 };
+
+
+ WMT_INFO_FUNC("clock frequency 0x%x\n", kind);
+ WMT_SET_MCU_CLK_CMD[6] = (kind & 0xff);
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ iRet = wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize);
+ break;
+ }
+
+ iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize);
+ if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize);
+ mtk_wcn_stp_dbg_dump_package();
+ break;
+ }
+
+ if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]);
+ WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n",
+ evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ if (fgFail == MTK_WCN_BOOL_FALSE)
+ WMT_INFO_FUNC("wmt-core:set mcu clock ok!\n");
+ else
+ WMT_INFO_FUNC("wmt-core:set mcu clock fail!\n");
+
+ return fgFail;
+}
+
+static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp)
+{
+ UINT32 kind = 0;
+ UINT32 version = 0;
+ MTK_WCN_BOOL ret;
+
+ kind = pWmtOp->au4OpData[0];
+ version = pWmtOp->au4OpData[1];
+
+ switch (version) {
+ case 0:
+ ret = wmt_core_gen2_set_mcu_clk(kind);
+ break;
+ case 1:
+ ret = wmt_core_gen3_set_mcu_clk(kind);
+ break;
+ case 2:
+ ret = wmt_core_set_mcu_clk(kind);
+ break;
+ default:
+ WMT_ERR_FUNC("wmt-core: version(%d) is not support!\n", version);
+ ret = MTK_WCN_BOOL_TRUE;
+ }
+
+ return ret;
+}
+
+static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp)
+{
+ UINT8 *buffer = NULL;
+ MTK_WCN_BOOL fgFail;
+ UINT32 u4Res;
+ UINT32 aDieChipid = 0;
+ UINT8 soc_adie_chipid_cmd[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 };
+ UINT8 soc_adie_chipid_evt[] = { 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ UINT8 evtbuf[20];
+ INT32 iRet = -1;
+
+ buffer = (PUINT8) pWmtOp->au4OpData[1];
+
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ /* read A die chipid by wmt cmd */
+ iRet =
+ wmt_core_tx((PUINT8) &soc_adie_chipid_cmd[0], osal_sizeof(soc_adie_chipid_cmd), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_cmd))) {
+ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res);
+ break;
+ }
+ osal_memset(evtbuf, 0, osal_sizeof(evtbuf));
+ iRet = wmt_core_rx(evtbuf, osal_sizeof(soc_adie_chipid_evt), &u4Res);
+ if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_evt))) {
+ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res);
+ break;
+ }
+ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2);
+ osal_memcpy(buffer, &evtbuf[u4Res - 2], 2);
+ pWmtOp->au4OpData[0] = 2;
+ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid);
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ return fgFail;
+}
+
+MTK_WCN_BOOL wmt_core_trigger_stp_assert(VOID)
+{
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_WMT_CTX pctx = &gMtkWmtCtx;
+
+ if (mtk_wcn_stp_coredump_flag_get() == 0) {
+ WMT_INFO_FUNC("coredump is disabled, omit trigger STP assert\n");
+ wmt_lib_trigger_reset();
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->trigger_stp_assert != NULL)) {
+ WMT_INFO_FUNC("trigger stp assert function is supported by 0x%X\n",
+ pctx->p_ic_ops->icId);
+ bRet = (*(pctx->p_ic_ops->trigger_stp_assert)) ();
+ } else {
+ if (pctx->p_ic_ops != NULL)
+ WMT_INFO_FUNC("trigger stp assert function is not supported by 0x%X\n",
+ pctx->p_ic_ops->icId);
+ bRet = MTK_WCN_BOOL_FALSE;
+ }
+
+ return bRet;
+}
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+MTK_WCN_BOOL wmt_core_deep_sleep_ctrl(INT32 value)
+{
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_WMT_CTX pctx = &gMtkWmtCtx;
+
+ if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->deep_sleep_ctrl != NULL)) {
+ bRet = (*(pctx->p_ic_ops->deep_sleep_ctrl)) (value);
+ } else {
+ if (pctx->p_ic_ops != NULL)
+ WMT_INFO_FUNC("deep sleep function is not supported by 0x%x\n",
+ pctx->p_ic_ops->icId);
+ bRet = MTK_WCN_BOOL_FALSE;
+ }
+ return bRet;
+}
+#endif
+INT32 opfunc_pin_state(P_WMT_OP pWmtOp)
+{
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+ INT32 iRet = 0;
+
+ iRet = wmt_core_ctrl(WMT_CTRL_HW_STATE_DUMP, &ctrlPa1, &ctrlPa2);
+ return iRet;
+}
+
+#ifdef CONFIG_MTK_COMBO_ANT
+INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = 0;
+ size_t ctrlPa1 = pWmtOp->au4OpData[0];
+ UINT32 ctrlPa2 = pWmtOp->au4OpData[1];
+ PUINT8 pbuf = (PUINT8) ctrlPa1;
+ UINT32 fragSeq = 0;
+ UINT16 fragSize = 0;
+ UINT16 wmtCmdLen;
+ UINT16 wmtPktLen;
+ UINT32 u4Res = 0;
+ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_DWN_EVT)];
+#if 1
+ UINT32 ctrlPa3 = pWmtOp->au4OpData[2];
+
+ do {
+ fragSize = ctrlPa2;
+ fragSeq = ctrlPa3;
+ gAntBuf[5] = fragSeq;
+
+
+ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_DWN_CMD) + 1;
+
+ /*WMT command length cal */
+ wmtCmdLen = wmtPktLen - 4;
+#if 0
+ WMT_ANT_RAM_DWN_CMD[2] = wmtCmdLen & 0xFF;
+ WMT_ANT_RAM_DWN_CMD[3] = (wmtCmdLen & 0xFF00) >> 16;
+#else
+ osal_memcpy(&WMT_ANT_RAM_DWN_CMD[2], &wmtCmdLen, 2);
+#endif
+
+
+
+ WMT_ANT_RAM_DWN_CMD[4] = 1; /*RAM CODE download */
+
+ osal_memcpy(gAntBuf, WMT_ANT_RAM_DWN_CMD, sizeof(WMT_ANT_RAM_DWN_CMD));
+
+ /*copy ram code content to global buffer */
+ osal_memcpy(&gAntBuf[osal_sizeof(WMT_ANT_RAM_DWN_CMD) + 1], pbuf, fragSize);
+
+ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != wmtPktLen)) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ wmtPktLen, u4Res, iRet);
+ iRet = -4;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, wmtPktLen, u4Res);
+
+ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf));
+
+ WMT_ANT_RAM_DWN_EVT[4] = 0; /*download result; 0 */
+
+ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_DWN_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_DWN_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res, iRet);
+ iRet = -5;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_DWN_EVT, sizeof(WMT_ANT_RAM_DWN_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_DWN_EVT result error\n");
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3],
+ antEvtBuf[4], sizeof(WMT_ANT_RAM_DWN_EVT), WMT_ANT_RAM_DWN_EVT[0],
+ WMT_ANT_RAM_DWN_EVT[1], WMT_ANT_RAM_DWN_EVT[2], WMT_ANT_RAM_DWN_EVT[3],
+ WMT_ANT_RAM_DWN_EVT[4]);
+ iRet = -6;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_ANT_RAM_DWN_EVT), u4Res);
+
+ } while (0);
+#else
+ UINT32 patchSize = ctrlPa2;
+ UINT32 patchSizePerFrag = 1000;
+ UINT32 offset;
+ UINT32 fragNum = 0;
+ /*cal patch fragNum */
+ fragNum = (patchSize + patchSizePerFrag - 1) / patchSizePerFrag;
+ if (fragNum <= 2) {
+ WMT_WARN_FUNC("ANT ramcode size(%d) too short\n", patchSize);
+ return -1;
+ }
+
+ while (fragSeq < fragNum) {
+ /*update fragNum */
+ fragSeq++;
+
+ if (fragSeq == 1) {
+ fragSize = patchSizePerFrag;
+ /*first package */
+ gAntBuf[5] = 1; /*RAM CODE start */
+ } else if (fragNum == fragSeq) {
+ /*last package */
+ fragSize = patchSizePerFrag;
+ gAntBuf[5] = 3; /*RAM CODE end */
+ } else {
+ /*middle package */
+ fragSize = patchSize - ((fragNum - 1) * patchSizePerFrag);
+ gAntBuf[5] = 2; /*RAM CODE confinue */
+ }
+ wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_OP_CMD) + 1;
+
+ /*WMT command length cal */
+ wmtCmdLen = wmtPktLen - 4;
+
+ WMT_ANT_RAM_OP_CMD[2] = wmtCmdLen & 0xFF;
+ WMT_ANT_RAM_OP_CMD[3] = (wmtCmdLen & 0xFF00) >> 16;
+
+ WMT_ANT_RAM_OP_CMD[4] = 1; /*RAM CODE download */
+
+ osal_memcpy(gAntBuf, WMT_ANT_RAM_OP_CMD, sizeof(WMT_ANT_RAM_OP_CMD));
+
+ /*copy ram code content to global buffer */
+ osal_memcpy(&gAntBuf[6], pbuf, fragSize);
+
+ /*update offset */
+ offset += fragSize;
+ pbuf += offset;
+
+ iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != wmtPktLen)) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ wmtPktLen, u4Res, iRet);
+ iRet = -4;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, wmtPktLen, u4Res);
+
+ osal_memset(antEvtBuf, 0, sizeof(antEvtBuf));
+
+ WMT_SET_RAM_OP_EVT[4] = 0; /*download result; 0 */
+
+ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_SET_RAM_OP_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_SET_RAM_OP_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) fail(%d)\n",
+ sizeof(WMT_SET_RAM_OP_EVT), u4Res, iRet);
+ iRet = -5;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(antEvtBuf, WMT_SET_RAM_OP_EVT, sizeof(WMT_SET_RAM_OP_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_SET_RAM_OP_EVT result error\n");
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3],
+ antEvtBuf[4], sizeof(WMT_SET_RAM_OP_EVT), WMT_SET_RAM_OP_EVT[0],
+ WMT_SET_RAM_OP_EVT[1], WMT_SET_RAM_OP_EVT[2], WMT_SET_RAM_OP_EVT[3],
+ WMT_SET_RAM_OP_EVT[4]);
+ iRet = -6;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) ok\n",
+ sizeof(WMT_SET_RAM_OP_EVT), u4Res);
+
+
+ }
+ if (fragSeq != fragNum)
+ iRet = -7;
+#endif
+ return iRet;
+}
+
+
+INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = 0;
+ UINT32 u4Res = 0;
+ UINT32 wmtPktLen = osal_sizeof(WMT_ANT_RAM_STA_GET_CMD);
+ UINT32 u4AntRamStatus = 0;
+ UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_STA_GET_EVT)];
+
+
+ iRet = wmt_core_tx(WMT_ANT_RAM_STA_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != wmtPktLen)) {
+ WMT_ERR_FUNC
+ ("wmt_core: write wmt and ramcode status query command failed, (%d, %d), iRet(%d)\n",
+ wmtPktLen, u4Res, iRet);
+ iRet = -4;
+ return iRet;
+ }
+
+
+ iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_STA_GET_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_ANT_RAM_STA_GET_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_STA_GET_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_ANT_RAM_STA_GET_EVT), u4Res, iRet);
+ iRet = -5;
+ return iRet;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_STA_GET_EVT, sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1) !=
+ 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_STA_GET_EVT result error\n");
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], antEvtBuf[4],
+ sizeof(WMT_ANT_RAM_STA_GET_EVT), WMT_ANT_RAM_STA_GET_EVT[0],
+ WMT_ANT_RAM_STA_GET_EVT[1], WMT_ANT_RAM_STA_GET_EVT[2],
+ WMT_ANT_RAM_STA_GET_EVT[3], WMT_ANT_RAM_STA_GET_EVT[4]);
+ iRet = -6;
+ return iRet;
+ }
+#endif
+ if (iRet == 0) {
+ u4AntRamStatus = antEvtBuf[sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1];
+ pWmtOp->au4OpData[2] = u4AntRamStatus;
+ WMT_INFO_FUNC("ANT ram code %s\n",
+ u4AntRamStatus == 1 ? "exist already" : "not exist");
+ }
+ return iRet;
+}
+#endif
+VOID wmt_core_set_coredump_state(ENUM_DRV_STS state)
+{
+ WMT_INFO_FUNC("wmt-core: set coredump state(%d)\n", state);
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = state;
+}
+
+INT32 opfunc_flash_patch_down(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = 0;
+ PUINT8 u4pbuf = (PUINT8)pWmtOp->au4OpData[0];
+ UINT16 u4PatchSize = pWmtOp->au4OpData[1];
+ UINT32 u4PatchSeq = pWmtOp->au4OpData[2];
+ UINT32 u4PatchType = pWmtOp->au4OpData[3];
+ UINT32 u4PatchVersion = pWmtOp->au4OpData[4];
+ UINT32 u4PatchChecksum = pWmtOp->au4OpData[5];
+ UINT16 wmtCmdLen;
+ UINT16 wmtPktLen = 0;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[osal_sizeof(WMT_FLASH_PATCH_DWN_EVT)];
+ UINT32 i = 0;
+
+ do {
+ osal_memcpy(gFlashBuf, WMT_FLASH_PATCH_DWN_CMD, sizeof(WMT_FLASH_PATCH_DWN_CMD));
+
+ switch (u4PatchSeq) {
+ case WMT_FLASH_PATCH_HEAD_PKT:
+ /*WMT command length cal */
+ wmtPktLen = sizeof(WMT_FLASH_PATCH_DWN_CMD) + WMT_FLASH_PATCH_DWN_CMD[2] - 1;
+ osal_memcpy(&gFlashBuf[5], &u4PatchType, sizeof(u4PatchType));
+ osal_memcpy(&gFlashBuf[9], &u4PatchVersion, sizeof(u4PatchVersion));
+ osal_memcpy(&gFlashBuf[13], &u4PatchChecksum, sizeof(u4PatchChecksum));
+ break;
+ case WMT_FLASH_PATCH_START_PKT:
+ case WMT_FLASH_PATCH_CONTINUE_PKT:
+ case WMT_FLASH_PATCH_END_PKT:
+ gFlashBuf[4] = u4PatchSeq;
+ /*WMT command length cal */
+ wmtCmdLen = u4PatchSize + 1;
+ wmtPktLen = u4PatchSize + sizeof(WMT_FLASH_PATCH_DWN_CMD);
+ gFlashBuf[2] = wmtCmdLen & 0xFF;
+ gFlashBuf[3] = (wmtCmdLen & 0xFF00) >> 8;
+ /*copy ram code content to global buffer */
+ osal_memcpy(&gFlashBuf[osal_sizeof(WMT_FLASH_PATCH_DWN_CMD)], u4pbuf, u4PatchSize);
+ break;
+ default:
+ break;
+ }
+
+ iRet = wmt_core_tx(gFlashBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != wmtPktLen)) {
+ WMT_ERR_FUNC("wmt_core: write PatchSeq(%d) size(%d, %d) fail(%d)\n", u4PatchSeq,
+ wmtPktLen, u4Res, iRet);
+ iRet = -4;
+ u4Res = -1;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write PatchSeq(%d) size(%d, %d) ok\n",
+ u4PatchSeq, wmtPktLen, u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+
+ /* flash patch download time longer than WMT command timeout */
+ for (i = 0; i < 3; i++) {
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_FLASH_PATCH_DWN_EVT), &u4Res);
+ if (!iRet)
+ break;
+ }
+ if (iRet || (u4Res != sizeof(WMT_FLASH_PATCH_DWN_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_FLASH_PATCH_DWN_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_FLASH_PATCH_DWN_EVT), u4Res, iRet);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 39);
+
+ iRet = -5;
+ u4Res = -2;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_FLASH_PATCH_DWN_EVT, sizeof(WMT_FLASH_PATCH_DWN_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_FLASH_PATCH_DWN_EVT result error\n");
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_FLASH_PATCH_DWN_EVT), WMT_FLASH_PATCH_DWN_EVT[0],
+ WMT_FLASH_PATCH_DWN_EVT[1], WMT_FLASH_PATCH_DWN_EVT[2],
+ WMT_FLASH_PATCH_DWN_EVT[3], WMT_FLASH_PATCH_DWN_EVT[4]);
+ iRet = -6;
+ u4Res = -3;
+ break;
+ }
+#endif
+ u4Res = 0;
+ WMT_DBG_FUNC("wmt_core: read WMT_FLASH_PATCH_DWN_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_FLASH_PATCH_DWN_EVT), u4Res);
+
+ } while (0);
+
+ pWmtOp->au4OpData[6] = u4Res;
+ return iRet;
+}
+
+INT32 opfunc_flash_patch_ver_get(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = 0;
+ UINT32 u4Res = 0;
+ UINT32 wmtPktLen = osal_sizeof(WMT_FLASH_PATCH_VER_GET_CMD);
+ UINT32 u4PatchType = pWmtOp->au4OpData[3];
+ UINT32 u4PatchVer = 0;
+ UINT8 evtBuf[osal_sizeof(WMT_FLASH_PATCH_VER_GET_EVT)];
+
+ do {
+ osal_memcpy(&WMT_FLASH_PATCH_VER_GET_CMD[5], &u4PatchType, sizeof(u4PatchType));
+
+ iRet = wmt_core_tx(WMT_FLASH_PATCH_VER_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != wmtPktLen)) {
+ WMT_ERR_FUNC
+ ("wmt_core: write wmt and flash patch query command failed, (%d, %d), iRet(%d)\n",
+ wmtPktLen, u4Res, iRet);
+ iRet = -4;
+ u4Res = -1;
+ break;
+ }
+
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_FLASH_PATCH_VER_GET_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_FLASH_PATCH_VER_GET_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_FLASH_PATCH_VER_GET_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_FLASH_PATCH_VER_GET_EVT), u4Res, iRet);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 38);
+
+ iRet = -5;
+ u4Res = -2;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_FLASH_PATCH_VER_GET_EVT,
+ sizeof(WMT_FLASH_PATCH_VER_GET_EVT) - 8) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_FLASH_PATCH_VER_GET_EVT result error\n");
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_FLASH_PATCH_VER_GET_EVT), WMT_FLASH_PATCH_VER_GET_EVT[0],
+ WMT_FLASH_PATCH_VER_GET_EVT[1], WMT_FLASH_PATCH_VER_GET_EVT[2],
+ WMT_FLASH_PATCH_VER_GET_EVT[3], WMT_FLASH_PATCH_VER_GET_EVT[4]);
+ iRet = -6;
+ u4Res = -3;
+ break;
+ }
+#endif
+ if (iRet == 0) {
+ osal_memcpy(&u4PatchVer, &evtBuf[9], sizeof(u4PatchVer));
+ pWmtOp->au4OpData[4] = u4PatchVer;
+ u4Res = 0;
+ WMT_INFO_FUNC("flash patch type: %x, flash patch version %x\n",
+ u4PatchType, u4PatchVer);
+ }
+ } while (0);
+
+ pWmtOp->au4OpData[6] = u4Res;
+ return iRet;
+}
+
+#if CFG_WMT_LTE_COEX_HANDLING
+static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp)
+{
+ MTK_WCN_BOOL fgFail;
+ UINT32 u4Res;
+ UINT8 host_lte_btwf_coex_cmd[] = { 0x01, 0x10, 0x00, 0x00, 0x00 };
+ UINT8 host_lte_btwf_coex_evt[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+ UINT8 *pTxBuf = NULL;
+ UINT8 evtbuf[8] = { 0 };
+ INT32 iRet = -1;
+ UINT16 msg_len = 0;
+ UINT32 total_len = 0;
+ UINT32 index = 0;
+ UINT32 evtLen;
+
+ pTxBuf = (UINT8 *) pWmtOp->au4OpData[0];
+ if (pTxBuf == NULL) {
+ WMT_ERR_FUNC("idc msg buffer is NULL\n");
+ return -1;
+ }
+ iRet = wmt_lib_idc_lock_aquire();
+ if (iRet) {
+ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", iRet);
+ return iRet;
+ }
+ osal_memcpy(&msg_len, &pTxBuf[0], osal_sizeof(msg_len));
+ if (msg_len > WMT_IDC_MSG_MAX_SIZE) {
+ wmt_lib_idc_lock_release();
+ WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len);
+ return -2;
+ }
+ msg_len += 1; /*flag byte */
+ osal_memcpy(&host_lte_btwf_coex_cmd[2], &msg_len, 2);
+ host_lte_btwf_coex_cmd[4] = (pWmtOp->au4OpData[1] & 0x00ff);
+ osal_memcpy(&msg_local_buffer[0], &host_lte_btwf_coex_cmd[0],
+ osal_sizeof(host_lte_btwf_coex_cmd));
+ osal_memcpy(&msg_local_buffer[osal_sizeof(host_lte_btwf_coex_cmd)],
+ &pTxBuf[osal_sizeof(msg_len)], msg_len - 1);
+ wmt_lib_idc_lock_release();
+ total_len = osal_sizeof(host_lte_btwf_coex_cmd) + msg_len - 1;
+ WMT_DBG_FUNC("wmt_core:idc msg payload len form lte(%d),wmt msg total len(%d)\n",
+ msg_len - 1, total_len);
+ WMT_DBG_FUNC("wmt_core:idc msg payload:\n");
+ for (index = 0; index < total_len; index++)
+ WMT_DBG_FUNC("0x%02x ", msg_local_buffer[index]);
+ do {
+ fgFail = MTK_WCN_BOOL_TRUE;
+
+ /* read A die chipid by wmt cmd */
+ iRet =
+ wmt_core_tx((PUINT8) &msg_local_buffer[0], total_len, &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != total_len)) {
+ WMT_ERR_FUNC("wmt_core:send lte idc msg to connsys fail(%d),size(%d)\n",
+ iRet, u4Res);
+ break;
+ }
+ osal_memset(evtbuf, 0, osal_sizeof(evtbuf));
+ evtLen = osal_sizeof(host_lte_btwf_coex_evt);
+ iRet = wmt_core_rx(evtbuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("wmt_core:recv host_lte_btwf_coex_evt fail(%d) len(%d, %d)\n",
+ iRet, u4Res, evtLen);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 41);
+ break;
+ }
+
+ fgFail = MTK_WCN_BOOL_FALSE;
+
+ } while (0);
+
+ return fgFail;
+}
+
+/*TEST CODE*/
+VOID wmt_core_set_flag_for_test(UINT32 enable)
+{
+ WMT_INFO_FUNC("%s wmt_lte_flag\n", enable ? "enable" : "disable");
+ g_open_wmt_lte_flag = enable;
+}
+
+UINT32 wmt_core_get_flag_for_test(VOID)
+{
+ return g_open_wmt_lte_flag;
+}
+
+#endif
+
+static INT32 opfunc_utc_time_sync(P_WMT_OP pWmtOp)
+{
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ INT32 iRet;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+ UINT32 tsec;
+ UINT32 tusec;
+
+ connsys_dedicated_log_get_utc_time(&tsec, &tusec);
+ /* UTC time second unit */
+ osal_memcpy(&WMT_UTC_SYNC_CMD[5], &tsec, 4);
+ /* UTC time microsecond unit */
+ osal_memcpy(&WMT_UTC_SYNC_CMD[9], &tusec, 4);
+
+ /* send command */
+ iRet = wmt_core_tx(WMT_UTC_SYNC_CMD, sizeof(WMT_UTC_SYNC_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet) {
+ WMT_ERR_FUNC("Tx WMT_UTC_SYNC_CMD fail!(%d) len (%d, %zu)\n",
+ iRet, u4Res, sizeof(WMT_UTC_SYNC_CMD));
+ return -1;
+ }
+
+ /* receive event */
+ evtLen = osal_sizeof(WMT_UTC_SYNC_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("WMT-CORE: read WMT_UTC_SYNC_EVT fail(%d) len(%d, %d)\n",
+ iRet, u4Res, evtLen);
+ osal_assert(0);
+ return iRet;
+ }
+
+ if (osal_memcmp(evtBuf, WMT_UTC_SYNC_EVT,
+ osal_sizeof(WMT_UTC_SYNC_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: compare WMT_UTC_SYNC_EVT error\n");
+ WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]);
+ WMT_ERR_FUNC("WMT-CORE: exp(%zu):[%02X,%02X,%02X,%02X,%02X,%02X]\n",
+ osal_sizeof(WMT_UTC_SYNC_EVT), WMT_UTC_SYNC_EVT[0],
+ WMT_UTC_SYNC_EVT[1], WMT_UTC_SYNC_EVT[2], WMT_UTC_SYNC_EVT[3],
+ WMT_UTC_SYNC_EVT[4], WMT_UTC_SYNC_EVT[5]);
+ } else {
+ WMT_INFO_FUNC("Send WMT_UTC_SYNC_CMD command OK!\n");
+ }
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+static INT32 opfunc_fw_log_ctrl(P_WMT_OP pWmtOp)
+{
+ INT32 iRet;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[osal_sizeof(WMT_FW_LOG_CTRL_EVT)];
+
+ /* fill command parameters */
+ WMT_FW_LOG_CTRL_CMD[5] = (UINT8)pWmtOp->au4OpData[0]; /* type */
+ WMT_FW_LOG_CTRL_CMD[6] = (UINT8)pWmtOp->au4OpData[1]; /* on/off */
+ WMT_FW_LOG_CTRL_CMD[7] = (UINT8)pWmtOp->au4OpData[2]; /* log level */
+
+ /* send command */
+ iRet = wmt_core_tx(WMT_FW_LOG_CTRL_CMD, sizeof(WMT_FW_LOG_CTRL_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet) {
+ WMT_ERR_FUNC("Tx WMT_FW_LOG_CTRL_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res,
+ sizeof(WMT_FW_LOG_CTRL_CMD));
+ return -1;
+ }
+
+ /* receive event */
+ evtLen = osal_sizeof(WMT_FW_LOG_CTRL_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("WMT-CORE: read WMT_FW_LOG_CTRL_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen);
+ osal_assert(0);
+ return iRet;
+ }
+
+ if (osal_memcmp(evtBuf, WMT_FW_LOG_CTRL_EVT, evtLen) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: compare WMT_FW_LOG_CTRL_EVT error\n");
+ WMT_ERR_FUNC("WMT-CORE: tx(%zu):[%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ osal_sizeof(WMT_FW_LOG_CTRL_CMD), WMT_FW_LOG_CTRL_CMD[0], WMT_FW_LOG_CTRL_CMD[1],
+ WMT_FW_LOG_CTRL_CMD[2], WMT_FW_LOG_CTRL_CMD[3], WMT_FW_LOG_CTRL_CMD[4],
+ WMT_FW_LOG_CTRL_CMD[5], WMT_FW_LOG_CTRL_CMD[6], WMT_FW_LOG_CTRL_CMD[7]);
+ WMT_ERR_FUNC("WMT-CORE: rx(%u):[%02x,%02x,%02x,%02x,%02x]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4]);
+ } else {
+ WMT_INFO_FUNC("Send WMT_FW_LOG_CTRL_EVT command OK!\n");
+ }
+ return 0;
+}
+
+static INT32 opfunc_wlan_probe(P_WMT_OP pWmtOp)
+{
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ INT32 iRet;
+ UINT32 drvType = pWmtOp->au4OpData[0];
+
+
+ iRet = wmt_lib_wlan_lock_aquire();
+ atomic_set(&g_wifi_on_off_ready, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet);
+ return iRet;
+ }
+
+ if (gMtkWmtCtx.eDrvStatus[drvType] == DRV_STS_FUNC_ON) {
+ WMT_WARN_FUNC("func(%d) already on\n", drvType);
+ iRet = 0;
+ wmt_lib_wlan_lock_release();
+ goto done;
+ }
+
+ if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_UART) {
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO1;
+ ctrlPa2 = 1; /* turn on SDIO1 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("turn on SLOT_SDIO1 fail (%d)\n",
+ iRet);
+ osal_assert(0);
+ } else {
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] =
+ DRV_STS_FUNC_ON;
+ }
+ } else if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) {
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] == DRV_STS_FUNC_ON) {
+ WMT_DBG_FUNC("SLOT_SDIO2 ready for WIFI\n");
+ } else {
+ /* SDIO2 slot power shall be either turned on in STP init
+ * procedures already, or failed in STP init before. Here is
+ * the assert condition.
+ **/
+ WMT_ERR_FUNC("turn on Wi-Fi SDIO2 but SDIO in FUNC_OFF state(0x%x)\n",
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2]);
+ osal_assert(0);
+ iRet = -4;
+ wmt_lib_wlan_lock_release();
+ goto done;
+ }
+ } else {
+ WMT_ERR_FUNC("not implemented yet hifType: 0x%x, unspecified wifi_hif\n",
+ gMtkWmtCtx.wmtHifConf.hifType);
+ /* TODO: Wi-Fi/WMT uses other interfaces. NOT IMPLEMENTED YET! */
+ }
+
+ iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+ if (iRet != 0) {
+ if (WMT_HIF_UART == gMtkWmtCtx.wmtHifConf.hifType) {
+ /*need to power SDIO off when Power on Wi-Fi fail, in case of power leakage and
+ * right SDIO power status maintain
+ */
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO1;
+ ctrlPa2 = 0; /* turn off SDIO1 slot */
+ wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ /* does not need to check turn off result */
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF;
+ }
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+ } else
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON;
+
+ /* wlan_lock must release before try_pwr_off */
+ wmt_lib_wlan_lock_release();
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet);
+ /* FIX-ME:[Chaozhong Liang], Error handling? check subsystem state and do pwr off if necessary? */
+ /* check all sub-func and do power off */
+ wmt_lib_try_pwr_off();
+ }
+
+done:
+ wmt_core_dump_func_state("AF FUNC ON");
+ return iRet;
+}
+
+static INT32 opfunc_wlan_remove(P_WMT_OP pWmtOp)
+{
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ INT32 iRet;
+ UINT32 drvType = pWmtOp->au4OpData[0];
+
+ iRet = wmt_lib_wlan_lock_aquire();
+ atomic_set(&g_wifi_on_off_ready, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet);
+ return iRet;
+ }
+
+ if (gMtkWmtCtx.eDrvStatus[drvType] != DRV_STS_FUNC_ON) {
+ WMT_WARN_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n",
+ drvType, gMtkWmtCtx.eDrvStatus[drvType]);
+ iRet = 0;
+ wmt_lib_wlan_lock_release();
+ goto done;
+ }
+
+ iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg());
+
+ if (WMT_HIF_UART == gMtkWmtCtx.wmtHifConf.hifType) {
+ UINT32 iRet = 0;
+
+ ctrlPa1 = WMT_SDIO_SLOT_SDIO1;
+ ctrlPa2 = 0; /* turn off SDIO1 slot */
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: turn on SLOT_SDIO1 fail (%d)\n",
+ iRet);
+ osal_assert(0);
+ }
+ /* Anyway, turn SDIO1 state to POWER_OFF state */
+ gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF;
+ }
+
+ gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF;
+
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet);
+ osal_assert(0);
+ /* no matter subsystem function control fail or not, chip should be powered off
+ * when no subsystem is active
+ * return iRet;
+ */
+ }
+
+ /* wlan_lock must release before try_pwr_off */
+ wmt_lib_wlan_lock_release();
+ /* check all sub-func and do power off */
+ wmt_lib_try_pwr_off();
+
+done:
+ wmt_core_dump_func_state("AF FUNC OFF");
+ return iRet;
+}
+
+static INT32 opfunc_try_pwr_off(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = 0;
+ UINT32 drvType = pWmtOp->au4OpData[0];
+
+ if (atomic_read(&g_wifi_on_off_ready) == 1) {
+ WMT_INFO_FUNC("wlan on/off procedure will be started, do not power off now.\n");
+ return iRet;
+ }
+
+ /* Why it can use try lock?
+ * Because only wmtd_worker_thread get wlan lock for wifi on/off in current design.
+ * It means it can decide whether to do Connsys power off after Wifi function on/off complete.
+ */
+ if (wmt_lib_wlan_lock_trylock() == 0) {
+ WMT_INFO_FUNC("Can't lock wlan mutex which might be held by wlan on/off procedure.\n");
+ return iRet;
+ }
+
+ if ((gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPSL5] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT] == DRV_STS_POWER_OFF) &&
+ (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] == DRV_STS_POWER_OFF)) {
+ WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType);
+ mtk_wcn_wmt_system_state_reset();
+ iRet = opfunc_pwr_off(pWmtOp);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n",
+ iRet, drvType);
+ osal_assert(0);
+ }
+ }
+ wmt_lib_wlan_lock_release();
+ return iRet;
+}
+
+static INT32 opfunc_gps_mcu_ctrl(P_WMT_OP pWmtOp)
+{
+ INT32 iRet = -1;
+ UINT32 u4WrittenSize = 0;
+ UINT32 u4ReadSize = 0;
+ INT32 fgFail = -1;
+ PUINT8 p_tx_data_buf;
+ UINT32 tx_data_len;
+ PUINT8 p_rx_data_buf;
+ UINT32 rx_data_buf_len;
+ PUINT32 p_rx_data_len;
+ UINT8 WMT_GPS_MCU_CTRL_CMD[] = {0x01, 0x32, 0x00, 0x00};
+ PUINT8 p_tx_buf = NULL;
+ PUINT8 p_rx_buf = NULL;
+
+ p_tx_data_buf = (PUINT8)pWmtOp->au4OpData[0];
+ tx_data_len = pWmtOp->au4OpData[1];
+ p_rx_data_buf = (PUINT8)pWmtOp->au4OpData[2];
+ rx_data_buf_len = pWmtOp->au4OpData[3];
+ p_rx_data_len = (PINT32)(pWmtOp->au4OpData[4]);
+
+ if ((!p_tx_data_buf) || (tx_data_len == 0) || (!p_rx_data_buf) || (rx_data_buf_len == 0)) {
+ pWmtOp->au4OpData[5] = -1;
+ WMT_ERR_FUNC("Parameter error!\n");
+ return fgFail;
+ }
+
+ p_tx_buf = osal_malloc(tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD));
+ if (!p_tx_buf) {
+ pWmtOp->au4OpData[5] = -2;
+ WMT_ERR_FUNC("p_tx_buf alloc fail!\n");
+ return fgFail;
+ }
+
+ p_rx_buf = osal_malloc(rx_data_buf_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD));
+ if (!p_rx_buf) {
+ osal_free(p_tx_buf);
+ pWmtOp->au4OpData[5] = -3;
+ WMT_ERR_FUNC("p_rx_buf alloc fail!\n");
+ return fgFail;
+ }
+
+ WMT_GPS_MCU_CTRL_CMD[2] = (tx_data_len & 0x000000ff);
+ WMT_GPS_MCU_CTRL_CMD[3] = ((tx_data_len & 0x0000ff00) >> 8);
+ osal_memcpy(p_tx_buf, WMT_GPS_MCU_CTRL_CMD, osal_sizeof(WMT_GPS_MCU_CTRL_CMD));
+ osal_memcpy(p_tx_buf + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), p_tx_data_buf, tx_data_len);
+
+ do {
+
+ iRet = wmt_core_tx(p_tx_buf, tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), &u4WrittenSize,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4WrittenSize != (tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD)))) {
+ WMT_ERR_FUNC("gps mcu ctrl tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize);
+ break;
+ }
+
+ iRet = wmt_core_rx(p_rx_buf, rx_data_buf_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD),
+ &u4ReadSize);
+ if (iRet || (p_rx_buf[1] != WMT_GPS_MCU_CTRL_CMD[1])) {
+ WMT_ERR_FUNC("gps mcu ctrl rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize);
+ break;
+ }
+ *p_rx_data_len = (p_rx_buf[2] | (p_rx_buf[3] << 8));
+ osal_memcpy(p_rx_data_buf, p_rx_buf + osal_sizeof(WMT_GPS_MCU_CTRL_CMD),
+ *p_rx_data_len > rx_data_buf_len ? rx_data_buf_len : *p_rx_data_len);
+
+ fgFail = 0;
+ } while (0);
+
+ osal_free(p_tx_buf);
+ osal_free(p_rx_buf);
+
+ return fgFail;
+}
+
+P_WMT_GEN_CONF wmt_get_gen_conf_pointer(VOID)
+{
+ P_WMT_GEN_CONF pWmtGenConf = NULL;
+
+ pWmtGenConf = wmt_conf_get_cfg();
+ return pWmtGenConf;
+}
+
+VOID wmt_core_set_blank_status(UINT32 on_off_flag)
+{
+ gMtkWmtCtx.wmtBlankStatus = on_off_flag;
+}
+
+UINT32 wmt_core_get_blank_status(VOID)
+{
+ return gMtkWmtCtx.wmtBlankStatus;
+}
+
+INT32 wmt_blank_status_ctrl(UINT32 on_off_flag)
+{
+ INT32 iRet = 0;
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+
+ WMT_BLANK_STATUS_CMD[5] = (on_off_flag) ? 0x1 : 0x0;
+
+ /* send command */
+ iRet = wmt_core_tx((PUINT8)WMT_BLANK_STATUS_CMD, osal_sizeof(WMT_BLANK_STATUS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != osal_sizeof(WMT_BLANK_STATUS_CMD))) {
+ WMT_ERR_FUNC("WMT-CORE: WMT_BLANK_STATUS_CMD iRet(%d) cmd len err(%d, %zu)\n",
+ (iRet == 0 ? -1 : iRet), u4Res, osal_sizeof(WMT_BLANK_STATUS_CMD));
+ return iRet;
+ }
+
+ evtLen = osal_sizeof(WMT_BLANK_STATUS_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if (iRet || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("WMT-CORE: read WMT_BLANK_STATUS_EVT fail(%d) len(%d, %d)\n",
+ iRet, u4Res, evtLen);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ WMT_BLANK_STATUS_EVT[0], WMT_BLANK_STATUS_EVT[1],
+ WMT_BLANK_STATUS_EVT[2], WMT_BLANK_STATUS_EVT[3],
+ WMT_BLANK_STATUS_EVT[4]);
+ }
+ else
+ wmt_lib_set_blank_status(WMT_BLANK_STATUS_CMD[5]);
+#endif
+ return iRet;
+}
+
+static INT32 opfunc_blank_status_ctrl(P_WMT_OP pWmtOp)
+{
+ return wmt_blank_status_ctrl(pWmtOp->au4OpData[0]);
+}
+
+static INT32 opfunc_met_ctrl(P_WMT_OP pWmtOp)
+{
+ INT32 iRet;
+ UINT32 u4Res;
+ UINT32 evtLen;
+ UINT8 evtBuf[16] = { 0 };
+ UINT32 value;
+ UINT8 WMT_MET_CTRL_CMD[] = { 0x01, 0x31, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00};
+ UINT8 WMT_MET_CTRL_EVT[] = { 0x02, 0x31, 0x01, 0x00, 0x00 };
+
+ value = pWmtOp->au4OpData[0];
+ WMT_MET_CTRL_CMD[5] = (value & 0x000000ff);
+ WMT_MET_CTRL_CMD[6] = (value & 0x0000ff00) >> 8;
+ WMT_MET_CTRL_CMD[7] = (value & 0x00ff0000) >> 16;
+ WMT_MET_CTRL_CMD[8] = (value & 0xff000000) >> 24;
+
+ /* send command */
+ iRet = wmt_core_tx(WMT_MET_CTRL_CMD, sizeof(WMT_MET_CTRL_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if ((iRet) || (u4Res != sizeof(WMT_MET_CTRL_CMD))) {
+ WMT_ERR_FUNC("Tx MET_CTRL_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res,
+ sizeof(WMT_MET_CTRL_CMD));
+ return -2;
+ }
+
+ /* receive event */
+ evtLen = sizeof(WMT_MET_CTRL_EVT);
+ iRet = wmt_core_rx(evtBuf, evtLen, &u4Res);
+ if ((iRet) || (u4Res != evtLen)) {
+ WMT_ERR_FUNC("Rx MET_CTRL_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen);
+ mtk_wcn_stp_dbg_dump_package();
+ wmt_core_trigger_assert();
+ return -3;
+ }
+
+ return 0;
+}
+
+static INT32 opfunc_get_consys_state(P_WMT_OP pWmtOp)
+{
+ INT32 ret = 0, i;
+ INT32 times = 0, slp_ms;
+ P_CONSYS_STATE_DMP_OP dmp_op = (P_CONSYS_STATE_DMP_OP)pWmtOp->au4OpData[0];
+ ULONG ver = (ULONG)pWmtOp->au4OpData[1];
+
+ osal_lock_sleepable_lock(&dmp_op->lock);
+ if (dmp_op->status == WMT_DUMP_STATE_NONE
+ || dmp_op->version != ver) {
+ ret = -1;
+ goto done;
+ }
+
+ /* WMT should be ON */
+ if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) {
+ WMT_INFO_FUNC("WMT is not on");
+ ret = -1;
+ goto done;
+ }
+
+ if (mtk_wcn_consys_sleep_info_read_all_ctrl(&dmp_op->dmp_info.state) != 0)
+ ret = -1;
+
+ /* Consys register should be readable */
+ if (mtk_consys_check_reg_readable() == 0) {
+ WMT_INFO_FUNC("cr cannot readable");
+ ret = -1;
+ goto done;
+ }
+
+ times = dmp_op->times;
+ slp_ms = dmp_op->cpu_sleep_ms;
+
+ /* dmp cpu_pcr */
+ for (i = 0; i < times; i++) {
+ dmp_op->dmp_info.cpu_pcr[i] = wmt_plat_read_cpupcr();
+ if (slp_ms > 0)
+ osal_sleep_ms(slp_ms);
+ }
+
+ ret = mtk_consys_dump_osc_state(&dmp_op->dmp_info.state);
+ if (ret != MTK_WCN_BOOL_TRUE)
+ ret = -2;
+
+ ret = mtk_wcn_consys_dump_gating_state(&dmp_op->dmp_info.state);
+ if (ret != MTK_WCN_BOOL_TRUE)
+ ret = -3;
+
+done:
+ osal_unlock_sleepable_lock(&dmp_op->lock);
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f94dd002bd6c53d82347004a6e7696b2325d500
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c
@@ -0,0 +1,1197 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-CTRL]"
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "osal.h"
+
+#include "wmt_ctrl.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "wmt_dev.h"
+#include "wmt_plat.h"
+#include "hif_sdio.h"
+#include "stp_core.h"
+#include "stp_dbg.h"
+#include "wmt_ic.h"
+#include "wmt_step.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+/* moved to wmt_ctrl.h */
+/*static INT32 wmt_ctrl_tx_ex (UINT8 *pData, UINT32 size, UINT32 *writtenSize, MTK_WCN_BOOL bRawFlag);*/
+
+static INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value);
+
+static INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_others(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData);
+static INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData);
+static INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData);
+static INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_trg_assert(P_WMT_CTRL_DATA);
+static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData);
+#if CFG_WMT_LTE_COEX_HANDLING
+static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA);
+#endif
+
+static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData);
+
+static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData);
+
+static INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData);
+
+static INT32 wmt_ctrl_get_rom_patch_info(P_WMT_CTRL_DATA pWmtCtrlData);
+
+static INT32 wmt_ctrl_update_patch_version(P_WMT_CTRL_DATA);
+
+/* TODO: [FixMe][GeorgeKuo]: remove unused function */
+/*static INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA);*/
+
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/* GeorgeKuo: Use designated initializers described in
+ * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html
+ */
+static const WMT_CTRL_FUNC wmt_ctrl_func[] = {
+ [WMT_CTRL_HW_PWR_OFF] = wmt_ctrl_hw_pwr_off,
+ [WMT_CTRL_HW_PWR_ON] = wmt_ctrl_hw_pwr_on,
+ [WMT_CTRL_HW_RST] = wmt_ctrl_hw_rst,
+ [WMT_CTRL_STP_CLOSE] = wmt_ctrl_stp_close,
+ [WMT_CTRL_STP_OPEN] = wmt_ctrl_stp_open,
+ [WMT_CTRL_STP_CONF] = wmt_ctrl_stp_conf,
+ [WMT_CTRL_FREE_PATCH] = wmt_ctrl_free_patch,
+ [WMT_CTRL_GET_PATCH] = wmt_ctrl_get_patch,
+ [WMT_CTRL_GET_PATCH_NAME] = wmt_ctrl_get_patch_name,
+ [WMT_CTRL_HOST_BAUDRATE_SET] = wmt_ctrl_host_baudrate_set,
+ [WMT_CTRL_SDIO_HW] = wmt_ctrl_sdio_hw,
+ [WMT_CTRL_SDIO_FUNC] = wmt_ctrl_sdio_func,
+ [WMT_CTRL_HWIDVER_SET] = wmt_ctrl_hwidver_set,
+ [WMT_CTRL_HWVER_GET] = NULL, /* TODO: [FixMe][GeorgeKuo]: remove unused function. */
+ [WMT_CTRL_STP_RST] = wmt_ctrl_stp_rst,
+ [WMT_CTRL_GET_WMT_CONF] = wmt_ctrl_get_wmt_conf,
+ [WMT_CTRL_TX] = wmt_ctrl_tx,
+ [WMT_CTRL_RX] = wmt_ctrl_rx,
+ [WMT_CTRL_RX_FLUSH] = wmt_ctrl_rx_flush,
+ [WMT_CTRL_GPS_SYNC_SET] = wmt_ctrl_gps_sync_set,
+ [WMT_CTRL_GPS_LNA_SET] = wmt_ctrl_gps_lna_set,
+ [WMT_CTRL_PATCH_SEARCH] = wmt_ctrl_patch_search,
+ [WMT_CTRL_CRYSTAL_TRIMING_GET] = wmt_ctrl_crystal_triming_get,
+ [WMT_CTRL_CRYSTAL_TRIMING_PUT] = wmt_ctrl_crystal_triming_put,
+ [WMT_CTRL_HW_STATE_DUMP] = wmt_ctrl_hw_state_show,
+ [WMT_CTRL_GET_PATCH_NUM] = wmt_ctrl_get_patch_num,
+ [WMT_CTRL_GET_PATCH_INFO] = wmt_ctrl_get_patch_info,
+ [WMT_CTRL_SOC_PALDO_CTRL] = wmt_ctrl_soc_paldo_ctrl,
+ [WMT_CTRL_SOC_WAKEUP_CONSYS] = wmt_ctrl_soc_wakeup_consys,
+ [WMT_CTRL_SET_STP_DBG_INFO] = wmt_ctrl_set_stp_dbg_info,
+ [WMT_CTRL_BGW_DESENSE_CTRL] = wmt_ctrl_bgw_desense_ctrl,
+ [WMT_CTRL_TRG_ASSERT] = wmt_ctrl_trg_assert,
+ #if CFG_WMT_LTE_COEX_HANDLING
+ [WMT_CTRL_GET_TDM_REQ_ANTSEL] = wmt_ctrl_get_tdm_req_antsel,
+#endif
+ [WMT_CTRL_EVT_PARSER] = wmt_ctrl_evt_parser,
+ [WMT_CTRL_GET_ROM_PATCH_INFO] = wmt_ctrl_get_rom_patch_info,
+ [WMT_CTRL_UPDATE_PATCH_VERSION] = wmt_ctrl_update_patch_version,
+ [WMT_CTRL_MAX] = wmt_ctrl_others,
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+INT32 __weak mtk_wcn_consys_stp_btif_parser_wmt_evt(const PUINT8 str, UINT32 len)
+{
+ return 0;
+}
+
+INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ UINT32 ctrlId = 0;
+
+ if (pWmtCtrlData == NULL) {
+ osal_assert(0);
+ return -1;
+ }
+
+ ctrlId = pWmtCtrlData->ctrlId;
+ /*1sanity check, including wmtCtrlId */
+ if ((pWmtCtrlData == NULL)
+ || (ctrlId >= WMT_CTRL_MAX))
+ /* || (ctrlId < WMT_CTRL_HW_PWR_OFF) ) [FixMe][GeorgeKuo]: useless comparison */
+ {
+ osal_assert(pWmtCtrlData != NULL);
+ osal_assert(ctrlId < WMT_CTRL_MAX);
+ /* osal_assert(ctrlId >= WMT_CTRL_HW_PWR_OFF); [FixMe][GeorgeKuo]: useless comparison */
+ return -2;
+ }
+ /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */
+ if (wmt_ctrl_func[ctrlId]) {
+ /*call servicd handling API */
+ return (*(wmt_ctrl_func[ctrlId])) (pWmtCtrlData); /* serviceHandlerPack[ctrlId].serviceHandler */
+ }
+ osal_assert(wmt_ctrl_func[ctrlId] != NULL);
+ return -3;
+}
+
+INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pData, UINT32 size, UINT32 *writtenSize */)
+{
+ PUINT8 pData = (PUINT8) pWmtCtrlData->au4CtrlData[0];
+ UINT32 size = pWmtCtrlData->au4CtrlData[1];
+ PUINT32 writtenSize = (PUINT32) pWmtCtrlData->au4CtrlData[2];
+ MTK_WCN_BOOL bRawFlag = pWmtCtrlData->au4CtrlData[3];
+
+ return wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag);
+}
+
+static VOID wmt_ctrl_show_sched_stats_log(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS pSchedstats)
+{
+ if ((pThread) && (pThread->pThread) && (pSchedstats))
+ WMT_ERR_FUNC("WMT rx_timeout, pid[%d/%s] stats duration:%llums, sched(x%llu/r%llu/i%llu)\n",
+ pThread->pThread->pid,
+ pThread->threadName,
+ pSchedstats->time,
+ pSchedstats->exec,
+ pSchedstats->runnable,
+ pSchedstats->iowait);
+}
+
+INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pBuff, UINT32 buffLen, UINT32 *readSize */)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 readLen;
+ INT32 waitRet = -1;
+ INT32 loopCnt = 1;
+ INT32 leftCnt;
+ PUINT8 pBuff = (PUINT8) pWmtCtrlData->au4CtrlData[0];
+ UINT32 buffLen = pWmtCtrlData->au4CtrlData[1];
+ PUINT32 readSize = (PUINT32) pWmtCtrlData->au4CtrlData[2];
+ INT32 stpRxState;
+ INT32 extended = 0;
+ P_OSAL_THREAD p_rx_thread = NULL;
+ OSAL_THREAD_SCHEDSTATS schedstats;
+
+ if (readSize)
+ *readSize = 0;
+
+ /* sanity check */
+ if (!buffLen) {
+ WMT_WARN_FUNC("buffLen = 0\n");
+ osal_assert(buffLen);
+ return 0;
+ }
+
+ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) {
+ WMT_WARN_FUNC("state(0x%lx)\n", pDev->state.data);
+ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state));
+ return -2;
+ }
+ if (wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON)
+ loopCnt = 4;
+ leftCnt = loopCnt;
+
+ /* sanity ok, proceeding rx operation */
+ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX);
+ p_rx_thread = mtk_stp_rx_thread_get();
+ osal_thread_sched_mark(p_rx_thread, &schedstats);
+
+ while (readLen == 0 && leftCnt > 0) { /* got nothing, wait for STP's signal */
+ /* if assert happen, do not wait for any signal again */
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 1
+ && mtk_wcn_stp_is_wmt_last_close() == 0)
+ break;
+ pDev->rWmtRxWq.timeoutValue = WMT_LIB_RX_TIMEOUT/loopCnt;
+ waitRet = wmt_dev_rx_timeout(&pDev->rWmtRxWq);
+ if (waitRet == 0) {
+ leftCnt--;
+ /* dump btif_rxd's backtrace to check whether it is blocked or not */
+ osal_dump_thread_state("btif_rxd");
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ if (!mtk_wcn_stp_is_sdio_mode())
+ mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_IRQ);
+
+ if (leftCnt <= 0) {
+ if (extended == 0) {
+ stpRxState = mtk_stp_check_rx_has_pending_data();
+ WMT_INFO_FUNC("check rx pending data(%d)\n", stpRxState);
+ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX);
+ if (readLen > 0) {
+ WMT_INFO_FUNC("rx data received, rx done.\n");
+ break;
+ } else if (stpRxState > 0) {
+ osal_thread_sched_unmark(p_rx_thread, &schedstats);
+ wmt_ctrl_show_sched_stats_log(p_rx_thread, &schedstats);
+ WMT_INFO_FUNC("stp has pending data, extend ~4 seconds\n");
+ leftCnt = WMT_LIB_RX_EXTEND_TIMEOUT/pDev->rWmtRxWq.timeoutValue;
+ extended = 1;
+ osal_thread_sched_mark(p_rx_thread, &schedstats);
+ continue;
+ }
+ /* wmt is closed, device is shuting down */
+ if (wmt_dev_is_close() || mtk_wcn_stp_is_wmt_last_close() == 1) {
+ leftCnt = 10;
+ continue;
+ }
+ }
+
+ osal_thread_sched_unmark(p_rx_thread, &schedstats);
+ wmt_ctrl_show_sched_stats_log(p_rx_thread, &schedstats);
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ WMT_ERR_FUNC("wmt_dev_rx_timeout: timeout,jiffies(%lu),timeoutvalue(%d)\n",
+ jiffies, pDev->rWmtRxWq.timeoutValue);
+ WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP RX timeout");
+
+ /* Reason number 44 means that stp data path still has data,
+ * possibly a driver problem
+ */
+ if (stpRxState != 0)
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 44);
+ return -1;
+ }
+ } else if (waitRet < 0) {
+ WMT_WARN_FUNC("wmt_dev_rx_timeout: interrupted by signal (%d)\n", waitRet);
+ WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP RX timeout");
+ return waitRet;
+ }
+ readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX);
+
+ if (readLen == 0)
+ WMT_DBG_FUNC("wmt_ctrl_rx be signaled, but no rx data(%d)\n", waitRet);
+ WMT_DBG_FUNC("stp_receive_data: readLen(%d)\n", readLen);
+ }
+
+ if (readSize)
+ *readSize = readLen;
+
+ return 0;
+}
+
+
+INT32
+wmt_ctrl_tx_ex(const PUINT8 pData,
+ const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 iRet;
+
+ if (writtenSize != NULL)
+ *writtenSize = 0;
+
+ /* sanity check */
+ if (size == 0) {
+ WMT_WARN_FUNC("size to tx is 0\n");
+ osal_assert(size);
+ return -1;
+ }
+
+ /* if STP is not enabled yet, can't use this function. Use tx_raw instead */
+ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state) ||
+ !osal_test_bit(WMT_STAT_STP_EN, &pDev->state)) {
+ WMT_ERR_FUNC("wmt state(0x%lx)\n", pDev->state.data);
+ osal_assert(osal_test_bit(WMT_STAT_STP_EN, &pDev->state));
+ osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state));
+ iRet = -2;
+ if (writtenSize)
+ *writtenSize = iRet;
+ return iRet;
+ }
+
+ /* sanity ok, proceeding tx operation */
+ /*retval = mtk_wcn_stp_send_data(data, size, WMTDRV_TYPE_WMT); */
+ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX);
+ if (bRawFlag)
+ iRet = mtk_wcn_stp_send_data_raw(pData, size, WMT_TASK_INDX);
+ else
+ iRet = mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX);
+
+ if (iRet != size) {
+ WMT_WARN_FUNC("write(%d) written(%d)\n", size, iRet);
+ osal_assert(iRet == size);
+ }
+
+ if (writtenSize)
+ *writtenSize = iRet;
+
+ return 0;
+
+}
+
+INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ UINT32 type = pWmtCtrlData->au4CtrlData[0];
+
+ WMT_INFO_FUNC("flush rx %d queue\n", type);
+ mtk_wcn_stp_flush_rx_queue(type);
+
+ return 0;
+}
+
+
+INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iret;
+ /*psm should be disabled before wmt_ic_deinit*/
+ P_DEV_WMT pDev = &gDevWmt;
+
+ if (osal_test_and_clear_bit(WMT_STAT_PWR, &pDev->state)) {
+ WMT_DBG_FUNC("on->off\n");
+ iret = wmt_plat_pwr_ctrl(FUNC_OFF);
+ } else {
+ WMT_WARN_FUNC("already off\n");
+ iret = 0;
+ }
+
+ return iret;
+}
+
+INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iret;
+ /*psm should be enabled right after wmt_ic_init */
+ P_DEV_WMT pDev = &gDevWmt;
+
+ if (osal_test_and_set_bit(WMT_STAT_PWR, &pDev->state)) {
+ WMT_WARN_FUNC("already on\n");
+ iret = 0;
+ } else {
+ WMT_DBG_FUNC("off->on\n");
+ iret = wmt_plat_pwr_ctrl(FUNC_ON);
+ }
+
+ return iret;
+}
+
+INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const PUINT8 pCmdStr)
+{
+ INT32 waitRet = -1;
+ P_OSAL_SIGNAL pCmdSignal;
+ P_OSAL_EVENT pCmdReq;
+
+ if (osal_test_and_set_bit(WMT_STAT_CMD, &pWmtDev->state)) {
+ WMT_WARN_FUNC("cmd buf is occupied by (%s)\n", pWmtDev->cCmd);
+ return -1;
+ }
+
+ /* indicate baud rate change to user space app */
+#if 0
+ INIT_COMPLETION(pWmtDev->cmd_comp);
+ pWmtDev->cmd_result = -1;
+ strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX);
+ pWmtDev->cCmd[NAME_MAX] = '\0';
+ wake_up_interruptible(&pWmtDev->cmd_wq);
+#endif
+
+ pCmdSignal = &pWmtDev->cmdResp;
+ osal_signal_init(pCmdSignal);
+ pCmdSignal->timeoutValue = 6000;
+ osal_strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX);
+ pWmtDev->cCmd[NAME_MAX] = '\0';
+
+ pCmdReq = &pWmtDev->cmdReq;
+
+ osal_trigger_event(&pWmtDev->cmdReq);
+ WMT_DBG_FUNC("str(%s) request ok\n", pCmdStr);
+
+/* waitRet = wait_for_completion_interruptible_timeout(&pWmtDev->cmd_comp, msecs_to_jiffies(2000)); */
+ waitRet = osal_wait_for_signal_timeout(pCmdSignal, NULL);
+ WMT_LOUD_FUNC("wait signal iRet:%d\n", waitRet);
+ if (waitRet == 0) {
+ WMT_ERR_FUNC("wait signal timeout\n");
+ return -2;
+ }
+
+ WMT_DBG_FUNC("str(%s) result(%d)\n", pCmdStr, pWmtDev->cmdResult);
+
+ return pWmtDev->cmdResult;
+}
+
+INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ wmt_plat_pwr_ctrl(FUNC_RST);
+ return 0;
+}
+
+INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ wmt_plat_pwr_ctrl(FUNC_STAT);
+ return 0;
+}
+
+INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 iRet = 0;
+ UINT8 cmdStr[NAME_MAX + 1] = { 0 };
+ /* un-register to STP-core for rx */
+
+ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, NULL); /* mtk_wcn_stp_register_event_cb */
+ if (iRet) {
+ WMT_WARN_FUNC("stp_reg cb unregister fail(%d)\n", iRet);
+ return -1;
+ }
+
+ if (pDev->rWmtHifConf.hifType == WMT_HIF_UART) {
+
+ osal_snprintf(cmdStr, NAME_MAX, "close_stp");
+
+ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr);
+ if (iRet) {
+ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet);
+ return -2;
+ }
+ }
+ if (pDev->rWmtHifConf.hifType == WMT_HIF_BTIF) {
+ /*un-register rxcb to btif */
+ iRet = mtk_wcn_stp_rxcb_register(NULL);
+ if (iRet) {
+ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_unregister fail(%d)\n", iRet);
+ return -2;
+ }
+
+ iRet = mtk_wcn_stp_close_btif();
+ if (iRet) {
+ WMT_WARN_FUNC("mtk_wcn_stp_close_btif fail(%d)\n", iRet);
+ return -3;
+ }
+ }
+
+ osal_clear_bit(WMT_STAT_STP_OPEN, &pDev->state);
+
+ return 0;
+}
+
+INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 iRet;
+ UINT8 cmdStr[NAME_MAX + 1] = { 0 };
+
+ if (pDev->rWmtHifConf.hifType == WMT_HIF_UART) {
+ osal_snprintf(cmdStr, NAME_MAX, "open_stp");
+ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr);
+ if (iRet) {
+ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet);
+ return -1;
+ }
+ }
+ if (pDev->rWmtHifConf.hifType == WMT_HIF_BTIF) {
+ iRet = mtk_wcn_stp_open_btif();
+ if (iRet) {
+ WMT_WARN_FUNC("mtk_wcn_stp_open_btif fail(%d)\n", iRet);
+ return -1;
+ }
+
+ /*register stp rx call back to btif */
+ iRet = mtk_wcn_stp_rxcb_register((MTK_WCN_BTIF_RX_CB)mtk_wcn_stp_parser_data);
+ if (iRet) {
+ WMT_WARN_FUNC("mtk_wcn_stp_rxcb_register fail(%d)\n", iRet);
+ return -2;
+ }
+ }
+ /* register to STP-core for rx */
+ /* mtk_wcn_stp_register_event_cb */
+ iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, wmt_dev_rx_event_cb);
+ if (iRet) {
+ WMT_WARN_FUNC("stp_reg cb fail(%d)\n", iRet);
+ return -2;
+ }
+
+ osal_set_bit(WMT_STAT_STP_OPEN, &pDev->state);
+#if 0
+ iRet = mtk_wcn_stp_lpbk_ctrl(1);
+#endif
+
+ return 0;
+}
+
+
+INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 iRet;
+ UINT8 cmdStr[NAME_MAX + 1] = { 0 };
+
+ osal_snprintf(cmdStr, NAME_MAX, "srh_patch");
+ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr);
+ if (iRet) {
+ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet);
+ return -1;
+ }
+ return 0;
+}
+
+
+INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+
+ pWmtCtrlData->au4CtrlData[0] = pDev->patchNum;
+ return 0;
+}
+
+
+INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ UINT32 downLoadSeq = 0;
+ P_WMT_PATCH_INFO pPatchinfo = NULL;
+ PUINT8 pNbuf = NULL;
+ PUINT8 pAbuf = NULL;
+
+ if (pDev->pWmtPatchInfo == NULL) {
+ WMT_ERR_FUNC("pWmtPatchInfo is NULL\n");
+ return -1;
+ }
+
+ downLoadSeq = pWmtCtrlData->au4CtrlData[0];
+ WMT_DBG_FUNC("download seq is %d\n", downLoadSeq);
+
+ pPatchinfo = pDev->pWmtPatchInfo + downLoadSeq - 1;
+ pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1];
+ pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2];
+ if (pPatchinfo) {
+ osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName));
+ osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess));
+ WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", pAbuf[0], pAbuf[1],
+ pAbuf[2], pAbuf[3]);
+ } else
+ WMT_ERR_FUNC("NULL patchinfo pointer\n");
+
+ return 0;
+}
+
+INT32 wmt_ctrl_get_rom_patch_info(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ UINT32 type = 0;
+ struct wmt_rom_patch_info *pPatchinfo = NULL;
+ PUINT8 pNbuf = NULL;
+ PUINT8 pAbuf = NULL;
+ INT32 ret = 0;
+ UINT8 cmdStr[NAME_MAX + 1] = { 0 };
+
+ type = pWmtCtrlData->au4CtrlData[0];
+ WMT_DBG_FUNC("rom patch type is %d\n", type);
+ pDev->ip_ver = pWmtCtrlData->au4CtrlData[3];
+ pDev->fw_ver = pWmtCtrlData->au4CtrlData[4];
+ WMT_DBG_FUNC("ip version is [%x] [%x]\n", pDev->ip_ver, pDev->fw_ver);
+
+ if (!pDev->pWmtRomPatchInfo[WMTDRV_TYPE_WMT]) {
+ osal_snprintf(cmdStr, NAME_MAX, "srh_rom_patch");
+ ret = wmt_ctrl_ul_cmd(pDev, cmdStr);
+ if (ret) {
+ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", ret);
+ return -1;
+ }
+ }
+
+ if (type < WMTDRV_TYPE_ANT) {
+ pPatchinfo = pDev->pWmtRomPatchInfo[type];
+ pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1];
+ pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2];
+ if (pPatchinfo) {
+ osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName));
+ osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess));
+ WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x",
+ pAbuf[0], pAbuf[1], pAbuf[2], pAbuf[3]);
+ } else {
+ WMT_ERR_FUNC("NULL patchinfo pointer\n");
+ ret = 1;
+ }
+ } else {
+ WMT_ERR_FUNC("rom patch type %d is error!\n", type);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+INT32 wmt_ctrl_update_patch_version(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ INT32 iRet;
+ UINT8 cmdStr[NAME_MAX + 1] = { 0 };
+
+ osal_snprintf(cmdStr, NAME_MAX, "update_patch_version");
+ iRet = wmt_ctrl_ul_cmd(pDev, cmdStr);
+ if (iRet) {
+ WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet);
+ return -1;
+ }
+ return 0;
+}
+
+INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = 0;
+ ENUM_PALDO_TYPE ept = pWmtCtrlData->au4CtrlData[0];
+ ENUM_PALDO_OP epo = pWmtCtrlData->au4CtrlData[1];
+
+ WMT_DBG_FUNC("ept(%d),epo(%d)\n", ept, epo);
+ iRet = wmt_plat_soc_paldo_ctrl(ept, epo);
+ if (iRet) {
+ if (ept == PMIC_CHIPID_PALDO) {
+ /* special handling for PMIC CHIPID */
+ pWmtCtrlData->au4CtrlData[2] = iRet;
+ } else {
+ /* for other PA handling */
+ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet);
+ }
+ }
+
+ return iRet;
+}
+
+INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = 0;
+
+ iRet = mtk_wcn_stp_wakeup_consys();
+ if (iRet)
+ WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet);
+
+ return iRet;
+}
+
+static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ UINT32 cmd = pWmtCtrlData->au4CtrlData[0];
+
+ WMT_INFO_FUNC("wmt-ctrl:send native cmd(%d)\n", cmd);
+ wmt_dev_send_cmd_to_daemon(cmd);
+
+ return 0;
+}
+
+#if CFG_WMT_LTE_COEX_HANDLING
+static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 antsel_index = wmt_plat_get_tdm_antsel_index();
+
+ if (antsel_index >= 0)
+ pWmtCtrlData->au4CtrlData[0] = antsel_index;
+ else
+ pWmtCtrlData->au4CtrlData[0] = 0xff;
+
+ WMT_INFO_FUNC("get tdm req antsel index is %d\n", antsel_index);
+
+ return 0;
+}
+#endif
+
+static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 ret = -1;
+ UINT32 evt_idx = (UINT32) pWmtCtrlData->au4CtrlData[0];
+ UINT8 *p_buf = NULL;
+
+ static UINT8 sleep_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 };
+ static UINT8 wakeup_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+ static UINT8 hostawake_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 };
+ static UINT8 *evt_array[] = { sleep_evt, wakeup_evt, hostawake_evt };
+
+ p_buf = evt_array[evt_idx - 1];
+
+ WMT_INFO_FUNC("evt index:%d,p_buf:%p\n", evt_idx, p_buf);
+
+ ret = mtk_wcn_consys_stp_btif_parser_wmt_evt(p_buf, 6);
+ if (ret == 1) {
+ WMT_INFO_FUNC("parser wmt evt from BTIF buf is OK\n");
+ return 0;
+ }
+ WMT_ERR_FUNC("parser wmt evt from BTIF buf fail(%d)\n", ret);
+ return -1;
+}
+
+INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value)
+{
+ INT32 iRet = -1;
+
+ switch (type) {
+ case WMT_STP_CONF_EN:
+ iRet = mtk_wcn_stp_enable(value);
+ break;
+
+ case WMT_STP_CONF_RDY:
+ iRet = mtk_wcn_stp_ready(value);
+ break;
+
+ case WMT_STP_CONF_MODE:
+ mtk_wcn_stp_set_mode(value);
+ iRet = 0;
+ break;
+
+ default:
+ WMT_WARN_FUNC("invalid type(%d) value(%d)\n", type, value);
+ break;
+ }
+ return iRet;
+}
+
+
+INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = -1;
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ UINT32 type;
+ UINT32 value;
+
+ if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) {
+ WMT_WARN_FUNC("CTRL_STP_ENABLE but invalid Handle of WmtStp\n");
+ return -1;
+ }
+
+ type = pWmtCtrlData->au4CtrlData[0];
+ value = pWmtCtrlData->au4CtrlData[1];
+ iRet = wmt_ctrl_stp_conf_ex(type, value);
+
+ if (!iRet) {
+ if (type == WMT_STP_CONF_EN) {
+ if (value) {
+ osal_set_bit(WMT_STAT_STP_EN, &pDev->state);
+ WMT_DBG_FUNC("enable STP\n");
+ } else {
+ osal_clear_bit(WMT_STAT_STP_EN, &pDev->state);
+ WMT_DBG_FUNC("disable STP\n");
+ }
+ }
+ if (type == WMT_STP_CONF_RDY) {
+ if (value) {
+ osal_set_bit(WMT_STAT_STP_RDY, &pDev->state);
+ WMT_DBG_FUNC("STP ready\n");
+ } else {
+ osal_clear_bit(WMT_STAT_STP_RDY, &pDev->state);
+ WMT_DBG_FUNC("STP not ready\n");
+ }
+ }
+ }
+
+ return iRet;
+}
+
+
+INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ UINT32 patchSeq = pWmtCtrlData->au4CtrlData[0];
+
+ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch);
+ if (gDevWmt.pPatch != NULL)
+ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pPatch));
+ WMT_DBG_FUNC("AF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch);
+ if (patchSeq == gDevWmt.patchNum)
+ WMT_DBG_FUNC("the %d patch has been download\n", patchSeq);
+ return 0;
+}
+
+INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ PUINT8 pBuf = (PUINT8) pWmtCtrlData->au4CtrlData[0];
+
+ osal_memcpy(pBuf, gDevWmt.cPatchName, osal_sizeof(gDevWmt.cPatchName));
+ return 0;
+}
+
+INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch);
+ if (gDevWmt.pNvram != NULL)
+ wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pNvram));
+ WMT_DBG_FUNC("AF free patch, gDevWmt.pNvram(%p)\n", gDevWmt.pNvram);
+ return 0;
+}
+
+
+INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = 0x0;
+ PUINT8 pFileName = (PUINT8) pWmtCtrlData->au4CtrlData[0];
+ PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[1];
+ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[2];
+ osal_firmware *pNvram = NULL;
+
+ if ((pFileName == NULL) || (pSize == NULL)) {
+ WMT_ERR_FUNC("parameter error, pFileName(%p), pSize(%p)\n", pFileName, pSize);
+ iRet = -1;
+ return iRet;
+ }
+ if (wmt_dev_patch_get(pFileName, &pNvram) == 0) {
+ *ppBuf = (PUINT8)(pNvram)->data;
+ *pSize = (pNvram)->size;
+ gDevWmt.pNvram = pNvram;
+ return 0;
+ }
+ return -1;
+}
+
+
+INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ PUINT8 pFullPatchName = NULL;
+ PUINT8 pDefPatchName = NULL;
+ PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[2];
+ PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[3];
+ osal_firmware *pPatch = NULL;
+
+ pFullPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[1];
+ WMT_DBG_FUNC("BF get patch, pPatch(%p)\n", pPatch);
+ if ((pFullPatchName != NULL)
+ && (wmt_dev_patch_get(pFullPatchName, &pPatch) == 0)) {
+ /*get full name patch success */
+ WMT_DBG_FUNC("get full patch name(%s) buf(0x%p) size(%zu)\n",
+ pFullPatchName, (pPatch)->data, (pPatch)->size);
+ WMT_DBG_FUNC("AF get patch, pPatch(%p)\n", pPatch);
+ *ppBuf = (PUINT8)(pPatch)->data;
+ *pSize = (pPatch)->size;
+ gDevWmt.pPatch = pPatch;
+ return 0;
+ }
+
+ pDefPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[0];
+ if ((pDefPatchName != NULL)
+ && (wmt_dev_patch_get(pDefPatchName, &pPatch) == 0)) {
+ WMT_DBG_FUNC("get def patch name(%s) buf(0x%p) size(%zu)\n",
+ pDefPatchName, (pPatch)->data, (pPatch)->size);
+ WMT_DBG_FUNC("AF get patch, pPatch(%p)\n", pPatch);
+ /*get full name patch success */
+ *ppBuf = (PUINT8)(pPatch)->data;
+ *pSize = (pPatch)->size;
+ gDevWmt.pPatch = pPatch;
+ return 0;
+ }
+ return -1;
+
+}
+
+INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = -1;
+ INT8 cmdStr[NAME_MAX + 1] = { 0 };
+ UINT32 u4Baudrate = pWmtCtrlData->au4CtrlData[0];
+ UINT32 u4FlowCtrl = pWmtCtrlData->au4CtrlData[1];
+
+ WMT_DBG_FUNC("baud(%d), flowctrl(%d)\n", u4Baudrate, u4FlowCtrl);
+
+ if (osal_test_bit(WMT_STAT_STP_OPEN, &gDevWmt.state)) {
+ osal_snprintf(cmdStr, NAME_MAX, "baud_%d_%d", u4Baudrate, u4FlowCtrl);
+ iRet = wmt_ctrl_ul_cmd(&gDevWmt, cmdStr);
+ if (iRet)
+ WMT_WARN_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%zu) fail(%d)\n",
+ u4Baudrate, pWmtCtrlData->au4CtrlData[1], iRet);
+ else
+ WMT_DBG_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) ok\n",
+ u4Baudrate, u4FlowCtrl);
+ } else
+ WMT_INFO_FUNC("CTRL_BAUDRATE but invalid Handle of WmtStp\n");
+ return iRet;
+}
+
+INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = 0;
+ UINT32 statBit = WMT_STAT_SDIO1_ON;
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+
+ WMT_SDIO_SLOT_NUM sdioSlotNum = pWmtCtrlData->au4CtrlData[0];
+ ENUM_FUNC_STATE funcState = pWmtCtrlData->au4CtrlData[1];
+
+ if ((sdioSlotNum == WMT_SDIO_SLOT_INVALID)
+ || (sdioSlotNum >= WMT_SDIO_SLOT_MAX)) {
+ WMT_WARN_FUNC("CTRL_SDIO_SLOT(%d) but invalid slot num\n", sdioSlotNum);
+ return -1;
+ }
+
+ WMT_DBG_FUNC("WMT_CTRL_SDIO_HW (0x%x, %d)\n", sdioSlotNum, funcState);
+
+ if (sdioSlotNum == WMT_SDIO_SLOT_SDIO2)
+ statBit = WMT_STAT_SDIO2_ON;
+
+ if (funcState) {
+ if (osal_test_and_set_bit(statBit, &pDev->state)) {
+ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already ON\n", sdioSlotNum);
+ /* still return 0 */
+ iRet = 0;
+ } else
+ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_ON);
+ } else {
+ if (osal_test_and_clear_bit(statBit, &pDev->state))
+ iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_OFF);
+ else {
+ WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already OFF\n", sdioSlotNum);
+ /* still return 0 */
+ iRet = 0;
+ }
+ }
+
+ return iRet;
+}
+
+INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = -1;
+ UINT32 statBit = WMT_STAT_SDIO_WIFI_ON;
+ INT32 retry = 10;
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+ WMT_SDIO_FUNC_TYPE sdioFuncType = pWmtCtrlData->au4CtrlData[0];
+ UINT32 u4On = pWmtCtrlData->au4CtrlData[1];
+
+ if (sdioFuncType >= WMT_SDIO_FUNC_MAX) {
+ WMT_ERR_FUNC("CTRL_SDIO_FUNC, invalid func type (%d)\n", sdioFuncType);
+ return -1;
+ }
+
+ if (sdioFuncType == WMT_SDIO_FUNC_STP)
+ statBit = WMT_STAT_SDIO_STP_ON;
+
+ if (u4On) {
+ if (osal_test_bit(statBit, &pDev->state)) {
+ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already ON\n", sdioFuncType);
+ iRet = 0;
+ } else {
+ while (retry-- > 0 && iRet != 0) {
+ if (iRet) {
+ /* sleep 150ms before sdio slot ON ready */
+ osal_sleep_ms(150);
+ }
+ iRet =
+ mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_TRUE);
+ if (iRet == HIF_SDIO_ERR_NOT_PROBED) {
+ /* not probed case, retry */
+ continue;
+ } else if (iRet == HIF_SDIO_ERR_CLT_NOT_REG) {
+ /* For WiFi, client not reg yet, no need to retry,
+ * WiFi function can work any time when wlan.ko is insert into system
+ */
+ iRet = 0;
+ } else {
+ /* other fail cases, stop */
+ break;
+ }
+ }
+ if (iRet)
+ WMT_ERR_FUNC
+ ("mtk_wcn_hif_sdio_wmt_control(%d, TRUE) fail(%d) retry(%d)\n",
+ sdioFuncType, iRet, retry);
+ else
+ osal_set_bit(statBit, &pDev->state);
+ }
+ } else {
+ if (osal_test_bit(statBit, &pDev->state)) {
+ iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_FALSE);
+ if (iRet)
+ WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, FALSE) fail(%d)\n",
+ sdioFuncType, iRet);
+ /*any way, set to OFF state */
+ osal_clear_bit(statBit, &pDev->state);
+ } else {
+ WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already OFF\n", sdioFuncType);
+ iRet = 0;
+ }
+ }
+
+ return iRet;
+}
+
+#if 0
+/* TODO: [FixMe][GeorgeKuo]: remove unused function. get hwver from core is not needed. */
+INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+
+ return 0;
+}
+#endif
+
+INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+
+ /* input sanity check is done in wmt_ctrl() */
+ pDev->chip_id = (pWmtCtrlData->au4CtrlData[0] & 0xFFFF0000) >> 16;
+ pDev->hw_ver = pWmtCtrlData->au4CtrlData[0] & 0x0000FFFF;
+ pDev->fw_ver = pWmtCtrlData->au4CtrlData[1] & 0x0000FFFF;
+
+ return 0;
+}
+
+static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData)
+{
+ INT32 iret;
+
+ WMT_DBG_FUNC("ctrl GPS_SYNC(%d)\n",
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX);
+ iret =
+ wmt_plat_gpio_ctrl(PIN_GPS_SYNC,
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX);
+
+ if (iret)
+ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n",
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX, iret);
+
+ return 0;
+}
+
+
+static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData)
+{
+ INT32 iret;
+
+ WMT_DBG_FUNC("ctrl GPS_LNA(%d)\n",
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H);
+ iret =
+ wmt_plat_gpio_ctrl(PIN_GPS_LNA,
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H);
+
+ if (iret)
+ WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n",
+ (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H, iret);
+
+ return 0;
+}
+
+
+INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ return 0;
+}
+
+INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ P_DEV_WMT pDev = &gDevWmt; /* single instance */
+
+ pWmtCtrlData->au4CtrlData[0] = (size_t) &pDev->rWmtGenConf;
+
+ return 0;
+}
+
+INT32 wmt_ctrl_others(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ WMT_ERR_FUNC("wmt_ctrl_others, invalid CTRL ID (%d)\n", pWmtCtrlData->ctrlId);
+ return -1;
+}
+
+
+INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ PUINT8 pRomVer = NULL;
+ P_WMT_PATCH pPatch = NULL;
+ UINT32 chipID = 0;
+
+ chipID = pWmtCtrlData->au4CtrlData[0];
+ pRomVer = (PUINT8) (pWmtCtrlData->au4CtrlData[1]);
+ pPatch = (P_WMT_PATCH)(pWmtCtrlData->au4CtrlData[2]);
+ if (!pRomVer) {
+ WMT_ERR_FUNC("pRomVer null pointer\n");
+ return -1;
+ }
+
+ if (!pPatch) {
+ WMT_ERR_FUNC("pPatch null pointer\n");
+ return -2;
+ }
+ WMT_DBG_FUNC("chipid(0x%x),rom(%s),patch date(%s),patch plat(%s)\n", chipID, pRomVer,
+ pPatch->ucDateTime, pPatch->ucPLat);
+ return stp_dbg_set_version_info(chipID, pRomVer, &(pPatch->ucDateTime[0]),
+ &(pPatch->ucPLat[0]));
+}
+
+static INT32 wmt_ctrl_trg_assert(P_WMT_CTRL_DATA pWmtCtrlData)
+{
+ INT32 iRet = -1;
+
+ ENUM_WMTDRV_TYPE_T drv_type;
+ UINT32 reason = 0;
+ PUINT8 keyword;
+
+ drv_type = pWmtCtrlData->au4CtrlData[0];
+ reason = pWmtCtrlData->au4CtrlData[1];
+ keyword = (PUINT8) pWmtCtrlData->au4CtrlData[2];
+ WMT_INFO_FUNC("wmt-ctrl:drv_type(%d),reason(%d),keyword(%s)\n", drv_type, reason, keyword);
+
+ if (wmt_dev_is_close())
+ WMT_INFO_FUNC("WMT is closing, don't trigger assert\n");
+ else if (chip_reset_only == 1)
+ WMT_INFO_FUNC("Do chip reset only, don't trigger assert\n");
+ else if (mtk_wcn_stp_get_wmt_trg_assert() == 0) {
+ mtk_wcn_stp_dbg_dump_package();
+ mtk_wcn_stp_set_wmt_trg_assert(1);
+ mtk_wcn_stp_assert_flow_ctrl(1);
+
+ iRet = mtk_wcn_stp_wmt_trg_assert();
+ if (iRet == 0) {
+ wmt_lib_set_host_assert_info(drv_type, reason, 1);
+ stp_dbg_set_keyword(keyword);
+ }
+ } else
+ WMT_INFO_FUNC("do trigger assert & chip reset in stp noack\n");
+
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0cc26da0c2cfd87b6e515690ab28a18e0c80c449
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c
@@ -0,0 +1,876 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-EXP]"
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_step.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+wmt_wlan_probe_cb mtk_wcn_wlan_probe;
+wmt_wlan_remove_cb mtk_wcn_wlan_remove;
+wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt;
+wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr;
+wmt_wlan_emi_mpu_set_protection_cb mtk_wcn_wlan_emi_mpu_set_protection;
+wmt_wlan_is_wifi_drv_own_cb mtk_wcn_wlan_is_wifi_drv_own;
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+OSAL_BIT_OP_VAR gBtWifiGpsState;
+OSAL_BIT_OP_VAR gGpsFmState;
+UINT32 gWifiProbed;
+INT32 gWmtDbgLvl = WMT_LOG_INFO;
+MTK_WCN_BOOL g_pwr_off_flag = MTK_WCN_BOOL_TRUE;
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static MTK_WCN_BOOL mtk_wcn_wmt_pwr_on(VOID);
+static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId);
+static MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl_by_type(MTK_WCN_BOOL gps_l1, MTK_WCN_BOOL gps_l5, MTK_WCN_BOOL suspend);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static MTK_WCN_BOOL mtk_wcn_wmt_pwr_on(VOID)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ pSignal = &pOp->signal;
+
+ pOp->op.opId = WMT_OPID_PWR_ON;
+ pSignal->timeoutValue = MAX_FUNC_ON_TIME;
+ pOp->op.au4OpData[0] = WMTDRV_TYPE_WMT;
+
+ wmt_lib_host_awake_get();
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ wmt_lib_put_op_to_free_queue(pOp);
+ wmt_lib_host_awake_put();
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+
+ ENABLE_PSM_MONITOR();
+ wmt_lib_host_awake_put();
+
+ if (bRet == MTK_WCN_BOOL_FALSE)
+ WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ return bRet;
+}
+
+static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+ MTK_WCN_BOOL bOffload;
+ MTK_WCN_BOOL bExplicitPwrOn;
+
+ bOffload = (type == WMTDRV_TYPE_WIFI);
+ bExplicitPwrOn = (bOffload && opId == WMT_OPID_FUNC_ON &&
+ wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) != DRV_STS_FUNC_ON);
+
+ /* WIFI on no need to disable psm and prevent WIFI on blocked by psm lock. */
+ /* So we power on connsys separately from function on flow. */
+ if (bExplicitPwrOn)
+ mtk_wcn_wmt_pwr_on();
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &pOp->signal;
+
+ pOp->op.opId = opId;
+ pOp->op.au4OpData[0] = type;
+ if (type == WMTDRV_TYPE_WIFI)
+ pSignal->timeoutValue = 4000;
+ else
+ pSignal->timeoutValue = (pOp->op.opId == WMT_OPID_FUNC_ON) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME;
+
+ WMT_INFO_FUNC("wmt-exp: OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, opId);
+
+ /*do not check return value, we will do this either way */
+ wmt_lib_host_awake_get();
+ /* wake up chip first */
+ if (!bOffload) {
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ wmt_lib_put_op_to_free_queue(pOp);
+ wmt_lib_host_awake_put();
+ return MTK_WCN_BOOL_FALSE;
+ }
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ if (!bOffload)
+ ENABLE_PSM_MONITOR();
+ wmt_lib_host_awake_put();
+
+ if (bRet == MTK_WCN_BOOL_FALSE)
+ WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ else
+ WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ return bRet;
+}
+
+INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag)
+{
+ return -EFAULT;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl);
+
+MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type)
+{
+ MTK_WCN_BOOL ret;
+
+ if (type == WMTDRV_TYPE_BT) {
+ osal_printtimeofday("############ BT OFF ====>");
+ }
+
+ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF);
+
+ if (type == WMTDRV_TYPE_BT)
+ osal_printtimeofday("############ BT OFF <====");
+
+ return ret;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_func_off);
+
+MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type)
+{
+ MTK_WCN_BOOL ret;
+
+ if (type == WMTDRV_TYPE_BT)
+ osal_printtimeofday("############ BT ON ====>");
+
+ ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON);
+
+ if (type == WMTDRV_TYPE_BT)
+ osal_printtimeofday(" ############BT ON <====");
+
+ return ret;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_func_on);
+
+/*
+*return value:
+*enable/disable thermal sensor function: true(1)/false(0)
+*read thermal sensor function:thermal value
+*/
+VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type)
+{
+ MTK_WCN_BOOL ret;
+
+ if (on)
+ ret = mtk_wcn_wmt_func_on(type);
+ else
+ ret = mtk_wcn_wmt_func_off(type);
+
+ WMT_INFO_FUNC("on=%d type=%d ret=%d\n", on, type, ret);
+}
+
+INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType)
+{
+ P_OSAL_OP pOp;
+ P_WMT_OP pOpData;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ /*parameter validation check */
+ if (eType > WMTTHERM_MAX || eType < WMTTHERM_ENABLE) {
+ WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ /*check if chip support thermal control function or not */
+ bRet = wmt_lib_is_therm_ctrl_support(eType);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_DBG_FUNC("thermal ctrl function not supported\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &pOp->signal;
+ pOpData = &pOp->op;
+ pOpData->opId = WMT_OPID_THERM_CTRL;
+ /*parameter fill */
+ pOpData->au4OpData[0] = eType;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+
+ WMT_DBG_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_READ_THERMAL);
+
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n\n", pOpData->opId, pOpData->au4OpData[0]);
+ /*0xFF means read error occurs */
+ /*will return to function driver */
+ pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE;
+ } else
+ WMT_DBG_FUNC("OPID(%d) type(%zu) return(%zu) ok\n\n",
+ pOpData->opId, pOpData->au4OpData[0], pOpData->au4OpData[1]);
+ /*return value will be put to lxop->op.au4OpData[1] */
+ WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08zx)\n", eType, pOpData->au4OpData[1]);
+
+ return (INT8) pOpData->au4OpData[1];
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl);
+
+ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID)
+{
+ /* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */
+ /* TODO: how do we extend for new chip and newer revision? */
+ /* TODO: This way is hard to extend */
+ return wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get);
+
+UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type)
+{
+ return wmt_lib_get_icinfo(type);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get);
+
+MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType)
+{
+ P_OSAL_OP pOp;
+ P_WMT_OP pOpData;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ if (eType >= WMTDSNS_MAX) {
+ WMT_ERR_FUNC("invalid desense control command (%d)\n", eType);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ /*check if chip support thermal control function or not */
+ bRet = wmt_lib_is_dsns_ctrl_support();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC("thermal ctrl function not supported\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &pOp->signal;
+ pOpData = &pOp->op;
+ pOpData->opId = WMT_OPID_DSNS;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+ /*parameter fill */
+ if ((eType >= WMTDSNS_FM_DISABLE) && (eType <= WMTDSNS_FM_GPS_ENABLE)) {
+ pOpData->au4OpData[0] = WMTDRV_TYPE_FM;
+ pOpData->au4OpData[1] = eType;
+ }
+
+ WMT_INFO_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ wmt_lib_put_op_to_free_queue(pOp);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet == MTK_WCN_BOOL_FALSE)
+ WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n\n", pOpData->opId, pOpData->au4OpData[0]);
+ else
+ WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n\n", pOpData->opId, pOpData->au4OpData[0]);
+
+ return bRet;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl);
+
+INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb)
+{
+ return (INT32) wmt_lib_msgcb_reg(eType, pCb);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg);
+
+INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType)
+{
+ return (INT32) wmt_lib_msgcb_unreg(eType);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg);
+
+INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb)
+{
+ wmt_lib_ps_set_sdio_psop(own_cb);
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg);
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb)
+{
+ wmt_lib_sdio_deep_sleep_flag_set_cb_reg(flag_cb);
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg);
+#endif
+
+INT32 mtk_wcn_wmt_sdio_rw_cb_reg(PF_WMT_SDIO_DEBUG reg_rw_cb)
+{
+ wmt_lib_sdio_reg_rw_cb(reg_rw_cb);
+ return 0;
+}
+
+INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID)
+{
+ wmt_lib_ps_irq_cb();
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake);
+
+MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout)
+{
+ MTK_WCN_BOOL bRet;
+
+ bRet = wmt_lib_trigger_assert(type, reason);
+
+ return bRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_assert_timeout);
+
+MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason)
+{
+ return mtk_wcn_wmt_assert_timeout(type, reason, MAX_EACH_WMT_CMD);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_assert);
+
+MTK_WCN_BOOL mtk_wcn_wmt_assert_keyword(ENUM_WMTDRV_TYPE_T type, PUINT8 keyword)
+{
+ MTK_WCN_BOOL bRet;
+
+ bRet = wmt_lib_trigger_assert_keyword(type, 0, keyword);
+
+ return bRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_assert_keyword);
+
+/*
+* ctrlId: get flash patch version opId or flash patch download opId
+* pBuf: pointer to flash patch
+* length: total length of flash patch
+* type: flash patch type
+* version: flash patch version
+* checksum: flash patch checksum
+*/
+ENUM_WMT_FLASH_PATCH_STATUS mtk_wcn_wmt_flash_patch_ctrl(ENUM_WMT_FLASH_PATCH_CTRL ctrlId,
+ PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type,
+ PUINT32 version, UINT32 checksum)
+{
+ ENUM_WMT_FLASH_PATCH_STATUS eRet = 0;
+ P_OSAL_OP pOp = NULL;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_OSAL_SIGNAL pSignal;
+
+ /*1. parameter validation check */
+ /*for WMT_FLASH_PATCH_VERSION_GET, ignore pBuf and length */
+ /*for WMT_ANT_RAM_DOWNLOAD,
+ * pBuf must not be NULL, kernel space memory pointer
+ * length must be large than 0
+ */
+ switch (ctrlId) {
+ case WMT_FLASH_PATCH_VERSION_GET:
+ break;
+ case WMT_FLASH_PATCH_DOWNLOAD:
+ if ((pBuf == NULL) || (length <= 0) || (length > 1000)) {
+ WMT_ERR_FUNC("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x).\n",
+ ctrlId, pBuf, length);
+ eRet = WMT_FLASH_PATCH_PARA_ERR;
+ goto exit;
+ } else
+ break;
+ default:
+ WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId);
+ eRet = WMT_FLASH_PATCH_PARA_ERR;
+ goto exit;
+ }
+
+ /*get WMT opId */
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ eRet = WMT_FLASH_PATCH_OP_ERR;
+ goto exit;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue =
+ (ctrlId == WMT_FLASH_PATCH_DOWNLOAD) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD;
+
+ pOp->op.opId = (ctrlId == WMT_FLASH_PATCH_DOWNLOAD) ?
+ WMT_OPID_FLASH_PATCH_DOWN : WMT_OPID_FLASH_PATCH_VER_GET;
+ pOp->op.au4OpData[0] = (size_t) pBuf;
+ pOp->op.au4OpData[1] = length;
+ pOp->op.au4OpData[2] = seq;
+ pOp->op.au4OpData[3] = type;
+ pOp->op.au4OpData[4] = *version;
+ pOp->op.au4OpData[5] = checksum;
+
+ /*disable PSM monitor */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ eRet = WMT_FLASH_PATCH_OP_ERR;
+ goto exit;
+ }
+ /*wakeup wmtd thread */
+ bRet = wmt_lib_put_act_op(pOp);
+
+ /*enable PSM monitor */
+ ENABLE_PSM_MONITOR();
+
+ WMT_INFO_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n",
+ pOp->op.opId,
+ bRet,
+ pOp->op.au4OpData[6], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed");
+
+ /*check return value and return result */
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ eRet = WMT_FLASH_PATCH_OP_ERR;
+ } else {
+ switch (ctrlId) {
+ case WMT_FLASH_PATCH_VERSION_GET:
+ if (pOp->op.au4OpData[6] == 0) {
+ *version = pOp->op.au4OpData[4];
+ eRet = WMT_FLASH_PATCH_VERSION_GET_OK;
+ } else
+ eRet = WMT_FLASH_PATCH_VERSION_GET_FAIL;
+ break;
+ case WMT_FLASH_PATCH_DOWNLOAD:
+ eRet = (pOp->op.au4OpData[6] == 0) ?
+ WMT_FLASH_PATCH_DOWNLOAD_OK : WMT_FLASH_PATCH_DOWNLOAD_FAIL;
+ break;
+ default:
+ WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId);
+ eRet = WMT_FLASH_PATCH_PARA_ERR;
+ break;
+ }
+ }
+
+exit:
+ return eRet;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_flash_patch_ctrl);
+
+#if !(DELETE_HIF_SDIO_CHRDEV)
+extern INT32 mtk_wcn_wmt_chipid_query(VOID)
+{
+ return mtk_wcn_hif_sdio_query_chipid(0);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query);
+#endif
+
+INT8 mtk_wcn_wmt_co_clock_flag_get(void)
+{
+ return wmt_lib_co_clock_get();
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_co_clock_flag_get);
+
+INT32 mtk_wcn_wmt_system_state_reset(void)
+{
+ osal_memset(&gBtWifiGpsState, 0, osal_sizeof(gBtWifiGpsState));
+ osal_memset(&gGpsFmState, 0, osal_sizeof(gGpsFmState));
+
+ return 0;
+}
+
+INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo)
+{
+ INT32 iRet = -1;
+
+ if (!pWmtWlanCbInfo) {
+ WMT_ERR_FUNC("wlan cb info in null!\n");
+ return -1;
+ }
+
+ WMT_INFO_FUNC("wmt wlan cb register\n");
+ mtk_wcn_wlan_probe = pWmtWlanCbInfo->wlan_probe_cb;
+ mtk_wcn_wlan_remove = pWmtWlanCbInfo->wlan_remove_cb;
+ mtk_wcn_wlan_bus_tx_cnt = pWmtWlanCbInfo->wlan_bus_cnt_get_cb;
+ mtk_wcn_wlan_bus_tx_cnt_clr = pWmtWlanCbInfo->wlan_bus_cnt_clr_cb;
+ mtk_wcn_wlan_emi_mpu_set_protection = pWmtWlanCbInfo->wlan_emi_mpu_set_protection_cb;
+ mtk_wcn_wlan_is_wifi_drv_own = pWmtWlanCbInfo->wlan_is_wifi_drv_own_cb;
+
+ if (gWifiProbed) {
+ WMT_INFO_FUNC("wlan has been done power on,call probe directly\n");
+ iRet = (*mtk_wcn_wlan_probe) ();
+ if (!iRet) {
+ WMT_INFO_FUNC("call wlan probe OK when do wlan register to wmt\n");
+ gWifiProbed = 0;
+ } else {
+ WMT_ERR_FUNC("call wlan probe fail(%d) when do wlan register to wmt\n", iRet);
+ return -2;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_wlan_reg);
+
+INT32 mtk_wcn_wmt_wlan_unreg(void)
+{
+ WMT_INFO_FUNC("wmt wlan cb unregister\n");
+ mtk_wcn_wlan_probe = NULL;
+ mtk_wcn_wlan_remove = NULL;
+ mtk_wcn_wlan_bus_tx_cnt = NULL;
+ mtk_wcn_wlan_bus_tx_cnt_clr = NULL;
+ mtk_wcn_wlan_emi_mpu_set_protection = NULL;
+ mtk_wcn_wlan_is_wifi_drv_own = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_wlan_unreg);
+
+MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value)
+{
+ g_pwr_off_flag = value;
+ if (g_pwr_off_flag)
+ WMT_DBG_FUNC("enable connsys power off flag\n");
+ else
+ WMT_INFO_FUNC("disable connsys power off, maybe need trigger coredump!\n");
+ return g_pwr_off_flag;
+}
+EXPORT_SYMBOL(mtk_wcn_set_connsys_power_off_flag);
+
+#ifdef CONFIG_MTK_COMBO_ANT
+/*
+* ctrlId: get ram code status opId or ram code download opId
+* pBuf: pointer to ANT ram code
+* length: total length of ANT ram code
+*/
+ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf,
+ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq)
+{
+ ENUM_WMT_ANT_RAM_STATUS eRet = 0;
+ P_OSAL_OP pOp = NULL;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_OSAL_SIGNAL pSignal;
+
+ /*1. parameter validation check */
+ /*for WMT_ANT_RAM_GET_STATUS, ignore pBuf and length */
+ /*for WMT_ANT_RAM_DOWNLOAD,
+ * pBuf must not be NULL, kernel space memory pointer
+ * length must be large than 0
+ */
+ if ((ctrlId < WMT_ANT_RAM_GET_STATUS) || (ctrlId >= WMT_ANT_RAM_CTRL_MAX)) {
+ WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId);
+ eRet = WMT_ANT_RAM_PARA_ERR;
+ return eRet;
+ }
+
+ if ((ctrlId == WMT_ANT_RAM_DOWNLOAD) && ((pBuf == NULL) || (length <= 0) ||
+ (length > 1000) || (seq >= WMT_ANT_RAM_SEQ_MAX) || (seq < WMT_ANT_RAM_START_PKT))) {
+ eRet = WMT_ANT_RAM_PARA_ERR;
+ WMT_ERR_FUNC
+ ("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x),seq(%d) .\n",
+ ctrlId, pBuf, length, seq);
+ return eRet;
+ }
+ /*get WMT opId */
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue =
+ (ctrlId == WMT_ANT_RAM_DOWNLOAD) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD;
+
+ pOp->op.opId =
+ (ctrlId == WMT_ANT_RAM_DOWNLOAD) ? WMT_OPID_ANT_RAM_DOWN : WMT_OPID_ANT_RAM_STA_GET;
+ pOp->op.au4OpData[0] = (size_t) pBuf;
+ pOp->op.au4OpData[1] = length;
+ pOp->op.au4OpData[2] = seq;
+
+
+ /*disable PSM monitor */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return MTK_WCN_BOOL_FALSE;
+ }
+ /*wakeup wmtd thread */
+ bRet = wmt_lib_put_act_op(pOp);
+
+ /*enable PSM monitor */
+ ENABLE_PSM_MONITOR();
+
+ WMT_INFO_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n",
+ pOp->op.opId,
+ bRet,
+ pOp->op.au4OpData[2], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed");
+
+ /*check return value and return result */
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ eRet = WMT_ANT_RAM_OP_ERR;
+ } else {
+ eRet = (ctrlId == WMT_ANT_RAM_DOWNLOAD) ?
+ WMT_ANT_RAM_DOWN_OK :
+ ((pOp->op.au4OpData[2] == 1) ? WMT_ANT_RAM_EXIST : WMT_ANT_RAM_NOT_EXIST);
+ }
+
+ return eRet;
+
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_ant_ram_ctrl);
+#endif
+MTK_WCN_BOOL mtk_wcn_wmt_do_reset(ENUM_WMTDRV_TYPE_T type)
+{
+ INT32 iRet = -1;
+ UINT8 *drv_name[] = {
+ [0] = "DRV_TYPE_BT",
+ [1] = "DRV_TYPE_FM",
+ [2] = "DRV_TYPE_GPS",
+ [3] = "DRV_TYPE_WIFI",
+ [4] = "DRV_TYPE_WMT",
+ [5] = "DRV_TYPE_ANT",
+ [11] = "DRV_TYPE_GPSL5",
+ };
+
+ if ((type < WMTDRV_TYPE_BT) || (type > WMTDRV_TYPE_ANT)) {
+ WMT_INFO_FUNC("Wrong driver type: %d, do not trigger reset.\n", type);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_INFO_FUNC("Subsystem trigger whole chip reset, reset source: %s\n", drv_name[type]);
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 0)
+ iRet = wmt_lib_trigger_reset();
+ else {
+ WMT_INFO_FUNC("assert has been triggered that no chip reset is required\n");
+ iRet = 0;
+ }
+
+ return iRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_do_reset);
+
+MTK_WCN_BOOL mtk_wcn_wmt_do_reset_only(ENUM_WMTDRV_TYPE_T type)
+{
+ INT32 iRet = -1;
+
+ WMT_INFO_FUNC("Whole chip reset without trigger assert\n");
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 0) {
+ chip_reset_only = 1;
+ iRet = wmt_lib_trigger_reset();
+ } else {
+ WMT_INFO_FUNC("assert has been triggered already\n");
+ iRet = 0;
+ }
+
+ return iRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_do_reset_only);
+
+VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value)
+{
+ wmt_lib_soc_set_wifiver(Value);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_set_wifi_ver);
+
+INT32 mtk_wcn_wmt_wifi_fem_cfg_report(PVOID pvInfoBuf)
+{
+ INT32 iRet = -1;
+
+ iRet = wmt_lib_wifi_fem_cfg_report(pvInfoBuf);
+ return iRet;
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_wifi_fem_cfg_report);
+
+VOID mtk_wcn_wmt_dump_wmtd_backtrace(VOID)
+{
+ wmt_lib_dump_wmtd_backtrace();
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_dump_wmtd_backtrace);
+
+UINT32 mtk_wmt_get_gps_lna_pin_num(VOID)
+{
+ return wmt_lib_get_gps_lna_pin_num();
+}
+EXPORT_SYMBOL(mtk_wmt_get_gps_lna_pin_num);
+
+VOID mtk_wmt_set_ext_ldo(UINT32 flag)
+{
+ wmt_lib_set_ext_ldo(flag);
+}
+EXPORT_SYMBOL(mtk_wmt_set_ext_ldo);
+
+INT32 mtk_wmt_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf,
+ UINT32 rx_data_buf_len, PUINT32 p_rx_data_len)
+{
+ return wmt_lib_gps_mcu_ctrl(p_tx_data_buf, tx_data_len, p_rx_data_buf, rx_data_buf_len,
+ p_rx_data_len);
+}
+EXPORT_SYMBOL(mtk_wmt_gps_mcu_ctrl);
+
+VOID mtk_wcn_wmt_set_mcif_mpu_protection(MTK_WCN_BOOL enable)
+{
+ mtk_consys_set_mcif_mpu_protection(enable);
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_set_mcif_mpu_protection);
+
+static MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl_by_type(MTK_WCN_BOOL gps_l1, MTK_WCN_BOOL gps_l5, MTK_WCN_BOOL suspend)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &pOp->signal;
+
+ pOp->op.opId = WMT_OPID_GPS_SUSPEND;
+ pOp->op.au4OpData[0] = (MTK_WCN_BOOL_FALSE == suspend ? 0 : 1);
+ pOp->op.au4OpData[1] = (MTK_WCN_BOOL_FALSE == gps_l1 ? 0 : 1);
+ pOp->op.au4OpData[2] = (MTK_WCN_BOOL_FALSE == gps_l5 ? 0 : 1);
+ pSignal->timeoutValue = (MTK_WCN_BOOL_FALSE == suspend) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME;
+
+ WMT_INFO_FUNC("wmt-exp: OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ /*do not check return value, we will do this either way */
+ wmt_lib_host_awake_get();
+ /* wake up chip first */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ wmt_lib_put_op_to_free_queue(pOp);
+ wmt_lib_host_awake_put();
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+ wmt_lib_host_awake_put();
+
+ if (bRet == MTK_WCN_BOOL_FALSE)
+ WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]);
+ else
+ WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ return bRet;
+}
+
+MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL suspend)
+{
+ return mtk_wmt_gps_suspend_ctrl_by_type(MTK_WCN_BOOL_TRUE, MTK_WCN_BOOL_TRUE, suspend);
+}
+EXPORT_SYMBOL(mtk_wmt_gps_suspend_ctrl);
+
+MTK_WCN_BOOL mtk_wmt_gps_l1_suspend_ctrl(MTK_WCN_BOOL suspend)
+{
+ return mtk_wmt_gps_suspend_ctrl_by_type(MTK_WCN_BOOL_TRUE, MTK_WCN_BOOL_FALSE, suspend);
+}
+EXPORT_SYMBOL(mtk_wmt_gps_l1_suspend_ctrl);
+
+MTK_WCN_BOOL mtk_wmt_gps_l5_suspend_ctrl(MTK_WCN_BOOL suspend)
+{
+ return mtk_wmt_gps_suspend_ctrl_by_type(MTK_WCN_BOOL_FALSE, MTK_WCN_BOOL_TRUE, suspend);
+}
+EXPORT_SYMBOL(mtk_wmt_gps_l5_suspend_ctrl);
+
+INT32 mtk_wcn_wmt_mpu_lock_aquire(VOID)
+{
+ return wmt_lib_mpu_lock_aquire();
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_mpu_lock_aquire);
+
+VOID mtk_wcn_wmt_mpu_lock_release(VOID)
+{
+ wmt_lib_mpu_lock_release();
+}
+EXPORT_SYMBOL(mtk_wcn_wmt_mpu_lock_release);
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0374a4727e6b6a5ccdeeaee4a41169dddb1356a
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-FUNC]"
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+
+#include "wmt_func.h"
+#include "wmt_lib.h"
+#include "wmt_core.h"
+#include "wmt_exp.h"
+#include "wmt_detect.h"
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+#if CFG_FUNC_BT_SUPPORT
+
+static INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_bt_ops = {
+ /* BT subsystem function on/off */
+ .func_on = wmt_func_bt_on,
+ .func_off = wmt_func_bt_off
+};
+#endif
+
+#if CFG_FUNC_FM_SUPPORT
+
+static INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_fm_ops = {
+ /* FM subsystem function on/off */
+ .func_on = wmt_func_fm_on,
+ .func_off = wmt_func_fm_off
+};
+#endif
+
+#if CFG_FUNC_GPS_SUPPORT
+
+static INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_gps_ops = {
+ /* GPS subsystem function on/off */
+ .func_on = wmt_func_gps_on,
+ .func_off = wmt_func_gps_off
+};
+
+#endif
+
+#if CFG_FUNC_GPSL5_SUPPORT
+
+static INT32 wmt_func_gpsl5_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_gpsl5_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_gpsl5_ops = {
+ /* GPS subsystem function on/off */
+ .func_on = wmt_func_gpsl5_on,
+ .func_off = wmt_func_gpsl5_off
+};
+
+#endif
+
+#if CFG_FUNC_WIFI_SUPPORT
+static INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_wifi_ops = {
+ /* Wi-Fi subsystem function on/off */
+ .func_on = wmt_func_wifi_on,
+ .func_off = wmt_func_wifi_off
+};
+#endif
+
+
+#if CFG_FUNC_ANT_SUPPORT
+
+static INT32 wmt_func_ant_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+static INT32 wmt_func_ant_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf);
+
+WMT_FUNC_OPS wmt_func_ant_ops = {
+ /* BT subsystem function on/off */
+ .func_on = wmt_func_ant_on,
+ .func_off = wmt_func_ant_off
+};
+#endif
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+#if CFG_FUNC_GPS_SUPPORT
+CMB_PIN_CTRL_REG eediPinOhRegs[] = {
+ {
+ /* pull down ctrl register */
+ .regAddr = 0x80050020,
+ .regValue = ~(0x1L << 5),
+ .regMask = 0x00000020L,
+ },
+ {
+ /* pull up ctrl register */
+ .regAddr = 0x80050000,
+ .regValue = 0x1L << 5,
+ .regMask = 0x00000020L,
+ },
+ {
+ /* iomode ctrl register */
+ .regAddr = 0x80050110,
+ .regValue = 0x1L << 0,
+ .regMask = 0x00000007L,
+ },
+ {
+ /* output high/low ctrl register */
+ .regAddr = 0x80050040,
+ .regValue = 0x1L << 5,
+ .regMask = 0x00000020L,
+ }
+
+};
+
+CMB_PIN_CTRL_REG eediPinOlRegs[] = {
+ {
+ .regAddr = 0x80050020,
+ .regValue = 0x1L << 5,
+ .regMask = 0x00000020L,
+ },
+ {
+ .regAddr = 0x80050000,
+ .regValue = ~(0x1L << 5),
+ .regMask = 0x00000020L,
+ },
+ {
+ .regAddr = 0x80050110,
+ .regValue = 0x1L << 0,
+ .regMask = 0x00000007L,
+ },
+ {
+ .regAddr = 0x80050040,
+ .regValue = ~(0x1L << 5),
+ .regMask = 0x00000020L,
+ }
+};
+
+CMB_PIN_CTRL_REG eedoPinOhRegs[] = {
+ {
+ .regAddr = 0x80050020,
+ .regValue = ~(0x1L << 7),
+ .regMask = 0x00000080L,
+ },
+ {
+ .regAddr = 0x80050000,
+ .regValue = 0x1L << 7,
+ .regMask = 0x00000080L,
+ },
+ {
+ .regAddr = 0x80050110,
+ .regValue = 0x1L << 12,
+ .regMask = 0x00007000L,
+ },
+ {
+ .regAddr = 0x80050040,
+ .regValue = 0x1L << 7,
+ .regMask = 0x00000080L,
+ }
+};
+
+
+CMB_PIN_CTRL_REG eedoPinOlRegs[] = {
+ {
+ .regAddr = 0x80050020,
+ .regValue = 0x1L << 7,
+ .regMask = 0x00000080L,
+ },
+ {
+ .regAddr = 0x80050000,
+ .regValue = ~(0x1L << 7),
+ .regMask = 0x00000080L,
+ },
+ {
+ .regAddr = 0x80050110,
+ .regValue = 0x1L << 12,
+ .regMask = 0x00007000L,
+ },
+ {
+ .regAddr = 0x80050040,
+ .regValue = ~(0x1L << 7),
+ .regMask = 0x00000080L,
+ }
+
+};
+
+CMB_PIN_CTRL_REG gsyncPinOnRegs[] = {
+ {
+ .regAddr = 0x80050110,
+ .regValue = 0x3L << 20,
+ .regMask = 0x7L << 20,
+ }
+
+};
+
+CMB_PIN_CTRL_REG gsyncPinOffRegs[] = {
+ {
+ .regAddr = 0x80050110,
+ .regValue = 0x0L << 20,
+ .regMask = 0x7L << 20,
+ }
+};
+
+/* templete usage for GPIO control */
+CMB_PIN_CTRL gCmbPinCtrl[3] = {
+ {
+ .pinId = CMB_PIN_EEDI_ID,
+ .regNum = 4,
+ .pFuncOnArray = eediPinOhRegs,
+ .pFuncOffArray = eediPinOlRegs,
+ },
+ {
+ .pinId = CMB_PIN_EEDO_ID,
+ .regNum = 4,
+ .pFuncOnArray = eedoPinOhRegs,
+ .pFuncOffArray = eedoPinOlRegs,
+ },
+ {
+ .pinId = CMB_PIN_GSYNC_ID,
+ .regNum = 1,
+ .pFuncOnArray = gsyncPinOnRegs,
+ .pFuncOffArray = gsyncPinOffRegs,
+ }
+};
+#endif
+
+
+
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#if CFG_FUNC_BT_SUPPORT
+
+INT32 _osal_inline_ wmt_func_bt_ctrl(ENUM_FUNC_STATE funcState)
+{
+ /*only need to send turn BT subsystem wmt command */
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT,
+ (FUNC_ON ==
+ funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE);
+}
+
+INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = -1;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE);
+
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_ON;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl failed(%d)(%lu)(%lu)\n",
+ iRet, ctrlPa1, ctrlPa2);
+ return -1;
+ }
+ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_on) failed(%d)\n", iRet);
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+
+ return -2;
+ }
+ osal_set_bit(WMT_BT_ON, &gBtWifiGpsState);
+ return 0;
+}
+
+INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet1 = -1;
+ INT32 iRet2 = -1;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE);
+
+ iRet1 = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE);
+ if (iRet1)
+ WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_off) failed(%d)\n", iRet1);
+
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet2 = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ if (iRet2)
+ WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl(bt_off) failed(%d)\n", iRet2);
+
+ if (iRet1 + iRet2)
+ return -1;
+
+ osal_clear_bit(WMT_BT_ON, &gBtWifiGpsState);
+ return 0;
+}
+
+#endif
+#if CFG_FUNC_ANT_SUPPORT
+
+INT32 _osal_inline_ wmt_func_ant_ctrl(ENUM_FUNC_STATE funcState)
+{
+ /*only need to send turn BT subsystem wmt command */
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT,
+ (FUNC_ON ==
+ funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE);
+}
+
+INT32 wmt_func_ant_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT, MTK_WCN_BOOL_TRUE);
+}
+
+INT32 wmt_func_ant_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT, MTK_WCN_BOOL_FALSE);
+}
+
+#endif
+
+#if CFG_FUNC_GPS_SUPPORT
+
+INT32 _osal_inline_ wmt_func_gps_ctrl(ENUM_FUNC_STATE funcState)
+{
+ /*send turn GPS subsystem wmt command */
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_GPS,
+ (FUNC_ON ==
+ funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE);
+}
+
+INT32 wmt_func_gps_pre_ctrl(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf, ENUM_FUNC_STATE funcStatus)
+{
+ UINT32 i = 0;
+ UINT32 iRet = 0;
+ UINT32 regAddr = 0;
+ UINT32 regValue = 0;
+ UINT32 regMask = 0;
+ UINT32 regNum = 0;
+ P_CMB_PIN_CTRL_REG pReg;
+ P_CMB_PIN_CTRL pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID];
+ WMT_CTRL_DATA ctrlData;
+ WMT_IC_PIN_ID wmtIcPinId = WMT_IC_PIN_MAX;
+ /* sanity check */
+ if (FUNC_ON != funcStatus && FUNC_OFF != funcStatus) {
+ WMT_ERR_FUNC("invalid funcStatus(%d)\n", funcStatus);
+ return -1;
+ }
+ /* turn on GPS sync function on both side */
+ ctrlData.ctrlId = WMT_CTRL_GPS_SYNC_SET;
+ ctrlData.au4CtrlData[0] = (funcStatus == FUNC_ON) ? 1 : 0;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /*we suppose this would never print */
+ WMT_ERR_FUNC("ctrl GPS_SYNC_SET(%d) fail, ret(%d)\n", funcStatus, iRet);
+ /* TODO:[FixMe][George] error handling? */
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GPS_SYNC_SET(%d) ok\n", funcStatus);
+
+ if ((pOps->ic_pin_ctrl == NULL) || (pOps->ic_pin_ctrl(WMT_IC_PIN_GSYNC, FUNC_ON ==
+ funcStatus ? WMT_IC_PIN_MUX : WMT_IC_PIN_GPIO, 1) < 0)) {
+ /*WMT_IC_PIN_GSYNC */
+ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID];
+ regNum = pCmbPinCtrl->regNum;
+ for (i = 0; i < regNum; i++) {
+ pReg =
+ FUNC_ON ==
+ funcStatus ? &pCmbPinCtrl->
+ pFuncOnArray[i] : &pCmbPinCtrl->pFuncOffArray[i];
+ regAddr = pReg->regAddr;
+ regValue = pReg->regValue;
+ regMask = pReg->regMask;
+
+ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask);
+ if (iRet) {
+ WMT_ERR_FUNC("set reg for GPS_SYNC function fail(%d)\n", iRet);
+ /* TODO:[FixMe][Chaozhong] error handling? */
+ return -2;
+ }
+
+ }
+ } else {
+ WMT_DBG_FUNC("set reg for GPS_SYNC function okay by chip ic_pin_ctrl\n");
+ }
+ WMT_DBG_FUNC("ctrl combo chip gps sync function succeed\n");
+ /* turn on GPS lna ctrl function */
+ if (pConf != NULL) {
+ if (pConf->wmt_gps_lna_enable == 0) {
+
+ WMT_INFO_FUNC("host pin used for gps lna\n");
+ /* host LNA ctrl pin needed */
+ ctrlData.ctrlId = WMT_CTRL_GPS_LNA_SET;
+ ctrlData.au4CtrlData[0] = funcStatus == FUNC_ON ? 1 : 0;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /*we suppose this would never print */
+ WMT_ERR_FUNC("ctrl host GPS_LNA output high fail, ret(%d)\n", iRet);
+ /* TODO:[FixMe][Chaozhong] error handling? */
+ return -3;
+ }
+ WMT_INFO_FUNC("GPS LNA pin number(%d)\n", mtk_wmt_get_gps_lna_pin_num());
+ WMT_DBG_FUNC("ctrl host gps lna function succeed\n");
+ } else {
+ WMT_INFO_FUNC("combo chip pin(%s) used for gps lna\n",
+ pConf->wmt_gps_lna_pin == 0 ? "EEDI" : "EEDO");
+ wmtIcPinId =
+ pConf->wmt_gps_lna_pin == 0 ? WMT_IC_PIN_EEDI : WMT_IC_PIN_EEDO;
+ if ((pOps->ic_pin_ctrl == NULL) || (pOps->ic_pin_ctrl(wmtIcPinId, FUNC_ON ==
+ funcStatus ? WMT_IC_PIN_GPIO_HIGH : WMT_IC_PIN_GPIO_LOW, 1) < 0)) {
+ /*WMT_IC_PIN_GSYNC */
+ if (pConf->wmt_gps_lna_pin == 0) {
+ /* EEDI needed */
+ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDI_ID];
+ } else if (pConf->wmt_gps_lna_pin == 1) {
+ /* EEDO needed */
+ pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDO_ID];
+ }
+ regNum = pCmbPinCtrl->regNum;
+ for (i = 0; i < regNum; i++) {
+ pReg =
+ funcStatus == FUNC_ON ? &pCmbPinCtrl->pFuncOnArray[i] :
+ &pCmbPinCtrl->pFuncOffArray[i];
+ regAddr = pReg->regAddr;
+ regValue = pReg->regValue;
+ regMask = pReg->regMask;
+
+ iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask);
+ if (iRet) {
+ WMT_ERR_FUNC
+ ("set reg for GPS_LNA function fail(%d)\n",
+ iRet);
+ /* TODO:[FixMe][Chaozhong] error handling? */
+ return -3;
+ }
+ }
+ WMT_INFO_FUNC("ctrl combo chip gps lna succeed\n");
+ } else {
+ WMT_INFO_FUNC
+ ("set reg for GPS_LNA function okay by chip ic_pin_ctrl\n");
+ }
+ }
+ }
+ return 0;
+
+}
+
+INT32 wmt_func_gps_pre_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_ON);
+}
+
+INT32 wmt_func_gps_pre_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+
+ return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_OFF);
+}
+
+
+INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+ UINT8 co_clock_type = 0;
+
+ if (!pConf)
+ return -1;
+
+ co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */
+ if (!osal_test_bit(WMT_FM_ON, &gGpsFmState) && !osal_test_bit(WMT_GPSL5_ON, &gGpsFmState)) {
+ ctrlPa1 = GPS_PALDO;
+ ctrlPa2 = PALDO_ON;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ } else {
+ WMT_INFO_FUNC("LDO VCN28 has been turn on by FM or GPSL5\n");
+ }
+ }
+ }
+ if (!osal_test_bit(WMT_GPSL5_ON, &gGpsFmState))
+ iRet = wmt_func_gps_pre_on(pOps, pConf);
+ else
+ WMT_INFO_FUNC("gps has been pre on by GPSL5\n");
+ if (iRet == 0) {
+ if (!pConf || pConf->wmt_gps_suspend_ctrl == 0)
+ iRet = wmt_func_gps_ctrl(FUNC_ON);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (!iRet) {
+ osal_set_bit(WMT_GPS_ON, &gBtWifiGpsState);
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) /* use SOC external LNA */
+ osal_set_bit(WMT_GPS_ON, &gGpsFmState);
+ osal_clear_bit(WMT_GPS_SUSPEND, &gGpsFmState);
+ }
+ }
+ }
+ return iRet;
+}
+
+INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+ unsigned long ctrlPa1 = 0;
+ unsigned long ctrlPa2 = 0;
+ UINT8 co_clock_type = 0;
+
+ if (!pConf)
+ return -1;
+
+ co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (osal_test_bit(WMT_GPSL5_ON, &gGpsFmState))
+ WMT_INFO_FUNC("GPSL5 is still on, do not pre off gps\n");
+ else if (!osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState))
+ iRet = wmt_func_gps_pre_off(pOps, pConf);
+ if (iRet == 0) {
+ if (!pConf || pConf->wmt_gps_suspend_ctrl == 0)
+ iRet = wmt_func_gps_ctrl(FUNC_OFF);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (!iRet)
+ osal_clear_bit(WMT_GPS_ON, &gBtWifiGpsState);
+ }
+ }
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */
+ if (osal_test_bit(WMT_FM_ON, &gGpsFmState) || osal_test_bit(WMT_GPSL5_ON, &gGpsFmState))
+ WMT_INFO_FUNC("FM or GPSL5 is still on, do not turn off LDO VCN28\n");
+ else if (osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState))
+ WMT_INFO_FUNC("It's GPS suspend mode, LDO VCN28 has been turned off\n");
+ else {
+ ctrlPa1 = GPS_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ }
+ osal_clear_bit(WMT_GPS_ON, &gGpsFmState);
+ }
+ if (pConf->wmt_gps_suspend_ctrl == 1)
+ osal_set_bit(WMT_GPS_SUSPEND, &gGpsFmState);
+ }
+ return iRet;
+
+}
+#endif
+
+#if CFG_FUNC_GPSL5_SUPPORT
+INT32 _osal_inline_ wmt_func_gpsl5_ctrl(ENUM_FUNC_STATE funcState)
+{
+ /*send turn GPS subsystem wmt command */
+ return wmt_core_func_ctrl_cmd(6,
+ (FUNC_ON ==
+ funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE);
+}
+
+INT32 wmt_func_gpsl5_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+ UINT8 co_clock_type = 0;
+
+ if (!pConf) {
+ WMT_INFO_FUNC("pConf == NULL\n");
+ return -1;
+ }
+
+ co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */
+ if (!osal_test_bit(WMT_FM_ON, &gGpsFmState) &&
+ !osal_test_bit(WMT_GPS_ON, &gGpsFmState)) {
+ ctrlPa1 = GPS_PALDO;
+ ctrlPa2 = PALDO_ON;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ } else {
+ WMT_INFO_FUNC("LDO VCN28 has been turn on by FM or GPSL1\n");
+ }
+ }
+ }
+ if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState))
+ iRet = wmt_func_gps_pre_on(pOps, pConf);
+ else
+ WMT_INFO_FUNC("gps has been pre on by GPSL1\n");
+ if (iRet == 0) {
+ if (pConf->wmt_gps_suspend_ctrl == 0)
+ iRet = wmt_func_gpsl5_ctrl(FUNC_ON);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (!iRet) {
+ osal_set_bit(WMT_GPSL5_ON, &gBtWifiGpsState);
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) /* use SOC external LNA */
+ osal_set_bit(WMT_GPSL5_ON, &gGpsFmState);
+ osal_clear_bit(WMT_GPSL5_SUSPEND, &gGpsFmState);
+ }
+ }
+ }
+ return iRet;
+}
+
+INT32 wmt_func_gpsl5_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+ unsigned long ctrlPa1 = 0;
+ unsigned long ctrlPa2 = 0;
+ UINT8 co_clock_type = 0;
+
+ if (!pConf) {
+ WMT_INFO_FUNC("pConf == NULL\n");
+ return -1;
+ }
+
+ co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (osal_test_bit(WMT_GPS_ON, &gGpsFmState))
+ WMT_INFO_FUNC("GPSL1 is still on, do not pre off gps\n");
+ else if (!osal_test_bit(WMT_GPSL5_SUSPEND, &gGpsFmState))
+ iRet = wmt_func_gps_pre_off(pOps, pConf);
+ if (iRet == 0) {
+ if (pConf->wmt_gps_suspend_ctrl == 0)
+ iRet = wmt_func_gpsl5_ctrl(FUNC_OFF);
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (!iRet)
+ osal_clear_bit(WMT_GPSL5_ON, &gBtWifiGpsState);
+ }
+ }
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */
+ if (osal_test_bit(WMT_FM_ON, &gGpsFmState) || osal_test_bit(WMT_GPS_ON, &gGpsFmState))
+ WMT_INFO_FUNC("FM or GPSL1 is still on, do not turn off LDO VCN28\n");
+ else if (osal_test_bit(WMT_GPSL5_SUSPEND, &gGpsFmState))
+ WMT_INFO_FUNC("It's GPS suspend mode, LDO VCN28 has been turned off\n");
+ else {
+ ctrlPa1 = GPS_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ }
+ osal_clear_bit(WMT_GPSL5_ON, &gGpsFmState);
+ }
+ if (pConf->wmt_gps_suspend_ctrl == 1)
+ osal_set_bit(WMT_GPSL5_SUSPEND, &gGpsFmState);
+ }
+ return iRet;
+
+}
+#endif
+
+#if CFG_FUNC_FM_SUPPORT
+
+INT32 _osal_inline_ wmt_func_fm_ctrl(ENUM_FUNC_STATE funcState)
+{
+ /*only need to send turn FM subsystem wmt command */
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM,
+ (FUNC_ON ==
+ funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE);
+}
+
+
+INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+ INT32 iRet = -1;
+ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ if (co_clock_type) {
+ if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState) && !osal_test_bit(WMT_GPSL5_ON, &gGpsFmState)) {
+ ctrlPa1 = FM_PALDO;
+ ctrlPa2 = PALDO_ON;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ } else {
+ WMT_INFO_FUNC("LDO VCN28 has been turn on by GPS\n");
+ }
+ } else
+ WMT_ERR_FUNC("wmt-func: co_clock_type is not 1!\n");
+ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE);
+ if (!iRet) {
+ if (co_clock_type)
+ osal_set_bit(WMT_FM_ON, &gGpsFmState);
+ }
+ return iRet;
+ }
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE);
+}
+
+INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+ INT32 iRet = -1;
+ UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f);
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE);
+ if (co_clock_type) {
+ if (osal_test_bit(WMT_GPS_ON, &gGpsFmState) || osal_test_bit(WMT_GPSL5_ON, &gGpsFmState)) {
+ WMT_INFO_FUNC("GPS is still on, do not turn off LDO VCN28\n");
+ } else {
+ ctrlPa1 = FM_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ }
+ osal_clear_bit(WMT_FM_ON, &gGpsFmState);
+ }
+ return iRet;
+ }
+ return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE);
+}
+
+#endif
+
+#if CFG_FUNC_WIFI_SUPPORT
+
+INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState)
+{
+ INT32 iRet = 0;
+ ULONG ctrlPa1 = WMT_SDIO_FUNC_WIFI;
+ ULONG ctrlPa2 = (funcState == FUNC_ON) ? 1 : 0; /* turn on Wi-Fi driver */
+
+ iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-FUNC: turn on WIFI function fail (%d)", iRet);
+ return -1;
+ }
+ return 0;
+}
+
+
+INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ return wmt_func_wifi_ctrl(FUNC_ON);
+
+ if (mtk_wcn_wlan_probe != NULL) {
+ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan probe\n");
+ iRet = (*mtk_wcn_wlan_probe) ();
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan probe fail(%d)\n", iRet);
+ iRet = -1;
+ } else {
+ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan probe ok\n");
+ }
+ } else {
+ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_probe\n");
+ gWifiProbed = 1;
+ iRet = -2;
+ }
+ if (!iRet)
+ osal_set_bit(WMT_WIFI_ON, &gBtWifiGpsState);
+ return iRet;
+}
+
+INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf)
+{
+ INT32 iRet = 0;
+
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ return wmt_func_wifi_ctrl(FUNC_OFF);
+
+ if (mtk_wcn_wlan_remove != NULL) {
+ WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan remove\n");
+ iRet = (*mtk_wcn_wlan_remove) ();
+ if (iRet) {
+ WMT_ERR_FUNC("WMT-FUNC: wmt call wlan remove fail(%d)\n", iRet);
+ iRet = -1;
+ } else {
+ WMT_WARN_FUNC("WMT-FUNC: wmt call wlan remove ok\n");
+ }
+ } else {
+ WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_remove\n");
+ iRet = -2;
+ }
+ if (!iRet)
+ osal_clear_bit(WMT_WIFI_ON, &gBtWifiGpsState);
+ return iRet;
+}
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b033ad92dd4c42183bc86b441884bede8a69d49
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c
@@ -0,0 +1,1909 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-IC]"
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "osal.h"
+#include "wmt_ic.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "stp_core.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define DEFAULT_PATCH_FRAG_SIZE (1000)
+#define MT6620E2_PATCH_FRAG_SIZE (900)
+#define WMT_PATCH_FRAG_1ST (0x1)
+#define WMT_PATCH_FRAG_MID (0x2)
+#define WMT_PATCH_FRAG_LAST (0x3)
+
+#define CFG_CHECK_WMT_RESULT (1)
+/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */
+#define CFG_WMT_BT_PORT2 (0)
+
+#define CFG_SET_OPT_REG (0)
+#define CFG_WMT_I2S_DBGUART_SUPPORT (0)
+#define CFG_SET_OPT_REG_SWLA (0)
+#define CFG_SET_OPT_REG_MCUCLK (0)
+#define CFG_SET_OPT_REG_MCUIRQ (0)
+
+#define CFG_WMT_COREDUMP_ENABLE 0
+
+#define CFG_WMT_MULTI_PATCH (1)
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+#if !(CFG_WMT_MULTI_PATCH)
+static UINT8 gDefPatchName[NAME_MAX + 1];
+#endif
+static UINT8 gFullPatchName[NAME_MAX + 1];
+static const WMT_IC_INFO_S *gp_mt6620_info;
+static WMT_PATCH gp_mt6620_patch_info;
+
+static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 };
+static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 };
+
+#if 0
+static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 };
+static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 };
+#endif
+static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 };
+static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 };
+static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 };
+static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 };
+static UINT8 WMT_QUERY_STP_EVT_UART[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 };
+static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF };
+static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+
+#if CFG_WMT_MULTI_PATCH
+static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x64, 0x0E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x38, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+#endif
+
+static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 };
+static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 };
+static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 };
+static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 };
+
+#if CFG_WMT_BT_PORT2
+static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 };
+static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+/*coex cmd/evt++*/
+static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x04, 0x00, 0x01, 0xAA, 0xBB, 0xCC };
+static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C,
+ 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A,
+ 0x00, 0x04,
+ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE
+};
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09,
+ 0x00, 0x05,
+ 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB
+};
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+/*coex cmd/evt--*/
+static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 };
+static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 };
+
+#if 0
+static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 };
+static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 };
+#endif
+
+static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+/* enable all interrupt */
+static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */
+ , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */
+ , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */
+};
+
+static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */
+static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */
+ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */
+ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */
+ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */
+};
+
+static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */
+static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */
+ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */
+ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */
+ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */
+ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */
+};
+
+static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+};
+#endif
+
+#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */
+static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */
+ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */
+ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */
+ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */
+};
+
+static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */
+#if 1 /* Ray */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */
+ /* cirq_int_n */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */
+ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */
+ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 5 registers */
+};
+#elif 0 /* KC */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */
+ , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */
+ , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */
+ , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */
+ , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */
+ , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */
+ , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */
+ , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */
+ , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+};
+#endif
+#endif
+
+/* stp sdio init scripts */
+static struct init_script init_table_1_1[] = {
+ /* table_1_1 is only applied to common SDIO interface */
+ INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"),
+ /* only applied to MT6620 E1/E2? */
+ INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"),
+};
+
+
+static struct init_script init_table_1_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"),
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"),
+ INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"),
+};
+
+static struct init_script init_table_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_3[] = {
+ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"),
+#if CFG_WMT_BT_PORT2
+ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"),
+#endif
+};
+
+#if 0
+static struct init_script init_table_3_1[] = {
+ INIT_CMD(WMT_WAKEUP_EN_GATE_CMD, WMT_WAKEUP_EN_GATE_EVT, "ensable gating"),
+};
+#endif
+
+static struct init_script init_table_4[] = {
+ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"),
+};
+
+static struct init_script init_table_5[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"),
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_5_1[] = {
+ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"),
+};
+
+static struct init_script init_table_6[] = {
+#if 0
+ INIT_CMD(WMT_SET_OSC32K_BYPASS_CMD, WMT_SET_OSC32K_BYPASS_EVT, "set OSC32k by pass mode."),
+#endif
+ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"),
+};
+
+#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG
+static struct init_script set_registers[] = {
+ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */
+ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */
+#if CFG_WMT_I2S_DBGUART_SUPPORT
+ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"),
+#endif
+#if CFG_SET_OPT_REG_SWLA
+ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUCLK
+ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUIRQ
+ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"),
+#endif
+};
+#endif
+
+static struct init_script coex_table[] = {
+ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"),
+ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"),
+ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"),
+ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"),
+ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"),
+};
+
+/* MT6620 Chip Version and Info Table */
+static const WMT_IC_INFO_S mt6620_info_table[] = {
+ {
+ .u4HwVer = 0x8A00,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E1,
+ .cPatchNameExt = WMT_IC_PATCH_NO_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_FALSE,
+ },
+ {
+ .u4HwVer = 0x8A01,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_NO_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_FALSE,
+ },
+ {
+ .u4HwVer = 0x8A10,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E3,
+ .cPatchNameExt = WMT_IC_PATCH_E3_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A11,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E4,
+ .cPatchNameExt = WMT_IC_PATCH_E3_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A30,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E6,
+ .cPatchNameExt = WMT_IC_PATCH_E6_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B30,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E6,
+ .cPatchNameExt = WMT_IC_PATCH_E6_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B31,
+ .cChipName = WMT_IC_NAME_MT6620,
+ .cChipVersion = WMT_IC_VER_E7,
+ .cPatchNameExt = WMT_IC_PATCH_E6_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+};
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6620_sw_deinit(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6620_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6620_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6620_ver_check(VOID);
+
+static const WMT_IC_INFO_S *mt6620_find_wmt_ic_info(const UINT32 hw_ver);
+
+static INT32 wmt_stp_init_coex(VOID);
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mt6620_patch_dwn(UINT32 index);
+static INT32 mt6620_patch_info_prepare(VOID);
+#else
+static INT32 mt6620_update_patch_name(VOID);
+
+static INT32 mt6620_patch_dwn(VOID);
+#endif
+static MTK_WCN_BOOL mt6620_quick_sleep_flag_get(VOID);
+
+static MTK_WCN_BOOL mt6620_aee_dump_flag_get(VOID);
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/* MT6620 Operation Function Table */
+WMT_IC_OPS wmt_ic_ops_mt6620 = {
+ .icId = 0x6620,
+ .sw_init = mt6620_sw_init,
+ .sw_deinit = mt6620_sw_deinit,
+ .ic_pin_ctrl = mt6620_pin_ctrl,
+ .ic_ver_check = mt6620_ver_check,
+ .co_clock_ctrl = NULL,
+ .is_quick_sleep = mt6620_quick_sleep_flag_get,
+ .is_aee_dump_support = mt6620_aee_dump_flag_get,
+ .trigger_stp_assert = NULL,
+ .deep_sleep_ctrl = NULL,
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+#if 0
+static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[256];
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+ UINT32 hw_ver;
+
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_mt6620_info != NULL);
+ if ((gp_mt6620_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_mt6620_info(0x%p), pWmtHifConf(0x%p)\n",
+ gp_mt6620_info, pWmtHifConf);
+ return -1;
+ }
+
+ hw_ver = gp_mt6620_info->u4HwVer;
+
+ /* 4 <3.1> start init for sdio */
+ if (pWmtHifConf->hifType == WMT_HIF_SDIO) {
+ /* 1. enable all INT32 */
+ /* 2. disable mcu gate (only MT6620E1/E2) */
+ iRet = wmt_core_init_script(init_table_1_1, osal_array_size(init_table_1_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet);
+ osal_assert(0);
+ return -1;
+ }
+ }
+ /* 4 <3.2> start init for uart */
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* init variable fields for script execution */
+ osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control no flow control */
+ osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control no flow control */
+ /* 3. Query chip baud rate (TEST-ONLY) */
+ /* 4. Query chip STP options (TEST-ONLY) */
+ /* 5. Change chip baud rate: t_baud */
+ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]);
+ */
+ iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 6. Set host baudrate and flow control */
+ ctrlPa1 = pWmtHifConf->au4HifConf[0];
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0],
+ iRet);
+ return -3;
+ }
+ WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]);
+
+ /* 7. Wake up chip and check event */
+/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res,
+ MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != 1)) {
+ WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res);
+ return -4;
+ }
+
+ osal_memset(evtBuf, 0, osal_sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res);
+#ifdef CFG_DUMP_EVT
+ WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5]);
+#endif
+ if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) {
+ WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet);
+ return -5;
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */
+
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp
+ (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n");
+ return -6;
+ }
+#endif
+
+ /* 8. Query baud rate (TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet);
+ return -7;
+ }
+ }
+
+ /* 9. download patch */
+ iRet = mt6620_patch_dwn();
+
+ WMT_INFO_FUNC("Not to check the patch validity\n");
+#if 0
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d)\n", iRet);
+ return -8;
+ }
+ WMT_INFO_FUNC("patch dwn ok\n");
+#endif
+ /* 10. WMT Reset command */
+ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -9;
+ }
+ iRet = wmt_stp_init_coex();
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -10;
+ }
+ WMT_INFO_FUNC("init_coex ok\n");
+
+#if 0
+ /*10-2 enable 32K By Pass Mode */
+ /* if hwVer = E3/E4, please enable 32K by pass mode. */
+ /* does not support mt6620E1/E2, always enable 32k bypass mode */
+ /* if ((hwVer == 0x8a10 || hwVer == 0x8a11)) */
+ {
+ WMT_INFO_FUNC("WMT-CORE: init_table_6 OSC32K");
+ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6));
+ if (iRet == 0) {
+ WMT_DBG_FUNC("WMT-CORE: init_table_6 OSC32K, successful\n");
+ } else {
+ WMT_WARN_FUNC("init table 6 OSC32K fail, continue init...\n");
+ /*return -11; */
+ }
+ }
+#endif
+
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* 11. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -12;
+ }
+
+ /* 12. Enable host STP-UART mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet);
+ return -13;
+ }
+ WMT_INFO_FUNC("enable host STP-UART-FULL mode\n");
+ /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+ /* 14. Query chip STP options (TEST-ONLY) */
+ /* 15. Query baud rate (stp, TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -14;
+ }
+ }
+
+ /* 15. Set FM strap */
+ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n",
+ pWmtHifConf->au4StrapConf[0], iRet);
+ return -15;
+ }
+ WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]);
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers));
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -16;
+ }
+#endif
+
+#if 0
+ /* 16. trace32 dump when fw assert */
+ {
+ INT32 val = 0x00000001;
+
+ WMT_INFO_FUNC("WMT-CORE: enable assert dump");
+ wmt_reg_rw_raw(1, 0x0100092c, &val, 0xFFFFFFFF);
+ }
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6620_info != NULL);
+ if (gp_mt6620_info != NULL) {
+ if (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ return 0;
+}
+#endif
+
+static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[256];
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ UINT32 hw_ver;
+ UINT32 patch_num = 0;
+ UINT32 patch_index = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_mt6620_info != NULL);
+ if ((gp_mt6620_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_mt6620_info(0x%p), pWmtHifConf(0x%p)\n",
+ gp_mt6620_info, pWmtHifConf);
+ return -1;
+ }
+
+ hw_ver = gp_mt6620_info->u4HwVer;
+
+ /* 4 <3.1> start init for sdio */
+ if (pWmtHifConf->hifType == WMT_HIF_SDIO) {
+ /* 1. enable all INT32 */
+ /* 2. disable mcu gate (only MT6620E1/E2) */
+ iRet = wmt_core_init_script(init_table_1_1, osal_array_size(init_table_1_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet);
+ osal_assert(0);
+ return -1;
+ }
+ }
+ /* 4 <3.2> start init for uart */
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+
+ /* init variable fields for script execution */
+ osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ if (pWmtHifConf->uartFcCtrl == WMT_UART_MTK_SW_FC) {
+ WMT_INFO_FUNC("enable MTK SW Flow Control\n");
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x80; /* MTK SW flow control */
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x80; /* MTK SW flow control */
+ } else if (pWmtHifConf->uartFcCtrl == WMT_UART_LUX_SW_FC) {
+ WMT_INFO_FUNC("enable Linux SW Flow Control\n");
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x80; /* Linux SW flow control */
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x80; /* Linux SW flow control */
+ } else if (pWmtHifConf->uartFcCtrl == WMT_UART_HW_FC) {
+ WMT_INFO_FUNC("enable HW Flow Control\n");
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0xC0; /* HW flow control */
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0xC0; /* HW flow control */
+ } else {
+ /* WMT_UART_NO_FC and all other cases!!! */
+ WMT_INFO_FUNC("no Flow Control (uartFcCtrl:%d)\n", pWmtHifConf->uartFcCtrl);
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* no flow control */
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* no flow control */
+ }
+
+ /* 3. Query chip baud rate (TEST-ONLY) */
+ /* 4. Query chip STP options (TEST-ONLY) */
+ /* 5. Change chip baud rate: t_baud */
+ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */
+ iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 6. Set host baudrate and flow control */
+ ctrlPa1 = pWmtHifConf->au4HifConf[0];
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0],
+ iRet);
+ return -3;
+ }
+ WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]);
+
+ /* 7. Wake up chip and check event */
+/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res,
+ MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != 1)) {
+ WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res);
+ return -4;
+ }
+
+ osal_memset(evtBuf, 0, osal_sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res);
+#ifdef CFG_DUMP_EVT
+ WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5]);
+#endif
+ if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) {
+ WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet);
+ return -5;
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */
+
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp
+ (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n");
+ return -6;
+ }
+#endif
+
+ /* 8. Query baud rate (TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet);
+ return -7;
+ }
+ }
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* 9. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -8;
+ }
+
+ /* 10. Enable host STP-UART mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet);
+ return -9;
+ }
+ WMT_INFO_FUNC("enable host STP-UART-FULL mode\n");
+ /*10. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+ /* 11. Query chip STP options (TEST-ONLY) */
+ /* 12. Query baud rate (stp, TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -10;
+ }
+ }
+ /* 13. download patch */
+#if CFG_WMT_MULTI_PATCH
+ iRet = mt6620_patch_info_prepare();
+ if (iRet) {
+ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet);
+ return -11;
+ }
+
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2);
+ patch_num = ctrlPa1;
+ WMT_INFO_FUNC("patch total num = [%d]\n", patch_num);
+
+ for (patch_index = 0; patch_index < patch_num; patch_index++) {
+ iRet = mt6620_patch_dwn(patch_index);
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index);
+ return -12;
+ }
+ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -13;
+ }
+ }
+#else
+ iRet = mt6620_patch_dwn();
+
+ WMT_INFO_FUNC("Not to check the patch validity\n");
+#if 0
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d)\n", iRet);
+ return -11;
+ }
+ WMT_INFO_FUNC("patch dwn ok\n");
+#endif
+ /* 14. WMT Reset command */
+ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -13;
+ }
+#endif
+ iRet = wmt_stp_init_coex();
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -14;
+ }
+ WMT_INFO_FUNC("init_coex ok\n");
+
+#if 0
+ /*10-2 enable 32K By Pass Mode */
+ /* if hwVer = E3/E4, please enable 32K by pass mode. */
+ /* does not support mt6620E1/E2, always enable 32k bypass mode */
+ /* if ((hwVer == 0x8a10 || hwVer == 0x8a11)) */
+ {
+ WMT_INFO_FUNC("WMT-CORE: init_table_6 OSC32K");
+ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6));
+ if (iRet == 0) {
+ WMT_DBG_FUNC("WMT-CORE: init_table_6 OSC32K, successful\n");
+ } else {
+ WMT_WARN_FUNC("init table 6 OSC32K fail, continue init...\n");
+ /*return -14; */
+ }
+ }
+#endif
+
+
+
+ /* 15. Set FM strap */
+ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n",
+ pWmtHifConf->au4StrapConf[0], iRet);
+ return -15;
+ }
+ WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]);
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers));
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -16;
+ }
+#endif
+
+#if 0
+ /* 16. trace32 dump when fw assert */
+ {
+ INT32 val = 0x00000001;
+
+ WMT_INFO_FUNC("WMT-CORE: enable assert dump");
+ wmt_reg_rw_raw(1, 0x0100092c, &val, 0xFFFFFFFF);
+ }
+#endif
+
+#if CFG_WMT_COREDUMP_ENABLE
+ /*Open Core Dump Function @QC begin */
+ mtk_wcn_stp_coredump_flag_ctrl(1);
+#endif
+ if (mtk_wcn_stp_coredump_flag_get() != 0) {
+ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet);
+ return -17;
+ }
+ WMT_INFO_FUNC("enable mt662x firmware coredump\n");
+ } else
+ WMT_INFO_FUNC("disable mt662x firmware coredump\n");
+
+#if 1
+ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO;
+ ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6620.icId;
+ ctrlData.au4CtrlData[1] = (size_t) gp_mt6620_info->cChipVersion;
+ ctrlData.au4CtrlData[2] = (size_t) &gp_mt6620_patch_info;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet);
+ return -16;
+ }
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6620_info != NULL);
+ if (gp_mt6620_info != NULL) {
+ if (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ return 0;
+}
+
+
+static INT32 mt6620_sw_deinit(P_WMT_HIF_CONF pWmtHifConf)
+{
+ WMT_DBG_FUNC(" start\n");
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6620_info != NULL);
+ if ((gp_mt6620_info != NULL)
+ && (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) {
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ gp_mt6620_info = NULL;
+
+ return 0;
+}
+
+static INT32 mt6620_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+ UINT32 val;
+
+ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) {
+ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n");
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000710;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+ } else {
+ /*PCM & I2S separate */
+ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n");
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000070;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+
+ break;
+ case WMT_IC_AIF_3:
+ val = 0x00000000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!ret)
+ WMT_INFO_FUNC("new state(%d) ok\n", state);
+ else
+ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret);
+
+ return ret;
+}
+
+static INT32 mt6620_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret;
+
+ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag);
+
+ ret = -1;
+ switch (id) {
+ case WMT_IC_PIN_AUDIO:
+ ret = mt6620_aif_ctrl(state, flag);
+ break;
+
+ case WMT_IC_PIN_EEDI:
+ WMT_WARN_FUNC("TBD!!");
+ ret = -1;
+ break;
+
+ case WMT_IC_PIN_EEDO:
+ WMT_WARN_FUNC("TBD!!");
+ ret = -1;
+ break;
+ case WMT_IC_PIN_GSYNC:
+ ret = -1;
+ WMT_WARN_FUNC("TBD!!");
+ break;
+ default:
+ break;
+ }
+ WMT_INFO_FUNC("ret = (%d)\n", ret);
+
+ return ret;
+}
+
+
+static MTK_WCN_BOOL mt6620_quick_sleep_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static MTK_WCN_BOOL mt6620_aee_dump_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+static INT32 mt6620_ver_check(VOID)
+{
+ UINT32 hw_ver = 0;
+ UINT32 fw_ver = 0;
+ INT32 iret;
+ const WMT_IC_INFO_S *p_info = NULL;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */
+ WMT_LOUD_FUNC("MT6620: before read hw_ver (hw version)\n");
+ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("MT6620: read hw_ver fail:%d\n", iret);
+ return -2;
+ }
+ WMT_INFO_FUNC("MT6620: read hw_ver (hw version) (0x%x)\n", hw_ver);
+
+ WMT_LOUD_FUNC("MT6620: before fw_ver (rom version)\n");
+ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("MT6620: read fw_ver fail:%d\n", iret);
+ return -2;
+ }
+ WMT_INFO_FUNC("MT6620: read fw_ver (rom version) (0x%x)\n", fw_ver);
+
+ p_info = mt6620_find_wmt_ic_info(hw_ver);
+ if (p_info == NULL) {
+ WMT_ERR_FUNC("MT6620: hw_ver(0x%x) find wmt ic info fail\n", hw_ver);
+ return -3;
+ }
+
+ WMT_INFO_FUNC("MT6620: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n",
+ p_info->cChipName, p_info->cChipVersion,
+ p_info->u4HwVer, p_info->cPatchNameExt);
+
+ /* hw id & version */
+ ctrlPa1 = (0x00006620UL << 16) | (hw_ver & 0x0000FFFF);
+ /* translated fw rom version */
+ ctrlPa2 = (fw_ver & 0x0000FFFF);
+
+ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2);
+ if (iret)
+ WMT_WARN_FUNC("MT6620: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret);
+
+ gp_mt6620_info = p_info;
+ return 0;
+}
+
+static const WMT_IC_INFO_S *mt6620_find_wmt_ic_info(const UINT32 hw_ver)
+{
+ /* match chipversion with u4HwVer item in mt6620_info_table */
+ const UINT32 size = osal_array_size(mt6620_info_table);
+ INT32 index;
+
+ /* George: reverse the search order to favor newer version products */
+ /* TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver()
+ * is changed correctly in the future!!
+ */
+ /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */
+ index = size - 1;
+ /* full match */
+ while ((index >= 0)
+ && (hw_ver != mt6620_info_table[index].u4HwVer) /* full match */
+ ) {
+ --index;
+ }
+ if (index >= 0) {
+ WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index);
+ return &mt6620_info_table[index];
+ }
+ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver);
+
+ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR
+ * NUM only can help us support future minor hw ECO, or fab switch, etc.
+ * FULL matching eliminate such flexibility and software package have to be
+ * updated EACH TIME even when minor hw ECO or fab switch!!!
+ */
+ /* George: reverse the search order to favor newer version products */
+ index = size - 1;
+ /* major num match */
+ while ((index >= 0)
+ && (MAJORNUM(hw_ver) != MAJORNUM(mt6620_info_table[index].u4HwVer))
+ ) {
+ --index;
+ }
+ if (index >= 0) {
+ WMT_INFO_FUNC("MT6620: found ic info for hw_ver(0x%x) by major num! index:%d\n",
+ hw_ver, index);
+ return &mt6620_info_table[index];
+ }
+
+ WMT_ERR_FUNC
+ ("MT6620: find no ic info for hw_ver(0x%x) by full match nor major num match!\n",
+ hw_ver);
+ return NULL;
+}
+
+
+static INT32 wmt_stp_init_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+#define COEX_WMT 0
+#define COEX_BT 1
+#define COEX_WIFI 2
+#define COEX_PTA 3
+#define COEX_MISC 4
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ /*Dump the coex-related info */
+ WMT_DBG_FUNC("coex_wmt:0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wmt_ant_mode,
+ pWmtGenConf->coex_wmt_wifi_time_ctl, pWmtGenConf->coex_wmt_ext_pta_dev_on);
+ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_bt_rssi_upper_limit,
+ pWmtGenConf->coex_bt_rssi_mid_limit,
+ pWmtGenConf->coex_bt_rssi_lower_limit,
+ pWmtGenConf->coex_bt_pwr_high,
+ pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low);
+ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wifi_rssi_upper_limit,
+ pWmtGenConf->coex_wifi_rssi_mid_limit,
+ pWmtGenConf->coex_wifi_rssi_lower_limit,
+ pWmtGenConf->coex_wifi_pwr_high,
+ pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low);
+ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_ext_pta_hi_tx_tag,
+ pWmtGenConf->coex_ext_pta_hi_rx_tag,
+ pWmtGenConf->coex_ext_pta_lo_tx_tag,
+ pWmtGenConf->coex_ext_pta_lo_rx_tag,
+ pWmtGenConf->coex_ext_pta_sample_t1,
+ pWmtGenConf->coex_ext_pta_sample_t2,
+ pWmtGenConf->coex_ext_pta_wifi_bt_con_trx);
+ WMT_DBG_FUNC("coex_misc:0x%x 0x%x\n",
+ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set);
+
+ /*command adjustion due to WMT.cfg */
+ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode;
+ coex_table[COEX_WMT].cmd[6] = pWmtGenConf->coex_wmt_wifi_time_ctl;
+ coex_table[COEX_WMT].cmd[7] = pWmtGenConf->coex_wmt_ext_pta_dev_on;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0],
+ coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz);
+ }
+
+ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit;
+ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit;
+ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit;
+ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high;
+ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid;
+ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0],
+ coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz);
+ }
+ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit;
+ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit;
+ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit;
+ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high;
+ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid;
+ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0],
+ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz);
+ }
+ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag;
+ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag;
+ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag;
+ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag;
+ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0],
+ coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz);
+ }
+
+ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on,
+ sizeof(pWmtGenConf->coex_misc_ext_pta_on));
+ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set,
+ sizeof(pWmtGenConf->coex_misc_ext_feature_set));
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str,
+ coex_table[COEX_MISC].cmdSz);
+ }
+ iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table));
+
+ return iRet;
+}
+
+#if CFG_WMT_MULTI_PATCH
+
+static INT32 mt6620_patch_info_prepare(VOID)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+static INT32 mt6620_patch_dwn(UINT32 index)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr = NULL;
+ PUINT8 pbuf = NULL;
+ UINT32 patchSize = 0;
+ UINT32 fragSeq = 0;
+ UINT32 fragNum = 0;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 patchevtBuf[8];
+ UINT8 addressevtBuf[12];
+ UINT8 addressByte[4];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6620_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6620_info!\n");
+ return -1;
+ }
+
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = index + 1;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &addressByte;
+ iRet = wmt_ctrl(&ctrlData);
+ WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName);
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+
+ ctrlData.au4CtrlData[2] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+ /*cPlat = &patchHdr->ucPLat[0]; */
+ cDataTime[15] = '\0';
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -1;
+ goto done;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+
+ if (index == 0) {
+ WMT_INFO_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime);
+ WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n",
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n",
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >>
+ 16));
+ WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0],
+ patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_INFO_FUNC("[Combo Patch] Content Size = 0x%x\n", patchSize);
+ WMT_INFO_FUNC("[Combo Patch] Content CRC = 0x%04x\n", osal_crc16(pbuf, patchSize));
+ WMT_INFO_FUNC("===========================================\n");
+ }
+
+ patchSizePerFrag = (MAJORNUM(gp_mt6620_info->u4HwVer) != 0) ?
+ DEFAULT_PATCH_FRAG_SIZE : MT6620E2_PATCH_FRAG_SIZE;
+
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ osal_memcpy(&gp_mt6620_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ /*send wmt part patch address command */
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ iRet -= 1;
+ goto done;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) !=
+ 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n");
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /*send part patch address command */
+ osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte));
+ WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_P_ADDRESS_CMD[12], WMT_PATCH_P_ADDRESS_CMD[13],
+ WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]);
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n",
+ iRet, u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet,
+ u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT))
+ != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n",
+ index);
+ iRet -= 1;
+ goto done;
+ }
+#endif
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+ /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ * fragSize + sizeof(WMT_PATCH_CMD), &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet = -4;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(patchevtBuf, 0, sizeof(patchevtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(patchevtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ iRet = -5;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(patchevtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, patchevtBuf[0], patchevtBuf[1], patchevtBuf[2], patchevtBuf[3],
+ patchevtBuf[4], sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0],
+ WMT_PATCH_EVT[1], WMT_PATCH_EVT[2], WMT_PATCH_EVT[3],
+ WMT_PATCH_EVT[4]);
+ iRet = -6;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+
+#if 0
+ WMT_DBG_FUNC("wmt_core: send patch frag(%d) [%02X,%02X,%02X,%02X,%02X] (%d) ok",
+ fragSeq, WMT_PATCH_CMD[0], WMT_PATCH_CMD[1], WMT_PATCH_CMD[2],
+ WMT_PATCH_CMD[3], WMT_PATCH_CMD[4], fragSize);
+#endif
+
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet = -7;
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = index + 1;
+ wmt_ctrl(&ctrlData);
+ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */
+ if ((iRet == -2) || (iRet == -3)) {
+ /*no patch found or patch version does not match with hw version,
+ * we check if patch is mandatory or not, if yes, return iRet, if not return 0
+ */
+ if (gp_mt6620_info->bWorkWithoutPatch != MTK_WCN_BOOL_FALSE)
+ iRet = 0;
+ }
+
+ return iRet;
+}
+
+
+#else
+static INT32 mt6620_patch_dwn(VOID)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr;
+ PUINT8 pbuf;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6620_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6620_info!\n");
+ return -1;
+ }
+#if 0
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME;
+ ctrlData.au4CtrlData[0] = (UINT32) &gDefPatchName;
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (mt6620_update_patch_name()) {
+ WMT_ERR_FUNC("invalid patch name, ommit patch download process.\n");
+ return -1;
+ }
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (UINT32) &gDefPatchName;
+ ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (UINT32) &pbuf;
+ ctrlData.au4CtrlData[3] = (UINT32) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet = -2;
+ goto done;
+ }
+#else
+ /* <2> search patch and read patch content */
+ /* <2.1> search patch */
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet == 0) {
+ /* patch with correct Hw Ver Major Num found */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME;
+ ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName;
+ iRet = wmt_ctrl(&ctrlData);
+
+ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName);
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+
+ } else {
+ iRet -= 1;
+ return iRet;
+ }
+ ctrlData.au4CtrlData[2] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ return -1;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+ WMT_INFO_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime);
+ WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n",
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n",
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16));
+ WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0],
+ patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_INFO_FUNC("[Combo Patch] Content Size = 0x%x\n", patchSize);
+ WMT_INFO_FUNC("[Combo Patch] Content CRC = 0x%04x\n", osal_crc16(pbuf, patchSize));
+ WMT_INFO_FUNC("===========================================\n");
+
+ patchSizePerFrag = (MAJORNUM(gp_mt6620_info->u4HwVer) != 0) ?
+ DEFAULT_PATCH_FRAG_SIZE : MT6620E2_PATCH_FRAG_SIZE;
+
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ osal_memcpy(&gp_mt6620_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+
+ /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ * fragSize + sizeof(WMT_PATCH_CMD), &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet = -4;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ iRet = -5;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet = -6;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+
+#if 0
+ WMT_DBG_FUNC("wmt_core: send patch frag(%d) [%02X,%02X,%02X,%02X,%02X] (%d) ok",
+ fragSeq, WMT_PATCH_CMD[0], WMT_PATCH_CMD[1], WMT_PATCH_CMD[2],
+ WMT_PATCH_CMD[3], WMT_PATCH_CMD[4], fragSize);
+#endif
+
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet = -7;
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL);
+ if ((iRet == -2) || (iRet == -3)) {
+ /*no patch found or patch version does not match with hw version,
+ * we check if patch is mandatory or not, if yes, return iRet, if not return 0
+ */
+ if (gp_mt6620_info->bWorkWithoutPatch != MTK_WCN_BOOL_FALSE)
+ iRet = 0;
+ }
+
+ return iRet;
+}
+
+static INT32 mt6620_update_patch_name(VOID)
+{
+ INT32 len;
+ UINT8 cTmpPatchName[NAME_MAX + 1] = { 0 };
+
+ /*init.get hardware version */
+ /* TODO:[FixMe][GeorgeKuo]: check using memcpy or strncpy??? */
+ /*osal_memcpy (gFullPatchName, gDefPatchName, osal_strlen(gDefPatchName)); */
+ osal_strncpy(gFullPatchName, gDefPatchName, osal_sizeof(gFullPatchName));
+
+ /*1.check hardware information */
+ if (gp_mt6620_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6620_info!\n");
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+ return -1;
+ }
+
+ /*2.make possible firmware patch name with original name and hardware version */
+ if ((osal_strlen(gDefPatchName) > osal_strlen(WMT_IC_PATCH_TAIL))
+ && ((osal_strlen(gDefPatchName) + osal_strlen(WMT_IC_PATCH_DUMMY_EXT) <= NAME_MAX))
+ ) {
+ len = osal_strlen(gDefPatchName) - osal_strlen(WMT_IC_PATCH_TAIL);
+ osal_memcpy(cTmpPatchName, gDefPatchName, len > NAME_MAX ? NAME_MAX : len);
+ osal_memcpy(cTmpPatchName + osal_strlen(cTmpPatchName),
+ gp_mt6620_info->cPatchNameExt,
+ osal_strlen(gp_mt6620_info->cPatchNameExt));
+ osal_memcpy(cTmpPatchName + osal_strlen(cTmpPatchName), WMT_IC_PATCH_TAIL,
+ osal_strlen(WMT_IC_PATCH_TAIL));
+ cTmpPatchName[osal_strlen(cTmpPatchName)] = '\0';
+ } else {
+ WMT_ERR_FUNC("invalid default firmware patch name (%s)\n", gDefPatchName);
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+ return -2;
+ }
+
+ /*patch with versioned name exist , update cFullPatchName with full named patch */
+ osal_memcpy(gFullPatchName, cTmpPatchName, osal_strlen(cTmpPatchName));
+ *(gFullPatchName + osal_strlen(cTmpPatchName)) = '\0';
+ WMT_INFO_FUNC("full firmware patch name: %s\n", cTmpPatchName);
+
+ return 0;
+}
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c
new file mode 100644
index 0000000000000000000000000000000000000000..68b5336e3022015b26c492adf3f8f924182786aa
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c
@@ -0,0 +1,1981 @@
+/*
+* Copyright (C) 2016 MediaTek Inc.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+*/
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-IC]"
+#define CFG_IC_MT6628 1
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_ic.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "stp_core.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define DEFAULT_PATCH_FRAG_SIZE (1000)
+#define WMT_PATCH_FRAG_1ST (0x1)
+#define WMT_PATCH_FRAG_MID (0x2)
+#define WMT_PATCH_FRAG_LAST (0x3)
+
+#define CFG_CHECK_WMT_RESULT (1)
+/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */
+#define CFG_WMT_BT_PORT2 (0)
+
+#define CFG_SET_OPT_REG (0)
+#define CFG_WMT_I2S_DBGUART_SUPPORT (0)
+#define CFG_SET_OPT_REG_SWLA (0)
+#define CFG_SET_OPT_REG_MCUCLK (0)
+#define CFG_SET_OPT_REG_MCUIRQ (0)
+
+#define CFG_SUBSYS_COEX_NEED 0
+
+#define CFG_WMT_COREDUMP_ENABLE 0
+
+#define CFG_WMT_MULTI_PATCH (1)
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static UINT8 gFullPatchName[NAME_MAX + 1];
+static const WMT_IC_INFO_S *gp_mt6628_info;
+static WMT_PATCH gp_mt6628_patch_info;
+static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS;
+#if 0
+static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 };
+static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 };
+
+static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 };
+static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 };
+#endif
+
+static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 };
+static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 };
+static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 };
+static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 };
+static UINT8 WMT_QUERY_STP_EVT_UART[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 };
+static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF };
+static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 };
+static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 };
+static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 };
+static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 };
+
+#if CFG_WMT_BT_PORT2
+static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 };
+static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+#if CFG_WMT_MULTI_PATCH
+static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0xD4, 0x01, 0x09, 0xF0, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x48, 0x03, 0x09, 0xF0, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+#endif
+
+/*coex cmd/evt++*/
+static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+#if CFG_SUBSYS_COEX_NEED
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C,
+ 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A,
+ 0x00, 0x04,
+ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE
+};
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09,
+ 0x00, 0x05,
+ 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB
+};
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+/*coex cmd/evt--*/
+static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 };
+static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 };
+
+#if 0
+static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 };
+static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 };
+#endif
+
+#if 0
+/* to enable dump feature */
+static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 };
+static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get system stack dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get task and system stack dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get bt related memory dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A };
+static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+#endif
+/* to get full dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 };
+static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 };
+
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */
+ , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */
+ , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */
+ , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */
+ , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */
+ , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */
+ , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+#endif
+
+
+#ifndef CFG_IC_MT6628 /* For MT6628 no need to set ALLEINT registers, done in f/w */
+/* enable all interrupt */
+static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */
+ , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */
+ , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */
+};
+
+static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+#endif
+
+#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */
+static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */
+ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */
+ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */
+ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */
+};
+
+static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */
+static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */
+ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */
+ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */
+ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */
+ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */
+};
+
+static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+};
+#endif
+
+#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */
+static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */
+ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */
+ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */
+ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */
+};
+
+static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */
+#if 1 /* Ray */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */
+ /* cirq_int_n */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */
+ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */
+ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 5 registers */
+};
+#elif 0 /* KC */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */
+ , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */
+ , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */
+ , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */
+ , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */
+ , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */
+ , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */
+ , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */
+ , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+};
+#endif
+#endif
+
+static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 };
+
+static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 };
+static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 };
+
+/* set sdio driving */
+static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */
+ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */
+ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */
+};
+
+static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+
+#ifndef CFG_IC_MT6628
+
+/* stp sdio init scripts */
+static struct init_script init_table_1_1[] = {
+ /* table_1_1 is only applied to common SDIO interface */
+ INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"),
+ /* applied to MT6628 ? */
+ INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"),
+};
+
+#endif
+
+static struct init_script init_table_1_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"),
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"),
+ INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"),
+};
+
+
+static struct init_script init_table_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_3[] = {
+ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"),
+#if CFG_WMT_BT_PORT2
+ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"),
+#endif
+};
+
+static struct init_script set_crystal_timing_script[] = {
+ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT,
+ "set crystal trim value"),
+};
+
+static struct init_script get_crystal_timing_script[] = {
+ INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT,
+ "get crystal trim value"),
+};
+
+
+#if 0
+static struct init_script init_table_3_1[] = {
+ INIT_CMD(WMT_WAKEUP_EN_GATE_CMD, WMT_WAKEUP_EN_GATE_EVT, "ensable gating"),
+};
+#endif
+
+static struct init_script init_table_4[] = {
+ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"),
+};
+
+static struct init_script init_table_5[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"),
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_5_1[] = {
+ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"),
+};
+
+static struct init_script init_table_6[] = {
+#if 0
+ INIT_CMD(WMT_CORE_DUMP_EN_CMD, WMT_CORE_DUMP_EN_EVT, "configure memory and core dump"),
+#endif
+ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"),
+};
+
+#if 0
+static struct init_script init_table_6[] = {
+ INIT_CMD(WMT_SET_OSC32K_BYPASS_CMD, WMT_SET_OSC32K_BYPASS_EVT, "set OSC32k by pass mode."),
+};
+#endif
+
+#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG
+static struct init_script set_registers[] = {
+ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */
+ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */
+#if CFG_WMT_I2S_DBGUART_SUPPORT
+ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"),
+#endif
+#if CFG_SET_OPT_REG_SWLA
+ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUCLK
+ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUIRQ
+ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"),
+#endif
+};
+#endif
+
+static struct init_script coex_table[] = {
+ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"),
+
+#if CFG_SUBSYS_COEX_NEED
+/* no need in MT6628 */
+ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"),
+ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"),
+ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"),
+ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"),
+#endif
+};
+
+static struct init_script osc_type_table[] = {
+ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"),
+};
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static struct init_script merge_pcm_table[] = {
+ INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"),
+ INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"),
+ INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"),
+};
+#endif
+
+
+static struct init_script sdio_driving_table[] = {
+ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"),
+};
+
+
+/* MT6628 Chip Version and Info Table */
+static const WMT_IC_INFO_S mt6628_info_table[] = {
+ {
+ .u4HwVer = 0x8A00,
+ .cChipName = WMT_IC_NAME_MT6628,
+ .cChipVersion = WMT_IC_VER_E1,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A10,
+ .cChipName = WMT_IC_NAME_MT6628,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B10,
+ .cChipName = WMT_IC_NAME_MT6628,
+ .cChipVersion = WMT_IC_VER_E3,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B11,
+ .cChipName = WMT_IC_NAME_MT6628,
+ .cChipVersion = WMT_IC_VER_E4,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8a11,
+ .cChipName = WMT_IC_NAME_MT6628,
+ .cChipVersion = WMT_IC_VER_E5,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ }
+};
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6628_sw_init(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6628_sw_deinit(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6628_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6628_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6628_ver_check(VOID);
+
+static const WMT_IC_INFO_S *mt6628_find_wmt_ic_info(const UINT32 hw_ver);
+
+static INT32 wmt_stp_init_coex(VOID);
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mt6628_patch_dwn(UINT32 index);
+static INT32 mt6628_patch_info_prepare(VOID);
+#else
+static INT32 mt6628_patch_dwn(VOID);
+#endif
+
+static INT32 mt6628_co_clock_ctrl(WMT_CO_CLOCK on);
+static WMT_CO_CLOCK mt6628_co_clock_get(VOID);
+
+static INT32 mt6628_crystal_triming_set(VOID);
+
+
+static MTK_WCN_BOOL mt6628_quick_sleep_flag_get(VOID);
+
+static MTK_WCN_BOOL mt6628_aee_dump_flag_get(VOID);
+
+static INT32 mt6628_set_sdio_driving(VOID);
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/* MT6628 Operation Function Table */
+WMT_IC_OPS wmt_ic_ops_mt6628 = {
+ .icId = 0x6628,
+ .sw_init = mt6628_sw_init,
+ .sw_deinit = mt6628_sw_deinit,
+ .ic_pin_ctrl = mt6628_pin_ctrl,
+ .ic_ver_check = mt6628_ver_check,
+ .co_clock_ctrl = mt6628_co_clock_ctrl,
+ .is_quick_sleep = mt6628_quick_sleep_flag_get,
+ .is_aee_dump_support = mt6628_aee_dump_flag_get,
+ .trigger_stp_assert = NULL,
+ .deep_sleep_ctrl = NULL,
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6628_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[256];
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+ UINT32 hw_ver;
+#if CFG_WMT_MULTI_PATCH
+ UINT32 patch_num = 0;
+ UINT32 patch_index = 0;
+#endif
+ WMT_CTRL_DATA ctrlData;
+
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_mt6628_info != NULL);
+ if ((gp_mt6628_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_mt6628_info(0x%p), pWmtHifConf(0x%p)\n",
+ gp_mt6628_info, pWmtHifConf);
+ return -1;
+ }
+
+ hw_ver = gp_mt6628_info->u4HwVer;
+
+ /* 4 <3.1> start init for sdio */
+#ifndef CFG_IC_MT6628 /* For MT6628 no need to do this operation */
+ if (pWmtHifConf->hifType == WMT_HIF_SDIO) {
+ wmt_lib_ps_set_idle_time(STP_PSM_SDIO_IDLE_TIME_SLEEP);
+ /* 1. enable all INT32 */
+ /* 2. disable mcu gate (only MT6628E1/E2) */
+ iRet = wmt_core_init_script(init_table_1_1, ARRAY_SIZE(init_table_1_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet);
+ osal_assert(0);
+ return -1;
+ }
+ }
+#endif
+ /* 4 <3.2> start init for uart */
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* init variable fields for script execution */
+ osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+ osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+
+ /* 3. Query chip baud rate (TEST-ONLY) */
+ /* 4. Query chip STP options (TEST-ONLY) */
+ /* 5. Change chip baud rate: t_baud */
+ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */
+ iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 6. Set host baudrate and flow control */
+ ctrlPa1 = pWmtHifConf->au4HifConf[0];
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0],
+ iRet);
+ return -3;
+ }
+ WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]);
+
+ /* 7. Wake up chip and check event */
+ /* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res,
+ MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != 1)) {
+ WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res);
+ return -4;
+ }
+
+ osal_memset(evtBuf, 0, osal_sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res);
+#ifdef CFG_DUMP_EVT
+ WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5]);
+#endif
+ if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) {
+ WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet);
+ return -5;
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */
+
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp
+ (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n");
+ return -6;
+ }
+#endif
+
+ /* 8. Query baud rate (TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_2, ARRAY_SIZE(init_table_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet);
+ return -7;
+ }
+ }
+
+ /* 9. download patch */
+#if CFG_WMT_MULTI_PATCH
+ /* 9.1 Let launcher to search patch info */
+ iRet = mt6628_patch_info_prepare();
+ if (iRet) {
+ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet);
+ return -8;
+ }
+
+ /* 9.2 Read patch number */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2);
+ patch_num = ctrlPa1;
+ WMT_INFO_FUNC("patch total num = [%d]\n", patch_num);
+
+ /* 9.3 Multi-patch Patch download */
+ for (patch_index = 0; patch_index < patch_num; patch_index++) {
+ iRet = mt6628_patch_dwn(patch_index);
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index);
+ return -12;
+ }
+ iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -13;
+ }
+ }
+#else
+ /* 9.3 Patch download */
+ iRet = mt6628_patch_dwn();
+ /* If patch download fail, we just ignore this error and let chip init process goes on */
+ if (iRet)
+ WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet);
+#endif /* End of #if CFG_WMT_MULTI_PATCH */
+
+ /* 10. WMT Reset command */
+ iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -9;
+ }
+ iRet = wmt_stp_init_coex();
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -10;
+ }
+ WMT_INFO_FUNC("init_coex ok\n");
+
+ mt6628_crystal_triming_set();
+
+ mt6628_set_sdio_driving();
+
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* 11. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -12;
+ }
+
+ /* 12. Enable host STP-UART mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet);
+ return -13;
+ }
+ WMT_INFO_FUNC("enable host STP-UART-FULL mode\n");
+ /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+ /* 14. Query chip STP options (TEST-ONLY) */
+ /* 15. Query baud rate (stp, TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -14;
+ }
+ }
+
+ if (mt6628_co_clock_get() == WMT_CO_CLOCK_EN) {
+ WMT_INFO_FUNC("co-clock enabled.\n");
+
+ iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table));
+ if (iRet) {
+ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+ } else {
+ WMT_INFO_FUNC("co-clock disabled.\n");
+ }
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+ iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table));
+ if (iRet) {
+ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+#endif
+
+ /* 15. Set FM strap */
+ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ iRet = wmt_core_init_script(init_table_5_1, ARRAY_SIZE(init_table_5_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n",
+ pWmtHifConf->au4StrapConf[0], iRet);
+ return -16;
+ }
+ WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]);
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers));
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -17;
+ }
+#endif
+
+#if CFG_WMT_COREDUMP_ENABLE
+ /*Open Core Dump Function @QC begin */
+ mtk_wcn_stp_coredump_flag_ctrl(1);
+#endif
+ if (mtk_wcn_stp_coredump_flag_get() != 0) {
+ iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet);
+ return -18;
+ }
+ WMT_INFO_FUNC("enable mt662x firmware coredump\n");
+ } else
+ WMT_INFO_FUNC("disable mt662x firmware coredump. hifType: %d\n",
+ pWmtHifConf->hifType);
+
+#if 1
+ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO;
+ ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6628.icId;
+ ctrlData.au4CtrlData[1] = (size_t) gp_mt6628_info->cChipVersion;
+ ctrlData.au4CtrlData[2] = (size_t) &gp_mt6628_patch_info;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet);
+ return -16;
+ }
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ osal_assert(gp_mt6628_info != NULL);
+ if (gp_mt6628_info != NULL) {
+ if (gp_mt6628_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+ } else if (pWmtHifConf->hifType == WMT_HIF_SDIO) {
+ /* COMMON SDIO is used different PS from UART, so disable current ps support
+ * Note: using wmt_lib_ps_ctrl() due to wmt_lib_ps_disable() cannot clear gPsEnable setting
+ */
+ wmt_lib_ps_ctrl(0);
+ }
+#endif
+
+ return 0;
+}
+
+static INT32 mt6628_sw_deinit(P_WMT_HIF_CONF pWmtHifConf)
+{
+ WMT_DBG_FUNC(" start\n");
+
+#if CFG_WMT_PS_SUPPORT
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ osal_assert(gp_mt6628_info != NULL);
+ if ((gp_mt6628_info != NULL)
+ && (gp_mt6628_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) {
+ wmt_lib_ps_disable();
+ }
+ }
+#endif
+
+ gp_mt6628_info = NULL;
+
+ return 0;
+}
+
+static INT32 mt6628_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+ UINT32 val;
+
+ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) {
+ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n");
+#if 0
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000710;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#else
+ WMT_WARN_FUNC("TBD!!");
+ ret = 0;
+#endif
+ } else {
+ /*PCM & I2S separate */
+ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n");
+#if 0
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000070;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+
+ break;
+ case WMT_IC_AIF_3:
+ val = 0x00000000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#else
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ ret = 0;
+ break;
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x01110000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000);
+
+ break;
+ case WMT_IC_AIF_3:
+ ret = 0;
+ break;
+
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#endif
+ }
+
+ if (!ret)
+ WMT_INFO_FUNC("new state(%d) ok\n", state);
+ else
+ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret);
+
+ return ret;
+}
+
+static INT32 mt6628_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+ UINT32 uVal = 0;
+
+ if (state == WMT_IC_PIN_MUX)
+ uVal = 0x1 << 28;
+ else
+ uVal = 0x5 << 28;
+ ret = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28);
+ if (ret != 0)
+ WMT_ERR_FUNC("gps_sync pin ctrl failed, ret(%d)\n", ret);
+ /* anyway, we return 0 */
+ return 0;
+}
+
+
+static INT32 mt6628_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret;
+
+ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag);
+
+ ret = -1;
+ switch (id) {
+ case WMT_IC_PIN_AUDIO:
+ ret = mt6628_aif_ctrl(state, flag);
+ break;
+
+ case WMT_IC_PIN_EEDI:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_EEDO:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+ case WMT_IC_PIN_GSYNC:
+ ret = mt6628_gps_sync_ctrl(state, flag);
+ break;
+ default:
+ break;
+ }
+ WMT_INFO_FUNC("ret = (%d)\n", ret);
+
+ return ret;
+}
+
+INT32 mt6628_co_clock_ctrl(WMT_CO_CLOCK on)
+{
+ INT32 iRet = 0;
+
+ if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX))
+ gCoClockEn = on;
+ else {
+ WMT_DBG_FUNC("MT6628: error parameter:%d\n", on);
+ iRet = -1;
+ }
+ WMT_DBG_FUNC("MT6628: Co-clock %s\n",
+ (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled");
+
+ return iRet;
+}
+
+static MTK_WCN_BOOL mt6628_quick_sleep_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+static MTK_WCN_BOOL mt6628_aee_dump_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+WMT_CO_CLOCK mt6628_co_clock_get(VOID)
+{
+ return gCoClockEn;
+}
+
+
+
+static INT32 mt6628_ver_check(VOID)
+{
+ UINT32 hw_ver = 0;
+ UINT32 fw_ver = 0;
+ INT32 iret;
+ const WMT_IC_INFO_S *p_info = NULL;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+
+ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */
+ WMT_LOUD_FUNC("MT6628: before read hw_ver (hw version)\n");
+ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("MT6628: read hw_ver fail:%d\n", iret);
+ return -2;
+ }
+ WMT_INFO_FUNC("MT6628: read hw_ver (hw version) (0x%x)\n", hw_ver);
+
+ WMT_LOUD_FUNC("MT6628: before fw_ver (rom version)\n");
+ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("MT6628: read fw_ver fail:%d\n", iret);
+ return -2;
+ }
+ WMT_INFO_FUNC("MT6628: read fw_ver (rom version) (0x%x)\n", fw_ver);
+
+ p_info = mt6628_find_wmt_ic_info(hw_ver);
+ if (p_info == NULL) {
+ WMT_ERR_FUNC("MT6628: hw_ver(0x%x) find wmt ic info fail\n", hw_ver);
+ return -3;
+ }
+
+ WMT_INFO_FUNC("MT6628: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n",
+ p_info->cChipName, p_info->cChipVersion,
+ p_info->u4HwVer, p_info->cPatchNameExt);
+
+ /* hw id & version */
+ ctrlPa1 = (0x00006628UL << 16) | (hw_ver & 0x0000FFFF);
+ /* translated fw rom version */
+ ctrlPa2 = (fw_ver & 0x0000FFFF);
+
+ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2);
+ if (iret)
+ WMT_WARN_FUNC("MT6628: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret);
+
+ gp_mt6628_info = p_info;
+ return 0;
+}
+
+static const WMT_IC_INFO_S *mt6628_find_wmt_ic_info(const UINT32 hw_ver)
+{
+ /* match chipversion with u4HwVer item in mt6628_info_table */
+ const UINT32 size = ARRAY_SIZE(mt6628_info_table);
+ INT32 index;
+
+ /* George: reverse the search order to favor newer version products */
+ /* TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver()
+ * is changed correctly in the future!!
+ * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs.
+ */
+ index = size - 1;
+ /* full match */
+ while ((index >= 0)
+ && (hw_ver != mt6628_info_table[index].u4HwVer) /* full match */
+ ) {
+ --index;
+ }
+ if (index >= 0) {
+ WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index);
+ return &mt6628_info_table[index];
+ }
+
+ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver);
+
+ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR
+ * NUM only can help us support future minor hw ECO, or fab switch, etc.
+ * FULL matching eliminate such flexibility and software package have to be
+ * updated EACH TIME even when minor hw ECO or fab switch!!!
+ */
+ /* George: reverse the search order to favor newer version products */
+ index = size - 1;
+ /* major num match */
+ while ((index >= 0)
+ && (MAJORNUM(hw_ver) != MAJORNUM(mt6628_info_table[index].u4HwVer))
+ ) {
+ --index;
+ }
+ if (index >= 0) {
+ WMT_INFO_FUNC("MT6628: found ic info for hw_ver(0x%x) by major num! index:%d\n",
+ hw_ver, index);
+ return &mt6628_info_table[index];
+ }
+
+ WMT_ERR_FUNC
+ ("MT6628: find no ic info for hw_ver(0x%x) by full match nor major num match!\n",
+ hw_ver);
+ return NULL;
+}
+
+
+static INT32 wmt_stp_init_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+#define COEX_WMT 0
+
+#if CFG_SUBSYS_COEX_NEED
+ /* no need for MT6628 */
+#define COEX_BT 1
+#define COEX_WIFI 2
+#define COEX_PTA 3
+#define COEX_MISC 4
+#endif
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+
+ /*Dump the coex-related info */
+ WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode);
+#if CFG_SUBSYS_COEX_NEED
+ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_bt_rssi_upper_limit,
+ pWmtGenConf->coex_bt_rssi_mid_limit,
+ pWmtGenConf->coex_bt_rssi_lower_limit,
+ pWmtGenConf->coex_bt_pwr_high,
+ pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low);
+ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wifi_rssi_upper_limit,
+ pWmtGenConf->coex_wifi_rssi_mid_limit,
+ pWmtGenConf->coex_wifi_rssi_lower_limit,
+ pWmtGenConf->coex_wifi_pwr_high,
+ pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low);
+ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_ext_pta_hi_tx_tag,
+ pWmtGenConf->coex_ext_pta_hi_rx_tag,
+ pWmtGenConf->coex_ext_pta_lo_tx_tag,
+ pWmtGenConf->coex_ext_pta_lo_rx_tag,
+ pWmtGenConf->coex_ext_pta_sample_t1,
+ pWmtGenConf->coex_ext_pta_sample_t2,
+ pWmtGenConf->coex_ext_pta_wifi_bt_con_trx);
+ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set);
+#endif
+
+ /*command adjustion due to WMT.cfg */
+ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0],
+ coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz);
+ }
+#if CFG_SUBSYS_COEX_NEED
+ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit;
+ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit;
+ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit;
+ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high;
+ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid;
+ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0],
+ coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz);
+ }
+ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit;
+ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit;
+ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit;
+ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high;
+ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid;
+ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0],
+ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz);
+ }
+ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag;
+ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag;
+ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag;
+ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag;
+ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx;
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0],
+ coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz);
+ }
+
+ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on,
+ sizeof(pWmtGenConf->coex_misc_ext_pta_on));
+ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set,
+ sizeof(pWmtGenConf->coex_misc_ext_feature_set));
+
+ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str,
+ coex_table[COEX_MISC].cmdSz);
+#endif
+
+ iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table));
+
+ return iRet;
+}
+
+
+static INT32 mt6628_set_sdio_driving(VOID)
+{
+ INT32 ret = 0;
+
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ UINT32 drv_val = 0;
+
+ /*Get wmt config */
+ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (ret) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret);
+ return -1;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%8lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ drv_val = pWmtGenConf->sdio_driving_cfg;
+
+ /*Dump the sdio driving related info */
+ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val);
+
+ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */
+ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */
+ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */
+
+ ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table));
+
+ return ret;
+}
+
+
+static INT32 mt6628_crystal_triming_set(VOID)
+{
+ INT32 iRet = 0;
+ PUINT8 pbuf = NULL;
+ UINT32 bufLen = 0;
+ WMT_CTRL_DATA ctrlData;
+ UINT32 uCryTimOffset = 0x6D;
+ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ INT8 cCrystalTimingOffset = 0x0;
+ UINT8 cCrystalTiming = 0x0;
+ INT32 iCrystalTiming = 0x0;
+ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ UINT32 u4Res;
+
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ ctrlData.au4CtrlData[1] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[2] = (size_t) &bufLen;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ iRet = -1;
+ } else {
+ WMT_DBG_FUNC("MT6628: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen);
+ if (bufLen < (uCryTimOffset + 1)) {
+ WMT_ERR_FUNC
+ ("MT6628: nvram len(%d) too short, crystalTimging value offset(%d)\n",
+ bufLen, uCryTimOffset);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ } else {
+ bIsNvramExist = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = *(pbuf + uCryTimOffset);
+ if (cCrystalTimingOffset & 0x80) {
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f;
+ }
+ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n",
+ cCrystalTimingOffset, bIsCrysTrimEnabled);
+ }
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet);
+ iRet = -2;
+ } else {
+ WMT_DBG_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n");
+ }
+ }
+ if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) {
+ /*get CrystalTiming value before set it */
+ iRet =
+ wmt_core_tx(get_crystal_timing_script[0].cmd,
+ get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].cmdSz);
+ iRet = -3;
+ goto done;
+ }
+ /* EVENT BUF */
+ osal_memset(get_crystal_timing_script[0].evt, 0,
+ get_crystal_timing_script[0].evtSz);
+ iRet =
+ wmt_core_rx(get_crystal_timing_script[0].evt,
+ get_crystal_timing_script[0].evtSz, &u4Res);
+ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].evtSz);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet = -4;
+ goto done;
+ }
+
+ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f;
+ if (cCrystalTimingOffset & 0x40) {
+ /*nagative offset value */
+ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128;
+ } else {
+ iCrystalTiming += cCrystalTimingOffset;
+ }
+ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming);
+ if (iCrystalTiming > 0x7f)
+ cCrystalTiming = 0x7f;
+ else if (iCrystalTiming < 0)
+ cCrystalTiming = 0;
+ else
+ cCrystalTiming = iCrystalTiming;
+ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming);
+ /* set_crystal_timing_script */
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming;
+ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming;
+
+ iRet =
+ wmt_core_init_script(set_crystal_timing_script,
+ osal_array_size(set_crystal_timing_script));
+ if (iRet) {
+ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -5;
+ } else {
+ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n",
+ WMT_SET_CRYSTAL_TRIMING_CMD[5]);
+ iRet =
+ wmt_core_init_script(get_crystal_timing_script,
+ osal_array_size(get_crystal_timing_script));
+ if (iRet) {
+ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -6;
+ } else {
+ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n",
+ WMT_GET_CRYSTAL_TRIMING_EVT[5]);
+ iRet = 0x0;
+ }
+ }
+ }
+done:
+ return iRet;
+}
+
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mt6628_patch_info_prepare(VOID)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+
+static INT32 mt6628_patch_dwn(UINT32 index)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr;
+ PUINT8 pbuf;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ UINT8 addressevtBuf[12];
+ UINT8 addressByte[4];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6628_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6628_info!\n");
+ return -1;
+ }
+
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = index + 1;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &addressByte;
+ iRet = wmt_ctrl(&ctrlData);
+ WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName);
+
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+ if (index == 0) {
+ WMT_INFO_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime);
+ WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n",
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n",
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >>
+ 16));
+ WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0],
+ patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_INFO_FUNC("===========================================\n");
+ }
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -1;
+ goto done;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ osal_memcpy(&gp_mt6628_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+
+ /*send wmt part patch address command */
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ iRet -= 1;
+ goto done;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) !=
+ 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n");
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /*send part patch address command */
+ osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte));
+ WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_P_ADDRESS_CMD[12],
+ WMT_PATCH_P_ADDRESS_CMD[13],
+ WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]);
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n",
+ iRet, u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet,
+ u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT))
+ != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n",
+ index);
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+ /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ * fragSize + sizeof(WMT_PATCH_CMD), &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = index + 1;
+ wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+#else
+static INT32 mt6628_patch_dwn(VOID)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr;
+ PUINT8 pbuf;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6628_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6628_info!\n");
+ return -1;
+ }
+ /* <2> search patch and read patch content */
+ /* <2.1> search patch */
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet == 0) {
+ /* patch with correct Hw Ver Major Num found */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME;
+ ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName;
+ iRet = wmt_ctrl(&ctrlData);
+
+ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName);
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+
+ } else {
+ iRet -= 1;
+ return iRet;
+ }
+ ctrlData.au4CtrlData[2] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+ WMT_INFO_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime);
+ WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n",
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n",
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16));
+ WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0],
+ patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_INFO_FUNC("===========================================\n");
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ return -1;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ osal_memcpy(&gp_mt6628_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+
+ /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ * fragSize + sizeof(WMT_PATCH_CMD), &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL);
+
+ return iRet;
+}
+
+#endif
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c
new file mode 100644
index 0000000000000000000000000000000000000000..31974df9853fbfbeb7a348a296e7db647edc0c9a
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c
@@ -0,0 +1,2043 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-IC]"
+#define CFG_IC_MT6630 1
+
+#define MT6630_BRINGUP 0
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_ic.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "stp_core.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define DEFAULT_PATCH_FRAG_SIZE (1000)
+#define WMT_PATCH_FRAG_1ST (0x1)
+#define WMT_PATCH_FRAG_MID (0x2)
+#define WMT_PATCH_FRAG_LAST (0x3)
+
+#define CFG_CHECK_WMT_RESULT (1)
+/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */
+#define CFG_WMT_BT_PORT2 (0)
+
+#define CFG_SET_OPT_REG (0)
+#define CFG_WMT_I2S_DBGUART_SUPPORT (0)
+#define CFG_SET_OPT_REG_SWLA (0)
+#define CFG_SET_OPT_REG_MCUCLK (0)
+#define CFG_SET_OPT_REG_MCUIRQ (0)
+
+#define CFG_SUBSYS_COEX_NEED 0
+
+#define CFG_WMT_COREDUMP_ENABLE 0
+
+#define CFG_WMT_MULTI_PATCH (1)
+
+#define CFG_WMT_CRYSTAL_TIMING_SET (0)
+
+#if CFG_WMT_LTE_COEX_HANDLING
+#define CFG_WMT_FILTER_MODE_SETTING (1)
+#else
+#define CFG_WMT_FILTER_MODE_SETTING (0)
+#endif
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static UINT8 gFullPatchName[NAME_MAX + 1];
+static const WMT_IC_INFO_S *gp_mt6630_info;
+static WMT_PATCH gp_mt6630_patch_info;
+static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS;
+
+static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 };
+static UINT8 WMT_QUERY_BAUD_EVT_115200[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 };
+static UINT8 WMT_QUERY_BAUD_EVT_X[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 };
+static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 };
+static UINT8 WMT_QUERY_STP_EVT_UART[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 };
+static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF };
+static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 };
+static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 };
+static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 };
+static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 };
+
+#if CFG_WMT_BT_PORT2
+static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 };
+static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+#if CFG_WMT_MULTI_PATCH
+static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+0xD4, 0x03, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff };
+
+static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+0xfc, 0x08, 0x09, 0x02, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0xff, 0xff };
+
+static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+#endif
+
+/*coex cmd/evt++*/
+static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+#if CFG_SUBSYS_COEX_NEED
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C,
+ 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A,
+ 0x00, 0x04,
+ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE
+};
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINt8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09,
+ 0x00, 0x05,
+ 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB
+};
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+/*coex cmd/evt--*/
+static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 };
+static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 };
+
+/* to get full dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = {
+ 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 };
+static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 };
+
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+
+
+static UINT8 WMT_SET_DAI_MODE_REG_CMD[] = { 0x01, 0x08, 0x28, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x03 /*2 registers */
+ , 0x6c, 0x50, 0x02, 0x80 /*addr:0x8002506c */
+ , 0x00, 0x00, 0x10, 0x11 /*value:0x11100000 */
+ , 0x00, 0x00, 0xf0, 0xff /*mask:0xfff00000 */
+ , 0x70, 0x50, 0x02, 0x80 /*addr:0x80025070 */
+ , 0x01, 0x00, 0x00, 0x00 /*value:0x00000001 */
+ , 0x0f, 0x00, 0x00, 0x00 /*mask:0x0000000f */
+ , 0x00, 0x53, 0x02, 0x80 /*addr:0x80025300 */
+ , 0x04, 0x00, 0x00, 0x00 /*value:0x00000004 */
+ , 0x04, 0x00, 0x00, 0x00 /*mask:0x00000004 */
+};
+
+static UINT8 WMT_SET_DAI_MODE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x03 /*2 registers */
+};
+
+
+#endif
+
+
+#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */
+static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */
+ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */
+ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */
+ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */
+};
+
+static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */
+static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */
+ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */
+ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */
+ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */
+ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */
+};
+
+static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+};
+#endif
+
+#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */
+static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */
+ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */
+ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */
+ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */
+};
+
+static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */
+ /* cirq_int_n */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */
+ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */
+ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 5 registers */
+};
+#endif
+
+static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 };
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 };
+static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 };
+#endif
+
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { 0x01, 0x10, 0x45, 0x00, 0x11,
+ 0x00, 0x00, 0x01, 0x00, 0x11,
+ 0x11, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x63, 0x63, 0x63,
+ 0x00, 0x39, 0x43, 0x63, 0x63,
+ 0x02, 0x02, 0x03, 0x00, 0x01,
+ 0x01, 0x01, 0x01, 0x0e, 0x0e,
+ 0x0e, 0x00, 0x0a, 0x0c, 0x0e,
+ 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { 0x01, 0x10, 0x21, 0x00, 0x12,
+ 0xfc, 0x08, 0x15, 0x09, 0x2e,
+ 0x09, 0x47, 0x09, 0xc4, 0x09,
+ 0xd4, 0x09, 0xe3, 0x09, 0x5a,
+ 0x0a, 0x14, 0x09, 0x2d, 0x09,
+ 0x46, 0x09, 0x60, 0x09, 0xd3,
+ 0x09, 0xe2, 0x09, 0x59, 0x0a,
+ 0x8B, 0x0a
+};
+
+static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 };
+
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+#else
+static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 };
+#endif
+
+static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 };
+
+static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+static struct init_script init_table_1_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"),
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"),
+ INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"),
+};
+
+
+static struct init_script init_table_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_3[] = {
+ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"),
+#if CFG_WMT_BT_PORT2
+ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"),
+#endif
+};
+
+static struct init_script set_crystal_timing_script[] = {
+ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT,
+ "set crystal trim value"),
+};
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static struct init_script get_crystal_timing_script[] = {
+ INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT,
+ "get crystal trim value"),
+};
+#endif
+
+static struct init_script init_table_4[] = {
+ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"),
+};
+
+static struct init_script init_table_5[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"),
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_5_1[] = {
+ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"),
+};
+
+static struct init_script init_table_6[] = {
+ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"),
+};
+
+
+#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG
+static struct init_script set_registers[] = {
+ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */
+ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */
+#if CFG_WMT_I2S_DBGUART_SUPPORT
+ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"),
+#endif
+#if CFG_SET_OPT_REG_SWLA
+ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUCLK
+ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUIRQ
+ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"),
+#endif
+};
+#endif
+
+static struct init_script coex_table[] = {
+ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"),
+
+#if CFG_SUBSYS_COEX_NEED
+/* no need in MT6630 */
+ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"),
+ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"),
+ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"),
+ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"),
+#endif
+};
+
+static struct init_script osc_type_table[] = {
+ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"),
+};
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static struct init_script merge_pcm_table[] = {
+ INIT_CMD(WMT_SET_DAI_MODE_REG_CMD, WMT_SET_DAI_MODE_REG_EVT, "DAI_PAD"),
+};
+#endif
+
+#if CFG_WMT_FILTER_MODE_SETTING
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+static struct init_script set_wifi_lte_coex_table_0[] = {
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"),
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT,
+ "wifi lte freq id table"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"),
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"),
+};
+#else
+static struct init_script set_wifi_lte_coex_table_0[] = {
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"),
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"),
+ INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"),
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"),
+};
+#endif
+#endif
+
+/* MT6630 Chip Version and Info Table */
+static const WMT_IC_INFO_S mt6630_info_table[] = {
+ {
+ .u4HwVer = 0x8A00,
+ .cChipName = WMT_IC_NAME_MT6630,
+ .cChipVersion = WMT_IC_VER_E1,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A10,
+ .cChipName = WMT_IC_NAME_MT6630,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A11,
+ .cChipName = WMT_IC_NAME_MT6630,
+ .cChipVersion = WMT_IC_VER_E3,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B11,
+ .cChipName = WMT_IC_NAME_MT6630,
+ .cChipVersion = WMT_IC_VER_E4,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ }
+};
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6630_sw_init(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6630_sw_deinit(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6630_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6630_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6630_ver_check(VOID);
+
+static const WMT_IC_INFO_S *mt6630_find_wmt_ic_info(const UINT32 hw_ver);
+
+static INT32 wmt_stp_init_coex(VOID);
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mt6630_patch_dwn(UINT32 index);
+static INT32 mt6630_patch_info_prepare(VOID);
+#else
+static INT32 mt6630_patch_dwn(VOID);
+#endif
+
+static INT32 mt6630_co_clock_ctrl(WMT_CO_CLOCK on);
+static WMT_CO_CLOCK mt6630_co_clock_get(VOID);
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static INT32 mt6630_crystal_triming_set(VOID);
+#endif
+
+static MTK_WCN_BOOL mt6630_quick_sleep_flag_get(VOID);
+
+static MTK_WCN_BOOL mt6630_aee_dump_flag_get(VOID);
+#if 0
+/* set sdio driving */
+static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */
+ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */
+ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */
+};
+
+static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static INT32 mt6630_set_sdio_driving(void);
+static struct init_script sdio_driving_table[] = {
+ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"),
+};
+
+#endif
+static MTK_WCN_BOOL mt6630_trigger_stp_assert(VOID);
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID);
+#endif
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/* MT6630 Operation Function Table */
+WMT_IC_OPS wmt_ic_ops_mt6630 = {
+ .icId = 0x6630,
+ .sw_init = mt6630_sw_init,
+ .sw_deinit = mt6630_sw_deinit,
+ .ic_pin_ctrl = mt6630_pin_ctrl,
+ .ic_ver_check = mt6630_ver_check,
+ .co_clock_ctrl = mt6630_co_clock_ctrl,
+ .is_quick_sleep = mt6630_quick_sleep_flag_get,
+ .is_aee_dump_support = mt6630_aee_dump_flag_get,
+ .trigger_stp_assert = mt6630_trigger_stp_assert,
+ .deep_sleep_ctrl = NULL,
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6630_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[256];
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ UINT32 hw_ver;
+#if CFG_WMT_MULTI_PATCH
+ UINT32 patch_num = 0;
+ UINT32 patch_index = 0;
+#endif
+ WMT_CTRL_DATA ctrlData;
+
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_mt6630_info != NULL);
+
+ if ((gp_mt6630_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_mt6630_info(0x%p), pWmtHifConf(0x%p)\n",
+ gp_mt6630_info, pWmtHifConf);
+ return -1;
+ }
+
+ hw_ver = gp_mt6630_info->u4HwVer;
+
+ /* 4 <3.1> start init for sdio */
+
+ /* 4 <3.2> start init for uart */
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* init variable fields for script execution */
+ osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+ osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+
+ /* 3. Query chip baud rate (TEST-ONLY) */
+ /* 4. Query chip STP options (TEST-ONLY) */
+ /* 5. Change chip baud rate: t_baud */
+ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */
+ iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 6. Set host baudrate and flow control */
+ ctrlPa1 = pWmtHifConf->au4HifConf[0];
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+
+ if (iRet) {
+ WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0],
+ iRet);
+ return -3;
+ }
+
+ WMT_DBG_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]);
+
+ /* 7. Wake up chip and check event */
+/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res,
+ MTK_WCN_BOOL_TRUE);
+
+ if (iRet || (u4Res != 1)) {
+ WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res);
+ return -4;
+ }
+
+ osal_memset(evtBuf, 0, osal_sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res);
+#ifdef CFG_DUMP_EVT
+ WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5]);
+#endif
+
+ if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) {
+ WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ return -5;
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */
+
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp
+ (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n");
+ return -6;
+ }
+#endif
+
+ /* 8. Query baud rate (TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet);
+ return -7;
+ }
+ }
+
+ /* 9. download patch */
+#if CFG_WMT_MULTI_PATCH
+ /* 9.1 Let launcher to search patch info */
+ iRet = mt6630_patch_info_prepare();
+
+ if (iRet) {
+ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet);
+ return -8;
+ }
+
+ /* 9.2 Read patch number */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2);
+ patch_num = ctrlPa1;
+ WMT_INFO_FUNC("patch total num = [%d]\n", patch_num);
+
+ /* 9.3 Multi-patch Patch download */
+ for (patch_index = 0; patch_index < patch_num; patch_index++) {
+ iRet = mt6630_patch_dwn(patch_index);
+
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index);
+ return -12;
+ }
+
+ iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -13;
+ }
+ }
+
+#else
+ /* 9.3 Patch download */
+ iRet = mt6630_patch_dwn();
+
+ /* If patch download fail, we just ignore this error and let chip init process goes on */
+ if (iRet)
+ WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet);
+#endif /* End of #if CFG_WMT_MULTI_PATCH */
+
+ /* 10. WMT Reset command */
+ iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -9;
+ }
+
+ iRet = wmt_stp_init_coex();
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -10;
+ }
+ WMT_DBG_FUNC("init_coex ok\n");
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+ mt6630_crystal_triming_set();
+#endif
+
+#if MT6630_BRINGUP
+ WMT_INFO_FUNC("Bring up period, skip sdio driving settings\n");
+#else
+ WMT_DBG_FUNC("Temp solution, skip sdio driving settings\n");
+ /* 6630_set_sdio_driving(); */
+#endif
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* 11. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -12;
+ }
+
+ /* 12. Enable host STP-UART mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet);
+ return -13;
+ }
+
+ WMT_INFO_FUNC("enable host STP-UART-FULL mode\n");
+ /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+ /* 14. Query chip STP options (TEST-ONLY) */
+ /* 15. Query baud rate (stp, TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -14;
+ }
+ }
+
+ if (mt6630_co_clock_get() == WMT_CO_CLOCK_EN) {
+ WMT_INFO_FUNC("co-clock enabled.\n");
+
+ iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table));
+
+ if (iRet) {
+ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+ } else if (mt6630_co_clock_get() == WMT_CO_CLOCK_DCXO) {
+ WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_EVT[5] = 0x0;
+ iRet = wmt_core_init_script(set_crystal_timing_script, ARRAY_SIZE(set_crystal_timing_script));
+ if (iRet == 0)
+ WMT_INFO_FUNC("set to Xtal mode suceed\n");
+ else
+ WMT_INFO_FUNC("set to Xtal mode failed, iRet:%d.\n", iRet);
+
+
+ } else
+ WMT_DBG_FUNC("co-clock disabled.\n");
+#if MT6630_BRINGUP
+ WMT_INFO_FUNC("Bring up period, skip merge interface settings\n");
+#else
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+ iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table));
+
+ if (iRet) {
+ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+#endif
+#endif
+ /* 15. Set FM strap */
+ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ iRet = wmt_core_init_script(init_table_5_1, ARRAY_SIZE(init_table_5_1));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n",
+ pWmtHifConf->au4StrapConf[0], iRet);
+ return -16;
+ }
+
+ WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]);
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers));
+
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -17;
+ }
+#endif
+
+#if CFG_WMT_COREDUMP_ENABLE
+ /*Open Core Dump Function @QC begin */
+ mtk_wcn_stp_coredump_flag_ctrl(1);
+#endif
+
+ if (mtk_wcn_stp_coredump_flag_get() != 0) {
+ iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet);
+ return -18;
+ }
+ WMT_INFO_FUNC("enable mt662x firmware coredump\n");
+ } else
+ WMT_INFO_FUNC("disable mt662x firmware coredump\n");
+
+ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO;
+ ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6630.icId;
+ ctrlData.au4CtrlData[1] = (size_t) gp_mt6630_info->cChipVersion;
+ ctrlData.au4CtrlData[2] = (size_t) &gp_mt6630_patch_info;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet);
+ return -16;
+ }
+#if CFG_WMT_FILTER_MODE_SETTING
+ wmt_stp_wifi_lte_coex();
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6630_info != NULL);
+
+ if (gp_mt6630_info != NULL) {
+ if (gp_mt6630_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ return 0;
+}
+
+static INT32 mt6630_sw_deinit(P_WMT_HIF_CONF pWmtHifConf)
+{
+ WMT_DBG_FUNC(" start\n");
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6630_info != NULL);
+
+ if ((gp_mt6630_info != NULL)
+ && (gp_mt6630_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) {
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ gp_mt6630_info = NULL;
+
+ return 0;
+}
+
+static INT32 mt6630_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+
+#if MT6630_BRINGUP
+ ret = 0;
+ WMT_INFO_FUNC("Bring up period, skip aif settings\n");
+#else
+
+ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) {
+ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n");
+
+ WMT_WARN_FUNC("TBD!!");
+ ret = 0;
+ } else {
+ /*PCM & I2S separate */
+ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n");
+
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+#if 0
+ val = 0x01110000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000);
+#else
+ ret = 0;
+ WMT_INFO_FUNC("Bring up period, skip WMT_IC_AIF_2 settings\n");
+#endif
+ break;
+
+ case WMT_IC_AIF_3:
+ ret = 0;
+ break;
+
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!ret)
+ WMT_INFO_FUNC("new state(%d) ok\n", state);
+ else
+ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret);
+#endif
+ return ret;
+}
+
+static INT32 mt6630_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+#if 0
+ INT32 iRet = -1;
+ UINT32 uVal = 0;
+
+ if (state == WMT_IC_PIN_MUX)
+ uVal = 0x1 << 4;
+ else
+ uVal = 0x0 << 4;
+ /*0x80025070[7:4]: 1-A-GPS_SYNC mode, 0-Jtag mode */
+#if MT6630_BRINGUP
+ iRet = 0;
+ WMT_INFO_FUNC("Bring up period, skip gps sync settings\n");
+
+#else
+ iRet = wmt_core_reg_rw_raw(1, 0x80025070, &uVal, 0xf << 4);
+#endif
+ if (iRet != 0)
+ WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet);
+#endif
+ /* anyway, we return 0 */
+ return 0;
+}
+
+
+static INT32 mt6630_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret;
+
+ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag);
+
+ ret = -1;
+
+ switch (id) {
+ case WMT_IC_PIN_AUDIO:
+ ret = mt6630_aif_ctrl(state, flag);
+ break;
+
+ case WMT_IC_PIN_EEDI:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_EEDO:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_GSYNC:
+ ret = mt6630_gps_sync_ctrl(state, flag);
+ break;
+
+ default:
+ break;
+ }
+
+ WMT_INFO_FUNC("ret = (%d)\n", ret);
+
+ return ret;
+}
+
+INT32 mt6630_co_clock_ctrl(WMT_CO_CLOCK on)
+{
+ INT32 iRet = 0;
+
+ if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) {
+ gCoClockEn = on;
+ } else {
+ WMT_DBG_FUNC("MT6630: error parameter:%d\n", on);
+ iRet = -1;
+ }
+
+ WMT_DBG_FUNC("MT6630: Co-clock type: %d\n", gCoClockEn);
+
+ return iRet;
+}
+
+static MTK_WCN_BOOL mt6630_quick_sleep_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+static MTK_WCN_BOOL mt6630_aee_dump_flag_get(VOID)
+{
+ if (mtk_wcn_stp_coredump_flag_get() == 1)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static MTK_WCN_BOOL mt6630_trigger_stp_assert(VOID)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ UINT8 STP_DO_ASSERT_CMD[] = { 0x80, 0x50, 0x0a, 0x00, 'd', 'o', 'c', 'o', 'r', 'e', 'd', 'u', 'm', 'p', 0x00,
+ 0x00
+ };
+
+ iRet =
+ wmt_core_tx((PUINT8)&STP_DO_ASSERT_CMD[0], sizeof(STP_DO_ASSERT_CMD), &u4Res,
+ MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != sizeof(STP_DO_ASSERT_CMD))) {
+ WMT_ERR_FUNC("wmt_core:send STP ASSERT COMMAND fail(%d),size(%d)\n", iRet, u4Res);
+ bRet = MTK_WCN_BOOL_FALSE;
+ } else
+ bRet = MTK_WCN_BOOL_TRUE;
+ return bRet;
+}
+
+WMT_CO_CLOCK mt6630_co_clock_get(VOID)
+{
+ return gCoClockEn;
+}
+
+
+
+static INT32 mt6630_ver_check(VOID)
+{
+ UINT32 hw_ver = 0;
+ UINT32 fw_ver = 0;
+ INT32 iret;
+ const WMT_IC_INFO_S *p_info = NULL;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */
+ WMT_LOUD_FUNC("MT6630: before read hw_ver (hw version)\n");
+ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK);
+
+ if (iret) {
+ WMT_ERR_FUNC("MT6630: read hw_ver fail:%d\n", iret);
+ return -2;
+ }
+
+ WMT_LOUD_FUNC("MT6630: before fw_ver (rom version)\n");
+ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK);
+
+ if (iret) {
+ WMT_ERR_FUNC("MT6630: read fw_ver fail:%d\n", iret);
+ return -2;
+ }
+
+ WMT_INFO_FUNC("MT6630: read (hw version)(0x%x), (fw version version)(0x%x)\n", hw_ver, fw_ver);
+
+ p_info = mt6630_find_wmt_ic_info(hw_ver);
+
+ if (p_info == NULL) {
+ WMT_ERR_FUNC("MT6630: hw_ver(0x%x) find wmt ic info fail\n", hw_ver);
+ return -3;
+ }
+
+ WMT_INFO_FUNC("MT6630: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n",
+ p_info->cChipName, p_info->cChipVersion,
+ p_info->u4HwVer, p_info->cPatchNameExt);
+
+ /* hw id & version */
+ ctrlPa1 = (0x00006630UL << 16) | (hw_ver & 0x0000FFFF);
+ /* translated fw rom version */
+ ctrlPa2 = (fw_ver & 0x0000FFFF);
+
+ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2);
+
+ if (iret)
+ WMT_WARN_FUNC("MT6630: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret);
+
+ gp_mt6630_info = p_info;
+ return 0;
+}
+
+static const WMT_IC_INFO_S *mt6630_find_wmt_ic_info(const UINT32 hw_ver)
+{
+ /* match chipversion with u4HwVer item in mt6630_info_table */
+ const UINT32 size = ARRAY_SIZE(mt6630_info_table);
+ INT32 index;
+
+ /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */
+ index = size - 1;
+
+ /* full match */
+ while ((index >= 0)
+ && (hw_ver != mt6630_info_table[index].u4HwVer) /* full match */
+ ) {
+ --index;
+ }
+
+ if (index >= 0) {
+ WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index);
+ return &mt6630_info_table[index];
+ }
+
+ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver);
+
+ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR
+ * NUM only can help us support future minor hw ECO, or fab switch, etc.
+ * FULL matching eliminate such flexibility and software package have to be
+ * updated EACH TIME even when minor hw ECO or fab switch!!!
+ */
+ /* George: reverse the search order to favor newer version products */
+ index = size - 1;
+
+ /* major num match */
+ while ((index >= 0)
+ && (MAJORNUM(hw_ver) != MAJORNUM(mt6630_info_table[index].u4HwVer))
+ ) {
+ --index;
+ }
+
+ if (index >= 0) {
+ WMT_INFO_FUNC("MT6630: found ic info for hw_ver(0x%x) by major num! index:%d\n",
+ hw_ver, index);
+ return &mt6630_info_table[index];
+ }
+
+ WMT_ERR_FUNC
+ ("MT6630: find no ic info for hw_ver(0x%x) by full match nor major num match!\n",
+ hw_ver);
+ return NULL;
+}
+
+
+static INT32 wmt_stp_init_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+#define COEX_WMT 0
+
+#if CFG_SUBSYS_COEX_NEED
+ /* no need for MT6630 */
+#define COEX_BT 1
+#define COEX_WIFI 2
+#define COEX_PTA 3
+#define COEX_MISC 4
+#endif
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+
+ /*Dump the coex-related info */
+ WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode);
+#if CFG_SUBSYS_COEX_NEED
+ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_bt_rssi_upper_limit,
+ pWmtGenConf->coex_bt_rssi_mid_limit,
+ pWmtGenConf->coex_bt_rssi_lower_limit,
+ pWmtGenConf->coex_bt_pwr_high,
+ pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low);
+ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wifi_rssi_upper_limit,
+ pWmtGenConf->coex_wifi_rssi_mid_limit,
+ pWmtGenConf->coex_wifi_rssi_lower_limit,
+ pWmtGenConf->coex_wifi_pwr_high,
+ pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low);
+ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_ext_pta_hi_tx_tag,
+ pWmtGenConf->coex_ext_pta_hi_rx_tag,
+ pWmtGenConf->coex_ext_pta_lo_tx_tag,
+ pWmtGenConf->coex_ext_pta_lo_rx_tag,
+ pWmtGenConf->coex_ext_pta_sample_t1,
+ pWmtGenConf->coex_ext_pta_sample_t2,
+ pWmtGenConf->coex_ext_pta_wifi_bt_con_trx);
+ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set);
+#endif
+
+ /*command adjustion due to WMT.cfg */
+ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0],
+ coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz);
+ }
+#if CFG_SUBSYS_COEX_NEED
+ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit;
+ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit;
+ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit;
+ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high;
+ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid;
+ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0],
+ coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz);
+ }
+
+ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit;
+ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit;
+ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit;
+ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high;
+ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid;
+ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0],
+ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz);
+ }
+
+ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag;
+ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag;
+ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag;
+ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag;
+ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0],
+ coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz);
+ }
+
+ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on,
+ sizeof(pWmtGenConf->coex_misc_ext_pta_on));
+ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set,
+ sizeof(pWmtGenConf->coex_misc_ext_feature_set));
+
+ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str,
+ coex_table[COEX_MISC].cmdSz);
+#endif
+
+ iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table));
+
+ return iRet;
+}
+
+#if 0
+static INT32 mt6630_set_sdio_driving(void)
+{
+ INT32 ret = 0;
+
+ UINT32 addr = 0;
+ WMT_GEN_CONF *pWmtGenConf;
+ UINT32 drv_val = 0;
+
+ /*Get wmt config */
+ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (ret) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret);
+ return -1;
+ }
+
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%x)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ drv_val = pWmtGenConf->sdio_driving_cfg;
+
+ /*Dump the sdio driving related info */
+ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val);
+
+ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */
+ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */
+ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */
+
+ ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table));
+
+ return ret;
+}
+#endif
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static INT32 mt6630_crystal_triming_set(VOID)
+{
+ INT32 iRet = 0;
+ PUINT8 pbuf = NULL;
+ UINT32 bufLen = 0;
+ WMT_CTRL_DATA ctrlData;
+ UINT32 uCryTimOffset = 0x6D;
+ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ INT8 cCrystalTimingOffset = 0x0;
+ UINT8 cCrystalTiming = 0x0;
+ INT32 iCrystalTiming = 0x0;
+ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ UINT32 u4Res;
+
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ ctrlData.au4CtrlData[1] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[2] = (size_t) &bufLen;
+
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ iRet = -1;
+ } else {
+ WMT_DBG_FUNC("MT6630: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen);
+
+ if (bufLen < (uCryTimOffset + 1)) {
+ WMT_ERR_FUNC
+ ("MT6630: nvram len(%d) too short, crystalTimging value offset(%d)\n",
+ bufLen, uCryTimOffset);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ } else {
+ bIsNvramExist = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = *(pbuf + uCryTimOffset);
+
+ if (cCrystalTimingOffset & 0x80) {
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f;
+ }
+
+ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n",
+ cCrystalTimingOffset, bIsCrysTrimEnabled);
+ }
+
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet);
+ iRet = -2;
+ } else {
+ WMT_DBG_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n");
+ }
+ }
+
+ if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) {
+ /*get CrystalTiming value before set it */
+ iRet =
+ wmt_core_tx(get_crystal_timing_script[0].cmd,
+ get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].cmdSz);
+ iRet = -3;
+ goto done;
+ }
+
+ /* EVENT BUF */
+ osal_memset(get_crystal_timing_script[0].evt, 0,
+ get_crystal_timing_script[0].evtSz);
+ iRet =
+ wmt_core_rx(get_crystal_timing_script[0].evt,
+ get_crystal_timing_script[0].evtSz, &u4Res);
+
+ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].evtSz);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet = -4;
+ goto done;
+ }
+
+ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f;
+
+ if (cCrystalTimingOffset & 0x40) {
+ /*nagative offset value */
+ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128;
+ } else {
+ iCrystalTiming += cCrystalTimingOffset;
+ }
+
+ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming);
+ if (iCrystalTiming > 0x7f)
+ cCrystalTiming = 0x7f;
+ else if (iCrystalTiming < 0)
+ cCrystalTiming = 0;
+ else
+ cCrystalTiming = iCrystalTiming;
+ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming);
+ /* set_crystal_timing_script */
+ /*set crystal trim value command*/
+ WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x1;
+ WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x1;
+
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming;
+ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming;
+
+ iRet =
+ wmt_core_init_script(set_crystal_timing_script,
+ ARRAY_SIZE(set_crystal_timing_script));
+
+ if (iRet) {
+ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -5;
+ } else {
+ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n",
+ WMT_SET_CRYSTAL_TRIMING_CMD[5]);
+ iRet =
+ wmt_core_init_script(get_crystal_timing_script,
+ ARRAY_SIZE(get_crystal_timing_script));
+
+ if (iRet) {
+ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -6;
+ } else {
+ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n",
+ WMT_GET_CRYSTAL_TRIMING_EVT[5]);
+ iRet = 0x0;
+ }
+ }
+ }
+
+done:
+ return iRet;
+}
+#endif
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mt6630_patch_info_prepare(VOID)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+
+static INT32 mt6630_patch_dwn(UINT32 index)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr = NULL;
+ PUINT8 pBuf = NULL;
+ PUINT8 pPatchBuf = NULL;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ UINT8 addressevtBuf[12];
+ UINT8 addressByte[4];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6630_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6630_info!\n");
+ return -1;
+ }
+
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = index + 1;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &addressByte;
+ iRet = wmt_ctrl(&ctrlData);
+ WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName);
+
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &pBuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ pPatchBuf = osal_malloc(patchSize);
+ if (pPatchBuf == NULL) {
+ WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n");
+ return -2;
+ }
+ osal_memcpy(pPatchBuf, pBuf, patchSize);
+ /* check patch file information */
+
+ patchHdr = (P_WMT_PATCH) pPatchBuf;
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+
+ osal_memcpy(&gp_mt6630_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+
+ if (index == 0) {
+ WMT_INFO_FUNC("Combo Patch:Build Time(%s)Hw(0x%x) Sw(0x%x) Ph(0x%04x)Platform(%c%c%c%c)\n",
+ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8),
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8),
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16),
+ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ }
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -1;
+ goto done;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pPatchBuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ pPatchBuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+
+ /*send wmt part patch address command */
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ iRet -= 1;
+ goto done;
+ }
+
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) !=
+ 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n");
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /*send part patch address command */
+ osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte));
+ WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_P_ADDRESS_CMD[12],
+ WMT_PATCH_P_ADDRESS_CMD[13],
+ WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]);
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n",
+ iRet, u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet,
+ u4Res, index);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT))
+ != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n",
+ index);
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+
+ iRet =
+ wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+
+done:
+ if (patchHdr != NULL) {
+ osal_free(patchHdr);
+ pPatchBuf = NULL;
+ patchHdr = NULL;
+ }
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = index + 1;
+ wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+#else
+static INT32 mt6630_patch_dwn(VOID)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr;
+ PUINT8 pbuf;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6630_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6630_info!\n");
+ return -1;
+ }
+ /* <2> search patch and read patch content */
+ /* <2.1> search patch */
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet == 0) {
+ /* patch with correct Hw Ver Major Num found */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME;
+ ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName;
+ iRet = wmt_ctrl(&ctrlData);
+
+ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName);
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+
+ } else {
+ iRet -= 1;
+ return iRet;
+ }
+
+ ctrlData.au4CtrlData[2] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+
+ osal_memcpy(&gp_mt6630_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+ WMT_INFO_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime);
+ WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n",
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n",
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16));
+ WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0],
+ patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_INFO_FUNC("===========================================\n");
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ return -1;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+
+ /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ * fragSize + sizeof(WMT_PATCH_CMD), &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL);
+
+ return iRet;
+}
+
+#endif
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ if (pWmtGenConf->coex_wmt_filter_mode == 0) {
+ /*add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 xLNA demand*/
+ if (pWmtGenConf->coex_wmt_ext_component) {
+ WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component);
+ set_wifi_lte_coex_table_0[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component;
+ }
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_0,
+ ARRAY_SIZE(set_wifi_lte_coex_table_0));
+ if (iRet)
+ WMT_ERR_FUNC("wmt_core:set_wifi_lte_coex_table_0 fail(%d)\n", iRet);
+ else
+ WMT_INFO_FUNC("wmt_core:set_wifi_lte_coex_table_0 ok\n");
+ }
+
+ return iRet;
+}
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c
new file mode 100644
index 0000000000000000000000000000000000000000..20847f00a4a1511d8ecbf272f98b2fc1ed829f11
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c
@@ -0,0 +1,1989 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-IC]"
+#define CFG_IC_MT6632 1
+
+#define MT6632_BRINGUP 0
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_ic.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "stp_core.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define DEFAULT_PATCH_FRAG_SIZE (1000)
+#define WMT_PATCH_FRAG_1ST (0x1)
+#define WMT_PATCH_FRAG_MID (0x2)
+#define WMT_PATCH_FRAG_LAST (0x3)
+
+#define CFG_CHECK_WMT_RESULT (1)
+/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */
+#define CFG_WMT_BT_PORT2 (0)
+
+#define CFG_SET_OPT_REG (0)
+#define CFG_WMT_I2S_DBGUART_SUPPORT (0)
+#define CFG_SET_OPT_REG_SWLA (0)
+#define CFG_SET_OPT_REG_MCUCLK (0)
+#define CFG_SET_OPT_REG_MCUIRQ (0)
+
+#define CFG_SUBSYS_COEX_NEED 0
+
+#define CFG_WMT_COREDUMP_ENABLE 0
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 g_deep_sleep_flag = 1;
+#else
+INT32 g_deep_sleep_flag;
+#endif
+
+#if CFG_WMT_LTE_COEX_HANDLING
+#define CFG_WMT_FILTER_MODE_SETTING (1)
+#else
+#define CFG_WMT_FILTER_MODE_SETTING (0)
+#endif
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static UINT8 gFullPatchName[NAME_MAX + 1];
+static const WMT_IC_INFO_S *gp_mt6632_info;
+static WMT_PATCH gp_mt6632_patch_info;
+static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS;
+
+static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 };
+static UINT8 WMT_QUERY_BAUD_EVT_115200[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 };
+static UINT8 WMT_QUERY_BAUD_EVT_X[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 };
+static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 };
+static UINT8 WMT_QUERY_STP_EVT_UART[] = {
+ 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 };
+static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF };
+static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 };
+static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 };
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+UINT8 WMT_DEEP_SLEEP_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x11, 0x00 };
+UINT8 WMT_DEEP_SLEEP_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00 };
+#endif
+
+UINT8 WMT_CLOCK_RATE_CMD[] = {0x01, 0x0A, 0x04, 0x00, 0x09, 0x01, 0x00, 0x00};
+UINT8 WMT_CLOCK_RATE_EVT[] = {0x02, 0x0A, 0x01, 0x00, 0x00};
+UINT8 WMT_PATCH_DWN_USE_DMA_CMD[] = {0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0xc0, 0x0a, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+UINT8 WMT_PATCH_DWN_USE_DMA_EVT[] = {0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 };
+static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 };
+
+#if CFG_WMT_BT_PORT2
+static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 };
+static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x01, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
+
+static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00};
+
+/*coex cmd/evt++*/
+static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+#if CFG_SUBSYS_COEX_NEED
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C,
+ 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A,
+ 0x00, 0x04,
+ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE
+};
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINt8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09,
+ 0x00, 0x05,
+ 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB
+};
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#else
+static UINT8 WMT_COEX_WIFI_PATH_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x1A, 0x0F, 0x00 };
+static UINT8 WMT_COEX_WIFI_PATH_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_CMD[] = { 0x01, 0x10, 0x12, 0x00, 0x1B, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+/*coex cmd/evt--*/
+static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 };
+
+static UINT8 WMT_SET_SDIO_RETRY_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x18, 0x01 };
+static UINT8 WMT_SET_SDIO_RETRY_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x01 };
+
+/* to get full dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = {
+ 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 };
+static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 };
+
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+
+
+static UINT8 WMT_SET_DAI_MODE_REG_CMD[] = { 0x01, 0x08, 0x1c, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x54, 0x30, 0x02, 0x81 /*addr:0x81023054 */
+ , 0x00, 0x00, 0x33, 0x33 /*value:0x33330000 */
+ , 0x00, 0x00, 0xff, 0xff /*mask:0xffff0000 */
+ , 0x00, 0x53, 0x02, 0x80 /*addr:0x80025300 */
+ , 0x04, 0x00, 0x00, 0x00 /*value:0x00000004 */
+ , 0x04, 0x00, 0x00, 0x00 /*mask:0x00000004 */
+};
+
+static UINT8 WMT_SET_DAI_MODE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+
+
+#endif
+
+
+#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */
+static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */
+ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */
+ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */
+ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */
+};
+
+static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */
+static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */
+ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */
+ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */
+ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */
+ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */
+};
+
+static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+};
+#endif
+
+#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */
+static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */
+ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */
+ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */
+ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */
+};
+
+static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */
+ /* cirq_int_n */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */
+ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */
+ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 5 registers */
+};
+#endif
+
+static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 };
+
+/*
+* static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 };
+* static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 };
+*/
+
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { 0x01, 0x10, 0x45, 0x00, 0x11,
+ 0x00, 0x00, 0x01, 0x00, 0x11,
+ 0x11, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x63, 0x63, 0x63,
+ 0x00, 0x39, 0x43, 0x63, 0x63,
+ 0x02, 0x02, 0x03, 0x00, 0x01,
+ 0x01, 0x01, 0x01, 0x0e, 0x0e,
+ 0x0e, 0x00, 0x0a, 0x0c, 0x0e,
+ 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { 0x01, 0x10, 0x21, 0x00, 0x12,
+ 0xfc, 0x08, 0x15, 0x09, 0x2e,
+ 0x09, 0x47, 0x09, 0xc4, 0x09,
+ 0xd4, 0x09, 0xe3, 0x09, 0x5a,
+ 0x0a, 0x14, 0x09, 0x2d, 0x09,
+ 0x46, 0x09, 0x60, 0x09, 0xd3,
+ 0x09, 0xe2, 0x09, 0x59, 0x0a,
+ 0x8B, 0x0a
+};
+
+static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 };
+
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+#else
+static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 };
+#endif
+
+static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 };
+
+static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+static struct init_script init_table_1_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"),
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"),
+ INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"),
+};
+
+
+static struct init_script init_table_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_3[] = {
+ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"),
+#if CFG_WMT_BT_PORT2
+ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"),
+#endif
+};
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+static struct init_script init_deep_sleep_script[] = {
+ INIT_CMD(WMT_DEEP_SLEEP_CMD, WMT_DEEP_SLEEP_EVT, "chip deep sleep"),
+};
+#endif
+
+static struct init_script clock_rate_modify[] = {
+ INIT_CMD(WMT_CLOCK_RATE_CMD, WMT_CLOCK_RATE_EVT, "clock rate modify"),
+};
+
+/* WMT_CLOCK_RATE_CMD[6] = 0xD0, promote the XTAL(26MHz) rate to 208MHz */
+static struct init_script clock_rate_pro_and_use_dma[] = {
+ INIT_CMD(WMT_CLOCK_RATE_CMD, WMT_CLOCK_RATE_EVT, "clock rate modify"),
+ INIT_CMD(WMT_PATCH_DWN_USE_DMA_CMD, WMT_PATCH_DWN_USE_DMA_EVT, "patch dwn use DMA"),
+};
+
+
+static struct init_script set_crystal_timing_script[] = {
+ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT,
+ "set crystal trim value"),
+};
+/*
+* static struct init_script get_crystal_timing_script[] = {
+* INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT,
+* "get crystal trim value"),
+* };
+*/
+
+static struct init_script init_table_4[] = {
+ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"),
+};
+
+static struct init_script set_sdio_retry_script[] = {
+ INIT_CMD(WMT_SET_SDIO_RETRY_CMD, WMT_SET_SDIO_RETRY_EVT, "set sdio retry"),
+};
+
+static struct init_script init_table_5[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"),
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+
+static struct init_script init_table_6[] = {
+ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"),
+};
+
+
+#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG
+static struct init_script set_registers[] = {
+ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */
+ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */
+#if CFG_WMT_I2S_DBGUART_SUPPORT
+ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"),
+#endif
+#if CFG_SET_OPT_REG_SWLA
+ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUCLK
+ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUIRQ
+ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"),
+#endif
+};
+#endif
+
+static struct init_script coex_table[] = {
+ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"),
+
+#if CFG_SUBSYS_COEX_NEED
+/* no need in MT6632 */
+ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"),
+ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"),
+ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"),
+ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"),
+#else
+ INIT_CMD(WMT_COEX_WIFI_PATH_CMD, WMT_COEX_WIFI_PATH_EVT, "wifi path"),
+ INIT_CMD(WMT_COEX_EXT_ELAN_GAIN_P1_CMD, WMT_COEX_EXT_ELAN_GAIN_P1_EVT, "wifi elan gain p1"),
+#endif
+};
+
+static struct init_script osc_type_table[] = {
+ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"),
+};
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static struct init_script merge_pcm_table[] = {
+ INIT_CMD(WMT_SET_DAI_MODE_REG_CMD, WMT_SET_DAI_MODE_REG_EVT, "DAI_PAD"),
+};
+#endif
+
+#if CFG_WMT_FILTER_MODE_SETTING
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+static struct init_script set_wifi_lte_coex_table_0[] = {
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"),
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT,
+ "wifi lte freq id table"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"),
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"),
+};
+#else
+static struct init_script set_wifi_lte_coex_table_0[] = {
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"),
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"),
+ INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"),
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"),
+};
+#endif
+#endif
+
+/* MT6632 Chip Version and Info Table */
+static const WMT_IC_INFO_S mt6632_info_table[] = {
+ {
+ .u4HwVer = 0x8A00,
+ .cChipName = WMT_IC_NAME_MT6632,
+ .cChipVersion = WMT_IC_VER_E1,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A10,
+ .cChipName = WMT_IC_NAME_MT6632,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A11,
+ .cChipName = WMT_IC_NAME_MT6632,
+ .cChipVersion = WMT_IC_VER_E3,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B11,
+ .cChipName = WMT_IC_NAME_MT6632,
+ .cChipVersion = WMT_IC_VER_E4,
+ .cPatchNameExt = WMT_IC_PATCH_E2_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ }
+};
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6632_sw_init(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6632_sw_deinit(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mt6632_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6632_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mt6632_ver_check(VOID);
+
+static const WMT_IC_INFO_S *mt6632_find_wmt_ic_info(const UINT32 hw_ver);
+
+static INT32 wmt_stp_init_coex(VOID);
+
+static INT32 mt6632_patch_dwn(UINT32 index);
+static INT32 mt6632_patch_info_prepare(VOID);
+
+static INT32 mt6632_co_clock_ctrl(WMT_CO_CLOCK on);
+static WMT_CO_CLOCK mt6632_co_clock_get(VOID);
+
+/*static INT32 mt6632_crystal_triming_set(VOID);*/
+
+
+static MTK_WCN_BOOL mt6632_quick_sleep_flag_get(VOID);
+
+static MTK_WCN_BOOL mt6632_aee_dump_flag_get(VOID);
+#if 0
+/* set sdio driving */
+static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */
+ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */
+ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */
+};
+
+static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static INT32 mt6632_set_sdio_driving(void);
+static struct init_script sdio_driving_table[] = {
+ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"),
+};
+
+#endif
+static MTK_WCN_BOOL mt6632_trigger_stp_assert(VOID);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+static MTK_WCN_BOOL mt6632_deep_sleep_ctrl(INT32 value);
+static INT32 wmt_stp_get_deep_sleep_flag_from_cfg(VOID);
+#endif
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID);
+#endif
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/* MT6632 Operation Function Table */
+WMT_IC_OPS wmt_ic_ops_mt6632 = {
+ .icId = 0x6632,
+ .sw_init = mt6632_sw_init,
+ .sw_deinit = mt6632_sw_deinit,
+ .ic_pin_ctrl = mt6632_pin_ctrl,
+ .ic_ver_check = mt6632_ver_check,
+ .co_clock_ctrl = mt6632_co_clock_ctrl,
+ .is_quick_sleep = mt6632_quick_sleep_flag_get,
+ .is_aee_dump_support = mt6632_aee_dump_flag_get,
+ .trigger_stp_assert = mt6632_trigger_stp_assert,
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ .deep_sleep_ctrl = mt6632_deep_sleep_ctrl,
+#else
+ .deep_sleep_ctrl = NULL,
+#endif
+
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static INT32 mt6632_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ UINT8 evtBuf[256];
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+ UINT32 hw_ver;
+ UINT32 patch_num = 0;
+ UINT32 patch_index = 0;
+ WMT_CTRL_DATA ctrlData;
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ INT32 deep_sleep_flag_from_cfg;
+#endif
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_mt6632_info != NULL);
+
+ if ((gp_mt6632_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_mt6632_info(0x%p), pWmtHifConf(0x%p)\n",
+ gp_mt6632_info, pWmtHifConf);
+ return -1;
+ }
+
+ hw_ver = gp_mt6632_info->u4HwVer;
+
+ /* 4 <3.1> start init for sdio */
+
+ /* 4 <3.2> start init for uart */
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* init variable fields for script execution */
+ osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+ osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0],
+ osal_sizeof(UINT32));
+ WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */
+
+ /* 3. Query chip baud rate (TEST-ONLY) */
+ /* 4. Query chip STP options (TEST-ONLY) */
+ /* 5. Change chip baud rate: t_baud */
+ /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */
+ iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 6. Set host baudrate and flow control */
+ ctrlPa1 = pWmtHifConf->au4HifConf[0];
+ ctrlPa2 = 0;
+ iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2);
+
+ if (iRet) {
+ WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0],
+ iRet);
+ return -3;
+ }
+
+ WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]);
+
+ /* 7. Wake up chip and check event */
+/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */
+ iRet =
+ wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res,
+ MTK_WCN_BOOL_TRUE);
+
+ if (iRet || (u4Res != 1)) {
+ WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res);
+ return -4;
+ }
+
+ osal_memset(evtBuf, 0, osal_sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res);
+#ifdef CFG_DUMP_EVT
+ WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n",
+ (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ evtBuf[5]);
+#endif
+
+ if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) {
+ WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ return -5;
+ }
+ /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */
+
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp
+ (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) {
+ WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n");
+ return -6;
+ }
+#endif
+
+ /* 8. Query baud rate (TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet);
+ return -7;
+ }
+ }
+
+ /* 9. download patch */
+ /* 9.1 Let launcher to search patch info */
+ iRet = mt6632_patch_info_prepare();
+
+ if (iRet) {
+ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet);
+ return -8;
+ }
+
+ /* 9.2 Read patch number */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2);
+ patch_num = ctrlPa1;
+ WMT_DBG_FUNC("patch total num = [%d]\n", patch_num);
+
+ /* improve patch down load speed */
+ WMT_DBG_FUNC("improve patch dwn speed, clock rate promote, copy data use DMA at firmware side\n");
+ WMT_CLOCK_RATE_CMD[6] = 0xD0;
+ /* If WMT_CLOCK_RATE_CMD[6] = 0xD0, promote the XTAL(26MHz) rate to 208MHz
+ * copy data use DMA at firmware side
+ */
+ iRet = wmt_core_init_script(clock_rate_pro_and_use_dma, ARRAY_SIZE(clock_rate_pro_and_use_dma));
+ if (iRet) {
+ WMT_ERR_FUNC("clock_rate_pro_and_use_dma fail(%d)\n", iRet);
+ return -30;
+ }
+ /* 9.3 Multi-patch Patch download */
+ for (patch_index = 0; patch_index < patch_num; patch_index++) {
+ iRet = mt6632_patch_dwn(patch_index);
+
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index);
+ return -12;
+ }
+
+ /* 10. WMT Reset command */
+ iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -13;
+ }
+ }
+ /*close clock rate promote*/
+ WMT_CLOCK_RATE_CMD[6] = 0x00;
+ WMT_DBG_FUNC("close clock rate promote, made XTAL to 26MHz\n");
+ iRet = wmt_core_init_script(clock_rate_modify, ARRAY_SIZE(clock_rate_modify));
+ if (iRet) {
+ WMT_ERR_FUNC("close clock rate promote fail(%d)\n", iRet);
+ return -31;
+ }
+
+ /* SDIO data patch retry feature enable/disable */
+ mtk_stp_sdio_retry_flag_ctrl(1);
+ if (mtk_stp_sdio_retry_flag_get()) {
+ iRet = wmt_core_init_script(set_sdio_retry_script, ARRAY_SIZE(set_sdio_retry_script));
+
+ if (iRet) {
+ WMT_ERR_FUNC("set_sdio_retry_script fail(%d)\n", iRet);
+ mtk_stp_sdio_retry_flag_ctrl(0);
+ }
+ }
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ if (g_deep_sleep_flag) {
+ /*get flag form mt6632_ant_m1.cfg*/
+ deep_sleep_flag_from_cfg = wmt_stp_get_deep_sleep_flag_from_cfg();
+ if (deep_sleep_flag_from_cfg == 1) {
+ WMT_DEEP_SLEEP_CMD[5] = 1;
+ iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script));
+ if (iRet) {
+ WMT_ERR_FUNC("enalbe deep sleep feature fail\n");
+ return -20;
+ }
+ WMT_DBG_FUNC("chip deep sleep feature is enable\n");
+ wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_TRUE);
+ } else {
+ WMT_DEEP_SLEEP_CMD[5] = 0;
+ iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script));
+ if (iRet) {
+ WMT_ERR_FUNC("disable deep sleep feature fail\n");
+ return -21;
+ }
+ WMT_INFO_FUNC("chip deep sleep feature is disable\n");
+ wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE);
+ }
+ } else {
+ WMT_DEEP_SLEEP_CMD[5] = 0;
+ iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script));
+ if (iRet) {
+ WMT_ERR_FUNC("disable deep sleep feature fail\n");
+ return -22;
+ }
+ WMT_INFO_FUNC("chip deep sleep feature is disable\n");
+ wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE);
+ }
+#endif
+ iRet = wmt_stp_init_coex();
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -10;
+ }
+ WMT_DBG_FUNC("init_coex ok\n");
+ /*If TCXO or co-clock is applied in mt6632, remove the triming patch*/
+ /*mt6632_crystal_triming_set();*/
+#if MT6632_BRINGUP
+ WMT_DBG_FUNC("Bring up period, skip sdio driving settings\n");
+#else
+ WMT_DBG_FUNC("Temp solution, skip sdio driving settings\n");
+ /* 6632_set_sdio_driving(); */
+#endif
+ if (pWmtHifConf->hifType == WMT_HIF_UART) {
+ /* 11. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -12;
+ }
+
+ /* 12. Enable host STP-UART mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_UART_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet);
+ return -13;
+ }
+
+ WMT_INFO_FUNC("enable host STP-UART-FULL mode\n");
+ /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+ /* 14. Query chip STP options (TEST-ONLY) */
+ /* 15. Query baud rate (stp, TEST-ONLY) */
+ iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -14;
+ }
+ }
+
+ if (mt6632_co_clock_get() == WMT_CO_CLOCK_EN) {
+ WMT_INFO_FUNC("co-clock enabled.\n");
+
+ iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table));
+
+ if (iRet) {
+ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+ } else if (mt6632_co_clock_get() == WMT_CO_CLOCK_DCXO) {
+ WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x2;
+ WMT_SET_CRYSTAL_TRIMING_EVT[5] = 0x0;
+ iRet = wmt_core_init_script(set_crystal_timing_script, ARRAY_SIZE(set_crystal_timing_script));
+ if (iRet == 0)
+ WMT_INFO_FUNC("set to Xtal mode suceed\n");
+ else
+ WMT_INFO_FUNC("set to Xtal mode failed, iRet:%d.\n", iRet);
+
+
+ } else
+ WMT_INFO_FUNC("co-clock disabled.\n");
+#if MT6632_BRINGUP
+ WMT_INFO_FUNC("Bring up period, skip merge interface settings\n");
+#else
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+ iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table));
+
+ if (iRet) {
+ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet);
+ return -15;
+ }
+#endif
+#endif
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers));
+
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -17;
+ }
+#endif
+
+#if CFG_WMT_COREDUMP_ENABLE
+ /*Open Core Dump Function @QC begin */
+ mtk_wcn_stp_coredump_flag_ctrl(1);
+#endif
+
+ if (mtk_wcn_stp_coredump_flag_get() != 0) {
+ iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6));
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet);
+ return -18;
+ }
+ WMT_INFO_FUNC("enable mt662x firmware coredump\n");
+ } else
+ WMT_INFO_FUNC("disable mt662x firmware coredump\n");
+
+ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO;
+ ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6632.icId;
+ ctrlData.au4CtrlData[1] = (size_t) gp_mt6632_info->cChipVersion;
+ ctrlData.au4CtrlData[2] = (size_t) &gp_mt6632_patch_info;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("set dump info fail(%d)\n", iRet);
+ return -16;
+ }
+#if CFG_WMT_FILTER_MODE_SETTING
+ wmt_stp_wifi_lte_coex();
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6632_info != NULL);
+
+ if (gp_mt6632_info != NULL) {
+ if (gp_mt6632_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ return 0;
+}
+
+static INT32 mt6632_sw_deinit(P_WMT_HIF_CONF pWmtHifConf)
+{
+ WMT_DBG_FUNC(" start\n");
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_mt6632_info != NULL);
+
+ if ((gp_mt6632_info != NULL)
+ && (gp_mt6632_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) {
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ gp_mt6632_info = NULL;
+
+ return 0;
+}
+
+static INT32 mt6632_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+
+#if MT6632_BRINGUP
+ ret = 0;
+ WMT_INFO_FUNC("Bring up period, skip aif settings\n");
+#else
+
+ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) {
+ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n");
+
+ WMT_WARN_FUNC("TBD!!");
+ ret = 0;
+ } else {
+ /*PCM & I2S separate */
+ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n");
+
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+#if 0
+ val = 0x01110000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000);
+#else
+ ret = 0;
+ WMT_INFO_FUNC("Bring up period, skip WMT_IC_AIF_2 settings\n");
+#endif
+ break;
+
+ case WMT_IC_AIF_3:
+ ret = 0;
+ break;
+
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!ret)
+ WMT_INFO_FUNC("new state(%d) ok\n", state);
+ else
+ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret);
+#endif
+ return ret;
+}
+
+static INT32 mt6632_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ WMT_DBG_FUNC("MT6632 do not need gps sync settings\n");
+
+ /* anyway, we return 0 */
+ return 0;
+}
+
+
+static INT32 mt6632_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret;
+
+ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag);
+
+ ret = -1;
+
+ switch (id) {
+ case WMT_IC_PIN_AUDIO:
+ ret = mt6632_aif_ctrl(state, flag);
+ break;
+
+ case WMT_IC_PIN_EEDI:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_EEDO:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_GSYNC:
+ ret = mt6632_gps_sync_ctrl(state, flag);
+ break;
+
+ default:
+ break;
+ }
+
+ WMT_DBG_FUNC("ret = (%d)\n", ret);
+
+ return ret;
+}
+
+INT32 mt6632_co_clock_ctrl(WMT_CO_CLOCK on)
+{
+ INT32 iRet = 0;
+
+ if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) {
+ gCoClockEn = on;
+ } else {
+ WMT_DBG_FUNC("MT6632: error parameter:%d\n", on);
+ iRet = -1;
+ }
+
+ WMT_DBG_FUNC("MT6632: Co-clock type: %d\n", gCoClockEn);
+
+ return iRet;
+}
+
+static MTK_WCN_BOOL mt6632_quick_sleep_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+static MTK_WCN_BOOL mt6632_aee_dump_flag_get(VOID)
+{
+ if (mtk_wcn_stp_coredump_flag_get() == 1)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static MTK_WCN_BOOL mt6632_trigger_stp_assert(VOID)
+{
+ INT32 iRet = -1;
+ UINT32 u4Res = 0;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ UINT8 STP_DO_ASSERT_CMD[] = { 0x80, 0x50, 0x0a, 0x00, 'd', 'o', 'c', 'o', 'r', 'e', 'd', 'u', 'm', 'p', 0x00,
+ 0x00
+ };
+
+ iRet =
+ wmt_core_tx((PUINT8)&STP_DO_ASSERT_CMD[0], sizeof(STP_DO_ASSERT_CMD), &u4Res,
+ MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != sizeof(STP_DO_ASSERT_CMD))) {
+ WMT_ERR_FUNC("wmt_core:send STP ASSERT COMMAND fail(%d),size(%d)\n", iRet, u4Res);
+ bRet = MTK_WCN_BOOL_FALSE;
+ } else
+ bRet = MTK_WCN_BOOL_TRUE;
+ return bRet;
+}
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+static MTK_WCN_BOOL mt6632_deep_sleep_ctrl(INT32 value)
+{
+ INT32 ret = 0;
+
+ g_deep_sleep_flag = value;
+ if (value) {
+ WMT_DEEP_SLEEP_CMD[5] = 1;
+ WMT_INFO_FUNC("enable chip deep sleep feature from wmt_dbg command\n");
+ } else {
+ WMT_DEEP_SLEEP_CMD[5] = 0;
+ WMT_INFO_FUNC("disable chip deep sleep feature from wmt_dbg command\n");
+ }
+ ret = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script));
+ if (ret == 0)
+ return MTK_WCN_BOOL_TRUE;
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static INT32 wmt_stp_get_deep_sleep_flag_from_cfg(VOID)
+{
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ ULONG addr;
+ INT32 ret;
+
+ /*Get wmt config */
+ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (ret) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret);
+ return -2;
+ }
+
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return -1;
+ }
+ if (pWmtGenConf->disable_deep_sleep_cfg == 0) {
+ WMT_DBG_FUNC("disable_deep_sleep_cfg (%d) get form mt6632_ant_m1.cfg, enable deep sleep feature\n",
+ pWmtGenConf->disable_deep_sleep_cfg);
+ ret = 1;
+ } else {
+ WMT_DBG_FUNC("disable_deep_sleep_cfg (%d) get form mt6632_ant_m1.cfg, disable deep sleep feature\n",
+ pWmtGenConf->disable_deep_sleep_cfg);
+ ret = 0;
+ }
+ return ret;
+}
+
+#endif
+
+WMT_CO_CLOCK mt6632_co_clock_get(VOID)
+{
+ return gCoClockEn;
+}
+
+
+
+static INT32 mt6632_ver_check(VOID)
+{
+ UINT32 hw_ver = 0;
+ UINT32 fw_ver = 0;
+ INT32 iret;
+ const WMT_IC_INFO_S *p_info = NULL;
+ ULONG ctrlPa1;
+ ULONG ctrlPa2;
+
+
+ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */
+ WMT_LOUD_FUNC("MT6632: before read hw_ver (hw version)\n");
+ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK);
+
+ if (iret) {
+ WMT_ERR_FUNC("MT6632: read hw_ver fail:%d\n", iret);
+ return -2;
+ }
+
+ WMT_LOUD_FUNC("MT6632: before fw_ver (rom version)\n");
+ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK);
+
+ if (iret) {
+ WMT_ERR_FUNC("MT6632: read fw_ver fail:%d\n", iret);
+ return -2;
+ }
+ WMT_INFO_FUNC("MT6632: read (hw version)(0x%x), (fw version version)(0x%x)\n", hw_ver, fw_ver);
+
+ p_info = mt6632_find_wmt_ic_info(hw_ver);
+
+ if (p_info == NULL) {
+ WMT_ERR_FUNC("MT6632: hw_ver(0x%x) find wmt ic info fail\n", hw_ver);
+ return -3;
+ }
+
+ WMT_DBG_FUNC("MT6632: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n",
+ p_info->cChipName, p_info->cChipVersion,
+ p_info->u4HwVer, p_info->cPatchNameExt);
+
+ /* hw id & version */
+ ctrlPa1 = (0x00006632UL << 16) | (hw_ver & 0x0000FFFF);
+ /* translated fw rom version */
+ ctrlPa2 = (fw_ver & 0x0000FFFF);
+
+ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2);
+
+ if (iret)
+ WMT_WARN_FUNC("MT6632: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret);
+
+ gp_mt6632_info = p_info;
+ return 0;
+}
+
+static const WMT_IC_INFO_S *mt6632_find_wmt_ic_info(const UINT32 hw_ver)
+{
+ /* match chipversion with u4HwVer item in mt6632_info_table */
+ const UINT32 size = ARRAY_SIZE(mt6632_info_table);
+ INT32 index;
+
+ /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */
+ index = size - 1;
+
+ /* full match */
+ while ((index >= 0)
+ && (hw_ver != mt6632_info_table[index].u4HwVer) /* full match */
+ ) {
+ --index;
+ }
+
+ if (index >= 0) {
+ WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index);
+ return &mt6632_info_table[index];
+ }
+
+ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver);
+
+ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR
+ * NUM only can help us support future minor hw ECO, or fab switch, etc.
+ * FULL matching eliminate such flexibility and software package have to be
+ * updated EACH TIME even when minor hw ECO or fab switch!!!
+ */
+ /* George: reverse the search order to favor newer version products */
+ index = size - 1;
+
+ /* major num match */
+ while ((index >= 0)
+ && (MAJORNUM(hw_ver) != MAJORNUM(mt6632_info_table[index].u4HwVer))
+ ) {
+ --index;
+ }
+
+ if (index >= 0) {
+ WMT_INFO_FUNC("MT6632: found ic info for hw_ver(0x%x) by major num! index:%d\n",
+ hw_ver, index);
+ return &mt6632_info_table[index];
+ }
+
+ WMT_ERR_FUNC
+ ("MT6632: find no ic info for hw_ver(0x%x) by full match nor major num match!\n",
+ hw_ver);
+ return NULL;
+}
+
+
+static INT32 wmt_stp_init_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+#define COEX_WMT 0
+
+#if CFG_SUBSYS_COEX_NEED
+ /* no need for MT6632 */
+#define COEX_BT 1
+#define COEX_WIFI 2
+#define COEX_PTA 3
+#define COEX_MISC 4
+#else
+#define COEX_WIFI_PATH 1
+#define COEX_EXT_ELAN_GAIN_P1 2
+#endif
+#define WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE 6
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+
+ /*Dump the coex-related info */
+ WMT_DBG_FUNC("coex_wmt_ant_mode:0x%x, coex_wmt_wifi_path:0x%x\n",
+ pWmtGenConf->coex_wmt_ant_mode, pWmtGenConf->coex_wmt_wifi_path);
+#if CFG_SUBSYS_COEX_NEED
+ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_bt_rssi_upper_limit,
+ pWmtGenConf->coex_bt_rssi_mid_limit,
+ pWmtGenConf->coex_bt_rssi_lower_limit,
+ pWmtGenConf->coex_bt_pwr_high,
+ pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low);
+ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wifi_rssi_upper_limit,
+ pWmtGenConf->coex_wifi_rssi_mid_limit,
+ pWmtGenConf->coex_wifi_rssi_lower_limit,
+ pWmtGenConf->coex_wifi_pwr_high,
+ pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low);
+ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_ext_pta_hi_tx_tag,
+ pWmtGenConf->coex_ext_pta_hi_rx_tag,
+ pWmtGenConf->coex_ext_pta_lo_tx_tag,
+ pWmtGenConf->coex_ext_pta_lo_rx_tag,
+ pWmtGenConf->coex_ext_pta_sample_t1,
+ pWmtGenConf->coex_ext_pta_sample_t2,
+ pWmtGenConf->coex_ext_pta_wifi_bt_con_trx);
+ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set);
+#endif
+
+ /*command adjustion due to WMT.cfg */
+ coex_table[COEX_WMT].cmd[4] = WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE;
+ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0],
+ coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz);
+ }
+
+#if CFG_SUBSYS_COEX_NEED
+ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit;
+ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit;
+ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit;
+ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high;
+ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid;
+ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0],
+ coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz);
+ }
+
+ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit;
+ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit;
+ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit;
+ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high;
+ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid;
+ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0],
+ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz);
+ }
+
+ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag;
+ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag;
+ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag;
+ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag;
+ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx;
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0],
+ coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz);
+ }
+
+ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on,
+ sizeof(pWmtGenConf->coex_misc_ext_pta_on));
+ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set,
+ sizeof(pWmtGenConf->coex_misc_ext_feature_set));
+
+ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str,
+ coex_table[COEX_MISC].cmdSz);
+#else
+ coex_table[COEX_WIFI_PATH].cmd[5] =
+ (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0x00FF) >> 0);
+ coex_table[COEX_WIFI_PATH].cmd[6] =
+ (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0xFF00) >> 8);
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI_PATH].cmd[0],
+ coex_table[COEX_WIFI_PATH].str, coex_table[COEX_WIFI_PATH].cmdSz);
+ }
+
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[5] = pWmtGenConf->coex_wmt_ext_elna_gain_p1_support;
+ /* wmt_ext_elna_gain_p1 D0*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[6] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[7] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[8] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[9] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D1*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[10] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[11] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[12] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[13] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D2*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[14] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[15] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[16] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[17] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D3*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[18] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[19] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[20] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[21] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0xFF000000) >> 24);
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[0],
+ coex_table[COEX_EXT_ELAN_GAIN_P1].str, coex_table[COEX_EXT_ELAN_GAIN_P1].cmdSz);
+ }
+
+#endif
+
+ iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table));
+
+ return iRet;
+}
+
+#if 0
+static INT32 mt6632_set_sdio_driving(void)
+{
+ INT32 ret = 0;
+
+ UINT32 addr = 0;
+ WMT_GEN_CONF *pWmtGenConf;
+ UINT32 drv_val = 0;
+
+ /*Get wmt config */
+ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (ret) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret);
+ return -1;
+ }
+
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%x)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ drv_val = pWmtGenConf->sdio_driving_cfg;
+
+ /*Dump the sdio driving related info */
+ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val);
+
+ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */
+ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */
+ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */
+
+ ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table));
+
+ return ret;
+}
+
+static INT32 mt6632_crystal_triming_set(VOID)
+{
+ INT32 iRet = 0;
+ PUINT8 pbuf = NULL;
+ UINT32 bufLen = 0;
+ WMT_CTRL_DATA ctrlData;
+ UINT32 uCryTimOffset = 0x6D;
+ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ INT8 cCrystalTimingOffset = 0x0;
+ UINT8 cCrystalTiming = 0x0;
+ INT32 iCrystalTiming = 0x0;
+ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ UINT32 u4Res;
+
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ ctrlData.au4CtrlData[1] = (size_t) &pbuf;
+ ctrlData.au4CtrlData[2] = (size_t) &bufLen;
+
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ iRet = -1;
+ } else {
+ WMT_DBG_FUNC("MT6632: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen);
+
+ if (bufLen < (uCryTimOffset + 1)) {
+ WMT_ERR_FUNC
+ ("MT6632: nvram len(%d) too short, crystalTimging value offset(%d)\n",
+ bufLen, uCryTimOffset);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ } else {
+ bIsNvramExist = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = *(pbuf + uCryTimOffset);
+
+ if (cCrystalTimingOffset & 0x80) {
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f;
+ }
+
+ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n",
+ cCrystalTimingOffset, bIsCrysTrimEnabled);
+ }
+
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT;
+ ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI";
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet != 0) {
+ WMT_ERR_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet);
+ iRet = -2;
+ } else {
+ WMT_DBG_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n");
+ }
+ }
+
+ if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) {
+ /*get CrystalTiming value before set it */
+ iRet =
+ wmt_core_tx(get_crystal_timing_script[0].cmd,
+ get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].cmdSz);
+ iRet = -3;
+ goto done;
+ }
+
+ /* EVENT BUF */
+ osal_memset(get_crystal_timing_script[0].evt, 0,
+ get_crystal_timing_script[0].evtSz);
+ iRet =
+ wmt_core_rx(get_crystal_timing_script[0].evt,
+ get_crystal_timing_script[0].evtSz, &u4Res);
+
+ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res,
+ get_crystal_timing_script[0].evtSz);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet = -4;
+ goto done;
+ }
+
+ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f;
+
+ if (cCrystalTimingOffset & 0x40) {
+ /*nagative offset value */
+ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128;
+ } else {
+ iCrystalTiming += cCrystalTimingOffset;
+ }
+
+ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming);
+ if (iCrystalTiming > 0x7f)
+ cCrystalTiming = 0x7f;
+ else if (iCrystalTiming < 0)
+ cCrystalTiming = 0;
+ else
+ cCrystalTiming = iCrystalTiming;
+ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming);
+ /* set_crystal_timing_script */
+ /*set crystal trim value command*/
+ WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x1;
+ WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x1;
+
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming;
+ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming;
+
+ iRet =
+ wmt_core_init_script(set_crystal_timing_script,
+ ARRAY_SIZE(set_crystal_timing_script));
+
+ if (iRet) {
+ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -5;
+ } else {
+ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n",
+ WMT_SET_CRYSTAL_TRIMING_CMD[5]);
+ iRet =
+ wmt_core_init_script(get_crystal_timing_script,
+ ARRAY_SIZE(get_crystal_timing_script));
+
+ if (iRet) {
+ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -6;
+ } else {
+ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n",
+ WMT_GET_CRYSTAL_TRIMING_EVT[5]);
+ iRet = 0x0;
+ }
+ }
+ }
+
+done:
+ return iRet;
+}
+#endif
+
+static INT32 mt6632_patch_info_prepare(VOID)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+
+static INT32 mt6632_patch_dwn(UINT32 index)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr = NULL;
+ PUINT8 pBuf = NULL;
+ PUINT8 pPatchBuf = NULL;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ UINT8 addressevtBuf[12];
+ UINT8 addressByte[4];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_mt6632_info == NULL) {
+ WMT_ERR_FUNC("null gp_mt6632_info!\n");
+ return -1;
+ }
+
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = index + 1;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &addressByte;
+ iRet = wmt_ctrl(&ctrlData);
+ WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName);
+
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (size_t) NULL;
+ ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName;
+ ctrlData.au4CtrlData[2] = (size_t) &pBuf;
+ ctrlData.au4CtrlData[3] = (size_t) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ pPatchBuf = osal_malloc(patchSize);
+ if (pPatchBuf == NULL) {
+ WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n");
+ return -2;
+ }
+ osal_memcpy(pPatchBuf, pBuf, patchSize);
+ patchHdr = (P_WMT_PATCH) pPatchBuf;
+
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+
+ osal_memcpy(&gp_mt6632_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+
+ if (index == 0) {
+ WMT_INFO_FUNC("Combo Patch:Build Time(%s)Hw(0x%x) Sw(0x%x) Ph(0x%04x)Platform(%c%c%c%c)\n",
+ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8),
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8),
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16),
+ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ }
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -1;
+ goto done;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pPatchBuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+
+ /* remove patch checksum, MT6632 no need:
+ * |<-patch checksum: 2Bytes->|<-patch body: X Bytes (X=patchSize)--->|
+ */
+ pPatchBuf += BCNT_PATCH_BUF_CHECKSUM;
+ patchSize -= BCNT_PATCH_BUF_CHECKSUM;
+
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ pPatchBuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ /*send patch address command */
+ osal_memcpy(&WMT_PATCH_ADDRESS_CMD[5], addressByte, osal_sizeof(addressByte));
+ WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_ADDRESS_CMD[5], WMT_PATCH_ADDRESS_CMD[6],
+ WMT_PATCH_ADDRESS_CMD[7], WMT_PATCH_ADDRESS_CMD[8]);
+ iRet = wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n",
+ iRet, u4Res, index);
+ iRet -= 1;
+ goto done;
+ }
+
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet,
+ u4Res, index);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ goto done;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT))
+ != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n",
+ index);
+ iRet -= 1;
+ goto done;
+ }
+#endif
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD,
+ sizeof(WMT_PATCH_CMD));
+
+ iRet =
+ wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD),
+ fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n",
+ sizeof(WMT_PATCH_EVT), u4Res, iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n",
+ sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+
+done:
+ if (patchHdr != NULL) {
+ osal_free(patchHdr);
+ pPatchBuf = NULL;
+ patchHdr = NULL;
+ }
+
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = index + 1;
+ wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID)
+{
+ INT32 iRet;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ if (pWmtGenConf->coex_wmt_filter_mode == 0) {
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_0,
+ ARRAY_SIZE(set_wifi_lte_coex_table_0));
+ if (iRet)
+ WMT_ERR_FUNC("wmt_core:set_wifi_lte_coex_table_0 fail(%d)\n", iRet);
+ else
+ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 ok\n");
+ }
+
+ return iRet;
+}
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c
new file mode 100644
index 0000000000000000000000000000000000000000..15138c9b695712b21738973988436e050a773aad
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c
@@ -0,0 +1,4074 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-IC]"
+#define CFG_IC_SOC 1
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_ic.h"
+#include "wmt_core.h"
+#include "wmt_lib.h"
+#include "stp_core.h"
+#include "mtk_wcn_consys_hw.h"
+#include "wmt_step.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define DEFAULT_PATCH_FRAG_SIZE (1000)
+#define WMT_PATCH_FRAG_1ST (0x1)
+#define WMT_PATCH_FRAG_MID (0x2)
+#define WMT_PATCH_FRAG_LAST (0x3)
+
+#define CFG_CHECK_WMT_RESULT (1)
+/* BT Port 2 Feature. this command does not need
+ * after coex command is downconfirmed by LC,
+ */
+#define CFG_WMT_BT_PORT2 (0)
+
+#define CFG_SET_OPT_REG (0)
+#define CFG_WMT_I2S_DBGUART_SUPPORT (0)
+#define CFG_SET_OPT_REG_SWLA (0)
+#define CFG_SET_OPT_REG_MCUCLK (0)
+#define CFG_SET_OPT_REG_MCUIRQ (0)
+
+#define CFG_SUBSYS_COEX_NEED 0
+
+#define CFG_WMT_COREDUMP_ENABLE 0
+
+#define CFG_WMT_MULTI_PATCH (1)
+
+#define CFG_WMT_CRYSTAL_TIMING_SET (0)
+
+#define CFG_WMT_SDIO_DRIVING_SET (0)
+
+#define CFG_WMT_UART_HIF_USE (0)
+
+#define CFG_WMT_WIFI_5G_SUPPORT (1)
+
+#define CFG_WMT_PATCH_DL_OPTM (1)
+#if CFG_WMT_LTE_COEX_HANDLING
+#define CFG_WMT_FILTER_MODE_SETTING (1)
+#else
+#define CFG_WMT_FILTER_MODE_SETTING (0)
+#endif
+/* #define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT (0) */
+
+#define CFG_WMT_POWER_ON_DLM (1)
+
+/* Define local option for debug purpose */
+#define CFG_CALIBRATION_BACKUP_RESTORE (1)
+#define CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE (640)
+
+#define PATCH_BUILD_TIME_SIZE (16)
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+static UINT8 gFullPatchName[NAME_MAX + 1];
+static const WMT_IC_INFO_S *gp_soc_info;
+static WMT_PATCH gp_soc_patch_info;
+static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS;
+
+#if CFG_CALIBRATION_BACKUP_RESTORE
+static PUINT8 gBTCalResult;
+static UINT16 gBTCalResultSize;
+static UINT32 gWiFiCalAddrOffset;
+static UINT32 gWiFiCalSize;
+static PUINT8 gWiFiCalResult;
+#endif
+
+#if 0
+static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 };
+static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 };
+
+static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 };
+static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 };
+#endif
+
+#if CFG_WMT_UART_HIF_USE
+static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 };
+static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 };
+static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB };
+static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 };
+static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF };
+static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 };
+#endif
+static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 };
+static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 };
+static UINT8 WMT_QUERY_STP_EVT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDB, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 };
+static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 };
+static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 };
+static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_SET_CHIP_ID_CMD[] = { 0x01, 0x02, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_SET_CHIP_ID_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00};
+
+#if CFG_WMT_BT_PORT2
+static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 };
+static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+static UINT8 WMT_QUERY_A_DIE_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x12 };
+static UINT8 WMT_QUERY_A_DIE_EVT[] = { 0x02, 0x02, 0x05, 0x00, 0x00 };
+
+/*soc patial patch address cmd & evt need firmware owner provide*/
+#if CFG_WMT_MULTI_PATCH
+static UINT8 WMT_PATCH_ADDRESS_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x3c, 0x02, 0x09, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0xc4, 0x04, 0x09, 0x02,
+ 0x00, 0x3f, 0x00, 0x01,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_PATCH_PDA_CFG_CMD[] = {
+ 0x01, 0x01, 0x11, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, /*Target address*/
+ 0x00, 0x00, 0x00, 0x00, /*Download size*/
+ 0x00, 0x00, 0x00, 0x00, /*Scramble key*/
+ 0x2f, 0x02, 0x02, 0x00 /*Configuration*/
+};
+static UINT8 WMT_PATCH_PDA_CFG_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00};
+
+static UINT8 WMT_PATCH_ADDRESS_CMD_NEW[] = { 0x01, 0x01, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
+
+static UINT8 WMT_PATCH_ADDRESS_EVT_NEW[] = { 0x02, 0x01, 0x01, 0x00, 0x00};
+#endif
+
+/*coex cmd/evt++*/
+static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+#if CFG_SUBSYS_COEX_NEED
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B,
+ 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C,
+ 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA
+};
+static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A,
+ 0x00, 0x04,
+ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE
+};
+static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09,
+ 0x00, 0x05,
+ 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB
+};
+static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#else
+static UINT8 WMT_COEX_WIFI_PATH_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x1A, 0x0F, 0x00 };
+static UINT8 WMT_COEX_WIFI_PATH_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_CMD[] = { 0x01, 0x10, 0x12, 0x00, 0x1B, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_EXT_EPA_MODE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x1D, 0x00 };
+static UINT8 WMT_COEX_EXT_EPA_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+#endif
+
+static UINT8 WMT_EPA_SETTING_CONFIG_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x0E, 0x00 };
+static UINT8 WMT_EPA_SETTING_CONFIG_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_EPA_ELNA_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+/*coex cmd/evt--*/
+static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDB, 0x0E, 0x68, 0x01 };
+static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 };
+static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 };
+static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 };
+
+#if 0
+static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 };
+static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 };
+#endif
+
+#if 0
+/* to enable dump feature */
+static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 };
+static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get system stack dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get task and system stack dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+/* to get bt related memory dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A };
+static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+#endif
+/* to get full dump when f/w assert */
+static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 };
+static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 };
+
+static UINT8 WMT_CORE_START_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x1, 0x00, 0x01 };
+static UINT8 WMT_CORE_START_RF_CALIBRATION_EVT[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x01 };
+
+#if CFG_CALIBRATION_BACKUP_RESTORE
+static UINT8 WMT_CORE_GET_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x01, 0x00, 0x03 };
+/* byte[2] & byte[3] is left for length */
+static UINT8 WMT_CORE_SEND_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00 };
+static UINT8 WMT_CORE_SEND_RF_CALIBRATION_EVT_OK[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x02 };
+static UINT8 WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL[] = { 0x2, 0x14, 0x02, 0x00, 0x01, 0x02 };
+#endif
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */
+ , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */
+ , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */
+ , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */
+ , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */
+ , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */
+ , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */
+};
+
+static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+#endif
+
+#if !(CFG_IC_SOC) /* For MT6628 no need to set ALLEINT registers, done in f/w */
+/* enable all interrupt */
+static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */
+ , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */
+ , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */
+};
+
+static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+
+#endif
+
+#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */
+static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */
+ , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */
+ , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */
+ , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */
+};
+
+static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */
+static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */
+ , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */
+ , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */
+ , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */
+ , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */
+};
+
+static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+};
+#endif
+
+#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */
+static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+ , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */
+ , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */
+ , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */
+ , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */
+ , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */
+ , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */
+};
+
+static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x02 /*2 registers */
+};
+#endif
+
+#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */
+#if 1 /* Ray */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 4 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */
+ , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */
+ /* cirq_int_n */
+ , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */
+ , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */
+ , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */
+ , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x04 /* 5 registers */
+};
+#elif 0 /* KC */
+static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+ , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */
+ , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */
+ , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */
+ /* 1. ARM irq_b, monitor flag 0 */
+ , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */
+ , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */
+ , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */
+ , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */
+ , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */
+ , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */
+ /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */
+ , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */
+ , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */
+ , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */
+ , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */
+ , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */
+ , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */
+};
+
+static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /* S: 0 */
+ , 0x00 /* type: reg */
+ , 0x00 /* rev */
+ , 0x05 /* 5 registers */
+};
+#endif
+#endif
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 };
+static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 };
+
+static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 };
+static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 };
+#endif
+
+#ifdef CFG_WMT_READ_EFUSE_VCN33
+static UINT8 WMT_GET_EFUSE_VCN33_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x04, 0x00 };
+static UINT8 WMT_GET_EFUSE_VCN33_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x04, 0x00 };
+#endif
+
+/* set sdio driving */
+#if CFG_WMT_SDIO_DRIVING_SET
+static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */
+ , 0x01 /* op: w */
+ , 0x01 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+ , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */
+ , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */
+ , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */
+};
+
+static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */
+ , 0x00 /*S: 0 */
+ , 0x00 /*type: reg */
+ , 0x00 /*rev */
+ , 0x01 /*1 registers */
+};
+#endif
+
+#if CFG_WMT_WIFI_5G_SUPPORT
+static UINT8 WMT_GET_SOC_ADIE_CHIPID_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 };
+static UINT8 WMT_GET_SOC_ADIE_CHIPID_EVT[] = {
+ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static UINT8 WMT_GET_SOC_6625_L_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x20, 0x01 };
+static UINT8 WMT_GET_SOC_6625_L_EVT[] = {
+ 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x20,
+ 0x01, 0x00, 0x00, 0x00, 0x00
+};
+#endif
+
+#if CFG_WMT_PATCH_DL_OPTM
+static UINT8 WMT_SET_MCU_CLK_EN_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x34, 0x03, 0x00, 0x80,
+ 0x00, 0x00, 0x01, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_SET_MCU_CLK_EN_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_SET_MCU_CLK_138_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x0c, 0x01, 0x00, 0x80,
+ 0x59, 0x4d, 0x84, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_SET_MCU_CLK_138_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_SET_MCU_CLK_26_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x0c, 0x01, 0x00, 0x80,
+ 0x00, 0x4d, 0x84, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_SET_MCU_CLK_26_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+static UINT8 WMT_SET_MCU_CLK_DIS_CMD[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x34, 0x03, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+static UINT8 WMT_SET_MCU_CLK_DIS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+/*only for 6797,enable high clock frequency*/
+/*CLK EN*/
+static UINT8 WMT_SET_MCU_CLK_EN_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x10
+};
+/*RATIO SET*/
+static UINT8 WMT_SET_MCU_RATIO_SET_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x0c, 0x01, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00
+};
+/*DIV SET*/
+static UINT8 WMT_SET_MCU_DIV_SET_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x18, 0x11, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00
+};
+/*HCLK SET*/
+static UINT8 WMT_SET_MCU_HCLK_SET_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x00, 0x11, 0x02, 0x81, 0x04, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00
+};
+
+/*Change clock to 26MHz*/
+/*HCLK DIS*/
+static UINT8 WMT_SET_MCU_HCLK_DIS_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x00, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00
+};
+/*RATIO DIS*/
+static UINT8 WMT_SET_MCU_RATIO_DIS_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x0c, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00
+};
+/*CLK DIS*/
+static UINT8 WMT_SET_MCU_CLK_DIS_6797[] = {
+ 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01,
+ 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10
+};
+
+static UINT8 WMT_SET_MCU_CLK_EVT_6797[] = {
+ 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01
+};
+
+#endif
+
+
+static UINT8 WMT_COEX_CONFIG_BT_CTRL_CMD[] = {
+ 0x01, 0x10, 0x04, 0x00, 0x1A, 0x00, 0x00, 0x00 };
+static UINT8 WMT_COEX_CONFIG_ADDJUST_OPP_TIME_RATIO_CMD[] = {
+ 0x01, 0x10, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00 };
+static UINT8 WMT_COEX_CONFIG_ADDJUST_BLE_SCAN_TIME_RATIO_CMD[] = {
+ 0x01, 0x10, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00 };
+
+static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 };
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static UINT8 WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x14, 0x00 };
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = {
+ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63,
+ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01,
+ 0x01, 0x0e, 0x0e, 0x0e, 0x00, 0x0a, 0x0c, 0x0e,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = {
+ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15,
+ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xd4,
+ 0x09, 0xe3, 0x09, 0x5a, 0x0a, 0x14, 0x09, 0x2d,
+ 0x09, 0x46, 0x09, 0x60, 0x09, 0xd3, 0x09, 0xe2,
+ 0x09, 0x59, 0x0a, 0x8B, 0x0a};
+static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 };
+static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 };
+
+#if 0
+static UINT8 WMT_COEX_SPLIT_FILTER_CMD_TEST[] = {
+ 0x01, 0x10, 0x19, 0x00, 0x0F, 0x00, 0x00, 0x00,
+ 0x00, 0x6c, 0x09, 0x8a, 0x09, 0x8a, 0x09, 0x9e,
+ 0x09, 0x01, 0x07, 0x07, 0x0b, 0x07, 0x07, 0x00,
+ 0x32, 0x27, 0x4e, 0x27, 0x32
+};
+
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = {
+ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x07, 0x07, 0x07, 0x54, 0x54, 0x00, 0x00,
+ 0x00, 0x50, 0x50, 0x50, 0x54, 0x54, 0x39, 0x39,
+ 0x39, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x01, 0x01,
+ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+};
+
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST[] = {
+ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15,
+ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd,
+ 0x09, 0xf6, 0x09, 0x0f, 0xaf, 0x14, 0x09, 0x2d,
+ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5,
+ 0x09, 0x0d, 0x0a, 0x27, 0x0a
+};
+static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 };
+static UINT8 WMT_COEX_EXT_COMPONENT_CMD_TEST[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x7f, 0x03 };
+#endif
+
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_0[] = {
+ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x63, 0x63, 0x63, 0x63, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+};
+
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0[] = {
+ 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15,
+ 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd,
+ 0x09, 0xf6, 0x09, 0x0f, 0x0a, 0x14, 0x09, 0x2d,
+ 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5,
+ 0x09, 0x0d, 0x0a, 0x27, 0x0a
+};
+static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 };
+
+static UINT8 WMT_COEX_FILTER_SPEC_CMD_6752[] = {
+ 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63,
+ 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01,
+ 0x01, 0x0E, 0x0E, 0x0E, 0x00, 0x0A, 0x0C, 0x0E,
+ 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+};
+
+static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752[] = {
+ 0x01, 0x10, 0x21, 0x00, 0x12, 0xFC, 0x08, 0x15,
+ 0x09, 0x2E, 0x09, 0x47, 0x09, 0xC4, 0x09, 0xD4,
+ 0x09, 0xE3, 0x09, 0x5A, 0x0A, 0x14, 0x09, 0x2D,
+ 0x09, 0x46, 0x09, 0x60, 0x09, 0xD3, 0x09, 0xE2,
+ 0x09, 0x59, 0x0A, 0x8B, 0x0A
+};
+#endif
+
+static UINT8 WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[] = {
+ 0x01, 0x02, 0x04, 0x00, 0x0D, 0x01, 0x1E, 0x00
+};
+
+static UINT8 WMT_BT_TSSI_FROM_WIFI_EVENT[] = {
+ 0x02, 0x02, 0x01, 0x00, 0x00
+};
+
+#if CFG_WMT_POWER_ON_DLM
+static UINT8 WMT_POWER_CTRL_DLM_CMD1[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x60, 0x00, 0x10, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00
+};
+
+static UINT8 WMT_POWER_CTRL_DLM_CMD2[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x60, 0x00, 0x10, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xf0, 0x00, 0x00, 0x00
+};
+
+static UINT8 WMT_POWER_CTRL_DLM_CMD3[] = {
+ 0x01, 0x08, 0x10, 0x00,
+ 0x01, 0x01, 0x00, 0x01,
+ 0x60, 0x00, 0x10, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00
+};
+static UINT8 WMT_POWER_CTRL_DLM_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 };
+#endif
+
+static UINT8 WMT_WIFI_ANT_SWAP_CMD[] = { 0x01, 0x14, 0x04, 0x00, 0x07, 0x02, 0x00, 0x00 };
+static UINT8 WMT_WIFI_ANT_SWAP_EVT[] = { 0x02, 0x14, 0x02, 0x00, 0x00, 0x07 };
+
+static UINT8 WMT_WIFI_CONFIG_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00 };
+
+#if (!CFG_IC_SOC)
+
+/* stp sdio init scripts */
+static struct init_script init_table_1_1[] = {
+ /* table_1_1 is only applied to common SDIO interface */
+ INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"),
+ /* applied to MT6628 ? */
+ INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"),
+};
+
+#endif
+
+static struct init_script init_table_1_2[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"),
+};
+
+#if CFG_WMT_UART_HIF_USE
+static struct init_script init_table_2[] = {
+ INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"),
+};
+#endif
+
+static struct init_script init_table_3[] = {
+ INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"),
+#if CFG_WMT_BT_PORT2
+ INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"),
+#endif
+};
+
+static struct init_script set_chipid_script[] = {
+ INIT_CMD(WMT_SET_CHIP_ID_CMD, WMT_SET_CHIP_ID_EVT, "wmt set chipid"),
+};
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static struct init_script set_crystal_timing_script[] = {
+ INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, "set crystal trim value"),
+};
+
+static struct init_script get_crystal_timing_script[] = {
+ INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, "get crystal trim value"),
+};
+#endif
+#ifdef CFG_WMT_READ_EFUSE_VCN33
+static struct init_script get_efuse_vcn33_script[] = {
+ INIT_CMD(WMT_GET_EFUSE_VCN33_CMD, WMT_GET_EFUSE_VCN33_EVT, "get efuse vcn33 value"),
+};
+#endif
+
+static struct init_script get_a_die_script[] = {
+ INIT_CMD(WMT_QUERY_A_DIE_CMD, WMT_QUERY_A_DIE_EVT, "query A-die"),
+};
+
+static struct init_script init_table_4[] = {
+ INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"),
+};
+
+static struct init_script init_table_5[] = {
+ INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT, "query stp"),
+};
+
+static struct init_script init_table_5_1[] = {
+ INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"),
+};
+
+static struct init_script init_table_6[] = {
+ INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"),
+};
+
+static struct init_script calibration_table[] = {
+ INIT_CMD(WMT_CORE_START_RF_CALIBRATION_CMD, WMT_CORE_START_RF_CALIBRATION_EVT, "start RF calibration data"),
+};
+
+#if CFG_WMT_PATCH_DL_OPTM
+static struct init_script set_mcuclk_table_1[] = {
+ INIT_CMD(WMT_SET_MCU_CLK_EN_CMD, WMT_SET_MCU_CLK_EN_EVT, "enable set mcu clk"),
+ INIT_CMD(WMT_SET_MCU_CLK_138_CMD, WMT_SET_MCU_CLK_138_EVT, "set mcu clk to 138.67MH"),
+};
+
+static struct init_script set_mcuclk_table_2[] = {
+ INIT_CMD(WMT_SET_MCU_CLK_26_CMD, WMT_SET_MCU_CLK_26_EVT, "set mcu clk to 26MH"),
+ INIT_CMD(WMT_SET_MCU_CLK_DIS_CMD, WMT_SET_MCU_CLK_DIS_EVT, "disable set mcu clk"),
+};
+
+static struct init_script set_mcuclk_table_3[] = {
+ INIT_CMD(WMT_SET_MCU_CLK_EN_6797, WMT_SET_MCU_CLK_EVT_6797, "enable set mcu clk"),
+ INIT_CMD(WMT_SET_MCU_RATIO_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu ratio set"),
+ INIT_CMD(WMT_SET_MCU_DIV_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu div set"),
+ INIT_CMD(WMT_SET_MCU_HCLK_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "set mcu clk to hclk"),
+};
+static struct init_script set_mcuclk_table_4[] = {
+ INIT_CMD(WMT_SET_MCU_HCLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu hclk"),
+ INIT_CMD(WMT_SET_MCU_RATIO_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu ratio set"),
+ INIT_CMD(WMT_SET_MCU_CLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu clk set"),
+};
+
+#endif
+
+static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = {0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00};
+
+static struct init_script set_wifi_ext_component_table[] = {
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi ext component"),
+};
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static struct init_script set_wifi_lte_coex_table_1[] = {
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"),
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"),
+};
+
+static struct init_script set_wifi_lte_coex_table_2[] = {
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"),
+ INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"),
+};
+
+static struct init_script set_wifi_lte_coex_table_3[] = {
+ INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"),
+};
+
+static struct init_script set_wifi_lte_coex_table_0[] = {
+#if 0
+ INIT_CMD(WMT_COEX_SPLIT_FILTER_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex split filter"),
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"),
+ INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte channel unsafe"),
+ INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi coex ext component"),
+#endif
+ INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte coex filter spec"),
+ INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte freq idx"),
+};
+
+static struct init_script get_tdm_req_antsel_num_table[] = {
+ INIT_CMD(WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD, WMT_COEX_SPLIT_MODE_EVT, "get tdm req antsel num"),
+};
+#endif
+
+static struct init_script bt_tssi_from_wifi_table[] = {
+ INIT_CMD(WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD, WMT_BT_TSSI_FROM_WIFI_EVENT, "get bt tssi value from wifi"),
+};
+
+static struct init_script coex_config_addjust_table[] = {
+ INIT_CMD(WMT_COEX_CONFIG_BT_CTRL_CMD, WMT_COEX_SPLIT_MODE_EVT, "coex config bt ctrl"),
+ INIT_CMD(WMT_COEX_CONFIG_ADDJUST_OPP_TIME_RATIO_CMD, WMT_COEX_SPLIT_MODE_EVT, "opp time ratio"),
+ INIT_CMD(WMT_COEX_CONFIG_ADDJUST_BLE_SCAN_TIME_RATIO_CMD, WMT_COEX_SPLIT_MODE_EVT, "ble scan time ratio"),
+
+};
+
+#if CFG_SET_OPT_REG
+static struct init_script set_registers[] = {
+ /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */
+ /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */
+#if CFG_WMT_I2S_DBGUART_SUPPORT
+ INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"),
+#endif
+#if CFG_SET_OPT_REG_SWLA
+ INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUCLK
+ INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"),
+#endif
+#if CFG_SET_OPT_REG_MCUIRQ
+ INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"),
+#endif
+};
+#endif
+
+static struct init_script coex_table[] = {
+ INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"),
+
+#if CFG_SUBSYS_COEX_NEED
+/* no need in MT6628 */
+ INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"),
+ INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"),
+ INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"),
+ INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"),
+#else
+ INIT_CMD(WMT_COEX_WIFI_PATH_CMD, WMT_COEX_WIFI_PATH_EVT, "wifi path"),
+ INIT_CMD(WMT_COEX_EXT_ELAN_GAIN_P1_CMD, WMT_COEX_EXT_ELAN_GAIN_P1_EVT, "wifi elan gain p1"),
+ INIT_CMD(WMT_COEX_EXT_EPA_MODE_CMD, WMT_COEX_EXT_EPA_MODE_EVT, "wifi ext epa mode"),
+#endif
+};
+
+static struct init_script epa_table[] = {
+ INIT_CMD(WMT_EPA_SETTING_CONFIG_CMD, WMT_EPA_SETTING_CONFIG_EVT, "coex_wmt_epa"),
+};
+
+static struct init_script osc_type_table[] = {
+ INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"),
+};
+
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+static struct init_script merge_pcm_table[] = {
+ INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"),
+ INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"),
+ INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"),
+};
+#endif
+
+#if CFG_WMT_SDIO_DRIVING_SET
+static struct init_script sdio_driving_table[] = {
+ INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"),
+};
+#endif
+
+#if CFG_WMT_POWER_ON_DLM
+static struct init_script wmt_power_on_dlm_table[] = {
+ INIT_CMD(WMT_POWER_CTRL_DLM_CMD1, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd1"),
+ INIT_CMD(WMT_POWER_CTRL_DLM_CMD2, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd2"),
+ INIT_CMD(WMT_POWER_CTRL_DLM_CMD3, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd3")
+};
+#endif
+
+
+static struct init_script wifi_ant_swap_table[] = {
+ INIT_CMD(WMT_WIFI_ANT_SWAP_CMD, WMT_WIFI_ANT_SWAP_EVT, "ant swap"),
+};
+
+/* SOC Chip Version and Info Table */
+static const WMT_IC_INFO_S mtk_wcn_soc_info_table[] = {
+ {
+ .u4HwVer = 0x8A00,
+ .cChipName = WMT_IC_NAME_DEFAULT,
+ .cChipVersion = WMT_IC_VER_E1,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8A01,
+ .cChipName = WMT_IC_NAME_DEFAULT,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B00,
+ .cChipName = WMT_IC_NAME_DEFAULT,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8B01,
+ .cChipName = WMT_IC_NAME_DEFAULT,
+ .cChipVersion = WMT_IC_VER_E3,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ },
+ {
+ .u4HwVer = 0x8C00,
+ .cChipName = WMT_IC_NAME_DEFAULT,
+ .cChipVersion = WMT_IC_VER_E2,
+ .cPatchNameExt = WMT_IC_PATCH_E1_EXT,
+ .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE,
+ .bPsmSupport = MTK_WCN_BOOL_TRUE,
+ }
+};
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+static MTK_WCN_BOOL mtk_wcn_soc_trigger_assert(VOID);
+
+static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf);
+
+static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag);
+
+static INT32 mtk_wcn_soc_ver_check(VOID);
+
+static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver);
+
+static INT32 wmt_stp_init_coex(VOID);
+
+static INT32 wmt_stp_init_epa(VOID);
+
+static INT32 wmt_stp_init_epa_elna(VOID);
+
+static INT32 wmt_stp_init_epa_elna_invert_cr(VOID);
+
+static INT32 wmt_init_wifi_config(VOID);
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID);
+#endif
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mtk_wcn_soc_patch_dwn(UINT32 index);
+static INT32 mtk_wcn_soc_patch_info_prepare(VOID);
+static UINT32 mtk_wcn_soc_get_patch_num(VOID);
+static INT32 mtk_wcn_soc_normal_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte);
+static INT32 mtk_wcn_soc_pda_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte);
+#else
+static INT32 mtk_wcn_soc_patch_dwn(VOID);
+#endif
+
+static INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on);
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static INT32 mtk_wcn_soc_crystal_triming_set(VOID);
+#endif
+
+static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID);
+
+static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID);
+
+#if CFG_WMT_SDIO_DRIVING_SET
+static INT32 mtk_wcn_soc_set_sdio_driving(void);
+#endif
+static UINT32 mtk_wcn_soc_update_patch_version(VOID);
+
+static INT32 mtk_wcn_soc_calibration(void);
+static INT32 mtk_wcn_soc_do_calibration(void);
+#if CFG_CALIBRATION_BACKUP_RESTORE
+static INT32 mtk_wcn_soc_calibration_backup(void);
+static INT32 mtk_wcn_soc_calibration_restore(void);
+#endif
+
+static INT32 wmt_stp_init_wifi_ant_swap(VOID);
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/* SOC Operation Function Table */
+WMT_IC_OPS wmt_ic_ops_soc = {
+ .icId = 0x0000, /* soc may have mt6572/82/71/83,but they have the same sw init flow */
+ .options = 0,
+ .sw_init = mtk_wcn_soc_sw_init,
+ .sw_deinit = mtk_wcn_soc_sw_deinit,
+ .ic_pin_ctrl = mtk_wcn_soc_pin_ctrl,
+ .ic_ver_check = mtk_wcn_soc_ver_check,
+ .co_clock_ctrl = mtk_wcn_soc_co_clock_ctrl,
+ .is_quick_sleep = mtk_wcn_soc_quick_sleep_flag_get,
+ .is_aee_dump_support = mtk_wcn_soc_aee_dump_flag_get,
+ .trigger_stp_assert = mtk_wcn_soc_trigger_assert,
+ .deep_sleep_ctrl = NULL,
+};
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+static INT32 _wmt_soc_mode_ctrl(UINT32 mode)
+{
+ INT32 iRet = -1;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+
+ /* only consider full mode situation for the moment */
+ if (mode != MTKSTP_BTIF_FULL_MODE)
+ return -1;
+
+ /* 1. Query chip STP default options */
+ iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet);
+ osal_assert(0);
+ return -2;
+ }
+
+ /* 2. Set chip STP options */
+ iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet);
+ return -3;
+ }
+
+ /* 3. Enable host full mode */
+ ctrlPa1 = WMT_STP_CONF_MODE;
+ ctrlPa2 = MTKSTP_BTIF_FULL_MODE;
+ iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WMT_STP_CONF_EN;
+ ctrlPa2 = 1;
+ iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2);
+ if (iRet) {
+ WMT_ERR_FUNC("enable host STP-BTIF-FULL mode fail(%d)\n", iRet);
+ return -4;
+ }
+ WMT_DBG_FUNC("enable host STP-BTIF-FULL mode\n");
+
+ /*4. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */
+ osal_sleep_ms(10);
+
+ /* 5. Query chip STP options */
+ iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet);
+ return -5;
+ }
+
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf)
+{
+ INT32 iRet = -1;
+ INT32 retry = 3;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+ UINT32 hw_ver;
+ WMT_CTRL_DATA ctrlData;
+ UINT32 chipid = 0;
+#ifdef CFG_WMT_READ_EFUSE_VCN33
+ UINT32 efuse_d3_vcn33 = 2; /*default voltage is 3.5V*/
+#endif
+#if CFG_WMT_MULTI_PATCH
+ UINT32 patch_num = 0;
+ UINT32 patch_index = 0;
+#endif
+#if CFG_WMT_WIFI_5G_SUPPORT
+ UINT32 dDieChipid = 0;
+ UINT32 aDieChipid = 0;
+ UINT8 evtbuf[20];
+ UINT32 u4Res;
+ UINT32 pmicChipid = 0;
+#endif
+ P_WMT_GEN_CONF pWmtGenConf = NULL;
+ P_CONSYS_EMI_ADDR_INFO emiInfo = NULL;
+
+ WMT_DBG_FUNC(" start\n");
+
+ osal_assert(gp_soc_info != NULL);
+ if ((gp_soc_info == NULL)
+ || (pWmtHifConf == NULL)
+ ) {
+ WMT_ERR_FUNC("null pointers: gp_soc_info(0x%p), pWmtHifConf(0x%p)\n", gp_soc_info, pWmtHifConf);
+ return -WMT_ERRCODE_NULL_FUNC_POINTER;
+ }
+
+ hw_ver = gp_soc_info->u4HwVer;
+
+ /* 4 <3.2> start init for BTIF */
+ if (pWmtHifConf->hifType == WMT_HIF_BTIF) {
+
+ emiInfo = mtk_wcn_consys_soc_get_emi_phy_add();
+ if (!emiInfo) {
+ WMT_ERR_FUNC("get emi info fail!\n");
+ return -WMT_ERRCODE_EMI_NOT_READY;
+ }
+ /* non-PDA mode, enable full mode before patch download */
+ if (!emiInfo->pda_dl_patch_flag) {
+ iRet = _wmt_soc_mode_ctrl(MTKSTP_BTIF_FULL_MODE);
+ if (iRet) {
+ WMT_ERR_FUNC("config btif full mode fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ }
+ }
+
+ /* Check whether need to update property of patch version.
+ * If yes, notify stp_launcher to update.
+ */
+ if (wmt_lib_get_need_update_patch_version()) {
+ wmt_lib_set_need_update_patch_version(0);
+ mtk_wcn_soc_update_patch_version();
+ WMT_INFO_FUNC("wmt update patch version\n");
+ }
+
+#if CFG_WMT_POWER_ON_DLM
+ if (wmt_ic_ops_soc.options & OPT_POWER_ON_DLM_TABLE) {
+ iRet = wmt_core_init_script(wmt_power_on_dlm_table,
+ osal_array_size(wmt_power_on_dlm_table));
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_power_on_dlm_table fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_DLM_TABLE_FAIL;
+ }
+ WMT_DBG_FUNC("wmt_power_on_dlm_table ok\n");
+ }
+#endif
+ /* 6. download patch */
+#if CFG_WMT_MULTI_PATCH
+ /* 6.1 Let launcher to search patch info */
+ /* 6.2 Read patch number */
+ /* If patch number is 0, it's first time connys power on */
+ if ((wmt_ic_ops_soc.options & OPT_DISABLE_ROM_PATCH_DWN) == 0) {
+ patch_num = mtk_wcn_soc_get_patch_num();
+ while (patch_num == 0 || wmt_lib_get_patch_info() == NULL) {
+ if (retry-- <= 0) {
+ WMT_ERR_FUNC("patch info retry fail, patch num = %d\n", patch_num);
+ return -WMT_ERRCODE_PATCH_INFO_FAIL;
+ }
+ iRet = mtk_wcn_soc_patch_info_prepare();
+ if (iRet)
+ WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet);
+ patch_num = mtk_wcn_soc_get_patch_num();
+ }
+ WMT_INFO_FUNC("patch total num = [%d]\n", patch_num);
+ } else
+ patch_num = 0;
+#if CFG_WMT_PATCH_DL_OPTM
+ if (patch_num != 0) {
+ if (wmt_ic_ops_soc.options & OPT_SET_MCUCLK_TABLE_1_2) {
+ iRet = wmt_core_init_script(set_mcuclk_table_1, osal_array_size(set_mcuclk_table_1));
+ if (iRet) {
+ WMT_ERR_FUNC("set_mcuclk_table_1 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_MCUCLK_TABLE_FAIL;
+ }
+ } else if (wmt_ic_ops_soc.options & OPT_SET_MCUCLK_TABLE_3_4) {
+ iRet = wmt_core_init_script(set_mcuclk_table_3, osal_array_size(set_mcuclk_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("set_mcuclk_table_3 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_MCUCLK_TABLE_FAIL;
+ }
+ }
+ }
+#endif
+ /* 6.3 Multi-patch Patch download */
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH);
+ for (patch_index = 0; patch_index < patch_num; patch_index++) {
+ iRet = mtk_wcn_soc_patch_dwn(patch_index);
+ if (iRet) {
+ WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index);
+ return -WMT_ERRCODE_PATCH_DWN_FAIL;
+ }
+ if (patch_index == (patch_num - 1))
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET);
+
+ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_PATCH_DWN_FAIL;
+ }
+ }
+
+#if CFG_WMT_PATCH_DL_OPTM
+ if (patch_num != 0) {
+ if (wmt_ic_ops_soc.options & OPT_SET_MCUCLK_TABLE_1_2) {
+ iRet = wmt_core_init_script(set_mcuclk_table_2, osal_array_size(set_mcuclk_table_2));
+ if (iRet) {
+ WMT_ERR_FUNC("set_mcuclk_table_2 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_MCUCLK_TABLE_FAIL;
+ }
+ } else if (wmt_ic_ops_soc.options & OPT_SET_MCUCLK_TABLE_3_4) {
+ iRet = wmt_core_init_script(set_mcuclk_table_4, osal_array_size(set_mcuclk_table_4));
+ if (iRet) {
+ WMT_ERR_FUNC("set_mcuclk_table_4 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_MCUCLK_TABLE_FAIL;
+ }
+ }
+ }
+#endif
+
+#else
+ /* 6.3 Patch download */
+ if ((wmt_ic_ops_soc.options & OPT_DISABLE_ROM_PATCH_DWN) == 0) {
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH);
+ iRet = mtk_wcn_soc_patch_dwn();
+ /* If patch download fail, we just ignore this error and let chip init process goes on */
+ if (iRet)
+ WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet);
+
+ /* 6.4. WMT Reset command */
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET);
+ iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_RESET_CMD_FAIL;
+ }
+ }
+#endif
+
+ /* PDA mode, enable full mode after patch download */
+ if (pWmtHifConf->hifType == WMT_HIF_BTIF &&
+ emiInfo->pda_dl_patch_flag) {
+ iRet = _wmt_soc_mode_ctrl(MTKSTP_BTIF_FULL_MODE);
+ if (iRet) {
+ WMT_ERR_FUNC("config btif full mode fail!\n");
+ return -WMT_ERRCODE_STP_CONFIG_FAIL;
+ }
+ }
+
+ chipid = wmt_plat_get_soc_chipid();
+ WMT_SET_CHIP_ID_CMD[5] = chipid & 0xff;
+ WMT_SET_CHIP_ID_CMD[6] = (chipid >> 8) & 0xff;
+ iRet = wmt_core_init_script(set_chipid_script, osal_array_size(set_chipid_script));
+ if (iRet)
+ WMT_ERR_FUNC("wmt_core:set_chipid_script %s(%d)\n", iRet ? "fail" : "ok", iRet);
+
+ if (wmt_ic_ops_soc.options & OPT_QUERY_ADIE) {
+ iRet = wmt_core_init_script_retry(get_a_die_script, osal_array_size(get_a_die_script), 1, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("get_a_die_script fail(%d)\n", iRet);
+#ifdef CFG_WMT_EVB
+ /* prevent printing too much log */
+ osal_sleep_ms(1000);
+#else
+ osal_dbg_assert_aee("Connsys A-die is not exist", "Please check Connsys A-die\0");
+#endif
+ return -WMT_ERRCODE_ADIE_NOT_EXIST;
+ }
+ }
+
+ iRet = wmt_init_wifi_config();
+ if (iRet) {
+ WMT_ERR_FUNC("init_wifi_config fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_WIFI_CONFIG_FAIL;
+ }
+
+#ifdef CFG_WMT_READ_EFUSE_VCN33
+ /*get CrystalTiming value before set it */
+ iRet = wmt_core_tx(get_efuse_vcn33_script[0].cmd, get_efuse_vcn33_script[0].cmdSz, &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != get_efuse_vcn33_script[0].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].cmdSz);
+ }
+ /* EVENT BUF */
+ osal_memset(get_efuse_vcn33_script[0].evt, 0, get_efuse_vcn33_script[0].evtSz);
+ iRet = wmt_core_rx(get_efuse_vcn33_script[0].evt, get_efuse_vcn33_script[0].evtSz, &u4Res);
+ if (iRet || (u4Res != get_efuse_vcn33_script[0].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].evtSz);
+ mtk_wcn_stp_dbg_dump_package();
+ }
+ efuse_d3_vcn33 = WMT_GET_EFUSE_VCN33_EVT[5] & 0x03;
+ WMT_INFO_FUNC("Read efuse to set PMIC voltage:(%d)\n", efuse_d3_vcn33);
+ wmt_set_pmic_voltage(efuse_d3_vcn33);
+#endif
+ pWmtGenConf = wmt_get_gen_conf_pointer();
+ if (wmt_ic_ops_soc.options & OPT_SET_WIFI_EXT_COMPONENT) {
+ /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/
+ if (pWmtGenConf->coex_wmt_ext_component) {
+ WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component);
+ set_wifi_ext_component_table[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component;
+ }
+ iRet = wmt_core_init_script(set_wifi_ext_component_table,
+ osal_array_size(set_wifi_ext_component_table));
+ if (iRet)
+ WMT_ERR_FUNC("wmt_core:set_wifi_ext_component_table %s(%d)\n",
+ iRet ? "fail" : "ok", iRet);
+ }
+
+#if CFG_WMT_FILTER_MODE_SETTING
+ if (wmt_ic_ops_soc.options & OPT_WIFI_LTE_COEX) {
+ wmt_stp_wifi_lte_coex();
+ WMT_DBG_FUNC("wmt_stp_wifi_lte_coex done!\n");
+ }
+ if (wmt_ic_ops_soc.options & OPT_COEX_TDM_REQ_ANTSEL_NUM) {
+ /*get gpio tdm req antsel number */
+ ctrlPa1 = 0;
+ ctrlPa2 = 0;
+ wmt_core_ctrl(WMT_CTRL_GET_TDM_REQ_ANTSEL, &ctrlPa1, &ctrlPa2);
+ WMT_INFO_FUNC("get GPIO TDM REQ ANTSEL number(%lu)\n", ctrlPa1);
+ /*set gpio tdm req antsel number to firmware */
+ WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[5] = ctrlPa1;
+ iRet = wmt_core_init_script(get_tdm_req_antsel_num_table,
+ osal_array_size(get_tdm_req_antsel_num_table));
+ if (iRet)
+ WMT_ERR_FUNC("get_tdm_req_antsel_num_table fail(%d)\n", iRet);
+ }
+#endif
+ WMT_INFO_FUNC("bt_tssi_from_wifi=%d, bt_tssi_target=%d\n",
+ pWmtGenConf->bt_tssi_from_wifi, pWmtGenConf->bt_tssi_target);
+ if (pWmtGenConf->bt_tssi_from_wifi) {
+ if (wmt_ic_ops_soc.options & OPT_BT_TSSI_FROM_WIFI_CONFIG_NEW_OPID)
+ WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[4] = 0x10;
+
+ WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[5] = pWmtGenConf->bt_tssi_from_wifi;
+ WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[6] = (pWmtGenConf->bt_tssi_target & 0x00FF) >> 0;
+ WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[7] = (pWmtGenConf->bt_tssi_target & 0xFF00) >> 8;
+ iRet = wmt_core_init_script(bt_tssi_from_wifi_table, osal_array_size(bt_tssi_from_wifi_table));
+ if (iRet)
+ WMT_ERR_FUNC("bt_tssi_from_wifi_table fail(%d)\n", iRet);
+ }
+
+ /* init epa before start RF calibration */
+ /* for chip 0x6739 */
+ iRet = wmt_stp_init_epa();
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_epa fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_EPA_FAIL;
+ }
+
+ /* for chip 0x6779 */
+ iRet = wmt_stp_init_epa_elna();
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_epa_elna fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_EPA_ELNA_FAIL;
+ }
+
+ iRet = wmt_stp_init_epa_elna_invert_cr();
+ if (iRet) {
+ WMT_ERR_FUNC("init_invert_cr fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_EPA_ELNA_INVERT_CR_FAIL;
+ }
+
+ /* init coex before start RF calibration */
+ if (wmt_ic_ops_soc.options & OPT_INIT_COEX_BEFORE_RF_CALIBRATION) {
+ iRet = wmt_stp_init_coex();
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_COEX_FAIL;
+ }
+ WMT_DBG_FUNC("init_coex ok\n");
+ }
+
+ iRet = wmt_stp_init_wifi_ant_swap();
+
+ if (iRet) {
+ WMT_ERR_FUNC("init_wifi_ant_swap fail(%d)\n", iRet);
+ WMT_INFO_FUNC("A-DIE chip id=0x%x", mtk_wcn_consys_get_adie_chipid());
+ }
+
+ /* 7. start RF calibration data */
+ iRet = mtk_wcn_soc_calibration();
+ if (iRet) {
+ WMT_ERR_FUNC("calibration failed\n");
+ return -WMT_ERRCODE_CALIBRATION_FAIL;
+ }
+
+ /* turn off VCN28 after reading efuse */
+ ctrlPa1 = EFUSE_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+
+ if (wmt_ic_ops_soc.options & OPT_INIT_COEX_AFTER_RF_CALIBRATION) {
+ iRet = wmt_stp_init_coex();
+ if (iRet) {
+ WMT_ERR_FUNC("init_coex fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_COEX_FAIL;
+ }
+ WMT_DBG_FUNC("init_coex ok\n");
+ }
+
+ if (wmt_ic_ops_soc.options & OPT_COEX_CONFIG_ADJUST) {
+ WMT_INFO_FUNC("coex_config_bt_ctrl:0x%x\n", pWmtGenConf->coex_config_bt_ctrl);
+ coex_config_addjust_table[0].cmd[5] = pWmtGenConf->coex_config_bt_ctrl;
+ WMT_INFO_FUNC("coex_config_bt_ctrl_mode:0x%x\n", pWmtGenConf->coex_config_bt_ctrl_mode);
+ coex_config_addjust_table[0].cmd[6] = pWmtGenConf->coex_config_bt_ctrl_mode;
+ WMT_INFO_FUNC("coex_config_bt_ctrl_rw:0x%x\n", pWmtGenConf->coex_config_bt_ctrl_rw);
+ coex_config_addjust_table[0].cmd[7] = pWmtGenConf->coex_config_bt_ctrl_rw;
+
+ WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio:0x%x\n",
+ pWmtGenConf->coex_config_addjust_opp_time_ratio);
+ coex_config_addjust_table[1].cmd[5] = pWmtGenConf->coex_config_addjust_opp_time_ratio;
+ WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio_bt_slot:0x%x\n",
+ pWmtGenConf->coex_config_addjust_opp_time_ratio_bt_slot);
+ coex_config_addjust_table[1].cmd[6] =
+ pWmtGenConf->coex_config_addjust_opp_time_ratio_bt_slot;
+ WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio_wifi_slot:0x%x\n",
+ pWmtGenConf->coex_config_addjust_opp_time_ratio_wifi_slot);
+ coex_config_addjust_table[1].cmd[7] =
+ pWmtGenConf->coex_config_addjust_opp_time_ratio_wifi_slot;
+
+ WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio:0x%x\n",
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio);
+ coex_config_addjust_table[2].cmd[5] =
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio;
+ WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio_bt_slot:0x%x\n",
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_bt_slot);
+ coex_config_addjust_table[2].cmd[6] =
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_bt_slot;
+ WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio_wifi_slot:0x%x\n",
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_wifi_slot);
+ coex_config_addjust_table[2].cmd[7] =
+ pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_wifi_slot;
+
+ /* COEX flag is different in these project. */
+ if (wmt_ic_ops_soc.options & OPT_COEX_CONFIG_ADJUST_NEW_FLAG) {
+ coex_config_addjust_table[0].cmd[4] = 0x1e;
+ coex_config_addjust_table[1].cmd[4] = 0x1f;
+ coex_config_addjust_table[2].cmd[4] = 0x20;
+ }
+
+ iRet = wmt_core_init_script(coex_config_addjust_table,
+ osal_array_size(coex_config_addjust_table));
+ if (iRet)
+ WMT_ERR_FUNC("wmt_core:coex_config_addjust_table %s(%d)\n",
+ iRet ? "fail" : "ok", iRet);
+ }
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+ mtk_wcn_soc_crystal_triming_set();
+#endif
+
+#if CFG_WMT_SDIO_DRIVING_SET
+ mtk_wcn_soc_set_sdio_driving();
+#endif
+
+ if (wmt_ic_ops_soc.options & OPT_SET_OSC_TYPE) {
+ if (wmt_plat_soc_co_clock_flag_get() == WMT_CO_CLOCK_EN) {
+ WMT_INFO_FUNC("co-clock enabled.\n");
+
+ iRet = wmt_core_init_script(osc_type_table, osal_array_size(osc_type_table));
+ if (iRet) {
+ WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet);
+ return -WMT_ERRCODE_INIT_COCLOCK_TYPE_FAIL;
+ }
+ } else {
+ WMT_WARN_FUNC("co-clock disabled.\n");
+ }
+ }
+#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT)
+ iRet = wmt_core_init_script(merge_pcm_table, osal_array_size(merge_pcm_table));
+ if (iRet) {
+ WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet);
+ return -WMT_ERRCODE_INIT_MERGE_PCM_TABLE_FAIL;
+ }
+#endif
+
+ /* 15. Set FM strap */
+ WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0];
+ iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", pWmtHifConf->au4StrapConf[0], iRet);
+ return -WMT_ERRCODE_INIT_FM_MODE_FAIL;
+ }
+ WMT_DBG_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]);
+
+#if CFG_SET_OPT_REG /*set registers */
+ iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers));
+ if (iRet) {
+ WMT_ERR_FUNC("set_registers fail(%d)", iRet);
+ return -WMT_ERRCODE_INIT_SET_REGISTER_FAIL;
+ }
+#endif
+
+ if (wmt_ic_ops_soc.options & OPT_SET_COREDUMP_LEVEL) {
+ if (mtk_wcn_stp_coredump_flag_get() != 0) {
+ iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6));
+ if (iRet) {
+ WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet);
+ return -WMT_ERRCODE_INIT_SET_COREDUMP_FAIL;
+ }
+ WMT_DBG_FUNC("enable soc_consys firmware coredump\n");
+ } else {
+ WMT_DBG_FUNC("disable soc_consys firmware coredump\n");
+ }
+ }
+
+#if CFG_WMT_WIFI_5G_SUPPORT
+ dDieChipid = wmt_ic_ops_soc.icId;
+ WMT_DBG_FUNC("current SOC chipid is 0x%x\n", dDieChipid);
+ if (wmt_ic_ops_soc.options & OPT_WIFI_5G_PALDO) {
+ /* read A die chipid by wmt cmd */
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_GET_SOC_ADIE_CHIPID_CMD[0], sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD))) {
+ WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res);
+ return -WMT_ERRCODE_READ_ADIE_TX_CMD_FAIL;
+ }
+ osal_memset(evtbuf, 0, sizeof(evtbuf));
+ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT))) {
+ WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtbuf[0], evtbuf[1], evtbuf[2], evtbuf[3], evtbuf[4],
+ WMT_GET_SOC_ADIE_CHIPID_EVT[0],
+ WMT_GET_SOC_ADIE_CHIPID_EVT[1],
+ WMT_GET_SOC_ADIE_CHIPID_EVT[2],
+ WMT_GET_SOC_ADIE_CHIPID_EVT[3],
+ WMT_GET_SOC_ADIE_CHIPID_EVT[4]);
+ mtk_wcn_stp_dbg_dump_package();
+ return -WMT_ERRCODE_READ_ADIE_RX_EVT_FAIL;
+ }
+
+ osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2);
+ WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid);
+
+ if (aDieChipid == 0x6625) {
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_GET_SOC_6625_L_CMD[0], sizeof(WMT_GET_SOC_6625_L_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_CMD)))
+ WMT_ERR_FUNC("wmt_core:read A die efuse CMD fail(%d),size(%d)\n", iRet, u4Res);
+ osal_memset(evtbuf, 0, sizeof(evtbuf));
+ iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_6625_L_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_EVT))) {
+ WMT_ERR_FUNC("wmt_core:read A die efuse EVT fail(%d),size(%d)\n", iRet, u4Res);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X]\n",
+ evtbuf[0], evtbuf[1], evtbuf[2], evtbuf[3],
+ WMT_GET_SOC_6625_L_EVT[0],
+ WMT_GET_SOC_6625_L_EVT[1],
+ WMT_GET_SOC_6625_L_EVT[2],
+ WMT_GET_SOC_6625_L_EVT[3]);
+ mtk_wcn_stp_dbg_dump_package();
+ }
+ WMT_INFO_FUNC("read SOC Adie Efuse(0x120) value:0x%2x,0x%2x,0x%2x,0x%2x -> %s\n",
+ evtbuf[u4Res - 4], evtbuf[u4Res - 3], evtbuf[u4Res - 2], evtbuf[u4Res - 1],
+ evtbuf[u4Res - 2] == 0x31 ? "MT6625L" : "MT6625");
+ }
+ /* get PMIC chipid */
+
+ ctrlData.ctrlId = WMT_CTRL_SOC_PALDO_CTRL;
+ ctrlData.au4CtrlData[0] = PMIC_CHIPID_PALDO;
+ ctrlData.au4CtrlData[1] = 0;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet < 0) {
+ WMT_ERR_FUNC("wmt_core: read PMIC chipid fail(%d)\n", iRet);
+ return -WMT_ERRCODE_READ_PMIC_CHIPID_FAIL;
+ }
+ pmicChipid = ctrlData.au4CtrlData[2];
+ WMT_INFO_FUNC("current PMIC chipid(0x%x)\n", pmicChipid);
+
+ /* MT6625 & MT6322, write 1 to 0x0414[12] */
+ /* MT6625 & MT6323, assert */
+ /* MT6627 & (MT6322 or MT6323),write 0 to 0x0414[12] */
+
+ switch (aDieChipid) {
+ case 0x6625:
+ if (pmicChipid == 0x6322 || pmicChipid == 0x6356) {
+ WMT_INFO_FUNC("wmt-core:enable wifi 5G support\n");
+ ctrlPa1 = WIFI_5G_PALDO;
+ ctrlPa2 = PALDO_ON;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ } else if (pmicChipid == 0x6323) {
+ osal_assert(0);
+ } else {
+ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n");
+ }
+ break;
+ case 0x6627:
+ if ((pmicChipid == 0x6322) || (pmicChipid == 0x6323)) {
+ WMT_INFO_FUNC("wmt-core: disable wifi 5G support\n");
+ ctrlPa1 = WIFI_5G_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ } else {
+ WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n");
+ }
+ break;
+ default:
+ WMT_WARN_FUNC("wmt-core: unknown A die chipid(0x%x)\n", aDieChipid);
+ break;
+ }
+ }
+#endif
+
+#if 1
+ ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO;
+ ctrlData.au4CtrlData[0] = wmt_ic_ops_soc.icId;
+ ctrlData.au4CtrlData[1] = (SIZE_T) gp_soc_info->cChipVersion;
+ ctrlData.au4CtrlData[2] = (SIZE_T) &gp_soc_patch_info;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("set stp dbg info fail(%d)\n", iRet);
+ return -WMT_ERRCODE_SET_STP_DBG_INFO_FAIL;
+ }
+#endif
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_soc_info != NULL);
+ if (gp_soc_info != NULL) {
+ if (gp_soc_info->bPsmSupport != MTK_WCN_BOOL_FALSE)
+ wmt_lib_ps_enable();
+ else
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_END);
+
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf)
+{
+ WMT_DBG_FUNC(" start\n");
+
+#if CFG_WMT_PS_SUPPORT
+ osal_assert(gp_soc_info != NULL);
+ if ((gp_soc_info != NULL)
+ && (gp_soc_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) {
+ wmt_lib_ps_disable();
+ }
+#endif
+
+ gp_soc_info = NULL;
+
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret = -1;
+ UINT32 val;
+
+ if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) {
+ WMT_INFO_FUNC("PCM & I2S PIN SHARE\n");
+#if 0
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000710;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#else
+ WMT_WARN_FUNC("TBD!!");
+ ret = 0;
+#endif
+ } else {
+ /*PCM & I2S separate */
+ WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n");
+#if 0
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ val = 0x00000770;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ val = 0x00000700;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000000;
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x00000070;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+
+ break;
+ case WMT_IC_AIF_3:
+ val = 0x00000000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0);
+ val = 0x00000800; /* 800:3-wire, 000: 4-wire */
+ ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800);
+
+ break;
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#else
+ switch (state) {
+ case WMT_IC_AIF_0:
+ /* BT_PCM_OFF & FM line in/out */
+ ret = 0;
+ break;
+ case WMT_IC_AIF_1:
+ /* BT_PCM_ON & FM line in/out */
+ ret = 0;
+ break;
+
+ case WMT_IC_AIF_2:
+ /* BT_PCM_OFF & FM I2S */
+ val = 0x01110000;
+ ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000);
+
+ break;
+ case WMT_IC_AIF_3:
+ ret = 0;
+ break;
+
+ default:
+ WMT_ERR_FUNC("unsupported state (%d)\n", state);
+ ret = -1;
+ break;
+ }
+#endif
+ }
+
+ if (!ret)
+ WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret);
+ WMT_INFO_FUNC("new state(%d) ok\n", state);
+
+ return ret;
+}
+
+static INT32 mtk_wcn_soc_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 iRet = -1;
+ UINT32 uVal = 0;
+
+ /* gen3(6631) CONSYS can not access reg:0x80050078 and no need to do GPS SYNC
+ * may cause bus hang
+ */
+ if (wmt_ic_ops_soc.options & OPT_GPS_SYNC) {
+ if (state == WMT_IC_PIN_MUX)
+ uVal = 0x1 << 28;
+ else
+ uVal = 0x5 << 28;
+ iRet = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28);
+ if (iRet)
+ WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet);
+ } else
+ WMT_INFO_FUNC("This chip no need to sync GPS and MODEM!\n");
+
+ /* anyway, we return 0 */
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag)
+{
+ INT32 ret;
+
+ WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag);
+
+ ret = -1;
+ switch (id) {
+ case WMT_IC_PIN_AUDIO:
+ ret = mtk_wcn_soc_aif_ctrl(state, flag);
+ break;
+
+ case WMT_IC_PIN_EEDI:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+
+ case WMT_IC_PIN_EEDO:
+ WMT_WARN_FUNC("TBD!!");
+ /* We just return 0 here, prevent from WMT-FUNC do other register read/write */
+ ret = 0;
+ break;
+ case WMT_IC_PIN_GSYNC:
+ ret = mtk_wcn_soc_gps_sync_ctrl(state, flag);
+ break;
+ default:
+ break;
+ }
+ WMT_INFO_FUNC("ret = (%d)\n", ret);
+
+ return ret;
+}
+
+INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on)
+{
+ INT32 iRet = 0;
+
+ if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) {
+ gCoClockEn = on;
+ } else {
+ WMT_DBG_FUNC("0x%x: error parameter:%d\n", wmt_ic_ops_soc.icId, on);
+ iRet = -1;
+ }
+ WMT_DBG_FUNC("0x%x: Co-clock %s\n", wmt_ic_ops_soc.icId,
+ (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled");
+
+ return iRet;
+}
+
+static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_TRUE;
+}
+
+static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID)
+{
+ return MTK_WCN_BOOL_FALSE;
+}
+static MTK_WCN_BOOL mtk_wcn_soc_trigger_assert(VOID)
+{
+ INT32 ret = 0;
+ UINT32 u4Res;
+ UINT32 tstCmdSz = 0;
+ UINT32 tstEvtSz = 0;
+ UINT8 tstCmd[64];
+ UINT8 tstEvt[64];
+ UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 };
+ UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 };
+
+ WMT_INFO_FUNC("Send Assert command !\n");
+ tstCmdSz = osal_sizeof(WMT_ASSERT_CMD);
+ tstEvtSz = osal_sizeof(WMT_ASSERT_EVT);
+ osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz);
+ osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz);
+
+ ret = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (ret || (u4Res != tstCmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", ret, u4Res,
+ tstCmdSz);
+ ret = -1;
+ }
+ return (ret == 0);
+}
+
+static INT32 mtk_wcn_soc_ver_check(VOID)
+{
+ UINT32 hw_ver = 0;
+ UINT32 fw_ver = 0;
+ INT32 iret;
+ const WMT_IC_INFO_S *p_info = NULL;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+
+ /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */
+ WMT_LOUD_FUNC("0x%x: before read hw_ver (hw version)\n", wmt_ic_ops_soc.icId);
+ iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("0x%x: read hw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret);
+ return -2;
+ }
+ WMT_DBG_FUNC("0x%x: read hw_ver (hw version) (0x%x)\n", wmt_ic_ops_soc.icId, hw_ver);
+
+ WMT_LOUD_FUNC("0x%x: before fw_ver (rom version)\n", wmt_ic_ops_soc.icId);
+ wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK);
+ if (iret) {
+ WMT_ERR_FUNC("0x%x: read fw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret);
+ return -2;
+ }
+ WMT_DBG_FUNC("0x%x: read fw_ver (rom version) (0x%x)\n", wmt_ic_ops_soc.icId, fw_ver);
+
+ p_info = mtk_wcn_soc_find_wmt_ic_info(hw_ver);
+ if (p_info == NULL) {
+ WMT_ERR_FUNC("0x%x: hw_ver(0x%x) find wmt ic info fail\n", wmt_ic_ops_soc.icId, hw_ver);
+ return -3;
+ }
+ WMT_WARN_FUNC("0x%x: ic info: %s.%s (0x%x/0x%x, HWVER:0x%04x, patch_ext:%s)\n",
+ wmt_ic_ops_soc.icId, p_info->cChipName, p_info->cChipVersion,
+ hw_ver, fw_ver, p_info->u4HwVer, p_info->cPatchNameExt);
+
+ /* hw id & version */
+ ctrlPa1 = (wmt_ic_ops_soc.icId << 16) | (hw_ver & 0x0000FFFF);
+ /* translated fw rom version */
+ ctrlPa2 = (fw_ver & 0x0000FFFF);
+
+ iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2);
+ if (iret)
+ WMT_WARN_FUNC("0x%x: WMT_CTRL_HWIDVER_SET fail(%d)\n", wmt_ic_ops_soc.icId, iret);
+
+ gp_soc_info = p_info;
+ return 0;
+}
+
+static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver)
+{
+ /* match chipversion with u4HwVer item in mtk_wcn_soc_info_table */
+ const UINT32 size = osal_array_size(mtk_wcn_soc_info_table);
+ INT32 index = 0;
+
+ /* George: reverse the search order to favor newer version products
+ * TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver()
+ * is changed correctly in the future!!
+ * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs.
+ */
+ index = size - 1;
+ /* full match */
+ while ((index >= 0) && (hw_ver != mtk_wcn_soc_info_table[index].u4HwVer))
+ --index;
+ if (index >= 0) {
+ WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index);
+ return &mtk_wcn_soc_info_table[index];
+ }
+
+ WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver);
+
+ /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR
+ * NUM only can help us support future minor hw ECO, or fab switch, etc.
+ * FULL matching eliminate such flexibility and software package have to be
+ * updated EACH TIME even when minor hw ECO or fab switch!!!
+ */
+ /* George: reverse the search order to favor newer version products */
+ index = size - 1;
+ /* major num match */
+ while ((index >= 0) &&
+ (MAJORNUM(hw_ver) != MAJORNUM(mtk_wcn_soc_info_table[index].u4HwVer))) {
+ --index;
+ }
+ if (index >= 0) {
+ WMT_DBG_FUNC("0x%x: found ic info for hw_ver(0x%x) by major num! index:%d\n",
+ wmt_ic_ops_soc.icId, hw_ver, index);
+ return &mtk_wcn_soc_info_table[index];
+ }
+
+ WMT_ERR_FUNC("0x%x: find no ic info for hw_ver(0x%x) by full match nor major num match!\n",
+ wmt_ic_ops_soc.icId, hw_ver);
+ WMT_ERR_FUNC("Set default chip version: E1!\n");
+ return &mtk_wcn_soc_info_table[0];
+}
+
+#if CFG_WMT_FILTER_MODE_SETTING
+static INT32 wmt_stp_wifi_lte_coex(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ osal_sleep_ms(5);
+
+ if (pWmtGenConf->coex_wmt_filter_mode == 0) {
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SET_WIFI_LTE_COEX);
+ if (wmt_ic_ops_soc.options & OPT_WIFI_LTE_COEX_TABLE_1) {
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_1, osal_array_size(set_wifi_lte_coex_table_1));
+ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_1 %s(%d)\n", iRet ? "fail" : "ok", iRet);
+ } else if (wmt_ic_ops_soc.options & OPT_WIFI_LTE_COEX_TABLE_2) {
+ /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/
+ if (pWmtGenConf->coex_wmt_ext_component) {
+ WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component);
+ set_wifi_lte_coex_table_2[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component;
+ }
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_2, osal_array_size(set_wifi_lte_coex_table_2));
+ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_2 %s(%d)\n", iRet ? "fail" : "ok", iRet);
+ } else if (wmt_ic_ops_soc.options & OPT_WIFI_LTE_COEX_TABLE_3) {
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_3,
+ osal_array_size(set_wifi_lte_coex_table_3));
+ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_3 %s(%d)\n",
+ iRet ? "fail" : "ok", iRet);
+ } else {
+ iRet =
+ wmt_core_init_script(set_wifi_lte_coex_table_0, osal_array_size(set_wifi_lte_coex_table_0));
+ WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 %s(%d)\n", iRet ? "fail" : "ok", iRet);
+ }
+ }
+
+ return iRet;
+}
+#endif
+
+static INT32 wmt_stp_init_coex(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+#define COEX_WMT 0
+
+#if CFG_SUBSYS_COEX_NEED
+ /* no need for MT6628 */
+#define COEX_BT 1
+#define COEX_WIFI 2
+#define COEX_PTA 3
+#define COEX_MISC 4
+#else
+#define COEX_WIFI_PATH 1
+#define COEX_EXT_ELAN_GAIN_P1 2
+#define COEX_EXT_EPA_MODE 3
+#endif
+#define WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE 6
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ if (wmt_ic_ops_soc.options & OPT_COEX_EXT_ELNA_GAIN_P1_SUPPORT) {
+ WMT_INFO_FUNC("elna_gain_p1_support:0x%x\n", pWmtGenConf->coex_wmt_ext_elna_gain_p1_support);
+ if (pWmtGenConf->coex_wmt_ext_elna_gain_p1_support != 1)
+ return 0;
+ }
+
+ /*Dump the coex-related info */
+ WMT_DBG_FUNC("coex_wmt_ant_mode:0x%x, coex_wmt_wifi_path:0x%x\n",
+ pWmtGenConf->coex_wmt_ant_mode, pWmtGenConf->coex_wmt_wifi_path);
+#if CFG_SUBSYS_COEX_NEED
+ WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_bt_rssi_upper_limit,
+ pWmtGenConf->coex_bt_rssi_mid_limit,
+ pWmtGenConf->coex_bt_rssi_lower_limit,
+ pWmtGenConf->coex_bt_pwr_high, pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low);
+ WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_wifi_rssi_upper_limit,
+ pWmtGenConf->coex_wifi_rssi_mid_limit,
+ pWmtGenConf->coex_wifi_rssi_lower_limit,
+ pWmtGenConf->coex_wifi_pwr_high, pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low);
+ WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_ext_pta_hi_tx_tag,
+ pWmtGenConf->coex_ext_pta_hi_rx_tag,
+ pWmtGenConf->coex_ext_pta_lo_tx_tag,
+ pWmtGenConf->coex_ext_pta_lo_rx_tag,
+ pWmtGenConf->coex_ext_pta_sample_t1,
+ pWmtGenConf->coex_ext_pta_sample_t2, pWmtGenConf->coex_ext_pta_wifi_bt_con_trx);
+ WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n",
+ pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set);
+#endif
+
+ /*command adjustion due to WMT.cfg */
+ coex_table[COEX_WMT].cmd[4] = WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE;
+ coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode;
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz);
+
+#if CFG_SUBSYS_COEX_NEED
+ coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit;
+ coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit;
+ coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit;
+ coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high;
+ coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid;
+ coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz);
+
+ coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit;
+ coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit;
+ coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit;
+ coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high;
+ coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid;
+ coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low;
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0],
+ coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz);
+
+ coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag;
+ coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag;
+ coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag;
+ coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag;
+ coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8);
+ coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0);
+ coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx;
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz);
+
+ osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on,
+ sizeof(pWmtGenConf->coex_misc_ext_pta_on));
+ osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set,
+ sizeof(pWmtGenConf->coex_misc_ext_feature_set));
+
+ wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, coex_table[COEX_MISC].cmdSz);
+#else
+ coex_table[COEX_WIFI_PATH].cmd[5] =
+ (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0x00FF) >> 0);
+ coex_table[COEX_WIFI_PATH].cmd[6] =
+ (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0xFF00) >> 8);
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_WIFI_PATH].cmd[0],
+ coex_table[COEX_WIFI_PATH].str, coex_table[COEX_WIFI_PATH].cmdSz);
+ }
+
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[5] = pWmtGenConf->coex_wmt_ext_elna_gain_p1_support;
+ /* wmt_ext_elna_gain_p1 D0*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[6] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[7] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[8] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[9] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D1*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[10] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[11] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[12] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[13] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D2*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[14] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[15] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[16] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[17] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0xFF000000) >> 24);
+ /* wmt_ext_elna_gain_p1 D3*/
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[18] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x000000FF) >> 0);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[19] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x0000FF00) >> 8);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[20] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x00FF0000) >> 16);
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[21] =
+ (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0xFF000000) >> 24);
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG) {
+ wmt_core_dump_data(&coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[0],
+ coex_table[COEX_EXT_ELAN_GAIN_P1].str,
+ coex_table[COEX_EXT_ELAN_GAIN_P1].cmdSz);
+ }
+
+ coex_table[COEX_EXT_EPA_MODE].cmd[5] = pWmtGenConf->coex_wmt_ext_epa_mode;
+#endif
+
+ iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table));
+
+ return iRet;
+}
+
+static INT32 wmt_stp_init_epa(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_DBG_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ WMT_INFO_FUNC("epa_mode:0x%x\n", pWmtGenConf->coex_wmt_ant_mode_ex);
+
+ if (pWmtGenConf->coex_wmt_ant_mode_ex != 1)
+ return 0;
+
+ epa_table[0].cmd[5] = pWmtGenConf->coex_wmt_ant_mode_ex;
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&epa_table[0].cmd[0], epa_table[0].str, epa_table[0].cmdSz);
+ iRet = wmt_core_init_script(epa_table, ARRAY_SIZE(epa_table));
+
+ return iRet;
+}
+
+static INT32 wmt_stp_init_epa_elna(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ struct init_script script[1];
+ struct WMT_BYTE_ARRAY *ba = NULL;
+ INT32 cmd_size;
+ INT32 data_size;
+ PUINT8 cmd;
+ UINT16 index = 0;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_DBG_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ if (pWmtGenConf->coex_wmt_epa_elna == NULL)
+ return 0;
+
+ ba = pWmtGenConf->coex_wmt_epa_elna;
+
+ /* cmd_size = direction(1) + op(1) + length(2) + coex op(1) + data */
+ cmd_size = ba->size + 5;
+ cmd = (PUINT8)osal_malloc(cmd_size);
+
+ if (cmd == NULL) {
+ WMT_ERR_FUNC("failed to malloc when init epa elna\n");
+ return -1;
+ }
+
+ /* 0x1: direction, 0x10: op code */
+ cmd[index++] = 0x1;
+ cmd[index++] = 0x10;
+
+ /* add 1 for coex op id */
+ data_size = ba->size + 1;
+ /* assign data length */
+ cmd[index++] = (data_size & 0x00FF) >> 0;
+ cmd[index++] = (data_size & 0xFF00) >> 8;
+ /* assign coex op id: 0x1D */
+ cmd[index++] = 0x1D;
+
+ osal_memcpy(&cmd[index], ba->data, ba->size);
+
+ script[0].cmd = cmd;
+ script[0].cmdSz = cmd_size;
+ script[0].evt = WMT_EPA_ELNA_SETTING_CONFIG_EVT;
+ script[0].evtSz = sizeof(WMT_EPA_ELNA_SETTING_CONFIG_EVT);
+ script[0].str = "coex_wmt_epa_elna";
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&(script[0].cmd[0]), script[0].str,
+ script[0].cmdSz);
+
+ iRet = wmt_core_init_script(script, ARRAY_SIZE(script));
+
+ osal_free(cmd);
+ return iRet;
+}
+
+static INT32 wmt_stp_init_epa_elna_invert_cr(VOID)
+{
+ INT32 iRet;
+ UINT32 uVal = 0;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ UINT32 default_invert_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ UINT32 default_invert_bit[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ PINT8 pbuf;
+ long res = 0;
+ PINT8 tok1, tok2;
+ UINT32 item1, item2, item_index;
+ UINT32 invert_cr, invert_bit;
+
+ mtk_wcn_consys_ic_get_ant_sel_cr_addr(default_invert_cr, default_invert_bit);
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_DBG_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ WMT_DBG_FUNC("pWmtGenConf->coex_wmt_antsel_invert_support=[%s]\n",
+ pWmtGenConf->coex_wmt_antsel_invert_support);
+
+ if (pWmtGenConf->coex_wmt_antsel_invert_support == NULL ||
+ osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support) <= 0)
+ return 0;
+
+ pbuf = osal_malloc(osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support)+1);
+ if (pbuf == NULL) {
+ WMT_ERR_FUNC("init_invert_cr, malloc fail, size %d\n",
+ osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support)+1);
+ return -1;
+ }
+
+ osal_strcpy(pbuf, pWmtGenConf->coex_wmt_antsel_invert_support);
+
+ while ((tok1 = osal_strsep(&pbuf, " /\\")) != NULL) {
+ if (*tok1 == '\0')
+ continue;
+ if (!*tok1)
+ continue;
+ item1 = 0;
+ item2 = 0;
+ item_index = 0;
+ while ((tok2 = osal_strsep(&tok1, " ,")) != NULL) {
+ if (*tok2 == '\0')
+ continue;
+ if (!*tok2)
+ continue;
+ if ((osal_strlen(tok2) > 2) && ((*tok2) == '0') && (*(tok2 + 1) == 'x'))
+ osal_strtol(tok2 + 2, 16, &res);
+ else
+ osal_strtol(tok2, 10, &res);
+ if (item_index == 0)
+ item1 = res;
+ else if (item_index == 1)
+ item2 = res;
+ item_index++;
+ }
+
+ if (item_index != 1 && item_index != 2)
+ continue;
+ if ((item_index == 1) && (item1 > 7 || item1 < 0))
+ continue;
+ if ((item_index == 2) && (item2 > 31 || item2 < 0))
+ continue;
+
+ if (item_index == 1) {
+ invert_cr = default_invert_cr[item1];
+ invert_bit = default_invert_bit[item1];
+ } else if (item_index == 2) {
+ invert_cr = item1;
+ invert_bit = item2;
+ }
+
+ if (invert_cr == 0)
+ continue;
+
+ uVal = 0;
+ iRet = wmt_core_reg_rw_raw(0, invert_cr, &uVal, 0xFFFFFFFF);
+ if (iRet) {
+ WMT_ERR_FUNC("init_invert_cr, read 0x%x[%d](before write) fail(%d)\n",
+ invert_cr, invert_bit, iRet);
+ continue;
+ }
+ WMT_DBG_FUNC("init_invert_cr, 0x%x[%d](before write) = 0x%x\n",
+ invert_cr, invert_bit, uVal);
+
+ uVal = 0x1 << invert_bit;
+ iRet = wmt_core_reg_rw_raw(1, invert_cr, &uVal, 0x1 << invert_bit);
+ if (iRet) {
+ WMT_ERR_FUNC("init_invert_cr, write 0x%x[%d]=1 fail(%d)\n",
+ invert_cr, invert_bit, iRet);
+ continue;
+ }
+
+ uVal = 0;
+ iRet = wmt_core_reg_rw_raw(0, invert_cr, &uVal, 0xFFFFFFFF);
+ if (iRet) {
+ WMT_ERR_FUNC("init_invert_cr, read 0x%x[%d](after write) fail(%d)\n",
+ invert_cr, invert_bit, iRet);
+ continue;
+ }
+ WMT_DBG_FUNC("init_invert_cr, 0x%x[%d](after write) = 0x%x\n",
+ invert_cr, invert_bit, uVal);
+ }
+
+ if (pbuf != NULL) {
+ osal_free(pbuf);
+ pbuf = NULL;
+ }
+
+ return 0;
+}
+
+static INT32 wmt_stp_init_wifi_ant_swap(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ UINT8 ant_swap_mode, polarity, ant_sel;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_DBG_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ ant_swap_mode = pWmtGenConf->wifi_ant_swap_mode;
+ polarity = pWmtGenConf->wifi_main_ant_polarity;
+ ant_sel = pWmtGenConf->wifi_ant_swap_ant_sel_gpio;
+
+ WMT_INFO_FUNC("ant swap mode = %d, main_polarity = %d, ant_sel = %d\n",
+ ant_swap_mode, polarity, ant_sel);
+
+ if (ant_swap_mode <= 0 || ant_swap_mode > 2)
+ return 0;
+
+ if (ant_swap_mode == 2 &&
+ mtk_consys_is_ant_swap_enable_by_hwid() == 0)
+ return 0;
+
+ wifi_ant_swap_table[0].cmd[6] = polarity;
+
+ if (ant_sel > 0)
+ wifi_ant_swap_table[0].cmd[7] = ant_sel;
+ else {
+ /* backward compatible */
+ wifi_ant_swap_table[0].cmdSz = sizeof(WMT_WIFI_ANT_SWAP_CMD) - 1;
+ wifi_ant_swap_table[0].cmd[2] = 3; /* length */
+ wifi_ant_swap_table[0].cmd[4] = 6; /* op id */
+ wifi_ant_swap_table[0].evt[5] = 6; /* op id */
+ }
+
+ iRet = wmt_core_init_script(wifi_ant_swap_table, ARRAY_SIZE(wifi_ant_swap_table));
+
+ return iRet;
+}
+
+static INT32 wmt_init_wifi_config(VOID)
+{
+ INT32 iRet;
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ struct init_script script[1];
+ struct WMT_BYTE_ARRAY *ba = NULL;
+ INT32 cmd_size;
+ INT32 data_size;
+ PUINT8 cmd;
+ UINT16 index = 0;
+
+ /*Get wmt config */
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_DBG_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ if (pWmtGenConf->wifi_config == NULL)
+ return 0;
+
+ ba = pWmtGenConf->wifi_config;
+
+ /* cmd_size = direction(1) + op(1) + length(2) + sub op(1) + data_len(1) + data */
+ cmd_size = ba->size + 6;
+ cmd = (PUINT8)osal_malloc(cmd_size);
+
+ if (cmd == NULL) {
+ WMT_ERR_FUNC("failed to malloc when init wifi config\n");
+ return -1;
+ }
+
+ /* 0x1: direction, 0x2: op code */
+ cmd[index++] = 0x1;
+ cmd[index++] = 0x2;
+
+ /* add 2 for test op id and data length */
+ data_size = ba->size + 2;
+ /* assign data length */
+ cmd[index++] = (data_size & 0x00FF) >> 0;
+ cmd[index++] = (data_size & 0xFF00) >> 8;
+ /* assign op id: 0x14 */
+ cmd[index++] = 0x14;
+ /* assign data length */
+ /* A byte to store data length is because firmware test op handler cannot see data length*/
+ cmd[index++] = (UINT8)ba->size;
+
+ osal_memcpy(&cmd[index], ba->data, ba->size);
+
+ script[0].cmd = cmd;
+ script[0].cmdSz = cmd_size;
+ script[0].evt = WMT_WIFI_CONFIG_EVT;
+ script[0].evtSz = sizeof(WMT_WIFI_CONFIG_EVT);
+ script[0].str = "wifi_config";
+
+ if (gWmtDbgLvl >= WMT_LOG_DBG)
+ wmt_core_dump_data(&(script[0].cmd[0]), script[0].str,
+ script[0].cmdSz);
+
+ iRet = wmt_core_init_script(script, ARRAY_SIZE(script));
+
+ osal_free(cmd);
+
+ return iRet;
+}
+
+#if CFG_WMT_SDIO_DRIVING_SET
+static INT32 mtk_wcn_soc_set_sdio_driving(void)
+{
+ INT32 ret = 0;
+
+ unsigned long addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+ UINT32 drv_val = 0;
+
+ /*Get wmt config */
+ ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+ if (ret) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret);
+ return -1;
+ }
+ WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr);
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ /*Check if WMT.cfg exists */
+ if (pWmtGenConf->cfgExist == 0) {
+ WMT_INFO_FUNC("cfgExist == 0, skip config chip\n");
+ /*if WMT.cfg not existed, still return success and adopt the default value */
+ return 0;
+ }
+
+ drv_val = pWmtGenConf->sdio_driving_cfg;
+
+ /*Dump the sdio driving related info */
+ WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val);
+
+ sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */
+ sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */
+ sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */
+
+ ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table));
+
+ return ret;
+}
+#endif
+
+#if CFG_WMT_CRYSTAL_TIMING_SET
+static INT32 mtk_wcn_soc_crystal_triming_set(VOID)
+{
+ INT32 iRet = 0;
+ PUINT8 pbuf = NULL;
+ UINT32 bufLen = 0;
+ WMT_CTRL_DATA ctrlData;
+ UINT32 uCryTimOffset = 0x6D;
+ MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ INT8 cCrystalTimingOffset = 0x0;
+ UINT8 cCrystalTiming = 0x0;
+ INT32 iCrystalTiming = 0x0;
+ MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ UINT32 u4Res;
+
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ /**/ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET;
+ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI";
+ ctrlData.au4CtrlData[1] = (UINT32) &pbuf;
+ ctrlData.au4CtrlData[2] = (UINT32) &bufLen;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet != 0) {
+ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", wmt_ic_ops_soc.icId, iRet);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ iRet = -1;
+ } else {
+ WMT_DBG_FUNC("0x%x: nvram pBuf(0x%08x), bufLen(%d)\n", wmt_ic_ops_soc.icId, pbuf, bufLen);
+ if (bufLen < (uCryTimOffset + 1)) {
+ WMT_ERR_FUNC("0x%x: nvram len(%d) too short, crystalTimging value offset(%d)\n",
+ wmt_ic_ops_soc.icId, bufLen, uCryTimOffset);
+ bIsNvramExist = MTK_WCN_BOOL_FALSE;
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE;
+ cCrystalTimingOffset = 0x0;
+ cCrystalTiming = 0x0;
+ } else {
+ bIsNvramExist = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = *(pbuf + uCryTimOffset);
+ if (cCrystalTimingOffset & 0x80) {
+ bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE;
+ cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f;
+ }
+ WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", cCrystalTimingOffset,
+ bIsCrysTrimEnabled);
+ }
+ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT;
+ ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI";
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet != 0) {
+ WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", wmt_ic_ops_soc.icId, iRet);
+ iRet = -2;
+ } else {
+ WMT_DBG_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n", wmt_ic_ops_soc.icId);
+ }
+ }
+ if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) {
+ /*get CrystalTiming value before set it */
+ iRet =
+ wmt_core_tx(get_crystal_timing_script[0].cmd, get_crystal_timing_script[0].cmdSz, &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) {
+ WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].cmdSz);
+ iRet = -3;
+ goto done;
+ }
+ /* EVENT BUF */
+ osal_memset(get_crystal_timing_script[0].evt, 0, get_crystal_timing_script[0].evtSz);
+ iRet = wmt_core_rx(get_crystal_timing_script[0].evt, get_crystal_timing_script[0].evtSz, &u4Res);
+ if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) {
+ WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n",
+ get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].evtSz);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet = -4;
+ goto done;
+ }
+
+ iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f;
+ if (cCrystalTimingOffset & 0x40) {
+ /*nagative offset value */
+ iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128;
+ } else {
+ iCrystalTiming += cCrystalTimingOffset;
+ }
+ WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming);
+ if (iCrystalTiming > 0x7f)
+ cCrystalTiming = 0x7f;
+ else if (iCrystalTiming < 0)
+ cCrystalTiming = 0;
+ else
+ cCrystalTiming = iCrystalTiming;
+ WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming);
+ /* set_crystal_timing_script */
+ WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming;
+ WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming;
+
+ iRet = wmt_core_init_script(set_crystal_timing_script, osal_array_size(set_crystal_timing_script));
+ if (iRet) {
+ WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -5;
+ } else {
+ WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", WMT_SET_CRYSTAL_TRIMING_CMD[5]);
+ iRet =
+ wmt_core_init_script(get_crystal_timing_script, osal_array_size(get_crystal_timing_script));
+ if (iRet) {
+ WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet);
+ iRet = -6;
+ } else {
+ WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n",
+ WMT_GET_CRYSTAL_TRIMING_EVT[5]);
+ iRet = 0x0;
+ }
+ }
+ }
+done:
+ return iRet;
+}
+#endif
+
+#if CFG_WMT_MULTI_PATCH
+static INT32 mtk_wcn_soc_patch_info_prepare(VOID)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+static UINT32 mtk_wcn_soc_get_patch_num(VOID)
+{
+ ULONG ctrlPa1 = 0;
+ ULONG ctrlPa2 = 0;
+
+ wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2);
+ WMT_DBG_FUNC("patch total num = [%lu]\n", ctrlPa1);
+ return ctrlPa1;
+}
+
+static UINT32 mtk_wcn_soc_update_patch_version(VOID)
+{
+ return wmt_core_ctrl(WMT_CTRL_UPDATE_PATCH_VERSION, NULL, NULL);
+}
+
+static INT32 mtk_wcn_soc_normal_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte)
+{
+ INT32 iRet = -1;
+ UINT32 patchSizePerFrag = 0;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ UINT8 addressevtBuf[12];
+
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ pPatchBuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_INFO_FUNC("normal patch download patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ /*send wmt part patch address command */
+ if (wmt_ic_ops_soc.options & OPT_NORMAL_PATCH_DWN_0) {
+ /* ROMv2 patch RAM base */
+ WMT_PATCH_ADDRESS_CMD[8] = 0x40;
+ WMT_PATCH_P_ADDRESS_CMD[8] = 0xc8;
+ }
+ /*send wmt part patch address command */
+ if (wmt_ic_ops_soc.options & OPT_NORMAL_PATCH_DWN_1) {
+ /* ROMv3 patch RAM base */
+ WMT_PATCH_ADDRESS_CMD[8] = 0x08;
+ WMT_PATCH_ADDRESS_CMD[9] = 0x05;
+ WMT_PATCH_P_ADDRESS_CMD[8] = 0x2c;
+ WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b;
+ }
+
+ if (wmt_ic_ops_soc.options & OPT_NORMAL_PATCH_DWN_2) {
+ /* ROMv4 patch RAM base */
+ WMT_PATCH_ADDRESS_CMD[8] = 0x18;
+ WMT_PATCH_ADDRESS_CMD[9] = 0x05;
+ WMT_PATCH_P_ADDRESS_CMD[8] = 0x7c;
+ WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b;
+ }
+
+ if (wmt_ic_ops_soc.options & OPT_NORMAL_PATCH_DWN_3) {
+ /*send part patch address command */
+ WMT_PATCH_ADDRESS_CMD_NEW[5] = addressByte[0];
+ WMT_PATCH_ADDRESS_CMD_NEW[6] = addressByte[1];
+ WMT_PATCH_ADDRESS_CMD_NEW[7] = addressByte[2];
+ WMT_PATCH_ADDRESS_CMD_NEW[8] = addressByte[3];
+ WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_ADDRESS_CMD_NEW[5],
+ WMT_PATCH_ADDRESS_CMD_NEW[6],
+ WMT_PATCH_ADDRESS_CMD_NEW[7],
+ WMT_PATCH_ADDRESS_CMD_NEW[8]);
+ iRet = wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD_NEW[0], sizeof(WMT_PATCH_ADDRESS_CMD_NEW),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD_NEW))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ return -1;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT_NEW), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT_NEW))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ addressevtBuf[0], addressevtBuf[1], addressevtBuf[2],
+ addressevtBuf[3], addressevtBuf[4],
+ WMT_PATCH_ADDRESS_EVT_NEW[0], WMT_PATCH_ADDRESS_EVT_NEW[1],
+ WMT_PATCH_ADDRESS_EVT_NEW[2], WMT_PATCH_ADDRESS_EVT_NEW[3],
+ WMT_PATCH_ADDRESS_EVT_NEW[4]);
+ mtk_wcn_stp_dbg_dump_package();
+ return -1;
+ }
+ goto patch_download;
+ }
+
+ /*send wmt part patch address command */
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ return -1;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ mtk_wcn_stp_dbg_dump_package();
+ return -1;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n");
+ return -1;
+ }
+#endif
+
+ /*send part patch address command */
+ WMT_PATCH_P_ADDRESS_CMD[12] = addressByte[0];
+ WMT_PATCH_P_ADDRESS_CMD[13] = addressByte[1];
+ WMT_PATCH_P_ADDRESS_CMD[14] = addressByte[2];
+ WMT_PATCH_P_ADDRESS_CMD[15] = addressByte[3];
+ WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x",
+ WMT_PATCH_P_ADDRESS_CMD[12],
+ WMT_PATCH_P_ADDRESS_CMD[13], WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]);
+ iRet =
+ wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d)\n", iRet, u4Res);
+ return -1;
+ }
+ osal_memset(addressevtBuf, 0, sizeof(addressevtBuf));
+ iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res);
+ mtk_wcn_stp_dbg_dump_package();
+ return -1;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n");
+ return -1;
+ }
+#endif
+
+patch_download:
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD));
+
+ /* iRet =
+ *(*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD),
+ *&u4Res);
+ */
+ iRet =
+ wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%lu, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet = -1;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%lu, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%lu, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT),
+ u4Res, iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet = -1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res,
+ evtBuf[0],
+ evtBuf[1],
+ evtBuf[2],
+ evtBuf[3],
+ evtBuf[4]);
+ WMT_ERR_FUNC("wmt_core: exp(%lu):[%02X,%02X,%02X,%02X,%02X]\n",
+ sizeof(WMT_PATCH_EVT),
+ WMT_PATCH_EVT[0],
+ WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2],
+ WMT_PATCH_EVT[3],
+ WMT_PATCH_EVT[4]);
+ iRet = -1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%lu, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ return -1;
+
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_pda_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte)
+{
+#define PDAHDRLEN 12
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ INT32 iRet = -1;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT32 patchSizePerFrag = 0;
+ UINT32 offset;
+ UINT8 pdaHdr[PDAHDRLEN];
+
+ /* PDA download address, LSB */
+ WMT_PATCH_PDA_CFG_CMD[5] = addressByte[0];
+ WMT_PATCH_PDA_CFG_CMD[6] = addressByte[1];
+ WMT_PATCH_PDA_CFG_CMD[7] = addressByte[2];
+ WMT_PATCH_PDA_CFG_CMD[8] = addressByte[3];
+
+ /* PDA download size, LSB */
+ WMT_PATCH_PDA_CFG_CMD[9] = (patchSize & 0x000000FF);
+ WMT_PATCH_PDA_CFG_CMD[10] = (patchSize & 0x0000FF00) >> 8;
+ WMT_PATCH_PDA_CFG_CMD[11] = (patchSize & 0x00FF0000) >> 16;
+ WMT_PATCH_PDA_CFG_CMD[12] = (patchSize & 0xFF000000) >> 24;
+
+ iRet = wmt_core_tx((PUINT8) &WMT_PATCH_PDA_CFG_CMD[0], sizeof(WMT_PATCH_PDA_CFG_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_PDA_CFG_CMD))) {
+ WMT_ERR_FUNC("wmt_core:wmt part patch PDA config CMD fail(%d),size(%d)\n",
+ iRet, u4Res);
+ return -1;
+ }
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_PDA_CFG_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_PDA_CFG_EVT))) {
+ WMT_ERR_FUNC("wmt_core:wmt patch PDA config EVT fail(%d),size(%d)\n",
+ iRet, u4Res);
+ WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4],
+ WMT_PATCH_PDA_CFG_EVT[0], WMT_PATCH_PDA_CFG_EVT[1],
+ WMT_PATCH_PDA_CFG_EVT[2], WMT_PATCH_PDA_CFG_EVT[3],
+ WMT_PATCH_PDA_CFG_EVT[4]);
+ mtk_wcn_stp_dbg_dump_package();
+ return -1;
+ }
+
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ osal_memset(pdaHdr, 0, PDAHDRLEN);
+ pdaHdr[0] = (patchSize + PDAHDRLEN) & 0x000000FF;
+ pdaHdr[1] = ((patchSize + PDAHDRLEN) & 0x0000FF00) >> 8;
+ pdaHdr[2] = ((patchSize + PDAHDRLEN) & 0x00FF0000) >> 16;
+ pdaHdr[3] = ((patchSize + PDAHDRLEN) & 0xFF000000) >> 24;
+
+ iRet = wmt_core_tx(pdaHdr, PDAHDRLEN, &u4Res, MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != PDAHDRLEN)) {
+ WMT_ERR_FUNC("wmt_core: set length:%d fails, u4Res:%d\n", PDAHDRLEN, u4Res);
+ return -1;
+ }
+
+ /* send all fragments */
+ offset = 0;
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ } else
+ fragSize = patchSizePerFrag;
+
+ iRet = wmt_core_tx(pPatchBuf + offset, fragSize, &u4Res, MTK_WCN_BOOL_TRUE);
+ if (iRet || (u4Res != fragSize)) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n",
+ fragSeq, fragSize, u4Res, iRet);
+ iRet = -1;
+ break;
+ }
+
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, fragSize, u4Res);
+
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ return -1;
+
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_patch_dwn(UINT32 index)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr = NULL;
+ PUINT8 pBuf = NULL;
+ PUINT8 pPatchBuf = NULL;
+ PUINT8 patchBuildTimeAddr;
+ UINT32 patchSize;
+ PINT8 cDataTime = NULL;
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ WMT_CTRL_DATA ctrlData;
+ P_CONSYS_EMI_ADDR_INFO emiInfo;
+ UINT8 addressByte[4];
+
+ /*1.check hardware information */
+ if (gp_soc_info == NULL) {
+ WMT_ERR_FUNC("null gp_soc_info!\n");
+ return -1;
+ }
+
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = index + 1;
+ ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName;
+ ctrlData.au4CtrlData[2] = (SIZE_T)&addressByte;
+ iRet = wmt_ctrl(&ctrlData);
+ WMT_DBG_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName);
+
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH_INFO fail:%d\n", iRet);
+ goto done;
+ }
+
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (SIZE_T)NULL;
+ ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName;
+ ctrlData.au4CtrlData[2] = (SIZE_T)&pBuf;
+ ctrlData.au4CtrlData[3] = (SIZE_T)&patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ pPatchBuf = osal_malloc(patchSize);
+ if (pPatchBuf == NULL) {
+ WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n");
+ return -2;
+ }
+ osal_memcpy(pPatchBuf, pBuf, patchSize);
+ /* check patch file information */
+ patchHdr = (P_WMT_PATCH) pPatchBuf;
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+
+ cDataTime[15] = '\0';
+ if (index == 0) {
+ WMT_INFO_FUNC("[Patch]BuiltTime=%s,HVer=0x%x,SVer=0x%x,PhVer=0x%04x,Platform=%c%c%c%c\n",
+ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8),
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8),
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16),
+ patchHdr->ucPLat[0], patchHdr->ucPLat[1],
+ patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ }
+ osal_memcpy(&gp_soc_patch_info, patchHdr, osal_sizeof(WMT_PATCH));
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -1;
+ goto done;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pPatchBuf += sizeof(WMT_PATCH);
+
+ if (wmt_ic_ops_soc.options & OPT_PATCH_CHECKSUM) {
+ /* remove patch checksum:
+ * |<-patch checksum: 2Bytes->|<-patch body: X Bytes (X=patchSize)--->|
+ */
+ pPatchBuf += BCNT_PATCH_BUF_CHECKSUM;
+ patchSize -= BCNT_PATCH_BUF_CHECKSUM;
+ }
+
+ emiInfo = mtk_wcn_consys_soc_get_emi_phy_add();
+ if (!emiInfo) {
+ WMT_ERR_FUNC("get emi info fail!\n");
+ iRet = -1;
+ goto done;
+ }
+
+ if (emiInfo->pda_dl_patch_flag)
+ iRet = mtk_wcn_soc_pda_patch_dwn(pPatchBuf, patchSize, addressByte);
+ else
+ iRet = mtk_wcn_soc_normal_patch_dwn(pPatchBuf, patchSize, addressByte);
+
+ /* Set FW patch buildtime into EMI for debugging */
+ if (emiInfo->emi_ram_mcu_buildtime_offset) {
+ patchBuildTimeAddr = ioremap_nocache(emiInfo->emi_ap_phy_addr +
+ emiInfo->emi_patch_mcu_buildtime_offset, PATCH_BUILD_TIME_SIZE);
+ if (patchBuildTimeAddr) {
+ osal_memcpy_toio(patchBuildTimeAddr, cDataTime, PATCH_BUILD_TIME_SIZE);
+ iounmap(patchBuildTimeAddr);
+ } else
+ WMT_ERR_FUNC("ioremap_nocache fail\n");
+ }
+done:
+ if (patchHdr != NULL) {
+ osal_free(patchHdr);
+ pPatchBuf = NULL;
+ patchHdr = NULL;
+ }
+
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = index + 1;
+ wmt_ctrl(&ctrlData);
+
+ return iRet;
+}
+
+#else
+static INT32 mtk_wcn_soc_patch_dwn(VOID)
+{
+ INT32 iRet = -1;
+ P_WMT_PATCH patchHdr;
+ PUINT8 pbuf;
+ UINT32 patchSize;
+ UINT32 fragSeq;
+ UINT32 fragNum;
+ UINT16 fragSize = 0;
+ UINT16 cmdLen;
+ UINT32 offset;
+ UINT32 u4Res;
+ UINT8 evtBuf[8];
+ PINT8 cDataTime = NULL;
+ /*PINT8 cPlat = NULL; */
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchVer = 0;
+ UINT32 patchSizePerFrag = 0;
+ WMT_CTRL_DATA ctrlData;
+
+ /*1.check hardware information */
+ if (gp_soc_info == NULL) {
+ WMT_ERR_FUNC("null gp_soc_info!\n");
+ return -1;
+ }
+ /* <2> search patch and read patch content */
+ /* <2.1> search patch */
+ ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet == 0) {
+ /* patch with correct Hw Ver Major Num found */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME;
+ ctrlData.au4CtrlData[0] = (UINT32) &gFullPatchName;
+ iRet = wmt_ctrl(&ctrlData);
+
+ WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName);
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (UINT32) NULL;
+ ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName;
+
+ } else {
+ iRet -= 1;
+ return iRet;
+ }
+ ctrlData.au4CtrlData[2] = (UINT32) &pbuf;
+ ctrlData.au4CtrlData[3] = (UINT32) &patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet -= 1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */
+ pbuf += BCNT_PATCH_BUF_HEADROOM;
+ /* patch file with header:
+ * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->|
+ */
+ patchHdr = (P_WMT_PATCH) pbuf;
+ /* check patch file information */
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchVer = patchHdr->u4PatchVer;
+ /*cPlat = &patchHdr->ucPLat[0]; */
+
+ cDataTime[15] = '\0';
+ WMT_DBG_FUNC("===========================================\n");
+ WMT_INFO_FUNC("[ConsysPatch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n",
+ cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8),
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8),
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16),
+ patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8));
+ WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8));
+ WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n",
+ ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16));
+ WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1],
+ patchHdr->ucPLat[2], patchHdr->ucPLat[3]);
+ WMT_DBG_FUNC("===========================================\n");
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(WMT_PATCH)) {
+ WMT_ERR_FUNC("error patch size\n");
+ return -1;
+ }
+ patchSize -= sizeof(WMT_PATCH);
+ pbuf += sizeof(WMT_PATCH);
+ patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE;
+ /* reserve 1st patch cmd space before patch body
+ * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->|
+ */
+ pbuf -= sizeof(WMT_PATCH_CMD);
+
+ fragNum = patchSize / patchSizePerFrag;
+ fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1;
+
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+
+ /* send all fragments */
+ offset = sizeof(WMT_PATCH_CMD);
+ fragSeq = 0;
+ while (fragSeq < fragNum) {
+ WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum);
+ if (fragSeq == (fragNum - 1)) {
+ /* last fragment */
+ fragSize = patchSize - fragSeq * patchSizePerFrag;
+ WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST;
+ } else {
+ fragSize = patchSizePerFrag;
+ WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID;
+ }
+ /* update length field in CMD:flag+frag */
+ cmdLen = 1 + fragSize;
+ osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2);
+ /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */
+ osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD));
+
+ /* iRet =
+ * (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD),
+ * &u4Res);
+ */
+ iRet =
+ wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), &u4Res,
+ MTK_WCN_BOOL_FALSE);
+ if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) {
+ WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq,
+ fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet);
+ iRet -= 1;
+ break;
+ }
+ WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n",
+ fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res);
+
+ osal_memset(evtBuf, 0, sizeof(evtBuf));
+ /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */
+ iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res);
+ if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) {
+ WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT),
+ u4Res, iRet);
+ mtk_wcn_stp_dbg_dump_package();
+ iRet -= 1;
+ break;
+ }
+#if CFG_CHECK_WMT_RESULT
+ if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) {
+ WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ u4Res,
+ evtBuf[0],
+ evtBuf[1],
+ evtBuf[2],
+ evtBuf[3],
+ evtBuf[4]);
+ WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n",
+ sizeof(WMT_PATCH_EVT),
+ WMT_PATCH_EVT[0],
+ WMT_PATCH_EVT[1],
+ WMT_PATCH_EVT[2],
+ WMT_PATCH_EVT[3],
+ WMT_PATCH_EVT[4]);
+ iRet -= 1;
+ break;
+ }
+#endif
+ WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res);
+ offset += patchSizePerFrag;
+ ++fragSeq;
+ }
+
+ WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n",
+ iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail");
+
+ if (fragSeq != fragNum)
+ iRet -= 1;
+done:
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL);
+
+ return iRet;
+}
+
+#endif
+
+INT32 mtk_wcn_soc_rom_patch_dwn(UINT32 ip_ver, UINT32 fw_ver)
+{
+ INT32 iRet = -1;
+ struct wmt_rom_patch *patchHdr = NULL;
+ PUINT8 pBuf = NULL;
+ PUINT8 pPatchBuf = NULL;
+ UINT32 patchSize;
+ UINT8 addressByte[4];
+ PINT8 cDataTime = NULL;
+ UINT16 u2HwVer = 0;
+ UINT16 u2SwVer = 0;
+ UINT32 u4PatchType = 0;
+ UINT32 type;
+ UINT32 patchEmiOffset;
+ PUINT8 patchAddr;
+ UINT32 patchBuildTimeOffset = 0;
+ PUINT8 patchBuildTimeAddr;
+ WMT_CTRL_DATA ctrlData;
+ P_CONSYS_EMI_ADDR_INFO emiInfo;
+
+ for (type = WMTDRV_TYPE_BT; type < WMTDRV_TYPE_ANT; type++) {
+ osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName));
+
+ ctrlData.ctrlId = WMT_CTRL_GET_ROM_PATCH_INFO;
+ ctrlData.au4CtrlData[0] = type;
+ ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName;
+ ctrlData.au4CtrlData[2] = (SIZE_T)&addressByte;
+ ctrlData.au4CtrlData[3] = ip_ver;
+ ctrlData.au4CtrlData[4] = fw_ver;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet > 0) {
+ WMT_INFO_FUNC("There is no need to download (%d) type patch!\n", type);
+ continue;
+ } else if (iRet < 0) {
+ WMT_ERR_FUNC("failed to get patch (type: %d, ret: %d)\n", type, iRet);
+ goto done;
+ }
+
+ /* <2.2> read patch content */
+ ctrlData.ctrlId = WMT_CTRL_GET_PATCH;
+ ctrlData.au4CtrlData[0] = (SIZE_T)NULL;
+ ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName;
+ ctrlData.au4CtrlData[2] = (SIZE_T)&pBuf;
+ ctrlData.au4CtrlData[3] = (SIZE_T)&patchSize;
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet);
+ iRet = -1;
+ goto done;
+ }
+
+ /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->|
+ * patch file with header:
+ * |<-patch header: 32 Bytes->|<-patch body: X Bytes ----->|
+ */
+ pPatchBuf = osal_malloc(patchSize);
+ if (pPatchBuf == NULL) {
+ WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n");
+ iRet = -2;
+ goto done;
+ }
+ osal_memcpy(pPatchBuf, pBuf, patchSize);
+ /* check patch file information */
+ patchHdr = (struct wmt_rom_patch *) pPatchBuf;
+
+ cDataTime = patchHdr->ucDateTime;
+ u2HwVer = patchHdr->u2HwVer;
+ u2SwVer = patchHdr->u2SwVer;
+ u4PatchType = patchHdr->u4PatchType;
+
+ cDataTime[15] = '\0';
+ WMT_INFO_FUNC("[RomPatch]BTime=%s,HVer=0x%x,SVer=0x%x,Platform=%c%c%c%c\n,Type=%x\n",
+ cDataTime,
+ ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8),
+ ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8),
+ patchHdr->ucPLat[0], patchHdr->ucPLat[1],
+ patchHdr->ucPLat[2], patchHdr->ucPLat[3],
+ u4PatchType);
+
+ /* remove patch header:
+ * |<-patch body: X Bytes (X=patchSize)--->|
+ */
+ if (patchSize < sizeof(struct wmt_rom_patch)) {
+ WMT_ERR_FUNC("error patch size\n");
+ iRet = -3;
+ goto done;
+ }
+ patchSize -= sizeof(struct wmt_rom_patch);
+ pPatchBuf += sizeof(struct wmt_rom_patch);
+
+ patchEmiOffset = (addressByte[2] << 16) | (addressByte[1] << 8) | addressByte[0];
+
+ emiInfo = mtk_wcn_consys_soc_get_emi_phy_add();
+ if (!emiInfo) {
+ WMT_ERR_FUNC("get emi info fail!\n");
+ iRet = -4;
+ goto done;
+ }
+
+ if (patchEmiOffset + patchSize < emiInfo->emi_size) {
+ WMT_INFO_FUNC("[Rom Patch] emiInfo: emi_ap_phy_addr=0x%x emi_size=%d emi_phy_addr=0x%x\n",
+ emiInfo->emi_ap_phy_addr, emiInfo->emi_size, emiInfo->emi_phy_addr);
+ WMT_INFO_FUNC("[Rom Patch]Name=%s,EmiOffset=0x%x,Size=0x%x\n",
+ gFullPatchName, patchEmiOffset, patchSize);
+
+ if (type == WMTDRV_TYPE_WIFI) {
+ wmt_lib_mpu_lock_aquire();
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(false);
+ }
+
+ patchAddr = ioremap_nocache(emiInfo->emi_ap_phy_addr + patchEmiOffset, patchSize);
+ WMT_INFO_FUNC("physAddr=0x%x, size=%d virAddr=0x%p\n",
+ emiInfo->emi_ap_phy_addr + patchEmiOffset, patchSize, patchAddr);
+ if (patchAddr) {
+ osal_memcpy_toio(patchAddr, pPatchBuf, patchSize);
+ iounmap(patchAddr);
+ } else
+ WMT_ERR_FUNC("ioremap_nocache fail\n");
+
+ if (type == WMTDRV_TYPE_BT)
+ patchBuildTimeOffset = emiInfo->emi_ram_bt_buildtime_offset;
+ else if (type == WMTDRV_TYPE_WIFI)
+ patchBuildTimeOffset = emiInfo->emi_ram_wifi_buildtime_offset;
+ else if (type == WMTDRV_TYPE_WMT)
+ patchBuildTimeOffset = emiInfo->emi_ram_mcu_buildtime_offset;
+ /* Set ROM patch buildtime into EMI for debugging */
+ if (patchBuildTimeOffset) {
+ patchBuildTimeAddr = ioremap_nocache(emiInfo->emi_ap_phy_addr +
+ patchBuildTimeOffset, PATCH_BUILD_TIME_SIZE);
+ if (patchBuildTimeAddr) {
+ osal_memcpy_toio(patchBuildTimeAddr, cDataTime,
+ PATCH_BUILD_TIME_SIZE);
+ iounmap(patchBuildTimeAddr);
+ } else
+ WMT_ERR_FUNC("ioremap_nocache fail\n");
+ }
+
+ if (type == WMTDRV_TYPE_WIFI) {
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+ wmt_lib_mpu_lock_release();
+ }
+ } else
+ WMT_ERR_FUNC("The rom patch is too big to overflow on EMI\n");
+
+done:
+ if (patchHdr != NULL) {
+ osal_free(patchHdr);
+ pPatchBuf = NULL;
+ patchHdr = NULL;
+ }
+
+ /* WMT_CTRL_FREE_PATCH always return 0 */
+ ctrlData.ctrlId = WMT_CTRL_FREE_PATCH;
+ ctrlData.au4CtrlData[0] = type;
+ wmt_ctrl(&ctrlData);
+ if (iRet)
+ break;
+ }
+
+ return iRet;
+}
+
+
+VOID mtk_wcn_soc_restore_wifi_cal_result(VOID)
+{
+#if CFG_CALIBRATION_BACKUP_RESTORE
+ P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add();
+ PUINT8 wifiCalAddr = NULL;
+
+ if (!emiInfo) {
+ WMT_ERR_FUNC("Get EMI info failed.\n");
+ return;
+ }
+
+ if (mtk_consys_is_calibration_backup_restore_support() == 0 ||
+ mtk_wcn_stp_assert_flow_get() == 0) {
+ WMT_INFO_FUNC(
+ "Skip restore, chip id=%x mtk_wcn_stp_assert_flow_get()=%d\n",
+ wmt_ic_ops_soc.icId, mtk_wcn_stp_assert_flow_get());
+ return;
+ }
+ /* Disable Wi-Fi MPU to touch Wi-Fi calibration data */
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(false);
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_RESTORE_CAL_RESULT);
+ /* Write Wi-Fi data to EMI */
+ if (gWiFiCalAddrOffset + gWiFiCalSize < emiInfo->emi_size) {
+ wifiCalAddr = ioremap_nocache(emiInfo->emi_ap_phy_addr + gWiFiCalAddrOffset,
+ gWiFiCalSize);
+ if (wifiCalAddr) {
+ osal_memcpy_toio(wifiCalAddr, gWiFiCalResult, gWiFiCalSize);
+ iounmap(wifiCalAddr);
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_RESULT);
+ } else {
+ WMT_ERR_FUNC("ioremap_nocache fail\n");
+ }
+ }
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+#else
+ WMT_INFO_FUNC("Skip restore because it is not supported.\n");
+#endif
+}
+
+#if CFG_CALIBRATION_BACKUP_RESTORE
+/*
+ * To restore calibration data
+ * For BT, send by STP command.
+ * For Wi-Fi write to EMI directly.
+ *
+ * Return value:
+ * 0: restore success
+ * 1: recalibration happened. Caller need to re-get calibration data
+ * < 0: fail. Caller need to re-send calibration command.
+ */
+static INT32 mtk_wcn_soc_calibration_restore(void)
+{
+ INT32 iRet = 0;
+ PUINT8 evtBuf = NULL;
+ UINT32 u4Res;
+ UINT16 len = 0;
+
+ /* Allocate event buffer */
+ evtBuf = osal_malloc(CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE);
+ if (evtBuf == NULL) {
+ WMT_ERR_FUNC("allocate event buffer failed\n");
+ return -1;
+ }
+
+ if ((gBTCalResultSize != 0 && gBTCalResult != NULL &&
+ (gBTCalResultSize + sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD)) < CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE) &&
+ (gWiFiCalResult != NULL && gWiFiCalSize != 0 && gWiFiCalAddrOffset != 0)) {
+ WMT_INFO_FUNC("Send calibration data size=%d\n", gBTCalResultSize);
+ WMT_INFO_FUNC("Send calibration data start\n");
+ /* Construct send calibration cmd for BT
+ * Format: 0x01 0x14 [ X+3 (2 bytes)] 0x02
+ * [BT data len (2 bytes)] [BT data (X bytes)]
+ */
+ /* clear buffer */
+ osal_memset(&evtBuf[0], 0, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE);
+ /* copy cmd template */
+ osal_memcpy(
+ &evtBuf[0],
+ WMT_CORE_SEND_RF_CALIBRATION_CMD,
+ sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD));
+ /* Setup length to byte 2&3 */
+ len = gBTCalResultSize + 3;
+ osal_memcpy(&evtBuf[2], &len, 2);
+ osal_memcpy(&evtBuf[5], &gBTCalResultSize, 2);
+ osal_memcpy(&evtBuf[7], gBTCalResult, gBTCalResultSize);
+ len = sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD) + gBTCalResultSize;
+ iRet = wmt_core_tx(evtBuf, len, &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || u4Res != len) {
+ WMT_ERR_FUNC("Send calibration data TX failed (%d), %d bytes writes, expect %d\n",
+ iRet, u4Res, len);
+ iRet = -4;
+ goto restore_end;
+ }
+ /* RX: 02 14 02 00 XX 02
+ * XX means status
+ * 0: OK
+ * 1: recalibration happened
+ */
+ iRet = wmt_core_rx(evtBuf, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE, &u4Res);
+ WMT_INFO_FUNC("Send calibration data end\n");
+ if (iRet || u4Res != sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK)) {
+ WMT_ERR_FUNC("Send calibration data event failed(%d), %d bytes get, expect %lu\n",
+ iRet, u4Res, sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK));
+ iRet = -5;
+ goto restore_end;
+ }
+ /* Check return */
+ if (osal_memcmp(&evtBuf[0], WMT_CORE_SEND_RF_CALIBRATION_EVT_OK,
+ sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK)) == 0) {
+ WMT_INFO_FUNC("Send calibration data OK.\n");
+ iRet = 0;
+ } else if (osal_memcmp(&evtBuf[0], WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL,
+ sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL)) == 0) {
+ WMT_INFO_FUNC("Recalibration happened. Re-get calibration data\n");
+ iRet = 1;
+ goto restore_end;
+ } else {
+ /* Do calibration */
+ WMT_ERR_FUNC("Send calibration event error. 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]);
+ iRet = -5;
+ goto restore_end;
+ }
+ } else {
+ WMT_ERR_FUNC("Did not restore calibration data. Buf=0x%p, size=%d\n",
+ gBTCalResult, gBTCalResultSize);
+ iRet = -6;
+ goto restore_end;
+ }
+
+restore_end:
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(false);
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_CMD);
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+ osal_free(evtBuf);
+ return iRet;
+}
+
+/*
+ * To backup calibration data
+ * For BT, get data by STP command.
+ * For Wi-Fi, get EMI offset and length from STP command and then
+ * backup data from EMI
+ *
+ * Return value:
+ * 0: backup success
+ * < 0: fail
+ */
+static INT32 mtk_wcn_soc_calibration_backup(void)
+{
+ INT32 iRet = 0;
+ PUINT8 evtBuf;
+ UINT32 u4Res;
+ UINT16 len = 0;
+ P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add();
+ UINT32 wifiOffset = 0;
+ UINT32 wifiLen = 0;
+ void __iomem *virWiFiAddrBase;
+
+ /* Allocate RX event buffer */
+ evtBuf = osal_malloc(CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE);
+ if (evtBuf == NULL) {
+ WMT_ERR_FUNC("Allocate event buffer failed\n");
+ return -1;
+ }
+ /* Get calibration data TX */
+ iRet = wmt_core_tx(WMT_CORE_GET_RF_CALIBRATION_CMD,
+ sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD),
+ &u4Res, MTK_WCN_BOOL_FALSE);
+ if (iRet || u4Res != sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD)) {
+ WMT_ERR_FUNC("Write get calibration cmd failed(%d), exp: %lu but write %d\n",
+ iRet, sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD), u4Res);
+ goto get_calibration_fail;
+ }
+ osal_memset(&evtBuf[0], 0, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE);
+ iRet = wmt_core_rx(evtBuf, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE, &u4Res);
+ /* RX expected format:
+ * 02 14 [X+14 (2 bytes)] 00 03
+ * [BT size = X (2 bytes)] [BT Cal. Data (X bytes)]
+ * [WiFi Size = 8 (2 bytes)] [WiFi Offset (4 bytes)] [WiFi len(4 bytes)]
+ */
+ if (iRet || u4Res < 8) {
+ WMT_ERR_FUNC("Get calibration event failed(%d), get %d bytes\n", iRet, u4Res);
+ goto get_calibration_fail;
+ }
+ /* Check data validaness */
+ if (evtBuf[0] != 0x02 || evtBuf[1] != 0x14 ||
+ evtBuf[4] != 0x00 || evtBuf[5] != 0x03) {
+ WMT_ERR_FUNC("Get calibration event error. 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x\n",
+ evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]);
+ goto get_calibration_fail;
+ }
+ /* Get data success, backup it.
+ * Data size is not the same as previous, realloc memory
+ */
+ osal_memcpy(&len, &evtBuf[6], 2);
+ if (len != gBTCalResultSize) {
+ gBTCalResultSize = len;
+ if (gBTCalResult != NULL) {
+ osal_free(gBTCalResult);
+ gBTCalResult = NULL;
+ }
+ }
+ if (gBTCalResult == NULL)
+ gBTCalResult = osal_malloc(gBTCalResultSize);
+ if (gBTCalResult == NULL) {
+ WMT_ERR_FUNC("Allocate BT calibration buffer failed.\n");
+ goto get_calibration_fail;
+ }
+ osal_memcpy(gBTCalResult, &evtBuf[8], gBTCalResultSize);
+ /* Get Wi-Fi info */
+ osal_memcpy(&wifiOffset, &evtBuf[10 + gBTCalResultSize], 4);
+ osal_memcpy(&wifiLen, &evtBuf[14 + gBTCalResultSize], 4);
+ if (wifiLen != gWiFiCalSize) {
+ gWiFiCalSize = wifiLen;
+ if (gWiFiCalResult != NULL) {
+ osal_free(gWiFiCalResult);
+ gWiFiCalResult = NULL;
+ }
+ }
+ if (gWiFiCalResult == NULL)
+ gWiFiCalResult = osal_malloc(gWiFiCalSize);
+ if (gWiFiCalResult == NULL) {
+ WMT_ERR_FUNC("Allocate Wi-Fi calibration buffer failed.\n");
+ goto get_calibration_fail;
+ }
+ /* Start to backup Wi-Fi data */
+ if (!emiInfo) {
+ WMT_ERR_FUNC("get emi info fail!\n");
+ goto get_calibration_fail;
+ }
+ /* Before copy, disable Wi-Fi MPU to access EMI */
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(false);
+ WMT_STEP_DO_ACTIONS_FUNC(
+ STEP_TRIGGER_POINT_POWER_ON_AFTER_BT_WIFI_CALIBRATION);
+ gWiFiCalAddrOffset = wifiOffset;
+ virWiFiAddrBase = ioremap_nocache(
+ emiInfo->emi_ap_phy_addr + gWiFiCalAddrOffset,
+ gWiFiCalSize);
+ if (virWiFiAddrBase) {
+ osal_memcpy_fromio(gWiFiCalResult, virWiFiAddrBase, gWiFiCalSize);
+ iounmap(virWiFiAddrBase);
+ } else {
+ WMT_ERR_FUNC("Remap Wi-Fi EMI fail: offset=%d size=%d\n",
+ gWiFiCalAddrOffset, gWiFiCalSize);
+ goto get_calibration_fail;
+ }
+ /* Enable Wi-Fi MPU after finished. */
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+ WMT_INFO_FUNC("gBTCalResultSize=%d gWiFiCalResult=0x%p gWiFiCalSize=%d gWiFiCalAddrOffset=0x%x\n",
+ gBTCalResultSize,
+ gWiFiCalResult,
+ gWiFiCalSize,
+ gWiFiCalAddrOffset);
+ osal_free(evtBuf);
+ return 0;
+get_calibration_fail:
+ WMT_ERR_FUNC("Get calibration failed.\n");
+ if (emiInfo) {
+ WMT_ERR_FUNC("emiInfo: emi_ap_phy_addr=0x%x emi_size=%d emi_phy_addr=0x%x\n",
+ emiInfo->emi_ap_phy_addr,
+ emiInfo->emi_size,
+ emiInfo->emi_phy_addr);
+ }
+ WMT_ERR_FUNC("gBTCalResultSize=%d gWiFiCalResult=0x%p gWiFiCalSize=%d gWiFiCalAddrOffset=0x%x\n",
+ gBTCalResultSize, gWiFiCalResult,
+ gWiFiCalSize, gWiFiCalAddrOffset);
+ if (gBTCalResult != NULL) {
+ osal_free(gBTCalResult);
+ gBTCalResult = NULL;
+ }
+ gBTCalResultSize = 0;
+ if (gWiFiCalResult != NULL) {
+ osal_free(gWiFiCalResult);
+ gWiFiCalResult = NULL;
+ }
+ gWiFiCalSize = 0;
+ gWiFiCalAddrOffset = 0;
+ /* Enable Wi-Fi MPU after finished. */
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+ osal_free(evtBuf);
+ return -1;
+}
+#endif
+
+static INT32 mtk_wcn_soc_do_calibration(void)
+{
+ INT32 iRet = 0;
+
+#if CFG_CALIBRATION_BACKUP_RESTORE
+ /* When chip reset is caused by assert, skip calibration.
+ * Restore old data.
+ */
+ if (mtk_consys_is_calibration_backup_restore_support() == 0 ||
+ mtk_wcn_stp_assert_flow_get() == 0) {
+ WMT_INFO_FUNC(
+ "Skip restore, chip id=%x mtk_wcn_stp_assert_flow_get()=%d\n",
+ wmt_ic_ops_soc.icId, mtk_wcn_stp_assert_flow_get());
+ goto do_calibration;
+ }
+
+ iRet = mtk_wcn_soc_calibration_restore();
+ if (iRet == 0) {
+ WMT_INFO_FUNC("Restore success\n");
+ return 0;
+ } else if (iRet == 1) {
+ WMT_INFO_FUNC("Recal happened. Re-get calibration data.\n");
+ goto get_calibration;
+ } else
+ /* For all other case, re-cali. */
+ WMT_ERR_FUNC("Re-cal because restore fail(%d)\n", iRet);
+
+do_calibration:
+#endif /* CFG_CALIBRATION_BACKUP_RESTORE */
+ /* Do calibration */
+ WMT_INFO_FUNC("Calibration start\n");
+ iRet = wmt_core_init_script(
+ calibration_table,
+ osal_array_size(calibration_table));
+ WMT_INFO_FUNC("Calibration end\n");
+ if (iRet) {
+ #if CFG_CALIBRATION_BACKUP_RESTORE
+ /* Calibration failed. Clear backup data. */
+ if (gBTCalResult != NULL) {
+ osal_free(gBTCalResult);
+ gBTCalResult = NULL;
+ }
+ gBTCalResultSize = 0;
+ if (gWiFiCalResult != NULL) {
+ osal_free(gWiFiCalResult);
+ gWiFiCalResult = NULL;
+ }
+ gWiFiCalSize = 0;
+ gWiFiCalAddrOffset = 0;
+ #endif
+ WMT_ERR_FUNC("do calibration failed (%d)\n", iRet);
+ return -1;
+ }
+
+#if CFG_CALIBRATION_BACKUP_RESTORE
+ if (mtk_consys_is_calibration_backup_restore_support() == 0)
+ return 0;
+
+get_calibration:
+ iRet = mtk_wcn_soc_calibration_backup();
+ /* Backup process should not influence power on sequence.
+ * Hence, even it return error, just record it and
+ * report calibration success.
+ */
+ if (iRet == 0)
+ WMT_INFO_FUNC("Backup success\n");
+ else
+ WMT_ERR_FUNC("Backup failed(%d)\n", iRet);
+#endif
+ return 0;
+}
+
+static INT32 mtk_wcn_soc_calibration(void)
+{
+ INT32 iRet = -1;
+ INT32 iCalRet = -1;
+ unsigned long ctrlPa1;
+ unsigned long ctrlPa2;
+
+ /* Turn on BT/Wi-Fi */
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_ON;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WIFI_PALDO;
+ ctrlPa2 = PALDO_ON;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+
+ WMT_INFO_FUNC("mtk_wcn_soc_do_calibration start\n");
+ iCalRet = mtk_wcn_soc_do_calibration();
+ WMT_INFO_FUNC("mtk_wcn_soc_do_calibration end\n");
+
+ /* Turn off BT/Wi-Fi */
+ ctrlPa1 = BT_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+ ctrlPa1 = WIFI_PALDO;
+ ctrlPa2 = PALDO_OFF;
+ iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2);
+
+ if (iCalRet) {
+ /* pwrap_read(0x0210,&ctrlPa1); */
+ /* pwrap_read(0x0212,&ctrlPa2); */
+ /* WMT_ERR_FUNC("power status: 210:(%d),212:(%d)!\n", ctrlPa1, ctrlPa2); */
+ WMT_ERR_FUNC("calibration_table fail(%d)\n", iCalRet);
+ return -1;
+ }
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c
new file mode 100644
index 0000000000000000000000000000000000000000..13ebe4c8ad096b68842a6a3dae247d9e3289656d
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c
@@ -0,0 +1,3382 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[WMT-LIB]"
+
+
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_dbg.h"
+
+#include "wmt_dev.h"
+#include "wmt_lib.h"
+#include "wmt_conf.h"
+#include "wmt_core.h"
+#include "wmt_plat.h"
+#include "wmt_plat_stub.h"
+#include "wmt_detect.h"
+#include "mtk_wcn_consys_hw.h"
+
+#include "stp_core.h"
+#include "btm_core.h"
+#include "psm_core.h"
+#include "stp_sdio.h"
+#include "stp_dbg.h"
+#include "wmt_step.h"
+#include
+#include
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/* A table for translation: enum CMB_STUB_AIF_X=>WMT_IC_PIN_STATE */
+static const WMT_IC_PIN_STATE cmb_aif2pin_stat[] = {
+ [CMB_STUB_AIF_0] = WMT_IC_AIF_0,
+ [CMB_STUB_AIF_1] = WMT_IC_AIF_1,
+ [CMB_STUB_AIF_2] = WMT_IC_AIF_2,
+ [CMB_STUB_AIF_3] = WMT_IC_AIF_3,
+ [CMB_STUB_AIF_4] = WMT_IC_PIN_STATE_MAX,
+};
+
+#if CFG_WMT_PS_SUPPORT
+static UINT32 gPsIdleTime = STP_PSM_IDLE_TIME_SLEEP;
+static UINT32 gPsEnable = 1;
+static PF_WMT_SDIO_PSOP sdio_own_ctrl;
+static PF_WMT_SDIO_DEBUG sdio_reg_rw;
+#endif
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+static PF_WMT_SDIO_DEEP_SLEEP sdio_deep_sleep_flag_set;
+#endif
+
+
+#define WMT_STP_CPUPCR_BUF_SIZE 73728
+static UINT8 g_cpupcr_buf[WMT_STP_CPUPCR_BUF_SIZE] = { 0 };
+static UINT32 g_quick_sleep_ctrl = 1;
+static UINT32 g_fw_patch_update_rst;
+static u64 fw_patch_rst_time;
+
+#define ASSERT_KEYWORD_LENGTH 20
+struct assert_work_st {
+ struct work_struct work;
+ ENUM_WMTDRV_TYPE_T type;
+ UINT32 reason;
+ UINT8 keyword[ASSERT_KEYWORD_LENGTH];
+};
+
+static struct assert_work_st wmt_assert_work;
+
+static INT32 g_bt_no_acl_link = 1;
+static INT32 g_bt_no_br_acl_link = 1;
+
+#define CONSYS_MET_WAIT (1000*10) /* ms */
+#define MET_DUMP_MAX_NUM (1)
+#define MET_DUMP_SIZE (4*MET_DUMP_MAX_NUM)
+#define EMI_MET_READ_OFFSET 0x0
+#define EMI_MET_WRITE_OFFSET 0x4
+#define EMI_MET_DATA_OFFSET 0x8
+#define FW_PATCH_UPDATE_RST_DURATION 180 /* 180 seconds */
+
+#define WMT_LIB_DMP_CONSYS_MAX_TIMES 10
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+DEV_WMT gDevWmt;
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+#if CFG_WMT_PS_SUPPORT
+static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action);
+static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID);
+static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID);
+static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID);
+static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action);
+#endif
+
+static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pLxOp);
+
+static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ);
+
+static INT32 wmtd_thread(PVOID pvData);
+static INT32 met_thread(PVOID pvData);
+static INT32 wmtd_worker_thread(PVOID pvData);
+
+static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag);
+static MTK_WCN_BOOL wmt_lib_hw_state_show(VOID);
+static VOID wmt_lib_utc_sync_timeout_handler(timer_handler_arg arg);
+static VOID wmt_lib_utc_sync_worker_handler(struct work_struct *work);
+static VOID wmt_lib_wmtd_worker_thread_timeout_handler(timer_handler_arg);
+static VOID wmt_lib_wmtd_worker_thread_work_handler(struct work_struct *work);
+
+static VOID wmt_lib_assert_work_cb(struct work_struct *work);
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+INT32 __weak mtk_wcn_consys_stp_btif_dpidle_ctrl(UINT32 en_flag)
+{
+ WMT_ERR_FUNC("mtk_wcn_consys_stp_btif_dpidle_ctrl is not define!!!\n");
+
+ return 0;
+}
+
+INT32 wmt_lib_wlan_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.wlan_lock);
+}
+
+VOID wmt_lib_wlan_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.wlan_lock);
+}
+
+INT32 wmt_lib_wlan_lock_trylock(VOID)
+{
+ return osal_trylock_sleepable_lock(&gDevWmt.wlan_lock);
+}
+
+INT32 wmt_lib_idc_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.idc_lock);
+}
+
+VOID wmt_lib_idc_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.idc_lock);
+}
+
+INT32 wmt_lib_psm_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.psm_lock);
+}
+
+void wmt_lib_psm_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.psm_lock);
+}
+
+INT32 wmt_lib_psm_lock_trylock(VOID)
+{
+ return osal_trylock_sleepable_lock(&gDevWmt.psm_lock);
+}
+
+INT32 wmt_lib_assert_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.assert_lock);
+}
+
+VOID wmt_lib_assert_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.assert_lock);
+}
+
+INT32 wmt_lib_assert_lock_trylock(VOID)
+{
+ return osal_trylock_sleepable_lock(&gDevWmt.assert_lock);
+}
+
+INT32 wmt_lib_mpu_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.mpu_lock);
+}
+
+VOID wmt_lib_mpu_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.mpu_lock);
+}
+
+INT32 wmt_lib_power_lock_aquire(VOID)
+{
+ return osal_lock_sleepable_lock(&gDevWmt.power_lock);
+}
+
+VOID wmt_lib_power_lock_release(VOID)
+{
+ osal_unlock_sleepable_lock(&gDevWmt.power_lock);
+}
+
+INT32 wmt_lib_power_lock_trylock(VOID)
+{
+ return osal_trylock_sleepable_lock(&gDevWmt.power_lock);
+}
+
+INT32 DISABLE_PSM_MONITOR(VOID)
+{
+ INT32 ret = 0;
+ PUINT8 pbuf = NULL;
+ INT32 len = 0;
+
+ /* osal_lock_sleepable_lock(&gDevWmt.psm_lock); */
+ ret = wmt_lib_psm_lock_aquire();
+ if (ret) {
+ WMT_ERR_FUNC("--->lock psm_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+#if CFG_WMT_PS_SUPPORT
+ ret = wmt_lib_ps_disable();
+ if (ret) {
+ WMT_ERR_FUNC("wmt_lib_ps_disable fail, ret=%d\n", ret);
+ wmt_lib_psm_lock_release();
+ if (mtk_wcn_stp_coredump_start_get() == 0 &&
+ chip_reset_only == 0 &&
+ mtk_wcn_stp_get_wmt_trg_assert() == 0) {
+ pbuf = "wmt_lib_ps_disable fail, just collect SYS_FTRACE to DB";
+ len = osal_strlen(pbuf);
+ stp_dbg_trigger_collect_ftrace(pbuf, len);
+ wmt_lib_trigger_reset();
+ }
+ }
+#endif
+ return ret;
+}
+
+VOID ENABLE_PSM_MONITOR(VOID)
+{
+#if CFG_WMT_PS_SUPPORT
+ wmt_lib_ps_enable();
+#endif
+ /* osal_unlock_sleepable_lock(&gDevWmt.psm_lock); */
+ wmt_lib_psm_lock_release();
+}
+
+
+INT32 wmt_lib_init(VOID)
+{
+ INT32 iRet;
+ UINT32 i;
+ P_DEV_WMT pDevWmt;
+ P_OSAL_THREAD pThread;
+ P_OSAL_THREAD pWorkerThread;
+ ENUM_WMT_CHIP_TYPE chip_type;
+
+ /* create->init->start */
+ /* 1. create: static allocation with zero initialization */
+ pDevWmt = &gDevWmt;
+ osal_memset(&gDevWmt, 0, sizeof(gDevWmt));
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) {
+ iRet = wmt_conf_read_file();
+ if (iRet) {
+ WMT_ERR_FUNC("read wmt config file fail(%d)\n", iRet);
+ return -1;
+ }
+ }
+ osal_op_history_init(&pDevWmt->wmtd_op_history, 16);
+ osal_op_history_init(&pDevWmt->worker_op_history, 8);
+
+ pThread = &gDevWmt.thread;
+
+ /* Create mtk_wmtd thread */
+ osal_strncpy(pThread->threadName, "mtk_wmtd", sizeof(pThread->threadName));
+ pThread->pThreadData = (PVOID) pDevWmt;
+ pThread->pThreadFunc = (PVOID) wmtd_thread;
+ iRet = osal_thread_create(pThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThread, iRet);
+ return -2;
+ }
+
+ /* create worker timer */
+ gDevWmt.worker_timer.timeoutHandler = wmt_lib_wmtd_worker_thread_timeout_handler;
+ gDevWmt.worker_timer.timeroutHandlerData = 0;
+ osal_timer_create(&gDevWmt.worker_timer);
+ pWorkerThread = &gDevWmt.worker_thread;
+ INIT_WORK(&pDevWmt->wmtd_worker_thread_work, wmt_lib_wmtd_worker_thread_work_handler);
+
+ /* Create wmtd_worker thread */
+ osal_strncpy(pWorkerThread->threadName, "mtk_wmtd_worker", sizeof(pWorkerThread->threadName));
+ pWorkerThread->pThreadData = (PVOID) pDevWmt;
+ pWorkerThread->pThreadFunc = (PVOID) wmtd_worker_thread;
+ iRet = osal_thread_create(pWorkerThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pWorkerThread, iRet);
+ return -2;
+ }
+
+ /* init timer */
+ pDevWmt->utc_sync_timer.timeoutHandler = wmt_lib_utc_sync_timeout_handler;
+ osal_timer_create(&pDevWmt->utc_sync_timer);
+ osal_timer_start(&pDevWmt->utc_sync_timer, UTC_SYNC_TIME);
+ INIT_WORK(&pDevWmt->utcSyncWorker, wmt_lib_utc_sync_worker_handler);
+
+ /* 2. initialize */
+ /* Initialize wmt_core */
+
+ iRet = wmt_core_init();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core_init() fail(%d)\n", iRet);
+ return -1;
+ }
+
+ /* Initialize WMTd Thread Information: Thread */
+ osal_event_init(&pDevWmt->rWmtdWq);
+ osal_event_init(&pDevWmt->rWmtdWorkerWq);
+ osal_sleepable_lock_init(&pDevWmt->psm_lock);
+ osal_sleepable_lock_init(&pDevWmt->idc_lock);
+ osal_sleepable_lock_init(&pDevWmt->wlan_lock);
+ osal_sleepable_lock_init(&pDevWmt->assert_lock);
+ osal_sleepable_lock_init(&pDevWmt->mpu_lock);
+ osal_sleepable_lock_init(&pDevWmt->power_lock);
+ osal_sleepable_lock_init(&pDevWmt->rActiveOpQ.sLock);
+ osal_sleepable_lock_init(&pDevWmt->rWorkerOpQ.sLock);
+ osal_sleepable_lock_init(&pDevWmt->rFreeOpQ.sLock);
+ pDevWmt->state.data = 0;
+
+ atomic_set(&pDevWmt->state_dmp_req.version, 0);
+ for (i = 0; i < WMT_LIB_DMP_SLOT; i++)
+ osal_sleepable_lock_init(&(pDevWmt->state_dmp_req.consys_ops[i].lock));
+
+ /* Initialize op queue */
+ RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE);
+ RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE);
+ RB_INIT(&pDevWmt->rWorkerOpQ, WMT_OP_BUF_SIZE);
+ /* Put all to free Q */
+ for (i = 0; i < WMT_OP_BUF_SIZE; i++) {
+ osal_signal_init(&(pDevWmt->arQue[i].signal));
+ wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i]));
+ }
+
+ /* initialize stp resources */
+ osal_event_init(&pDevWmt->rWmtRxWq);
+
+ /*function driver callback */
+ for (i = 0; i < WMTDRV_TYPE_WIFI; i++)
+ pDevWmt->rFdrvCb.fDrvRst[i] = NULL;
+
+ pDevWmt->hw_ver = WMTHWVER_MAX;
+ WMT_DBG_FUNC("***********Init, hw->ver = %x\n", pDevWmt->hw_ver);
+
+ /* TODO:[FixMe][GeorgeKuo]: wmt_lib_conf_init */
+ /* initialize default configurations */
+ /* i4Result = wmt_lib_conf_init(VOID); */
+ /* WMT_WARN_FUNC("wmt_drv_conf_init(%d)\n", i4Result); */
+
+ osal_signal_init(&pDevWmt->cmdResp);
+ osal_event_init(&pDevWmt->cmdReq);
+ /* initialize platform resources */
+
+ if (gDevWmt.rWmtGenConf.cfgExist != 0) {
+ PWR_SEQ_TIME pwrSeqTime;
+
+ pwrSeqTime.ldoStableTime = gDevWmt.rWmtGenConf.pwr_on_ldo_slot;
+ pwrSeqTime.rstStableTime = gDevWmt.rWmtGenConf.pwr_on_rst_slot;
+ pwrSeqTime.onStableTime = gDevWmt.rWmtGenConf.pwr_on_on_slot;
+ pwrSeqTime.offStableTime = gDevWmt.rWmtGenConf.pwr_on_off_slot;
+ pwrSeqTime.rtcStableTime = gDevWmt.rWmtGenConf.pwr_on_rtc_slot;
+ WMT_INFO_FUNC("set pwr on seq par to hw conf\n");
+ WMT_INFO_FUNC("ldo(%d)rst(%d)on(%d)off(%d)rtc(%d)\n", pwrSeqTime.ldoStableTime,
+ pwrSeqTime.rstStableTime, pwrSeqTime.onStableTime,
+ pwrSeqTime.offStableTime, pwrSeqTime.rtcStableTime);
+ iRet = wmt_plat_init(&pwrSeqTime, gDevWmt.rWmtGenConf.co_clock_flag & 0x0f);
+ } else {
+ WMT_ERR_FUNC("no pwr on seq and clk par found\n");
+ iRet = wmt_plat_init(NULL, 0);
+ }
+ chip_type = wmt_detect_get_chip_type();
+ if (chip_type == WMT_CHIP_TYPE_SOC)
+ gDevWmt.rWmtGenConf.co_clock_flag = wmt_plat_soc_co_clock_flag_get();
+
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_plat_init() fail(%d)\n", iRet);
+ return -3;
+ }
+
+#if CFG_WMT_PS_SUPPORT
+ iRet = wmt_lib_ps_init();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_lib_ps_init() fail(%d)\n", iRet);
+ return -4;
+ }
+#endif
+
+ /* 3. start: start running mtk_wmtd */
+ iRet = osal_thread_run(pThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_run(wmtd 0x%p) fail(%d)\n", pThread, iRet);
+ return -5;
+ }
+
+ iRet = osal_thread_run(pWorkerThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_run(worker 0x%p) fail(%d)\n", pWorkerThread, iRet);
+ return -5;
+ }
+ /*4. register irq callback to WMT-PLAT */
+ wmt_plat_irq_cb_reg(wmt_lib_ps_irq_cb);
+ /*5. register audio if control callback to WMT-PLAT */
+ wmt_plat_aif_cb_reg(wmt_lib_set_aif);
+ /*6. register function control callback to WMT-PLAT */
+ wmt_plat_func_ctrl_cb_reg(mtk_wcn_wmt_func_ctrl_for_plat);
+
+ wmt_plat_deep_idle_ctrl_cb_reg(mtk_wcn_consys_stp_btif_dpidle_ctrl);
+ /*7 reset gps/bt state */
+
+ mtk_wcn_wmt_system_state_reset();
+
+#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+ mtk_wcn_wmt_exp_init();
+#endif
+
+#if CFG_WMT_LTE_COEX_HANDLING
+ wmt_idc_init();
+#endif
+
+ INIT_WORK(&(wmt_assert_work.work), wmt_lib_assert_work_cb);
+
+ WMT_DBG_FUNC("init success\n");
+ return 0;
+}
+
+
+INT32 wmt_lib_deinit(VOID)
+{
+ INT32 iRet;
+ P_DEV_WMT pDevWmt;
+ P_OSAL_THREAD pThread;
+ P_OSAL_THREAD pWorkerThread;
+ INT32 i;
+ INT32 iResult;
+ struct vendor_patch_table *table = &(gDevWmt.patch_table);
+
+ pDevWmt = &gDevWmt;
+ pThread = &gDevWmt.thread;
+ pWorkerThread = &gDevWmt.worker_thread;
+ iResult = 0;
+
+ /* stop->deinit->destroy */
+
+ /* 1. stop: stop running mtk_wmtd */
+ iRet = osal_thread_stop(pThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThread, iRet);
+ iResult += 1;
+ }
+
+ iRet = osal_thread_stop(pWorkerThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pWorkerThread, iRet);
+ iResult += 1;
+ }
+
+ /* 2. deinit: */
+
+#if CFG_WMT_PS_SUPPORT
+ iRet = wmt_lib_ps_deinit();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_lib_ps_deinit fail(%d)\n", iRet);
+ iResult += 2;
+ }
+#endif
+
+ iRet = wmt_plat_deinit();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_plat_deinit fail(%d)\n", iRet);
+ iResult += 4;
+ }
+
+ osal_event_deinit(&pDevWmt->cmdReq);
+ osal_signal_deinit(&pDevWmt->cmdResp);
+
+ /* de-initialize stp resources */
+ osal_event_deinit(&pDevWmt->rWmtRxWq);
+
+ for (i = 0; i < WMT_OP_BUF_SIZE; i++)
+ osal_signal_deinit(&(pDevWmt->arQue[i].signal));
+
+ osal_sleepable_lock_deinit(&pDevWmt->rFreeOpQ.sLock);
+ osal_sleepable_lock_deinit(&pDevWmt->rActiveOpQ.sLock);
+ osal_sleepable_lock_deinit(&pDevWmt->rWorkerOpQ.sLock);
+ osal_sleepable_lock_deinit(&pDevWmt->power_lock);
+ osal_sleepable_lock_deinit(&pDevWmt->mpu_lock);
+ osal_sleepable_lock_deinit(&pDevWmt->idc_lock);
+ osal_sleepable_lock_deinit(&pDevWmt->wlan_lock);
+ osal_sleepable_lock_deinit(&pDevWmt->assert_lock);
+ osal_sleepable_lock_deinit(&pDevWmt->psm_lock);
+
+ for (i = 0; i < WMT_LIB_DMP_SLOT; i++)
+ osal_sleepable_lock_deinit(&(pDevWmt->state_dmp_req.consys_ops[i].lock));
+
+ osal_event_deinit(&pDevWmt->rWmtdWq);
+ osal_event_deinit(&pDevWmt->rWmtdWorkerWq);
+
+ for (i = 0; i < WMTDRV_TYPE_ANT; i++) {
+ kfree(pDevWmt->pWmtRomPatchInfo[i]);
+ pDevWmt->pWmtRomPatchInfo[i] = NULL;
+ }
+
+ iRet = wmt_core_deinit();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_core_deinit fail(%d)\n", iRet);
+ iResult += 8;
+ }
+
+ /* 3. destroy */
+ iRet = osal_thread_destroy(pThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThread, iRet);
+ iResult += 16;
+ }
+
+ iRet = osal_thread_destroy(pWorkerThread);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pWorkerThread, iRet);
+ iResult += 32;
+ }
+
+ iRet = wmt_conf_deinit();
+ if (iRet) {
+ WMT_ERR_FUNC("wmt_conf_deinit fail(%d)\n", iRet);
+ iResult += 64;
+ }
+
+ osal_memset(&gDevWmt, 0, sizeof(gDevWmt));
+#if 0
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+ mtk_wcn_wmt_exp_deinit();
+#endif
+#endif
+
+#if CFG_WMT_LTE_COEX_HANDLING
+ wmt_idc_deinit();
+#endif
+
+ if (table->active_version != NULL) {
+ for (i = 0; i < table->num; i++) {
+ if (table->active_version[i])
+ osal_free(table->active_version[i]);
+ }
+ osal_free(table->active_version);
+ table->active_version = NULL;
+ }
+
+ WMT_STEP_DEINIT_FUNC();
+
+ return iResult;
+}
+
+VOID wmt_lib_flush_rx(VOID)
+{
+ mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX);
+}
+
+INT32 wmt_lib_trigger_cmd_signal(INT32 result)
+{
+ P_OSAL_SIGNAL pSignal = &gDevWmt.cmdResp;
+
+ gDevWmt.cmdResult = result;
+ osal_raise_signal(pSignal);
+ WMT_DBG_FUNC("wakeup cmdResp\n");
+ return 0;
+}
+
+P_OSAL_EVENT wmt_lib_get_cmd_event(VOID)
+{
+ return &gDevWmt.cmdReq;
+}
+
+INT32 wmt_lib_set_patch_name(PUINT8 cPatchName)
+{
+ osal_strncpy(gDevWmt.cPatchName, cPatchName, NAME_MAX);
+ return 0;
+}
+
+INT32 wmt_lib_set_uart_name(PINT8 cUartName)
+{
+#if WMT_PLAT_ALPS
+
+ WMT_DBG_FUNC("orig uart: %s\n", wmt_uart_port_desc);
+#endif
+ osal_strncpy(gDevWmt.cUartName, cUartName, NAME_MAX);
+#if WMT_PLAT_ALPS
+ wmt_uart_port_desc = gDevWmt.cUartName;
+ WMT_DBG_FUNC("new uart: %s\n", wmt_uart_port_desc);
+#endif
+ return 0;
+}
+
+INT32 wmt_lib_set_hif(ULONG hifconf)
+{
+ UINT32 val;
+ P_WMT_HIF_CONF pHif = &gDevWmt.rWmtHifConf;
+
+ val = hifconf & 0xF;
+ switch (val) {
+ case STP_UART_FULL:
+ pHif->hifType = WMT_HIF_UART;
+ pHif->uartFcCtrl = ((hifconf & 0xc) >> 2);
+ val = (hifconf >> 8);
+ pHif->au4HifConf[0] = val;
+ pHif->au4HifConf[1] = val;
+ mtk_wcn_stp_set_if_tx_type(STP_UART_IF_TX);
+ wmt_plat_set_comm_if_type(STP_UART_IF_TX);
+ break;
+ case STP_SDIO:
+ pHif->hifType = WMT_HIF_SDIO;
+ mtk_wcn_stp_set_if_tx_type(STP_SDIO_IF_TX);
+ wmt_plat_set_comm_if_type(STP_SDIO_IF_TX);
+ break;
+ case STP_BTIF_FULL:
+ pHif->hifType = WMT_HIF_BTIF;
+ mtk_wcn_stp_set_if_tx_type(STP_BTIF_IF_TX);
+ break;
+ default:
+ WMT_WARN_FUNC("invalid stp mode: %lu %u\n", hifconf, val);
+ return -1;
+ }
+
+ val = (hifconf & 0xF0) >> 4;
+ if (val == WMT_FM_COMM) {
+ pHif->au4StrapConf[0] = WMT_FM_COMM;
+ } else if (val == WMT_FM_I2C) {
+ pHif->au4StrapConf[0] = WMT_FM_I2C;
+ } else {
+ WMT_WARN_FUNC("invalid fm mode: %u\n", val);
+ return -2;
+ }
+
+ WMT_DBG_FUNC("new hifType:%d, fcCtrl:%d, baud:%d, fm:%d\n",
+ pHif->hifType, pHif->uartFcCtrl, pHif->au4HifConf[0], pHif->au4StrapConf[0]);
+ return 0;
+}
+
+
+P_WMT_HIF_CONF wmt_lib_get_hif(VOID)
+{
+ return &gDevWmt.rWmtHifConf;
+}
+
+PUINT8 wmt_lib_get_cmd(VOID)
+{
+ if (osal_test_and_clear_bit(WMT_STAT_CMD, &gDevWmt.state))
+ return gDevWmt.cCmd;
+
+ return NULL;
+}
+
+MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID)
+{
+ return osal_test_bit(WMT_STAT_CMD, &gDevWmt.state) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+
+MTK_WCN_BOOL wmt_lib_stp_is_btif_fullset_mode(VOID)
+{
+ return mtk_wcn_stp_is_btif_fullset_mode();
+}
+
+#if CFG_WMT_PS_SUPPORT
+INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime)
+{
+ gPsIdleTime = psIdleTime;
+ return gPsIdleTime;
+}
+
+INT32 wmt_lib_ps_ctrl(UINT32 state)
+{
+ if (state == 0) {
+ wmt_lib_ps_disable();
+ gPsEnable = 0;
+ } else {
+ gPsEnable = 1;
+ wmt_lib_ps_enable();
+ }
+ return 0;
+}
+
+
+INT32 wmt_lib_ps_enable(VOID)
+{
+ if (gPsEnable)
+ mtk_wcn_stp_psm_enable(gPsIdleTime);
+
+ return 0;
+}
+
+INT32 wmt_lib_ps_disable(VOID)
+{
+ if (gPsEnable)
+ return mtk_wcn_stp_psm_disable();
+
+ return 0;
+}
+
+INT32 wmt_lib_ps_init(VOID)
+{
+ /* mtk_wcn_stp_psm_register_wmt_cb(wmt_lib_ps_stp_cb); */
+ return 0;
+}
+
+INT32 wmt_lib_ps_deinit(VOID)
+{
+ /* mtk_wcn_stp_psm_unregister_wmt_cb(); */
+ return 0;
+}
+
+static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action)
+{
+ P_OSAL_OP lxop;
+ MTK_WCN_BOOL bRet;
+ UINT32 u4Wait;
+ P_OSAL_SIGNAL pSignal;
+
+ lxop = wmt_lib_get_free_op();
+ if (!lxop) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ pSignal = &lxop->signal;
+ pSignal->timeoutValue = 0;
+ lxop->op.opId = WMT_OPID_PWR_SV;
+ lxop->op.au4OpData[0] = action;
+ lxop->op.au4OpData[1] = (SIZE_T) mtk_wcn_stp_psm_notify_stp;
+ u4Wait = 0;
+ bRet = wmt_lib_put_act_op(lxop);
+ return bRet;
+}
+
+#if CFG_WMT_LTE_COEX_HANDLING
+MTK_WCN_BOOL wmt_lib_handle_idc_msg(conn_md_ipc_ilm_t *idc_infor)
+{
+ P_OSAL_OP lxop;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_OSAL_SIGNAL pSignal;
+ INT32 ret = 0;
+ UINT16 msg_len = 0;
+
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+ MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE;
+#endif
+ WMT_DBG_FUNC("idc_infor from conn_md is 0x%p\n", idc_infor);
+
+ ret = wmt_lib_idc_lock_aquire();
+ if (ret) {
+ WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", ret);
+ return MTK_WCN_BOOL_FALSE;
+ }
+ msg_len = idc_infor->local_para_ptr->msg_len - osal_sizeof(struct local_para);
+ if (msg_len > WMT_IDC_MSG_MAX_SIZE) {
+ wmt_lib_idc_lock_release();
+ WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len);
+ return -2;
+ }
+ osal_memcpy(&gDevWmt.msg_local_buffer[0], &msg_len, osal_sizeof(msg_len));
+ osal_memcpy(&gDevWmt.msg_local_buffer[osal_sizeof(msg_len)],
+ &(idc_infor->local_para_ptr->data[0]), msg_len - 1);
+ wmt_lib_idc_lock_release();
+
+ lxop = wmt_lib_get_free_op();
+ if (!lxop) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ pSignal = &lxop->signal;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+ lxop->op.opId = WMT_OPID_IDC_MSG_HANDLING;
+ lxop->op.au4OpData[0] = (size_t) gDevWmt.msg_local_buffer;
+
+ /*msg opcode fill rule is still not clrear,need scott comment */
+ /***********************************************************/
+ WMT_DBG_FUNC("ilm msg id is (0x%08x)\n", idc_infor->msg_id);
+
+#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING
+ switch (idc_infor->msg_id) {
+ case IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_PARA;
+ break;
+ case IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_FREQ;
+ break;
+ case IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_WIFI_MAX_POWER;
+ break;
+ case IPC_MSG_ID_EL1_LTE_TX_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_INDICATION;
+ break;
+ case IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS;
+ break;
+ case IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND:
+ lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION;
+ break;
+ default:
+ unknown_msgid = MTK_WCN_BOOL_TRUE;
+ break;
+ }
+ if (unknown_msgid == MTK_WCN_BOOL_FALSE) {
+ /*wake up chip first */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(lxop);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ bRet = wmt_lib_put_act_op(lxop);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet);
+ } else {
+ WMT_DBG_FUNC("OPID(%d) type(%zu) ok\n",
+ lxop->op.opId, lxop->op.au4OpData[1]);
+ }
+ } else {
+ bRet = MTK_WCN_BOOL_FALSE;
+ wmt_lib_put_op_to_free_queue(lxop);
+ WMT_ERR_FUNC("unknown msgid from LTE(%d)\n", idc_infor->msg_id);
+ }
+#else
+ if ((idc_infor->msg_id >= IPC_EL1_MSG_ID_BEGIN)
+ && (idc_infor->msg_id <= IPC_EL1_MSG_ID_BEGIN + IPC_EL1_MSG_ID_RANGE)) {
+ lxop->op.au4OpData[1] = idc_infor->msg_id - IPC_EL1_MSG_ID_BEGIN + LTE_MSG_ID_OFFSET - 1;
+
+ /*wake up chip first */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(lxop);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ bRet = wmt_lib_put_act_op(lxop);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet);
+ } else {
+ WMT_DBG_FUNC("wmt_lib_handle_idc_msg OPID(%d) type(%zu) ok\n",
+ lxop->op.opId, lxop->op.au4OpData[1]);
+ }
+ } else {
+ wmt_lib_put_op_to_free_queue(lxop);
+ WMT_ERR_FUNC("msgid(%d) out of range,wmt drop it!\n", idc_infor->msg_id);
+ }
+
+#endif
+ return bRet;
+}
+#endif
+
+static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID)
+{
+ return wmt_lib_ps_action(SLEEP);
+}
+
+static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID)
+{
+ return wmt_lib_ps_action(WAKEUP);
+}
+
+static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID)
+{
+ return wmt_lib_ps_action(HOST_AWAKE);
+}
+
+/* extern int g_block_tx; */
+static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action)
+{
+ INT32 ret;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 1);
+
+ ret = 0; /* TODO:[FixMe][George] initial value or compile warning? */
+ /* if(g_block_tx && (action == SLEEP)) */
+ if ((mtk_wcn_stp_coredump_start_get() != 0) && (action == SLEEP)) {
+ ret = mtk_wcn_stp_psm_notify_stp(SLEEP);
+ return ret;
+ }
+
+ /*MT662x Not Ready */
+ if (!mtk_wcn_stp_is_ready()) {
+ if (!mtk_wcn_stp_is_sdio_mode()) {
+ WMT_DBG_FUNC("MT662x Not Ready, Dont Send Sleep/Wakeup Command\n");
+ ret = mtk_wcn_stp_psm_notify_stp(ROLL_BACK);
+ } else {
+ WMT_DBG_FUNC("MT662x Not Ready, SDIO mode, skip EIRQ");
+ }
+ return ret;
+ }
+
+ if (action == SLEEP) {
+ WMT_DBG_FUNC("send op--------------------------------> sleep job\n");
+
+ if (!mtk_wcn_stp_is_sdio_mode()) {
+ bRet = wmt_lib_ps_do_sleep();
+ ret = bRet ? 0 : -1;
+ WMT_DBG_FUNC("enable host eirq\n");
+ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_EN);
+#if CFG_WMT_DUMP_INT_STATUS
+ if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE)
+ wmt_plat_BGF_irq_dump_status();
+#endif
+ } else {
+ /* ret = mtk_wcn_stp_sdio_do_own_set(); */
+ if (sdio_own_ctrl) {
+ ret = (*sdio_own_ctrl) (OWN_SET);
+ mtk_wcn_stp_dbg_pkt_log(8, PKT_DIR_TX);
+ } else {
+ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n");
+ ret = -1;
+ }
+
+ if (!ret) {
+ mtk_wcn_stp_psm_notify_stp(SLEEP);
+ } else if (ret == -2) {
+ mtk_wcn_stp_psm_notify_stp(ROLL_BACK);
+ WMT_WARN_FUNC
+ ("========[SDIO-PS] rollback due to tx busy ========%%\n");
+ } else {
+ mtk_wcn_stp_psm_notify_stp(SLEEP);
+ WMT_ERR_FUNC
+ ("========[SDIO-PS] set own fails! ========%%\n");
+ }
+ }
+
+ WMT_DBG_FUNC("send op<--------------------------------- sleep job\n");
+ } else if (action == WAKEUP) {
+ WMT_DBG_FUNC("send op --------------------------------> wake job\n");
+
+ if (!mtk_wcn_stp_is_sdio_mode()) {
+ WMT_DBG_FUNC("disable host eirq\n");
+#if CFG_WMT_DUMP_INT_STATUS
+ if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE)
+ wmt_plat_BGF_irq_dump_status();
+#endif
+ wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS);
+ bRet = wmt_lib_ps_do_wakeup();
+ ret = bRet ? 0 : -1;
+ } else {
+ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */
+
+ if (sdio_own_ctrl) {
+ ret = (*sdio_own_ctrl) (OWN_CLR);
+ } else {
+ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n");
+ ret = -1;
+ }
+
+ if (!ret) {
+ mtk_wcn_stp_psm_notify_stp(WAKEUP);
+ } else {
+ mtk_wcn_stp_psm_notify_stp(WAKEUP);
+ WMT_ERR_FUNC
+ ("========[SDIO-PS] set own back fails! ========%%\n");
+ }
+ }
+
+ WMT_DBG_FUNC("send op<--------------------------------- wake job\n");
+ } else if (action == HOST_AWAKE) {
+ WMT_DBG_FUNC("send op --------------------------------> host awake job\n");
+
+ if (!mtk_wcn_stp_is_sdio_mode()) {
+ WMT_DBG_FUNC("disable host eirq\n");
+ /* IRQ already disabled */
+ /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */
+#if 0
+ if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE)
+ wmt_plat_BGF_irq_dump_status();
+#endif
+ bRet = wmt_lib_ps_do_host_awake();
+ ret = bRet ? 0 : -1;
+ } else {
+ WMT_DBG_FUNC("[SDIO-PS] SDIO host awake! ####\n");
+
+ /* ret = mtk_wcn_stp_sdio_do_own_clr(); */
+
+ if (sdio_own_ctrl) {
+ ret = (*sdio_own_ctrl) (OWN_CLR);
+ } else {
+ WMT_ERR_FUNC("sdio_own_ctrl is not registered\n");
+ ret = -1;
+ }
+
+ mtk_wcn_stp_psm_notify_stp(HOST_AWAKE);
+ }
+
+ WMT_DBG_FUNC("send op<--------------------------------- host awake job\n");
+ } else if (action == EIRQ) {
+ WMT_DBG_FUNC("send op --------------------------------> eirq job\n");
+
+ if (!mtk_wcn_stp_is_sdio_mode()) {
+ if (__ratelimit(&_rs))
+ pr_info("conn2ap_btif0_wakeup_out_b EIRQ handler\n");
+ WMT_DBG_FUNC("disable host eirq\n");
+ /* Disable interrupt */
+ /*wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS);*/
+ ret = mtk_wcn_stp_psm_notify_stp(EIRQ);
+ } else {
+ WMT_DBG_FUNC("[SDIO-PS]sdio own-back eirq!######\n");
+ ret = mtk_wcn_stp_psm_notify_stp(EIRQ);
+ }
+
+ WMT_DBG_FUNC("send op<--------------------------------- eirq job\n");
+ }
+
+ return ret;
+}
+#endif /* end of CFG_WMT_PS_SUPPORT */
+
+INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action)
+{
+#if CFG_WMT_PS_SUPPORT
+ return wmt_lib_ps_handler(action);
+#else
+ WMT_WARN_FUNC("CFG_WMT_PS_SUPPORT is not set\n");
+ return 0;
+#endif
+}
+
+VOID wmt_lib_set_bt_link_status(INT32 type, INT32 value)
+{
+ WMT_INFO_FUNC("t = %d, v = %d, no_acl = %d, no_br = %d\n",
+ type, value, g_bt_no_acl_link, g_bt_no_br_acl_link);
+
+ if (type == 0)
+ g_bt_no_acl_link = value;
+ else if (type == 1)
+ g_bt_no_br_acl_link = value;
+}
+
+/*
+ * Allow BT to reset as long as one of the conditions is true.
+ * 1. no ACL link
+ * 2. no BR ACL link at 2 AM
+ */
+static INT32 wmt_lib_is_bt_able_to_reset(VOID)
+{
+ if (g_bt_no_acl_link)
+ return 1;
+ else if (g_bt_no_br_acl_link) {
+ struct timeval time;
+ ULONG local_time;
+ struct rtc_time tm;
+
+ osal_do_gettimeofday(&time);
+ local_time = (ULONG)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+ rtc_time_to_tm(local_time, &tm);
+ if (tm.tm_hour == 2)
+ return 1;
+ }
+ return 0;
+}
+
+INT32 wmt_lib_update_fw_patch_chip_rst(VOID)
+{
+ MTK_WCN_BOOL wifiDrvOwn = MTK_WCN_BOOL_FALSE;
+
+ if (g_fw_patch_update_rst == 0)
+ return 0;
+
+ if (chip_reset_only == 1)
+ return 0;
+
+ if (time_before_eq64(get_jiffies_64(), fw_patch_rst_time))
+ return 0;
+
+ if (wmt_lib_get_drv_status(WMTDRV_TYPE_WIFI) == DRV_STS_FUNC_ON) {
+ if (wmt_lib_wlan_lock_trylock() == 0)
+ return 0;
+
+ if (mtk_wcn_wlan_is_wifi_drv_own != NULL)
+ wifiDrvOwn = ((*mtk_wcn_wlan_is_wifi_drv_own)() == 0) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE;
+
+ wmt_lib_wlan_lock_release();
+ }
+
+ if (wmt_lib_get_drv_status(WMTDRV_TYPE_BT) == DRV_STS_FUNC_ON &&
+ wmt_lib_is_bt_able_to_reset() == 0)
+ return 0;
+
+ if (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_FALSE
+ || wmt_lib_get_drv_status(WMTDRV_TYPE_FM) == DRV_STS_FUNC_ON
+ || mtk_wcn_stp_is_ready() == MTK_WCN_BOOL_FALSE
+ || wifiDrvOwn == MTK_WCN_BOOL_TRUE)
+ return 0;
+
+ if (wmt_lib_psm_lock_trylock() == 0)
+ return 0;
+ wmt_lib_psm_lock_release();
+
+ wmt_lib_fw_patch_update_rst_ctrl(0);
+ chip_reset_only = 1;
+ fw_patch_rst_time = get_jiffies_64() + (FW_PATCH_UPDATE_RST_DURATION * HZ);
+ WMT_INFO_FUNC("Invoke whole chip reset from fw patch update!!!\n");
+ return wmt_lib_trigger_reset();
+}
+
+MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID)
+{
+ if ((g_quick_sleep_ctrl) && (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_TRUE))
+ return wmt_core_is_quick_ps_support();
+ else
+ return MTK_WCN_BOOL_FALSE;
+}
+
+VOID wmt_lib_ps_irq_cb(VOID)
+{
+#if CFG_WMT_PS_SUPPORT
+ wmt_lib_ps_handler(EIRQ);
+#else
+ WMT_DBG_FUNC("CFG_WMT_PS_SUPPORT is not set\n");
+ return;
+#endif
+}
+
+VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb)
+{
+#if CFG_WMT_PS_SUPPORT
+ sdio_own_ctrl = own_cb;
+#endif
+}
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+VOID wmt_lib_sdio_deep_sleep_flag_set_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb)
+{
+ sdio_deep_sleep_flag_set = flag_cb;
+}
+#endif
+
+VOID wmt_lib_sdio_reg_rw_cb(PF_WMT_SDIO_DEBUG reg_rw_cb)
+{
+ sdio_reg_rw = reg_rw_cb;
+}
+
+UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread)
+{
+ P_DEV_WMT pDevWmt;
+
+ if (pThread) {
+ pDevWmt = (P_DEV_WMT) (pThread->pThreadData);
+ return !RB_EMPTY(&pDevWmt->rActiveOpQ);
+ }
+ WMT_ERR_FUNC("pThread(NULL)\n");
+ return 0;
+}
+
+UINT32 wmt_lib_worker_wait_event_checker(P_OSAL_THREAD pThread)
+{
+ P_DEV_WMT pDevWmt;
+
+ if (pThread) {
+ pDevWmt = (P_DEV_WMT) (pThread->pThreadData);
+ return !RB_EMPTY(&pDevWmt->rWorkerOpQ);
+ }
+ WMT_ERR_FUNC("pThread(NULL)\n");
+ return 0;
+}
+
+static INT32 wmtd_thread(void *pvData)
+{
+ P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData;
+ P_OSAL_EVENT pEvent = NULL;
+ P_OSAL_OP pOp;
+ INT32 iResult;
+
+ if (pWmtDev == NULL) {
+ WMT_ERR_FUNC("pWmtDev(NULL)\n");
+ return -1;
+ }
+ WMT_INFO_FUNC("wmtd thread starts\n");
+
+ pEvent = &(pWmtDev->rWmtdWq);
+
+ for (;;) {
+ pOp = NULL;
+ pEvent->timeoutValue = 0;
+/* osal_thread_wait_for_event(&pWmtDev->thread, pEvent);*/
+ osal_thread_wait_for_event(&pWmtDev->thread, pEvent, wmt_lib_wait_event_checker);
+
+ if (osal_thread_should_stop(&pWmtDev->thread)) {
+ WMT_INFO_FUNC("wmtd thread should stop now...\n");
+ /* TODO: clean up active opQ */
+ break;
+ }
+
+ /* get Op from activeQ */
+ pOp = wmt_lib_get_op(&pWmtDev->rActiveOpQ);
+ if (!pOp) {
+ WMT_WARN_FUNC("get_lxop activeQ fail\n");
+ continue;
+ }
+
+ osal_op_history_save(&pWmtDev->wmtd_op_history, pOp);
+
+#if 0 /* wmt_core_opid_handler will do sanity check on opId, so no usage here */
+ id = lxop_get_opid(pLxOp);
+ if (id >= WMT_OPID_MAX) {
+ WMT_WARN_FUNC("abnormal opid id: 0x%x\n", id);
+ iResult = -1;
+ goto handlerDone;
+ }
+#endif
+
+ if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) {
+ /* when whole chip reset, only HW RST and SW RST cmd can execute */
+ if ((pOp->op.opId == WMT_OPID_HW_RST)
+ || (pOp->op.opId == WMT_OPID_SW_RST)
+ || (pOp->op.opId == WMT_OPID_GPIO_STATE)
+ || (pOp->op.opId == WMT_OPID_GET_CONSYS_STATE)) {
+ iResult = wmt_core_opid(&pOp->op);
+ } else {
+ iResult = -2;
+ WMT_WARN_FUNC
+ ("Whole chip resetting, opid (0x%x) failed, iRet(%d)\n",
+ pOp->op.opId, iResult);
+ }
+ } else {
+ wmt_lib_set_current_op(pWmtDev, pOp);
+ iResult = wmt_core_opid(&pOp->op);
+ wmt_lib_set_current_op(pWmtDev, NULL);
+ }
+
+ if (iResult)
+ WMT_WARN_FUNC("opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult);
+
+ if (iResult == 0 &&
+ (pOp->op.opId == WMT_OPID_WLAN_PROBE || pOp->op.opId == WMT_OPID_WLAN_REMOVE))
+ continue;
+
+ if (atomic_dec_and_test(&pOp->ref_count)) {
+ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp);
+ } else if (osal_op_is_wait_for_signal(pOp)) {
+ osal_op_raise_signal(pOp, iResult);
+ }
+
+ if (pOp->op.opId == WMT_OPID_EXIT) {
+ WMT_INFO_FUNC("wmtd thread received exit signal\n");
+ break;
+ }
+ }
+
+ WMT_INFO_FUNC("wmtd thread exits succeed\n");
+
+ return 0;
+};
+
+static INT32 met_thread(void *pvData)
+{
+ P_DEV_WMT p_wmtdev = (P_DEV_WMT) pvData;
+ INT32 log_ctrl;
+ UINT32 read_ptr = 0;
+ UINT32 write_ptr = 0;
+ UINT32 emi_met_size = 0;
+ UINT32 emi_met_offset = 0;
+ P_CONSYS_EMI_ADDR_INFO emi_info;
+ PUINT8 emi_met_base = NULL;
+ PINT32 met_dump_buf = 0;
+ UINT32 met_buf_offset = 0;
+ UINT32 value = 0;
+
+ if (p_wmtdev == NULL) {
+ WMT_ERR_FUNC("pWmtDev(NULL)\n");
+ return -1;
+ }
+
+ WMT_INFO_FUNC("met thread starts\n");
+
+ emi_info = mtk_wcn_consys_soc_get_emi_phy_add();
+ if (!emi_info) {
+ WMT_ERR_FUNC("get EMI info failed.\n");
+ return -1;
+ }
+
+ emi_met_size = emi_info->emi_met_size;
+ if (!emi_met_size) {
+ WMT_ERR_FUNC("get met emi size fail\n");
+ return -1;
+ }
+
+ emi_met_offset = emi_info->emi_met_data_offset;
+ if (!emi_met_offset) {
+ WMT_ERR_FUNC("get met emi offset fail\n");
+ return -1;
+ }
+
+ met_dump_buf = osal_malloc(MET_DUMP_SIZE);
+ if (!met_dump_buf) {
+ WMT_ERR_FUNC("alloc dump buffer fail\n");
+ return -1;
+ }
+ osal_memset(met_dump_buf, 0, MET_DUMP_SIZE);
+
+ emi_met_base = ioremap_nocache(emi_info->emi_ap_phy_addr + emi_met_offset, emi_met_size);
+ if (!emi_met_base) {
+ osal_free(met_dump_buf);
+ WMT_ERR_FUNC("met emi ioremap fail\n");
+ return -1;
+ }
+
+ WMT_INFO_FUNC("emi phy base:%x, emi vir base:%p, met offset:%x, size:%x\n",
+ emi_info->emi_ap_phy_addr,
+ emi_met_base,
+ emi_met_offset,
+ emi_met_size);
+
+
+ log_ctrl = p_wmtdev->met_log_ctrl;
+ if (log_ctrl)
+ osal_ftrace_print_ctrl(1);
+
+ for (;;) {
+ if (osal_thread_should_stop(&p_wmtdev->met_thread)) {
+ WMT_INFO_FUNC("met thread should stop now...\n");
+ goto met_exit;
+ }
+
+ read_ptr = CONSYS_REG_READ(emi_met_base + EMI_MET_READ_OFFSET);
+ write_ptr = CONSYS_REG_READ(emi_met_base + EMI_MET_WRITE_OFFSET);
+
+ if (read_ptr == write_ptr)
+ WMT_DBG_FUNC("read_ptr(0x%x) == write_ptr(0x%x) no met data need dump!!!\n",
+ read_ptr, write_ptr);
+ else if (write_ptr > (emi_met_size - EMI_MET_DATA_OFFSET)) {
+ WMT_ERR_FUNC("write_ptr(0x%x) overflow!!!\n", write_ptr);
+ wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 42);
+ goto met_exit;
+ } else {
+ if (read_ptr > write_ptr) {
+ for (; read_ptr < emi_met_size; read_ptr += 0x4) {
+ value = CONSYS_REG_READ(emi_met_base + EMI_MET_DATA_OFFSET + read_ptr);
+ met_dump_buf[met_buf_offset] = value;
+ met_buf_offset++;
+ if (met_buf_offset >= MET_DUMP_MAX_NUM) {
+ met_buf_offset = 0;
+ osal_buffer_dump_data(met_dump_buf, "MCU_MET_DATA:",
+ MET_DUMP_MAX_NUM, MET_DUMP_MAX_NUM,
+ log_ctrl);
+ }
+ }
+ read_ptr = 0;
+ }
+
+ for (; read_ptr < write_ptr; read_ptr += 0x4) {
+ value = CONSYS_REG_READ(emi_met_base + EMI_MET_DATA_OFFSET + read_ptr);
+ met_dump_buf[met_buf_offset] = value;
+ met_buf_offset++;
+ if (met_buf_offset >= MET_DUMP_MAX_NUM) {
+ met_buf_offset = 0;
+ osal_buffer_dump_data(met_dump_buf, "MCU_MET_DATA:", MET_DUMP_MAX_NUM,
+ MET_DUMP_MAX_NUM,
+ log_ctrl);
+ }
+ }
+ CONSYS_REG_WRITE(emi_met_base, read_ptr);
+ }
+ osal_usleep_range(CONSYS_MET_WAIT, CONSYS_MET_WAIT);
+ }
+
+met_exit:
+ osal_free(met_dump_buf);
+ iounmap(emi_met_base);
+ WMT_INFO_FUNC("met thread exits succeed\n");
+
+ return 0;
+};
+
+static VOID wmt_lib_wmtd_worker_thread_timeout_handler(timer_handler_arg arg)
+{
+ schedule_work(&gDevWmt.wmtd_worker_thread_work);
+}
+
+static VOID wmt_lib_wmtd_worker_thread_work_handler(struct work_struct *work)
+{
+ PUINT8 pbuf = NULL;
+ INT32 len = 0;
+ P_OSAL_OP pOp;
+
+ pOp = wmt_lib_get_worker_op(&gDevWmt);
+ if (pOp) {
+ switch (pOp->op.opId) {
+ case WMT_OPID_WLAN_PROBE:
+ pbuf = "DrvWMT turn on wifi fail, just collect SYS_FTRACE to DB";
+ len = osal_strlen(pbuf);
+ break;
+ case WMT_OPID_WLAN_REMOVE:
+ pbuf = "DrvWMT turn off wifi fail, just collect SYS_FTRACE to DB";
+ len = osal_strlen(pbuf);
+ break;
+ default:
+ pbuf = "DrvWMT unknown op fail, just collect SYS_FTRACE to DB";
+ len = osal_strlen(pbuf);
+ break;
+ }
+ wmt_lib_trigger_assert_keyword(WMTDRV_TYPE_WIFI, 0, pbuf);
+ }
+}
+
+static INT32 wmtd_worker_thread(void *pvData)
+{
+ P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData;
+ P_OSAL_EVENT pEvent = NULL;
+ P_OSAL_OP pOp;
+ INT32 iResult = 0;
+
+ pEvent = &(pWmtDev->rWmtdWorkerWq);
+
+ for (;;) {
+ osal_thread_wait_for_event(&pWmtDev->worker_thread, pEvent, wmt_lib_worker_wait_event_checker);
+
+ if (osal_thread_should_stop(&pWmtDev->worker_thread)) {
+ WMT_INFO_FUNC("wmtd worker thread should stop now...\n");
+ /* TODO: clean up active opQ */
+ break;
+ }
+
+ /* get Op from activeWorkerQ */
+ pOp = wmt_lib_get_op(&pWmtDev->rWorkerOpQ);
+ if (!pOp) {
+ WMT_WARN_FUNC("get activeWorkerQ fail\n");
+ continue;
+ }
+ osal_op_history_save(&pWmtDev->worker_op_history, pOp);
+
+ if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) {
+ iResult = -2;
+ WMT_WARN_FUNC("Whole chip resetting, opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult);
+ } else {
+ WMT_WARN_FUNC("opid: 0x%x", pOp->op.opId);
+ wmt_lib_set_worker_op(pWmtDev, pOp);
+ osal_timer_start(&gDevWmt.worker_timer, MAX_FUNC_ON_TIME);
+ iResult = wmt_core_opid(&pOp->op);
+ osal_timer_stop(&gDevWmt.worker_timer);
+ wmt_lib_set_worker_op(pWmtDev, NULL);
+ }
+
+ if (iResult)
+ WMT_WARN_FUNC("opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult);
+
+ if (atomic_dec_and_test(&pOp->ref_count))
+ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp);
+ else if (osal_op_is_wait_for_signal(pOp))
+ osal_op_raise_signal(pOp, iResult);
+ }
+
+ return 0;
+}
+
+static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp)
+{
+ INT32 iRet;
+
+ if (!pOpQ || !pOp) {
+ WMT_WARN_FUNC("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", pOpQ, pOp);
+ osal_assert(pOpQ);
+ osal_assert(pOp);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ iRet = osal_lock_sleepable_lock(&pOpQ->sLock);
+ if (iRet) {
+ WMT_WARN_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD)
+ if (osal_opq_has_op(pOpQ, pOp)) {
+ WMT_ERR_FUNC("Op(%p) already exists in queue(%p)\n", pOp, pOpQ);
+ iRet = -2;
+ }
+#endif
+
+ /* acquire lock success */
+ if (!RB_FULL(pOpQ))
+ RB_PUT(pOpQ, pOp);
+ else {
+ WMT_WARN_FUNC("RB_FULL(%p -> %p)\n", pOp, pOpQ);
+ iRet = -1;
+ }
+
+ osal_unlock_sleepable_lock(&pOpQ->sLock);
+
+ if (iRet) {
+ osal_opq_dump("FreeOpQ", &gDevWmt.rFreeOpQ);
+ osal_opq_dump("ActiveOpQ", &gDevWmt.rActiveOpQ);
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+
+static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ)
+{
+ P_OSAL_OP pOp;
+ INT32 iRet;
+
+ if (pOpQ == NULL) {
+ WMT_ERR_FUNC("pOpQ = NULL\n");
+ osal_assert(pOpQ);
+ return NULL;
+ }
+
+ iRet = osal_lock_sleepable_lock(&pOpQ->sLock);
+ if (iRet) {
+ WMT_ERR_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet);
+ return NULL;
+ }
+
+ /* acquire lock success */
+ RB_GET(pOpQ, pOp);
+ osal_unlock_sleepable_lock(&pOpQ->sLock);
+
+ if (pOp == NULL) {
+ P_OSAL_OP pCurOp = wmt_lib_get_current_op(&gDevWmt);
+
+ WMT_WARN_FUNC("RB_GET(%p) return NULL\n", pOpQ);
+ if (pCurOp != NULL)
+ WMT_WARN_FUNC("Current opId (%d)\n", pCurOp->op.opId);
+
+ wmt_lib_print_wmtd_op_history();
+ wmt_lib_print_worker_op_history();
+ osal_opq_dump("FreeOpQ", &gDevWmt.rFreeOpQ);
+ osal_opq_dump("ActiveOpQ", &gDevWmt.rActiveOpQ);
+ osal_assert(pOp);
+ }
+
+ return pOp;
+}
+
+
+INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ if (wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp) == MTK_WCN_BOOL_FALSE)
+ return -1;
+
+ return 0;
+}
+
+
+P_OSAL_OP wmt_lib_get_free_op(VOID)
+{
+ P_OSAL_OP pOp = NULL;
+ P_DEV_WMT pDevWmt = &gDevWmt;
+
+ osal_assert(pDevWmt);
+ pOp = wmt_lib_get_op(&pDevWmt->rFreeOpQ);
+ if (pOp) {
+ osal_memset(pOp, 0, osal_sizeof(OSAL_OP));
+ }
+ return pOp;
+}
+
+MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_OSAL_SIGNAL pSignal = NULL;
+ INT32 waitRet = -1;
+
+ osal_assert(pWmtDev);
+ osal_assert(pOp);
+
+ do {
+ if (!pWmtDev || !pOp) {
+ WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp);
+ break;
+ }
+
+ /* Init ref_count to 1 indicating that current thread holds a ref to it */
+ atomic_set(&pOp->ref_count, 1);
+
+ if ((mtk_wcn_stp_coredump_start_get() != 0) &&
+ (pOp->op.opId != WMT_OPID_HW_RST) &&
+ (pOp->op.opId != WMT_OPID_SW_RST) && (pOp->op.opId != WMT_OPID_GPIO_STATE)) {
+ WMT_WARN_FUNC("block tx flag is set\n");
+ break;
+ }
+ pSignal = &pOp->signal;
+/* pOp->u4WaitMs = u4WaitMs; */
+ if (pSignal->timeoutValue) {
+ pOp->result = -9;
+ osal_signal_init(pSignal);
+ }
+
+ /* Increment ref_count by 1 as wmtd thread will hold a reference also,
+ * this must be done here instead of on target thread, because
+ * target thread might not be scheduled until a much later time,
+ * allowing current thread to decrement ref_count at the end of function,
+ * putting op back to free queue before target thread has a chance to process.
+ */
+ atomic_inc(&pOp->ref_count);
+
+ /* put to active Q */
+ bRet = wmt_lib_put_op(&pWmtDev->rActiveOpQ, pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("put to active queue fail\n");
+ atomic_dec(&pOp->ref_count);
+ break;
+ }
+
+ /* wake up wmtd */
+ /* wake_up_interruptible(&pWmtDev->rWmtdWq); */
+ osal_trigger_event(&pWmtDev->rWmtdWq);
+
+ if (pSignal->timeoutValue == 0) {
+ bRet = MTK_WCN_BOOL_TRUE;
+ /* clean it in wmtd */
+ break;
+ }
+
+ /* check result */
+ /* wait_ret = wait_for_completion_interruptible_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */
+ /* wait_ret = wait_for_completion_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */
+ if (pOp->op.opId == WMT_OPID_FUNC_ON &&
+ pOp->op.au4OpData[0] == WMTDRV_TYPE_WIFI)
+ waitRet = osal_wait_for_signal_timeout(pSignal, &pWmtDev->worker_thread);
+ else
+ waitRet = osal_wait_for_signal_timeout(pSignal, &pWmtDev->thread);
+ WMT_DBG_FUNC("osal_wait_for_signal_timeout:%d\n", waitRet);
+
+ /* if (unlikely(!wait_ret)) { */
+ if (waitRet == 0)
+ WMT_ERR_FUNC("opId(%d) completion timeout\n", pOp->op.opId);
+ else if (pOp->result)
+ WMT_WARN_FUNC("opId(%d) result:%d\n", pOp->op.opId, pOp->result);
+
+ /* op completes, check result */
+ bRet = (pOp->result) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE;
+ } while (0);
+
+ if (pOp && atomic_dec_and_test(&pOp->ref_count)) {
+ /* put Op back to freeQ */
+ wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp);
+ }
+
+ return bRet;
+}
+
+MTK_WCN_BOOL wmt_lib_put_worker_op(P_OSAL_OP pOp)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+
+ osal_assert(pWmtDev);
+ osal_assert(pOp);
+
+ do {
+ if (!pWmtDev || !pOp) {
+ WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp);
+ break;
+ }
+
+ /* put to activeWorker Q */
+ bRet = wmt_lib_put_op(&pWmtDev->rWorkerOpQ, pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("put to ActiveWorker queue fail\n");
+ break;
+ }
+
+ /* wake up wmtd_worker */
+ osal_trigger_event(&pWmtDev->rWmtdWorkerWq);
+ } while (0);
+
+ return bRet;
+}
+
+/* TODO:[ChangeFeature][George] is this function obsoleted? */
+#if 0
+INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask)
+{
+ P_WMT_LXOP lxop;
+ MTK_WCN_BOOL bRet;
+ PUINT32 plv = NULL;
+ UINT32 pbuf[2];
+ P_OSAL_EVENT pSignal = NULL;
+
+ if (!pvalue) {
+ WMT_WARN_FUNC("!pvalue\n");
+ return -1;
+ }
+ lxop = wmt_lib_get_free_lxop();
+ if (!lxop) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+
+ return -1;
+ }
+
+ plv = (PUINT32) (((UINT32) pbuf + 0x3) & ~0x3UL);
+ *plv = *pvalue;
+ pSignal = &lxop->signal;
+ WMT_DBG_FUNC("OPID_REG_RW isWrite(%d) offset(0x%x) value(0x%x) mask(0x%x)\n",
+ isWrite, offset, *pvalue, mask);
+
+ lxop->op.opId = WMT_OPID_REG_RW;
+ lxop->op.au4OpData[0] = isWrite;
+ lxop->op.au4OpData[1] = offset;
+ lxop->op.au4OpData[2] = (UINT32) plv;
+ lxop->op.au4OpData[3] = mask;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+
+ DISABLE_PSM_MONITOR();
+ bRet = wmt_lib_put_act_lxop(lxop);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet != MTK_WCN_BOOL_FALSE) {
+ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n",
+ isWrite, offset, *plv, mask);
+ if (!isWrite)
+ *pvalue = *plv;
+ } else {
+ WMT_WARN_FUNC
+ ("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n",
+ isWrite, offset, *plv, mask, bRet);
+ }
+
+ return bRet;
+}
+#endif
+
+/* TODO:[ChangeFeature][George] is this function obsoleted? */
+#if 0
+static VOID wmt_lib_clear_chip_id(VOID)
+{
+/*
+ * gDevWmt.pChipInfo = NULL;
+*/
+ gDevWmt.hw_ver = WMTHWVER_INVALID;
+}
+#endif
+
+UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T index)
+{
+ UINT32 chip_id = 0;
+
+ if (index == WMTCHIN_CHIPID) {
+ if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ chip_id = gDevWmt.chip_id;
+ else
+ chip_id = mtk_wcn_consys_soc_chipid();
+ WMT_INFO_FUNC("chip_id=[%x]", chip_id);
+ return chip_id;
+ } else if (index == WMTCHIN_HWVER)
+ return gDevWmt.hw_ver;
+ else if (index == WMTCHIN_FWVER)
+ return gDevWmt.fw_ver;
+ else if (index == WMTCHIN_IPVER)
+ return gDevWmt.ip_ver;
+ else if (index == WMTCHIN_ADIE)
+ return mtk_wcn_consys_get_adie_chipid();
+
+ return 0;
+
+}
+
+
+PUINT8 wmt_lib_def_patch_name(VOID)
+{
+ WMT_INFO_FUNC("wmt-lib: use default patch name (%s)\n", gDevWmt.cPatchName);
+ return gDevWmt.cPatchName;
+}
+
+
+MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(ENUM_WMTTHERM_TYPE_T eType)
+{
+ MTK_WCN_BOOL bIsSupportTherm = MTK_WCN_BOOL_TRUE;
+ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */
+ if ((gDevWmt.chip_id == 0x6620) && (gDevWmt.hw_ver == 0x8A00 /*E1*/ || gDevWmt.hw_ver == 0x8A01 /*E2*/)) {
+ WMT_ERR_FUNC("thermal command fail: chip version(HWVER:0x%04x) is not valid\n",
+ gDevWmt.hw_ver);
+ bIsSupportTherm = MTK_WCN_BOOL_FALSE;
+ }
+ if ((!osal_test_bit(WMT_STAT_STP_EN, &gDevWmt.state))
+ || (!osal_test_bit(WMT_STAT_STP_RDY, &gDevWmt.state))) {
+ if (eType == WMTTHERM_READ)
+ WMT_INFO_FUNC
+ ("thermal command can`t send: STP is not enable(%d) or ready(%d)\n",
+ osal_test_bit(WMT_STAT_STP_EN, &gDevWmt.state),
+ osal_test_bit(WMT_STAT_STP_RDY, &gDevWmt.state));
+ bIsSupportTherm = MTK_WCN_BOOL_FALSE;
+ }
+
+ return bIsSupportTherm;
+}
+
+MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID)
+{
+ /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */
+ if ((gDevWmt.chip_id == 0x6620) && (gDevWmt.hw_ver == 0x8A00 /*E1*/ || gDevWmt.hw_ver == 0x8A01 /*E2*/)) {
+ WMT_ERR_FUNC("thermal command fail: chip version(HWVER:0x%04x) is not valid\n",
+ gDevWmt.hw_ver);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+/*!
+ * \brief Update combo chip pin settings (GPIO)
+ *
+ * An internal library function to support various settings for chip GPIO. It is
+ * updated in a grouping way: configure all required pins in a single call.
+ *
+ * \param id desired pin ID to be controlled
+ * \param stat desired pin states to be set
+ * \param flag supplementary options for this operation
+ *
+ * \retval 0 operation success
+ * \retval -1 invalid id
+ * \retval -2 invalid stat
+ * \retval < 0 error for operation fail
+ */
+static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ /* input sanity check */
+ if (id >= WMT_IC_PIN_MAX) {
+ WMT_ERR_FUNC("invalid ic pin id(%d)\n", id);
+ return -1;
+ }
+ if (stat >= WMT_IC_PIN_STATE_MAX) {
+ WMT_ERR_FUNC("invalid ic pin state (%d)\n", stat);
+ return -2;
+ }
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_DBG_FUNC("call WMT_OPID_GPIO_CTRL (ic pin id:%d, stat:%d, flag:0x%x)\n", id, stat,
+ flag);
+
+ pSignal = &pOp->signal;
+ pOp->op.opId = WMT_OPID_GPIO_CTRL;
+ pOp->op.au4OpData[0] = id;
+ pOp->op.au4OpData[1] = stat;
+ pOp->op.au4OpData[2] = flag;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+
+ /*wake up chip first */
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE)
+ WMT_WARN_FUNC("PIN_ID(%d) PIN_STATE(%d) flag(%d) fail\n", id, stat, flag);
+ else
+ WMT_DBG_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]);
+
+ return 0;
+}
+
+INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ UINT32 value;
+ P_OSAL_SIGNAL pSignal;
+
+ if (!pvalue) {
+ WMT_WARN_FUNC("!pvalue\n");
+ return -1;
+ }
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_WMT_OP_TIMEOUT;
+ value = *pvalue;
+ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n",
+ isWrite, offset, *pvalue, mask);
+ pOp->op.opId = WMT_OPID_REG_RW;
+ pOp->op.au4OpData[0] = isWrite;
+ pOp->op.au4OpData[1] = offset;
+ pOp->op.au4OpData[2] = (size_t) &value;
+ pOp->op.au4OpData[3] = mask;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet != MTK_WCN_BOOL_FALSE) {
+ WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n",
+ isWrite, offset, value, mask);
+ if (!isWrite)
+ *pvalue = value;
+
+ return 0;
+ }
+ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n",
+ isWrite, offset, value, mask, bRet);
+
+ return -1;
+}
+
+INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ UINT32 value;
+ P_OSAL_SIGNAL pSignal;
+
+ if (!pvalue) {
+ WMT_WARN_FUNC("!pvalue\n");
+ return -1;
+ }
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_WMT_OP_TIMEOUT;
+ value = *pvalue;
+ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n",
+ isWrite, offset, *pvalue, mask);
+ pOp->op.opId = WMT_OPID_EFUSE_RW;
+ pOp->op.au4OpData[0] = isWrite;
+ pOp->op.au4OpData[1] = offset;
+ pOp->op.au4OpData[2] = (size_t) &value;
+ pOp->op.au4OpData[3] = mask;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet != MTK_WCN_BOOL_FALSE) {
+ WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n",
+ isWrite, offset, value, mask);
+ if (!isWrite)
+ *pvalue = value;
+ return 0;
+ }
+ WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n",
+ isWrite, offset, value, mask, bRet);
+ return -1;
+}
+
+INT32 wmt_lib_utc_time_sync(VOID)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_WARN_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+ pOp->op.opId = WMT_OPID_UTC_TIME_SYNC;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -2;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_UTC_TIME_SYNC fail(%d)\n", bRet);
+ return -3;
+ }
+ WMT_DBG_FUNC("wmt_lib_utc_time_sync OPID(%d) ok\n", pOp->op.opId);
+
+ return 0;
+}
+
+INT32 wmt_lib_try_pwr_off(VOID)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_WARN_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_FUNC_OFF_TIME;
+ pOp->op.opId = WMT_OPID_TRY_PWR_OFF;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -2;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_TRY_PWR_OFF fail(%d)\n", bRet);
+ return -2;
+ }
+ WMT_DBG_FUNC("wmt_lib_try_pwr_off OPID(%d) ok\n", pOp->op.opId);
+
+ return 0;
+}
+
+P_WMT_PATCH_INFO wmt_lib_get_patch_info(VOID)
+{
+ return gDevWmt.pWmtPatchInfo;
+}
+
+/*!
+ * \brief update combo chip AUDIO Interface (AIF) settings
+ *
+ * A library function to support updating chip AUDIO pin settings. A group of
+ * pins is updated as a whole.
+ *
+ * \param aif desired audio interface state to use
+ * \param flag whether audio pin is shared or not
+ *
+ * \retval 0 operation success
+ * \retval -1 invalid aif
+ * \retval < 0 error for invalid parameters or operation fail
+ */
+INT32 wmt_lib_set_aif(enum CMB_STUB_AIF_X aif, MTK_WCN_BOOL share)
+{
+ if (aif < 0 || aif >= CMB_STUB_AIF_MAX) {
+ WMT_ERR_FUNC("invalid aif (%d)\n", aif);
+ return -1;
+ }
+ WMT_DBG_FUNC("call pin_ctrl for aif:%d, share:%d\n", aif,
+ (share == MTK_WCN_BOOL_TRUE) ? 1 : 0);
+ /* Translate enum CMB_STUB_AIF_X into WMT_IC_PIN_STATE by array */
+ return wmt_lib_pin_ctrl(WMT_IC_PIN_AUDIO,
+ cmb_aif2pin_stat[aif],
+ (MTK_WCN_BOOL_TRUE ==
+ share) ? WMT_LIB_AIF_FLAG_SHARE : WMT_LIB_AIF_FLAG_SEPARATE);
+}
+
+INT32 wmt_lib_host_awake_get(VOID)
+{
+ return wmt_plat_wake_lock_ctrl(WL_OP_GET);
+}
+
+INT32 wmt_lib_host_awake_put(VOID)
+{
+ return wmt_plat_wake_lock_ctrl(WL_OP_PUT);
+}
+
+MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op)
+{
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+
+ if (op == BTM_RST_OP) {
+ /* high priority, not to enqueue into the queue of wmtd */
+ WMT_INFO_FUNC("Invoke whole chip reset from stp_btm!!!\n");
+ wmt_lib_cmb_rst(WMTRSTSRC_RESET_STP);
+ bRet = MTK_WCN_BOOL_TRUE;
+ } else if (op == BTM_DMP_OP) {
+
+ WMT_WARN_FUNC("TBD!!!\n");
+ } else if (op == BTM_GET_AEE_SUPPORT_FLAG) {
+ bRet = wmt_core_get_aee_dump_flag();
+ } else if (op == BTM_TRIGGER_STP_ASSERT_OP) {
+ bRet = wmt_core_trigger_stp_assert();
+ }
+ return bRet;
+}
+
+MTK_WCN_BOOL wmt_cdev_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg)
+{
+
+ INT32 i = 0;
+ P_DEV_WMT pDevWmt = &gDevWmt;
+ UINT8 *drv_name[] = {
+ "DRV_TYPE_BT",
+ "DRV_TYPE_FM",
+ "DRV_TYPE_GPS",
+ "DRV_TYPE_WIFI",
+ "DRV_TYPE_ANT",
+ "UNKNOWN"
+ };
+
+ for (i = 0; i <= WMTDRV_TYPE_ANT; i++) {
+ /* <1> check if reset callback is registered */
+ if (pDevWmt->rFdrvCb.fDrvRst[i]) {
+ /* <2> send the msg to this subfucntion */
+ /*src, dst, msg_type, msg_data, msg_size */
+ pDevWmt->rFdrvCb.fDrvRst[i] (WMTDRV_TYPE_WMT, i, WMTMSG_TYPE_RESET, &msg,
+ sizeof(ENUM_WMTRSTMSG_TYPE_T));
+ WMT_INFO_FUNC("type = %s, msg sent\n", drv_name[i]);
+ } else {
+ WMT_DBG_FUNC("type = %s, unregistered\n", drv_name[i]);
+ }
+ }
+
+ return MTK_WCN_BOOL_TRUE;
+}
+
+VOID wmt_lib_state_init(VOID)
+{
+ /* UINT32 i = 0; */
+ P_DEV_WMT pDevWmt = &gDevWmt;
+ P_OSAL_OP pOp;
+
+ /* Initialize op queue */
+ /* RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); */
+ /* RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); */
+
+ while (!RB_EMPTY(&pDevWmt->rActiveOpQ)) {
+ pOp = wmt_lib_get_op(&pDevWmt->rActiveOpQ);
+ if (pOp) {
+ if (atomic_dec_and_test(&pOp->ref_count))
+ wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp);
+ else if (osal_op_is_wait_for_signal(pOp))
+ osal_op_raise_signal(pOp, -1);
+ }
+ }
+}
+
+
+INT32 wmt_lib_sdio_ctrl(UINT32 on)
+{
+
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_DBG_FUNC("call WMT_OPID_SDIO_CTRL\n");
+
+ pSignal = &pOp->signal;
+ pOp->op.opId = WMT_OPID_SDIO_CTRL;
+ pOp->op.au4OpData[0] = on;
+ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME;
+
+
+ bRet = wmt_lib_put_act_op(pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_SDIO_CTRL failed\n");
+ return -1;
+ }
+ WMT_DBG_FUNC("OPID(WMT_OPID_SDIO_CTRL)ok\n");
+ return 0;
+}
+
+MTK_WCN_BOOL wmt_lib_hw_state_show(VOID)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_DBG_FUNC("call WMT_OPID_HW_STATE_SHOW\n");
+
+ pSignal = &pOp->signal;
+ pOp->op.opId = WMT_OPID_GPIO_STATE;
+ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME;
+
+ bRet = wmt_lib_put_act_op(pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_HW_STATE_SHOW failed\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ WMT_DBG_FUNC("OPID(WMT_OPID_HW_STATE_SHOW)ok\n");
+
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+MTK_WCN_BOOL wmt_lib_hw_rst(VOID)
+{
+
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+ P_DEV_WMT pDevWmt = &gDevWmt;
+
+ wmt_lib_state_init();
+
+ osal_clear_bit(WMT_STAT_STP_REG, &pDevWmt->state);
+ osal_clear_bit(WMT_STAT_STP_OPEN, &pDevWmt->state);
+ osal_clear_bit(WMT_STAT_STP_EN, &pDevWmt->state);
+ osal_clear_bit(WMT_STAT_STP_RDY, &pDevWmt->state);
+ osal_clear_bit(WMT_STAT_RX, &pDevWmt->state);
+ osal_clear_bit(WMT_STAT_CMD, &pDevWmt->state);
+
+ /*Before do hardware reset, we show GPIO state to check if others modified our pin state accidentially */
+ wmt_lib_hw_state_show();
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_DBG_FUNC("call WMT_OPID_HW_RST\n");
+
+ pSignal = &pOp->signal;
+ pOp->op.opId = WMT_OPID_HW_RST;
+ pSignal->timeoutValue = MAX_GPIO_CTRL_TIME;
+
+
+ bRet = wmt_lib_put_act_op(pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_HW_RST failed\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ WMT_DBG_FUNC("OPID(WMT_OPID_HW_RST)ok\n");
+
+ return MTK_WCN_BOOL_TRUE;
+}
+
+MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst)
+{
+
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ /* <1> wmt state reset */
+ wmt_lib_state_init();
+
+ /* <2> Reset STP data structure */
+ WMT_DBG_FUNC("Cleanup STP context\n");
+ mtk_wcn_stp_flush_context();
+ stp_dbg_reset();
+
+ /* <3> Reset STP-PSM data structure */
+ WMT_DBG_FUNC("Cleanup STP-PSM context\n");
+ mtk_wcn_stp_psm_reset();
+
+ /* <4> do sw reset in wmt-core */
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_WARN_FUNC("get_free_lxop fail\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ WMT_DBG_FUNC("call WMT_OPID_SW_RST\n");
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_FUNC_ON_TIME;
+
+ pOp->op.opId = WMT_OPID_SW_RST;
+ pOp->op.au4OpData[0] = baudRst;
+
+
+
+ bRet = wmt_lib_put_act_op(pOp);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_SW_RST failed\n");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ WMT_DBG_FUNC("OPID(WMT_OPID_SW_RST)ok\n");
+
+ return MTK_WCN_BOOL_TRUE;
+}
+
+
+ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src)
+{
+#define RETRYTIMES 10
+ MTK_WCN_BOOL bRet;
+ ENUM_WMTRSTRET_TYPE_T retval = WMTRSTRET_MAX;
+ ENUM_WMTRSTMSG_TYPE_T rstMsg = WMTRSTMSG_RESET_MAX;
+ INT32 retries = RETRYTIMES;
+ P_DEV_WMT pDevWmt = &gDevWmt;
+ P_OSAL_OP pOp;
+ UINT8 *srcName[] = { "WMTRSTSRC_RESET_BT",
+ "WMTRSTSRC_RESET_FM",
+ "WMTRSTSRC_RESET_GPS",
+ "WMTRSTSRC_RESET_WIFI",
+ "WMTRSTSRC_RESET_STP",
+ "WMTRSTSRC_RESET_TEST"
+ };
+ INT32 coredump_mode = mtk_wcn_stp_coredump_flag_get();
+
+ WMT_INFO_FUNC("coredump mode == %d. Connsys coredump is %s.",
+ coredump_mode, coredump_mode ? "enabled" : "disabled");
+
+ if (src >= 0 && src < WMTRSTSRC_RESET_MAX)
+ WMT_INFO_FUNC("reset source = %s\n", srcName[src]);
+
+ if (src == WMTRSTSRC_RESET_TEST) {
+ pOp = wmt_lib_get_current_op(pDevWmt);
+ if (pOp && ((pOp->op.opId == WMT_OPID_FUNC_ON)
+ || (pOp->op.opId == WMT_OPID_FUNC_OFF))) {
+ WMT_INFO_FUNC("can't do reset by test src when func on/off\n");
+ return -1;
+ }
+ }
+ /* <1> Consider the multi-context combo_rst case. */
+ if (osal_test_and_set_bit(WMT_STAT_RST_ON, &pDevWmt->state)) {
+ retval = WMTRSTRET_ONGOING;
+ goto rstDone;
+ }
+ /* <2> Block all STP request */
+ if (wmt_lib_psm_lock_trylock() == 0) {
+ if (chip_reset_only == 1) {
+ wmt_lib_fw_patch_update_rst_ctrl(1);
+ fw_patch_rst_time = 0;
+ retval = WMTRSTRET_RETRY;
+ goto rstDone;
+ }
+ mtk_wcn_stp_enable(0);
+ } else {
+ mtk_wcn_stp_enable(0);
+ wmt_lib_psm_lock_release();
+ }
+
+ /* <3> RESET_START notification */
+ bRet = wmt_cdev_rstmsg_snd(WMTRSTMSG_RESET_START);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n");
+ retval = WMTRSTRET_FAIL;
+ goto rstDone;
+ }
+ /* wakeup blocked opid */
+ pOp = wmt_lib_get_current_op(pDevWmt);
+ if (osal_op_is_wait_for_signal(pOp))
+ osal_op_raise_signal(pOp, -1);
+ /* wakeup blocked cmd */
+ wmt_dev_rx_event_cb();
+
+ /* <4> retry until reset flow successful */
+ while (retries > 0) {
+ /* <4.1> reset combo hw */
+ bRet = wmt_lib_hw_rst();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_hw_rst!\n");
+ retries--;
+ continue;
+ }
+ /* <4.2> reset driver/combo sw */
+ bRet = wmt_lib_sw_rst(1);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_sw_rst!\n");
+ retries--;
+ continue;
+ }
+ break;
+ }
+ osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ rstMsg = WMTRSTMSG_RESET_END_FAIL;
+ WMT_INFO_FUNC("[whole chip reset] fail! retries = %d\n", RETRYTIMES - retries);
+ } else {
+ rstMsg = WMTRSTMSG_RESET_END;
+ WMT_INFO_FUNC("[whole chip reset] ok! retries = %d\n", RETRYTIMES - retries);
+ }
+
+
+ /* <5> RESET_END notification */
+ bRet = wmt_cdev_rstmsg_snd(rstMsg);
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n");
+ retval = WMTRSTRET_FAIL;
+ } else {
+ retval = rstMsg == WMTRSTMSG_RESET_END ? WMTRSTRET_SUCCESS : WMTRSTRET_FAIL;
+ }
+ mtk_wcn_stp_assert_flow_ctrl(0);
+ mtk_wcn_stp_coredump_start_ctrl(0);
+ mtk_wcn_stp_set_wmt_trg_assert(0);
+ mtk_wcn_stp_emi_dump_flag_ctrl(0);
+rstDone:
+ osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state);
+ chip_reset_only = 0;
+ mtk_wcn_consys_sleep_info_restore();
+ return retval;
+}
+
+
+MTK_WCN_BOOL wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb)
+{
+
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ if (eType >= 0 && eType <= WMTDRV_TYPE_ANT) {
+ WMT_DBG_FUNC("reg ok!\n");
+ pWmtDev->rFdrvCb.fDrvRst[eType] = pCb;
+ bRet = MTK_WCN_BOOL_TRUE;
+ } else {
+ WMT_WARN_FUNC("reg fail!\n");
+ }
+
+ return bRet;
+}
+
+MTK_WCN_BOOL wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType)
+{
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) {
+ WMT_DBG_FUNC("unreg ok!\n");
+ pWmtDev->rFdrvCb.fDrvRst[eType] = NULL;
+ bRet = MTK_WCN_BOOL_TRUE;
+ } else {
+ WMT_WARN_FUNC("unreg fail!\n");
+ }
+
+ return bRet;
+}
+
+
+UINT32 wmt_lib_dbg_level_set(UINT32 level)
+{
+ gWmtDbgLvl = level > WMT_LOG_LOUD ? WMT_LOG_LOUD : level;
+ return 0;
+}
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 wmt_lib_deep_sleep_ctrl(INT32 value)
+{
+ MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE;
+
+ WMT_INFO_FUNC("g_deep_sleep_flag value (%d) set form wmt_dbg.\n", value);
+ ret = wmt_core_deep_sleep_ctrl(value);
+ if (sdio_deep_sleep_flag_set) {
+ if (value)
+ (*sdio_deep_sleep_flag_set)(MTK_WCN_BOOL_TRUE);
+ else
+ (*sdio_deep_sleep_flag_set)(MTK_WCN_BOOL_FALSE);
+ } else {
+ WMT_ERR_FUNC("sdio_deep_sleep_flag_set is not register");
+ return -1;
+ }
+ return 0;
+}
+
+MTK_WCN_BOOL wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL flag)
+{
+ if (sdio_deep_sleep_flag_set) {
+ (*sdio_deep_sleep_flag_set)(flag);
+ } else {
+ WMT_ERR_FUNC("sdio_deep_sleep_flag_set is not register");
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return MTK_WCN_BOOL_TRUE;
+}
+#endif
+INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value)
+{
+ return mtk_wcn_stp_set_wmt_last_close(value);
+}
+
+INT32 wmt_lib_notify_stp_sleep(VOID)
+{
+ INT32 iRet = 0x0;
+
+ iRet = wmt_lib_psm_lock_aquire();
+ if (iRet) {
+ WMT_ERR_FUNC("--->lock psm_lock failed, iRet=%d\n", iRet);
+ return iRet;
+ }
+
+ iRet = mtk_wcn_stp_notify_sleep_for_thermal();
+ wmt_lib_psm_lock_release();
+
+ return iRet;
+}
+
+VOID wmt_lib_set_patch_num(UINT32 num)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ pWmtDev->patchNum = num;
+}
+
+VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ pWmtDev->pWmtPatchInfo = pPatchinfo;
+}
+
+VOID wmt_lib_set_rom_patch_info(struct wmt_rom_patch_info *PatchInfo, ENUM_WMTDRV_TYPE_T type)
+{
+ P_DEV_WMT pWmtDev = &gDevWmt;
+
+ if (type < 0)
+ return;
+
+ /* Allow info of a type to be set only once, to avoid inproper usage */
+ if (pWmtDev->pWmtRomPatchInfo[type])
+ return;
+
+ pWmtDev->pWmtRomPatchInfo[type] = kcalloc(1, sizeof(struct wmt_rom_patch_info),
+ GFP_ATOMIC);
+
+ if (pWmtDev->pWmtRomPatchInfo[type])
+ osal_memcpy(pWmtDev->pWmtRomPatchInfo[type], PatchInfo,
+ sizeof(struct wmt_rom_patch_info));
+}
+
+INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp)
+{
+ if (pWmtDev) {
+ pWmtDev->pCurOP = pOp;
+ WMT_DBG_FUNC("pOp=0x%p\n", pOp);
+ return 0;
+ }
+ WMT_ERR_FUNC("Invalid pointer\n");
+ return -1;
+}
+
+P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev)
+{
+ if (pWmtDev)
+ return pWmtDev->pCurOP;
+ WMT_ERR_FUNC("Invalid pointer\n");
+ return NULL;
+}
+
+INT32 wmt_lib_set_worker_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp)
+{
+ if (pWmtDev) {
+ pWmtDev->pWorkerOP = pOp;
+ WMT_DBG_FUNC("pOp=0x%p\n", pOp);
+ return 0;
+ }
+ WMT_ERR_FUNC("Invalid pointer\n");
+ return -1;
+}
+
+P_OSAL_OP wmt_lib_get_worker_op(P_DEV_WMT pWmtDev)
+{
+ if (pWmtDev)
+ return pWmtDev->pWorkerOP;
+ WMT_ERR_FUNC("Invalid pointer\n");
+ return NULL;
+}
+
+UINT8 *wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, UINT8 *buf, UINT32 len)
+{
+ UINT8 *pAddr = NULL;
+ UINT32 sublen1 = 0;
+ UINT32 sublen2 = 0;
+ P_CONSYS_EMI_ADDR_INFO p_consys_info;
+
+ p_consys_info = wmt_plat_get_emi_phy_add();
+ osal_assert(p_consys_info);
+
+ if (section == 0) {
+ pAddr = wmt_plat_get_emi_virt_add(0x0);
+ if (len > 1024)
+ len = 1024;
+ if (!pAddr) {
+ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n");
+ } else {
+ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr);
+ osal_memcpy_fromio(&buf[0], pAddr, len);
+ }
+ } else {
+ if (p_consys_info == NULL) {
+ WMT_ERR_FUNC("wmt-lib: get EMI physical address fail!\n");
+ return 0;
+ }
+
+ if (offset >= 0x7fff)
+ offset = 0x0;
+
+ if (offset + len > 32768) {
+ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off);
+ if (!pAddr) {
+ WMT_ERR_FUNC("wmt-lib: get part1 EMI virtual base address fail\n");
+ } else {
+ WMT_INFO_FUNC("part1 vir addr(0x%p)\n", pAddr);
+ sublen1 = 0x7fff - offset;
+ osal_memcpy_fromio(&buf[0], pAddr, sublen1);
+ }
+ pAddr = wmt_plat_get_emi_virt_add(p_consys_info->paged_trace_off);
+ if (!pAddr) {
+ WMT_ERR_FUNC("wmt-lib: get part2 EMI virtual base address fail\n");
+ } else {
+ WMT_INFO_FUNC("part2 vir addr(0x%p)\n", pAddr);
+ sublen2 = len - sublen1;
+ osal_memcpy_fromio(&buf[sublen1], pAddr, sublen2);
+ }
+ } else {
+ pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off);
+ if (!pAddr) {
+ WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n");
+ } else {
+ WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr);
+ osal_memcpy_fromio(&buf[0], pAddr, len);
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(wmt_lib_get_fwinfor_from_emi);
+
+INT32 wmt_lib_merge_if_flag_ctrl(UINT32 enable)
+{
+#if WMT_PLAT_ALPS
+ return wmt_plat_merge_if_flag_ctrl(enable);
+#endif
+}
+
+
+INT32 wmt_lib_merge_if_flag_get(UINT32 enable)
+{
+#if WMT_PLAT_ALPS
+ return wmt_plat_merge_if_flag_get();
+#endif
+}
+
+
+PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 pLen)
+{
+ PUINT8 temp;
+
+ osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE);
+ temp = g_cpupcr_buf;
+ *pLen += stp_dbg_cpupcr_infor_format(temp, WMT_STP_CPUPCR_BUF_SIZE);
+ *pLen += mtk_stp_dbg_dmp_append(temp + *pLen, WMT_STP_CPUPCR_BUF_SIZE - *pLen);
+
+ WMT_INFO_FUNC("print xml buffer,len(%d):\n\n", *pLen);
+
+ WMT_INFO_FUNC("%s", g_cpupcr_buf);
+
+ return &g_cpupcr_buf[0];
+}
+
+
+/**
+ * called by wmt_dev wmt_dev_proc_for_dump_info_read
+ */
+PUINT8 wmt_lib_get_cpupcr_reg_info(PUINT32 pLen, PUINT32 consys_reg)
+{
+ osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE);
+ if (consys_reg != NULL)
+ *pLen += stp_dbg_dump_cpupcr_reg_info(g_cpupcr_buf, consys_reg[1]);
+ else
+ *pLen += osal_sprintf(g_cpupcr_buf + *pLen, "0\n");
+ WMT_INFO_FUNC("print buffer,len(%d):\n\n", *pLen);
+ WMT_INFO_FUNC("%s", g_cpupcr_buf);
+ return &g_cpupcr_buf[0];
+}
+
+INT32 wmt_lib_tm_temp_query(VOID)
+{
+ return wmt_dev_tm_temp_query();
+}
+
+INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl)
+{
+ wmt_plat_thermal_ctrl_cb_reg(thermal_ctrl);
+ return 0;
+}
+
+INT32 wmt_lib_register_trigger_assert_cb(trigger_assert_cb trigger_assert)
+{
+ wmt_plat_trigger_assert_cb_reg(trigger_assert);
+ return 0;
+}
+
+UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en)
+{
+ return stp_dbg_set_host_assert_info(type, reason, en);
+}
+
+INT8 wmt_lib_co_clock_get(void)
+{
+ if (gDevWmt.rWmtGenConf.cfgExist)
+ return gDevWmt.rWmtGenConf.co_clock_flag;
+ else
+ return -1;
+}
+
+
+UINT32 wmt_lib_get_drv_status(UINT32 type)
+{
+ return wmt_core_get_drv_status((ENUM_WMTDRV_TYPE_T) type);
+}
+
+INT32 wmt_lib_trigger_reset(VOID)
+{
+ return wmt_btm_trigger_reset();
+}
+
+INT32 wmt_lib_trigger_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason)
+{
+ return wmt_lib_trigger_assert_keyword(type, reason, NULL);
+}
+
+INT32 wmt_lib_trigger_assert_keyword(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword)
+{
+ INT32 iRet = -1;
+ WMT_CTRL_DATA ctrlData;
+
+ if (wmt_lib_assert_lock_trylock() == 0) {
+ WMT_INFO_FUNC("Can't lock assert mutex which might be held by another trigger assert procedure.\n");
+ return iRet;
+ }
+
+ wmt_core_set_coredump_state(DRV_STS_FUNC_ON);
+
+ ctrlData.ctrlId = (SIZE_T) WMT_CTRL_TRG_ASSERT;
+ ctrlData.au4CtrlData[0] = (SIZE_T) type;
+ ctrlData.au4CtrlData[1] = (SIZE_T) reason;
+ ctrlData.au4CtrlData[2] = (SIZE_T) keyword;
+
+ iRet = wmt_ctrl(&ctrlData);
+ if (iRet) {
+ /* ERROR */
+ WMT_ERR_FUNC
+ ("WMT-CORE: wmt_core_ctrl failed: type(%d), reason(%d), keyword(%s), iRet(%d)\n",
+ type, reason, keyword, iRet);
+ osal_assert(0);
+ }
+ wmt_lib_assert_lock_release();
+
+ return iRet;
+}
+
+#if CFG_WMT_PS_SUPPORT
+UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en)
+{
+ WMT_WARN_FUNC("%s quick sleep mode\n", en ? "enable" : "disable");
+ g_quick_sleep_ctrl = en;
+ return 0;
+}
+#endif
+
+UINT32 wmt_lib_fw_patch_update_rst_ctrl(UINT32 en)
+{
+ WMT_WARN_FUNC("%s fw patch update reset\n", en ? "enable" : "disable");
+ g_fw_patch_update_rst = en;
+ return 0;
+}
+
+#if CONSYS_ENALBE_SET_JTAG
+UINT32 wmt_lib_jtag_flag_set(UINT32 en)
+{
+ return wmt_plat_jtag_flag_ctrl(en);
+}
+#endif
+
+UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver)
+{
+ return stp_dbg_set_wifiver(wifiver);
+}
+
+UINT32 wmt_lib_co_clock_flag_get(VOID)
+{
+ return wmt_plat_soc_co_clock_flag_get();
+}
+
+INT32 wmt_lib_wifi_fem_cfg_report(PVOID pvInfoBuf)
+{
+ INT32 iRet = 0;
+ ULONG addr = 0;
+ WMT_GEN_CONF *pWmtGenConf = NULL;
+
+ /* sanity check */
+ ASSERT(pvInfoBuf);
+
+ iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0);
+
+ if (iRet) {
+ WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet);
+ return -2;
+ }
+
+ pWmtGenConf = (P_WMT_GEN_CONF) addr;
+
+ WMT_DBG_FUNC("pWmtGenConf->coex_wmt_wifi_path=0x%x\n", pWmtGenConf->coex_wmt_wifi_path);
+
+ /* Memory copy */
+ osal_memcpy((PUINT8)(pvInfoBuf), &pWmtGenConf->coex_wmt_wifi_path,
+ osal_sizeof(pWmtGenConf->coex_wmt_wifi_path));
+ return iRet;
+}
+
+INT32 wmt_lib_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value)
+{
+ INT32 ret = -1;
+ ENUM_WMT_CHIP_TYPE chip_type;
+
+ chip_type = wmt_detect_get_chip_type();
+
+ if (chip_type == WMT_CHIP_TYPE_COMBO) {
+ if (sdio_reg_rw)
+ ret = sdio_reg_rw(func_num, direction, offset, value);
+ else
+ WMT_ERR_FUNC("sdio_reg_rw callback is not set, maybe the sdio funcxx write/read not used\n");
+ } else
+ WMT_ERR_FUNC("It`s soc project, this function is not used\n");
+ return ret;
+}
+
+VOID wmt_lib_dump_wmtd_backtrace(VOID)
+{
+ osal_thread_show_stack(&gDevWmt.thread);
+}
+
+INT32 wmt_lib_met_cmd(UINT32 value)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+ WMT_DBG_FUNC("met ctrl value(0x%x)\n", value);
+ pOp->op.opId = WMT_OPID_MET_CTRL;
+ pOp->op.au4OpData[0] = value;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet != MTK_WCN_BOOL_FALSE)
+ return 0;
+
+ return -1;
+}
+
+UINT32 wmt_lib_get_gps_lna_pin_num(VOID)
+{
+ return mtk_consys_get_gps_lna_pin_num();
+}
+
+INT32 wmt_lib_met_ctrl(INT32 met_ctrl, INT32 log_ctrl)
+{
+ P_DEV_WMT p_devwmt;
+ P_OSAL_THREAD p_thread;
+ INT32 ret;
+ P_CONSYS_EMI_ADDR_INFO emi_info;
+
+ emi_info = mtk_wcn_consys_soc_get_emi_phy_add();
+ if (emi_info == NULL) {
+ WMT_ERR_FUNC("get EMI info failed\n");
+ return -1;
+ }
+
+ if (!emi_info->emi_met_size) {
+ WMT_ERR_FUNC("met debug function is not support\n");
+ return -1;
+ }
+
+ ret = wmt_lib_met_cmd(met_ctrl);
+ if (ret) {
+ WMT_ERR_FUNC("send MET ctrl command fail(%d)\n", ret);
+ return -1;
+ }
+
+ p_devwmt = &gDevWmt;
+ p_thread = &gDevWmt.met_thread;
+ if (met_ctrl & 0x1) {
+ /*met enable*/
+ /* Create mtk_wmt_met thread */
+ osal_strncpy(p_thread->threadName, "mtk_wmt_met", sizeof(p_thread->threadName));
+ p_devwmt->met_log_ctrl = log_ctrl;
+ p_thread->pThreadData = (PVOID) p_devwmt;
+ p_thread->pThreadFunc = (PVOID) met_thread;
+ ret = osal_thread_create(p_thread);
+ if (ret) {
+ WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", p_thread, ret);
+ return -1;
+ }
+ /* start running mtk_wmt_met */
+ ret = osal_thread_run(p_thread);
+ if (ret) {
+ WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", p_thread, ret);
+ return -1;
+ }
+ } else {
+ /*met disable*/
+ /* stop running mtk_wmt_met */
+ ret = osal_thread_stop(p_thread);
+ if (ret) {
+ WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", p_thread, ret);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+VOID wmt_lib_set_ext_ldo(UINT32 flag)
+{
+ gDevWmt.ext_ldo_flag = flag;
+}
+
+UINT32 wmt_lib_get_ext_ldo(VOID)
+{
+ return gDevWmt.ext_ldo_flag;
+}
+
+static VOID wmt_lib_utc_sync_timeout_handler(timer_handler_arg arg)
+{
+ schedule_work(&gDevWmt.utcSyncWorker);
+}
+
+static VOID wmt_lib_utc_sync_worker_handler(struct work_struct *work)
+{
+ wmt_lib_utc_time_sync();
+}
+
+INT32 wmt_lib_fw_log_ctrl(enum wmt_fw_log_type type, UINT8 onoff, UINT8 level)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_WARN_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = 0;
+ pOp->op.opId = WMT_OPID_FW_LOG_CTRL;
+ pOp->op.au4OpData[0] = type;
+ pOp->op.au4OpData[1] = onoff;
+ pOp->op.au4OpData[2] = level;
+
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -2;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId);
+ return -3;
+ }
+ WMT_DBG_FUNC("OPID(%d) ok\n", pOp->op.opId);
+
+ return 0;
+}
+
+INT32 wmt_lib_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf,
+ UINT32 rx_data_buf_len, PUINT32 p_rx_data_len)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_WMT_OP_TIMEOUT;
+ pOp->op.opId = WMT_OPID_GPS_MCU_CTRL;
+ pOp->op.au4OpData[0] = (SIZE_T)p_tx_data_buf;
+ pOp->op.au4OpData[1] = tx_data_len;
+ pOp->op.au4OpData[2] = (SIZE_T)p_rx_data_buf;
+ pOp->op.au4OpData[3] = rx_data_buf_len;
+ pOp->op.au4OpData[4] = (SIZE_T)p_rx_data_len;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_GPS_MCU_CTRL fail(%zu)\n", pOp->op.au4OpData[5]);
+ return -1;
+ }
+
+ return 0;
+}
+
+VOID wmt_lib_print_wmtd_op_history(VOID)
+{
+ osal_op_history_print(&gDevWmt.wmtd_op_history, "wmtd_thread");
+}
+
+VOID wmt_lib_print_worker_op_history(VOID)
+{
+ osal_op_history_print(&gDevWmt.worker_op_history, "wmtd_worker_thread");
+}
+VOID wmt_lib_set_blank_status(UINT32 on_off_flag)
+{
+ wmt_core_set_blank_status(on_off_flag);
+}
+
+UINT32 wmt_lib_get_blank_status(VOID)
+{
+ return wmt_core_get_blank_status();
+}
+
+INT32 wmt_lib_blank_status_ctrl(UINT32 on_off_flag)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet;
+ P_OSAL_SIGNAL pSignal;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_lxop fail\n");
+ return -1;
+ }
+
+ pSignal = &pOp->signal;
+ pSignal->timeoutValue = MAX_EACH_WMT_CMD;
+ WMT_DBG_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x)\n\n", on_off_flag);
+ pOp->op.opId = WMT_OPID_BLANK_STATUS_CTRL;
+ pOp->op.au4OpData[0] = on_off_flag;
+ if (DISABLE_PSM_MONITOR()) {
+ WMT_ERR_FUNC("wake up failed\n");
+ wmt_lib_put_op_to_free_queue(pOp);
+ return -1;
+ }
+
+ bRet = wmt_lib_put_act_op(pOp);
+ ENABLE_PSM_MONITOR();
+
+ if (bRet != MTK_WCN_BOOL_FALSE) {
+ WMT_DBG_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x) ok\n", on_off_flag);
+ return 0;
+ }
+ WMT_WARN_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x) bRet(%d)\n", on_off_flag, bRet);
+ return -1;
+}
+
+/**
+ * Desinged for native service to get number of patches
+ * resides in /vendor/firmware
+ */
+INT32 wmt_lib_get_vendor_patch_num(VOID)
+{
+ return gDevWmt.patch_table.num;
+}
+
+INT32 wmt_lib_set_vendor_patch_version(struct wmt_vendor_patch *p)
+{
+ struct vendor_patch_table *table = &(gDevWmt.patch_table);
+ struct wmt_vendor_patch *patch = table->patch;
+
+ if (patch == NULL) {
+ INT32 init_capacity = 5;
+
+ patch = (struct wmt_vendor_patch *)osal_malloc(
+ sizeof(struct wmt_vendor_patch) * init_capacity);
+ if (patch == NULL) {
+ WMT_ERR_FUNC("[oom]set vendor patch version");
+ return -1;
+ }
+
+ table->patch = patch;
+ table->capacity = init_capacity;
+ table->num = 0;
+
+ table->active_version = (PUINT8 *)osal_malloc(sizeof(PUINT8) * init_capacity);
+ if (table->active_version == NULL) {
+ osal_free(table->patch);
+ table->patch = NULL;
+ WMT_ERR_FUNC("[oom]alloc active patch");
+ return -1;
+ }
+ osal_memset(table->active_version, 0, sizeof(PUINT8) * init_capacity);
+ }
+
+ if (table->capacity == table->num) {
+ WMT_ERR_FUNC("reach to limit");
+ return -1;
+ }
+
+ /* copy patch info to table */
+ patch = patch + table->num;
+ patch->type = p->type;
+ osal_strncpy(patch->file_name, p->file_name, sizeof(p->file_name));
+ osal_strncpy(patch->version, p->version, sizeof(p->version));
+
+ table->num++;
+ WMT_INFO_FUNC("set version %s %s %d",
+ patch->file_name, patch->version, patch->type);
+ return 0;
+}
+
+INT32 wmt_lib_get_vendor_patch_version(struct wmt_vendor_patch *p)
+{
+ struct vendor_patch_table *table = &(gDevWmt.patch_table);
+
+ if (p->id >= table->num || p->id < 0) {
+ WMT_ERR_FUNC("id %d out of range", p->id);
+ return -1;
+ }
+
+ osal_memcpy(p, &table->patch[p->id], sizeof(struct wmt_vendor_patch));
+ WMT_INFO_FUNC("get version: %s %s t:%d",
+ p->file_name, p->version, p->type);
+ return 0;
+}
+
+INT32 wmt_lib_set_check_patch_status(INT32 status)
+{
+ gDevWmt.patch_table.status = status;
+ return 0;
+}
+
+INT32 wmt_lib_get_check_patch_status(VOID)
+{
+ return gDevWmt.patch_table.status;
+}
+
+INT32 wmt_lib_set_active_patch_version(struct wmt_vendor_patch *p)
+{
+ struct vendor_patch_table *table = &(gDevWmt.patch_table);
+
+ if (p->id < 0 || p->id >= table->num) {
+ WMT_ERR_FUNC("patch id: %d is invalid. num = %d", p->id, table->num);
+ return -1;
+ }
+
+ if (table->active_version == NULL) {
+ WMT_ERR_FUNC("active version is NULL");
+ return -1;
+ }
+
+ if (table->active_version[p->id] == NULL) {
+ table->active_version[p->id] = osal_malloc(sizeof(UINT8) * (WMT_FIRMWARE_VERSION_LENGTH + 1));
+ if (table->active_version[p->id] == NULL) {
+ WMT_ERR_FUNC("oom when alloc active_version");
+ return -1;
+ }
+ } else if (osal_strcmp(p->version, table->active_version[p->id]) == 0)
+ return 0;
+
+ wmt_lib_set_need_update_patch_version(1);
+ osal_strncpy(table->active_version[p->id], p->version, WMT_FIRMWARE_VERSION_LENGTH + 1);
+ return 0;
+}
+
+INT32 wmt_lib_get_active_patch_version(struct wmt_vendor_patch *p)
+{
+ struct vendor_patch_table *table = &(gDevWmt.patch_table);
+ INT32 id = p->id;
+
+ if (id >= table->num || id < 0) {
+ WMT_ERR_FUNC("id %d out of range", p->id);
+ return -1;
+ }
+ if (table->active_version[id] == NULL) {
+ WMT_ERR_FUNC("active_version is null: id = %d", id);
+ return -1;
+ }
+
+ osal_memcpy(p, &table->patch[id], sizeof(struct wmt_vendor_patch));
+ osal_strncpy(p->version, table->active_version[id],
+ WMT_FIRMWARE_VERSION_LENGTH + 1);
+ WMT_INFO_FUNC("get active version: %s %s t:%d id:%d",
+ p->file_name, p->version, p->type, id);
+ return 0;
+}
+
+INT32 wmt_lib_get_need_update_patch_version(VOID)
+{
+ return gDevWmt.patch_table.need_update;
+}
+
+
+INT32 wmt_lib_set_need_update_patch_version(INT32 need)
+{
+ gDevWmt.patch_table.need_update = need > 0 ? 1 : 0;
+ return 0;
+}
+
+VOID mtk_lib_set_mcif_mpu_protection(MTK_WCN_BOOL enable)
+{
+ mtk_consys_set_mcif_mpu_protection(enable);
+}
+
+static VOID wmt_lib_assert_work_cb(struct work_struct *work)
+{
+ struct assert_work_st *a = &wmt_assert_work;
+
+ wmt_lib_trigger_assert_keyword(a->type, a->reason, a->keyword);
+}
+
+VOID wmt_lib_trigger_assert_keyword_delay(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword)
+{
+ struct assert_work_st *a = &wmt_assert_work;
+
+ a->type = type;
+ a->reason = reason;
+ if (snprintf(a->keyword, sizeof(a->keyword), "%s", keyword) < 0) {
+ WMT_INFO_FUNC("snprintf a->keyword fail\n");
+ } else {
+ WMT_ERR_FUNC("Assert: type = %d, reason = %d, keyword = %s", type, reason, keyword);
+ schedule_work(&(a->work));
+ }
+}
+
+INT32 wmt_lib_dmp_consys_state(P_CONSYS_STATE_DMP_INFO dmp_info,
+ unsigned int cpupcr_times, unsigned int slp_ms)
+{
+ P_OSAL_OP pOp;
+ MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE;
+ P_OSAL_SIGNAL pSignal;
+ P_CONSYS_STATE_DMP_OP dmp_op = NULL;
+ P_CONSYS_STATE_DMP_OP tmp_op;
+ int i, wait_ms = 1000, tmp;
+ struct consys_state_dmp_req *p_req = &gDevWmt.state_dmp_req;
+
+
+ if (cpupcr_times > WMT_LIB_DMP_CONSYS_MAX_TIMES) {
+ pr_warn("dump too many times [%d]\n", cpupcr_times);
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ /* make sure: */
+ /* 1. consys already power on */
+ /* 2. consys register is readable */
+ if (wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) != DRV_STS_FUNC_ON
+ || osal_test_bit(WMT_STAT_PWR, &gDevWmt.state) == 0) {
+ return MTK_WCN_BOOL_FALSE;
+ }
+
+ for (i = 0; i < WMT_LIB_DMP_SLOT; i++) {
+ tmp_op = &p_req->consys_ops[i];
+ if (osal_trylock_sleepable_lock(&tmp_op->lock) == 1) {
+ if (tmp_op->status == WMT_DUMP_STATE_NONE) {
+ tmp = atomic_add_return(1, &p_req->version);
+ dmp_op = tmp_op;
+ dmp_op->status = WMT_DUMP_STATE_SCHEDULED;
+ dmp_op->version = tmp;
+ }
+ osal_unlock_sleepable_lock(&tmp_op->lock);
+ if (dmp_op != NULL)
+ break;
+ }
+ }
+
+ if (dmp_op == NULL)
+ return MTK_WCN_BOOL_FALSE;
+
+ memset(&dmp_op->dmp_info, 0, sizeof(struct consys_state_dmp_info));
+ dmp_op->times = cpupcr_times;
+ dmp_op->cpu_sleep_ms = slp_ms;
+
+ pOp = wmt_lib_get_free_op();
+ if (!pOp) {
+ WMT_DBG_FUNC("get_free_op fail\n");
+ bRet = MTK_WCN_BOOL_FALSE;
+ goto err;
+ }
+
+ tmp = cpupcr_times * slp_ms;
+ if (wait_ms < tmp)
+ wait_ms = tmp + 300;
+
+ pSignal = &pOp->signal;
+ pOp->op.opId = WMT_OPID_GET_CONSYS_STATE;
+ pOp->op.au4OpData[0] = (SIZE_T)dmp_op;
+ pOp->op.au4OpData[1] = (SIZE_T)dmp_op->version;
+ pSignal->timeoutValue = wait_ms;
+
+ bRet = wmt_lib_put_act_op(pOp);
+
+ if (bRet == MTK_WCN_BOOL_FALSE) {
+ WMT_WARN_FUNC("WMT_OPID_GET_CONSYS_STATE failed\n");
+ goto err;
+ }
+
+ memcpy(dmp_info, &dmp_op->dmp_info, sizeof(struct consys_state_dmp_info));
+err:
+ osal_lock_sleepable_lock(&dmp_op->lock);
+ dmp_op->status = WMT_DUMP_STATE_NONE;
+ osal_unlock_sleepable_lock(&dmp_op->lock);
+ return bRet;
+}
+
+INT32 wmt_lib_reg_readable(VOID)
+{
+ return wmt_lib_reg_readable_by_addr(0);
+}
+
+INT32 wmt_lib_reg_readable_by_addr(SIZE_T addr)
+{
+ if (wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_POWER_OFF
+ || osal_test_bit(WMT_STAT_PWR, &gDevWmt.state) == 0) {
+ return MTK_WCN_BOOL_FALSE;
+ }
+ return mtk_consys_check_reg_readable_by_addr(addr);
+}
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h b/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h
new file mode 100644
index 0000000000000000000000000000000000000000..adbd4399a872e2dcf3566f1ea3aeca834eb3cb04
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+
+
+#ifndef _MTK_WCN_CMB_HW_H_
+#define _MTK_WCN_CMB_HW_H_
+
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+#include
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+typedef struct _PWR_SEQ_TIME_ {
+ UINT32 rtcStableTime;
+ UINT32 ldoStableTime;
+ UINT32 rstStableTime;
+ UINT32 offStableTime;
+ UINT32 onStableTime;
+} PWR_SEQ_TIME, *P_PWR_SEQ_TIME;
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+
+
+
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+extern INT32 mtk_wcn_cmb_hw_pwr_off(VOID);
+extern INT32 mtk_wcn_cmb_hw_pwr_on(VOID);
+extern INT32 mtk_wcn_cmb_hw_rst(VOID);
+extern INT32 mtk_wcn_cmb_hw_init(P_PWR_SEQ_TIME pPwrSeqTime);
+extern INT32 mtk_wcn_cmb_hw_deinit(VOID);
+extern INT32 mtk_wcn_cmb_hw_state_show(VOID);
+
+
+#endif /* _MTK_WCN_CMB_HW_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h
new file mode 100644
index 0000000000000000000000000000000000000000..b1c5e69e03a3572594cc6e6859c5ec2731a70dd1
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+#ifndef _STP_EXP_H_
+#define _STP_EXP_H_
+
+#include "osal.h"
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+#if (WMT_IDC_SUPPORT)
+#define CFG_WMT_LTE_COEX_HANDLING 1
+#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0
+#else
+#define CFG_WMT_LTE_COEX_HANDLING 0
+#endif
+
+#define BT_TASK_INDX (0)
+#define FM_TASK_INDX (1)
+#define GPS_TASK_INDX (2)
+#define WIFI_TASK_INDX (3)
+#define WMT_TASK_INDX (4)
+#define STP_TASK_INDX (5)
+#define GPSL5_TASK_INDX (6)
+#define INFO_TASK_INDX (6)
+#define ANT_TASK_INDX (7)
+#if CFG_WMT_LTE_COEX_HANDLING
+#define COEX_TASK_INDX (8)
+#define MTKSTP_MAX_TASK_NUM (9)
+#else
+#define MTKSTP_MAX_TASK_NUM (8)
+#endif
+
+#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */
+
+#define STP_EXP_HID_API_EXPORT 0
+
+#else
+
+#define STP_EXP_HID_API_EXPORT 1
+
+#endif
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+typedef VOID (*MTK_WCN_STP_EVENT_CB) (VOID);
+typedef INT32 (*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size);
+/* export for HIF driver */
+typedef VOID(*MTK_WCN_STP_IF_RX)(const PUINT8 data, INT32 size);
+typedef INT32 (*MTK_WCN_STP_RX_HAS_PENDING_DATA) (VOID);
+typedef INT32 (*MTK_WCN_STP_TX_HAS_PENDING_DATA) (VOID);
+typedef P_OSAL_THREAD (*MTK_WCN_STP_RX_THREAD_GET) (VOID);
+
+typedef enum {
+ STP_UART_IF_TX = 0,
+ STP_SDIO_IF_TX = 1,
+ STP_BTIF_IF_TX = 2,
+ STP_MAX_IF_TX
+} ENUM_STP_TX_IF_TYPE;
+#endif
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_receive_data
+* DESCRIPTION
+* receive data from serial protocol engine
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* INT32 >= 0: size of data received; < 0: error
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_send_data
+* DESCRIPTION
+* subfunction send data through STP
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* type [IN] subfunction type
+* RETURNS
+* INT32 >= 0: length transmitted; < 0: error
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_rxqueue_empty
+* DESCRIPTION
+* Is certain rx queue empty?
+* PARAMETERS
+* type [IN] subfunction type
+* RETURNS
+* INT32 0: queue is NOT empyt; !0: queue is empty
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_is_enable
+* DESCRIPTION
+* Is STP ready?
+* PARAMETERS
+* none.
+* RETURNS
+* MTK_WCN_BOOL TRUE:ready, FALSE:not ready
+*****************************************************************************/
+extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_parser_data
+* DESCRIPTION
+* push data to serial transport protocol parser engine
+* PARAMETERS
+* buffer [IN] data buffer
+* length [IN] data buffer length
+* RETURNS
+* void
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length);
+
+/*****************************************************************************
+* FUNCTION
+* set_bluetooth_rx_interface
+* DESCRIPTION
+* Set bluetooth rx interface
+* PARAMETERS
+* rx interface type
+* RETURNS
+* void
+*****************************************************************************/
+extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_tx_event_cb
+* DESCRIPTION
+* regiter Tx event callback function
+* PARAMETERS
+* func
+* RETURNS
+* INT32: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_event_cb
+* DESCRIPTION
+* regiter Rx event callback function
+* PARAMETERS
+* func
+* RETURNS
+* INT32: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_if_tx
+* DESCRIPTION
+* regiter Tx event callback function
+* PARAMETERS
+* stp_if: SDIO or UART, fnnc: Call back function
+* RETURNS
+* INT32: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_if_rx
+* DESCRIPTION
+* regiter Rx event callback function
+* PARAMETERS
+* stp_if: SDIO or UART, fnnc: Call back function
+* RETURNS
+* int: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_coredump_start_get
+* DESCRIPTION
+* get f/w assert flag in STP context
+* PARAMETERS
+* VOID
+* RETURNS
+* INT32 0= f/w assert flag is not set, others=f/w assert flag is set
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_coredump_start_get(VOID);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_rx_has_pending_data
+* DESCRIPTION
+* regiter rx has pending data call back function
+* PARAMETERS
+* stp_if: SDIO or UART, fnnc: Call back function
+* RETURNS
+* int: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_tx_has_pending_data
+* DESCRIPTION
+* regiter tx has pending data call back function
+* PARAMETERS
+* stp_if: SDIO or UART, fnnc: Call back function
+* RETURNS
+* int: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func);
+
+/*****************************************************************************
+* FUNCTION
+* mtk_wcn_stp_register_rx_thread_get
+* DESCRIPTION
+* regiter rx thread call back function
+* PARAMETERS
+* stp_if: SDIO or UART, fnnc: Call back function
+* RETURNS
+* int: 0:successful , -1: fail
+*****************************************************************************/
+extern INT32 mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func);
+
+extern INT32 mtk_stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd);
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#else
+extern INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type);
+extern INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type);
+extern INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type);
+extern MTK_WCN_BOOL _mtk_wcn_stp_is_rxqueue_empty(UINT8 type);
+extern MTK_WCN_BOOL _mtk_wcn_stp_is_ready(VOID);
+extern INT32 _mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length);
+extern VOID _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag);
+extern INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func);
+extern INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func);
+extern INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func);
+extern INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func);
+extern INT32 _mtk_wcn_stp_coredump_start_get(VOID);
+extern INT32 _mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if,
+ MTK_WCN_STP_RX_HAS_PENDING_DATA func);
+extern INT32 _mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if,
+ MTK_WCN_STP_TX_HAS_PENDING_DATA func);
+extern INT32 _mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func);
+
+#endif /* MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT */
+
+#endif /* _STP_EXP_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h
new file mode 100644
index 0000000000000000000000000000000000000000..c65f504b48b84a849e4320a6ebaebf4f2b4fdc4b
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _MTKWMT_H_
+#define _MTKWMT_H_
+#include "wmt_core.h"
+
+#endif /*_MTKWMT_H_*/
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea08503a02f30debceada30c40a9e9b7dcc3a217
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+#ifndef _WMT_EXP_H_
+#define _WMT_EXP_H_
+
+#include
+#include "osal.h"
+#include "wmt_plat.h"
+#include "osal_typedef.h"
+/* not to reference to internal wmt */
+/* #include "wmt_core.h" */
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#if 1 /* moved from wmt_lib.h */
+#ifndef DFT_TAG
+#define DFT_TAG "[WMT-DFT]"
+#endif
+
+#define WMT_LOUD_FUNC(fmt, arg...) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_LOUD) \
+ osal_warn_print(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_INFO_FUNC(fmt, arg...) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_INFO) \
+ osal_warn_print(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_WARN_FUNC(fmt, arg...) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_WARN) \
+ osal_warn_print(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_ERR_FUNC(fmt, arg...) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_ERR) \
+ osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+#define WMT_DBG_FUNC(fmt, arg...) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_DBG) \
+ osal_warn_print(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_TRC_FUNC(f) \
+do { \
+ if (gWmtDbgLvl >= WMT_LOG_DBG) \
+ osal_warn_print(DFT_TAG "<%s> <%d>\n", __func__, __LINE__); \
+} while (0)
+
+#endif
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#if 1 /* moved from wmt_lib.h */
+extern INT32 gWmtDbgLvl;
+#endif
+extern OSAL_BIT_OP_VAR gBtWifiGpsState;
+extern OSAL_BIT_OP_VAR gGpsFmState;
+extern UINT32 gWifiProbed;
+extern MTK_WCN_BOOL g_pwr_off_flag;
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+#if 1 /* moved from wmt_lib.h */
+#define WMT_LOG_LOUD 4
+#define WMT_LOG_DBG 3
+#define WMT_LOG_INFO 2
+#define WMT_LOG_WARN 1
+#define WMT_LOG_ERR 0
+#endif
+#define CFG_CORE_INTERNAL_TXRX 0 /*just do TX/RX in host side */
+
+#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_lib.h */
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+typedef enum _ENUM_WMTDRV_TYPE_T {
+ WMTDRV_TYPE_BT = 0,
+ WMTDRV_TYPE_FM = 1,
+ WMTDRV_TYPE_GPS = 2,
+ WMTDRV_TYPE_WIFI = 3,
+ WMTDRV_TYPE_WMT = 4,
+ WMTDRV_TYPE_ANT = 5,
+ WMTDRV_TYPE_STP = 6,
+ WMTDRV_TYPE_SDIO1 = 7,
+ WMTDRV_TYPE_SDIO2 = 8,
+ WMTDRV_TYPE_LPBK = 9,
+ WMTDRV_TYPE_COREDUMP = 10,
+ WMTDRV_TYPE_GPSL5 = 11,
+ WMTDRV_TYPE_MAX
+} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T;
+
+/* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */
+/* TODO: how do we extend for new chip and newer revision? */
+/* TODO: This way is hard to extend */
+typedef enum _ENUM_WMTHWVER_TYPE_T {
+ WMTHWVER_E1 = 0x0,
+ WMTHWVER_E2 = 0x1,
+ WMTHWVER_E3 = 0x2,
+ WMTHWVER_E4 = 0x3,
+ WMTHWVER_E5 = 0x4,
+ WMTHWVER_E6 = 0x5,
+ WMTHWVER_E7 = 0x6,
+ WMTHWVER_MAX,
+ WMTHWVER_INVALID = 0xff
+} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T;
+
+typedef enum _ENUM_WMTDSNS_TYPE_T {
+ WMTDSNS_FM_DISABLE = 0,
+ WMTDSNS_FM_ENABLE = 1,
+ WMTDSNS_FM_GPS_DISABLE = 2,
+ WMTDSNS_FM_GPS_ENABLE = 3,
+ WMTDSNS_MAX
+} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T;
+
+typedef enum _ENUM_WMTTHERM_TYPE_T {
+ WMTTHERM_ZERO = 0,
+ WMTTHERM_ENABLE = WMTTHERM_ZERO + 1,
+ WMTTHERM_READ = WMTTHERM_ENABLE + 1,
+ WMTTHERM_DISABLE = WMTTHERM_READ + 1,
+ WMTTHERM_MAX
+} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T;
+
+typedef enum _ENUM_WMTMSG_TYPE_T {
+ WMTMSG_TYPE_POWER_ON = 0,
+ WMTMSG_TYPE_POWER_OFF = 1,
+ WMTMSG_TYPE_RESET = 2,
+ WMTMSG_TYPE_STP_RDY = 3,
+ WMTMSG_TYPE_HW_FUNC_ON = 4,
+ WMTMSG_TYPE_MAX
+} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T;
+
+typedef VOID(*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */
+ ENUM_WMTDRV_TYPE_T, /* Destination driver type */
+ ENUM_WMTMSG_TYPE_T, /* Message type */
+ /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv.
+ * Client can't touch this buffer after this function return.
+ */
+ PVOID,
+ UINT32 /* Buffer size in unit of byte */
+ );
+
+typedef enum _SDIO_PS_OP {
+ OWN_SET = 0,
+ OWN_CLR = 1,
+ OWN_STATE = 2,
+} SDIO_PS_OP;
+
+typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP);
+typedef INT32(*PF_WMT_SDIO_DEEP_SLEEP)(MTK_WCN_BOOL);
+typedef INT32(*PF_WMT_SDIO_DEBUG)(INT32, INT32, UINT32, UINT32);
+
+
+typedef enum _ENUM_WMTCHIN_TYPE_T {
+ WMTCHIN_CHIPID = 0x0,
+ WMTCHIN_HWVER = WMTCHIN_CHIPID + 1,
+ WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1,
+ WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1,
+ WMTCHIN_IPVER = WMTCHIN_FWVER + 1,
+ WMTCHIN_ADIE = WMTCHIN_IPVER + 1,
+ WMTCHIN_MAX,
+} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T;
+
+typedef enum _ENUM_WMT_FLASH_PATCH_CTRL_T {
+ WMT_FLASH_PATCH_VERSION_GET = 0,
+ WMT_FLASH_PATCH_DOWNLOAD = WMT_FLASH_PATCH_VERSION_GET + 1,
+ WMT_FLASH_PATCH_CTRL_MAX,
+} ENUM_WMT_FLASH_PATCH_CTRL, *P_ENUM_WMT_FLASH_PATCH_CTRL;
+
+typedef enum _ENUM_WMT_FLASH_PATCH_SEQ_T {
+ WMT_FLASH_PATCH_HEAD_PKT = 0,
+ WMT_FLASH_PATCH_START_PKT = WMT_FLASH_PATCH_HEAD_PKT + 1,
+ WMT_FLASH_PATCH_CONTINUE_PKT = WMT_FLASH_PATCH_START_PKT + 1,
+ WMT_FLASH_PATCH_END_PKT = WMT_FLASH_PATCH_CONTINUE_PKT + 1,
+ WMT_FLASH_PATCH_SEQ_MAX,
+} ENUM_WMT_FLASH_PATCH_SEQ, *P_ENUM_WMT_FLASH_PATCH_SEQ;
+
+typedef enum _ENUM_WMT_FLASH_PATCH_TYPE_T {
+ WMT_FLASH_PATCH_HIF_SW_EFUSE = 0,
+ WMT_FLASH_PATCH_GATT = WMT_FLASH_PATCH_HIF_SW_EFUSE + 1,
+ WMT_FLASH_PATCH_SYSROM = WMT_FLASH_PATCH_GATT + 1,
+ WMT_FLASH_PATCH_ILM = WMT_FLASH_PATCH_SYSROM + 1,
+ WMT_FLASH_PATCH_FLP1 = WMT_FLASH_PATCH_ILM + 1,
+ WMT_FLASH_PATCH_FLP2 = WMT_FLASH_PATCH_FLP1 + 1,
+ WMT_FLASH_PATCH_TYPE_MAX,
+} ENUM_WMT_FLASH_PATCH_TYPE, *P_ENUM_WMT_FLASH_PATCH_TYPE;
+
+typedef enum _ENUM_WMT_FLASH_PATCH_STATUS_T {
+ WMT_FLASH_PATCH_VERSION_GET_OK = 0,
+ WMT_FLASH_PATCH_VERSION_GET_FAIL = WMT_FLASH_PATCH_VERSION_GET_OK + 1,
+ WMT_FLASH_PATCH_DOWNLOAD_OK = WMT_FLASH_PATCH_VERSION_GET_FAIL + 1,
+ WMT_FLASH_PATCH_DOWNLOAD_FAIL = WMT_FLASH_PATCH_DOWNLOAD_OK + 1,
+ WMT_FLASH_PATCH_PARA_ERR = WMT_FLASH_PATCH_DOWNLOAD_FAIL + 1,
+ WMT_FLASH_PATCH_OP_ERR = WMT_FLASH_PATCH_PARA_ERR + 1,
+ WMT_FLASH_PATCH_MAX
+} ENUM_WMT_FLASH_PATCH_STATUS, *P_ENUM_WMT_FLASH_PATCH_STATUS;
+
+typedef MTK_WCN_BOOL(*MTK_WCN_WMT_FUNC_CTRL) (ENUM_WMTDRV_TYPE_T type);
+typedef INT8(*MTK_WCN_WMT_THERM_CTRL) (ENUM_WMTTHERM_TYPE_T eType);
+typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET) (VOID);
+typedef MTK_WCN_BOOL(*MTK_WCN_WMT_DSNS_CTRL) (ENUM_WMTDSNS_TYPE_T eType);
+typedef INT32(*MTK_WCN_WMT_MSGCB_REG) (ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb);
+typedef INT32(*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType);
+typedef INT32(*MTK_WCN_WMT_SDIO_OP_REG) (PF_WMT_SDIO_PSOP own_cb);
+typedef INT32(*MTK_WCN_WMT_SDIO_HOST_AWAKE) (VOID);
+typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT) (ENUM_WMTDRV_TYPE_T type, UINT32 reason);
+typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT_TIMEOUT)(ENUM_WMTDRV_TYPE_T type,
+ UINT32 reason, INT32 timeout);
+typedef UINT32(*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type);
+typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag);
+
+typedef ENUM_WMT_FLASH_PATCH_STATUS(*MTK_WCN_WMT_FLASH_PATCH_CTRL)(ENUM_WMT_FLASH_PATCH_CTRL ctrlId,
+ PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type,
+ PUINT32 version, UINT32 checksum);
+
+typedef struct _MTK_WCN_WMT_EXP_CB_INFO_ {
+ MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb;
+ MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb;
+ MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb;
+ MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb;
+ MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb;
+ MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb;
+ MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb;
+ MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb;
+ MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb;
+ MTK_WCN_WMT_ASSERT wmt_assert_cb;
+ MTK_WCN_WMT_ASSERT_TIMEOUT wmt_assert_timeout_cb;
+ MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb;
+ MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb;
+ MTK_WCN_WMT_FLASH_PATCH_CTRL wmt_flash_patch_ctrl_cb;
+} MTK_WCN_WMT_EXP_CB_INFO, *P_MTK_WCN_WMT_EXP_CB_INFO;
+
+#endif
+
+typedef enum _ENUM_WMTRSTMSG_TYPE_T {
+ WMTRSTMSG_RESET_START = 0x0,
+ WMTRSTMSG_RESET_END = 0x1,
+ WMTRSTMSG_RESET_END_FAIL = 0x2,
+ WMTRSTMSG_RESET_MAX,
+ WMTRSTMSG_RESET_INVALID = 0xff
+} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T;
+
+typedef enum _ENUM_BT_GPS_ONOFF_STATE_T {
+ WMT_BT_ON = 0,
+ WMT_GPS_ON = 1,
+ WMT_WIFI_ON = 2,
+ WMT_FM_ON = 3,
+ WMT_GPS_SUSPEND = 4,
+ WMT_GPSL5_ON = 5,
+ WMT_GPSL5_SUSPEND = 6,
+ WMT_BT_GPS_STATE_MAX,
+ WMT_BT_GPS_STATE_INVALID = 0xff
+} ENUM_BT_GPS_ONOFF_STATE_T, *P_ENUM_BT_GPS_ONOFF_STATE_T;
+
+#if 1 /* moved from wmt_core.h */
+typedef enum {
+ WMT_SDIO_SLOT_INVALID = 0,
+ WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */
+ WMT_SDIO_SLOT_SDIO2 = 2,
+ WMT_SDIO_SLOT_MAX
+} WMT_SDIO_SLOT_NUM;
+
+typedef enum {
+ WMT_SDIO_FUNC_STP = 0,
+ WMT_SDIO_FUNC_WIFI = 1,
+ WMT_SDIO_FUNC_MAX
+} WMT_SDIO_FUNC_TYPE;
+#endif
+
+typedef INT32(*wmt_wlan_probe_cb) (VOID);
+typedef INT32(*wmt_wlan_remove_cb) (VOID);
+typedef INT32(*wmt_wlan_bus_cnt_get_cb) (VOID);
+typedef INT32(*wmt_wlan_bus_cnt_clr_cb) (VOID);
+typedef INT32(*wmt_wlan_emi_mpu_set_protection_cb) (bool);
+typedef INT32(*wmt_wlan_is_wifi_drv_own_cb) (VOID);
+
+typedef struct _MTK_WCN_WMT_WLAN_CB_INFO {
+ wmt_wlan_probe_cb wlan_probe_cb;
+ wmt_wlan_remove_cb wlan_remove_cb;
+ wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb;
+ wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb;
+ wmt_wlan_emi_mpu_set_protection_cb wlan_emi_mpu_set_protection_cb;
+ wmt_wlan_is_wifi_drv_own_cb wlan_is_wifi_drv_own_cb;
+} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO;
+
+#ifdef CONFIG_MTK_COMBO_ANT
+typedef enum _ENUM_WMT_ANT_RAM_CTRL_T {
+ WMT_ANT_RAM_GET_STATUS = 0,
+ WMT_ANT_RAM_DOWNLOAD = WMT_ANT_RAM_GET_STATUS + 1,
+ WMT_ANT_RAM_CTRL_MAX
+} ENUM_WMT_ANT_RAM_CTRL, *P_ENUM_WMT_ANT_RAM_CTRL;
+
+typedef enum _ENUM_WMT_ANT_RAM_SEQ_T {
+ WMT_ANT_RAM_START_PKT = 1,
+ WMT_ANT_RAM_CONTINUE_PKT = WMT_ANT_RAM_START_PKT + 1,
+ WMT_ANT_RAM_END_PKT = WMT_ANT_RAM_CONTINUE_PKT + 1,
+ WMT_ANT_RAM_SEQ_MAX
+} ENUM_WMT_ANT_RAM_SEQ, *P_ENUM_WMT_ANT_RAM_SEQ;
+
+typedef enum _ENUM_WMT_ANT_RAM_STATUS_T {
+ WMT_ANT_RAM_NOT_EXIST = 0,
+ WMT_ANT_RAM_EXIST = WMT_ANT_RAM_NOT_EXIST + 1,
+ WMT_ANT_RAM_DOWN_OK = WMT_ANT_RAM_EXIST + 1,
+ WMT_ANT_RAM_DOWN_FAIL = WMT_ANT_RAM_DOWN_OK + 1,
+ WMT_ANT_RAM_PARA_ERR = WMT_ANT_RAM_DOWN_FAIL + 1,
+ WMT_ANT_RAM_OP_ERR = WMT_ANT_RAM_PARA_ERR + 1,
+ WMT_ANT_RAM_MAX
+} ENUM_WMT_ANT_RAM_STATUS, *P_ENUM_WMT_ANT_RAM_STATUS;
+#endif
+
+extern INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo);
+extern INT32 mtk_wcn_wmt_wlan_unreg(VOID);
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+extern wmt_wlan_probe_cb mtk_wcn_wlan_probe;
+extern wmt_wlan_remove_cb mtk_wcn_wlan_remove;
+extern wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt;
+extern wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr;
+extern wmt_wlan_emi_mpu_set_protection_cb mtk_wcn_wlan_emi_mpu_set_protection;
+extern wmt_wlan_is_wifi_drv_own_cb mtk_wcn_wlan_is_wifi_drv_own;
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+/*subsystem function ctrl APIs*/
+extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason);
+
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_assert_keyword(ENUM_WMTDRV_TYPE_T type, PUINT8 keyword);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_do_reset(ENUM_WMTDRV_TYPE_T type);
+
+extern MTK_WCN_BOOL mtk_wcn_wmt_do_reset_only(ENUM_WMTDRV_TYPE_T type);
+
+extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb);
+
+extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType);
+
+extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb);
+
+extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID);
+/*
+*return value:
+*enable/disable thermal sensor function: true(1)/false(0)
+*read thermal sensor function: thermal value
+*/
+extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType);
+
+extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID);
+
+extern UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type);
+
+
+extern INT32 mtk_wcn_wmt_chipid_query(VOID);
+
+extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag);
+extern ENUM_WMT_FLASH_PATCH_STATUS mtk_wcn_wmt_flash_patch_ctrl(ENUM_WMT_FLASH_PATCH_CTRL ctrlId,
+ PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type,
+ PUINT32 version, UINT32 checksum);
+
+#endif
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+extern INT32 mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb);
+#endif
+extern INT32 mtk_wcn_wmt_sdio_rw_cb_reg(PF_WMT_SDIO_DEBUG reg_rw_cb);
+
+#ifdef CONFIG_MTK_COMBO_ANT
+extern ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf,
+ UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq);
+#endif
+extern INT32 wmt_lib_set_aif(enum CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */
+extern VOID wmt_lib_ps_irq_cb(VOID);
+
+extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type);
+
+extern INT32 mtk_wcn_wmt_system_state_reset(VOID);
+extern MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value);
+#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+extern VOID mtk_wcn_wmt_exp_init(VOID);
+extern VOID mtk_wcn_wmt_exp_deinit(VOID);
+#endif
+extern INT8 mtk_wcn_wmt_co_clock_flag_get(VOID);
+extern INT32 mtk_wcn_wmt_wifi_fem_cfg_report(PVOID pvInfoBuf);
+extern VOID mtk_wcn_wmt_dump_wmtd_backtrace(VOID);
+extern UINT32 mtk_wmt_get_gps_lna_pin_num(VOID);
+extern VOID mtk_wmt_set_ext_ldo(UINT32 flag);
+extern INT32 mtk_wmt_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf,
+ UINT32 rx_data_buf_len, PUINT32 p_rx_data_len);
+extern VOID mtk_wcn_wmt_set_mcif_mpu_protection(MTK_WCN_BOOL enable);
+extern MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL suspend);
+extern MTK_WCN_BOOL mtk_wmt_gps_l1_suspend_ctrl(MTK_WCN_BOOL suspend);
+extern MTK_WCN_BOOL mtk_wmt_gps_l5_suspend_ctrl(MTK_WCN_BOOL suspend);
+
+extern INT32 mtk_wcn_wmt_mpu_lock_aquire(VOID);
+extern VOID mtk_wcn_wmt_mpu_lock_release(VOID);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif /* _WMT_EXP_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f0113cf40b09fbfe35bc1ec40a027f9224eb1e9
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+* \brief Declaration of library functions
+*
+* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+*/
+
+#ifndef _WMT_PLAT_H_
+#define _WMT_PLAT_H_
+#include "osal_typedef.h"
+#include "stp_exp.h"
+#include
+#include "mtk_wcn_cmb_hw.h"
+
+/* #include "mtk_wcn_consys_hw.h" */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#if 1 /* moved from wmt_exp.h */
+#ifndef DFT_TAG
+#define DFT_TAG "[WMT-DFT]"
+#endif
+
+#define WMT_PLAT_LOG_LOUD 4
+#define WMT_PLAT_LOG_DBG 3
+#define WMT_PLAT_LOG_INFO 2
+#define WMT_PLAT_LOG_WARN 1
+#define WMT_PLAT_LOG_ERR 0
+
+extern INT32 wmtPlatLogLvl;
+
+#define WMT_PLAT_PR_LOUD(fmt, arg...) \
+do { \
+ if (wmtPlatLogLvl >= WMT_PLAT_LOG_LOUD) \
+ pr_info(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_PLAT_PR_INFO(fmt, arg...) \
+do { \
+ if (wmtPlatLogLvl >= WMT_PLAT_LOG_INFO) \
+ pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_PLAT_PR_WARN(fmt, arg...) \
+do { \
+ if (wmtPlatLogLvl >= WMT_PLAT_LOG_WARN) \
+ pr_warn(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define WMT_PLAT_PR_ERR(fmt, arg...) \
+do { \
+ if (wmtPlatLogLvl >= WMT_PLAT_LOG_ERR) \
+ pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+#define WMT_PLAT_PR_DBG(fmt, arg...) \
+do { \
+ if (wmtPlatLogLvl >= WMT_PLAT_LOG_DBG) \
+ pr_info(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#endif
+
+#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_exp.h */
+
+#define CFG_WMT_DUMP_INT_STATUS 0
+#define CONSYS_ENALBE_SET_JTAG 1
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#if (defined(MT6630) || defined(MT6632))
+#define CONSYS_WMT_REG_SUSPEND_CB_ENABLE 1
+#else
+#define CONSYS_WMT_REG_SUSPEND_CB_ENABLE 0
+#endif
+
+#if defined(MERGE_INTERFACE_SUPPORT) && (defined(MT6628) || defined(MT6630) || defined(MT6632))
+#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT 1
+#else
+#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT 0
+#endif
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef enum _ENUM_PIN_ID_ {
+ PIN_LDO = 0,
+ PIN_PMU = 1,
+ PIN_RTC = 2,
+ PIN_RST = 3,
+ PIN_BGF_EINT = 4,
+ PIN_WIFI_EINT = 5,
+ PIN_ALL_EINT = 6,
+ PIN_UART_GRP = 7,
+ PIN_PCM_GRP = 8,
+ PIN_I2S_GRP = 9,
+ PIN_SDIO_GRP = 10,
+ PIN_GPS_SYNC = 11,
+ PIN_GPS_LNA = 12,
+ PIN_UART_RX = 13,
+#if CFG_WMT_LTE_COEX_HANDLING
+ PIN_TDM_REQ = 14,
+#endif
+ PIN_ID_MAX
+} ENUM_PIN_ID, *P_ENUM_PIN_ID;
+#if 0
+typedef enum _ENUM_PIN_ID_ {
+ PIN_BGF_EINT = 0,
+ PIN_I2S_GRP = 1,
+ PIN_GPS_SYNC = 2,
+ PIN_GPS_LNA = 3,
+#if CFG_WMT_LTE_COEX_HANDLING
+ PIN_TDM_REQ = 4,
+#endif
+ PIN_ID_MAX
+} ENUM_PIN_ID, *P_ENUM_PIN_ID;
+#endif
+
+typedef enum _ENUM_FUNC_STATE_ {
+ FUNC_ON = 0,
+ FUNC_OFF = 1,
+ FUNC_RST = 2,
+ FUNC_STAT = 3,
+ FUNC_CTRL_MAX,
+} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE;
+
+typedef enum _ENUM_PIN_STATE_ {
+ PIN_STA_INIT = 0,
+ PIN_STA_OUT_L = 1,
+ PIN_STA_OUT_H = 2,
+ PIN_STA_IN_L = 3,
+ PIN_STA_MUX = 4,
+ PIN_STA_EINT_EN = 5,
+ PIN_STA_EINT_DIS = 6,
+ PIN_STA_DEINIT = 7,
+ PIN_STA_SHOW = 8,
+ PIN_STA_IN_PU = 9,
+ PIN_STA_IN_NP = 10,
+ PIN_STA_IN_H = 11,
+ PIN_STA_MAX
+} ENUM_PIN_STATE, *P_ENUM_PIN_STATE;
+
+typedef enum _CMB_IF_TYPE_ {
+ CMB_IF_UART = 0,
+ CMB_IF_WIFI_SDIO = 1,
+ CMB_IF_BGF_SDIO = 2,
+ CMB_IF_BGWF_SDIO = 3,
+ CMB_IF_TYPE_MAX
+} CMB_IF_TYPE, *P_CMB_IF_TYPE;
+
+typedef INT32(*fp_set_pin) (ENUM_PIN_STATE);
+
+typedef enum _ENUM_WL_OP_ {
+ WL_OP_GET = 0,
+ WL_OP_PUT = 1,
+ WL_OP_MAX
+} ENUM_WL_OP, *P_ENUM_WL_OP;
+
+typedef enum _ENUM_PALDO_TYPE_ {
+ BT_PALDO = 0,
+ WIFI_PALDO = 1,
+ FM_PALDO = 2,
+ GPS_PALDO = 3,
+ PMIC_CHIPID_PALDO = 4,
+ WIFI_5G_PALDO = 5,
+ EFUSE_PALDO = 6,
+ PALDO_TYPE_MAX
+} ENUM_PALDO_TYPE, *P_ENUM_PALDO_TYPE;
+
+typedef enum _ENUM_PALDO_OP_ {
+ PALDO_OFF = 0,
+ PALDO_ON = 1,
+ PALDO_OP_MAX
+} ENUM_PALDO_OP, *P_ENUM_PALDO_OP;
+
+typedef enum _ENUM_HOST_DUMP_STATE_T {
+ STP_HOST_DUMP_NOT_START = 0,
+ STP_HOST_DUMP_GET = 1,
+ STP_HOST_DUMP_GET_DONE = 2,
+ STP_HOST_DUMP_END = 3,
+ STP_HOST_DUMP_MAX
+} ENUM_HOST_DUMP_STATE, *P_ENUM_HOST_DUMP_STATE_T;
+
+typedef enum _ENUM_FORCE_TRG_ASSERT_T {
+ STP_FORCE_TRG_ASSERT_EMI = 0,
+ STP_FORCE_TRG_ASSERT_DEBUG_PIN = 1,
+ STP_FORCE_TRG_ASSERT_MAX = 2
+} ENUM_FORCE_TRG_ASSERT_T, *P_ENUM_FORCE_TRG_ASSERT_T;
+
+typedef enum _ENUM_CHIP_DUMP_STATE_T {
+ STP_CHIP_DUMP_NOT_START = 0,
+ STP_CHIP_DUMP_PUT = 1,
+ STP_CHIP_DUMP_PUT_DONE = 2,
+ STP_CHIP_DUMP_END = 3,
+ STP_CHIP_DUMP_MAX
+} ENUM_CHIP_DUMP_STATE, *P_ENUM_CHIP_DUMP_STATE_T;
+
+#define CONSYS_BUS_CLK_STATUS_OFFSET 0x00000100
+#define CONSYS_CPU_CLK_STATUS_OFFSET 0x0000010c
+#define CONSYS_DBG_CR1_OFFSET 0x00000408
+#define CONSYS_DBG_CR2_OFFSET 0x0000040c
+typedef enum _ENUM_CONNSYS_DEBUG_CR {
+ CONNSYS_CPU_CLK = 0,
+ CONNSYS_BUS_CLK = 1,
+ CONNSYS_DEBUG_CR1 = 2,
+ CONNSYS_DEBUG_CR2 = 3,
+ CONNSYS_EMI_REMAP = 4,
+ CONNSYS_CR_MAX
+} ENUM_CONNSYS_DEBUG_CR, *P_ENUM_CONNSYS_DEBUG_CR;
+
+typedef enum {
+ WMT_SLEEP_COUNT_TOP = 0,
+ WMT_SLEEP_COUNT_MCU = 1,
+ WMT_SLEEP_COUNT_BT = 2,
+ WMT_SLEEP_COUNT_WF = 3,
+ WMT_SLEEP_COUNT_GPS = 4,
+ WMT_SLEEP_COUNT_MAX
+} WMT_SLEEP_COUNT_TYPE;
+
+typedef enum {
+ WMT_ERRCODE_SUCCESS = 0,
+ WMT_ERRCODE_ALREADY_ON,
+ WMT_ERRCODE_ALREADY_OFF,
+ WMT_ERRCODE_READYTO_OFF,
+ WMT_ERRCODE_EMI_NOT_READY,
+ WMT_ERRCODE_GPIO_CTRL_FAIL,
+ WMT_ERRCODE_POLL_CHIPID_FAIL,
+ WMT_ERRCODE_POLL_NOT_GOTO_IDLE,
+ WMT_ERRCODE_NO_HIF_INFO,
+ WMT_ERRCODE_SDIO_SLOT_SDIO2_FAIL,
+ WMT_ERRCODE_SDIO_FUNC_STP_FAIL,
+ WMT_ERRCODE_OPEN_STP_FAIL,
+ WMT_ERRCODE_UART_BAUDRATE_FAIL,
+ WMT_ERRCODE_STP_CONFIG_FAIL,
+ WMT_ERRCODE_HW_CHECK_FAIL,
+ WMT_ERRCODE_VER_CHECK_FAIL,
+ WMT_ERRCODE_CHIPID_NOT_SUPPORT,
+ WMT_ERRCODE_NULL_FUNC_POINTER,
+ WMT_ERRCODE_PATCH_INFO_FAIL,
+ WMT_ERRCODE_PATCH_DWN_FAIL,
+ WMT_ERRCODE_ADIE_NOT_EXIST,
+ WMT_ERRCODE_INIT_TABLE_FAIL,
+ WMT_ERRCODE_INIT_DLM_TABLE_FAIL,
+ WMT_ERRCODE_INIT_MCUCLK_TABLE_FAIL,
+ WMT_ERRCODE_INIT_RESET_CMD_FAIL,
+ WMT_ERRCODE_INIT_COCLOCK_TYPE_FAIL,
+ WMT_ERRCODE_INIT_MERGE_PCM_TABLE_FAIL,
+ WMT_ERRCODE_INIT_FM_MODE_FAIL,
+ WMT_ERRCODE_INIT_SET_REGISTER_FAIL,
+ WMT_ERRCODE_INIT_SET_COREDUMP_FAIL,
+ WMT_ERRCODE_INIT_WIFI_CONFIG_FAIL,
+ WMT_ERRCODE_INIT_WIFI_ANT_SWAP_FAIL,
+ WMT_ERRCODE_INIT_EPA_FAIL,
+ WMT_ERRCODE_INIT_EPA_ELNA_FAIL,
+ WMT_ERRCODE_INIT_EPA_ELNA_INVERT_CR_FAIL,
+ WMT_ERRCODE_INIT_COEX_FAIL,
+ WMT_ERRCODE_CALIBRATION_FAIL,
+ WMT_ERRCODE_READ_ADIE_TX_CMD_FAIL,
+ WMT_ERRCODE_READ_ADIE_RX_EVT_FAIL,
+ WMT_ERRCODE_READ_PMIC_CHIPID_FAIL,
+ WMT_ERRCODE_SET_STP_DBG_INFO_FAIL,
+ /* return error code for WMT */
+ WMT_ERRCODE_MAX
+} WMT_ERRCODE_TYPE;
+
+typedef struct _EMI_CTRL_STATE_OFFSET_ {
+ UINT32 emi_apmem_ctrl_state;
+ UINT32 emi_apmem_ctrl_host_sync_state;
+ UINT32 emi_apmem_ctrl_host_sync_num;
+ UINT32 emi_apmem_ctrl_chip_sync_state;
+ UINT32 emi_apmem_ctrl_chip_sync_num;
+ UINT32 emi_apmem_ctrl_chip_sync_addr;
+ UINT32 emi_apmem_ctrl_chip_sync_len;
+ UINT32 emi_apmem_ctrl_chip_print_buff_start;
+ UINT32 emi_apmem_ctrl_chip_print_buff_len;
+ UINT32 emi_apmem_ctrl_chip_print_buff_idx;
+ UINT32 emi_apmem_ctrl_chip_int_status;
+ UINT32 emi_apmem_ctrl_chip_paded_dump_end;
+ UINT32 emi_apmem_ctrl_host_outband_assert_w1;
+ UINT32 emi_apmem_ctrl_chip_page_dump_num;
+ UINT32 emi_apmem_ctrl_assert_flag;
+ UINT32 emi_apmem_ctrl_chip_check_sleep;
+} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET;
+
+typedef struct _BGF_IRQ_BALANCE_ {
+ UINT32 counter;
+ unsigned long flags;
+ spinlock_t lock;
+} BGF_IRQ_BALANCE, *P_BGF_IRQ_BALANCE;
+
+typedef struct _CONSYS_EMI_ADDR_INFO_ {
+ UINT32 emi_phy_addr;
+ UINT32 emi_ap_phy_addr;
+ UINT32 paged_trace_off;
+ UINT32 paged_dump_off;
+ UINT32 full_dump_off;
+ UINT32 emi_remap_offset;
+ P_EMI_CTRL_STATE_OFFSET p_ecso;
+ UINT32 emi_size;
+ UINT32 pda_dl_patch_flag;
+ UINT32 emi_met_size;
+ UINT32 emi_met_data_offset;
+ UINT32 emi_core_dump_offset;
+ UINT32 emi_direct_path_ap_phy_addr;
+ UINT32 emi_direct_path_size;
+ UINT32 emi_ram_bt_buildtime_offset;
+ UINT32 emi_ram_wifi_buildtime_offset;
+ UINT32 emi_ram_mcu_buildtime_offset;
+ UINT32 emi_patch_mcu_buildtime_offset;
+} CONSYS_EMI_ADDR_INFO, *P_CONSYS_EMI_ADDR_INFO;
+
+typedef struct _GPIO_TDM_REQ_INFO_ {
+ UINT32 ant_sel_index;
+ UINT32 gpio_number;
+ UINT32 cr_address;
+} GPIO_TDM_REQ_INFO, *P_GPIO_TDM_REQ_INFO;
+
+struct consys_sw_state {
+ UINT16 clock_hif_ctrl;
+ UINT16 clock_umac_ctrl;
+ UINT32 resource_disable_sleep;
+ UINT32 clock_mcu;
+ UINT32 info_time;
+ UINT8 is_gating;
+ UINT8 sub_system;
+};
+
+typedef struct consys_state {
+ UINT32 lp[2];
+ UINT32 gating[2];
+ UINT64 sleep_counter[WMT_SLEEP_COUNT_MAX];
+ UINT64 sleep_timer[WMT_SLEEP_COUNT_MAX];
+ struct consys_sw_state sw_state;
+} CONSYS_STATE, *P_CONSYS_STATE;
+
+
+typedef VOID(*irq_cb) (VOID);
+typedef INT32(*device_audio_if_cb) (enum CMB_STUB_AIF_X aif, MTK_WCN_BOOL share);
+typedef VOID(*func_ctrl_cb) (UINT32 on, UINT32 type);
+typedef long (*thermal_query_ctrl_cb) (VOID);
+typedef INT32(*trigger_assert_cb) (UINT32 type, UINT32 reason);
+typedef INT32(*deep_idle_ctrl_cb) (UINT32);
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+extern INT32 gWmtDbgLvl;
+extern struct device *wmt_dev;
+#ifdef CFG_WMT_READ_EFUSE_VCN33
+extern INT32 wmt_set_pmic_voltage(UINT32 level);
+#endif
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+INT32 wmt_plat_init(P_PWR_SEQ_TIME pPwrSeqTime, UINT32 co_clock_type);
+INT32 wmt_plat_deinit(VOID);
+INT32 wmt_plat_merge_if_flag_get(VOID);
+INT32 wmt_plat_set_comm_if_type(ENUM_STP_TX_IF_TYPE type);
+INT32 wmt_plat_merge_if_flag_ctrl(UINT32 enagle);
+ENUM_STP_TX_IF_TYPE wmt_plat_get_comm_if_type(VOID);
+
+INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state);
+
+INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state);
+
+INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state);
+
+INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId);
+INT32 wmt_plat_sdio_ctrl(UINT32 sdioPortNum, ENUM_FUNC_STATE on);
+
+INT32 wmt_plat_audio_ctrl(enum CMB_STUB_AIF_X state, enum CMB_STUB_AIF_CTRL ctrl);
+VOID wmt_lib_plat_irq_cb_reg(irq_cb bgf_irq_cb);
+VOID wmt_lib_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb);
+
+VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb);
+VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb);
+VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl);
+VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl);
+VOID wmt_plat_trigger_assert_cb_reg(trigger_assert_cb trigger_assert);
+VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl);
+
+INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo);
+UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset);
+#if CONSYS_ENALBE_SET_JTAG
+UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en);
+#endif
+#if CFG_WMT_DUMP_INT_STATUS
+VOID wmt_plat_BGF_irq_dump_status(VOID);
+MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID);
+#endif
+P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID);
+UINT32 wmt_plat_read_cpupcr(VOID);
+UINT32 wmt_plat_read_dmaregs(UINT32);
+INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state);
+UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type);
+INT32 wmt_plat_update_host_sync_num(VOID);
+INT32 wmt_plat_get_dump_info(UINT32 offset);
+INT32 wmt_plat_write_emi_l(UINT32 offset, UINT32 value);
+UINT32 wmt_plat_get_soc_chipid(VOID);
+INT32 wmt_plat_get_adie_chipid(VOID);
+UINT32 wmt_plat_soc_co_clock_flag_get(VOID);
+INT32 wmt_plat_set_dbg_mode(UINT32 flag);
+INT32 wmt_plat_set_dynamic_dumpmem(PUINT32 buf);
+#if CFG_WMT_LTE_COEX_HANDLING
+INT32 wmt_plat_get_tdm_antsel_index(VOID);
+#endif
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#endif /* _WMT_PLAT_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h
new file mode 100644
index 0000000000000000000000000000000000000000..59d30fa735a2efc6bc31323f3be1b7195e561f0b
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+
+#ifndef _WMT_PLAT_STUB_H_
+#define _WMT_PLAT_STUB_H_
+
+
+INT32 wmt_plat_audio_ctrl(enum CMB_STUB_AIF_X state, enum CMB_STUB_AIF_CTRL ctrl);
+
+INT32 wmt_plat_stub_init(VOID);
+
+#endif /*_WMT_PLAT_STUB_H_*/
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c
new file mode 100644
index 0000000000000000000000000000000000000000..35d6a7c6a00e16d5c5a403cfa5ffcb162ba68137
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c
@@ -0,0 +1,141 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include "bgw_desense.h"
+
+static struct sock *g_nl_sk;
+/* static struct sockaddr_nl src_addr, des_addr; */
+/* static struct iovec iov; */
+static int pid;
+/* static struct msghdr msg; */
+
+void bgw_destroy_netlink_kernel(void)
+{
+ if (g_nl_sk != NULL) {
+ /* sock_release(g_nl_sk->sk_socket); */
+ netlink_kernel_release(g_nl_sk);
+ MSG("release socket\n");
+ return;
+ }
+ ERR("no socket yet\n");
+}
+
+void send_command_to_daemon(const int command /*struct sk_buff *skb */)
+{
+ struct nlmsghdr *nlh = NULL;
+ struct sk_buff *nl_skb = NULL;
+ int res;
+
+ MSG("here we will send command to native daemon\n");
+ if (!g_nl_sk) {
+ ERR("invalid socket\n");
+ return;
+ }
+ if (pid == 0) {
+ ERR("invalid native process pid\n");
+ return;
+ }
+ /*alloc data buffer for sending to native */
+ /*malloc data space at least 1500 bytes, which is ethernet data length */
+ nl_skb = alloc_skb(NLMSG_SPACE(MAX_NL_MSG_LEN), GFP_ATOMIC);
+ if (nl_skb == NULL) {
+ ERR("malloc skb error\n");
+ return;
+ }
+ MSG("malloc data space done\n");
+
+/* nlh = NLMSG_PUT(nl_skb, 0, 0, 0, NLMSG_SPACE(1500)-sizeof(struct nlmsghdr)); */
+ nlh = nlmsg_put(nl_skb, 0, 0, 0, MAX_NL_MSG_LEN, 0);
+ if (nlh == NULL) {
+ MSG("nlh is NULL\n");
+ kfree_skb(nl_skb);
+ return;
+ }
+ NETLINK_CB(nl_skb).portid = 0;
+
+/* memcpy(NLMSG_DATA(nlh), ACK, 5); */
+ *(char *)NLMSG_DATA(nlh) = command;
+ res = netlink_unicast(g_nl_sk, nl_skb, pid, MSG_DONTWAIT);
+ if (res == 0) {
+ MSG("send to user space process error\n");
+ return;
+ }
+ ERR("send to user space process done, data length = %d\n", res);
+}
+
+static void nl_data_handler(struct sk_buff *__skb)
+{
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int i;
+ int len;
+ char str[128];
+
+ MSG("we got netlink message\n");
+ len = NLMSG_SPACE(MAX_NL_MSG_LEN);
+ skb = skb_get(__skb);
+ if (skb == NULL) {
+ ERR("skb_get return NULL");
+ return;
+ }
+ if (skb->len >= NLMSG_SPACE(0)) { /*presume there is 5byte payload at leaset */
+ MSG("length is enough\n");
+ nlh = nlmsg_hdr(skb); /* point to data which include in skb */
+ memcpy(str, NLMSG_DATA(nlh), sizeof(str));
+ for (i = 0; i < 3; i++)
+ MSG("str[%d = %c]", i, str[i]);
+ MSG("str[0] = %d, str[1] = %d, str[2] = %d\n", str[0], str[1], str[2]);
+ if (str[0] == 'B' && str[1] == 'G' && str[2] == 'W') {
+ MSG("got native daemon init command, record it's pid\n");
+ pid = nlh->nlmsg_pid; /*record the native process PID */
+ MSG("native daemon pid is %d\n", pid);
+ } else {
+ ERR("this is not BGW message, ignore it\n");
+ return;
+ }
+ } else {
+ ERR("not engouth data length\n");
+ return;
+ }
+
+ kfree_skb(skb);
+
+ send_command_to_daemon(ACK);
+}
+
+int bgw_init_socket(void)
+{
+ struct netlink_kernel_cfg cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.input = nl_data_handler;
+
+ g_nl_sk = __netlink_kernel_create(&init_net, NETLINK_TEST, THIS_MODULE, &cfg);
+
+ if (g_nl_sk == NULL) {
+ ERR("netlink_kernel_create error\n");
+ return -1;
+ }
+ MSG("netlink_kernel_create ok\n");
+ return 0;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c
new file mode 100644
index 0000000000000000000000000000000000000000..bf495f83f06ed25a0bf173a0d34fa0763650e26d
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+#include "fw_log_wmt.h"
+#include "connsys_debug_utility.h"
+#include
+#include
+#include
+#include
+#include "wmt_lib.h"
+
+#define DRIVER_NAME "fw_log_wmt"
+#define WMT_FW_LOG_IOC_MAGIC 0xfc
+#define WMT_FW_LOG_IOCTL_ON_OFF _IOW(WMT_FW_LOG_IOC_MAGIC, 0, int)
+#define WMT_FW_LOG_IOCTL_SET_LEVEL _IOW(WMT_FW_LOG_IOC_MAGIC, 1, int)
+
+static dev_t gDevId;
+static struct cdev gLogCdev;
+static struct class *fw_log_wmt_class;
+static struct device *fw_log_wmt_dev;
+static wait_queue_head_t wq;
+
+static int fw_log_wmt_open(struct inode *inode, struct file *file)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static int fw_log_wmt_close(struct inode *inode, struct file *file)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static ssize_t fw_log_wmt_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ ssize_t size = 0;
+
+ pr_debug("%s\n", __func__);
+ size = connsys_log_read_to_user(CONNLOG_TYPE_MCU, buf, count);
+ return size;
+}
+
+static ssize_t fw_log_wmt_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static unsigned int fw_log_wmt_poll(struct file *filp, poll_table *wait)
+{
+ pr_debug("%s\n", __func__);
+
+ poll_wait(filp, &wq, wait);
+ if (connsys_log_get_buf_size(CONNLOG_TYPE_MCU) > 0)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static long fw_log_wmt_unlocked_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+
+ switch (cmd) {
+ case WMT_FW_LOG_IOCTL_ON_OFF:
+ pr_debug("ioctl: WMT_FW_LOG_IOCTL_ON_OFF(%lu)", arg);
+ if (arg == 0 || arg == 1)
+ wmt_lib_fw_log_ctrl(WMT_FWLOG_MCU, (unsigned char)arg, 0xFF);
+ break;
+ case WMT_FW_LOG_IOCTL_SET_LEVEL:
+ pr_debug("ioctl: WMT_FW_LOG_IOCTL_SET_LEVEL(%lu)", arg);
+ if (arg <= 4)
+ wmt_lib_fw_log_ctrl(WMT_FWLOG_MCU, 0xFF, (unsigned char)arg);
+ break;
+ default:
+ /*no action*/
+ break;
+ }
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long fw_log_wmt_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return fw_log_wmt_unlocked_ioctl(filp, cmd, arg);
+}
+#endif
+
+const struct file_operations gLogFops = {
+ .open = fw_log_wmt_open,
+ .release = fw_log_wmt_close,
+ .read = fw_log_wmt_read,
+ .write = fw_log_wmt_write,
+ .poll = fw_log_wmt_poll,
+ .unlocked_ioctl = fw_log_wmt_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fw_log_wmt_compat_ioctl,
+#endif
+};
+
+static void fw_log_wmt_event_cb(void)
+{
+ wake_up_interruptible(&wq);
+}
+
+int fw_log_wmt_init(void)
+{
+ int cdevErr = -1;
+ int ret = -1;
+
+ ret = alloc_chrdev_region(&gDevId, 0, 1, DRIVER_NAME);
+ if (ret)
+ pr_err("fail to alloc_chrdev_region\n");
+
+ cdev_init(&gLogCdev, &gLogFops);
+ gLogCdev.owner = THIS_MODULE;
+
+ cdevErr = cdev_add(&gLogCdev, gDevId, 1);
+ if (cdevErr) {
+ pr_err("cdev_add() fails (%d)\n", cdevErr);
+ goto error;
+ }
+
+ fw_log_wmt_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(fw_log_wmt_class)) {
+ pr_err("class_create fail\n");
+ goto error;
+ }
+
+ fw_log_wmt_dev = device_create(fw_log_wmt_class, NULL, gDevId, NULL,
+ DRIVER_NAME);
+ if (IS_ERR(fw_log_wmt_dev)) {
+ pr_err("device_create fail\n");
+ goto error;
+ }
+
+ init_waitqueue_head(&wq);
+ ret = connsys_log_init(CONNLOG_TYPE_MCU);
+ if (ret)
+ pr_err("fail to connsys_log_init\n");
+
+ ret = connsys_log_register_event_cb(CONNLOG_TYPE_MCU,
+ fw_log_wmt_event_cb);
+ if (ret)
+ pr_err("fail to connsys_log_register_event_cb\n");
+
+ return 0;
+
+error:
+ if (!(IS_ERR(fw_log_wmt_dev)))
+ device_destroy(fw_log_wmt_class, gDevId);
+ if (!(IS_ERR(fw_log_wmt_class))) {
+ class_destroy(fw_log_wmt_class);
+ fw_log_wmt_class = NULL;
+ }
+
+ if (cdevErr == 0)
+ cdev_del(&gLogCdev);
+ if (ret == 0)
+ unregister_chrdev_region(gDevId, 1);
+ pr_err("fw_log_wmt_init fail\n");
+ return -1;
+}
+EXPORT_SYMBOL(fw_log_wmt_init);
+
+void fw_log_wmt_deinit(void)
+{
+ connsys_log_deinit(CONNLOG_TYPE_MCU);
+ if (fw_log_wmt_dev) {
+ device_destroy(fw_log_wmt_class, gDevId);
+ fw_log_wmt_dev = NULL;
+ }
+
+ if (fw_log_wmt_class) {
+ class_destroy(fw_log_wmt_class);
+ fw_log_wmt_class = NULL;
+ }
+
+ cdev_del(&gLogCdev);
+ unregister_chrdev_region(gDevId, 1);
+ pr_warn("fw_log_wmt_driver_deinit done\n");
+}
+EXPORT_SYMBOL(fw_log_wmt_deinit);
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c
new file mode 100644
index 0000000000000000000000000000000000000000..207064aa7f87ecab8bd5107f3dfce02bc94b9283
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c
@@ -0,0 +1,2924 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*
+ *
+ * 07 25 2010 george.kuo
+ *
+ * Move hif_sdio driver to linux directory.
+ *
+ * 07 23 2010 george.kuo
+ *
+ * Add MT6620 driver source tree
+ * , including char device driver (wmt, bt, gps), stp driver,
+ * interface driver (tty ldisc and hif_sdio), and bt hci driver.
+**
+**
+*/
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+#define HIF_SDIO_UPDATE (1)
+#define HIF_SDIO_SUPPORT_SUSPEND (1)
+#define HIF_SDIO_SUPPORT_WAKEUP (0)
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+#include
+#include "hif_sdio.h"
+#include "wmt_gpio.h"
+/* #include "hif_sdio_chrdev.h" */
+#include
+#include
+#include
+
+#define mmc_power_up_ext(x)
+#define mmc_power_off_ext(x)
+MTK_WCN_BOOL g_hif_deep_sleep_flag = MTK_WCN_BOOL_FALSE;
+
+#ifndef MMC_CARD_REMOVED
+#define MMC_CARD_REMOVED (1<<4)
+#endif
+
+#ifndef mmc_card_removed
+#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
+#endif
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+/* #define DRV_NAME "[hif_sdio]" */
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+#if HIF_SDIO_SUPPORT_SUSPEND
+static INT32 hif_sdio_suspend(struct device *dev);
+
+static INT32 hif_sdio_resume(struct device *dev);
+#endif
+static INT32 hif_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
+
+static VOID hif_sdio_remove(struct sdio_func *func);
+
+static VOID hif_sdio_irq(struct sdio_func *func);
+
+static _osal_inline_ INT32 hif_sdio_clt_probe_func(MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p,
+ INT8 probe_idx);
+
+static VOID hif_sdio_clt_probe_worker(struct work_struct *work);
+
+static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_func(struct sdio_func *func);
+
+#if 0 /* TODO:[ChangeFeature][George] remove obsolete function? */
+static INT32 hif_sdio_find_probed_list_index_by_clt_index(INT32 clt_index);
+#endif
+
+static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_id_func(UINT16 vendor, UINT16 device,
+ UINT16 func_num);
+
+static _osal_inline_ VOID hif_sdio_init_clt_list(INT32 index);
+
+static _osal_inline_ INT32 hif_sdio_find_clt_list_index(UINT16 vendor, UINT16 device, UINT16 func_num);
+
+static _osal_inline_ INT32 hif_sdio_check_supported_sdio_id(UINT16 vendor, UINT16 device);
+
+static _osal_inline_ INT32 hif_sdio_check_duplicate_sdio_id(UINT16 vendor, UINT16 device, UINT16 func_num);
+
+static _osal_inline_ INT32 hif_sdio_add_clt_list(PINT32 clt_index_p, const MTK_WCN_HIF_SDIO_CLTINFO *pinfo,
+ UINT32 tbl_index);
+
+static _osal_inline_ INT32 hif_sdio_stp_on(VOID);
+
+static _osal_inline_ INT32 hif_sdio_stp_off(VOID);
+
+static _osal_inline_ INT32 hif_sdio_wifi_on(VOID);
+
+static _osal_inline_ INT32 hif_sdio_wifi_off(VOID);
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_init(VOID);
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_set_act(UINT32 chipid, UINT16 func_num,
+ MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT8 act_flag);
+
+static INT32 _hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx);
+
+static _osal_inline_ INT32 wmt_tra_sdio_update(VOID);
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_dmp(MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info);
+
+static _osal_inline_ VOID hif_sdio_dump_probe_list(VOID);
+
+static _osal_inline_ VOID hif_sdio_init_probed_list(INT32 index);
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/* Supported SDIO device table */
+static const struct sdio_device_id mtk_sdio_id_tbl[] = {
+ /* MT6618 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */
+ {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */
+ {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */
+
+ /* MT6619 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */
+
+ /* MT6620 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */
+ {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */
+ {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
+
+ /* MT5921 *//* Not an SDIO standard class device */
+ {SDIO_DEVICE(0x037A, 0x5921)},
+
+ /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6628)},
+
+ /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6630)},
+
+ /* MT6632 *//* SDIO1: Wi-Fi */
+ {SDIO_DEVICE(0x037A, 0x6602)},
+
+ /* MT6632 *//* SDIO2: BGF */
+ {SDIO_DEVICE(0x037A, 0x6632)},
+
+ { /* end: all zeroes */ },
+};
+
+#if HIF_SDIO_SUPPORT_SUSPEND
+static const struct dev_pm_ops mtk_sdio_pmops = {
+ .suspend = hif_sdio_suspend,
+ .resume = hif_sdio_resume,
+};
+#endif
+
+static struct sdio_driver mtk_sdio_client_drv = {
+ .name = "mtk_sdio_client", /* MTK SDIO Client Driver */
+ .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */
+ .probe = hif_sdio_probe,
+ .remove = hif_sdio_remove,
+#if HIF_SDIO_SUPPORT_SUSPEND
+ .drv = {
+ .pm = &mtk_sdio_pmops,
+ },
+#endif
+};
+
+/* Registered client driver list */
+/* static list g_hif_sdio_clt_drv_list */
+static MTK_WCN_HIF_SDIO_REGISTINFO g_hif_sdio_clt_drv_list[CFG_CLIENT_COUNT];
+
+/* MMC probed function list */
+/* static list g_hif_sdio_probed_func_list */
+static MTK_WCN_HIF_SDIO_PROBEINFO g_hif_sdio_probed_func_list[CFG_CLIENT_COUNT];
+
+/* spin lock info for g_hif_sdio_clt_drv_list and g_hif_sdio_probed_func_list */
+static MTK_WCN_HIF_SDIO_LOCKINFO g_hif_sdio_lock_info;
+
+/* reference count, debug information? */
+static INT32 gRefCount;
+static INT32 (*fp_wmt_tra_sdio_update)(VOID);
+static atomic_t hif_sdio_irq_enable_flag = ATOMIC_INIT(0);
+
+/*deep sleep related information*/
+MTK_WCN_HIF_SDIO_DS_INFO g_hif_sdio_ds_info_list[] = {
+ {
+ .chip_id = 0x6630,
+ .reg_offset = 0xF1,
+ .value = 0x1,
+ },
+ {
+ .chip_id = 0x6632,
+ .reg_offset = 0xF1,
+ .value = 0x1,
+ },
+ { /* end: all zeroes */ }
+};
+
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3");
+MODULE_DESCRIPTION("MediaTek MT6620 HIF SDIO Driver");
+
+MODULE_DEVICE_TABLE(sdio, mtk_sdio_id_tbl);
+
+INT32 gHifSdioDbgLvl = HIF_SDIO_LOG_INFO;
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#if 0
+INT32 __weak mtk_wcn_sdio_irq_flag_set(INT32 falg)
+{
+ HIF_SDIO_INFO_FUNC("mtk_wcn_sdio_irq_flag_set is not define!!!!!\n");
+
+ return 0;
+}
+#endif
+
+INT32 mtk_wcn_hif_sdio_irq_flag_set(INT32 flag)
+{
+
+ if (flag == 0) {
+ atomic_dec(&hif_sdio_irq_enable_flag);
+ if (atomic_read(&hif_sdio_irq_enable_flag) == 0)
+ wmt_export_mtk_wcn_sdio_irq_flag_set(0);
+ } else {
+ atomic_inc(&hif_sdio_irq_enable_flag);
+ if (atomic_read(&hif_sdio_irq_enable_flag) == 1)
+ wmt_export_mtk_wcn_sdio_irq_flag_set(1);
+ }
+
+ return 0;
+}
+
+
+/*!
+ * \brief register the callback funciton for record the timestamp of sdio access
+ *
+ * \param callback function
+ *
+ * \retval -EINVAL, when registered callback is invalid
+ * \retval 0, when registered callback is valid
+ */
+INT32 mtk_wcn_hif_sdio_update_cb_reg(INT32(*ts_update) (VOID))
+{
+ if (ts_update) {
+ fp_wmt_tra_sdio_update = ts_update;
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_update_cb_reg);
+
+/*!
+ * \brief update the accessing time of SDIO via callback function
+ *
+ * \param void
+ *
+ * \retval -EINVAL, when callback is not registered
+ * \retval returned value of callback
+ */
+static _osal_inline_ INT32 wmt_tra_sdio_update(VOID)
+{
+ if (fp_wmt_tra_sdio_update)
+ return (*fp_wmt_tra_sdio_update) ();
+ /* HIF_SDIO_WARN_FUNC("wmt_tra_sdio_update == NULL\n"); */
+ return -EINVAL;
+}
+
+/*!
+ * \brief Translate CLTCTX into a pointer to struct sdio_func if it is valid
+ *
+ * Translate a CLTCTX into a pointer to struct sdio_func if it is
+ * 1) probed by mmc_core, and
+ * 2) client driver is registered, and
+ * 3) clt_idx of client driver is valid
+ *
+ * \param ctx a context provided by client driver
+ *
+ * \retval null if any condition is not valie
+ * \retval a pointer to a struct sdio_func mapped by provided ctx
+ */
+static _osal_inline_ struct sdio_func *hif_sdio_ctx_to_func(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ UINT32 probe_index;
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_UIDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ return NULL;
+ }
+ /* the client has not been registered */
+ if (unlikely(g_hif_sdio_probed_func_list[probe_index].clt_idx < 0)) {
+ HIF_SDIO_WARN_FUNC
+ ("can't find client idx in probed list!ctx(0x%x) prob_idx(%d) clt_idx(%d)\n",
+ ctx, probe_index, g_hif_sdio_probed_func_list[probe_index].clt_idx);
+ return NULL;
+ }
+ return g_hif_sdio_probed_func_list[probe_index].func;
+}
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_dmp(MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info)
+{
+ UINT32 i = 0;
+ MTK_WCN_HIF_SDIO_DS_CLT_INFO *ctl_info = NULL;
+ UINT32 ctl_info_array_size = ARRAY_SIZE(p_ds_info->clt_info);
+
+ mutex_lock(&p_ds_info->lock);
+ HIF_SDIO_DBG_FUNC("p_ds_info: %p, chipid:0x%x, reg_offset:0x%x, value:0x%x\n",
+ p_ds_info, p_ds_info->chip_id, p_ds_info->reg_offset, p_ds_info->value);
+
+ for (i = 0; i < ctl_info_array_size; i++) {
+ ctl_info = &p_ds_info->clt_info[i];
+
+ HIF_SDIO_DBG_FUNC
+ ("ctl_info[%d]--ctx:0x%08x, func_num:%d, act_flag:%d, en_flag:%d\n", i,
+ ctl_info->ctx, ctl_info->func_num, ctl_info->act_flag, ctl_info->ds_en_flag);
+ }
+ mutex_unlock(&p_ds_info->lock);
+ return 0;
+}
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_init(VOID)
+{
+ UINT32 array_size = 0;
+ UINT32 clt_info_size = 0;
+ UINT32 i = 0;
+ UINT32 j = 0;
+
+ array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list);
+
+ /*set clt_info segment to 0 by default, when do stp/wifi on, write real information back */
+ for (i = 0; i < array_size; i++) {
+ mutex_init(&g_hif_sdio_ds_info_list[i].lock);
+ clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info);
+
+ mutex_lock(&g_hif_sdio_ds_info_list[i].lock);
+ for (j = 0; j < clt_info_size; j++)
+ memset(&g_hif_sdio_ds_info_list[i].clt_info[j],
+ 0, sizeof(MTK_WCN_HIF_SDIO_DS_CLT_INFO));
+ mutex_unlock(&g_hif_sdio_ds_info_list[i].lock);
+
+ hif_sdio_deep_sleep_info_dmp(&g_hif_sdio_ds_info_list[i]);
+ }
+
+ return 0;
+}
+
+static _osal_inline_ INT32 hif_sdio_deep_sleep_info_set_act(UINT32 chipid, UINT16 func_num,
+ MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT8 act_flag)
+{
+ UINT32 i = 0;
+ UINT32 array_size = 0;
+ UINT32 clt_info_size = 0;
+ UINT32 idx = 0;
+ MTK_WCN_HIF_SDIO_DS_CLT_INFO *p_ds_clt_info = NULL;
+
+ array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list);
+
+ /*search write index */
+ for (i = 0; i < array_size; i++) {
+ if (g_hif_sdio_ds_info_list[i].chip_id == chipid)
+ break;
+ }
+ if (i >= array_size) {
+ HIF_SDIO_WARN_FUNC("no valid ds info found for 0x%x\n", chipid);
+ return -1;
+ }
+ HIF_SDIO_DBG_FUNC("valid ds info found for 0x%x\n", chipid);
+
+ clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info);
+
+ if (func_num > clt_info_size) {
+ HIF_SDIO_WARN_FUNC("func num <%d> exceed max clt info size <%d>\n", func_num,
+ clt_info_size);
+ return -2;
+ }
+ idx = func_num - 1;
+ p_ds_clt_info = &g_hif_sdio_ds_info_list[i].clt_info[idx];
+
+ mutex_lock(&g_hif_sdio_ds_info_list[i].lock);
+ p_ds_clt_info->func_num = func_num;
+ p_ds_clt_info->ctx = ctx;
+ p_ds_clt_info->act_flag = act_flag;
+ p_ds_clt_info->ds_en_flag = 0;
+ mutex_unlock(&g_hif_sdio_ds_info_list[i].lock);
+
+ HIF_SDIO_DBG_FUNC("set act_flag to %d for ctx:0x%x whose chipid:0x%x, func_num:%d done\n",
+ act_flag, ctx, chipid, func_num);
+ /* hif_sdio_deep_sleep_info_dmp(&g_hif_sdio_ds_info_list[0]); */
+
+ return 0;
+}
+
+static INT32 _hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ INT32 ret = 0;
+ INT32 gpio_state = -1;
+ INT32 sec_old = 0;
+ INT32 usec_old = 0;
+ INT32 sec = 0;
+ INT32 usec = 0;
+ INT32 polling_counter = 0;
+ UINT8 cccr_value = 0x0;
+ UINT32 cpupcr_value = 0x00;
+ INT32 i = 0;
+ UINT32 delay_us = 500;
+ WMT_GPIO_STATE_INFO gpio_state_list[2];
+
+ HIF_SDIO_DBG_FUNC("wakeup chip from deep sleep!\n");
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 1);
+ HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 1: %d!\n",
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num));
+ } else {
+ HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n");
+ return -2;
+ }
+ /*1.pull GPIO_CHIP_WAKE_UP_PIN out 0*/
+ gpio_state_list[0].gpio_num = gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num-280;
+ _wmt_gpio_pre_regs(gpio_state_list[0].gpio_num, &gpio_state_list[0]);
+ gpio_state_list[1].gpio_num = gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_num-280;
+ _wmt_gpio_pre_regs(gpio_state_list[1].gpio_num, &gpio_state_list[1]);
+
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 0);
+ HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 0: %d!\n",
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num));
+ } else {
+ HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n");
+ return -2;
+ }
+ /*2.waiting for DEEP_SLEEP_PIN become high*/
+ osal_gettimeofday(&sec_old, &usec_old);
+ HIF_SDIO_DBG_FUNC("wakeup flow, prepare polling DEEP_SLEEP_PIN high state, timing: %d us\n", usec_old);
+ while (1) {
+ osal_gettimeofday(&sec, &usec);
+ gpio_state =
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_num);
+ if (gpio_state == 0) {
+ HIF_SDIO_DBG_FUNC("wmt_gpio:Polling GPIO_CHIP_DEEP_SLEEP_PIN low success!\n");
+ if (polling_counter >= 20)
+ HIF_SDIO_WARN_FUNC
+ ("polling ACK_B pin low success but over 20 count, time:%dus, count:%d\n",
+ (usec - usec_old), polling_counter);
+ polling_counter = 0;
+ break;
+ }
+ if (polling_counter >= 60) {
+ HIF_SDIO_ERR_FUNC
+ ("wake up fail!, polling ACK_B pin low over 60 count, time:%dus, count:%d\n",
+ (usec - usec_old), polling_counter);
+ HIF_SDIO_INFO_FUNC("Dump EINT_B, ACT_B history states!\n");
+ _wmt_dump_gpio_pre_regs(gpio_state_list[0]);
+ _wmt_dump_gpio_pre_regs(gpio_state_list[1]);
+ HIF_SDIO_INFO_FUNC("Dump EINT_B, ACT_B current states!\n");
+ _wmt_dump_gpio_regs(gpio_state_list[0].gpio_num);
+ _wmt_dump_gpio_regs(gpio_state_list[1].gpio_num);
+
+ HIF_SDIO_INFO_FUNC("read cccr info !\n");
+ for (i = 0; i < 8; i++) {
+ ret = mtk_wcn_hif_sdio_f0_readb(ctx, CCCR_F8 + i, &cccr_value);
+ if (ret)
+ HIF_SDIO_ERR_FUNC("read CCCR fail(%d), address(0x%x)\n", ret, CCCR_F8 + i);
+ else
+ HIF_SDIO_INFO_FUNC("read CCCR value(0x%x), address(0x%x)\n",
+ cccr_value, CCCR_F8 + i);
+ cccr_value = 0x0;
+ }
+
+ HIF_SDIO_INFO_FUNC("read cpupcr info !\n");
+ for (i = 0; i < 5; i++) {
+ ret = mtk_wcn_hif_sdio_readl(ctx, SWPCDBGR, &cpupcr_value);
+ if (ret)
+ HIF_SDIO_ERR_FUNC("read cpupcr fail, ret(%d)\n", ret);
+ else
+ HIF_SDIO_ERR_FUNC("read cpupcr value (0x%x)\n", cpupcr_value);
+ msleep(20);
+ }
+ _wmt_dump_gpio_regs(gpio_state_list[0].gpio_num);
+ _wmt_dump_gpio_regs(gpio_state_list[1].gpio_num);
+ ret = -11;
+ break;
+ }
+ polling_counter++;
+ osal_usleep_range(delay_us, 2 * delay_us);
+ }
+ /*3.pull GPIO_CHIP_WAKE_UP_PIN high, clear interrupt*/
+ if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) {
+ gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 1);
+ HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 1: %d!\n",
+ gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num));
+ } else {
+ HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n");
+ return -3;
+ }
+
+ return ret;
+}
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 mtk_wcn_hif_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag)
+{
+ g_hif_deep_sleep_flag = flag;
+ return 0;
+}
+#endif
+INT32 hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ UINT32 i = 0;
+ UINT32 j = 0;
+ INT32 ret = 0;
+ UINT32 array_size = 0;
+ UINT32 clt_info_size = 0;
+ MTK_WCN_HIF_SDIO_DS_CLT_INFO *p_ds_clt_info = NULL;
+ MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info = NULL;
+ UINT8 do_ds_op_flag = 0;
+
+ array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list);
+ /*search write index */
+ for (i = 0; i < array_size; i++) {
+ mutex_lock(&(g_hif_sdio_ds_info_list[i].lock));
+ clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info);
+
+ for (j = 0; j < clt_info_size; j++) {
+ if (g_hif_sdio_ds_info_list[i].clt_info[j].ctx == ctx) {
+ do_ds_op_flag = 1;
+ break;
+ }
+ }
+
+ if (do_ds_op_flag != 0)
+ break;
+ mutex_unlock(&(g_hif_sdio_ds_info_list[i].lock));
+ }
+
+ if ((i >= array_size) || (j >= clt_info_size)) {
+ HIF_SDIO_ERR_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, no valid ds info found for ctx 0x%08x\n", ctx);
+ return -1;
+ }
+ HIF_SDIO_DBG_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, valid ds info found for ctx 0x%08x\n", ctx);
+ p_ds_info = &g_hif_sdio_ds_info_list[i];
+ p_ds_clt_info = &p_ds_info->clt_info[j];
+ HIF_SDIO_DBG_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, func_num:(%d), chid(%x)\n",
+ p_ds_clt_info->func_num, p_ds_info->chip_id);
+ if (g_hif_deep_sleep_flag) {
+ HIF_SDIO_DBG_FUNC("deep sleep feature is enable!\n");
+ ret = _hif_sdio_wake_up_ctrl(ctx);
+ if (ret == -11) {
+ HIF_SDIO_DBG_FUNC("wake up chip from deep sleep fail, retry wake up operation\n");
+ ret = _hif_sdio_wake_up_ctrl(ctx);
+ if (ret == 0)
+ HIF_SDIO_INFO_FUNC("retry wake up from deep sleep success\n");
+ else if (ret == -11)
+ HIF_SDIO_INFO_FUNC("retry wake up from deep sleep fail!\n");
+ }
+ } else
+ HIF_SDIO_DBG_FUNC("deep sleep feature is disable!\n");
+ mutex_unlock(&(g_hif_sdio_ds_info_list[i].lock));
+ return ret;
+}
+
+/*!
+ * \brief MTK hif sdio client registration function
+ *
+ * Client uses this function to register itself to hif_sdio driver
+ *
+ * \param pinfo a pointer of client's information
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo)
+{
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 clt_index = -1;
+ UINT32 i = 0;
+ UINT32 j = 0;
+ MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ /* 4 <1> check input pointer is valid */
+ HIF_SDIO_ASSERT(pinfo);
+
+ /* 4 <2> check if input parameters are all supported and valid */
+ for (i = 0; i < pinfo->func_tbl_size; i++) {
+ ret =
+ hif_sdio_check_supported_sdio_id(pinfo->func_tbl[i].manf_id,
+ pinfo->func_tbl[i].card_id);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC
+ ("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported!\n",
+ pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id);
+ goto out;
+ }
+ }
+ HIF_SDIO_DBG_FUNC("hif_sdio_check_supported_sdio_id() done!\n");
+
+ /* 4 <3> check if the specific {manf id, card id, function number} tuple is */
+ /* 4 already resigstered */
+ for (i = 0; i < pinfo->func_tbl_size; i++) {
+ ret =
+ hif_sdio_check_duplicate_sdio_id(pinfo->func_tbl[i].manf_id,
+ pinfo->func_tbl[i].card_id,
+ pinfo->func_tbl[i].func_num);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) of\n",
+ pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id,
+ pinfo->func_tbl[i].func_num);
+ HIF_SDIO_WARN_FUNC("sdio_func are duplicated in g_hif_sdio_clt_drv_list!\n");
+ goto out;
+ }
+ }
+ HIF_SDIO_DBG_FUNC("hif_sdio_check_duplicate_sdio_id() done!\n");
+
+ /*
+ * 4 <4> add the specified {manf id, card id, function number}
+ * tuple to registered client list
+ */
+ HIF_SDIO_DBG_FUNC("pinfo->func_tbl_size:%d\n", pinfo->func_tbl_size);
+ for (i = 0; i < pinfo->func_tbl_size; i++) {
+ ret = hif_sdio_add_clt_list(&clt_index, pinfo, i);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC
+ ("client's info are added in registed client list failed (buffer is full)!\n");
+ goto out;
+ }
+ HIF_SDIO_DBG_FUNC("hif_sdio_add_clt_list() done (gRefCount=%d)!\n", gRefCount);
+
+ /* 4 <5> if the specific {manf id, card id, function number} tuple has already */
+ /* 4 been probed by mmc, schedule another task to call client's .hif_clt_probe() */
+ for (j = 0; j < CFG_CLIENT_COUNT; j++) {
+ /* probed spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ if (g_hif_sdio_probed_func_list[j].func == 0) {
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ continue;
+ }
+ /* the function has been probed */
+ if ((g_hif_sdio_clt_drv_list[clt_index].func_info->manf_id ==
+ g_hif_sdio_probed_func_list[j].func->vendor)
+ && (g_hif_sdio_clt_drv_list[clt_index].func_info->card_id ==
+ g_hif_sdio_probed_func_list[j].func->device)
+ && (g_hif_sdio_clt_drv_list[clt_index].func_info->func_num ==
+ g_hif_sdio_probed_func_list[j].func->num)) {
+ g_hif_sdio_probed_func_list[j].clt_idx = clt_index;
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ if (g_hif_sdio_probed_func_list[j].func->num != 1
+ || (g_hif_sdio_probed_func_list[j].on_by_wmt == MTK_WCN_BOOL_TRUE
+ && g_hif_sdio_probed_func_list[j].func->num == 1)) {
+ /* use worker thread to perform the client's .hif_clt_probe() */
+ clt_probe_worker_info =
+ vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO));
+ if (clt_probe_worker_info) {
+ INIT_WORK(&clt_probe_worker_info->probe_work,
+ hif_sdio_clt_probe_worker);
+ clt_probe_worker_info->registinfo_p =
+ &g_hif_sdio_clt_drv_list[clt_index];
+ clt_probe_worker_info->probe_idx = j;
+ schedule_work(&clt_probe_worker_info->probe_work);
+ }
+ /* 4 <5.1> remember to do claim_irq for the */
+ /* func if it's irq had been released. */
+ if (!(g_hif_sdio_probed_func_list[j].func->irq_handler)) {
+ sdio_claim_host(g_hif_sdio_probed_func_list[j].func);
+ ret =
+ sdio_claim_irq(g_hif_sdio_probed_func_list[j].func,
+ hif_sdio_irq);
+ mtk_wcn_hif_sdio_irq_flag_set(1);
+ sdio_release_host(g_hif_sdio_probed_func_list[j].func);
+ HIF_SDIO_INFO_FUNC
+ ("sdio_claim_irq for func(0x%p) j(%d) v(0x%x) d(0x%x) ok\n",
+ g_hif_sdio_probed_func_list[j].func, j,
+ g_hif_sdio_probed_func_list[j].func->vendor,
+ g_hif_sdio_probed_func_list[j].func->device);
+ }
+ /* 4 <5.2> Reset the block size of the function provided by client */
+ HIF_SDIO_INFO_FUNC("Reset sdio block size: %d!\n",
+ g_hif_sdio_clt_drv_list[clt_index].
+ func_info->blk_sz);
+ sdio_claim_host(g_hif_sdio_probed_func_list[j].func);
+ ret = sdio_set_block_size(g_hif_sdio_probed_func_list[j].func,
+ g_hif_sdio_clt_drv_list
+ [clt_index].func_info->blk_sz);
+ sdio_release_host(g_hif_sdio_probed_func_list[j].func);
+ }
+ } else {
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ }
+ }
+ HIF_SDIO_DBG_FUNC
+ ("map g_hif_sdio_clt_drv_list to g_hif_sdio_probed_func_list done!\n");
+ }
+ ret = HIF_SDIO_ERR_SUCCESS;
+ gRefCount++;
+
+out:
+ /* 4 error handling */
+
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_reg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_reg);
+
+/*!
+ * \brief MTK hif sdio client un-registration function
+ *
+ * Client uses this function to un-register itself
+ *
+ * \param pinfo a pointer of client's information
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_client_unreg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo)
+{
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 clt_list_index = 0;
+ UINT32 i = 0;
+ UINT32 j = 0;
+
+ HIF_SDIO_INFO_FUNC("start!\n");
+
+ /* 4 <1> check if input pointer is valid */
+ HIF_SDIO_ASSERT(pinfo);
+
+ /* 4 <2> check if input parameters are all supported and valid */
+ for (i = 0; i < pinfo->func_tbl_size; i++) {
+ ret =
+ hif_sdio_check_supported_sdio_id(pinfo->func_tbl[i].manf_id,
+ pinfo->func_tbl[i].card_id);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC
+ ("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n",
+ pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id);
+ goto out;
+ }
+ }
+
+ /* 4 <3> check if the specific {manf id, card id, function number} tuple is already resigstered */
+ /* 4 and find the corresponding client ctx and call client's .hif_clt_remove() in THIS context */
+ for (i = 0; i < pinfo->func_tbl_size; i++) {
+ clt_list_index =
+ hif_sdio_find_clt_list_index(pinfo->func_tbl[i].manf_id,
+ pinfo->func_tbl[i].card_id,
+ pinfo->func_tbl[i].func_num);
+ if (clt_list_index < 0) {
+ HIF_SDIO_WARN_FUNC("vendor id(0x%x),", pinfo->func_tbl[i].manf_id);
+ HIF_SDIO_WARN_FUNC(" device id(0x%x),", pinfo->func_tbl[i].card_id);
+ HIF_SDIO_WARN_FUNC(" and fun_num(%d)", pinfo->func_tbl[i].func_num);
+ HIF_SDIO_WARN_FUNC(" client info is not in the client's registed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ /* 4 <4> mark the specified {manf id, card id, function number} tuple as */
+ /* 4 un-registered and invalidate client's context */
+ hif_sdio_init_clt_list(clt_list_index);
+
+ /* un-map g_hif_sdio_clt_drv_list index in g_hif_sdio_probed_func_list */
+ for (j = 0; j < CFG_CLIENT_COUNT; j++) {
+ if (g_hif_sdio_probed_func_list[j].clt_idx == clt_list_index)
+ g_hif_sdio_probed_func_list[j].clt_idx = -1;
+ }
+ }
+ gRefCount--;
+
+ ret = HIF_SDIO_ERR_SUCCESS;
+out:
+ HIF_SDIO_INFO_FUNC("end (gRefCount=%d) !\n", gRefCount);
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_unreg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_unreg);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pvb);
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+
+ /* 4 <2> */
+ osal_ftrace_print("%s|S\n", __func__);
+ sdio_claim_host(func);
+ *pvb = sdio_readb(func, offset, &ret);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E\n", __func__);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_unreg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_readb);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ wmt_tra_sdio_update();
+ osal_ftrace_print("%s|S\n", __func__);
+ sdio_claim_host(func);
+ sdio_writeb(func, vb, offset, &ret);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E\n", __func__);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_unreg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_writeb);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_readl(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT32 pvl)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pvl);
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ osal_ftrace_print("%s|S\n", __func__);
+ sdio_claim_host(func);
+ *pvl = sdio_readl(func, offset, &ret);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E\n", __func__);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_unreg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_readl);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_writel(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT32 vl)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ wmt_tra_sdio_update();
+ osal_ftrace_print("%s|S\n", __func__);
+ sdio_claim_host(func);
+ sdio_writel(func, vl, offset, &ret);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E\n", __func__);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_client_unreg() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_writel);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_read_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx,
+ UINT32 offset, PUINT32 pbuf, UINT32 len)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pbuf);
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ osal_ftrace_print("%s|S|L|%d\n", __func__, len);
+ sdio_claim_host(func);
+ ret = sdio_readsb(func, pbuf, offset, len);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E|L|%d\n", __func__, len);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_read_buf() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_read_buf);
+
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_write_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx,
+ UINT32 offset, PUINT32 pbuf, UINT32 len)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pbuf);
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ wmt_tra_sdio_update();
+ osal_ftrace_print("%s|S|L|%d\n", __func__, len);
+ sdio_claim_host(func);
+ ret = sdio_writesb(func, offset, pbuf, len);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E|L|%d\n", __func__, len);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret);
+
+ return ret;
+} /* end of mtk_wcn_hif_sdio_write_buf() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_write_buf);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_abort(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pbuf);
+
+ /* 4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+ /* 4 <1.1> check if input parameters are valid */
+
+ /* 4 <2> */
+ osal_ftrace_print("%s|S|L|\n", __func__);
+ sdio_claim_host(func);
+ /* SDIO Control must be switched to function 2 before the abort command send
+ * firmware can receive function 2 abort interrupt
+ * read CTMDPCR1(0xBC) to switch function 2
+ */
+ sdio_readl(func, 0xBC, &ret);
+ ret = KERNEL_mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_ABORT, func->num, NULL);
+ sdio_release_host(func);
+ osal_ftrace_print("%s|E|L|\n", __func__);
+
+ /* 4 <3> check result code and return proper error code */
+
+out:
+ HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret);
+
+ return ret;
+} /* end of mtk_wcn_hif_sdio_write_buf() */
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_abort);
+
+/*!
+ * \brief store client driver's private data function.
+ *
+ *
+ * \param clent's MTK_WCN_HIF_SDIO_CLTCTX.
+ *
+ * \retval none.
+ */
+VOID mtk_wcn_hif_sdio_set_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx, PVOID private_data_p)
+{
+ UINT8 probed_idx = CLTCTX_IDX(ctx);
+
+ if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), private_data_p not stored!\n", ctx);
+ } else {
+ /* store client driver's private data to dev driver */
+ g_hif_sdio_probed_func_list[probed_idx].private_data_p = private_data_p;
+ HIF_SDIO_DBG_FUNC("private_data_p(0x%p) for ctx(0x%x) probed idx(%d) stored!\n",
+ private_data_p, ctx, probed_idx);
+ }
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_set_drvdata);
+
+/*!
+ * \brief get client driver's private data function.
+ *
+ *
+ * \param clent's MTK_WCN_HIF_SDIO_CLTCTX.
+ *
+ * \retval private data pointer.
+ */
+PVOID mtk_wcn_hif_sdio_get_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ UINT8 probed_idx = CLTCTX_IDX(ctx);
+
+ /* get client driver's private data to dev driver */
+ if (likely(CLTCTX_UIDX_VALID(probed_idx)))
+ return g_hif_sdio_probed_func_list[probed_idx].private_data_p;
+ /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), return null!\n", ctx);
+ return NULL;
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_drvdata);
+
+/*!
+ * \brief control stp/wifi on/off from wmt.
+ *
+ *
+ * \param (1)control function type, (2)on/off control.
+ *
+ * \retval (1)control results ,(2)unknown type: -5.
+ * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
+ */
+INT32 mtk_wcn_hif_sdio_wmt_control(WMT_SDIO_FUNC_TYPE func_type, MTK_WCN_BOOL is_on)
+{
+ /* TODO:[FixMe][George]: return value of this function shall distinguish */
+ /* 1) not probed by mmc_core yet or */
+ /* 2) probed by mmc_core but init fail... */
+ switch (func_type) {
+ case WMT_SDIO_FUNC_STP:
+ if (is_on == MTK_WCN_BOOL_TRUE)
+ return hif_sdio_stp_on();
+ else
+ return hif_sdio_stp_off();
+ break;
+
+ case WMT_SDIO_FUNC_WIFI:
+ if (is_on == MTK_WCN_BOOL_TRUE)
+ return hif_sdio_wifi_on();
+ else
+ return hif_sdio_wifi_off();
+ break;
+
+ default:
+ HIF_SDIO_WARN_FUNC("unknown type(%d)\n", func_type);
+ return HIF_SDIO_ERR_INVALID_PARAM;
+ }
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_wmt_control);
+
+/*!
+ * \brief ???
+ *
+ * \detail ???
+ *
+ * \param ctx a context provided by client driver
+ * \param struct device ** ???
+ *
+ * \retval none
+ */
+VOID mtk_wcn_hif_sdio_get_dev(MTK_WCN_HIF_SDIO_CLTCTX ctx, struct device **dev)
+{
+#if HIF_SDIO_UPDATE
+ struct sdio_func *func = NULL;
+#else
+ UINT8 probe_index = CLTCTX_IDX(ctx);
+#endif
+
+#if HIF_SDIO_UPDATE
+ *dev = NULL; /* ensure we does not return any invalid value back. */
+ func = hif_sdio_ctx_to_func(ctx);
+ if (unlikely(!func)) {
+ HIF_SDIO_WARN_FUNC("no valid *func with ctx(0x%x)\n", ctx);
+ return;
+ }
+ *dev = &(func->dev);
+ HIF_SDIO_DBG_FUNC("return *dev(0x%p) for ctx(0x%x)\n", *dev, ctx);
+#else
+ if (probe_index < 0) {
+ HIF_SDIO_WARN_FUNC("func not probed, probe_index = %d", probe_index);
+ return;
+ }
+ *dev = &g_hif_sdio_probed_func_list[probe_index].func->dev;
+#endif
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_dev);
+
+/*!
+ * \brief client's probe() function.
+ *
+ *
+ * \param work queue structure.
+ *
+ * \retval none.
+ */
+static _osal_inline_ INT32 hif_sdio_clt_probe_func(MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p, INT8 probe_idx)
+{
+ UINT16 card_id = 0;
+ UINT16 func_num = 0;
+ UINT16 blk_sz = 0;
+ INT32 ret;
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(registinfo_p);
+ if (!registinfo_p) {
+ HIF_SDIO_WARN_FUNC("registinfo_p NULL!!!\n");
+ return -1;
+ }
+
+ /* special case handling: if the clt's unregister is called during probe procedures */
+ if (!registinfo_p->func_info || !registinfo_p->sdio_cltinfo) {
+ HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n");
+ return -1;
+ }
+
+ card_id = registinfo_p->func_info->card_id;
+ func_num = registinfo_p->func_info->func_num;
+ blk_sz = registinfo_p->func_info->blk_sz;
+ ret =
+ registinfo_p->sdio_cltinfo->hif_clt_probe(CLTCTX(card_id, func_num, blk_sz, probe_idx),
+ registinfo_p->func_info);
+
+ HIF_SDIO_DBG_FUNC
+ ("clt_probe_func card_id(%x) func_num(%x) blk_sz(%d) prob_idx(%x) ret(%d) %s\n",
+ card_id, func_num, blk_sz, probe_idx, ret, (ret) ? "fail" : "ok");
+
+ return ret;
+}
+
+/*!
+ * \brief client's probe() worker.
+ *
+ *
+ * \param work queue structure.
+ *
+ * \retval none.
+ */
+static VOID hif_sdio_clt_probe_worker(struct work_struct *work)
+{
+ MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_worker_info_p = 0;
+ UINT16 card_id = 0;
+ UINT16 func_num = 0;
+ UINT16 blk_sz = 0;
+ INT8 prob_idx = 0;
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+ HIF_SDIO_ASSERT(work);
+
+ /* get client's information */
+ clt_worker_info_p = container_of(work, MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO, probe_work);
+ HIF_SDIO_ASSERT(clt_worker_info_p);
+ HIF_SDIO_ASSERT(clt_worker_info_p->registinfo_p);
+
+ /* special case handling: if the clt's unregister is called during probe procedures */
+ if ((clt_worker_info_p->registinfo_p->func_info == 0)
+ || (clt_worker_info_p->registinfo_p->sdio_cltinfo == 0)) {
+ HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n");
+ vfree(clt_worker_info_p);
+ return;
+ }
+
+ card_id = clt_worker_info_p->registinfo_p->func_info->card_id;
+ func_num = clt_worker_info_p->registinfo_p->func_info->func_num;
+ blk_sz = clt_worker_info_p->registinfo_p->func_info->blk_sz;
+ prob_idx = clt_worker_info_p->probe_idx;
+
+ /* Execute client's probe() func */
+ clt_worker_info_p->registinfo_p->
+ sdio_cltinfo->hif_clt_probe(CLTCTX(card_id, func_num, blk_sz, prob_idx),
+ clt_worker_info_p->registinfo_p->func_info);
+
+ vfree(clt_worker_info_p);
+
+ HIF_SDIO_DBG_FUNC("card_id(0x%x) func_num(0x%x) blk_sz(0x%x) prob_idx(0x%x)\n", card_id,
+ func_num, blk_sz, prob_idx);
+ HIF_SDIO_DBG_FUNC("end!\n");
+}
+
+/*!
+ * \brief client's probe() worker.
+ *
+ *
+ * \param work queue structure.
+ *
+ * \retval none.
+ */
+static _osal_inline_ VOID hif_sdio_dump_probe_list(VOID)
+{
+ INT32 i;
+
+ HIF_SDIO_DBG_FUNC("== DUMP probed list start ==\n");
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (g_hif_sdio_probed_func_list[i].func) {
+ HIF_SDIO_DBG_FUNC("index(%d) func(0x%p) clt_idx(%d)\n",
+ i, g_hif_sdio_probed_func_list[i].func,
+ g_hif_sdio_probed_func_list[i].clt_idx);
+
+ HIF_SDIO_DBG_FUNC("vendor(0x%x) device(0x%x) num(0x%x) state(%d)\n",
+ g_hif_sdio_probed_func_list[i].func->vendor,
+ g_hif_sdio_probed_func_list[i].func->device,
+ g_hif_sdio_probed_func_list[i].func->num,
+ g_hif_sdio_probed_func_list[i].on_by_wmt);
+
+ }
+ }
+
+ HIF_SDIO_DBG_FUNC("== DUMP probed list end ==\n");
+}
+
+
+/*!
+ * \brief Initialize g_hif_sdio_probed_func_list
+ *
+ *
+ * \param index of g_hif_sdio_probed_func_list.
+ *
+ * \retval none.
+ */
+static _osal_inline_ VOID hif_sdio_init_probed_list(INT32 index)
+{
+ if ((index >= 0) && (index < CFG_CLIENT_COUNT)) {
+ /* probed spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ g_hif_sdio_probed_func_list[index].func = 0;
+ g_hif_sdio_probed_func_list[index].clt_idx = -1;
+ g_hif_sdio_probed_func_list[index].private_data_p = 0;
+ g_hif_sdio_probed_func_list[index].on_by_wmt = MTK_WCN_BOOL_FALSE;
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ } else
+ HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_probed_func_list[] boundary!\n");
+}
+
+
+/*!
+ * \brief Initialize g_hif_sdio_clt_drv_list
+ *
+ *
+ * \param index of g_hif_sdio_clt_drv_list.
+ *
+ * \retval none.
+ */
+static _osal_inline_ VOID hif_sdio_init_clt_list(INT32 index)
+{
+ /* client list spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ if ((index >= 0) && (index < CFG_CLIENT_COUNT)) {
+ g_hif_sdio_clt_drv_list[index].sdio_cltinfo = 0;
+ g_hif_sdio_clt_drv_list[index].func_info = 0;
+ } else
+ HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_clt_drv_list[] boundary!\n");
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+}
+
+
+/*!
+ * \brief find matched g_hif_sdio_probed_func_list index from sdio function handler
+ *
+ *
+ * \param sdio function handler
+ *
+ * \retval -1 index not found
+ * \retval >= 0 return found index
+ */
+static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_func(struct sdio_func *func)
+{
+ INT32 i = 0;
+
+ HIF_SDIO_ASSERT(func);
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (g_hif_sdio_probed_func_list[i].func == func)
+ return i;
+ }
+
+ return -1;
+}
+
+/*!
+ * \brief find matched g_hif_sdio_probed_func_list from vendor_id, device_id, and function number
+ *
+ *
+ * \param vendor id, device id, and function number of the sdio card.
+ *
+ * \retval -1 index not found
+ * \retval >= 0 return found index
+ */
+static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_id_func(UINT16 vendor, UINT16 device,
+ UINT16 func_num)
+{
+ INT32 i;
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (g_hif_sdio_probed_func_list[i].func) {
+ HIF_SDIO_DBG_FUNC("probed entry: vendor(0x%x) device(0x%x) num(0x%x)\n",
+ g_hif_sdio_probed_func_list[i].func->vendor,
+ g_hif_sdio_probed_func_list[i].func->device,
+ g_hif_sdio_probed_func_list[i].func->num);
+ }
+ }
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (!g_hif_sdio_probed_func_list[i].func) {
+ continue;
+ } else if ((g_hif_sdio_probed_func_list[i].func->vendor == vendor) &&
+ (g_hif_sdio_probed_func_list[i].func->device == device) &&
+ (g_hif_sdio_probed_func_list[i].func->num == func_num)) {
+ return i;
+ }
+ }
+
+ if (i == CFG_CLIENT_COUNT) {
+ /*
+ * pr_warn(DRV_NAME "Cannot find vendor:0x%x, device:0x%x, func_num:0x%x, i=%d\n",
+ * vendor, device, func_num, i);
+ */
+ /* client func has not been probed */
+ return -1;
+ }
+ return -1;
+}
+
+/*!
+ * \brief find matched g_hif_sdio_clt_drv_list index
+ *
+ * find the matched g_hif_sdio_clt_drv_list index from card_id and function number.
+ *
+ * \param vendor id, device id, and function number of the sdio card
+ *
+ * \retval -1 index not found
+ * \retval >= 0 return found index
+ */
+static _osal_inline_ INT32 hif_sdio_find_clt_list_index(UINT16 vendor, UINT16 device, UINT16 func_num)
+{
+ INT32 i = 0;
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (g_hif_sdio_clt_drv_list[i].func_info != 0) {
+ if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor) &&
+ (g_hif_sdio_clt_drv_list[i].func_info->card_id == device) &&
+ (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num)) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+/*!
+ * \brief check if the vendor, device ids are supported in mtk_sdio_id_tbl.
+ *
+ *
+ * \param vendor id and device id of the sdio card
+ *
+ * \retval (-HIF_SDIO_ERR_FAIL) vendor, device ids are not supported
+ * \retval HIF_SDIO_ERR_SUCCESS vendor, device ids are supported
+ */
+static _osal_inline_ INT32 hif_sdio_check_supported_sdio_id(UINT16 vendor, UINT16 device)
+{
+ INT32 i = 0;
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if ((mtk_sdio_id_tbl[i].vendor == vendor) && (mtk_sdio_id_tbl[i].device == device))
+ return HIF_SDIO_ERR_SUCCESS; /* mtk_sdio_id is supported */
+ }
+ return -HIF_SDIO_ERR_FAIL; /* mtk_sdio_id is not supported */
+}
+
+
+/*!
+ * \brief check if the vendor, device ids are duplicated in g_hif_sdio_clt_drv_list.
+ *
+ *
+ * \param vendor id, device id, and function number of the sdio card
+ *
+ * \retval (-HIF_SDIO_ERR_DUPLICATED) vendor, device, func_num are duplicated
+ * \retval HIF_SDIO_ERR_SUCCESS vendor, device, func_num are not duplicated
+ */
+static _osal_inline_ INT32 hif_sdio_check_duplicate_sdio_id(UINT16 vendor, UINT16 device, UINT16 func_num)
+{
+ INT32 i = 0;
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ if (g_hif_sdio_clt_drv_list[i].func_info != 0) {
+ if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor) &&
+ (g_hif_sdio_clt_drv_list[i].func_info->card_id == device) &&
+ (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num)) {
+ return -HIF_SDIO_ERR_DUPLICATED; /* duplicated */
+ }
+ }
+ }
+ return HIF_SDIO_ERR_SUCCESS; /* Not duplicated */
+}
+
+
+/*!
+ * \brief Add the client info into g_hif_sdio_clt_drv_list.
+ *
+ *
+ * \param [output] client's index pointer.
+ * \param MTK_WCN_HIF_SDIO_CLTINFO of client's contex.
+ *
+ * \retval (-HIF_SDIO_ERR_FAIL) Add to clt_list successfully
+ * \retval HIF_SDIO_ERR_SUCCESS Add to clt_list failed (buffer is full)
+ */
+static _osal_inline_ INT32 hif_sdio_add_clt_list(PINT32 clt_index_p,
+ const MTK_WCN_HIF_SDIO_CLTINFO *pinfo, UINT32 tbl_index)
+{
+ INT32 i = 0;
+
+ HIF_SDIO_ASSERT(clt_index_p);
+ HIF_SDIO_ASSERT(pinfo);
+
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ /* client list spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ if (g_hif_sdio_clt_drv_list[i].func_info == 0) {
+ g_hif_sdio_clt_drv_list[i].func_info = &(pinfo->func_tbl[tbl_index]);
+ g_hif_sdio_clt_drv_list[i].sdio_cltinfo = pinfo;
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ *clt_index_p = i;
+ return HIF_SDIO_ERR_SUCCESS; /* Add to client list successfully */
+ }
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ }
+ return -HIF_SDIO_ERR_FAIL; /* Add to client list failed (buffer is full) */
+}
+
+#if HIF_SDIO_SUPPORT_SUSPEND
+static INT32 hif_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = NULL;
+ mmc_pm_flag_t flag;
+ INT32 ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ func = dev_to_sdio_func(dev);
+ HIF_SDIO_DBG_FUNC("prepare for func(0x%p)\n", func);
+ flag = sdio_get_host_pm_caps(func);
+#if HIF_SDIO_SUPPORT_WAKEUP
+ if (!(flag & MMC_PM_KEEP_POWER) || !(flag & MMC_PM_WAKE_SDIO_IRQ)) {
+ HIF_SDIO_WARN_FUNC
+ ("neither MMC_PM_KEEP_POWER or MMC_PM_WAKE_SDIO_IRQ is supported by host, return -ENOTSUPP\n");
+ return -ENOTSUPP;
+ }
+
+ /* set both */
+ flag |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
+#else
+ if (!(flag & MMC_PM_KEEP_POWER)) {
+ HIF_SDIO_WARN_FUNC
+ ("neither MMC_PM_KEEP_POWER is supported by host, return -ENOTSUPP\n");
+ return -ENOTSUPP;
+ }
+ flag |= MMC_PM_KEEP_POWER;
+#endif
+ ret = sdio_set_host_pm_flags(func, flag);
+ if (ret) {
+ HIF_SDIO_INFO_FUNC
+ ("set MMC_PM_KEEP_POWER to host fail(%d)\n", ret);
+ return -EFAULT;
+ }
+#if HIF_SDIO_SUPPORT_WAKEUP
+ sdio_claim_host(func);
+#endif
+ HIF_SDIO_INFO_FUNC("set MMC_PM_KEEP_POWER ok\n");
+ return 0;
+}
+
+static INT32 hif_sdio_resume(struct device *dev)
+{
+#if HIF_SDIO_SUPPORT_WAKEUP
+ struct sdio_func *func = NULL;
+#endif
+ if (!dev) {
+ HIF_SDIO_WARN_FUNC("null dev!\n");
+ return -EINVAL;
+ }
+#if HIF_SDIO_SUPPORT_WAKEUP
+ func = dev_to_sdio_func(dev);
+ sdio_release_host(func);
+#endif
+ HIF_SDIO_INFO_FUNC("do nothing\n");
+
+ return 0;
+}
+#endif
+
+/*!
+ * \brief hif_sdio probe function
+ *
+ * hif_sdio probe function called by mmc driver when any matched SDIO function
+ * is detected by it.
+ *
+ * \param func
+ * \param id
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+static INT32 hif_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ INT32 ret = 0;
+ INT32 i = 0;
+ MTK_WCN_HIF_SDIO_PROBEINFO *hif_sdio_probed_funcp = 0;
+ INT32 probe_index = -1;
+ INT32 idx;
+#if 0
+ INT32 clt_index = -1;
+ MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(func);
+#if !(DELETE_HIF_SDIO_CHRDEV)
+ hif_sdio_match_chipid_by_dev_id(id);
+#endif
+ /* 4 <0> display debug information */
+ HIF_SDIO_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device,
+ func->num);
+ for (i = 0; i < func->card->num_info; i++)
+ HIF_SDIO_DBG_FUNC("card->info[%d]: %s\n", i, func->card->info[i]);
+
+ /* 4 <1> Check if this is supported by us (mtk_sdio_id_tbl) */
+ ret = hif_sdio_check_supported_sdio_id(func->vendor, func->device);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC
+ ("vendor id and device id of sdio_func are not supported in mtk_sdio_id_tbl!\n");
+ goto out;
+ }
+ /* 4 <2> Add this struct sdio_func *func to g_hif_sdio_probed_func_list */
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ /* probed spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ if (g_hif_sdio_probed_func_list[i].func == 0) {
+ hif_sdio_probed_funcp = &g_hif_sdio_probed_func_list[i];
+ hif_sdio_probed_funcp->func = func;
+ hif_sdio_probed_funcp->clt_idx =
+ hif_sdio_find_clt_list_index(func->vendor, func->device, func->num);
+ hif_sdio_probed_funcp->on_by_wmt = MTK_WCN_BOOL_FALSE;
+ hif_sdio_probed_funcp->sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ probe_index = i;
+ break;
+ }
+ /* probed spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock);
+ }
+ if ((probe_index < 0) || (probe_index >= CFG_CLIENT_COUNT)) {
+ HIF_SDIO_ERR_FUNC("probe function list if full!\n");
+ goto out;
+ }
+ /* 4 <3> Initialize this function */
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) {
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ /* client list spin lock */
+ spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ if (g_hif_sdio_clt_drv_list[i].func_info == 0) {
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ continue;
+ }
+ HIF_SDIO_INFO_FUNC("manf_id:%x, card_id:%x, func_num:%d\n",
+ g_hif_sdio_clt_drv_list[i].func_info->manf_id,
+ g_hif_sdio_clt_drv_list[i].func_info->card_id,
+ g_hif_sdio_clt_drv_list[i].func_info->func_num);
+ if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id ==
+ g_hif_sdio_probed_func_list[probe_index].func->vendor)
+ && (g_hif_sdio_clt_drv_list[i].func_info->card_id ==
+ g_hif_sdio_probed_func_list[probe_index].func->device)
+ && (g_hif_sdio_clt_drv_list[i].func_info->func_num ==
+ g_hif_sdio_probed_func_list[probe_index].func->num)) {
+ g_hif_sdio_probed_func_list[probe_index].clt_idx = i;
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ break;
+ }
+ /* client list spin unlock */
+ spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock);
+ }
+ HIF_SDIO_INFO_FUNC("map to g_hif_sdio_clt_drv_list[] done: %d\n",
+ g_hif_sdio_probed_func_list[probe_index].clt_idx);
+ }
+ /* 4 <3.1> enable this function */
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ sdio_release_host(func);
+ if (ret) {
+ HIF_SDIO_ERR_FUNC("sdio_enable_func failed!\n");
+ goto out;
+ }
+
+ /* 4 <3.2> set block size according to the table storing function characteristics */
+ if (hif_sdio_probed_funcp == 0) {
+ HIF_SDIO_ERR_FUNC("hif_sdio_probed_funcp is null!\n");
+ goto out;
+ }
+ if (hif_sdio_probed_funcp->clt_idx >= 0 &&
+ hif_sdio_probed_funcp->clt_idx < CFG_CLIENT_COUNT) {
+ /* The clt contex has been registed */
+ sdio_claim_host(func);
+ idx = hif_sdio_probed_funcp->clt_idx;
+ ret = sdio_set_block_size(func, g_hif_sdio_clt_drv_list[idx].func_info->blk_sz);
+ sdio_release_host(func);
+ } else { /* The clt contex has not been registed */
+
+ sdio_claim_host(func);
+ ret = sdio_set_block_size(func, HIF_DEFAULT_BLK_SIZE);
+ sdio_release_host(func);
+ }
+ if (ret) {
+ HIF_SDIO_ERR_FUNC("set sdio block size failed!\n");
+ goto out;
+ }
+
+ HIF_SDIO_DBG_FUNC("cur_blksize(%d) max(%d), host max blk_size(%d) blk_count(%d)\n",
+ func->cur_blksize, func->max_blksize,
+ func->card->host->max_blk_size, func->card->host->max_blk_count);
+
+
+ hif_sdio_dump_probe_list();
+
+out:
+ /* 4 error handling */
+ return ret;
+}
+
+
+/*!
+ * \brief hif_sdio remove function
+ *
+ * hif_sdio probe function called by mmc driver when the probed func should be
+ * removed.
+ *
+ * \param func
+ *
+ */
+static VOID hif_sdio_remove(struct sdio_func *func)
+{
+ INT32 probed_list_index = 0;
+#if 0
+ INT32 registed_list_index = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(func);
+
+ /* 4 <1> check input parameter is valid and has been probed previously */
+ if (func == NULL) {
+ HIF_SDIO_ERR_FUNC("func null(%p)\n", func);
+ return;
+ }
+ /* 4 <2> if this function has been initialized by any client driver, */
+ /* 4 call client's .hif_clt_remove() call back in THIS context. */
+ probed_list_index = hif_sdio_find_probed_list_index_by_func(func);
+ if (probed_list_index < 0) {
+ HIF_SDIO_WARN_FUNC
+ ("sdio function pointer is not in g_hif_sdio_probed_func_list!\n");
+ return;
+ }
+#if 0
+ registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx;
+ if (registed_list_index >= 0) {
+ g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_remove(CLTCTX
+ (func->
+ device,
+ func->
+ num,
+ func->
+ cur_blksize,
+ probed_list_index));
+ }
+#endif
+
+ /* 4 <3> mark this function as de-initialized and invalidate client's context */
+ hif_sdio_init_probed_list(probed_list_index);
+
+#if 0
+ /* 4 <4> release irq for this function */
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+#endif
+
+ /* 4 <5> disable this function */
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ /* 4 <6> mark this function as removed */
+
+ HIF_SDIO_DBG_FUNC("sdio func(0x%p) is removed successfully!\n", func);
+}
+
+/*!
+ * \brief hif_sdio interrupt handler
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ */
+static VOID hif_sdio_irq(struct sdio_func *func)
+{
+ INT32 probed_list_index = -1;
+ INT32 registed_list_index = -1;
+ INT32 ret;
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+ osal_ftrace_print("%s|S\n", __func__);
+ /* 4 <1> check if func is valid */
+ HIF_SDIO_ASSERT(func);
+
+ /* 4 <2> if func has valid corresponding hif_sdio client's context, mark it */
+ /* 4 host-locked, use it to call client's .hif_clt_irq() callback function in */
+ /* 4 THIS context. */
+ probed_list_index = hif_sdio_find_probed_list_index_by_func(func);
+ if ((probed_list_index < 0) || (probed_list_index >= CFG_CLIENT_COUNT)) {
+ HIF_SDIO_ERR_FUNC("probed_list_index not found!\n");
+ return;
+ }
+ /* [George] added for sdio irq sync and mmc single_irq workaround. It's set
+ * enabled later by client driver call mtk_wcn_hif_sdio_enable_irq()
+ */
+ /* skip smp_rmb() here */
+ if (g_hif_sdio_probed_func_list[probed_list_index].sdio_irq_enabled == MTK_WCN_BOOL_FALSE) {
+ HIF_SDIO_WARN_FUNC("func(0x%p),probed_idx(%d) sdio irq not enabled yet\n",
+ func, probed_list_index);
+ return;
+ }
+
+ registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx;
+/* g_hif_sdio_probed_func_list[probed_list_index].interrupted = MTK_WCN_BOOL_TRUE; */
+ if ((registed_list_index >= 0)
+ && (registed_list_index < CFG_CLIENT_COUNT)) {
+ HIF_SDIO_DBG_FUNC("[%d]SDIO IRQ (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n",
+ probed_list_index, func, func->vendor, func->device, func->num);
+
+ g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_irq(CLTCTX
+ (func->
+ device,
+ func->num,
+ func->
+ cur_blksize,
+ probed_list_index));
+ } else {
+ /* 4 <3> if func has no VALID hif_sdio client's context, release irq for this */
+ /* 4 func and mark it in g_hif_sdio_probed_func_list (remember: donnot claim host in irq contex). */
+ HIF_SDIO_WARN_FUNC("release irq (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n",
+ func, func->vendor, func->device, func->num);
+ mtk_wcn_hif_sdio_irq_flag_set(0);
+ ret = sdio_release_irq(func);
+ if (ret)
+ HIF_SDIO_WARN_FUNC("sdio_release_irq() fail(%d)\n", ret);
+ }
+ osal_ftrace_print("%s|E\n", __func__);
+}
+
+/*!
+ * \brief hif_sdio init function
+ *
+ * detailed descriptions
+ *
+ * \retval
+ */
+static INT32 hif_sdio_init(VOID)
+{
+ INT32 ret = 0;
+ INT32 i = 0;
+
+ HIF_SDIO_INFO_FUNC("start!\n");
+
+ /* 4 <1> init all private variables */
+ /* init reference count to 0 */
+ gRefCount = 0;
+
+ atomic_set(&hif_sdio_irq_enable_flag, 0);
+ /* init spin lock information */
+ spin_lock_init(&g_hif_sdio_lock_info.probed_list_lock);
+ spin_lock_init(&g_hif_sdio_lock_info.clt_list_lock);
+
+ /* init probed function list and g_hif_sdio_clt_drv_list */
+ for (i = 0; i < CFG_CLIENT_COUNT; i++) {
+ hif_sdio_init_probed_list(i);
+ hif_sdio_init_clt_list(i);
+ }
+
+ /* 4 <2> register to mmc driver */
+ ret = sdio_register_driver(&mtk_sdio_client_drv);
+ if (ret != 0)
+ HIF_SDIO_INFO_FUNC("sdio_register_driver() fail, ret=%d\n", ret);
+
+#if !(DELETE_HIF_SDIO_CHRDEV)
+ /* 4 <3> create thread for query chip id and device node for launcher to access */
+ if (hifsdiod_start() == 0)
+ hif_sdio_create_dev_node();
+#endif
+ hif_sdio_deep_sleep_info_init();
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+}
+
+/*!
+ * \brief hif_sdio init function
+ *
+ * detailed descriptions
+ *
+ * \retval
+ */
+static VOID hif_sdio_exit(VOID)
+{
+ HIF_SDIO_INFO_FUNC("start!\n");
+
+#if !(DELETE_HIF_SDIO_CHRDEV)
+ hif_sdio_remove_dev_node();
+ hifsdiod_stop();
+#endif
+
+ /* 4 <0> if client driver is not removed yet, we shall NOT be called... */
+
+ /* 4 <1> check reference count */
+ if (gRefCount != 0)
+ HIF_SDIO_WARN_FUNC("gRefCount=%d !!!\n", gRefCount);
+ /* 4 <2> check if there is any hif_sdio-registered clients. There should be */
+ /* 4 no registered client... */
+
+ /* 4 <3> Reregister with mmc driver. Our remove handler hif_sdio_remove() */
+ /* 4 will be called later by mmc_core. Clean up driver resources there. */
+ sdio_unregister_driver(&mtk_sdio_client_drv);
+ atomic_set(&hif_sdio_irq_enable_flag, 0);
+ HIF_SDIO_DBG_FUNC("end!\n");
+} /* end of exitWlan() */
+
+/*!
+ * \brief stp on by wmt (probe client driver).
+ *
+ *
+ * \param none.
+ *
+ * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
+ */
+static _osal_inline_ INT32 hif_sdio_stp_on(VOID)
+{
+#if 0
+ MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
+#endif
+ INT32 clt_index = -1;
+ INT32 probe_index = -1;
+ INT32 ret = -1;
+ INT32 ret2 = -1;
+ struct sdio_func *func = NULL;
+ UINT32 chip_id = 0;
+ UINT16 func_num = 0;
+
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL;
+
+ HIF_SDIO_DBG_FUNC("hif_sdio_stp_on, start!\n");
+
+ /* 4 <1> If stp client drv has not been probed, return error code */
+ /* MT6620 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+
+ /* MT6628 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+ /* MT6630 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 2);
+ if (probe_index >= 0) {
+ chip_id = 0x6630;
+ func_num = 2;
+ goto stp_on_exist;
+ }
+ /* MT6632 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6632, 2);
+ if (probe_index >= 0) {
+ chip_id = 0x6632;
+ func_num = 2;
+ goto stp_on_exist;
+ }
+ /* MT6619 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+
+ /* MT6618 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1);
+ if (probe_index >= 0)
+ goto stp_on_exist;
+ else {
+ /* 4 <2> If stp client drv has not been probed, return error code */
+ /* client func has not been probed */
+ HIF_SDIO_INFO_FUNC("no supported func probed\n");
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+
+stp_on_exist:
+ /* 4 <3> If stp client drv has been on by wmt, return error code */
+ if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt != MTK_WCN_BOOL_FALSE) {
+ HIF_SDIO_INFO_FUNC("already on...\n");
+ return HIF_SDIO_ERR_ALRDY_ON;
+ }
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE;
+
+ clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx;
+ if (clt_index >= 0) { /* the function has been registered */
+ g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
+ /* 4 <4> claim irq for this function */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+ if (unlikely(!(func) || !(func->card) || !(func->card->host)
+ || mmc_card_removed(func->card))) {
+ HIF_SDIO_ERR_FUNC("sdio host is missing\n");
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+ sdio_claim_host(func);
+ ret = sdio_claim_irq(func, hif_sdio_irq);
+ mtk_wcn_hif_sdio_irq_flag_set(1);
+ sdio_release_host(func);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC("sdio_claim_irq() for stp fail(%d)\n", ret);
+ return ret;
+ }
+ HIF_SDIO_DBG_FUNC("sdio_claim_irq() for stp ok\n");
+
+ /* 4 <5> If this struct sdio_func *func is supported by any driver in */
+ /* 4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() */
+ /* TODO: [FixMe][George] WHY probe worker is removed??? */
+#if 1
+ /* Call client's .hif_clt_probe() */
+ ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC("clt_probe_func() for stp fail(%d) release irq\n", ret);
+ sdio_claim_host(func);
+ mtk_wcn_hif_sdio_irq_flag_set(0);
+ ret2 = sdio_release_irq(func);
+ sdio_release_host(func);
+ if (ret2)
+ HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2);
+
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
+ return ret;
+ }
+ g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_TRUE;
+
+ /*set deep sleep information to global data struct */
+ func_info = g_hif_sdio_clt_drv_list[clt_index].func_info;
+ hif_sdio_deep_sleep_info_set_act(chip_id, func_num,
+ CLTCTX(func_info->card_id, func_info->func_num,
+ func_info->blk_sz, probe_index), 1);
+
+
+ HIF_SDIO_DBG_FUNC("hif_sdio_stp_on, ok!\n");
+
+ return 0;
+#else
+ /* use worker thread to perform the client's .hif_clt_probe() */
+ clt_probe_worker_info = vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO));
+ INIT_WORK(&clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker);
+ clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
+ clt_probe_worker_info->probe_idx = probe_index;
+ schedule_work(&clt_probe_worker_info->probe_work);
+#endif
+ } else {
+ /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */
+ HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
+ return HIF_SDIO_ERR_CLT_NOT_REG;
+ }
+}
+
+/*!
+ * \brief stp off by wmt (remove client driver).
+ *
+ *
+ * \param none.
+ *
+ * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors.
+ */
+static _osal_inline_ INT32 hif_sdio_stp_off(VOID)
+{
+ INT32 clt_index = -1;
+ INT32 probe_index = -1;
+ INT32 ret = -1;
+ INT32 ret2 = -1;
+ struct sdio_func *func = NULL;
+ UINT32 chip_id = 0;
+ UINT16 func_num = 0;
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL;
+
+ HIF_SDIO_DBG_FUNC("hif_sdio_stp_off, start!\n");
+
+ /* 4 <1> If stp client drv has not been probed, return error code */
+ /* MT6620 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+
+ /* MT6628 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+ /* MT6630 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 2);
+ if (probe_index >= 0) {
+ chip_id = 0x6630;
+ func_num = 2;
+ goto stp_off_exist;
+ }
+ /* MT6632 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6632, 2);
+ if (probe_index >= 0) {
+ chip_id = 0x6632;
+ func_num = 2;
+ goto stp_off_exist;
+ }
+
+ /* MT6619 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+
+ /* MT6618 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1);
+ if (probe_index >= 0)
+ goto stp_off_exist;
+ else {
+ /* 4 <2> If stp client drv has not been probed, return error code */
+ /* client func has not been probed */
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+
+stp_off_exist:
+ /* 4 <3> If stp client drv has been off by wmt, return error code */
+ if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt == MTK_WCN_BOOL_FALSE) {
+ HIF_SDIO_WARN_FUNC("already off...\n");
+ return HIF_SDIO_ERR_ALRDY_OFF;
+ }
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
+
+#if 0 /* TODO: [FixMe][George] moved below as done in stp_on. */
+ /* 4 <4> release irq for this function */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+ sdio_claim_host(func);
+ ret = sdio_release_irq(func);
+ sdio_release_host(func);
+ if (ret)
+ pr_warn(DRV_NAME "sdio_release_irq for stp fail(%d)\n", ret);
+ else
+ pr_warn(DRV_NAME "sdio_release_irq for stp ok\n");
+#endif
+ clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx;
+ if (clt_index >= 0) { /* the function has been registered */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+
+ if (unlikely(!(func) || !(func->card) || !(func->card->host)
+ || mmc_card_removed(func->card))) {
+ HIF_SDIO_ERR_FUNC("sdio host is missing\n");
+ return HIF_SDIO_ERR_ALRDY_OFF;
+ }
+ /* 4 <4> release irq for this function */
+ sdio_claim_host(func);
+ mtk_wcn_hif_sdio_irq_flag_set(0);
+ ret2 = sdio_release_irq(func);
+ sdio_release_host(func);
+
+ if (ret2)
+ HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2);
+ else
+ HIF_SDIO_DBG_FUNC("sdio_release_irq() for stp ok\n");
+
+ /* 4 <5> Callback to client driver's remove() func */
+ ret =
+ g_hif_sdio_clt_drv_list[clt_index].
+ sdio_cltinfo->hif_clt_remove(CLTCTX
+ (func->device, func->num, func->cur_blksize,
+ probe_index));
+ if (ret)
+ HIF_SDIO_WARN_FUNC("clt_remove for stp fail(%d)\n", ret);
+ else
+ HIF_SDIO_DBG_FUNC("hif_sdio_stp_off, ok!\n");
+
+ /*set deep sleep information to global data struct */
+ func_info = g_hif_sdio_clt_drv_list[clt_index].func_info;
+ hif_sdio_deep_sleep_info_set_act(chip_id, func_num,
+ CLTCTX(func_info->card_id, func_info->func_num,
+ func_info->blk_sz, probe_index), 0);
+ return ret + ret2;
+ }
+ /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */
+ HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
+ return HIF_SDIO_ERR_CLT_NOT_REG;
+}
+
+/*!
+ * \brief wifi on by wmt (probe client driver).
+ *
+ *
+ * \param none.
+ *
+ * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
+ */
+static _osal_inline_ INT32 hif_sdio_wifi_on(VOID)
+{
+#if 0
+ MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
+#endif
+ INT32 clt_index = -1;
+ INT32 probe_index = -1;
+ INT32 ret = 0;
+ INT32 ret2 = 0;
+ struct sdio_func *func = NULL;
+ UINT32 chip_id = 0;
+ UINT16 func_num = 0;
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL;
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+ /* 4 <1> If wifi client drv has not been probed, return error code */
+ /* MT6620 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1);
+ if (probe_index >= 0)
+ goto wifi_on_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2);
+ if (probe_index >= 0)
+ goto wifi_on_exist;
+ /* MT6628 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1);
+ if (probe_index == 0)
+ goto wifi_on_exist;
+ /* MT6630 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 1);
+ if (probe_index >= 0) {
+ chip_id = 0x6630;
+ func_num = 1;
+ goto wifi_on_exist;
+ }
+ /* MT6632 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6602, 1);
+ if (probe_index >= 0) {
+ chip_id = 0x6632;
+ func_num = 1;
+ goto wifi_on_exist;
+ }
+
+ /* MT6618 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1);
+ if (probe_index == 0)
+ goto wifi_on_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2);
+ if (probe_index >= 0)
+ goto wifi_on_exist;
+ else {
+ /* 4 <2> If wifi client drv has not been probed, return error code */
+ /* client func has not been probed */
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+
+wifi_on_exist:
+ /* 4 <3> If wifi client drv has been on by wmt, return error code */
+ if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt) {
+ HIF_SDIO_INFO_FUNC("probe_index (%d), already on...\n", probe_index);
+ return HIF_SDIO_ERR_ALRDY_ON;
+ }
+ clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx;
+ if (clt_index >= 0) { /* the function has been registered */
+ g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
+ /* 4 <4> claim irq for this function */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+ if (unlikely(!(func) || !(func->card) || !(func->card->host)
+ || mmc_card_removed(func->card))) {
+ HIF_SDIO_ERR_FUNC("sdio host is missing\n");
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+ sdio_claim_host(func);
+ ret = sdio_claim_irq(func, hif_sdio_irq);
+ mtk_wcn_hif_sdio_irq_flag_set(1);
+ sdio_release_host(func);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC("sdio_claim_irq() for wifi fail(%d)\n", ret);
+ return ret;
+ }
+ HIF_SDIO_INFO_FUNC("sdio_claim_irq() for wifi ok\n");
+
+ /* 4 <5> If this struct sdio_func *func is supported by any driver in */
+ /* 4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() */
+ /* TODO: [FixMe][George] WHY probe worker is removed??? */
+#if 1
+ /*set deep sleep information to global data struct */
+ func_info = g_hif_sdio_clt_drv_list[clt_index].func_info;
+ hif_sdio_deep_sleep_info_set_act(chip_id, func_num,
+ CLTCTX(func_info->card_id, func_info->func_num,
+ func_info->blk_sz, probe_index), 1);
+
+ /* Call client's .hif_clt_probe() */
+ ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index);
+ if (ret) {
+ HIF_SDIO_WARN_FUNC("clt_probe_func() for wifi fail(%d) release irq\n", ret);
+ sdio_claim_host(func);
+ mtk_wcn_hif_sdio_irq_flag_set(0);
+ ret2 = sdio_release_irq(func);
+ sdio_release_host(func);
+ if (ret2)
+ HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2);
+
+ hif_sdio_deep_sleep_info_set_act(chip_id, func_num,
+ CLTCTX(func_info->card_id,
+ func_info->func_num,
+ func_info->blk_sz, probe_index),
+ 0);
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
+ return ret;
+ }
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE;
+
+ HIF_SDIO_DBG_FUNC("ok!\n");
+ return 0;
+#else
+ /* use worker thread to perform the client's .hif_clt_probe() */
+ clt_probe_worker_info = vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO));
+ INIT_WORK(&clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker);
+ clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
+ clt_probe_worker_info->probe_idx = probe_index;
+ schedule_work(&clt_probe_worker_info->probe_work);
+#endif
+ } else {
+ /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */
+ HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE;
+ return HIF_SDIO_ERR_CLT_NOT_REG;
+ }
+}
+
+/*!
+ * \brief wifi off by wmt (remove client driver).
+ *
+ *
+ * \param none.
+ *
+ * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors.
+ */
+static _osal_inline_ INT32 hif_sdio_wifi_off(VOID)
+{
+ INT32 clt_index = -1;
+ INT32 probe_index = -1;
+ INT32 ret = -1;
+ INT32 ret2 = -1;
+ struct sdio_func *func = NULL;
+ UINT32 chip_id = 0;
+ UINT16 func_num = 0;
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL;
+
+ HIF_SDIO_INFO_FUNC("start!\n");
+
+ /* 4 <1> If wifi client drv has not been probed, return error code */
+ /* MT6620 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1);
+ if (probe_index >= 0)
+ goto wifi_off_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2);
+ if (probe_index >= 0)
+ goto wifi_off_exist;
+
+ /* MT6628 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1);
+ if (probe_index >= 0)
+ goto wifi_off_exist;
+ /* MT6630 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 1);
+ if (probe_index >= 0) {
+ chip_id = 0x6630;
+ func_num = 1;
+ goto wifi_off_exist;
+ }
+ /* MT6632 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6602, 1);
+ if (probe_index >= 0) {
+ chip_id = 0x6632;
+ func_num = 1;
+ goto wifi_off_exist;
+ }
+
+ /* MT6618 */
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1);
+ if (probe_index >= 0)
+ goto wifi_off_exist;
+ probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2);
+ if (probe_index >= 0)
+ goto wifi_off_exist;
+ else {
+ /* 4 <2> If wifi client drv has not been probed, return error code */
+ /* client func has not been probed */
+ return HIF_SDIO_ERR_NOT_PROBED;
+ }
+
+wifi_off_exist:
+ /* 4 <3> If wifi client drv has been off by wmt, return error code */
+ if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt == MTK_WCN_BOOL_FALSE) {
+ HIF_SDIO_WARN_FUNC("already off...\n");
+ return HIF_SDIO_ERR_ALRDY_OFF;
+ }
+ g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
+
+
+#if 0 /* TODO: [FixMe][George] moved below as done in wifi_on. */
+ /* 4 <4> release irq for this function */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+ sdio_claim_host(func);
+ ret = sdio_release_irq(func);
+ sdio_release_host(func);
+ if (ret)
+ pr_warn(DRV_NAME "sdio_release_irq for wifi fail(%d)\n", ret);
+ else
+ pr_warn(DRV_NAME "sdio_release_irq for wifi ok\n");
+
+#endif
+ clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx;
+ if (clt_index >= 0) { /* the function has been registered */
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+
+ /* 4 <4> Callback to client driver's remove() func */
+ ret =
+ g_hif_sdio_clt_drv_list[clt_index].
+ sdio_cltinfo->hif_clt_remove(CLTCTX
+ (func->device, func->num, func->cur_blksize,
+ probe_index));
+ if (ret)
+ HIF_SDIO_WARN_FUNC("clt_remove for wifi fail(%d)\n", ret);
+ else
+ HIF_SDIO_INFO_FUNC("ok!\n");
+
+ if (unlikely(!(func) || !(func->card) || !(func->card->host)
+ || mmc_card_removed(func->card))) {
+ HIF_SDIO_ERR_FUNC("sdio host is missing\n");
+ return HIF_SDIO_ERR_ALRDY_OFF;
+ }
+ /* 4 <5> release irq for this function */
+ sdio_claim_host(func);
+ mtk_wcn_hif_sdio_irq_flag_set(0);
+ ret2 = sdio_release_irq(func);
+ sdio_release_host(func);
+ g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
+ if (ret2)
+ HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2);
+ else
+ HIF_SDIO_INFO_FUNC("sdio_release_irq() for wifi ok\n");
+
+ /*set deep sleep information to global data struct */
+ func_info = g_hif_sdio_clt_drv_list[clt_index].func_info;
+ hif_sdio_deep_sleep_info_set_act(chip_id, func_num,
+ CLTCTX(func_info->card_id, func_info->func_num,
+ func_info->blk_sz, probe_index), 0);
+
+ return ret + ret2;
+ }
+ /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */
+ HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
+ return HIF_SDIO_ERR_CLT_NOT_REG;
+}
+
+/*!
+ * \brief set mmc power up/off
+ *
+ * detailed descriptions
+ *
+ * \param: 1. ctx client's context variable, 2.power state: 1:power up, other:power off
+ *
+ * \retval 0:success, -1:fail
+ */
+INT32 mtk_wcn_hif_sdio_bus_set_power(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 pwrState)
+{
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+
+ HIF_SDIO_INFO_FUNC("turn Bus Power to: %d\n", pwrState);
+
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ return -1;
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+
+ if (!func) {
+ HIF_SDIO_WARN_FUNC("Cannot find sdio_func !!!\n");
+ return -1;
+ }
+
+ if (pwrState == 1) {
+ sdio_claim_host(func);
+ mmc_power_up_ext(func->card->host);
+ sdio_release_host(func);
+ HIF_SDIO_WARN_FUNC("SDIO BUS Power UP\n");
+ } else {
+ sdio_claim_host(func);
+ mmc_power_off_ext(func->card->host);
+ sdio_release_host(func);
+ HIF_SDIO_WARN_FUNC("SDIO BUS Power OFF\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_bus_set_power);
+
+VOID mtk_wcn_hif_sdio_enable_irq(MTK_WCN_HIF_SDIO_CLTCTX ctx, MTK_WCN_BOOL enable)
+{
+ UINT8 probed_idx = CLTCTX_IDX(ctx);
+
+ if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), sdio_irq no change\n", ctx);
+ return;
+ }
+ if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ return;
+ }
+ /* store client driver's private data to dev driver */
+ g_hif_sdio_probed_func_list[probed_idx].sdio_irq_enabled = enable;
+ smp_wmb();
+ HIF_SDIO_DBG_FUNC("ctx(0x%x) sdio irq enable(%d)\n",
+ ctx, (enable == MTK_WCN_BOOL_FALSE) ? 0 : 1);
+
+
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_enable_irq);
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0 register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_f0_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+ HIF_SDIO_ASSERT(pvb);
+
+/*4 <1> check if ctx is valid, registered, and probed */
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ return -1;
+ }
+ if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+
+/*4 <2>*/
+ sdio_claim_host(func);
+ *pvb = sdio_f0_readb(func, offset, &ret);
+ sdio_release_host(func);
+
+/*4 <3> check result code and return proper error code*/
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_f0_readb() */
+
+
+/*!
+ * \brief
+ *
+ * detailed descriptions
+ *
+ * \param ctx client's context variable
+ *
+ * \retval 0register successfully
+ * \retval < 0 list error code here
+ */
+INT32 mtk_wcn_hif_sdio_f0_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb)
+{
+#if HIF_SDIO_UPDATE
+ INT32 ret;
+ struct sdio_func *func = NULL;
+#else
+ INT32 ret = -HIF_SDIO_ERR_FAIL;
+ INT32 probe_index = -1;
+ struct sdio_func *func = 0;
+#endif
+
+ HIF_SDIO_DBG_FUNC("start!\n");
+
+/*4 <1> check if ctx is valid, registered, and probed*/
+#if HIF_SDIO_UPDATE
+ ret = -HIF_SDIO_ERR_FAIL;
+ func = hif_sdio_ctx_to_func(ctx);
+ if (!func) {
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+#else
+ probe_index = CLTCTX_IDX(ctx);
+ if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */
+ HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
+ goto out;
+ }
+ if (probe_index < 0) { /* the function has not been probed */
+ HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ } else {
+ if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */
+ HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
+ ret = -HIF_SDIO_ERR_FAIL;
+ goto out;
+ }
+ }
+ func = g_hif_sdio_probed_func_list[probe_index].func;
+#endif
+
+/*4 <1.1> check if input parameters are valid*/
+
+/*4 <2>*/
+ wmt_tra_sdio_update();
+ sdio_claim_host(func);
+ sdio_f0_writeb(func, vb, offset, &ret);
+ sdio_release_host(func);
+
+/*4 <3> check result code and return proper error code*/
+
+out:
+ HIF_SDIO_DBG_FUNC("end!\n");
+ return ret;
+} /* end of mtk_wcn_hif_sdio_f0_writeb() */
+
+
+INT32 mtk_wcn_hif_sdio_drv_init(VOID)
+{
+ return hif_sdio_init();
+
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_drv_init);
+
+VOID mtk_wcn_hif_sdio_driver_exit(VOID)
+{
+ return hif_sdio_exit();
+}
+EXPORT_SYMBOL(mtk_wcn_hif_sdio_driver_exit);
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e9db7cbeb9338b33a812af5a850252e567506af
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h
@@ -0,0 +1,73 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see .
+*/
+
+#ifndef __BGW_DESENSE_H_
+#define __BGW_DESENSE_H_
+
+#ifdef MSG
+#undef MSG
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+
+#define PFX1 "[BWG] "
+#define MSG(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__, ##arg)
+#define ERR(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__, ##arg)
+
+#ifdef NETLINK_TEST
+#undef NETLINK_TEST
+#endif
+
+#define NETLINK_TEST 17
+
+#ifdef MAX_NL_MSG_LEN
+#undef MAX_NL_MSG_LEN
+#endif
+
+#define MAX_NL_MSG_LEN 1024
+
+
+#ifdef ON
+#undef ON
+#endif
+#ifdef OFF
+#undef OFF
+#endif
+#ifdef ACK
+#undef ACK
+#endif
+
+#define ON 1
+#define OFF 0
+#define ACK 2
+
+/*
+ * used send command to native process
+ *
+ * parameter: command could be macro ON: enable co-exist; OFF: disable co-exist;
+ * ACK: after get native process init message send ACK
+ */
+extern void send_command_to_daemon(const int command);
+
+/*
+ * before use kernel socket, please call init socket first
+ * return value: 0: ok; -1: fail
+ */
+extern int bgw_init_socket(void);
+
+extern void bgw_destroy_netlink_kernel(void);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h
new file mode 100644
index 0000000000000000000000000000000000000000..7871f467e64d11701eaf93aab57879537bfc1261
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _FW_LOG_WMT_H_
+#define _FW_LOG_WMT_H_
+
+#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH
+int fw_log_wmt_init(void);
+void fw_log_wmt_deinit(void);
+#endif
+
+#endif /*_FW_LOG_WMT_H_*/
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h
new file mode 100644
index 0000000000000000000000000000000000000000..bafbc26fd8b218129ad16c2603a3572a84791b9e
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*!
+ * \file "hif_sdio.h"
+ * \brief
+ */
+
+/*
+ *
+ * 07 25 2010 george.kuo
+ *
+ * Move hif_sdio driver to linux directory.
+ *
+ * 07 23 2010 george.kuo
+ *
+ * Add MT6620 driver source tree
+ * , including char device driver (wmt, bt, gps), stp driver,
+ * interface driver (tty ldisc and hif_sdio), and bt hci driver.
+**
+**
+*/
+
+#ifndef _HIF_SDIO_H
+#define _HIF_SDIO_H
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+#define HIF_SDIO_DEBUG (0) /* 0:turn off debug msg and assert, 1:turn off debug msg and assert */
+#define HIF_SDIO_API_EXTENSION (0)
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "osal_typedef.h"
+#include "osal.h"
+#include "wmt_exp.h"
+
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+#define CFG_CLIENT_COUNT (12)
+
+#define HIF_DEFAULT_BLK_SIZE (256)
+#define HIF_DEFAULT_VENDOR (0x037A)
+
+#define HIF_SDIO_LOG_LOUD 4
+#define HIF_SDIO_LOG_DBG 3
+#define HIF_SDIO_LOG_INFO 2
+#define HIF_SDIO_LOG_WARN 1
+#define HIF_SDIO_LOG_ERR 0
+
+#define CCCR_F8 (0X00F8)
+#define SWPCDBGR (0x0154)
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/* Function info provided by client driver */
+typedef struct _MTK_WCN_HIF_SDIO_FUNCINFO MTK_WCN_HIF_SDIO_FUNCINFO;
+
+/* Client context provided by hif_sdio driver for the following function call */
+typedef UINT32 MTK_WCN_HIF_SDIO_CLTCTX;
+
+/* Callback functions provided by client driver */
+typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX,
+ const MTK_WCN_HIF_SDIO_FUNCINFO *);
+typedef INT32 (*MTK_WCN_HIF_SDIO_REMOVE)(MTK_WCN_HIF_SDIO_CLTCTX);
+typedef INT32 (*MTK_WCN_HIF_SDIO_IRQ)(MTK_WCN_HIF_SDIO_CLTCTX);
+
+/* Function info provided by client driver */
+struct _MTK_WCN_HIF_SDIO_FUNCINFO {
+ UINT16 manf_id; /* TPLMID_MANF: manufacturer ID */
+ UINT16 card_id; /* TPLMID_CARD: card ID */
+ UINT16 func_num; /* Function Number */
+ UINT16 blk_sz; /* Function block size */
+};
+
+/* Client info provided by client driver */
+typedef struct _MTK_WCN_HIF_SDIO_CLTINFO {
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_tbl; /* supported function info table */
+ UINT32 func_tbl_size; /* supported function table info element number */
+ MTK_WCN_HIF_SDIO_PROBE hif_clt_probe; /* callback function for probing */
+ MTK_WCN_HIF_SDIO_REMOVE hif_clt_remove; /* callback function for removing */
+ MTK_WCN_HIF_SDIO_IRQ hif_clt_irq; /* callback function for interrupt handling */
+} MTK_WCN_HIF_SDIO_CLTINFO;
+
+/* function info provided by registed function */
+typedef struct _MTK_WCN_HIF_SDIO_REGISTINFO {
+ const MTK_WCN_HIF_SDIO_CLTINFO *sdio_cltinfo; /* client's MTK_WCN_HIF_SDIO_CLTINFO pointer */
+ const MTK_WCN_HIF_SDIO_FUNCINFO *func_info; /* supported function info pointer */
+} MTK_WCN_HIF_SDIO_REGISTINFO;
+
+/* Card info provided by probed function */
+typedef struct _MTK_WCN_HIF_SDIO_PROBEINFO {
+ struct sdio_func *func; /* probed sdio function pointer */
+ PVOID private_data_p; /* clt's private data pointer */
+ MTK_WCN_BOOL on_by_wmt; /* TRUE: on by wmt, FALSE: not on by wmt */
+ /* added for sdio irq sync and mmc single_irq workaround */
+ MTK_WCN_BOOL sdio_irq_enabled; /* TRUE: can handle sdio irq; FALSE: no sdio irq handling */
+ INT32 clt_idx; /* registered function table info element number (initial value is -1) */
+} MTK_WCN_HIF_SDIO_PROBEINFO;
+
+/* work queue info needed by worker */
+typedef struct _MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO {
+ struct work_struct probe_work; /* work queue structure */
+ MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p; /* MTK_WCN_HIF_SDIO_REGISTINFO pointer of the client */
+ INT8 probe_idx; /* probed function table info element number (initial value is -1) */
+} MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO;
+
+/* global resource locks info of hif_sdio drv */
+typedef struct _MTK_WCN_HIF_SDIO_LOCKINFO {
+ spinlock_t probed_list_lock; /* spin lock for probed list */
+ spinlock_t clt_list_lock; /* spin lock for client registed list */
+} MTK_WCN_HIF_SDIO_LOCKINFO;
+
+/* SDIO Deep Sleep Information by chip, maintained by HIF-SDIO itself */
+typedef struct _MTK_WCN_HIF_SDIO_DS_CLT_INFO {
+ MTK_WCN_HIF_SDIO_CLTCTX ctx;
+ UINT16 func_num;
+ UINT8 act_flag;
+ UINT8 ds_en_flag;
+} MTK_WCN_HIF_SDIO_DS_CLT_INFO;
+
+typedef struct _MTK_WCN_HIF_SDIO_DS_INFO {
+ UINT32 chip_id; /*chipid */
+ UINT32 reg_offset; /*offset in CCCR of control register of deep sleep */
+ UINT8 value; /*value to set to CCCR reg_offset, when enable deep sleep */
+ MTK_WCN_HIF_SDIO_DS_CLT_INFO clt_info[2]; /*currently, only BGF and WIFI function need this function */
+ struct mutex lock;
+} MTK_WCN_HIF_SDIO_DS_INFO;
+
+
+/* error code returned by hif_sdio driver (use NEGATIVE number) */
+typedef enum {
+ HIF_SDIO_ERR_SUCCESS = 0,
+ HIF_SDIO_ERR_FAIL = HIF_SDIO_ERR_SUCCESS - 1, /* generic error */
+ HIF_SDIO_ERR_INVALID_PARAM = HIF_SDIO_ERR_FAIL - 1,
+ HIF_SDIO_ERR_DUPLICATED = HIF_SDIO_ERR_INVALID_PARAM - 1,
+ HIF_SDIO_ERR_UNSUP_MANF_ID = HIF_SDIO_ERR_DUPLICATED - 1,
+ HIF_SDIO_ERR_UNSUP_CARD_ID = HIF_SDIO_ERR_UNSUP_MANF_ID - 1,
+ HIF_SDIO_ERR_INVALID_FUNC_NUM = HIF_SDIO_ERR_UNSUP_CARD_ID - 1,
+ HIF_SDIO_ERR_INVALID_BLK_SZ = HIF_SDIO_ERR_INVALID_FUNC_NUM - 1,
+ HIF_SDIO_ERR_NOT_PROBED = HIF_SDIO_ERR_INVALID_BLK_SZ - 1,
+ HIF_SDIO_ERR_ALRDY_ON = HIF_SDIO_ERR_NOT_PROBED - 1,
+ HIF_SDIO_ERR_ALRDY_OFF = HIF_SDIO_ERR_ALRDY_ON - 1,
+ HIF_SDIO_ERR_CLT_NOT_REG = HIF_SDIO_ERR_ALRDY_OFF - 1,
+} MTK_WCN_HIF_SDIO_ERR;
+
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+/*!
+ * \brief A macro used to generate hif_sdio client's context
+ *
+ * Generate a context for hif_sdio client based on the following input parameters
+ * |<-card id (16bits)->|<-block size in unit of 256 bytes(8 bits)->|<-function number(4bits)->|<-index(4bits)->|
+ *
+ * \param manf the 16 bit manufacturer id
+ * \param card the 16 bit card id
+ * \param func the 16 bit function number
+ * \param b_sz the 16 bit function block size
+ */
+#define CLTCTX(cid, func, blk_sz, idx) \
+(MTK_WCN_HIF_SDIO_CLTCTX)((((UINT32)(cid) & 0xFFFFUL) << 16) | \
+ (((UINT32)(func) & 0xFUL) << 4) | \
+ (((UINT32)(blk_sz) & 0xFF00UL) << 0) | \
+ (((UINT32)idx & 0xFUL) << 0))
+
+/*!
+ * \brief A set of macros used to get information out of an hif_sdio client context
+ *
+ * Generate a context for hif_sdio client based on the following input parameters
+ */
+#define CLTCTX_CID(ctx) (((ctx) >> 16) & 0xFFFF)
+#define CLTCTX_FUNC(ctx) (((ctx) >> 4) & 0xF)
+#define CLTCTX_BLK_SZ(ctx) (((ctx) >> 0) & 0xFF00)
+#define CLTCTX_IDX(ctx) ((ctx) & 0xF)
+#define CLTCTX_IDX_VALID(idx) ((idx >= 0) && (idx < CFG_CLIENT_COUNT))
+#define CLTCTX_UIDX_VALID(idx) (idx < CFG_CLIENT_COUNT)
+
+
+/*!
+ * \brief A macro used to describe an SDIO function
+ *
+ * Fill an MTK_WCN_HIF_SDIO_FUNCINFO structure with function-specific information
+ *
+ * \param manf the 16 bit manufacturer id
+ * \param card the 16 bit card id
+ * \param func the 16 bit function number
+ * \param b_sz the 16 bit function block size
+ */
+#define MTK_WCN_HIF_SDIO_FUNC(manf, card, func, b_sz) \
+ .manf_id = (manf), .card_id = (card), .func_num = (func), .blk_sz = (b_sz)
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+
+#ifndef DFT_TAG
+#define DFT_TAG "[HIF-SDIO]"
+#endif
+
+extern INT32 gHifSdioDbgLvl;
+
+
+#define HIF_SDIO_LOUD_FUNC(fmt, arg...) \
+do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_LOUD) \
+ osal_warn_print(DFT_TAG"[L]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define HIF_SDIO_DBG_FUNC(fmt, arg...) \
+do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_DBG) \
+ osal_warn_print(DFT_TAG"[D]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define HIF_SDIO_INFO_FUNC(fmt, arg...) \
+do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_INFO) \
+ osal_warn_print(DFT_TAG"[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+#define HIF_SDIO_WARN_FUNC(fmt, arg...) \
+do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_WARN) \
+ osal_warn_print(DFT_TAG"[W]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+#define HIF_SDIO_ERR_FUNC(fmt, arg...) \
+do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_ERR) \
+ osal_err_print(DFT_TAG"[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+/*!
+ * \brief ASSERT function definition.
+ *
+ */
+#if HIF_SDIO_DEBUG
+#define HIF_SDIO_ASSERT(expr) \
+{ \
+ if (!(expr)) { \
+ osal_warn_print("assertion failed! %s[%d]: %s\n",\
+ __func__, __LINE__, #expr); \
+ osal_bug_on(!(expr));\
+ } \
+}
+#else
+#define HIF_SDIO_ASSERT(expr) do {} while (0)
+#endif
+
+/* define function 0 CR */
+#define CCCR_06 (0x06)
+#define CCCR_F0 (0xF0)
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+/*!
+ * \brief MTK hif sdio client registration function
+ *
+ * Client uses this function to do hif sdio registration
+ *
+ * \param pinfo a pointer of client's information
+ *
+ * \retval 0 register successfully
+ * \retval < 0 error code
+ */
+extern INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo);
+
+extern INT32 mtk_wcn_hif_sdio_client_unreg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo);
+
+extern INT32 mtk_wcn_hif_sdio_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb);
+
+extern INT32 mtk_wcn_hif_sdio_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb);
+
+extern INT32 mtk_wcn_hif_sdio_readl(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT32 pvl);
+
+extern INT32 mtk_wcn_hif_sdio_writel(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT32 vl);
+
+extern INT32 mtk_wcn_hif_sdio_read_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx,
+ UINT32 offset, PUINT32 pbuf, UINT32 len);
+
+extern INT32 mtk_wcn_hif_sdio_write_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx,
+ UINT32 offset, PUINT32 pbuf, UINT32 len);
+
+extern INT32 mtk_wcn_hif_sdio_abort(MTK_WCN_HIF_SDIO_CLTCTX ctx);
+
+INT32 hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx);
+
+extern VOID mtk_wcn_hif_sdio_set_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx, PVOID private_data_p);
+
+extern PVOID mtk_wcn_hif_sdio_get_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx);
+
+extern INT32 mtk_wcn_hif_sdio_wmt_control(WMT_SDIO_FUNC_TYPE func_type, MTK_WCN_BOOL is_on);
+
+extern INT32 mtk_wcn_hif_sdio_bus_set_power(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 pwrState);
+
+extern VOID mtk_wcn_hif_sdio_get_dev(MTK_WCN_HIF_SDIO_CLTCTX ctx, struct device **dev);
+
+extern INT32 mtk_wcn_hif_sdio_update_cb_reg(INT32(*ts_update)(VOID));
+
+extern VOID mtk_wcn_hif_sdio_enable_irq(MTK_WCN_HIF_SDIO_CLTCTX ctx, MTK_WCN_BOOL enable);
+
+extern INT32 mtk_wcn_hif_sdio_f0_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb);
+
+extern INT32 mtk_wcn_hif_sdio_f0_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 mtk_wcn_hif_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag);
+#endif
+
+#define DELETE_HIF_SDIO_CHRDEV 1
+#if !(DELETE_HIF_SDIO_CHRDEV)
+INT32 mtk_wcn_hif_sdio_tell_chipid(INT32 chipId);
+INT32 mtk_wcn_hif_sdio_query_chipid(INT32 waitFlag);
+#endif
+
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* E X T E R N A L 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
+********************************************************************************
+*/
+#endif /* _HIF_SDIO_H */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal.h
new file mode 100644
index 0000000000000000000000000000000000000000..c006d2f5cbaec5044076eecb05fbedd6eadce98e
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+
+/*! \file
+ * \brief Declaration of library functions
+ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+ */
+
+#ifndef _OSAL_H_
+#define _OSAL_H_
+
+#include "osal_typedef.h"
+#include "../../debug_utility/ring.h"
+#include
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+#define OS_BIT_OPS_SUPPORT 1
+
+#define _osal_inline_ inline
+
+#define MAX_THREAD_NAME_LEN 16
+#define MAX_WAKE_LOCK_NAME_LEN 16
+#define MAX_HISTORY_NAME_LEN 16
+#define OSAL_OP_BUF_SIZE 64
+
+
+#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD))
+#define OSAL_OP_DATA_SIZE 8
+#else
+#define OSAL_OP_DATA_SIZE 32
+#endif
+
+#define DBG_LOG_STR_SIZE 256
+
+#define osal_sizeof(x) sizeof(x)
+
+#define osal_array_size(x) ARRAY_SIZE(x)
+
+#ifndef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+#define WMT_OP_BIT(x) (0x1UL << x)
+#define WMT_OP_HIF_BIT WMT_OP_BIT(0)
+
+#define GET_BIT_MASK(value, mask) ((value) & (mask))
+#define SET_BIT_MASK(pdest, value, mask) (*(pdest) = (GET_BIT_MASK(*(pdest), ~(mask)) | GET_BIT_MASK(value, mask)))
+#define GET_BIT_RANGE(data, end, begin) ((data) & GENMASK(end, begin))
+#define SET_BIT_RANGE(pdest, data, end, begin) (SET_BIT_MASK(pdest, data, GENMASK(end, begin)))
+
+#define RB_LATEST(prb) ((prb)->write - 1)
+#define RB_SIZE(prb) ((prb)->size)
+#define RB_MASK(prb) (RB_SIZE(prb) - 1)
+#define RB_COUNT(prb) ((prb)->write - (prb)->read)
+#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb))
+#define RB_EMPTY(prb) ((prb)->write == (prb)->read)
+
+#define RB_INIT(prb, qsize) \
+do { \
+ (prb)->read = (prb)->write = 0; \
+ (prb)->size = (qsize); \
+} while (0)
+
+#define RB_PUT(prb, value) \
+do { \
+ if (!RB_FULL(prb)) { \
+ (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \
+ ++((prb)->write); \
+ } \
+ else { \
+ osal_assert(!RB_FULL(prb)); \
+ } \
+} while (0)
+
+#define RB_GET(prb, value) \
+do { \
+ if (!RB_EMPTY(prb)) { \
+ value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \
+ ++((prb)->read); \
+ if (RB_EMPTY(prb)) { \
+ (prb)->read = (prb)->write = 0; \
+ } \
+ } \
+ else { \
+ value = NULL; \
+ osal_assert(!RB_EMPTY(prb)); \
+ } \
+} while (0)
+
+#define RB_GET_LATEST(prb, value) \
+do { \
+ if (!RB_EMPTY(prb)) { \
+ value = (prb)->queue[RB_LATEST(prb) & RB_MASK(prb)]; \
+ if (RB_EMPTY(prb)) { \
+ (prb)->read = (prb)->write = 0; \
+ } \
+ } \
+ else { \
+ value = NULL; \
+ } \
+} while (0)
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+typedef VOID(*P_TIMEOUT_HANDLER) (struct timer_list *t);
+typedef struct timer_list *timer_handler_arg;
+#define GET_HANDLER_DATA(arg, data) \
+do { \
+ P_OSAL_TIMER osal_timer = from_timer(osal_timer, arg, timer); \
+ data = osal_timer->timeroutHandlerData; \
+} while (0)
+#else
+typedef VOID(*P_TIMEOUT_HANDLER) (ULONG);
+typedef ULONG timer_handler_arg;
+#define GET_HANDLER_DATA(arg, data) (data = arg)
+#endif
+
+typedef INT32(*P_COND) (PVOID);
+
+typedef struct _OSAL_TIMER_ {
+ struct timer_list timer;
+ P_TIMEOUT_HANDLER timeoutHandler;
+ ULONG timeroutHandlerData;
+} OSAL_TIMER, *P_OSAL_TIMER;
+
+typedef struct _OSAL_UNSLEEPABLE_LOCK_ {
+ spinlock_t lock;
+ ULONG flag;
+} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK;
+
+typedef struct _OSAL_SLEEPABLE_LOCK_ {
+ struct mutex lock;
+} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK;
+
+typedef struct _OSAL_SIGNAL_ {
+ struct completion comp;
+ UINT32 timeoutValue;
+ UINT32 timeoutExtension; /* max number of timeout caused by thread not able to acquire CPU */
+} OSAL_SIGNAL, *P_OSAL_SIGNAL;
+
+typedef struct _OSAL_EVENT_ {
+ wait_queue_head_t waitQueue;
+/* VOID *pWaitQueueData; */
+ UINT32 timeoutValue;
+ INT32 waitFlag;
+
+} OSAL_EVENT, *P_OSAL_EVENT;
+
+/* Data collected from sched_entity and sched_statistics */
+typedef struct _OSAL_THREAD_SCHEDSTATS_ {
+ UINT64 time; /* when marked: the profiling start time(ms), when unmarked: total duration(ms) */
+ UINT64 exec; /* time spent in exec (sum_exec_runtime) */
+ UINT64 runnable; /* time spent in run-queue while not being scheduled (wait_sum) */
+ UINT64 iowait; /* time spent waiting for I/O (iowait_sum) */
+} OSAL_THREAD_SCHEDSTATS, *P_OSAL_THREAD_SCHEDSTATS;
+
+typedef struct _OSAL_THREAD_ {
+ struct task_struct *pThread;
+ PVOID pThreadFunc;
+ PVOID pThreadData;
+ INT8 threadName[MAX_THREAD_NAME_LEN];
+} OSAL_THREAD, *P_OSAL_THREAD;
+
+
+typedef struct _OSAL_FIFO_ {
+ /*fifo definition */
+ PVOID pFifoBody;
+ spinlock_t fifoSpinlock;
+ /*fifo operations */
+ INT32 (*FifoInit)(struct _OSAL_FIFO_ *pFifo, PUINT8 buf, UINT32);
+ INT32 (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoReset)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoSz)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoLen)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo);
+ INT32 (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const PVOID buf, UINT32 len);
+ INT32 (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, PVOID buf, UINT32 len);
+} OSAL_FIFO, *P_OSAL_FIFO;
+
+typedef struct firmware osal_firmware;
+
+typedef struct _OSAL_OP_DAT {
+ UINT32 opId; /* Event ID */
+ UINT32 u4InfoBit; /* Reserved */
+ SIZE_T au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */
+} OSAL_OP_DAT, *P_OSAL_OP_DAT;
+
+typedef struct _OSAL_LXOP_ {
+ OSAL_OP_DAT op;
+ OSAL_SIGNAL signal;
+ INT32 result;
+ atomic_t ref_count;
+} OSAL_OP, *P_OSAL_OP;
+
+typedef struct _OSAL_LXOP_Q {
+ OSAL_SLEEPABLE_LOCK sLock;
+ UINT32 write;
+ UINT32 read;
+ UINT32 size;
+ P_OSAL_OP queue[OSAL_OP_BUF_SIZE];
+} OSAL_OP_Q, *P_OSAL_OP_Q;
+
+typedef struct _OSAL_WAKE_LOCK_ {
+ struct wakeup_source *wake_lock;
+ UINT8 name[MAX_WAKE_LOCK_NAME_LEN];
+ INT32 init_flag;
+} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK;
+#if 1
+typedef struct _OSAL_BIT_OP_VAR_ {
+ ULONG data;
+ OSAL_UNSLEEPABLE_LOCK opLock;
+} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR;
+#else
+#define OSAL_BIT_OP_VAR unsigned long
+#define P_OSAL_BIT_OP_VAR unsigned long *
+
+#endif
+typedef UINT32(*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread);
+
+struct osal_op_history_entry {
+ VOID *opbuf_address;
+ UINT32 op_id;
+ UINT32 opbuf_ref_count;
+ UINT32 op_info_bit;
+ SIZE_T param_0;
+ SIZE_T param_1;
+ SIZE_T param_2;
+ SIZE_T param_3;
+ UINT64 ts;
+ ULONG usec;
+};
+
+struct osal_op_history {
+ struct ring ring_buffer;
+ struct osal_op_history_entry *queue;
+ spinlock_t lock;
+ struct ring dump_ring_buffer;
+ struct work_struct dump_work;
+ UINT8 name[MAX_HISTORY_NAME_LEN];
+};
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+UINT32 osal_strlen(const PINT8 str);
+INT32 osal_strcmp(const PINT8 dst, const PINT8 src);
+INT32 osal_strncmp(const PINT8 dst, const PINT8 src, UINT32 len);
+PINT8 osal_strcpy(PINT8 dst, const PINT8 src);
+PINT8 osal_strncpy(PINT8 dst, const PINT8 src, UINT32 len);
+PINT8 osal_strcat(PINT8 dst, const PINT8 src);
+PINT8 osal_strncat(PINT8 dst, const PINT8 src, UINT32 len);
+PINT8 osal_strchr(const PINT8 str, UINT8 c);
+PINT8 osal_strsep(PPINT8 str, const PINT8 c);
+INT32 osal_strtol(const PINT8 str, UINT32 adecimal, PLONG res);
+PINT8 osal_strstr(PINT8 str1, const PINT8 str2);
+PINT8 osal_strnstr(PINT8 str1, const PINT8 str2, INT32 n);
+
+VOID osal_bug_on(UINT32 val);
+
+INT32 osal_snprintf(PINT8 buf, UINT32 len, const PINT8 fmt, ...);
+INT32 osal_err_print(const PINT8 str, ...);
+INT32 osal_dbg_print(const PINT8 str, ...);
+INT32 osal_warn_print(const PINT8 str, ...);
+
+INT32 osal_dbg_assert(INT32 expr, const PINT8 file, INT32 line);
+INT32 osal_dbg_assert_aee(const PINT8 module, const PINT8 detail_description, ...);
+INT32 osal_sprintf(PINT8 str, const PINT8 format, ...);
+PVOID osal_malloc(UINT32 size);
+VOID osal_free(const PVOID dst);
+PVOID osal_memset(PVOID buf, INT32 i, UINT32 len);
+PVOID osal_memcpy(PVOID dst, const PVOID src, UINT32 len);
+VOID osal_memcpy_fromio(PVOID dst, const PVOID src, UINT32 len);
+VOID osal_memcpy_toio(PVOID dst, const PVOID src, UINT32 len);
+INT32 osal_memcmp(const PVOID buf1, const PVOID buf2, UINT32 len);
+
+UINT16 osal_crc16(const PUINT8 buffer, const UINT32 length);
+VOID osal_thread_show_stack(P_OSAL_THREAD pThread);
+
+INT32 osal_sleep_ms(UINT32 ms);
+INT32 osal_udelay(UINT32 us);
+INT32 osal_usleep_range(ULONG min, ULONG max);
+INT32 osal_timer_create(P_OSAL_TIMER);
+INT32 osal_timer_start(P_OSAL_TIMER, UINT32);
+INT32 osal_timer_stop(P_OSAL_TIMER);
+INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer);
+INT32 osal_timer_modify(P_OSAL_TIMER, UINT32);
+INT32 osal_timer_delete(P_OSAL_TIMER);
+
+INT32 osal_fifo_init(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size);
+VOID osal_fifo_deinit(P_OSAL_FIFO pFifo);
+INT32 osal_fifo_reset(P_OSAL_FIFO pFifo);
+UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size);
+UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size);
+UINT32 osal_fifo_len(P_OSAL_FIFO pFifo);
+UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo);
+UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo);
+UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo);
+UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo);
+
+INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK plock);
+INT32 osal_wake_lock(P_OSAL_WAKE_LOCK plock);
+INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK plock);
+INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK plock);
+INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock);
+
+#if defined(CONFIG_PROVE_LOCKING)
+#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); }
+#else
+INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK);
+#endif
+INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK);
+INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK);
+INT32 osal_trylock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK);
+INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK);
+
+#if defined(CONFIG_PROVE_LOCKING)
+#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); }
+#else
+INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK);
+#endif
+INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK);
+INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK);
+INT32 osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK);
+INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK);
+
+INT32 osal_signal_init(P_OSAL_SIGNAL);
+INT32 osal_wait_for_signal(P_OSAL_SIGNAL);
+INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL, P_OSAL_THREAD);
+INT32 osal_raise_signal(P_OSAL_SIGNAL);
+INT32 osal_signal_active_state(P_OSAL_SIGNAL pSignal);
+INT32 osal_signal_deinit(P_OSAL_SIGNAL);
+
+INT32 osal_event_init(P_OSAL_EVENT);
+INT32 osal_wait_for_event(P_OSAL_EVENT, P_COND, PVOID);
+INT32 osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, PVOID);
+extern INT32 osal_trigger_event(P_OSAL_EVENT);
+
+INT32 osal_event_deinit(P_OSAL_EVENT);
+LONG osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset);
+LONG osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset);
+
+INT32 osal_thread_create(P_OSAL_THREAD);
+INT32 osal_thread_run(P_OSAL_THREAD);
+INT32 osal_thread_should_stop(P_OSAL_THREAD);
+INT32 osal_thread_stop(P_OSAL_THREAD);
+/*INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/
+INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER);
+/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/
+INT32 osal_thread_destroy(P_OSAL_THREAD);
+INT32 osal_thread_sched_mark(P_OSAL_THREAD, P_OSAL_THREAD_SCHEDSTATS schedstats);
+INT32 osal_thread_sched_unmark(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS schedstats);
+
+INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData);
+INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData);
+INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData);
+INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData);
+INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData);
+
+INT32 osal_gettimeofday(PINT32 sec, PINT32 usec);
+void osal_do_gettimeofday(struct timeval *tv);
+INT32 osal_printtimeofday(const PUINT8 prefix);
+VOID osal_get_local_time(PUINT64 sec, PULONG nsec);
+UINT64 osal_elapsed_us(UINT64 ts, ULONG usec);
+
+VOID osal_buffer_dump(const PUINT8 buf, const PUINT8 title, UINT32 len, UINT32 limit);
+VOID osal_buffer_dump_data(const PUINT32 buf, const PUINT8 title, const UINT32 len, const UINT32 limit,
+ const INT32 flag);
+
+UINT32 osal_op_get_id(P_OSAL_OP pOp);
+MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp);
+VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result);
+VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result);
+VOID osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ);
+VOID osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ);
+MTK_WCN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp);
+
+INT32 osal_ftrace_print(const PINT8 str, ...);
+INT32 osal_ftrace_print_ctrl(INT32 flag);
+
+VOID osal_dump_thread_state(const PUINT8 name);
+VOID osal_op_history_init(struct osal_op_history *log_history, INT32 queue_size);
+VOID osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp);
+VOID osal_op_history_print(struct osal_op_history *log_history, PINT8 name);
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+
+#define osal_assert(condition) \
+do { \
+ if (!(condition)) \
+ osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition); \
+} while (0)
+
+#endif /* _OSAL_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal_typedef.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal_typedef.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca48a7b7bac512d99dffea3cd7d56cca9dbecdac
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/osal_typedef.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+ * \brief Declaration of library functions
+ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+ */
+
+#ifndef _OSAL_TYPEDEF_H_
+#define _OSAL_TYPEDEF_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if defined(WMT_PLAT_ALPS) && WMT_PLAT_ALPS
+#if IS_ENABLED(CONFIG_MTK_AEE_AED)
+#include
+#endif
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _TYPEDEFS_H /*fix redifine */
+typedef signed char INT8;
+#endif
+
+typedef void VOID, *PVOID, **PPVOID;
+typedef char *PINT8, **PPINT8;
+typedef short INT16, *PINT16, **PPINT16;
+typedef int INT32, *PINT32, **PPINT32;
+typedef long LONG, *PLONG, **PPLONG;
+typedef long long INT64, *PINT64, **PPINT64;
+
+typedef unsigned char UINT8, *PUINT8, **PPUINT8;
+typedef unsigned short UINT16, *PUINT16, **PPUINT16;
+typedef unsigned int UINT32, *PUINT32, **PPUINT32;
+typedef unsigned long ULONG, *PULONG, **PPULONG;
+typedef unsigned long long UINT64, *PUINT64, **PPUINT64;
+
+typedef size_t SIZE_T;
+
+typedef int MTK_WCN_BOOL;
+#ifndef MTK_WCN_BOOL_TRUE
+#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0)
+#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1)
+#endif
+
+#endif /*_OSAL_TYPEDEF_H_*/
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h
new file mode 100644
index 0000000000000000000000000000000000000000..68f6d2ae5f9ab542aa6b0ee34898f77e5e1d563f
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _STP_BTIF_H_
+#define _STP_BTIF_H_
+
+#include "osal_typedef.h"
+#include "mtk_btif_exp.h"
+#include "osal.h"
+
+struct stp_btif {
+ ULONG stpBtifId;
+ OSAL_THREAD btif_thread;
+};
+
+INT32 mtk_wcn_consys_stp_btif_open(VOID);
+INT32 mtk_wcn_consys_stp_btif_close(VOID);
+INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb);
+INT32 mtk_wcn_consys_stp_btif_tx(const PUINT8 pBuf, const UINT32 len, PUINT32 written_len);
+INT32 mtk_wcn_consys_stp_btif_wakeup(VOID);
+INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(UINT32 en_flag);
+INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode);
+INT32 mtk_wcn_consys_stp_btif_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag);
+INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const PUINT8 str, UINT32 len);
+INT32 mtk_wcn_consys_stp_btif_rx_has_pending_data(VOID);
+INT32 mtk_wcn_consys_stp_btif_tx_has_pending_data(VOID);
+P_OSAL_THREAD mtk_wcn_consys_stp_btif_rx_thread_get(VOID);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..9915eab428536425780004eef9c274616e856454
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _STP_DEBUG_H_
+#define _STP_DEBUG_H_
+
+#include
+#include "stp_btif.h"
+#include "osal.h"
+#include "wmt_exp.h"
+
+#define CONFIG_LOG_STP_INTERNAL
+
+#ifndef LOG_STP_DEBUG_DISABLE /* #ifndef CONFIG_LOG_STP_INTERNAL */
+#define STP_PKT_SZ 16
+#define STP_DMP_SZ 2048
+#define STP_PKT_NO 2048
+
+#define STP_DBG_LOG_ENTRY_NUM 1024
+#define STP_DBG_LOG_ENTRY_SZ 96
+
+#else
+
+#define STP_PKT_SZ 16
+#define STP_DMP_SZ 16
+#define STP_PKT_NO 16
+
+#define STP_DBG_LOG_ENTRY_NUM 28
+#define STP_DBG_LOG_ENTRY_SZ 96
+
+#endif
+#define EMICOREDUMP_CMD "emicoredump"
+#define FAKECOREDUMPEND "coredump end - fake"
+
+#define MAX_DUMP_HEAD_LEN 512
+/* netlink header packet length is 5 "[M](3 bytes) + length(2 bypes)" */
+#define NL_PKT_HEADER_LEN 5
+
+#define PFX_STP_DBG "[STPDbg]"
+#define STP_DBG_LOG_LOUD 4
+#define STP_DBG_LOG_DBG 3
+#define STP_DBG_LOG_INFO 2
+#define STP_DBG_LOG_WARN 1
+#define STP_DBG_LOG_ERR 0
+
+extern INT32 gStpDbgDbgLevel;
+
+#define STP_DBG_PR_LOUD(fmt, arg...) \
+do { \
+ if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \
+ pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_DBG_PR_DBG(fmt, arg...) \
+do { \
+ if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \
+ pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_DBG_PR_INFO(fmt, arg...) \
+do { \
+ if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \
+ pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_DBG_PR_WARN(fmt, arg...) \
+do { \
+ if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \
+ pr_warn(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \
+} while (0)
+#define STP_DBG_PR_ERR(fmt, arg...) \
+do { \
+ if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \
+ pr_err(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \
+} while (0)
+
+typedef enum {
+ STP_DBG_EN = 0,
+ STP_DBG_PKT = 1,
+ STP_DBG_DR = 2,
+ STP_DBG_FW_ASSERT = 3,
+ STP_DBG_FW_LOG = 4,
+ STP_DBG_FW_DMP = 5,
+ STP_DBG_MAX
+} STP_DBG_OP_T;
+
+typedef enum {
+ STP_DBG_PKT_FIL_ALL = 0,
+ STP_DBG_PKT_FIL_BT = 1,
+ STP_DBG_PKT_FIL_GPS = 2,
+ STP_DBG_PKT_FIL_FM = 3,
+ STP_DBG_PKT_FIL_WMT = 4,
+ STP_DBG_PKT_FIL_MAX
+} STP_DBG_PKT_FIL_T;
+
+static PINT8 const comboStpDbgType[] = {
+ "< BT>",
+ "< FM>",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+};
+
+static PINT8 const socStpDbgType[] = {
+ "< BT>",
+ "< FM>",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+};
+
+enum STP_DBG_TAKS_ID_T {
+ STP_DBG_TASK_WMT = 0,
+ STP_DBG_TASK_BT,
+ STP_DBG_TASK_WIFI,
+ STP_DBG_TASK_TST,
+ STP_DBG_TASK_FM,
+ STP_DBG_TASK_GPS,
+ STP_DBG_TASK_FLP,
+ STP_DBG_TASK_BT2,
+ STP_DBG_TASK_IDLE,
+ STP_DBG_TASK_DRVSTP,
+ STP_DBG_TASK_BUS,
+ STP_DBG_TASK_NATBT,
+ STP_DBG_TASK_DRVWIFI,
+ STP_DBG_TASK_DRVGPS,
+ STP_DBG_TASK_ID_MAX,
+};
+
+typedef enum {
+ STP_DBG_DR_MAX = 0,
+} STP_DBG_DR_FIL_T;
+
+typedef enum {
+ STP_DBG_FW_MAX = 0,
+} STP_DBG_FW_FIL_T;
+
+typedef enum {
+ PKT_DIR_RX = 0,
+ PKT_DIR_TX
+} STP_DBG_PKT_DIR_T;
+
+/*simple log system ++*/
+
+typedef struct {
+ /*type: 0. pkt trace 1. fw info
+ * 2. assert info 3. trace32 dump .
+ * -1. linked to the the previous
+ */
+ INT32 id;
+ INT32 len;
+ INT8 buffer[STP_DBG_LOG_ENTRY_SZ];
+} MTKSTP_LOG_ENTRY_T;
+
+typedef struct log_sys {
+ MTKSTP_LOG_ENTRY_T queue[STP_DBG_LOG_ENTRY_NUM];
+ UINT32 size;
+ UINT32 in;
+ UINT32 out;
+ spinlock_t lock;
+ MTKSTP_LOG_ENTRY_T *dump_queue;
+ UINT32 dump_size;
+ struct work_struct dump_work;
+} MTKSTP_LOG_SYS_T;
+/*--*/
+
+typedef struct stp_dbg_pkt_hdr {
+ /* packet information */
+ UINT32 sec;
+ UINT32 usec;
+ UINT32 dbg_type;
+ UINT32 last_dbg_type;
+ UINT32 dmy;
+ UINT32 no;
+ UINT32 dir;
+
+ /* packet content */
+ UINT32 type;
+ UINT32 len;
+ UINT32 ack;
+ UINT32 seq;
+ UINT32 chs;
+ UINT32 crc;
+ UINT64 l_sec;
+ ULONG l_nsec;
+} STP_DBG_HDR_T;
+
+typedef struct stp_dbg_pkt {
+ struct stp_dbg_pkt_hdr hdr;
+ UINT8 raw[STP_DMP_SZ];
+} STP_PACKET_T;
+
+typedef struct mtkstp_dbg_t {
+ /*log_sys */
+ INT32 pkt_trace_no;
+ PVOID btm;
+ INT32 is_enable;
+ MTKSTP_LOG_SYS_T *logsys;
+} MTKSTP_DBG_T;
+
+/* extern void aed_combo_exception(const int *, int, const int *, int, const char *); */
+#if WMT_DBG_SUPPORT
+#define STP_CORE_DUMP_TIMEOUT (1*60*1000) /* default 1 minutes */
+#else
+#define STP_CORE_DUMP_TIMEOUT (10*1000) /* user load default 10 seconds */
+#endif
+#if WMT_DBG_SUPPORT
+#define STP_EMI_DUMP_TIMEOUT (30*1000)
+#else
+#define STP_EMI_DUMP_TIMEOUT (5*1000)
+#endif
+#define STP_OJB_NAME_SZ 20
+#define STP_CORE_DUMP_INFO_SZ 500
+#define STP_CORE_DUMP_INIT_SIZE 512
+typedef enum wcn_compress_algorithm_t {
+ GZIP = 0,
+ BZIP2 = 1,
+ RAR = 2,
+ LMA = 3,
+ MAX
+} WCN_COMPRESS_ALG_T;
+
+typedef INT32 (*COMPRESS_HANDLER) (PVOID worker, UINT8 *in_buf, INT32 in_sz, PUINT8 out_buf, PINT32 out_sz,
+ INT32 finish);
+typedef struct wcn_compressor_t {
+ /* current object name */
+ UINT8 name[STP_OJB_NAME_SZ + 1];
+
+ /* buffer for raw data, named L1 */
+ PUINT8 L1_buf;
+ INT32 L1_buf_sz;
+ INT32 L1_pos;
+
+ /* target buffer, named L2 */
+ PUINT8 L2_buf;
+ INT32 L2_buf_sz;
+ INT32 L2_pos;
+
+ /* compress state */
+ UINT8 f_done;
+ UINT16 reserved;
+ UINT32 uncomp_size;
+ UINT32 crc32;
+
+ /* compress algorithm */
+ UINT8 f_compress_en;
+ WCN_COMPRESS_ALG_T compress_type;
+ PVOID worker;
+ COMPRESS_HANDLER handler;
+} WCN_COMPRESSOR_T, *P_WCN_COMPRESSOR_T;
+
+typedef enum core_dump_state_t {
+ CORE_DUMP_INIT = 0,
+ CORE_DUMP_DOING,
+ CORE_DUMP_TIMEOUT,
+ CORE_DUMP_DONE,
+ CORE_DUMP_MAX
+} CORE_DUMP_STA;
+
+typedef struct core_dump_t {
+ /* compress dump data and buffered */
+ P_WCN_COMPRESSOR_T compressor;
+
+ /* timer for monitor timeout */
+ OSAL_TIMER dmp_timer;
+ UINT32 timeout;
+ LONG dmp_num;
+ UINT32 count;
+ OSAL_SLEEPABLE_LOCK dmp_lock;
+
+ /* timer for monitor emi dump */
+ OSAL_TIMER dmp_emi_timer;
+ UINT32 emi_timeout;
+
+ /* state machine for core dump flow */
+ CORE_DUMP_STA sm;
+
+ /* dump info */
+ INT8 info[STP_CORE_DUMP_INFO_SZ + 1];
+
+ PUINT8 p_head;
+ UINT32 head_len;
+} WCN_CORE_DUMP_T, *P_WCN_CORE_DUMP_T;
+
+typedef enum _ENUM_STP_FW_ISSUE_TYPE_ {
+ STP_FW_ISSUE_TYPE_INVALID = 0x0,
+ STP_FW_ASSERT_ISSUE = 0x1,
+ STP_FW_NOACK_ISSUE = 0x2,
+ STP_FW_WARM_RST_ISSUE = 0x3,
+ STP_DBG_PROC_TEST = 0x4,
+ STP_HOST_TRIGGER_FW_ASSERT = 0x5,
+ STP_HOST_TRIGGER_ASSERT_TIMEOUT = 0x6,
+ STP_FW_ABT = 0x7,
+ STP_HOST_TRIGGER_COLLECT_FTRACE = 0x8,
+ STP_FW_ISSUE_TYPE_MAX
+} ENUM_STP_FW_ISSUE_TYPE, *P_ENUM_STP_FW_ISSUE_TYPE;
+
+/* this was added for support dmareg's issue */
+typedef enum _ENUM_DMA_ISSUE_TYPE_ {
+ CONNSYS_CLK_GATE_STATUS = 0x00,
+ CONSYS_EMI_STATUS,
+ SYSRAM1,
+ SYSRAM2,
+ SYSRAM3,
+ DMA_REGS_MAX
+} ENUM_DMA_ISSUE_TYPE;
+#define STP_PATCH_TIME_SIZE 12
+#define STP_DBG_CPUPCR_NUM 30
+#define STP_DBG_DMAREGS_NUM 16
+#define STP_PATCH_BRANCH_SZIE 8
+#define STP_ASSERT_INFO_SIZE 164
+#define STP_DBG_ROM_VER_SIZE 4
+#define STP_ASSERT_TYPE_SIZE 64
+
+#define STP_DBG_KEYWORD_SIZE 256
+typedef struct stp_dbg_host_assert_t {
+ UINT32 drv_type;
+ UINT32 reason;
+ UINT32 assert_from_host;
+} STP_DBG_HOST_ASSERT_T, *P_STP_DBG_HOST_ASSERT_T;
+
+typedef struct stp_dbg_cpupcr_t {
+ UINT32 chipId;
+ UINT8 romVer[STP_DBG_ROM_VER_SIZE];
+ UINT8 patchVer[STP_PATCH_TIME_SIZE];
+ UINT8 branchVer[STP_PATCH_BRANCH_SZIE];
+ UINT32 wifiVer;
+ UINT32 count;
+ UINT32 stop_flag;
+ UINT32 buffer[STP_DBG_CPUPCR_NUM];
+ UINT64 sec_buffer[STP_DBG_CPUPCR_NUM];
+ ULONG nsec_buffer[STP_DBG_CPUPCR_NUM];
+ UINT8 assert_info[STP_ASSERT_INFO_SIZE];
+ UINT32 fwTaskId;
+ UINT32 fwRrq;
+ UINT32 fwIsr;
+ STP_DBG_HOST_ASSERT_T host_assert_info;
+ UINT8 assert_type[STP_ASSERT_TYPE_SIZE];
+ ENUM_STP_FW_ISSUE_TYPE issue_type;
+ UINT8 keyword[STP_DBG_KEYWORD_SIZE];
+ OSAL_SLEEPABLE_LOCK lock;
+} STP_DBG_CPUPCR_T, *P_STP_DBG_CPUPCR_T;
+
+typedef struct stp_dbg_dmaregs_t {
+ UINT32 count;
+ UINT32 dmaIssue[DMA_REGS_MAX][STP_DBG_DMAREGS_NUM];
+ OSAL_SLEEPABLE_LOCK lock;
+} STP_DBG_DMAREGS_T, *P_STP_DBG_DMAREGS_T;
+
+typedef enum _ENUM_ASSERT_INFO_PARSER_TYPE_ {
+ STP_DBG_ASSERT_INFO = 0x0,
+ STP_DBG_FW_TASK_ID = 0x1,
+ STP_DBG_FW_ISR = 0x2,
+ STP_DBG_FW_IRQ = 0x3,
+ STP_DBG_ASSERT_TYPE = 0x4,
+ STP_DBG_PARSER_TYPE_MAX
+} ENUM_ASSERT_INFO_PARSER_TYPE, *P_ENUM_ASSERT_INFO_PARSER_TYPE;
+
+VOID stp_dbg_nl_init(VOID);
+VOID stp_dbg_nl_deinit(VOID);
+INT32 stp_dbg_core_dump_deinit_gcoredump(VOID);
+INT32 stp_dbg_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout);
+INT32 stp_dbg_core_dump(INT32 dump_sink);
+INT32 stp_dbg_trigger_collect_ftrace(PUINT8 pbuf, INT32 len);
+#if BTIF_RXD_BE_BLOCKED_DETECT
+MTK_WCN_BOOL stp_dbg_is_btif_rxd_be_blocked(VOID);
+#endif
+INT32 stp_dbg_enable(MTKSTP_DBG_T *stp_dbg);
+INT32 stp_dbg_disable(MTKSTP_DBG_T *stp_dbg);
+INT32 stp_dbg_dmp_print(MTKSTP_DBG_T *stp_dbg);
+INT32 stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, PINT8 buf, PINT32 len);
+INT32 stp_dbg_dmp_append(MTKSTP_DBG_T *stp_dbg, PUINT8 pBuf, INT32 max_len);
+
+INT32 stp_dbg_dmp_out_ex(PINT8 buf, PINT32 len);
+INT32 stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, INT32 dbg_type,
+ INT32 type, INT32 ack_no, INT32 seq_no, INT32 crc, INT32 dir, INT32 len,
+ const PUINT8 body);
+INT32 stp_dbg_log_ctrl(UINT32 on);
+INT32 stp_dbg_aee_send(PUINT8 aucMsg, INT32 len, INT32 cmd);
+INT32 stp_dbg_dump_num(LONG dmp_num);
+INT32 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len);
+INT32 stp_dbg_dump_send_retry_handler(PINT8 tmp, INT32 len);
+VOID stp_dbg_set_coredump_timer_state(CORE_DUMP_STA state);
+INT32 stp_dbg_get_coredump_timer_state(VOID);
+INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd);
+INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep);
+INT32 stp_dbg_poll_cpupcr_ctrl(UINT32 en);
+INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, PUINT8 pPatchBrh);
+INT32 stp_dbg_set_wifiver(UINT32 wifiver);
+INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en);
+VOID stp_dbg_set_keyword(PINT8 keyword);
+UINT32 stp_dbg_get_host_trigger_assert(VOID);
+INT32 stp_dbg_set_fw_info(PUINT8 issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type);
+INT32 stp_dbg_cpupcr_infor_format(PUINT8 buf, UINT32 max_len);
+INT32 stp_dbg_dump_cpupcr_reg_info(PUINT8 buf, UINT32 consys_lp_reg);
+VOID stp_dbg_clear_cpupcr_reg_info(VOID);
+PUINT8 stp_dbg_id_to_task(UINT32 id);
+VOID stp_dbg_reset(VOID);
+
+MTKSTP_DBG_T *stp_dbg_init(PVOID btm_half);
+INT32 stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg);
+INT32 stp_dbg_start_coredump_timer(VOID);
+INT32 stp_dbg_start_emi_dump(VOID);
+INT32 stp_dbg_stop_emi_dump(VOID);
+INT32 stp_dbg_nl_send_data(const PINT8 buf, INT32 len);
+#endif /* end of _STP_DEBUG_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab5a137e56cfaa8f03b5774cf95ead1f17d035c4
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _STP_DEBUG_COMBO_H_
+#define _STP_DEBUG_COMBO_H_
+
+#include
+#include "osal.h"
+
+INT32 stp_dbg_combo_core_dump(INT32 dump_sink);
+PUINT8 stp_dbg_combo_id_to_task(UINT32 id);
+
+#endif /* end of _STP_DEBUG_COMBO_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c070f9a88d3dd40c9c41a95150a9cf60aceaf9a
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _STP_DEBUG_SOC_H_
+#define _STP_DEBUG_SOC_H_
+
+#include
+#include "osal.h"
+#include "wmt_plat.h"
+
+#define STP_DBG_PAGED_DUMP_BUFFER_SIZE (32*1024*sizeof(char))
+
+INT32 stp_dbg_soc_core_dump(INT32 dump_sink);
+PUINT8 stp_dbg_soc_id_to_task(UINT32 id);
+UINT32 stp_dbg_soc_read_debug_crs(ENUM_CONNSYS_DEBUG_CR cr);
+INT32 stp_dbg_soc_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd);
+
+#endif /* end of _STP_DEBUG_SOC_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1b9f45082c9b101ccc52d268480ee06413d039b
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*
+ * Id:
+ */
+
+/*! \file "stp_sdio.h"
+ * \brief
+ */
+
+/*
+ * Log:
+ */
+
+#ifndef _STP_SDIO_H
+#define _STP_SDIO_H
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+
+#define KMALLOC_UPDATE 1
+
+#if 0 /* NO support for multiple STP-SDIO instances (multiple MT6620) on a single host */
+#define STP_SDIO_HOST_COUNT (1)
+#define STP_SDIO_ONLY_ONE_HOST (0)
+#endif
+#define STP_SDIO_POLL_OWNBACK_INTR (1)
+
+#define STP_SDIO_NEW_TXRING (0)
+/* George: Keep old (0) codes for debugging only!
+ * Use new code (1) for SQC and MP!
+ */
+
+#define STP_SDIO_OWN_THREAD (1)
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+#include "osal.h"
+#include "hif_sdio.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+/* Common HIF 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 CTMDPCR0 (0x00B8)
+#define CTMDPCR1 (0x00BC)
+#define CSR (0x00D8) /* MT6630 & MT6632 only for the moment */
+
+
+
+/* Common HIF register bit field address */
+/* CCCR_F0*/
+#define CCCR_F0_RX_CRC (0x1)
+#define CCCR_F0_RX_INT (0x8)
+
+/* CHLPCR */
+#define C_FW_OWN_REQ_CLR (0x00000200)
+#define C_FW_OWN_REQ_SET (0x00000100)
+#define C_FW_INT_EN_CLR (0x00000002)
+#define C_FW_INT_EN_SET (0x00000001)
+#define C_FW_COM_DRV_OWN (0x00000100)
+
+/* CHIER */
+#define CHISR_EN_15_7 (0x0000ff80)
+#define CHISR_EN_3_0 (0x0000000f)
+/* CHISR */
+#define RX_PKT_LEN (0xffff0000)
+#define FIRMWARE_INT (0x0000fe00)
+#define TX_RETRY (0x00000200)
+#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)
+
+/* hardware settings */
+#define STP_SDIO_TX_FIFO_SIZE (2080UL)
+#define STP_SDIO_RX_FIFO_SIZE (2304UL) /* 256*9 */
+#define STP_SDIO_TX_PKT_MAX_CNT (7) /* Max outstanding tx pkt count, as defined in TX_COMPLETE_COUNT */
+#define STP_SDIO_HDR_SIZE (4) /* hw,fw,sw follow the same format: 2 bytes length + 2 bytes reserved */
+
+#define STP_SDIO_DBG_SUPPORT 1
+#define STP_SDIO_RXDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */
+#define STP_SDIO_TXDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */
+#define STP_TXDBG 1
+
+/* sdio bus settings */
+#define STP_SDIO_BLK_SIZE (512UL)
+
+/* software driver settings */
+#define STP_SDIO_TX_BUF_CNT (16UL) /*(7) */
+#define STP_SDIO_TX_BUF_CNT_MASK (STP_SDIO_TX_BUF_CNT - 1)
+#define STP_SDIO_TX_PKT_LIST_SIZE (STP_SDIO_TX_BUF_CNT) /* must be 2^x now... */
+#define STP_SDIO_TX_PKT_LIST_SIZE_MASK (STP_SDIO_TX_PKT_LIST_SIZE - 1)
+
+#define STP_SDIO_FW_CPUPCR_POLLING_CNT (5)
+
+#define STP_SDIO_RETRY_LIMIT (10)
+#define STP_SDIO_MAX_RETRY_NUM (100)
+
+#define STP_SDIO_RETRY_NONE (0)
+#define STP_SDIO_RETRY_CRC_ERROR (1)
+#define STP_SDIO_RETRY_INT (2)
+
+/* tx buffer size for a single entry */
+/* George: SHALL BE a multiple of the used BLK_SIZE!! */
+#if 1
+/* round up: 512*5 = 2560 > 2080 */
+#define STP_SDIO_TX_ENTRY_SIZE ((STP_SDIO_TX_FIFO_SIZE + (STP_SDIO_BLK_SIZE - 1)) & ~(STP_SDIO_BLK_SIZE - 1))
+#else
+/* round down: 512*4 = 2048 < 2080 */
+#define STP_SDIO_TX_MAX_BLK_CNT (STP_SDIO_TX_FIFO_SIZE / STP_SDIO_BLK_SIZE)
+#define STP_SDIO_TX_ENTRY_SIZE (STP_SDIO_TX_MAX_BLK_CNT * STP_SDIO_BLK_SIZE)
+#endif
+
+/*software rx buffer size */
+/*#define STP_SDIO_RX_BUF_SIZE (STP_SDIO_RX_FIFO_SIZE)*/
+/* George: SHALL BE a multiple of the used BLK_SIZE!! */
+#if 1
+/* round up: 512*5 = 2560 > 2304 */
+#define STP_SDIO_RX_BUF_SIZE ((STP_SDIO_RX_FIFO_SIZE + (STP_SDIO_BLK_SIZE - 1)) & ~(STP_SDIO_BLK_SIZE - 1))
+#else
+/* round down: 512*4 = 2048 < 2304 */
+#define STP_SDIO_RX_MAX_BLK_CNT (STP_SDIO_RX_FIFO_SIZE / STP_SDIO_BLK_SIZE)
+#define STP_SDIO_RX_BUF_SIZE (STP_SDIO_RX_MAX_BLK_CNT * STP_SDIO_BLK_SIZE)
+#endif
+
+#define COHEC_00006052 (1)
+/* #define COHEC_00006052 (0) */
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+typedef enum _ENUM_STP_SDIO_HIF_TYPE_T {
+ HIF_TYPE_READB = 0,
+ HIF_TYPE_READL = HIF_TYPE_READB + 1,
+ HIF_TYPE_READ_BUF = HIF_TYPE_READL + 1,
+ HIF_TYPE_WRITEB = HIF_TYPE_READ_BUF + 1,
+ HIF_TYPE_WRITEL = HIF_TYPE_WRITEB + 1,
+ HIF_TYPE_WRITE_BUF = HIF_TYPE_WRITEL + 1,
+ HIF_TYPE_MAX
+} ENUM_STP_SDIO_HIF_TYPE_T, *P_ENUM_STP_SDIO_HIF_TYPE_T;
+
+/* HIF's local packet buffer variables for Tx/Rx */
+typedef struct _MTK_WCN_STP_SDIO_PKT_BUF {
+ /* Tx entry ring buffer. Entry size is aligned to SDIO block size. */
+#if KMALLOC_UPDATE
+ PUINT8 tx_buf;
+#else
+ UINT8 tx_buf[STP_SDIO_TX_BUF_CNT][STP_SDIO_TX_ENTRY_SIZE];
+#endif
+
+ /* Tx size ring buffer. Record valid data size in tx_buf. */
+ UINT32 tx_buf_sz[STP_SDIO_TX_BUF_CNT];
+ /* Tx debug timestamp: 1st time when the entry is filled with data */
+ UINT32 tx_buf_ts[STP_SDIO_TX_BUF_CNT];
+ UINT64 tx_buf_local_ts[STP_SDIO_TX_BUF_CNT];
+ ULONG tx_buf_local_nsec[STP_SDIO_TX_BUF_CNT];
+
+#if KMALLOC_UPDATE
+ PUINT8 rx_buf;
+#else
+ UINT8 rx_buf[STP_SDIO_RX_BUF_SIZE]; /* Rx buffer (not ring) */
+#endif
+#if STP_SDIO_NEW_TXRING
+ atomic_t wr_cnt; /* Tx entry ring buffer write count */
+ atomic_t rd_cnt; /* Tx entry ring buffer read count */
+ spinlock_t rd_cnt_lock; /* Tx entry ring buffer read count spin lock */
+#else
+ atomic_t wr_idx; /* Tx ring buffer write index *//*George: obsolete */
+ atomic_t rd_idx; /* Tx ring buffer read index *//*George: obsolete */
+ spinlock_t rd_idx_lock; /* spin lock for Tx ring buffer read index */
+#endif
+ MTK_WCN_BOOL full_flag; /* Tx entry ring buffer full flag (TRUE: full, FALSE: not full) */
+ /* save interrupt status flag for Tx entry ring buf spin lock */
+ ULONG rd_irq_flag;
+ /* wait queue head for Tx entry ring buf full case */
+ wait_queue_head_t fullwait_q;
+} MTK_WCN_STP_SDIO_PKT_BUF;
+
+/* Tx packet list information */
+typedef struct _MTK_WCN_STP_SDIO_Tx_Pkt_LIST {
+ UINT32 pkt_rd_cnt;
+ UINT32 pkt_wr_cnt;
+ UINT16 pkt_size_list[STP_SDIO_TX_PKT_LIST_SIZE]; /*max length is FIFO Size */
+ UINT32 out_ts[STP_SDIO_TX_PKT_LIST_SIZE];
+ UINT32 in_ts[STP_SDIO_TX_PKT_LIST_SIZE];
+} MTK_WCN_STP_SDIO_Tx_Pkt_LIST;
+
+/* STP HIF firmware information */
+typedef struct _MTK_WCN_STP_SDIO_FIRMWARE_INFO {
+ UINT32 tx_fifo_size; /* Current left tx FIFO size */
+ UINT32 tx_packet_num; /* Current outstanding tx packet (0~7) */
+ atomic_t tx_comp_num; /* Current total tx ok but fifo size not released packet count */
+} MTK_WCN_STP_SDIO_FIRMWARE_INFO;
+
+/* STP SDIO private information */
+typedef struct _MTK_WCN_STP_SDIO_PRIVATE_INFO {
+ UINT8 stp_sdio_host_idx;
+} MTK_WCN_STP_SDIO_PRIVATE_INFO;
+
+/* STP SDIO host information */
+typedef struct _MTK_WCN_STP_SDIO_HIF_INFO {
+ MTK_WCN_HIF_SDIO_CLTCTX sdio_cltctx;
+ MTK_WCN_STP_SDIO_PKT_BUF pkt_buf;
+ MTK_WCN_STP_SDIO_Tx_Pkt_LIST tx_pkt_list;
+ UINT32 rx_pkt_len; /* George: use 32-bit for efficiency. Correct name to pkt for packet */
+ MTK_WCN_STP_SDIO_FIRMWARE_INFO firmware_info;
+ MTK_WCN_STP_SDIO_PRIVATE_INFO private_info;
+#if STP_SDIO_OWN_THREAD
+ /* struct tasklet_struct tx_rx_job; */
+ OSAL_THREAD tx_rx_thread;
+ INT32 irq_pending;
+ INT32 sleep_flag;
+ INT32 wakeup_flag;
+ INT32 awake_flag;
+ INT32 txwkr_flag;
+ OSAL_EVENT tx_rx_event;
+ OSAL_SIGNAL isr_check_complete;
+ INT32 dump_flag;
+#endif
+ INT32 tx_dbg_dump_flag;
+ INT32 tx_retry_flag;
+ INT32 retry_enable_flag;
+ INT32 tx_retry_count;
+ INT32 rx_retry_count;
+ struct work_struct tx_work;
+ struct work_struct rx_work;
+} MTK_WCN_STP_SDIO_HIF_INFO;
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+extern MTK_WCN_STP_SDIO_HIF_INFO g_stp_sdio_host_info;
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+/* STP_SDIO_TX_PKT_LIST_SIZE must be 2^x */
+#define STP_SDIO_GET_PKT_AR_IDX(idx) ((idx) & STP_SDIO_TX_PKT_LIST_SIZE_MASK)
+
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+
+/*!
+ * \brief MTK hif sdio client registration function
+ *
+ * Client uses this function to do hif sdio registration
+ *
+ * \param pinfo a pointer of client's information
+ *
+ * \retval 0 register successfully
+ * \retval < 0 error code
+ */
+extern INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo);
+extern INT32 stp_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value);
+
+#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG)
+VOID stp_sdio_txdbg_dump(VOID);
+#endif
+
+extern INT32 mtk_wcn_stp_sdio_do_own_clr(VOID);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag);
+#endif
+/* extern INT32 */
+/* mtk_wcn_stp_sdio_do_own_set (void); */
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+INT32 stp_sdio_rw_retry(ENUM_STP_SDIO_HIF_TYPE_T type, UINT32 retry_limit,
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 offset, PUINT32 pData, UINT32 len);
+VOID stp_sdio_retry_flag_ctrl(INT32 flag);
+INT32 stp_sdio_retry_flag_get(VOID);
+INT32 stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx);
+VOID stp_sdio_dump_register(VOID);
+INT32 stp_sdio_issue_fake_coredump(UINT8 *str);
+VOID stp_sdio_dump_info(MTK_WCN_STP_SDIO_HIF_INFO *p_info);
+
+
+#endif /* _STP_SDIO_H */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_alarm.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_alarm.h
new file mode 100644
index 0000000000000000000000000000000000000000..d45d632770578032de1765665665e5c3dd58f8b8
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_alarm.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef _WMT_ALARM_H_
+#define _WMT_ALARM_H_
+
+int wmt_alarm_init(void);
+int wmt_alarm_deinit(void);
+
+int wmt_alarm_start(unsigned int sec);
+int wmt_alarm_cancel(void);
+
+#endif
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc16dbd6acd3d8d6f6d98765d43898b3755aed3c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _WMT_DBG_H_
+#define _WMT_DBG_H_
+#include "osal.h"
+
+#define STP_SDIO 0x04
+#define STP_UART_MAND 0x02
+#define STP_UART_FULL 0x01
+
+#if (WMT_DBG_SUPPORT)
+#define CFG_WMT_DBG_SUPPORT 1 /* support wmt_dbg or not */
+#else
+#define CFG_WMT_DBG_SUPPORT 0
+#endif
+
+#define CFG_WMT_PROC_FOR_AEE 1
+
+typedef struct _COEX_BUF {
+ UINT8 buffer[128];
+ INT32 availSize;
+} COEX_BUF, *P_COEX_BUF;
+
+typedef enum _ENUM_CMD_TYPE_T {
+ WMTDRV_CMD_ASSERT = 0,
+ WMTDRV_CMD_EXCEPTION = 1,
+ WMTDRV_CMD_COEXDBG_00 = 2,
+ WMTDRV_CMD_COEXDBG_01 = 3,
+ WMTDRV_CMD_COEXDBG_02 = 4,
+ WMTDRV_CMD_COEXDBG_03 = 5,
+ WMTDRV_CMD_COEXDBG_04 = 6,
+ WMTDRV_CMD_COEXDBG_05 = 7,
+ WMTDRV_CMD_COEXDBG_06 = 8,
+ WMTDRV_CMD_COEXDBG_07 = 9,
+ WMTDRV_CMD_COEXDBG_08 = 10,
+ WMTDRV_CMD_COEXDBG_09 = 11,
+ WMTDRV_CMD_COEXDBG_10 = 12,
+ WMTDRV_CMD_COEXDBG_11 = 13,
+ WMTDRV_CMD_COEXDBG_12 = 14,
+ WMTDRV_CMD_COEXDBG_13 = 15,
+ WMTDRV_CMD_COEXDBG_14 = 16,
+ WMTDRV_CMD_COEXDBG_15 = 17,
+ WMTDRV_CMD_NOACK_TEST = 18,
+ WMTDRV_CMD_WARNRST_TEST = 19,
+ WMTDRV_CMD_FWTRACE_TEST = 20,
+ WMTDRV_CMD_MAX
+} ENUM_WMTDRV_CMD_T, *P_ENUM_WMTDRV_CMD_T;
+
+
+typedef INT32(*WMT_DEV_DBG_FUNC) (INT32 par1, INT32 par2, INT32 par3);
+INT32 wmt_dev_dbg_setup(VOID);
+INT32 wmt_dev_dbg_remove(VOID);
+INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3);
+
+#endif /* _WMT_DBG_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h
new file mode 100644
index 0000000000000000000000000000000000000000..0aec923213db586304b32036351bd7d23047dbf5
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _WMT_DEV_H_
+#define _WMT_DEV_H_
+
+#include "osal.h"
+
+#define STP_UART_FULL 0x01
+#define STP_UART_MAND 0x02
+#define STP_BTIF_FULL 0x03
+#define STP_SDIO 0x04
+
+VOID wmt_dev_rx_event_cb(VOID);
+INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent);
+INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch);
+INT32 wmt_dev_patch_put(osal_firmware **ppPatch);
+VOID wmt_dev_patch_info_free(VOID);
+VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd);
+MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID);
+INT32 wmt_lpbk_handler(UINT32 on_off_flag, UINT32 retry);
+VOID wmt_dev_blank_handler(VOID);
+UINT32 wmt_dev_get_blank_state(VOID);
+INT32 wmt_dev_apo_ctrl(UINT32 enable);
+VOID wmt_dev_set_temp_threshold(INT32 val);
+UINT8 wmt_dev_is_close(VOID);
+extern LONG wmt_dev_tm_temp_query(VOID);
+
+INT32 mtk_wcn_common_drv_init(VOID);
+VOID mtk_wcn_common_drv_exit(VOID);
+
+int mtk_wcn_hif_sdio_drv_init(VOID);
+int mtk_wcn_stp_uart_drv_init(VOID);
+int mtk_wcn_stp_sdio_drv_init(VOID);
+int mtk_wcn_hif_sdio_driver_exit(VOID);
+int mtk_wcn_stp_sdio_drv_exit(VOID);
+int mtk_wcn_stp_uart_drv_exit(VOID);
+
+#endif /*_WMT_DEV_H_*/
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ea063561949262fb982ee651c4e488a724941bf
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _WMT_IDC_H_
+#define _WMT_IDC_H_
+
+#include "osal.h"
+#include "stp_exp.h"
+
+#if CFG_WMT_LTE_COEX_HANDLING
+
+#include
+#include "conn_md_exp.h"
+
+#define LTE_IDC_BUFFER_MAX_SIZE 1024
+/*comment from firmware owner,max pckage num is 5,but should not happened*/
+#define WMT_IDC_RX_MAX_LEN 384
+#define LTE_MSG_ID_OFFSET 0x30
+
+typedef enum {
+ WMT_IDC_TX_OPCODE_MIN = 0,
+ WMT_IDC_TX_OPCODE_LTE_PARA = 0x0a,
+ WMT_IDC_TX_OPCODE_LTE_FREQ = 0x0b,
+ WMT_IDC_TX_OPCODE_WIFI_MAX_POWER = 0x0c,
+ WMT_IDC_TX_OPCODE_DEBUG_MONITOR = 0x0e,
+ WMT_IDC_TX_OPCODE_SPLIT_FILTER = 0x0f,
+ WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS = 0x16,
+ WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION = 0x17,
+ WMT_IDC_TX_OPCODE_LTE_INDICATION = 0x20,
+ WMT_IDC_TX_OPCODE_MAX
+} WMT_IDC_TX_OPCODE;
+
+typedef enum {
+ WMT_IDC_RX_OPCODE_BTWF_DEF_PARA = 0x0,
+ WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN = 0x1,
+ /* WMT_IDC_RX_OPCODE_TDM_REQ = 0x10, */
+ WMT_IDC_RX_OPCODE_DEBUG_MONITOR = 0x02,
+ WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE = 0x03,
+ WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND = 0x04,
+ WMT_IDC_RX_OPCODE_UART_PIN_SEL = 0x05,
+ WMT_IDC_RX_OPCODE_MAX
+} WMT_IDC_RX_OPCODE;
+
+#if (CFG_WMT_LTE_ENABLE_MSGID_MAPPING == 0)
+typedef enum {
+ IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN,
+ IPC_L4C_MSG_ID_END,
+ IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN,
+ /* below are EL1 IPC messages sent from AP */
+ IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND,
+ IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND,
+ IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND,
+ IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND,
+ IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND,
+
+ /* below are EL1 messages sent to AP */
+ IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND,
+ IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND,
+ IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND,
+ IPC_MSG_ID_EL1_LTE_TX_IND,
+ IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND,
+ IPC_MSG_ID_EL1_PIN_TYPE_IND,
+ IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND,
+ IPC_MSG_ID_EL1_DUMMY13_IND,
+ IPC_MSG_ID_EL1_DUMMY14_IND,
+ IPC_MSG_ID_EL1_DUMMY15_IND,
+ IPC_MSG_ID_EL1_DUMMY16_IND,
+ IPC_MSG_ID_EL1_DUMMY17_IND,
+ IPC_MSG_ID_EL1_DUMMY18_IND,
+ IPC_MSG_ID_EL1_DUMMY19_IND,
+ IPC_MSG_ID_EL1_DUMMY20_IND,
+ IPC_MSG_ID_EL1_DUMMY21_IND,
+ IPC_MSG_ID_EL1_DUMMY22_IND,
+ IPC_MSG_ID_EL1_DUMMY23_IND,
+ IPC_MSG_ID_EL1_DUMMY24_IND,
+ IPC_MSG_ID_EL1_DUMMY25_IND,
+ IPC_MSG_ID_EL1_DUMMY26_IND,
+ IPC_MSG_ID_EL1_DUMMY27_IND,
+ IPC_MSG_ID_EL1_DUMMY28_IND,
+ IPC_MSG_ID_EL1_DUMMY29_IND,
+ IPC_MSG_ID_EL1_DUMMY30_IND,
+ IPC_MSG_ID_MD_CONSYS_VERIFICATION_IND,
+ IPC_MSG_ID_MD_CONSYS_VERIFICATION_REQ,
+ IPC_EL1_MSG_ID_END,
+} IPC_MSG_ID_CODE;
+#endif
+
+typedef struct _MTK_WCN_WMT_IDC_INFO_ {
+ conn_md_ipc_ilm_t iit;
+ struct conn_md_bridge_ops ops;
+ UINT8 buffer[LTE_IDC_BUFFER_MAX_SIZE];
+} MTK_WCN_WMT_IDC_INFO, *P_MTK_WCN_WMT_IDC_INFO;
+
+INT32 wmt_idc_init(VOID);
+INT32 wmt_idc_deinit(VOID);
+INT32 wmt_idc_msg_from_lte_handing(conn_md_ipc_ilm_t *ilm);
+INT32 wmt_idc_msg_to_lte_handing(VOID);
+UINT32 wmt_idc_msg_to_lte_handing_for_test(PUINT8 p_buf, UINT32 len);
+
+#endif /* endif CFG_WMT_LTE_COEX_HANDLING */
+
+#endif /* _WMT_IDC_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_proc_dbg.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_proc_dbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e8ed9be99f8d60ac8245e8be949dbc4ce3a3636
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_proc_dbg.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef _WMT_PROC_DBG_H_
+#define _WMT_PROC_DBG_H_
+
+#include "osal.h"
+
+#define CFG_WMT_PROC_FOR_AEE 1
+#define CFG_WMT_PROC_FOR_DUMP_INFO 1
+
+#if CFG_WMT_PROC_FOR_DUMP_INFO
+INT32 wmt_dev_proc_for_dump_info_setup(VOID);
+INT32 wmt_dev_proc_for_dump_info_remove(VOID);
+#else
+INT32 wmt_dev_proc_for_dump_info_setup(VOID) {}
+INT32 wmt_dev_proc_for_dump_info_remove(VOID) {}
+#endif
+
+INT32 wmt_dev_proc_init(VOID);
+INT32 wmt_dev_proc_deinit(VOID);
+
+
+#endif /* _WMT_PROC_DBG_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h
new file mode 100644
index 0000000000000000000000000000000000000000..8be5dc860b610b1bb058b762cdb9a7ae3e71acb7
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc. *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#ifndef _WMT_STEP_H_
+#define _WMT_STEP_H_
+
+#include
+
+#include "osal.h"
+#include "wmt_exp.h"
+#include "wmt_core.h"
+
+#define STEP_CONFIG_NAME "WMT_STEP.cfg"
+#define STEP_VERSION 2
+
+#define STEP_PERIODIC_DUMP_WORK_QUEUE "wmt_step_pd_wq"
+#define STEP_PERIODIC_DUMP_THREAD "wmt_pd"
+
+#define STEP_ACTION_NAME_EMI "_EMI"
+#define STEP_ACTION_NAME_REGISTER "_REG"
+#define STEP_ACTION_NAME_GPIO "GPIO"
+#define STEP_ACTION_NAME_DISABLE_RESET "DRST"
+#define STEP_ACTION_NAME_CHIP_RESET "_RST"
+#define STEP_ACTION_NAME_KEEP_WAKEUP "WAK+"
+#define STEP_ACTION_NAME_CANCEL_WAKEUP "WAK-"
+#define STEP_ACTION_NAME_SHOW_STRING "SHOW"
+#define STEP_ACTION_NAME_SLEEP "_SLP"
+#define STEP_ACTION_NAME_CONDITION "COND"
+#define STEP_ACTION_NAME_VALUE "_VAL"
+#define STEP_ACTION_NAME_CONDITION_EMI "CEMI"
+#define STEP_ACTION_NAME_CONDITION_REGISTER "CREG"
+
+extern struct platform_device *g_pdev;
+
+enum step_action_id {
+ STEP_ACTION_INDEX_NO_DEFINE = 0,
+ STEP_ACTION_INDEX_EMI = 1,
+ STEP_ACTION_INDEX_REGISTER,
+ STEP_ACTION_INDEX_GPIO,
+ STEP_ACTION_INDEX_DISABLE_RESET,
+ STEP_ACTION_INDEX_CHIP_RESET,
+ STEP_ACTION_INDEX_KEEP_WAKEUP,
+ STEP_ACTION_INDEX_CANCEL_WAKEUP,
+ STEP_ACTION_INDEX_PERIODIC_DUMP,
+ STEP_ACTION_INDEX_SHOW_STRING,
+ STEP_ACTION_INDEX_SLEEP,
+ STEP_ACTION_INDEX_CONDITION,
+ STEP_ACTION_INDEX_VALUE,
+ STEP_ACTION_INDEX_CONDITION_EMI,
+ STEP_ACTION_INDEX_CONDITION_REGISTER,
+ STEP_ACTION_INDEX_MAX,
+};
+
+enum step_trigger_point_id {
+ STEP_TRIGGER_POINT_NO_DEFINE = 0,
+ STEP_TRIGGER_POINT_COMMAND_TIMEOUT = 1,
+ STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT,
+ STEP_TRIGGER_POINT_BEFORE_CHIP_RESET,
+ STEP_TRIGGER_POINT_AFTER_CHIP_RESET,
+ STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_ON,
+ STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_OFF,
+ STEP_TRIGGER_POINT_BEFORE_BT_FUNC_ON,
+ STEP_TRIGGER_POINT_BEFORE_BT_FUNC_OFF,
+ STEP_TRIGGER_POINT_BEFORE_FM_FUNC_ON,
+ STEP_TRIGGER_POINT_BEFORE_FM_FUNC_OFF,
+ STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_ON,
+ STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_OFF,
+ STEP_TRIGGER_POINT_BEFORE_READ_THERMAL,
+ STEP_TRIGGER_POINT_POWER_ON_START,
+ STEP_TRIGGER_POINT_POWER_ON_BEFORE_GET_CONNSYS_ID,
+ STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH,
+ STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET,
+ STEP_TRIGGER_POINT_POWER_ON_BEFORE_SET_WIFI_LTE_COEX,
+ STEP_TRIGGER_POINT_POWER_ON_BEFORE_BT_WIFI_CALIBRATION,
+ STEP_TRIGGER_POINT_POWER_ON_END,
+ STEP_TRIGGER_POINT_BEFORE_POWER_OFF,
+ STEP_TRIGGER_POINT_WHEN_AP_SUSPEND,
+ STEP_TRIGGER_POINT_WHEN_AP_RESUME,
+ STEP_TRIGGER_POINT_POWER_OFF_HANDSHAKE,
+ STEP_TRIGGER_POINT_BEFORE_RESTORE_CAL_RESULT,
+ STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_RESULT,
+ STEP_TRIGGER_POINT_POWER_ON_AFTER_BT_WIFI_CALIBRATION,
+ STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_CMD,
+ STEP_TRIGGER_POINT_WHEN_CLOCK_FAIL,
+ STEP_TRIGGER_POINT_BEFORE_GPSL5_FUNC_ON,
+ STEP_TRIGGER_POINT_BEFORE_GPSL5_FUNC_OFF,
+ STEP_TRIGGER_POINT_MAX,
+};
+
+enum step_base_address_index {
+ STEP_MCU_BASE_INDEX = 0,
+ STEP_TOP_RGU_BASE_INDEX,
+ STEP_INFRACFG_AO_BASE_INDEX,
+ STEP_SPM_BASE_INDEX,
+ STEP_MCU_CONN_HIF_ON_BASE_INDEX,
+ STEP_MCU_TOP_MISC_OFF_BASE_INDEX,
+ STEP_MCU_CFG_ON_BASE_INDEX,
+ STEP_MCU_CIRQ_BASE_INDEX,
+ STEP_MCU_TOP_MISC_ON_BASE_INDEX,
+ STEP_BASE_ADDRESS_MAX,
+};
+
+enum step_register_base_id {
+ STEP_REGISTER_PHYSICAL_ADDRESS = 0,
+ STEP_REGISTER_CONN_MCU_CONFIG_BASE,
+ STEP_REGISTER_AP_RGU_BASE,
+ STEP_REGISTER_TOPCKGEN_BASE,
+ STEP_REGISTER_SPM_BASE,
+ STEP_REGISTER_HIF_ON_BASE,
+ STEP_REGISTER_MISC_OFF_BASE,
+ STEP_REGISTER_CFG_ON_BASE,
+ STEP_CIRQ_BASE,
+ STEP_MCU_TOP_MISC_ON_BASE,
+ STEP_REGISTER_MAX,
+};
+
+enum step_condition_operator_id {
+ STEP_OPERATOR_GREATER = 0,
+ STEP_OPERATOR_GREATER_EQUAL,
+ STEP_OPERATOR_LESS,
+ STEP_OPERATOR_LESS_EQUAL,
+ STEP_OPERATOR_EQUAL,
+ STEP_OPERATOR_NOT_EQUAL,
+ STEP_OPERATOR_AND,
+ STEP_OPERATOR_OR,
+ STEP_OPERATOR_MAX,
+};
+
+struct step_register_base_struct {
+ unsigned long vir_addr;
+ unsigned long long size;
+};
+
+struct step_action_list {
+ struct list_head list;
+};
+
+struct step_pd_entry {
+ bool is_enable;
+ unsigned int expires_ms;
+ struct step_action_list action_list;
+ struct delayed_work pd_work;
+ struct list_head list;
+};
+
+struct step_pd_struct {
+ bool is_init;
+ struct workqueue_struct *step_pd_wq;
+ struct list_head pd_list;
+};
+
+struct step_action {
+ struct list_head list;
+ enum step_action_id action_id;
+};
+
+typedef int (*STEP_WRITE_ACT_TO_LIST) (struct step_action_list *, enum step_action_id, int, char **);
+typedef void (*STEP_DO_EXTRA) (unsigned int, ...);
+
+#define STEP_OUTPUT_LOG 0
+#define STEP_OUTPUT_REGISTER 1
+
+struct step_emi_info {
+ bool is_write;
+ unsigned int begin_offset;
+ unsigned int end_offset;
+ int value;
+ unsigned int temp_reg_id;
+ int output_mode;
+ int mask;
+};
+
+struct step_emi_action {
+ struct step_emi_info info;
+ struct step_action base;
+};
+
+struct step_reigster_info {
+ bool is_write;
+ enum step_register_base_id address_type;
+ unsigned long address;
+ unsigned int offset;
+ unsigned int times;
+ unsigned int delay_time;
+ int value;
+ int mask;
+ unsigned int temp_reg_id;
+ int output_mode;
+};
+
+struct step_register_action {
+ struct step_reigster_info info;
+ struct step_action base;
+};
+
+struct step_gpio_action {
+ bool is_write;
+ unsigned int pin_symbol;
+ struct step_action base;
+};
+
+struct step_disable_reset_action {
+ struct step_action base;
+};
+
+struct step_chip_reset_action {
+ struct step_action base;
+};
+
+struct step_keep_wakeup_action {
+ struct step_action base;
+};
+
+struct step_cancel_wakeup_action {
+ struct step_action base;
+};
+
+struct step_periodic_dump_action {
+ struct step_pd_entry *pd_entry;
+ struct step_action base;
+};
+
+struct step_show_string_action {
+ char *content;
+ struct step_action base;
+};
+
+struct step_sleep_action {
+ unsigned int ms;
+ struct step_action base;
+};
+
+#define STEP_CONDITION_RIGHT_REGISTER 0
+#define STEP_CONDITION_RIGHT_VALUE 1
+struct step_condition_action {
+ unsigned int result_temp_reg_id;
+ unsigned int l_temp_reg_id;
+ unsigned int r_temp_reg_id;
+ int value;
+ int mode;
+ enum step_condition_operator_id operator_id;
+ struct step_action base;
+};
+
+struct step_value_action {
+ unsigned int temp_reg_id;
+ int value;
+ struct step_action base;
+};
+
+struct step_condition_emi_action {
+ unsigned int cond_reg_id;
+ struct step_emi_info info;
+ struct step_action base;
+};
+
+struct step_condition_register_action {
+ unsigned int cond_reg_id;
+ struct step_reigster_info info;
+ struct step_action base;
+};
+
+#define list_entry_action(act_struct, ptr) \
+ container_of(ptr, struct step_##act_struct##_action, base)
+
+struct step_reg_addr_info {
+ int address_type;
+ unsigned long address;
+};
+
+struct step_target_act_list_info {
+ enum step_trigger_point_id tp_id;
+ struct step_action_list *p_target_list;
+ struct step_pd_entry *p_pd_entry;
+};
+
+#define STEP_PARAMETER_SIZE 10
+struct step_parse_line_data_param_info {
+ int state;
+ enum step_action_id act_id;
+ char *act_params[STEP_PARAMETER_SIZE];
+ int param_index;
+};
+
+typedef struct step_action *(*STEP_CREATE_ACTION) (int, char *[]);
+typedef int (*STEP_DO_ACTIONS) (struct step_action *, STEP_DO_EXTRA);
+typedef void (*STEP_REMOVE_ACTION) (struct step_action *);
+struct step_action_contrl {
+ STEP_CREATE_ACTION func_create_action;
+ STEP_DO_ACTIONS func_do_action;
+ STEP_REMOVE_ACTION func_remove_action;
+};
+
+#define STEP_REGISTER_BASE_SYMBOL '#'
+#define STEP_TEMP_REGISTER_SYMBOL '$'
+
+#define STEP_VALUE_INFO_UNKNOWN -1
+#define STEP_VALUE_INFO_NUMBER 0
+#define STEP_VALUE_INFO_SYMBOL_REG_BASE 1
+#define STEP_VALUE_INFO_SYMBOL_TEMP_REG 2
+
+#define STEP_TEMP_REGISTER_SIZE 10
+struct step_env_struct {
+ bool is_enable;
+ bool is_keep_wakeup;
+ struct step_action_list actions[STEP_TRIGGER_POINT_MAX];
+ unsigned char __iomem *emi_base_addr;
+ struct step_register_base_struct reg_base[STEP_REGISTER_MAX];
+ struct step_pd_struct pd_struct;
+ int temp_register[STEP_TEMP_REGISTER_SIZE];
+ bool is_setup;
+ struct rw_semaphore init_rwsem;
+};
+
+/********************************************************************************
+ * F U N C T I O N D E C L A R A T I O N S
+*********************************************************************************/
+void wmt_step_init(void);
+void wmt_step_deinit(void);
+void wmt_step_do_actions(enum step_trigger_point_id tp_id);
+void wmt_step_func_crtl_do_actions(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId);
+void wmt_step_command_timeout_do_actions(char *reason);
+#ifdef CFG_WMT_STEP
+#define WMT_STEP_INIT_FUNC() wmt_step_init()
+#define WMT_STEP_DEINIT_FUNC() wmt_step_deinit()
+#define WMT_STEP_DO_ACTIONS_FUNC(tp) wmt_step_do_actions(tp)
+#define WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, id) wmt_step_func_crtl_do_actions(type, id)
+#define WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC(reason) wmt_step_command_timeout_do_actions(reason)
+#else
+#define WMT_STEP_INIT_FUNC()
+#define WMT_STEP_DEINIT_FUNC()
+#define WMT_STEP_DO_ACTIONS_FUNC(tp)
+#define WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, id)
+#define WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC(reason)
+#endif
+
+/********************************************************************************
+ * D E C L A R E F O R T E S T
+*********************************************************************************/
+int wmt_step_read_file(const char *file_name);
+int wmt_step_parse_data(const char *in_buf, unsigned int size, STEP_WRITE_ACT_TO_LIST func_act_to_list);
+int wmt_step_init_pd_env(void);
+int wmt_step_deinit_pd_env(void);
+struct step_pd_entry *wmt_step_get_periodic_dump_entry(unsigned int expires);
+struct step_action *wmt_step_create_action(enum step_action_id act_id, int param_num, char *params[]);
+int wmt_step_do_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_gpio_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_disable_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_chip_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_keep_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_cancel_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_periodic_dump_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_show_string_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_sleep_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_condition_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_value_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_condition_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+int wmt_step_do_condition_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra);
+void wmt_step_remove_action(struct step_action *p_act);
+void wmt_step_print_version(void);
+
+#endif /* end of _WMT_STEP_H_ */
+
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_user_proc.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_user_proc.h
new file mode 100644
index 0000000000000000000000000000000000000000..1bef0e0f78dddee4e3578fb37cbad800e04ffe9c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_user_proc.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ */
+
+#ifndef _WMT_USER_PROC_H_
+#define _WMT_USER_PROC_H_
+#include "osal.h"
+
+typedef INT32(*WMT_DEV_USER_PROC_FUNC) (INT32 par1, INT32 par2, INT32 par3);
+INT32 wmt_dev_user_proc_setup(VOID);
+INT32 wmt_dev_user_proc_remove(VOID);
+
+#endif /* _WMT_USER_PROC_H_ */
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/osal.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/osal.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ef123a87492818c8d6413d27dafba34265cc92d
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/osal.c
@@ -0,0 +1,1823 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file
+ * \brief Declaration of library functions
+ * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack.
+ */
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+
+#include "osal.h"
+#include "connectivity_build_in_adapter.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#define GPIO_ASSERT 70
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/* CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+static UINT16 const crc16_table[256] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+INT32 ftrace_flag;
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+/*string operations*/
+UINT32 osal_strlen(const PINT8 str)
+{
+ return strlen(str);
+}
+
+INT32 osal_strcmp(const PINT8 dst, const PINT8 src)
+{
+ return strcmp(dst, src);
+}
+
+INT32 osal_strncmp(const PINT8 dst, const PINT8 src, UINT32 len)
+{
+ return strncmp(dst, src, len);
+}
+
+PINT8 osal_strcpy(PINT8 dst, const PINT8 src)
+{
+ return strncpy(dst, src, strlen(src)+1);
+}
+
+PINT8 osal_strncpy(PINT8 dst, const PINT8 src, UINT32 len)
+{
+ return strncpy(dst, src, len);
+}
+
+PINT8 osal_strcat(PINT8 dst, const PINT8 src)
+{
+ return strncat(dst, src, strlen(src));
+}
+
+PINT8 osal_strncat(PINT8 dst, const PINT8 src, UINT32 len)
+{
+ return strncat(dst, src, len);
+}
+
+PINT8 osal_strchr(const PINT8 str, UINT8 c)
+{
+ return strchr(str, c);
+}
+
+PINT8 osal_strsep(PPINT8 str, const PINT8 c)
+{
+ return strsep(str, c);
+}
+
+INT32 osal_strtol(const PINT8 str, UINT32 adecimal, PLONG res)
+{
+ if (sizeof(LONG) == 4)
+ return kstrtou32(str, adecimal, (UINT32 *) res);
+ else
+ return kstrtol(str, adecimal, res);
+}
+
+PINT8 osal_strstr(PINT8 str1, const PINT8 str2)
+{
+ return strstr(str1, str2);
+}
+
+PINT8 osal_strnstr(PINT8 str1, const PINT8 str2, INT32 n)
+{
+ return strnstr(str1, str2, n);
+}
+
+VOID osal_bug_on(UINT32 val)
+{
+ WARN_ON(val);
+}
+
+INT32 osal_snprintf(PINT8 buf, UINT32 len, const PINT8 fmt, ...)
+{
+ INT32 iRet = 0;
+ va_list args;
+
+ va_start(args, fmt);
+ iRet = vsnprintf(buf, len, fmt, args);
+ va_end(args);
+
+ if (iRet < 0)
+ pr_info("vsnprintf error:%d\n", iRet);
+
+ return iRet;
+}
+
+INT32 osal_err_print(const PINT8 str, ...)
+{
+ va_list args;
+ INT32 ret;
+ INT8 tempString[DBG_LOG_STR_SIZE];
+
+ va_start(args, str);
+ ret = vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args);
+ va_end(args);
+
+ if (ret > 0)
+ pr_err("%s", tempString);
+
+ return ret;
+}
+
+INT32 osal_dbg_print(const PINT8 str, ...)
+{
+ va_list args;
+ INT32 ret;
+ INT8 tempString[DBG_LOG_STR_SIZE];
+
+ va_start(args, str);
+ ret = vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args);
+ va_end(args);
+
+ if (ret > 0)
+ pr_debug("%s", tempString);
+
+ return ret;
+}
+
+INT32 osal_warn_print(const PINT8 str, ...)
+{
+ va_list args;
+ INT32 ret;
+ INT8 tempString[DBG_LOG_STR_SIZE];
+
+ va_start(args, str);
+ ret = vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args);
+ va_end(args);
+
+ if (ret > 0)
+ pr_warn("%s", tempString);
+
+ return ret;
+}
+
+INT32 osal_dbg_assert(INT32 expr, const PINT8 file, INT32 line)
+{
+ if (!expr) {
+ pr_warn("%s (%d)\n", file, line);
+ /*BUG_ON(!expr); */
+#ifdef CFG_COMMON_GPIO_DBG_PIN
+/* package this part */
+ gpio_direction_output(GPIO_ASSERT, 0);
+ pr_warn("toggle GPIO_ASSERT = %d\n", GPIO_ASSERT);
+ udelay(10);
+ gpio_set_value(GPIO_ASSERT, 1);
+#endif
+ return 1;
+ }
+ return 0;
+
+}
+
+INT32 osal_dbg_assert_aee(const PINT8 module, const PINT8 detail_description, ...)
+{
+ INT8 tempString[DBG_LOG_STR_SIZE];
+ va_list args;
+
+ va_start(args, detail_description);
+ if (vsnprintf(tempString, DBG_LOG_STR_SIZE, detail_description, args) > 0) {
+ osal_err_print("[WMT-ASSERT][E][Module]:%s, [INFO]%s\n", module, tempString);
+#ifdef WMT_PLAT_ALPS
+ /* There exists Format-String vulnerability. For safety, we must use the %s
+ * format parameter to read data.
+ */
+#if IS_ENABLED(CONFIG_MTK_AEE_AED)
+ aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_WCN_ISSUE_INFO, module,
+ detail_description, "%s", tempString);
+#endif
+#endif
+ }
+ va_end(args);
+ return 0;
+}
+
+INT32 osal_sprintf(PINT8 str, const PINT8 format, ...)
+{
+ INT32 iRet = 0;
+ va_list args;
+
+ va_start(args, format);
+ iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args);
+ if (iRet < 0)
+ osal_err_print("vsnprintf error [%d]\n", iRet);
+ va_end(args);
+
+ return iRet;
+}
+
+PVOID osal_malloc(UINT32 size)
+{
+ PVOID p = NULL;
+
+ if (size > (PAGE_SIZE << 1))
+ p = vmalloc(size);
+ else
+ p = kmalloc(size, GFP_KERNEL);
+
+ /* If there is fragment, kmalloc may not get memory when size > one page.
+ * For this case, use vmalloc instead.
+ */
+ if (p == NULL && size > PAGE_SIZE)
+ p = vmalloc(size);
+ return p;
+}
+
+VOID osal_free(const PVOID dst)
+{
+ kvfree(dst);
+}
+
+PVOID osal_memset(PVOID buf, INT32 i, UINT32 len)
+{
+ return memset(buf, i, len);
+}
+
+PVOID osal_memcpy(PVOID dst, const PVOID src, UINT32 len)
+{
+ return memcpy(dst, src, len);
+}
+
+VOID osal_memcpy_fromio(PVOID dst, const PVOID src, UINT32 len)
+{
+ return memcpy_fromio(dst, src, len);
+}
+
+VOID osal_memcpy_toio(PVOID dst, const PVOID src, UINT32 len)
+{
+ return memcpy_toio(dst, src, len);
+}
+
+INT32 osal_memcmp(const PVOID buf1, const PVOID buf2, UINT32 len)
+{
+ return memcmp(buf1, buf2, len);
+}
+
+UINT16 osal_crc16(const PUINT8 buffer, const UINT32 length)
+{
+ UINT16 crc = 0;
+ UINT32 i = 0;
+ PUINT8 temp = buffer;
+
+ /* FIXME: Add STP checksum feature */
+ crc = 0;
+ for (i = 0; i < length; i++, temp++)
+ crc = (crc >> 8) ^ crc16_table[(crc ^ (*temp)) & 0xff];
+ return crc;
+}
+
+VOID osal_dump_thread_state(const PUINT8 name)
+{
+#if defined(KERNEL_dump_thread_state)
+ return KERNEL_dump_thread_state(name);
+#endif
+}
+
+VOID osal_thread_show_stack(P_OSAL_THREAD pThread)
+{
+ if ((pThread) && (pThread->pThread))
+ KERNEL_show_stack(pThread->pThread, NULL);
+}
+
+/*
+ *OSAL layer Thread Opeartion related APIs
+ *
+ *
+*/
+INT32 osal_thread_create(P_OSAL_THREAD pThread)
+{
+ if (!pThread)
+ return -1;
+
+ pThread->pThread = kthread_create(pThread->pThreadFunc, pThread->pThreadData, pThread->threadName);
+ if (pThread->pThread == NULL)
+ return -1;
+
+ return 0;
+}
+
+INT32 osal_thread_run(P_OSAL_THREAD pThread)
+{
+ if ((pThread) && (pThread->pThread)) {
+ wake_up_process(pThread->pThread);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+INT32 osal_thread_stop(P_OSAL_THREAD pThread)
+{
+ INT32 iRet;
+
+ if ((pThread) && (pThread->pThread)) {
+ iRet = kthread_stop(pThread->pThread);
+ /* pThread->pThread = NULL; */
+ return iRet;
+ }
+ return -1;
+}
+
+INT32 osal_thread_should_stop(P_OSAL_THREAD pThread)
+{
+ if ((pThread) && (pThread->pThread))
+ return kthread_should_stop();
+ else
+ return 1;
+
+}
+
+INT32 osal_thread_wait_for_event(P_OSAL_THREAD pThread, P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker)
+{
+ /* P_DEV_WMT pDevWmt;*/
+
+ if ((pThread) && (pThread->pThread) && (pEvent) && (pChecker)) {
+ /* pDevWmt = (P_DEV_WMT)(pThread->pThreadData);*/
+ return wait_event_interruptible(pEvent->waitQueue, (/*!RB_EMPTY(&pDevWmt->rActiveOpQ) || */
+ osal_thread_should_stop(pThread)
+ || (*pChecker) (pThread)));
+ }
+ return -1;
+}
+
+INT32 osal_thread_destroy(P_OSAL_THREAD pThread)
+{
+ if (pThread && (pThread->pThread)) {
+ kthread_stop(pThread->pThread);
+ pThread->pThread = NULL;
+ }
+ return 0;
+}
+
+/*
+ * osal_thread_sched_retrieve
+ * Retrieve thread's current scheduling statistics and stored in output "sched".
+ * Return value:
+ * 0 : Schedstats successfully retrieved
+ * -1 : Kernel's schedstats feature not enabled
+ * -2 : pThread not yet initialized or sched is a NULL pointer
+ */
+static INT32 osal_thread_sched_retrieve(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS sched)
+{
+#ifdef CONFIG_SCHEDSTATS
+ struct sched_entity se;
+ UINT64 sec;
+ ULONG usec;
+
+ if (!sched)
+ return -2;
+
+ /* always clear sched to simplify error handling at caller side */
+ memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS));
+
+ if (!pThread || !pThread->pThread)
+ return -2;
+
+ memcpy(&se, &pThread->pThread->se, sizeof(struct sched_entity));
+ osal_get_local_time(&sec, &usec);
+
+ sched->time = sec*1000 + usec/1000;
+ sched->exec = se.sum_exec_runtime;
+ sched->runnable = se.statistics.wait_sum;
+ sched->iowait = se.statistics.iowait_sum;
+
+ return 0;
+#else
+ /* always clear sched to simplify error handling at caller side */
+ if (sched)
+ memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS));
+ return -1;
+#endif
+}
+
+/*
+ * osal_thread_sched_mark
+ * Record the thread's current schedstats and stored in output "schedstats" parameter for profiling at later time.
+ * Return value:
+ * 0 : Schedstats successfully recorded
+ * -1 : Kernel's schedstats feature not enabled
+ * -2 : pThread not yet initialized or invalid parameters
+ */
+INT32 osal_thread_sched_mark(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS schedstats)
+{
+ return osal_thread_sched_retrieve(pThread, schedstats);
+}
+
+/*
+ * osal_thread_sched_unmark
+ * Calculate scheduling statistics against the previously marked point.
+ * The result will be filled back into the schedstats output parameter.
+ * Return value:
+ * 0 : Schedstats successfully calculated
+ * -1 : Kernel's schedstats feature not enabled
+ * -2 : pThread not yet initialized or invalid parameters
+ */
+INT32 osal_thread_sched_unmark(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS schedstats)
+{
+ INT32 ret;
+ OSAL_THREAD_SCHEDSTATS sched_now;
+
+ if (unlikely(!schedstats)) {
+ ret = -2;
+ } else {
+ ret = osal_thread_sched_retrieve(pThread, &sched_now);
+ if (ret == 0) {
+ schedstats->time = sched_now.time - schedstats->time;
+ schedstats->exec = sched_now.exec - schedstats->exec;
+ schedstats->runnable = sched_now.runnable - schedstats->runnable;
+ schedstats->iowait = sched_now.iowait - schedstats->iowait;
+ }
+ }
+ return ret;
+}
+
+/*
+ *OSAL layer Signal Opeartion related APIs
+ *initialization
+ *wait for signal
+ *wait for signal timerout
+ *raise signal
+ *destroy a signal
+ *
+*/
+
+INT32 osal_signal_init(P_OSAL_SIGNAL pSignal)
+{
+ if (pSignal) {
+ init_completion(&pSignal->comp);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+INT32 osal_wait_for_signal(P_OSAL_SIGNAL pSignal)
+{
+ if (pSignal) {
+ wait_for_completion_interruptible(&pSignal->comp);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * osal_wait_for_signal_timeout
+ *
+ * Wait for a signal to be triggered by the corresponding thread, within the
+ * expected timeout specified by the signal's timeoutValue.
+ * When the pThread parameter is specified, the thread's scheduling ability is
+ * considered, the timeout will be extended when thread cannot acquire CPU
+ * resource, and will only extend for a number of times specified by the
+ * signal's timeoutExtension should the situation continues.
+ *
+ * Return value:
+ * 0 : timeout
+ * >0 : signal triggered
+ */
+INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal, P_OSAL_THREAD pThread)
+{
+ OSAL_THREAD_SCHEDSTATS schedstats;
+ INT32 waitRet;
+
+ /* return wait_for_completion_interruptible_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); */
+ /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS.
+ * Avoid using *interruptible" version in order to complete our jobs, such
+ * as function off gracefully.
+ */
+ if (!pThread || !pThread->pThread)
+ return wait_for_completion_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue));
+
+ do {
+ osal_thread_sched_mark(pThread, &schedstats);
+ waitRet = wait_for_completion_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue));
+ osal_thread_sched_unmark(pThread, &schedstats);
+
+ if (waitRet > 0)
+ break;
+
+ if (schedstats.runnable > schedstats.exec) {
+ osal_err_print(
+ "[E]%s:wait completion timeout, %s cannot get CPU, extension(%d), show backtrace:\n",
+ __func__,
+ pThread->threadName,
+ pSignal->timeoutExtension);
+ } else {
+ osal_err_print("[E]%s:wait completion timeout, show %s backtrace:\n",
+ __func__,
+ pThread->threadName);
+ pSignal->timeoutExtension = 0;
+ }
+ osal_err_print("[E]%s:\tduration:%llums, sched(x%llu/r%llu/i%llu)\n",
+ __func__,
+ schedstats.time,
+ schedstats.exec,
+ schedstats.runnable,
+ schedstats.iowait);
+ /*
+ * no need to disginguish combo or A/D die projects
+ * osal_dump_thread_state will just return if target thread does not exist
+ */
+ osal_dump_thread_state("mtk_wmtd");
+ osal_dump_thread_state("mtk_wmtd_worker");
+ osal_dump_thread_state("btif_rxd");
+ osal_dump_thread_state("mtk_stp_psm");
+ osal_dump_thread_state("mtk_stp_btm");
+ osal_dump_thread_state("stp_sdio_tx_rx");
+ } while (pSignal->timeoutExtension--);
+ return waitRet;
+}
+
+INT32 osal_raise_signal(P_OSAL_SIGNAL pSignal)
+{
+ if (pSignal) {
+ complete(&pSignal->comp);
+ return 0;
+ } else
+ return -1;
+}
+
+INT32 osal_signal_active_state(P_OSAL_SIGNAL pSignal)
+{
+ if (pSignal)
+ return pSignal->timeoutValue;
+ else
+ return -1;
+}
+
+INT32 osal_signal_deinit(P_OSAL_SIGNAL pSignal)
+{
+ if (pSignal) {
+ pSignal->timeoutValue = 0;
+ return 0;
+ } else
+ return -1;
+}
+
+/*
+ *OSAL layer Event Opeartion related APIs
+ *initialization
+ *wait for signal
+ *wait for signal timerout
+ *raise signal
+ *destroy a signal
+ *
+*/
+
+INT32 osal_event_init(P_OSAL_EVENT pEvent)
+{
+ if (pEvent) {
+ init_waitqueue_head(&pEvent->waitQueue);
+ return 0;
+ }
+ return -1;
+}
+
+INT32 osal_trigger_event(P_OSAL_EVENT pEvent)
+{
+ INT32 ret = 0;
+
+ if (pEvent) {
+ wake_up_interruptible(&pEvent->waitQueue);
+ return ret;
+ }
+ return -1;
+}
+
+INT32 osal_wait_for_event(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), PVOID cond_pa)
+{
+ if (pEvent)
+ return wait_event_interruptible(pEvent->waitQueue, condition(cond_pa));
+ else
+ return -1;
+}
+
+INT32 osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), PVOID cond_pa)
+{
+ if (pEvent)
+ return wait_event_interruptible_timeout(pEvent->waitQueue,
+ condition(cond_pa),
+ msecs_to_jiffies(pEvent->timeoutValue));
+ return -1;
+}
+
+
+
+INT32 osal_event_deinit(P_OSAL_EVENT pEvent)
+{
+ return 0;
+}
+
+LONG osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset)
+{
+ UINT32 ms = 0;
+
+ if (pEvent) {
+ ms = pEvent->timeoutValue;
+ if (ms != 0)
+ return wait_event_interruptible_timeout(pEvent->waitQueue,
+ test_bit(bitOffset, pState),
+ msecs_to_jiffies(ms));
+ else
+ return wait_event_interruptible(pEvent->waitQueue,
+ test_bit(bitOffset, pState));
+ } else
+ return -1;
+
+}
+
+LONG osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, PULONG pState, UINT32 bitOffset)
+{
+ UINT32 ms = 0;
+
+ if (pEvent) {
+ ms = pEvent->timeoutValue;
+ if (ms != 0)
+ return wait_event_interruptible_timeout(pEvent->waitQueue,
+ !test_bit(bitOffset, pState),
+ msecs_to_jiffies(ms));
+ else
+ return wait_event_interruptible(pEvent->waitQueue,
+ !test_bit(bitOffset, pState));
+ } else
+ return -1;
+}
+
+/*
+ *bit test and set/clear operations APIs
+ *
+ *
+*/
+#if OS_BIT_OPS_SUPPORT
+#define osal_bit_op_lock(x)
+#define osal_bit_op_unlock(x)
+#else
+
+INT32 osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock)
+{
+
+ return 0;
+}
+
+INT32 osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock)
+{
+
+ return 0;
+}
+#endif
+INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData)
+{
+ if (bitOffset >= BITS_PER_LONG) {
+ pr_info("bitOffset(%d) is out of range.\n", bitOffset);
+ return -1;
+ }
+ osal_bit_op_lock(&(pData->opLock));
+ clear_bit(bitOffset, &pData->data);
+ osal_bit_op_unlock(&(pData->opLock));
+ return 0;
+}
+
+INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData)
+{
+ if (bitOffset >= BITS_PER_LONG) {
+ pr_info("bitOffset(%d) is out of range.\n", bitOffset);
+ return -1;
+ }
+ osal_bit_op_lock(&(pData->opLock));
+ set_bit(bitOffset, &pData->data);
+ osal_bit_op_unlock(&(pData->opLock));
+ return 0;
+}
+
+INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData)
+{
+ UINT32 iRet = 0;
+
+ if (bitOffset >= BITS_PER_LONG) {
+ pr_info("bitOffset(%d) is out of range.\n", bitOffset);
+ return -1;
+ }
+ osal_bit_op_lock(&(pData->opLock));
+ iRet = test_bit(bitOffset, &pData->data);
+ osal_bit_op_unlock(&(pData->opLock));
+ return iRet;
+}
+
+INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData)
+{
+ UINT32 iRet = 0;
+
+ if (bitOffset >= BITS_PER_LONG) {
+ pr_info("bitOffset(%d) is out of range.\n", bitOffset);
+ return -1;
+ }
+ osal_bit_op_lock(&(pData->opLock));
+ iRet = test_and_clear_bit(bitOffset, &pData->data);
+ osal_bit_op_unlock(&(pData->opLock));
+ return iRet;
+
+}
+
+INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData)
+{
+ UINT32 iRet = 0;
+
+ if (bitOffset >= BITS_PER_LONG) {
+ pr_info("bitOffset(%d) is out of range.\n", bitOffset);
+ return -1;
+ }
+ osal_bit_op_lock(&(pData->opLock));
+ iRet = test_and_set_bit(bitOffset, &pData->data);
+ osal_bit_op_unlock(&(pData->opLock));
+ return iRet;
+}
+
+/*
+ *tiemr operations APIs
+ *create
+ *stop
+ * modify
+ *create
+ *delete
+ *
+*/
+
+INT32 osal_timer_create(P_OSAL_TIMER pTimer)
+{
+ struct timer_list *timer = &pTimer->timer;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+ timer_setup(timer, pTimer->timeoutHandler, 0);
+#else
+ init_timer(timer);
+ timer->function = pTimer->timeoutHandler;
+ timer->data = (ULONG)pTimer->timeroutHandlerData;
+#endif
+ return 0;
+}
+
+INT32 osal_timer_start(P_OSAL_TIMER pTimer, UINT32 ms)
+{
+
+ struct timer_list *timer = &pTimer->timer;
+
+ timer->expires = jiffies + (ms / (1000 / HZ));
+ add_timer(timer);
+ return 0;
+}
+
+INT32 osal_timer_stop(P_OSAL_TIMER pTimer)
+{
+ struct timer_list *timer = &pTimer->timer;
+
+ del_timer(timer);
+ return 0;
+}
+
+INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer)
+{
+ struct timer_list *timer = &pTimer->timer;
+
+ del_timer_sync(timer);
+ return 0;
+}
+
+INT32 osal_timer_modify(P_OSAL_TIMER pTimer, UINT32 ms)
+{
+
+ mod_timer(&pTimer->timer, jiffies + (ms) / (1000 / HZ));
+ return 0;
+}
+
+INT32 _osal_fifo_init(OSAL_FIFO *pFifo, PUINT8 buf, UINT32 size)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = -1;
+
+ if (!pFifo) {
+ pr_err("pFifo must be !NULL\n");
+ return -1;
+ }
+ if (pFifo->pFifoBody) {
+ pr_err("pFifo->pFifoBody must be NULL\n");
+ pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", pFifo, pFifo->pFifoBody);
+ return -1;
+ }
+ fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC);
+ if (!buf) {
+ /*fifo's buffer is not ready, we allocate automatically */
+ ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC);
+ } else {
+ if (is_power_of_2(size)) {
+ kfifo_init(fifo, buf, size);
+ ret = 0;
+ } else {
+ kfifo_free(fifo);
+ fifo = NULL;
+ ret = -1;
+ }
+ }
+
+ pFifo->pFifoBody = fifo;
+ return (ret < 0) ? (-1) : (0);
+}
+
+INT32 _osal_fifo_deinit(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ kfifo_free(fifo);
+
+ return 0;
+}
+
+INT32 _osal_fifo_size(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ ret = kfifo_size(fifo);
+
+ return ret;
+}
+
+/*returns unused bytes in fifo*/
+INT32 _osal_fifo_avail_size(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ ret = kfifo_avail(fifo);
+
+ return ret;
+}
+
+/*returns used bytes in fifo*/
+INT32 _osal_fifo_len(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ ret = kfifo_len(fifo);
+
+ return ret;
+}
+
+INT32 _osal_fifo_is_empty(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ ret = kfifo_is_empty(fifo);
+
+ return ret;
+}
+
+INT32 _osal_fifo_is_full(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ ret = kfifo_is_full(fifo);
+
+ return ret;
+}
+
+INT32 _osal_fifo_data_in(OSAL_FIFO *pFifo, const PVOID buf, UINT32 len)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) {
+ ret = kfifo_in(fifo, buf, len);
+ } else {
+ pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n",
+ __func__, len, _osal_fifo_avail_size(pFifo), buf);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+INT32 _osal_fifo_data_out(OSAL_FIFO *pFifo, PVOID buf, UINT32 len)
+{
+ struct kfifo *fifo = NULL;
+ INT32 ret = 0;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo && buf && (len <= _osal_fifo_len(pFifo))) {
+ ret = kfifo_out(fifo, buf, len);
+ } else {
+ pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n",
+ __func__, len, _osal_fifo_len(pFifo), buf);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+INT32 _osal_fifo_reset(OSAL_FIFO *pFifo)
+{
+ struct kfifo *fifo = NULL;
+
+ if (!pFifo || !pFifo->pFifoBody) {
+ pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__);
+ return -1;
+ }
+
+ fifo = (struct kfifo *)pFifo->pFifoBody;
+
+ if (fifo)
+ kfifo_reset(fifo);
+
+ return 0;
+}
+
+INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size)
+{
+ if (!pFifo) {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ return -1;
+ }
+
+ pFifo->FifoInit = _osal_fifo_init;
+ pFifo->FifoDeInit = _osal_fifo_deinit;
+ pFifo->FifoSz = _osal_fifo_size;
+ pFifo->FifoAvailSz = _osal_fifo_avail_size;
+ pFifo->FifoLen = _osal_fifo_len;
+ pFifo->FifoIsEmpty = _osal_fifo_is_empty;
+ pFifo->FifoIsFull = _osal_fifo_is_full;
+ pFifo->FifoDataIn = _osal_fifo_data_in;
+ pFifo->FifoDataOut = _osal_fifo_data_out;
+ pFifo->FifoReset = _osal_fifo_reset;
+
+ if (pFifo->pFifoBody != NULL) {
+ pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__);
+ pFifo->FifoDeInit(pFifo);
+ pFifo->pFifoBody = NULL;
+ }
+
+ pFifo->FifoInit(pFifo, buffer, size);
+
+ return 0;
+}
+
+VOID osal_fifo_deinit(P_OSAL_FIFO pFifo)
+{
+ if (pFifo)
+ pFifo->FifoDeInit(pFifo);
+ else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ return;
+ }
+ kfree(pFifo->pFifoBody);
+ pFifo->pFifoBody = NULL;
+}
+
+INT32 osal_fifo_reset(P_OSAL_FIFO pFifo)
+{
+ INT32 ret = -1;
+
+ if (pFifo) {
+ ret = pFifo->FifoReset(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = -1;
+ }
+ return ret;
+}
+
+UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoDataIn(pFifo, buffer, size);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoDataOut(pFifo, buffer, size);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_len(P_OSAL_FIFO pFifo)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoLen(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoSz(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoAvailSz(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoIsEmpty(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo)
+{
+ UINT32 ret = 0;
+
+ if (pFifo) {
+ ret = pFifo->FifoIsFull(pFifo);
+ } else {
+ pr_err("%s:pFifo = NULL, error\n", __func__);
+ ret = 0;
+ }
+ return ret;
+}
+
+INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock)
+{
+ if (!pLock)
+ return -1;
+
+ if (pLock->init_flag == 0) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 149))
+ pLock->wake_lock = wakeup_source_register(NULL, pLock->name);
+#else
+ pLock->wake_lock = wakeup_source_register(pLock->name);
+#endif
+ pLock->init_flag = 1;
+ }
+
+ return 0;
+}
+
+INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock)
+{
+ if (!pLock)
+ return -1;
+
+ if (pLock->init_flag == 1) {
+ wakeup_source_unregister(pLock->wake_lock);
+ pLock->init_flag = 0;
+ } else
+ pr_info("%s: wake_lock is not initialized!\n", __func__);
+
+ return 0;
+}
+
+INT32 osal_wake_lock(P_OSAL_WAKE_LOCK pLock)
+{
+ if (!pLock)
+ return -1;
+
+ if (pLock->init_flag == 1)
+ __pm_stay_awake(pLock->wake_lock);
+ else
+ pr_info("%s: wake_lock is not initialized!\n", __func__);
+
+ return 0;
+}
+
+INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK pLock)
+{
+ if (!pLock)
+ return -1;
+
+ if (pLock->init_flag == 1)
+ __pm_relax(pLock->wake_lock);
+ else
+ pr_info("%s: wake_lock is not initialized!\n", __func__);
+
+ return 0;
+
+}
+
+INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock)
+{
+ INT32 count = 0;
+
+ if (!pLock)
+ return -1;
+
+ if (pLock->init_flag == 1)
+ count = pLock->wake_lock->active;
+ else
+ pr_info("%s: wake_lock is not initialized!\n", __func__);
+
+ return count;
+}
+
+/*
+ *sleepable lock operations APIs
+ *init
+ *lock
+ *unlock
+ *destroy
+ *
+*/
+
+#if !defined(CONFIG_PROVE_LOCKING)
+INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL)
+{
+ spin_lock_init(&(pUSL->lock));
+ return 0;
+}
+#endif
+
+INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL)
+{
+ spin_lock_irqsave(&(pUSL->lock), pUSL->flag);
+ return 0;
+}
+
+INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL)
+{
+ spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag);
+ return 0;
+}
+
+INT32 osal_trylock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL)
+{
+ return spin_trylock_irqsave(&(pUSL->lock), pUSL->flag);
+}
+
+INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL)
+{
+ return 0;
+}
+
+/*
+ *unsleepable operations APIs
+ *init
+ *lock
+ *unlock
+ *destroy
+
+ *
+*/
+
+#if !defined(CONFIG_PROVE_LOCKING)
+INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL)
+{
+ mutex_init(&pSL->lock);
+ return 0;
+}
+#endif
+
+INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL)
+{
+ return mutex_lock_killable(&pSL->lock);
+}
+
+INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL)
+{
+ mutex_unlock(&pSL->lock);
+ return 0;
+}
+
+INT32 osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL)
+{
+ return mutex_trylock(&pSL->lock);
+}
+
+INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL)
+{
+ mutex_destroy(&pSL->lock);
+ return 0;
+}
+
+INT32 osal_sleep_ms(UINT32 ms)
+{
+ msleep(ms);
+ return 0;
+}
+
+INT32 osal_udelay(UINT32 us)
+{
+ udelay(us);
+ return 0;
+}
+
+INT32 osal_usleep_range(ULONG min, ULONG max)
+{
+ usleep_range(min, max);
+ return 0;
+}
+
+INT32 osal_gettimeofday(PINT32 sec, PINT32 usec)
+{
+ INT32 ret = 0;
+ struct timeval now;
+
+ osal_do_gettimeofday(&now);
+
+ if (sec != NULL)
+ *sec = now.tv_sec;
+ else
+ ret = -1;
+
+ if (usec != NULL)
+ *usec = now.tv_usec;
+ else
+ ret = -1;
+
+ return ret;
+}
+
+void osal_do_gettimeofday(struct timeval *tv)
+{
+ struct timespec64 now;
+
+ ktime_get_real_ts64(&now);
+ tv->tv_sec = now.tv_sec;
+ tv->tv_usec = now.tv_nsec / NSEC_PER_USEC;
+}
+
+INT32 osal_printtimeofday(const PUINT8 prefix)
+{
+ INT32 ret;
+ INT32 sec;
+ INT32 usec;
+
+ ret = osal_gettimeofday(&sec, &usec);
+ ret += osal_dbg_print("%s>sec=%d, usec=%d\n", prefix, sec, usec);
+
+ return ret;
+}
+
+VOID osal_get_local_time(PUINT64 sec, PULONG nsec)
+{
+ if (sec != NULL && nsec != NULL) {
+ *sec = local_clock();
+ *nsec = do_div(*sec, 1000000000)/1000;
+ } else
+ pr_err("The input parameters error when get local time\n");
+}
+
+UINT64 osal_elapsed_us(UINT64 ts, ULONG usec)
+{
+ UINT64 current_ts = 0;
+ ULONG current_usec = 0;
+
+ osal_get_local_time(¤t_ts, ¤t_usec);
+ return (current_ts*1000000 + current_usec) - (ts*1000000 + usec);
+}
+
+VOID osal_buffer_dump(const PUINT8 buf, const PUINT8 title, const UINT32 len, const UINT32 limit)
+{
+ INT32 k;
+ UINT32 dump_len;
+ char str[DBG_LOG_STR_SIZE] = {""};
+ INT32 strlen = 0;
+ char *p = NULL;
+
+ pr_info("[%s] len=%d, limit=%d, start dump\n", title, len, limit);
+
+ dump_len = ((limit != 0) && (len > limit)) ? limit : len;
+ p = str;
+ for (k = 0; k < dump_len; k++) {
+ if ((k+1) % 16 != 0) {
+ strlen = osal_sprintf(p, "%02x ", buf[k]);
+ p += strlen;
+ } else {
+ strlen = osal_sprintf(p, "%02x\n", buf[k]);
+ pr_info("%s", str);
+ p = str;
+ }
+ }
+ if (k % 16 != 0)
+ pr_info("%s\n", str);
+
+ pr_info("end of dump\n");
+}
+
+VOID osal_buffer_dump_data(const PUINT32 buf, const PUINT8 title, const UINT32 len, const UINT32 limit,
+ const INT32 flag)
+{
+ INT32 k;
+ UINT32 dump_len;
+ char str[DBG_LOG_STR_SIZE] = {""};
+ INT32 strlen = 0;
+ char *p = NULL;
+ INT32 count = 0;
+
+ dump_len = ((limit != 0) && (len > limit)) ? limit : len;
+ p = str;
+ for (k = 0; k < dump_len; k++) {
+ count++;
+ if (count % 8 != 0) {
+ strlen = osal_sprintf(p, "0x%08x,", buf[k]);
+ p += strlen;
+ } else {
+ strlen = osal_sprintf(p, "0x%08x\n", buf[k]);
+ if (flag)
+ osal_ftrace_print("%s%s", title, str);
+ else
+ pr_info("%s%s", title, str);
+ p = str;
+ }
+ }
+ if (count % 8 != 0) {
+ if (flag)
+ osal_ftrace_print("%s%s\n", title, str);
+ else
+ pr_info("%s%s\n", title, str);
+ }
+}
+
+UINT32 osal_op_get_id(P_OSAL_OP pOp)
+{
+ return (pOp) ? pOp->op.opId : 0xFFFFFFFF;
+}
+
+MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp)
+{
+ return (pOp && pOp->signal.timeoutValue) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE;
+}
+
+VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result)
+{
+ if (pOp) {
+ pOp->result = result;
+ osal_raise_signal(&pOp->signal);
+ }
+}
+
+INT32 osal_ftrace_print(const PINT8 str, ...)
+{
+ int ret = 0;
+#ifdef CONFIG_TRACING
+ va_list args;
+ INT8 tempString[DBG_LOG_STR_SIZE];
+
+ if (ftrace_flag) {
+ va_start(args, str);
+ ret = vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args);
+ va_end(args);
+
+ if (ret > 0)
+ trace_printk("%s\n", tempString);
+ }
+#endif
+ return ret;
+}
+
+INT32 osal_ftrace_print_ctrl(INT32 flag)
+{
+#ifdef CONFIG_TRACING
+ if (flag)
+ ftrace_flag = 1;
+ else
+ ftrace_flag = 0;
+#endif
+ return 0;
+}
+
+VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result)
+{
+ if (pOp)
+ pOp->result = result;
+
+}
+
+static VOID _osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ)
+{
+ /* Line format:
+ * [LogicalIdx(PhysicalIdx)]Address:OpId(Ref)(Result)-Info-OpData0,OpData1,OpData2,OpData3,OpData5_
+ * [LogicalIdx] max 10+2=12 chars (decimal)
+ * (PhysicalIdx) max 10+2=12 chars (decimal)
+ * Address: max 16+1=17 chars (hex)
+ * OpId max 10 chars (decimal)
+ * (Ref) max 2+2=4 chars (should only be 1 digit, reserve 2 in case of negative number)
+ * (Result) max 11+2=13 chars (signed decimal)
+ * -Info- max 8+2=10 chars (hex)
+ * OpData, max 16+1=17 chars (hex)
+ */
+#define OPQ_DUMP_OP_PER_LINE 1
+#define OPQ_DUMP_OPDATA_PER_OP 6
+#define OPQ_DUMP_OP_BUF_SIZE (12 + 12 + 17 + 10 + 4 + 13 + 10 + (17 * (OPQ_DUMP_OPDATA_PER_OP)) + 1)
+#define OPQ_DUMP_LINE_BUF_SIZE ((OPQ_DUMP_OP_BUF_SIZE * OPQ_DUMP_OP_PER_LINE) + 1)
+ UINT32 rd;
+ UINT32 wt;
+ UINT32 idx = 0;
+ UINT32 opDataIdx;
+ UINT32 idxInBuf;
+ int printed;
+ P_OSAL_OP op;
+ char buf[OPQ_DUMP_LINE_BUF_SIZE];
+
+ rd = pOpQ->read;
+ wt = pOpQ->write;
+
+ pr_info("%s(%p), sz:%u/%u, rd:%u, wt:%u\n", qName, pOpQ, RB_COUNT(pOpQ), RB_SIZE(pOpQ), rd, wt);
+ while (rd != wt && idx < RB_SIZE(pOpQ)) {
+ idxInBuf = idx % OPQ_DUMP_OP_PER_LINE;
+ op = pOpQ->queue[rd & RB_MASK(pOpQ)];
+
+ if (idxInBuf == 0) {
+ printed = 0;
+ buf[0] = 0;
+ }
+
+ if (op) {
+ printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed,
+ "[%u(%u)]%p:%u(%d)(%d)-%u-",
+ idx,
+ (rd & RB_MASK(pOpQ)),
+ op,
+ op->op.opId,
+ atomic_read(&op->ref_count),
+ op->result,
+ op->op.u4InfoBit);
+ for (opDataIdx = 0; opDataIdx < OPQ_DUMP_OPDATA_PER_OP; opDataIdx++)
+ printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed,
+ "%zx,", op->op.au4OpData[opDataIdx]);
+ if (printed > 0)
+ buf[printed-1] = ' ';
+ } else {
+ printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed,
+ "[%u(%u)]%p ", idx, (rd & RB_MASK(pOpQ)), op);
+ }
+ if (printed < 1 || printed >= (sizeof(buf) - 1))
+ return;
+
+ buf[printed++] = ' ';
+
+ if (idxInBuf == OPQ_DUMP_OP_PER_LINE - 1 || rd == wt - 1) {
+ buf[printed - 1] = 0;
+ pr_info("%s\n", buf);
+ }
+ rd++;
+ idx++;
+ }
+}
+
+VOID osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ)
+{
+ int err;
+
+ err = osal_lock_sleepable_lock(&pOpQ->sLock);
+ if (err) {
+ pr_info("Failed to lock queue (%d)\n", err);
+ return;
+ }
+
+ _osal_opq_dump(qName, pOpQ);
+
+ osal_unlock_sleepable_lock(&pOpQ->sLock);
+}
+
+VOID osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ)
+{
+ _osal_opq_dump(qName, pOpQ);
+}
+
+MTK_WCN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp)
+{
+ UINT32 rd;
+ UINT32 wt;
+ P_OSAL_OP op;
+
+ rd = pOpQ->read;
+ wt = pOpQ->write;
+
+ while (rd != wt) {
+ op = pOpQ->queue[rd & RB_MASK(pOpQ)];
+ if (op == pOp)
+ return MTK_WCN_BOOL_TRUE;
+ rd++;
+ }
+ return MTK_WCN_BOOL_FALSE;
+}
+
+static VOID osal_op_history_print_work(struct work_struct *work)
+{
+ struct osal_op_history *log_history = container_of(work, struct osal_op_history, dump_work);
+ struct ring *ring_buffer = &log_history->dump_ring_buffer;
+ struct ring_segment seg;
+ struct osal_op_history_entry *queue = ring_buffer->base;
+ struct osal_op_history_entry *entry = NULL;
+ INT32 index = 0;
+
+ if (queue == NULL) {
+ pr_info("queue shouldn't be NULL, %s", log_history->name);
+ return;
+ }
+
+ RING_READ_FOR_EACH_ITEM(RING_SIZE(ring_buffer), seg, ring_buffer) {
+ index = seg.ring_pt - ring_buffer->base;
+ entry = &queue[index];
+ pr_info("(%llu.%06lu) %s: pOp(%p):%u(%d)-%x-%zx,%zx,%zx,%zx\n",
+ entry->ts,
+ entry->usec,
+ log_history->name,
+ entry->opbuf_address,
+ entry->op_id,
+ entry->opbuf_ref_count,
+ entry->op_info_bit,
+ entry->param_0,
+ entry->param_1,
+ entry->param_2,
+ entry->param_3);
+ }
+ kfree(queue);
+ ring_buffer->base = NULL;
+}
+
+VOID osal_op_history_init(struct osal_op_history *log_history, INT32 queue_size)
+{
+ int size = queue_size * sizeof(struct osal_op_history_entry);
+
+ spin_lock_init(&(log_history->lock));
+
+ log_history->queue = kzalloc(size, GFP_ATOMIC);
+ if (log_history->queue == NULL)
+ return;
+
+ /* queue_size must be power of 2 */
+ ring_init(
+ &log_history->queue,
+ queue_size,
+ 0,
+ 0,
+ &log_history->ring_buffer);
+
+ INIT_WORK(&log_history->dump_work, osal_op_history_print_work);
+}
+
+VOID osal_op_history_print(struct osal_op_history *log_history, PINT8 name)
+{
+ struct osal_op_history_entry *queue = NULL;
+ struct ring *ring_buffer = NULL, *dump_ring_buffer = NULL;
+ INT32 queue_size;
+ ULONG flags;
+ struct work_struct *work = &log_history->dump_work;
+ spinlock_t *lock = &(log_history->lock);
+
+ if (log_history->queue == NULL) {
+ pr_info("Queue is NULL, name: %s\n", name);
+ return;
+ }
+
+ spin_lock_irqsave(lock, flags);
+ ring_buffer = &log_history->ring_buffer;
+ queue_size = sizeof(struct osal_op_history_entry)
+ * RING_SIZE(ring_buffer);
+
+ /* Allocate memory before getting lock to save time of holding lock */
+ queue = kmalloc(queue_size, GFP_ATOMIC);
+ if (queue == NULL) {
+ spin_unlock_irqrestore(lock, flags);
+ return;
+ }
+ dump_ring_buffer = &log_history->dump_ring_buffer;
+
+ if (dump_ring_buffer->base != NULL) {
+ spin_unlock_irqrestore(lock, flags);
+ kfree(queue);
+ pr_info("print is ongoing: %s\n", name);
+ return;
+ }
+
+ osal_snprintf(log_history->name, sizeof(log_history->name), "%s", name);
+ osal_memcpy(queue, log_history->queue, queue_size);
+ osal_memcpy(dump_ring_buffer, ring_buffer, sizeof(struct ring));
+ /* assign value to base after memory copy */
+ dump_ring_buffer->base = queue;
+ spin_unlock_irqrestore(lock, flags);
+ schedule_work(work);
+}
+
+VOID osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp)
+{
+ struct osal_op_history_entry *entry = NULL;
+ struct ring_segment seg;
+ INT32 index;
+ UINT64 sec = 0;
+ ULONG usec = 0;
+ ULONG flags;
+
+ if (log_history->queue == NULL)
+ return;
+
+ osal_get_local_time(&sec, &usec);
+
+ spin_lock_irqsave(&(log_history->lock), flags);
+ RING_OVERWRITE_FOR_EACH(1, seg, &log_history->ring_buffer) {
+ index = seg.ring_pt - log_history->ring_buffer.base;
+ entry = &log_history->queue[index];
+ }
+
+ if (entry == NULL) {
+ pr_info("Entry is null, size %d\n", RING_SIZE(&log_history->ring_buffer));
+ spin_unlock_irqrestore(&(log_history->lock), flags);
+ return;
+ }
+
+ entry->opbuf_address = pOp;
+ entry->op_id = pOp->op.opId;
+ entry->opbuf_ref_count = atomic_read(&pOp->ref_count);
+ entry->op_info_bit = pOp->op.u4InfoBit;
+ entry->param_0 = pOp->op.au4OpData[0];
+ entry->param_1 = pOp->op.au4OpData[1];
+ entry->param_2 = pOp->op.au4OpData[2];
+ entry->param_3 = pOp->op.au4OpData[3];
+ entry->ts = sec;
+ entry->usec = usec;
+ spin_unlock_irqrestore(&(log_history->lock), flags);
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d26156b878f6d765ff3b7ded0afd133ccee4990
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*file: stp_btif, mainly control stp & btif interaction*/
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[STP-BTIF]"
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include "osal_typedef.h"
+#include "wmt_exp.h"
+#include "stp_exp.h"
+#include "stp_btif.h"
+
+#include
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+#define BTIF_OWNER_NAME "CONSYS_STP"
+
+#define STP_MAX_PACKAGE_ALLOWED (2000)
+
+#define STP_BTIF_TX_RTY_LMT (10)
+#define STP_BTIF_TX_RTY_DLY (5)
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+struct stp_btif g_stp_btif;
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/*******************************************************************************
+* 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
+********************************************************************************
+*/
+
+INT32 mtk_wcn_consys_stp_btif_open(VOID)
+{
+ INT32 iRet = -1;
+ P_OSAL_THREAD thread = &g_stp_btif.btif_thread;
+
+ iRet = mtk_wcn_btif_open(BTIF_OWNER_NAME, &g_stp_btif.stpBtifId);
+ if (iRet) {
+ WMT_WARN_FUNC("STP open btif fail(%d)\n", iRet);
+ return -1;
+ }
+ WMT_DBG_FUNC("STP open bitf OK\n");
+
+ thread->pThread = mtk_btif_exp_rx_thread_get(g_stp_btif.stpBtifId);
+ if (!thread->pThread) {
+ WMT_INFO_FUNC("thread->pThread is NULL\n");
+ return -1;
+ }
+
+ osal_strncpy(thread->threadName, thread->pThread->comm, sizeof(thread->pThread->comm));
+ mtk_wcn_stp_register_if_tx(STP_BTIF_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_consys_stp_btif_tx);
+ mtk_wcn_stp_register_rx_has_pending_data(STP_BTIF_IF_TX,
+ (MTK_WCN_STP_RX_HAS_PENDING_DATA) mtk_wcn_consys_stp_btif_rx_has_pending_data);
+ mtk_wcn_stp_register_tx_has_pending_data(STP_BTIF_IF_TX,
+ (MTK_WCN_STP_TX_HAS_PENDING_DATA) mtk_wcn_consys_stp_btif_tx_has_pending_data);
+ mtk_wcn_stp_register_rx_thread_get(STP_BTIF_IF_TX,
+ (MTK_WCN_STP_RX_THREAD_GET) mtk_wcn_consys_stp_btif_rx_thread_get);
+
+ return 0;
+}
+
+INT32 mtk_wcn_consys_stp_btif_close(VOID)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId)
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ else {
+ iRet = mtk_wcn_btif_close(g_stp_btif.stpBtifId);
+ if (iRet) {
+ WMT_WARN_FUNC("STP close btif fail(%d)\n", iRet);
+ iRet = -2;
+ } else {
+ g_stp_btif.stpBtifId = 0;
+ WMT_DBG_FUNC("STP close btif OK\n");
+ }
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference\n!");
+ if (rx_cb)
+ iRet = -1;
+ } else {
+ iRet = mtk_wcn_btif_rx_cb_register(g_stp_btif.stpBtifId, rx_cb);
+ if (iRet) {
+ WMT_WARN_FUNC("STP register rxcb to btif fail(%d)\n", iRet);
+ iRet = -2;
+ } else
+ WMT_DBG_FUNC("STP register rxcb to btif OK\n");
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_tx(const PUINT8 pBuf, const UINT32 len, PUINT32 written_len)
+{
+ INT32 retry_left = STP_BTIF_TX_RTY_LMT;
+ INT32 wr_count = 0;
+ INT32 written = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ return -1;
+ }
+
+ if (len == 0) {
+ *written_len = 0;
+ WMT_INFO_FUNC("special case for STP-CORE,pbuf(%p)\n", pBuf);
+ return 0;
+ }
+
+ *written_len = 0;
+
+ if (len > STP_MAX_PACKAGE_ALLOWED) {
+ WMT_WARN_FUNC("abnormal pacage length,len(%d),pid[%d/%s]\n", len, current->pid, current->comm);
+ return -2;
+ }
+ wr_count = mtk_wcn_btif_write(g_stp_btif.stpBtifId, pBuf, len);
+
+ if (wr_count < 0) {
+ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)\n", wr_count);
+ *written_len = 0;
+ return -3;
+ }
+ if (wr_count == len) {
+ /*perfect case */
+ *written_len = wr_count;
+ return wr_count;
+ }
+
+ while ((retry_left--) && (wr_count < len)) {
+ osal_sleep_ms(STP_BTIF_TX_RTY_DLY);
+ written = mtk_wcn_btif_write(g_stp_btif.stpBtifId, pBuf + wr_count, len - wr_count);
+ if (written < 0) {
+ WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)when do recovered\n", written);
+ break;
+ }
+ wr_count += written;
+ }
+
+ if (wr_count == len) {
+ WMT_INFO_FUNC("recovered,len(%d),retry_left(%d)\n", len, retry_left);
+ /*recovered case */
+ *written_len = wr_count;
+ return wr_count;
+ }
+
+ WMT_ERR_FUNC("stp btif write fail,len(%d),written(%d),retry_left(%d),pid[%d/%s]\n",
+ len, wr_count, retry_left, current->pid, current->comm);
+ *written_len = 0;
+
+ return -wr_count;
+}
+
+INT32 mtk_wcn_consys_stp_btif_rx(PUINT8 pBuf, UINT32 len)
+{
+ return 0;
+}
+
+INT32 mtk_wcn_consys_stp_btif_wakeup(VOID)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ iRet = -1;
+ } else {
+ iRet = mtk_wcn_btif_wakeup_consys(g_stp_btif.stpBtifId);
+ if (iRet) {
+ WMT_WARN_FUNC("STP btif wakeup consys fail(%d)\n", iRet);
+ iRet = -2;
+ } else
+ WMT_DBG_FUNC("STP btif wakeup consys ok\n");
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(UINT32 en_flag)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ iRet = -1;
+ } else {
+ mtk_wcn_btif_dpidle_ctrl(g_stp_btif.stpBtifId, (enum _ENUM_BTIF_DPIDLE_) en_flag);
+ WMT_DBG_FUNC("stp btif dpidle ctrl done,en_flag(%d)\n", en_flag);
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ iRet = -1;
+ } else {
+ iRet = mtk_wcn_btif_loopback_ctrl(g_stp_btif.stpBtifId, mode);
+ if (iRet) {
+ WMT_WARN_FUNC("STP btif lpbk ctrl fail(%d)\n", iRet);
+ iRet = -2;
+ } else
+ WMT_INFO_FUNC("stp btif lpbk ctrl ok,mode(%d)\n", mode);
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag)
+{
+ INT32 iRet = 0;
+
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ iRet = -1;
+ } else {
+ iRet = mtk_wcn_btif_dbg_ctrl(g_stp_btif.stpBtifId, flag);
+ if (iRet) {
+ WMT_WARN_FUNC("STP btif log dbg ctrl fail(%d)\n", iRet);
+ iRet = -2;
+ } else
+ WMT_INFO_FUNC("stp btif log dbg ctrl ok,flag(%d)\n", flag);
+ }
+
+ return iRet;
+}
+
+INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const PUINT8 str, UINT32 len)
+{
+ if (!g_stp_btif.stpBtifId) {
+ WMT_WARN_FUNC("NULL BTIF ID reference!\n");
+ return -1;
+ } else
+ return (INT32) mtk_wcn_btif_parser_wmt_evt(g_stp_btif.stpBtifId, str, len);
+}
+
+INT32 mtk_wcn_consys_stp_btif_rx_has_pending_data(VOID)
+{
+ return mtk_btif_exp_rx_has_pending_data(g_stp_btif.stpBtifId);
+}
+
+INT32 mtk_wcn_consys_stp_btif_tx_has_pending_data(VOID)
+{
+ return mtk_btif_exp_tx_has_pending_data(g_stp_btif.stpBtifId);
+}
+
+P_OSAL_THREAD mtk_wcn_consys_stp_btif_rx_thread_get(VOID)
+{
+ return &g_stp_btif.btif_thread;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c
new file mode 100644
index 0000000000000000000000000000000000000000..b8206d50474cd73627daed652e9970fdb2fdc28c
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c
@@ -0,0 +1,2906 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include /* GFP_KERNEL */
+#include /* init_timer, add_time, del_timer_sync */
+#include /* gettimeofday */
+#include
+#include /* kzalloc */
+#include /* task's status */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "osal.h"
+#include "stp_dbg.h"
+#include "stp_dbg_combo.h"
+#include "stp_dbg_soc.h"
+/* #include "stp_btm.h" */
+#include "btm_core.h"
+#include "wmt_plat.h"
+#include "wmt_detect.h"
+#include "stp_sdio.h"
+#include "stp_core.h"
+#include "mtk_wcn_consys_hw.h"
+#include "wmt_lib.h"
+
+
+UINT32 gStpDbgLogOut;
+UINT32 gStpDbgDumpType = STP_DBG_PKT;
+INT32 gStpDbgDbgLevel = STP_DBG_LOG_INFO;
+static CONSYS_STATE_DMP_INFO g_dmp_info;
+
+MTKSTP_DBG_T *g_stp_dbg;
+
+static OSAL_SLEEPABLE_LOCK g_dbg_nl_lock;
+
+#define STP_DBG_FAMILY_NAME "STP_DBG"
+#define MAX_BIND_PROCESS (4)
+#ifdef WMT_PLAT_ALPS
+#ifndef LOG_STP_DEBUG_DISABLE
+#define STP_DBG_AEE_EXP_API (1)
+#else
+#define STP_DBG_AEE_EXP_API (0)
+#endif
+#else
+#define STP_DBG_AEE_EXP_API (0)
+#endif
+
+#define STP_MAGIC_NUM (0xDEADFEED)
+
+#ifndef GENL_ID_GENERATE
+#define GENL_ID_GENERATE 0
+#endif
+
+enum {
+ __STP_DBG_ATTR_INVALID,
+ STP_DBG_ATTR_MSG,
+ __STP_DBG_ATTR_MAX,
+};
+#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1)
+
+enum {
+ __STP_DBG_COMMAND_INVALID,
+ STP_DBG_COMMAND_BIND,
+ STP_DBG_COMMAND_RESET,
+ __STP_DBG_COMMAND_MAX,
+};
+#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1)
+
+/* attribute policy */
+static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = {
+ [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING},
+};
+
+static UINT32 stp_dbg_seqnum;
+static INT32 num_bind_process;
+static pid_t bind_pid[MAX_BIND_PROCESS];
+static P_WCN_CORE_DUMP_T g_core_dump;
+static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr;
+/* just show in log at present */
+static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs;
+
+static VOID stp_dbg_core_dump_timeout_handler(timer_handler_arg arg);
+static VOID stp_dbg_dump_emi_timeout_handler(timer_handler_arg arg);
+static _osal_inline_ P_WCN_CORE_DUMP_T stp_dbg_core_dump_init(UINT32 timeout);
+static _osal_inline_ INT32 stp_dbg_core_dump_deinit(P_WCN_CORE_DUMP_T dmp);
+static _osal_inline_ INT32 stp_dbg_core_dump_check_end(PUINT8 buf, INT32 len);
+static _osal_inline_ INT32 stp_dbg_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len);
+static _osal_inline_ INT32 stp_dbg_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp);
+static _osal_inline_ INT32 stp_dbg_core_dump_out(P_WCN_CORE_DUMP_T dmp, PPUINT8 pbuf, PINT32 plen);
+static _osal_inline_ INT32 stp_dbg_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout);
+static _osal_inline_ INT32 stp_dbg_core_dump_nl(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len);
+static _osal_inline_ UINT32 stp_dbg_get_chip_id(VOID);
+static _osal_inline_ INT32 stp_dbg_gzip_compressor(PVOID worker, PUINT8 in_buf, INT32 in_sz, PUINT8 out_buf,
+ PINT32 out_sz, INT32 finish);
+static _osal_inline_ P_WCN_COMPRESSOR_T stp_dbg_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz);
+static _osal_inline_ INT32 stp_dbg_compressor_deinit(P_WCN_COMPRESSOR_T cprs);
+static _osal_inline_ INT32 stp_dbg_compressor_in(P_WCN_COMPRESSOR_T cprs,
+ PUINT8 buf, INT32 len, INT32 is_iobuf, INT32 finish);
+static _osal_inline_ INT32 stp_dbg_compressor_out(P_WCN_COMPRESSOR_T cprs, PPUINT8 pbuf, PINT32 plen);
+static _osal_inline_ INT32 stp_dbg_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type);
+static _osal_inline_ VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len);
+static _osal_inline_ INT32 stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len);
+static _osal_inline_ INT32 stp_dbg_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg);
+static _osal_inline_ INT32 stp_dbg_get_avl_entry_num(MTKSTP_DBG_T *stp_dbg);
+static _osal_inline_ INT32 stp_dbg_fill_hdr(STP_DBG_HDR_T *hdr, INT32 type, INT32 ack, INT32 seq,
+ INT32 crc, INT32 dir, INT32 len, INT32 dbg_type);
+static _osal_inline_ INT32 stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, STP_DBG_HDR_T *hdr, const PUINT8 body);
+static INT32 stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info);
+static INT32 stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info);
+static _osal_inline_ INT32 stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type);
+static _osal_inline_ P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID);
+static _osal_inline_ VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr);
+static _osal_inline_ P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID);
+static _osal_inline_ VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs);
+
+INT32 __weak mtk_btif_rxd_be_blocked_flag_get(VOID)
+{
+ STP_DBG_PR_INFO("mtk_btif_rxd_be_blocked_flag_get is not define!!!\n");
+ return 0;
+}
+
+/* operation definition */
+static struct genl_ops stp_dbg_gnl_ops_array[] = {
+ {
+ .cmd = STP_DBG_COMMAND_BIND,
+ .flags = 0,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
+ .policy = stp_dbg_genl_policy,
+#endif
+ .doit = stp_dbg_nl_bind,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = STP_DBG_COMMAND_RESET,
+ .flags = 0,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
+ .policy = stp_dbg_genl_policy,
+#endif
+ .doit = stp_dbg_nl_reset,
+ .dumpit = NULL,
+ },
+};
+
+static struct genl_family stp_dbg_gnl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = STP_DBG_FAMILY_NAME,
+ .version = 1,
+ .maxattr = STP_DBG_ATTR_MAX,
+ .ops = stp_dbg_gnl_ops_array,
+ .n_ops = ARRAY_SIZE(stp_dbg_gnl_ops_array),
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
+ .policy = stp_dbg_genl_policy,
+#endif
+};
+/* stp_dbg_core_dump_timeout_handler - handler of coredump timeout
+ * @ data - core dump object's pointer
+ *
+ * No return value
+ */
+static VOID stp_dbg_core_dump_timeout_handler(timer_handler_arg arg)
+{
+ stp_dbg_set_coredump_timer_state(CORE_DUMP_TIMEOUT);
+ stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm);
+ STP_DBG_PR_WARN(" coredump timer timeout, coredump maybe not finished successfully\n");
+}
+
+/* stp_dbg_dump_emi_timeout_handler - handler of emi dump timeout
+ * @ data - core dump object's pointer
+ *
+ * No return value
+ */
+static VOID stp_dbg_dump_emi_timeout_handler(timer_handler_arg arg)
+{
+ STP_DBG_PR_ERR("dump emi timeout!\n");
+ mtk_stp_notify_emi_dump_end();
+}
+
+/* stp_dbg_core_dump_init - create core dump sys
+ * @ packet_num - core dump packet number unit 32k
+ * @ timeout - core dump time out value
+ *
+ * Return object pointer if success, else NULL
+ */
+static _osal_inline_ P_WCN_CORE_DUMP_T stp_dbg_core_dump_init(UINT32 timeout)
+{
+ P_WCN_CORE_DUMP_T core_dmp = NULL;
+
+ core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T));
+ if (!core_dmp) {
+ STP_DBG_PR_ERR("alloc mem failed!\n");
+ return NULL;
+ }
+
+ osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T));
+
+ core_dmp->dmp_timer.timeoutHandler = stp_dbg_core_dump_timeout_handler;
+ core_dmp->dmp_timer.timeroutHandlerData = (ULONG)core_dmp;
+ osal_timer_create(&core_dmp->dmp_timer);
+ core_dmp->timeout = timeout;
+ core_dmp->dmp_emi_timer.timeoutHandler = stp_dbg_dump_emi_timeout_handler;
+ core_dmp->dmp_emi_timer.timeroutHandlerData = (ULONG)core_dmp;
+ osal_timer_create(&core_dmp->dmp_emi_timer);
+
+ osal_sleepable_lock_init(&core_dmp->dmp_lock);
+
+ core_dmp->sm = CORE_DUMP_INIT;
+ STP_DBG_PR_INFO("create coredump object OK!\n");
+
+ return core_dmp;
+}
+
+
+/* stp_dbg_core_dump_deinit - destroy core dump object
+ * @ dmp - pointer of object
+ *
+ * Retunr 0 if success, else error code
+ */
+static _osal_inline_ INT32 stp_dbg_core_dump_deinit(P_WCN_CORE_DUMP_T dmp)
+{
+ if (dmp) {
+ if (dmp->p_head != NULL) {
+ osal_free(dmp->p_head);
+ dmp->p_head = NULL;
+ }
+ osal_sleepable_lock_deinit(&dmp->dmp_lock);
+ osal_timer_stop(&dmp->dmp_timer);
+ osal_timer_stop(&dmp->dmp_emi_timer);
+ osal_free(dmp);
+ dmp = NULL;
+ }
+
+ return 0;
+}
+
+INT32 stp_dbg_core_dump_deinit_gcoredump(VOID)
+{
+ stp_dbg_core_dump_deinit(g_core_dump);
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_dbg_core_dump_check_end(PUINT8 buf, INT32 len)
+{
+ if (strnstr(buf, "coredump end", len))
+ return 1;
+ else
+ return 0;
+}
+
+static UINT32 stp_dbg_core_dump_header_init(P_WCN_CORE_DUMP_T dmp)
+{
+ dmp->head_len = 0;
+ if (dmp->p_head == NULL) {
+ dmp->p_head = osal_malloc(MAX_DUMP_HEAD_LEN);
+ if (dmp->p_head == NULL) {
+ STP_DBG_PR_ERR("alloc memory for head information failed\n");
+ return -1;
+ }
+ }
+ if (dmp->p_head != NULL)
+ osal_memset(dmp->p_head, 0, MAX_DUMP_HEAD_LEN);
+
+ return 0;
+}
+
+static UINT32 stp_dbg_core_dump_header_append(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
+{
+ INT32 tmp = 0;
+
+ if ((dmp->p_head != NULL) && (dmp->head_len < (MAX_DUMP_HEAD_LEN - 1))) {
+ tmp =
+ (dmp->head_len + len) >
+ (MAX_DUMP_HEAD_LEN - 1) ? (MAX_DUMP_HEAD_LEN - 1 - dmp->head_len) : len;
+ osal_memcpy(dmp->p_head + dmp->head_len, buf, tmp);
+ dmp->head_len += tmp;
+ return tmp;
+ }
+ return 0;
+}
+
+/* stp_dbg_core_dump_in - add a packet to compressor buffer
+ * @ dmp - pointer of object
+ * @ buf - input buffer
+ * @ len - data length
+ *
+ * Retunr 0 if success; return 1 if find end string; else error code
+ */
+static _osal_inline_ INT32 stp_dbg_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
+{
+ INT32 ret = 0;
+
+ if ((!dmp) || (!buf)) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
+ if (ret) {
+ STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ switch (dmp->sm) {
+ case CORE_DUMP_INIT:
+ stp_dbg_compressor_reset(dmp->compressor, 1, GZIP);
+ stp_dbg_core_dump_header_init(dmp);
+ /* show coredump start info on UI */
+ /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */
+ /* parsing data, and check end srting */
+ ret = stp_dbg_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_PR_INFO("core dump end!\n");
+ dmp->sm = CORE_DUMP_DONE;
+ stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0);
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0);
+ }
+ break;
+
+ case CORE_DUMP_DOING:
+ /* parsing data, and check end srting */
+ ret = stp_dbg_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_PR_INFO("core dump end!\n");
+ dmp->sm = CORE_DUMP_DONE;
+ stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0);
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0);
+ }
+ break;
+
+ case CORE_DUMP_DONE:
+ stp_dbg_compressor_reset(dmp->compressor, 1, GZIP);
+ osal_timer_stop(&dmp->dmp_timer);
+ stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0);
+ dmp->sm = CORE_DUMP_DOING;
+ break;
+
+ case CORE_DUMP_TIMEOUT:
+ ret = -1;
+ break;
+ default:
+ break;
+ }
+
+ stp_dbg_core_dump_header_append(dmp, buf, len);
+ osal_unlock_sleepable_lock(&dmp->dmp_lock);
+
+ return ret;
+}
+
+static _osal_inline_ INT32 stp_dbg_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp)
+{
+#define INFO_HEAD ";CONSYS FW CORE, "
+ INT32 ret = 0;
+ INT32 tmp = 0;
+ ENUM_STP_FW_ISSUE_TYPE issue_type;
+
+ if ((dmp->p_head != NULL)
+ && ((osal_strnstr(dmp->p_head, "", dmp->head_len)) != NULL ||
+ stp_dbg_get_host_trigger_assert())) {
+ PINT8 pStr = dmp->p_head;
+ PINT8 pDtr = NULL;
+
+ if (stp_dbg_get_host_trigger_assert())
+ issue_type = STP_HOST_TRIGGER_FW_ASSERT;
+ else
+ issue_type = STP_FW_ASSERT_ISSUE;
+ STP_DBG_PR_INFO("dmp->head_len = %d\n", dmp->head_len);
+ /*parse f/w assert additional informationi for f/w's analysis */
+ ret = stp_dbg_set_fw_info(dmp->p_head, dmp->head_len, issue_type);
+ if (ret) {
+ STP_DBG_PR_ERR("set fw issue infor fail(%d),maybe fw warm reset...\n",
+ ret);
+ stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"),
+ STP_FW_WARM_RST_ISSUE);
+ }
+ /* first package, copy to info buffer */
+ osal_strcpy(&dmp->info[0], INFO_HEAD);
+
+ /* set f/w assert information to warm reset */
+ pStr = osal_strnstr(pStr, "", dmp->head_len);
+ if (pStr != NULL) {
+ pDtr = osal_strchr(pStr, '-');
+ if (pDtr != NULL) {
+ tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD);
+ tmp = ((pDtr - pStr) > tmp) ? tmp : (pDtr - pStr);
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp);
+ dmp->info[osal_strlen(dmp->info) + 1] = '\0';
+ } else {
+ tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD);
+ tmp = (dmp->head_len > tmp) ? tmp : dmp->head_len;
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp);
+ dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0';
+ }
+ }
+ } else if ((dmp->p_head != NULL)
+ && ((osal_strnstr(dmp->p_head, "", dmp->head_len) != NULL)
+ || (osal_strnstr(dmp->p_head, "ABT", dmp->head_len) != NULL))) {
+ stp_dbg_set_fw_info(dmp->p_head, dmp->head_len, STP_FW_ABT);
+ osal_strcpy(&dmp->info[0], INFO_HEAD);
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw ABT Exception...",
+ osal_strlen("Fw ABT Exception..."));
+ dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw ABT Exception...") + 1] = '\0';
+ } else {
+ STP_DBG_PR_INFO(" string not found, dmp->head_len:%d\n", dmp->head_len);
+ if (dmp->p_head == NULL)
+ STP_DBG_PR_INFO(" dmp->p_head is NULL\n");
+ else
+ STP_DBG_PR_INFO(" dmp->p_head:%s\n", dmp->p_head);
+
+ /* first package, copy to info buffer */
+ osal_strcpy(&dmp->info[0], INFO_HEAD);
+ /* set f/w assert information to warm reset */
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...",
+ osal_strlen("Fw warm reset exception..."));
+ dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] =
+ '\0';
+
+ }
+ dmp->head_len = 0;
+
+ /*set ret value to notify upper layer do dump flush operation */
+ ret = 1;
+
+ return ret;
+}
+
+/* stp_dbg_core_dump_out - get compressed data from compressor buffer
+ * @ dmp - pointer of object
+ * @ pbuf - target buffer's pointer
+ * @ len - data length
+ *
+ * Retunr 0 if success; else error code
+ */
+static _osal_inline_ INT32 stp_dbg_core_dump_out(P_WCN_CORE_DUMP_T dmp, PPUINT8 pbuf, PINT32 plen)
+{
+ INT32 ret = 0;
+
+ if ((!dmp) || (!pbuf) || (!plen)) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
+ if (ret) {
+ STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = stp_dbg_compressor_out(dmp->compressor, pbuf, plen);
+
+ osal_unlock_sleepable_lock(&dmp->dmp_lock);
+
+ return ret;
+}
+
+/* stp_dbg_core_dump_reset - reset core dump sys
+ * @ dmp - pointer of object
+ * @ timeout - core dump time out value
+ *
+ * Retunr 0 if success, else error code
+ */
+static _osal_inline_ INT32 stp_dbg_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout)
+{
+ if (!dmp) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ dmp->sm = CORE_DUMP_INIT;
+ dmp->timeout = timeout;
+ osal_timer_stop(&dmp->dmp_timer);
+ osal_timer_stop(&dmp->dmp_emi_timer);
+ osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1);
+
+ stp_dbg_core_dump_deinit(dmp);
+ g_core_dump = stp_dbg_core_dump_init(STP_CORE_DUMP_TIMEOUT);
+
+ return 0;
+}
+
+#define ENABLE_F_TRACE 0
+/* stp_dbg_core_dump_flush - Fulsh dump data and reset core dump sys
+ *
+ * Retunr 0 if success, else error code
+ */
+INT32 stp_dbg_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout)
+{
+ PUINT8 pbuf = NULL;
+ INT32 len = 0;
+
+ if (!g_core_dump) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ osal_lock_sleepable_lock(&g_core_dump->dmp_lock);
+ stp_dbg_core_dump_post_handle(g_core_dump);
+ osal_unlock_sleepable_lock(&g_core_dump->dmp_lock);
+ stp_dbg_core_dump_out(g_core_dump, &pbuf, &len);
+ STP_DBG_PR_INFO("buf 0x%zx, len %d\n", (SIZE_T) pbuf, len);
+
+#if IS_ENABLED(CONFIG_MTK_AEE_AED)
+ /* show coredump end info on UI */
+ /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */
+#if STP_DBG_AEE_EXP_API
+#if ENABLE_F_TRACE
+ aed_combo_exception_api(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info,
+ DB_OPT_FTRACE);
+#else
+ aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info);
+#endif
+#endif
+
+#endif
+ /* reset */
+ g_core_dump->count = 0;
+ stp_dbg_compressor_deinit(g_core_dump->compressor);
+ stp_dbg_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT);
+
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_dbg_core_dump_nl(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
+{
+ INT32 ret = 0;
+
+ if ((!dmp) || (!buf)) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
+ if (ret) {
+ STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ switch (dmp->sm) {
+ case CORE_DUMP_INIT:
+ STP_DBG_PR_WARN("CONSYS coredump start, please wait up to %d minutes.\n",
+ STP_CORE_DUMP_TIMEOUT/60000);
+ stp_dbg_core_dump_header_init(dmp);
+ /* check end srting */
+ ret = stp_dbg_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_PR_INFO("core dump end!\n");
+ osal_timer_stop(&dmp->dmp_timer);
+ dmp->sm = CORE_DUMP_INIT;
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ }
+ break;
+
+ case CORE_DUMP_DOING:
+ /* check end srting */
+ ret = stp_dbg_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_PR_INFO("core dump end!\n");
+ osal_timer_stop(&dmp->dmp_timer);
+ dmp->sm = CORE_DUMP_INIT;
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ }
+ break;
+
+ case CORE_DUMP_DONE:
+ osal_timer_stop(&dmp->dmp_timer);
+ dmp->sm = CORE_DUMP_INIT;
+ break;
+
+ case CORE_DUMP_TIMEOUT:
+ ret = 32;
+ break;
+ default:
+ break;
+ }
+
+ /* Skip nl packet header */
+ stp_dbg_core_dump_header_append(dmp, buf + NL_PKT_HEADER_LEN, len - NL_PKT_HEADER_LEN);
+ osal_unlock_sleepable_lock(&dmp->dmp_lock);
+
+ return ret;
+}
+
+INT32 stp_dbg_core_dump(INT32 dump_sink)
+{
+ ENUM_WMT_CHIP_TYPE chip_type;
+ INT32 ret = 0;
+
+ chip_type = wmt_detect_get_chip_type();
+ switch (chip_type) {
+ case WMT_CHIP_TYPE_COMBO:
+ ret = stp_dbg_combo_core_dump(dump_sink);
+ break;
+ case WMT_CHIP_TYPE_SOC:
+ ret = stp_dbg_soc_core_dump(dump_sink);
+ break;
+ default:
+ STP_DBG_PR_ERR("error chip type(%d)\n", chip_type);
+ }
+
+ return ret;
+}
+
+static _osal_inline_ UINT32 stp_dbg_get_chip_id(VOID)
+{
+ ENUM_WMT_CHIP_TYPE chip_type;
+ UINT32 chip_id = 0;
+
+ chip_type = wmt_detect_get_chip_type();
+ switch (chip_type) {
+ case WMT_CHIP_TYPE_COMBO:
+ chip_id = mtk_wcn_wmt_chipid_query();
+ break;
+ case WMT_CHIP_TYPE_SOC:
+ chip_id = wmt_plat_get_soc_chipid();
+ break;
+ default:
+ STP_DBG_PR_ERR("error chip type(%d)\n", chip_type);
+ }
+
+ return chip_id;
+}
+
+/* stp_dbg_trigger_collect_ftrace - this func can collect SYS_FTRACE
+ *
+ * Retunr 0 if success
+ */
+INT32 stp_dbg_trigger_collect_ftrace(PUINT8 pbuf, INT32 len)
+{
+ if (!pbuf) {
+ STP_DBG_PR_ERR("Parameter error\n");
+ return -1;
+ }
+
+ if (mtk_wcn_stp_coredump_start_get()) {
+ STP_DBG_PR_ERR("assert has been triggered\n");
+ return -1;
+ }
+
+ stp_dbg_set_host_assert_info(WMTDRV_TYPE_WMT, 30, 1);
+
+ if (stp_dbg_set_fw_info(pbuf, len, STP_HOST_TRIGGER_COLLECT_FTRACE))
+ return -1;
+
+ if (g_core_dump) {
+ osal_strncpy(&g_core_dump->info[0], pbuf, len);
+#if IS_ENABLED(CONFIG_MTK_AEE_AED)
+ aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info);
+#endif
+ } else {
+ STP_DBG_PR_INFO("g_core_dump is not initialized\n");
+#if IS_ENABLED(CONFIG_MTK_AEE_AED)
+ aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)pbuf);
+#endif
+ }
+
+ return 0;
+}
+
+#if BTIF_RXD_BE_BLOCKED_DETECT
+MTK_WCN_BOOL stp_dbg_is_btif_rxd_be_blocked(VOID)
+{
+ MTK_WCN_BOOL flag = MTK_WCN_BOOL_FALSE;
+
+ if (mtk_btif_rxd_be_blocked_flag_get())
+ flag = MTK_WCN_BOOL_TRUE;
+ return flag;
+}
+#endif
+
+static _osal_inline_ INT32 stp_dbg_gzip_compressor(PVOID worker, PUINT8 in_buf, INT32 in_sz, PUINT8 out_buf,
+ PINT32 out_sz, INT32 finish)
+{
+ INT32 ret = 0;
+ z_stream *stream = NULL;
+ INT32 tmp = *out_sz;
+
+ STP_DBG_PR_DBG("before compressor:buf 0x%zx, size %d, avalible buf: 0x%zx, size %d\n",
+ (SIZE_T) in_buf, in_sz, (SIZE_T) out_buf, tmp);
+
+ stream = (z_stream *) worker;
+ if (!stream) {
+ STP_DBG_PR_ERR("invalid workspace!\n");
+ return -1;
+ }
+
+ if (in_sz > 0) {
+#if 0
+ ret = zlib_deflateReset(stream);
+ if (ret != Z_OK) {
+ STP_DBG_PR_ERR("reset failed!\n");
+ return -2;
+ }
+#endif
+ stream->next_in = in_buf;
+ stream->avail_in = in_sz;
+ stream->next_out = out_buf;
+ stream->avail_out = tmp;
+
+ zlib_deflate(stream, Z_FULL_FLUSH);
+
+ if (finish) {
+ while (1) {
+ INT32 val = zlib_deflate(stream, Z_FINISH);
+
+ if (val == Z_OK)
+ continue;
+ else if (val == Z_STREAM_END)
+ break;
+ STP_DBG_PR_ERR("finish operation failed %d\n", val);
+ return -3;
+ }
+ }
+ *out_sz = tmp - stream->avail_out;
+ }
+
+ STP_DBG_PR_DBG("after compressor,avalible buf: 0x%zx, compress rate %d -> %d\n",
+ (SIZE_T) out_buf, in_sz, *out_sz);
+
+ return ret;
+}
+
+/* stp_dbg_compressor_init - create a compressor and do init
+ * @ name - compressor's name
+ * @ L1_buf_sz - L1 buffer size
+ * @ L2_buf_sz - L2 buffer size
+ *
+ * Retunr object's pointer if success, else NULL
+ */
+static _osal_inline_ P_WCN_COMPRESSOR_T stp_dbg_compressor_init(PUINT8 name, INT32 L1_buf_sz,
+ INT32 L2_buf_sz)
+{
+ INT32 ret = 0;
+ z_stream *pstream = NULL;
+ P_WCN_COMPRESSOR_T compress = NULL;
+
+ compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T));
+ if (!compress) {
+ STP_DBG_PR_ERR("alloc compressor failed!\n");
+ goto fail;
+ }
+
+ osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T));
+ osal_memcpy(compress->name, name, STP_OJB_NAME_SZ);
+
+ compress->f_compress_en = 0;
+ compress->compress_type = GZIP;
+
+ if (compress->compress_type == GZIP) {
+ compress->worker = osal_malloc(sizeof(z_stream));
+ if (!compress->worker) {
+ STP_DBG_PR_ERR("alloc stream failed!\n");
+ goto fail;
+ }
+ pstream = (z_stream *) compress->worker;
+
+ pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
+ if (!pstream->workspace) {
+ STP_DBG_PR_ERR("alloc workspace failed!\n");
+ goto fail;
+ }
+ ret = zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (ret != Z_OK) {
+ STP_DBG_PR_INFO("[%s::%d] zlib_deflateInit2 failed!\n", __func__, __LINE__);
+ goto fail;
+ }
+ }
+
+ compress->handler = stp_dbg_gzip_compressor;
+ compress->L1_buf_sz = L1_buf_sz;
+ compress->L2_buf_sz = L2_buf_sz;
+ compress->L1_pos = 0;
+ compress->L2_pos = 0;
+ compress->uncomp_size = 0;
+ compress->crc32 = 0xffffffffUL;
+
+ compress->L1_buf = osal_malloc(compress->L1_buf_sz);
+ if (!compress->L1_buf) {
+ STP_DBG_PR_ERR("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz);
+ goto fail;
+ }
+
+ compress->L2_buf = osal_malloc(compress->L2_buf_sz);
+ if (!compress->L2_buf) {
+ STP_DBG_PR_ERR("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz);
+ goto fail;
+ }
+
+ STP_DBG_PR_INFO("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz);
+ return compress;
+
+fail:
+ if (compress) {
+ if (compress->L2_buf) {
+ osal_free(compress->L2_buf);
+ compress->L2_buf = NULL;
+ }
+
+ if (compress->L1_buf) {
+ osal_free(compress->L1_buf);
+ compress->L1_buf = NULL;
+ }
+
+ if (compress->worker) {
+ pstream = (z_stream *) compress->worker;
+ if ((compress->compress_type == GZIP) && pstream->workspace) {
+ zlib_deflateEnd(pstream);
+ osal_free(pstream->workspace);
+ }
+ osal_free(compress->worker);
+ compress->worker = NULL;
+ }
+
+ if (compress->worker) {
+ osal_free(compress->worker);
+ compress->worker = NULL;
+ }
+
+ osal_free(compress);
+ compress = NULL;
+ }
+
+ STP_DBG_PR_ERR("init failed!\n");
+
+ return NULL;
+}
+
+/* stp_dbg_compressor_deinit - distroy a compressor
+ * @ cprs - compressor's pointer
+ *
+ * Retunr 0 if success, else NULL
+ */
+static _osal_inline_ INT32 stp_dbg_compressor_deinit(P_WCN_COMPRESSOR_T cprs)
+{
+ z_stream *pstream = NULL;
+
+ if (cprs) {
+ if (cprs->L2_buf) {
+ osal_free(cprs->L2_buf);
+ cprs->L2_buf = NULL;
+ }
+
+ if (cprs->L1_buf) {
+ osal_free(cprs->L1_buf);
+ cprs->L1_buf = NULL;
+ }
+
+ if (cprs->worker) {
+ pstream = (z_stream *) cprs->worker;
+ if ((cprs->compress_type == GZIP) && pstream->workspace) {
+ zlib_deflateEnd(pstream);
+ osal_free(pstream->workspace);
+ }
+ osal_free(cprs->worker);
+ cprs->worker = NULL;
+ }
+
+ cprs->handler = NULL;
+
+ osal_free(cprs);
+ }
+
+ STP_DBG_PR_INFO("destroy OK\n");
+
+ return 0;
+}
+
+/* stp_dbg_compressor_in - put in a raw data, and compress L1 buffer if need
+ * @ cprs - compressor's pointer
+ * @ buf - raw data buffer
+ * @ len - raw data length
+ * @ is_iobuf - is buf a pointer to EMI? 1: yes, 0: no
+ * @ finish - core dump finish or not, 1: finished; 0: not finish
+ *
+ * Retunr 0 if success, else NULL
+ */
+static _osal_inline_ INT32 stp_dbg_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len,
+ INT32 is_iobuf, INT32 finish)
+{
+ INT32 tmp_len = 0;
+ INT32 ret = 0;
+
+ if (!cprs) {
+ STP_DBG_PR_ERR("invalid para!\n");
+ return -1;
+ }
+
+ cprs->uncomp_size += len;
+
+ /* check L1 buf valid space */
+ if (len > (cprs->L1_buf_sz - cprs->L1_pos)) {
+ STP_DBG_PR_DBG("L1 buffer full\n");
+
+ if (cprs->f_compress_en && cprs->handler) {
+ /* need compress */
+ /* compress L1 buffer, and put result to L2 buffer */
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+ ret =
+ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos,
+ &cprs->L2_buf[cprs->L2_pos], &tmp_len, finish);
+ if (!ret) {
+ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
+ cprs->L2_pos += tmp_len;
+ if (cprs->L2_pos >= cprs->L2_buf_sz)
+ STP_DBG_PR_ERR("coredump size too large(%d), L2 buf overflow\n",
+ cprs->L2_pos);
+
+ if (finish) {
+ /* Add 8 byte suffix
+ * ===
+ * 32 bits UNCOMPRESS SIZE
+ * 32 bits CRC
+ */
+ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) =
+ (cprs->crc32 ^ 0xffffffffUL);
+ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size;
+ cprs->L2_pos += 8;
+ }
+ STP_DBG_PR_DBG("compress OK!\n");
+ } else
+ STP_DBG_PR_ERR("compress error!\n");
+ } else {
+ /* no need compress */
+ /* Flush L1 buffer to L2 buffer */
+ STP_DBG_PR_INFO("No need do compress, Put to L2 buf\n");
+
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
+ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
+ cprs->L2_pos += tmp_len;
+ }
+
+ /* reset L1 buf pos */
+ cprs->L1_pos = 0;
+
+ /* put curren data to L1 buf */
+ if (len > cprs->L1_buf_sz) {
+ STP_DBG_PR_ERR("len=%d, too long err!\n", len);
+ } else {
+ STP_DBG_PR_DBG("L1 Flushed, and Put %d bytes to L1 buf\n", len);
+ if (is_iobuf)
+ osal_memcpy_fromio(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ else
+ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ cprs->L1_pos += len;
+ }
+ } else {
+ /* put to L1 buffer */
+ STP_DBG_PR_DBG("Put %d bytes to L1 buf\n", len);
+ if (is_iobuf)
+ osal_memcpy_fromio(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ else
+ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ cprs->L1_pos += len;
+ }
+
+ return ret;
+}
+
+/* stp_dbg_compressor_out - get the result data from L2 buffer
+ * @ cprs - compressor's pointer
+ * @ pbuf - point to L2 buffer
+ * @ plen - out len
+ *
+ * Retunr 0 if success, else NULL
+ */
+static _osal_inline_ INT32 stp_dbg_compressor_out(P_WCN_COMPRESSOR_T cprs, PPUINT8 pbuf, PINT32 plen)
+{
+ INT32 ret = 0;
+ INT32 tmp_len = 0;
+
+ if ((!cprs) || (!pbuf) || (!plen)) {
+ STP_DBG_PR_ERR("invalid para!\n");
+ return -1;
+ }
+ /* check if there's L1 data need flush to L2 buffer */
+ if (cprs->L1_pos > 0) {
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+
+ if (cprs->f_compress_en && cprs->handler) {
+ /* need compress */
+ ret =
+ cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos,
+ &cprs->L2_buf[cprs->L2_pos], &tmp_len, 1);
+
+ if (!ret) {
+ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
+ cprs->L2_pos += tmp_len;
+
+ /* Add 8 byte suffix
+ * ===
+ * 32 bits UNCOMPRESS SIZE
+ * 32 bits CRC
+ */
+ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL);
+ *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size;
+ cprs->L2_pos += 8;
+
+ STP_DBG_PR_INFO("compress OK!\n");
+ } else {
+ STP_DBG_PR_ERR("compress error!\n");
+ }
+ } else {
+ /* no need compress */
+ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
+ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
+ cprs->L2_pos += tmp_len;
+ }
+
+ cprs->L1_pos = 0;
+ }
+
+ *pbuf = cprs->L2_buf;
+ *plen = cprs->L2_pos;
+
+ STP_DBG_PR_INFO("0x%zx, len %d, l2_buf_remain %d\n", (SIZE_T)*pbuf, *plen, cprs->L2_buf_sz - cprs->L2_pos);
+
+#if 1
+ ret = zlib_deflateReset((z_stream *) cprs->worker);
+ if (ret != Z_OK) {
+ STP_DBG_PR_ERR("reset failed!\n");
+ return -2;
+ }
+#endif
+ return 0;
+}
+
+/* stp_dbg_compressor_reset - reset compressor
+ * @ cprs - compressor's pointer
+ * @ enable - enable/disable compress
+ * @ type - compress algorithm
+ *
+ * Retunr 0 if success, else NULL
+ */
+static _osal_inline_ INT32 stp_dbg_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable,
+ WCN_COMPRESS_ALG_T type)
+{
+ if (!cprs) {
+ STP_DBG_PR_ERR("invalid para!\n");
+ return -1;
+ }
+
+ cprs->f_compress_en = enable;
+ /* cprs->f_compress_en = 0; // disable compress for test */
+ cprs->compress_type = type;
+ cprs->L1_pos = 0;
+ cprs->L2_pos = 0;
+ cprs->uncomp_size = 0;
+ cprs->crc32 = 0xffffffffUL;
+
+ /* zlib_deflateEnd((z_stream*)cprs->worker); */
+
+ STP_DBG_PR_INFO("OK! compress algorithm %d\n", type);
+
+ return 0;
+}
+
+#if 0
+static _osal_inline_ VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len)
+{
+ INT32 idx = 0;
+ UINT8 str[240];
+ PUINT8 p_str;
+
+ p_str = &str[0];
+ pr_debug(" %s-len:%d\n", title, len);
+ for (idx = 0; idx < len; idx++, pBuf++) {
+ sprintf(p_str, "%02x ", *pBuf);
+ p_str += 3;
+ if (15 == (idx % 16)) {
+ sprintf(p_str, "--end\n");
+ *(p_str + 6) = '\0';
+ pr_debug("%s", str);
+ p_str = 0;
+ }
+ }
+ if (len % 16) {
+ sprintf(p_str, "--end\n");
+ *(p_str + 6) = '\0';
+ pr_debug("%s", str);
+ }
+}
+#endif
+static VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len)
+{
+ INT32 k = 0;
+ char str[240] = {""};
+ char buf_str[32] = {""};
+
+ pr_warn(" %s-len:%d\n", title, len);
+ /* pr_warn(" ", title, len); */
+ for (k = 0; k < len; k++) {
+ if (strlen(str) < 200) {
+ if (snprintf(buf_str, sizeof(buf_str), "0x%02x ", pBuf[k]) > 0)
+ strncat(str, buf_str, strlen(buf_str));
+ } else {
+ pr_warn("More than 200 of the data is too much\n");
+ break;
+ }
+ }
+ strncat(str, "--end\n", strlen("--end\n"));
+ pr_warn("%s", str);
+}
+
+
+INT32 stp_dbg_enable(MTKSTP_DBG_T *stp_dbg)
+{
+ ULONG flags;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ stp_dbg->pkt_trace_no = 0;
+ stp_dbg->is_enable = 1;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+INT32 stp_dbg_disable(MTKSTP_DBG_T *stp_dbg)
+{
+ ULONG flags;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ stp_dbg->pkt_trace_no = 0;
+ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T));
+ stp_dbg->is_enable = 0;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+static PINT8 stp_get_dbg_type_string(const PINT8 *pType, UINT32 type)
+{
+ PINT8 info_task_type = "";
+
+ if (!pType)
+ return NULL;
+
+ if ((mtk_wcn_stp_is_support_gpsl5() == 0) && (type == INFO_TASK_INDX))
+ return info_task_type;
+ else
+ return pType[type];
+}
+
+static _osal_inline_ INT32 stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len)
+{
+ ULONG flags;
+ STP_DBG_HDR_T *pHdr = NULL;
+ PINT8 pBuf = NULL;
+ UINT32 length = 0;
+ const PINT8 *pType = NULL;
+
+ pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ?
+ comboStpDbgType : socStpDbgType;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+
+ stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0;
+ stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len;
+ memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),
+ 0, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len)));
+ memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),
+ buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len)));
+ stp_dbg->logsys->size++;
+ stp_dbg->logsys->size = (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ?
+ STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size;
+ if (gStpDbgLogOut != 0) {
+ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]);
+ pBuf = (PINT8)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) +
+ sizeof(STP_DBG_HDR_T);
+ length = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T);
+ pr_info("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n",
+ pHdr->sec,
+ pHdr->usec,
+ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
+ stp_get_dbg_type_string(pType, pHdr->type),
+ pHdr->no, pHdr->len, pHdr->seq, pHdr->ack);
+
+ if (length > 0)
+ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", length);
+ }
+ stp_dbg->logsys->in =
+ (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1);
+ STP_DBG_PR_DBG("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in);
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_dbg_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg)
+{
+ INT32 retval = 0;
+
+/* #ifndef CONFIG_LOG_STP_INTERNAL */
+ if (stp_dbg->btm != NULL)
+ retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm);
+/* #endif */
+
+ return retval;
+}
+
+static VOID stp_dbg_dmp_print_work(struct work_struct *work)
+{
+ MTKSTP_LOG_SYS_T *logsys = container_of(work, MTKSTP_LOG_SYS_T, dump_work);
+ INT32 dumpSize = logsys->dump_size;
+ MTKSTP_LOG_ENTRY_T *queue = logsys->dump_queue;
+ INT32 i;
+ PINT8 pBuf = NULL;
+ INT32 len = 0;
+ STP_DBG_HDR_T *pHdr = NULL;
+ const PINT8 *pType = NULL;
+
+ if (queue == NULL || queue == (MTKSTP_LOG_ENTRY_T *)STP_MAGIC_NUM)
+ return;
+
+ pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ?
+ comboStpDbgType : socStpDbgType;
+
+ for (i = 0; i < dumpSize; i++) {
+ pHdr = (STP_DBG_HDR_T *) &(queue[i].buffer[0]);
+ pBuf = &(queue[i].buffer[0]) + sizeof(STP_DBG_HDR_T);
+ len = queue[i].len - sizeof(STP_DBG_HDR_T);
+ len = len > STP_PKT_SZ ? STP_PKT_SZ : len;
+ pr_info("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d), time[%llu.%06lu]\n",
+ pHdr->sec,
+ pHdr->usec,
+ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
+ stp_get_dbg_type_string(pType, pHdr->type),
+ pHdr->no, pHdr->len, pHdr->seq,
+ pHdr->ack, pHdr->l_sec, pHdr->l_nsec);
+
+ if (len > 0)
+ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len);
+
+ }
+ vfree(queue);
+ logsys->dump_queue = NULL;
+}
+
+INT32 stp_dbg_dmp_print(MTKSTP_DBG_T *stp_dbg)
+{
+#define MAX_DMP_NUM 80
+ ULONG flags;
+ UINT32 dumpSize = 0;
+ UINT32 inIndex = 0;
+ UINT32 outIndex = 0;
+ MTKSTP_LOG_ENTRY_T *dump_queue = NULL;
+ MTKSTP_LOG_ENTRY_T *queue = stp_dbg->logsys->queue;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ if (stp_dbg->logsys->dump_queue != NULL) {
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+ return 0;
+ }
+
+ stp_dbg->logsys->dump_queue = (MTKSTP_LOG_ENTRY_T *)STP_MAGIC_NUM;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ /* allocate memory may take long time, thus allocate it before get lock */
+ dump_queue = vmalloc(sizeof(MTKSTP_LOG_ENTRY_T) * MAX_DMP_NUM);
+ if (dump_queue == NULL) {
+ stp_dbg->logsys->dump_queue = NULL;
+ pr_info("fail to allocate memory");
+ return -1;
+ }
+
+ if (spin_trylock_irqsave(&(stp_dbg->logsys->lock), flags) == 0) {
+ stp_dbg->logsys->dump_queue = NULL;
+ vfree(dump_queue);
+ pr_info("fail to get lock");
+ return -1;
+ }
+ /* Not to dequeue from loging system */
+ inIndex = stp_dbg->logsys->in;
+ dumpSize = stp_dbg->logsys->size;
+
+ /* chance is little but still needs to check */
+ if (dumpSize == 0) {
+ stp_dbg->logsys->dump_queue = NULL;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+ vfree(dump_queue);
+ return 0;
+ }
+
+ if (dumpSize == STP_DBG_LOG_ENTRY_NUM)
+ outIndex = inIndex;
+ else
+ outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM;
+
+ if (dumpSize > MAX_DMP_NUM) {
+ outIndex += (dumpSize - MAX_DMP_NUM);
+ outIndex %= STP_DBG_LOG_ENTRY_NUM;
+ dumpSize = MAX_DMP_NUM;
+ }
+
+ stp_dbg->logsys->dump_queue = dump_queue;
+ stp_dbg->logsys->dump_size = dumpSize;
+
+ /* copy content of stp_dbg->logsys->queue out, don't print log while holding */
+ /* spinlock to prevent blocking other process */
+ if (outIndex + dumpSize > STP_DBG_LOG_ENTRY_NUM) {
+ UINT32 tailNum = STP_DBG_LOG_ENTRY_NUM - outIndex;
+
+ osal_memcpy(dump_queue, &(queue[outIndex]), sizeof(MTKSTP_LOG_ENTRY_T) * tailNum);
+ osal_memcpy(dump_queue + tailNum, &(queue[0]), sizeof(MTKSTP_LOG_ENTRY_T) *
+ (dumpSize - tailNum));
+ } else {
+ osal_memcpy(dump_queue, &(queue[outIndex]), sizeof(MTKSTP_LOG_ENTRY_T) * dumpSize);
+ }
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+ STP_DBG_PR_INFO("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex);
+ schedule_work(&(stp_dbg->logsys->dump_work));
+ return 0;
+}
+
+INT32 stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, PINT8 buf, PINT32 len)
+{
+ ULONG flags;
+ INT32 remaining = 0;
+ *len = 0;
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+
+ if (stp_dbg->logsys->size > 0) {
+ if (stp_dbg->logsys->queue[stp_dbg->logsys->out].len >= STP_DBG_LOG_ENTRY_SZ)
+ stp_dbg->logsys->queue[stp_dbg->logsys->out].len = STP_DBG_LOG_ENTRY_SZ - 1;
+ memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]),
+ stp_dbg->logsys->queue[stp_dbg->logsys->out].len);
+
+ (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len;
+ stp_dbg->logsys->out =
+ (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1)) ?
+ (0) : (stp_dbg->logsys->out + 1);
+ stp_dbg->logsys->size--;
+
+ STP_DBG_PR_DBG("logsys size = %d, out = %d\n", stp_dbg->logsys->size,
+ stp_dbg->logsys->out);
+ } else
+ STP_DBG_PR_LOUD("logsys EMPTY!\n");
+
+ remaining = (stp_dbg->logsys->size == 0) ? (0) : (1);
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return remaining;
+}
+
+INT32 stp_dbg_dmp_out_ex(PINT8 buf, PINT32 len)
+{
+ return stp_dbg_dmp_out(g_stp_dbg, buf, len);
+}
+
+INT32 stp_dbg_dmp_append(MTKSTP_DBG_T *stp_dbg, PUINT8 pBuf, INT32 max_len)
+{
+ PUINT8 p = NULL;
+ UINT32 l = 0;
+ UINT32 i = 0;
+ INT32 j = 0;
+ ULONG flags;
+ UINT32 len = 0;
+ UINT32 dumpSize = 0;
+ STP_DBG_HDR_T *pHdr = NULL;
+ const PINT8 *pType = NULL;
+
+ if (!pBuf || max_len < 8) { /* 8: length of "\n" */
+ STP_DBG_PR_WARN("invalid param, pBuf:%p, max_len:%d\n", pBuf, max_len);
+ return 0;
+ }
+
+ pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ?
+ comboStpDbgType : socStpDbgType;
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ /* Not to dequeue from loging system */
+ dumpSize = stp_dbg->logsys->size;
+ j = stp_dbg->logsys->in;
+
+ /* format */
+ len += osal_sprintf(pBuf, "\n"
+ */
+ if ((len + 53 + 3 * l + 4) > max_len)
+ break;
+
+ pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[j].buffer[0]);
+ p = (PUINT8)pHdr + sizeof(STP_DBG_HDR_T);
+
+ len += osal_sprintf(pBuf + len, "\t%llu.%06lus, %s:pT%sn(%d)l(%4d)s(%d)a(%d)\t",
+ pHdr->l_sec, pHdr->l_nsec,
+ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
+ stp_get_dbg_type_string(pType, pHdr->type),
+ pHdr->no, pHdr->len, pHdr->seq,
+ pHdr->ack);
+
+ for (i = 0; i < l; i++, p++)
+ len += osal_sprintf(pBuf + len, " %02x", *p, 3);
+
+ pBuf[len] = '\n';
+ len += 1;
+
+ dumpSize--;
+ }
+
+ len += osal_sprintf(pBuf + len, "-->\n");
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return len;
+}
+
+static _osal_inline_ INT32 stp_dbg_get_avl_entry_num(MTKSTP_DBG_T *stp_dbg)
+{
+ if (stp_dbg->logsys->size == 0)
+ return STP_DBG_LOG_ENTRY_NUM;
+ else
+ return (stp_dbg->logsys->in > stp_dbg->logsys->out) ?
+ (STP_DBG_LOG_ENTRY_NUM - stp_dbg->logsys->in + stp_dbg->logsys->out) :
+ (stp_dbg->logsys->out - stp_dbg->logsys->in);
+}
+
+static _osal_inline_ INT32 stp_dbg_fill_hdr(STP_DBG_HDR_T *hdr, INT32 type, INT32 ack, INT32 seq,
+ INT32 crc, INT32 dir, INT32 len, INT32 dbg_type)
+{
+
+ struct timeval now;
+ UINT64 ts;
+ ULONG nsec;
+
+ if (!hdr) {
+ STP_DBG_PR_ERR("function invalid\n");
+ return -EINVAL;
+ }
+
+ osal_do_gettimeofday(&now);
+ osal_get_local_time(&ts, &nsec);
+ hdr->last_dbg_type = gStpDbgDumpType;
+ gStpDbgDumpType = dbg_type;
+ hdr->dbg_type = dbg_type;
+ hdr->ack = ack;
+ hdr->seq = seq;
+ hdr->sec = now.tv_sec;
+ hdr->usec = now.tv_usec;
+ hdr->crc = crc;
+ hdr->dir = dir; /* rx */
+ hdr->dmy = 0xffffffff;
+ hdr->len = len;
+ hdr->type = type;
+ hdr->l_sec = ts;
+ hdr->l_nsec = nsec;
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, STP_DBG_HDR_T *hdr, const PUINT8 body)
+{
+ /* fix the frame size large issues. */
+ static STP_PACKET_T stp_pkt;
+ UINT32 hdr_sz = sizeof(struct stp_dbg_pkt_hdr);
+ UINT32 body_sz = 0;
+ ULONG flags;
+ UINT32 avl_num;
+
+ if (hdr->dbg_type == STP_DBG_PKT)
+ body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ);
+ else
+ body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ);
+
+ hdr->no = stp_dbg->pkt_trace_no++;
+ memcpy((PUINT8) &stp_pkt.hdr, (PUINT8) hdr, hdr_sz);
+ if (body != NULL)
+ memcpy((PUINT8) &stp_pkt.raw[0], body, body_sz);
+
+ if (hdr->dbg_type == STP_DBG_FW_DMP) {
+ if (hdr->last_dbg_type != STP_DBG_FW_DMP) {
+
+ STP_DBG_PR_INFO
+ ("reset stp_dbg logsys when queue fw coredump package(%d)\n",
+ hdr->last_dbg_type);
+ STP_DBG_PR_INFO("dump 1st fw coredump package len(%d) for confirming\n",
+ hdr->len);
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ stp_dbg->logsys->in = 0;
+ stp_dbg->logsys->out = 0;
+ stp_dbg->logsys->size = 0;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+ } else {
+ avl_num = stp_dbg_get_avl_entry_num(stp_dbg);
+
+ if (!avl_num)
+ STP_DBG_PR_ERR("there is no avl entry stp_dbg logsys!!!\n");
+ }
+ }
+ stp_dbg_dmp_in(stp_dbg, (PINT8) &stp_pkt, hdr_sz + body_sz);
+ /* Only FW DMP MSG should inform BTM-CORE to dump packet to native process */
+ if (hdr->dbg_type == STP_DBG_FW_DMP)
+ stp_dbg_notify_btm_dmp_wq(stp_dbg);
+
+ return 0;
+}
+
+INT32 stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, INT32 dbg_type,
+ INT32 type, INT32 ack_no, INT32 seq_no, INT32 crc, INT32 dir, INT32 len,
+ const PUINT8 body)
+{
+ STP_DBG_HDR_T hdr;
+
+ osal_bug_on(!stp_dbg);
+
+ if (!stp_dbg)
+ return -1;
+
+ if (stp_dbg->is_enable == 0) {
+ /*dbg is disable,and not to log */
+ } else {
+ hdr.no = 0;
+ hdr.chs = 0;
+ stp_dbg_fill_hdr(&hdr,
+ (INT32) type,
+ (INT32) ack_no,
+ (INT32) seq_no, (INT32) crc, (INT32) dir, (INT32) len,
+ (INT32) dbg_type);
+
+ stp_dbg_add_pkt(stp_dbg, &hdr, body);
+ }
+
+ return 0;
+}
+
+INT32 stp_dbg_log_ctrl(UINT32 on)
+{
+ if (on != 0) {
+ gStpDbgLogOut = 1;
+ pr_warn("STP-DBG: enable pkt log dump out.\n");
+ } else {
+ gStpDbgLogOut = 0;
+ pr_warn("STP-DBG: disable pkt log dump out.\n");
+ }
+
+ return 0;
+}
+
+VOID stp_dbg_nl_init(VOID)
+{
+#if 0
+ if (genl_register_family(&stp_dbg_gnl_family) != 0) {
+ STP_DBG_PR_ERR("%s(): GE_NELINK family registration fail\n", __func__);
+ } else {
+ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0)
+ STP_DBG_PR_ERR("%s(): BIND operation registration fail\n", __func__);
+
+ if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0)
+ STP_DBG_PR_ERR("%s(): RESET operation registration fail\n", __func__);
+
+ }
+#endif
+ osal_sleepable_lock_init(&g_dbg_nl_lock);
+ if (genl_register_family(&stp_dbg_gnl_family) != 0)
+ STP_DBG_PR_ERR("%s(): GE_NELINK family registration fail\n", __func__);
+}
+
+VOID stp_dbg_nl_deinit(VOID)
+{
+ int i;
+
+ num_bind_process = 0;
+ for (i = 0; i < MAX_BIND_PROCESS; i++)
+ bind_pid[i] = 0;
+ genl_unregister_family(&stp_dbg_gnl_family);
+ osal_sleepable_lock_deinit(&g_dbg_nl_lock);
+}
+
+static INT32 stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nlattr *na = NULL;
+ PINT8 mydata;
+ INT32 i;
+
+ if (info == NULL)
+ goto out;
+
+ STP_DBG_PR_INFO("%s():->\n", __func__);
+
+ na = info->attrs[STP_DBG_ATTR_MSG];
+
+ if (na)
+ mydata = (PINT8) nla_data(na);
+
+ if (osal_lock_sleepable_lock(&g_dbg_nl_lock))
+ return -1;
+
+ for (i = 0; i < MAX_BIND_PROCESS; i++) {
+ if (bind_pid[i] == 0) {
+ bind_pid[i] = info->snd_portid;
+ num_bind_process++;
+ STP_DBG_PR_INFO("%s():-> pid = %d\n", __func__, info->snd_portid);
+ break;
+ }
+ }
+
+ if (i == MAX_BIND_PROCESS) {
+ STP_DBG_PR_ERR("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS);
+ bind_pid[0] = info->snd_portid;
+ }
+
+ osal_unlock_sleepable_lock(&g_dbg_nl_lock);
+
+out:
+ return 0;
+}
+
+static INT32 stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info)
+{
+ STP_DBG_PR_ERR("%s(): should not be invoked\n", __func__);
+
+ return 0;
+}
+
+INT32 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len)
+{
+ struct sk_buff *skb = NULL;
+ PVOID msg_head = NULL;
+ INT32 rc = -1;
+ INT32 i, j;
+ INT32 ret = 0;
+ INT32 killed_num = 0;
+
+ if (num_bind_process == 0) {
+ /* no listening process */
+ STP_DBG_PR_ERR("%s(): the process is not invoked\n", __func__);
+ return 0;
+ }
+
+ ret = stp_dbg_core_dump_nl(g_core_dump, aucMsg, len);
+ if (ret < 0)
+ return ret;
+ if (ret == 32)
+ return ret;
+
+ ret = -1;
+ for (i = 0; i < num_bind_process; i++) {
+ if (bind_pid[i] == 0) {
+ killed_num++;
+ continue;
+ }
+
+ skb = genlmsg_new(2048, GFP_KERNEL);
+ if (skb) {
+ msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd);
+ if (msg_head == NULL) {
+ nlmsg_free(skb);
+ STP_DBG_PR_ERR("%s(): genlmsg_put fail...\n", __func__);
+ return -1;
+ }
+
+ rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg);
+ if (rc != 0) {
+ nlmsg_free(skb);
+ STP_DBG_PR_ERR("%s(): nla_put_string fail...: %d\n", __func__, rc);
+ return rc;
+ }
+
+ /* finalize the message */
+ genlmsg_end(skb, msg_head);
+
+ /* sending message */
+ rc = genlmsg_unicast(&init_net, skb, bind_pid[i]);
+ if (rc != 0) {
+ STP_DBG_PR_INFO("%s(): genlmsg_unicast fail...: %d pid: %d\n",
+ __func__, rc, bind_pid[i]);
+ if (rc == -ECONNREFUSED) {
+ bind_pid[i] = 0;
+ killed_num++;
+ }
+ } else {
+ /* don't retry as long as at least one process receives data */
+ ret = 0;
+ }
+ } else {
+ STP_DBG_PR_ERR("%s(): genlmsg_new fail...\n", __func__);
+ }
+ }
+
+ if (killed_num > 0) {
+ if (osal_lock_sleepable_lock(&g_dbg_nl_lock)) {
+ /* if fail to get lock, it is fine to update bind_pid[] later */
+ return ret;
+ }
+
+ for (i = 0; i < num_bind_process - killed_num; i++) {
+ if (bind_pid[i] == 0) {
+ for (j = num_bind_process - 1; j > i; j--) {
+ if (bind_pid[j] > 0) {
+ bind_pid[i] = bind_pid[j];
+ bind_pid[j] = 0;
+ }
+ }
+ }
+ }
+ num_bind_process -= killed_num;
+ osal_unlock_sleepable_lock(&g_dbg_nl_lock);
+ }
+
+ return ret;
+}
+
+INT32 stp_dbg_dump_send_retry_handler(PINT8 tmp, INT32 len)
+{
+ INT32 ret = 0;
+ INT32 nl_retry = 0;
+
+ if (tmp == NULL)
+ return -1;
+
+ ret = stp_dbg_nl_send(tmp, 2, len+5);
+ while (ret) {
+ nl_retry++;
+ if (ret == 32) {
+ STP_DBG_PR_ERR("**dump send timeout : %d**\n", ret);
+ ret = 1;
+ break;
+ }
+ if (nl_retry > 1000) {
+ STP_DBG_PR_ERR("**dump send fails, and retry more than 1000: %d.**\n", ret);
+ ret = 2;
+ break;
+ }
+ STP_DBG_PR_WARN("**dump send fails, and retry again.**\n");
+ osal_sleep_ms(3);
+ ret = stp_dbg_nl_send(tmp, 2, len+5);
+ if (!ret)
+ STP_DBG_PR_DBG("****retry again ok!**\n");
+ }
+
+ return ret;
+}
+
+INT32 stp_dbg_aee_send(PUINT8 aucMsg, INT32 len, INT32 cmd)
+{
+#define KBYTES (1024*sizeof(char))
+#ifndef LOG_STP_DEBUG_DISABLE
+#define L1_BUF_SIZE (32*KBYTES)
+#define PKT_MULTIPLIER 18
+#else
+#define L1_BUF_SIZE (4*KBYTES)
+#define PKT_MULTIPLIER 1
+#endif
+ INT32 ret = 0;
+
+ if (g_core_dump->count == 0) {
+ g_core_dump->compressor = stp_dbg_compressor_init("core_dump_compressor",
+ L1_BUF_SIZE,
+ PKT_MULTIPLIER*g_core_dump->dmp_num*KBYTES);
+ g_core_dump->count++;
+ if (!g_core_dump->compressor) {
+ STP_DBG_PR_ERR("create compressor failed!\n");
+ stp_dbg_compressor_deinit(g_core_dump->compressor);
+ return -1;
+ }
+ }
+ /* buffered to compressor */
+ ret = stp_dbg_core_dump_in(g_core_dump, aucMsg, len);
+ if (ret == 1 && wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO)
+ stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_FALSE);
+
+ return ret;
+}
+
+INT32 stp_dbg_dump_num(LONG dmp_num)
+{
+ g_core_dump->dmp_num = dmp_num;
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type)
+{
+#define WDT_INFO_HEAD "Watch Dog Timeout"
+ PINT8 pStr = NULL;
+ PINT8 pDtr = NULL;
+ PINT8 pTemp = NULL;
+ PINT8 pTemp2 = NULL;
+ INT8 tempBuf[STP_ASSERT_TYPE_SIZE] = { 0 };
+ UINT32 len = 0;
+ LONG res;
+ INT32 ret;
+ INT32 remain_array_len = 0;
+
+ PUINT8 parser_sub_string[] = {
+ "{ASSERT} ",
+ "id=",
+ "isr=",
+ "irq=",
+ "rc="
+ };
+
+ if (!str) {
+ STP_DBG_PR_ERR("NULL string source\n");
+ return -1;
+ }
+
+ if (!g_stp_dbg_cpupcr) {
+ STP_DBG_PR_ERR("NULL pointer\n");
+ return -2;
+ }
+
+ pStr = str;
+ STP_DBG_PR_DBG("source infor:%s\n", pStr);
+ switch (type) {
+ case STP_DBG_ASSERT_INFO:
+
+
+ pDtr = osal_strstr(pStr, parser_sub_string[type]);
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr, ' ');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]);
+ return -3;
+ }
+
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("delimiter( ) is not found,substring(%s)\n",
+ parser_sub_string[type]);
+ return -4;
+ }
+
+ len = pTemp - pDtr;
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@"));
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len);
+ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_';
+
+ pTemp = osal_strchr(pDtr, '#');
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("parser '#' is not find\n");
+ return -5;
+ }
+ pTemp += 1;
+
+ pTemp2 = osal_strchr(pTemp, ' ');
+ if (pTemp2 == NULL) {
+ STP_DBG_PR_ERR("parser ' ' is not find\n");
+ pTemp2 = pTemp + 1;
+ }
+ remain_array_len = osal_array_size(g_stp_dbg_cpupcr->assert_info) - (osal_strlen("assert@") + len + 1);
+ if (remain_array_len - 1 > pTemp2 - pTemp) {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp,
+ pTemp2 - pTemp);
+ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0';
+ } else {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp,
+ remain_array_len - 1);
+ g_stp_dbg_cpupcr->assert_info[STP_ASSERT_INFO_SIZE - 1] = '\0';
+ }
+ STP_DBG_PR_INFO("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]);
+ break;
+ case STP_DBG_FW_TASK_ID:
+ pDtr = osal_strstr(pStr, parser_sub_string[type]);
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr, ' ');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]);
+ return -3;
+ }
+
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("delimiter( ) is not found,substring(%s)\n",
+ parser_sub_string[type]);
+ return -4;
+ }
+
+ len = pTemp - pDtr;
+ len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+ ret = osal_strtol(tempBuf, 16, &res);
+ if (ret) {
+ STP_DBG_PR_ERR("get fw task id fail(%d)\n", ret);
+ return -4;
+ }
+ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res;
+
+ STP_DBG_PR_INFO("fw task id :%x\n", (UINT32)res);
+ break;
+ case STP_DBG_FW_ISR:
+ pDtr = osal_strstr(pStr, parser_sub_string[type]);
+
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr, ',');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n",
+ parser_sub_string[type]);
+ return -3;
+ }
+
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n",
+ parser_sub_string[type]);
+ return -4;
+ }
+
+ len = pTemp - pDtr;
+ len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+ ret = osal_strtol(tempBuf, 16, &res);
+ if (ret) {
+ STP_DBG_PR_ERR("get fw isr id fail(%d)\n", ret);
+ return -4;
+ }
+ g_stp_dbg_cpupcr->fwIsr = (UINT32)res;
+
+ STP_DBG_PR_INFO("fw isr str:%x\n", (UINT32)res);
+ break;
+ case STP_DBG_FW_IRQ:
+ pDtr = osal_strstr(pStr, parser_sub_string[type]);
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr, ',');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]);
+ return -3;
+ }
+
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n",
+ parser_sub_string[type]);
+ return -4;
+ }
+
+ len = pTemp - pDtr;
+ len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+ ret = osal_strtol(tempBuf, 16, &res);
+ if (ret) {
+ STP_DBG_PR_ERR("get fw irq id fail(%d)\n", ret);
+ return -4;
+ }
+ g_stp_dbg_cpupcr->fwRrq = (UINT32)res;
+
+ STP_DBG_PR_INFO("fw irq value:%x\n", (UINT32)res);
+ break;
+ case STP_DBG_ASSERT_TYPE:
+ pDtr = osal_strstr(pStr, parser_sub_string[type]);
+ if (pDtr != NULL) {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr, ',');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]);
+ return -3;
+ }
+
+ if (pTemp == NULL) {
+ STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n",
+ parser_sub_string[type]);
+ return -4;
+ }
+
+ len = pTemp - pDtr;
+ len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+
+ if (osal_memcmp(tempBuf, "*", osal_strlen("*")) == 0)
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert",
+ osal_strlen("general assert"));
+ if (osal_memcmp(tempBuf, WDT_INFO_HEAD, osal_strlen(WDT_INFO_HEAD)) == 0)
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt"));
+ if (osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL")) == 0) {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len);
+
+ pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL(");
+ if (pDtr != NULL) {
+ pDtr += osal_strlen("RB_FULL(");
+ pTemp = osal_strchr(pDtr, ')');
+ } else {
+ STP_DBG_PR_ERR("parser str is NULL,substring(RB_FULL()\n");
+ return -5;
+ }
+ len = pTemp - pDtr;
+ len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len;
+ osal_memcpy(&tempBuf[0], pDtr, len);
+ tempBuf[len] = '\0';
+ ret = osal_strtol(tempBuf, 16, &res);
+ if (ret) {
+ STP_DBG_PR_ERR("get fw task id fail(%d)\n", ret);
+ return -5;
+ }
+ g_stp_dbg_cpupcr->fwTaskId = (UINT32)res;
+
+ STP_DBG_PR_INFO("update fw task id :%x\n", (UINT32)res);
+ }
+
+ STP_DBG_PR_INFO("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type);
+ break;
+ default:
+ STP_DBG_PR_ERR("unknown parser type\n");
+ break;
+ }
+
+ return 0;
+}
+
+static _osal_inline_ P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID)
+{
+ P_STP_DBG_CPUPCR_T pSdCpupcr = NULL;
+
+ pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T));
+ if (!pSdCpupcr) {
+ STP_DBG_PR_ERR("stp dbg cpupcr allocate memory fail!\n");
+ return NULL;
+ }
+
+ osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T));
+
+ osal_sleepable_lock_init(&pSdCpupcr->lock);
+
+ return pSdCpupcr;
+}
+
+static _osal_inline_ VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr)
+{
+ if (pCpupcr) {
+ osal_sleepable_lock_deinit(&pCpupcr->lock);
+ osal_free(pCpupcr);
+ pCpupcr = NULL;
+ }
+}
+
+static _osal_inline_ P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID)
+{
+ P_STP_DBG_DMAREGS_T pDmaRegs = NULL;
+
+ pDmaRegs = (P_STP_DBG_DMAREGS_T) osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T));
+ if (!pDmaRegs) {
+ STP_DBG_PR_ERR("stp dbg dmareg allocate memory fail!\n");
+ return NULL;
+ }
+
+ osal_memset(pDmaRegs, 0, osal_sizeof(STP_DBG_DMAREGS_T));
+
+ osal_sleepable_lock_init(&pDmaRegs->lock);
+
+ return pDmaRegs;
+}
+
+static VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs)
+{
+ if (pDmaRegs) {
+ osal_sleepable_lock_deinit(&pDmaRegs->lock);
+ osal_free(pDmaRegs);
+ pDmaRegs = NULL;
+ }
+}
+
+/*
+ * who call this ?
+ * - stp_dbg_soc_paged_dump
+ * generate coredump and coredump timeout
+ * - wmt_dbg_poll_cpupcr
+ * dump cpupcr through command
+ * - mtk_stp_dbg_poll_cpupcr (should remove this)
+ * export to other drivers
+ * - _stp_btm_handler
+ * coredump timeout
+ * - wmt_ctrl_rx
+ * rx timeout
+ * - stp_do_tx_timeout
+ * tx timeout
+ *
+ */
+INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd)
+{
+ INT32 i = 0;
+ UINT32 value = 0x0;
+ ENUM_WMT_CHIP_TYPE chip_type;
+ UINT8 cccr_value = 0x0;
+ INT32 chip_id = -1;
+ INT32 i_ret = 0;
+ INT32 count = 0;
+
+ if (!g_stp_dbg_cpupcr) {
+ STP_DBG_PR_ERR("NULL reference pointer\n");
+ return -1;
+ }
+
+ chip_type = wmt_detect_get_chip_type();
+
+ if (times > STP_DBG_CPUPCR_NUM)
+ times = STP_DBG_CPUPCR_NUM;
+
+ switch (chip_type) {
+ case WMT_CHIP_TYPE_COMBO:
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ for (i = 0; i < times; i++) {
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ g_stp_sdio_host_info.sdio_cltctx, SWPCDBGR, &value, 0);
+ g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count] = value;
+ osal_get_local_time(&(g_stp_dbg_cpupcr->sec_buffer[g_stp_dbg_cpupcr->count]),
+ &(g_stp_dbg_cpupcr->nsec_buffer[g_stp_dbg_cpupcr->count]));
+ if (sleep > 0)
+ osal_sleep_ms(sleep);
+ g_stp_dbg_cpupcr->count++;
+ if (g_stp_dbg_cpupcr->count >= STP_DBG_CPUPCR_NUM)
+ g_stp_dbg_cpupcr->count = 0;
+ }
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ break;
+ case WMT_CHIP_TYPE_SOC:
+ if (times > WMT_CORE_DMP_CPUPCR_NUM)
+ times = WMT_CORE_DMP_CPUPCR_NUM;
+ if (wmt_lib_dmp_consys_state(&g_dmp_info, times, sleep) == MTK_WCN_BOOL_TRUE) {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ for (i = 0; i < times; i++) {
+ g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count] = g_dmp_info.cpu_pcr[i];
+ osal_get_local_time(&(g_stp_dbg_cpupcr->sec_buffer[g_stp_dbg_cpupcr->count]),
+ &(g_stp_dbg_cpupcr->nsec_buffer[g_stp_dbg_cpupcr->count]));
+ g_stp_dbg_cpupcr->count++;
+ if (g_stp_dbg_cpupcr->count >= STP_DBG_CPUPCR_NUM)
+ g_stp_dbg_cpupcr->count = 0;
+ }
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }
+ break;
+ default:
+ STP_DBG_PR_INFO("error chip type(%d)\n", chip_type);
+ }
+
+ if (cmd) {
+ UINT8 str[DBG_LOG_STR_SIZE] = {""};
+ PUINT8 p = str;
+ INT32 str_len = 0;
+
+ for (i = 0; i < STP_DBG_CPUPCR_NUM; i++) {
+ if (g_stp_dbg_cpupcr->sec_buffer[i] == 0 &&
+ g_stp_dbg_cpupcr->nsec_buffer[i] == 0)
+ continue;
+
+ count++;
+ if (count % 4 != 0) {
+ str_len = osal_sprintf(p, "%llu.%06lu/0x%08x;",
+ g_stp_dbg_cpupcr->sec_buffer[i],
+ g_stp_dbg_cpupcr->nsec_buffer[i],
+ g_stp_dbg_cpupcr->buffer[i]);
+ p += str_len;
+ } else {
+ str_len = osal_sprintf(p, "%llu.%06lu/0x%08x;",
+ g_stp_dbg_cpupcr->sec_buffer[i],
+ g_stp_dbg_cpupcr->nsec_buffer[i],
+ g_stp_dbg_cpupcr->buffer[i]);
+ STP_DBG_PR_INFO("TIME/CPUPCR: %s\n", str);
+ p = str;
+ }
+ }
+ if (count % 4 != 0)
+ STP_DBG_PR_INFO("TIME/CPUPCR: %s\n", str);
+
+ if (wmt_lib_power_lock_trylock()) {
+ if (chip_type == WMT_CHIP_TYPE_SOC && wmt_lib_reg_readable()) {
+ STP_DBG_PR_INFO("CONNSYS cpu:0x%x/bus:0x%x/dbg_cr1:0x%x/dbg_cr2:0x%x/EMIaddr:0x%x\n",
+ stp_dbg_soc_read_debug_crs(CONNSYS_CPU_CLK),
+ stp_dbg_soc_read_debug_crs(CONNSYS_BUS_CLK),
+ stp_dbg_soc_read_debug_crs(CONNSYS_DEBUG_CR1),
+ stp_dbg_soc_read_debug_crs(CONNSYS_DEBUG_CR2),
+ stp_dbg_soc_read_debug_crs(CONNSYS_EMI_REMAP));
+ }
+ wmt_lib_power_lock_release();
+ }
+
+ chip_id = mtk_wcn_wmt_chipid_query();
+ if (chip_id == 0x6632) {
+ for (i = 0; i < 8; i++) {
+ i_ret = mtk_wcn_hif_sdio_f0_readb(g_stp_sdio_host_info.sdio_cltctx,
+ CCCR_F8 + i, &cccr_value);
+ if (i_ret)
+ STP_DBG_PR_ERR("read CCCR fail(%d), address(0x%x)\n",
+ i_ret, CCCR_F8 + i);
+ else
+ STP_DBG_PR_INFO("read CCCR value(0x%x), address(0x%x)\n",
+ cccr_value, CCCR_F8 + i);
+ cccr_value = 0x0;
+ }
+ }
+ /* Need in platform code - mtxxxx.c to provide function implementation */
+ mtk_wcn_consys_hang_debug();
+ }
+ if (chip_type == WMT_CHIP_TYPE_COMBO) {
+ STP_DBG_PR_INFO("dump sdio register for debug\n");
+ mtk_stp_dump_sdio_register();
+ }
+ return 0;
+}
+
+INT32 stp_dbg_dump_cpupcr_reg_info(PUINT8 buf, UINT32 consys_lp_reg)
+{
+ INT32 i = 0;
+ INT32 count = 0;
+ UINT32 len = 0;
+
+ /* never retrun negative value */
+ if (!g_stp_dbg_cpupcr || !buf) {
+ STP_DBG_PR_DBG("NULL pointer, g_stp_dbg_cpupcr:%p, buf:%p\n",
+ g_stp_dbg_cpupcr, buf);
+ return 0;
+ }
+
+ for (i = 0; i < STP_DBG_CPUPCR_NUM; i++) {
+ if (g_stp_dbg_cpupcr->sec_buffer[i] == 0 &&
+ g_stp_dbg_cpupcr->nsec_buffer[i] == 0)
+ continue;
+ count++;
+ if (count == 1)
+ len += osal_sprintf(buf + len, "0x%08x", g_stp_dbg_cpupcr->buffer[i]);
+ else
+ len += osal_sprintf(buf + len, ";0x%08x", g_stp_dbg_cpupcr->buffer[i]);
+ }
+
+ if (count == 0)
+ len += osal_sprintf(buf + len, "0x%08x\n", consys_lp_reg);
+ else
+ len += osal_sprintf(buf + len, ";0x%08x\n", consys_lp_reg);
+
+ stp_dbg_clear_cpupcr_reg_info();
+
+ return len;
+}
+
+VOID stp_dbg_clear_cpupcr_reg_info(VOID)
+{
+ if (osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock)) {
+ STP_DBG_PR_DBG("lock failed\n");
+ return;
+ }
+
+ osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM);
+ g_stp_dbg_cpupcr->count = 0;
+ g_stp_dbg_cpupcr->host_assert_info.reason = 0;
+ g_stp_dbg_cpupcr->host_assert_info.drv_type = 0;
+ g_stp_dbg_cpupcr->issue_type = STP_FW_ISSUE_TYPE_INVALID;
+ g_stp_dbg_cpupcr->keyword[0] = '\0';
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+}
+
+INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep)
+{
+#if 0
+ INT32 i = 0;
+
+ if (!g_stp_dbg_dmaregs) {
+ STP_DBG_PR_ERR("NULL reference pointer\n");
+ return -1;
+ }
+
+ osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock);
+
+ if (g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM) {
+ if (g_stp_dbg_dmaregs->count > STP_DBG_DMAREGS_NUM) {
+ STP_DBG_PR_ERR("g_stp_dbg_dmaregs->count:%d must less than STP_DBG_DMAREGS_NUM:%d\n",
+ g_stp_dbg_dmaregs->count, STP_DBG_DMAREGS_NUM);
+ g_stp_dbg_dmaregs->count = 0;
+ STP_DBG_PR_ERR("g_stp_dbg_dmaregs->count be set default value 0\n");
+ }
+ times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count;
+ }
+ if (times > STP_DBG_DMAREGS_NUM) {
+ STP_DBG_PR_ERR("times overflow, set default value:0\n");
+ times = 0;
+ }
+
+ for (i = 0; i < times; i++) {
+ INT32 k = 0;
+
+ for (; k < DMA_REGS_MAX; k++) {
+ STP_DBG_PR_INFO("times:%d,i:%d reg: %s, regs:%08x\n", times, i, dmaRegsStr[k],
+ wmt_plat_read_dmaregs(k));
+ /* g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] =
+ * wmt_plat_read_dmaregs(k);
+ */
+ }
+ osal_sleep_ms(sleep);
+ }
+
+ g_stp_dbg_dmaregs->count += times;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock);
+#else
+ return 0;
+#endif
+}
+
+INT32 stp_dbg_poll_cpupcr_ctrl(UINT32 en)
+{
+ STP_DBG_PR_INFO("%s polling cpupcr\n", en == 0 ? "start" : "stop");
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->stop_flag = en;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ return 0;
+}
+
+INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, PUINT8 pPatchBrh)
+{
+ if (g_stp_dbg_cpupcr) {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->chipId = chipid;
+
+ if (pRomVer)
+ osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2);
+ if (pPatchVer)
+ osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8);
+ if (pPatchBrh)
+ osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4);
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ } else {
+ STP_DBG_PR_ERR("NULL pointer\n");
+ return -1;
+ }
+
+ STP_DBG_PR_DBG("chipid(0x%x),romver(%s),patchver(%s),branchver(%s)\n",
+ g_stp_dbg_cpupcr->chipId,
+ &g_stp_dbg_cpupcr->romVer[0],
+ &g_stp_dbg_cpupcr->patchVer[0],
+ &g_stp_dbg_cpupcr->branchVer[0]);
+
+ return 0;
+}
+
+INT32 stp_dbg_set_wifiver(UINT32 wifiver)
+{
+ if (!g_stp_dbg_cpupcr) {
+ STP_DBG_PR_ERR("NULL pointer\n");
+ return -1;
+ }
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->wifiVer = wifiver;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ STP_DBG_PR_INFO("wifiver(%x)\n", g_stp_dbg_cpupcr->wifiVer);
+
+ return 0;
+}
+
+INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en)
+{
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en;
+ g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type;
+ g_stp_dbg_cpupcr->host_assert_info.reason = reason;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ return 0;
+}
+
+VOID stp_dbg_set_keyword(PINT8 keyword)
+{
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ if (keyword != NULL) {
+ if (osal_strlen(keyword) >= STP_DBG_KEYWORD_SIZE)
+ STP_DBG_PR_INFO("Keyword over max size(%d)\n", STP_DBG_KEYWORD_SIZE);
+ else if (osal_strchr(keyword, '<') != NULL || osal_strchr(keyword, '>') != NULL)
+ STP_DBG_PR_INFO("Keyword has < or >, keywrod: %s\n", keyword);
+ else
+ osal_strncat(&g_stp_dbg_cpupcr->keyword[0], keyword, osal_strlen(keyword));
+ } else {
+ g_stp_dbg_cpupcr->keyword[0] = '\0';
+ }
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+}
+
+UINT32 stp_dbg_get_host_trigger_assert(VOID)
+{
+ return g_stp_dbg_cpupcr->host_assert_info.assert_from_host;
+}
+
+VOID stp_dbg_set_coredump_timer_state(CORE_DUMP_STA state)
+{
+ if (g_core_dump)
+ g_core_dump->sm = state;
+}
+
+INT32 stp_dbg_get_coredump_timer_state(VOID)
+{
+ if (g_core_dump)
+ return g_core_dump->sm;
+ return -1;
+}
+
+INT32 stp_dbg_set_fw_info(PUINT8 issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type)
+{
+ ENUM_ASSERT_INFO_PARSER_TYPE type_index;
+ PUINT8 tempbuf = NULL;
+ UINT32 i = 0;
+ INT32 iRet = 0;
+
+ if (issue_info == NULL) {
+ STP_DBG_PR_ERR("null issue infor\n");
+ return -1;
+ }
+
+ if (g_stp_dbg_cpupcr->issue_type &&
+ g_stp_dbg_cpupcr->issue_type != STP_HOST_TRIGGER_COLLECT_FTRACE) {
+ STP_DBG_PR_ERR("assert information has been set up\n");
+ return -1;
+ }
+
+ STP_DBG_PR_INFO("issue type(%d)\n", issue_type);
+ g_stp_dbg_cpupcr->issue_type = issue_type;
+ osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE);
+
+ /*print patch version when assert happened */
+ STP_DBG_PR_INFO("[consys patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer);
+ STP_DBG_PR_INFO("[consys patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer);
+
+ if ((issue_type == STP_FW_ASSERT_ISSUE) ||
+ (issue_type == STP_HOST_TRIGGER_FW_ASSERT) ||
+ (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT) ||
+ (issue_type == STP_HOST_TRIGGER_COLLECT_FTRACE) ||
+ (issue_type == STP_FW_ABT)) {
+ if ((issue_type == STP_FW_ASSERT_ISSUE) || (issue_type == STP_HOST_TRIGGER_FW_ASSERT)
+ || (issue_type == STP_FW_ABT)) {
+ tempbuf = osal_malloc(len + 1);
+ if (!tempbuf)
+ return -2;
+
+ osal_memcpy(&tempbuf[0], issue_info, len);
+
+ for (i = 0; i < len; i++) {
+ if (tempbuf[i] == '\0')
+ tempbuf[i] = '?';
+ else if (tempbuf[i] == '<')
+ tempbuf[i] = '{';
+ else if (tempbuf[i] == '>')
+ tempbuf[i] = '}';
+ }
+
+ tempbuf[len] = '\0';
+
+ for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX;
+ type_index++) {
+ iRet = stp_dbg_parser_assert_str(&tempbuf[0], type_index);
+ if (iRet)
+ STP_DBG_PR_INFO("fail to parse assert str %s, type = %d, ret = %d\n",
+ &tempbuf[0], type_index, iRet);
+ }
+
+ }
+ if ((issue_type == STP_HOST_TRIGGER_FW_ASSERT) ||
+ (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT) ||
+ (issue_type == STP_HOST_TRIGGER_COLLECT_FTRACE)) {
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) {
+ case WMTDRV_TYPE_BT:
+ STP_DBG_PR_INFO("BT trigger assert\n");
+ if (g_stp_dbg_cpupcr->host_assert_info.reason != 31)
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_BT; /*BT firmware trigger assert */
+ else {
+ /*BT stack trigger assert */
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_NATBT;
+ }
+ break;
+ case WMTDRV_TYPE_FM:
+ STP_DBG_PR_INFO("FM trigger assert\n");
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_FM;
+ break;
+ case WMTDRV_TYPE_GPS:
+ STP_DBG_PR_INFO("GPS trigger assert\n");
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVGPS;
+ break;
+ case WMTDRV_TYPE_GPSL5:
+ STP_DBG_PR_INFO("GPSL5 trigger assert\n");
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVGPS;
+ break;
+ case WMTDRV_TYPE_WIFI:
+ STP_DBG_PR_INFO("WIFI trigger assert\n");
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVWIFI;
+ break;
+ case WMTDRV_TYPE_WMT:
+ STP_DBG_PR_INFO("WMT trigger assert\n");
+ if (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT)
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
+ /* 30: adb trigger assert */
+ /* 43: process packet fail count > 10 */
+ /* 44: rx timeout with pending data */
+ /* 45: tx timeout with pending data */
+ if (g_stp_dbg_cpupcr->host_assert_info.reason == 30 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 43 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 44 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 45)
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVSTP;
+ else
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT;
+ break;
+ default:
+ break;
+ }
+ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ } else if (issue_type == STP_FW_ABT) {
+ INT32 copyLen = (len < STP_ASSERT_INFO_SIZE ? len : STP_ASSERT_INFO_SIZE - 1);
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], tempbuf, copyLen);
+ g_stp_dbg_cpupcr->assert_info[copyLen] = '\0';
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }
+
+ if (tempbuf)
+ osal_free(tempbuf);
+ } else if (issue_type == STP_FW_NOACK_ISSUE) {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVSTP;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ } else if (issue_type == STP_DBG_PROC_TEST) {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ } else if (issue_type == STP_FW_WARM_RST_ISSUE) {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
+ g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ } else {
+ STP_DBG_PR_ERR("invalid issue type(%d)\n", issue_type);
+ return -3;
+ }
+
+ return 0;
+}
+
+INT32 stp_dbg_cpupcr_infor_format(PUINT8 buf, UINT32 max_len)
+{
+ UINT32 len = 0;
+ UINT32 i = 0;
+
+ /* never retrun negative value */
+ if (!g_stp_dbg_cpupcr || !buf) {
+ STP_DBG_PR_ERR("NULL pointer, g_stp_dbg_cpupcr:%p, buf:%p\n",
+ g_stp_dbg_cpupcr, buf);
+ return 0;
+ }
+
+ /* format common information about issue */
+ /* max_len can guarantee there's enough buffer for section */
+ len = osal_sprintf(buf, "\n\t");
+ len += osal_sprintf(buf + len, "\n\t\tMT%x\n\t\n\t",
+ g_stp_dbg_cpupcr->chipId);
+ len += osal_sprintf(buf + len, "\n\t\t");
+ len += osal_sprintf(buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->romVer);
+ if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", strlen("ALPS"))))
+ len += osal_sprintf(buf + len, "Internal Dev\n\t\t",
+ g_stp_dbg_cpupcr->branchVer);
+ else
+ len += osal_sprintf(buf + len, "W%sMP\n\t\t",
+ g_stp_dbg_cpupcr->branchVer);
+
+ len += osal_sprintf(buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->patchVer);
+
+ if (g_stp_dbg_cpupcr->wifiVer == 0)
+ len += osal_sprintf(buf + len, "NULL\n\t");
+ else
+ len += osal_sprintf(buf + len, "0x%X.%X\n\t",
+ (UINT8)((g_stp_dbg_cpupcr->wifiVer & 0xFF00)>>8),
+ (UINT8)(g_stp_dbg_cpupcr->wifiVer & 0xFF));
+
+ len += osal_sprintf(buf + len, "\n\t");
+
+ /*format issue information: no ack, assert */
+ len += osal_sprintf(buf + len, "\n\t\t\n\t\t\t");
+ if ((g_stp_dbg_cpupcr->issue_type == STP_FW_NOACK_ISSUE) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_DBG_PROC_TEST) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_FW_WARM_RST_ISSUE) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_FW_ABT)) {
+ len += osal_sprintf(buf + len, "%s\n\t\t\n\t\t\n\t\t\t",
+ g_stp_dbg_cpupcr->assert_info);
+ len += osal_sprintf(buf + len, "NULL\n\t\t\n\t\n\t");
+ len += osal_sprintf(buf + len, "\n\t\tNULL\n\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t");
+ len += osal_sprintf(buf + len, "\n\t\t\t%s\n\t\t\t",
+ stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
+ len += osal_sprintf(buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq);
+ len += osal_sprintf(buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr);
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "%s\n\t\t\t",
+ g_stp_dbg_cpupcr->keyword);
+ } else if ((g_stp_dbg_cpupcr->issue_type == STP_FW_ASSERT_ISSUE) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_FW_ASSERT) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT)) {
+ len += osal_sprintf(buf + len, "%s\n\t\t\n\t\t\n\t\t\t",
+ g_stp_dbg_cpupcr->assert_info);
+ len += osal_sprintf(buf + len, "%s\n\t\t\n\t\n\t",
+ g_stp_dbg_cpupcr->assert_type);
+ len += osal_sprintf(buf + len, "\n\t\tNULL\n\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t");
+ len += osal_sprintf(buf + len, "\n\t\t\t%s\n\t\t\t",
+ stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
+ if (g_stp_dbg_cpupcr->host_assert_info.reason == 32 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 33 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 34 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 35 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 36 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 37 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 38 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 39 ||
+ g_stp_dbg_cpupcr->host_assert_info.reason == 40) {
+ /*handling wmt turn on/off bt cmd has ack but no evt issue */
+ /*one of both the irqx and irs is nULL, then use task to find MOF */
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ } else
+ len += osal_sprintf(buf + len, "IRQ_0x%x\n\t\t\t",
+ g_stp_dbg_cpupcr->fwRrq);
+ len += osal_sprintf(buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr);
+
+ if (g_stp_dbg_cpupcr->issue_type == STP_FW_ASSERT_ISSUE) {
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ }
+
+ if ((g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_FW_ASSERT) ||
+ (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT)) {
+ len += osal_sprintf(buf + len, "%d\n\t\t\t",
+ g_stp_dbg_cpupcr->host_assert_info.drv_type);
+ len += osal_sprintf(buf + len, "%d\n\t\t\t",
+ g_stp_dbg_cpupcr->host_assert_info.reason);
+ }
+
+ len += osal_sprintf(buf + len, "%s\n\t\t\t",
+ g_stp_dbg_cpupcr->keyword);
+ } else {
+ len += osal_sprintf(buf + len, "NULL\n\t\t\n\t\t\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\n\t\n\t");
+ len += osal_sprintf(buf + len, "\n\t\tNULL\n\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t");
+ len += osal_sprintf(buf + len, "\n\t\t\t%s\n\t\t\t",
+ stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "NULL\n\t\t\t");
+ len += osal_sprintf(buf + len, "%s\n\t\t\t",
+ g_stp_dbg_cpupcr->keyword);
+ }
+
+ len += osal_sprintf(buf + len, "");
+ STP_DBG_PR_INFO("stp-dbg:sub len1 for debug(%d)\n", len);
+
+ if (!g_stp_dbg_cpupcr->count)
+ len += osal_sprintf(buf + len, "NULL");
+ else {
+ for (i = 0; i < g_stp_dbg_cpupcr->count; i++)
+ len += osal_sprintf(buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]);
+ }
+ STP_DBG_PR_INFO("stp-dbg:sub len2 for debug(%d)\n", len);
+ len += osal_sprintf(buf + len, "\n\t\t\t");
+ len += osal_sprintf(buf + len,
+ "NULL\n\t\t\n\t\n\n");
+
+ STP_DBG_PR_INFO("buffer len[%d]\n", len);
+ /* STP_DBG_PR_INFO("Format infor:\n%s\n",buf); */
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM);
+ g_stp_dbg_cpupcr->count = 0;
+ g_stp_dbg_cpupcr->host_assert_info.reason = 0;
+ g_stp_dbg_cpupcr->host_assert_info.drv_type = 0;
+ g_stp_dbg_cpupcr->issue_type = STP_FW_ISSUE_TYPE_INVALID;
+ g_stp_dbg_cpupcr->keyword[0] = '\0';
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ return len;
+}
+
+PUINT8 stp_dbg_id_to_task(UINT32 id)
+{
+ ENUM_WMT_CHIP_TYPE chip_type;
+ PUINT8 task_id = NULL;
+
+ chip_type = wmt_detect_get_chip_type();
+ switch (chip_type) {
+ case WMT_CHIP_TYPE_COMBO:
+ task_id = stp_dbg_combo_id_to_task(id);
+ break;
+ case WMT_CHIP_TYPE_SOC:
+ task_id = stp_dbg_soc_id_to_task(id);
+ break;
+ default:
+ STP_DBG_PR_ERR("error chip type(%d)\n", chip_type);
+ }
+
+ return task_id;
+}
+
+VOID stp_dbg_reset(VOID)
+{
+ if (g_stp_dbg_cpupcr) {
+ osal_memset(g_stp_dbg_cpupcr->buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->buffer));
+ osal_memset(g_stp_dbg_cpupcr->sec_buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->sec_buffer));
+ osal_memset(g_stp_dbg_cpupcr->nsec_buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->nsec_buffer));
+ }
+
+ if (g_stp_dbg_dmaregs) {
+ g_stp_dbg_dmaregs->count = 0;
+ osal_memset(g_stp_dbg_dmaregs->dmaIssue, 0, osal_sizeof(g_stp_dbg_dmaregs->dmaIssue));
+ }
+}
+
+MTKSTP_DBG_T *stp_dbg_init(PVOID btm_half)
+{
+ MTKSTP_DBG_T *stp_dbg = NULL;
+
+ stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL);
+ if (stp_dbg == NULL)
+ goto ERR_EXIT1;
+ if (IS_ERR(stp_dbg)) {
+ STP_DBG_PR_ERR("-ENOMEM\n");
+ goto ERR_EXIT1;
+ }
+
+ stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T));
+ if (stp_dbg->logsys == NULL)
+ goto ERR_EXIT2;
+ if (IS_ERR(stp_dbg->logsys)) {
+ STP_DBG_PR_ERR("-ENOMEM stp_gdb->logsys\n");
+ goto ERR_EXIT2;
+ }
+ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T));
+ spin_lock_init(&(stp_dbg->logsys->lock));
+ INIT_WORK(&(stp_dbg->logsys->dump_work), stp_dbg_dmp_print_work);
+ stp_dbg->pkt_trace_no = 0;
+ stp_dbg->is_enable = 0;
+ g_stp_dbg = stp_dbg;
+
+ if (btm_half != NULL)
+ stp_dbg->btm = btm_half;
+ else
+ stp_dbg->btm = NULL;
+
+ g_core_dump = stp_dbg_core_dump_init(STP_CORE_DUMP_TIMEOUT);
+ if (!g_core_dump) {
+ STP_DBG_PR_ERR("-ENOMEM wcn_coer_dump_init fail!");
+ goto ERR_EXIT2;
+ }
+ g_stp_dbg_cpupcr = stp_dbg_cpupcr_init();
+ if (!g_stp_dbg_cpupcr) {
+ STP_DBG_PR_ERR("-ENOMEM stp_dbg_cpupcr_init fail!");
+ goto ERR_EXIT2;
+ }
+ g_stp_dbg_dmaregs = stp_dbg_dmaregs_init();
+ if (!g_stp_dbg_dmaregs) {
+ STP_DBG_PR_ERR("-ENOMEM stp_dbg_dmaregs_init fail!");
+ goto ERR_EXIT2;
+ }
+ return stp_dbg;
+
+ERR_EXIT2:
+ stp_dbg_deinit(stp_dbg);
+ return NULL;
+
+ERR_EXIT1:
+ kfree(stp_dbg);
+ return NULL;
+}
+
+INT32 stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg)
+{
+ stp_dbg_core_dump_deinit(g_core_dump);
+
+ stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr);
+ stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs);
+ /* unbind with netlink */
+ stp_dbg_nl_deinit();
+
+ if (stp_dbg->logsys)
+ vfree(stp_dbg->logsys);
+
+ kfree(stp_dbg);
+
+ return 0;
+}
+
+INT32 stp_dbg_start_coredump_timer(VOID)
+{
+ if (!g_core_dump) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ return osal_timer_modify(&g_core_dump->dmp_timer, STP_CORE_DUMP_TIMEOUT);
+}
+
+INT32 stp_dbg_start_emi_dump(VOID)
+{
+ INT32 ret = 0;
+
+ if (!g_core_dump) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(false);
+ /* Disable MCIF EMI protection */
+ mtk_wcn_wmt_set_mcif_mpu_protection(false);
+ stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING);
+ osal_timer_modify(&g_core_dump->dmp_emi_timer, STP_EMI_DUMP_TIMEOUT);
+ ret = stp_dbg_nl_send_data(EMICOREDUMP_CMD, sizeof(EMICOREDUMP_CMD));
+ if (ret)
+ stp_dbg_stop_emi_dump();
+
+ return ret ? -1 : 0;
+}
+
+INT32 stp_dbg_stop_emi_dump(VOID)
+{
+ if (!g_core_dump) {
+ STP_DBG_PR_ERR("invalid pointer!\n");
+ return -1;
+ }
+
+ if (mtk_wcn_stp_emi_dump_flag_get() == 1) {
+ STP_DBG_PR_ERR("stopping emi dump!\n");
+ return -2;
+ }
+
+ mtk_wcn_stp_emi_dump_flag_ctrl(1);
+ /* Enable MCIF EMI protection */
+ mtk_wcn_wmt_set_mcif_mpu_protection(true);
+ if (mtk_wcn_wlan_emi_mpu_set_protection)
+ (*mtk_wcn_wlan_emi_mpu_set_protection)(true);
+ osal_timer_stop(&g_core_dump->dmp_emi_timer);
+ return 0;
+}
+
+INT32 stp_dbg_nl_send_data(const PINT8 buf, INT32 len)
+{
+ PINT8 pdata = NULL;
+ INT32 ret = 0;
+
+ pdata = kmalloc(len+5, GFP_KERNEL);
+ if (!pdata)
+ return -1;
+ pdata[0] = '[';
+ pdata[1] = 'M';
+ pdata[2] = ']';
+ osal_memcpy(&pdata[3], &len, 2);
+ osal_memcpy(&pdata[5], buf, len);
+ ret = stp_dbg_dump_send_retry_handler(pdata, len);
+ kfree(pdata);
+ return ret;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c
new file mode 100644
index 0000000000000000000000000000000000000000..796c98fce8d6f7309fbea9060733ec074ba4d473
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include "stp_dbg.h"
+#include "stp_dbg_combo.h"
+
+static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_aee(VOID);
+static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_nl(VOID);
+
+static PUINT8 combo_task_str[STP_DBG_TASK_ID_MAX] = {
+ "Task_WMT",
+ "Task_BT",
+ "Task_Wifi",
+ "Task_Tst",
+ "Task_FM",
+ "Task_GPS",
+ "Task_FLP",
+ "Task_BAL",
+ "Task_Idle",
+ "Task_DrvStp",
+ "Task_DrvSdio",
+ "Task_NatBt",
+ "Task_DrvWifi",
+ "Task_GPS"
+};
+
+INT32 const combo_legacy_task_id_adapter[STP_DBG_TASK_ID_MAX] = {
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_BT,
+ STP_DBG_TASK_WIFI,
+ STP_DBG_TASK_TST,
+ STP_DBG_TASK_FM,
+ STP_DBG_TASK_IDLE,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_DRVSTP,
+ STP_DBG_TASK_BUS,
+ STP_DBG_TASK_NATBT,
+ STP_DBG_TASK_DRVWIFI,
+ STP_DBG_TASK_DRVGPS
+};
+
+static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_aee(VOID)
+{
+ static UINT8 buf[2048];
+ static UINT8 tmp[2048];
+
+ UINT32 buf_len;
+ STP_PACKET_T *pkt = NULL;
+ STP_DBG_HDR_T *hdr = NULL;
+ INT32 remain = 0;
+ INT32 retry = 0;
+ INT32 ret = 0;
+
+ do {
+ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len);
+ if (buf_len > 0) {
+ pkt = (STP_PACKET_T *) buf;
+ hdr = &pkt->hdr;
+ if (hdr->dbg_type == STP_DBG_FW_DMP) {
+ if (pkt->hdr.len <= 1500) {
+ tmp[pkt->hdr.len] = '\n';
+ tmp[pkt->hdr.len + 1] = '\0';
+ if (pkt->hdr.len < STP_DMP_SZ)
+ osal_memcpy(&tmp[0], pkt->raw, pkt->hdr.len);
+ else
+ osal_memcpy(&tmp[0], pkt->raw, STP_DMP_SZ);
+ ret = stp_dbg_aee_send(tmp, pkt->hdr.len, 0);
+ } else {
+ STP_DBG_PR_INFO("dump entry length is over long\n");
+ osal_bug_on(0);
+ }
+ retry = 0;
+ }
+ retry = 0;
+ } else {
+ retry++;
+ osal_sleep_ms(20);
+ }
+ } while ((remain > 0) || (retry < 10));
+
+ return ret;
+}
+
+static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_nl(VOID)
+{
+#define NUM_FETCH_ENTRY 8
+
+ static UINT8 buf[2048];
+ static UINT8 tmp[2048];
+
+ UINT32 buf_len;
+ STP_PACKET_T *pkt = NULL;
+ STP_DBG_HDR_T *hdr = NULL;
+ INT32 remain = 0;
+ INT32 index = 0;
+ INT32 retry = 0;
+ INT32 ret = 0;
+ INT32 len;
+
+ index = 0;
+ tmp[index++] = '[';
+ tmp[index++] = 'M';
+ tmp[index++] = ']';
+
+ do {
+ index = 3;
+ remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len);
+ if (buf_len > 0) {
+ pkt = (STP_PACKET_T *) buf;
+ hdr = &pkt->hdr;
+ len = pkt->hdr.len;
+ osal_memcpy(&tmp[index], &len, 2);
+ index += 2;
+ if (hdr->dbg_type == STP_DBG_FW_DMP) {
+ osal_memcpy(&tmp[index], pkt->raw, pkt->hdr.len);
+
+ if (pkt->hdr.len <= 1500) {
+ tmp[index + pkt->hdr.len] = '\n';
+ tmp[index + pkt->hdr.len + 1] = '\0';
+
+ /* pr_warn("\n%s\n+++\n", tmp); */
+ ret = stp_dbg_dump_send_retry_handler((PINT8)&tmp, len);
+ if (ret)
+ break;
+
+ /* schedule(); */
+ } else {
+ STP_DBG_PR_INFO("dump entry length is over long\n");
+ osal_bug_on(0);
+ }
+ retry = 0;
+ }
+ } else {
+ retry++;
+ osal_sleep_ms(100);
+ }
+ } while ((remain > 0) || (retry < 2));
+
+ return ret;
+}
+
+INT32 stp_dbg_combo_core_dump(INT32 dump_sink)
+{
+ INT32 ret = 0;
+
+ switch (dump_sink) {
+ case 0:
+ STP_DBG_PR_INFO("coredump is disabled!\n");
+ break;
+ case 1:
+ ret = stp_dbg_combo_put_dump_to_aee();
+ break;
+ case 2:
+ ret = stp_dbg_combo_put_dump_to_nl();
+ break;
+ default:
+ ret = -1;
+ STP_DBG_PR_ERR("unknown sink %d\n", dump_sink);
+ }
+
+ return ret;
+}
+
+PUINT8 stp_dbg_combo_id_to_task(UINT32 id)
+{
+ UINT32 chip_id = mtk_wcn_wmt_chipid_query();
+ UINT32 temp_id;
+
+ if (id >= STP_DBG_TASK_ID_MAX) {
+ STP_DBG_PR_ERR("task id(%d) overflow(%d)\n", id, STP_DBG_TASK_ID_MAX);
+ return NULL;
+ }
+
+ switch (chip_id) {
+ case 0x6632:
+ temp_id = id;
+ break;
+ default:
+ temp_id = combo_legacy_task_id_adapter[id];
+ break;
+ }
+
+ return combo_task_str[temp_id];
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c
new file mode 100644
index 0000000000000000000000000000000000000000..15ebea85608f700e09e9eb9ca4945158b36b0831
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include "stp_dbg.h"
+#include "stp_dbg_soc.h"
+#include "btm_core.h"
+#include "stp_core.h"
+#include "mtk_wcn_consys_hw.h"
+#include "wmt_step.h"
+#include "wmt_lib.h"
+#include
+
+#define STP_DBG_PAGED_TRACE_SIZE (2048*sizeof(char))
+#define SUB_PKT_SIZE 1024
+#define EMI_SYNC_TIMEOUT 100 /* FW guarantee that MCU copy data time is ~20ms. We set 100ms for safety */
+#define IS_VISIBLE_CHAR(c) ((c) >= 32 && (c) <= 126)
+#define DUMP_LOG_BYTES_PER_LINE (128)
+
+#define ROM_V2_PATCH "ROMv2"
+#define ROM_V3_PATCH "ROMv3"
+#define ROM_V4_PATCH "ROMv4"
+
+ENUM_STP_FW_ISSUE_TYPE issue_type;
+UINT8 g_paged_trace_buffer[STP_DBG_PAGED_TRACE_SIZE] = { 0 };
+UINT32 g_paged_trace_len;
+UINT8 g_paged_dump_buffer[STP_DBG_PAGED_DUMP_BUFFER_SIZE] = { 0 };
+UINT32 g_paged_dump_len;
+
+static PUINT8 soc_task_str[STP_DBG_TASK_ID_MAX] = {
+ "Task_WMT",
+ "Task_BT",
+ "Task_Wifi",
+ "Task_Tst",
+ "Task_FM",
+ "Task_GPS",
+ "Task_FLP",
+ "Task_BT2",
+ "Task_Idle",
+ "Task_DrvStp",
+ "Task_DrvBtif",
+ "Task_NatBt",
+ "Task_DrvWifi",
+ "Task_GPS"
+};
+
+INT32 const soc_gen_two_task_id_adapter[STP_DBG_TASK_ID_MAX] = {
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_BT,
+ STP_DBG_TASK_WIFI,
+ STP_DBG_TASK_TST,
+ STP_DBG_TASK_FM,
+ STP_DBG_TASK_IDLE,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_DRVSTP,
+ STP_DBG_TASK_BUS,
+ STP_DBG_TASK_NATBT,
+ STP_DBG_TASK_DRVWIFI,
+ STP_DBG_TASK_DRVGPS
+};
+
+INT32 const soc_gen_three_task_id_adapter[STP_DBG_TASK_ID_MAX] = {
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_BT,
+ STP_DBG_TASK_WIFI,
+ STP_DBG_TASK_TST,
+ STP_DBG_TASK_FM,
+ STP_DBG_TASK_GPS,
+ STP_DBG_TASK_FLP,
+ STP_DBG_TASK_IDLE,
+ STP_DBG_TASK_WMT,
+ STP_DBG_TASK_DRVSTP,
+ STP_DBG_TASK_BUS,
+ STP_DBG_TASK_NATBT,
+ STP_DBG_TASK_DRVWIFI,
+ STP_DBG_TASK_DRVGPS
+};
+
+static _osal_inline_ INT32 stp_dbg_soc_paged_dump(INT32 dump_sink);
+static _osal_inline_ INT32 stp_dbg_soc_paged_trace(VOID);
+static _osal_inline_ INT32 stp_dbg_soc_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len);
+static _osal_inline_ VOID stp_dbg_soc_emi_dump_buffer(UINT8 *buffer, UINT32 len);
+
+static VOID stp_dbg_dump_log(PUINT8 buf, INT32 size)
+{
+ INT32 i = 0;
+ UINT8 line[DUMP_LOG_BYTES_PER_LINE + 1];
+
+ while (size--) {
+ if (IS_VISIBLE_CHAR(*buf))
+ line[i] = *buf;
+ else
+ line[i] = '.';
+ i++;
+ buf++;
+
+ if (i >= DUMP_LOG_BYTES_PER_LINE || !size) {
+ line[i] = 0;
+ pr_info("page_trace: %s\n", line);
+ i = 0;
+ }
+ }
+}
+
+static _osal_inline_ VOID stp_dbg_soc_emi_dump_buffer(UINT8 *buffer, UINT32 len)
+{
+ UINT32 i = 0;
+
+ if (len > 16)
+ len = 16;
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0 && i != 0)
+ pr_cont("\n ");
+
+ if (buffer[i] == ']' || buffer[i] == '[' || buffer[i] == ',')
+ pr_cont("%c", buffer[i]);
+ else
+ pr_cont("0x%02x ", buffer[i]);
+ }
+}
+
+static _osal_inline_ INT32 stp_dbg_soc_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len)
+{
+ static UINT8 tmp[SUB_PKT_SIZE + NL_PKT_HEADER_LEN];
+ INT32 remain = dump_len, index = 0;
+ INT32 ret = 0;
+ INT32 len;
+ INT32 offset = 0;
+
+ if (dump_len > 0) {
+ index = 0;
+ tmp[index++] = '[';
+ tmp[index++] = 'M';
+ tmp[index++] = ']';
+
+ do {
+ index = 3;
+ if (remain >= SUB_PKT_SIZE)
+ len = SUB_PKT_SIZE;
+ else
+ len = remain;
+ remain -= len;
+
+ osal_memcpy(&tmp[index], &len, 2);
+ index += 2;
+ osal_memcpy(&tmp[index], data_buf + offset, len);
+ offset += len;
+ STP_DBG_PR_DBG("send %d remain %d\n", len, remain);
+
+ ret = stp_dbg_dump_send_retry_handler((PINT8)&tmp, len);
+ if (ret)
+ break;
+
+ /* schedule(); */
+ } while (remain > 0);
+ } else
+ STP_DBG_PR_INFO("dump entry length is 0\n");
+
+ return ret;
+}
+
+static _osal_inline_ UINT64 stp_dbg_soc_elapsed_time(UINT64 ts, ULONG nsec)
+{
+ UINT64 current_ts = 0;
+ ULONG current_nsec = 0;
+
+ osal_get_local_time(¤t_ts, ¤t_nsec);
+ return (current_ts*1000 + current_nsec/1000) - (ts*1000 + nsec/1000);
+}
+
+static _osal_inline_ INT32 stp_dbg_soc_paged_dump(INT32 dump_sink)
+{
+ INT32 ret = 0;
+ UINT32 counter = 0;
+ UINT32 dump_num = 0;
+ UINT32 packet_num = STP_PAGED_DUMP_TIME_LIMIT/100;
+ UINT32 page_counter = 0;
+ ENUM_CHIP_DUMP_STATE chip_state;
+ UINT32 dump_phy_addr = 0;
+ PUINT8 dump_vir_addr = NULL;
+ INT32 dump_len = 0;
+ P_CONSYS_EMI_ADDR_INFO p_ecsi;
+ UINT64 start_ts = 0;
+ ULONG start_nsec = 0;
+ UINT64 elapsed_time = 0;
+ INT32 abort = 0;
+#if WMT_DBG_SUPPORT
+ static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1);
+#endif
+
+ g_paged_dump_len = 0;
+ p_ecsi = wmt_plat_get_emi_phy_add();
+ osal_assert(p_ecsi);
+ if (p_ecsi == NULL)
+ return -1;
+
+ issue_type = STP_FW_ASSERT_ISSUE;
+ if (chip_reset_only) {
+ STP_DBG_PR_WARN("is chip reset only\n");
+ ret = -3;
+ return ret;
+ }
+
+ if (dump_sink == 0)
+ return 0;
+
+ /* handshake error handle: notify FW assert in abnormal case */
+ if (p_ecsi->p_ecso->emi_apmem_ctrl_state == 0x0) {
+ mtk_wcn_force_trigger_assert_debug_pin();
+ osal_sleep_ms(100);
+ }
+
+ /*packet number depend on dump_num get from register:0xf0080044 ,support jade*/
+ dump_num = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_page_dump_num);
+ if (dump_num != 0) {
+ packet_num = dump_num;
+ STP_DBG_PR_INFO("get consys dump num packet_num(%d)\n", packet_num);
+ } else {
+ dump_num = CORE_DUMP_NUM;
+ STP_DBG_PR_ERR("can not get consys dump num and default num is %d\n", CORE_DUMP_NUM);
+ }
+
+ stp_dbg_dump_num(dump_num);
+ stp_dbg_start_coredump_timer();
+ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START);
+ page_counter = 0;
+ if (mtk_wcn_stp_get_wmt_trg_assert() == 0)
+ WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT);
+
+ while (1) {
+ /* assert flag 2 means mcu is ready to start coredump */
+ if (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_assert_flag) == 2) {
+ STP_DBG_PR_INFO("coredump handshake start\n");
+ break;
+ } else if (stp_dbg_get_coredump_timer_state() == CORE_DUMP_TIMEOUT)
+ goto paged_dump_end;
+ osal_sleep_ms(1);
+ }
+
+ do {
+ dump_phy_addr = 0;
+ dump_vir_addr = NULL;
+ dump_len = 0;
+
+ counter++;
+ osal_get_local_time(&start_ts, &start_nsec);
+ while (1) {
+ elapsed_time = stp_dbg_soc_elapsed_time(start_ts, start_nsec);
+ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info(
+ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state);
+ if (chip_state == STP_CHIP_DUMP_PUT_DONE) {
+ STP_DBG_PR_DBG("chip put done\n");
+ break;
+ }
+ STP_DBG_PR_DBG("waiting chip put done, chip_state: %d\n", chip_state);
+#if WMT_DBG_SUPPORT
+ if (chip_state == 0 && __ratelimit(&_rs))
+ stp_dbg_poll_cpupcr(5, 1, 1);
+#endif
+
+ if (elapsed_time > EMI_SYNC_TIMEOUT) {
+#if !WMT_DBG_SUPPORT
+ STP_DBG_PR_ERR("Wait Timeout: %llu > %d\n", elapsed_time, EMI_SYNC_TIMEOUT);
+ /* Since customer's user/userdebug load get coredump via netlink(dump_sink==2). */
+ /* For UX, if get coredump timeout, skip it and do chip reset ASAP. */
+ if (dump_sink == 2)
+ abort = 1;
+#endif
+ goto paged_dump_end;
+ }
+ osal_sleep_ms(1);
+ }
+
+ dump_phy_addr = wmt_plat_get_dump_info(
+ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr);
+
+ if (!dump_phy_addr) {
+ STP_DBG_PR_ERR("get paged dump phy address fail\n");
+ ret = -1;
+ break;
+ }
+
+ dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr);
+ if (!dump_vir_addr) {
+ STP_DBG_PR_ERR("get paged dump phy address fail\n");
+ ret = -2;
+ break;
+ }
+ dump_len = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len);
+ STP_DBG_PR_DBG("dump_phy_ddr(%08x),dump_vir_add(0x%p),dump_len(%d)\n",
+ dump_phy_addr, dump_vir_addr, dump_len);
+
+ /* dump_len should not be negative */
+ if (dump_len < 0)
+ dump_len = 0;
+
+ /*move dump info according to dump_addr & dump_len */
+ osal_memcpy_fromio(&g_paged_dump_buffer[0], dump_vir_addr, dump_len);
+
+ if (dump_len <= 32 * 1024) {
+ STP_DBG_PR_DBG("coredump mode: %d!\n", dump_sink);
+ switch (dump_sink) {
+ case 1:
+ ret = stp_dbg_aee_send(&g_paged_dump_buffer[0], dump_len, 0);
+ if (ret == 0)
+ STP_DBG_PR_DBG("aee send ok!\n");
+ else if (ret == 1)
+ STP_DBG_PR_DBG("aee send fisish!\n");
+ else if (ret == -1) {
+ STP_DBG_PR_ERR("aee send timeout!\n");
+ abort = 1;
+ goto paged_dump_end;
+ } else
+ STP_DBG_PR_ERR("aee send error!\n");
+ break;
+ case 2:
+ ret = stp_dbg_soc_put_emi_dump_to_nl(&g_paged_dump_buffer[0], dump_len);
+ if (ret == 0)
+ STP_DBG_PR_DBG("dump send ok!\n");
+ else if (ret == 1) {
+ STP_DBG_PR_ERR("dump send timeout!\n");
+ abort = 1;
+ goto paged_dump_end;
+ } else
+ STP_DBG_PR_ERR("dump send error!\n");
+ break;
+ default:
+ STP_DBG_PR_ERR("unknown sink %d\n", dump_sink);
+ return -1;
+ }
+ } else
+ STP_DBG_PR_ERR("dump len is over than 32K(%d)\n", dump_len);
+
+ g_paged_dump_len += dump_len;
+ wmt_plat_update_host_sync_num();
+ wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE);
+
+ STP_DBG_PR_DBG("host sync num(%d),chip sync num(%d)\n",
+ wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num),
+ wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num));
+ page_counter++;
+ STP_DBG_PR_DBG("++ paged dump counter(%d) ++\n", page_counter);
+ /* dump 1st 512 bytes data to kernel log for fw requirement */
+ if (page_counter == 1)
+ stp_dbg_dump_log(&g_paged_dump_buffer[0], dump_len < 512 ? dump_len : 512);
+
+ osal_get_local_time(&start_ts, &start_nsec);
+ while (1) {
+ elapsed_time = stp_dbg_soc_elapsed_time(start_ts, start_nsec);
+ chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info(
+ p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state);
+ if (chip_state == STP_CHIP_DUMP_END) {
+ STP_DBG_PR_DBG("chip put end\n");
+ break;
+ }
+ STP_DBG_PR_DBG("waiting chip put end, chip_state: %d\n", chip_state);
+ if (elapsed_time > EMI_SYNC_TIMEOUT) {
+#if !WMT_DBG_SUPPORT
+ STP_DBG_PR_ERR("Wait Timeout: %llu > %d\n", elapsed_time, EMI_SYNC_TIMEOUT);
+ /* Since customer's user/userdebug load get coredump via netlink(dump_sink==2). */
+ /* For UX, if wait sync state timeout, skip it and do chip reset ASAP. */
+ if (dump_sink == 2)
+ abort = 1;
+#endif
+ goto paged_dump_end;
+ }
+ osal_sleep_ms(1);
+ }
+
+paged_dump_end:
+ wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START);
+ STP_DBG_PR_INFO("++ counter(%d) packet_num(%d) page_counter(%d) g_paged_dump_len(%d) fw_state(%d)++\n",
+ counter, packet_num, page_counter, g_paged_dump_len,
+ wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state));
+ if (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_paded_dump_end) ||
+ (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state) == 0x8)) {
+ if (stp_dbg_get_coredump_timer_state() == CORE_DUMP_DOING) {
+ STP_DBG_PR_INFO("paged dump end by emi flag\n");
+ if (dump_sink == 1)
+ stp_dbg_aee_send(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND), 0);
+ else if (dump_sink == 2)
+ stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND));
+ } else
+ STP_DBG_PR_INFO("paged dump end\n");
+ ret = 0;
+ break;
+ } else if (abort || stp_dbg_get_coredump_timer_state() == CORE_DUMP_TIMEOUT) {
+ STP_DBG_PR_ERR("paged dump fail, generate fake coredump message\n");
+ stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING);
+ if (dump_sink == 1)
+ stp_dbg_aee_send(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND), 0);
+ else if (dump_sink == 2)
+ stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND));
+ stp_dbg_set_coredump_timer_state(CORE_DUMP_TIMEOUT);
+ stp_dbg_poll_cpupcr(5, 5, 0);
+ stp_dbg_poll_dmaregs(5, 1);
+ ret = -1;
+ break;
+ }
+ } while (1);
+
+ return ret;
+}
+
+static _osal_inline_ INT32 stp_dbg_soc_paged_trace(VOID)
+{
+ INT32 ret = 0;
+ UINT32 ctrl_val = 0;
+ UINT32 loop_cnt1 = 0;
+ UINT32 buffer_start = 0;
+ UINT32 buffer_idx = 0;
+ PUINT8 dump_vir_addr = NULL;
+ P_CONSYS_EMI_ADDR_INFO p_ecsi;
+ INT32 dump_len = 0;
+
+ p_ecsi = wmt_plat_get_emi_phy_add();
+ if (p_ecsi == NULL) {
+ STP_DBG_PR_ERR("get EMI info failed.\n");
+ return -1;
+ }
+
+ do {
+ ctrl_val = 0;
+ loop_cnt1 = 0;
+ buffer_start = 0;
+ buffer_idx = 0;
+ dump_vir_addr = NULL;
+
+ while (loop_cnt1 < 10) {
+ ctrl_val = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state);
+ if (ctrl_val == 0x8)
+ break;
+ osal_sleep_ms(10);
+ loop_cnt1++;
+ }
+ if (loop_cnt1 >= 10) {
+ STP_DBG_PR_ERR("polling CTRL STATE fail\n");
+ ret = -1;
+ break;
+ }
+
+ buffer_start = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_start);
+ buffer_idx = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_idx);
+ g_paged_trace_len = buffer_idx;
+ STP_DBG_PR_INFO("paged trace buffer addr(%08x),buffer_len(%d)\n", buffer_start,
+ buffer_idx);
+ dump_vir_addr = wmt_plat_get_emi_virt_add(buffer_start - p_ecsi->emi_phy_addr);
+ if (!dump_vir_addr) {
+ STP_DBG_PR_ERR("get vir dump address fail\n");
+ ret = -2;
+ break;
+ }
+ osal_memcpy_fromio(&g_paged_trace_buffer[0], dump_vir_addr,
+ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE);
+ /*moving paged trace according to buffer_start & buffer_len */
+
+ dump_len =
+ buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE;
+ pr_info("-- paged trace ascii output --");
+ stp_dbg_dump_log(&g_paged_trace_buffer[0], dump_len);
+ ret = 0;
+ } while (0);
+
+ return ret;
+}
+
+INT32 stp_dbg_soc_core_dump(INT32 dump_sink)
+{
+ INT32 ret = 0;
+
+ if (dump_sink == 0 || chip_reset_only == 1) {
+ if (chip_reset_only) {
+ STP_DBG_PR_INFO("Chip reset only\n");
+ chip_reset_only = 0;
+ }
+ mtk_wcn_stp_ctx_restore();
+ } else if (dump_sink == 1 || dump_sink == 2) {
+ stp_dbg_soc_paged_dump(dump_sink);
+ ret = stp_dbg_soc_paged_trace();
+ if (ret)
+ STP_DBG_PR_ERR("stp_dbg_soc_paged_trace fail: %d!\n", ret);
+ if (stp_dbg_start_emi_dump() < 0)
+ mtk_wcn_stp_ctx_restore();
+ }
+
+ return ret;
+}
+
+PUINT8 stp_dbg_soc_id_to_task(UINT32 id)
+{
+ P_WMT_PATCH_INFO p_patch_info;
+ PUINT8 patch_name = NULL;
+ UINT32 temp_id;
+
+ if (id >= STP_DBG_TASK_ID_MAX) {
+ STP_DBG_PR_ERR("task id(%d) overflow(%d)\n", id, STP_DBG_TASK_ID_MAX);
+ return NULL;
+ }
+
+ p_patch_info = wmt_lib_get_patch_info();
+ if (p_patch_info)
+ patch_name = p_patch_info->patchName;
+
+ if (patch_name == NULL) {
+ STP_DBG_PR_INFO("patch_name is null\n");
+ /* For projects without patch download */
+ return soc_task_str[id];
+ }
+
+ if (osal_strncmp(patch_name, ROM_V2_PATCH, strlen(ROM_V2_PATCH)) == 0) {
+ temp_id = soc_gen_two_task_id_adapter[id];
+ STP_DBG_PR_INFO("id = %d, gen two task_id = %d\n", id, temp_id);
+ } else if (osal_strncmp(patch_name, ROM_V3_PATCH, strlen(ROM_V3_PATCH)) == 0) {
+ temp_id = soc_gen_three_task_id_adapter[id];
+ STP_DBG_PR_INFO("id = %d, gen three task_id = %d\n", id, temp_id);
+ } else if (osal_strncmp(patch_name, ROM_V4_PATCH, strlen(ROM_V4_PATCH)) == 0) {
+ temp_id = soc_gen_three_task_id_adapter[id];
+ STP_DBG_PR_INFO("id = %d, gen three (ROMv4) task_id = %d\n", id, temp_id);
+ } else {
+ temp_id = id;
+ STP_DBG_PR_INFO("id = %d, CONNAC project task_id = %d\n", id, temp_id);
+ }
+
+ return soc_task_str[temp_id];
+}
+
+UINT32 stp_dbg_soc_read_debug_crs(ENUM_CONNSYS_DEBUG_CR cr)
+{
+#define CONSYS_REG_READ(addr) (*((volatile UINT32 *)(addr)))
+#ifdef CONFIG_OF /*use DT */
+ P_CONSYS_EMI_ADDR_INFO emi_phy_addr;
+ UINT32 chip_id = 0;
+
+ chip_id = wmt_plat_get_soc_chipid();
+ emi_phy_addr = mtk_wcn_consys_soc_get_emi_phy_add();
+
+ if (cr == CONNSYS_EMI_REMAP) {
+ if (emi_phy_addr != NULL && emi_phy_addr->emi_remap_offset)
+ return CONSYS_REG_READ(conn_reg.topckgen_base +
+ emi_phy_addr->emi_remap_offset);
+ else
+ STP_DBG_PR_INFO("EMI remap has no value\n");
+ }
+
+ if (chip_id == 0x6765 || chip_id == 0x3967 || chip_id == 0x6761
+ || chip_id == 0x6779 || chip_id == 0x6768 || chip_id == 0x6785
+ || chip_id == 0x6873 || chip_id == 0x8168 || chip_id == 0x6853
+ || chip_id == 0x6833)
+ return 0;
+
+ if (conn_reg.mcu_base) {
+ switch (cr) {
+ case CONNSYS_CPU_CLK:
+ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPU_CLK_STATUS_OFFSET);
+ case CONNSYS_BUS_CLK:
+ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CLK_STATUS_OFFSET);
+ case CONNSYS_DEBUG_CR1:
+ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DBG_CR1_OFFSET);
+ case CONNSYS_DEBUG_CR2:
+ return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DBG_CR2_OFFSET);
+ default:
+ return 0;
+ }
+ }
+#endif
+ return -1;
+}
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c
new file mode 100644
index 0000000000000000000000000000000000000000..6c663ed5cb374a7385a53759ec3075a6c8c463b0
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c
@@ -0,0 +1,3584 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+/*! \file "stp_sdio.c"
+ * \brief
+ *
+ * detailed description
+*/
+
+/*******************************************************************************
+* C O M P I L E R F L A G S
+********************************************************************************
+*/
+
+#define STP_SDIO_TXPERFDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */
+#define STP_SDIO_OWNBACKDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */
+#define STP_SDIO_NEW_IRQ_HANDLER 1
+
+/*******************************************************************************
+* E X T E R N A L R E F E R E N C E S
+********************************************************************************
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "osal.h"
+#include "stp_exp.h"
+#include "hif_sdio.h"
+#include "stp_sdio.h"
+#include "stp_dbg.h"
+#include "wmt_lib.h"
+#include "wmt_exp.h"
+
+/*******************************************************************************
+* C O N S T A N T S
+********************************************************************************
+*/
+
+#ifdef DFT_TAG
+#undef DFT_TAG
+#endif
+#define DFT_TAG "[STP SDIO]"
+
+#define STPSDIO_LOG_LOUD 5
+#define STPSDIO_LOG_DBG 4
+#define STPSDIO_LOG_HINT 3
+#define STPSDIO_LOG_INFO 2
+#define STPSDIO_LOG_WARN 1
+#define STPSDIO_LOG_ERR 0
+
+/*******************************************************************************
+* D A T A T Y P E S
+********************************************************************************
+*/
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+#define STP_SDIO_RXDBG_COUNT (0x10UL)
+#define STP_SDIO_RXDBG_COUNT_MASK (STP_SDIO_RXDBG_COUNT - 1)
+struct stp_sdio_rxdbg {
+ UINT32 ts;
+ UINT32 bus_rxlen;
+ UINT32 chisr_rxlen;
+ UINT8 rx_pkt_buf[STP_SDIO_RX_BUF_SIZE];
+};
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+#define STP_SDIO_TXDBG_COUNT (0x10UL)
+#define STP_SDIO_TXDBG_COUNT_MASK (STP_SDIO_TXDBG_COUNT - 1)
+struct stp_sdio_txdbg {
+ UINT32 ts;
+ UINT32 bus_txlen;
+ UINT64 l_sec;
+ ULONG l_nsec;
+ UINT32 four_byte_align_len;
+ UINT8 tx_pkt_buf[STP_SDIO_TX_ENTRY_SIZE];
+};
+#define STP_SDIO_TXDBG_MAX_SIZE (0x20)
+#endif
+OSAL_SLEEPABLE_LOCK fake_coredump_lock;
+/*******************************************************************************
+* F U N C T I O N D E C L A R A T I O N S
+********************************************************************************
+*/
+static INT32 stp_sdio_func0_reg_rw(INT32 direction, UINT32 offset, UINT32 value);
+static INT32 stp_sdio_func_reg_rw(INT32 direction, UINT32 offset, UINT32 value);
+
+static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx);
+static INT32 stp_sdio_probe(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx,
+ const MTK_WCN_HIF_SDIO_FUNCINFO *sdio_func_infop);
+static INT32 stp_sdio_remove(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx);
+
+static VOID stp_sdio_rx_wkr(struct work_struct *work);
+static VOID stp_sdio_tx_wkr(struct work_struct *work);
+#if STP_SDIO_OWN_THREAD
+static INT32 stp_sdio_wait_for_msg(PVOID pvData);
+static VOID stp_sdio_tx_rx_handling(PVOID pData);
+#endif
+static _osal_inline_ INT32 stp_sdio_host_info_deinit(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf);
+static _osal_inline_ INT32 stp_sdio_host_info_init(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf);
+static _osal_inline_ INT32 stp_sdio_host_info_op(INT32 opId);
+static _osal_inline_ SDIO_PS_OP stp_sdio_get_own_state(VOID);
+static _osal_inline_ INT32 stp_sdio_do_own_set(MTK_WCN_STP_SDIO_HIF_INFO *p_info);
+static _osal_inline_ INT32 stp_sdio_do_own_clr(INT32 wait);
+static _osal_inline_ VOID stp_sdio_check_tx_sanity(const MTK_WCN_STP_SDIO_HIF_INFO *p_info, const UINT32 id);
+static _osal_inline_ VOID stp_sdio_tx_wkr_comp(MTK_WCN_STP_SDIO_HIF_INFO * const p_info);
+static _osal_inline_ INT32 stp_sdio_ownback_poll(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 retry,
+ UINT32 delay_us);
+static _osal_inline_ VOID stp_sdio_txperf_dump(VOID);
+/*******************************************************************************
+* P R I V A T E D A T A
+********************************************************************************
+*/
+
+/* Supported SDIO device table */
+static const MTK_WCN_HIF_SDIO_FUNCINFO mtk_stp_sdio_id_tbl[] = {
+ /* MT6618 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x018B, 1, STP_SDIO_BLK_SIZE)},
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x018C, 1, STP_SDIO_BLK_SIZE)}, /* 2-function */
+
+ /* MT6619 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6619, 1, STP_SDIO_BLK_SIZE)},
+
+ /* MT6620 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x020B, 1, STP_SDIO_BLK_SIZE)},
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x020C, 1, STP_SDIO_BLK_SIZE)}, /* 2-function */
+
+ /* MT6628 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6628, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */
+
+ /* MT6630 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6630, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */
+
+ /* MT6632 *//* Not an SDIO standard class device */
+ {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6632, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */
+ { /* end: all zeroes */ },
+};
+
+wait_queue_head_t g_ownback_done;
+INT32 is_wait_ownback;
+/* static void (*cmb_bgf_eirq_cb)(void) = NULL; */
+
+/* STP SDIO client information for hif sdio driver registration */
+const MTK_WCN_HIF_SDIO_CLTINFO g_stp_sdio_cltinfo = {
+ .func_tbl = mtk_stp_sdio_id_tbl,
+ .func_tbl_size = (sizeof(mtk_stp_sdio_id_tbl) / sizeof(MTK_WCN_HIF_SDIO_FUNCINFO) - 1),
+ .hif_clt_irq = stp_sdio_irq,
+ .hif_clt_probe = stp_sdio_probe,
+ .hif_clt_remove = stp_sdio_remove,
+};
+
+/* STP SDIO host array for multiple hosts maintenance */
+MTK_WCN_STP_SDIO_HIF_INFO g_stp_sdio_host_info; /*[STP_SDIO_HOST_COUNT]; */
+/* STP SDIO host information pointer (for stp if_tx() function) */
+MTK_WCN_STP_SDIO_HIF_INFO *const gp_info = &g_stp_sdio_host_info;
+
+/* STP-SDIO probe count (not support multiple probe and hosts) */
+UINT32 g_stp_sdio_host_count;
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+#define STP_SDIO_RXDBG_PROCNAME "driver/stp_sdio_rxdbg"
+static struct proc_dir_entry *gStpSdioRxDbgEntry;
+static INT32 stp_sdio_rxdbg_cnt;
+static struct stp_sdio_rxdbg stp_sdio_rxdbg_buffer[STP_SDIO_RXDBG_COUNT];
+static struct timeval old = {0};
+#define TX_NO_ACK_TIMEOUT_ASSERT 5 /* tx no ack timeout assert, unit:second*/
+
+static ssize_t stp_sdio_rxdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
+static ssize_t stp_sdio_rxdbg_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos);
+static const struct file_operations stp_sdio_rxdbg_fops = {
+ .read = stp_sdio_rxdbg_read,
+ .write = stp_sdio_rxdbg_write,
+};
+
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG
+#define STP_SDIO_OWNDBG_PROCNAME "driver/stp_sdio_own"
+static struct proc_dir_entry *gStpSdioOwnEntry;
+static ssize_t stp_sdio_own_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
+static ssize_t stp_sdio_own_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos);
+static const struct file_operations stp_sdio_own_fops = {
+ .read = stp_sdio_own_read,
+ .write = stp_sdio_own_write,
+};
+
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG)
+#define STP_SDIO_TXDBG_PROCNAME "driver/stp_sdio_txdbg"
+static struct proc_dir_entry *gStpSdioTxDbgEntry;
+
+static ssize_t stp_sdio_txdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
+static ssize_t stp_sdio_txdbg_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos);
+static const struct file_operations stp_sdio_txdbg_fops = {
+ .read = stp_sdio_txdbg_read,
+ .write = stp_sdio_txdbg_write,
+};
+
+#if STP_SDIO_TXDBG
+static INT32 stp_sdio_txdbg_cnt;
+static struct stp_sdio_txdbg stp_sdio_txdbg_buffer[STP_SDIO_TXDBG_COUNT];
+#endif
+
+#if STP_SDIO_TXPERFDBG
+/* a record for tx worker loop counter */
+static UINT32 stp_sdio_txperf_worker_cnt;
+
+/* a record for left fifo size in hw when tx wait */
+static UINT32 stp_sdio_txperf_fifo_left;
+/* a record for data length when tx wait */
+static UINT32 stp_sdio_txperf_to_send;
+/* a record for tx wait fifo limit counter */
+static UINT32 stp_sdio_txperf_fifo_lmt_cnt;
+
+/* a record for left txed pkt number in tx worker */
+static UINT32 stp_sdio_txperf_txed_pkt_num;
+/* a record for tx wait pkt_num limit counter */
+static UINT32 stp_sdio_txperf_pkt_num_lmt_cnt;
+#endif
+#endif
+
+/*******************************************************************************
+* P U B L I C D A T A
+********************************************************************************
+*/
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3");
+MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
+
+INT32 gStpSdioDbgLvl = STPSDIO_LOG_INFO;
+/*******************************************************************************
+* M A C R O S
+********************************************************************************
+*/
+#define STPSDIO_PR_LOUD(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_LOUD) \
+ pr_info(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#define STPSDIO_PR_DBG(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_DBG) \
+ pr_info(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#define STPSDIO_PR_HINT(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_HINT) \
+ pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#define STPSDIO_PR_INFO(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_INFO) \
+ pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#define STPSDIO_PR_WARN(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_WARN) \
+ pr_warn(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \
+} while (0)
+
+#define STPSDIO_PR_ERR(fmt, arg...) \
+do { \
+ if (gStpSdioDbgLvl >= STPSDIO_LOG_ERR) \
+ pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+/*******************************************************************************
+* F U N C T I O N S
+********************************************************************************
+*/
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+INT32 stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag)
+{
+ return mtk_wcn_hif_sdio_deep_sleep_flag_set(flag);
+}
+#endif
+
+VOID stp_sdio_retry_flag_ctrl(INT32 flag)
+{
+ gp_info->retry_enable_flag = flag == 0 ? 0 : 1;
+}
+
+INT32 stp_sdio_retry_flag_get(VOID)
+{
+ return gp_info->retry_enable_flag;
+}
+
+static _osal_inline_ INT32 stp_sdio_host_info_op(INT32 opId)
+{
+ INT32 iRet = 0;
+#if KMALLOC_UPDATE
+ static PUINT8 p_tx_buffer;
+ static PUINT8 p_rx_buffer;
+
+ if (p_tx_buffer == NULL) {
+ p_tx_buffer = kmalloc(STP_SDIO_TX_BUF_CNT * STP_SDIO_TX_ENTRY_SIZE, GFP_ATOMIC);
+ if (p_tx_buffer == NULL) {
+ STPSDIO_PR_ERR
+ ("memory allocate for g_stp_sdio_host_info.pkt_buf.tx_buf fail!\n");
+ iRet = -1;
+ } else {
+ STPSDIO_PR_DBG
+ ("memory allocate for g_stp_sdio_host_info.pkt_buf.tx_buf succeed!\n");
+ iRet = 0;
+ }
+ } else {
+ STPSDIO_PR_DBG
+ ("memory already allocated for g_stp_sdio_host_info.pkt_buf.tx_buf!\n");
+ iRet = 0;
+ }
+ if (p_rx_buffer == NULL) {
+ p_rx_buffer = kmalloc(STP_SDIO_RX_BUF_SIZE, GFP_ATOMIC);
+ if (p_rx_buffer == NULL) {
+ STPSDIO_PR_ERR
+ ("memory allocate for g_stp_sdio_host_info.pkt_buf.rx_buf fail!\n");
+ iRet = -1;
+ } else {
+ STPSDIO_PR_DBG
+ ("memory allocate for g_stp_sdio_host_info.pkt_buf.rx_buf succeed!\n");
+ iRet = 0;
+ }
+ } else {
+ STPSDIO_PR_DBG
+ ("memory already allocated for g_stp_sdio_host_info.pkt_buf.rx_buf!\n");
+ iRet = 0;
+ }
+#endif /* KMALLOC_UPDATE */
+
+ if (iRet == 0 && opId == 0)
+ iRet = stp_sdio_host_info_deinit(&p_tx_buffer, &p_rx_buffer);
+ else if (iRet == 0)
+ iRet = stp_sdio_host_info_init(&p_tx_buffer, &p_rx_buffer);
+ else
+ STPSDIO_PR_ERR("iRet (%d)!\n", iRet);
+
+ return iRet;
+}
+
+static _osal_inline_ INT32 stp_sdio_host_info_init(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf)
+{
+ /* Init host count */
+ memset(&g_stp_sdio_host_info, 0, sizeof(g_stp_sdio_host_info));
+
+#if KMALLOC_UPDATE
+ g_stp_sdio_host_info.pkt_buf.tx_buf = *ppTxBuf;
+ g_stp_sdio_host_info.pkt_buf.rx_buf = *ppRxBuf;
+#endif
+
+ return 0;
+}
+
+static _osal_inline_ INT32 stp_sdio_host_info_deinit(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf)
+{
+#if KMALLOC_UPDATE
+ if (*ppTxBuf != NULL) {
+ kfree(*ppTxBuf);
+ *ppTxBuf = NULL;
+ }
+ if (*ppRxBuf != NULL) {
+ kfree(*ppRxBuf);
+ *ppRxBuf = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+INT32 stp_sdio_issue_fake_coredump(UINT8 *str)
+{
+#define MAX_STRING_LENGTH 140
+ UINT8 AssertStr[4 + MAX_STRING_LENGTH + 1 + 2] = { 0 };
+ UINT32 length = strlen(str) >= MAX_STRING_LENGTH ? MAX_STRING_LENGTH : strlen(str);
+ /*pack str into STP SDIO packet format */
+ osal_lock_sleepable_lock(&fake_coredump_lock);
+ /*STP header */
+ AssertStr[0] = 0x80;
+ AssertStr[1] = 0x50;
+ AssertStr[2] = (length + 1) & 0xff;
+ AssertStr[3] = 0x0;
+ /*STP content */
+ memcpy(&AssertStr[4], str, length);
+ /*string end character */
+ AssertStr[4 + length] = '\n';
+ /*STP CRC */
+ AssertStr[4 + length + 1] = 0x0;
+ AssertStr[4 + length + 2] = 0x0;
+ /*send to STP layer coredump content */
+ mtk_wcn_stp_parser_data(&AssertStr[0], 4 + length + 1 + 2);
+
+ /*send coredump end content */
+ length = strlen("coredump end");
+ AssertStr[0] = 0x80;
+ AssertStr[1] = 0x50;
+ AssertStr[2] = (length + 2) & 0xff;
+ AssertStr[3] = 0x0;
+ memcpy(&AssertStr[4], "coredump end", length);
+ /*string end character */
+ AssertStr[4 + length] = '\r';
+ AssertStr[4 + length + 1] = '\n';
+ /*STP CRC */
+ AssertStr[4 + length + 2] = 0x0;
+ AssertStr[4 + length + 3] = 0x0;
+ mtk_wcn_stp_parser_data(&AssertStr[0], 4 + length + 2 + 2);
+ osal_unlock_sleepable_lock(&fake_coredump_lock);
+
+ STPSDIO_PR_ERR("trigger fake coredump with str:[%s] finished\n", str);
+
+ return 0;
+}
+
+/*!
+ * \brief
+ *
+ * \details
+ *
+ * \retval 0 success
+ * \retval !=0 fail
+ */
+static _osal_inline_ SDIO_PS_OP stp_sdio_get_own_state(VOID)
+{
+ SDIO_PS_OP ret = OWN_SET;
+ INT32 i_ret = 0;
+ UINT32 chlcpr_value = 0x0;
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx;
+
+ clt_ctx = gp_info->sdio_cltctx;
+ i_ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlcpr_value,
+ 0);
+ if (i_ret) {
+ ret = OWN_SET;
+ STPSDIO_PR_ERR("read CHLPCR fail(%d), return\n", ret);
+ return ret;
+ }
+ if ((chlcpr_value & C_FW_COM_DRV_OWN) == C_FW_COM_DRV_OWN)
+ ret = OWN_CLR;
+ else
+ ret = OWN_SET;
+
+ return ret;
+}
+
+static _osal_inline_ INT32 stp_sdio_do_own_set(MTK_WCN_STP_SDIO_HIF_INFO *p_info)
+{
+ UINT32 value = 0;
+ UINT32 iRet = 0;
+
+ /* [COHEC_00006052] SW work-around solution:
+ * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR
+ */
+#if COHEC_00006052
+ value = (C_FW_OWN_REQ_SET >> 8);
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ (UINT32)(CHLPCR + 0x01), &value, 0);
+#else
+ value = C_FW_OWN_REQ_SET;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CHLPCR, &value,
+ 0);
+#endif /* COHEC_00006052 */
+ if (iRet) {
+ STPSDIO_PR_ERR("write CHLPCR, set firmware own! (sleeping) fail\n");
+ } else {
+ iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CHLPCR,
+ &value, 0);
+ if (iRet)
+ STPSDIO_PR_ERR("get firmware own! (sleeping) fail iRet:%d\n", iRet);
+ else {
+ if (!(value & C_FW_COM_DRV_OWN)) {
+ STPSDIO_PR_DBG("set firmware own! (sleeping) ok\n");
+ osal_ftrace_print("set F own okay, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)",
+ p_info->sleep_flag, p_info->wakeup_flag, p_info->awake_flag);
+ p_info->awake_flag = 0;
+ p_info->sleep_flag = 0;
+ osal_raise_signal(&p_info->isr_check_complete);
+ osal_ftrace_print("set F own okay and raise signal done");
+ } else {
+ STPSDIO_PR_WARN("set firmware own fail!, set CLR BACK\n");
+ osal_ftrace_print("set F own fail, set CLR BACK\n");
+ /* if set firmware own not successful(possibly pending interrupts),
+ * indicate an own clear event
+ */
+ /* [COHEC_00006052] SW work-around solution:
+ * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR
+ */
+#if COHEC_00006052
+ value = (C_FW_OWN_REQ_CLR >> 8);
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT,
+ p_info->sdio_cltctx, (UINT32)(CHLPCR + 0x01), &value, 0);
+#else
+ value = C_FW_OWN_REQ_CLR;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT,
+ p_info->sdio_cltctx, CHLPCR, &value, 0);
+#endif /* COHEC_00006052 */
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief
+ *
+ * \details
+ *
+ * \retval 0 success
+ * \retval !=0 fail
+ */
+static _osal_inline_ INT32 stp_sdio_do_own_clr(INT32 wait)
+{
+#define CLR_OWN_RETRY 50
+ INT32 ret = -1;
+ UINT32 time_out;
+ INT32 retry;
+ UINT32 chlcpr_value = 0x0;
+ UINT32 write_value = 0x0;
+ UINT32 delay_us = 500;
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx;
+
+ clt_ctx = gp_info->sdio_cltctx;
+ retry = 40;
+
+ /* <1> request firmware-own back */
+ STPSDIO_PR_DBG("Do FW-Own back!(Wakeup)\n");
+ if (wait) {
+ /* TODO:[FixMe][George] why use both polling & interrupt methods here??? */
+ init_waitqueue_head(&g_ownback_done);
+
+ is_wait_ownback = 1;
+ }
+/* need to wait for the ownback completion */
+/* [COHEC_00006052] SW work-around solution:
+ * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR
+ */
+ while (retry-- > 0) {
+#if COHEC_00006052
+ write_value = (C_FW_OWN_REQ_CLR>>8);
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx,
+ (UINT32)(CHLPCR+0x1), &write_value, 0);
+#else
+ write_value = C_FW_OWN_REQ_CLR;
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#endif /* COHEC_00006052 */
+ if (ret) {
+ STPSDIO_PR_ERR("request firmware own back fail(%d)\n", ret);
+ osal_dbg_assert_aee(" sdio_write ERROR",
+ "write CHLPCR by SDIO report error");
+ if (retry == 0)
+ goto out;
+ } else
+ break;
+ }
+ retry = 1200;/*wait for 1200*500 = 600 000 us*/
+ do {
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &chlcpr_value, 0);
+ if (ret) {
+ /* 4 <1.1> get CHISR Rx error handling */
+ STPSDIO_PR_ERR("get CHLPCR information rx error!(%d)\n", ret);
+ goto out;
+ }
+
+ if ((chlcpr_value & C_FW_COM_DRV_OWN) == C_FW_COM_DRV_OWN) {
+ /* 4 <2> handle ownership back interrupt */
+ STPSDIO_PR_DBG("firmware ownback is polled!(%d)\n",
+ CLR_OWN_RETRY - retry);
+ /*osal_usleep_range(2000, 2000);*/
+ break;
+ }
+ STPSDIO_PR_DBG("firmware ownback is no polled, wait for (%d us) and retry\n", delay_us);
+ osal_usleep_range(delay_us, 2*delay_us);
+ if (0 == (retry - 1)%40)
+ STPSDIO_PR_ERR("own back failed in %d us, something might goes wrong\n",
+ 40*delay_us);
+
+ if (0 == (retry - 1)%200) {
+#if COHEC_00006052
+ write_value = (C_FW_OWN_REQ_CLR>>8);
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx,
+ (UINT32)(CHLPCR+0x1), &write_value, 0);
+#else
+ write_value = C_FW_OWN_REQ_CLR;
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#endif /* COHEC_00006052 */
+ if (ret)
+ STPSDIO_PR_ERR("request firmware own back fail(%d)\n", ret);
+ STPSDIO_PR_ERR("own back failed in %d us, write again\n", 200*delay_us);
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ }
+ } while (retry-- > 0);
+ if (wait) {
+ /* <2> wait own_back bit is set. */
+ time_out = wait_event_timeout(g_ownback_done,
+ is_wait_ownback == 0, (1000 / (1000 / HZ)));
+
+ if (time_out != 0) {
+ STPSDIO_PR_INFO("Do FW-Own back!(Wakeup) succeed\n");
+ ret = 0;
+ } else {
+ STPSDIO_PR_ERR("Do FW-Own back!(Wakeup) fail\n");
+ ret = -1;
+ }
+ } else
+ ret = retry > 0 ? 0 : -1;
+
+out:
+ return ret;
+}
+
+/*!
+ * \brief
+ *
+ * \details
+ *
+ * \param[IN] op code for SDIO PS and OWN control
+ *
+ * \retval 0 success
+ * \retval !=0 fail
+ */
+INT32 stp_sdio_own_ctrl(SDIO_PS_OP op)
+{
+ INT32 ret = -1;
+ P_OSAL_SIGNAL pOsalSignal = NULL;
+
+ if (g_stp_sdio_host_count == 0) {
+ STPSDIO_PR_WARN("g_stp_sdio_host_count is 0, do nothing!\n");
+ return 0;
+ }
+ pOsalSignal = &gp_info->isr_check_complete;
+ switch (op) {
+ case OWN_SET:
+ gp_info->wakeup_flag = 0;
+ gp_info->sleep_flag = 1;
+ osal_trigger_event(&gp_info->tx_rx_event);
+ STPSDIO_PR_LOUD("before op(%d)\n", op);
+ osal_ftrace_print("own set start, wakeup_flag(%d), sleep_flag(%d), wait signal",
+ gp_info->wakeup_flag, gp_info->sleep_flag);
+ ret = osal_wait_for_signal_timeout(pOsalSignal, NULL);
+ if (!ret)
+ STPSDIO_PR_ERR("OWN_SET fail, done(%d), sleep(%d), wakeup(%d)\n",
+ pOsalSignal->comp.done, gp_info->sleep_flag, gp_info->wakeup_flag);
+ STPSDIO_PR_LOUD("after op(%d)\n", op);
+ ret = 0;
+ break;
+
+ case OWN_CLR:
+ /* ret = stp_sdio_do_own_clr(1); */
+ gp_info->sleep_flag = 0;
+ gp_info->wakeup_flag = 1;
+ osal_trigger_event(&gp_info->tx_rx_event);
+ osal_ftrace_print("own clear start, wakeup_flag(%d), sleep_flag(%d), wait signal",
+ gp_info->wakeup_flag, gp_info->sleep_flag);
+ STPSDIO_PR_LOUD("before op(%d)\n", op);
+ ret = osal_wait_for_signal_timeout(pOsalSignal, NULL);
+ if (!ret)
+ STPSDIO_PR_ERR("OWN_CLER fail, done(%d), sleep(%d), wakeup(%d)\n",
+ pOsalSignal->comp.done, gp_info->sleep_flag, gp_info->wakeup_flag);
+ STPSDIO_PR_LOUD("after op(%d)\n", op);
+ ret = 0;
+ break;
+ case OWN_STATE:
+ /* ret = stp_sdio_get_own_state(); */
+ STPSDIO_PR_INFO("omit op(%d)\n", op);
+ ret = 0;
+ break;
+ default:
+ STPSDIO_PR_WARN("omit op(%d)\n", op);
+ ret = -1;
+ break;
+ }
+ osal_ftrace_print("own control end, wakeup_flag(%d), sleep_flag(%d), signal done",
+ gp_info->wakeup_flag, gp_info->sleep_flag);
+ return ret;
+}
+
+#if STP_SDIO_OWN_THREAD
+
+static INT32 stp_sdio_wait_for_msg(PVOID pvData)
+{
+ MTK_WCN_STP_SDIO_HIF_INFO *pInfo = (MTK_WCN_STP_SDIO_HIF_INFO *) pvData;
+#if STP_SDIO_NEW_TXRING
+ STPSDIO_PR_LOUD
+ ("len(%u), wr_cnt(%u), rd_cnt(%u), irq_pending(%u), sleep(%u), wakeup(%u)\n",
+ pInfo->rx_pkt_len, atomic_read(&pInfo->pkt_buf.wr_cnt), atomic_read(&pInfo->pkt_buf.rd_cnt),
+ pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag);
+ osal_ftrace_print("len(%u), txwkr(%u), irq(%u), sleep(%u), wakeup(%u), tx_pkt_num(%u))\n",
+ pInfo->rx_pkt_len, pInfo->txwkr_flag, pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag,
+ pInfo->firmware_info.tx_packet_num);
+ return (pInfo->rx_pkt_len != 0)
+ || (pInfo->txwkr_flag != 0)
+ || (pInfo->irq_pending != 0)
+ || (pInfo->sleep_flag != 0)
+ || (pInfo->wakeup_flag != 0)
+ || (osal_thread_should_stop(&pInfo->tx_rx_thread));
+#else
+ STPSDIO_PR_LOUD
+ ("len(%u), rd_idx(%u), wr_idx(%u), irq_pending(%u), sleep(%u), wakeup(%u)\n",
+ pInfo->rx_pkt_len, atomic_read(&pInfo->pkt_buf.rd_idx), atomic_read(&pInfo->pkt_buf.wr_idx),
+ pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag);
+ osal_ftrace_print("len(%u), txwkr(%u), irq(%u), sleep(%u), wakeup(%u), tx_pkt_num(%u)\n",
+ pInfo->rx_pkt_len, pInfo->txwkr_flag, pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag,
+ pInfo->firmware_info.tx_packet_num);
+ return (pInfo->rx_pkt_len != 0)
+ || (pInfo->txwkr_flag != 0)
+ || (pInfo->irq_pending != 0)
+ || (pInfo->sleep_flag != 0)
+ || (pInfo->wakeup_flag != 0)
+ || (osal_thread_should_stop(&pInfo->tx_rx_thread));
+#endif /* STP_SDIO_NEW_TXRING */
+}
+
+static VOID stp_sdio_tx_rx_handling(PVOID pData)
+{
+ MTK_WCN_STP_SDIO_HIF_INFO *pInfo = (MTK_WCN_STP_SDIO_HIF_INFO *) pData;
+ UINT32 iRet = 0;
+ UINT32 chisr = 0;
+ UINT32 chlcpr_value = 0;
+ UINT32 write_value = 0;
+ UINT32 tx_comp = 0;
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx;
+ UINT32 while_loop_counter = 0;
+ UINT32 own_fail_counter = 0;
+ UINT32 val = 0;
+ UINT32 delay_us = 10000;
+ UINT32 chisr_error_count = 3;
+
+ STPSDIO_PR_INFO("stp_tx_rx_thread start running...\n");
+ if (pInfo == NULL) {
+ STPSDIO_PR_WARN("sanity check fail, (pInfo == NULL)\n");
+ return;
+ }
+ clt_ctx = pInfo->sdio_cltctx;
+
+ while (!osal_thread_should_stop(&pInfo->tx_rx_thread)) {
+ while_loop_counter++;
+ osal_ftrace_print("loop_count:%d\n", while_loop_counter);
+ /* <0> get CHLPCR information */
+ if (pInfo->awake_flag == 0) {
+ if (CLTCTX_CID(clt_ctx) == 0x6632)
+ stp_sdio_wake_up_ctrl(clt_ctx);
+ if (stp_sdio_do_own_clr(0) == 0) {
+ STPSDIO_PR_DBG("set OWN to driver side ok!\n");
+ pInfo->awake_flag = 1;
+ osal_ftrace_print("set OWN D ok!, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)",
+ pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag);
+ own_fail_counter = 0;
+ } else {
+ if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) {
+ pInfo->wakeup_flag = 0;
+ pInfo->sleep_flag = 0;
+ STPSDIO_PR_WARN("clr fw own fail,signal for sleep/wakeup to return\n");
+ osal_raise_signal(&pInfo->isr_check_complete);
+ }
+ if ((own_fail_counter % 50) == 0) {
+ STPSDIO_PR_ERR("set OWN to driver side error!\n");
+ /*trigger whole chip reset by send fake coredump content */
+ if (own_fail_counter == 0)
+ stp_sdio_issue_fake_coredump
+ ("ABT: STP-SDIO clear f/w own failed");
+ }
+ own_fail_counter++;
+ }
+ } else {
+ STPSDIO_PR_DBG("OWN on driver side!\n");
+ osal_ftrace_print("OWN D , sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)",
+ pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag);
+ }
+
+ if ((pInfo->wakeup_flag != 0) && (pInfo->awake_flag != 0)) {
+ while_loop_counter = 0;
+ STPSDIO_PR_DBG("clr firmware own! (wakeup) ok\n");
+ pInfo->wakeup_flag = 0;
+ osal_raise_signal(&pInfo->isr_check_complete);
+ osal_ftrace_print("wakeup done\n");
+ }
+
+ if ((pInfo->irq_pending != 0) && (pInfo->awake_flag == 1)) {
+ while_loop_counter = 0;
+
+ /* <1> get CHISR information */
+ iRet = mtk_wcn_hif_sdio_readl(clt_ctx, CHISR, &chisr);
+ if (iRet) {
+ /* 4 <1.1> get CHISR Rx error handling */
+ /* TODO: error handling! */
+ STPSDIO_PR_ERR("get CHISR information rx error, ret:%d\n", iRet);
+ if (-5 == iRet) {
+ iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_MAX_RETRY_NUM,
+ clt_ctx, CSR, &chisr, 0);
+ pInfo->irq_pending = 0;
+ }
+ } else {
+ pInfo->irq_pending = 0;
+ osal_ftrace_print("CHISR(0x%08x)\n", chisr);
+ }
+
+ if (pInfo->dump_flag != 0)
+ STPSDIO_PR_ERR("CHISR(0x%08x)\n", chisr);
+ else
+ STPSDIO_PR_DBG("CHISR(0x%08x)\n", chisr);
+
+
+ if (chisr == 0x0) {
+ STPSDIO_PR_ERR("******CHISR == 0*****\n");
+ while (chisr_error_count) {
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CCIR, &val, 0);
+ STPSDIO_PR_ERR("******CCIR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHLPCR, &val, 0);
+ STPSDIO_PR_ERR("******CHLPCR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CSDIOCSR, &val, 0);
+ STPSDIO_PR_ERR("******CSDIOCSR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHCR, &val, 0);
+ STPSDIO_PR_ERR("******CHCR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHISR, &chisr, 0);
+ STPSDIO_PR_ERR("******CHISR == 0x%x*****\n", chisr);
+ if (chisr)
+ break;
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHIER, &val, 0);
+ STPSDIO_PR_ERR("******CHIER == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CTFSR, &val, 0);
+ STPSDIO_PR_ERR("******CTFSR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CRPLR, &val, 0);
+ STPSDIO_PR_ERR("******CRPLR == 0x%x*****\n", val);
+ chisr_error_count--;
+ osal_usleep_range(delay_us, 2 * delay_us);
+ }
+ }
+
+ if (chisr & FW_OWN_BACK_INT)
+ STPSDIO_PR_HINT("FW_OWN_BACK_INT\n");
+
+ /* <4> handle Tx interrupt */
+ if ((chisr & TX_EMPTY) || (chisr & TX_UNDER_THOLD) || (chisr & TX_RETRY)) {
+ while_loop_counter = 0;
+ STPSDIO_PR_DBG("Tx interrupt\n");
+ /* get complete count */
+ tx_comp = (chisr & TX_COMPLETE_COUNT) >> 4;
+
+ tx_comp =
+ atomic_add_return(tx_comp, &pInfo->firmware_info.tx_comp_num);
+ if (tx_comp > STP_SDIO_TX_PKT_MAX_CNT)
+ STPSDIO_PR_ERR
+ ("Abnormal accumulated comp count(%d) chisr(0x%x)\n",
+ tx_comp, chisr);
+ if (chisr & TX_RETRY)
+ pInfo->tx_retry_flag = STP_SDIO_RETRY_INT;
+ }
+ if (pInfo->awake_flag == 1 && pInfo->tx_retry_flag != STP_SDIO_RETRY_CRC_ERROR)
+ stp_sdio_tx_wkr(&pInfo->tx_work);
+
+ if (chisr & RX_DONE) {
+ /* STPSDIO_PR_INFO("RX_DONE_INT\n"); */
+ if (pInfo->rx_pkt_len)
+ STPSDIO_PR_ERR("rx worker is not finished yet!\n");
+
+ /* get Rx packet length */
+ pInfo->rx_pkt_len = (chisr & RX_PKT_LEN) >> 16;
+ STPSDIO_PR_HINT("rx_pkt_len(%d)\n", pInfo->rx_pkt_len);
+ /* sanity check */
+ if ((pInfo->rx_pkt_len == 0) ||
+ (pInfo->rx_pkt_len > STP_SDIO_RX_FIFO_SIZE)) {
+ STPSDIO_PR_ERR
+ ("abnormal rx_pkt_len(%d) in CHISR(0x%08x) skip rx_worker\n",
+ pInfo->rx_pkt_len, chisr);
+ pInfo->rx_pkt_len = 0;
+ } else {
+ /* Before host driver read all rx data, chip/fw will not send more
+ * data to host. No need to mask rx interrupt. schedule rx worker to
+ * get data back and handle it.
+ */
+ if (pInfo->rx_pkt_len & 0x3)
+ STPSDIO_PR_WARN("rx len not 4 bytes, CHISR(0x%08x), rx len (%d).\n",
+ chisr, pInfo->rx_pkt_len);
+ }
+ /*Rx job */
+ stp_sdio_rx_wkr(&pInfo->rx_work);
+ mtk_wcn_stp_wmt_sdio_host_awake();
+ }
+
+ }
+
+ /* We schedule Tx job here without condition */
+ /*Tx job */
+ if (pInfo->awake_flag == 1 && pInfo->tx_retry_flag != STP_SDIO_RETRY_CRC_ERROR)
+ stp_sdio_tx_wkr(&pInfo->tx_work);
+
+ /*Enable IRQ */
+ /*Disable Common interrupt output in CHLPCR */
+ STPSDIO_PR_DBG("enable COM IRQ\n");
+ osal_ftrace_print("enable COM IRQ\n");
+/* need to wait for the ownback completion */
+/* [COHEC_00006052] SW work-around solution:
+ * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR
+ */
+#if COHEC_00006052
+ write_value = C_FW_INT_EN_SET;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#else
+ write_value = C_FW_INT_EN_SET;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#endif /* COHEC_00006052 */
+ if (iRet) {
+ STPSDIO_PR_ERR("enable IRQ fail. iRet:%d\n", iRet);
+ osal_ftrace_print("enable COM IRQ fail, iRet:%d\n", iRet);
+ } else {
+ STPSDIO_PR_HINT("enable COM IRQ\n");
+ iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &chlcpr_value, 0);
+ if (iRet) {
+ STPSDIO_PR_ERR("read CHLPCR fail. iRet:%d\n", iRet);
+ } else {
+ if (chlcpr_value & C_FW_INT_EN_SET) {
+ STPSDIO_PR_HINT("enable COM IRQ okay (0x%x)\n",
+ chlcpr_value);
+ osal_ftrace_print("enable COM IRQ done\n");
+
+ /* INTR_STATUS CHECK */
+#if 0
+ write_value = 0x00000002;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHCR, &write_value, 0);
+
+ iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHISR, &chisr, 0);
+ STPSDIO_PR_INFO("Query CHISR(0x%08x)\n", chisr);
+
+ write_value = 0x00000000;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT,
+ clt_ctx, CHCR, &write_value, 0);
+#endif
+ }
+ }
+
+ }
+
+ if ((pInfo->sleep_flag != 0)
+ && (pInfo->wakeup_flag == 0)
+ && (pInfo->irq_pending == 0)
+ && (pInfo->rx_pkt_len == 0)
+ && mtk_wcn_stp_is_ready()
+ && !mtk_wcn_stp_coredump_start_get() /* f/w assert disable sdio sleep */
+ ) {
+ if (pInfo->firmware_info.tx_packet_num == 0) {
+ /* pInfo->awake_flag = 0; */
+ /* STPSDIO_PR_INFO("set firmware own! (sleeping)\n"); */
+ while_loop_counter = 0;
+ osal_ftrace_print("|S|set F own\n");
+ stp_sdio_do_own_set(pInfo);
+ osal_ftrace_print("|E|set F own, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)",
+ pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag);
+ } else {
+#if 0
+ /* debug code */
+ if (while_loop_counter > 150) {
+ osal_ftrace_print("assert, w_l_c > %u\n", while_loop_counter);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx,
+ CHLPCR, &val, 0);
+ osal_ftrace_print("CHLPCR(0x%x)\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx,
+ CHISR, &val, 0);
+ osal_ftrace_print("CHISR(0x%x)\n", val);
+ iRet = wmt_core_trigger_stp_assert();
+ if (!iRet)
+ STPSDIO_PR_INFO("trigger assert fail\n");
+ }
+#endif
+ /*Avoid competition for SDIO operations with ksdioirqd/mmc2 thread*/
+ osal_usleep_range(300, 500);
+ }
+ }
+ if (while_loop_counter > 1000) {
+ while_loop_counter = 0;
+ pInfo->dump_flag = 1;
+ STPSDIO_PR_ERR("stp_sdio_tx_rx thread while_loop_counter over1000\n");
+ stp_sdio_dump_info(pInfo);
+ osal_ftrace_print("stp(%d)irq(%d)tx_pkt_num(%d)rx_pkt_len(%d)",
+ mtk_wcn_stp_is_ready(), pInfo->irq_pending,
+ pInfo->firmware_info.tx_packet_num, pInfo->rx_pkt_len);
+ /*make fake irq flag to dump CHISR information */
+ pInfo->irq_pending = 1;
+
+ if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) {
+ osal_ftrace_print("loop_count > 1000, sleep_flag(%d), wakeup_flag(%d), awake_flag(%d)",
+ pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag);
+ /*clear wakeup/sleep pending flag, wakeup wmtd thread */
+ pInfo->wakeup_flag = 0;
+ pInfo->sleep_flag = 0;
+ osal_raise_signal(&pInfo->isr_check_complete);
+ if (pInfo->firmware_info.tx_packet_num == STP_SDIO_TX_PKT_MAX_CNT) {
+ STPSDIO_PR_ERR("STP-SDIO can't handle tx request. tx_packet_num:%d\n",
+ pInfo->firmware_info.tx_packet_num);
+ osal_sleep_ms(200);
+ }
+ }
+ } else {
+ pInfo->dump_flag = 0;
+ }
+ osal_wait_for_event(&pInfo->tx_rx_event, stp_sdio_wait_for_msg, (PVOID) pInfo);
+ /* Read Packet from Firmware until firmware rx packet empty */
+ STPSDIO_PR_DBG("stp_tx_rx_thread receive signal\n");
+ }
+ /*make sure thread who is waiting for STP-SDIO's sleep/wakeup completion event */
+ if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) {
+ osal_ftrace_print("wait for sleep/wakeup event, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)",
+ pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag);
+ pInfo->wakeup_flag = 0;
+ pInfo->sleep_flag = 0;
+ STPSDIO_PR_WARN("someone is wait for sleep/wakeup event, signal it to return\n");
+ osal_raise_signal(&pInfo->isr_check_complete);
+ }
+ STPSDIO_PR_INFO("stp_tx_rx_thread exit\n");
+}
+#endif /* STP_SDIO_OWN_THREAD */
+
+/*!
+ * \brief Tx callback function for STP-CORE module
+ *
+ * \details A function registered to STP-CORE to provide STP-SDIO tx method.
+ * Multiple STP packet may be aggregated when available.
+ *
+ * \param[IN] data STP packet buffer to be sent through STP-SDIO
+ * \param[IN] size STP packet length to be sent
+ * \param[OUT] written_size Accepted buffer length by STP-SDIO. Shall be $size
+ * if success.
+ *
+ *\note Tx may do aggregation to previous entry with lock protection. If no
+ * aggregation is done, protection is NOT required.
+ *
+ * \retval 0 success
+ * \retval -1 invalid input parameters
+ * \todo return !0 when fail case (TBD)
+ */
+#if STP_SDIO_NEW_TXRING
+INT32 stp_sdio_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size)
+{
+ PUINT8 pkt_bufp;
+ UINT32 prev_wr_idx;
+ UINT32 prev_size;
+ MTK_WCN_STP_SDIO_PKT_BUF *pb = NULL;
+ UINT32 idx;
+
+ osal_ftrace_print("%s|S|L|%d\n", __func__, size);
+ if (written_size)
+ *written_size = 0;
+
+ /* do sanity check */
+ if ((size > STP_SDIO_TX_FIFO_SIZE)
+ || (!data)) {
+ STPSDIO_PR_LOUD("invalid size(%ld) > fifo(%d) or data(0x%p)\n",
+ size, STP_SDIO_TX_FIFO_SIZE, data);
+ return -1;
+ }
+
+ pb = &gp_info->pkt_buf;
+ /* 4 <1> enqueue the stp Tx packet */
+
+ spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ /* Case 1: buffer is empty (No aggregation). Full flag is useless in this
+ * condition.
+ */
+ if (atomic_read(&pb->rd_cnt) == atomic_read(&pb->wr_cnt)) {
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ /* Set the size in SDIO packet header later in tx_worker, not here */
+ idx = atomic_read(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK;
+ pb->tx_buf_ts[idx] = jiffies;
+ pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE;
+#if KMALLOC_UPDATE
+ pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE];
+#endif
+ memcpy(pkt_bufp, data, size);
+ gp_info->txwkr_flag = 1;
+ atomic_inc(&pb->wr_cnt);
+
+ if (written_size)
+ *written_size = size;
+ STPSDIO_PR_DBG("(Empty) Enqueue done\n");
+ }
+ /* Case 2: buffer is neither empty(w != r) nor full (w-r < s) */
+ else if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) < STP_SDIO_TX_BUF_CNT) {
+ prev_wr_idx = (atomic_read(&pb->wr_cnt) - 1) & STP_SDIO_TX_BUF_CNT_MASK;
+ prev_size = pb->tx_buf_sz[prev_wr_idx];
+
+ /* Case 2.1 Aggregate if rd_cnt+1 != wr_cnt */
+ /* George: do length check using add instead of sub operation. Compare
+ * to FIFO size instead of sw entry size.
+ */
+ if (((atomic_read(&pb->rd_cnt) + 1) != atomic_read(&pb->wr_cnt))
+ && ((size + prev_size) <= STP_SDIO_TX_FIFO_SIZE)) {
+#if KMALLOC_UPDATE
+ pkt_bufp = pb->tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + prev_size;
+#else
+ pkt_bufp = &pb->tx_buf[prev_wr_idx][prev_size];
+#endif
+ pb->tx_buf_sz[prev_wr_idx] += size;
+
+ memcpy(pkt_bufp, data, size);
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+
+ STPSDIO_PR_DBG("(Not empty-aggre) Enqueue done\n");
+
+ if (written_size)
+ *written_size = size;
+ }
+ /* Case 2.2 Use next entry w/o aggregation */
+ else {
+ /* Check the ring buf is full or not */
+ if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) == 1)
+ pb->full_flag = MTK_WCN_BOOL_TRUE;
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+
+ /* George: if tx_wkr preempts here and pop out all buffered entries,
+ * ie increase rd_idx utill wr_idx, tx_wkr will encounter buffer
+ * empty condition and stop, then being scheduled before end of this
+ * function. It's safe!
+ */
+ idx = atomic_read(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK;
+ pb->tx_buf_ts[idx] = jiffies;
+ pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE;
+#if KMALLOC_UPDATE
+ pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE];
+#endif
+ memcpy(pkt_bufp, data, size);
+ gp_info->txwkr_flag = 1;
+ atomic_inc(&pb->wr_cnt);
+
+ STPSDIO_PR_DBG("(Not empty-no aggre) Enqueue done\n");
+ if (written_size)
+ *written_size = size;
+ }
+ }
+ /* Case 3: buffer is full (w-r >= s), (try aggregation) */
+ else {
+ if (!((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) >= STP_SDIO_TX_BUF_CNT)) {
+ STPSDIO_PR_ERR
+ ("abnormal condition and flow, wr_cnt(0x%x), rd_cnt(0x%x)\n",
+ atomic_read(&pb->wr_cnt), atomic_read(&pb->rd_cnt));
+ }
+ prev_wr_idx = (atomic_read(&pb->wr_cnt) - 1) & STP_SDIO_TX_BUF_CNT_MASK;
+ prev_size = pb->tx_buf_sz[prev_wr_idx];
+
+ /* George: do length check using add instead of sub operation. Compare
+ * to FIFO size instead of sw entry size. (buf_allocation != 0) shall be
+ * an assert true condition, not a if () condition......
+ */
+ /* Case 3.1 Aggregation */
+ if ((size + prev_size) <= STP_SDIO_TX_FIFO_SIZE) {
+ if (prev_size != 0)
+ STPSDIO_PR_ERR("abnormal, wr_cnt(0x%x), rd_cnt(0x%x), prev(%d), prev_size(%d)\n",
+ atomic_read(&pb->wr_cnt), atomic_read(&pb->rd_cnt),
+ prev_wr_idx, prev_size);
+#if KMALLOC_UPDATE
+ pkt_bufp = pb->tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + prev_size;
+#else
+ pkt_bufp = &pb->tx_buf[prev_wr_idx][prev_size];
+#endif
+ pb->tx_buf_sz[prev_wr_idx] += size;
+
+ /* unlock after copying data to ring buffer done so that rd_cnt can
+ * move forward and may overlap to prev_wr_idx.
+ */
+ memcpy(pkt_bufp, data, size);
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+
+ STPSDIO_PR_DBG("(full-aggre) Enqueue done\n");
+
+ if (written_size)
+ *written_size = size;
+ }
+ /* Case 3.2 Buffer is full */
+ else {
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ STPSDIO_PR_WARN("Local Tx buffer is full !\n");
+
+ /* Wait for tx ring buffer is not full */
+ /* TODO:[FixMe][George] This wait() call IS a problem if caller runs
+ * in interrupt context (sw or hw) !!
+ */
+ /* TODO:[FixMe][George] should use timeout version,
+ * not interruptible version. Return error when timeout!
+ */
+ wait_event_interruptible(pb->fullwait_q,
+ (pb->full_flag == MTK_WCN_BOOL_FALSE));
+ STPSDIO_PR_INFO("wait event return\n");
+
+ spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ /* Check if the local buf is free enough */
+ if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) == 1)
+ pb->full_flag = MTK_WCN_BOOL_TRUE;
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+
+ /* George: use this new entry w/o protection */
+ idx = atomic(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK;
+ pb->tx_buf_ts[idx] = jiffies;
+ pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE;
+#if KMALLOC_UPDATE
+ pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE];
+#endif
+ /* Copy data to ring buffer */
+ memcpy(pkt_bufp, data, size);
+ gp_info->txwkr_flag = 1;
+ atomic_inc(&pb->wr_cnt);
+
+ if (written_size)
+ *written_size = size;
+ }
+ }
+
+ /* <2> schedule for Tx worker tasklet */
+ osal_ftrace_print("%s|E|signal stp_sdio_tx_rx\n", __func__);
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_schedule(&gp_info->tx_rx_job); */
+ STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n");
+ osal_trigger_event(&gp_info->tx_rx_event);
+#else
+ schedule_work(&gp_info->tx_work);
+#endif
+ osal_ftrace_print("%s|E|L|%d\n", __func__, size);
+
+ return 0;
+}
+
+#else
+INT32 stp_sdio_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size)
+{
+ PUINT8 pkt_bufp;
+ UINT32 prev_wr_idx;
+ UINT32 buf_allocation;
+ UINT32 room;
+ UINT64 ts;
+ ULONG nsec;
+
+ osal_ftrace_print("%s|S|L|%d\n", __func__, size);
+
+ /* 4 <1> enqueue the stp Tx packet */
+ *written_size = 0;
+
+ spin_lock_irqsave(&gp_info->pkt_buf.rd_idx_lock, gp_info->pkt_buf.rd_irq_flag);
+ /* Case 1: buffer is empty (Not aggregation) */
+ if ((atomic_read(&gp_info->pkt_buf.rd_idx) == atomic_read(&gp_info->pkt_buf.wr_idx))
+ && (gp_info->pkt_buf.full_flag == MTK_WCN_BOOL_FALSE)) {
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, gp_info->pkt_buf.rd_irq_flag);
+ /* set the size in SDIO packet header */
+#if KMALLOC_UPDATE
+ *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) *
+ STP_SDIO_TX_ENTRY_SIZE + 0) = (UINT8)((size + STP_SDIO_HDR_SIZE) & 0xff);
+ *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) *
+ STP_SDIO_TX_ENTRY_SIZE + 1) = (UINT8)((size + STP_SDIO_HDR_SIZE) >> 8);
+#else
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff);
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8);
+#endif
+ gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies;
+ osal_get_local_time(&ts, &nsec);
+ gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts;
+ gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec;
+
+ STPSDIO_PR_DBG("(Empty) Enqueue done\n");
+#if KMALLOC_UPDATE
+ pkt_bufp = gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) *
+ STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ pkt_bufp = &gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE];
+#endif
+ memcpy(pkt_bufp, data, size);
+ *written_size = size;
+ gp_info->txwkr_flag = 1;
+ atomic_set(&gp_info->pkt_buf.wr_idx,
+ (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT);
+ }
+ /* Case 2: buffer is not empty */
+ else if (atomic_read(&gp_info->pkt_buf.rd_idx) != atomic_read(&gp_info->pkt_buf.wr_idx)) {
+ prev_wr_idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 + STP_SDIO_TX_BUF_CNT) %
+ STP_SDIO_TX_BUF_CNT;
+ /* set the packet size form previous SDIO packet header */
+#if KMALLOC_UPDATE
+ buf_allocation =
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1);
+ buf_allocation =
+ (buf_allocation << 8) | *(gp_info->pkt_buf.tx_buf +
+ prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0);
+#else
+ buf_allocation = gp_info->pkt_buf.tx_buf[prev_wr_idx][1];
+ buf_allocation = (buf_allocation << 8) | gp_info->pkt_buf.tx_buf[prev_wr_idx][0];
+#endif
+ /* Case 2.1 Aggregation */
+ /* George: do length check using add instead of sub operation. Compare
+ * to FIFO size instead of sw entry size.
+ */
+ if ((prev_wr_idx != atomic_read(&gp_info->pkt_buf.rd_idx))
+ && ((size + buf_allocation) <= STP_SDIO_TX_FIFO_SIZE)) {
+#if KMALLOC_UPDATE
+ pkt_bufp =
+ gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE +
+ buf_allocation;
+
+ buf_allocation += size;
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0) =
+ (UINT8) (buf_allocation & 0xff);
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1) =
+ (UINT8) (buf_allocation >> 8);
+#else
+ pkt_bufp = &gp_info->pkt_buf.tx_buf[prev_wr_idx][buf_allocation];
+
+ buf_allocation += size;
+ gp_info->pkt_buf.tx_buf[prev_wr_idx][0] = (UINT8) (buf_allocation & 0xff);
+ gp_info->pkt_buf.tx_buf[prev_wr_idx][1] = (UINT8) (buf_allocation >> 8);
+#endif
+ memcpy(pkt_bufp, data, size);
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+
+ STPSDIO_PR_DBG("(Not empty-aggre) Enqueue done\n");
+
+ *written_size = size;
+ }
+ /* Case 2.2 Not aggregation */
+ else {
+ /* Check the ring buf is full or not */
+ room = (atomic_read(&gp_info->pkt_buf.wr_idx) >=
+ atomic_read(&gp_info->pkt_buf.rd_idx)) ? (STP_SDIO_TX_BUF_CNT -
+ (atomic_read(&gp_info->pkt_buf.wr_idx) -
+ atomic_read(&gp_info->pkt_buf.rd_idx))) :
+ (atomic_read(&gp_info->pkt_buf.rd_idx) -
+ atomic_read(&gp_info->pkt_buf.wr_idx));
+ if (room == 1)
+ gp_info->pkt_buf.full_flag = MTK_WCN_BOOL_TRUE;
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+
+ /* George: if tx_wkr preempts here and pop out all buffered entries,
+ * ie increase rd_idx utill wr_idx, tx_wkr will encounter buffer
+ * empty condition and stop, then being scheduled before end of this
+ * function. It's safe!
+ */
+
+ /* set the size in SDIO packet header */
+#if KMALLOC_UPDATE
+ *(gp_info->pkt_buf.tx_buf +
+ atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + 0) =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff);
+ *(gp_info->pkt_buf.tx_buf +
+ atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + 1) =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8);
+ gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies;
+ osal_get_local_time(&ts, &nsec);
+ gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts;
+ gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec;
+
+ pkt_bufp =
+ gp_info->pkt_buf.tx_buf +
+ atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff);
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8);
+ gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies;
+
+ pkt_bufp = &gp_info->pkt_buf.
+ tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE];
+#endif
+ memcpy(pkt_bufp, data, size);
+
+ STPSDIO_PR_DBG("(Not empty-no aggre) Enqueue done\n");
+
+ *written_size = size;
+ gp_info->txwkr_flag = 1;
+ atomic_set(&gp_info->pkt_buf.wr_idx,
+ (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT);
+ }
+ }
+ /* Case 3: buffer is full (Aggregation) */
+ else if (gp_info->pkt_buf.full_flag != MTK_WCN_BOOL_FALSE) {
+ prev_wr_idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 + STP_SDIO_TX_BUF_CNT) %
+ STP_SDIO_TX_BUF_CNT;
+#if KMALLOC_UPDATE
+ buf_allocation =
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1);
+ buf_allocation =
+ (buf_allocation << 8) | *(gp_info->pkt_buf.tx_buf +
+ prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0);
+#else
+ buf_allocation = gp_info->pkt_buf.tx_buf[prev_wr_idx][1];
+ buf_allocation = (buf_allocation << 8) | gp_info->pkt_buf.tx_buf[prev_wr_idx][0];
+#endif
+ /* Case 3.1 Aggregation */
+ /* George: do length check using add instead of sub operation. Compare
+ * to FIFO size instead of sw entry size. (buf_allocation != 0) shall be
+ * an assert true condition, not a if () condition......
+ */
+ if ((buf_allocation != 0)
+ && ((size + buf_allocation) <= STP_SDIO_TX_FIFO_SIZE)) {
+#if KMALLOC_UPDATE
+ pkt_bufp =
+ gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE +
+ buf_allocation;
+#else
+ pkt_bufp = &gp_info->pkt_buf.tx_buf[prev_wr_idx][buf_allocation];
+#endif
+ buf_allocation += size;
+#if KMALLOC_UPDATE
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0) =
+ (UINT8) (buf_allocation & 0xff);
+ *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1) =
+ (UINT8) (buf_allocation >> 8);
+#else
+ gp_info->pkt_buf.tx_buf[prev_wr_idx][0] = (UINT8) (buf_allocation & 0xff);
+ gp_info->pkt_buf.tx_buf[prev_wr_idx][1] = (UINT8) (buf_allocation >> 8);
+#endif
+ /* Copy data to ring buffer */
+ memcpy(pkt_bufp, data, size);
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+
+ STPSDIO_PR_DBG("(full-aggre) Enqueue done\n");
+
+ *written_size = size;
+ }
+ /* Case 3.2 Buffer is full */
+ else {
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+ STPSDIO_PR_WARN("Local Tx buffer is full !!!!!\n");
+
+ /* Wait for tx ring buffer is not full
+ * TODO:[FixMe][George] This wait() call IS a problem
+ * if caller runs in interrupt context (sw or hw) !!
+ * TODO:[FixMe][George] should use timeout version,
+ * not interruptible version. Return error when timeout!
+ */
+ wait_event_interruptible(gp_info->pkt_buf.fullwait_q,
+ (!gp_info->pkt_buf.full_flag));
+ STPSDIO_PR_INFO("wait event return\n");
+
+ spin_lock_irqsave(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+ /* Check if the local buf is free enough */
+ room = (atomic_read(&gp_info->pkt_buf.wr_idx) >=
+ atomic_read(&gp_info->pkt_buf.rd_idx)) ?
+ (STP_SDIO_TX_BUF_CNT - (atomic_read(&gp_info->pkt_buf.wr_idx) -
+ atomic_read(&gp_info->pkt_buf.rd_idx))) :
+ (atomic_read(&gp_info->pkt_buf.rd_idx) -
+ atomic_read(&gp_info->pkt_buf.wr_idx));
+ if (room == 1)
+ gp_info->pkt_buf.full_flag = MTK_WCN_BOOL_TRUE;
+ spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock,
+ gp_info->pkt_buf.rd_irq_flag);
+
+ /* George: use this new entry w/o protection */
+#if KMALLOC_UPDATE
+ *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) *
+ STP_SDIO_TX_ENTRY_SIZE + 0) =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff);
+ *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) *
+ STP_SDIO_TX_ENTRY_SIZE + 1) =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8);
+ gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies;
+ osal_get_local_time(&ts, &nsec);
+ gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts;
+ gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec;
+
+ pkt_bufp = gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx)
+ * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE;
+#else
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff);
+ gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] =
+ (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8);
+ gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies;
+
+ pkt_bufp = &gp_info->pkt_buf.
+ tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE];
+#endif
+ /* Copy data to ring buffer */
+ memcpy(pkt_bufp, data, size);
+ *written_size = size;
+ gp_info->txwkr_flag = 1;
+ atomic_set(&gp_info->pkt_buf.wr_idx,
+ (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT);
+ }
+ }
+ /* <2> schedule for Tx worker tasklet */
+ osal_ftrace_print("%s|E|signal stp_sdio_tx_rx\n", __func__);
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_schedule(&gp_info->tx_rx_job); */
+ STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n");
+ osal_trigger_event(&gp_info->tx_rx_event);
+#else
+ schedule_work(&gp_info->tx_work);
+#endif
+ osal_ftrace_print("%s|E|L|%d\n", __func__, size);
+
+ return 0;
+}
+#endif /* end of !STP_SDIO_NEW_TXRING */
+
+/*!
+ * \brief Do STP-SDIO tx status, counters, debug information sanity check
+ *
+ * \details A function doing sanity checks on STP-SDIO Tx-related status,
+ * counters, debugging information. Used in tx_worker before and after bus
+ * write to check if any abnormal status happened.
+ *
+ * \param[IN] p_info The STP-SDIO HIF information structure pointer
+ * \param[IN] id The sanity check location ID, assigned by caller
+ *
+ * \retval none.
+ */
+static _osal_inline_ VOID stp_sdio_check_tx_sanity(const MTK_WCN_STP_SDIO_HIF_INFO *p_info, const UINT32 id)
+{
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ if ((p_info) && (p_info->firmware_info.tx_packet_num == 0)) {
+ if (!(p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt)) {
+ STPSDIO_PR_ERR
+ ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n",
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt),
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id);
+ /* stp_sdio_dump_txdbg(); */
+ }
+ if (p_info->firmware_info.tx_fifo_size != STP_SDIO_TX_FIFO_SIZE) {
+ STPSDIO_PR_ERR
+ ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n",
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt),
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id);
+ /* stp_sdio_dump_txdbg(); */
+ }
+ } else {
+ if ((p_info) && (p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt)) {
+ STPSDIO_PR_ERR
+ ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n",
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt),
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id);
+ /* stp_sdio_dump_txdbg(); */
+ }
+ }
+#endif
+}
+
+/*!
+ * \brief Handle STP-SDIO TX IRQ BH part and complete count
+ *
+ * \details Handle STP-SDIO TX IRQ bottom half part and reported tx complete
+ * coount. This function is used in tx_worker ONLY to avoid race condition.
+ *
+ * \note tx_comp_num in firmware_info structure shall be handled atomically.
+ * It is added in STP-SDIO Tx IRQ top half handler with the number reported
+ * in CHISR. It is deducted in this function.
+ *
+ * \note tx_fifo_size is deducted in tx_worker when writing data to bus and
+ * added back in this function when tx complete.
+ *
+ * \param[IN] p_info The STP-SDIO HIF information structure pointer
+ *
+ * \retval none.
+ */
+static VOID stp_sdio_tx_wkr_comp(MTK_WCN_STP_SDIO_HIF_INFO * const p_info)
+{
+ INT32 comp_count;
+ UINT32 idx;
+ INT32 i;
+ INT32 max;
+ INT32 ret;
+ UINT32 value = 0;
+
+ comp_count = atomic_read(&p_info->firmware_info.tx_comp_num);
+ atomic_sub(comp_count, &p_info->firmware_info.tx_comp_num);
+
+ /* update tx to firemware information */
+ if (p_info->firmware_info.tx_packet_num >= comp_count) {
+ STPSDIO_PR_DBG("tx_pack_num(%d), comp_count(%d),tx_comp_num(%d), retry flag(%d)\n",
+ p_info->firmware_info.tx_packet_num, comp_count,
+ atomic_read(&p_info->firmware_info.tx_comp_num),
+ p_info->tx_retry_flag);
+ p_info->firmware_info.tx_packet_num -= comp_count;
+ } else {
+ STPSDIO_PR_INFO("abnormal complete count(%d), tx_packet_num(%d), retry flag(%d)!\n",
+ comp_count, p_info->firmware_info.tx_packet_num, p_info->tx_retry_flag);
+ /* TODO: [FixMe][George] Add error handling or bug report!! */
+ STPSDIO_PR_INFO("tx_fifo_size(%d), tx_packet_num(%d)\n",
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num);
+ }
+
+ while (comp_count > 0) {
+ if (p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt) {
+ STPSDIO_PR_ERR("tx complete count(%d) but tx_pkt_list empty\n",
+ comp_count);
+ STPSDIO_PR_ERR("rd_cnt(%u, idx:%lx), wr_cnt(%u, idx:%lx)!\n",
+ p_info->tx_pkt_list.pkt_rd_cnt,
+ p_info->tx_pkt_list.pkt_rd_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK,
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ p_info->tx_pkt_list.pkt_wr_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK);
+ break;
+ }
+
+ idx = p_info->tx_pkt_list.pkt_rd_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK;
+ p_info->firmware_info.tx_fifo_size += p_info->tx_pkt_list.pkt_size_list[idx];
+ p_info->tx_pkt_list.out_ts[idx] = jiffies;
+ --comp_count;
+ }
+ if (p_info->retry_enable_flag) {
+ if (p_info->tx_retry_flag == STP_SDIO_RETRY_INT) {
+ for (i = 0; i < 100; i++) {
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ CTMDPCR0, &value, 0);
+ if (value & 1)
+ break;
+ osal_sleep_ms(10);
+ }
+ if (!(value & 1)) {
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ CTMDPCR0, &value, 0);
+ STPSDIO_PR_ERR("tx retry: firmware rx buffer is disable CTMDPCR0 value(%x)!\n",
+ value);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ CTMDPCR1, &value, 0);
+ STPSDIO_PR_ERR("tx retry: firmware rx buffer is disable CTMDPCR1 value(%x)!\n",
+ value);
+ stp_sdio_issue_fake_coredump
+ ("ABT: tx retry ERROR: firmware rx buffer is disable");
+ }
+ idx = p_info->tx_pkt_list.pkt_rd_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK;
+ max = p_info->firmware_info.tx_packet_num;
+ STPSDIO_PR_ERR("tx retry idx(%d) tx retry max(%d)\n", idx, max);
+ for (i = 0; i < max; i++) {
+ /* sdio crc error tx retry */
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT,
+ p_info->sdio_cltctx, CTDR,
+ (PUINT32)(p_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0),
+ p_info->tx_pkt_list.pkt_size_list[idx]);
+ if (ret) {
+ STPSDIO_PR_ERR("sdio tx retry get CTDR information Tx error(%d)!\n",
+ ret);
+ /* TODO: error handling! */
+ p_info->tx_retry_count++;
+ if (p_info->tx_retry_count > STP_SDIO_RETRY_LIMIT) {
+ STPSDIO_PR_INFO("sdio tx retry fail complete count(%d)\n",
+ comp_count);
+ STPSDIO_PR_INFO("tx_packet_num(%d), tx_fifo_size(%d)\n",
+ p_info->firmware_info.tx_packet_num,
+ p_info->firmware_info.tx_fifo_size);
+ STPSDIO_PR_INFO("retry flag(%d)!\n", p_info->tx_retry_flag);
+ /* TODO: error handling! */
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ stp_sdio_txdbg_dump();
+#endif
+ p_info->tx_retry_count = 0;
+ stp_sdio_issue_fake_coredump
+ ("ABT: write_readsb retry ERROR");
+ }
+ } else
+ p_info->tx_retry_count = 0;
+ idx++;
+ idx = idx & STP_SDIO_TX_PKT_LIST_SIZE_MASK;
+ }
+ p_info->tx_retry_flag = STP_SDIO_RETRY_NONE;
+ }
+ }
+}
+
+/*!
+ * \brief Handle STP-SDIO Tx buffer and send to bus
+ *
+ * \details Handle STP-SDIO Tx buffer and send SDIO packet to bus if everything
+ * is checked ok.
+ *
+ * \note Tx count to FIFO is counted on a 4-byte aligned base. 1~3 bytes padding
+ * are also sent into HW FIFO and SHALL be trimmed off by firmware.
+ * tx_fifo_size is deducted in this bus when writing data to bus and added
+ * back in handle_tx_comp() function.
+ *
+ * \note Data length written to bus shall be 4-byte aligned AND block_size
+ * aligned if length > block_size. Padding bytes added for block_size is
+ * removed by HW.
+ *
+ * \note Max accumulated Tx size to FIFO is limited by STP_SDIO_TX_FIFO_SIZE and
+ * it is (2080) for MT6620. It is NOT limited to 256*5=1280 bytes.
+ *
+ * \note Max outstanding Tx packet count is limited by STP_SDIO_TX_PKT_MAX_CNT
+ * and it is (7) for MT6620.
+ *
+ * \param[IN] work Tx work struct work_struct pointer used by STP-SDIO
+ *
+ * \retval none.
+ */
+#if STP_SDIO_NEW_TXRING
+static VOID stp_sdio_tx_wkr(struct work_struct *work)
+{
+ MTK_WCN_STP_SDIO_HIF_INFO *p_info;
+ UINT32 bus_txlen;
+ UINT32 four_byte_align_len;
+ PUINT8 buf_tx;
+ INT32 ret;
+ UINT32 idx;
+ MTK_WCN_STP_SDIO_PKT_BUF *pb;
+ struct timeval now;
+ UINT64 ts;
+ ULONG nsec;
+
+ p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, tx_work);
+ ret = HIF_SDIO_ERR_SUCCESS;
+ pb = &p_info->pkt_buf;
+
+ /* 4 <0> Tx worker has been scheduled to send data */
+ do {
+ /* handle tx complete count if any */
+ stp_sdio_tx_wkr_comp(p_info);
+ /* check sanity of local tx information */
+ stp_sdio_check_tx_sanity(p_info, 1);
+
+ /* check if Tx ring buffer is empty */
+ if (atomic_read(&p_info->pkt_buf.wr_cnt) == atomic_read(&p_info->pkt_buf.rd_cnt)) {
+ /* full flag is use less in this condition */
+ STPSDIO_PR_DBG("Tx entry ring buffer empty\n");
+ break;
+ }
+ p_info->txwkr_flag = 0;
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ ++stp_sdio_txperf_worker_cnt;
+#endif
+
+ /* George: check txed packet number < limit(7)
+ * tx_packet_num is maintained only in tw_worker, no protection.
+ */
+ if (p_info->firmware_info.tx_packet_num >= STP_SDIO_TX_PKT_MAX_CNT) {
+ STPSDIO_PR_DBG
+ ("tx_packet_num(%ld) limit, tx_fifo_size(%ld), four_byte_align_len(%ld)\n",
+ p_info->firmware_info.tx_packet_num,
+ p_info->firmware_info.tx_fifo_size, four_byte_align_len);
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ ++stp_sdio_txperf_pkt_num_lmt_cnt;
+#endif
+ break;
+ }
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ stp_sdio_txperf_txed_pkt_num += p_info->firmware_info.tx_packet_num;
+#endif
+
+ /* Access content in rd_cnt is safe because it will not be aggregated
+ * anymore in sdio_tx(). Check current tx condition with info in rd_cnt.
+ */
+ idx = atomic(&pb->rd_cnt) & STP_SDIO_TX_BUF_CNT_MASK;
+
+ /* Get Tx packet size from Tx size ring buf */
+ bus_txlen = pb->tx_buf_sz[idx];
+ /* Update packet length in Tx entry */
+#if KMALLOC_UPDATE
+ buf_tx = gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0;
+#else
+ buf_tx = &pb->tx_buf[idx][0];
+#endif
+ buf_tx[0] = (UINT8) (bus_txlen & 0xff);
+ buf_tx[1] = (UINT8) ((bus_txlen >> 8) & 0xff);
+
+ /* George: hw always count fifo in 4-byte aligned length */
+ bus_txlen += 0x3;
+ bus_txlen &= ~(0x3UL);
+ four_byte_align_len = bus_txlen;
+
+ /* Sanity check: 4-byte aligned length shall not exceed HW FIFO Size */
+ if (four_byte_align_len > STP_SDIO_TX_FIFO_SIZE) {
+ STPSDIO_PR_ERR("abnormal four_byte_align_len(%d) > TX_FIFO_SIZE(%ld)!!\n",
+ four_byte_align_len, STP_SDIO_TX_FIFO_SIZE);
+ }
+
+ /* George: check if tx FIFO space is enough for 4-byte aligned length.
+ * If enough, tx this entry and increase rd_cnt.
+ */
+ if (p_info->firmware_info.tx_fifo_size >= four_byte_align_len) {
+ /* George: refine block_size alignment with the assumption: block_size is 2^*x */
+ if (bus_txlen > STP_SDIO_BLK_SIZE) {
+ bus_txlen += (STP_SDIO_BLK_SIZE - 1);
+ bus_txlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1);
+ }
+
+ /* Sanity check: bus_txlen shall not exceed SW entry size */
+ if (bus_txlen > STP_SDIO_TX_ENTRY_SIZE) {
+ STPSDIO_PR_ERR
+ ("abnormal bus_txlen(%d) > STP_SDIO_TX_ENTRY_SIZE(%ld)!!\n",
+ bus_txlen, STP_SDIO_TX_ENTRY_SIZE);
+ }
+
+ ++(p_info->firmware_info.tx_packet_num);
+ /* decrease Tx FIFO size: using 4-byte aligned length! */
+ p_info->firmware_info.tx_fifo_size -= four_byte_align_len;
+ /* record the SDIO packet size in packet size list: using 4-byte aligned length! */
+ idx = p_info->tx_pkt_list.pkt_wr_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK;
+ p_info->tx_pkt_list.pkt_size_list[idx] = four_byte_align_len;
+ p_info->tx_pkt_list.in_ts[idx] = jiffies;
+ p_info->tx_pkt_list.out_ts[idx] = 0;
+
+ STPSDIO_PR_DBG("wr(0x%x, %ld) rd(0x%x, %ld), tx fifo(size:%d), pkt_num(%d)done\n",
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt),
+ p_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt),
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num);
+
+ /* port write the packet to CTDR */
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ CTDR, (PUINT32) buf_tx, bus_txlen);
+ STPSDIO_PR_DBG("write to CTDR done\n");
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ do {
+ osal_get_local_time(&ts, &nsec);
+ idx = stp_sdio_txdbg_cnt++ & STP_SDIO_TXDBG_COUNT_MASK;
+ /* skip clear buf */
+ stp_sdio_txdbg_buffer[idx].ts = jiffies;
+ stp_sdio_txdbg_buffer[idx].l_sec = ts;
+ stp_sdio_txdbg_buffer[idx].l_nsec = nsec;
+ stp_sdio_txdbg_buffer[idx].bus_txlen = bus_txlen;
+ stp_sdio_txdbg_buffer[idx].four_byte_align_len =
+ four_byte_align_len;
+ /* store content */
+ if (bus_txlen <= STP_SDIO_TX_ENTRY_SIZE) {
+ memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx,
+ bus_txlen);
+ } else {
+ memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx,
+ STP_SDIO_TX_ENTRY_SIZE);
+ STPSDIO_PR_ERR("abnormal bus_txlen (%d)!\n", bus_txlen);
+ }
+ } while (0);
+#endif
+ if (ret) {
+ STPSDIO_PR_ERR("get CTDR information Tx error(%d)!\n", ret);
+ if (p_info->retry_enable_flag) {
+ if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY)
+ p_info->tx_retry_flag = STP_SDIO_RETRY_CRC_ERROR;
+ else {
+ p_info->tx_retry_count = 0;
+ p_info->tx_retry_flag = STP_SDIO_RETRY_NONE;
+ stp_sdio_issue_fake_coredump
+ ("ABT: write_readsb retry ERROR");
+ }
+ } else
+ stp_sdio_issue_fake_coredump("ABT: write_readsb retry ERROR");
+ }
+
+ /* clear rd index entry of Tx ring buffer */
+ /*memset(buf_tx, 0, STP_SDIO_TX_ENTRY_SIZE); */
+ /* George: clear STP-SDIO header only for debugging. */
+ /*memset(buf_tx, 0, 4); */
+ /* need clear??? skip it for debugging */
+
+ spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ atomic_inc(&pb->rd_cnt);
+ /* TODO: [FixMe][George] check if full_flag needed? */
+ if (pb->full_flag != MTK_WCN_BOOL_FALSE) {
+ pb->full_flag = MTK_WCN_BOOL_FALSE;
+ wake_up_interruptible(&pb->fullwait_q);
+ }
+ spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag);
+ osal_do_gettimeofday(&old);
+ } else {
+ /* tx FIFO free space < packet size, wait next time */
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ stp_sdio_txperf_fifo_left += p_info->firmware_info.tx_fifo_size;
+ stp_sdio_txperf_to_send += four_byte_align_len;
+ ++stp_sdio_txperf_fifo_lmt_cnt;
+#endif
+
+ osal_do_gettimeofday(&now);
+ if ((now.tv_sec - old.tv_sec) > TX_NO_ACK_TIMEOUT_ASSERT) {
+ STPSDIO_PR_INFO("tx_fifo_size(%d), four_byte_align_len(%d), tx_packet_num(%d)\n",
+ p_info->firmware_info.tx_fifo_size, four_byte_align_len,
+ p_info->firmware_info.tx_packet_num);
+ STPSDIO_PR_INFO("No ack trigger assert, tx %d seconds later\n",
+ TX_NO_ACK_TIMEOUT_ASSERT);
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ p_info->firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE;
+ p_info->firmware_info.tx_packet_num = 0;
+ if (pb->full_flag != MTK_WCN_BOOL_FALSE) {
+ pb->full_flag = MTK_WCN_BOOL_FALSE;
+ wake_up_interruptible(&pb->fullwait_q);
+ }
+ ret = mtk_wcn_wmt_assert_timeout(WMTDRV_TYPE_STP, 33, 0);
+ if (!ret)
+ STPSDIO_PR_INFO("trigger assert fail\n");
+ }
+ break;
+ }
+
+ stp_sdio_check_tx_sanity(p_info, 2);
+ } while (1);
+}
+
+#else
+static VOID stp_sdio_tx_wkr(struct work_struct *work)
+{
+ MTK_WCN_STP_SDIO_HIF_INFO *p_info;
+ UINT32 bus_txlen;
+ UINT32 four_byte_align_len;
+ PUINT8 buf_tx;
+ INT32 ret;
+ UINT32 idx;
+ MTK_WCN_STP_SDIO_PKT_BUF *pb;
+ struct timeval now;
+ UINT64 ts;
+ ULONG nsec;
+
+ p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, tx_work);
+ ret = HIF_SDIO_ERR_SUCCESS;
+ pb = &p_info->pkt_buf;
+
+ /* 4 <0> Tx worker has been scheduled to send data */
+ do {
+ /* handle tx complete count if any */
+ stp_sdio_tx_wkr_comp(p_info);
+ stp_sdio_check_tx_sanity(p_info, 1);
+
+ /* check if Tx ring buffer is empty */
+ if ((atomic_read(&p_info->pkt_buf.wr_idx) == atomic_read(&p_info->pkt_buf.rd_idx))
+ && (p_info->pkt_buf.full_flag == MTK_WCN_BOOL_FALSE)) {
+ STPSDIO_PR_DBG("Tx ring buffer is empty\n");
+ break;
+ }
+ p_info->txwkr_flag = 0;
+
+ /* George: no race condition here! Updating rd_idx content will not be
+ * put into more data by stp_sdio_tx
+ */
+ /* Get Tx packet size from Tx ring buf */
+#if KMALLOC_UPDATE
+ buf_tx = gp_info->pkt_buf.tx_buf +
+ atomic_read(&p_info->pkt_buf.rd_idx) * STP_SDIO_TX_ENTRY_SIZE + 0;
+#else
+ buf_tx = &p_info->pkt_buf.tx_buf[atomic_read(&p_info->pkt_buf.rd_idx)][0];
+#endif
+ bus_txlen = buf_tx[1];
+ bus_txlen = (bus_txlen << 8) | buf_tx[0];
+
+ /* George: hw always count fifo in 4-byte aligned length */
+ bus_txlen += 0x3;
+ bus_txlen &= ~(0x3UL);
+ four_byte_align_len = bus_txlen;
+ /* Sanity check: 4-byte aligned length shall not exceed HW FIFO Size */
+ if (four_byte_align_len > STP_SDIO_TX_FIFO_SIZE) {
+ STPSDIO_PR_ERR("abnormal four_byte_align_len(%d) > TX_FIFO_SIZE(%ld)!!\n",
+ four_byte_align_len, STP_SDIO_TX_FIFO_SIZE);
+ }
+
+ osal_ftrace_print("%s|S|bus_txlen(%d)\n", __func__, four_byte_align_len);
+ /* George: check if
+ * 1. tx FIFO free space is enough using 4-byte aligned length
+ * 2. tx max pkt count is not reached
+ */
+ if ((p_info->firmware_info.tx_fifo_size >= four_byte_align_len)
+ && (p_info->firmware_info.tx_packet_num < STP_SDIO_TX_PKT_MAX_CNT)) {
+ /* George: refine block_size alignment with the assumption: block_size is 2^*x */
+ if (bus_txlen > STP_SDIO_BLK_SIZE) {
+ bus_txlen += (STP_SDIO_BLK_SIZE - 1);
+ bus_txlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1);
+ }
+
+ /* Sanity check: bus_txlen shall not exceed SW entry size */
+ if (bus_txlen > STP_SDIO_TX_ENTRY_SIZE) {
+ STPSDIO_PR_ERR
+ ("abnormal bus_txlen(%d) > STP_SDIO_TX_ENTRY_SIZE(%ld)!!\n",
+ bus_txlen, STP_SDIO_TX_ENTRY_SIZE);
+ }
+
+ ++(p_info->firmware_info.tx_packet_num);
+ /* decrease Tx FIFO size: using 4-byte aligned length! */
+ p_info->firmware_info.tx_fifo_size -= four_byte_align_len;
+ /* record the SDIO packet size in packet size list: using 4-byte aligned length! */
+ idx = p_info->tx_pkt_list.pkt_wr_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK;
+ p_info->tx_pkt_list.pkt_size_list[idx] = four_byte_align_len;
+ p_info->tx_pkt_list.in_ts[idx] = jiffies;
+ p_info->tx_pkt_list.out_ts[idx] = 0;
+
+ STPSDIO_PR_DBG("wr(0x%x, %ld) rd(0x%x, %ld), tx fifo(size:%d), pkt_num(%d)done\n",
+ p_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt),
+ p_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt),
+ p_info->firmware_info.tx_fifo_size,
+ p_info->firmware_info.tx_packet_num);
+
+ /* port write the packet to CTDR */
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx,
+ CTDR, (PUINT32) buf_tx, bus_txlen);
+ STPSDIO_PR_DBG("write to CTDR done\n");
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ do {
+ osal_get_local_time(&ts, &nsec);
+ idx = stp_sdio_txdbg_cnt++ & STP_SDIO_TXDBG_COUNT_MASK;
+ /* skip clear buf */
+ stp_sdio_txdbg_buffer[idx].ts = jiffies;
+ stp_sdio_txdbg_buffer[idx].l_sec = ts;
+ stp_sdio_txdbg_buffer[idx].l_nsec = nsec;
+ stp_sdio_txdbg_buffer[idx].bus_txlen = bus_txlen;
+ stp_sdio_txdbg_buffer[idx].four_byte_align_len =
+ four_byte_align_len;
+ /* store content */
+ if (bus_txlen <= STP_SDIO_TX_ENTRY_SIZE) {
+ memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx,
+ bus_txlen);
+ } else {
+ memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx,
+ STP_SDIO_TX_ENTRY_SIZE);
+ STPSDIO_PR_ERR("abnormal bus_txlen(%d)!\n", bus_txlen);
+ }
+ } while (0);
+#endif
+
+ if (ret) {
+ STPSDIO_PR_ERR("get CTDR information Tx error(%d)!\n", ret);
+ if (p_info->retry_enable_flag) {
+ if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY)
+ p_info->tx_retry_flag = STP_SDIO_RETRY_CRC_ERROR;
+ else {
+ p_info->tx_retry_count = 0;
+ p_info->tx_retry_flag = STP_SDIO_RETRY_NONE;
+ stp_sdio_issue_fake_coredump
+ ("ABT: write_readsb retry ERROR");
+ }
+ } else
+ stp_sdio_issue_fake_coredump("ABT: write_readsb retry ERROR");
+ }
+
+ /* clear rd index entry of Tx ring buffer */
+ /*memset(buf_tx, 0, STP_SDIO_TX_ENTRY_SIZE); */
+ /* George: clear STP-SDIO header only for debugging. */
+ /*memset(buf_tx, 0, 4); */
+ /* need clear??? skip it for debugging */
+
+ spin_lock_irqsave(&p_info->pkt_buf.rd_idx_lock,
+ p_info->pkt_buf.rd_irq_flag);
+ /* release tx ring buffer */
+ atomic_set(&p_info->pkt_buf.rd_idx,
+ (atomic_read(&p_info->pkt_buf.rd_idx) + 1) % STP_SDIO_TX_BUF_CNT);
+ /* Set Tx ring buffer is not full */
+ if (p_info->pkt_buf.full_flag != MTK_WCN_BOOL_FALSE) {
+ p_info->pkt_buf.full_flag = MTK_WCN_BOOL_FALSE;
+ wake_up_interruptible(&p_info->pkt_buf.fullwait_q);
+ }
+ spin_unlock_irqrestore(&p_info->pkt_buf.rd_idx_lock,
+ p_info->pkt_buf.rd_irq_flag);
+ osal_do_gettimeofday(&old);
+ } else {
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ stp_sdio_txperf_fifo_left += p_info->firmware_info.tx_fifo_size;
+ stp_sdio_txperf_to_send += four_byte_align_len;
+ ++stp_sdio_txperf_fifo_lmt_cnt;
+#endif
+ /* (tx FIFO free space < packet size) or (the number of tx packets >= 7) */
+ osal_do_gettimeofday(&now);
+ if ((now.tv_sec - old.tv_sec) > TX_NO_ACK_TIMEOUT_ASSERT) {
+ STPSDIO_PR_INFO("tx_fifo_size(%d), four_byte_align_len(%d), tx_packet_num(%d)\n",
+ p_info->firmware_info.tx_fifo_size, four_byte_align_len,
+ p_info->firmware_info.tx_packet_num);
+ STPSDIO_PR_INFO("No ack trigger assert, tx %d seconds later\n",
+ TX_NO_ACK_TIMEOUT_ASSERT);
+ stp_dbg_poll_cpupcr(5, 1, 1);
+ osal_ftrace_print("tx_fifo_size:%d, four_byte_align_len:%d, tx_packet_num(%d)\n",
+ p_info->firmware_info.tx_fifo_size, four_byte_align_len,
+ p_info->firmware_info.tx_packet_num);
+ p_info->firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE;
+ p_info->firmware_info.tx_packet_num = 0;
+ if (pb->full_flag != MTK_WCN_BOOL_FALSE) {
+ pb->full_flag = MTK_WCN_BOOL_FALSE;
+ wake_up_interruptible(&pb->fullwait_q);
+ }
+ ret = mtk_wcn_wmt_assert_timeout(WMTDRV_TYPE_STP, 33, 0);
+ if (!ret)
+ STPSDIO_PR_INFO("trigger assert fail\n");
+ }
+ break;
+ }
+
+ stp_sdio_check_tx_sanity(p_info, 2);
+ } while (1);
+
+ osal_ftrace_print("%s|E|\n", __func__);
+}
+#endif /* end of stp_sdio_tx_wkr and STP_SDIO_NEW_TXRING */
+
+/*!
+ * \brief Handle STP-SDIO Rx IRQ BH and read data from bus
+ *
+ * \details Handle STP-SDIO Rx IRQ buttom half and read data from bus according
+ * to the length read in Rx IRQ top half (stp_sdio_irq()) from CHISR
+ *
+ * \note rx_pkt_len read in stp_sdio_irq() from CHISR. No Rx IRQ would be
+ * triggered by FW before all Rx FIFO data is read by host driver. Do
+ * sanity check for this condition.
+ *
+ * \note HW Rx FIFO size is (2304 = 256*9) for MT6620
+ *
+ * \param[IN] work Rx work struct work_struct pointer used by STP-SDIO
+ *
+ * \retval none.
+ */
+static VOID stp_sdio_rx_wkr(struct work_struct *work)
+{
+ PUINT8 bufp;
+ UINT32 bus_rxlen;
+ UINT32 chisr_rxlen;
+ INT32 ret;
+ INT32 ret_1;
+ UINT8 cccr_value = 0;
+ MTK_WCN_STP_SDIO_HIF_INFO *p_info;
+
+ p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, rx_work);
+
+ /* 4 <0> receive data from CRDR */
+ /* George: refine 4-byte alignment */
+ chisr_rxlen = p_info->rx_pkt_len;
+
+
+ if (chisr_rxlen > STP_SDIO_RX_FIFO_SIZE) {
+ /* TODO: error handling! */
+ STPSDIO_PR_ERR("abnormal chisr_rxlen(%d) rx_worker stop\n", chisr_rxlen);
+ return;
+ }
+
+ bus_rxlen = chisr_rxlen;
+ bus_rxlen += 0x3;
+ bus_rxlen &= ~(0x3UL);
+
+ /* George: refine block_size alignment with the assumption: BLK_SIZE is 2^x. */
+ if (bus_rxlen > STP_SDIO_BLK_SIZE) {
+ bus_rxlen += (STP_SDIO_BLK_SIZE - 1);
+ bus_rxlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1);
+ }
+
+ ret = stp_sdio_rw_retry(HIF_TYPE_READ_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CRDR,
+ (PUINT32)(&(p_info->pkt_buf.rx_buf[0])), bus_rxlen);
+ if (p_info->retry_enable_flag) {
+ if (ret) {
+ if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) {
+ cccr_value = 0;
+ ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_ERR("read CCCR_F0: (0x%x)\n", cccr_value);
+ cccr_value |= CCCR_F0_RX_CRC;
+ cccr_value |= CCCR_F0_RX_INT;
+ ret_1 = mtk_wcn_hif_sdio_f0_writeb(p_info->sdio_cltctx, CCCR_F0, cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("write CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_ERR("write CCCR_F0: (0x%x)\n", cccr_value);
+ cccr_value = 0;
+ ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_ERR("read CCCR_F0: (0x%x)\n", cccr_value);
+ STPSDIO_PR_ERR("sdio read buffer happen crc error will be retry(%d)\n", ret);
+ p_info->rx_retry_count++;
+ if (p_info->rx_retry_count > STP_SDIO_RETRY_LIMIT) {
+ p_info->rx_retry_count = 0;
+ stp_sdio_issue_fake_coredump("ABT: sdio_readsb retry ERROR");
+ }
+ } else {
+ p_info->rx_retry_count = 0;
+ stp_sdio_issue_fake_coredump("ABT: sdio_readsb retry ERROR");
+ }
+ } else {
+ cccr_value = 0;
+ ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_DBG("read CCCR_F0: (0x%x)\n", cccr_value);
+ cccr_value &= ~CCCR_F0_RX_CRC;
+ cccr_value |= CCCR_F0_RX_INT;
+ ret_1 = mtk_wcn_hif_sdio_f0_writeb(p_info->sdio_cltctx, CCCR_F0, cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("write CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_DBG("write CCCR_F0: (0x%x)\n", cccr_value);
+ cccr_value = 0;
+ ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value);
+ if (ret_1)
+ STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1);
+ STPSDIO_PR_DBG("read CCCR_F0: (0x%x)\n", cccr_value);
+ STPSDIO_PR_DBG("sdio read buffer success(%d)\n", ret);
+
+ p_info->rx_retry_count = 0;
+ }
+ } else {
+ if (ret) {
+ STPSDIO_PR_HINT("set to p_info->rx_pkt_len 0\n");
+ stp_sdio_issue_fake_coredump("ABT: sdio_readsb retry ERROR");
+ }
+ }
+ if (ret) {
+ /* TODO: error handling! */
+ STPSDIO_PR_ERR("read CRDR len(%d) rx error!(%d)\n", bus_rxlen, ret);
+ p_info->rx_pkt_len = 0;
+ return;
+ }
+ p_info->rx_pkt_len = 0;
+ STPSDIO_PR_HINT("set to p_info->rx_pkt_len 0\n");
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+ do {
+ UINT32 idx = stp_sdio_rxdbg_cnt++ & (STP_SDIO_RXDBG_COUNT - 1);
+ /* skip clear buf */
+ stp_sdio_rxdbg_buffer[idx].ts = jiffies;
+ stp_sdio_rxdbg_buffer[idx].chisr_rxlen = chisr_rxlen;
+ stp_sdio_rxdbg_buffer[idx].bus_rxlen = bus_rxlen;
+ /* store content */
+ memcpy(&stp_sdio_rxdbg_buffer[idx].rx_pkt_buf[0], &p_info->pkt_buf.rx_buf[0],
+ bus_rxlen);
+ } while (0);
+#endif
+
+ bufp = &p_info->pkt_buf.rx_buf[4];
+
+ /* Notice: len = SDIO_HDR(4) + (STP Packet + padding)*N */
+ /* George: refine sanity check */
+ bus_rxlen = p_info->pkt_buf.rx_buf[1];
+ bus_rxlen = (bus_rxlen << 8) | p_info->pkt_buf.rx_buf[0];
+ STPSDIO_PR_DBG("bus_rxlen(%d) rx_len in chisr(%d)\n", bus_rxlen, chisr_rxlen);
+ if (bus_rxlen != chisr_rxlen) {
+ STPSDIO_PR_ERR("abnormal bus_rxlen(%d) in SDIO packet header!in chisr(%d)\n",
+ bus_rxlen, chisr_rxlen);
+ return;
+ }
+ if (p_info->pkt_buf.rx_buf[2] || p_info->pkt_buf.rx_buf[3]) {
+ STPSDIO_PR_ERR("abnormal p_info->pkt_buf.rx_buf[2](0x%02x) [3](0x%02x)\n",
+ p_info->pkt_buf.rx_buf[2], p_info->pkt_buf.rx_buf[3]);
+ return;
+ }
+
+ if (bus_rxlen > STP_SDIO_HDR_SIZE) {
+ bus_rxlen -= STP_SDIO_HDR_SIZE;
+ /* transmit data to stp core driver */
+ osal_ftrace_print("%s|B|parser|L|%d\n", __func__, bus_rxlen);
+ ret = mtk_wcn_stp_parser_data(bufp, bus_rxlen);
+ osal_ftrace_print("%s|A|parser|L|%d\n", __func__, bus_rxlen);
+#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG)
+ if (ret && (p_info->tx_dbg_dump_flag == 0)) {
+ p_info->tx_dbg_dump_flag = 1;
+ stp_sdio_txdbg_dump();
+ }
+#endif
+ } else {
+ STPSDIO_PR_ERR("abnormal rx length(%d, %d)\n", bus_rxlen, chisr_rxlen);
+ }
+
+ /* [George]: no need to mask/unmask rx interrupt. chip/fw assert next rx int
+ * if and only if host reads all rx data.
+ */
+}
+
+#if STP_SDIO_NEW_IRQ_HANDLER
+static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx)
+{
+ INT32 iRet = 0;
+ UINT32 chlcpr_value = 0;
+ UINT32 write_value = 0;
+ MTK_WCN_STP_SDIO_HIF_INFO *p_info = gp_info;
+
+ STPSDIO_PR_HINT("disable IRQ\n");
+ /*Disable Common interrupt output in CHLPCR */
+/* [COHEC_00006052] SW work-around solution:
+ * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR
+ */
+#if COHEC_00006052
+ write_value = C_FW_INT_EN_CLR;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#else
+ write_value = C_FW_INT_EN_CLR;
+ iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#endif /* COHEC_00006052 */
+ if (iRet)
+ STPSDIO_PR_ERR("disalbe IRQ fail\n");
+ else {
+ iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &chlcpr_value, 0);
+ if (iRet)
+ STPSDIO_PR_ERR("read CHLPCR fail. iRet(%d)\n", iRet);
+ else {
+ if (!(chlcpr_value & C_FW_INT_EN_SET)) {
+ STPSDIO_PR_DBG("disable COM IRQ okay (0x%x)\n", chlcpr_value);
+ p_info->irq_pending = 1;
+
+ /*inform stp_sdio thread to to rx/tx job */
+ STPSDIO_PR_DBG("signal stp_tx_rx\n");
+ osal_trigger_event(&gp_info->tx_rx_event);
+ osal_ftrace_print("%s|stp_tx_rx\n", __func__);
+ } else
+ STPSDIO_PR_ERR
+ ("**********disable COM IRQ fail, don't signal stp-sdio thread******\n");
+ }
+
+ }
+ return 0;
+
+}
+
+#else
+/*!
+ * \brief Handle STP-SDIO interrupt
+ *
+ * \details Top half interrupt handler of STP-SDIO. Most of Tx/Rx jobs are put
+ * to bottom half workers respectively.
+ *
+ * \note Rx ok interrupt shall be asserted by hw ONLY after last data are all
+ * read by driver. Do sanity check on rx_pkt_len and should be 0: rx BH
+ * finished.
+ *
+ * \note Tx complete count shall be handled atomically TH here and BH in
+ * tx_worker.
+ *
+ * \param[IN] clt_ctx A HIF-SDIO client context
+ *
+ * \retval 0 success
+ * \retval !=0 fail
+ */
+static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx)
+{
+ /*MTK_WCN_STP_SDIO_PRIVATE_INFO *p_priv; */
+ MTK_WCN_STP_SDIO_HIF_INFO *p_info = NULL;
+ UINT32 chisr = 0;
+ UINT32 tx_comp;
+ INT32 ret;
+
+#if 0
+ p_priv = mtk_wcn_hif_sdio_get_drvdata(clt_ctx);
+TODO:[FixMe][George] do sanity check !
+ p_info = &g_stp_sdio_host_info[p_priv->stp_sdio_host_idx];
+#endif
+ p_info = gp_info;
+ ret = HIF_SDIO_ERR_SUCCESS;
+ /* 4 <0> get CHLPCR information */
+ if (stp_sdio_get_own_state() == OWN_CLR)
+ STPSDIO_PR_DBG("OWN on driver side!\n");
+ else {
+ STPSDIO_PR_DBG("OWN on fw side!\n");
+ if (stp_sdio_do_own_clr(0) == 0)
+ STPSDIO_PR_DBG("set OWN to driver side ok!\n");
+ else {
+ STPSDIO_PR_ERR("set OWN to driver side error!\n");
+ return -1;
+ }
+
+ }
+retry:
+ /* 4 <1> get CHISR information */
+ ret = mtk_wcn_hif_sdio_readl(clt_ctx, CHISR, &chisr);
+ if (ret) {
+ /* 4 <1.1> get CHISR Rx error handling */
+ /* TODO: error handling! */
+ STPSDIO_PR_ERR("get CHISR information rx error,ret:%d\n", ret);
+ if (ret == -5) {
+ STPSDIO_PR_ERR("get CHISR DAT CRC error, retry.\n");
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_MAX_RETRY_NUM, clt_ctx, CSR, &chisr,
+ 0);
+ } else
+ goto retry;
+ }
+ STPSDIO_PR_HINT("CHISR(0x%08x)\n", chisr);
+ if (chisr == 0x0) {
+ STPSDIO_PR_ERR("******CHISR == 0*****\n");
+ return 0;
+ }
+ /* 4 <2> handle ownership back interrupt */
+ if (chisr & FW_OWN_BACK_INT) {
+ STPSDIO_PR_INFO("FW_OWN_BACK_INT\n");
+
+ if (is_wait_ownback) {
+ is_wait_ownback = 0;
+ wake_up(&g_ownback_done);
+ } else {
+ mtk_wcn_stp_wmt_sdio_host_awake();
+ /* if (cmb_bgf_eirq_cb) { */
+ /* (*cmb_bgf_eirq_cb)(); */
+ /* } */
+ }
+ }
+ /* 4 <3> handle Rx interrupt */
+ if (chisr & RX_DONE) {
+ /* STPSDIO_PR_INFO("RX_DONE_INT\n"); */
+
+ /* TODO: [FixMe][George] testing... */
+ if (p_info->rx_pkt_len)
+ STPSDIO_PR_ERR("rx worker is not finished yet!!!(%d)\n",
+ p_info->rx_pkt_len);
+
+ /* get Rx packet length */
+ p_info->rx_pkt_len = (chisr & RX_PKT_LEN) >> 16;
+ STPSDIO_PR_HINT("rx_pkt_len(%d)\n", p_info->rx_pkt_len);
+ /* sanity check */
+ if ((p_info->rx_pkt_len == 0)
+ || (p_info->rx_pkt_len > STP_SDIO_RX_FIFO_SIZE)) {
+ STPSDIO_PR_ERR
+ ("abnormal rx_pkt_len(%d) in CHISR(0x%08x) skip rx_worker\n",
+ p_info->rx_pkt_len, chisr);
+ p_info->rx_pkt_len = 0;
+ } else {
+ /* Before host driver read all rx data, chip/fw will not send more data
+ * to host. No need to mask rx interrupt. schedule rx worker to get data
+ * back and handle it.
+ */
+ if (p_info->rx_pkt_len & 0x3) {
+ STPSDIO_PR_WARN
+ ("rx data len is not 4 bytes allignment, CHISR(0x%08x), rx len (%d).\n",
+ chisr, p_info->rx_pkt_len);
+ }
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_schedule(&p_info->tx_rx_job); */
+ STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n");
+ osal_trigger_event(&gp_info->tx_rx_event);
+#else
+ schedule_work(&p_info->rx_work);
+#endif
+ }
+ }
+ /* 4 <4> handle Tx interrupt */
+ if ((chisr & TX_EMPTY) || (chisr & TX_UNDER_THOLD)) {
+ STPSDIO_PR_DBG("Tx interrupt\n");
+ /* get complete count */
+ tx_comp = (chisr & TX_COMPLETE_COUNT) >> 4;
+#if 0
+ atomic_add(tx_comp, &p_info->firmware_info.tx_comp_num);
+ /* TODO:[FixMe][George]: debug and to be removed... */
+ tx_comp = atomic_read(&p_info->firmware_info.tx_comp_num);
+#else
+ tx_comp = atomic_add_return(tx_comp, &p_info->firmware_info.tx_comp_num);
+#endif
+ if (tx_comp > STP_SDIO_TX_PKT_MAX_CNT) {
+ STPSDIO_PR_ERR("Abnormal accumulated comp count(%d) chisr(0x%x)\n",
+ tx_comp, chisr);
+ }
+
+ /* move most of tx jobs to tx_worker */
+ /* schedule tx worker for tx complete count and following tx data */
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_schedule(&p_info->tx_rx_job); */
+ STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n");
+ osal_trigger_event(&gp_info->tx_rx_event);
+#else
+ schedule_work(&p_info->tx_work);
+#endif
+ }
+
+ return ret;
+}
+#endif /* STP_SDIO_NEW_IRQ_HANDLER */
+
+#if STP_SDIO_POLL_OWNBACK_INTR
+/*****************************************************************************
+ * FUNCTION
+ * stp_sdio_ownback_poll
+ * DESCRIPTION
+ * Poll ownback interrupt
+ * PARAMETERS
+ * 1. *func [IN] sdio driver function pointer
+ * 2. retryp [IN] polling retry times
+ * 3. delay_us [IN] polling delay (unit: us)
+ * RETURNS
+ * ret: Probe result
+ *****************************************************************************/
+static INT32 stp_sdio_ownback_poll(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 retry, UINT32 delay_us)
+{
+ INT32 ret;
+ UINT32 chlpcr = 0;
+
+ do {
+#if 0
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHISR, &chisr_value,
+ 0);
+#endif
+ /* 20111020: change to poll CHLPCR instead of read-cleared CHISR */
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlpcr, 0);
+ if (ret) {
+ /* 4 <1.1> get CHISR Rx error handling */
+ STPSDIO_PR_ERR("get CHLPCR information rx error!(%d)\n", ret);
+ return ret;
+ }
+
+ /*if (chisr_value & FW_OWN_BACK_INT) { */
+ if (chlpcr & C_FW_COM_DRV_OWN) {
+ /* 4 <2> handle ownership back interrupt */
+ STPSDIO_PR_DBG("Driver own is polled!(%d)\n", retry);
+ gp_info->awake_flag = 1;
+ break;
+ }
+ osal_usleep_range(delay_us, delay_us);
+ } while (retry-- > 0);
+
+ /*return (chisr_value & FW_OWN_BACK_INT) ? 0 : -HIF_SDIO_ERR_FAIL; */
+ return (chlpcr & C_FW_COM_DRV_OWN) ? 0 : -HIF_SDIO_ERR_FAIL;
+}
+#endif /* STP_SDIO_POLL_OWNBACK_INTR */
+
+/*****************************************************************************
+ * FUNCTION
+ * stp_sdio_probe
+ * DESCRIPTION
+ * Probe function of SDIO driver
+ * PARAMETERS
+ * 1. *func [IN] sdio driver function pointer
+ * 2. *id [IN] sdio function id
+ * RETURNS
+ * ret: Probe result
+ *****************************************************************************/
+/* typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX, const MTK_WCN_HIF_SDIO_FUNCINFO *); */
+static INT32 stp_sdio_probe(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx,
+ const MTK_WCN_HIF_SDIO_FUNCINFO *sdio_func_infop)
+{
+ INT32 ret = HIF_SDIO_ERR_SUCCESS;
+ UINT32 i = 0, chlcpr_value = 0;
+ UINT32 write_value = 0;
+
+ STPSDIO_PR_DBG("sdio_cltctx: 0x%08x\n", clt_ctx);
+
+ if (g_stp_sdio_host_count) {
+ STPSDIO_PR_ERR("g_stp_sdio_host_count(%d) probed already!\n",
+ g_stp_sdio_host_count);
+ return -1;
+ }
+ /* 4 <1> check if input pointer is valid */
+ if (g_stp_sdio_host_info.sdio_cltctx == clt_ctx) {
+ STPSDIO_PR_WARN("sdio_cltctx(%d) already probed!\n", clt_ctx);
+ return 0;
+ }
+ /* 4 <2> allocate host inform structure and initialize private variables */
+ /* init host info private variables */
+ g_stp_sdio_host_info.sdio_cltctx = clt_ctx;
+
+ /* init Tx packet ring buffer */
+ for (i = 0; i < STP_SDIO_TX_BUF_CNT; ++i) {
+#if KMALLOC_UPDATE
+ UINT8 *pData = g_stp_sdio_host_info.pkt_buf.tx_buf + i * STP_SDIO_TX_ENTRY_SIZE + 0;
+
+ memset(pData, 0, STP_SDIO_TX_ENTRY_SIZE);
+#else
+ memset(&g_stp_sdio_host_info.pkt_buf.tx_buf[i][0], 0,
+ sizeof(g_stp_sdio_host_info.pkt_buf.tx_buf[i]));
+#endif
+ }
+ osal_sleepable_lock_init(&fake_coredump_lock);
+
+#if STP_SDIO_NEW_TXRING
+ spin_lock_init(&g_stp_sdio_host_info.pkt_buf.rd_cnt_lock);
+ atomic_set(&g_stp_sdio_host_info.pkt_buf.wr_cnt, 0);
+ atomic_set(&g_stp_sdio_host_info.pkt_buf.rd_cnt, 0);
+#else
+ /*g_stp_sdio_host_info.pkt_buf.rd_idx_lock = SPIN_LOCK_UNLOCKED; */
+ spin_lock_init(&g_stp_sdio_host_info.pkt_buf.rd_idx_lock);
+ atomic_set(&g_stp_sdio_host_info.pkt_buf.wr_idx, 0);
+ atomic_set(&g_stp_sdio_host_info.pkt_buf.rd_idx, 0);
+#endif
+ g_stp_sdio_host_info.pkt_buf.full_flag = MTK_WCN_BOOL_FALSE;
+
+ /* init wait queue head for Tx ring buf full */
+ init_waitqueue_head(&g_stp_sdio_host_info.pkt_buf.fullwait_q);
+
+ /* init Tx packet size list information */
+ memset(&g_stp_sdio_host_info.tx_pkt_list.pkt_size_list[0], 0,
+ sizeof(g_stp_sdio_host_info.tx_pkt_list.pkt_size_list));
+ g_stp_sdio_host_info.tx_pkt_list.pkt_rd_cnt = 0;
+ g_stp_sdio_host_info.tx_pkt_list.pkt_wr_cnt = 0;
+
+ /* init Rx interrupt mask */
+ /* g_stp_sdio_host_info.rx_intr_mask = MTK_WCN_BOOL_FALSE; */
+
+ /* init firmware related information */
+ g_stp_sdio_host_info.firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE;
+ g_stp_sdio_host_info.firmware_info.tx_packet_num = 0;
+ atomic_set(&g_stp_sdio_host_info.firmware_info.tx_comp_num, 0);
+
+ /* init SDIO data path retry flag */
+ g_stp_sdio_host_info.retry_enable_flag = 0;
+ g_stp_sdio_host_info.tx_retry_flag = STP_SDIO_RETRY_NONE;
+
+ g_stp_sdio_host_info.isr_check_complete.timeoutValue = 1000;
+ osal_signal_init(&g_stp_sdio_host_info.isr_check_complete);
+
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_init(&g_stp_sdio_host_info.tx_rx_job, stp_sdio_tx_rx_handling, */
+ /* (unsigned long) &g_stp_sdio_host_info); */
+ /* Create stp_sdio_tx_rx_thread, in suspend state */
+ g_stp_sdio_host_info.irq_pending = 0;
+ g_stp_sdio_host_info.sleep_flag = 0;
+ g_stp_sdio_host_info.wakeup_flag = 0;
+ osal_event_init(&g_stp_sdio_host_info.tx_rx_event);
+ g_stp_sdio_host_info.tx_rx_thread.pThreadFunc = stp_sdio_tx_rx_handling;
+ g_stp_sdio_host_info.tx_rx_thread.pThreadData = (PVOID) &g_stp_sdio_host_info;
+ g_stp_sdio_host_info.tx_dbg_dump_flag = 0;
+ osal_strncpy((PINT8)&g_stp_sdio_host_info.tx_rx_thread.threadName,
+ "stp_sdio_tx_rx", osal_sizeof(g_stp_sdio_host_info.tx_rx_thread.threadName));
+ ret = osal_thread_create(&g_stp_sdio_host_info.tx_rx_thread);
+ if (ret < 0) {
+ STPSDIO_PR_ERR("osal_thread_create fail...: %p\n",
+ g_stp_sdio_host_info.tx_rx_thread.pThread);
+ return ret;
+ }
+#else
+ /* init tx_tasklet and rx work_queue */
+ INIT_WORK(&g_stp_sdio_host_info.tx_work, stp_sdio_tx_wkr);
+ INIT_WORK(&g_stp_sdio_host_info.rx_work, stp_sdio_rx_wkr);
+#endif
+ /* init stp sdio host private information *//* TODO: [FixMe][George] Still need this? */
+ g_stp_sdio_host_info.private_info.stp_sdio_host_idx = g_stp_sdio_host_count;
+ mtk_wcn_hif_sdio_set_drvdata(clt_ctx, &g_stp_sdio_host_info.private_info);
+
+ ++g_stp_sdio_host_count;
+
+ /* 4 <3> request firmware-own back */
+/* [COHEC_00006052] SW work-around solution: */
+/* using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR */
+#if COHEC_00006052
+ write_value = (C_FW_OWN_REQ_CLR >> 8);
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, (UINT32)(CHLPCR + 0x1),
+ &write_value, 0);
+#else
+ write_value = C_FW_OWN_REQ_CLR;
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR,
+ &write_value, 0);
+#endif /* COHEC_00006052 */
+ if (ret) {
+ STPSDIO_PR_ERR("request FW-Own back fail!(%d)\n", ret);
+ goto out;
+ }
+ STPSDIO_PR_DBG("request FW-Own back done\n");
+
+#if STP_SDIO_POLL_OWNBACK_INTR
+ /* 4 <3.1> polling own back bit */
+ ret = stp_sdio_ownback_poll(clt_ctx, 10, 100);
+ if (ret) {
+ STPSDIO_PR_ERR("poll FW-Own back fail!(%d)\n", ret);
+ goto out;
+ }
+#endif
+ /* 4 <4.0> enable irq flag in HIF-SDIO */
+ mtk_wcn_hif_sdio_enable_irq(clt_ctx, MTK_WCN_BOOL_TRUE);
+ /* 4 <4> enabling all host interrupt except abnormal ones */
+ /*write_value = (CHISR_EN_15_7 | CHISR_EN_3_0);*/ /* enable CHISR interrupt output */
+ /*ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER, &write_value, 0);*/
+ write_value = (FIRMWARE_INT | TX_FIFO_OVERFLOW | FW_INT_IND_INDICATOR | TX_COMPLETE_COUNT
+ | TX_UNDER_THOLD | TX_EMPTY | RX_DONE);
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER,
+ &write_value, 0);
+ if (ret) {
+ STPSDIO_PR_ERR("set interrupt output fail!(%d)\n", ret);
+ goto out;
+ }
+ STPSDIO_PR_DBG("set interrupt output done\n");
+/* [COHEC_00006052] SW work-around solution: */
+/* using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR */
+#if COHEC_00006052
+ write_value = C_FW_INT_EN_SET;
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &write_value,
+ 0); /* enable interrupt */
+#else
+ write_value = C_FW_INT_EN_SET;
+ ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &write_value,
+ 0); /* enable interrupt */
+#endif /* COHEC_00006052 */
+ if (ret) {
+ STPSDIO_PR_ERR("enable interrupt fail!(%d)\n", ret);
+ goto out;
+ }
+ ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlcpr_value,
+ 0);
+ if (ret) {
+ STPSDIO_PR_ERR("Read CHLPCR fail!(%d)\n", ret);
+ goto out;
+ } else {
+ if (chlcpr_value & C_FW_INT_EN_SET)
+ STPSDIO_PR_DBG("enable interrupt okay (0x%x)\n", chlcpr_value);
+ }
+
+ STPSDIO_PR_DBG("enable interrupt done\n");
+
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE);
+#endif
+
+#if STP_SDIO_OWN_THREAD
+ ret = osal_thread_run(&g_stp_sdio_host_info.tx_rx_thread);
+ if (ret < 0) {
+ STPSDIO_PR_ERR("osal_thread_run fail...\n");
+ goto out;
+ }
+#endif
+
+ /* 4 <5> register mtk_wcn_stp_if_tx() to stp driver */
+ mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, (MTK_WCN_STP_IF_TX) stp_sdio_tx);
+
+#if 0 /* controlled by 6620_launcher & WMT */
+ /*set STP sdio mode */
+ pr_warn(DFT_TAG "%s: set stp sdio mode\n", __func__);
+ mtk_wcn_stp_set_sdio_mode(1);
+
+ /*indicate the stp the sdio ready */
+ pr_warn(DFT_TAG "%s: stp enable\n", __func__);
+ mtk_wcn_stp_enable(1);
+#endif
+
+out:
+ /* 4 <6> error handling */
+ /* TODO: error handling */
+ if (ret) {
+#if STP_SDIO_OWN_THREAD
+ osal_thread_destroy(&g_stp_sdio_host_info.tx_rx_thread);
+#endif
+ if (g_stp_sdio_host_count > 0)
+ --g_stp_sdio_host_count;
+ }
+
+ return ret;
+}
+
+/*****************************************************************************
+ * FUNCTION
+ * stp_sdio_probe
+ * DESCRIPTION
+ * SDIO hardware remove function.
+ * PARAMETERS
+ * *func [IN] SDIO driver handler pointer.
+ * RETURNS
+ * none.
+ *****************************************************************************/
+static INT32 stp_sdio_remove(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx)
+{
+#if 0
+ MTK_WCN_STP_SDIO_PRIVATE_INFO *p_priv;
+
+ p_priv = mtk_wcn_hif_sdio_get_drvdata(clt_ctx);
+#endif
+
+ if (g_stp_sdio_host_info.sdio_cltctx == clt_ctx)
+ STPSDIO_PR_DBG("sdio_cltctx(%d) found\n", clt_ctx);
+ else {
+ STPSDIO_PR_ERR("sdio_cltctx(%d) not found\n", clt_ctx);
+ return -1;
+ }
+ osal_sleepable_lock_deinit(&fake_coredump_lock);
+ if (g_stp_sdio_host_count > 0)
+ --g_stp_sdio_host_count;
+ /* 4 <0> disable irq flag in HIF-SDIO */
+ mtk_wcn_hif_sdio_enable_irq(clt_ctx, MTK_WCN_BOOL_FALSE);
+ /* 4 <1> unregister if_tx() function */
+ mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, NULL);
+
+ /* <2> stop Tx tasklet/Rx work queue of the host */
+#if STP_SDIO_OWN_THREAD
+ /* tasklet_kill(&g_stp_sdio_host_info.tx_rx_job); */
+ /* STPSDIO_PR_INFO("kill tasklet finished\n"); */
+ osal_thread_destroy(&g_stp_sdio_host_info.tx_rx_thread);
+ osal_event_deinit(&g_stp_sdio_host_info.tx_rx_event);
+ osal_signal_deinit(&g_stp_sdio_host_info.isr_check_complete);
+ STPSDIO_PR_DBG("destroy STP-SDIO tx_rx_thread\n");
+#else
+ flush_scheduled_work();
+ STPSDIO_PR_INFO("flush scheduled work end\n");
+#endif
+
+ /* 4 <3> return ownership to firmware of the host */
+ /* TODO: check set which register ! */
+
+ /* 4 <4> clear the host struct list */
+ stp_sdio_host_info_op(1);
+
+
+ STPSDIO_PR_DBG("clear g_stp_sdio_host_info[p_priv->stp_sdio_host_idx] done\n");
+
+ return 0;
+}
+
+INT32 stp_sdio_rw_retry(ENUM_STP_SDIO_HIF_TYPE_T type, UINT32 retry_limit,
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 offset, PUINT32 pData, UINT32 len)
+{
+ INT32 ret = -1;
+ INT32 ret_1 = -1;
+ UINT32 value = 0;
+ INT32 retry_flag = 0;
+
+ UINT32 card_id = CLTCTX_CID(clt_ctx);
+
+ if (card_id != 0x6630 && card_id != 0x6632) {
+ STPSDIO_PR_LOUD("card_id is :0x%x, does not support CSR (Common Snapshot Register)\n",
+ card_id);
+ retry_limit = 1;
+ }
+ STPSDIO_PR_LOUD("clt_ctx:0x%x, offset:0x%x, retry_limit:%d\n", clt_ctx, offset, retry_limit);
+
+ retry_limit = retry_limit == 0 ? 1 : retry_limit;
+ retry_limit = retry_limit > STP_SDIO_MAX_RETRY_NUM ? STP_SDIO_MAX_RETRY_NUM : retry_limit;
+
+ while (retry_limit > 0) {
+ switch (type) {
+ case HIF_TYPE_READB:
+ if (retry_flag)
+ ret = mtk_wcn_hif_sdio_readb(clt_ctx, CSR, (PUINT8)pData);
+ else
+ ret = mtk_wcn_hif_sdio_readb(clt_ctx, offset, (PUINT8)pData);
+ break;
+ case HIF_TYPE_READL:
+ if (retry_flag)
+ ret = mtk_wcn_hif_sdio_readl(clt_ctx, CSR, pData);
+ else
+ ret = mtk_wcn_hif_sdio_readl(clt_ctx, offset, pData);
+ break;
+ case HIF_TYPE_READ_BUF:
+ ret = mtk_wcn_hif_sdio_read_buf(clt_ctx, offset, pData, len);
+ break;
+ case HIF_TYPE_WRITEB:
+ ret = mtk_wcn_hif_sdio_writeb(clt_ctx, offset, (UINT8)(*pData));
+ break;
+ case HIF_TYPE_WRITEL:
+ ret = mtk_wcn_hif_sdio_writel(clt_ctx, offset, *pData);
+ break;
+ case HIF_TYPE_WRITE_BUF:
+ ret = mtk_wcn_hif_sdio_write_buf(clt_ctx, offset, pData, len);
+ break;
+ default:
+ STPSDIO_PR_ERR("unknown hif sdio type!\n");
+ goto exit;
+ }
+
+ if (ret) {
+ STPSDIO_PR_ERR("sdio read or write failed, ret:%d\n", ret);
+ if (ret == -ETIMEDOUT) {
+ ret_1 = mtk_wcn_hif_sdio_readl(clt_ctx, CCIR, &value);
+ STPSDIO_PR_ERR("sdio read or write timeout, ret:%d ret_1:%d, read chip id:%x\n",
+ ret, ret_1, value);
+ stp_sdio_dump_register();
+ }
+ /* sdio CRC error read CSR */
+ if (type == HIF_TYPE_READ_BUF || type == HIF_TYPE_WRITE_BUF) {
+ if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) {
+ ret_1 = mtk_wcn_hif_sdio_abort(clt_ctx);
+ if (ret_1)
+ STPSDIO_PR_ERR("sdio crc error send abort fail, ret_1:%d\n",
+ ret_1);
+ else
+ STPSDIO_PR_ERR("sdio crc error send abort success, ret_1:%d\n",
+ ret_1);
+ goto exit;
+ }
+ } else
+ retry_flag = 1;
+ } else {
+ STPSDIO_PR_LOUD("CR:0x:%x value:0x%x\n", offset, *pData);
+ break;
+ }
+ retry_limit--;
+ }
+
+exit:
+ return ret;
+}
+
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+
+/*!
+ * \brief /proc debug read interface and dump rx dbg information
+ *
+ * \details Dump all rx debug information to console.
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_rxdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ UINT32 idx;
+ UINT32 i;
+ UINT32 j;
+ PUINT8 pbuf;
+ UINT32 len;
+
+ if (*f_pos > 0)
+ return 0;
+
+ for (i = 0; i < STP_SDIO_RXDBG_COUNT; ++i) {
+ idx = (stp_sdio_rxdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK;
+ len = stp_sdio_rxdbg_buffer[idx].bus_rxlen;
+ if (len == 0) {
+ pr_warn(DFT_TAG "idx(0x%x) 0 == len dump skip\n",
+ stp_sdio_rxdbg_cnt);
+ }
+ pr_warn(DFT_TAG "idx(0x%x) chisr_rxlen(%d) bus_rxlen(%d) ts(%d)\n",
+ stp_sdio_rxdbg_cnt, stp_sdio_rxdbg_buffer[idx].chisr_rxlen, len,
+ stp_sdio_rxdbg_buffer[idx].ts);
+ for (j = 0; j < STP_SDIO_RX_BUF_SIZE && j < len; j += 16) {
+ pbuf = &stp_sdio_rxdbg_buffer[idx].rx_pkt_buf[j];
+ pr_warn(DFT_TAG "[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
+ pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6],
+ pbuf[7]);
+ pr_warn(DFT_TAG "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13],
+ pbuf[14], pbuf[15]);
+ msleep(20);
+ }
+ pr_warn(DFT_TAG "dump ok\n");
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief /proc debug write interface. do nothing.
+ *
+ * \details
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_rxdbg_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ ULONG len = count;
+
+ pr_warn(DFT_TAG "write parameter len = %lu\n\r", len);
+
+ return len;
+}
+
+/*!
+ * \brief /proc initial procedures. Initialize global debugging information.
+ *
+ * \details Setup entry for /proc debugging for rx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_rxdbg_setup(VOID)
+{
+ stp_sdio_rxdbg_cnt = 0;
+
+ gStpSdioRxDbgEntry = proc_create(STP_SDIO_RXDBG_PROCNAME, 0644, NULL, &stp_sdio_rxdbg_fops);
+ if (gStpSdioRxDbgEntry == NULL) {
+ pr_warn(DFT_TAG "Unable to create /proc entry\n\r");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief /proc de-init procedures.
+ *
+ * \details remove entry for /proc debugging for rx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_rxdbg_remove(VOID)
+{
+ if (gStpSdioRxDbgEntry != NULL)
+ proc_remove(gStpSdioRxDbgEntry);
+
+ return 0;
+}
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG)
+
+static VOID stp_sdio_txperf_dump(VOID)
+{
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG
+ UINT32 cnt;
+ UINT32 fifo;
+ UINT32 data;
+ UINT32 wkr;
+ UINT32 pkt_num;
+ UINT32 lmt_cnt;
+
+ /* get debug counter snapshot */
+ cnt = stp_sdio_txperf_fifo_lmt_cnt;
+ fifo = stp_sdio_txperf_fifo_left;
+ data = stp_sdio_txperf_to_send;
+
+ wkr = stp_sdio_txperf_worker_cnt;
+ pkt_num = stp_sdio_txperf_txed_pkt_num;
+ lmt_cnt = stp_sdio_txperf_pkt_num_lmt_cnt;
+
+ pr_warn(DFT_TAG "txwait_fifo_left(%d), txwait_to_send(%d), txwait_count(%d)\n",
+ fifo, data, cnt);
+ if (cnt)
+ pr_warn(DFT_TAG "avg left(%d), to_send(%d)\n", (fifo / cnt), (data / cnt));
+ pr_warn(DFT_TAG "tx_worker_cnt(%d), pkt_num(%d), pkt_num_lmt_cnt(%d)\n",
+ wkr, pkt_num, lmt_cnt);
+
+#endif
+}
+
+VOID stp_sdio_dump_info(MTK_WCN_STP_SDIO_HIF_INFO *p_info)
+{
+ STPSDIO_PR_INFO("stp_is_ready(%d) irq_pending(%d) tx_packet_num(%d) rx_pkt_len(%d)\n",
+ mtk_wcn_stp_is_ready(), p_info->irq_pending,
+ p_info->firmware_info.tx_packet_num, p_info->rx_pkt_len);
+ STPSDIO_PR_INFO("sleep_flag(%d) wakeup_flag(%d) awake_flag(%d) txwkr_flag(%d)\n",
+ p_info->sleep_flag, p_info->wakeup_flag, p_info->awake_flag, p_info->txwkr_flag);
+ STPSDIO_PR_INFO("wr_idx(%d), rd_idx(%d), full_flag(%d), tx_fifo_size(%d)\n",
+ atomic_read(&p_info->pkt_buf.wr_idx), atomic_read(&p_info->pkt_buf.rd_idx),
+ p_info->pkt_buf.full_flag, p_info->firmware_info.tx_fifo_size);
+}
+
+VOID stp_sdio_txdbg_dump(VOID)
+{
+#if STP_SDIO_TXDBG
+ UINT32 idx;
+ UINT32 i;
+ UINT32 j;
+ PUINT8 pbuf;
+ UINT32 len;
+
+ for (i = 0; i < STP_SDIO_TXDBG_COUNT; ++i) {
+ idx = (stp_sdio_txdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK;
+ len = stp_sdio_txdbg_buffer[idx].bus_txlen;
+ if (len == 0) {
+ STPSDIO_PR_INFO("idx(%x) 0 == len dump skip\n", idx);
+ continue;
+ }
+
+ len = len > STP_SDIO_TXDBG_MAX_SIZE ? STP_SDIO_TXDBG_MAX_SIZE : len;
+ STPSDIO_PR_INFO(
+ "stp_sdio_txdbg_buffer idx(%x) bus_txlen(0x%x, %d), time[%llu.%06lu]\n",
+ idx, len, len, stp_sdio_txdbg_buffer[idx].l_sec, stp_sdio_txdbg_buffer[idx].l_nsec);
+ for (j = 0; j < STP_SDIO_TX_ENTRY_SIZE && j < len; j += 16) {
+ pbuf = &stp_sdio_txdbg_buffer[idx].tx_pkt_buf[j];
+ STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6], pbuf[7]);
+ STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13], pbuf[14],
+ pbuf[15]);
+ msleep(20);
+ }
+ STPSDIO_PR_INFO("stp_sdio_txdbg_buffer dump ok\n");
+ }
+#if STP_TXDBG
+ for (i = 0; i < STP_SDIO_TXDBG_COUNT; ++i) {
+ idx = (stp_sdio_txdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK;
+ len = stp_sdio_txdbg_buffer[idx].bus_txlen;
+ STPSDIO_PR_INFO(
+ "stp_sdio_txdbg_buffer idx(%x) bus_txlen(0x%x, %d) ts(%d)\n", idx, len, len,
+ stp_sdio_txdbg_buffer[idx].ts);
+ }
+ STPSDIO_PR_INFO(
+ "Dump tx info: pkt_num(%d) fifo(%d) pkt_list.rd(0x%x, %ld) pkt_list.wr(0x%x, %ld)\n",
+ gp_info->firmware_info.tx_packet_num, gp_info->firmware_info.tx_fifo_size,
+ gp_info->tx_pkt_list.pkt_rd_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_rd_cnt),
+ gp_info->tx_pkt_list.pkt_wr_cnt,
+ STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_wr_cnt));
+
+ for (i = 0; i < STP_SDIO_TX_PKT_LIST_SIZE; ++i) {
+ idx = STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_wr_cnt - 1 - i);
+ STPSDIO_PR_INFO(
+ "tx_pkt_list idx(0x%x, %d) size(0x%x, %d), in_ts(%d), out_ts(%d)\n",
+ (gp_info->tx_pkt_list.pkt_wr_cnt - 1 - i), idx,
+ gp_info->tx_pkt_list.pkt_size_list[idx],
+ gp_info->tx_pkt_list.pkt_size_list[idx], gp_info->tx_pkt_list.in_ts[idx],
+ gp_info->tx_pkt_list.out_ts[idx]);
+ }
+
+#if STP_SDIO_NEW_TXRING
+ STPSDIO_PR_INFO("\n\ndump pkt_buf.tx_buf: rd(%d) wr(%d) full(%d)\n",
+ atomic_read(&gp_info->pkt_buf.rd_cnt), atomic_read(&gp_info->pkt_buf.wr_cnt),
+ gp_info->pkt_buf.full_flag);
+#else
+ STPSDIO_PR_INFO("\n\ndump pkt_buf.tx_buf: rdi(%d) wri(%d) full(%d)\n",
+ atomic_read(&gp_info->pkt_buf.rd_idx), atomic_read(&gp_info->pkt_buf.wr_idx),
+ gp_info->pkt_buf.full_flag);
+#endif
+
+ for (i = 0; i < STP_SDIO_TX_BUF_CNT; ++i) {
+#if STP_SDIO_NEW_TXRING
+ idx = (atomic_read(&gp_info->pkt_buf.wr_cnt) - 1 - i) & STP_SDIO_TX_BUF_CNT_MASK;
+ len = gp_info->pkt_buf.tx_buf_sz[idx];
+#else
+ idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 - i + STP_SDIO_TX_BUF_CNT) %
+ STP_SDIO_TX_BUF_CNT;
+#if KMALLOC_UPDATE
+ len = *(gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 1);
+ len = (len << 8) | *(gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0);
+#else
+ len = gp_info->pkt_buf.tx_buf[idx][1];
+ len = (len << 8) | gp_info->pkt_buf.tx_buf[idx][0];
+#endif
+
+#endif
+ STPSDIO_PR_INFO("pkt_buf.tx_buf idx(%x) ts(%d) len(%d), time[%llu.%06lu]\n",
+ idx, gp_info->pkt_buf.tx_buf_ts[idx], len,
+ gp_info->pkt_buf.tx_buf_local_ts[idx], gp_info->pkt_buf.tx_buf_local_nsec[idx]);
+ if (len == 0) {
+ STPSDIO_PR_INFO("idx(%x) 0 == len dump skip\n", idx);
+ continue;
+ }
+ len = len > STP_SDIO_TXDBG_MAX_SIZE ? STP_SDIO_TXDBG_MAX_SIZE : len;
+ for (j = 0; j < STP_SDIO_TX_ENTRY_SIZE && j < len; j += 16) {
+#if KMALLOC_UPDATE
+ pbuf = gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + j;
+#else
+ pbuf = &gp_info->pkt_buf.tx_buf[idx][j];
+#endif
+ STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6],
+ pbuf[7]);
+ STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13], pbuf[14],
+ pbuf[15]);
+ msleep(20);
+ }
+ STPSDIO_PR_INFO("pkt_buf.tx_buf dump ok\n");
+ }
+#endif /*end of STP_TXDBG*/
+#endif /* end of STP_SDIO_TXDBG */
+}
+
+/*!
+ * \brief /proc debug read interface and dump tx dbg information
+ *
+ * \details Dump all tx debug information to console.
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_txdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ if (*f_pos > 0)
+ return 0;
+
+ stp_sdio_txdbg_dump();
+ stp_sdio_txperf_dump();
+
+ return 0;
+}
+
+/*!
+ * \brief /proc debug write interface. do nothing.
+ *
+ * \details
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_txdbg_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ ULONG len = count;
+
+ pr_warn(DFT_TAG "write parameter len = %lu\n\r", len);
+
+ return len;
+}
+
+/*!
+ * \brief /proc debug read interface and dump tx dbg information
+ *
+ * \details Dump all tx debug information to console.
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_own_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ if (*f_pos > 0)
+ return 0;
+
+ return 0;
+}
+
+/*!
+ * \brief /proc debug write interface. do nothing.
+ *
+ * \details
+ *
+ * \retval 0 success
+ */
+ssize_t stp_sdio_own_write(struct file *filp, const char __user *buffer, size_t count,
+ loff_t *f_pos)
+{
+ ULONG len = count;
+ PINT8 pBuf = NULL;
+ PINT8 pToken = NULL;
+ PINT8 pDelimiter = " \t";
+ INT32 x = 0;
+ INT8 buf[128] = { 0 };
+ LONG res = 0;
+
+ if (len >= osal_sizeof(buf)) {
+ STPSDIO_PR_ERR("input handling fail!\n");
+ len = osal_sizeof(buf) - 1;
+ return -1;
+ }
+
+ if (copy_from_user(buf, buffer, len)) {
+ STPSDIO_PR_ERR("copy_from_user error.\n");
+ return -EFAULT;
+ }
+
+ buf[len] = '\0';
+ pBuf = buf;
+ pToken = osal_strsep(&pBuf, pDelimiter);
+ if (pToken != NULL) {
+ osal_strtol(pToken, 16, &res);
+ x = (INT32)res;
+ } else {
+ x = 0;
+ }
+
+ if (x == 0) {
+ STPSDIO_PR_INFO("stp_sdio_own_ctrl(OWN_CLR)\n\r");
+ stp_sdio_own_ctrl(OWN_CLR);
+ } else if (x == 2) {
+ STPSDIO_PR_INFO("stp_sdio_own_ctrl(OWN_SET) -->Sleep\n\r");
+ stp_sdio_own_ctrl(OWN_SET);
+ } else if (x == 3) {
+ gStpSdioDbgLvl = STPSDIO_LOG_WARN;
+ STPSDIO_PR_WARN("set STP-SDIO LogLevel to STPSDIO_LOG_WARN\n\r");
+ } else if (x == 4) {
+ gStpSdioDbgLvl = STPSDIO_LOG_INFO;
+ STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_INFO\n\r");
+ } else if (x == 5) {
+ gStpSdioDbgLvl = STPSDIO_LOG_HINT;
+ STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_HINT\n\r");
+ } else if (x == 6) {
+ gStpSdioDbgLvl = STPSDIO_LOG_DBG;
+ STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_DBG\n\r");
+ } else if (x == 7) {
+ gStpSdioDbgLvl = STPSDIO_LOG_LOUD;
+ STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_LOUD\n\r");
+ }
+
+ return len;
+}
+
+
+/*!
+ * \brief /proc initial procedures. Initialize global debugging information.
+ *
+ * \details Setup entry for /proc debugging for tx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_txdbg_setup(VOID)
+{
+ gStpSdioTxDbgEntry = proc_create(STP_SDIO_TXDBG_PROCNAME, 0644, NULL, &stp_sdio_txdbg_fops);
+ if (gStpSdioTxDbgEntry == NULL) {
+ pr_warn(DFT_TAG "Unable to create /proc entry\n\r");
+ return -1;
+ }
+
+#if STP_SDIO_TXPERFDBG
+ stp_sdio_txperf_worker_cnt = 0;
+
+ stp_sdio_txperf_fifo_left = 0;
+ stp_sdio_txperf_to_send = 0;
+ stp_sdio_txperf_fifo_lmt_cnt = 0;
+
+ stp_sdio_txperf_txed_pkt_num = 0;
+ stp_sdio_txperf_pkt_num_lmt_cnt = 0;
+#endif
+
+#if STP_SDIO_TXDBG
+ stp_sdio_txdbg_cnt = 0;
+#endif
+
+ return 0;
+}
+
+/*!
+ * \brief /proc de-init procedures.
+ *
+ * \details remove entry for /proc debugging for tx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_txdbg_remove(VOID)
+{
+ if (gStpSdioTxDbgEntry != NULL)
+ proc_remove(gStpSdioTxDbgEntry);
+
+ return 0;
+}
+
+#endif /* end of STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) */
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG
+
+/*!
+ * \brief /proc initial procedures. Initialize global debugging information.
+ *
+ * \details Setup entry for /proc debugging for tx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_owndbg_setup(VOID)
+{
+ gStpSdioOwnEntry = proc_create(STP_SDIO_OWNDBG_PROCNAME, 0644, NULL, &stp_sdio_own_fops);
+ if (gStpSdioOwnEntry == NULL) {
+ pr_warn(DFT_TAG "Unable to create /proc entry\n\r");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/*!
+ * \brief /proc de-init procedures.
+ *
+ * \details remove entry for /proc debugging for tx
+ *
+ * \retval 0 success
+ */
+INT32 stp_sdio_owndbg_remove(VOID)
+{
+ if (gStpSdioOwnEntry != NULL)
+ proc_remove(gStpSdioOwnEntry);
+
+ return 0;
+}
+#endif
+
+/*!
+ * \brief hif_sdio init function
+ *
+ * detailed descriptions
+ *
+ * \retval
+ */
+static INT32 stp_sdio_init(VOID)
+{
+ INT32 ret;
+ INT32 i;
+
+ /* 4 <1> initialize all private variables */
+ stp_sdio_host_info_op(1);
+ g_stp_sdio_host_count = 0;
+ /* Init stp sdio client info */
+#if 0 /* George: chage to be a constant struct */
+ g_stp_sdio_cltinfo.func_tbl = mtk_stp_sdio_id_tbl;
+ g_stp_sdio_cltinfo.func_tbl_size =
+ sizeof(mtk_stp_sdio_id_tbl) / sizeof(MTK_WCN_HIF_SDIO_FUNCINFO) - 1;
+ g_stp_sdio_cltinfo.hif_clt_irq = stp_sdio_irq;
+ g_stp_sdio_cltinfo.hif_clt_probe = stp_sdio_probe;
+ g_stp_sdio_cltinfo.hif_clt_remove = stp_sdio_remove;
+#endif
+
+ STPSDIO_PR_DBG("cltinfo func table size:%d\n", g_stp_sdio_cltinfo.func_tbl_size);
+ for (i = 0; i < g_stp_sdio_cltinfo.func_tbl_size; i++) {
+ STPSDIO_PR_DBG("manf_id:0x%x, card_id:0x%x, func_num:%d, blk_size:%d\n",
+ mtk_stp_sdio_id_tbl[i].manf_id, mtk_stp_sdio_id_tbl[i].card_id,
+ mtk_stp_sdio_id_tbl[i].func_num, mtk_stp_sdio_id_tbl[i].blk_sz);
+ }
+
+ /* 4 <2> register supported functions from sdio id table to hif sdio driver */
+ ret = mtk_wcn_hif_sdio_client_reg(&g_stp_sdio_cltinfo);
+ if (ret)
+ STPSDIO_PR_ERR("mtk_wcn_hif_sdio_client_reg fail(%d)!\n", ret);
+
+ ret = mtk_wcn_stp_wmt_sdio_op_reg(stp_sdio_own_ctrl);
+ if (ret)
+ STPSDIO_PR_ERR
+ ("mtk_wcn_stp_wmt_sdio_op_reg(mtk_wcn_stp_sdio_own_ctrl) fail(%d)!\n", ret);
+#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT
+ mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(stp_sdio_deep_sleep_flag_set);
+#endif
+ mtk_wcn_wmt_sdio_rw_cb_reg(stp_sdio_reg_rw);
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+ stp_sdio_rxdbg_setup();
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ stp_sdio_txdbg_setup();
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG
+ stp_sdio_owndbg_setup();
+#endif
+
+ STPSDIO_PR_DBG
+ ("blk_size(%ld), tx_buf_cnt(%ld), fifo tx(%ld) rx(%ld), buf tx(%ld) rx(%ld)\n",
+ STP_SDIO_BLK_SIZE, STP_SDIO_TX_BUF_CNT, STP_SDIO_TX_FIFO_SIZE, STP_SDIO_RX_FIFO_SIZE,
+ STP_SDIO_TX_ENTRY_SIZE, STP_SDIO_TX_ENTRY_SIZE);
+
+ return ret;
+}
+
+INT32 stp_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value)
+{
+
+ if (func_num == 0)
+ return stp_sdio_func0_reg_rw(direction, offset, value);
+ else if (func_num == 2)
+ return stp_sdio_func_reg_rw(direction, offset, value);
+
+ STPSDIO_PR_ERR("func_num(%d) is not support!\n", func_num);
+ return -1;
+}
+
+INT32 stp_sdio_func0_reg_rw(INT32 direction, UINT32 offset, UINT32 value)
+{
+ INT32 ret = -1;
+ UINT8 val = 0x00;
+
+ val = (UINT8) value;
+ switch (direction) {
+ case 0:
+ ret = mtk_wcn_hif_sdio_f0_readb(g_stp_sdio_host_info.sdio_cltctx, offset, &val);
+ STPSDIO_PR_INFO("read func0 CR(0x%x), value(0x%x)\n", offset, val);
+ break;
+ case 1:
+ ret = mtk_wcn_hif_sdio_f0_writeb(g_stp_sdio_host_info.sdio_cltctx, offset, val);
+ STPSDIO_PR_INFO("write func0 CR(0x%x), value(0x%x)\n", offset, val);
+ break;
+ default:
+ break;
+ }
+ return ret;
+
+}
+
+INT32 stp_sdio_func_reg_rw(INT32 direction, UINT32 offset, UINT32 value)
+{
+ INT32 ret = -1;
+ UINT32 val = 0x00;
+
+ val = (UINT32) value;
+ switch (direction) {
+ case 0:
+ ret = mtk_wcn_hif_sdio_readl(g_stp_sdio_host_info.sdio_cltctx, offset, &val);
+ STPSDIO_PR_INFO("read sdio CR(0x%x), value(0x%x)\n", offset, val);
+ break;
+ case 1:
+ ret = mtk_wcn_hif_sdio_writel(g_stp_sdio_host_info.sdio_cltctx, offset, val);
+ STPSDIO_PR_INFO("write sdio CR(0x%x), value(0x%x)\n", offset, val);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+INT32 stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx)
+{
+ INT32 ret;
+
+ ret = hif_sdio_wake_up_ctrl(ctx);
+ if (ret == -11) {
+ STPSDIO_PR_ERR("wake up fail, polling [GPIO_CHIP_DEEP_SLEEP_PIN] low over 30ms\n");
+ ret = stp_sdio_issue_fake_coredump
+ (" wake up fail, polling [GPIO_CHIP_DEEP_SLEEP_PIN] low over 30ms # -");
+ } else if (ret == -2 || ret == -3)
+ STPSDIO_PR_ERR("get wake up, sleep pin error\n");
+
+ return ret;
+}
+
+VOID stp_sdio_dump_register(VOID)
+{
+ UINT32 count = 3;
+ MTK_WCN_HIF_SDIO_CLTCTX clt_ctx;
+ UINT32 val = 0;
+ UINT32 delay_us = 10000;
+
+ clt_ctx = gp_info->sdio_cltctx;
+ while (count) {
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CCIR, &val, 0);
+ STPSDIO_PR_ERR("******CCIR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &val, 0);
+ STPSDIO_PR_ERR("******CHLPCR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CSDIOCSR, &val, 0);
+ STPSDIO_PR_ERR("******CSDIOCSR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHCR, &val, 0);
+ STPSDIO_PR_ERR("******CHCR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHISR, &val, 0);
+ STPSDIO_PR_ERR("******CHISR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER, &val, 0);
+ STPSDIO_PR_ERR("******CHIER == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CTFSR, &val, 0);
+ STPSDIO_PR_ERR("******CTFSR == 0x%x*****\n", val);
+ stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CRPLR, &val, 0);
+ STPSDIO_PR_ERR("******CRPLR == 0x%x*****\n", val);
+ count--;
+ osal_usleep_range(delay_us, 2 * delay_us);
+ }
+
+}
+
+/*!
+ * \brief hif_sdio init function
+ *
+ * detailed descriptions
+ *
+ * \retval
+ */
+static VOID stp_sdio_exit(VOID)
+{
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG
+ stp_sdio_txdbg_remove();
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG
+ stp_sdio_rxdbg_remove();
+#endif
+
+#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG
+ stp_sdio_owndbg_remove();
+#endif
+
+ /* 4 <0> unregister if_tx() function */
+ mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, 0x0);
+
+ /* 4 <1> for all functions that have not been unregistered */
+ /* 4 <1.1> unregister stp sdio func of the host */
+ mtk_wcn_hif_sdio_client_unreg(&g_stp_sdio_cltinfo);
+
+ /* 4 <1.2> stop Tx tasklet/Rx work queue of the host */
+ flush_scheduled_work();
+ STPSDIO_PR_DBG("flush scheduled work end\n");
+
+ /* 4 <1.3> return ownership to firmware of the host */
+ /* TODO: check set which register ! */
+
+ /* 4 <1.4> clear the host struct list and free the memory allocation of the host */
+ g_stp_sdio_host_count = 0;
+ stp_sdio_host_info_op(0);
+ /* 4 <1.5> Notice: while rmmod client driver, the stp_sdio_remove() */
+ /* will not be called after stp_sdio_exit() ! */
+}
+
+INT32 mtk_wcn_stp_sdio_drv_init(VOID)
+{
+ return stp_sdio_init();
+
+}
+EXPORT_SYMBOL(mtk_wcn_stp_sdio_drv_init);
+
+VOID mtk_wcn_stp_sdio_drv_exit(VOID)
+{
+ return stp_sdio_exit();
+}
+EXPORT_SYMBOL(mtk_wcn_stp_sdio_drv_exit);
diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c
new file mode 100644
index 0000000000000000000000000000000000000000..8803c2375b25ca728210701bea8b3ab1fb8ab9fb
--- /dev/null
+++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include