blob: 66de1d5890c33b8fbe0808c78536c5003e42a1b6 [file] [log] [blame]
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include "if_pci.h"
/*chaninfo*/
#define CHANINFOMEM_S2_READ_MASK 0x00000008
#define CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK 0x00000001
#define CHANINFO_CTRL_CHANINFOMEM_BW_MASK 0x00000030
#define MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK 0x00000007
/*agc*/
#define GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK 0x00040000
#define GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK 0x00080000
#define GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK 0x00100000
#define GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK 0x00200000
#define AGC_HISTORY_DUMP_MASK GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK| \
GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK| \
GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK| \
GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK
#define BB_chaninfo_ctrl 0x1a370
#define BB_multichain_enable 0x1a2a0
#define BB_chn_tables_intf_addr 0x19894
#define BB_chn1_tables_intf_addr 0x1a894
#define BB_chn_tables_intf_data 0x19898
#define BB_chn1_tables_intf_data 0x1a898
#define BB_gains_min_offsets 0x19e08
#define BB_chaninfo_tab_b0 0x03200
#define BB_chaninfo_tab_b1 0x03300
#define BB_watchdog_status 0x1a7c0
#define BB_watchdog_ctrl_1 0x1a7c4
#define BB_watchdog_ctrl_2 0x1a7c8
#define BB_watchdog_status_B 0x1a7e0
#define PHY_BB_CHN_TABLES_INTF_ADDR 0x19894
#define PHY_BB_CHN_TABLES_INTF_DATA 0x19898
#define PHY_BB_CHN1_TABLES_INTF_ADDR 0x1a894
#define PHY_BB_CHN1_TABLES_INTF_DATA 0x1a898
struct priv_ctrl_ctx {
u_int32_t chaninfo_ctrl_orig;
u_int32_t gain_min_offsets_orig;
u_int32_t anyreg_start;
u_int32_t anyreg_len;
};
static struct priv_ctrl_ctx g_Priv_Dump_Ctx;
static INLINE void set_target_reg_bits(struct hif_pci_softc* hif, u_int32_t reg, u_int32_t bitmask, u_int32_t val)
{
u_int32_t value = A_PCI_READ32(hif->mem + (reg));
u_int32_t shift = 0;
value &= ~(bitmask);
while (!((bitmask >> shift) & 0x01)) {
shift++;
}
value |= (((val)<<shift)&(bitmask));
A_PCI_WRITE32(hif->mem + (reg), value);
}
static INLINE u_int32_t get_target_reg_bits(struct hif_pci_softc* hif, u_int32_t reg, u_int32_t bitmask)
{
u_int32_t value = A_PCI_READ32(hif->mem + (reg));
u_int32_t shift = 0;
while (!((bitmask >> shift) & 0x01)) {
shift++;
}
return (value>>shift)&bitmask;
}
void priv_start_cap_chaninfo(struct hif_pci_softc* hif_sc)
{
set_target_reg_bits(hif_sc, BB_chaninfo_ctrl, CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK, 1);
}
void priv_start_agc(struct hif_pci_softc* hif_sc)
{
g_Priv_Dump_Ctx.gain_min_offsets_orig = A_PCI_READ32(hif_sc->mem + BB_gains_min_offsets);
set_target_reg_bits(hif_sc, BB_gains_min_offsets, AGC_HISTORY_DUMP_MASK, 0x0f);
}
void priv_stop_agc(struct hif_pci_softc* hif_sc)
{
set_target_reg_bits(hif_sc, BB_gains_min_offsets, AGC_HISTORY_DUMP_MASK, 0);
}
void priv_dump_chaninfo(struct hif_pci_softc* hif_sc)
{
u_int32_t bw, val;
u_int32_t len, i, tmp;
u_int32_t chain_mask;
u_int32_t chain0, chain1;
chain_mask = get_target_reg_bits(hif_sc, BB_multichain_enable, MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK);
chain0 = chain_mask & 1;
chain1 = chain_mask & 2;
printk("\nChannel info dump:\n");
bw = get_target_reg_bits(hif_sc, BB_chaninfo_ctrl, CHANINFO_CTRL_CHANINFOMEM_BW_MASK);
if (bw == 0) {
len = 53;
} else if (bw == 1) {
len = 57;
} else if (bw == 2) {
len = 59*2-1;
} else {
len = 60*2+61*2;
}
/*
* each tone is 16 bit valid, write to 32bit buffer each.
* bw==0(legacy20): 53 tones.
* bw==1(ht/vht20): 57 tones.
* bw==2(ht/vht40): 59+58 tones.
* bw==3(vht80): 60*2+61*2 tones.
*/
if (chain0) {
A_PCI_WRITE32(hif_sc->mem+BB_chn_tables_intf_addr, 0x80003200);
}
if (chain1) {
A_PCI_WRITE32(hif_sc->mem+BB_chn1_tables_intf_addr, 0x80003200);
}
set_target_reg_bits(hif_sc, BB_chaninfo_ctrl, CHANINFOMEM_S2_READ_MASK, 0);
if (chain0) {
if (bw < 2) {
len = (bw == 0) ? 53 : 57;
for (i=0; i<len; i++) {
val = A_PCI_READ32(hif_sc->mem+BB_chn_tables_intf_data) & 0x0000ffff;
printk("0x%x\t",val);
if (i%4 == 0)
printk("\n");
}
} else {
len = (bw == 2) ? 59 : 60;
for (i=0; i<len; i++) {
tmp = A_PCI_READ32(hif_sc->mem+BB_chn_tables_intf_data);
printk("0x%x\t", ((tmp>>16) & 0x0000ffff));
printk("0x%x\t", (tmp & 0x0000ffff));
if (i%2 == 0)
printk("\n");
}
if (bw > 2) {
//bw == 3 for vht80
A_PCI_WRITE32(hif_sc->mem+BB_chn_tables_intf_addr, 0x80003300);
len = 61;
for (i=0; i<len; i++) {
tmp = A_PCI_READ32(hif_sc->mem+BB_chn_tables_intf_data);
printk("0x%x\t", ((tmp>>16) & 0x0000ffff));
printk("0x%x\t", (tmp & 0x0000ffff));
if (i%2 == 0)
printk("\n");
}
}
}
}
if (chain1) {
if (bw < 2) {
len = (bw == 0) ? 53 : 57;
for (i=0; i<len; i++) {
val = A_PCI_READ32(hif_sc->mem+BB_chn1_tables_intf_data) & 0x0000ffff;
printk("0x%x\t",val);
if (i%4 == 0)
printk("\n");
}
} else {
len = (bw == 2) ? 59 : 60;
for (i=0; i<len; i++) {
tmp = A_PCI_READ32(hif_sc->mem+BB_chn1_tables_intf_data);
printk("0x%x\n", (tmp>>16) & 0x0000ffff);
printk("0x%x\n", tmp & 0x0000ffff);
if (i%2 == 0)
printk("\n");
}
if (bw > 2) {
//bw == 3 for vht80
A_PCI_WRITE32(hif_sc->mem+BB_chn1_tables_intf_addr, 0x80003300);
len = 61;
for (i=0; i<len; i++) {
tmp = A_PCI_READ32(hif_sc->mem+BB_chn1_tables_intf_data);
printk("0x%x\t", ((tmp>>16) & 0x0000ffff));
printk("0x%x\t", (tmp & 0x0000ffff));
if (i%2 == 0)
printk("\n");
}
}
}
}
printk("\nChannel info dump complete\n");
}
void priv_dump_agc(struct hif_pci_softc* hif_sc)
{
int i, len = 30; //check this value for Rome and Peregrine
u_int32_t chain0, chain1, chain_mask, val;
A_target_id_t targid = TARGID(hif_sc);
A_TARGET_ACCESS_BEGIN(targid);
chain_mask = get_target_reg_bits(hif_sc, BB_multichain_enable, MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK);
chain0 = chain_mask & 1;
chain1 = chain_mask & 2;
len = len<<1; //each agc item is 64bit, total*2
priv_stop_agc(hif_sc);
set_target_reg_bits(hif_sc, BB_chaninfo_ctrl, CHANINFOMEM_S2_READ_MASK, 0);
printk("AGC history buffer dump:\n");
if (chain0) {
for (i = 0; i < len; i++) {
A_PCI_WRITE32(hif_sc->mem + PHY_BB_CHN_TABLES_INTF_ADDR,
BB_chaninfo_tab_b0 + i*4);
val = A_PCI_READ32(hif_sc->mem + PHY_BB_CHN_TABLES_INTF_DATA);
printk("0x%x\t", val);
if (i%4 == 0)
printk("\n");
}
}
if (chain1) {
for (i = 0; i < len; i++) {
A_PCI_WRITE32(hif_sc->mem + PHY_BB_CHN1_TABLES_INTF_ADDR,
BB_chaninfo_tab_b0 + i*4);
val = A_PCI_READ32(hif_sc->mem + PHY_BB_CHN1_TABLES_INTF_DATA);
printk("0x%x\t", val);
if (i%4 == 0)
printk("\n");
}
}
printk("\nAGC history buffer dump complete\n");
//restore original value
A_PCI_WRITE32(hif_sc->mem + BB_gains_min_offsets, g_Priv_Dump_Ctx.gain_min_offsets_orig);
A_TARGET_ACCESS_END(targid);
return;
}
void priv_dump_bbwatchdog(struct hif_pci_softc* hif_sc)
{
u_int32_t val;
printk("BB watchdog dump\n");
val = A_PCI_READ32(hif_sc->mem + BB_watchdog_status);
printk("0x%x\t",val);
val = A_PCI_READ32(hif_sc->mem + BB_watchdog_ctrl_1);
printk("0x%x\t",val);
val = A_PCI_READ32(hif_sc->mem + BB_watchdog_ctrl_2);
printk("0x%x\t",val);
val = A_PCI_READ32(hif_sc->mem + BB_watchdog_status_B);
printk("0x%x\n",val);
}