| /** |
| Copyright (c) 2008 - 2013 Quantenna Communications Inc |
| All Rights Reserved |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| 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, write to the Free Software |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| |
| **/ |
| |
| #ifndef AUTOCONF_INCLUDED |
| #include <linux/config.h> |
| #endif |
| #include <linux/version.h> |
| |
| #include <linux/device.h> |
| #include <linux/if_vlan.h> |
| #include "qdrv_features.h" |
| #include "qdrv_debug.h" |
| #include "qdrv_mac.h" |
| #include "qdrv_soc.h" |
| #include "qdrv_hal.h" |
| #include "qdrv_muc.h" |
| #include "qdrv_uc_print.h" |
| #include "qdrv_dsp.h" |
| #include "qdrv_auc.h" |
| #include <qtn/registers.h> |
| #include <qtn/shared_params.h> |
| #include <qtn/txbf_mbox.h> |
| #include <qtn/qtn_bb_mutex.h> |
| #include <qtn/bootcfg.h> |
| #include <net80211/if_ethersubr.h> |
| #include <qtn/qtn_vlan.h> |
| #include <asm/board/board_config.h> |
| #include "qdrv_comm.h" |
| #include "qdrv_wlan.h" |
| #include "qdrv_radar.h" |
| #include "qdrv_vap.h" |
| #include "qdrv_config.h" |
| #include "qtn/qdrv_bld.h" |
| #include "qdrv_mu.h" |
| #include "qtn/qdrv_sch.h" |
| #include <qtn/lhost_muc_comm.h> |
| #include <common/ruby_config.h> |
| #include <qtn/qtn_global.h> |
| #include <qtn/hardware_revision.h> |
| #include <qtn/topaz_fwt_sw.h> |
| |
| extern unsigned int g_catch_fcs_corruption; |
| extern unsigned int g_qos_q_merge; |
| |
| static int tqe_sem_en = 0; |
| module_param(tqe_sem_en, int, 0644); |
| |
| static int env_wifi_hw = 0; |
| module_param(env_wifi_hw, int, 0644); |
| |
| extern void qtn_show_info_register(void *fn); |
| extern void qtn_show_info_unregister(void); |
| extern int qtn_get_hw_config_id(void); |
| |
| struct _shared_params_alloc |
| { |
| struct shared_params params; |
| struct qtn_txbf_mbox txbf_mbox; |
| struct qtn_muc_dsp_mbox muc_dsp_mbox; |
| struct qtn_bb_mutex bb_mutex; |
| struct qtn_csa_info csa; |
| struct qtn_samp_chan_info chan_sample; |
| struct qtn_scan_chan_info chan_scan; |
| struct qtn_scs_info_set scs_info_set; |
| struct qtn_remain_chan_info remain_chan; |
| struct qtn_ocac_info ocac; |
| struct qtn_meas_chan_info chan_meas; |
| #if QTN_SEM_TRACE |
| struct qtn_sem_trace_log sem_trace_log; |
| #endif |
| #if defined(QBMPS_ENABLE) |
| struct qtn_bmps_info bmps; |
| #endif |
| #ifdef CONFIG_NAC_MONITOR |
| struct nac_mon_info nac_mon; |
| #endif |
| }; |
| |
| int qdrv_soc_cb_size(void) |
| { |
| return(sizeof(struct qdrv_cb)); |
| } |
| |
| int qdrv_soc_start_vap(struct qdrv_cb *qcb, int devid, struct qdrv_mac *mac, |
| char *name, uint8_t *mac_addr, int opmode, int flags) |
| { |
| if ((mac->enabled != 1) || (mac->data == NULL)) { |
| DBGPRINTF_E("MAC unit not enabled\n"); |
| return(-1); |
| } |
| |
| if (qdrv_wlan_start_vap((struct qdrv_wlan*)mac->data, name, mac_addr, |
| devid, opmode, flags) < 0) { |
| DBGPRINTF_E("Failed to start VAP\n"); |
| return(-1); |
| } |
| |
| return(0); |
| } |
| |
| int qdrv_soc_stop_vap(struct qdrv_cb *qcb, struct qdrv_mac *mac, struct net_device *vdev) |
| { |
| if ((mac->enabled != 1) || (mac->data == NULL)) { |
| DBGPRINTF_E("MAC unit not enabled\n"); |
| return -1; |
| } |
| |
| if (qdrv_wlan_stop_vap(mac, vdev) < 0) { |
| DBGPRINTF_E("qdrv_wlan_stop_vap failed\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int qdrv_soc_stats(void *data, struct qdrv_mac *mac) |
| { |
| if ((mac->enabled != 1) || (mac->data == NULL)) { |
| DBGPRINTF_E("MAC unit not enabled\n"); |
| return(-1); |
| } |
| |
| if (qdrv_wlan_stats(mac) < 0) { |
| DBGPRINTF_E("Failed to get statistics for VAP\n"); |
| return(-1); |
| } |
| |
| return(0); |
| } |
| |
| static struct shared_params *params_bus = NULL; |
| |
| u_int32_t qdrv_soc_get_hostlink_mbox(void) |
| { |
| return soc_shared_params->m2l_hostlink_mbox; |
| } |
| |
| char *qdrv_soc_get_hw_desc(enum hw_opt_t bond_opt) |
| { |
| char *desc = "unknown"; |
| uint8_t rf_chipid = soc_shared_params->rf_chip_id; |
| |
| if (bond_opt == 0) |
| bond_opt = soc_shared_params->hardware_options; |
| |
| /* |
| * These strings are in use by customers and should not be changed. |
| * The platform ID must appear at the end of the string. |
| */ |
| switch (bond_opt) { |
| case HW_OPTION_BONDING_TOPAZ_QD840: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11n/ac Data Only QD842"; |
| else |
| desc = "4x4 11n/ac Data Only QD840"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV840: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11ac FO RGMII/PCIe QV842"; |
| else |
| desc = "4x4 11ac FO RGMII/PCIe QV840"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV840_2X4: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x4 11ac FO RGMII/PCIe QV842"; |
| else |
| desc = "2x4 11ac FO RGMII/PCIe QV840"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV840C: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11ac FO RGMII/PCIe QV842C"; |
| else |
| desc = "4x4 11ac FO RGMII/PCIe QV840C"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV860: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11ac FO RGMII DBDC QV862"; |
| else |
| desc = "4x4 11ac FO RGMII DBDC QV860"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV860_2X2: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x2 11ac FO RGMII DBDC QV862"; |
| else |
| desc = "2x2 11ac FO RGMII DBDC QV860"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV860_2X4: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x4 11ac FO RGMII DBDC QV862"; |
| else |
| desc = "2x4 11ac FO RGMII DBDC QV860"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV860_3X3: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "3x3 11ac FO RGMII DBDC QV862"; |
| else |
| desc = "3x3 11ac FO RGMII DBDC QV860"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV880: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11ac FO RGMII DBDC QV882"; |
| else |
| desc = "4x4 11ac FO RGMII DBDC QV880"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV880_2X2: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x2 11ac FO RGMII DBDC QV882"; |
| else |
| desc = "2x2 11ac FO RGMII DBDC QV880"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV880_2X4: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x4 11ac FO RGMII DBDC QV882"; |
| else |
| desc = "2x4 11ac FO RGMII DBDC QV880"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV880_3X3: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "3x3 11ac FO RGMII DBDC QV882"; |
| else |
| desc = "3x3 11ac FO RGMII DBDC QV880"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV920: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "4x4 11ac PCIe Memoryless QV922"; |
| else |
| desc = "4x4 11ac PCIe Memoryless QV920"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV920_2X4: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x4 11ac PCIe Memoryless QV922"; |
| else |
| desc = "2x4 11ac PCIe Memoryless QV920"; |
| break; |
| case HW_OPTION_BONDING_TOPAZ_QV940: |
| if (rf_chipid == CHIPID_DUAL) |
| desc = "2x4 11ac FO RGMII/PCIe QV942"; |
| else |
| desc = "2x4 11ac FO RGMII/PCIe QV940"; |
| break; |
| } |
| |
| return desc; |
| } |
| |
| char *qdrv_soc_get_hw_id(enum hw_opt_t bond_opt) |
| { |
| char *hw_desc = qdrv_soc_get_hw_desc(bond_opt); |
| |
| /* Last string in the hardware desc is the ID */ |
| return strrchr(hw_desc, ' ') + 1; |
| } |
| |
| uint32_t qdrv_soc_get_hw_options(void) |
| { |
| if (!soc_shared_params) |
| return 0; |
| |
| return soc_shared_params->hardware_options; |
| } |
| |
| static const char *qdrv_hw_ver_descs[] = { |
| [HARDWARE_REVISION_UNKNOWN] = "unknown", |
| [HARDWARE_REVISION_RUBY_A] = "bbic3_rev_a", |
| [HARDWARE_REVISION_RUBY_B] = "bbic3_rev_b_c", |
| [HARDWARE_REVISION_RUBY_D] = "bbic3_rev_d", |
| [HARDWARE_REVISION_TOPAZ_A] = "bbic4_rev_a0", |
| [HARDWARE_REVISION_TOPAZ_B] = "bbic4_rev_a1", |
| [HARDWARE_REVISION_TOPAZ_A2] = "bbic4_rev_a2" |
| }; |
| |
| const char *qdrv_soc_get_hw_rev_desc(uint16_t hw_rev) |
| { |
| if (hw_rev >= ARRAY_SIZE(qdrv_hw_ver_descs)) |
| hw_rev = HARDWARE_REVISION_UNKNOWN; |
| |
| return qdrv_hw_ver_descs[hw_rev]; |
| } |
| EXPORT_SYMBOL(qdrv_soc_get_hw_rev_desc); |
| |
| static void qdrv_soc_revoke_params(void) |
| { |
| if (soc_shared_params) { |
| dma_free_coherent( |
| NULL, |
| sizeof(struct _shared_params_alloc), |
| container_of(soc_shared_params, struct _shared_params_alloc, params), |
| (dma_addr_t)container_of(params_bus, struct _shared_params_alloc, params)); |
| soc_shared_params = params_bus = NULL; |
| } |
| |
| qtn_mproc_sync_shared_params_set(0); |
| } |
| |
| static int read_hardware_revision(void) |
| { |
| /* |
| * BB should be active and out of reset. ok to query version register |
| * |
| * check that soft reset is low, and global enable is high |
| */ |
| int ret = HARDWARE_REVISION_UNKNOWN; |
| |
| qtn_bb_mutex_enter(QTN_LHOST_SOC_CPU); |
| |
| if (readl(RUBY_QT3_BB_GLBL_SOFT_RST) == 0x0) { |
| ret = _read_hardware_revision(); |
| } else { |
| printk(KERN_ERR "%s called when BB in soft reset\n", __FUNCTION__); |
| } |
| |
| qtn_bb_mutex_leave(QTN_LHOST_SOC_CPU); |
| |
| return ret; |
| } |
| |
| static uint8_t |
| get_bootcfg_calstate(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int calstate = QTN_CALSTATE_DEFAULT; |
| |
| varstart = bootcfg_get_var("calstate", tmpbuf); |
| if (varstart != NULL) { |
| if (sscanf(varstart, "=%d", &calstate) != 1) { |
| calstate = QTN_CALSTATE_DEFAULT; |
| } |
| } |
| |
| return calstate; |
| } |
| |
| static uint8_t get_bootcfg_power_recheck(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int recheck = 1; |
| |
| varstart = bootcfg_get_var("power_recheck", tmpbuf); |
| if (varstart != NULL) { |
| sscanf(varstart, "=%d", &recheck); |
| } |
| |
| return recheck; |
| } |
| |
| static uint8_t |
| get_bootcfg_post_mask(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int post_mask = 0; |
| |
| varstart = bootcfg_get_var("post_mask", tmpbuf); |
| if (varstart != NULL) { |
| if (sscanf(varstart, "=%d", &post_mask) != 1) { |
| post_mask = 0; |
| } |
| } |
| |
| return post_mask; |
| } |
| |
| static int |
| get_ext_lna_gain_from_bootcfg(const char *var) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int value; |
| int lna_gain = QTN_EXT_LNA_GAIN_MAX; |
| |
| varstart = bootcfg_get_var(var, tmpbuf); |
| if (varstart != NULL) { |
| if (sscanf(varstart, "=%d", &value) == 1) { |
| if ((-127 < value) && (value < QTN_EXT_LNA_GAIN_MAX)) { |
| lna_gain = value; |
| } |
| } |
| } |
| |
| return lna_gain; |
| } |
| |
| static int |
| get_bootcfg_tx_power_cal(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int tx_power_cal = 0; |
| |
| varstart = bootcfg_get_var("tx_power_cal", tmpbuf); |
| if (varstart != NULL) { |
| sscanf(varstart, "=%d", &tx_power_cal); |
| } |
| |
| return tx_power_cal; |
| } |
| |
| static int |
| get_bootcfg_min_tx_power(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int min_tx_power = 0; |
| |
| varstart = bootcfg_get_var("min_tx_power", tmpbuf); |
| if (varstart != NULL) { |
| sscanf(varstart, "=%d", &min_tx_power); |
| } |
| |
| return min_tx_power; |
| } |
| |
| static int |
| get_bootcfg_max_tx_power(void) |
| { |
| char tmpbuf[256]; |
| char *varstart; |
| int max_tx_power = 0; |
| |
| varstart = bootcfg_get_var("max_tx_power", tmpbuf); |
| if (varstart != NULL) { |
| sscanf(varstart, "=%d", &max_tx_power); |
| } |
| |
| return max_tx_power; |
| } |
| |
| static int |
| qdrv_soc_publish_params(struct qdrv_cb *qcb) |
| { |
| int ret = 0; |
| int current_wifi_hw = 0; |
| int current_rf_chip_id; |
| struct _shared_params_alloc *params_alloc = NULL, *params_alloc_bus = NULL; |
| |
| /* Guard againt second call to function */ |
| qdrv_soc_revoke_params(); |
| |
| /* Allocate what we are going to publish. |
| * Pointer can be used by any processor in system, |
| * so published pointer must be "bus" pointer. |
| * If other processors want to convert pointer for example |
| * to be non-cacheable, they must remap it themself. |
| * Structure must be allocated using dma_alloc_coherent(). |
| */ |
| if((params_alloc = (struct _shared_params_alloc*)dma_alloc_coherent(NULL, |
| sizeof(struct _shared_params_alloc), (dma_addr_t*)(¶ms_alloc_bus), GFP_KERNEL)) == NULL) |
| { |
| DBGPRINTF_E("%s: failed to alloc soc_shared_params\n", __FUNCTION__); |
| ret = -1; |
| goto bad; |
| } |
| memset(params_alloc, 0, sizeof(*params_alloc)); |
| |
| /* Initialize shared soc_shared_params structure */ |
| soc_shared_params = ¶ms_alloc->params; |
| params_bus = ¶ms_alloc_bus->params; |
| soc_shared_params->hardware_id = qtn_get_hw_config_id(); |
| memcpy(soc_shared_params->fw_version, QDRV_BLD_NAME, |
| MIN(QTN_FW_VERSION_LENGTH, strlen(QDRV_BLD_NAME))); |
| |
| /* Initialize beamforming message box structure */ |
| soc_shared_params->txbf_mbox_lhost = ¶ms_alloc->txbf_mbox; |
| soc_shared_params->txbf_mbox_bus = ¶ms_alloc_bus->txbf_mbox; |
| soc_shared_params->muc_dsp_mbox_lhost = ¶ms_alloc->muc_dsp_mbox; |
| soc_shared_params->muc_dsp_mbox_bus = ¶ms_alloc_bus->muc_dsp_mbox; |
| soc_shared_params->muc_dsp_mbox_lhost->muc_to_dsp_mbox = QTN_TXBF_MBOX_BAD_IDX; |
| soc_shared_params->muc_dsp_mbox_lhost->dsp_to_muc_mbox = QTN_TXBF_MBOX_BAD_IDX; |
| soc_shared_params->txbf_mbox_lhost->muc_to_dsp_ndp_mbox = QTN_TXBF_MBOX_BAD_IDX; |
| int i; |
| for (i = 0; i < ARRAY_SIZE(soc_shared_params->txbf_mbox_lhost->muc_to_dsp_action_frame_mbox); i++) { |
| soc_shared_params->txbf_mbox_lhost->muc_to_dsp_action_frame_mbox[i] = QTN_TXBF_MBOX_BAD_IDX; |
| } |
| |
| soc_shared_params->txbf_mbox_lhost->dsp_to_host_mbox = QTN_TXBF_MBOX_BAD_IDX; |
| |
| /* Initialize RIFS mode structure */ |
| soc_shared_params->bb_mutex_lhost = ¶ms_alloc->bb_mutex; |
| soc_shared_params->bb_mutex_bus = ¶ms_alloc_bus->bb_mutex; |
| |
| /* deferred channel switch */ |
| soc_shared_params->csa_lhost = ¶ms_alloc->csa; |
| soc_shared_params->csa_bus = ¶ms_alloc_bus->csa; |
| |
| /* cca scan */ |
| soc_shared_params->chan_sample_lhost = ¶ms_alloc->chan_sample; |
| soc_shared_params->chan_sample_bus = ¶ms_alloc_bus->chan_sample; |
| |
| soc_shared_params->chan_scan_lhost = ¶ms_alloc->chan_scan; |
| soc_shared_params->chan_scan_bus = ¶ms_alloc_bus->chan_scan; |
| |
| /* SCS info */ |
| soc_shared_params->scs_info_lhost = ¶ms_alloc->scs_info_set; |
| soc_shared_params->scs_info_bus = ¶ms_alloc_bus->scs_info_set; |
| |
| /* remain channel info */ |
| soc_shared_params->remain_chan_lhost = ¶ms_alloc->remain_chan; |
| soc_shared_params->remain_chan_bus = ¶ms_alloc_bus->remain_chan; |
| /* ocac */ |
| soc_shared_params->ocac_lhost = ¶ms_alloc->ocac; |
| soc_shared_params->ocac_bus = ¶ms_alloc_bus->ocac; |
| |
| /* Measurement info */ |
| soc_shared_params->chan_meas_lhost = ¶ms_alloc->chan_meas; |
| soc_shared_params->chan_meas_bus = ¶ms_alloc_bus->chan_meas; |
| |
| /* remain channel info */ |
| soc_shared_params->remain_chan_lhost = ¶ms_alloc->remain_chan; |
| soc_shared_params->remain_chan_bus = ¶ms_alloc_bus->remain_chan; |
| |
| #if QTN_SEM_TRACE |
| /* semaphore calltrace log */ |
| soc_shared_params->sem_trace_log_lhost = ¶ms_alloc->sem_trace_log; |
| soc_shared_params->sem_trace_log_bus = ¶ms_alloc_bus->sem_trace_log; |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, |
| "semaphore calltrace log buffer: %p %p\n", |
| soc_shared_params->sem_trace_log_lhost, soc_shared_params->sem_trace_log_bus); |
| #endif |
| #ifdef CONFIG_NAC_MONITOR |
| soc_shared_params->nac_mon_info = ¶ms_alloc->nac_mon; |
| soc_shared_params->nac_mon_info_bus = ¶ms_alloc_bus->nac_mon; |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, "nac_mon_info %p bus %x\n", |
| soc_shared_params->nac_mon_info, |
| (uint32_t)soc_shared_params->nac_mon_info_bus); |
| #endif |
| |
| /* FIXME: to be replaced */ |
| soc_shared_params->vdev_lhost = vdev_tbl_lhost; |
| soc_shared_params->vdev_bus = (struct qtn_vlan_dev **)virt_to_bus(vdev_tbl_bus); |
| soc_shared_params->vport_lhost = vport_tbl_lhost; |
| soc_shared_params->vport_bus = (struct qtn_vlan_dev **)virt_to_bus(vport_tbl_bus); |
| soc_shared_params->vlan_info = (struct qtn_vlan_info *)virt_to_bus(&qtn_vlan_info); |
| soc_shared_params->auc.vdev_bus = soc_shared_params->vdev_bus; |
| soc_shared_params->auc.vport_bus = soc_shared_params->vport_bus; |
| |
| #if defined(QBMPS_ENABLE) |
| /* bmps info */ |
| soc_shared_params->bmps_lhost = ¶ms_alloc->bmps; |
| soc_shared_params->bmps_bus = ¶ms_alloc_bus->bmps; |
| #endif |
| |
| soc_shared_params->ipmac_table_bus = (struct topaz_ipmac_uc_table *)ipmac_hash_bus; |
| |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, |
| "txbf_mbox %p %p shared soc_shared_params %p %p bb_mutex %p %p\n", |
| soc_shared_params->txbf_mbox_bus, soc_shared_params->txbf_mbox_lhost, soc_shared_params, params_bus, |
| soc_shared_params->bb_mutex_bus, soc_shared_params->bb_mutex_lhost); |
| |
| /* Fill shared parameters structure */ |
| if (get_board_config( BOARD_CFG_WIFI_HW, ¤t_wifi_hw ) != 0) { |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, |
| "%s: get board config returned error status\n", __FUNCTION__); |
| /* This error is relatively harmless, so carry on. */ |
| } |
| |
| /* Initialise flag for TQE hang WAR */ |
| #ifdef CONFIG_TOPAZ_PCIE_TARGET |
| soc_shared_params->tqe_sem_en = tqe_sem_en; |
| soc_shared_params->auc.auc_tqe_sem_en = tqe_sem_en; |
| #else |
| soc_shared_params->tqe_sem_en = 0; |
| soc_shared_params->auc.auc_tqe_sem_en = 0; |
| #endif |
| |
| printk("%s: parames->tqe_sem_en %d, auc_tqe_sem_en %d\n", __FUNCTION__, soc_shared_params->tqe_sem_en, |
| soc_shared_params->auc.auc_tqe_sem_en); |
| |
| soc_shared_params->lh_wifi_hw = current_wifi_hw; |
| if (get_board_config( BOARD_CFG_RFIC, ¤t_rf_chip_id ) != 0) { |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, |
| "%s: get board config returned error status\n", __FUNCTION__); |
| /* This error is relatively harmless, so carry on. */ |
| } |
| soc_shared_params->rf_chip_id = current_rf_chip_id; |
| printk("..... Current RFIC Chip ID -- %d\n", soc_shared_params->rf_chip_id ); |
| |
| |
| memcpy(soc_shared_params->lh_mac_0, qcb->mac0, sizeof(soc_shared_params->lh_mac_0)); |
| memcpy(soc_shared_params->lh_mac_1, qcb->mac1, sizeof(soc_shared_params->lh_mac_1)); |
| soc_shared_params->lh_chip_id = (u_int16_t) readl( RUBY_SYS_CTL_CSR ); |
| soc_shared_params->lh_num_devices = 1; |
| |
| soc_shared_params->uc_flags = g_catch_fcs_corruption; |
| soc_shared_params->uc_flags |= g_qos_q_merge; |
| soc_shared_params->fw_no_mu = qcb->fw_no_mu; |
| |
| soc_shared_params->hardware_revision = read_hardware_revision(); |
| soc_shared_params->hardware_options = get_bootcfg_bond_opt(); |
| |
| soc_shared_params->shortrange_scancnt = get_bootcfg_scancnt(); |
| soc_shared_params->ext_lna_gain = get_ext_lna_gain_from_bootcfg("ext_lna_gain"); |
| soc_shared_params->ext_lna_bypass_gain = get_ext_lna_gain_from_bootcfg("ext_lna_bypass_gain"); |
| soc_shared_params->tx_power_cal = get_bootcfg_tx_power_cal(); |
| soc_shared_params->min_tx_power = get_bootcfg_min_tx_power(); |
| soc_shared_params->max_tx_power = get_bootcfg_max_tx_power(); |
| |
| /* This slow ethernet check is done twice in qdrv as sc is initialized at this point */ |
| soc_shared_params->slow_ethernet_war = board_slow_ethernet(); |
| soc_shared_params->iot_tweaks = QTN_IOT_DEFAULT_TWEAK; |
| soc_shared_params->calstate = get_bootcfg_calstate(); |
| soc_shared_params->post_rfloop = (get_bootcfg_post_mask() & 0x4) ? 1 : 0; |
| |
| DBGPRINTF(DBG_LL_CRIT, QDRV_LF_TRACE, |
| "System rev: %08X\n", |
| soc_shared_params->lh_chip_id); |
| /* |
| * CPUs will access the shared parameters. |
| */ |
| qtn_mproc_sync_shared_params_set((struct shared_params*)params_bus); |
| |
| return ret; |
| |
| bad: |
| qdrv_soc_revoke_params(); |
| return ret; |
| } |
| |
| static void qtn_show_info (void) { |
| printk("\nFirmware build version: %s", QDRV_BLD_NAME); |
| printk("\nFirmware configuration: %s", QDRV_CFG_TYPE); |
| printk("\nHardware ID : %d\n", qtn_get_hw_config_id()); |
| } |
| |
| int qdrv_start_dsp_only(struct device *dev) |
| { |
| struct qdrv_cb *qcb; |
| int retval = 0; |
| |
| #ifdef QTN_RC_ENABLE_HDP |
| /* for RC only: if not PCIE_TQE_INTR_WORKAROUND ignore the dsp fw download */ |
| if (!((readl(RUBY_SYS_CTL_CSR) & 0xff) == TOPAZ_BOARD_REVB)) |
| return retval; |
| #endif |
| |
| qcb = (struct qdrv_cb *) dev_get_drvdata(dev); |
| qcb->dev = dev; |
| |
| /* Bring up the DSP */ |
| retval = qdrv_dsp_init(qcb); |
| if(retval == 0) |
| qcb->resources |= QDRV_RESOURCE_DSP; |
| |
| return retval; |
| } |
| |
| int qdrv_soc_init(struct device *dev) |
| { |
| struct qdrv_cb *qcb; |
| int retval = 0; |
| int error_code = 0; |
| |
| /* Get the private device data */ |
| qcb = (struct qdrv_cb *) dev_get_drvdata(dev); |
| |
| /* MATS FIX This should be initialized better somewhere else */ |
| qcb->instances = 1; |
| |
| /* Make sure we have firmware image specified for the MuC */ |
| if(qcb->muc_firmware[0] == '\0') |
| { |
| error_code = 0x00000001; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Set the device in the control block */ |
| qcb->dev = dev; |
| |
| /* initiate the power control block */ |
| qcb->power_table_ctrl.power_recheck = get_bootcfg_power_recheck(); |
| |
| /* |
| * Reset the SoC. |
| * |
| * Must be called *before* qdrv_soc_publish_params, so that BB is out of reset |
| * when reading the version register |
| */ |
| hal_reset(); |
| |
| /* Publish SoC parameters */ |
| if (qdrv_soc_publish_params(qcb) < 0) |
| { |
| error_code = 0x00000002; |
| retval = -ENOMEM; |
| goto error; |
| } |
| |
| /* Register scheduler */ |
| if(qdrv_sch_module_init() != 0) |
| { |
| error_code = 0x00000004; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Initialize the MAC 0 device */ |
| if(qdrv_mac_init(&qcb->macs[0], qcb->mac0, 0, IRQ_MAC0_0, &qcb->params) < 0) |
| { |
| error_code = 0x00000010; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_MAC0; |
| |
| /* Ruby (ARC host) does not support MAC 1 */ |
| #ifndef CONFIG_ARC |
| /* Initialize the MAC 1 device */ |
| if(qdrv_mac_init(&qcb->macs[1], qcb->mac1, 1, IRQ_MAC0_1, &qcb->params) < 0) |
| { |
| error_code = 0x00000020; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_MAC1; |
| #endif |
| |
| /* Initialize the message module */ |
| if(qdrv_comm_init(qcb) < 0) |
| { |
| error_code = 0x00000040; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_COMM; |
| |
| /* Bring up the DSP */ |
| if(qdrv_dsp_init(qcb) != 0) |
| { |
| error_code = 0x00000100; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_DSP; |
| |
| /* Initialise MuC print buf */ |
| if(qdrv_uc_print_init(qcb) != 0) { |
| DBGPRINTF_E("Could not initialise MuC shared print buffer!\n"); |
| } else { |
| qcb->resources |= QDRV_RESOURCE_UC_PRINT; |
| } |
| |
| /* Bring up the MuC */ |
| if(qdrv_muc_init(qcb) != 0) |
| { |
| error_code = 0x00000080; |
| retval = -ENODEV; |
| goto error; |
| } |
| |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_MUC; |
| |
| /* Bring up the AuC */ |
| if(qdrv_auc_init(qcb) != 0) |
| { |
| error_code = 0x00000100; |
| retval = -ENODEV; |
| goto error; |
| } |
| if (qdrv_mu_stat_init(qcb) != 0) |
| { |
| error_code = 0x00000200; |
| retval = -ENODEV; |
| goto error; |
| } |
| /* Mark that we have successfully allocated a resource */ |
| qcb->resources |= QDRV_RESOURCE_AUC; |
| |
| qtn_show_info_register(qtn_show_info); |
| |
| /* That went well .... */ |
| return(0); |
| |
| error: |
| |
| DBGPRINTF_E("Failed with error code 0x%08x\n", error_code); |
| |
| /* Clean up as much as we can */ |
| (void) qdrv_soc_exit(dev); |
| |
| /* Not so good .... */ |
| return(retval); |
| } |
| |
| int qdrv_soc_exit(struct device *dev) |
| { |
| struct qdrv_cb *qcb; |
| |
| /* Get the private device data */ |
| qcb = dev_get_drvdata(dev); |
| |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, "Begin resources 0x%08x\n", qcb->resources); |
| |
| qtn_show_info_unregister(); |
| |
| (void)qdrv_mu_stat_exit(qcb); |
| /* Release resources in reverse order */ |
| if(qcb->resources & QDRV_RESOURCE_AUC) |
| { |
| (void) qdrv_auc_exit(qcb); |
| qcb->resources &= ~QDRV_RESOURCE_AUC; |
| } |
| |
| /* Release resources in reverse order */ |
| if(qcb->resources & QDRV_RESOURCE_DSP) |
| { |
| (void) qdrv_dsp_exit(qcb); |
| qcb->resources &= ~QDRV_RESOURCE_DSP; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_MUC) |
| { |
| (void) qdrv_muc_exit(qcb); |
| qcb->resources &= ~QDRV_RESOURCE_MUC; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_UC_PRINT) |
| { |
| (void) qdrv_uc_print_exit(qcb); |
| qcb->resources &= ~QDRV_RESOURCE_UC_PRINT; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_MAC0) |
| { |
| (void) qdrv_mac_exit(&qcb->macs[0]); |
| qcb->resources &= ~QDRV_RESOURCE_MAC0; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_MAC1) |
| { |
| (void) qdrv_mac_exit(&qcb->macs[1]); |
| qcb->resources &= ~QDRV_RESOURCE_MAC1; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_COMM) |
| { |
| (void) qdrv_comm_exit(qcb); |
| qcb->resources &= ~QDRV_RESOURCE_COMM; |
| } |
| |
| if(qcb->resources & QDRV_RESOURCE_WLAN) |
| { |
| (void) qdrv_wlan_exit(&qcb->macs[0]); |
| qcb->resources &= ~QDRV_RESOURCE_WLAN; |
| } |
| |
| |
| qdrv_sch_module_exit(); |
| |
| qdrv_soc_revoke_params(); |
| |
| DBGPRINTF(DBG_LL_INFO, QDRV_LF_TRACE, "End resources 0x%08x\n", qcb->resources); |
| |
| return(0); |
| } |