diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/net/wireless/rtl8192cd/8192cd_hw.c')
-rw-r--r-- | target/linux/realtek/files/drivers/net/wireless/rtl8192cd/8192cd_hw.c | 13920 |
1 files changed, 13920 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/wireless/rtl8192cd/8192cd_hw.c b/target/linux/realtek/files/drivers/net/wireless/rtl8192cd/8192cd_hw.c new file mode 100644 index 000000000..25bbe3109 --- /dev/null +++ b/target/linux/realtek/files/drivers/net/wireless/rtl8192cd/8192cd_hw.c @@ -0,0 +1,13920 @@ +/* + * Routines to access hardware + * + * $Id: 8192cd_hw.c,v 1.107.2.43 2011/01/17 13:21:01 victoryman Exp $ + * + * Copyright (c) 2009 Realtek Semiconductor Corp. + * + * 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. + */ + +#define _8192CD_HW_C_ + +#ifdef __KERNEL__ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <asm/unistd.h> +#include <linux/synclink.h> +#endif + +#include "./8192cd_cfg.h" +#include "./8192cd.h" +#include "./8192cd_hw.h" +#include "./8192cd_headers.h" +#include "./8192cd_debug.h" + +#ifdef __KERNEL__ +#ifdef __LINUX_2_6__ +#include <linux/syscalls.h> +#else +#include <linux/fs.h> +#endif +#endif + +#ifdef USE_RTL8186_SDK +#ifdef CONFIG_RTL8672 + #include <platform.h> +#else +#if defined(__LINUX_2_6__) +#include <bsp/bspchip.h> +#else + #include <asm/rtl865x/platform.h> +#endif +#endif + +#if defined(__LINUX_2_6__) && !defined(CONFIG_RTL8672) +#define _WDTCNR_ BSP_WDTCNR +#else +#define _WDTCNR_ WDTCNR +#endif +#endif + +#ifndef REG32 + #define REG32(reg) (*(volatile unsigned int *)(reg)) +#endif + +#ifdef CONFIG_NET_PCI + #define BSP_WDTCNR 0xB800311C +#endif + +#define MAX_CONFIG_FILE_SIZE (20*1024) // for 8192, added to 20k + +int rtl8192cd_fileopen(const char *filename, int flags, int mode); +void selectMinPowerIdex(struct rtl8192cd_priv *priv); +void PHY_RF6052SetOFDMTxPower(struct rtl8192cd_priv *priv, unsigned int channel); +void PHY_RF6052SetCCKTxPower(struct rtl8192cd_priv *priv, unsigned int channel); +static void rtl8192cd_ReadFwHdr(struct rtl8192cd_priv * priv); +#ifdef CONFIG_RTL_92C_SUPPORT +static int Load_92C_Firmware(struct rtl8192cd_priv *priv); +#endif + + +static unsigned int OFDMSwingTable[] = { + 0x7f8001fe, // 0, +6.0dB + 0x788001e2, // 1, +5.5dB + 0x71c001c7, // 2, +5.0dB + 0x6b8001ae, // 3, +4.5dB + 0x65400195, // 4, +4.0dB + 0x5fc0017f, // 5, +3.5dB + 0x5a400169, // 6, +3.0dB + 0x55400155, // 7, +2.5dB + 0x50800142, // 8, +2.0dB + 0x4c000130, // 9, +1.5dB + 0x47c0011f, // 10, +1.0dB + 0x43c0010f, // 11, +0.5dB + 0x40000100, // 12, +0dB + 0x3c8000f2, // 13, -0.5dB + 0x390000e4, // 14, -1.0dB + 0x35c000d7, // 15, -1.5dB + 0x32c000cb, // 16, -2.0dB + 0x300000c0, // 17, -2.5dB + 0x2d4000b5, // 18, -3.0dB + 0x2ac000ab, // 19, -3.5dB + 0x288000a2, // 20, -4.0dB + 0x26000098, // 21, -4.5dB + 0x24000090, // 22, -5.0dB + 0x22000088, // 23, -5.5dB + 0x20000080, // 24, -6.0dB + 0x1e400079, // 25, -6.5dB + 0x1c800072, // 26, -7.0dB + 0x1b00006c, // 27. -7.5dB + 0x19800066, // 28, -8.0dB + 0x18000060, // 29, -8.5dB + 0x16c0005b, // 30, -9.0dB + 0x15800056, // 31, -9.5dB + 0x14400051, // 32, -10.0dB + 0x1300004c, // 33, -10.5dB + 0x12000048, // 34, -11.0dB + 0x11000044, // 35, -11.5dB + 0x10000040, // 36, -12.0dB +}; + +unsigned int TxPwrTrk_OFDM_SwingTbl[TxPwrTrk_OFDM_SwingTbl_Len] = { + /* +6.0dB */ 0x7f8001fe, + /* +5.5dB */ 0x788001e2, + /* +5.0dB */ 0x71c001c7, + /* +4.5dB */ 0x6b8001ae, + /* +4.0dB */ 0x65400195, + /* +3.5dB */ 0x5fc0017f, + /* +3.0dB */ 0x5a400169, + /* +2.5dB */ 0x55400155, + /* +2.0dB */ 0x50800142, + /* +1.5dB */ 0x4c000130, + /* +1.0dB */ 0x47c0011f, + /* +0.5dB */ 0x43c0010f, + /* 0.0dB */ 0x40000100, + /* -0.5dB */ 0x3c8000f2, + /* -1.0dB */ 0x390000e4, + /* -1.5dB */ 0x35c000d7, + /* -2.0dB */ 0x32c000cb, + /* -2.5dB */ 0x300000c0, + /* -3.0dB */ 0x2d4000b5, + /* -3.5dB */ 0x2ac000ab, + /* -4.0dB */ 0x288000a2, + /* -4.5dB */ 0x26000098, + /* -5.0dB */ 0x24000090, + /* -5.5dB */ 0x22000088, + /* -6.0dB */ 0x20000080, + /* -6.5dB */ 0x1a00006c, + /* -7.0dB */ 0x1c800072, + /* -7.5dB */ 0x18000060, + /* -8.0dB */ 0x19800066, + /* -8.5dB */ 0x15800056, + /* -9.0dB */ 0x26c0005b, + /* -9.5dB */ 0x14400051, + /* -10.0dB */ 0x24400051, + /* -10.5dB */ 0x1300004c, + /* -11.0dB */ 0x12000048, + /* -11.5dB */ 0x11000044, + /* -12.0dB */ 0x10000040 +}; + +unsigned char TxPwrTrk_CCK_SwingTbl[TxPwrTrk_CCK_SwingTbl_Len][8] = { + /* 0.0dB */ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, + /* 0.5dB */ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, + /* 1.0dB */ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, + /* 1.5dB */ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, + /* 2.0dB */ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, + /* 2.5dB */ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, + /* 3.0dB */ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, + /* 3.5dB */ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, + /* 4.0dB */ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, + /* 4.5dB */ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, + /* 5.0dB */ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, + /* 5.5dB */ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, + /* 6.0dB */ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, + /* 6.5dB */ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, + /* 7.0dB */ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, + /* 7.5dB */ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, + /* 8.0dB */ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, + /* 8.5dB */ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, + /* 9.0dB */ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, + /* 9.5dB */ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, + /* 10.0dB */ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, + /* 10.5dB */ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, + /* 11.0dB */ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} +}; + +unsigned char TxPwrTrk_CCK_SwingTbl_CH14[TxPwrTrk_CCK_SwingTbl_Len][8] = { + /* 0.0dB */ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, + /* 0.5dB */ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, + /* 1.0dB */ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, + /* 1.5dB */ {0x2d, 0x2d, 0x27, 0x17, 0x00, 0x00, 0x00, 0x00}, + /* 2.0dB */ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, + /* 2.5dB */ {0x28, 0x28, 0x22, 0x14, 0x00, 0x00, 0x00, 0x00}, + /* 3.0dB */ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, + /* 3.5dB */ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, + /* 4.0dB */ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, + /* 4.5dB */ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, + /* 5.0dB */ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, + /* 5.5dB */ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, + /* 6.0dB */ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, + /* 6.5dB */ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, + /* 7.0dB */ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, + /* 7.5dB */ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, + /* 8.0dB */ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, + /* 8.5dB */ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, + /* 9.0dB */ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, + /* 9.5dB */ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, + /* 10.0dB */ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, + /* 10.5dB */ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, + /* 11.0dB */ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} +}; + +static unsigned char CCKSwingTable_Ch1_Ch13[][8] = { +{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0dB +{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, // 1, -0.5dB +{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 2, -1.0dB +{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, // 3, -1.5dB +{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 4, -2.0dB +{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, // 5, -2.5dB +{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 6, -3.0dB +{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, // 7, -3.5dB +{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 8, -4.0dB +{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, // 9, -4.5dB +{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 10, -5.0dB +{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, // 11, -5.5dB +{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 12, -6.0dB +{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, // 13, -6.5dB +{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 14, -7.0dB +{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, // 15, -7.5dB +{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 16, -8.0dB +{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, // 17, -8.5dB +{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 18, -9.0dB +{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 19, -9.5dB +{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 20, -10.0dB +{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 21, -10.5dB +{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 22, -11.0dB +{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, // 23, -11.5dB +{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, // 24, -12.0dB +{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, // 25, -12.5dB +{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, // 26, -13.0dB +{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, // 27, -13.5dB +{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, // 28, -14.0dB +{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, // 29, -14.5dB +{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, // 30, -15.0dB +{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, // 31, -15.5dB +{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} // 32, -16.0dB +}; + +static unsigned char CCKSwingTable_Ch14 [][8]= { +{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0dB +{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, // 1, -0.5dB +{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 2, -1.0dB +{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, // 3, -1.5dB +{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 4, -2.0dB +{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, // 5, -2.5dB +{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 6, -3.0dB +{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, // 7, -3.5dB +{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 8, -4.0dB +{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, // 9, -4.5dB +{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 10, -5.0dB +{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 11, -5.5dB +{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 12, -6.0dB +{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, // 13, -6.5dB +{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 14, -7.0dB +{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 15, -7.5dB +{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 16, -8.0dB +{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 17, -8.5dB +{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 18, -9.0dB +{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 19, -9.5dB +{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 20, -10.0dB +{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, // 21, -10.5dB +{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, // 22, -11.0dB +{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 23, -11.5dB +{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 24, -12.0dB +{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, // 25, -12.5dB +{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 26, -13.0dB +{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 27, -13.5dB +{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 28, -14.0dB +{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 29, -14.5dB +{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 30, -15.0dB +{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 31, -15.5dB +{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} // 32, -16.0dB +}; + +#ifdef ADD_TX_POWER_BY_CMD +#define ASSIGN_TX_POWER_OFFSET(offset, setting) { \ + if (setting != 0x7f) \ + offset = setting; \ +} +#endif + +#define POWER_MIN_CHECK(a,b) (((a) > (b)) ? (b) : (a)) +#define POWER_RANGE_CHECK(val) (((val) > 0x3f)? 0x3f : ((val < 0) ? 0 : val)) +#define COUNT_SIGN_OFFSET(val, oft) (((oft & 0x08) == 0x08)? (val - (0x10 - oft)) : (val + oft)) + +#ifdef HW_ANT_SWITCH +#define RXDVY_A_EN ((priv->pshare->rf_ft_var.antHw_enable && !priv->pshare->rf_ft_var.antSw_select) ? 0x80 : 0) +#define RXDVY_B_EN ((priv->pshare->rf_ft_var.antHw_enable && priv->pshare->rf_ft_var.antSw_select) ? 0x80 : 0) +#endif + +#ifdef MERGE_FW +#define VAR_MAPPING(dst,src) \ +unsigned char *data_##dst##_start = &data_##src[0]; \ +unsigned char *data_##dst##_end = &data_##src[sizeof(data_##src)]; \ + +#ifdef CONFIG_RTL_92D_SUPPORT +#include "data_PHY_REG_n.c" +#include "data_AGC_TAB_n.c" +#include "data_AGC_TAB_2G_n.c" +#include "data_AGC_TAB_5G_n.c" +#include "data_radio_a_n.c" +#include "data_radio_b_n.c" +#ifdef RTL8192D_INT_PA +#ifdef USB_POWER_SUPPORT +#include "data_radio_a_intPA_GM.c" +#include "data_radio_b_intPA_GM.c" +#else +#include "data_radio_a_intPA.c" +#include "data_radio_b_intPA.c" +#endif +#endif +//_TXPWR_REDEFINE +#ifdef HIGH_POWER_EXT_PA +#include "data_radio_a_n_92d_hp.c" +#include "data_radio_b_n_92d_hp.c" +#endif +#include "data_PHY_REG_PG.c" +#include "data_PHY_REG_PG_FCC.c" +#include "data_PHY_REG_PG_CE.c" +#ifdef TXPWR_LMT +#include "data_TXPWR_LMT.c" +#include "data_TXPWR_LMT_FCC.c" +#include "data_TXPWR_LMT_CE.c" +#endif +#include "data_PHY_REG_MP_n.c" +#include "data_MACPHY_REG.c" +#include "data_rtl8192dfw_n.c" +VAR_MAPPING(PHY_REG_n, PHY_REG_n); +VAR_MAPPING(AGC_TAB_n, AGC_TAB_n); +VAR_MAPPING(AGC_TAB_2G_n, AGC_TAB_2G_n); +VAR_MAPPING(AGC_TAB_5G_n, AGC_TAB_5G_n); +VAR_MAPPING(radio_a_n, radio_a_n); +VAR_MAPPING(radio_b_n, radio_b_n); +#ifdef RTL8192D_INT_PA +#ifdef USB_POWER_SUPPORT +VAR_MAPPING(radio_a_intPA_GM, radio_a_intPA_GM); +VAR_MAPPING(radio_b_intPA_GM, radio_b_intPA_GM); +#else +VAR_MAPPING(radio_a_intPA, radio_a_intPA); +VAR_MAPPING(radio_b_intPA, radio_b_intPA); +#endif +#endif +//_TXPWR_REDEFINE +#ifdef HIGH_POWER_EXT_PA +VAR_MAPPING(radio_a_n_92d_hp, radio_a_n_92d_hp); +VAR_MAPPING(radio_b_n_92d_hp, radio_b_n_92d_hp); +#endif +VAR_MAPPING(PHY_REG_PG, PHY_REG_PG); +VAR_MAPPING(PHY_REG_PG_FCC, PHY_REG_PG_FCC); +VAR_MAPPING(PHY_REG_PG_CE, PHY_REG_PG_CE); +#ifdef TXPWR_LMT +VAR_MAPPING(TXPWR_LMT, TXPWR_LMT); +VAR_MAPPING(TXPWR_LMT_FCC, TXPWR_LMT_FCC); +VAR_MAPPING(TXPWR_LMT_CE, TXPWR_LMT_CE); +#endif +VAR_MAPPING(PHY_REG_MP_n, PHY_REG_MP_n); +VAR_MAPPING(MACPHY_REG, MACPHY_REG); +VAR_MAPPING(rtl8192dfw_n, rtl8192dfw_n); + +#endif //CONFIG_RTL_92D_SUPPORT + +#ifdef CONFIG_RTL_92C_SUPPORT + +#ifdef TESTCHIP_SUPPORT +#include "data_AGC_TAB.c" +#include "data_PHY_REG_1T.c" +#include "data_PHY_REG_2T.c" +#include "data_radio_a_1T.c" +#include "data_radio_a_2T.c" +#include "data_radio_b_2T.c" +#include "data_rtl8192cfw.c" +#endif + +#include "data_AGC_TAB_n_92C.c" +#include "data_PHY_REG_1T_n.c" +#include "data_PHY_REG_2T_n.c" +#include "data_radio_a_2T_n.c" +#include "data_radio_b_2T_n.c" +#include "data_radio_a_1T_n.c" +#include "data_rtl8192cfwn.c" +#include "data_rtl8192cfwua.c" + + +#include "data_PHY_REG_PG_92C.c" +#include "data_MACPHY_REG_92C.c" +#include "data_PHY_REG_MP_n_92C.c" + +#include "data_AGC_TAB_n_hp.c" +#include "data_PHY_REG_2T_n_hp.c" +#include "data_radio_a_2T_n_lna.c" +#include "data_radio_b_2T_n_lna.c" +#include "data_PHY_REG_1T_n_hp.c" + +#ifdef HIGH_POWER_EXT_PA +#include "data_radio_a_2T_n_hp.c" +#include "data_radio_b_2T_n_hp.c" +#include "data_PHY_REG_PG_hp.c" +#endif + + +#define VAR_MAPPING(dst,src) \ + unsigned char *data_##dst##_start = &data_##src[0]; \ + unsigned char *data_##dst##_end = &data_##src[sizeof(data_##src)]; \ + +#ifdef TESTCHIP_SUPPORT +VAR_MAPPING(AGC_TAB, AGC_TAB); +VAR_MAPPING(PHY_REG_1T, PHY_REG_1T); +VAR_MAPPING(PHY_REG_2T, PHY_REG_2T); +VAR_MAPPING(radio_a_1T, radio_a_1T); +VAR_MAPPING(radio_a_2T, radio_a_2T); +VAR_MAPPING(radio_b_2T, radio_b_2T); +VAR_MAPPING(rtl8192cfw, rtl8192cfw); +#endif + +VAR_MAPPING(AGC_TAB_n_92C, AGC_TAB_n_92C); +VAR_MAPPING(PHY_REG_1T_n, PHY_REG_1T_n); +VAR_MAPPING(PHY_REG_2T_n, PHY_REG_2T_n); +VAR_MAPPING(radio_a_1T_n, radio_a_1T_n); +VAR_MAPPING(radio_a_2T_n, radio_a_2T_n); +VAR_MAPPING(radio_b_2T_n, radio_b_2T_n); +VAR_MAPPING(rtl8192cfw_n, rtl8192cfwn); +VAR_MAPPING(rtl8192cfw_ua, rtl8192cfwua); + +VAR_MAPPING(MACPHY_REG_92C, MACPHY_REG_92C); +VAR_MAPPING(PHY_REG_PG_92C, PHY_REG_PG_92C); +VAR_MAPPING(PHY_REG_MP_n_92C, PHY_REG_MP_n_92C); + +VAR_MAPPING(AGC_TAB_n_hp, AGC_TAB_n_hp); +VAR_MAPPING(PHY_REG_2T_n_hp, PHY_REG_2T_n_hp); +VAR_MAPPING(PHY_REG_1T_n_hp, PHY_REG_1T_n_hp); +VAR_MAPPING(radio_a_2T_n_lna, radio_a_2T_n_lna); +VAR_MAPPING(radio_b_2T_n_lna, radio_b_2T_n_lna); + +#ifdef HIGH_POWER_EXT_PA +VAR_MAPPING(radio_a_2T_n_hp, radio_a_2T_n_hp); +VAR_MAPPING(radio_b_2T_n_hp, radio_b_2T_n_hp); +VAR_MAPPING(PHY_REG_PG_hp, PHY_REG_PG_hp); +#endif +#endif //CONFIG_RTL_92C_SUPPORT +#endif + + +/*----------------------------------------------------------------------------- + * Function: PHYCheckIsLegalRfPath8192cPci() + * + * Overview: Check different RF type to execute legal judgement. If RF Path is illegal + * We will return false. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/15/2007 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +int PHYCheckIsLegalRfPath8192cPci(struct rtl8192cd_priv *priv, unsigned int eRFPath) +{ + unsigned int rtValue = TRUE; + + if (get_rf_mimo_mode(priv) == MIMO_2T2R) { + if ((eRFPath == RF92CD_PATH_A) || (eRFPath == RF92CD_PATH_B)) + rtValue = TRUE; + else + rtValue = FALSE; + } + else if (get_rf_mimo_mode(priv) == MIMO_1T1R) { + if (eRFPath == RF92CD_PATH_A) + rtValue = TRUE; + else + rtValue = FALSE; + } + else { + rtValue = FALSE; + } + + return rtValue; +} +#if defined(CONFIG_RTL_8196CS) +void setBaseAddressRegister(void) +{ + int tmp32=0, status; + while(++tmp32 < 100) { + REG32(0xb8b00004) = 0x00100007; + REG32(0xb8b10004) = 0x00100007; + REG32(0xb8b10010) = 0x18c00001; + REG32(0xb8b10018) = 0x19000004; + status = (REG32(0xb8b10010) ^ 0x18c00001) |( REG32(0xb8b10018) ^ 0x19000004); + if(!status) + break; + else { + printk("set BAR fail,%x\n", status); + printk("%x %x %x %x \n", + REG32(0xb8b00004) , REG32(0xb8b10004) ,REG32(0xb8b10010), REG32(0xb8b10018) ); + } + } ; +} +#endif +/** +* Function: phy_CalculateBitShift +* +* OverView: Get shifted position of the BitMask +* +* Input: +* u4Byte BitMask, +* +* Output: none +* Return: u4Byte Return the shift bit bit position of the mask +*/ +unsigned int phy_CalculateBitShift(unsigned int BitMask) +{ + unsigned int i; + + for (i=0; i<=31; i++) { + if (((BitMask>>i) & 0x1) == 1) + break; + } + + return (i); +} + +/** +* Function: PHY_QueryBBReg +* +* OverView: Read "sepcific bits" from BB register +* +* Input: +* PADAPTER Adapter, +* u4Byte RegAddr, //The target address to be readback +* u4Byte BitMask //The target bit position in the target address +* //to be readback +* Output: None +* Return: u4Byte Data //The readback register value +* Note: This function is equal to "GetRegSetting" in PHY programming guide +*/ +unsigned int PHY_QueryBBReg(struct rtl8192cd_priv *priv, unsigned int RegAddr, unsigned int BitMask) +{ + unsigned int ReturnValue = 0, OriginalValue, BitShift; +#ifdef CONFIG_RTL_92D_DMDP + unsigned char reg; + reg = MAC_PHY_CTRL_MP; + if (!(RTL_R8(reg) & BIT(1)) && priv->pshare->wlandev_idx == 1){ + return DMDP_PHY_QueryBBReg(0, RegAddr, BitMask); + } +#endif + + OriginalValue = RTL_R32(RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + ReturnValue = (OriginalValue & BitMask) >> BitShift; + + return (ReturnValue); +} + + +/** +* Function: PHY_SetBBReg +* +* OverView: Write "Specific bits" to BB register (page 8~) +* +* Input: +* PADAPTER Adapter, +* u4Byte RegAddr, //The target address to be modified +* u4Byte BitMask //The target bit position in the target address +* //to be modified +* u4Byte Data //The new register value in the target bit position +* //of the target address +* +* Output: None +* Return: None +* Note: This function is equal to "PutRegSetting" in PHY programming guide +*/ +void PHY_SetBBReg(struct rtl8192cd_priv *priv, unsigned int RegAddr, unsigned int BitMask, unsigned int Data) +{ + unsigned int OriginalValue, BitShift, NewValue; +#ifdef CONFIG_RTL_92D_DMDP + unsigned char reg; + reg = MAC_PHY_CTRL_MP; + + if (!(RTL_R8(reg) & BIT(1)) && priv->pshare->wlandev_idx == 1){ + DMDP_PHY_SetBBReg(0, RegAddr, BitMask, Data); + return; + } +#endif + + if (BitMask != bMaskDWord) + {//if not "double word" write + //_TXPWR_REDEFINE ?? if have original value, how to count tx power index from PG file ?? + OriginalValue = RTL_R32(RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + NewValue = ((OriginalValue & (~BitMask)) | (Data << BitShift)); + RTL_W32(RegAddr, NewValue); + } + else + RTL_W32(RegAddr, Data); + + return; +} + + + +/** +* Function: phy_RFSerialWrite +* +* OverView: Write data to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF92CD_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte Offset, //The target address to be read +* u4Byte Data //The new register Data in the target bit position +* //of the target to be read +* +* Output: None +* Return: None +* Note: Threre are three types of serial operations: (1) Software serial write +* (2) Hardware LSSI-Low Speed Serial Interface (3) Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() + * + * Note: For RF8256 only + * The total count of RTL8256(Zebra4) register is around 36 bit it only employs + * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) + * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration + * programming guide" for more details. + * Thus, we define a sub-finction for RTL8526 register address conversion + * =========================================================== + * Register Mode RegCTL[1] RegCTL[0] Note + * (Reg00[12]) (Reg00[10]) + * =========================================================== + * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) + * ------------------------------------------------------------------ +*/ +void phy_RFSerialWrite(struct rtl8192cd_priv *priv, RF92CD_RADIO_PATH_E eRFPath, unsigned int Offset, unsigned int Data) +{ + struct rtl8192cd_hw *phw = GET_HW(priv); + unsigned int DataAndAddr = 0; + BB_REGISTER_DEFINITION_T *pPhyReg = &phw->PHYRegDef[eRFPath]; + unsigned int NewOffset; + + Offset &= 0x7f; + // + // Switch page for 8256 RF IC + // + NewOffset = Offset; + + // + // Put write addr in [5:0] and write data in [31:16] + // + //DataAndAddr = (Data<<16) | (NewOffset&0x3f); + DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; // T65 RF + + // + // Write Operation + // + PHY_SetBBReg(priv, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); +} + + +/** +* Function: phy_RFSerialRead +* +* OverView: Read regster from RF chips +* +* Input: +* PADAPTER Adapter, +* RF92CD_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte Offset, //The target address to be read +* u4Byte dbg_avoid, //set bitmask in reg 0 to prevent RF switchs to debug mode +* +* Output: None +* Return: u4Byte reback value +* Note: Threre are three types of serial operations: (1) Software serial write +* (2) Hardware LSSI-Low Speed Serial Interface (3) Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() +*/ +unsigned int phy_RFSerialRead(struct rtl8192cd_priv *priv, RF92CD_RADIO_PATH_E eRFPath, unsigned int Offset, unsigned int dbg_avoid) +{ + struct rtl8192cd_hw *phw = GET_HW(priv); + unsigned int tmplong, tmplong2; + unsigned int retValue = 0; + BB_REGISTER_DEFINITION_T *pPhyReg = &phw->PHYRegDef[eRFPath]; + unsigned int NewOffset; + + // + // Make sure RF register offset is correct + // + Offset &= 0x7f; + + // + // Switch page for 8256 RF IC + // + NewOffset = Offset; + + + // For 92S LSSI Read RFLSSIRead + // For RF A/B write 0x824/82c(does not work in the future) + // We must use 0x824 for RF A and B to execute read trigger + tmplong = RTL_R32(rFPGA0_XA_HSSIParameter2); + tmplong2 = RTL_R32(pPhyReg->rfHSSIPara2); + tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | ((NewOffset<<23) | bLSSIReadEdge); //T65 RF + + RTL_W32(rFPGA0_XA_HSSIParameter2,tmplong&(~bLSSIReadEdge)); + delay_us(20); + RTL_W32(pPhyReg->rfHSSIPara2,tmplong2); + delay_us(20); + RTL_W32(rFPGA0_XA_HSSIParameter2,tmplong|bLSSIReadEdge); + delay_us(20); + RTL_W32(rFPGA0_XA_HSSIParameter2,tmplong&(~bLSSIReadEdge)); + + //Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF + if (((eRFPath == RF92CD_PATH_A) && (RTL_R32(0x820)&BIT(8))) + || ((eRFPath == RF92CD_PATH_B) && (RTL_R32(0x828)&BIT(8)))) + retValue = PHY_QueryBBReg(priv, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData); + else + retValue = PHY_QueryBBReg(priv, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); + + return retValue; +} + + +/** +* Function: PHY_QueryRFReg +* +* OverView: Query "Specific bits" to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF92CD_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte RegAddr, //The target address to be read +* u4Byte BitMask //The target bit position in the target address +* //to be read +* u4Byte dbg_avoid //set bitmask in reg 0 to prevent RF switchs to debug mode +* +* Output: None +* Return: u4Byte Readback value +* Note: This function is equal to "GetRFRegSetting" in PHY programming guide +*/ +unsigned int PHY_QueryRFReg(struct rtl8192cd_priv *priv, RF92CD_RADIO_PATH_E eRFPath, + unsigned int RegAddr, unsigned int BitMask, unsigned int dbg_avoid) +{ + unsigned int Original_Value, Readback_Value, BitShift; +#ifdef CONFIG_RTL_92D_DMDP + unsigned char reg; + reg = MAC_PHY_CTRL_MP; + if (!(RTL_R8(reg) & BIT(1)) && priv->pshare->wlandev_idx == 1){ + return DMDP_PHY_QueryRFReg(0,eRFPath,RegAddr,BitMask,dbg_avoid); + } +#endif + + Original_Value = phy_RFSerialRead(priv, eRFPath, RegAddr, dbg_avoid); + BitShift = phy_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + + return (Readback_Value); +} + + +/** +* Function: PHY_SetRFReg +* +* OverView: Write "Specific bits" to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF92CD_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte RegAddr, //The target address to be modified +* u4Byte BitMask //The target bit position in the target address +* //to be modified +* u4Byte Data //The new register Data in the target bit position +* //of the target address +* +* Output: None +* Return: None +* Note: This function is equal to "PutRFRegSetting" in PHY programming guide +*/ +#ifdef CONFIG_RTL_KERNEL_MIPS16_WLAN +__NOMIPS16 +#endif +void PHY_SetRFReg(struct rtl8192cd_priv *priv, RF92CD_RADIO_PATH_E eRFPath, unsigned int RegAddr, + unsigned int BitMask, unsigned int Data) +{ + unsigned int Original_Value, BitShift, New_Value; + unsigned long flags; +#ifdef CONFIG_RTL_92D_DMDP + unsigned char reg; + reg = MAC_PHY_CTRL_MP; + + if (!(RTL_R8(reg) & BIT(1)) && priv->pshare->wlandev_idx == 1){ + DMDP_PHY_SetRFReg(0, eRFPath, RegAddr, BitMask, Data); + return; + } +#endif + + SAVE_INT_AND_CLI(flags); + + if (BitMask != bMask20Bits) { + Original_Value = phy_RFSerialRead(priv, eRFPath, RegAddr, 1); + BitShift = phy_CalculateBitShift(BitMask); + New_Value = ((Original_Value & (~BitMask)) | (Data << BitShift)); + + phy_RFSerialWrite(priv, eRFPath, RegAddr, New_Value); + } else { + phy_RFSerialWrite(priv, eRFPath, RegAddr, Data); + } + + RESTORE_INT(flags); +} + + +static int is_hex(char s) +{ + if (( s >= '0' && s <= '9') || ( s >= 'a' && s <= 'f') || (s >= 'A' && s <= 'F') || (s == 'x' || s == 'X')) + return 1; + else + return 0; +} + + +static int is_item(char s) +{ + if (s=='t' || s=='a' || s=='b' || s=='l' || s=='e' || s==':') + return 1; + else + return 0; +} + +static unsigned char *get_digit(unsigned char **data) +{ + unsigned char *buf=*data; + int i=0; + + while(buf[i] && ((buf[i] == ' ') || (buf[i] == '\t'))) + i++; + *data = &buf[i]; + + while(buf[i]) { + if ((buf[i] == ' ') || (buf[i] == '\t')) { + buf[i] = '\0'; + break; + } + if (buf[i]>='A' && buf[i]<='Z') + buf[i] += 32; + + if (!is_hex(buf[i])&&!is_item(buf[i])) + return NULL; + i++; + } + if (i == 0) + return NULL; + else + return &buf[i+1]; +} + +#ifdef TXPWR_LMT +static unsigned char *get_digit_dot(unsigned char **data) +{ + unsigned char *buf=*data; + int i=0; + + while(buf[i] && ((buf[i] == ' ') || (buf[i] == '\t'))) + i++; + + *data = &buf[i]; + + while(buf[i]) { + if(buf[i] == '.'){ + while((buf[i]==' ') ||(buf[i]=='\t') || (buf[i]=='\0') || (buf[i]=='/')) + i++; + + i++; + } + + if ((buf[i] == ' ') || (buf[i] == '\t')) { + buf[i] = '\0'; + break; + } + if (buf[i]>='A' && buf[i]<='Z') + buf[i] += 32; + + if (!is_hex(buf[i])&&!is_item(buf[i])) + return NULL; + i++; + } + if (i == 0) + return NULL; + else + { + return &buf[i+1]; + } +} + + +static int get_chnl_lmt_dot(unsigned char *line_head, unsigned int *ch_start, unsigned int *ch_end, unsigned int *limit, unsigned int *target) +{ + unsigned char *next, *next2; + int base, idx; + int num=0; + unsigned char *ch; + extern int _atoi(char *s, int base); + + *ch_start = *ch_start = '\0'; + + // remove comments + ch = line_head; + while (1) { + if ((*ch == '\0') || (*ch == '\n') || (*ch == '\r')) + break; + else if (*ch == '/') { + *ch = '\0'; + break; + } else { + ch++; + } + } + + next = get_digit_dot(&line_head); + if (next == NULL) + return num; + num++; + + if (!memcmp(line_head,"table",5)) { + *ch_start = 0; + *ch_end = 0; + } else { + char *s; + int format = 0; + int idx2; + + if ((!memcmp(line_head, "0x", 2)) || (!memcmp(line_head, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + idx2 = idx; + while (line_head[idx2]!='\0'){ + //printk("(%c)",line_head[idx2]); + if (line_head[idx2] == ':'){ + line_head[idx2] = '\0'; + format = 1; // format - start:end + break; + } + idx2++; + } + *ch_start = _atoi((char *)&line_head[idx], base); + if (format==0){ + *ch_end = *ch_start; + }else{ + *ch_end = _atoi((char *)&line_head[idx2+1], base); + } + } + + + *limit = 0; + if (next) { + if (!(next2 = get_digit_dot(&next))) + return num; + num++; + + base = 10; + idx = 0; + + if( (*ch_start == 0) && (*ch_end == 0) ) + *limit = _atoi((char *)&next[idx], base); //In this condition, 'limit' represents "# of table" + else + *limit = _convert_2_pwr_dot((char *)&next[idx], base); + } + + + *target = 0; + if (next2) { + if (!get_digit_dot(&next2)) + return num; + num++; + + base = 10; + idx = 0; + + *target = _convert_2_pwr_dot((char *)&next2[idx], base); + } + + + return num; +} +#endif + +static int get_offset_val(unsigned char *line_head, unsigned int *u4bRegOffset, unsigned int *u4bRegValue) +{ + unsigned char *next; + int base, idx; + int num=0; + unsigned char *ch; + extern int _atoi(char *s, int base); + + *u4bRegOffset = *u4bRegValue = '\0'; + + ch = line_head; + while (1) { + if ((*ch == '\0') || (*ch == '\n') || (*ch == '\r')) + break; + else if (*ch == '/') { + *ch = '\0'; + break; + } else { + ch++; + } + } + + next = get_digit(&line_head); + if (next == NULL) + return num; + num++; + if ((!memcmp(line_head, "0x", 2)) || (!memcmp(line_head, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + *u4bRegOffset = _atoi((char *)&line_head[idx], base); + + if (next) { + if (!get_digit(&next)) + return num; + num++; + if ((!memcmp(next, "0x", 2)) || (!memcmp(next, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + *u4bRegValue = _atoi((char *)&next[idx], base); + } + else + *u4bRegValue = 0; + + return num; +} + + +static int get_offset_mask_val(unsigned char *line_head, unsigned int *u4bRegOffset, unsigned int *u4bMask, unsigned int *u4bRegValue) +{ + unsigned char *next, *n1; + int base, idx; + int num=0; + unsigned char *ch; + extern int _atoi(char *s, int base); + + *u4bRegOffset = *u4bRegValue = *u4bMask = '\0'; + + ch = line_head; + while (1) { + if ((*ch == '\0') || (*ch == '\n') || (*ch == '\r')) + break; + else if (*ch == '/') { + *ch = '\0'; + break; + } else { + ch++; + } + } + + next = get_digit(&line_head); + if (next == NULL) + return num; + num++; + if ((!memcmp(line_head, "0x", 2)) || (!memcmp(line_head, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + *u4bRegOffset = _atoi((char *)&line_head[idx], base); + + if (next) { + n1 = get_digit(&next); + if (n1 == NULL) + return num; + num++; + if ((!memcmp(next, "0x", 2)) || (!memcmp(next, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + *u4bMask = _atoi((char *)&next[idx], base); + + if (n1) { + if (!get_digit(&n1)) + return num; + num++; + if ((!memcmp(n1, "0x", 2)) || (!memcmp(n1, "0X", 2))) { + base = 16; + idx = 2; + } + else { + base = 10; + idx = 0; + } + *u4bRegValue = _atoi((char *)&n1[idx], base); + } + else + *u4bRegValue = 0; + } + else + *u4bMask = 0; + + return num; +} + + +unsigned char *get_line(unsigned char **line) +{ + unsigned char *p=*line; + + while (*p && ((*p == '\n') || (*p == '\r'))) + p++; + + if (*p == '\0') { + *line = NULL; + return NULL; + } + *line = p; + + while (*p && (*p != '\n') && (*p != '\r')) + p++; + + *p = '\0'; + return p+1; +} + +#if defined(CONFIG_RTL_92D_SUPPORT) && defined(TXPWR_LMT) + +static int ch2idx(int ch) +{ + int val=-1; + // |1~14|36, 38, 40, ..., 64|100, 102, ..., 140|149, 151, ..., 165| + if (ch<=14) + val = ch-1; + else if (ch<=64) + val = ((ch-36)>>1)+14; + else if (ch<=140) + val = ((ch-100)>>1)+29; + else if (ch<=165) + val = ((ch-149)>>1)+50; + + return val; +} + +void find_pwr_limit(struct rtl8192cd_priv *priv) +{ + int tmp = ch2idx(priv->pshare->working_channel); + int tmp2 = ch2idx(priv->pmib->dot11RFEntry.dot11channel); //for CCK, OFDM & 20M bw + + //printk("tmp %d tmp2 %d working_channel %d dot11channel %d\n", + //tmp, tmp2, priv->pshare->working_channel, priv->pmib->dot11RFEntry.dot11channel); + + if ((tmp>=0) && (tmp2>=0)) { + priv->pshare->txpwr_lmt_CCK = priv->pshare->ch_pwr_lmtCCK[tmp2]; + priv->pshare->txpwr_lmt_OFDM = priv->pshare->ch_pwr_lmtOFDM[tmp2]; + priv->pshare->tgpwr_CCK = priv->pshare->ch_tgpwr_CCK[tmp2]; + priv->pshare->tgpwr_OFDM = priv->pshare->ch_tgpwr_OFDM[tmp2]; + + if (priv->pshare->is_40m_bw){ + priv->pshare->txpwr_lmt_HT1S = priv->pshare->ch_pwr_lmtHT40_1S[tmp]; + priv->pshare->txpwr_lmt_HT2S = priv->pshare->ch_pwr_lmtHT40_2S[tmp]; + priv->pshare->tgpwr_HT1S = priv->pshare->ch_tgpwr_HT40_1S[tmp]; + priv->pshare->tgpwr_HT2S = priv->pshare->ch_tgpwr_HT40_2S[tmp]; + } else { //if 20M bw, tmp == tmp2 ?? + priv->pshare->txpwr_lmt_HT1S = priv->pshare->ch_pwr_lmtHT20_1S[tmp2]; + priv->pshare->txpwr_lmt_HT2S = priv->pshare->ch_pwr_lmtHT20_2S[tmp2]; + priv->pshare->tgpwr_HT1S = priv->pshare->ch_tgpwr_HT20_1S[tmp2]; + priv->pshare->tgpwr_HT2S = priv->pshare->ch_tgpwr_HT20_2S[tmp2]; + } + } else { + priv->pshare->txpwr_lmt_CCK = 0; + priv->pshare->txpwr_lmt_OFDM = 0; + priv->pshare->txpwr_lmt_HT1S = 0; + priv->pshare->txpwr_lmt_HT2S = 0; + + printk("Cannot map current working channel to find power limit!\n"); + } + + //printk("txpwr_lmt_OFDM %d tgpwr_OFDM %d\n", priv->pshare->txpwr_lmt_OFDM, priv->pshare->tgpwr_OFDM); + +} + + +int PHY_ConfigTXLmtWithParaFile(struct rtl8192cd_priv *priv) +{ + int read_bytes, num, len=0; + unsigned int ch_start, ch_end, limit, target; + unsigned char *mem_ptr, *line_head, *next_head; + int idx=0, tbl_idx[6], set_en=0, type; + + priv->pshare->txpwr_lmt_CCK = 0; + priv->pshare->txpwr_lmt_OFDM = 0; + priv->pshare->txpwr_lmt_HT1S = 0; + priv->pshare->txpwr_lmt_HT2S = 0; + + struct TxPwrLmtTable *reg_table = (struct TxPwrLmtTable *)priv->pshare->txpwr_lmt_buf; + +#ifndef MERGE_FW + int fd=0; + mm_segment_t old_fs; + unsigned char *pFileName = "/usr/rtl8192Pci/TXPWR_LMT.txt"; +#ifndef CONFIG_X86 + extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +#endif +#endif + + if (GET_CHIP_VER(priv)!=VERSION_8192D) { + printk("[%s]NOT support! TXPWR_LMT is for RTL8192D ONLY!\n",__FUNCTION__); + return -1; + } + + if((mem_ptr = (unsigned char *)kmalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC)) == NULL) { + printk("PHY_ConfigMACWithParaFile(): not enough memory\n"); + return -1; + } + + + tbl_idx[0] = 1; + tbl_idx[1] = 2; + tbl_idx[2] = 3; + tbl_idx[3] = 4; + tbl_idx[4] = 5; + tbl_idx[5] = 6; + + + DEBUG_INFO("regdomain=%d tbl_idx=%d,%d\n",priv->pmib->dot11StationConfigEntry.dot11RegDomain, tbl_idx[0],tbl_idx[1]); + + + memset(mem_ptr, 0, MAX_CONFIG_FILE_SIZE); // clear memory + +#ifdef MERGE_FW + printk("[%s][TXPWR_LMT]\n",__FUNCTION__); + + if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_FCC){ + //printk("\nFCC LMT!!!\n"); + next_head = data_TXPWR_LMT_FCC_start; + read_bytes = (int)(data_TXPWR_LMT_FCC_end - data_TXPWR_LMT_FCC_start); + } + else if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_ETSI){ + //printk("\nCE LMT!!!\n"); + next_head = data_TXPWR_LMT_CE_start; + read_bytes = (int)(data_TXPWR_LMT_CE_end - data_TXPWR_LMT_CE_start); + } + else{ + //printk("\nOther !!!\n"); + next_head = data_TXPWR_LMT_start; + read_bytes = (int)(data_TXPWR_LMT_end - data_TXPWR_LMT_start); + } + + memcpy(mem_ptr, next_head, read_bytes); +#else + +old_fs = get_fs(); +set_fs(KERNEL_DS); + +#if defined(CONFIG_X86) +if ((fd = rtl8192cd_fileopen(pFileName, O_RDONLY, 0)) < 0) +#else +if ((fd = sys_open(pFileName, O_RDONLY, 0)) < 0) +#endif +{ + printk("PHY_ConfigMACWithParaFile(): cannot open %s\n", pFileName); + set_fs(old_fs); + kfree(mem_ptr); + return -1; +} + +read_bytes = sys_read(fd, mem_ptr, MAX_CONFIG_FILE_SIZE); +sys_close(fd); +set_fs(old_fs); +#endif // MERGE_FW + + next_head = mem_ptr; + while (1) { + line_head = next_head; + next_head = get_line(&line_head); + + if (line_head == NULL) + break; + + if (line_head[0] == '/') + continue; + + num = get_chnl_lmt_dot(line_head, &ch_start, &ch_end, &limit, &target); + + if (num > 0) { + reg_table[len].start = ch_start; + reg_table[len].end = ch_end; + reg_table[len].limit = limit; + reg_table[len].target = target; + + len++; + if ((len * sizeof(struct TxPwrLmtTable)) > MAC_REG_SIZE) + break; + } + } + + reg_table[len].start = 0xff; + + kfree(mem_ptr); + + if ((len * sizeof(struct TxPwrLmtTable)) > MAC_REG_SIZE) { + printk("TXPWR_LMT table buffer not large enough!\n"); + return -1; + } + + num = 0; + while (1) { + ch_start = reg_table[num].start; + ch_end = reg_table[num].end; + limit = reg_table[num].limit; + target = reg_table[num].target; + + //printk(">> %d-%d-%d-%d\n",ch_start,ch_end,limit,target); + if (ch_start == 0xff) + break; + + if (ch_start== 0 && ch_end == 0){ + if (limit == tbl_idx[0]) { + set_en=1; + type = 0; + memset(priv->pshare->ch_pwr_lmtCCK, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_CCK, 0, SUPPORT_CH_NUM); + }else if (limit == tbl_idx[1]) { + set_en=1; + type = 1; + memset(priv->pshare->ch_pwr_lmtOFDM, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_OFDM, 0, SUPPORT_CH_NUM); + } else if (limit == tbl_idx[2]) { + set_en=1; + type = 2; + memset(priv->pshare->ch_pwr_lmtHT20_1S, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_HT20_1S, 0, SUPPORT_CH_NUM); + } else if (limit == tbl_idx[3]) { + set_en=1; + type = 3; + memset(priv->pshare->ch_pwr_lmtHT20_2S, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_HT20_2S, 0, SUPPORT_CH_NUM); + } else if (limit == tbl_idx[4]) { + set_en=1; + type = 4; + memset(priv->pshare->ch_pwr_lmtHT40_1S, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_HT40_1S, 0, SUPPORT_CH_NUM); + } else if (limit == tbl_idx[5]) { + set_en=1; + type = 5; + memset(priv->pshare->ch_pwr_lmtHT40_2S, 0, SUPPORT_CH_NUM); + memset(priv->pshare->ch_tgpwr_HT40_2S, 0, SUPPORT_CH_NUM); + } else { + set_en = 0; + } + } + + if (set_en && ch_start){ + int j; + for (j=ch2idx(ch_start);j<=ch2idx(ch_end);j++){ + if (j<0||j>=SUPPORT_CH_NUM){ + panic_printk("channel out of bound!!\n"); + break; + } + + if (type == 0){ + priv->pshare->ch_pwr_lmtCCK[j] = limit; + priv->pshare->ch_tgpwr_CCK[j] = target; + }else if (type == 1){ + priv->pshare->ch_pwr_lmtOFDM[j] = limit; + priv->pshare->ch_tgpwr_OFDM[j] = target; + }else if (type==2){ + priv->pshare->ch_pwr_lmtHT20_1S[j] = limit; + priv->pshare->ch_tgpwr_HT20_1S[j] = target; + }else if (type==3){ + priv->pshare->ch_pwr_lmtHT20_2S[j] = limit; + priv->pshare->ch_tgpwr_HT20_2S[j] = target; + }else if (type==4){ + priv->pshare->ch_pwr_lmtHT40_1S[j] = limit; + priv->pshare->ch_tgpwr_HT40_1S[j] = target; + }else if (type==5){ + priv->pshare->ch_pwr_lmtHT40_2S[j] = limit; + priv->pshare->ch_tgpwr_HT40_2S[j] = target; + } + } + } + + num++; + } + + return 0; +} + +#endif + +//_TXPWR_REDEFINE +void Read_PG_File(struct rtl8192cd_priv *priv, int reg_file, int table_number, + char *MCSTxAgcOffset_A, char *MCSTxAgcOffset_B, char *OFDMTxAgcOffset_A, + char *OFDMTxAgcOffset_B, char *CCKTxAgc_A, char *CCKTxAgc_B) +{ + int read_bytes=0, num, len=0; + unsigned int u4bRegOffset, u4bRegValue, u4bRegMask; + unsigned char *mem_ptr, *line_head, *next_head=NULL; + struct PhyRegTable *phyreg_table=NULL; + struct MacRegTable *macreg_table=NULL; + unsigned short max_len=0; + int file_format=TWO_COLUMN; +#ifndef MERGE_FW + int fd=0; + mm_segment_t old_fs; + unsigned char *pFileName=NULL; + extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + int idx=0, pg_tbl_idx=table_number, write_en=0; +#endif + + int tmp_rTxAGC_A_CCK1_Mcs32= 0; + int tmp_rTxAGC_B_CCK5_1_Mcs32 = 0; + int prev_reg = 0; + + //printk("PHYREG_PG = %d\n", PHYREG_PG); + +#ifdef MERGE_FW + + if (reg_file == PHYREG_PG) { + //printk("[%s][PHY_REG_PG]\n",__FUNCTION__); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D){ + + if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_FCC){ + //printk("\nFCC PG!!!\n"); + next_head = data_PHY_REG_PG_FCC_start; + read_bytes = (int)(data_PHY_REG_PG_FCC_end - data_PHY_REG_PG_FCC_start); + } + else if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_ETSI){ + //printk("\nCE PG!!!\n"); + next_head = data_PHY_REG_PG_CE_start; + read_bytes = (int)(data_PHY_REG_PG_CE_end - data_PHY_REG_PG_CE_start); + } + else{ + //printk("\nOTHER PG!!!\n"); + next_head = data_PHY_REG_PG_start; + read_bytes = (int)(data_PHY_REG_PG_end - data_PHY_REG_PG_start); + } + + } +#endif //CONFIG_RTL_92D_SUPPORT + +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ +#ifdef HIGH_POWER_EXT_PA + if( priv->pshare->rf_ft_var.use_ext_pa) { + //printk("[%s][data_PHY_REG_PG_hp]\n", __FUNCTION__); + next_head = data_PHY_REG_PG_hp_start; + read_bytes = (int)(data_PHY_REG_PG_hp_end - data_PHY_REG_PG_hp_start); + + } else +#endif + { + //printk("[%s][data_PHY_REG_PG_92C]\n", __FUNCTION__); + next_head = data_PHY_REG_PG_92C_start; + read_bytes = (int)(data_PHY_REG_PG_92C_end - data_PHY_REG_PG_92C_start); + } + } +#endif //CONFIG_RTL_92C_SUPPORT + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + max_len = PHY_REG_PG_SIZE; + file_format = THREE_COLUMN; + } + +#ifdef CONFIG_RTL_92D_SUPPORT + else if (reg_file == PHYREG) { + if (GET_CHIP_VER(priv)==VERSION_8192D) { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; + //printk("[%s][PHY_REG_n]\n",__FUNCTION__); + next_head = data_PHY_REG_n_start; + read_bytes = (int)(data_PHY_REG_n_end - data_PHY_REG_n_start); + max_len = PHY_REG_SIZE; + } + } +#endif // CONFIG_RTL_92D_SUPPORT + +#ifdef MP_TEST + else if (reg_file == PHYREG_MP) { +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_mp_buf; + //printk("[%s][PHY_REG_MP_n]\n",__FUNCTION__); + next_head = data_PHY_REG_MP_n_start; + read_bytes = (int)(data_PHY_REG_MP_n_end - data_PHY_REG_MP_n_start); + max_len = PHY_REG_SIZE; + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_mp_buf; + next_head = data_PHY_REG_MP_n_92C_start; + read_bytes = (int)(data_PHY_REG_MP_n_92C_end - data_PHY_REG_MP_n_92C_start); + max_len = PHY_REG_SIZE; + } +#endif + } +#endif + +#else // !MERGE_FW + + switch (reg_file) { + case PHYREG_PG: + pFileName = "/usr/rtl8192Pci/PHY_REG_PG.txt"; + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + max_len = PHY_REG_PG_SIZE; + file_format = THREE_COLUMN; + break; + } +#endif // MERGE_FW + + { + if((mem_ptr = (unsigned char *)kmalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC)) == NULL) { + printk("PHY_ConfigBBWithParaFile(): not enough memory\n"); + return -1; + } + + memset(mem_ptr, 0, MAX_CONFIG_FILE_SIZE); // clear memory + +#ifdef MERGE_FW + memcpy(mem_ptr, next_head, read_bytes); +#else + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if ((fd = sys_open(pFileName, O_RDONLY, 0)) < 0) { + printk("PHY_ConfigBBWithParaFile(): cannot open %s\n", pFileName); + set_fs(old_fs); + kfree(mem_ptr); + return -1; + } + + read_bytes = sys_read(fd, mem_ptr, MAX_CONFIG_FILE_SIZE); + sys_close(fd); + set_fs(old_fs); +#endif // MERGE_FW + + next_head = mem_ptr; + while (1) { + line_head = next_head; + next_head = get_line(&line_head); + if (line_head == NULL) + break; + + if (line_head[0] == '/') + continue; + + if (file_format == TWO_COLUMN) { + num = get_offset_val(line_head, &u4bRegOffset, &u4bRegValue); + if (num > 0) { + phyreg_table[len].offset = u4bRegOffset; + phyreg_table[len].value = u4bRegValue; + len++; +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + //if ((len&0x7ff)==0) + //REG32(BSP_WDTCNR) |= 1 << 23; +#endif + if (u4bRegOffset == 0xff) + break; + if ((len * sizeof(struct PhyRegTable)) > max_len) + break; + } + } + else { + num = get_offset_mask_val(line_head, &u4bRegOffset, &u4bRegMask ,&u4bRegValue); + if (num > 0) { + macreg_table[len].offset = u4bRegOffset; + macreg_table[len].mask = u4bRegMask; + macreg_table[len].value = u4bRegValue; + len++; + if (u4bRegOffset == 0xff) + break; + if ((len * sizeof(struct MacRegTable)) > max_len) + break; +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + //if ((len&0x7ff)==0) + //REG32(BSP_WDTCNR) |= 1 << 23; +#endif + } + } + } + + kfree(mem_ptr); + + if ((len * sizeof(struct PhyRegTable)) > max_len) { +#ifdef MERGE_FW + printk("PHY REG table buffer not large enough!\n"); +#else + printk("PHY REG table buffer not large enough! (%s)\n", pFileName); +#endif + return -1; + } + } + + num = 0; + while (1) { + if (file_format == THREE_COLUMN) { + u4bRegOffset = macreg_table[num].offset; + u4bRegValue = macreg_table[num].value; + u4bRegMask = macreg_table[num].mask; + } + else { + u4bRegOffset = phyreg_table[num].offset; + u4bRegValue = phyreg_table[num].value; + } + + if (u4bRegOffset == 0xff) + break; + else if (file_format == THREE_COLUMN){ + +#ifdef CONFIG_RTL_92D_SUPPORT + if (reg_file == PHYREG_PG && GET_CHIP_VER(priv)==VERSION_8192D) { + if (u4bRegOffset==0xe00){ + if (idx == pg_tbl_idx) + write_en=1; + idx++; + } + if (write_en){ + //PHY_SetBBReg(priv, u4bRegOffset, u4bRegMask, u4bRegValue); + //printk("3C- 92D %x %x %x \n", u4bRegOffset, u4bRegMask, u4bRegValue); + if(u4bRegMask != bMaskDWord) + { + int BitShift = phy_CalculateBitShift(u4bRegMask); + u4bRegValue = (u4bRegValue << BitShift); + } + + //=== PATH A === + + if(u4bRegOffset == rTxAGC_A_Mcs03_Mcs00) + *(unsigned int *)(&MCSTxAgcOffset_A[0]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_A_Mcs07_Mcs04) + *(unsigned int *)(&MCSTxAgcOffset_A[4]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_A_Mcs11_Mcs08) + *(unsigned int *)(&MCSTxAgcOffset_A[8]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_A_Mcs15_Mcs12) + *(unsigned int *)(&MCSTxAgcOffset_A[12]) = cpu_to_be32(u4bRegValue); + + if(u4bRegOffset == rTxAGC_A_Rate18_06) + *(unsigned int *)(&OFDMTxAgcOffset_A[0]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_A_Rate54_24) + *(unsigned int *)(&OFDMTxAgcOffset_A[4]) = cpu_to_be32(u4bRegValue); + + if(u4bRegOffset == rTxAGC_A_CCK1_Mcs32) + { + tmp_rTxAGC_A_CCK1_Mcs32 = ((u4bRegValue & 0xff00) >> phy_CalculateBitShift(0xff00)); + prev_reg = rTxAGC_A_CCK1_Mcs32; + } + + if(u4bRegOffset == rTxAGC_A_CCK11_2_B_CCK11) + { + if(prev_reg == rTxAGC_A_CCK1_Mcs32) + { + //printk("\n%x %x %x\n", tmp_rTxAGC_A_CCK1_Mcs32, u4bRegValue, cpu_to_be32((u4bRegValue & 0xffffff00) | tmp_rTxAGC_A_CCK1_Mcs32)); + + *(unsigned int *)(&CCKTxAgc_A[0]) = + cpu_to_be32((u4bRegValue & 0xffffff00) | tmp_rTxAGC_A_CCK1_Mcs32); + } + } + + //=== PATH B === + + if(u4bRegOffset == rTxAGC_B_Mcs03_Mcs00) + *(unsigned int *)(&MCSTxAgcOffset_B[0]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_B_Mcs07_Mcs04) + *(unsigned int *)(&MCSTxAgcOffset_B[4]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_B_Mcs11_Mcs08) + *(unsigned int *)(&MCSTxAgcOffset_B[8]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_B_Mcs15_Mcs12) + *(unsigned int *)(&MCSTxAgcOffset_B[12]) = cpu_to_be32(u4bRegValue); + + if(u4bRegOffset == rTxAGC_B_Rate18_06) + *(unsigned int *)(&OFDMTxAgcOffset_B[0]) = cpu_to_be32(u4bRegValue); + if(u4bRegOffset == rTxAGC_B_Rate54_24) + *(unsigned int *)(&OFDMTxAgcOffset_B[4]) = cpu_to_be32(u4bRegValue); + + if(u4bRegOffset == rTxAGC_B_CCK5_1_Mcs32) + { + tmp_rTxAGC_B_CCK5_1_Mcs32 = u4bRegValue; + prev_reg = rTxAGC_B_CCK5_1_Mcs32; + } + + if(u4bRegOffset == rTxAGC_A_CCK11_2_B_CCK11) + { + if(prev_reg == rTxAGC_B_CCK5_1_Mcs32) + { + //printk("\n%x %x %x\n", tmp_rTxAGC_B_CCK5_1_Mcs32, u4bRegValue, cpu_to_be32((u4bRegValue << 24) | (tmp_rTxAGC_B_CCK5_1_Mcs32 >> 8))); + *(unsigned int *)(&CCKTxAgc_B[0]) = cpu_to_be32((u4bRegValue << 24) | (tmp_rTxAGC_B_CCK5_1_Mcs32 >> 8)); + } + } + + if (u4bRegOffset==0x868){ + write_en = 0; + break; + } + } + }else +#endif + { + //PHY_SetBBReg(priv, u4bRegOffset, u4bRegMask, u4bRegValue); + //printk("3C - 92C %x %x %x \n", u4bRegOffset, u4bRegMask, u4bRegValue); + } + } + else + { + //printk("Not 3C - %x %x %x \n", u4bRegOffset, bMaskDWord, u4bRegValue); + //PHY_SetBBReg(priv, u4bRegOffset, bMaskDWord, u4bRegValue); + } + num++; + } + + return 0; +} + + + +/*----------------------------------------------------------------------------- + * Function: PHY_ConfigBBWithParaFile() + * + * Overview: This function read BB parameters from general file format, and do register + * Read/Write + * + * Input: PADAPTER Adapter + * ps1Byte pFileName + * + * Output: NONE + * + * Return: RT_STATUS_SUCCESS: configuration file exist + * + *---------------------------------------------------------------------------*/ +int PHY_ConfigBBWithParaFile(struct rtl8192cd_priv *priv, int reg_file) +{ + int read_bytes=0, num, len=0; + unsigned int u4bRegOffset, u4bRegValue, u4bRegMask; + unsigned char *mem_ptr, *line_head, *next_head=NULL; + struct PhyRegTable *phyreg_table=NULL; + struct MacRegTable *macreg_table=NULL; + unsigned short max_len=0; + int file_format=TWO_COLUMN; +#ifndef MERGE_FW + int fd=0; + mm_segment_t old_fs; + unsigned char *pFileName=NULL; + extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + int idx=0, pg_tbl_idx=BGN_2040_ALL, write_en=0; +#endif + +#ifdef MERGE_FW + if (reg_file == AGCTAB) { + phyreg_table = (struct PhyRegTable *)priv->pshare->agc_tab_buf; +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY && priv->pshare->wlandev_idx==1) { + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + //printk("[%s][AGC_TAB_5G_n]\n",__FUNCTION__); + next_head = data_AGC_TAB_5G_n_start; + read_bytes = (int)(data_AGC_TAB_5G_n_end - data_AGC_TAB_5G_n_start); + } else { + //printk("[%s][AGC_TAB_2G_n]\n",__FUNCTION__); + next_head = data_AGC_TAB_2G_n_start; + read_bytes = (int)(data_AGC_TAB_2G_n_end - data_AGC_TAB_2G_n_start); + } + }else +#endif + { + //printk("[%s][AGC_TAB_n]\n",__FUNCTION__); + next_head = data_AGC_TAB_n_start; + read_bytes = (int)(data_AGC_TAB_n_end - data_AGC_TAB_n_start); + } + } +#endif //CONFIG_RTL_92D_SUPPORT + +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) { + next_head = data_AGC_TAB_start; + read_bytes = (int)(data_AGC_TAB_end - data_AGC_TAB_start); + } else +#endif + if (priv->pshare->rf_ft_var.use_ext_lna +#ifdef HIGH_POWER_EXT_PA + || priv->pshare->rf_ft_var.use_ext_pa +#endif + ) { + next_head = data_AGC_TAB_n_hp_start; + read_bytes = (int)(data_AGC_TAB_n_hp_end - data_AGC_TAB_n_hp_start); + } + else + { + next_head = data_AGC_TAB_n_92C_start; + read_bytes = (int)(data_AGC_TAB_n_92C_end - data_AGC_TAB_n_92C_start); + } + } +#endif + max_len = AGC_TAB_SIZE; + } + else if (reg_file == PHYREG_PG) { + //printk("[%s][PHY_REG_PG]\n",__FUNCTION__); +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D){ + + if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_FCC){ + //printk("\nFCC PG!!!\n"); + next_head = data_PHY_REG_PG_FCC_start; + read_bytes = (int)(data_PHY_REG_PG_FCC_end - data_PHY_REG_PG_FCC_start); + } + else if(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_ETSI){ + //printk("\nCE PG!!!\n"); + next_head = data_PHY_REG_PG_CE_start; + read_bytes = (int)(data_PHY_REG_PG_CE_end - data_PHY_REG_PG_CE_start); + } + else{ + //printk("\nOTHER PG!!!\n"); + next_head = data_PHY_REG_PG_start; + read_bytes = (int)(data_PHY_REG_PG_end - data_PHY_REG_PG_start); + } + +//_TXPWR_REDEFINE ?? Why 5G no need working channel ?? +//_TXPWR_REDEFINE in MP Tool, 3 Groups: 36-99 100-148 149-165 + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G){ + if (priv->pshare->is_40m_bw == 0){ + if (priv->pmib->dot11RFEntry.dot11channel<=99) + pg_tbl_idx = AN_20_CH_36_64; + else if (priv->pmib->dot11RFEntry.dot11channel<=148) + pg_tbl_idx = AN_20_CH_100_140; + else + pg_tbl_idx = AN_20_CH_149_165; + }else{ + //_TXPWR_REDEFINE ?? + int val = priv->pmib->dot11RFEntry.dot11channel; + + if (priv->pshare->offset_2nd_chan == 1) + val -= 2; + else + val += 2; + + if (priv->pmib->dot11RFEntry.dot11channel<=99) + pg_tbl_idx = AN_40_CH_36_64; + else if (priv->pmib->dot11RFEntry.dot11channel<=148) + pg_tbl_idx = AN_40_CH_100_140; + else + pg_tbl_idx = AN_40_CH_149_165; + } + }else{ + if (priv->pshare->is_40m_bw == 0) + { + if (priv->pmib->dot11RFEntry.dot11channel<=3) + pg_tbl_idx = BGN_20_CH1_3; + else if (priv->pmib->dot11RFEntry.dot11channel<=9) + pg_tbl_idx = BGN_20_CH4_9; + else + pg_tbl_idx = BGN_20_CH10_14; + }else{ + int val = priv->pmib->dot11RFEntry.dot11channel; + + if (priv->pshare->offset_2nd_chan == 1) + val -= 2; + else + val += 2; + + if (val<=3) + pg_tbl_idx = BGN_40_CH1_3; + else if (val<=9) + pg_tbl_idx = BGN_40_CH4_9; + else + pg_tbl_idx = BGN_40_CH10_14; + } + } + + //In Noraml Driver mode, and if mib 'pwr_by_rate' = 0 >> Use default power by rate table + if( (priv->pshare->rf_ft_var.mp_specific == 0) && (priv->pshare->rf_ft_var.pwr_by_rate == 0) ) + pg_tbl_idx = BGN_2040_ALL; + + DEBUG_INFO("channel=%d pg_tbl_idx=%d\n",priv->pmib->dot11RFEntry.dot11channel, pg_tbl_idx); + + } +#endif //CONFIG_RTL_92D_SUPPORT + +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ +#ifdef HIGH_POWER_EXT_PA + if( priv->pshare->rf_ft_var.use_ext_pa) { + //printk("[%s][data_PHY_REG_PG_hp]\n", __FUNCTION__); + next_head = data_PHY_REG_PG_hp_start; + read_bytes = (int)(data_PHY_REG_PG_hp_end - data_PHY_REG_PG_hp_start); + + } else +#endif + { + //printk("[%s][data_PHY_REG_PG_92C]\n", __FUNCTION__); + next_head = data_PHY_REG_PG_92C_start; + read_bytes = (int)(data_PHY_REG_PG_92C_end - data_PHY_REG_PG_92C_start); + } + } +#endif //CONFIG_RTL_92C_SUPPORT + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + max_len = PHY_REG_PG_SIZE; + file_format = THREE_COLUMN; + } +#if 0 + else if (reg_file == PHYREG_1T2R) { + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_2to1; + max_len = PHY_REG_1T2R; + file_format = THREE_COLUMN; + if (priv->pshare->rf_ft_var.pathB_1T == 0) { // PATH A + next_head = __PHY_to1T2R_start; + read_bytes = (int)(__PHY_to1T2R_end - __PHY_to1T2R_start); + } + else { // PATH B + next_head = __PHY_to1T2R_b_start; + read_bytes = (int)(__PHY_to1T2R_b_end - __PHY_to1T2R_b_start); + } + } +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + else if (reg_file == PHYREG) { + if (GET_CHIP_VER(priv)==VERSION_8192D) { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; + //printk("[%s][PHY_REG_n]\n",__FUNCTION__); + next_head = data_PHY_REG_n_start; + read_bytes = (int)(data_PHY_REG_n_end - data_PHY_REG_n_start); + max_len = PHY_REG_SIZE; + } + } +#endif // CONFIG_RTL_92D_SUPPORT + +#ifdef MP_TEST + else if (reg_file == PHYREG_MP) { +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_mp_buf; + //printk("[%s][PHY_REG_MP_n]\n",__FUNCTION__); + next_head = data_PHY_REG_MP_n_start; + read_bytes = (int)(data_PHY_REG_MP_n_end - data_PHY_REG_MP_n_start); + max_len = PHY_REG_SIZE; + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_mp_buf; + next_head = data_PHY_REG_MP_n_92C_start; + read_bytes = (int)(data_PHY_REG_MP_n_92C_end - data_PHY_REG_MP_n_92C_start); + max_len = PHY_REG_SIZE; + } +#endif + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + else if (reg_file == PHYREG_1T1R) { // PATH A + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; +#ifdef TESTCHIP_SUPPORT + if( IS_TEST_CHIP(priv) ) { + next_head = data_PHY_REG_1T_start; + read_bytes = (int)(data_PHY_REG_1T_end - data_PHY_REG_1T_start); + } else +#endif + { + + if (priv->pshare->rf_ft_var.use_ext_lna +#ifdef HIGH_POWER_EXT_PA + || priv->pshare->rf_ft_var.use_ext_pa +#endif + ) { + //printk("[%s][PHY_REG_1T_n_hp]\n", __FUNCTION__); + next_head = data_PHY_REG_1T_n_hp_start; + read_bytes = (int)(data_PHY_REG_1T_n_hp_end - data_PHY_REG_1T_n_hp_start); + } + else { + //printk("[%s][PHY_REG_1T_n]\n", __FUNCTION__); + next_head = data_PHY_REG_1T_n_start; + read_bytes = (int)(data_PHY_REG_1T_n_end - data_PHY_REG_1T_n_start); + } + } + + max_len = PHY_REG_SIZE; +#if 0 + if(priv->pshare->rf_ft_var.pathB_1T == 0) { + next_head = __PHY_to1T1R_start; + read_bytes = (int)(__PHY_to1T1R_end - __PHY_to1T1R_start); + } + else { // PATH B + next_head = __PHY_to1T1R_b_start; + read_bytes = (int)(__PHY_to1T1R_b_end - __PHY_to1T1R_b_start); + } +#endif + } + else if (reg_file == PHYREG_2T2R) { +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; + next_head = data_PHY_REG_2T_start; + read_bytes = (int)(data_PHY_REG_2T_end - data_PHY_REG_2T_start); + } else +#endif + { + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; + if (priv->pshare->rf_ft_var.use_ext_lna +#ifdef HIGH_POWER_EXT_PA + || priv->pshare->rf_ft_var.use_ext_pa +#endif + ) { + //printk("[%s][PHY_REG_2T_n_hp]\n", __FUNCTION__); + next_head = data_PHY_REG_2T_n_hp_start; + read_bytes = (int)(data_PHY_REG_2T_n_hp_end - data_PHY_REG_2T_n_hp_start); + } + else + { + //printk("[%s][PHY_REG_2T_n]\n", __FUNCTION__); + next_head = data_PHY_REG_2T_n_start; + read_bytes = (int)(data_PHY_REG_2T_n_end - data_PHY_REG_2T_n_start); + } + } + max_len = PHY_REG_SIZE; + } +#endif + +#else // !MERGE_FW + + switch (reg_file) { + case AGCTAB: + phyreg_table = (struct PhyRegTable *)priv->pshare->agc_tab_buf; + max_len = AGC_TAB_SIZE; + pFileName = "/usr/rtl8192Pci/AGC_TAB.txt"; + break; +/* + case PHYREG_1T2R: + if (priv->pshare->rf_ft_var.pathB_1T == 0) + pFileName = "/usr/rtl8192Pci/PHY_to1T2R.txt"; + else + pFileName = "/usr/rtl8192Pci/PHY_to1T2R_b.txt"; + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + file_format = THREE_COLUMN; + max_len = PHY_REG_SIZE; + break; +*/ + case PHYREG_2T2R: +/* +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) { + pFileName = "/usr/rtl8192Pci/phy_reg_mp.txt"; + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_mp_buf; + max_len = PHY_REG_SIZE; + } + else +#endif +*/ + phyreg_table = (struct PhyRegTable *)priv->pshare->phy_reg_buf; + max_len = PHY_REG_SIZE; + pFileName = "/usr/rtl8192Pci/phy_reg.txt"; + break; + case PHYREG_1T1R: + if (priv->pshare->rf_ft_var.pathB_1T == 0) + pFileName = "/usr/rtl8192Pci/PHY_to1T1R.txt"; + else + pFileName = "/usr/rtl8192Pci/PHY_to1T1R_b.txt"; + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + file_format = THREE_COLUMN; + max_len = PHY_REG_SIZE; + break; + case PHYREG_PG: + pFileName = "/usr/rtl8192Pci/PHY_REG_PG.txt"; + macreg_table = (struct MacRegTable *)priv->pshare->phy_reg_pg_buf; + max_len = PHY_REG_PG_SIZE; + file_format = THREE_COLUMN; + break; + } +#endif // MERGE_FW + + { + if((mem_ptr = (unsigned char *)kmalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC)) == NULL) { + printk("PHY_ConfigBBWithParaFile(): not enough memory\n"); + return -1; + } + + memset(mem_ptr, 0, MAX_CONFIG_FILE_SIZE); // clear memory + +#ifdef MERGE_FW + memcpy(mem_ptr, next_head, read_bytes); +#else + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if ((fd = sys_open(pFileName, O_RDONLY, 0)) < 0) { + printk("PHY_ConfigBBWithParaFile(): cannot open %s\n", pFileName); + set_fs(old_fs); + kfree(mem_ptr); + return -1; + } + + read_bytes = sys_read(fd, mem_ptr, MAX_CONFIG_FILE_SIZE); + sys_close(fd); + set_fs(old_fs); +#endif // MERGE_FW + + next_head = mem_ptr; + while (1) { + line_head = next_head; + next_head = get_line(&line_head); + if (line_head == NULL) + break; + + if (line_head[0] == '/') + continue; + + if (file_format == TWO_COLUMN) { + num = get_offset_val(line_head, &u4bRegOffset, &u4bRegValue); + if (num > 0) { + phyreg_table[len].offset = u4bRegOffset; + phyreg_table[len].value = u4bRegValue; + len++; +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + if ((len&0x7ff)==0) + REG32(BSP_WDTCNR) |= 1 << 23; +#endif + if (u4bRegOffset == 0xff) + break; + if ((len * sizeof(struct PhyRegTable)) > max_len) + break; + } + } + else { + num = get_offset_mask_val(line_head, &u4bRegOffset, &u4bRegMask ,&u4bRegValue); + if (num > 0) { + macreg_table[len].offset = u4bRegOffset; + macreg_table[len].mask = u4bRegMask; + macreg_table[len].value = u4bRegValue; + len++; + if (u4bRegOffset == 0xff) + break; + if ((len * sizeof(struct MacRegTable)) > max_len) + break; +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + if ((len&0x7ff)==0) + REG32(BSP_WDTCNR) |= 1 << 23; +#endif + } + } + } + + kfree(mem_ptr); + + if ((len * sizeof(struct PhyRegTable)) > max_len) { +#ifdef MERGE_FW + printk("PHY REG table buffer not large enough!\n"); +#else + printk("PHY REG table buffer not large enough! (%s)\n", pFileName); +#endif + return -1; + } + } + + num = 0; + while (1) { + if (file_format == THREE_COLUMN) { + u4bRegOffset = macreg_table[num].offset; + u4bRegValue = macreg_table[num].value; + u4bRegMask = macreg_table[num].mask; + } + else { + u4bRegOffset = phyreg_table[num].offset; + u4bRegValue = phyreg_table[num].value; + } + + if (u4bRegOffset == 0xff) + break; + else if (file_format == THREE_COLUMN){ +#ifdef CONFIG_RTL_92D_SUPPORT + if (reg_file == PHYREG_PG && GET_CHIP_VER(priv)==VERSION_8192D) { + if (u4bRegOffset==0xe00){ + if (idx == pg_tbl_idx) + write_en=1; + idx++; + } + if (write_en){ + PHY_SetBBReg(priv, u4bRegOffset, u4bRegMask, u4bRegValue); + if (u4bRegOffset==0x868){ + write_en = 0; + break; + } + } + }else +#endif + { + PHY_SetBBReg(priv, u4bRegOffset, u4bRegMask, u4bRegValue); + } + } + else + PHY_SetBBReg(priv, u4bRegOffset, bMaskDWord, u4bRegValue); + num++; + } + + return 0; +} + + +/*----------------------------------------------------------------------------- + * Function: PHY_ConfigRFWithParaFile() + * + * Overview: This function read RF parameters from general file format, and do RF 3-wire + * + * Input: PADAPTER Adapter + * ps1Byte pFileName + * RF92CD_RADIO_PATH_E eRFPath + * + * Output: NONE + * + * Return: RT_STATUS_SUCCESS: configuration file exist + * + * Note: Delay may be required for RF configuration + *---------------------------------------------------------------------------*/ +int PHY_ConfigRFWithParaFile(struct rtl8192cd_priv *priv, +#ifdef MERGE_FW + unsigned char *start, int read_bytes, +#else + unsigned char *pFileName, +#endif + RF92CD_RADIO_PATH_E eRFPath) +{ + int num; +#ifndef MERGE_FW + int fd=0, read_bytes; + mm_segment_t old_fs; +#endif + unsigned int u4bRegOffset, u4bRegValue; + unsigned char *mem_ptr, *line_head, *next_head; +#if !defined(NOT_RTK_BSP) && !defined(MERGE_FW) + extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +#endif + + if ((mem_ptr = (unsigned char *)kmalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC)) == NULL) { + printk("PHY_ConfigRFWithParaFile(): not enough memory\n"); + return -1; + } + + memset(mem_ptr, 0, MAX_CONFIG_FILE_SIZE); // clear memory + +#ifdef MERGE_FW + memcpy(mem_ptr, start, read_bytes); +#else + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#if defined(NOT_RTK_BSP) + if ((fd = rtl8192cd_fileopen(pFileName, O_RDONLY, 0)) < 0) +#else + if ((fd = sys_open(pFileName, O_RDONLY, 0)) < 0) +#endif + { + printk("PHY_ConfigRFWithParaFile(): cannot open %s\n", pFileName); + set_fs(old_fs); + kfree(mem_ptr); + return -1; + } + + read_bytes = sys_read(fd, mem_ptr, MAX_CONFIG_FILE_SIZE); + sys_close(fd); + set_fs(old_fs); +#endif // MERGE_FW + + next_head = mem_ptr; + while (1) { + line_head = next_head; + next_head = get_line(&line_head); + if (line_head == NULL) + break; + + if (line_head[0] == '/') + continue; + + num = get_offset_val(line_head, &u4bRegOffset, &u4bRegValue); + if (num > 0) { + if (u4bRegOffset == 0xff) + break; + else if (u4bRegOffset == 0xfe) + delay_ms(50); // Delay 50 ms. Only RF configuration require delay + else if (num == 2) { + PHY_SetRFReg(priv, eRFPath, u4bRegOffset, bMask20Bits, u4bRegValue); + delay_ms(1); + } + } +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + REG32(BSP_WDTCNR) |= 1 << 23; +#endif + } + + kfree(mem_ptr); + + return 0; +} + + +int PHY_ConfigMACWithParaFile(struct rtl8192cd_priv *priv) +{ + int read_bytes, num, len=0; + unsigned int u4bRegOffset, u4bRegValue; + unsigned char *mem_ptr, *line_head, *next_head; +#ifndef MERGE_FW + int fd=0; + mm_segment_t old_fs; + unsigned char *pFileName = "/usr/rtl8192Pci/MACPHY_REG.txt"; +#ifndef NOT_RTK_BSP + extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +#endif +#endif + struct PhyRegTable *reg_table = (struct PhyRegTable *)priv->pshare->mac_reg_buf; + + { + if((mem_ptr = (unsigned char *)kmalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC)) == NULL) { + printk("PHY_ConfigMACWithParaFile(): not enough memory\n"); + return -1; + } + + memset(mem_ptr, 0, MAX_CONFIG_FILE_SIZE); // clear memory + +#ifdef MERGE_FW +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + printk("[%s][MACPHY_REG]\n",__FUNCTION__); + read_bytes = (int)(data_MACPHY_REG_end - data_MACPHY_REG_start); + memcpy(mem_ptr, data_MACPHY_REG_start, read_bytes); + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + printk("[%s][MACPHY_REG_92C]\n",__FUNCTION__); + read_bytes = (int)(data_MACPHY_REG_92C_end - data_MACPHY_REG_92C_start); + memcpy(mem_ptr, data_MACPHY_REG_92C_start, read_bytes); + } +#endif +#else + + old_fs = get_fs(); + set_fs(KERNEL_DS); + +#if defined(NOT_RTK_BSP) + if ((fd = rtl8192cd_fileopen(pFileName, O_RDONLY, 0)) < 0) +#else + if ((fd = sys_open(pFileName, O_RDONLY, 0)) < 0) +#endif + { + printk("PHY_ConfigMACWithParaFile(): cannot open %s\n", pFileName); + set_fs(old_fs); + kfree(mem_ptr); + return -1; + } + + read_bytes = sys_read(fd, mem_ptr, MAX_CONFIG_FILE_SIZE); + sys_close(fd); + set_fs(old_fs); +#endif // MERGE_FW + + next_head = mem_ptr; + while (1) { + line_head = next_head; + next_head = get_line(&line_head); + if (line_head == NULL) + break; + + if (line_head[0] == '/') + continue; + + num = get_offset_val(line_head, &u4bRegOffset, &u4bRegValue); + if (num > 0) { + reg_table[len].offset = u4bRegOffset; + reg_table[len].value = u4bRegValue; + len++; + if (u4bRegOffset == 0xff) + break; + if ((len * sizeof(struct MacRegTable)) > MAC_REG_SIZE) + break; + } + } + reg_table[len].offset = 0xff; + + kfree(mem_ptr); + + if ((len * sizeof(struct MacRegTable)) > MAC_REG_SIZE) { + printk("MAC REG table buffer not large enough!\n"); + return -1; + } + } + + num = 0; + while (1) { + u4bRegOffset = reg_table[num].offset; + u4bRegValue = reg_table[num].value; + + if (u4bRegOffset == 0xff) + break; + else + RTL_W8(u4bRegOffset, u4bRegValue); + num++; + } + + return 0; +} + + +#ifdef UNIVERSAL_REPEATER +static struct rtl8192cd_priv *get_another_interface_priv(struct rtl8192cd_priv *priv) +{ + if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) + return GET_VXD_PRIV(priv); + else if (IS_DRV_OPEN(GET_ROOT_PRIV(priv))) + return GET_ROOT_PRIV(priv); + else + return NULL; +} + + +static int get_shortslot_for_another_interface(struct rtl8192cd_priv *priv) +{ + struct rtl8192cd_priv *p_priv; + + p_priv = get_another_interface_priv(priv); + if (p_priv) { + if (p_priv->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) + return (p_priv->pmib->dot11ErpInfo.shortSlot); + else { + if (p_priv->pmib->dot11OperationEntry.opmode & WIFI_ASOC_STATE) + return (p_priv->pmib->dot11ErpInfo.shortSlot); + } + } + return -1; +} +#endif // UNIVERSAL_REPEATER + + +void set_slot_time(struct rtl8192cd_priv *priv, int use_short) +{ +#ifdef UNIVERSAL_REPEATER + int is_short; + is_short = get_shortslot_for_another_interface(priv); + if (is_short != -1) { // not abtained + use_short &= is_short; + } +#endif + + if (use_short) + RTL_W8(SLOT_TIME, 0x09); + else + RTL_W8(SLOT_TIME, 0x14); +} + +void SwChnl(struct rtl8192cd_priv *priv, unsigned char channel, int offset) +{ + unsigned int val = channel, eRFPath, curMaxRFPath; + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + if( (priv->pshare->rf_ft_var.mp_specific == 0) || (priv->pshare->rf_ft_var.pwr_by_rate == 1) ) + reload_txpwr_pg(priv); + } +#endif + +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + curMaxRFPath = RF92CD_PATH_B; + else +#endif + curMaxRFPath = RF92CD_PATH_MAX; + + if (channel > 14) + priv->pshare->curr_band = BAND_5G; + else + priv->pshare->curr_band = BAND_2G; + +//_TXPWR_REDEFINE ?? Working channel also apply to 5G ?? what if channel = 165 + 2 or 36 -2 ?? + if (priv->pshare->CurrentChannelBW) { + if (offset == 1) + val -= 2; + else + val += 2; + } + +#ifdef CONFIG_RTL_92D_SUPPORT + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_2G) +#endif + if (priv->pshare->rf_ft_var.use_frq_2_3G) + val += 14; + + for(eRFPath = RF92CD_PATH_A; eRFPath < curMaxRFPath; eRFPath++) { +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) + PHY_SetRFReg(priv, eRFPath, rRfChannel, 0xff, val); +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + priv->pshare->RegRF18[eRFPath] = RTL_SET_MASK(priv->pshare->RegRF18[eRFPath],0xff,val,0); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, 0xff, val); + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + /* + * Set Bit18 when channel >= 100, for 5G only + */ + if (val >= 100) + priv->pshare->RegRF18[eRFPath] |= BIT(18); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(18), 1); + else + priv->pshare->RegRF18[eRFPath] &= (~(BIT(18))); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(18), 0); + + priv->pshare->RegRF18[eRFPath] |= BIT(16); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(16), 1); + priv->pshare->RegRF18[eRFPath] |= BIT(8); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(8), 1); + // CLOAD for RF paht_A/B (MP-chip) + if (val < 149) + PHY_SetRFReg(priv, eRFPath, 0xB, BIT(16)|BIT(15)|BIT(14), 0x7); + else + PHY_SetRFReg(priv, eRFPath, 0xB, BIT(16)|BIT(15)|BIT(14), 0x2); + } else { + priv->pshare->RegRF18[eRFPath] &= (~(BIT(18))); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(18, 0); + priv->pshare->RegRF18[eRFPath] &= (~(BIT(16))); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(16), 0); + priv->pshare->RegRF18[eRFPath] &= (~(BIT(8))); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, BIT(8), 0); + // CLOAD for RF paht_A/B (MP-chip) + PHY_SetRFReg(priv, eRFPath, 0xB, BIT(16)|BIT(15)|BIT(14), 0x7); + } + + PHY_SetRFReg(priv,eRFPath,rRfChannel,bMask20Bits,priv->pshare->RegRF18[eRFPath]); + //printk("%s(%d) RF 18 = 0x%05x[0x%05x]\n",__FUNCTION__,__LINE__,priv->pshare->RegRF18[eRFPath], + //PHY_QueryRFReg(priv,eRFPath,rRfChannel,bMask20Bits,1)); +#ifdef RX_GAIN_TRACK_92D + priv->pshare->RegRF3C[eRFPath] = PHY_QueryRFReg(priv, eRFPath, 0x3C, bMask20Bits, 1); +#endif + } +#endif + } + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + SetSYN_para(priv, val); +#ifdef SW_LCK_92D + phy_ReloadLCKSetting(priv); +#endif + SetIMR_n(priv, val); + + Update92DRFbyChannel(priv, val); + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_2G) +#endif + if (priv->pshare->rf_ft_var.use_frq_2_3G) + val -= 14; + + priv->pshare->working_channel = val; + +#ifdef TXPWR_LMT + if (!priv->pshare->rf_ft_var.disable_txpwrlmt){ + find_pwr_limit(priv); + } +#endif + + PHY_RF6052SetOFDMTxPower(priv, val); + if (priv->pshare->curr_band == BAND_2G) + PHY_RF6052SetCCKTxPower(priv, val); + + selectMinPowerIdex(priv); + + return; +} + +#if 0 +// switch 1 spatial stream path +//antPath: 01 for PathA,10 for PathB, 11for Path AB +void Switch_1SS_Antenna(struct rtl8192cd_priv *priv, unsigned int antPath ) +{ + unsigned int dword = 0; + if(get_rf_mimo_mode(priv) != MIMO_2T2R) + return; + + switch(antPath){ + case 1: + dword = RTL_R32(0x90C); + if((dword & 0x0ff00000) == 0x01100000) + goto switch_1ss_end; + dword &= 0xf00fffff; + dword |= 0x01100000; // Path A + RTL_W32(0x90C, dword); + break; + case 2: + dword = RTL_R32(0x90C); + if((dword & 0x0ff00000) == 0x02200000) + goto switch_1ss_end; + dword &= 0xf00fffff; + dword |= 0x02200000; // Path B + RTL_W32(0x90C, dword); + break; + + case 3: + if(priv->pshare->rf_ft_var.ofdm_1ss_oneAnt == 1)// use one ANT for 1ss + goto switch_1ss_end;// do nothing + dword = RTL_R32(0x90C); + if((dword & 0x0ff00000) == 0x03300000) + goto switch_1ss_end; + dword &= 0xf00fffff; + dword |= 0x03300000; // Path A,B + RTL_W32(0x90C, dword); + break; + + default:// do nothing + break; + } +switch_1ss_end: + return; + +} + +// switch OFDM path +//antPath: 01 for PathA,10 for PathB, 11for Path AB +void Switch_OFDM_Antenna(struct rtl8192cd_priv *priv, unsigned int antPath ) +{ + unsigned int dword = 0; + if(get_rf_mimo_mode(priv) != MIMO_2T2R) + return; + + switch(antPath){ + case 1: + dword = RTL_R32(0x90C); + if((dword & 0x000000f0) == 0x00000010) + goto switch_OFDM_end; + dword &= 0xffffff0f; + dword |= 0x00000010; // Path A + RTL_W32(0x90C, dword); + break; + case 2: + dword = RTL_R32(0x90C); + if((dword & 0x000000f0) == 0x00000020) + goto switch_OFDM_end; + dword &= 0xffffff0f; + dword |= 0x00000020; // Path B + RTL_W32(0x90C, dword); + break; + + case 3: + if(priv->pshare->rf_ft_var.ofdm_1ss_oneAnt == 1)// use one ANT for 1ss + goto switch_OFDM_end;// do nothing + dword = RTL_R32(0x90C); + if((dword & 0x000000f0) == 0x00000030) + goto switch_OFDM_end; + dword &= 0xffffff0f; + dword |= 0x00000030; // Path A,B + RTL_W32(0x90C, dword); + break; + + default:// do nothing + break; + } +switch_OFDM_end: + return; + +} + + +#endif + +void enable_hw_LED(struct rtl8192cd_priv *priv, unsigned int led_type) +{ + switch (led_type) { + case LEDTYPE_HW_TX_RX: +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) + RTL_W32(LEDCFG, LED_TX_RX_EVENT_ON<<LED1CM_SHIFT_92D | LED1DIS_92D); +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) + RTL_W32(LEDCFG, LED_RX_EVENT_ON<<LED1CM_SHIFT | LED_TX_EVENT_ON<<LED0CM_SHIFT); +#endif + + break; + case LEDTYPE_HW_LINKACT_INFRA: + RTL_W32(LEDCFG, LED_TX_RX_EVENT_ON<<LED0CM_SHIFT); + if ((OPMODE & WIFI_AP_STATE) || (OPMODE & WIFI_STATION_STATE)) + RTL_W32(LEDCFG, RTL_R32(LEDCFG) & 0x0ff); + else + RTL_W32(LEDCFG, (RTL_R32(LEDCFG) & 0xfffff0ff) | LED1SV); + break; + default: + break; + } +} + + +/** +* Function: phy_InitBBRFRegisterDefinition +* +* OverView: Initialize Register definition offset for Radio Path A/B/C/D +* +* Input: +* PADAPTER Adapter, +* +* Output: None +* Return: None +* Note: The initialization value is constant and it should never be changes +*/ +void phy_InitBBRFRegisterDefinition(struct rtl8192cd_priv *priv) +{ + struct rtl8192cd_hw *phw = GET_HW(priv); + + // RF Interface Sowrtware Control + phw->PHYRegDef[RF92CD_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 + phw->PHYRegDef[RF92CD_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) + + // RF Interface Readback Value + phw->PHYRegDef[RF92CD_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0 + phw->PHYRegDef[RF92CD_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) + + // RF Interface Output (and Enable) + phw->PHYRegDef[RF92CD_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860 + phw->PHYRegDef[RF92CD_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864 + + // RF Interface (Output and) Enable + phw->PHYRegDef[RF92CD_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) + phw->PHYRegDef[RF92CD_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) + + //Addr of LSSI. Wirte RF register by driver + phw->PHYRegDef[RF92CD_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter + phw->PHYRegDef[RF92CD_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; + + // RF parameter + phw->PHYRegDef[RF92CD_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select + phw->PHYRegDef[RF92CD_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; + + // Tx AGC Gain Stage (same for all path. Should we remove this?) + phw->PHYRegDef[RF92CD_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + phw->PHYRegDef[RF92CD_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + + // Tranceiver A~D HSSI Parameter-1 + phw->PHYRegDef[RF92CD_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1 + phw->PHYRegDef[RF92CD_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1 + + // Tranceiver A~D HSSI Parameter-2 + phw->PHYRegDef[RF92CD_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2 + phw->PHYRegDef[RF92CD_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2 + + // RF switch Control + phw->PHYRegDef[RF92CD_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control + phw->PHYRegDef[RF92CD_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; + + // AGC control 1 + phw->PHYRegDef[RF92CD_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; + phw->PHYRegDef[RF92CD_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; + + // AGC control 2 + phw->PHYRegDef[RF92CD_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; + phw->PHYRegDef[RF92CD_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; + + // RX AFE control 1 + phw->PHYRegDef[RF92CD_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; + phw->PHYRegDef[RF92CD_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; + + // RX AFE control 1 + phw->PHYRegDef[RF92CD_PATH_A].rfRxAFE = rOFDM0_XARxAFE; + phw->PHYRegDef[RF92CD_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; + + // Tx AFE control 1 + phw->PHYRegDef[RF92CD_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; + phw->PHYRegDef[RF92CD_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; + + // Tx AFE control 2 + phw->PHYRegDef[RF92CD_PATH_A].rfTxAFE = rOFDM0_XATxAFE; + phw->PHYRegDef[RF92CD_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; + + // Tranceiver LSSI Readback SI mode + phw->PHYRegDef[RF92CD_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; + phw->PHYRegDef[RF92CD_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; + + // Tranceiver LSSI Readback PI mode + phw->PHYRegDef[RF92CD_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; + phw->PHYRegDef[RF92CD_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; +} + + +void check_chipID_MIMO(struct rtl8192cd_priv *priv) +{ + unsigned int val32; + val32 = RTL_R32(SYS_CFG); +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + if (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + priv->pshare->phw->MIMO_TR_hw_support = MIMO_1T1R; + else + priv->pshare->phw->MIMO_TR_hw_support = MIMO_2T2R; + } else +#endif + if (val32 & BIT(27)) { + priv->pshare->version_id = VERSION_8192C; + priv->pshare->phw->MIMO_TR_hw_support = MIMO_2T2R; + } else { + priv->pshare->version_id = VERSION_8188C; + priv->pshare->phw->MIMO_TR_hw_support = MIMO_1T1R; + + if ((0x3 &(RTL_R32(0xec)>>22))== 0x01 ) + priv->pshare->version_id |= 0x200; // 88RE + } + + if (val32 & BIT(23)) { + priv->pshare->version_id |= 0x100; + } +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + if (val32 & BIT(19)) { + priv->pshare->version_id |= 0x400; // UMC + priv->pshare->version_id |= (0xf0 & (val32>>8)); // 0: a-cut + } + if( ((0x0f & (val32>>16)) ==0 ) && ((0x0f & (val32>>12)) ==1 ) ) { //6195B + priv->pshare->version_id |= 0x400; + priv->pshare->version_id |= 0x10; // 0x10: b-cut + } + } +#endif + return; +} + +void selectMinPowerIdex(struct rtl8192cd_priv *priv) +{ + int i=0,idx, pwr_min = 0xff; + unsigned int val32; + unsigned int pwr_regA[] = {0xe00,0xe04,0xe08,0x86c,0xe10,0xe14,0xe18,0xe1c}; + unsigned int pwr_regB[] = {0x830,0x834,0x838,0x86c,0x83c,0x848,0x84c,0x868}; + + for (idx=0 ; idx < 8 ; idx++) + { + val32 = RTL_R32(pwr_regA[idx]); + switch (pwr_regA[idx]) { + case 0xe08: + pwr_min = POWER_MIN_CHECK(pwr_min,(val32 >> 8) & 0xff); + break; + + case 0x86c: + for (i=8 ; i < 32 ; i+=8) + pwr_min = POWER_MIN_CHECK(pwr_min,(val32 >> i) & 0xff); + break; + + default: + for (i=0 ; i < 32 ; i+=8) + pwr_min = POWER_MIN_CHECK(pwr_min,(val32 >> i) & 0xff); + break; + } + } + + if (GET_CHIP_VER(priv) != VERSION_8188C) + { + for (idx=0 ; idx < 8 ; idx++) + { + val32 = RTL_R32(pwr_regB[idx]); + switch (pwr_regB[idx]) { + case 0x86c: + pwr_min = POWER_MIN_CHECK(pwr_min,val32 & 0xff); + break; + + case 0x838: + for (i=8 ; i < 32 ; i+=8) + pwr_min = POWER_MIN_CHECK(pwr_min,(val32 >> i) & 0xff); + break; + + default: + for (i=0 ; i < 32 ; i+=8) + pwr_min = POWER_MIN_CHECK(pwr_min,(val32 >> i) & 0xff); + break; + } + } + } + + priv->pshare->rf_ft_var.min_pwr_idex = pwr_min; +} + + +void PHY_RF6052SetOFDMTxPower(struct rtl8192cd_priv *priv, unsigned int channel) +{ + unsigned int writeVal, defValue =0x28 ; + unsigned char offset; + char base, byte0, byte1, byte2, byte3; + unsigned char pwrlevelHT40_1S_A = priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[channel-1]; + unsigned char pwrlevelHT40_1S_B = priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[channel-1]; + unsigned char pwrdiffHT40_2S = priv->pmib->dot11RFEntry.pwrdiffHT40_2S[channel-1]; + unsigned char pwrdiffHT20 = priv->pmib->dot11RFEntry.pwrdiffHT20[channel-1]; + unsigned char pwrdiffOFDM = priv->pmib->dot11RFEntry.pwrdiffOFDM[channel-1]; +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE + unsigned char pwrlevelHT40_6dBm_1S_A; + unsigned char pwrlevelHT40_6dBm_1S_B; + unsigned char pwrdiffHT40_6dBm_2S; + unsigned char pwrdiffHT20_6dBm; + unsigned char pwrdiffOFDM_6dBm; + unsigned char offset_6dBm; + char base_6dBm; +#endif + unsigned int ori_channel = channel; //Keep the original channel setting + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { +#ifdef CONFIG_RTL_8198 + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) + defValue=0x28; + else + defValue=0x2d; +#else + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) + defValue=0x26; + else + defValue=0x30; +#endif + + //TXPWR_REDEFINE + //FLASH GROUP [36-99] [100-148] [149-165] + //Special Cases: [34-2, 34, 34+2, 36-2, 165+2]:No DATA , [149-2]:FLASH DATA OF Channel-146-6dBm + //Use Flash data of channel 36 & 140 & 165 for these special cases. + if((channel > 30) && (channel < 36)) + channel = 36; + else if (channel == (149-2)) + channel = 140; + else if(channel > 165) + channel = 165; + + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + pwrlevelHT40_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[channel-1]; + pwrlevelHT40_1S_B = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel-1]; + pwrdiffHT40_2S = priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[channel-1]; + pwrdiffHT20 = priv->pmib->dot11RFEntry.pwrdiff5GHT20[channel-1]; + pwrdiffOFDM = priv->pmib->dot11RFEntry.pwrdiff5GOFDM[channel-1]; + } + +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE +//MCS 8 - 15: No Power By Rate +//Others: Power by Rate (Add Power) +//Remove PWR_5G_DIFF + +//?? phyBandSelect will auto swtich or 2G | 5G ?? + { + int i; + + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + pwrlevelHT40_6dBm_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[channel]; + pwrlevelHT40_6dBm_1S_B = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel]; + pwrdiffHT40_6dBm_2S = priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[channel]; + pwrdiffHT20_6dBm = priv->pmib->dot11RFEntry.pwrdiff5GHT20[channel]; + pwrdiffOFDM_6dBm = priv->pmib->dot11RFEntry.pwrdiff5GOFDM[channel]; + } else { + pwrlevelHT40_6dBm_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[channel-1]; + pwrlevelHT40_6dBm_1S_B = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel-1]; + pwrdiffHT40_6dBm_2S = priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[channel-1]; + pwrdiffHT20_6dBm = priv->pmib->dot11RFEntry.pwrdiff5GHT20[channel-1]; + pwrdiffOFDM_6dBm = priv->pmib->dot11RFEntry.pwrdiff5GOFDM[channel-1]; + } + } +#endif + + +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && + priv->pshare->wlandev_idx == 1) { + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) + pwrlevelHT40_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel-1]; + else { + pwrlevelHT40_1S_A = priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[channel-1]; + } +//_TXPWR_REDEFINE +#ifdef USB_POWER_SUPPORT + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + pwrlevelHT40_6dBm_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel]; + } else { + pwrlevelHT40_6dBm_1S_A = priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[channel-1]; + } +#endif + } +#endif + + channel = ori_channel; //_TXPWR_REDEFINE Restore the channel setting + +#ifdef TXPWR_LMT + if (!priv->pshare->rf_ft_var.disable_txpwrlmt){ + int i; + int max_idx; + + if (!priv->pshare->txpwr_lmt_OFDM || !priv->pshare->tgpwr_OFDM){ + //printk("No limit for OFDM TxPower\n"); + max_idx=255; + }else{ + // maximum additional power index + max_idx = (priv->pshare->txpwr_lmt_OFDM - priv->pshare->tgpwr_OFDM); + } + + for (i=0; i<=7; i++) { + priv->pshare->phw->OFDMTxAgcOffset_A[i] = POWER_MIN_CHECK(priv->pshare->phw->OFDMTxAgcOffset_A[i], max_idx); + priv->pshare->phw->OFDMTxAgcOffset_B[i] = POWER_MIN_CHECK(priv->pshare->phw->OFDMTxAgcOffset_B[i], max_idx); + //printk("priv->pshare->phw->OFDMTxAgcOffset_A[%d]=%x\n",i, priv->pshare->phw->OFDMTxAgcOffset_A[i]); + //printk("priv->pshare->phw->OFDMTxAgcOffset_B[%d]=%x\n",i, priv->pshare->phw->OFDMTxAgcOffset_B[i]); + } + + if (!priv->pshare->txpwr_lmt_HT1S || !priv->pshare->tgpwr_HT1S){ + //printk("No limit for HT1S TxPower\n"); + max_idx = 255; + }else{ + // maximum additional power index + max_idx = (priv->pshare->txpwr_lmt_HT1S - priv->pshare->tgpwr_HT1S); + } + + for (i=0; i<=7; i++) { + priv->pshare->phw->MCSTxAgcOffset_A[i] = POWER_MIN_CHECK(priv->pshare->phw->MCSTxAgcOffset_A[i], max_idx); + priv->pshare->phw->MCSTxAgcOffset_B[i] = POWER_MIN_CHECK(priv->pshare->phw->MCSTxAgcOffset_B[i], max_idx); + //printk("priv->pshare->phw->MCSTxAgcOffset_A[%d]=%x\n",i, priv->pshare->phw->MCSTxAgcOffset_A[i]); + //printk("priv->pshare->phw->MCSTxAgcOffset_B[%d]=%x\n",i, priv->pshare->phw->MCSTxAgcOffset_B[i]); + } + + if (!priv->pshare->txpwr_lmt_HT2S || !priv->pshare->tgpwr_HT2S){ + //printk("No limit for HT2S TxPower\n"); + max_idx = 255; + }else{ + // maximum additional power index + max_idx = (priv->pshare->txpwr_lmt_HT2S - priv->pshare->tgpwr_HT2S); + } + + for (i=8; i<=15; i++) { + priv->pshare->phw->MCSTxAgcOffset_A[i] = POWER_MIN_CHECK(priv->pshare->phw->MCSTxAgcOffset_A[i], max_idx); + priv->pshare->phw->MCSTxAgcOffset_B[i] = POWER_MIN_CHECK(priv->pshare->phw->MCSTxAgcOffset_B[i], max_idx); + //printk("priv->pshare->phw->MCSTxAgcOffset_A[%d]=%x\n",i, priv->pshare->phw->MCSTxAgcOffset_A[i]); + //printk("priv->pshare->phw->MCSTxAgcOffset_B[%d]=%x\n",i, priv->pshare->phw->MCSTxAgcOffset_B[i]); + } + } +#endif + } +#endif + + if (pwrlevelHT40_1S_A == 0) { // use default value + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + defValue = HP_OFDM_POWER_DEFAULT ; +#endif +#ifndef ADD_TX_POWER_BY_CMD + writeVal = (defValue<<24)|(defValue<<16)|(defValue<<8)|(defValue); + RTL_W32(rTxAGC_A_Rate18_06, writeVal); + RTL_W32(rTxAGC_A_Rate54_24, writeVal); + RTL_W32(rTxAGC_A_Mcs03_Mcs00, writeVal); + RTL_W32(rTxAGC_A_Mcs07_Mcs04, writeVal); + RTL_W32(rTxAGC_B_Rate18_06, writeVal); + RTL_W32(rTxAGC_B_Rate54_24, writeVal); + RTL_W32(rTxAGC_B_Mcs03_Mcs00, writeVal); + RTL_W32(rTxAGC_B_Mcs07_Mcs04, writeVal); + +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE, pwrlevelHT40_1S_A == 0 >> No 6dBm Power >> default value >> so USB = def - 14 + writeVal = POWER_RANGE_CHECK(defValue - USB_HT_2S_DIFF); + writeVal |= (writeVal<<24)|(writeVal<<16)|(writeVal<<8); +#endif + RTL_W32(rTxAGC_A_Mcs11_Mcs08, writeVal); + RTL_W32(rTxAGC_A_Mcs15_Mcs12, writeVal); + RTL_W32(rTxAGC_B_Mcs11_Mcs08, writeVal); + RTL_W32(rTxAGC_B_Mcs15_Mcs12, writeVal); +#else + base = defValue; + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_ofdm_18); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_ofdm_12); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_ofdm_9); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_ofdm_6); + + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Rate18_06, writeVal); + RTL_W32(rTxAGC_B_Rate18_06, writeVal); + + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_ofdm_54); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_ofdm_48); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_ofdm_36); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_ofdm_24); + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Rate54_24, writeVal); + RTL_W32(rTxAGC_B_Rate54_24, writeVal); + + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_mcs_3); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_mcs_2); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_mcs_1); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_mcs_0); + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs03_Mcs00, writeVal); + RTL_W32(rTxAGC_B_Mcs03_Mcs00, writeVal); + + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_mcs_7); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_mcs_6); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_mcs_5); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_mcs_4); + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs07_Mcs04, writeVal); + RTL_W32(rTxAGC_B_Mcs07_Mcs04, writeVal); + +//_TXPWR_REDEFINE +#ifdef USB_POWER_SUPPORT + byte0 = byte1 = byte2 = byte3 = -USB_HT_2S_DIFF; +#else + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_mcs_11); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_mcs_10); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_mcs_9); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_mcs_8); +#endif + + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs11_Mcs08, writeVal); + RTL_W32(rTxAGC_B_Mcs11_Mcs08, writeVal); + +//_TXPWR_REDEFINE +#ifdef USB_POWER_SUPPORT + byte0 = byte1 = byte2 = byte3 = -USB_HT_2S_DIFF; +#else + byte0 = byte1 = byte2 = byte3 = 0; + ASSIGN_TX_POWER_OFFSET(byte0, priv->pshare->rf_ft_var.txPowerPlus_mcs_15); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_mcs_14); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_mcs_13); + ASSIGN_TX_POWER_OFFSET(byte3, priv->pshare->rf_ft_var.txPowerPlus_mcs_12); +#endif + + byte0 = POWER_RANGE_CHECK(base + byte0); + byte1 = POWER_RANGE_CHECK(base + byte1); + byte2 = POWER_RANGE_CHECK(base + byte2); + byte3 = POWER_RANGE_CHECK(base + byte3); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs15_Mcs12, writeVal); + RTL_W32(rTxAGC_B_Mcs15_Mcs12, writeVal); + +#endif // ADD_TX_POWER_BY_CMD + return; // use default + } + + /****************************** PATH A ******************************/ + base = pwrlevelHT40_1S_A; + offset = (pwrdiffOFDM & 0x0f); +#if defined(CONFIG_RTL_92D_SUPPORT)&& defined(CONFIG_RTL_92D_DMDP) +//_TXPWR_REDEFINE?? + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && priv->pshare->wlandev_idx == 1) { + offset = ((pwrdiffOFDM & 0xf0) >> 4); + } +#endif + base = COUNT_SIGN_OFFSET(base, offset); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[0]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[1]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[2]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[3]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Rate18_06, writeVal); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[4]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[5]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[6]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_A[7]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Rate54_24, writeVal); + + base = pwrlevelHT40_1S_A; + if (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + offset = (pwrdiffHT20 & 0x0f); +#if defined(CONFIG_RTL_92D_SUPPORT)&& defined(CONFIG_RTL_92D_DMDP) +//_TXPWR_REDEFINE?? + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && priv->pshare->wlandev_idx == 1) { + offset = ((pwrdiffHT20 & 0xf0) >> 4); + } +#endif + base = COUNT_SIGN_OFFSET(base, offset); + } + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[0]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[1]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[2]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[3]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs03_Mcs00, writeVal); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[4]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[5]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[6]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[7]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs07_Mcs04, writeVal); + + offset = (pwrdiffHT40_2S & 0x0f); +#if defined(CONFIG_RTL_92D_SUPPORT)&& defined(CONFIG_RTL_92D_DMDP) +//_TXPWR_REDEFINE?? + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && priv->pshare->wlandev_idx == 1) { + offset = ((pwrdiffHT40_2S & 0xf0) >> 4); + } +#endif + base = COUNT_SIGN_OFFSET(base, offset); + + +//_TXPWR_REDEFINE +#ifdef USB_POWER_SUPPORT + + base_6dBm = pwrlevelHT40_6dBm_1S_A; + + if (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + offset_6dBm = (pwrdiffHT20_6dBm & 0x0f); + +#if defined(CONFIG_RTL_92D_SUPPORT)&& defined(CONFIG_RTL_92D_DMDP) + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && priv->pshare->wlandev_idx == 1) { + offset_6dBm = ((pwrdiffHT20_6dBm & 0xf0) >> 4); + } +#endif + + base_6dBm = COUNT_SIGN_OFFSET(base_6dBm, offset_6dBm); + } + + offset_6dBm = (pwrdiffHT40_6dBm_2S & 0x0f); + +#if defined(CONFIG_RTL_92D_SUPPORT)&& defined(CONFIG_RTL_92D_DMDP) + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && priv->pshare->wlandev_idx == 1) { + offset_6dBm = ((pwrdiffHT40_6dBm_2S & 0xf0) >> 4); + } +#endif + + base_6dBm = COUNT_SIGN_OFFSET(base_6dBm, offset_6dBm); + + if ((pwrlevelHT40_6dBm_1S_A != 0) && (pwrlevelHT40_6dBm_1S_A != pwrlevelHT40_1S_A)) + byte0 = byte1 = byte2 = byte3 = base_6dBm; + else if((base - USB_HT_2S_DIFF) > 0) + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(base - USB_HT_2S_DIFF); + else + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(defValue - USB_HT_2S_DIFF); + + +#else +//_TXPWR_REDEFINE ?? MCS 8 - 11, shall NOT add power by rate even NOT USB power ?? + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[8]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[9]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[10]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[11]); +#endif + + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + + //DEBUG_INFO("debug e18:%x,%x,[%x,%x,%x,%x],%x\n", offset, base, byte0, byte1, byte2, byte3, writeVal); + + RTL_W32(rTxAGC_A_Mcs11_Mcs08, writeVal); + +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE + if ((pwrlevelHT40_6dBm_1S_A != 0) && (pwrlevelHT40_6dBm_1S_A != pwrlevelHT40_1S_A)) + byte0 = byte1 = byte2 = byte3 = base_6dBm; + else if((base - USB_HT_2S_DIFF) > 0) + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(base - USB_HT_2S_DIFF); + else + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(defValue - USB_HT_2S_DIFF); + +#else + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[12]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[13]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[14]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_A[15]); +#endif + + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_A_Mcs15_Mcs12, writeVal); + + /****************************** PATH B ******************************/ + base = pwrlevelHT40_1S_B; + offset = ((pwrdiffOFDM & 0xf0) >> 4); + base = COUNT_SIGN_OFFSET(base, offset); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[0]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[1]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[2]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[3]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Rate18_06, writeVal); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[4]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[5]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[6]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->OFDMTxAgcOffset_B[7]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Rate54_24, writeVal); + + base = pwrlevelHT40_1S_B; + if (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + offset = ((pwrdiffHT20 & 0xf0) >> 4); + base = COUNT_SIGN_OFFSET(base, offset); + } + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[0]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[1]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[2]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[3]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Mcs03_Mcs00, writeVal); + + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[4]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[5]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[6]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[7]); + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Mcs07_Mcs04, writeVal); + + offset = ((pwrdiffHT40_2S & 0xf0) >> 4); + base = COUNT_SIGN_OFFSET(base, offset); + +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE ?? 2.4G + base_6dBm = pwrlevelHT40_6dBm_1S_B; + if (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + offset_6dBm = ((pwrdiffHT20_6dBm & 0xf0) >> 4); + base_6dBm = COUNT_SIGN_OFFSET(base_6dBm, offset_6dBm); + } + + offset_6dBm = ((pwrdiffHT40_6dBm_2S & 0xf0) >> 4); + base_6dBm = COUNT_SIGN_OFFSET(base_6dBm, offset_6dBm); + + if (( pwrlevelHT40_6dBm_1S_B != 0 ) && (pwrlevelHT40_6dBm_1S_B != pwrlevelHT40_1S_B)) + byte0 = byte1 = byte2 = byte3 = base_6dBm; + else if((base - USB_HT_2S_DIFF) > 0) + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(base - USB_HT_2S_DIFF); + else + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(defValue - USB_HT_2S_DIFF); + +#else + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[8]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[9]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[10]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[11]); +#endif + + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Mcs11_Mcs08, writeVal); + +#ifdef USB_POWER_SUPPORT +//_TXPWR_REDEFINE ?? 2.4G + if (( pwrlevelHT40_6dBm_1S_B != 0 ) && (pwrlevelHT40_6dBm_1S_B != pwrlevelHT40_1S_B)) + byte0 = byte1 = byte2 = byte3 = base_6dBm; + else if((base - USB_HT_2S_DIFF) > 0) + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(base - USB_HT_2S_DIFF); + else + byte0 = byte1 = byte2 = byte3 = POWER_RANGE_CHECK(defValue - USB_HT_2S_DIFF); + +#else + byte0 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[12]); + byte1 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[13]); + byte2 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[14]); + byte3 = POWER_RANGE_CHECK(base + priv->pshare->phw->MCSTxAgcOffset_B[15]); +#endif + + writeVal = (byte0<<24) | (byte1<<16) |(byte2<<8) | byte3; + RTL_W32(rTxAGC_B_Mcs15_Mcs12, writeVal); +} /* PHY_RF6052SetOFDMTxPower */ + + +void PHY_RF6052SetCCKTxPower(struct rtl8192cd_priv *priv, unsigned int channel) +{ + unsigned int writeVal = 0; + char byte, byte1, byte2; + char pwrlevelCCK_A = priv->pmib->dot11RFEntry.pwrlevelCCK_A[channel-1]; + char pwrlevelCCK_B = priv->pmib->dot11RFEntry.pwrlevelCCK_B[channel-1]; + +#if defined(CONFIG_RTL_92D_SUPPORT) && defined(CONFIG_RTL_92D_DMDP) + if (GET_CHIP_VER(priv)==VERSION_8192D) { + if (priv->pmib->dot11RFEntry.macPhyMode==DUALMAC_DUALPHY && + priv->pshare->wlandev_idx == 1){ + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_2G) { + pwrlevelCCK_A = priv->pmib->dot11RFEntry.pwrlevelCCK_B[channel-1]; + } + } + } +#endif +#ifdef TXPWR_LMT + if (!priv->pshare->rf_ft_var.disable_txpwrlmt){ + int max_idx, i; + if (!priv->pshare->txpwr_lmt_CCK || !priv->pshare->tgpwr_CCK){ + DEBUG_INFO("No limit for CCK TxPower\n"); + max_idx=255; + }else{ + // maximum additional power index + max_idx = (priv->pshare->txpwr_lmt_CCK - priv->pshare->tgpwr_CCK); + } + + for (i=0; i<=3; i++) { + priv->pshare->phw->CCKTxAgc_A[i] = POWER_MIN_CHECK(priv->pshare->phw->CCKTxAgc_A[i], max_idx); + priv->pshare->phw->CCKTxAgc_A[i] = POWER_MIN_CHECK(priv->pshare->phw->CCKTxAgc_A[i], max_idx); + //printk("priv->pshare->phw->CCKTxAgc_A[%d]=%x\n",i, priv->pshare->phw->CCKTxAgc_A[i]); + //printk("priv->pshare->phw->CCKTxAgc_A[%d]=%x\n",i, priv->pshare->phw->CCKTxAgc_A[i]); + } + } +#endif + + if (priv->pshare->rf_ft_var.cck_pwr_max) { + byte = POWER_RANGE_CHECK(priv->pshare->rf_ft_var.cck_pwr_max); + writeVal = byte; + PHY_SetBBReg(priv, rTxAGC_A_CCK1_Mcs32, 0x0000ff00, writeVal); + writeVal = (byte << 16) | (byte << 8) | byte; + PHY_SetBBReg(priv, rTxAGC_B_CCK5_1_Mcs32, 0xffffff00, writeVal); + writeVal = (byte << 24) | (byte << 16) | (byte << 8) | byte; + PHY_SetBBReg(priv, rTxAGC_A_CCK11_2_B_CCK11, 0xffffffff, writeVal); + return; + } + + if (pwrlevelCCK_A == 0) { // use default value +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + byte = HP_CCK_POWER_DEFAULT; + else +#endif + byte = 0x24; + +#ifndef ADD_TX_POWER_BY_CMD + writeVal = byte; + PHY_SetBBReg(priv, rTxAGC_A_CCK1_Mcs32, 0x0000ff00, writeVal); + writeVal = (byte << 16) | (byte << 8) | byte; + PHY_SetBBReg(priv, rTxAGC_B_CCK5_1_Mcs32, 0xffffff00, writeVal); + writeVal = (byte << 24) | (byte << 16) | (byte << 8) | byte; + PHY_SetBBReg(priv, rTxAGC_A_CCK11_2_B_CCK11, 0xffffffff, writeVal); +#else + pwrlevelCCK_A = pwrlevelCCK_B = byte; + byte = 0; + ASSIGN_TX_POWER_OFFSET(byte, priv->pshare->rf_ft_var.txPowerPlus_cck_1); + writeVal = POWER_RANGE_CHECK(pwrlevelCCK_A + byte); + PHY_SetBBReg(priv, rTxAGC_A_CCK1_Mcs32, 0x0000ff00, writeVal); + + byte = byte1 = byte2 = 0; + ASSIGN_TX_POWER_OFFSET(byte, priv->pshare->rf_ft_var.txPowerPlus_cck_1); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_cck_2); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_cck_5); + byte = POWER_RANGE_CHECK(pwrlevelCCK_B + byte); + byte1 = POWER_RANGE_CHECK(pwrlevelCCK_B + byte1); + byte2 = POWER_RANGE_CHECK(pwrlevelCCK_B + byte2); + writeVal = ((byte2 << 16) | (byte1 << 8) | byte); + PHY_SetBBReg(priv, rTxAGC_B_CCK5_1_Mcs32, 0xffffff00, writeVal); + + byte = byte1 = byte2 = 0; + ASSIGN_TX_POWER_OFFSET(byte, priv->pshare->rf_ft_var.txPowerPlus_cck_2); + ASSIGN_TX_POWER_OFFSET(byte1, priv->pshare->rf_ft_var.txPowerPlus_cck_5); + ASSIGN_TX_POWER_OFFSET(byte2, priv->pshare->rf_ft_var.txPowerPlus_cck_11); + byte = POWER_RANGE_CHECK(pwrlevelCCK_A + byte); + byte1 = POWER_RANGE_CHECK(pwrlevelCCK_A + byte1); + byte2 = POWER_RANGE_CHECK(pwrlevelCCK_A + byte2); + writeVal = ((byte2 << 24) | (byte1 << 16) | (byte << 8) | byte2); + PHY_SetBBReg(priv, rTxAGC_A_CCK11_2_B_CCK11, 0xffffffff, writeVal); +#endif + return; // use default + } + + writeVal = POWER_RANGE_CHECK(pwrlevelCCK_A + priv->pshare->phw->CCKTxAgc_A[3]); + PHY_SetBBReg(priv, rTxAGC_A_CCK1_Mcs32, 0x0000ff00, writeVal); + writeVal = (POWER_RANGE_CHECK(pwrlevelCCK_B + priv->pshare->phw->CCKTxAgc_B[1]) << 16) | + (POWER_RANGE_CHECK(pwrlevelCCK_B + priv->pshare->phw->CCKTxAgc_B[2]) << 8) | + POWER_RANGE_CHECK(pwrlevelCCK_B + priv->pshare->phw->CCKTxAgc_B[3]); + PHY_SetBBReg(priv, rTxAGC_B_CCK5_1_Mcs32, 0xffffff00, writeVal); + writeVal = (POWER_RANGE_CHECK(pwrlevelCCK_A + priv->pshare->phw->CCKTxAgc_A[0]) << 24) | + (POWER_RANGE_CHECK(pwrlevelCCK_A + priv->pshare->phw->CCKTxAgc_A[1]) << 16) | + (POWER_RANGE_CHECK(pwrlevelCCK_A + priv->pshare->phw->CCKTxAgc_A[2]) << 8) | + POWER_RANGE_CHECK(pwrlevelCCK_B + priv->pshare->phw->CCKTxAgc_B[0]); + PHY_SetBBReg(priv, rTxAGC_A_CCK11_2_B_CCK11, 0xffffffff, writeVal); +} + + +static int phy_BB8192CD_Config_ParaFile(struct rtl8192cd_priv *priv) +{ + int rtStatus=0; + unsigned short val16; + unsigned int val32; + + phy_InitBBRFRegisterDefinition(priv); + + // Enable BB and RF + val16 = RTL_R16(REG_SYS_FUNC_EN); + RTL_W16(REG_SYS_FUNC_EN, val16|BIT(13)|BIT(0)|BIT(1)); + + // 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. + RTL_W8(REG_AFE_PLL_CTRL, 0x83); + RTL_W8(REG_AFE_PLL_CTRL+1, 0xdb); + RTL_W8(REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB); + //RTL_W8(REG_SYS_FUNC_EN, FEN_PPLL|FEN_PCIEA|FEN_DIO_PCIE|FEN_USBA|FEN_BB_GLB_RST|FEN_BBRSTB); + //RTL_W8(REG_LDOHCI12_CTRL, 0x1f); + RTL_W8(REG_AFE_XTAL_CTRL+1, 0x80); + + val32 = RTL_R32(REG_AFE_XTAL_CTRL); + val32 = (val32 & (~(BIT(11) | BIT(14)))) | (BIT(18) | BIT(19) | BIT(21) | BIT(22)); + RTL_W32(REG_AFE_XTAL_CTRL, val32); + + /*----Check chip ID and hw TR MIMO config----*/ +// check_chipID_MIMO(priv); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + printk(">>> 92D load PHYREG \n"); + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG); + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + if (get_rf_mimo_mode(priv) == MIMO_2T2R) + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG_2T2R); + else if (get_rf_mimo_mode(priv) == MIMO_1T1R) + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG_1T1R); + } +#endif + +#ifdef MP_TEST + if ((priv->pshare->rf_ft_var.mp_specific) && (!IS_TEST_CHIP(priv) +#ifdef CONFIG_RTL_92D_SUPPORT + || (GET_CHIP_VER(priv)==VERSION_8192D) +#endif + )) { + delay_ms(10); + rtStatus |= PHY_ConfigBBWithParaFile(priv, PHYREG_MP); + } +#endif + + if (rtStatus) { + printk("phy_BB8192CD_Config_ParaFile(): Write BB Reg Fail!!\n"); + return rtStatus; + } + + /*----If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt----*/ + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG_PG); + if(rtStatus){ + printk("phy_BB8192CD_Config_ParaFile():BB_PG Reg Fail!!\n"); + return rtStatus; + } + + /*----BB AGC table Initialization----*/ +#ifdef CONFIG_RTL_92D_SUPPORT + + if (GET_CHIP_VER(priv)==VERSION_8192D) + PHY_SetBBReg(priv, rFPGA0_RFMOD, bOFDMEn | bCCKEn, 0); +#endif + rtStatus = PHY_ConfigBBWithParaFile(priv, AGCTAB); + + PHY_SetBBReg(priv, rFPGA0_RFMOD, bOFDMEn, 1); +#ifdef CONFIG_RTL_92D_SUPPORT + if (!(priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G)) + +#endif + PHY_SetBBReg(priv, rFPGA0_RFMOD, bCCKEn, 1); + if (rtStatus) { + printk("phy_BB8192CD_Config_ParaFile(): Write BB AGC Table Fail!!\n"); + return rtStatus; + } + +#if 0 + /*----For 1T2R Config----*/ + if (get_rf_mimo_mode(priv) == MIMO_1T2R) { + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG_1T2R); + if (rtStatus) { + printk("phy_BB8192CD_Config_ParaFile(): Write BB Reg for 1T2R Fail!!\n"); + return rtStatus; + } + }else if (get_rf_mimo_mode(priv) == MIMO_1T1R){ + delay_ms(100); + rtStatus = PHY_ConfigBBWithParaFile(priv, PHYREG_1T1R); + if (rtStatus) { + printk("phy_BB8192CD_Config_ParaFile(): Write BB Reg for 1T1R Fail!!\n"); + return rtStatus; + } + } +#endif + + DEBUG_INFO("PHY-BB Initialization Success\n"); + return 0; +} + + +int phy_RF6052_Config_ParaFile(struct rtl8192cd_priv *priv) +{ + int rtStatus=0; + RF92CD_RADIO_PATH_E eRFPath; + BB_REGISTER_DEFINITION_T *pPhyReg; + unsigned int u4RegValue = 0; + +#ifdef CONFIG_RTL_92D_SUPPORT + if ((GET_CHIP_VER(priv)==VERSION_8192D) && (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY)) + priv->pshare->phw->NumTotalRFPath = 1; + else +#endif + priv->pshare->phw->NumTotalRFPath = 2; + + for (eRFPath = RF92CD_PATH_A; eRFPath<priv->pshare->phw->NumTotalRFPath; eRFPath++) + { + pPhyReg = &priv->pshare->phw->PHYRegDef[eRFPath]; + + /*----Store original RFENV control type----*/ + switch(eRFPath) + { + case RF92CD_PATH_A: + u4RegValue = PHY_QueryBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV); + break; + case RF92CD_PATH_B : + u4RegValue = PHY_QueryBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV<<16); + break; + case RF92CD_PATH_MAX: + break; + } + + /*----Set RF_ENV enable----*/ + PHY_SetBBReg(priv, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + + /*----Set RF_ENV output high----*/ + PHY_SetBBReg(priv, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + PHY_SetBBReg(priv, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); + PHY_SetBBReg(priv, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); + + /*----Initialize RF fom connfiguration file----*/ +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + switch (eRFPath) { +#ifdef MERGE_FW + case RF92CD_PATH_A: +#ifdef CONFIG_RTL_92D_DMDP + if ((priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) && + (priv->pshare->wlandev_idx==1)){ +#ifdef RTL8192D_INT_PA + if (priv->pshare->rf_ft_var.use_intpa92d){ +#ifdef USB_POWER_SUPPORT + printk("[%s][radio_b_intPA_GM]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_intPA_GM_start, + (int)(data_radio_b_intPA_GM_end - data_radio_b_intPA_GM_start), eRFPath); +#else + printk("[%s][radio_b_intPA]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_intPA_start, + (int)(data_radio_b_intPA_end - data_radio_b_intPA_start), eRFPath); +#endif + + } else +#endif + { +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + printk("[%s][radio_b_n_92d_hp]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_n_92d_hp_start, + (int)(data_radio_b_n_92d_hp_end - data_radio_b_n_92d_hp_start), eRFPath); + } + else +#endif + { + printk("[%s] [radio_b_n]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_n_start, + (int)(data_radio_b_n_end - data_radio_b_n_start), eRFPath); + } + } + } else +#endif + { +#ifdef RTL8192D_INT_PA + if (priv->pshare->rf_ft_var.use_intpa92d) + { +#ifdef USB_POWER_SUPPORT + printk("[%s][radio_a_intPA_GM]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_intPA_GM_start, + (int)(data_radio_a_intPA_GM_end - data_radio_a_intPA_GM_start), eRFPath); +#else + printk("[%s][radio_a_intPA]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_intPA_start, + (int)(data_radio_a_intPA_end - data_radio_a_intPA_start), eRFPath); +#endif + } else +#endif + { +//_TXPWR_REDEFINE +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + printk("[%s][radio_a_n_92d_hp]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_n_92d_hp_start, + (int)(data_radio_a_n_92d_hp_end - data_radio_a_n_92d_hp_start), eRFPath); + } + else +#endif + { + printk("[%s][radio_a_n]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_n_start, + (int)(data_radio_a_n_end - data_radio_a_n_start), eRFPath); + } + } + } + break; + case RF92CD_PATH_B: +#ifdef RTL8192D_INT_PA + if (priv->pshare->rf_ft_var.use_intpa92d){ +#ifdef USB_POWER_SUPPORT + printk("[%s][radio_b_intPA_GM]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_intPA_GM_start, + (int)(data_radio_b_intPA_GM_end - data_radio_b_intPA_GM_start), eRFPath); +#else + printk("[%s][radio_b_intPA]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_intPA_start, + (int)(data_radio_b_intPA_end - data_radio_b_intPA_start), eRFPath); +#endif + } else +#endif + { +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + printk("[%s][radio_b_n_92d_hp]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_n_92d_hp_start, + (int)(data_radio_b_n_92d_hp_end - data_radio_b_n_92d_hp_start), eRFPath); + } + else +#endif + { + printk("[%s][radio_b_n]\n",__FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_n_start, + (int)(data_radio_b_n_end - data_radio_b_n_start), eRFPath); + } + } + break; +#else + case RF92CD_PATH_A: + rtStatus = PHY_ConfigRFWithParaFile(priv, "/usr/rtl8192Pci/radio_a.txt", eRFPath); + break; + case RF92CD_PATH_B: + rtStatus = PHY_ConfigRFWithParaFile(priv, "/usr/rtl8192Pci/radio_b.txt", eRFPath); + break; +#endif + default: + break; + } + } +#endif //!CONFIG_RTL_92D_SUPPORT +#if defined(CONFIG_RTL_92C_SUPPORT) + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) { + switch (eRFPath) + { +#ifdef MERGE_FW + case RF92CD_PATH_A: + if (get_rf_mimo_mode(priv) == MIMO_2T2R) { +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_2T_start, + (int)(data_radio_a_2T_end - data_radio_a_2T_start), eRFPath); + else +#endif + { +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + //printk("[%s][data_radio_a_2T_n_hp]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_2T_n_hp_start, + (int)(data_radio_a_2T_n_hp_end - data_radio_a_2T_n_hp_start), eRFPath); + } + else +#endif + { + if (priv->pshare->rf_ft_var.use_ext_lna) + { + //printk("[%s][data_radio_a_2T_n_lna]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_2T_n_lna_start, + (int)(data_radio_a_2T_n_lna_end - data_radio_a_2T_n_lna_start), eRFPath); + } + else + { + //printk("[%s][data_radio_a_2T_n]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_2T_n_start, + (int)(data_radio_a_2T_n_end - data_radio_a_2T_n_start), eRFPath); + } + } + } + } else if (get_rf_mimo_mode(priv) == MIMO_1T1R) { +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_1T_start, + (int)(data_radio_a_1T_end - data_radio_a_1T_start), eRFPath); + else +#endif + { +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + //printk("[%s][data_radio_a_2T_n_hp]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_2T_n_hp_start, + (int)(data_radio_a_2T_n_hp_end - data_radio_a_2T_n_hp_start), eRFPath); + } + else +#endif + { + //printk("[%s][data_radio_a_1T_n]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_a_1T_n_start, + (int)(data_radio_a_1T_n_end - data_radio_a_1T_n_start), eRFPath); + } + + } + } + break; + case RF92CD_PATH_B: + if (get_rf_mimo_mode(priv) == MIMO_2T2R) { +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_2T_start, + (int)(data_radio_b_2T_end - data_radio_b_2T_start), eRFPath); + else +#endif + { +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) + { + //printk("[%s][data_radio_b_2T_n_hp]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_2T_n_hp_start, + (int)(data_radio_b_2T_n_hp_end - data_radio_b_2T_n_hp_start), eRFPath); + } + else +#endif + { + if (priv->pshare->rf_ft_var.use_ext_lna) + { + //printk("[%s][data_radio_b_2T_n_lna]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_2T_n_lna_start, + (int)(data_radio_b_2T_n_lna_end - data_radio_b_2T_n_lna_start), eRFPath); + } + else + { + //printk("[%s][data_radio_b_2T_n]\n", __FUNCTION__); + rtStatus = PHY_ConfigRFWithParaFile(priv, data_radio_b_2T_n_start, + (int)(data_radio_b_2T_n_end - data_radio_b_2T_n_start), eRFPath); + } + } + } + } else if (get_rf_mimo_mode(priv) == MIMO_1T1R) + rtStatus=0; + break; +#else + case RF92CD_PATH_A: + rtStatus = PHY_ConfigRFWithParaFile(priv, "/usr/rtl8192Pci/radio_a.txt", eRFPath); + break; + case RF92CD_PATH_B: + rtStatus = PHY_ConfigRFWithParaFile(priv, "/usr/rtl8192Pci/radio_b.txt", eRFPath); + break; +#endif + default: + break; + } + } +#endif + /*----Restore RFENV control type----*/; + switch(eRFPath) + { + case RF92CD_PATH_A: + PHY_SetBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); + break; + case RF92CD_PATH_B : + PHY_SetBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); + break; + case RF92CD_PATH_MAX: + break; + } + } + + DEBUG_INFO("PHY-RF Initialization Success\n"); + + return rtStatus; +} + + +// +// Description: +// Set the MAC offset [0x09] and prevent all I/O for a while (about 20us~200us, suggested from SD4 Scott). +// If the protection is not performed well or the value is not set complete, the next I/O will cause the system hang. +// Note: +// This procudure is designed specifically for 8192S and references the platform based variables +// which violates the stucture of multi-platform. +// Thus, we shall not extend this procedure to common handler. +// By Bruce, 2009-01-08. +// +unsigned char +HalSetSysClk8192CD( struct rtl8192cd_priv *priv, unsigned char Data) +{ + RTL_W8((SYS_CLKR + 1), Data); + delay_us(200); + return TRUE; +} + + +static void LLT_table_init(struct rtl8192cd_priv *priv) +{ + + unsigned int i, count = 0; + +#if 1 + unsigned txpktbufSz, bufBd; +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode != SINGLEMAC_SINGLEPHY) { + txpktbufSz = 120; + bufBd = 127; + } else +#endif + { + txpktbufSz = 246; + bufBd = 255; + } +#else + unsigned txpktbufSz = 252; //174(0xAE) 120(0x78) 252(0xFC) +#endif + + for ( i = 0; i < txpktbufSz-1; i++) { + RTL_W32(LLT_INI, ((LLTE_RWM_WR&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT)|(i&LLTINI_ADDR_Mask)<<LLTINI_ADDR_SHIFT + |((i+1)&LLTINI_HDATA_Mask)<<LLTINI_HDATA_SHIFT); + + count = 0; + do { + if (!(RTL_R32(LLT_INI) & ((LLTE_RWM_RD&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT))) + break; + if (++count >= 100) { + printk("LLT_init, section 01, i=%d\n", i); + printk("LLT Polling failed 01 !!!\n"); + return; + } + } while(count < 100); + } + + RTL_W32(LLT_INI, ((LLTE_RWM_WR&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT) + |((txpktbufSz-1)&LLTINI_ADDR_Mask)<<LLTINI_ADDR_SHIFT|(255&LLTINI_HDATA_Mask)<<LLTINI_HDATA_SHIFT); + + count = 0; + do { + if (!(RTL_R32(LLT_INI) & ((LLTE_RWM_RD&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT))) + break; + if (++count >= 100) { + printk("LLT Polling failed 02 !!!\n"); + return; + } + } while(count < 100); + + + for (i = txpktbufSz; i < bufBd; i++) { + RTL_W32(LLT_INI, ((LLTE_RWM_WR&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT)|(i&LLTINI_ADDR_Mask)<<LLTINI_ADDR_SHIFT + |((i+1)&LLTINI_HDATA_Mask)<<LLTINI_HDATA_SHIFT); + + do{ + if (!(RTL_R32(LLT_INI) & ((LLTE_RWM_RD&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT))) + break; + if (++count >= 100) { + printk("LLT Polling failed 03 !!!\n"); + return; + } + }while(count < 100); + } + + RTL_W32(LLT_INI, ((LLTE_RWM_WR&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT)|(bufBd&LLTINI_ADDR_Mask)<<LLTINI_ADDR_SHIFT + |(txpktbufSz&LLTINI_HDATA_Mask)<<LLTINI_HDATA_SHIFT); + + count = 0; + do { + if (!(RTL_R32(LLT_INI) & ((LLTE_RWM_RD&LLTE_RWM_Mask)<<LLTE_RWM_SHIFT))) + break; + if(++count >= 100) { + printk("LLT Polling failed 04 !!!\n"); + return; + } + } while(count < 100); + +// Set reserved page for each queue + +#if 1 + /* normal queue init MUST be previoius of RQPN enable */ + //RTL_W8(RQPN_NPQ, 4); //RQPN_NPQ +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode != SINGLEMAC_SINGLEPHY ) + { + RTL_W8(RQPN_NPQ, 0x10); + //RTL_W32(RQPN, 0x80501010); + //RTL_W32(RQPN, 0x80630410); + RTL_W32(RQPN, 0x80600404); + } + else +#endif + { + RTL_W8(RQPN_NPQ, 0x29); + //RTL_W32(RQPN, 0x809f2929); + //RTL_W32(RQPN, 0x80a82029); + RTL_W32(RQPN, 0x80a92004); + } +#else + if(txpktbufSz == 120) + RTL_W32(RQPN, 0x80272828); + else if(txpktbufSz == 252) + { + //RTL_W32(RQPN, 0x80c31c1c); + + // Joseph test + //RTL_W32(RQPN, 0x80838484); + RTL_W32(RQPN, 0x80bd1c1c); + } + else + RTL_W32(RQPN, 0x80393a3a); +#endif + + //RTL_W32(TDECTRL, RTL_R32(TDECTRL)|(txpktbufSz&BCN_HEAD_Mask)<<BCN_HEAD_SHIFT); + RTL_W8(TXPKTBUF_BCNQ_BDNY, txpktbufSz); + RTL_W8(TXPKTBUF_MGQ_BDNY, txpktbufSz); + RTL_W8(TRXFF_BNDY, txpktbufSz); + RTL_W8(TDECTRL+1, txpktbufSz); + RTL_W8(0x45D, txpktbufSz); +} + + +static void MacInit(struct rtl8192cd_priv *priv) +{ + unsigned int bytetmp, retry; + DEBUG_INFO("CP: MacInit===>>"); + + RTL_W8(RSV_CTRL0, 0x00); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + RTL_W8(SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE); + + /* Enable PLL Power (LDOA15V) */ + RTL_W8(LDOA15_CTRL, LDA15_OBUF | LDA15_EN); + + /* advise by MAC team */ + RTL_W8(LDOHCI12_CTRL, 0x1f); + +#ifndef CONFIG_RTL_8198 + /* temp modifying, for 96c pocket ap better performance */ + bytetmp = REG32(0xb8000048); + bytetmp &= ~(BIT(10) | BIT(8)); + bytetmp |= BIT(19); + REG32(0xb8000048) = bytetmp; +#endif + } + +#endif + + // Power on when re-enter from IPS/Radio off/card disable + RTL_W8(AFE_XTAL_CTRL, 0x0d); // enable XTAL // clk inverted + RTL_W8(SPS0_CTRL, 0x2b); // enable SPS into PWM + delay_ms(1); + +#if 0 + // Enable AFE BANDGAP + RTL_W8(AFE_MISC, RTL_R8(AFE_MISC)|AFE_BGEN); + DEBUG_INFO("AFE_MISC = 0x%02x\n", RTL_R8(AFE_MISC)); + + // Enable AFE MBIAS + RTL_W8(AFE_MISC, RTL_R8(AFE_MISC)|AFE_MBEN); + DEBUG_INFO("AFE_MISC = 0x%02x\n", RTL_R8(AFE_MISC)); + + // Enable PLL Power (LDOA15V) +#ifdef CONFIG_RTL_92C_SUPPORT //#ifndef CONFIG_RTL_92D_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) + RTL_W8(LDOA15_CTRL, RTL_R8(LDOA15_CTRL)|LDA15_EN); +#endif + + // Enable VDDCORE (LDOD12V) + RTL_W8(LDOV12D_CTRL, RTL_R8(LDOV12D_CTRL)|LDV12_EN); + + // Release XTAL Gated for AFE PLL +// RTL_W32(AFE_XTAL_CTRL, RTL_R32(AFE_XTAL_CTRL)|XTAL_GATE_AFE); + RTL_W32(AFE_XTAL_CTRL, RTL_R32(AFE_XTAL_CTRL) & ~XTAL_GATE_AFE); + + // Enable AFE PLL + RTL_W32(AFE_PLL_CTRL, RTL_R32(AFE_PLL_CTRL)|APLL_EN); + + // Release Isolation AFE PLL & MD + RTL_W16(SYS_ISO_CTRL, RTL_R16(SYS_ISO_CTRL) & ~ISO_MD2PP); + + // Enable WMAC Clock + RTL_W16(SYS_CLKR, RTL_R16(SYS_CLKR)|MAC_CLK_EN|SEC_CLK_EN); + + // Release WMAC reset & register reset + RTL_W16(SYS_FUNC_EN, RTL_R16(SYS_FUNC_EN)|FEN_MREGEN|FEN_DCORE); + + // Release IMEM Isolation + RTL_W16(SYS_ISO_CTRL, RTL_R16(SYS_ISO_CTRL) & ~(BIT(10)|ISO_DIOR)); // need to confirm + +/* // need double setting??? + // Enable MAC IO registers + RTL_W16(SYS_FUNC_EN, RTL_R16(SYS_FUNC_EN)|FEN_MREGEN); +*/ + + // Switch HWFW select + RTL_W16(SYS_CLKR, (RTL_R16(SYS_CLKR)|CLKR_80M_SSC_DIS) & ~BIT(6)); // need to confirm +#else + // auto enable WLAN + + // Power On Reset for MAC Block + bytetmp = RTL_R8(APS_FSMCO+1) | BIT(0); + delay_us(2); + RTL_W8(APS_FSMCO+1, bytetmp); + delay_us(2); + + bytetmp = RTL_R8(APS_FSMCO+1); + delay_us(2); + retry = 0; + while((bytetmp & BIT(0)) && retry < 1000){ + retry++; + delay_us(50); + bytetmp = RTL_R8(APS_FSMCO+1); + delay_us(50); + } + + if (bytetmp & BIT(0)) { + DEBUG_ERR("%s ERROR: auto enable WLAN failed!!(0x%02X)\n", __FUNCTION__, bytetmp); + } + + // Enable Radio off, GPIO, and LED function + RTL_W16(APS_FSMCO, 0x1012); // when enable HWPDN + + // release RF digital isolation + RTL_W8(SYS_ISO_CTRL+1, 0x82); + + delay_us(2); +#endif + + // Release MAC IO register reset + RTL_W32(CR, RTL_R32(CR)|MACRXEN|MACTXEN|SCHEDULE_EN|PROTOCOL_EN + |RXDMA_EN|TXDMA_EN|HCI_RXDMA_EN|HCI_TXDMA_EN); + + //System init + LLT_table_init(priv); + + // Clear interrupt and enable interrupt + RTL_W32(HISR, 0xFFFFFFFF); + RTL_W16(HISRE, 0xFFFF); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + unsigned char reg; + reg = MAC_PHY_CTRL_MP; + + switch(priv->pmib->dot11RFEntry.macPhyMode) { + case SINGLEMAC_SINGLEPHY: +#if 0 + RTL_W8(reg, 0xf4); //enable super mac +#else + RTL_W8(reg, 0xfc); //enable super mac + RTL_W8(MAC_PHY_CTRL_T, 0xfc); +#endif + RTL_W32(AGGLEN_LMT, 0xb972a841); + break; + case DUALMAC_SINGLEPHY: + RTL_W8(reg, 0xf1); //enable supermac + RTL_W32(AGGLEN_LMT, 0x54325521); + break; + case DUALMAC_DUALPHY: + RTL_W8(reg, 0xf3); //DMDP + RTL_W32(AGGLEN_LMT, 0x54325521); + break; + default: + DEBUG_ERR("Unknown 92D macPhyMode selection!\n"); + } + /* + * Set Rx FF0 boundary, half sized for testchip & dual MAC + */ +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode!=SINGLEMAC_SINGLEPHY) + RTL_W32(TRXFF_BNDY, (RTL_R32(TRXFF_BNDY)&0x0000FFFF)|(0x13ff&RXFF0_BNDY_Mask)<<RXFF0_BNDY_SHIFT); + else +#endif + RTL_W32(TRXFF_BNDY, (RTL_R32(TRXFF_BNDY)&0x0000FFFF)|(0x27ff&RXFF0_BNDY_Mask)<<RXFF0_BNDY_SHIFT); + + } + else + { + RTL_W32(TRXFF_BNDY, (RTL_R32(TRXFF_BNDY)&0x0000FFFF)|(0x27FF&RXFF0_BNDY_Mask)<<RXFF0_BNDY_SHIFT); + } + +#else + // Set Rx FF0 boundary : 9K/10K + RTL_W32(TRXFF_BNDY, (RTL_R32(TRXFF_BNDY)&0x0000FFFF)|(0x27FF&RXFF0_BNDY_Mask)<<RXFF0_BNDY_SHIFT); + + if (IS_TEST_CHIP(priv)) { + // Set High priority queue select : HPQ:BC/H/VO/VI/MG, LPQ:BE/BK + // [5]:H, [4]:MG, [3]:BK, [2]:BE, [1]:VI, [0]:VO + RTL_W16(TRXDMA_CTRL, ((HPQ_SEL_HIQ|HPQ_SEL_MGQ|HPQ_SEL_VIQ|HPQ_SEL_VOQ)&HPQ_SEL_Mask)<<HPQ_SEL_SHIFT); + + /* + * Enable ampdu rx check error, and enable rx byte shift + */ + RTL_W8(TRXDMA_CTRL, RTL_R8(TRXDMA_CTRL) | RXSHFT_EN | RXDMA_ARBBW_EN); + } else +#endif + { + //RTL_W16(TRXDMA_CTRL, (0xB770 | RXSHFT_EN | RXDMA_ARBBW_EN)); + RTL_W16(TRXDMA_CTRL, (0x5660 | RXSHFT_EN | RXDMA_ARBBW_EN)); + } + + +// RTL_W8(TDECTRL, 0x11); // need to confirm + + // Set Network type: ap mode + RTL_W32(CR, RTL_R32(CR) | ((NETYPE_AP & NETYPE_Mask) << NETYPE_SHIFT)); + + // Set SLOT time + RTL_W8(SLOT_TIME, 0x09); + + // Set AMPDU min space + RTL_W8(AMPDU_MIN_SPACE, 0); // need to confirm + + // Set Tx/Rx page size (Tx must be 128 Bytes, Rx can be 64,128,256,512,1024 bytes) + RTL_W8(PBP, (PBP_128B&PSTX_Mask)<<PSTX_SHIFT|(PBP_128B&PSRX_Mask)<<PSRX_SHIFT); + + // Set RCR register + RTL_W32(RCR, RCR_APP_FCS|RCR_APP_MIC|RCR_APP_ICV|RCR_APP_PHYSTS|RCR_HTC_LOC_CTRL + |RCR_AMF|RCR_ADF|RCR_AICV|RCR_ACRC32|RCR_AB|RCR_AM|RCR_APM|RCR_AAP); + + // Set Driver info size + RTL_W8(RX_DRVINFO_SZ, 4); + + // This part is not in WMAC InitMAC() + // Set SEC register + RTL_W16(SECCFG, RTL_R16(SECCFG) & ~(RXUSEDK | TXUSEDK)); + + // Set TCR register +// RTL_W32(TCR, RTL_R32(TCR)|CRC|CFE_FORM); + RTL_W32(TCR, RTL_R32(TCR)|CFE_FORM); + + // Set TCR to avoid deadlock + RTL_W32(TCR, RTL_R32(TCR)|BIT(15)|BIT(14)|BIT(13)|BIT(12)); + + // Set RRSR (response rate set reg) + //SetResponseRate(); + // Set RRSR (response rate set reg) + // Set RRSR to all legacy rate and HT rate + // CCK rate is supported by default. + // CCK rate will be filtered out only when associated AP does not support it. + // Only enable ACK rate to OFDM 24M +#ifdef CONFIG_RTL_92D_SUPPORT + + if (GET_CHIP_VER(priv)==VERSION_8192D) { + /* + * Set RRSR at here before MACPHY_REG.txt is ready + */ + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { + /* + * PHY_BAND_5G + */ + RTL_W16(RRSR, 0x150); + } else{ + /* + * PHY_BAND_2G + */ + RTL_W16(RRSR, 0x15D); + } + RTL_W8(RRSR+2, 0); + + RTL_W8(RCR, 0x0e); //follow 92c MACPHY_REG + RTL_W8(RCR+1, 0x2a); //follow 92c MACPHY_REG + } + else + { + RTL_W16(RRSR, 0xFFFF); + RTL_W8(RRSR+2, 0xFF); + + } +#else + RTL_W16(RRSR, 0xFFFF); + RTL_W8(RRSR+2, 0xFF); +#endif + + // Set Spec SIFS (used in NAV) + // Joseph test + RTL_W16(SPEC_SIFS_A, (0x0A&SPEC_SIFS_OFDM_Mask)<<SPEC_SIFS_OFDM_SHIFT + |(0x0A&SPEC_SIFS_CCK_Mask)<<SPEC_SIFS_CCK_SHIFT); + + // Set SIFS for CCK + // Joseph test + RTL_W16(SIFS_CCK, (0x0A&SIFS_TRX_Mask)<<SIFS_TRX_SHIFT|(0x0A&SIFS_CTX_Mask)<<SIFS_CTX_SHIFT); + + // Set SIFS for OFDM + // Joseph test + RTL_W16(SIFS_OFDM, (0x0A&SIFS_TRX_Mask)<<SIFS_TRX_SHIFT|(0x0A&SIFS_CTX_Mask)<<SIFS_CTX_SHIFT); + + // Set retry limit + // Joseph test + priv->pshare->RLShort = 0x10;//0x30; + priv->pshare->RLLong = 0x10; //0x30; + +#ifdef CLIENT_MODE + if (priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) + { + priv->pshare->RLShort = 0x30; + priv->pshare->RLLong = 0x30; + } +#endif + + RTL_W16(RL, (priv->pshare->RLShort&SRL_Mask)<<SRL_SHIFT|(priv->pshare->RLLong&LRL_Mask)<<LRL_SHIFT); + + //Set Desc Address + RTL_W32(BCNQ_DESA, priv->pshare->phw->tx_ringB_addr); + RTL_W32(MGQ_DESA, priv->pshare->phw->tx_ring0_addr); + RTL_W32(VOQ_DESA, priv->pshare->phw->tx_ring4_addr); + RTL_W32(VIQ_DESA, priv->pshare->phw->tx_ring3_addr); + RTL_W32(BEQ_DESA, priv->pshare->phw->tx_ring2_addr); + RTL_W32(BKQ_DESA, priv->pshare->phw->tx_ring1_addr); + RTL_W32(HQ_DESA, priv->pshare->phw->tx_ring5_addr); + RTL_W32(RX_DESA, priv->pshare->phw->ring_dma_addr); +// RTL_W32(RCDA, priv->pshare->phw->rxcmd_ring_addr); +// RTL_W32(TCDA, priv->pshare->phw->txcmd_ring_addr); +// RTL_W32(TCDA, phw->tx_ring5_addr); + // 2009/03/13 MH Prevent incorrect DMA write after accident reset !!! +// RTL_W16(CMDR, 0x37FC); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) + RTL_W32(PCIE_CTRL_REG, (RTL_R32(PCIE_CTRL_REG) & 0x00ffffff)|(0x03&MAX_RXDMA_Mask)<<MAX_RXDMA_SHIFT + |(0x03&MAX_TXDMA_Mask)<<MAX_TXDMA_SHIFT | BCNQSTOP); + else +#endif + RTL_W32(PCIE_CTRL_REG, RTL_R32(PCIE_CTRL_REG)|(0x07&MAX_RXDMA_Mask)<<MAX_RXDMA_SHIFT + |(0x07&MAX_TXDMA_Mask)<<MAX_TXDMA_SHIFT | BCNQSTOP); + + // 20090928 Joseph + // Reconsider when to do this operation after asking HWSD. + RTL_W8(APSD_CTRL, RTL_R8(APSD_CTRL) & ~ BIT(6)); + retry = 0; + do{ + retry++; + bytetmp = RTL_R8(APSD_CTRL); + } while((retry<200) && (bytetmp&BIT(7))); //polling until BIT7 is 0. by tynli + + if (bytetmp & BIT(7)) { + DEBUG_ERR("%s ERROR: APSD_CTRL=0x%02X\n", __FUNCTION__, bytetmp); + } + // disable BT_enable + RTL_W8(GPIO_MUXCFG, 0); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + RTL_W16(TCR, RTL_R16(TCR) | WMAC_TCR_ERRSTEN3 | WMAC_TCR_ERRSTEN2 + | WMAC_TCR_ERRSTEN1 | WMAC_TCR_ERRSTEN0); +/* + * For 92DE,Mac0 and Mac1 power off. + * 0x1F BIT6: 0 mac0 off, 1: mac0 on + * BIT7: 0 mac1 off, 1: mac1 on. + */ +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pshare->wlandev_idx == 0) +#endif + { + RTL_W8(RSV_MAC0_CTRL, RTL_R8(RSV_MAC0_CTRL)|MAC0_EN); + + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G) + RTL_W8(RSV_MAC0_CTRL, RTL_R8(RSV_MAC0_CTRL) & (~BAND_STAT)); + else + RTL_W8(RSV_MAC0_CTRL, RTL_R8(RSV_MAC0_CTRL) | BAND_STAT); + } + +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pshare->wlandev_idx ==1) + { + RTL_W8(RSV_MAC1_CTRL, RTL_R8(RSV_MAC1_CTRL)|MAC1_EN); + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G) + RTL_W8(RSV_MAC1_CTRL, RTL_R8(RSV_MAC1_CTRL) & (~BAND_STAT)); + else + RTL_W8(RSV_MAC1_CTRL, RTL_R8(RSV_MAC1_CTRL) | BAND_STAT); + } +#endif + } +#endif //CONFIG_RTL_92D_SUPPORT + + DEBUG_INFO("DONE\n"); +} // MacInit + + +static void MacConfig(struct rtl8192cd_priv *priv) +{ + RTL_W8(INIRTS_RATE_SEL, 0x8); // 24M + + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + //For 92C,which reg? + // RTL_W8(BWOPMODE, BW_20M); // set if work at 20m + + // Ack timeout. + if ((priv->pmib->miscEntry.ack_timeout > 0) && (priv->pmib->miscEntry.ack_timeout < 0xff)) + RTL_W8(ACKTO, priv->pmib->miscEntry.ack_timeout); + else + RTL_W8(ACKTO, 0x40); + + // clear for mbid beacon tx + RTL_W8(MULTI_BCNQ_EN, 0); + RTL_W8(MULTI_BCNQ_OFFSET, 0); + +#ifdef CONFIG_RTL_92D_SUPPORT + if ((GET_CHIP_VER(priv)==VERSION_8192D) && (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G)){ + RTL_W32(ARFR0, 0xFF010); // 40M mode + RTL_W32(ARFR1, 0xFF010); // 20M mode + } else +#endif + { + // set user defining ARFR table for 11n 1T + RTL_W32(ARFR0, 0xFF015); // 40M mode + RTL_W32(ARFR1, 0xFF005); // 20M mode + } + /* + * Disable TXOP CFE + */ + RTL_W16(RD_CTRL, RTL_R16(RD_CTRL) | DIS_TXOP_CFE); + +#ifdef CONFIG_RTL_92D_SUPPORT + RTL_W8(MAC_SEL, 0); + RTL_W8(0x526, 0xff); /* enable all MBID interface beacon */ + + /* + * Protection mode control for hw RTS + */ + RTL_W16(PROT_MODE_CTRL, 0xff0D); +#endif + + /* + * RA try rate aggr limit + */ + RTL_W8(RA_TRY_RATE_AGG_LMT, 2); + + /* + * Max mpdu number per aggr + */ + RTL_W16(PROT_MODE_CTRL+2, 0x0909); +} + + +unsigned int get_mean_of_2_close_value(unsigned int *val_array) +{ + unsigned int tmp1, tmp2; + + //printk("v1 %08x v2 %08x v3 %08x\n", val_array[0], val_array[1], val_array[2]); + if (val_array[0] > val_array[1]) { + tmp1 = val_array[1]; + val_array[1] = val_array[0]; + val_array[0] = tmp1; + } + if (val_array[1] > val_array[2]) { + tmp1 = val_array[2]; + val_array[2] = val_array[1]; + val_array[1] = tmp1; + } + if (val_array[0] > val_array[1]) { + tmp1 = val_array[1]; + val_array[1] = val_array[0]; + val_array[0] = tmp1; + } + //printk("v1 %08x v2 %08x v3 %08x\n", val_array[0], val_array[1], val_array[2]); + + tmp1 = val_array[1] - val_array[0]; + tmp2 = val_array[2] - val_array[1]; + if (tmp1 < tmp2) + tmp1 = (val_array[0] + val_array[1]) / 2; + else + tmp1 = (val_array[1] + val_array[2]) / 2; + + //printk("final %08x\n", tmp1); + return tmp1; +} + +#ifdef CONFIG_RTL_92C_SUPPORT +#ifndef CONFIG_RTL_NEW_IQK +static void IQK_92CD(struct rtl8192cd_priv *priv) +{ + unsigned int cal_num=0, cal_retry=0, Oldval=0, temp_c04=0, temp_c08=0, temp_874=0, temp_eac; + unsigned int cal_e94, cal_e9c, cal_ea4, cal_eac, cal_eb4, cal_ebc, cal_ec4, cal_ecc, adda_on_reg; + unsigned int X, Y, val_e94[3], val_e9c[3], val_ea4[3], val_eac[3], val_eb4[3], val_ebc[3], val_ec4[3], val_ecc[3]; +#ifdef HIGH_POWER_EXT_PA + unsigned int temp_870=0, temp_860=0, temp_864=0; +#endif + + // step 1: save ADDA power saving parameters + unsigned int temp_85c = RTL_R32(0x85c); + unsigned int temp_e6c = RTL_R32(0xe6c); + unsigned int temp_e70 = RTL_R32(0xe70); + unsigned int temp_e74 = RTL_R32(0xe74); + unsigned int temp_e78 = RTL_R32(0xe78); + unsigned int temp_e7c = RTL_R32(0xe7c); + unsigned int temp_e80 = RTL_R32(0xe80); + unsigned int temp_e84 = RTL_R32(0xe84); + unsigned int temp_e88 = RTL_R32(0xe88); + unsigned int temp_e8c = RTL_R32(0xe8c); + unsigned int temp_ed0 = RTL_R32(0xed0); + unsigned int temp_ed4 = RTL_R32(0xed4); + unsigned int temp_ed8 = RTL_R32(0xed8); + unsigned int temp_edc = RTL_R32(0xedc); + unsigned int temp_ee0 = RTL_R32(0xee0); + unsigned int temp_eec = RTL_R32(0xeec); + +printk(">> %s \n",__FUNCTION__); + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + temp_870 = RTL_R32(0x870); + temp_860 = RTL_R32(0x860); + temp_864 = RTL_R32(0x864); + } +#endif + + // step 2: Path-A ADDA all on + adda_on_reg = 0x04db25a4; + + RTL_W32(0x85c, adda_on_reg); + RTL_W32(0xe6c, adda_on_reg); + RTL_W32(0xe70, adda_on_reg); + RTL_W32(0xe74, adda_on_reg); + RTL_W32(0xe78, adda_on_reg); + RTL_W32(0xe7c, adda_on_reg); + RTL_W32(0xe80, adda_on_reg); + RTL_W32(0xe84, adda_on_reg); + RTL_W32(0xe88, adda_on_reg); + RTL_W32(0xe8c, adda_on_reg); + RTL_W32(0xed0, adda_on_reg); + RTL_W32(0xed4, adda_on_reg); + RTL_W32(0xed8, adda_on_reg); + RTL_W32(0xedc, adda_on_reg); + RTL_W32(0xee0, adda_on_reg); + RTL_W32(0xeec, adda_on_reg); + + // step 3: IQ&LO calibration Setting + // BB switch to PI mode + //RTL_W32(0x820, 0x01000100); + //RTL_W32(0x828, 0x01000100); + //BB setting + temp_c04 = RTL_R32(0xc04); + temp_c08 = RTL_R32(0xc08); + temp_874 = RTL_R32(0x874); + RTL_W32(0xc04, 0x03a05600); + RTL_W32(0xc08, 0x000800e4); + RTL_W32(0x874, 0x00204000); + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + PHY_SetBBReg(priv, 0x870, BIT(10), 1); + PHY_SetBBReg(priv, 0x870, BIT(26), 1); + PHY_SetBBReg(priv, 0x860, BIT(10), 0); + PHY_SetBBReg(priv, 0x864, BIT(10), 0); + } +#endif + RTL_W32(0x840, 0x00010000); + RTL_W32(0x844, 0x00010000); + + //AP or IQK + RTL_W32(0xb68 , 0x00080000); + RTL_W32(0xb6c , 0x00080000); + + // IQK setting + RTL_W32(0xe28, 0x80800000); + RTL_W32(0xe40, 0x01007c00); + RTL_W32(0xe44, 0x01004800); + // path-A IQK setting + RTL_W32(0xe30, 0x10008c1f); + RTL_W32(0xe34, 0x10008c1f); + RTL_W32(0xe38, 0x82140102); + RTL_W32(0xe3c, 0x28160202); + // path-B IQK setting + RTL_W32(0xe50, 0x10008c22); + RTL_W32(0xe54, 0x10008c22); + RTL_W32(0xe58, 0x82140102); + RTL_W32(0xe5c, 0x28160202); + // LO calibration setting + RTL_W32(0xe4c, 0x001028d1); + + // delay to ensure Path-A IQK success + delay_ms(300); + + // step 4: One shot, path A LOK & IQK + while (cal_num < 3) { + // One shot, path A LOK & IQK + RTL_W32(0xe48, 0xf9000000); + RTL_W32(0xe48, 0xf8000000); + // delay 1ms + delay_ms(10); + + // check fail bit and check abnormal condition, then fill BB IQ matrix + cal_e94 = (RTL_R32(0xe94) >> 16) & 0x3ff; + cal_e9c = (RTL_R32(0xe9c) >> 16) & 0x3ff; + cal_ea4 = (RTL_R32(0xea4) >> 16) & 0x3ff; + temp_eac = RTL_R32(0xeac); + cal_eac = (temp_eac >> 16) & 0x3ff; + if (!(temp_eac & BIT(28)) && !(temp_eac & BIT(27)) && + (cal_e94 != 0x142) && (cal_e9c != 0x42) && + (cal_ea4 != 0x132) && (cal_eac != 0x36)) { + val_e94[cal_num] = cal_e94; + val_e9c[cal_num] = cal_e9c; + val_ea4[cal_num] = cal_ea4; + val_eac[cal_num] = cal_eac; + cal_num++; + } else { + if (++cal_retry >= 10) { + printk("%s Path-A Check\n",__FUNCTION__); + break; + } + } + } + + if (cal_num == 3) { + cal_e94 = get_mean_of_2_close_value(val_e94); + cal_e9c = get_mean_of_2_close_value(val_e9c); + cal_ea4 = get_mean_of_2_close_value(val_ea4); + cal_eac = get_mean_of_2_close_value(val_eac); + + priv->pshare->RegE94=cal_e94; + priv->pshare->RegE9C=cal_e9c; + + Oldval = (RTL_R32(0xc80) >> 22) & 0x3ff; + + X = cal_e94; + PHY_SetBBReg(priv, 0xc80, 0x3ff, X * (Oldval / 0x100)); + PHY_SetBBReg(priv, 0xc4c, BIT(24), ((X * Oldval) >> 7) & 0x1); + + Y = cal_e9c; + PHY_SetBBReg(priv, 0xc94, 0xf0000000, ((Y * (Oldval / 0x100)) >> 6) & 0xf); + PHY_SetBBReg(priv, 0xc80, 0x003f0000, (Y * (Oldval / 0x100)) & 0x3f); + PHY_SetBBReg(priv, 0xc4c, BIT(26), ((Y * Oldval) >> 7) & 0x1); + + PHY_SetBBReg(priv, 0xc14, 0x3ff, cal_ea4); + + PHY_SetBBReg(priv, 0xc14, 0xfc00, cal_eac & 0x3f); + + PHY_SetBBReg(priv, 0xca0, 0xf0000000, (cal_eac >> 6) & 0xf); + }else { + priv->pshare->RegE94=0x100; + priv->pshare->RegE9C=0x00; + } + + // step 5: Path-A standby mode + RTL_W32(0xe28, 0); + RTL_W32(0x840, 0x00010000); + RTL_W32(0xe28, 0x80800000); + + // step 6: Path-B ADDA all on + adda_on_reg = 0x0b1b25a4; + + RTL_W32(0x85c, adda_on_reg); + RTL_W32(0xe6c, adda_on_reg); + RTL_W32(0xe70, adda_on_reg); + RTL_W32(0xe74, adda_on_reg); + RTL_W32(0xe78, adda_on_reg); + RTL_W32(0xe7c, adda_on_reg); + RTL_W32(0xe80, adda_on_reg); + RTL_W32(0xe84, adda_on_reg); + RTL_W32(0xe88, adda_on_reg); + RTL_W32(0xe8c, adda_on_reg); + RTL_W32(0xed0, adda_on_reg); + RTL_W32(0xed4, adda_on_reg); + RTL_W32(0xed8, adda_on_reg); + RTL_W32(0xedc, adda_on_reg); + RTL_W32(0xee0, adda_on_reg); + RTL_W32(0xeec, adda_on_reg); + + // step 7: One shot, path B LOK & IQK + cal_num = 0; + cal_retry = 0; + while (cal_num < 3) { + // One shot, path B LOK & IQK + RTL_W32(0xe60, 2); + RTL_W32(0xe60, 0); + // delay 1ms + delay_ms(10); + + // check fail bit and check abnormal condition, then fill BB IQ matrix + cal_eb4 = (RTL_R32(0xeb4) >> 16) & 0x3ff; + cal_ebc = (RTL_R32(0xebc) >> 16) & 0x3ff; + cal_ec4 = (RTL_R32(0xec4) >> 16) & 0x3ff; + cal_ecc = (RTL_R32(0xecc) >> 16) & 0x3ff; + temp_eac = RTL_R32(0xeac); + if (!(temp_eac & BIT(31)) && !(temp_eac & BIT(30)) && + (cal_eb4 != 0x142) && (cal_ebc != 0x42) && + (cal_ec4 != 0x132) && (cal_ecc != 0x36)) { + val_eb4[cal_num] = cal_eb4; + val_ebc[cal_num] = cal_ebc; + val_ec4[cal_num] = cal_ec4; + val_ecc[cal_num] = cal_ecc; + cal_num++; + } else { + if (++cal_retry >= 10) { + printk("%s Path-B Check\n",__FUNCTION__); + break; + } + } + } + + if (cal_num == 3) { + cal_eb4 = get_mean_of_2_close_value(val_eb4); + cal_ebc = get_mean_of_2_close_value(val_ebc); + cal_ec4 = get_mean_of_2_close_value(val_ec4); + cal_ecc = get_mean_of_2_close_value(val_ecc); + + priv->pshare->RegEB4=cal_eb4; + priv->pshare->RegEBC=cal_ebc; + + Oldval = (RTL_R32(0xc88) >> 22) & 0x3ff; + + X = cal_eb4; + PHY_SetBBReg(priv, 0xc88, 0x3ff, X * (Oldval / 0x100)); + PHY_SetBBReg(priv, 0xc4c, BIT(28), ((X * Oldval) >> 7) & 0x1); + + Y = cal_ebc; + PHY_SetBBReg(priv, 0xc9c, 0xf0000000, ((Y * (Oldval / 0x100)) >> 6) & 0xf); + PHY_SetBBReg(priv, 0xc88, 0x003f0000, (Y * (Oldval / 0x100)) & 0x3f); + PHY_SetBBReg(priv, 0xc4c, BIT(30), ((Y * Oldval) >> 7) & 0x1); + + PHY_SetBBReg(priv, 0xc1c, 0x3ff, cal_ec4); + + PHY_SetBBReg(priv, 0xc1c, 0xfc00, cal_ecc & 0x3f); + + PHY_SetBBReg(priv, 0xc78, 0xf000, (cal_ecc >> 6) & 0xf); + }else { + priv->pshare->RegEB4=0x100; + priv->pshare->RegEBC=0x00; + } + + + // step 8: back to BB mode, load original values + RTL_W32(0xc04, temp_c04); + RTL_W32(0x874, temp_874); + RTL_W32(0xc08, temp_c08); + RTL_W32(0xe28, 0); + RTL_W32(0x840, 0x32ed3); + RTL_W32(0x844, 0x32ed3); +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + RTL_W32(0x870, temp_870); + RTL_W32(0x860, temp_860); + RTL_W32(0x864, temp_864); + } +#endif + // return to SI mode + //RTL_W32(0x820, 0x01000000); + //RTL_W32(0x828, 0x01000000); + + // step 9: reload ADDA power saving parameters + RTL_W32(0x85c, temp_85c); + RTL_W32(0xe6c, temp_e6c); + RTL_W32(0xe70, temp_e70); + RTL_W32(0xe74, temp_e74); + RTL_W32(0xe78, temp_e78); + RTL_W32(0xe7c, temp_e7c); + RTL_W32(0xe80, temp_e80); + RTL_W32(0xe84, temp_e84); + RTL_W32(0xe88, temp_e88); + RTL_W32(0xe8c, temp_e8c); + RTL_W32(0xed0, temp_ed0); + RTL_W32(0xed4, temp_ed4); + RTL_W32(0xed8, temp_ed8); + RTL_W32(0xedc, temp_edc); + RTL_W32(0xee0, temp_ee0); + RTL_W32(0xeec, temp_eec); + +} + + +static void IQK_88C(struct rtl8192cd_priv *priv) +{ + unsigned int cal_num=0, cal_retry=0; + unsigned int Oldval_0=0, temp_c04=0, temp_c08=0, temp_874=0; + unsigned int cal_e94, cal_e9c, cal_ea4, cal_eac, temp_eac; + unsigned int X, Y, val_e94[3], val_e9c[3], val_ea4[3], val_eac[3]; + +#ifdef HIGH_POWER_EXT_PA + unsigned int temp_870=0, temp_860=0, temp_864=0; +#endif + // step 1: save ADDA power saving parameters + unsigned int temp_85c = RTL_R32(0x85c); + unsigned int temp_e6c = RTL_R32(0xe6c); + unsigned int temp_e70 = RTL_R32(0xe70); + unsigned int temp_e74 = RTL_R32(0xe74); + unsigned int temp_e78 = RTL_R32(0xe78); + unsigned int temp_e7c = RTL_R32(0xe7c); + unsigned int temp_e80 = RTL_R32(0xe80); + unsigned int temp_e84 = RTL_R32(0xe84); + unsigned int temp_e88 = RTL_R32(0xe88); + unsigned int temp_e8c = RTL_R32(0xe8c); + unsigned int temp_ed0 = RTL_R32(0xed0); + unsigned int temp_ed4 = RTL_R32(0xed4); + unsigned int temp_ed8 = RTL_R32(0xed8); + unsigned int temp_edc = RTL_R32(0xedc); + unsigned int temp_ee0 = RTL_R32(0xee0); + unsigned int temp_eec = RTL_R32(0xeec); + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + temp_870 = RTL_R32(0x870); + temp_860 = RTL_R32(0x860); + temp_864 = RTL_R32(0x864); + } +#endif + + // step 2: ADDA all on + RTL_W32(0x85c, 0x0b1b25a0); + RTL_W32(0xe6c, 0x0bdb25a0); + RTL_W32(0xe70, 0x0bdb25a0); + RTL_W32(0xe74, 0x0bdb25a0); + RTL_W32(0xe78, 0x0bdb25a0); + RTL_W32(0xe7c, 0x0bdb25a0); + RTL_W32(0xe80, 0x0bdb25a0); + RTL_W32(0xe84, 0x0bdb25a0); + RTL_W32(0xe88, 0x0bdb25a0); + RTL_W32(0xe8c, 0x0bdb25a0); + RTL_W32(0xed0, 0x0bdb25a0); + RTL_W32(0xed4, 0x0bdb25a0); + RTL_W32(0xed8, 0x0bdb25a0); + RTL_W32(0xedc, 0x0bdb25a0); + RTL_W32(0xee0, 0x0bdb25a0); + RTL_W32(0xeec, 0x0bdb25a0); + + // step 3: start IQK + // BB switch to PI mode + //RTL_W32(0x820, 0x01000100); + //RTL_W32(0x828, 0x01000100); + //BB setting + temp_c04 = RTL_R32(0xc04); + temp_c08 = RTL_R32(0xc08); + temp_874 = RTL_R32(0x874); + RTL_W32(0xc04, 0x03a05600); + RTL_W32(0xc08, 0x000800e4); + RTL_W32(0x874, 0x00204000); +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + PHY_SetBBReg(priv, 0x870, BIT(10), 1); + PHY_SetBBReg(priv, 0x870, BIT(26), 1); + PHY_SetBBReg(priv, 0x860, BIT(10), 0); + PHY_SetBBReg(priv, 0x864, BIT(10), 0); + } +#endif + + //AP or IQK +// RTL_W32(0xb68, 0x0f600000); + RTL_W32(0xb68, 0x00080000); + + // IQK setting + RTL_W32(0xe28, 0x80800000); + RTL_W32(0xe40, 0x01007c00); + RTL_W32(0xe44, 0x01004800); + // path-A IQK setting + RTL_W32(0xe30, 0x10008c1f); + RTL_W32(0xe34, 0x10008c1f); + RTL_W32(0xe38, 0x82140102); + //RTL_W32(0xe3c, 0x28160502); + RTL_W32(0xe3c, 0x28160202); + + // LO calibration setting + RTL_W32(0xe4c, 0x001028d1); + + while (cal_num < 3) { + // One shot, path A LOK & IQK + RTL_W32(0xe48, 0xf9000000); + RTL_W32(0xe48, 0xf8000000); + // delay 1ms + delay_ms(150); + + // step 4: check fail bit and check abnormal condition, then fill BB IQ matrix + cal_e94 = (RTL_R32(0xe94) >> 16) & 0x3ff; + cal_e9c = (RTL_R32(0xe9c) >> 16) & 0x3ff; + cal_ea4 = (RTL_R32(0xea4) >> 16) & 0x3ff; + temp_eac = RTL_R32(0xeac); + cal_eac = (temp_eac >> 16) & 0x3ff; + if (!(temp_eac & BIT(28)) && !(temp_eac & BIT(27)) && + (cal_e94 != 0x142) && (cal_e9c != 0x42) && + (cal_ea4 != 0x132) && (cal_eac != 0x36)) { + val_e94[cal_num] = cal_e94; + val_e9c[cal_num] = cal_e9c; + val_ea4[cal_num] = cal_ea4; + val_eac[cal_num] = cal_eac; + cal_num++; + } else { + if (++cal_retry >= 10) { + printk("IQK Check\n"); + break; + } + } + } + + if (cal_num == 3) { + cal_e94 = get_mean_of_2_close_value(val_e94); + cal_e9c = get_mean_of_2_close_value(val_e9c); + cal_ea4 = get_mean_of_2_close_value(val_ea4); + cal_eac = get_mean_of_2_close_value(val_eac); + + priv->pshare->RegE94=cal_e94; + priv->pshare->RegE9C=cal_e9c; + + Oldval_0 = (RTL_R32(0xc80) >> 22) & 0x3ff; + + X = cal_e94; + PHY_SetBBReg(priv, 0xc80, 0x3ff, X * (Oldval_0 / 0x100)); + PHY_SetBBReg(priv, 0xc4c, BIT(24), ((X * Oldval_0) >> 7) & 0x1); + + Y = cal_e9c; + PHY_SetBBReg(priv, 0xc94, 0xf0000000, ((Y * (Oldval_0 / 0x100)) >> 6) & 0xf); + PHY_SetBBReg(priv, 0xc80, 0x003f0000, (Y * (Oldval_0 / 0x100)) & 0x3f); + PHY_SetBBReg(priv, 0xc4c, BIT(26), ((Y * Oldval_0) >> 7) & 0x1); + + PHY_SetBBReg(priv, 0xc14, 0x3ff, cal_ea4); + + PHY_SetBBReg(priv, 0xc14, 0xfc00, cal_eac & 0x3f); + + PHY_SetBBReg(priv, 0xca0, 0xf0000000, (cal_eac >> 6) & 0xf); + }else { + priv->pshare->RegE94=0x100; + priv->pshare->RegE9C=0x00; + } + + // back to BB mode + RTL_W32(0xc04, temp_c04); + RTL_W32(0x874, temp_874); + RTL_W32(0xc08, temp_c08); + RTL_W32(0xe28, 0); + RTL_W32(0x840, 0x00032ed3); +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + RTL_W32(0x870, temp_870); + RTL_W32(0x860, temp_860); + RTL_W32(0x864, temp_864); + } +#endif + // return to SI mode + //RTL_W32(0x820, 0x01000000); + //RTL_W32(0x828, 0x01000000); + + // step 5: reload ADDA power saving parameters + RTL_W32(0x85c, temp_85c); + RTL_W32(0xe6c, temp_e6c); + RTL_W32(0xe70, temp_e70); + RTL_W32(0xe74, temp_e74); + RTL_W32(0xe78, temp_e78); + RTL_W32(0xe7c, temp_e7c); + RTL_W32(0xe80, temp_e80); + RTL_W32(0xe84, temp_e84); + RTL_W32(0xe88, temp_e88); + RTL_W32(0xe8c, temp_e8c); + RTL_W32(0xed0, temp_ed0); + RTL_W32(0xed4, temp_ed4); + RTL_W32(0xed8, temp_ed8); + RTL_W32(0xedc, temp_edc); + RTL_W32(0xee0, temp_ee0); + RTL_W32(0xeec, temp_eec); +} // IQK +#endif + +void _PHY_SaveADDARegisters(struct rtl8192cd_priv *priv, unsigned int* ADDAReg, unsigned int* ADDABackup, unsigned int RegisterNum) +{ + unsigned int i; + for( i = 0 ; i < RegisterNum ; i++){ + ADDABackup[i] = PHY_QueryBBReg(priv, ADDAReg[i], bMaskDWord); + } +} + +void _PHY_SaveMACRegisters(struct rtl8192cd_priv *priv, unsigned int* MACReg, unsigned int* MACBackup) +{ + unsigned int i; + for( i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ + MACBackup[i] = RTL_R8(MACReg[i]); + } + MACBackup[i] = RTL_R32( MACReg[i]); +} + +void _PHY_ReloadADDARegisters(struct rtl8192cd_priv *priv, unsigned int* ADDAReg, unsigned int* ADDABackup, unsigned int RegiesterNum) +{ + unsigned int i; + for(i = 0 ; i < RegiesterNum; i++){ + PHY_SetBBReg(priv, ADDAReg[i], bMaskDWord, ADDABackup[i]); + } +} + +void _PHY_ReloadMACRegisters(struct rtl8192cd_priv *priv,unsigned int* MACReg, unsigned int* MACBackup) +{ + unsigned int i; + for(i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ + RTL_W8( MACReg[i], (unsigned char)MACBackup[i]); + } + RTL_W32( MACReg[i], MACBackup[i]); +} + +void _PHY_MACSettingCalibration(struct rtl8192cd_priv *priv, unsigned int* MACReg, unsigned int* MACBackup) +{ + unsigned int i = 0; + RTL_W8(MACReg[i], 0x3F); + for(i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++){ + RTL_W8( MACReg[i], (unsigned char)(MACBackup[i]&(~ BIT(3)))); + } + RTL_W8( MACReg[i], (unsigned char)(MACBackup[i]&(~ BIT(5)))); +} + +void _PHY_PathAStandBy(struct rtl8192cd_priv *priv) +{ + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x0); + PHY_SetBBReg(priv, 0x840, bMaskDWord, 0x00010000); + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x80800000); +} + +void _PHY_PathADDAOn(struct rtl8192cd_priv *priv, unsigned int* ADDAReg, char isPathAOn, char is2T) +{ + unsigned int pathOn; + unsigned int i; + + pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; + if(FALSE == is2T){ + pathOn = 0x0bdb25a0; + PHY_SetBBReg(priv, ADDAReg[0], bMaskDWord, 0x0b1b25a0); + } + else{ + PHY_SetBBReg(priv, ADDAReg[0], bMaskDWord, pathOn); + } + + for( i = 1 ; i < IQK_ADDA_REG_NUM ; i++){ + PHY_SetBBReg(priv, ADDAReg[i], bMaskDWord, pathOn); + } + +} + +/* + * PA Analog Pre-distortion Calibration R06 + */ +static void APK_MAIN(struct rtl8192cd_priv *priv, unsigned int is2T) +{ + unsigned int regD[PATH_NUM]; + unsigned int tmpReg, index, offset, path, i=0, pathbound = PATH_NUM, apkbound=6; + unsigned int BB_backup[APK_BB_REG_NUM]; + unsigned int BB_REG[APK_BB_REG_NUM] = {0x904, 0xc04, 0x800, 0xc08, 0x874}; + unsigned int BB_AP_MODE[APK_BB_REG_NUM] = {0x00000020, 0x00a05430, 0x02040000, 0x000800e4, 0x00204000}; + unsigned int BB_normal_AP_MODE[APK_BB_REG_NUM] = {0x00000020, 0x00a05430, 0x02040000, 0x000800e4, 0x22204000}; + unsigned int AFE_backup[APK_AFE_REG_NUM]; + unsigned int AFE_REG[APK_AFE_REG_NUM] = { 0x85c, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec}; + unsigned int MAC_backup[IQK_MAC_REG_NUM]; + unsigned int MAC_REG[IQK_MAC_REG_NUM] = {0x522, 0x550, 0x551, 0x040}; + unsigned int APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = {{0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, + {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e}}; + unsigned int APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = + { {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, //path settings equal to path b settings + {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} }; + + unsigned int APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = + { {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, + {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050}}; + + unsigned int APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = + { {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, //path settings equal to path b settings + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} }; + + unsigned int AFE_on_off[PATH_NUM] = {0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on + unsigned int APK_offset[PATH_NUM] = {0xb68, 0xb6c}; + unsigned int APK_normal_offset[PATH_NUM] = {0xb28, 0xb98}; + unsigned int APK_value[PATH_NUM] = {0x92fc0000, 0x12fc0000}; + unsigned int APK_normal_value[PATH_NUM] = {0x92680000, 0x12680000}; + char APK_delta_mapping[APK_BB_REG_NUM][13] = {{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0}}; + unsigned int APK_normal_setting_value_1[13] = + { 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, + 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, + 0x12680000, 0x00880000, 0x00880000 }; + unsigned int APK_normal_setting_value_2[16] = + { 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, + 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, + 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, + 0x00050006 }; + + + unsigned int APK_normal_RF_init_value_old[PATH_NUM][APK_BB_REG_NUM] = + {{0x0852c, 0x5a52c, 0x0a52c, 0x5a52c, 0x4a52c}, //path settings equal to path b settings + {0x0852c, 0x5a52c, 0x0a52c, 0x5a52c, 0x4a52c}}; + unsigned int APK_normal_RF_value_0_old[PATH_NUM][APK_BB_REG_NUM] = + {{0x52019, 0x52017, 0x52010, 0x5200d, 0x5200a}, //path settings equal to path b settings + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5200a}}; + unsigned int APK_normal_setting_value_1_old[13] = + {0x01017018, 0xf7ed8f84, 0x40372d20, 0x5b554e48, 0x6f6a6560, + 0x807c7873, 0x8f8b8884, 0x9d999693, 0xa9a6a3a0, 0xb5b2afac, + 0x12680000, 0x00880000, 0x00880000}; + unsigned int APK_normal_setting_value_2_old[16] = + {0x00810100, 0x00400056, 0x002b0032, 0x001f0024, 0x0019001c, + 0x00150017, 0x00120013, 0x00100011, 0x000e000f, 0x000c000d, + 0x000b000c, 0x000a000b, 0x0009000a, 0x00090009, 0x00080008, + 0x00080008}; + unsigned int AP_curve[PATH_NUM][APK_CURVE_REG_NUM]; + + unsigned int APK_result[PATH_NUM][APK_BB_REG_NUM]; //val_1_1a, val_1_2a, val_2a, val_3a, val_4a + unsigned int ThermalValue = 0; + int BB_offset, delta_V, delta_offset; + int newVerAPK = (IS_UMC_A_CUT_88C(priv)) ? 1 : 0; + unsigned int *pAPK_normal_setting_value_1 = APK_normal_setting_value_1, *pAPK_normal_setting_value_2 = APK_normal_setting_value_2 ; +#ifdef HIGH_POWER_EXT_PA + unsigned int tmp0x870=0, tmp0x860=0, tmp0x864=0; + + if(priv->pshare->rf_ft_var.use_ext_pa) + newVerAPK = 1; +#endif + + if(!newVerAPK) { + apkbound = 12; + pAPK_normal_setting_value_1 = APK_normal_setting_value_1_old; + pAPK_normal_setting_value_2 = APK_normal_setting_value_2_old; + } + + if(!is2T) + pathbound = 1; + + for(index = 0; index < PATH_NUM; index ++) { + APK_offset[index] = APK_normal_offset[index]; + APK_value[index] = APK_normal_value[index]; + AFE_on_off[index] = 0x6fdb25a4; + } + + for(index = 0; index < APK_BB_REG_NUM; index ++) { + for(path = 0; path < pathbound; path++) { + if(newVerAPK) { + APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; + APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; + } else { + APK_RF_init_value[path][index] = APK_normal_RF_init_value_old[path][index]; + APK_RF_value_0[path][index] = APK_normal_RF_value_0_old[path][index]; + } + + } + BB_AP_MODE[index] = BB_normal_AP_MODE[index]; + } + + /* + * save BB default value + */ + for(index = 1; index < APK_BB_REG_NUM ; index++) + BB_backup[index] = PHY_QueryBBReg(priv, BB_REG[index], bMaskDWord); + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + tmp0x870 = PHY_QueryBBReg(priv, 0x870, bMaskDWord); + tmp0x860 = PHY_QueryBBReg(priv, 0x860, bMaskDWord); + tmp0x864 = PHY_QueryBBReg(priv, 0x864, bMaskDWord); + } +#endif + + //save MAC default value + _PHY_SaveMACRegisters(priv, MAC_REG, MAC_backup); + + //save AFE default value + _PHY_SaveADDARegisters(priv, AFE_REG, AFE_backup, APK_AFE_REG_NUM); + + for(path = 0; path < pathbound; path++) { + /* + * save old AP curve + */ + if(path == RF92CD_PATH_A) { + /* + * path A APK + * load APK setting + * path-A + */ + offset = 0xb00; + for(index = 0; index < 11; index ++) { + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_1[index]); + offset += 0x04; + } + PHY_SetBBReg(priv, 0xb98, bMaskDWord, 0x12680000); + + offset = 0xb68; + for(; index < 13; index ++) { + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_1[index]); + offset += 0x04; + } + + /* + * page-B1 + */ + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x40000000); + + /* + *path A + */ + offset = 0xb00; + for(index = 0; index < 16; index++) { + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_2[index]); + offset += 0x04; + } + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x00000000); + } else if(path == RF92CD_PATH_B) { + /* + * path B APK + * load APK setting + * path-B + */ + offset = 0xb70; + for(index = 0; index < 10; index ++) { + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_1[index]); + offset += 0x04; + } + PHY_SetBBReg(priv, 0xb28, bMaskDWord, 0x12680000); + PHY_SetBBReg(priv, 0xb98, bMaskDWord, 0x12680000); + + offset = 0xb68; + index = 11; + for(; index < 13; index ++) { + //offset 0xb68, 0xb6c + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_1[index]); + offset += 0x04; + } + + /* + * page-B1 + */ + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x40000000); + + /* + * path B + */ + offset = 0xb60; + for(index = 0; index < 16; index++) { + PHY_SetBBReg(priv, offset, bMaskDWord, pAPK_normal_setting_value_2[index]); + offset += 0x04; + } + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x00000000); + } + + if(!newVerAPK) { + tmpReg = PHY_QueryRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x3, bMaskDWord, 1); + + AP_curve[path][0] = tmpReg & 0x1F; //[4:0] + + tmpReg = PHY_QueryRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x4, bMaskDWord, 1); + AP_curve[path][1] = (tmpReg & 0xF8000) >> 15; //[19:15] + AP_curve[path][2] = (tmpReg & 0x7C00) >> 10; //[14:10] + AP_curve[path][3] = (tmpReg & 0x3E0) >> 5; //[9:5] + } + + /* + * save RF default value + */ + regD[path] = PHY_QueryRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xd, bMaskDWord, 1); + + /* + * Path A AFE all on, path B AFE All off or vise versa + */ + for(index = 0; index < APK_AFE_REG_NUM ; index++) + PHY_SetBBReg(priv, AFE_REG[index], bMaskDWord, AFE_on_off[path]); + + /* + * BB to AP mode + */ + if(path == RF92CD_PATH_A) { + for(index = 1; index < APK_BB_REG_NUM ; index++) + PHY_SetBBReg(priv, BB_REG[index], bMaskDWord, BB_AP_MODE[index]); + } + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + PHY_SetBBReg(priv, 0x870, BIT(10), 1); + PHY_SetBBReg(priv, 0x870, BIT(26), 1); + PHY_SetBBReg(priv, 0x860, BIT(10), 0); + PHY_SetBBReg(priv, 0x864, BIT(10), 0); + } +#endif + + if(newVerAPK) { + if(path == RF92CD_PATH_A) { + PHY_SetBBReg(priv, 0xe30 , bMaskDWord, 0x01008c00); + PHY_SetBBReg(priv, 0xe34 , bMaskDWord, 0x01008c00); + } else if(path == RF92CD_PATH_B) { + PHY_SetBBReg(priv, 0xe50 , bMaskDWord, 0x01008c00); + PHY_SetBBReg(priv, 0xe54 , bMaskDWord, 0x01008c00); + } + } + + //MAC settings + _PHY_MACSettingCalibration(priv, MAC_REG, MAC_backup); + + + if(path == RF92CD_PATH_A) { + //Path B to standby mode + PHY_SetRFReg(priv, RF92CD_PATH_B, 0x0, bMaskDWord, 0x10000); + } else { + //Path A to standby mode + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x00, bMaskDWord, 0x10000); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x10, bMaskDWord, 0x1000f); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x11, bMaskDWord, 0x20103); + } + + /* + * Check Thermal value delta + */ + if (priv->pmib->dot11RFEntry.ther) { + ThermalValue = PHY_QueryRFReg(priv, RF92CD_PATH_A, 0x24, 0x1f, 1) & 0xff; + ThermalValue -= priv->pmib->dot11RFEntry.ther; + } + + delta_offset = ((ThermalValue+14)/2); + if(delta_offset < 0) + delta_offset = 0; + else if (delta_offset > 12) + delta_offset = 12; + + //AP calibration + for(index = 1; index < APK_BB_REG_NUM; index++) { + tmpReg = APK_RF_init_value[path][index]; + if (priv->pmib->dot11RFEntry.ther) { + BB_offset = (tmpReg & 0xF0000) >> 16; + + if(!(tmpReg & BIT(15))) //sign bit 0 + BB_offset = -BB_offset; + delta_V = APK_delta_mapping[index][delta_offset]; + BB_offset += delta_V; + + if(BB_offset < 0) { + tmpReg = tmpReg & (~BIT(15)); + BB_offset = -BB_offset; + } else { + tmpReg = tmpReg | BIT(15); + } + tmpReg = (tmpReg & 0xFFF0FFFF) | (BB_offset << 16); + } + + if(newVerAPK) + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xc, bMaskDWord, 0x8992e); + else + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xc, bMaskDWord, 0x8992f); + + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x0, bMaskDWord, APK_RF_value_0[path][index]); + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xd, bMaskDWord, tmpReg); + + /* + * PA11+PAD01111, one shot + */ + i = 0; + do { + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x80000000); + PHY_SetBBReg(priv, APK_offset[path], bMaskDWord, APK_value[0]); + delay_ms(3); + PHY_SetBBReg(priv, APK_offset[path], bMaskDWord, APK_value[1]); + delay_ms(20); + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x00000000); + + if(!newVerAPK) { + tmpReg = PHY_QueryRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xb, bMaskDWord, 1); + tmpReg = (tmpReg & 0x3E00) >> 9; + } else { + if(path == RF92CD_PATH_A) + tmpReg = PHY_QueryBBReg(priv, 0xbd8, 0x03E00000); + else + tmpReg = PHY_QueryBBReg(priv, 0xbd8, 0xF8000000); + } + i++; + } while((tmpReg > apkbound) && i < 4); + + APK_result[path][index] = tmpReg; + } + } + + /* + * reload MAC default value + */ + _PHY_ReloadMACRegisters(priv, MAC_REG, MAC_backup); + + /* + * reload BB default value + */ + for(index = 1; index < APK_BB_REG_NUM ; index++) + PHY_SetBBReg(priv, BB_REG[index], bMaskDWord, BB_backup[index]); + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + PHY_SetBBReg(priv, 0x870, bMaskDWord, tmp0x870); + PHY_SetBBReg(priv, 0x860, bMaskDWord, tmp0x860); + PHY_SetBBReg(priv, 0x864, bMaskDWord, tmp0x864); + } +#endif + + /* + * reload AFE default value + */ + _PHY_ReloadADDARegisters(priv, AFE_REG, AFE_backup, 16); + + + /* + * reload RF path default value + */ + for(path = 0; path < pathbound; path++) { + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xd, bMaskDWord, regD[path]); + if(path == RF92CD_PATH_B) { + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x10, bMaskDWord, 0x1000f); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x11, bMaskDWord, 0x20101); + } + + if(newVerAPK) { + if (APK_result[path][1] > 6) + APK_result[path][1] = 6; + } else { + if(APK_result[path][1] < 1) + APK_result[path][1] = 1; + else if (APK_result[path][1] > 5) + APK_result[path][1] = 5; + + if(APK_result[path][2] < 2) + APK_result[path][2] = 2; + else if (APK_result[path][2] > 6) + APK_result[path][2] = 6; + + if(APK_result[path][3] < 2) + APK_result[path][3] = 2; + else if (APK_result[path][3] > 6) + APK_result[path][3] = 6; + + if(APK_result[path][4] < 5) + APK_result[path][4] = 5; + else if (APK_result[path][4] > 9) + APK_result[path][4] = 9; + } + } + + for(path = 0; path < pathbound; path++) { + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x3, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); + if(newVerAPK) { + if(path == RF92CD_PATH_A) + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x4, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); + else + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x4, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xe, bMaskDWord, + ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); + } else { + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0x4, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][2] << 5) | APK_result[path][3])); + PHY_SetRFReg(priv, (RF92CD_RADIO_PATH_E)path, 0xe, bMaskDWord, + ((APK_result[path][4] << 15) | (APK_result[path][4] << 10) | (APK_result[path][4] << 5) | APK_result[path][4])); + } + } +} + + + +/* +return FALSE => do IQK again +*/ +char _PHY_SimularityCompare(struct rtl8192cd_priv *priv, int result[][8], unsigned char c1, unsigned char c2) +{ + unsigned int i, j, diff, SimularityBitMap, bound = 0; + unsigned char final_candidate[2] = {0xFF, 0xFF}; //for path A and path B + char bResult = TRUE, is2T = (GET_CHIP_VER(priv) == VERSION_8192C ? 1 : 0); + + bound = (is2T) ? 8 : 4; + SimularityBitMap = 0; + + for( i = 0; i < bound; i++ ) { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE) { + if((i == 2 || i == 6) && !SimularityBitMap) { + if( result[c1][i]+ result[c1][i+1] == 0) + final_candidate[(i>>2)] = c2; + else if (result[c2][i]+result[c2][i+1] == 0) + final_candidate[(i>>2)] = c1; + else + SimularityBitMap |= (1<<i); + } + else + SimularityBitMap |= (1<<i); + } + } + + if ( SimularityBitMap == 0) { + for( i = 0; i < (bound>>2); i++ ) { + if(final_candidate[i] != 0xFF) { + for( j = (i<<2); j < ((i+1)<<2)-2; j++) + result[3][j] = result[final_candidate[i]][j]; + bResult = FALSE; + } + } + return bResult; + } + else if (!(SimularityBitMap & 0x0F)) { //path A OK + for(i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + return FALSE; + } + else if (!(SimularityBitMap & 0xF0) && is2T) { //path B OK + for(i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + return FALSE; + } + else + return FALSE; + +} + + +//bit0 = 1 => Tx OK, bit1 = 1 => Rx OK +unsigned char _PHY_PathA_IQK(struct rtl8192cd_priv *priv, char configPathB) +{ + unsigned int regEAC, regE94, regE9C, regEA4; + unsigned char result = 0x00; + + //path-A IQK setting +// RTPRINT(FINIT, INIT_IQK, ("Path-A IQK setting!\n")); + PHY_SetBBReg(priv, 0xe30, bMaskDWord, 0x10008c1f); + PHY_SetBBReg(priv, 0xe34, bMaskDWord, 0x10008c1f); + PHY_SetBBReg(priv, 0xe38, bMaskDWord, 0x82140102); + PHY_SetBBReg(priv, 0xe3c, bMaskDWord, ((configPathB |IS_UMC_B_CUT_88C(priv)) ? 0x28160202 : 0x28160502)); + +#if 1 + //path-B IQK setting + if(configPathB) { + PHY_SetBBReg(priv, 0xe50, bMaskDWord, 0x10008c22); + PHY_SetBBReg(priv, 0xe54, bMaskDWord, 0x10008c22); + PHY_SetBBReg(priv, 0xe58, bMaskDWord, 0x82140102); + PHY_SetBBReg(priv, 0xe5c, bMaskDWord, 0x28160202); + } +#endif + //LO calibration setting + PHY_SetBBReg(priv, 0xe4c, bMaskDWord, 0x001028d1); + + //One shot, path A LOK & IQK + PHY_SetBBReg(priv, 0xe48, bMaskDWord, 0xf9000000); + PHY_SetBBReg(priv, 0xe48, bMaskDWord, 0xf8000000); + + // delay x ms + delay_ms(IQK_DELAY_TIME); + + // Check failed + regEAC = PHY_QueryBBReg(priv, 0xeac, bMaskDWord); + regE94 = PHY_QueryBBReg(priv, 0xe94, bMaskDWord); + regE9C= PHY_QueryBBReg(priv, 0xe9c, bMaskDWord); + regEA4= PHY_QueryBBReg(priv, 0xea4, bMaskDWord); + + if(!(regEAC & BIT(28)) && + (((regE94 & 0x03FF0000)>>16) != 0x142) && + (((regE9C & 0x03FF0000)>>16) != 0x42) ) + result |= 0x01; + else //if Tx not OK, ignore Rx + return result; + + if(!(regEAC & BIT(27)) && //if Tx is OK, check whether Rx is OK + (((regEA4 & 0x03FF0000)>>16) != 0x132) && + (((regEAC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else { +// RTPRINT(FINIT, INIT_IQK, ("Path A Rx IQK fail!!\n")); + } + + return result; +} + +//bit0 = 1 => Tx OK, bit1 = 1 => Rx OK +unsigned char _PHY_PathB_IQK(struct rtl8192cd_priv *priv) +{ + unsigned int regEAC, regEB4, regEBC, regEC4, regECC; + unsigned char result = 0x00; +#if 0 + //path-B IQK setting + RTPRINT(FINIT, INIT_IQK, ("Path-B IQK setting!\n")); + PHY_SetBBReg(pAdapter, 0xe50, bMaskDWord, 0x10008c22); + PHY_SetBBReg(pAdapter, 0xe54, bMaskDWord, 0x10008c22); + PHY_SetBBReg(pAdapter, 0xe58, bMaskDWord, 0x82140102); + PHY_SetBBReg(pAdapter, 0xe5c, bMaskDWord, 0x28160202); + + //LO calibration setting + RTPRINT(FINIT, INIT_IQK, ("LO calibration setting!\n")); + PHY_SetBBReg(pAdapter, 0xe4c, bMaskDWord, 0x001028d1); +#endif + //One shot, path B LOK & IQK +// RTPRINT(FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); + PHY_SetBBReg(priv, 0xe60, bMaskDWord, 0x00000002); + PHY_SetBBReg(priv, 0xe60, bMaskDWord, 0x00000000); + + // delay x ms + delay_ms(IQK_DELAY_TIME); + + // Check failed + regEAC = PHY_QueryBBReg(priv, 0xeac, bMaskDWord); + regEB4 = PHY_QueryBBReg(priv, 0xeb4, bMaskDWord); + regEBC= PHY_QueryBBReg(priv, 0xebc, bMaskDWord); + regEC4= PHY_QueryBBReg(priv, 0xec4, bMaskDWord); + regECC= PHY_QueryBBReg(priv, 0xecc, bMaskDWord); + + if(!(regEAC & BIT(31)) && + (((regEB4 & 0x03FF0000)>>16) != 0x142) && + (((regEBC & 0x03FF0000)>>16) != 0x42)) + result |= 0x01; + else + return result; + + if(!(regEAC & BIT(30)) && + (((regEC4 & 0x03FF0000)>>16) != 0x132) && + (((regECC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else { +// RTPRINT(FINIT, INIT_IQK, ("Path B Rx IQK fail!!\n")); + } + + return result; + +} + +void _PHY_PathAFillIQKMatrix(struct rtl8192cd_priv *priv, char bIQKOK, int result[][8], unsigned char final_candidate, char bTxOnly) +{ + int Oldval_0, X, TX0_A, reg; + int Y, TX0_C; + + if(final_candidate == 0xFF) + return; + + else if(bIQKOK) { + Oldval_0 = (PHY_QueryBBReg(priv, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][0]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX0_A = (X * Oldval_0) >> 8; + PHY_SetBBReg(priv, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(31), ((X* Oldval_0>>7) & 0x1)); + + Y = result[final_candidate][1]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + TX0_C = (Y * Oldval_0) >> 8; + PHY_SetBBReg(priv, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); + PHY_SetBBReg(priv, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(29), ((Y* Oldval_0>>7) & 0x1)); + + if(bTxOnly) { +// RTPRINT(FINIT, INIT_IQK, ("_PHY_PathAFillIQKMatrix only Tx OK\n")); + return; + } + + reg = result[final_candidate][2]; + PHY_SetBBReg(priv, rOFDM0_XARxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][3] & 0x3F; + PHY_SetBBReg(priv, rOFDM0_XARxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][3] >> 6) & 0xF; + PHY_SetBBReg(priv, 0xca0, 0xF0000000, reg); + } +} + + +void _PHY_PathBFillIQKMatrix(struct rtl8192cd_priv *priv, char bIQKOK, int result[][8], unsigned char final_candidate, char bTxOnly) +{ + int Oldval_1, X, TX1_A, reg; + int Y, TX1_C; + + //RTPRINT(FINIT, INIT_IQK, ("Path B IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); + + if(final_candidate == 0xFF) + return; + + else if(bIQKOK) + { + Oldval_1 = (PHY_QueryBBReg(priv, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][4]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX1_A = (X * Oldval_1) >> 8; + PHY_SetBBReg(priv, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(27), ((X* Oldval_1>>7) & 0x1)); + + Y = result[final_candidate][5]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + TX1_C = (Y * Oldval_1) >> 8; + PHY_SetBBReg(priv, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); + PHY_SetBBReg(priv, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(25), ((Y* Oldval_1>>7) & 0x1)); + + if(bTxOnly) + return; + + reg = result[final_candidate][6]; + PHY_SetBBReg(priv, rOFDM0_XBRxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][7] & 0x3F; + PHY_SetBBReg(priv, rOFDM0_XBRxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][7] >> 6) & 0xF; + PHY_SetBBReg(priv, rOFDM0_AGCRSSITable, 0x0000F000, reg); + } +} + +void _PHY_IQCalibrate(struct rtl8192cd_priv *priv, int result[][8], unsigned char t, char is2T) +{ + unsigned int i; + unsigned char PathAOK, PathBOK; + unsigned int ADDA_REG[IQK_ADDA_REG_NUM] = { 0x85c, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec }; + unsigned int IQK_MAC_REG[IQK_MAC_REG_NUM] = {0x522, 0x550, 0x551, 0x040}; + + char isNormal = IS_TEST_CHIP(priv) ? 0 : 1; + unsigned int retryCount = 2; + +#ifdef MP_TEST + if(priv->pshare->rf_ft_var.mp_specific) + retryCount = 9; +#endif + + if(t==0) { + // Save ADDA parameters, turn Path A ADDA on + _PHY_SaveADDARegisters(priv, ADDA_REG, priv->pshare->ADDA_backup, APK_AFE_REG_NUM); + _PHY_SaveMACRegisters(priv, IQK_MAC_REG, priv->pshare->IQK_MAC_backup); + } + + _PHY_PathADDAOn(priv, ADDA_REG, TRUE, is2T); + + if(t==0) { + // Store 0xC04, 0xC08, 0x874 vale + priv->pshare->RegC04 = PHY_QueryBBReg(priv, 0xc04, bMaskDWord); + priv->pshare->RegC08 = PHY_QueryBBReg(priv, 0xc08, bMaskDWord); + priv->pshare->Reg874 = PHY_QueryBBReg(priv, 0x874, bMaskDWord); + } + + PHY_SetBBReg(priv, 0x800, bMaskDWord, (PHY_QueryBBReg(priv, 0x800, bMaskDWord)& ~ BIT(24))); + PHY_SetBBReg(priv, 0xc04, bMaskDWord, 0x03a05600); + PHY_SetBBReg(priv, 0xc08, bMaskDWord, 0x000800e4); + PHY_SetBBReg(priv, 0x874, bMaskDWord, 0x22204000); + + PHY_SetBBReg(priv, 0x870, BIT(10), 1); + PHY_SetBBReg(priv, 0x870, BIT(26), 1); + PHY_SetBBReg(priv, 0x860, BIT(10), 0); + PHY_SetBBReg(priv, 0x864, BIT(10), 0); + + if(is2T) { + PHY_SetBBReg(priv, 0x840, bMaskDWord, 0x00010000); + PHY_SetBBReg(priv, 0x844, bMaskDWord, 0x00010000); + } + + //MAC settings + _PHY_MACSettingCalibration(priv, IQK_MAC_REG, priv->pshare->IQK_MAC_backup); + + //Page B init + if(isNormal) + PHY_SetBBReg(priv, 0xb68, bMaskDWord, 0x00080000); + else + PHY_SetBBReg(priv, 0xb68, bMaskDWord, 0x0f600000); + + if(is2T) { + if(isNormal) + PHY_SetBBReg(priv, 0xb6c, bMaskDWord, 0x00080000); + else + PHY_SetBBReg(priv, 0xb6c, bMaskDWord, 0x0f600000); + } + + // IQ calibration setting + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0x80800000); + PHY_SetBBReg(priv, 0xe40, bMaskDWord, 0x01007c00); + PHY_SetBBReg(priv, 0xe44, bMaskDWord, 0x01004800); + + for(i = 0 ; i < retryCount ; i++){ + PathAOK = _PHY_PathA_IQK(priv, is2T); + if(PathAOK == 0x03){ + result[t][0] = (PHY_QueryBBReg(priv, 0xe94, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (PHY_QueryBBReg(priv, 0xe9c, bMaskDWord)&0x3FF0000)>>16; + result[t][2] = (PHY_QueryBBReg(priv, 0xea4, bMaskDWord)&0x3FF0000)>>16; + result[t][3] = (PHY_QueryBBReg(priv, 0xeac, bMaskDWord)&0x3FF0000)>>16; + break; + } + else if (i == (retryCount-1) && PathAOK == 0x01) //Tx IQK OK + { + result[t][0] = (PHY_QueryBBReg(priv, 0xe94, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (PHY_QueryBBReg(priv, 0xe9c, bMaskDWord)&0x3FF0000)>>16; + } + } + + if(0x00 == PathAOK){ +// RTPRINT(FINIT, INIT_IQK, ("Path A IQK failed!!\n")); + } + + if(is2T){ + _PHY_PathAStandBy(priv); + + // Turn Path B ADDA on + _PHY_PathADDAOn(priv, ADDA_REG, FALSE, is2T); + + for(i = 0 ; i < retryCount ; i++){ + PathBOK = _PHY_PathB_IQK(priv); + if(PathBOK == 0x03){ +// RTPRINT(FINIT, INIT_IQK, ("Path B IQK Success!!\n")); + result[t][4] = (PHY_QueryBBReg(priv, 0xeb4, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (PHY_QueryBBReg(priv, 0xebc, bMaskDWord)&0x3FF0000)>>16; + result[t][6] = (PHY_QueryBBReg(priv, 0xec4, bMaskDWord)&0x3FF0000)>>16; + result[t][7] = (PHY_QueryBBReg(priv, 0xecc, bMaskDWord)&0x3FF0000)>>16; + break; + } + else if (i == (retryCount - 1) && PathBOK == 0x01) //Tx IQK OK + { +// RTPRINT(FINIT, INIT_IQK, ("Path B Only Tx IQK Success!!\n")); + result[t][4] = (PHY_QueryBBReg(priv, 0xeb4, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (PHY_QueryBBReg(priv, 0xebc, bMaskDWord)&0x3FF0000)>>16; + } + } + + if(0x00 == PathBOK){ +// RTPRINT(FINIT, INIT_IQK, ("Path B IQK failed!!\n")); + } + } + + //Back to BB mode, load original value +// RTPRINT(FINIT, INIT_IQK, ("IQK:Back to BB mode, load original value!\n")); + PHY_SetBBReg(priv, 0xc04, bMaskDWord, priv->pshare->RegC04); + PHY_SetBBReg(priv, 0x874, bMaskDWord, priv->pshare->Reg874); + PHY_SetBBReg(priv, 0xc08, bMaskDWord, priv->pshare->RegC08); + + PHY_SetBBReg(priv, 0xe28, bMaskDWord, 0); + + // Restore RX initial gain + PHY_SetBBReg(priv, 0x840, bMaskDWord, 0x00032ed3); + + if(is2T) + PHY_SetBBReg(priv, 0x844, bMaskDWord, 0x00032ed3); + + if(t!=0) { + // Reload ADDA power saving parameters + _PHY_ReloadADDARegisters(priv, ADDA_REG, priv->pshare->ADDA_backup, 16); + + // Reload MAC parameters + _PHY_ReloadMACRegisters(priv, IQK_MAC_REG, priv->pshare->IQK_MAC_backup); + } +} + + +void PHY_IQCalibrate_new(struct rtl8192cd_priv *priv) +{ + int result[4][8]; //last is final result + unsigned char i, final_candidate; + char bPathAOK, bPathBOK; + int RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0; + char is12simular, is13simular, is23simular; + unsigned int temp_870, temp_860, temp_864, temp_800; + + temp_870 = PHY_QueryBBReg(priv, 0x870, bMaskDWord); + temp_860 = PHY_QueryBBReg(priv, 0x860, bMaskDWord); + temp_864 = PHY_QueryBBReg(priv, 0x864, bMaskDWord); + temp_800 = PHY_QueryBBReg(priv, 0x800, bMaskDWord); + + memset(result, 0, sizeof(result)); + + final_candidate = 0xff; + bPathAOK = FALSE; + bPathBOK = FALSE; + is12simular = FALSE; + is23simular = FALSE; + is13simular = FALSE; + + for (i=0; i<3; i++) { + _PHY_IQCalibrate(priv, result, i, (GET_CHIP_VER(priv) == VERSION_8192C ? 1 : 0)); + + if(i == 1) { + is12simular = _PHY_SimularityCompare(priv, result, 0, 1); + if(is12simular) { + final_candidate = 0; + break; + } + } + + if(i == 2) { + is13simular = _PHY_SimularityCompare(priv, result, 0, 2); + if(is13simular) { + final_candidate = 0; + break; + } + + is23simular = _PHY_SimularityCompare(priv, result, 1, 2); + if(is23simular) + final_candidate = 1; + else + { + for(i = 0; i < 8; i++) + RegTmp += result[3][i]; + + if(RegTmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + + + RTL_W32(0x870, temp_870); + RTL_W32(0x860, temp_860); + RTL_W32(0x864, temp_864); + RTL_W32(0x800, temp_800); + + //load 0xe30 IQC default value + if(GET_CHIP_VER(priv) == VERSION_8188C) { + RTL_W32(0xe30, 0x01008c00); + RTL_W32(0xe34, 0x01008c00); + } + + for (i=0; i<4; i++) { + RegE94 = result[i][0]; + RegE9C = result[i][1]; + RegEA4 = result[i][2]; + RegEAC = result[i][3]; + RegEB4 = result[i][4]; + RegEBC = result[i][5]; + RegEC4 = result[i][6]; + RegECC = result[i][7]; + DEBUG_INFO("IQK: RegE94=%lx RegE9C=%lx RegEA4=%lx RegEAC=%lx RegEB4=%lx RegEBC=%lx RegEC4=%lx RegECC=%lx\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC); + } + + if(final_candidate != 0xff) { + priv->pshare->RegE94 = RegE94 = result[final_candidate][0]; + priv->pshare->RegE9C = RegE9C = result[final_candidate][1]; + RegEA4 = result[final_candidate][2]; + RegEAC = result[final_candidate][3]; + priv->pshare->RegEB4 = RegEB4 = result[final_candidate][4]; + priv->pshare->RegEBC = RegEBC = result[final_candidate][5]; + RegEC4 = result[final_candidate][6]; + RegECC = result[final_candidate][7]; + DEBUG_INFO ("IQK: final_candidate is %x\n",final_candidate); + DEBUG_INFO ("IQK: RegE94=%lx RegE9C=%lx RegEA4=%lx RegEAC=%lx RegEB4=%lx RegEBC=%lx RegEC4=%lx RegECC=%lx\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC); + bPathAOK = bPathBOK = TRUE; + } + else { + priv->pshare->RegE94 = priv->pshare->RegEB4 = 0x100; //X default value + priv->pshare->RegE9C = priv->pshare->RegEBC = 0x0; //Y default value + } + + if((RegE94 != 0)/*&&(RegEA4 != 0)*/) + _PHY_PathAFillIQKMatrix(priv, bPathAOK, result, final_candidate, (RegEA4 == 0)? 1 :0); + if(GET_CHIP_VER(priv) == VERSION_8192C){ + if((RegEB4 != 0)/*&&(RegEC4 != 0)*/) + _PHY_PathBFillIQKMatrix(priv, bPathBOK, result, final_candidate, (RegEC4 == 0)? 1 :0); + } +} + +void PHY_APCalibrate(struct rtl8192cd_priv *priv) +{ +#ifdef HIGH_POWER_EXT_PA + if (!priv->pshare->rf_ft_var.use_ext_pa) +#endif + if(!IS_TEST_CHIP(priv)) + APK_MAIN(priv, (GET_CHIP_VER(priv) == VERSION_8192C ? 1 : 0)); + +} + +#endif + +void PHY_IQCalibrate(struct rtl8192cd_priv *priv) +{ +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D){ +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) { + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { +#ifdef DFS + if ((priv->pshare->rf_ft_var.dfsdelayiqk) && + (OPMODE & WIFI_AP_STATE) && + !priv->pmib->dot11DFSEntry.disable_DFS && + (timer_pending(&priv->ch_avail_chk_timer) || + priv->pmib->dot11DFSEntry.disable_tx)) + return; +#endif + IQK_92D_5G_phy0_n(priv); + } + else + IQK_92D_2G_phy1(priv); + } + else +#endif + { + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { +#ifdef DFS + if ((priv->pshare->rf_ft_var.dfsdelayiqk) && + (OPMODE & WIFI_AP_STATE) && + !priv->pmib->dot11DFSEntry.disable_DFS && + (timer_pending(&priv->ch_avail_chk_timer) || + priv->pmib->dot11DFSEntry.disable_tx)) + return; +#endif + IQK_92D_5G_n(priv); + } + else + IQK_92D_2G(priv); + } + } +#endif +#ifdef CONFIG_RTL_92C_SUPPORT +if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ +#ifdef CONFIG_RTL_NEW_IQK + PHY_IQCalibrate_new(priv); +#else + if( IS_UMC_A_CUT_88C(priv) +#ifdef HIGH_POWER_EXT_PA + ||(priv->pshare->rf_ft_var.use_ext_pa) +#endif + ) { + PHY_IQCalibrate_new(priv); + } else { + if (GET_CHIP_VER(priv) == VERSION_8192C) + IQK_92CD(priv); + else + IQK_88C(priv); + } +#endif +} +#endif +} + + +static void PHY_LCCalibrate(struct rtl8192cd_priv *priv) +{ + unsigned char tmpReg, value_IGI; + unsigned int LC_Cal; + int isNormal; + +#ifdef TESTCHIP_SUPPORT + isNormal = (IS_TEST_CHIP(priv)? 0 : 1); +#else + isNormal = 1; +#endif + + /* Check continuous TX and Packet TX */ + tmpReg = RTL_R8(0xd03); + + if ((tmpReg & 0x70) != 0) /* Deal with contisuous TX case */ + RTL_W8(0xd03, tmpReg&0x8F); /* disable all continuous TX */ + else /* Deal with Packet TX case */ + RTL_W8(0x522, 0xFF); /* block all queues */ + + /* 2. Set RF mode = standby mode */ + if ((tmpReg & 0x70) != 0) { + /* Path-A */ + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x00, bMask20Bits, 0x10000); + + /* Path-B */ + if (get_rf_mimo_mode(priv) != MIMO_1T1R) + PHY_SetRFReg(priv, RF92CD_PATH_B, 0x00, bMask20Bits, 0x10000); + } + + /* 3. Read RF reg18 */ + LC_Cal = PHY_QueryRFReg(priv, RF92CD_PATH_A, 0x18, bMask12Bits, 1); + + /* 4. Set LC calibration begin */ + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x18, bMask12Bits, LC_Cal|0x08000); + +#if defined(CONFIG_RTL_8198) && defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv)==VERSION_8192D) + REG32(BSP_WDTCNR) |= 1 << 23; +#endif + + if (isNormal) + delay_ms(100); + else + delay_ms(3); + + /* Restore original situation */ + if ((tmpReg & 0x70) != 0) { + /* Deal with contisuous TX case */ + + /* Path-A */ + RTL_W8(0xd03, tmpReg); + + /* Restore RF mdoe & RF gain by change IGI to trigger HW tristate */ + value_IGI = (RTL_R8(0xc50) & 0x7F); + RTL_W8(0xc50, ((value_IGI!=0x30)?0x30:0x31)); + RTL_W8(0xc50, value_IGI); + + /* Path-B */ + if (get_rf_mimo_mode(priv) != MIMO_1T1R) { + /* Restore RF mdoe & RF gain by change IGI to trigger HW tristate */ + value_IGI = (RTL_R8(0xc58) & 0x7F); + RTL_W8(0xc58, ((value_IGI!=0x30)?0x30:0x31)); + RTL_W8(0xc58, value_IGI); + } + } else { + /* Deal with Packet TX case */ + + RTL_W8(0x522, 0x00); + } +} + + +const int OFDM_TABLE_SIZE= sizeof(OFDMSwingTable)/sizeof(int); +const int CCK_TABLE_SIZE= sizeof(CCKSwingTable_Ch1_Ch13) >>3; + + +int get_CCK_swing_index(struct rtl8192cd_priv *priv) +{ + int TempCCk, index=12, i; + short channel; +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) + channel=priv->pshare->working_channel; + else +#endif + channel = (priv->pmib->dot11RFEntry.dot11channel); + + //Query CCK default setting From 0xa24 + TempCCk = PHY_QueryBBReg(priv, rCCK0_TxFilter2, bMaskDWord)&bMaskCCK; + TempCCk = cpu_to_le32(TempCCk); + for(i=0 ; i<CCK_TABLE_SIZE ; i++) { + if(channel==14) { + if(memcmp((void*)&TempCCk, (void*)&CCKSwingTable_Ch14[i][2], 4)==0) { + index = i; + break; + } + } else { + if(memcmp((void*)&TempCCk, (void*)&CCKSwingTable_Ch1_Ch13[i][2], 4)==0) { + index = i; + break; + } + } + } + DEBUG_INFO("Initial reg0x%x = 0x%lx, CCK_index=0x%x, ch %d\n", + rCCK0_TxFilter2, TempCCk, index, channel); + return index; +} + +void set_CCK_swing_index(struct rtl8192cd_priv *priv, short CCK_index) +{ + short channel; +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) + channel=priv->pshare->working_channel; + else +#endif + channel = (priv->pmib->dot11RFEntry.dot11channel); + + if(channel !=14) { + RTL_W8( 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]); + RTL_W8( 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]); + RTL_W8( 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]); + RTL_W8( 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]); + RTL_W8( 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]); + RTL_W8( 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]); + RTL_W8( 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]); + RTL_W8( 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]); + } + else{ + RTL_W8( 0xa22, CCKSwingTable_Ch14[CCK_index][0]); + RTL_W8( 0xa23, CCKSwingTable_Ch14[CCK_index][1]); + RTL_W8( 0xa24, CCKSwingTable_Ch14[CCK_index][2]); + RTL_W8( 0xa25, CCKSwingTable_Ch14[CCK_index][3]); + RTL_W8( 0xa26, CCKSwingTable_Ch14[CCK_index][4]); + RTL_W8( 0xa27, CCKSwingTable_Ch14[CCK_index][5]); + RTL_W8( 0xa28, CCKSwingTable_Ch14[CCK_index][6]); + RTL_W8( 0xa29, CCKSwingTable_Ch14[CCK_index][7]); + } +} + +#ifdef HIGH_POWER_EXT_PA +void swingIndexRemap(int *a, int b) +{ + int d = (RTL_ABS(*a, b) *3)>>1; + if(*a < b ) + *a = b - d; + else + *a = b + d; +} +#endif + +unsigned char getThermalValue(struct rtl8192cd_priv *priv) +{ + unsigned char ThermalValue; + int sum=0, i=0; + PHY_SetRFReg(priv, RF92CD_PATH_A, RF_T_METER, bMask20Bits, 0x60); + ThermalValue =(unsigned char)PHY_QueryRFReg(priv, RF92CD_PATH_A, RF_T_METER, bMask20Bits, 1) & 0x01f; + priv->pshare->Thermal_idx = (priv->pshare->Thermal_idx+1)%8; + priv->pshare->Thermal_log[ priv->pshare->Thermal_idx ] = ThermalValue; + for(i=0; i<8; i++) { + if(!priv->pshare->Thermal_log[i]) + return ThermalValue; + sum += priv->pshare->Thermal_log[i]; + } + return (sum+4)>>3; +} +void tx_power_tracking(struct rtl8192cd_priv *priv) +{ + unsigned char ThermalValue = 0, delta, delta_LCK, delta_IQK; + int ele_A, ele_D, value32, X, Y, ele_C; + int OFDM_index[2]={0,0}, CCK_index; + int i = 0; + char is2T = ((GET_CHIP_VER(priv) == VERSION_8192C) ?1 :0); + unsigned char TxPwrLevel[2]; + unsigned char channel, OFDM_min_index = 6, rf=1; //OFDM BB Swing should be less than +3.0dB, which is required by Arthur +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + channel=priv->pshare->working_channel; + if(priv->pshare->mp_txpwr_tracking == FALSE) + return; + } else +#endif + { + channel = (priv->pmib->dot11RFEntry.dot11channel); + } + + ThermalValue = getThermalValue(priv); + + rf += is2T; + if(ThermalValue) { + + if(!priv->pshare->ThermalValue) { + priv->pshare->ThermalValue = priv->pmib->dot11RFEntry.ther; + priv->pshare->ThermalValue_LCK = ThermalValue; + priv->pshare->ThermalValue_IQK = ThermalValue; + + //Query OFDM path A default setting + ele_D = PHY_QueryBBReg(priv, rOFDM0_XATxIQImbalance, bMaskDWord)&bMaskOFDM_D; + for(i=0; i<OFDM_TABLE_SIZE; i++) { + if(ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) { + priv->pshare->OFDM_index[0] = i; + priv->pshare->OFDM_index0[0] = i; + break; + } + } + + //Query OFDM path B default setting + if(is2T) { + ele_D = PHY_QueryBBReg(priv, rOFDM0_XBTxIQImbalance, bMaskDWord)&bMaskOFDM_D; + for(i=0; i<OFDM_TABLE_SIZE; i++) { + if(ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) { + priv->pshare->OFDM_index[1] = i; + priv->pshare->OFDM_index0[1] = i; + break; + } + } + } + priv->pshare->CCK_index = get_CCK_swing_index(priv); + priv->pshare->CCK_index0 = priv->pshare->CCK_index; + + } + + delta = RTL_ABS(ThermalValue, priv->pshare->ThermalValue); + delta_LCK = RTL_ABS(ThermalValue, priv->pshare->ThermalValue_LCK); + delta_IQK = RTL_ABS(ThermalValue, priv->pshare->ThermalValue_IQK); + +// printk("Readback Thermal Meter = 0x%lx pre thermal meter 0x%lx EEPROMthermalmeter 0x%lx delta 0x%lx delta_LCK 0x%lx delta_IQK 0x%lx\n", +// ThermalValue, priv->pshare->ThermalValue, priv->pmib->dot11RFEntry.ther, delta, delta_LCK, delta_IQK); + + if(delta_LCK > 1) { + priv->pshare->ThermalValue_LCK = ThermalValue; + PHY_LCCalibrate(priv); + } + + if(delta > 0) { + if(ThermalValue > priv->pshare->ThermalValue) { + for(i = 0; i < rf; i++) + priv->pshare->OFDM_index[i] -= delta; + priv->pshare->CCK_index -= delta; + } else { + for(i = 0; i < rf; i++) + priv->pshare->OFDM_index[i] += delta; + priv->pshare->CCK_index += delta; + } + if(ThermalValue > priv->pmib->dot11RFEntry.ther) { + for(i = 0; i < rf; i++) + OFDM_index[i] = priv->pshare->OFDM_index[i]+1; + CCK_index = priv->pshare->CCK_index+1; + } else { + for(i = 0; i < rf; i++) + OFDM_index[i] = priv->pshare->OFDM_index[i]; + CCK_index = priv->pshare->CCK_index; + } +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + TxPwrLevel[0] = priv->pshare->mp_txpwr_patha; + TxPwrLevel[1] = priv->pshare->mp_txpwr_pathb; + } else +#endif + { + TxPwrLevel[0] = priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[channel-1]; + TxPwrLevel[1] = priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[channel-1]; + + if (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + unsigned char offset = (priv->pmib->dot11RFEntry.pwrdiffHT20[channel-1] & 0x0f); + TxPwrLevel[0] = COUNT_SIGN_OFFSET(TxPwrLevel[0], offset); + offset = ((priv->pmib->dot11RFEntry.pwrdiffOFDM[channel-1] & 0xf0) >> 4); + TxPwrLevel[1] = COUNT_SIGN_OFFSET(TxPwrLevel[1], offset); + } + } + +// printk("TxPwrLevel[0]=%d, TxPwrLevel[1]=%d\n", TxPwrLevel[0], TxPwrLevel[1]); + for(i = 0; i < rf; i++) { + if(/*TxPwrLevel[i] >=0 &&*/ TxPwrLevel[i] <=26) { + if(ThermalValue > priv->pmib->dot11RFEntry.ther) { + if (delta < 5) + OFDM_index[i] -= 1; + else + OFDM_index[i] -= 2; + } else if(delta > 5 && ThermalValue < priv->pmib->dot11RFEntry.ther) { + OFDM_index[i] += 1; + } + } else if (TxPwrLevel[i] >= 27 && TxPwrLevel[i] <= 32 && ThermalValue > priv->pmib->dot11RFEntry.ther) { + if (delta < 5) + OFDM_index[i] -= 1; + else + OFDM_index[i] -= 2; + } else if (TxPwrLevel[i] >= 32 && TxPwrLevel[i] <= 38 && ThermalValue > priv->pmib->dot11RFEntry.ther && delta > 5) { + OFDM_index[i] -= 1; + } +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + OFDM_index[i] = priv->pshare->OFDM_index[i]; + swingIndexRemap(&OFDM_index[i], priv->pshare->OFDM_index0[i]); + } +#endif + if(OFDM_index[i] > OFDM_TABLE_SIZE-1) + OFDM_index[i] = OFDM_TABLE_SIZE-1; + else if (OFDM_index[i] < OFDM_min_index) + OFDM_index[i] = OFDM_min_index; + } + i=0; + { + if(/*TxPwrLevel[i] >=0 &&*/ TxPwrLevel[i] <=26) { + if(ThermalValue > priv->pmib->dot11RFEntry.ther) { + if (delta < 5) + CCK_index -= 1; + else + CCK_index -= 2; + } else if(delta > 5 && ThermalValue < priv->pmib->dot11RFEntry.ther) { + CCK_index += 1; + } + } else if (TxPwrLevel[i] >= 27 && TxPwrLevel[i] <= 32 && ThermalValue > priv->pmib->dot11RFEntry.ther) { + if (delta < 5) + CCK_index -= 1; + else + CCK_index -= 2; + } else if (TxPwrLevel[i] >= 32 && TxPwrLevel[i] <= 38 && ThermalValue > priv->pmib->dot11RFEntry.ther && delta > 5) { + CCK_index -= 1; + } + +#ifdef HIGH_POWER_EXT_PA + if (priv->pshare->rf_ft_var.use_ext_pa) { + CCK_index = priv->pshare->CCK_index; + swingIndexRemap( &CCK_index, priv->pshare->CCK_index0); + } +#endif + if(CCK_index > CCK_TABLE_SIZE-1) + CCK_index = CCK_TABLE_SIZE-1; + else if (CCK_index < 0) + CCK_index = 0; + } + + //Adujst OFDM Ant_A according to IQK result + ele_D = (OFDMSwingTable[(unsigned int)OFDM_index[0]] & 0xFFC00000)>>22; + X = priv->pshare->RegE94; + Y = priv->pshare->RegE9C; + + if(X != 0) { + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D)>>8)&0x000003FF; + + //new element C = element D x Y + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D)>>8)&0x000003FF; + + //wirte new elements A, C, D to regC80 and regC94, element B is always 0 + value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A; + PHY_SetBBReg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + PHY_SetBBReg(priv, rOFDM0_XCTxAFE, bMaskH4Bits, value32); + + value32 = ((X * ele_D)>>7)&0x01; + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(24), value32); + + } else { + PHY_SetBBReg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[(unsigned int)OFDM_index[0]]); + PHY_SetBBReg(priv, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(24), 0x00); + } + + + set_CCK_swing_index(priv, CCK_index); + + + if(is2T) { + ele_D = (OFDMSwingTable[(unsigned int)OFDM_index[1]] & 0xFFC00000)>>22; + X = priv->pshare->RegEB4; + Y = priv->pshare->RegEBC; + + if(X != 0){ + if ((X & 0x00000200) != 0) //consider minus + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D)>>8)&0x000003FF; + + //new element C = element D x Y + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D)>>8)&0x00003FF; + + //wirte new elements A, C, D to regC88 and regC9C, element B is always 0 + value32=(ele_D<<22)|((ele_C&0x3F)<<16) |ele_A; + PHY_SetBBReg(priv, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + PHY_SetBBReg(priv, rOFDM0_XDTxAFE, bMaskH4Bits, value32); + + value32 = ((X * ele_D)>>7)&0x01; + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(28), value32); + + } else{ + PHY_SetBBReg(priv, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[(unsigned int)OFDM_index[1]]); + PHY_SetBBReg(priv, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); + PHY_SetBBReg(priv, rOFDM0_ECCAThreshold, BIT(28), 0x00); + } + } + } + + if(delta_IQK > 3) { + priv->pshare->ThermalValue_IQK = ThermalValue; + PHY_IQCalibrate(priv); + } + + //update thermal meter value + priv->pshare->ThermalValue = ThermalValue; + + } +} + + +#ifdef ADD_TX_POWER_BY_CMD +static void assign_txpwr_offset(struct rtl8192cd_priv *priv) +{ + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_A[0], priv->pshare->rf_ft_var.txPowerPlus_cck_11); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_A[1], priv->pshare->rf_ft_var.txPowerPlus_cck_5); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_A[2], priv->pshare->rf_ft_var.txPowerPlus_cck_2); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_A[3], priv->pshare->rf_ft_var.txPowerPlus_cck_1); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_B[0], priv->pshare->rf_ft_var.txPowerPlus_cck_11); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_B[1], priv->pshare->rf_ft_var.txPowerPlus_cck_5); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_B[2], priv->pshare->rf_ft_var.txPowerPlus_cck_2); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->CCKTxAgc_B[3], priv->pshare->rf_ft_var.txPowerPlus_cck_1); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[0], priv->pshare->rf_ft_var.txPowerPlus_ofdm_18); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[1], priv->pshare->rf_ft_var.txPowerPlus_ofdm_12); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[2], priv->pshare->rf_ft_var.txPowerPlus_ofdm_9); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[3], priv->pshare->rf_ft_var.txPowerPlus_ofdm_6); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[0], priv->pshare->rf_ft_var.txPowerPlus_ofdm_18); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[1], priv->pshare->rf_ft_var.txPowerPlus_ofdm_12); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[2], priv->pshare->rf_ft_var.txPowerPlus_ofdm_9); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[3], priv->pshare->rf_ft_var.txPowerPlus_ofdm_6); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[4], priv->pshare->rf_ft_var.txPowerPlus_ofdm_54); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[5], priv->pshare->rf_ft_var.txPowerPlus_ofdm_48); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[6], priv->pshare->rf_ft_var.txPowerPlus_ofdm_36); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_A[7], priv->pshare->rf_ft_var.txPowerPlus_ofdm_24); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[4], priv->pshare->rf_ft_var.txPowerPlus_ofdm_54); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[5], priv->pshare->rf_ft_var.txPowerPlus_ofdm_48); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[6], priv->pshare->rf_ft_var.txPowerPlus_ofdm_36); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->OFDMTxAgcOffset_B[7], priv->pshare->rf_ft_var.txPowerPlus_ofdm_24); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[0], priv->pshare->rf_ft_var.txPowerPlus_mcs_3); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[1], priv->pshare->rf_ft_var.txPowerPlus_mcs_2); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[2], priv->pshare->rf_ft_var.txPowerPlus_mcs_1); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[3], priv->pshare->rf_ft_var.txPowerPlus_mcs_0); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[0], priv->pshare->rf_ft_var.txPowerPlus_mcs_3); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[1], priv->pshare->rf_ft_var.txPowerPlus_mcs_2); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[2], priv->pshare->rf_ft_var.txPowerPlus_mcs_1); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[3], priv->pshare->rf_ft_var.txPowerPlus_mcs_0); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[4], priv->pshare->rf_ft_var.txPowerPlus_mcs_7); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[5], priv->pshare->rf_ft_var.txPowerPlus_mcs_6); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[6], priv->pshare->rf_ft_var.txPowerPlus_mcs_5); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[7], priv->pshare->rf_ft_var.txPowerPlus_mcs_4); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[4], priv->pshare->rf_ft_var.txPowerPlus_mcs_7); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[5], priv->pshare->rf_ft_var.txPowerPlus_mcs_6); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[6], priv->pshare->rf_ft_var.txPowerPlus_mcs_5); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[7], priv->pshare->rf_ft_var.txPowerPlus_mcs_4); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[8], priv->pshare->rf_ft_var.txPowerPlus_mcs_11); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[9], priv->pshare->rf_ft_var.txPowerPlus_mcs_10); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[10], priv->pshare->rf_ft_var.txPowerPlus_mcs_9); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[11], priv->pshare->rf_ft_var.txPowerPlus_mcs_8); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[8], priv->pshare->rf_ft_var.txPowerPlus_mcs_11); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[9], priv->pshare->rf_ft_var.txPowerPlus_mcs_10); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[10], priv->pshare->rf_ft_var.txPowerPlus_mcs_9); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[11], priv->pshare->rf_ft_var.txPowerPlus_mcs_8); + + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[12], priv->pshare->rf_ft_var.txPowerPlus_mcs_15); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[13], priv->pshare->rf_ft_var.txPowerPlus_mcs_14); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[14], priv->pshare->rf_ft_var.txPowerPlus_mcs_13); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_A[15], priv->pshare->rf_ft_var.txPowerPlus_mcs_12); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[12], priv->pshare->rf_ft_var.txPowerPlus_mcs_15); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[13], priv->pshare->rf_ft_var.txPowerPlus_mcs_14); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[14], priv->pshare->rf_ft_var.txPowerPlus_mcs_13); + ASSIGN_TX_POWER_OFFSET(priv->pshare->phw->MCSTxAgcOffset_B[15], priv->pshare->rf_ft_var.txPowerPlus_mcs_12); +} +#endif + + +void reload_txpwr_pg(struct rtl8192cd_priv *priv) +{ + PHY_ConfigBBWithParaFile(priv, PHYREG_PG); + +#ifdef HIGH_POWER_EXT_PA + if (!priv->pshare->rf_ft_var.use_ext_pa) +#endif + { + // get default Tx AGC offset + //_TXPWR_REDEFINE ?? CCKTxAgc_A[1] [2] [3] ?? + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[0]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs03_Mcs00)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[4]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs07_Mcs04)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[8]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs11_Mcs08)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[12]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs15_Mcs12)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_A[0]) = cpu_to_be32(RTL_R32(rTxAGC_A_Rate18_06)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_A[4]) = cpu_to_be32(RTL_R32(rTxAGC_A_Rate54_24)); + *(unsigned int *)(&priv->pshare->phw->CCKTxAgc_A[0]) = cpu_to_be32((RTL_R32(rTxAGC_A_CCK11_2_B_CCK11) & 0xffffff00) + | RTL_R8(rTxAGC_A_CCK1_Mcs32 + 1)); + + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[0]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs03_Mcs00)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[4]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs07_Mcs04)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[8]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs11_Mcs08)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[12]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs15_Mcs12)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_B[0]) = cpu_to_be32(RTL_R32(rTxAGC_B_Rate18_06)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_B[4]) = cpu_to_be32(RTL_R32(rTxAGC_B_Rate54_24)); + *(unsigned int *)(&priv->pshare->phw->CCKTxAgc_B[0]) = cpu_to_be32((RTL_R8(rTxAGC_A_CCK11_2_B_CCK11) << 24) + | (RTL_R32(rTxAGC_B_CCK5_1_Mcs32) >> 8)); + + } +#ifdef ADD_TX_POWER_BY_CMD + assign_txpwr_offset(priv); +#endif +} + + +int rtl8192cd_init_hw_PCI(struct rtl8192cd_priv *priv) +{ + struct wifi_mib *pmib; + unsigned int opmode; + unsigned long val32; + unsigned short val16; + int i; + unsigned int fwStatus=0, dwnRetry=5; + + pmib = GET_MIB(priv); + opmode = priv->pmib->dot11OperationEntry.opmode; + + DBFENTER; + +#if 0 // ==========>> later +//#ifdef DW_FW_BY_MALLOC_BUF + if ((priv->pshare->fw_IMEM_buf = kmalloc(FW_IMEM_SIZE, GFP_ATOMIC)) == NULL) { + DEBUG_ERR("alloc fw_IMEM_buf failed!\n"); + return -1; + } + if ((priv->pshare->fw_EMEM_buf = kmalloc(FW_EMEM_SIZE, GFP_ATOMIC)) == NULL) { + DEBUG_ERR("alloc fw_EMEM_buf failed!\n"); + return -1; + } + if ((priv->pshare->fw_DMEM_buf = kmalloc(FW_DMEM_SIZE, GFP_ATOMIC)) == NULL) { + DEBUG_ERR("alloc fw_DMEM_buf failed!\n"); + return -1; + } +#endif + + +//1 For Test, Firmware Downloading + +// MacConfigBeforeFwDownload(priv); + +#if 0 // ==========>> later + // =========================================================================================== + // Download Firmware + // allocate memory for tx cmd packet + if((priv->pshare->txcmd_buf = (unsigned char *)kmalloc((LoadPktSize), GFP_ATOMIC)) == NULL) { + printk("not enough memory for txcmd_buf\n"); + return -1; + } + + priv->pshare->cmdbuf_phyaddr = get_physical_addr(priv, priv->pshare->txcmd_buf, + LoadPktSize, PCI_DMA_TODEVICE); + + if(LoadFirmware(priv) == FALSE){ +// panic_printk("Load Firmware Fail!\n"); + panic_printk("Load Firmware check!\n"); + return -1; + }else { +// delay_ms(20); + PRINT_INFO("Load firmware successful! \n"); + } +#endif +// MacConfigAfterFwDownload(priv); + +#if 0 // defined(CONFIG_RTL_92D_SUPPORT) && defined(MP_TEST) // 92D MP DUAL-PHY SETTING + if (priv->pshare->rf_ft_var.mp_specific && (GET_CHIP_VER(priv) == VERSION_8192D)) + priv->pmib->dot11RFEntry.macPhyMode = DUALMAC_DUALPHY; + //priv->pmib->dot11RFEntry.macPhyMode = SINGLEMAC_SINGLEPHY; +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + check_chipID_MIMO(priv); + } +#endif +#if 0 //def CONFIG_RTL_92D_SUPPORT + if (check_MacPhyMode(priv)<0){ + printk("Check macPhyMode Fail!\n"); + return -1; + } +#endif +#ifdef SMART_CONCURRENT_92D + if (priv->pmib->dot11RFEntry.smcc==1 && priv->pmib->dot11RFEntry.macPhyMode != SINGLEMAC_SINGLEPHY + && (priv->pshare->wlandev_idx == 0) + ){ + printk("Switch to dual-mac-single-phy!!!\n"); + priv->pmib->dot11RFEntry.macPhyMode = DUALMAC_SINGLEPHY; + } +#endif + + + MacInit(priv); + +// RTL_W32(AGGLEN_LMT, RTL_R32(AGGLEN_LMT)|(0x0F&AGGLMT_MCS15S_Mask)<<AGGLMT_MCS15S_SHIFT +// |(0x0F&AGGLMT_MCS15_Mask)<<AGGLMT_MCS15_SHIFT); + +// RTL_W8(AGGR_BK_TIME, 0x10); + + // + // 2. Initialize MAC/PHY Config by MACPHY_reg.txt + // + PHY_ConfigMACWithParaFile(priv); + + // + // 3. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt + // +#ifdef DRVMAC_LB + if (!priv->pmib->miscEntry.drvmac_lb) +#endif + { + val32 = phy_BB8192CD_Config_ParaFile(priv); + if (val32) + return -1; + } + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + if(priv->pmib->dot11RFEntry.xcap != 0xff) { + PHY_SetBBReg(priv, 0x24, 0xF0, priv->pmib->dot11RFEntry.xcap & 0x0F); + PHY_SetBBReg(priv, 0x28, 0xF0000000, ((priv->pmib->dot11RFEntry.xcap & 0xF0) >> 4)); + } + } +#endif + + // support up to MCS7 for 1T1R, modify rx capability here + /* + if (get_rf_mimo_mode(priv) == MIMO_1T1R +#ifdef SMART_CONCURRENT_92D //-- fwdebug + && priv->pmib->dot11RFEntry.smcc==0 +#endif + ) + pmib->dot11nConfigEntry.dot11nSupportedMCS &= 0x00ff; + + */ +/* + // Set NAV protection length + // CF-END Threshold + if (priv->pmib->dot11OperationEntry.wifi_specific) { + RTL_W16(NAV_PROT_LEN, 0x80); +// RTL_W8(CFEND_TH, 0x2); + } + else { + RTL_W16(NAV_PROT_LEN, 0x01C0); +// RTL_W8(CFEND_TH, 0xFF); + } +*/ + // + // 4. Initiailze RF RAIO_A.txt RF RAIO_B.txt + // + // 2007/11/02 MH Before initalizing RF. We can not use FW to do RF-R/W. + // close loopback, normal mode + + // For RF test only from Scott's suggestion +// RTL_W8(0x27, 0xDB); // ==========>> ??? +// RTL_W8(0x1B, 0x07); // ACUT + +/* + // set RCR: RX_SHIFT and disable ACF +// RTL_W8(0x48, 0x3e); +// RTL_W32(0x48, RTL_R32(0x48) & ~ RCR_ACF & ~RCR_ACRC32); + RTL_W16(RCR, RCR_AAP | RCR_APM | RCR_ACRC32); + RTL_W32(RCR, RTL_R32(RCR) & ~ RCR_ACF & ~RCR_ACRC32); + // for debug by victoryman, 20081119 +// RTL_W32(RCR, RTL_R32(RCR) | RCR_APP_PHYST_RXFF); + RTL_W32(RCR, RTL_R32(RCR) | RCR_APP_PHYSTS); +*/ +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { +#if defined(RTL8192D_INT_PA) + u8 c9 = priv->pmib->dot11RFEntry.trsw_pape_C9; + u8 cc = priv->pmib->dot11RFEntry.trsw_pape_CC; + if ((c9 == 0xAA && cc == 0xA0) || // Type 2 : 5G TRSW+Int. PA, 2G TR co-matched + (c9 == 0xAA && cc == 0xAF) || // Type 3 : 5G SP3TSW+ Ext.(or Int.)PA, 2G TR co-matched + (c9 == 0x00 && cc == 0xA0)) { // Type 4 : 5G TRSW+ Ext( or Int.)PA, 2G TRSW+ Ext.(or Int.)PA + + panic_printk("\n**********************************\n"); + panic_printk("\n** NOTE!! RTL8192D INTERNAL PA! **\n"); + panic_printk("\n**********************************\n"); + + + priv->pshare->rf_ft_var.use_intpa92d = 1; + priv->pshare->phw->InternalPA5G[0]=1; + priv->pshare->phw->InternalPA5G[1]=1; + } else { + // if using default setting, set as external PA for safe. + priv->pshare->rf_ft_var.use_intpa92d = 0; + priv->pmib->dot11RFEntry.trsw_pape_C9 = 0x00; + priv->pmib->dot11RFEntry.trsw_pape_CC = 0xFF; + priv->pshare->phw->InternalPA5G[0]=0; + priv->pshare->phw->InternalPA5G[1]=0; + } +#else + // to ignore flash setting for external PA + priv->pmib->dot11RFEntry.trsw_pape_C9 = 0x00; + priv->pmib->dot11RFEntry.trsw_pape_CC = 0xFF; + priv->pshare->phw->InternalPA5G[0]=0; + priv->pshare->phw->InternalPA5G[1]=0; +#endif + } +#endif + +#ifdef DRVMAC_LB + if (priv->pmib->miscEntry.drvmac_lb) { + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_NOLINK & NETYPE_Mask) << NETYPE_SHIFT)); + drvmac_loopback(priv); + } + else +#endif + { +//#ifdef CHECK_HANGUP +#if 0 + if (!priv->reset_hangup +#ifdef CLIENT_MODE + || (!(OPMODE & WIFI_AP_STATE) && + (priv->join_res != STATE_Sta_Bss) && (priv->join_res != STATE_Sta_Ibss_Active)) +#endif + ) +#endif + { + val32 = phy_RF6052_Config_ParaFile(priv); + if (val32) + return -1; + + if(IS_UMC_A_CUT_88C(priv)) { + PHY_SetRFReg(priv, RF92CD_PATH_A, RF_RX_G1, bMask20Bits, 0x30255); + PHY_SetRFReg(priv, RF92CD_PATH_A, RF_RX_G2, bMask20Bits, 0x50a00); + } else if(IS_UMC_B_CUT_88C(priv)) { + + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x1e, bMask20Bits, 0x03 |(PHY_QueryRFReg(priv, RF92CD_PATH_A, 0x1e, bMaskDWord, 1)&0xff0f0)); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x1f, bMask20Bits, 0x200|(PHY_QueryRFReg(priv, RF92CD_PATH_A, 0x1f, bMaskDWord, 1)&0xff0ff)); + + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x0c, bMask20Bits, 0x0008992f); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x0a, bMask20Bits, 0x0001aef1); + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x15, bMask20Bits, 0x0008f425); + + } + + } + } + +#ifdef DW_FW_BY_MALLOC_BUF + kfree(priv->pshare->fw_IMEM_buf); + kfree(priv->pshare->fw_EMEM_buf); + kfree(priv->pshare->fw_DMEM_buf); +#endif + +/* + { + // for test, switch to 40Mhz mode + unsigned int val_read; + val_read = PHY_QueryRFReg(priv, 0, 18, bMask20Bits, 1); + val_read &= ~(BIT(10)|BIT(11)); + PHY_SetRFReg(priv, 0, 18, bMask20Bits, val_read); + val_read = PHY_QueryRFReg(priv, 1, 18, bMask20Bits, 1); + val_read &= ~(BIT(10)|BIT(11)); + PHY_SetRFReg(priv, 1, 18, bMask20Bits, val_read); + + RTL_W8(0x800,RTL_R8(0x800)|0x1); + RTL_W8(0x800,RTL_R8(0x900)|0x1); + + RTL_W8(0xc04 , 0x33); + RTL_W8(0xd04, 0x33); + + } +*/ + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + unsigned int eRFPath, curMaxRFPath=((priv->pmib->dot11RFEntry.macPhyMode==SINGLEMAC_SINGLEPHY)?RF92CD_PATH_MAX : RF92CD_PATH_B); + for(eRFPath = RF92CD_PATH_A; eRFPath <curMaxRFPath; eRFPath++) { + priv->pshare->RegRF18[eRFPath] = PHY_QueryRFReg(priv, eRFPath, 0x18, bMask20Bits, 1); + priv->pshare->RegRF28[eRFPath] = PHY_QueryRFReg(priv, eRFPath, 0x28, bMask20Bits, 1); + } + UpdateBBRFVal8192DE(priv); + } +#endif + /*---- Set CCK and OFDM Block "ON"----*/ + PHY_SetBBReg(priv, rFPGA0_RFMOD, bOFDMEn, 1); +#if defined(CONFIG_RTL_92D_SUPPORT) + if (!(priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G)) +#endif + PHY_SetBBReg(priv, rFPGA0_RFMOD, bCCKEn, 1); + + MacConfig(priv); + + /* + * Force CCK CCA for High Power products + */ + if (priv->pshare->rf_ft_var.use_ext_lna) + RTL_W8(0xa0a, 0xcd); + +// RTL_W8(BW_OPMODE, BIT(2)); // 40Mhz:0 20Mhz:1 +// RTL_W32(MACIDR,0x0); + + // under loopback mode +// RTL_W32(MACIDR,0xffffffff); // need to confirm +/* +#ifdef CONFIG_NET_PCI + if (IS_PCIBIOS_TYPE) + pci_unmap_single(priv->pshare->pdev, priv->pshare->cmdbuf_phyaddr, + (LoadPktSize), PCI_DMA_TODEVICE); +#endif +*/ +#if 0 +// RTL_W32(0x230, 0x40000000); //for test +//////////////////////////////////////////////////////////// + + printk("init_hw: 1\n"); + + RTL_W16(SIFS_OFDM, 0x1010); + RTL_W8(SLOT_TIME, 0x09); + + RTL_W8(MSR, MSR_AP); + +// RTL_W8(MSR,MSR_INFRA); + // for test, loopback +// RTL_W8(MSR, MSR_NOLINK); +// RTL_W8(LBKMD_SEL, BIT(0)| BIT(1) ); +// RTL_W16(LBDLY, 0xffff); + + //beacon related + RTL_W16(BCN_INTERVAL, pmib->dot11StationConfigEntry.dot11BeaconPeriod); + RTL_W16(ATIMWND, 2); //0 + RTL_W16(BCN_DRV_EARLY_INT, 10<<4); // 2 + RTL_W16(BCN_DMATIME, 256); // 0xf + RTL_W16(SIFS_OFDM, 0x0e0e); + RTL_W8(SLOT_TIME, 0x10); + +// CamResetAllEntry(priv); + RTL_W16(SECR, 0x0000); + +// By H.Y. advice +// RTL_W16(_BCNTCFG_, 0x060a); +// if (OPMODE & WIFI_AP_STATE) +// RTL_W16(BCNTCFG, 0x000a); +// else +// for debug +// RTL_W16(_BCNTCFG_, 0x060a); +// RTL_W16(BCNTCFG, 0x0204); + + + init_beacon(priv); + + priv->pshare->InterruptMask = (IMR_ROK | IMR_VODOK | IMR_VIDOK | IMR_BEDOK | IMR_BKDOK | \ + IMR_HCCADOK | IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK | \ + IMR_BDOK | /*IMR_RXCMDOK | IMR_TIMEOUT0 |*/ IMR_RDU | IMR_RXFOVW | \ + IMR_BcnInt/* | IMR_TXFOVW*/ /*| IMR_TBDOK | IMR_TBDER*/) ;// IMR_ROK | IMR_BcnInt | IMR_RDU | IMR_RXFOVW | IMR_RXCMDOK; + +// priv->pshare->InterruptMask = IMR_ROK| IMR_BDOK | IMR_BcnInt | IMR_MGNTDOK | IMR_TBDOK | IMR_RDU ; +// priv->pshare->InterruptMask = 0; + priv->pshare->InterruptMaskExt = 0; + RTL_W32(IMR, priv->pshare->InterruptMask); + RTL_W32(IMR+4, priv->pshare->InterruptMaskExt); + +////////////////////////////////////////////////////////////// + printk("end of init hw\n"); + + return 0; + +#endif +// clear TPPoll +// RTL_W16(TPPoll, 0x0); +// Should 8192SE do this initialize? I don't know yet, 080812. Joshua + // PJ 1-5-2007 Reset PHY parameter counters +// RTL_W32(0xD00, RTL_R32(0xD00)|BIT(27)); +// RTL_W32(0xD00, RTL_R32(0xD00)&(~(BIT(27)))); +/* + // configure timing parameter + RTL_W8(ACK_TIMEOUT, 0x30); + RTL_W8(PIFS_TIME,0x13); +// RTL_W16(LBDLY, 0x060F); +// RTL_W16(SIFS_OFDM, 0x0e0e); +// RTL_W8(SLOT_TIME, 0x10); + if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) { + RTL_W16(SIFS_OFDM, 0x0a0a); + RTL_W8(SLOT_TIME, 0x09); + } + else if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) { + RTL_W16(SIFS_OFDM, 0x0a0a); + RTL_W8(SLOT_TIME, 0x09); + } + else if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) { + RTL_W16(SIFS_OFDM, 0x0a0a); + RTL_W8(SLOT_TIME, 0x09); + } + else { // WIRELESS_11B + RTL_W16(SIFS_OFDM, 0x0a0a); + RTL_W8(SLOT_TIME, 0x14); + } +*/ + init_EDCA_para(priv, pmib->dot11BssType.net_work_type); + + + // we don't have EEPROM yet, Mark this for FPGA Platform +// RTL_W8(_9346CR_, CR9346_CFGRW); + +// 92SE Windows driver does not set the PCIF as 0x77, seems HW bug? + // Set Tx and Rx DMA burst size +// RTL_W8(PCIF, 0x77); + // Enable byte shift +// RTL_W8(_PCIF_+2, 0x01); + +/* + // Retry Limit + if (priv->pmib->dot11OperationEntry.dot11LongRetryLimit) + val16 = priv->pmib->dot11OperationEntry.dot11LongRetryLimit & 0xff; + else { + if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) + val16 = 0x30; + else + val16 = 0x06; + } + if (priv->pmib->dot11OperationEntry.dot11ShortRetryLimit) + val16 |= ((priv->pmib->dot11OperationEntry.dot11ShortRetryLimit & 0xff) << 8); + else { + if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) + val16 |= (0x30 << 8); + else + val16 |= (0x06 << 8); + } + RTL_W16(RETRY_LIMIT, val16); + + This should be done later, but Windows Driver not done yet. + // Response Rate Set + // let ACK sent by highest of 24Mbps + val32 = 0x1ff; + if (pmib->dot11RFEntry.shortpreamble) + val32 |= BIT(23); + RTL_W32(_RRSR_, val32); +*/ + + + + +// panic_printk("0x2c4 = bitmap = 0x%08x\n", (unsigned int)val32); +// panic_printk("0x2c0 = cmd | macid | band = 0x%08x\n", 0xfd0000a2 | (1<<9 | (sta_band & 0xf))<<8); +// panic_printk("Add id %d val %08x to ratr\n", 0, (unsigned int)val32); + +/* for (i = 0; i < 8; i++) + RTL_W32(ARFR0+i*4, val32 & 0x1f0ff0f0); +*/ + + //settting initial rate for control frame to 24M +// RTL_W8(INIRTSMCS_SEL, 8); // ==========>> later + + //setting MAR + RTL_W32(MAR, 0xffffffff); + RTL_W32((MAR+4), 0xffffffff); + + //setting BSSID, not matter AH/AP/station + memcpy((void *)&val32, (pmib->dot11OperationEntry.hwaddr), 4); + memcpy((void *)&val16, (pmib->dot11OperationEntry.hwaddr + 4), 2); + RTL_W32(BSSIDR, cpu_to_le32(val32)); + RTL_W16((BSSIDR + 4), cpu_to_le16(val16)); +// RTL_W32(BSSIDR, 0x814ce000); +// RTL_W16((BSSIDR + 4), 0xee92); + + //setting TCR + //TCR, use default value + + //setting RCR // set in MacConfigAfterFwDownload +// RTL_W32(_RCR_, _APWRMGT_ | _AMF_ | _ADF_ | _AICV_ | _ACRC32_ | _AB_ | _AM_ | _APM_); +// if (pmib->dot11OperationEntry.crc_log) +// RTL_W32(_RCR_, RTL_R32(_RCR_) | _ACRC32_); + + // setting network type + if (opmode & WIFI_AP_STATE) + { + DEBUG_INFO("AP-mode enabled...\n"); + +#if defined(CONFIG_RTK_MESH) //Mesh Mode but mesh not enable + if (priv->pmib->dot11WdsInfo.wdsPure || priv->pmib->dot1180211sInfo.meshSilence ) +#else + if (priv->pmib->dot11WdsInfo.wdsPure) +#endif + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_NOLINK & NETYPE_Mask) << NETYPE_SHIFT)); + else + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_AP & NETYPE_Mask) << NETYPE_SHIFT)); +// Move init beacon after f/w download +#if 0 + if (priv->auto_channel == 0) { + DEBUG_INFO("going to init beacon\n"); + init_beacon(priv); + } +#endif + } +#ifdef CLIENT_MODE + else if (opmode & WIFI_STATION_STATE) + { + DEBUG_INFO("Station-mode enabled...\n"); + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_INFRA & NETYPE_Mask) << NETYPE_SHIFT)); + } + else if (opmode & WIFI_ADHOC_STATE) + { + DEBUG_INFO("Adhoc-mode enabled...\n"); + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_ADHOC & NETYPE_Mask) << NETYPE_SHIFT)); + } +#endif + else + { + printk("Operation mode error!\n"); + return 2; + } + + CamResetAllEntry(priv); + RTL_W16(SECCFG, 0); + if ((OPMODE & (WIFI_AP_STATE|WIFI_STATION_STATE|WIFI_ADHOC_STATE)) && + !priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm && + (pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_40_PRIVACY_ || + pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_104_PRIVACY_)) { + pmib->dot11GroupKeysTable.dot11Privacy = pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm; + if (pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_40_PRIVACY_) + i = 5; + else + i = 13; +#ifdef USE_WEP_DEFAULT_KEY + memcpy(pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey, + &priv->pmib->dot11DefaultKeysTable.keytype[pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex].skey[0], i); + pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKeyLen = i; + pmib->dot11GroupKeysTable.keyid = pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex; + pmib->dot11GroupKeysTable.keyInCam = 0; + RTL_W16(SECCFG, RTL_R16(SECCFG) | NOSKMC); // no search multicast +#else +#if defined(CONFIG_RTL8196B_KLD) || defined(CONFIG_RTL8196C_KLD) + memcpy(pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey, + &priv->pmib->dot11DefaultKeysTable.keytype[pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex].skey[0], i); +#else + memcpy(pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey, + &priv->pmib->dot11DefaultKeysTable.keytype[0].skey[0], i); +#endif + pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKeyLen = i; + pmib->dot11GroupKeysTable.keyid = pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex; + pmib->dot11GroupKeysTable.keyInCam = 0; +#endif + } + +// for debug +#if 0 +// when hangup reset, re-init TKIP/AES key in ad-hoc mode +#ifdef CLIENT_MODE + if ((OPMODE & WIFI_ADHOC_STATE) && pmib->dot11OperationEntry.keep_rsnie && + (pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _TKIP_PRIVACY_ || + pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _CCMP_PRIVACY_)) { + DOT11_SET_KEY Set_Key; + Set_Key.KeyType = DOT11_KeyType_Group; + Set_Key.EncType = pmib->dot11GroupKeysTable.dot11Privacy; + DOT11_Process_Set_Key(priv->dev, NULL, &Set_Key, pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey); + } + else +#endif +//-------------------------------------- david+2006-06-30 + // restore group key if it has been set before open, david + if (pmib->dot11GroupKeysTable.keyInCam) { + int retVal; + retVal = CamAddOneEntry(priv, (unsigned char *)"\xff\xff\xff\xff\xff\xff", + pmib->dot11GroupKeysTable.keyid, + pmib->dot11GroupKeysTable.dot11Privacy<<2, + 0, pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey); + if (retVal) + priv->pshare->CamEntryOccupied++; + else { + DEBUG_ERR("Add group key failed!\n"); + } + } +#endif + //here add if legacy WEP + // if 1x is enabled, do not set default key, david +//#if 0 // marked by victoryman, use pairwise key at present, 20070627 +#ifdef USE_WEP_DEFAULT_KEY +#ifdef MBSSID + if (!(OPMODE & WIFI_AP_STATE) || !priv->pmib->miscEntry.vap_enable) +#endif + { + if(!SWCRYPTO && !IEEE8021X_FUN && + (pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_104_PRIVACY_ || + pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_40_PRIVACY_)) + init_DefaultKey_Enc(priv, NULL, 0); + } +#endif + + + //Setup Beacon Interval/interrupt interval, ATIM-WIND ATIM-Interrupt + RTL_W32(MBSSID_BCN_SPACE, pmib->dot11StationConfigEntry.dot11BeaconPeriod); + //Setting BCNITV is done by firmware now +// set_fw_reg(priv, (0xF1000000 | (pmib->dot11StationConfigEntry.dot11BeaconPeriod << 8)), 0, 0); + // Set max AMPDU aggregation time +// int max_aggre_time = 0xc0; // in 4us +// set_fw_reg(priv, (0xFD0000B1|((max_aggre_time << 8) & 0xff00)), 0 ,0); + +// RTL_W32(0x2A4, 0x00006300); +// RTL_W32(0x2A0, 0xb026007C); +// delay_ms(1); +// while(RTL_R32(0x2A0) != 0){}; + //RTL_W16(TBTT_PROHIBIT, 0xc804); + if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) + RTL_W32(TBTT_PROHIBIT, 0x1df04); + else + RTL_W32(TBTT_PROHIBIT, 0x40004); + +#ifdef SMART_CONCURRENT_92D + if (priv->pmib->dot11RFEntry.smcc==1 && priv->pmib->dot11RFEntry.macPhyMode != SINGLEMAC_SINGLEPHY){ + if (priv->pmib->dot11RFEntry.phyBandSelect==PHY_BAND_5G) + RTL_W8(DRVERLYINT, 3); + else + RTL_W8(DRVERLYINT, 3); + } else +#endif + RTL_W8(DRVERLYINT, 10); + RTL_W8(BCNDMATIM, 1); + RTL_W16(ATIMWND, 5); +/* + if (!((OPMODE & WIFI_AP_STATE) +#if defined(WDS) && defined(CONFIG_RTK_MESH) + && ((priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsPure) || priv->pmib->dot1180211sInfo.meshSilence)) +#elif defined(WDS) + && priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsPure ) +#elif defined(CONFIG_RTK_MESH) //Mesh Mode but mesh not enable + && priv->pmib->dot1180211sInfo.meshSilence ) +#else + ) +#endif + ) + + RTL_W16(BCN_DRV_EARLY_INT, RTL_R16(BCN_DRV_EARLY_INT)|BIT(15)); // sw beacon +*/ +#ifdef MBSSID + if (priv->pmib->miscEntry.vap_enable && RTL8192CD_NUM_VWLAN == 1 && + priv->pmib->dot11StationConfigEntry.dot11BeaconPeriod < 30) + //RTL_W16(BCN_DRV_EARLY_INT, (RTL_R16(BCN_DRV_EARLY_INT)&0xf00f) | ((6<<4)&0xff0)); + RTL_W8(DRVERLYINT, 6); +#endif + + if (IS_TEST_CHIP(priv) && ((GET_CHIP_VER(priv)==VERSION_8188C) || (GET_CHIP_VER(priv)==VERSION_8192C))) { + RTL_W8(BCN_CTRL, 0); + RTL_W8(0x553, 1); + RTL_W8(BCN_CTRL, EN_BCN_FUNCTION); + // RTL_W16(BCN_DMATIME, 0x400); // 1ms + + // for debug +#ifdef CLIENT_MODE + if (OPMODE & WIFI_ADHOC_STATE) + RTL_W8(BCN_MAX_ERR, 0xff); +#endif + } else { + RTL_W8(BCN_CTRL, DIS_TSF_UPDATE_N| DIS_SUB_STATE_N ); + RTL_W8(BCN_MAX_ERR, 0xff); + RTL_W16(0x518, 0); + RTL_W8(0x553, 3); + if(OPMODE & WIFI_STATION_STATE) + RTL_W8(0x422, RTL_R8(0x422)^BIT(6)); + +#ifdef MP_TEST + if (!priv->pshare->rf_ft_var.mp_specific) +#endif + RTL_W8(BCN_CTRL, RTL_R8(BCN_CTRL) | EN_BCN_FUNCTION | EN_TXBCN_RPT ); + } + + +//-------------- + +// By H.Y. advice +// RTL_W16(_BCNTCFG_, 0x060a); + if (OPMODE & WIFI_AP_STATE) + RTL_W16(BCNTCFG, 0x0001); + else +// for debug +// RTL_W16(_BCNTCFG_, 0x060a); + RTL_W16(BCNTCFG, 0x0204); + + +#if 1 + // Ack ISR, and then unmask IMR +#if 0 + RTL_W32(ISR, RTL_R32(ISR)); + RTL_W32(ISR+4, RTL_R16(ISR+4)); + RTL_W32(IMR, 0x0); + RTL_W32(IMR+4, 0x0); + priv->pshare->InterruptMask = _ROK_ | _BCNDMAINT_ | _RDU_ | _RXFOVW_ | _RXCMDOK_; + priv->pshare->InterruptMask = (IMR_ROK | IMR_VODOK | IMR_VIDOK | IMR_BEDOK | IMR_BKDOK | \ + IMR_HCCADOK | IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK | \ + IMR_BDOK | IMR_RXCMDOK | /*IMR_TIMEOUT0 |*/ IMR_RDU | IMR_RXFOVW | \ + IMR_BcnInt/* | IMR_TXFOVW*/ /*| IMR_TBDOK | IMR_TBDER*/);// IMR_ROK | IMR_BcnInt | IMR_RDU | IMR_RXFOVW | IMR_RXCMDOK; +#endif + //priv->pshare->InterruptMask = HIMR_ROK | HIMR_BCNDMA0 | HIMR_RDU | HIMR_RXFOVW; + priv->pshare->InterruptMask = HIMR_ROK | HIMR_BCNDMA0 | HIMR_RXFOVW; +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) + priv->pshare->InterruptMask |= HIMR_BEDOK; +#endif + priv->pshare->InterruptMaskExt = 0; + + if (opmode & WIFI_AP_STATE) + priv->pshare->InterruptMask |= HIMR_BCNDOK0 | HIMR_TXBCNERR; +#ifdef CLIENT_MODE + else if (opmode & WIFI_ADHOC_STATE) + priv->pshare->InterruptMaskExt |= (HIMR_TXBCNERR | HIMR_TXBCNOK); +#endif + +#endif + // FGPA does not have eeprom now +// RTL_W8(_9346CR_, 0); +/* + // =========================================================================================== + // Download Firmware + // allocate memory for tx cmd packet + if((priv->pshare->txcmd_buf = (unsigned char *)kmalloc((LoadPktSize), GFP_ATOMIC)) == NULL) { + printk("not enough memory for txcmd_buf\n"); + return -1; + } + + priv->pshare->cmdbuf_phyaddr = get_physical_addr(priv, priv->pshare->txcmd_buf, + LoadPktSize, PCI_DMA_TODEVICE); +*/ + + /* currently need not to download fw */ + rtl8192cd_ReadFwHdr(priv); + + while(dwnRetry-- && !fwStatus) { +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) + fwStatus = Load_92D_Firmware(priv); +#endif +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) + fwStatus = Load_92C_Firmware(priv); +#endif + delay_ms(20); + }; + if(fwStatus) { + DEBUG_INFO("Load firmware successful!\n"); + } + else { + DEBUG_INFO("Load firmware check!\n"); +#ifdef PCIE_POWER_SAVING + priv->pshare->rf_ft_var.power_save &= ~( L1_en|L2_en); +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + if (RTL_R8(0x1c5)==0xE0){ + DEBUG_INFO("RTL8192D part number failed!!\n"); + return -1; + } + } +#endif + } + +/* + MacConfigAfterFwDownload(priv); +*/ + + // Adaptive Rate Table for Basic Rate + val32 = 0; + for (i=0; i<32; i++) { + if (AP_BSSRATE[i]) { + if (AP_BSSRATE[i] & 0x80) + val32 |= get_bit_value_from_ieee_value(AP_BSSRATE[i] & 0x7f); + } + } + val32 |= (priv->pmib->dot11nConfigEntry.dot11nBasicMCS << 12); + + { + unsigned int delay_count = 10; + do { + if (!is_h2c_buf_occupy(priv)) + break; + delay_us(5); + delay_count--; + } while (delay_count); + } + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + if (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) { +#ifdef USB_POWER_SUPPORT + val32 &= USB_RA_MASK; +#endif + set_RATid_cmd(priv, 0, ARFR_Band_A_BMC, val32); + } + else + set_RATid_cmd(priv, 0, ARFR_BMC, val32); + } + else if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + set_RATid_cmd(priv, 0, ARFR_BMC, val32); + } + else + +#endif + set_RATid_cmd(priv, 0, ARFR_BMC, val32); + +// kfree(priv->pshare->txcmd_buf); + +#ifdef MP_TEST + if (!priv->pshare->rf_ft_var.mp_specific) +#endif + if (opmode & WIFI_AP_STATE) + { + if (priv->auto_channel == 0) { + DEBUG_INFO("going to init beacon\n"); + init_beacon(priv); + } + } + + //enable interrupt + RTL_W32(HIMR, priv->pshare->InterruptMask); +// RTL_W32(IMR+4, priv->pshare->InterruptMaskExt); +// RTL_W32(IMR, 0xffffffff); +// RTL_W8(IMR+4, 0x3f); + + // =========================================================================================== + +#ifdef CHECK_HANGUP + if (priv->reset_hangup) + priv->pshare->CurrentChannelBW = priv->pshare->is_40m_bw; + else +#endif + { + if (opmode & WIFI_AP_STATE) + priv->pshare->CurrentChannelBW = priv->pshare->is_40m_bw; + else + priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20; + } + +#ifdef HIGH_POWER_EXT_PA + if (!priv->pshare->rf_ft_var.use_ext_pa) +#endif + { + // get default Tx AGC offset + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[0]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs03_Mcs00)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[4]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs07_Mcs04)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[8]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs11_Mcs08)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_A[12]) = cpu_to_be32(RTL_R32(rTxAGC_A_Mcs15_Mcs12)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_A[0]) = cpu_to_be32(RTL_R32(rTxAGC_A_Rate18_06)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_A[4]) = cpu_to_be32(RTL_R32(rTxAGC_A_Rate54_24)); + *(unsigned int *)(&priv->pshare->phw->CCKTxAgc_A[0]) = cpu_to_be32((RTL_R32(rTxAGC_A_CCK11_2_B_CCK11) & 0xffffff00) + | RTL_R8(rTxAGC_A_CCK1_Mcs32 + 1)); + + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[0]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs03_Mcs00)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[4]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs07_Mcs04)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[8]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs11_Mcs08)); + *(unsigned int *)(&priv->pshare->phw->MCSTxAgcOffset_B[12]) = cpu_to_be32(RTL_R32(rTxAGC_B_Mcs15_Mcs12)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_B[0]) = cpu_to_be32(RTL_R32(rTxAGC_B_Rate18_06)); + *(unsigned int *)(&priv->pshare->phw->OFDMTxAgcOffset_B[4]) = cpu_to_be32(RTL_R32(rTxAGC_B_Rate54_24)); + *(unsigned int *)(&priv->pshare->phw->CCKTxAgc_B[0]) = cpu_to_be32((RTL_R8(rTxAGC_A_CCK11_2_B_CCK11) << 24) + | (RTL_R32(rTxAGC_B_CCK5_1_Mcs32) >> 8)); + + } +#ifdef ADD_TX_POWER_BY_CMD + assign_txpwr_offset(priv); +#endif + +#ifdef TXPWR_LMT + if (!priv->pshare->rf_ft_var.disable_txpwrlmt) + PHY_ConfigTXLmtWithParaFile(priv); +#endif + + + if ((priv->pmib->dot11RFEntry.ther < 0x07) || (priv->pmib->dot11RFEntry.ther > 0x1d)) { + DEBUG_ERR("TPT: unreasonable target ther %d, disable tpt\n", priv->pmib->dot11RFEntry.ther); + priv->pmib->dot11RFEntry.ther = 0; + } + +/* + if (opmode & WIFI_AP_STATE) + { + if (priv->auto_channel == 0) { + DEBUG_INFO("going to init beacon\n"); + init_beacon(priv); + } + } +*/ + /*---- Set CCK and OFDM Block "ON"----*/ + PHY_SetBBReg(priv, rFPGA0_RFMOD, bOFDMEn, 1); +#if defined(CONFIG_RTL_92D_SUPPORT) + if (!(priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G)) +#endif + PHY_SetBBReg(priv, rFPGA0_RFMOD, bCCKEn, 1); + delay_ms(2); + +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) { + RTL_W32(MACID, 0x87654321); + delay_ms(150); + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { +#ifdef SW_LCK_92D + PHY_LCCalibrate_92D(priv); +#endif + SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan); + SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan); + + /* + * IQK + */ + PHY_IQCalibrate(priv); + +#ifdef SMART_CONCURRENT_92D + if (priv->pmib->dot11RFEntry.smcc==1 && priv->pmib->dot11RFEntry.macPhyMode != SINGLEMAC_SINGLEPHY){ + if((priv->MAC_info = (struct SMCC_MAC_Info_Tbl*)kmalloc(sizeof(struct SMCC_MAC_Info_Tbl), GFP_ATOMIC)) == NULL) { + printk("kmalloc SMCC_MAC_Info_Tbl not enough memory\n"); + return -1; + } + memset(priv->MAC_info, 0, sizeof(struct SMCC_MAC_Info_Tbl)); + smcc_92D_fill_MAC_info(priv, priv->MAC_info); + + //if (priv->pmib->dot11RFEntry.smcc==1 && priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_SINGLEPHY) + // priv->pmib->dot11RFEntry.macPhyMode = DUALMAC_DUALPHY; + + /* Because our init flow is wlan0 5G enabled -> wlan1 2G enabled, + * SMCC collects IQC parameters by enabling wlan0 through 2x2A0->1x1A0 first. + * Then we enable wlan1 through 1x1A0G1->2x2G1->1x1A0G1. -- Chris + */ + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G) { + smcc_92D_enable1x1_5G(priv,0); + smcc_92D_fill_MAC_info(priv, priv->MAC_info); + smcc_dump_MAC_info(priv, priv->MAC_info); + smcc_signin_MAC_info(priv, priv->MAC_info); + } + else { + smcc_92D_enable2x2_2G(priv); + smcc_92D_fill_MAC_info(priv, priv->MAC_info); + smcc_dump_MAC_info(priv, priv->MAC_info); + smcc_signin_MAC_info(priv, priv->MAC_info); + // Restore 1x1_A0G1 + smcc_92D_enable1x1_5G(priv,1); + } + + priv->smcc_state = 0; + smcc_signin_linkstate(priv, 1, priv->pmib->dot11RFEntry.smcc_t, priv->smcc_state); + priv->pmib->dot11RFEntry.macPhyMode = DUALMAC_SINGLEPHY; + priv->pshare->phw->MIMO_TR_hw_support = MIMO_2T2R; + + if (priv->pshare->wlandev_idx == 1){ + RTL_W8(0x553, 1); // rst bcn0 + DMDP_RTL_W8(0, 0x553, 1); // rst bcn0 + printk("MAC0-TSF %x MAC1-TSF %x\n", DMDP_RTL_R32(0, TSFTR), RTL_R32(TSFTR)); + DMDP_RTL_W8(0, 0x1c2, 0x11); // enable mac0 smart concurrent + RTL_W8(0x1c2, 0x11); // enable mac1 smart concurrent + } + } +#endif + } +#endif // CONFIG_RTL_92D_SUPPORT + +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) { + PHY_IQCalibrate(priv); // IQK_92C IQK_88c + +#if defined(__LINUX_2_6__) && !defined(NOT_RTK_BSP) + REG32(_WDTCNR_) |= 1 << 23; +#endif + + //Do NOT perform APK fot RF team's request + //PHY_APCalibrate(priv); // APK_92C APK_88C + + PHY_LCCalibrate(priv); + + SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan); + SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan); + + /* + * Set RF & RRSR depends on band in use + */ + if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11G |WIRELESS_11N)) { + if ((priv->pmib->dot11StationConfigEntry.autoRate) || !(priv->pmib->dot11StationConfigEntry.fixedTxRate & 0xf)) { + + if( IS_UMC_A_CUT_88C(priv) || GET_CHIP_VER(priv) == VERSION_8192C ) + PHY_SetRFReg(priv, 0, 0x26, bMask20Bits, 0x4f000); + else + PHY_SetRFReg(priv, 0, 0x26, bMask20Bits, 0x4f200); + +// RTL_W32(RRSR, RTL_R32(RRSR) & ~(0x0c)); + } else { + PHY_SetRFReg(priv, 0, 0x26, bMask20Bits, 0x0f400); + } + } else { + PHY_SetRFReg(priv, 0, 0x26, bMask20Bits, 0x0f400); + } + } +#endif // CONFIG_RTL_92C_SUPPORT +/* + if(priv->pshare->rf_ft_var.ofdm_1ss_oneAnt == 1){// use one PATH for ofdm and 1SS + Switch_1SS_Antenna(priv, 2); + Switch_OFDM_Antenna(priv, 2); + } +*/ + +#if defined(__LINUX_2_6__) + REG32(_WDTCNR_) |= 1 << 23; +#endif + delay_ms(100); + +// 2009.09.10 + if (priv->pshare->rf_ft_var.cck_tx_pathB) { + RTL_W8(0xa07, 0x40); // 0x80 -> 0x40 CCK path B Tx + RTL_W8(0xa0b, 0x84); // 0x88 -> 0x84 CCK path B Tx + } + + //RTL_W32(0x100, RTL_R32(0x100) | BIT(14)); //for 8190 fw debug + + // init DIG variables + val32 = 0x40020064; // 0x20010020 + priv->pshare->threshold0 = (unsigned short)(val32&0x000000FF); + priv->pshare->threshold1 = (unsigned short)((val32&0x000FFF00)>>8); + priv->pshare->threshold2 = (unsigned short)((val32&0xFFF00000)>>20); + priv->pshare->digDownCount = 0; + priv->pshare->digDeadPoint = 0; + priv->pshare->digDeadPointHitCount = 0; + +// CCK path A Tx +#ifdef CONFIG_POCKET_ROUTER_SUPPORT +#ifdef CONFIG_RTL_92D_SUPPORT + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_2G) +#endif + { + RTL_W8(0xa07, (RTL_R8(0xa07) & 0xbf)); + RTL_W8(0xa0b, (RTL_R8(0xa0b) & 0xfb)); + } +#endif + +#ifdef CONFIG_RTL_8198 + RTL_W8(AGGR_BK_TIME, 0x18); + RTL_W16(0x4ca, 0x0a0a); +// RTL_W32(RESP_SIFS_CCK, 0x0e0e0a0a); + //RTL_W32(ACKTO, 0x40001440); + RTL_W16(ACKTO, 0x1440); + RTL_W16(RXFLTMAP2, 0xffff); + //RTL_W16(RCR, RTL_R16(RCR)&(~ BIT(11))); +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + //CBN debug + if (GET_CHIP_VER(priv)==VERSION_8192D) { +#ifndef SMART_CONCURRENT_92D + RTL_W32(RD_CTRL, RTL_R32(RD_CTRL)|BIT(13)); // enable force tx beacon + RTL_W8(BCN_MAX_ERR, 0); // tx beacon error threshold +#endif + RTL_W16(EIFS, 0x0040); // eifs < tbtt_prohibit + } +#endif + + RTL_W32(0x350, RTL_R32(0x350) | BIT(26)); // tx status check + +#ifdef HIGH_POWER_EXT_PA + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + if (priv->pshare->rf_ft_var.use_ext_pa) { + priv->pmib->dot11RFEntry.trswitch = 1; + PHY_SetBBReg(priv, 0x870, BIT(10), 0); + if (GET_CHIP_VER(priv) == VERSION_8192C) + PHY_SetBBReg(priv, 0x870, BIT(26), 0); + } + } +#endif + +#if defined(SW_ANT_SWITCH) || defined(HW_ANT_SWITCH) + priv->pmib->dot11RFEntry.trswitch = 1; +#endif + + if (priv->pmib->dot11RFEntry.trswitch) + RTL_W8(GPIO_MUXCFG, RTL_R8(GPIO_MUXCFG) | TRSW0EN); + else + RTL_W8(GPIO_MUXCFG, RTL_R8(GPIO_MUXCFG) & ~TRSW0EN); + +#ifdef DFS + if (!priv->pmib->dot11DFSEntry.disable_DFS) { + RTL_W8(0xc50, 0x24); + delay_us(10); + RTL_W8(0xc50, 0x20); + } +#endif + + DBFEXIT; + + return 0; + +} + +static void rtl8192cd_ReadFwHdr(struct rtl8192cd_priv *priv) +{ + struct __RTL8192C_FW_HDR__ *pFwHdr = NULL; + unsigned char *swap_arr; + +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) + return; +#endif + + swap_arr = kmalloc(RT_8192CD_FIRMWARE_HDR_SIZE, GFP_ATOMIC); + if (swap_arr == NULL) + return; + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + memcpy(swap_arr, data_rtl8192dfw_n_start, RT_8192CD_FIRMWARE_HDR_SIZE); + } +#endif + +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) + memcpy(swap_arr, data_rtl8192cfw_start, RT_8192CD_FIRMWARE_HDR_SIZE); + else +#endif + { + if( IS_UMC_A_CUT_88C(priv) ) + memcpy(swap_arr, data_rtl8192cfw_ua_start, RT_8192CD_FIRMWARE_HDR_SIZE); + else + memcpy(swap_arr, data_rtl8192cfw_n_start, RT_8192CD_FIRMWARE_HDR_SIZE); + } + } +#endif + + pFwHdr = (struct __RTL8192C_FW_HDR__ *)swap_arr; +#ifdef _BIG_ENDIAN_ + pFwHdr->signature = le16_to_cpu(pFwHdr->signature); + pFwHdr->version = le16_to_cpu(pFwHdr->version); + pFwHdr->year = le16_to_cpu(pFwHdr->year); // ready on after v33.1 +#endif + + priv->pshare->fw_signature = pFwHdr->signature; + priv->pshare->fw_category = pFwHdr->category; + priv->pshare->fw_function = pFwHdr->function; + priv->pshare->fw_version = pFwHdr->version; + priv->pshare->fw_sub_version = pFwHdr->subversion; + priv->pshare->fw_date_month = pFwHdr->month; + priv->pshare->fw_date_day = pFwHdr->day; + priv->pshare->fw_date_hour = pFwHdr->hour; + priv->pshare->fw_date_minute = pFwHdr->minute; + kfree(swap_arr); +/* + printk("fw_signature: "); + if (priv->pshare->fw_signature == RTL8192C_TEST_CHIP) + printk("92C_TEST_CHIP"); + else if (priv->pshare->fw_signature == RTL8188C_TEST_CHIP) + printk("88C_TEST_CHIP"); + else if (priv->pshare->fw_signature == RTL8192C_MP_CHIP_A) + printk("92C_MP_CHIP_A"); + else if (priv->pshare->fw_signature == RTL8188C_MP_CHIP_A) + printk("88C_MP_CHIP_A"); + else if (priv->pshare->fw_signature == RTL8192C_MP_CHIP_B) + printk("92C_MP_CHIP_B"); + else if (priv->pshare->fw_signature == RTL8188C_MP_CHIP_B) + printk("88C_MP_CHIP_B"); + printk(", "); + + printk("fw_category: "); + if (priv->pshare->fw_category == RTL8192C_NIC_PCIE) + printk("92C_NIC_PCIE"); + else if (priv->pshare->fw_category == RTL8192C_NIC_USB) + printk("92C_NIC_USB"); + else if (priv->pshare->fw_category == RTL8192C_AP_PCIE) + printk("92C_AP_PCIE"); + else if (priv->pshare->fw_category == RTL8192C_AP_USB) + printk("92C_AP_USB"); + printk(", "); + + printk("fw_function: "); + if (priv->pshare->fw_function == RTL8192C_NIC_NORMAL) + printk("92C_NIC_NORMAL"); + else if (priv->pshare->fw_function == RTL8192C_NIC_WWLAN) + printk("92C_NIC_WWLAN"); + else if (priv->pshare->fw_function == RTL8192C_AP_NORMAL) + printk("92C_AP_NORMAL"); + else if (priv->pshare->fw_function == RTL8192C_AP_SUSPEND) + printk("92C_AP_SUSPEND"); + printk("\n"); + + printk("fw_version: %d.%d, ", priv->pshare->fw_version, priv->pshare->fw_sub_version); + printk("fw_date: %02x-%02x %02x:%02x\n", priv->pshare->fw_date_month, priv->pshare->fw_date_day, + priv->pshare->fw_date_hour, priv->pshare->fw_date_minute); +*/ +} + +#ifdef CONFIG_RTL_92C_SUPPORT +static int Load_92C_Firmware(struct rtl8192cd_priv *priv) +{ + int fw_len, wait_cnt=0; + unsigned int CurPtr=0; + unsigned int WriteAddr; + unsigned int Temp; + unsigned char *ptmp; + +#ifdef CONFIG_RTL8672 + printk("val=%x\n", RTL_R8(0x80)); +#endif + +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) + return TRUE; +#endif + + printk("===> %s\n", __FUNCTION__); + +#ifdef TESTCHIP_SUPPORT + if (IS_TEST_CHIP(priv)) { + ptmp = data_rtl8192cfw_start + 32; + fw_len = (int)(data_rtl8192cfw_end - ptmp); + + } else +#endif + { + if( IS_UMC_A_CUT_88C(priv) ) { + ptmp = data_rtl8192cfw_ua_start + 32; + fw_len = (int)(data_rtl8192cfw_ua_end - ptmp); + + } else { + ptmp = data_rtl8192cfw_n_start + 32; + fw_len = (int)(data_rtl8192cfw_n_end - ptmp); + } + } + + // Disable SIC + RTL_W8(0x41, 0x40); + delay_ms(1); + + // Enable MCU + + RTL_W8(SYS_FUNC_EN+1, RTL_R8(SYS_FUNC_EN+1) | 0x04); + delay_ms(1); + +#ifdef CONFIG_RTL8672 + RTL_W8(0x04, RTL_R8(0x04) | 0x02); + delay_ms(1); //czyao +#endif + + // Load SRAM + WriteAddr = 0x1000; + RTL_W8(MCUFWDL, RTL_R8(MCUFWDL) | MCUFWDL_EN); + delay_ms(1); + +// if (IS_TEST_CHIP(priv)) +// RTL_W8(0x82, RTL_R8(0x82) & 0xf7); +// else + RTL_W32(MCUFWDL, RTL_R32(MCUFWDL) & 0xfff0ffff); + + delay_ms(1); + + while (CurPtr < fw_len) { + if ((CurPtr+4) > fw_len) { + // Reach the end of file. + while (CurPtr < fw_len) { + Temp = *(ptmp + CurPtr); + RTL_W8(WriteAddr, (unsigned char)Temp); + WriteAddr++; + CurPtr++; + } + } else { + // Write FW content to memory. + Temp = *((unsigned int *)(ptmp + CurPtr)); + Temp = cpu_to_le32(Temp); + RTL_W32(WriteAddr, Temp); + WriteAddr += 4; + + if((IS_TEST_CHIP(priv)==0) && (WriteAddr == 0x2000)) { + unsigned char tmp = RTL_R8(MCUFWDL+2); + tmp += 1; + WriteAddr = 0x1000; + RTL_W8(MCUFWDL+2, tmp) ; + delay_ms(10); +// printk("\n[CurPtr=%x, 0x82=%x]\n", CurPtr, RTL_R8(0x82)); + } + CurPtr += 4; + } + } + + Temp = RTL_R8(0x80); + Temp &= 0xfe; + Temp |= 0x02; + RTL_W8(0x80, (unsigned char)Temp); + delay_ms(1); + RTL_W8(0x81, 0x00); + + printk("<=== %s\n", __FUNCTION__); + + // check if firmware is ready + while (!(RTL_R8(MCUFWDL) & WINTINI_RDY)) { + if (++wait_cnt > 10) { + return FALSE; + } + printk("8192c firmware not ready\n"); + delay_ms(1); + } +#ifdef CONFIG_RTL8672 + printk("val=%x\n",RTL_R8(MCUFWDL)); +#endif + + return TRUE; +} +#endif + + +#define SET_RTL8192CD_RF_HALT(priv) \ +{ \ + unsigned char u1bTmp; \ + \ + do \ + { \ + u1bTmp = RTL_R8(LDOV12D_CTRL); \ + u1bTmp |= BIT(0); \ + RTL_W8(LDOV12D_CTRL, u1bTmp); \ + RTL_W8(SPS1_CTRL, 0x0); \ + RTL_W8(TXPAUSE, 0xFF); \ + RTL_W16(CMDR, 0x57FC); \ + delay_us(100); \ + RTL_W16(CMDR, 0x77FC); \ + RTL_W8(PHY_CCA, 0x0); \ + delay_us(10); \ + RTL_W16(CMDR, 0x37FC); \ + delay_us(10); \ + RTL_W16(CMDR, 0x77FC); \ + delay_us(10); \ + RTL_W16(CMDR, 0x57FC); \ + RTL_W16(CMDR, 0x0000); \ + u1bTmp = RTL_R8((SYS_CLKR + 1)); \ + if (u1bTmp & BIT(7)) \ + { \ + u1bTmp &= ~(BIT(6) | BIT(7)); \ + if (!HalSetSysClk8192CD(priv, u1bTmp)) \ + break; \ + } \ + RTL_W8(0x03, 0x71); \ + RTL_W8(0x09, 0x70); \ + RTL_W8(0x29, 0x68); \ + RTL_W8(0x28, 0x00); \ + RTL_W8(0x20, 0x50); \ + RTL_W8(0x26, 0x0E); \ + } while (FALSE); \ +} + +void FirmwareSelfReset(struct rtl8192cd_priv *priv) +{ + unsigned char u1bTmp; + unsigned char Delay = 100; + if(priv->pshare->fw_version > 0x21 +#ifdef CONFIG_RTL_92D_SUPPORT + || GET_CHIP_VER(priv) == VERSION_8192D +#endif + ) { + RTL_W32(FWIMR, 0x20); + RTL_W8(REG_HMETFR+3, 0x20); + u1bTmp = RTL_R8( REG_SYS_FUNC_EN+1); + while(u1bTmp& BIT(2)) { + Delay--; + DEBUG_INFO("polling 0x03[2] Delay = %d \n", Delay); + if(Delay == 0) + break; + delay_us(50); + u1bTmp = RTL_R8( REG_SYS_FUNC_EN+1); + } + if((u1bTmp& BIT(2)) && (Delay == 0)) { + DEBUG_ERR("FirmwareSelfReset fail: 0x03 = %x\n", u1bTmp); + }else{ + DEBUG_INFO("FirmwareSelfReset success: 0x03 = %x\n", u1bTmp); + } + } +} + +//Return Value: +// 1: Exception Case. Previous Operation is not terminated. +// 0: Correct Case. +int CheckNoResetHwExceptionCase(struct rtl8192cd_priv *priv) +{ + //Check PON register to decide + return ( (RTL_R16(SYS_FUNC_EN) & (FEN_MREGEN|FEN_DCORE))==(FEN_MREGEN|FEN_DCORE) ); +} + +int rtl8192cd_stop_hw(struct rtl8192cd_priv *priv) +{ + RTL_W32(HIMR, 0); + RTL_W16(HIMRE, 0); + RTL_W16(HIMRE+2, 0); + RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_NOLINK & NETYPE_Mask) << NETYPE_SHIFT)); + + RTL_W8(RCR, 0); + RTL_W8(TXPAUSE, 0xff); + RTL_W8(CR, RTL_R8(CR) & ~(MACTXEN|MACRXEN)); + +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pshare->wlandev_idx == 0) + RTL_W8(RSV_MAC0_CTRL, RTL_R8(RSV_MAC0_CTRL)&(~MAC0_EN)); + else + RTL_W8(RSV_MAC1_CTRL, RTL_R8(RSV_MAC1_CTRL)&(~MAC1_EN)); + + if ((RTL_R8(RSV_MAC0_CTRL)& MAC0_EN) || (RTL_R8(RSV_MAC1_CTRL)& MAC1_EN)) { // check if another interface exists + DEBUG_INFO("Another MAC exists, cannot stop hw!!\n"); + } else +#endif + { + //3 2.) ==== RF Off Sequence ==== + phy_InitBBRFRegisterDefinition(priv); // preparation for read/write RF register + + RTL_W8(TXPAUSE, 0xff); // Pause MAC TX queue + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x00, bMask20Bits, 0x00); // disable RF + RTL_W8(RF_CTRL, 0x00); + RTL_W8(APSD_CTRL, 0x40); + RTL_W8(SYS_FUNC_EN, 0xe2); // reset BB state machine + RTL_W8(SYS_FUNC_EN, 0xe0); // reset BB state machine + + + + //3 3.) ==== Reset digital sequence ==== + if (RTL_R8(MCUFWDL) & BIT(1)) { + //Make sure that Host Recovery Interrupt is handled by 8051 ASAP. + RTL_W32(FSIMR, 0); // clear FSIMR + RTL_W32(FWIMR, 0x20); // clear FWIMR except HRCV_INT + RTL_W32(FTIMR, 0); // clear FTIMR + FirmwareSelfReset(priv); + + //Clear FWIMR to guarantee if 8051 runs in ROM, it is impossible to run FWISR Interrupt handler + RTL_W32(FWIMR, 0x0); // clear All FWIMR + } else { + //Critical Error. + //the operation that reset 8051 is necessary to be done by 8051 + DEBUG_ERR("%s %d ERROR: (RTL_R8(MCUFWDL) & BIT(1))=0\n", __FUNCTION__, __LINE__); + DEBUG_ERR("%s %d ERROR: the operation that reset 8051 is necessary to be done by 8051,%d\n", __FUNCTION__, __LINE__, RTL_R8(MCUFWDL)); + } + + // ==== Reset digital sequence ==== + RTL_W8(SYS_FUNC_EN+1, 0x51); // reset MCU, MAC register, DCORE + RTL_W8(MCUFWDL, 0); // reset MCU ready status + + //3 4.) ==== Disable analog sequence ==== + RTL_W8(AFE_PLL_CTRL, 0x80); // disable PLL + +#if defined(CONFIG_RTL_92C_SUPPORT) && defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv) != VERSION_8192D) + RTL_W8(SPS0_CTRL, 0x2b); + else +#endif + { + if(IS_UMC_B_CUT_88C(priv)) + RTL_W8(SPS0_CTRL, 0x2b); + else + RTL_W8(SPS0_CTRL, 0x23); + } +#ifdef CONFIG_RTL8672 + RTL_W8(AFE_XTAL_CTRL, RTL_R8(AFE_XTAL_CTRL)&~BIT(0)); // only for ADSL platform because 40M crystal is only used by WiFi chip // disable XTAL, if No BT COEX +#endif + RTL_W8(APS_FSMCO+1, 0x10); + RTL_W8(RSV_CTRL0, 0x0e); // lock ISO/CLK/Power control register + + //3 5.) ==== interface into suspend ==== +// RTL_W16(APS_FSMCO, (RTL_R16(APS_FSMCO) & 0x00ff) | (0x18 << 8)); // PCIe suspend mode + } + return SUCCESS; +} + + +void SwBWMode(struct rtl8192cd_priv *priv, unsigned int bandwidth, int offset) +{ + unsigned char regBwOpMode, regRRSR_RSC, nCur40MhzPrimeSC; + unsigned int eRFPath, curMaxRFPath, val; + + DEBUG_INFO("SwBWMode(): Switch to %s bandwidth\n", bandwidth?"40MHz":"20MHz"); + +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + curMaxRFPath = RF92CD_PATH_B; + else +#endif + curMaxRFPath = RF92CD_PATH_MAX; + + if (offset == 1) + nCur40MhzPrimeSC = 2; + else + nCur40MhzPrimeSC = 1; + + //3 <1> Set MAC register + regBwOpMode = RTL_R8(BWOPMODE); + regRRSR_RSC = RTL_R8(RRSR+2); + + switch (bandwidth) + { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + RTL_W8(BWOPMODE, regBwOpMode); + break; + case HT_CHANNEL_WIDTH_20_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + RTL_W8(BWOPMODE, regBwOpMode); + regRRSR_RSC = (regRRSR_RSC&0x90) | (nCur40MhzPrimeSC<<5); + RTL_W8(RRSR+2, regRRSR_RSC); + + // Let 812cd_rx, re-assign value + if (priv->pshare->is_40m_bw){ + priv->pshare->Reg_RRSR_2 = 0; + priv->pshare->Reg_81b = 0; + } + break; + default: + DEBUG_ERR("SwBWMode(): bandwidth mode error!\n"); + return; + break; + } + + //3 <2> Set PHY related register + switch (bandwidth) + { + case HT_CHANNEL_WIDTH_20: + PHY_SetBBReg(priv, rFPGA0_RFMOD, bRFMOD, 0x0); + PHY_SetBBReg(priv, rFPGA1_RFMOD, bRFMOD, 0x0); +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + PHY_SetBBReg(priv, rFPGA0_AnalogParameter2, BIT(11) | BIT(10), 3);// SET BIT10 BIT11 for receive cck + } else +#endif + { + PHY_SetBBReg(priv, rFPGA0_AnalogParameter2, BIT(10), 1); + } + break; + case HT_CHANNEL_WIDTH_20_40: + PHY_SetBBReg(priv, rFPGA0_RFMOD, bRFMOD, 0x1); + PHY_SetBBReg(priv, rFPGA1_RFMOD, bRFMOD, 0x1); + // Set Control channel to upper or lower. These settings are required only for 40MHz + PHY_SetBBReg(priv, rCCK0_System, bCCKSideBand, (nCur40MhzPrimeSC>>1)); + PHY_SetBBReg(priv, rOFDM1_LSTF, 0xC00, nCur40MhzPrimeSC); +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D) { + PHY_SetBBReg(priv, rFPGA0_AnalogParameter2, BIT(11) | BIT(10), 0);// SET BIT10 BIT11 for receive cck + } else +#endif + { + PHY_SetBBReg(priv, rFPGA0_AnalogParameter2, BIT(10), 0); + } + PHY_SetBBReg(priv, 0x818, (BIT(26)|BIT(27)), (nCur40MhzPrimeSC==2)?1:2); + break; + default: + DEBUG_ERR("SwBWMode(): bandwidth mode error! %d\n", __LINE__); + return; + break; + } + + //3<3> Set RF related register + switch (bandwidth) + { + case HT_CHANNEL_WIDTH_20: + val = 1; + break; + case HT_CHANNEL_WIDTH_20_40: + val = 0; + break; + default: + DEBUG_ERR("SwBWMode(): bandwidth mode error! %d\n", __LINE__); + return; + break; + } + + for(eRFPath = RF92CD_PATH_A; eRFPath < curMaxRFPath; eRFPath++) { +#ifdef CONFIG_RTL_92C_SUPPORT + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + PHY_SetRFReg(priv, eRFPath, rRfChannel, (BIT(11)|BIT(10)), val); + } +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D){ + priv->pshare->RegRF18[eRFPath] = RTL_SET_MASK(priv->pshare->RegRF18[eRFPath],(BIT(11)|BIT(10)),val,10); + PHY_SetRFReg(priv, eRFPath, rRfChannel, bMask20Bits, priv->pshare->RegRF18[eRFPath]); + //PHY_SetRFReg(priv, eRFPath, rRfChannel, (BIT(11)|BIT(10)), val); + } +#endif + } + +#if 0 + if (priv->pshare->rf_ft_var.use_frq_2_3G) + PHY_SetRFReg(priv, RF90_PATH_C, 0x2c, 0x60, 0); +#endif +} + + +void init_EDCA_para(struct rtl8192cd_priv *priv, int mode) +{ + static unsigned int slot_time, VO_TXOP, VI_TXOP, sifs_time; + + struct ParaRecord EDCA[4]; +#ifdef RTL_MANUAL_EDCA + //unsigned char acm_bitmap; +#endif + + slot_time = 20; + sifs_time = 10; + + if (mode & WIRELESS_11N) + sifs_time = 16; + +#ifdef RTL_MANUAL_EDCA + if( priv->pmib->dot11QosEntry.ManualEDCA ) { + memset(EDCA, 0, 4*sizeof(struct ParaRecord)); + if( OPMODE & WIFI_AP_STATE ) + memcpy(EDCA, priv->pmib->dot11QosEntry.AP_manualEDCA, 4*sizeof(struct ParaRecord)); + else + memcpy(EDCA, priv->pmib->dot11QosEntry.STA_manualEDCA, 4*sizeof(struct ParaRecord)); + + + if ((mode & WIRELESS_11N) || + (mode & WIRELESS_11G)) { + slot_time = 9; + } + + + RTL_W32(EDCA_VO_PARA, (EDCA[VO].TXOPlimit << 16) | (EDCA[VO].ECWmax << 12) | (EDCA[VO].ECWmin << 8) | (sifs_time + EDCA[VO].AIFSN * slot_time)); +#ifdef WIFI_WMM + if (QOS_ENABLE) + RTL_W32(EDCA_VI_PARA, (EDCA[VI].TXOPlimit << 16) | (EDCA[VI].ECWmax << 12) | (EDCA[VI].ECWmin << 8) | (sifs_time + EDCA[VI].AIFSN * slot_time)); + else +#endif + RTL_W32(EDCA_VI_PARA, (EDCA[BE].TXOPlimit << 16) | (EDCA[BE].ECWmax << 12) | (EDCA[BE].ECWmin << 8) | (sifs_time + EDCA[VI].AIFSN * slot_time)); + + RTL_W32(EDCA_BE_PARA, (EDCA[BE].TXOPlimit << 16) | (EDCA[BE].ECWmax << 12) | (EDCA[BE].ECWmin << 8) | (sifs_time + EDCA[BE].AIFSN * slot_time)); + + RTL_W32(EDCA_BK_PARA, (EDCA[BK].TXOPlimit << 16) | (EDCA[BK].ECWmax << 12) | (EDCA[BK].ECWmin << 8) | (sifs_time + EDCA[BK].AIFSN * slot_time)); + }else +#endif //RTL_MANUAL_EDCA + { + memset(EDCA, 0, 4*sizeof(struct ParaRecord)); + /* copy BE, BK from static data */ + if( OPMODE & WIFI_AP_STATE ) + memcpy(EDCA, rtl_ap_EDCA, 2*sizeof(struct ParaRecord)); + else + memcpy(EDCA, rtl_sta_EDCA, 2*sizeof(struct ParaRecord)); + + /* VI, VO apply settings in AG by default */ + if( OPMODE & WIFI_AP_STATE ) + memcpy(&EDCA[2], &rtl_ap_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); + else + memcpy(&EDCA[2], &rtl_sta_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); + + if ((mode & WIRELESS_11N) || + (mode & WIRELESS_11G)) { + slot_time = 9; + } else { + /* replace with settings in B */ + if( OPMODE & WIFI_AP_STATE ) + memcpy(&EDCA[2], &rtl_ap_EDCA[VI], 2*sizeof(struct ParaRecord)); + else + memcpy(&EDCA[2], &rtl_sta_EDCA[VI], 2*sizeof(struct ParaRecord)); + } + VO_TXOP = EDCA[VO].TXOPlimit; + VI_TXOP = EDCA[VI].TXOPlimit; + + RTL_W32(EDCA_VO_PARA, (VO_TXOP << 16) | (EDCA[VO].ECWmax << 12) | (EDCA[VO].ECWmin << 8) | (sifs_time + EDCA[VO].AIFSN * slot_time)); +#ifdef WIFI_WMM + if (QOS_ENABLE) + RTL_W32(EDCA_VI_PARA, (VI_TXOP << 16) | (EDCA[VI].ECWmax << 12) | (EDCA[VI].ECWmin << 8) | (sifs_time + EDCA[VI].AIFSN * slot_time)); + else +#endif + RTL_W32(EDCA_VI_PARA, (EDCA[BK].ECWmax << 12) | (EDCA[BK].ECWmin << 8) | (sifs_time + EDCA[VI].AIFSN * slot_time)); + + RTL_W32(EDCA_BE_PARA, ((EDCA[BE].ECWmax) << 12) | (EDCA[BE].ECWmin << 8) | (sifs_time + EDCA[BE].AIFSN * slot_time)); + RTL_W32(EDCA_BK_PARA, (EDCA[BK].ECWmax << 12) | (EDCA[BK].ECWmin << 8) | (sifs_time + EDCA[BK].AIFSN * slot_time)); + + + RTL_W8(ACMHWCTRL, 0x00); + } + + priv->pshare->iot_mode_enable = 0; + priv->pshare->iot_mode_VO_exist = 0; +} + + +#ifdef WIFI_WMM +void IOT_EDCA_switch(struct rtl8192cd_priv *priv, int mode, char enable) +{ + unsigned int slot_time = 20, sifs_time = 10, BE_TXOP = 47, VI_TXOP = 94; + unsigned int vi_cw_max = 4, vi_cw_min = 3, vi_aifs; + + if (!(!priv->pmib->dot11OperationEntry.wifi_specific || + ((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)))) + return; + + if ((mode & WIRELESS_11N) && (priv->pshare->ht_sta_num +#ifdef WDS + || ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) +#endif + )) + sifs_time = 16; + + if ((mode & WIRELESS_11N) || (mode & WIRELESS_11G)) { + slot_time = 9; + } else { + BE_TXOP = 94; + VI_TXOP = 188; + } + + if ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11OperationEntry.wifi_specific) { + if (priv->pshare->iot_mode_VO_exist) { + vi_cw_max = 6; + vi_cw_min = 4; + vi_aifs = 0x2b; + } else { + vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); + } + + RTL_W32(EDCA_VI_PARA, ((VI_TXOP*(1-priv->pshare->iot_mode_VO_exist)) << 16) + | (vi_cw_max << 12) | (vi_cw_min << 8) | vi_aifs); + } + + if (!enable) { + RTL_W32(EDCA_BE_PARA, (((OPMODE & WIFI_AP_STATE)?6:10) << 12) | (4 << 8) + | (sifs_time + 3 * slot_time)); + } else { + if (priv->pshare->ht_sta_num +#ifdef WDS + || ((OPMODE & WIFI_AP_STATE) && (mode & WIRELESS_11N) && + priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) +#endif + ) { +/* + if (priv->pshare->txop_enlarge == 0xf) { + // is 8192S client + RTL_W32(EDCA_BE_PARA, ((BE_TXOP*2) << 16) | + (6 << 12) | (4 << 8) | (sifs_time + slot_time+ 0xf)); // 0xf is 92s circuit delay + priv->pshare->txop_enlarge = 2; + } + else +*/ + if (priv->pshare->txop_enlarge == 0xe) { + // is intel client, use a different edca value + RTL_W32(EDCA_BE_PARA, (BE_TXOP*2 << 16) | (6 << 12) | (4 << 8) | 0x1f); + priv->pshare->txop_enlarge = 2; + } else if (priv->pshare->txop_enlarge == 0xd) { + // is intel ralink, use a different edca value + RTL_W32(EDCA_BE_PARA, (BE_TXOP*2 << 16) | (4 << 12) | (3 << 8) | 0x19); + priv->pshare->txop_enlarge = 2; + } else { + if (get_rf_mimo_mode(priv) == MIMO_2T2R) + RTL_W32(EDCA_BE_PARA, ((BE_TXOP*priv->pshare->txop_enlarge) << 16) | + (6 << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); + else + RTL_W32(EDCA_BE_PARA, ((BE_TXOP*priv->pshare->txop_enlarge) << 16) | + (5 << 12) | (3 << 8) | (sifs_time + 2 * slot_time)); + } + } else { + RTL_W32(EDCA_BE_PARA, (BE_TXOP*2 << 16) | (6 << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); + } +/* + if (priv->pmib->dot11OperationEntry.wifi_specific == 2) { + RTL_W16(NAV_PROT_LEN, 0x01C0); + RTL_W8(CFEND_TH, 0xFF); + set_fw_reg(priv, 0xfd000ab0, 0, 0); + } +*/ + } +} +#endif + + +#ifdef SMART_CONCURRENT_92D +void setup_timer1(struct rtl8192cd_priv *priv, int timeout) +{ + unsigned int current_value=RTL_R32(TSFTR); + + if (TSF_LESS(timeout, current_value)) + timeout = current_value+20; + + RTL_W32(TIMER0, timeout); + RTL_W32(HIMR, RTL_R32(HIMR) | HIMR_TIMEOUT1); +} + + +void cancel_timer1(struct rtl8192cd_priv *priv) +{ + RTL_W32(HIMR, RTL_R32(HIMR) & ~HIMR_TIMEOUT1); +} + + +void setup_timer2(struct rtl8192cd_priv *priv, unsigned int timeout) +{ + unsigned int current_value=RTL_R32(TSFTR); + + if (TSF_LESS(timeout, current_value)) + timeout = current_value+20; + + RTL_W32(TIMER1, timeout); + RTL_W32(HIMR, RTL_R32(HIMR) | HIMR_TIMEOUT2); +} + + +void cancel_timer2(struct rtl8192cd_priv *priv) +{ + RTL_W32(HIMR, RTL_R32(HIMR) & ~HIMR_TIMEOUT2); +} +#endif + + +void check_EDCCA(struct rtl8192cd_priv *priv, short rssi) +{ + if ((priv->pshare->rf_ft_var.edcca_thd) && (priv->pmib->dot11RFEntry.dot11channel==14 + || priv->pshare->is_40m_bw +#if defined(CONFIG_RTL_92D_SUPPORT) + || (priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_5G) +#endif + )) { + if((rssi > priv->pshare->rf_ft_var.edcca_thd) && (priv->pshare->phw->EDCCA_on == 0)) { + RTL_W32(rOFDM0_ECCAThreshold, 0xfc03fd); +#if defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv)==VERSION_8192D) + RTL_W32(RD_CTRL, RTL_R32(RD_CTRL)& ~(BIT(13))); +#endif + priv->pshare->phw->EDCCA_on =1; + } else if( (rssi < priv->pshare->rf_ft_var.edcca_thd-5) && priv->pshare->phw->EDCCA_on) { + RTL_W32(rOFDM0_ECCAThreshold, 0x7f037f); +#if defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv)==VERSION_8192D) + RTL_W32(RD_CTRL, RTL_R32(RD_CTRL)|BIT(13)); +#endif + priv->pshare->phw->EDCCA_on =0; + } + } + if ((!priv->pshare->rf_ft_var.edcca_thd) && priv->pshare->phw->EDCCA_on) { + RTL_W32(0xc4c, 0x7f037f); +#if defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv)==VERSION_8192D) + RTL_W32(RD_CTRL, RTL_R32(RD_CTRL)|BIT(13)); +#endif + priv->pshare->phw->EDCCA_on = 0; + } +} + + +/* + * FA statistic functions + */ +#if !defined(CONFIG_RTL_NEW_AUTOCH) +static +#endif +void reset_FA_reg(struct rtl8192cd_priv *priv) +{ +#if !defined(CONFIG_RTL_NEW_AUTOCH) + unsigned char value8; + + value8 = RTL_R8(0xd03); + RTL_W8(0xd03, value8 | 0x08); // regD00[27]=1 to reset these OFDM FA counters + value8 = RTL_R8(0xd03); + RTL_W8(0xd03, value8 & 0xF7); // regD00[27]=0 to start counting + value8 = RTL_R8(0xa2d); + RTL_W8(0xa2d, value8 & 0x3F); // regA2D[7:6]=00 to disable counting + value8 = RTL_R8(0xa2d); + RTL_W8(0xa2d, value8 | 0x80); // regA2D[7:6]=10 to enable counting +#else + /* cck CCA */ + PHY_SetBBReg(priv, 0xa2c, BIT(13) | BIT(12), 0); + PHY_SetBBReg(priv, 0xa2c, BIT(13) | BIT(12), 2); + /* cck FA*/ + PHY_SetBBReg(priv, 0xa2c, BIT(15) | BIT(14), 0); + PHY_SetBBReg(priv, 0xa2c, BIT(15) | BIT(14), 2); + /* ofdm */ + PHY_SetBBReg(priv, 0xd00, BIT(27), 1); + PHY_SetBBReg(priv, 0xd00, BIT(27), 0); + +#endif + +#if defined(CONFIG_RTL_92D_SUPPORT) && defined(CONFIG_RTL_NOISE_CONTROL) + if (GET_CHIP_VER(priv) == VERSION_8192D){ + PHY_SetBBReg(priv, 0xf14, BIT(16),1); + PHY_SetBBReg(priv, 0xf14, BIT(16),0); + RTL_W32(RXERR_RPT, RTL_R32(RXERR_RPT)|BIT(27)); + RTL_W32(RXERR_RPT, RTL_R32(RXERR_RPT)&(~BIT(27))); + } +#endif + +} + +#if defined(CONFIG_RTL_NEW_AUTOCH) +void hold_CCA_FA_counter(struct rtl8192cd_priv *priv) +{ + /* hold cck CCA & FA counter */ + PHY_SetBBReg(priv, 0xa2c, BIT(12), 1); + PHY_SetBBReg(priv, 0xa2c, BIT(14), 1); + + /* hold ofdm CCA & FA counter */ + PHY_SetBBReg(priv, 0xc00, BIT(31), 1); + PHY_SetBBReg(priv, 0xd00, BIT(31), 1); +} + +void release_CCA_FA_counter(struct rtl8192cd_priv *priv) +{ + /* release cck CCA & FA counter */ + PHY_SetBBReg(priv, 0xa2c, BIT(12), 0); + PHY_SetBBReg(priv, 0xa2c, BIT(14), 0); + + /* release ofdm CCA & FA counter */ + PHY_SetBBReg(priv, 0xc00, BIT(31), 0); + PHY_SetBBReg(priv, 0xd00, BIT(31), 0); +} + + +void _FA_statistic(struct rtl8192cd_priv *priv) +{ + // read OFDM FA counters + priv->pshare->ofdm_FA_cnt1 = RTL_R16(0xda2); + priv->pshare->ofdm_FA_cnt2 = RTL_R16(0xda4); + priv->pshare->ofdm_FA_cnt3 = RTL_R16(0xda6); + priv->pshare->ofdm_FA_cnt4 = RTL_R16(0xda8); + + priv->pshare->cck_FA_cnt = (RTL_R8(0xa5b) << 8) + RTL_R8(0xa5c); + + priv->pshare->FA_total_cnt = priv->pshare->ofdm_FA_cnt1 + priv->pshare->ofdm_FA_cnt2 + + priv->pshare->ofdm_FA_cnt3 + priv->pshare->ofdm_FA_cnt4 + + priv->pshare->cck_FA_cnt + RTL_R16(0xcf0) + RTL_R16(0xcf2); +} +#endif + +void FA_statistic(struct rtl8192cd_priv *priv) +{ + +#if defined(CONFIG_RTL_92D_SUPPORT) && defined(CONFIG_RTL_NOISE_CONTROL) + if (GET_CHIP_VER(priv) == VERSION_8192D){ +// priv->pshare->F90_cnt = PHY_QueryBBReg(priv, 0xf90, bMaskHWord); + priv->pshare->F94_cnt = PHY_QueryBBReg(priv, 0xf94, bMaskHWord); + priv->pshare->F94_cntOK = PHY_QueryBBReg(priv, 0xf94, bMaskLWord); + RTL_W32(RXERR_RPT,(RTL_R32(RXERR_RPT)&0x0fffffff)|0x70000000); + priv->pshare->Reg664_cnt = RTL_R32(RXERR_RPT) & 0xfffff; + RTL_W32(RXERR_RPT,(RTL_R32(RXERR_RPT)&0x0fffffff)|0x60000000); + priv->pshare->Reg664_cntOK = RTL_R32(RXERR_RPT) & 0xfffff; + } +#endif + +#if !defined(CONFIG_RTL_NEW_AUTOCH) + signed char value8; + + // read OFDM FA counters + priv->pshare->ofdm_FA_cnt1 = RTL_R16(0xda2); + priv->pshare->ofdm_FA_cnt2 = RTL_R16(0xda4); + priv->pshare->ofdm_FA_cnt3 = RTL_R16(0xda6); + priv->pshare->ofdm_FA_cnt4 = RTL_R16(0xda8); + + // read the CCK FA counters + value8 = RTL_R8(0xa2d); + RTL_W8(0xa2d, value8 | 0x40); // regA2D[6]=1 to hold and read the CCK FA counters + priv->pshare->cck_FA_cnt = RTL_R8(0xa5b); + priv->pshare->cck_FA_cnt = priv->pshare->cck_FA_cnt << 8; + priv->pshare->cck_FA_cnt += RTL_R8(0xa5c); + + priv->pshare->FA_total_cnt = priv->pshare->ofdm_FA_cnt1 + priv->pshare->ofdm_FA_cnt2 + + priv->pshare->ofdm_FA_cnt3 + priv->pshare->ofdm_FA_cnt4 + + priv->pshare->cck_FA_cnt + RTL_R16(0xcf0) + RTL_R16(0xcf2); + + if (priv->pshare->rf_ft_var.rssi_dump) + priv->pshare->CCA_total_cnt = ((RTL_R8(0xa60)<<8)|RTL_R8(0xa61)) + RTL_R16(0xda0); +#else + hold_CCA_FA_counter(priv); + _FA_statistic(priv); + + if (priv->pshare->rf_ft_var.rssi_dump) + priv->pshare->CCA_total_cnt = ((RTL_R8(0xa60)<<8)|RTL_R8(0xa61)) + RTL_R16(0xda0); + + release_CCA_FA_counter(priv); +#endif + + reset_FA_reg(priv); + +#if defined(CONFIG_RTL_92D_SUPPORT) && defined(CONFIG_RTL_NOISE_CONTROL) + if (GET_CHIP_VER(priv) == VERSION_8192D){ + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G && !(OPMODE & WIFI_SITE_MONITOR)) { + if (priv->pshare->DNC_on == 0){ + //if ((priv->pshare->F94_cnt + priv->pshare->F90_cnt)> 3000){ + /* Reg 664: x > y && x > 1000 + Reg F94: x > 0.75*y && x > 1000 */ + if (((priv->pshare->Reg664_cnt>priv->pshare->Reg664_cntOK) && (priv->pshare->Reg664_cnt > 1000))|| + ((priv->pshare->F94_cnt > ((priv->pshare->Reg664_cntOK*3)>>2)) && (priv->pshare->F94_cnt > 1000))) { + priv->ext_stats.tp_average_pre = (priv->ext_stats.tx_avarage+priv->ext_stats.rx_avarage)>>17; + priv->pshare->DNC_on = 1; + priv->pshare->DNC_chk_cnt = 1; + priv->pshare->DNC_chk = 2; // 0: don't check, 1; check, 2: just entering DNC + //PHY_SetBBReg(priv, 0xb30, bMaskDWord, 0x00a00000); + PHY_SetBBReg(priv, 0x870, bMaskDWord, 0x07600760); + PHY_SetBBReg(priv, 0xc50, bMaskByte0, 0x20); + PHY_SetBBReg(priv, 0xc58, bMaskByte0, 0x20); + //printk("Dynamic Noise Control ON\n"); + } + } else { + if ((priv->pshare->DNC_chk_cnt % 5)==0){ // check every 5*2=10 seconds + unsigned long tp_now = (priv->ext_stats.tx_avarage+priv->ext_stats.rx_avarage)>>17; + priv->pshare->DNC_chk_cnt = 0; + + if ((priv->pshare->DNC_chk == 2) && (tp_now < priv->ext_stats.tp_average_pre+5)){ + //no advantage, leave DNC state + priv->pshare->DNC_on = 0; + priv->pshare->DNC_chk = 0; + //PHY_SetBBReg(priv, 0xb30, bMaskDWord, 0); + PHY_SetBBReg(priv, 0x870, bMaskDWord, 0x07000700); + } + else + { + priv->pshare->DNC_chk = 0; + + /* If TP < 20M or TP varies more than 5M. Start Checking...*/ + if ((tp_now < 20) || ((tp_now < (priv->ext_stats.tp_average_pre-5))|| (tp_now > (priv->ext_stats.tp_average_pre+5)))){ + priv->pshare->DNC_chk = 1; + //PHY_SetBBReg(priv, 0xb30, bMaskDWord, 0); + PHY_SetBBReg(priv, 0x870, bMaskDWord, 0x07000700); + if (!timer_pending(&priv->dnc_timer)) { + //printk("... Start Check Noise ...\n"); + mod_timer(&priv->dnc_timer, jiffies + 10); // 100 ms + } + } + } + + priv->ext_stats.tp_average_pre = tp_now; + + } else if ((priv->pshare->DNC_chk_cnt % 5)==1 && priv->pshare->DNC_chk == 1) { + priv->pshare->DNC_chk = 0; + //if ((priv->pshare->F94_cnt + priv->pshare->F90_cnt) < 120) { + if ((priv->pshare->F94_cnt + priv->pshare->Reg664_cnt) < 120) { + priv->pshare->DNC_on = 0; + //PHY_SetBBReg(priv, 0xb30, bMaskDWord, 0); + PHY_SetBBReg(priv, 0x870, bMaskDWord, 0x07000700); + //printk("Dynamic Noise Control OFF\n"); + } + } + priv->pshare->DNC_chk_cnt++; + } + } + } +#endif +} + + +/* + * + * DIG related functions + * + */ + +int getIGIFor1RCCA(int value_IGI) +{ + #define ONERCCA_LOW_TH 0x30 + #define ONERCCA_LOW_DIFF 8 + + if (value_IGI < ONERCCA_LOW_TH) { + if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) + return ONERCCA_LOW_TH; + else + return value_IGI + ONERCCA_LOW_DIFF; + } else { + return value_IGI; + } +} + + +void set_DIG_state(struct rtl8192cd_priv *priv, int state) +{ + int value_IGI; + + if (state) { + priv->pshare->DIG_on = 1; + priv->pshare->restore = 0; + } + else { + priv->pshare->DIG_on = 0; + if (priv->pshare->restore == 0) { + if (priv->pshare->rf_ft_var.use_ext_lna == 1) + value_IGI = 0x30; + else + value_IGI = 0x20; + +#if defined(HW_ANT_SWITCH) + // wirte new initial gain index into regC50/C58 + if (priv->pshare->rf_ft_var.one_path_cca == 0) { + RTL_W8(0xc50, value_IGI | RXDVY_A_EN); + RTL_W8(0xc58, value_IGI | RXDVY_B_EN); + } else if (priv->pshare->rf_ft_var.one_path_cca == 1) { + RTL_W8(0xc50, value_IGI | RXDVY_A_EN); + RTL_W8(0xc58, getIGIFor1RCCA(value_IGI) | RXDVY_B_EN); + } else if (priv->pshare->rf_ft_var.one_path_cca == 2) { + RTL_W8(0xc50, getIGIFor1RCCA(value_IGI) | RXDVY_A_EN); + RTL_W8(0xc58, value_IGI | RXDVY_B_EN); + } +#else + // Write IGI into HW + if (priv->pshare->rf_ft_var.one_path_cca == 0) { + RTL_W8(0xc50, value_IGI); + RTL_W8(0xc58, value_IGI); + } else if (priv->pshare->rf_ft_var.one_path_cca == 1) { + RTL_W8(0xc50, value_IGI); + RTL_W8(0xc58, getIGIFor1RCCA(value_IGI)); + } else if (priv->pshare->rf_ft_var.one_path_cca == 2) { + RTL_W8(0xc50, getIGIFor1RCCA(value_IGI)); + RTL_W8(0xc58, value_IGI); + } +#endif + priv->pshare->restore = 1; + } + } +} + + +void DIG_process(struct rtl8192cd_priv *priv) +{ + #define DEAD_POINT_TH 10000 + #define DOWN_IG_HIT_TH 5 + #define DEAD_POINT_HIT_TH 3 + + unsigned char value_IGI; + signed char value8; + + if (priv->pshare->DIG_on == 1) + { + if (priv->pshare->rf_ft_var.use_ext_lna == 1) { + priv->pshare->FA_upper = 0x42; + priv->pshare->FA_lower = 0x30; + } else { + // Reset initial gain upper & lower bounds +#ifdef DFS + if (!priv->pmib->dot11DFSEntry.disable_DFS && + (OPMODE & WIFI_AP_STATE) && + (((priv->pmib->dot11RFEntry.dot11channel >= 52) && + (priv->pmib->dot11RFEntry.dot11channel <= 64)) || + ((priv->pmib->dot11RFEntry.dot11channel >= 100) && + (priv->pmib->dot11RFEntry.dot11channel <= 140)))) + priv->pshare->FA_upper = 0x24; + else +#endif + priv->pshare->FA_upper = 0x32; + priv->pshare->FA_lower = 0x20; + + if (priv->pshare->rssi_min > 30) + priv->pshare->FA_lower = 0x24; + else if (priv->pshare->rssi_min > 25) + priv->pshare->FA_lower = 0x22; + } + + // determine a new initial gain index according to the sumation of all FA counters as well as upper & lower bounds + value8 = RTL_R8(0xc50); + value_IGI = (value8 & 0x7F); + +#if defined(CONFIG_RTL_NOISE_CONTROL_92C) + if(priv->pshare->rf_ft_var.dnc_enable) + if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)){ + unsigned long tp_now = (priv->ext_stats.tx_avarage+priv->ext_stats.rx_avarage)>>17; + if(priv->pshare->rf_ft_var.use_ext_lna) { + if( (priv->pshare->rssi_min > 50) ) { + if((!priv->pshare->DNC_on) && (value_IGI >= priv->pshare->FA_upper) && (priv->pshare->FA_total_cnt > priv->pshare->threshold2)) { + priv->pshare->DNC_on = 1; + priv->ext_stats.tp_average_pre = tp_now; + priv->pshare->FA_lower = 0x20; + PHY_SetBBReg(priv, 0x870, bMaskDWord, RTL_R32(0x870)|BIT(5)|BIT(6)|BIT(21)|BIT(22)); + +#ifdef HW_ANT_SWITCH + PHY_SetBBReg(priv, 0xc50, bMaskByte0, priv->pshare->FA_lower | RXDVY_A_EN); + PHY_SetBBReg(priv, 0xc58, bMaskByte0, priv->pshare->FA_lower | RXDVY_B_EN); +#else + PHY_SetBBReg(priv, 0xc50, bMaskByte0, priv->pshare->FA_lower); + PHY_SetBBReg(priv, 0xc58, bMaskByte0, priv->pshare->FA_lower); +#endif + + } else if(priv->pshare->DNC_on ==1) { + if(tp_now < priv->ext_stats.tp_average_pre + 2) { + priv->pshare->DNC_on = 0; + } + else { + priv->pshare->DNC_on =2; + priv->ext_stats.tp_average_pre = tp_now; + } + } else if(priv->pshare->DNC_on >= 2 ) { + if(( tp_now+10 < priv->ext_stats.tp_average_pre ) || (tp_now < 1) ) { + priv->pshare->DNC_on = 0; + } else if(priv->pshare->DNC_on<5) { + priv->ext_stats.tp_average_pre = tp_now; + ++priv->pshare->DNC_on; + } + } + }else { + priv->pshare->DNC_on = 0; + } + + if( priv->pshare->DNC_on ) + return; + else + PHY_SetBBReg(priv, 0x870, bMaskDWord, RTL_R32(0x870)& ~(BIT(5)|BIT(6)|BIT(21)|BIT(22))); + + } else { + if( (priv->pshare->rssi_min > 40) && (value_IGI >= priv->pshare->FA_upper) ) { +// unsigned long tp_now = (priv->ext_stats.tx_avarage+priv->ext_stats.rx_avarage)>>17; + if((!priv->pshare->DNC_on) && (priv->pshare->FA_total_cnt > priv->pshare->threshold2)) { + priv->pshare->DNC_on = 1; + priv->ext_stats.tp_average_pre = tp_now; + } else if(priv->pshare->DNC_on ==1) { + if(tp_now < priv->ext_stats.tp_average_pre + 2) { + priv->pshare->DNC_on = 0; + } + else { + priv->pshare->DNC_on = 2; + priv->ext_stats.tp_average_pre = tp_now; + } + } else if(priv->pshare->DNC_on >= 2 ) { + if((tp_now +10 < priv->ext_stats.tp_average_pre ) + || ((priv->ext_stats.tp_average_pre < 10) && (priv->pshare->FA_total_cnt < priv->pshare->threshold1))) { + priv->pshare->DNC_on = 0; + } else if(priv->pshare->DNC_on<6) { + priv->ext_stats.tp_average_pre = tp_now; + ++priv->pshare->DNC_on; + } + } + if(priv->pshare->DNC_on) { + priv->pshare->FA_upper = 0x3e; + } + }else { + priv->pshare->DNC_on = 0; + } + } + } +#endif + + if ((priv->pshare->digDeadPoint == 0) && (priv->pshare->FA_total_cnt > DEAD_POINT_TH)) { + if ((priv->pshare->digDeadPointHitCount > 0) && (priv->pshare->digDeadPointCandidate == value_IGI)) { + priv->pshare->digDeadPointHitCount++; + if (priv->pshare->digDeadPointHitCount == DEAD_POINT_HIT_TH) { + priv->pshare->digDeadPoint = priv->pshare->digDeadPointCandidate; + } + } else { + priv->pshare->digDeadPointCandidate = value_IGI; + priv->pshare->digDeadPointHitCount = 1; + } + } + + if (priv->pshare->FA_total_cnt < priv->pshare->threshold0) { + priv->pshare->digDownCount++; + if (priv->pshare->digDownCount > DOWN_IG_HIT_TH) { + // Reset deadpoint hit count + if ((priv->pshare->digDeadPoint == 0) && (priv->pshare->digDeadPointHitCount > 0) && (value_IGI == priv->pshare->digDeadPointCandidate)) + priv->pshare->digDeadPointHitCount = 0; + + value_IGI--; + + // Check if the new value is dead point + if ((priv->pshare->digDeadPoint > 0) && (value_IGI == priv->pshare->digDeadPoint)) + value_IGI++; + } + } else if (priv->pshare->FA_total_cnt < priv->pshare->threshold1) { + value_IGI += 0; + priv->pshare->digDownCount = 0; + } else if (priv->pshare->FA_total_cnt < priv->pshare->threshold2) { + value_IGI++; + priv->pshare->digDownCount = 0; + } else if (priv->pshare->FA_total_cnt >= priv->pshare->threshold2) { + value_IGI += 2; + priv->pshare->digDownCount = 0; + } else { + priv->pshare->digDownCount = 0; + } + + if (value_IGI > priv->pshare->FA_upper) + value_IGI = priv->pshare->FA_upper; + else if (value_IGI < priv->pshare->FA_lower) + value_IGI = priv->pshare->FA_lower; + +#if defined(HW_ANT_SWITCH) + // wirte new initial gain index into regC50/C58 + if (priv->pshare->rf_ft_var.one_path_cca == 0) { + RTL_W8(0xc50, value_IGI | RXDVY_A_EN); + RTL_W8(0xc58, value_IGI | RXDVY_B_EN); + } else if (priv->pshare->rf_ft_var.one_path_cca == 1) { + RTL_W8(0xc50, value_IGI | RXDVY_A_EN); + RTL_W8(0xc58, getIGIFor1RCCA(value_IGI) | RXDVY_B_EN); + } else if (priv->pshare->rf_ft_var.one_path_cca == 2) { + RTL_W8(0xc50, getIGIFor1RCCA(value_IGI) | RXDVY_A_EN); + RTL_W8(0xc58, value_IGI| RXDVY_B_EN); + } +#else + // Write IGI into HW + if (priv->pshare->rf_ft_var.one_path_cca == 0) { + RTL_W8(0xc50, value_IGI); + RTL_W8(0xc58, value_IGI); + } else if (priv->pshare->rf_ft_var.one_path_cca == 1) { + RTL_W8(0xc50, value_IGI); + RTL_W8(0xc58, getIGIFor1RCCA(value_IGI)); + } else if (priv->pshare->rf_ft_var.one_path_cca == 2) { + RTL_W8(0xc50, getIGIFor1RCCA(value_IGI)); + RTL_W8(0xc58, value_IGI); + } +#endif + + } +} + + +void check_DIG_by_rssi(struct rtl8192cd_priv *priv, unsigned char rssi_strength) +{ + unsigned int dig_on = 0; + + if (OPMODE & WIFI_SITE_MONITOR) + return; + + if ((rssi_strength > priv->pshare->rf_ft_var.digGoUpperLevel) + && (rssi_strength < HP_LOWER+1) && (priv->pshare->phw->signal_strength != 2)) { +#ifndef CONFIG_RTL_92D_SUPPORT + if (priv->pshare->is_40m_bw) + // RTL_W8(0xc87, (RTL_R8(0xc87) & 0xf) | 0x30); 92D + RTL_W8(0xc87, 0x30); + else + RTL_W8(0xc30, 0x44); +#endif + + if (priv->pshare->phw->signal_strength != 3) + dig_on++; + + priv->pshare->phw->signal_strength = 2; + } + else if ((rssi_strength > HP_LOWER+5) && (priv->pshare->phw->signal_strength != 3)) { +#ifndef CONFIG_RTL_92D_SUPPORT + if (priv->pshare->is_40m_bw) + // RTL_W8(0xc87, (RTL_R8(0xc87) & 0xf) | 0x30); 92D + RTL_W8(0xc87, 0x30); + else + RTL_W8(0xc30, 0x44); +#endif + + if (priv->pshare->phw->signal_strength != 2) + dig_on++; + + priv->pshare->phw->signal_strength = 3; + } + else if (((rssi_strength < priv->pshare->rf_ft_var.digGoLowerLevel) + && (priv->pshare->phw->signal_strength != 1)) || !priv->pshare->phw->signal_strength) { + // DIG off +#ifndef CONFIG_RTL8672 + set_DIG_state(priv, 0); +#endif + +#ifndef CONFIG_RTL_92D_SUPPORT + if (priv->pshare->is_40m_bw) + //RTL_W8(0xc87, (RTL_R8(0xc87) & 0xf) | 0x30); 92D + RTL_W8(0xc87, 0x30); + else + RTL_W8(0xc30, 0x44); +#endif + + priv->pshare->phw->signal_strength = 1; + } + + if (dig_on) { + // DIG on + set_DIG_state(priv, 1); + } + + //check_DC_TH_by_rssi(priv, rssi_strength); +} + + +void DIG_for_site_survey(struct rtl8192cd_priv *priv, int do_ss) +{ + if (do_ss) { + // DIG off + set_DIG_state(priv, 0); + } + else { + // DIG on + if (priv->pshare->phw->signal_strength > 1) { + set_DIG_state(priv, 1); + } + } +} + + +/* + * dynamic CCK CCA enhance by rssi + */ +void CCK_CCA_dynamic_enhance(struct rtl8192cd_priv *priv, unsigned char rssi_strength) +{ +#if 1 + unsigned int cck_fa = priv->pshare->FA_total_cnt; + int rssi_thd = 30; + + if (rssi_strength == 0xff) { + if (cck_fa < 1000) { + if (priv->pshare->phw->CCK_CCA_enhanced != 2) { + RTL_W8(0xa0a, 0x40); + priv->pshare->phw->CCK_CCA_enhanced = 2; + } + } else { + if (priv->pshare->phw->CCK_CCA_enhanced != 1) { + RTL_W8(0xa0a, 0x83); + priv->pshare->phw->CCK_CCA_enhanced = 1; + } + } + return; + } + + if (rssi_strength > rssi_thd+5) { + if (priv->pshare->phw->CCK_CCA_enhanced != 0) { + RTL_W8(0xa0a, 0xcd); + priv->pshare->phw->CCK_CCA_enhanced = 0; + } + } else if (rssi_strength< rssi_thd) { + if ((rssi_strength > 9) || (priv->assoc_num >1)) { + if (priv->pshare->phw->CCK_CCA_enhanced != 1) { + RTL_W8(0xa0a, 0x83); + priv->pshare->phw->CCK_CCA_enhanced = 1; + } + } else { + if(cck_fa<1000) { + if (priv->pshare->phw->CCK_CCA_enhanced != 2) { + RTL_W8(0xa0a, 0x40); + priv->pshare->phw->CCK_CCA_enhanced = 2; + } + } else { + if (priv->pshare->phw->CCK_CCA_enhanced != 1) { + RTL_W8(0xa0a, 0x83); + priv->pshare->phw->CCK_CCA_enhanced = 1; + } + } + } + } + +#else + + if (rssi_strength == 0xff) + return; + + if (!priv->pshare->phw->CCK_CCA_enhanced && (rssi_strength < 30)) { + priv->pshare->phw->CCK_CCA_enhanced = TRUE; + RTL_W8(0xa0a, 0x83); + } + else if (priv->pshare->phw->CCK_CCA_enhanced && (rssi_strength > 35)) { + priv->pshare->phw->CCK_CCA_enhanced = FALSE; + RTL_W8(0xa0a, 0xcd); + } +#endif +} + + +#if 0 +void tx_path_by_rssi(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned char enable){ + + if((get_rf_mimo_mode(priv) != MIMO_2T2R)) + return; // 1T2R, 1T1R; do nothing + + if(pstat == NULL) + return; + +#ifdef STA_EXT + if ((pstat->remapped_aid == FW_NUM_STAT-1) || + (priv->pshare->has_2r_sta & BIT(pstat->remapped_aid)))// 2r STA +#else + if (priv->pshare->has_2r_sta & BIT(pstat->aid))// 2r STA +#endif + return; // do nothing + + // for debug, by victoryman 20090623 + if (pstat->tx_ra_bitmap & 0xff00000) { + // this should be a 2r station!!! + return; + } + + if (pstat->tx_ra_bitmap & 0xffff000){// 11n 1R client + if(enable){ + if(pstat->rf_info.mimorssi[0] > pstat->rf_info.mimorssi[1]) + Switch_1SS_Antenna(priv, 1); + else + Switch_1SS_Antenna(priv, 2); + } + else + Switch_1SS_Antenna(priv, 3); + } + else if (pstat->tx_ra_bitmap & 0xff0){// 11bg client + if(enable){ + if(pstat->rf_info.mimorssi[0] > pstat->rf_info.mimorssi[1]) + Switch_OFDM_Antenna(priv, 1); + else + Switch_OFDM_Antenna(priv, 2); + } + else + Switch_OFDM_Antenna(priv, 3); + } + +#if 0 // original setup + if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N){ // for 11n 1ss sta + if(enable){ + if(pstat->rf_info.mimorssi[0] > pstat->rf_info.mimorssi[1]) + Switch_1SS_Antenna(priv, 1); + else + Switch_1SS_Antenna(priv, 2); + } + else + Switch_1SS_Antenna(priv, 3); + } + else if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G){ // for 11g + if(enable){ + if(pstat->rf_info.mimorssi[0] > pstat->rf_info.mimorssi[1]) + Switch_OFDM_Antenna(priv, 1); + else + Switch_OFDM_Antenna(priv, 2); + } + else + Switch_OFDM_Antenna(priv, 3); + } +#endif + + +} +//#endif + + +// dynamic Rx path selection by signal strength +void rx_path_by_rssi(struct rtl8192cd_priv *priv, struct stat_info *pstat, int enable) +{ + unsigned char highest_rssi=0, higher_rssi=0, under_ss_th_low=0; + RF92CD_RADIO_PATH_E eRFPath, eRFPath_highest=0, eRFPath_higher=0; + int ant_on_processing=0; +#ifdef _DEBUG_RTL8192CD_ + char path_name[] = {'A', 'B'}; +#endif + + if (enable == FALSE) { + if (priv->pshare->phw->ant_off_num) { + priv->pshare->phw->ant_off_num = 0; + priv->pshare->phw->ant_off_bitmap = 0; + RTL_W8(rOFDM0_TRxPathEnable, 0x0f); + RTL_W8(rOFDM1_TRxPathEnable, 0x0f); + DEBUG_INFO("More than 1 sta, turn on all path\n"); + } + return; + } + + for (eRFPath = RF92CD_PATH_A; eRFPath<priv->pshare->phw->NumTotalRFPath; eRFPath++) { + if (priv->pshare->phw->ant_off_bitmap & BIT(eRFPath)) + continue; + + if (pstat->rf_info.mimorssi[eRFPath] > highest_rssi) { + higher_rssi = highest_rssi; + eRFPath_higher = eRFPath_highest; + highest_rssi = pstat->rf_info.mimorssi[eRFPath]; + eRFPath_highest = eRFPath; + } + + else if (pstat->rf_info.mimorssi[eRFPath] > higher_rssi) { + higher_rssi = pstat->rf_info.mimorssi[eRFPath]; + eRFPath_higher = eRFPath; + } + + if (pstat->rf_info.mimorssi[eRFPath] < priv->pshare->rf_ft_var.ss_th_low) + under_ss_th_low = 1; + } + + // for OFDM + if (priv->pshare->phw->ant_off_num > 0) + { + for (eRFPath = RF92CD_PATH_A; eRFPath<priv->pshare->phw->NumTotalRFPath; eRFPath++) { + if (!(priv->pshare->phw->ant_off_bitmap & BIT(eRFPath))) + continue; + + if (highest_rssi >= priv->pshare->phw->ant_on_criteria[eRFPath]) { + priv->pshare->phw->ant_off_num--; + priv->pshare->phw->ant_off_bitmap &= (~BIT(eRFPath)); + RTL_W8(rOFDM0_TRxPathEnable, ~(priv->pshare->phw->ant_off_bitmap) & 0x0f); + RTL_W8(rOFDM1_TRxPathEnable, ~(priv->pshare->phw->ant_off_bitmap) & 0x0f); + DEBUG_INFO("Path %c is on due to >= %d%%\n", + path_name[eRFPath], priv->pshare->phw->ant_on_criteria[eRFPath]); + ant_on_processing = 1; + } + } + } + + if (!ant_on_processing) + { + if (priv->pshare->phw->ant_off_num < 2) { + for (eRFPath = RF92CD_PATH_A; eRFPath<priv->pshare->phw->NumTotalRFPath; eRFPath++) { + if ((eRFPath == eRFPath_highest) || (priv->pshare->phw->ant_off_bitmap & BIT(eRFPath))) + continue; + + if ((pstat->rf_info.mimorssi[eRFPath] < priv->pshare->rf_ft_var.ss_th_low) && + ((highest_rssi - pstat->rf_info.mimorssi[eRFPath]) > priv->pshare->rf_ft_var.diff_th)) { + priv->pshare->phw->ant_off_num++; + priv->pshare->phw->ant_off_bitmap |= BIT(eRFPath); + priv->pshare->phw->ant_on_criteria[eRFPath] = highest_rssi + 5; + RTL_W8(rOFDM0_TRxPathEnable, ~(priv->pshare->phw->ant_off_bitmap) & 0x0f); + RTL_W8(rOFDM1_TRxPathEnable, ~(priv->pshare->phw->ant_off_bitmap) & 0x0f); + DEBUG_INFO("Path %c is off due to under th_low %d%% and diff %d%%, will be on at %d%%\n", + path_name[eRFPath], priv->pshare->rf_ft_var.ss_th_low, + (highest_rssi - pstat->rf_info.mimorssi[eRFPath]), + priv->pshare->phw->ant_on_criteria[eRFPath]); + break; + } + } + } + } + + // For CCK + if (priv->pshare->rf_ft_var.cck_sel_ver == 1) { + if (under_ss_th_low && (pstat->rx_pkts > 20)) { + if (priv->pshare->phw->ant_cck_sel != ((eRFPath_highest << 2) | eRFPath_higher)) { + priv->pshare->phw->ant_cck_sel = ((eRFPath_highest << 2) | eRFPath_higher); + RTL_W8(0xa07, (RTL_R8(0xa07) & 0xf0) | priv->pshare->phw->ant_cck_sel); + DEBUG_INFO("CCK select default: path %c, optional: path %c\n", + path_name[eRFPath_highest], path_name[eRFPath_higher]); + } + } + } +} + + +// dynamic Rx path selection by signal strength +void rx_path_by_rssi_cck_v2(struct rtl8192cd_priv *priv, struct stat_info *pstat) +{ + int highest_rssi=-1000, higher_rssi=-1000; + RF92CD_RADIO_PATH_E eRFPath, eRFPath_highest=0, eRFPath_higher=0; +#ifdef _DEBUG_RTL8192CD_ + char path_name[] = {'A', 'B'}; +#endif + + for (eRFPath = RF92CD_PATH_A; eRFPath<priv->pshare->phw->NumTotalRFPath; eRFPath++) { + if (pstat->cck_mimorssi_total[eRFPath] > highest_rssi) { + higher_rssi = highest_rssi; + eRFPath_higher = eRFPath_highest; + highest_rssi = pstat->cck_mimorssi_total[eRFPath]; + eRFPath_highest = eRFPath; + } + + else if (pstat->cck_mimorssi_total[eRFPath] > higher_rssi) { + higher_rssi = pstat->cck_mimorssi_total[eRFPath]; + eRFPath_higher = eRFPath; + } + } + + if (priv->pshare->phw->ant_cck_sel != ((eRFPath_highest << 2) | eRFPath_higher)) { + priv->pshare->phw->ant_cck_sel = ((eRFPath_highest << 2) | eRFPath_higher); + RTL_W8(0xa07, (RTL_R8(0xa07) & 0xf0) | priv->pshare->phw->ant_cck_sel); + DEBUG_INFO("CCK rssi A:%d B:%d C:%d D:%d accu %d pkts\n", pstat->cck_mimorssi_total[0], + pstat->cck_mimorssi_total[1], pstat->cck_mimorssi_total[2], pstat->cck_mimorssi_total[3], pstat->cck_rssi_num); + DEBUG_INFO("CCK select default: path %c, optional: path %c\n", + path_name[eRFPath_highest], path_name[eRFPath_higher]); + } +} + + +// Tx power control +void tx_power_control(struct rtl8192cd_priv *priv, struct stat_info *pstat, int enable) +{ + if (enable) { + if (!priv->pshare->phw->lower_tx_power) { + // TX High power enable +// set_fw_reg(priv, 0xfd000009, 0, 0); + if (!priv->pshare->bcnTxAGC) + RTL_W8(0x364, RTL_R8(0x364) | FW_REG364_HP); + priv->pshare->phw->lower_tx_power++; + + if ((!priv->pshare->is_40m_bw || (pstat->tx_bw == HT_CHANNEL_WIDTH_20)) && + (!pstat->is_rtl8190_sta && !pstat->is_broadcom_sta && !pstat->is_marvell_sta && !pstat->is_intel_sta)) + set_fw_reg(priv, 0xfd004314, 0, 0); + else + set_fw_reg(priv, 0xfd000015, 0, 0); + } + } + else { + if (priv->pshare->phw->lower_tx_power) { + //TX High power disable +// set_fw_reg(priv, 0xfd000008, 0, 0); + RTL_W8(0x364, RTL_R8(0x364) & ~FW_REG364_HP); + priv->pshare->phw->lower_tx_power = 0; + } + } +} + + +void tx_power_tracking(struct rtl8192cd_priv *priv) +{ + if (priv->pmib->dot11RFEntry.ther) { + DEBUG_INFO("TPT: triggered(every %d seconds)\n", priv->pshare->rf_ft_var.tpt_period); + + // enable rf reg 0x24 power and trigger, to get ther value in 1 second + PHY_SetRFReg(priv, RF92CD_PATH_A, 0x24, bMask20Bits, 0x60); + mod_timer(&priv->pshare->phw->tpt_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(1000)); // 1000ms + } +} + + +void rtl8192cd_tpt_timer(unsigned long task_priv) +{ + struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv; + unsigned int val32; + + if (!(priv->drv_state & DRV_STATE_OPEN)) + return; + + if (timer_pending(&priv->pshare->phw->tpt_timer)) + del_timer_sync(&priv->pshare->phw->tpt_timer); + + if (priv->pmib->dot11RFEntry.ther) { + // query rf reg 0x24[4:0], for thermal meter value + val32 = PHY_QueryRFReg(priv, RF92CD_PATH_A, 0x24, bMask20Bits, 1) & 0x01f; + + if (val32) { + set_fw_reg(priv, 0xfd000019|(priv->pmib->dot11RFEntry.ther & 0xff)<<8|val32<<16, 0, 0); + DEBUG_INFO("TPT: finished once (ther: current=0x%02x, target=0x%02x)\n", + val32, priv->pmib->dot11RFEntry.ther); + } + else{ + DEBUG_WARN("TPT: cannot finish, since wrong current ther value report\n"); + } + } +} +#endif + +#ifdef HIGH_POWER_EXT_PA +void tx_power_control(struct rtl8192cd_priv *priv) +{ + unsigned long x; + + int pwr_value = 0x10101010; + if( priv->pshare->phw->signal_strength == 3 && priv->pshare->phw->lower_tx_power== 0) { + SAVE_INT_AND_CLI(x); + priv->pshare->phw->power_backup[0x00] = RTL_R32(rTxAGC_A_Rate18_06); + priv->pshare->phw->power_backup[0x01] = RTL_R32(rTxAGC_A_Rate54_24); + priv->pshare->phw->power_backup[0x02] = RTL_R32(rTxAGC_B_Rate18_06); + priv->pshare->phw->power_backup[0x03] = RTL_R32(rTxAGC_B_Rate54_24); + priv->pshare->phw->power_backup[0x04] = RTL_R32(rTxAGC_A_Mcs03_Mcs00); + priv->pshare->phw->power_backup[0x05] = RTL_R32(rTxAGC_A_Mcs07_Mcs04); + priv->pshare->phw->power_backup[0x06] = RTL_R32(rTxAGC_A_Mcs11_Mcs08); + priv->pshare->phw->power_backup[0x07] = RTL_R32(rTxAGC_A_Mcs15_Mcs12); + priv->pshare->phw->power_backup[0x08] = RTL_R32(rTxAGC_B_Mcs03_Mcs00); + priv->pshare->phw->power_backup[0x09] = RTL_R32(rTxAGC_B_Mcs07_Mcs04); + priv->pshare->phw->power_backup[0x0a] = RTL_R32(rTxAGC_B_Mcs11_Mcs08); + priv->pshare->phw->power_backup[0x0b] = RTL_R32(rTxAGC_B_Mcs15_Mcs12); + priv->pshare->phw->power_backup[0x0c] = RTL_R32(rTxAGC_A_CCK11_2_B_CCK11); + priv->pshare->phw->power_backup[0x0d] = RTL_R32(rTxAGC_A_CCK1_Mcs32); + priv->pshare->phw->power_backup[0x0e] = RTL_R32(rTxAGC_B_CCK5_1_Mcs32); + RTL_W32(rTxAGC_A_Rate18_06, pwr_value); + RTL_W32(rTxAGC_A_Rate54_24, pwr_value); + RTL_W32(rTxAGC_B_Rate18_06, pwr_value); + RTL_W32(rTxAGC_B_Rate54_24, pwr_value); + RTL_W32(rTxAGC_A_Mcs03_Mcs00, pwr_value); + RTL_W32(rTxAGC_A_Mcs07_Mcs04, pwr_value); + RTL_W32(rTxAGC_A_Mcs11_Mcs08, pwr_value); + RTL_W32(rTxAGC_A_Mcs15_Mcs12, pwr_value); + RTL_W32(rTxAGC_B_Mcs03_Mcs00, pwr_value); + RTL_W32(rTxAGC_B_Mcs07_Mcs04, pwr_value); + RTL_W32(rTxAGC_B_Mcs11_Mcs08, pwr_value); + RTL_W32(rTxAGC_B_Mcs15_Mcs12, pwr_value); + RTL_W32(rTxAGC_A_CCK11_2_B_CCK11, pwr_value); + RTL_W32(rTxAGC_A_CCK1_Mcs32, (pwr_value & 0x0000ff00) | (priv->pshare->phw->power_backup[0x0d] &0xffff00ff)); + RTL_W32(rTxAGC_B_CCK5_1_Mcs32, (pwr_value & 0xffffff00) | (priv->pshare->phw->power_backup[0x0e] &0x000000ff)); + priv->pshare->phw->lower_tx_power = 1; + RESTORE_INT(x); + } + else if( priv->pshare->phw->signal_strength != 3 && priv->pshare->phw->lower_tx_power) { + SAVE_INT_AND_CLI(x); + RTL_W32(rTxAGC_A_Rate18_06, priv->pshare->phw->power_backup[0x00]); + RTL_W32(rTxAGC_A_Rate54_24, priv->pshare->phw->power_backup[0x01]); + RTL_W32(rTxAGC_B_Rate18_06, priv->pshare->phw->power_backup[0x02]); + RTL_W32(rTxAGC_B_Rate54_24, priv->pshare->phw->power_backup[0x03]); + RTL_W32(rTxAGC_A_Mcs03_Mcs00, priv->pshare->phw->power_backup[0x04]); + RTL_W32(rTxAGC_A_Mcs07_Mcs04, priv->pshare->phw->power_backup[0x05]); + RTL_W32(rTxAGC_A_Mcs11_Mcs08, priv->pshare->phw->power_backup[0x06]); + RTL_W32(rTxAGC_A_Mcs15_Mcs12, priv->pshare->phw->power_backup[0x07]); + RTL_W32(rTxAGC_B_Mcs03_Mcs00, priv->pshare->phw->power_backup[0x08]); + RTL_W32(rTxAGC_B_Mcs07_Mcs04, priv->pshare->phw->power_backup[0x09]); + RTL_W32(rTxAGC_B_Mcs11_Mcs08, priv->pshare->phw->power_backup[0x0a]); + RTL_W32(rTxAGC_B_Mcs15_Mcs12, priv->pshare->phw->power_backup[0x0b]); + RTL_W32(rTxAGC_A_CCK11_2_B_CCK11, priv->pshare->phw->power_backup[0x0c]); + RTL_W32(rTxAGC_A_CCK1_Mcs32, priv->pshare->phw->power_backup[0x0d]); + RTL_W32(rTxAGC_B_CCK5_1_Mcs32, priv->pshare->phw->power_backup[0x0e]); + priv->pshare->phw->lower_tx_power = 0; + RESTORE_INT(x); + } +} +#endif + +#ifdef WIFI_WMM +void check_NAV_prot_len(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned int disassoc) +{ + if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && pstat + && pstat->ht_cap_len && pstat->is_intel_sta) { + if (!disassoc && (pstat->MIMO_ps & _HT_MIMO_PS_DYNAMIC_)) { +#ifdef STA_EXT + if (pstat->aid <= FW_NUM_STAT) + priv->pshare->mimo_ps_dynamic_sta |= BIT(pstat->aid - 1); + else + priv->pshare->mimo_ps_dynamic_sta_ext |= BIT(pstat->aid - 1 - FW_NUM_STAT); +#else + priv->pshare->mimo_ps_dynamic_sta |= BIT(pstat->aid -1); +#endif + } else { +#ifdef STA_EXT + if (pstat->aid <= FW_NUM_STAT) + priv->pshare->mimo_ps_dynamic_sta &= ~BIT(pstat->aid - 1); + else + priv->pshare->mimo_ps_dynamic_sta_ext &= ~BIT(pstat->aid - 1 - FW_NUM_STAT); +#else + priv->pshare->mimo_ps_dynamic_sta &= ~BIT(pstat->aid -1); +#endif + } + + if (priv->pshare->mimo_ps_dynamic_sta +#ifdef STA_EXT + || priv->pshare->mimo_ps_dynamic_sta_ext +#endif + ) { + RTL_W8(NAV_PROT_LEN, 0x40); + } else { + RTL_W8(NAV_PROT_LEN, 0x20); + } + } +} +#endif + + +/* + * + * CAM related functions + * + */ + +/*******************************************************/ +/*CAM related utility */ +/*CamAddOneEntry */ +/*CamDeleteOneEntry */ +/*CamResetAllEntry */ +/*******************************************************/ +#define TOTAL_CAM_ENTRY 32 + +#define CAM_CONTENT_COUNT 8 +#define CAM_CONTENT_USABLE_COUNT 6 + +#define CFG_VALID BIT(15) + + +static UCHAR CAM_find_usable(struct rtl8192cd_priv *priv) +{ + unsigned long command = 0, content = 0; + unsigned char index; + int for_begin = 4; + + for (index=for_begin; index<TOTAL_CAM_ENTRY; index++) { + // polling bit, and No Write enable, and address + command = CAM_CONTENT_COUNT*index; + RTL_W32(CAMCMD, (SECCAM_POLL|command)); + + // Check polling bit is clear + while (1) { + command = RTL_R32(CAMCMD); + if(command & SECCAM_POLL) + continue; + else + break; + } + content = RTL_R32(CAMREAD); + + // check valid bit. if not valid, + if ((content & CFG_VALID) == 0) { + return index; + } + } + return TOTAL_CAM_ENTRY; +} + + +static void CAM_program_entry(struct rtl8192cd_priv *priv, unsigned char index, unsigned char* macad, + unsigned char* key128, unsigned short config) +{ + unsigned long target_command = 0, target_content = 0; + unsigned char entry_i = 0; + struct stat_info *pstat; + + for (entry_i=0; entry_i<CAM_CONTENT_USABLE_COUNT; entry_i++) + { + // polling bit, and write enable, and address + target_command = entry_i + CAM_CONTENT_COUNT*index; + target_command = target_command |SECCAM_POLL | SECCAM_WE; + if (entry_i == 0) { + //first 32-bit is MAC address and CFG field + target_content = (ULONG)(*(macad+0))<<16 + |(ULONG)(*(macad+1))<<24 + |(ULONG)config; + target_content = target_content|config; + } + else if (entry_i == 1) { + //second 32-bit is MAC address + target_content = (ULONG)(*(macad+5))<<24 + |(ULONG)(*(macad+4))<<16 + |(ULONG)(*(macad+3))<<8 + |(ULONG)(*(macad+2)); + } + else { + target_content = (ULONG)(*(key128+(entry_i*4-8)+3))<<24 + |(ULONG)(*(key128+(entry_i*4-8)+2))<<16 + |(ULONG)(*(key128+(entry_i*4-8)+1))<<8 + |(ULONG)(*(key128+(entry_i*4-8)+0)); + } + + RTL_W32(CAMWRITE, target_content); + RTL_W32(CAMCMD, target_command); + } + + pstat = get_stainfo(priv, macad); + if (pstat) { + pstat->cam_id = index; + } + + target_content = RTL_R32(CR); + if ((target_content & MAC_SEC_EN) == 0) + RTL_W32(CR, (target_content | MAC_SEC_EN)); +} + + +int CamAddOneEntry(struct rtl8192cd_priv *priv,unsigned char *pucMacAddr, unsigned long keyId, + unsigned long encAlg, unsigned long useDK, unsigned char *pKey) +{ + unsigned char retVal = 0, camIndex = 0, wpaContent = 0; + unsigned short usConfig = 0; + + //use Hardware Polling to check the valid bit. + //in reality it should be done by software link-list + if ((!memcmp(pucMacAddr, "\xff\xff\xff\xff\xff\xff", 6)) || (useDK +#if defined(CONFIG_RTL_HW_WAPI_SUPPORT) + &&((encAlg>>2)!=DOT11_ENC_WAPI) +#endif + )) + camIndex = keyId; + else + camIndex = CAM_find_usable(priv); + + if (camIndex==TOTAL_CAM_ENTRY) + return retVal; + + usConfig = usConfig|CFG_VALID|((USHORT)(encAlg))|(UCHAR)keyId; + + #if defined(CONFIG_RTL_HW_WAPI_SUPPORT) + if((encAlg>>2) == DOT11_ENC_WAPI) + { + //ulUseDK is used to diff Parwise and Group + if(camIndex<4) //is group key + usConfig |= BIT(6); + + if(useDK==1) // ==0 sec key; == 1mic key + usConfig |= BIT(5); + + useDK = 0; + } + #endif + + CAM_program_entry(priv, camIndex, pucMacAddr, pKey, usConfig); + + if (priv->pshare->CamEntryOccupied == 0) { + if (useDK == 1) + wpaContent = RXUSEDK | TXUSEDK; + RTL_W16(SECCFG, RTL_R16(SECCFG) | RXDEC | TXENC | wpaContent | NOSKMC | CHK_KEYID); + } + + if (camIndex < 4) + RTL_W16(SECCFG, (RTL_R16(SECCFG) & ~NOSKMC) | (RXBCUSEDK | TXBCUSEDK)); + + return 1; +} + + +void CAM_read_mac_config(struct rtl8192cd_priv *priv, unsigned char index, unsigned char* pMacad, + unsigned short* pTempConfig) +{ + unsigned long command = 0, content = 0; + + // polling bit, and No Write enable, and address + // cam address... + // first 32-bit + command = CAM_CONTENT_COUNT*index+0; + command = command | SECCAM_POLL; + RTL_W32(CAMCMD, command); + + //Check polling bit is clear + while (1) { + command = RTL_R32(CAMCMD); + if(command & SECCAM_POLL) + continue; + else + break; + } + content = RTL_R32(CAMREAD); + + //first 32-bit is MAC address and CFG field + *(pMacad+0) = (UCHAR)((content>>16)&0x000000FF); + *(pMacad+1) = (UCHAR)((content>>24)&0x000000FF); + *pTempConfig = (USHORT)(content&0x0000FFFF); + + command = CAM_CONTENT_COUNT*index+1; + command = command | SECCAM_POLL; + RTL_W32(CAMCMD, command); + + //Check polling bit is clear + while (1) { + command = RTL_R32(CAMCMD); + if(command & SECCAM_POLL) + continue; + else + break; + } + content = RTL_R32(CAMREAD); + + *(pMacad+5) = (UCHAR)((content>>24)&0x000000FF); + *(pMacad+4) = (UCHAR)((content>>16)&0x000000FF); + *(pMacad+3) = (UCHAR)((content>>8)&0x000000FF); + *(pMacad+2) = (UCHAR)((content)&0x000000FF); +} + + +#if 0 +void CAM_mark_invalid(struct rtl8192cd_priv *priv,UCHAR ucIndex) +{ + ULONG ulCommand=0; + ULONG ulContent=0; + + // polling bit, and No Write enable, and address + ulCommand = CAM_CONTENT_COUNT*ucIndex; + ulCommand = ulCommand | _CAM_POLL_ |_CAM_WE_; + // write content 0 is equall to mark invalid + RTL_W32(_CAM_W_, ulContent); + RTL_W32(_CAMCMD_, ulCommand); +} +#endif + + +static void CAM_empty_entry(struct rtl8192cd_priv *priv,unsigned char index) +{ + unsigned long command=0, content=0; + unsigned int i; + + for (i = 0; i < CAM_CONTENT_COUNT; i++) { + // polling bit, and No Write enable, and address + command = CAM_CONTENT_COUNT*index+i; + command = command | SECCAM_POLL |SECCAM_WE; + // write content 0 is equal to mark invalid + RTL_W32(CAMWRITE, content); + RTL_W32(CAMCMD, command); + } +} + + +int CamDeleteOneEntry(struct rtl8192cd_priv *priv, unsigned char *pMacAddr, unsigned long keyId, unsigned int useDK) +{ + unsigned char ucIndex; + unsigned char ucTempMAC[6]; + unsigned short usTempConfig=0; + int for_begin=0; + + // group key processing + if ((!memcmp(pMacAddr, "\xff\xff\xff\xff\xff\xff", 6)) || (useDK)) { + CAM_read_mac_config(priv, keyId, ucTempMAC, &usTempConfig); + if (usTempConfig&CFG_VALID) { + CAM_empty_entry(priv, keyId); + if (priv->pshare->CamEntryOccupied == 1) + RTL_W16(SECCFG, 0); + return 1; + } + else + return 0; + } + + for_begin = 4; + + // unicast key processing + // key processing for RTL818X(B) series + for(ucIndex = for_begin; ucIndex < TOTAL_CAM_ENTRY; ucIndex++) { + CAM_read_mac_config(priv, ucIndex, ucTempMAC, &usTempConfig); + if(!memcmp(pMacAddr, ucTempMAC, 6)) { + +#if defined(CONFIG_RTL_HW_WAPI_SUPPORT) + if((((usTempConfig & 0x1c) >> 2) == DOT11_ENC_WAPI)&&((usTempConfig & 0x3) != keyId)) + continue; +#endif + CAM_empty_entry(priv, ucIndex); // reset MAC address, david+2007-1-15 + + if (priv->pshare->CamEntryOccupied == 1) + RTL_W16(SECCFG, 0); + + return 1; + } + } + return 0; +} + + +/*now use empty to fill in the first 4 entries*/ +void CamResetAllEntry(struct rtl8192cd_priv *priv) +{ + unsigned char index; + + RTL_W32(CAMCMD, SECCAM_CLR); + + for(index = 0; index < TOTAL_CAM_ENTRY; index++) + CAM_empty_entry(priv,index); + + priv->pshare->CamEntryOccupied = 0; + priv->pmib->dot11GroupKeysTable.keyInCam = 0; + + RTL_W32(CR, RTL_R32(CR) & (~MAC_SEC_EN)); +} + + +void CAM_read_entry(struct rtl8192cd_priv *priv, unsigned char index, unsigned char* macad, + unsigned char* key128, unsigned short* config) +{ + unsigned long target_command = 0, target_content = 0; + unsigned char entry_i = 0; + unsigned long status; + + for (entry_i=0; entry_i<CAM_CONTENT_USABLE_COUNT; entry_i++) + { + // polling bit, and No Write enable, and address + target_command = (unsigned long)(entry_i+CAM_CONTENT_COUNT*index); + target_command = target_command | SECCAM_POLL; + + RTL_W32(CAMCMD, target_command); + //Check polling bit is clear + while(1) { + status = RTL_R32(CAMCMD); + if(status & SECCAM_POLL) + continue; + else + break; + } + target_content = RTL_R32(CAMREAD); + + if (entry_i==0) { + //first 32-bit is MAC address and CFG field + *(config) = (unsigned short)((target_content)&0x0000FFFF); + *(macad+0) = (unsigned char)((target_content>>16)&0x000000FF); + *(macad+1) = (unsigned char)((target_content>>24)&0x000000FF); + } + else if (entry_i==1) { + *(macad+5) = (unsigned char)((target_content>>24)&0x000000FF); + *(macad+4) = (unsigned char)((target_content>>16)&0x000000FF); + *(macad+3) = (unsigned char)((target_content>>8)&0x000000FF); + *(macad+2) = (unsigned char)((target_content)&0x000000FF); + } + else { + *(key128+(entry_i*4-8)+3) = (unsigned char)((target_content>>24)&0x000000FF); + *(key128+(entry_i*4-8)+2) = (unsigned char)((target_content>>16)&0x000000FF); + *(key128+(entry_i*4-8)+1) = (unsigned char)((target_content>>8)&0x000000FF); + *(key128+(entry_i*4-8)+0) = (unsigned char)(target_content&0x000000FF); + } + + target_content = 0; + } +} + + +#if 0 +void debug_cam(UCHAR*TempOutputMac, UCHAR*TempOutputKey, USHORT TempOutputCfg) +{ + printk("MAC Address\n"); + printk(" %X %X %X %X %X %X\n",*TempOutputMac + ,*(TempOutputMac+1) + ,*(TempOutputMac+2) + ,*(TempOutputMac+3) + ,*(TempOutputMac+4) + ,*(TempOutputMac+5)); + printk("Config:\n"); + printk(" %X\n",TempOutputCfg); + + printk("Key:\n"); + printk("%X %X %X %X,%X %X %X %X,\n%X %X %X %X,%X %X %X %X\n" + ,*TempOutputKey,*(TempOutputKey+1),*(TempOutputKey+2) + ,*(TempOutputKey+3),*(TempOutputKey+4),*(TempOutputKey+5) + ,*(TempOutputKey+6),*(TempOutputKey+7),*(TempOutputKey+8) + ,*(TempOutputKey+9),*(TempOutputKey+10),*(TempOutputKey+11) + ,*(TempOutputKey+12),*(TempOutputKey+13),*(TempOutputKey+14) + ,*(TempOutputKey+15)); +} + + +void CamDumpAll(struct rtl8192cd_priv *priv) +{ + UCHAR TempOutputMac[6]; + UCHAR TempOutputKey[16]; + USHORT TempOutputCfg=0; + unsigned long flags; + int i; + + SAVE_INT_AND_CLI(flags); + for (i=0; i<TOTAL_CAM_ENTRY; i++) + { + printk("%X-", i); + CAM_read_entry(priv,i, TempOutputMac, TempOutputKey, &TempOutputCfg); + debug_cam(TempOutputMac, TempOutputKey, TempOutputCfg); + printk("\n\n"); + } + RESTORE_INT(flags); +} + + +void CamDump4(struct rtl8192cd_priv *priv) +{ + UCHAR TempOutputMac[6]; + UCHAR TempOutputKey[16]; + USHORT TempOutputCfg=0; + unsigned long flags; + int i; + + SAVE_INT_AND_CLI(flags); + for (i=0; i<4; i++) + { + printk("%X", i); + CAM_read_entry(priv, i, TempOutputMac, TempOutputKey, &TempOutputCfg); + debug_cam(TempOutputMac, TempOutputKey, TempOutputCfg); + printk("\n\n"); + } + RESTORE_INT(flags); +} +#endif + + + +/* + * + * Power Saving related functions + * + */ +#ifdef PCIE_POWER_SAVING + +#ifdef CONFIG_RTL_92D_DMDP +extern u32 if_priv[]; +#endif + +#ifdef CONFIG_RTL_92D_DMDP + +void Sw_PCIE_Func2(int func) +{ +#if (RTL_USED_PCIE_SLOT==1) + int reg = 0xb8b2100c; +#else + int reg = 0xb8b0100c; +#endif + + REG32(reg) &= ~(1); + REG32(reg) |= func; // switch to function # +} +#endif + +#if defined(__LINUX_2_6__) +extern void HostPCIe_SetPhyMdioWrite(unsigned int , unsigned int , unsigned short ); +#endif +#ifdef ASPM_ENABLE +void ASPM_on_off(struct rtl8192cd_priv *priv) ; +#endif + +#define CLK_MANAGE 0xb8000010 +#ifdef PCIE_POWER_SAVING_DEBUG +int PCIE_PowerDown(struct rtl8192cd_priv *priv, unsigned char *data) +{ +// #define PCIE_PHY0 0xb8b01008 + + #define dprintf printk + int tmp, mode, portnum=0; + unsigned int PCIE_PHY0, linkstatus; + unsigned int haddr, saddr; + + if (GET_CHIP_VER(priv) == VERSION_8192D) { + haddr = CFG_92D_SLOTH; + saddr = CFG_92D_SLOTS; + } else { + haddr = CFG_92C_SLOTH; + saddr = CFG_92C_SLOTS; + } + + PCIE_PHY0 = haddr + 0x1008; + linkstatus = haddr + 0x728; + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + +#if defined(CONFIG_RTL_92D_SUPPORT) + portnum = RTL_USED_PCIE_SLOT; +#endif + + mode = _atoi(data, 16); + + if(strlen(data)==0) { + dprintf("epdn mode.\n"); + dprintf("epdn 0: D0 ->L0 \n"); + dprintf("epdn 3: D3hot ->L1 \n"); + dprintf("epdn 4: board cast PME_TurnOff \n"); + dprintf("epdn 7: enable aspm and L0 entry \n"); + dprintf("epdn 8: enable aspm and L1 entry \n"); + dprintf("epdn 9: diable aspm \n"); + dprintf("epdn 5a: pcie reset \n"); + dprintf("epdn 6a: L0 -> L2 \n"); + dprintf("epdn 6b: L2 -> L0\n"); + dprintf("epdn 6c: L0 -> L1 \n"); + dprintf("epdn 6d: L1 -> L0\n"); + dprintf("epdn 6e: download probe rsp\n"); + dprintf("epdn a3: wake pin test\n"); + dprintf("epdn b: bar\n"); + dprintf("epdn b1: offload enable \n"); + dprintf("epdn b2: offload disable\n"); + dprintf("epdn c1: swith to 1T\n"); + dprintf("epdn c2: switch to 2T\n"); + dprintf("Link status=%x \n", REG32(linkstatus)&0x1f ); + return 0; + } + + if(mode==0) { + +#ifdef CONFIG_RTL_92D_DMDP + if (GET_CHIP_VER(priv) == VERSION_8192D) { + if(priv->pshare->wlandev_idx !=0) { + dprintf("not Root Interface!! \n"); + return 0; + } + Sw_PCIE_Func2(0); + } +#endif + +#ifdef SAVING_MORE_PWR + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0f0f); +#endif + tmp = REG32(0xb8b10044) &( ~(3)); + REG32(0xb8b10044) = tmp| (0); //D0 + delay_ms(1); + REG32(0xb8b10044) = tmp| (0); //D0 + dprintf("D0 \n"); + priv->pwr_state = L0; + +#if defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv) == VERSION_8192D) { +#ifdef CONFIG_RTL_92D_DMDP +// if(priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + { + Sw_PCIE_Func2(1); +#ifdef SAVING_MORE_PWR + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0f0f); +#endif + tmp = REG32(0xb8b10044) &( ~(3)); //D0 + REG32(0xb8b10044) = tmp| (0); //D0 + delay_ms(1); + REG32(0xb8b10044) = tmp| (0); //D0 + dprintf("D0 wlan1\n"); + ((struct rtl8192cd_priv *)if_priv[1])->pwr_state = L0; + } + Sw_PCIE_Func2(0); +#endif + delay_ms(1); + } +#endif + + } + + if(mode==3) { + +#if defined(CONFIG_RTL_92D_SUPPORT) + if (GET_CHIP_VER(priv) == VERSION_8192D){ +#ifdef CONFIG_RTL_92D_DMDP + if(priv->pshare->wlandev_idx !=0) { + dprintf("not Root Interface!! \n"); + return 0; + } +// if(priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + { + + dprintf("DMDP, disable wlan1 !!\n"); + Sw_PCIE_Func2(1); +#ifdef SAVING_MORE_PWR + REG32(0xb8b10080)|= (0x100); //enable clock PM +#endif + tmp = REG32(0xb8b10044) &( ~(3)); + REG32(0xb8b10044) = tmp| (3); //D3 + + ((struct rtl8192cd_priv *)if_priv[1])->pwr_state = L1; +#ifdef SAVING_MORE_PWR + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0708); +#endif + } + Sw_PCIE_Func2(0); +#endif + delay_ms(1); + + } +#endif + +#ifdef SAVING_MORE_PWR + REG32(0xb8b10080)|= (0x100); //enable clock PM +#endif + tmp = REG32(0xb8b10044) &( ~(3)); + REG32(0xb8b10044) = tmp| (3); //D3 + //HostPCIe_SetPhyMdioWrite(0xd, 0x15a6); + dprintf("D3 hot \n"); + priv->pwr_state = L1; +#ifdef SAVING_MORE_PWR + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0708); +#endif + } + + if(mode==4) { + + RTL_W8(0x1c, 0xe1); // reg lock, dis_prst + RTL_W8(0x1c, 0xe1); + +#ifdef SAVING_MORE_PWR + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0f0f); +#endif + + REG32(0xb8b01008) |= (0x200); + dprintf("Host boardcase PME_TurnOff \n"); + priv->pwr_state = L2; + } + + + if(mode==0xd) { + + RTL_W8(0x1c, 0x0); + priv->pshare->phw->cur_rx =0; +#ifdef DELAY_REFILL_RX_BUF + priv->pshare->phw->cur_rx_refill =0; +#endif + memset(&(priv->pshare->phw->txhead0), 0, sizeof(int)*12); + + RTL_W8(SPS0_CTRL, 0x2b); + RTL_W32(BCNQ_DESA, priv->pshare->phw->tx_ringB_addr); + RTL_W32(MGQ_DESA, priv->pshare->phw->tx_ring0_addr); + RTL_W32(VOQ_DESA, priv->pshare->phw->tx_ring4_addr); + RTL_W32(VIQ_DESA, priv->pshare->phw->tx_ring3_addr); + RTL_W32(BEQ_DESA, priv->pshare->phw->tx_ring2_addr); + RTL_W32(BKQ_DESA, priv->pshare->phw->tx_ring1_addr); + RTL_W32(HQ_DESA, priv->pshare->phw->tx_ring5_addr); + RTL_W32(RX_DESA, priv->pshare->phw->ring_dma_addr); + + } + + if(mode==7) { + REG32(0xb8b1070c) &= ~ ((0x7 <<27)|(0x7<<24)); + REG32(0xb8b1070c) |= ((3)<<27) | ((1)<<24); //L1=8us, L0s=2us + + REG32(0xb8b00080) &= ~(0x3); + REG32(0xb8b10080) &= ~(0x3); + + REG32(0xb8b00080) |= 1; //L0s + REG32(0xb8b10080) |= 1; + priv->pwr_state=ASPM_L0s_L1; + } + + if(mode==8) { + REG32(0xb8b1070c) &= ~ ((0x7 <<27)|(0x7<<24)); + REG32(0xb8b1070c) |= ((1)<<27) | ((3)<<24); //L1=2us, L0s=4us + + REG32(0xb8b00080) &= ~(0x3); + REG32(0xb8b10080) &= ~(0x3); + + REG32(0xb8b00080) |= 3; //L1 + REG32(0xb8b10080) |= 3; //L1 + priv->pwr_state=ASPM_L0s_L1; + + } + + if(mode==9) { + REG32(0xb8b00080) &= ~(0x3); + REG32(0xb8b10080) &= ~(0x3); + priv->pwr_state=L0; + } + + + if(mode==0x6a) { + priv->ps_ctrl = 1 | 32 |0x80; + mod_timer(&priv->ps_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(100)); + } + + if(mode==0x6c) { + priv->ps_ctrl = 1 | 16 |0x80; +// mod_timer(&priv->ps_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(100)); + PCIe_power_save_tasklet((unsigned long)priv); + } + + if((mode==0x6b) || (mode==0x6d)) { + priv->ps_ctrl = 0x82 | (priv->pwr_state<<4); + priv->pshare->rf_ft_var.power_save &=0xf0; + +#ifdef CONFIG_RTL_92D_DMDP + ((struct rtl8192cd_priv *)if_priv[1])->pshare->rf_ft_var.power_save &=0xf0; +#endif + PCIe_power_save_tasklet((unsigned long)priv); + signin_h2c_cmd(priv, _AP_OFFLOAD_CMD_ , 0 ); +#ifdef CONFIG_RTL_92D_DMDP + signin_h2c_cmd(((struct rtl8192cd_priv *)if_priv[1]), _AP_OFFLOAD_CMD_ , 0 ); +#endif + } + + if(mode==0x6e) { + priv->offload_ctrl = 1; + RTL_W16(0x100 , RTL_R16(0x100) | BIT(8)); // enable sw beacon + tasklet_hi_schedule(&priv->pshare->rx_tasklet); + } + + if(mode==0xc1) { +// PHY_ConfigBBWithParaFile(priv, PATHB_OFF); + switch_to_1x1(priv, IN); + + } + + if(mode==0xc2) { +// PHY_ConfigBBWithParaFile(priv, PATHB_ON); + switch_to_1x1(priv, OUT); + } + + if(mode==0xb) { + REG32(0xb8b00004) = 0x00100007; + REG32(0xb8b10004) = 0x00100007; + REG32(0xb8b10010) = 0x18c00001; + REG32(0xb8b10018) = 0x19000004; + printk("b1-00=%x, b0-04=%x, b1-04=%x, b1-10=%x, b1-18=%x\n", REG32(0xb8b10000), + REG32(0xb8b00004),REG32(0xb8b10004), REG32(0xb8b10010), REG32(0xb8b10018) ); + } + + if(mode==0xb1) { + unsigned int cmd = _AP_OFFLOAD_CMD_ | (1<<8) |(HIDDEN_AP<<16) | ((GET_MIB(priv))->dot11OperationEntry.deny_any)<<24; + int page = ((priv->offload_ctrl)>>7)&0xff; + int cmd2=0, cmd2e=0; + + if(!page) { + page = 2; + } + + if(GET_CHIP_VER(priv) != VERSION_8192D) { + cmd2= (_RSVDPAGE_CMD_ | page<<8) ; + } else { + cmd2 = ( _RSVDPAGE_CMD_ | BIT(7) | (page<<8)); + cmd2e= (page<<8)| (page) ; + } + +// RTL_W16(PCIE_CTRL_REG, 0xff00 ); + REG32(saddr+0x44) |= 0x8108; + + printk("cmd: %x %x\n", cmd2, cmd2e); + signin_h2c_cmd(priv, cmd2, cmd2e); + delay_ms(10); + signin_h2c_cmd(priv,cmd, 0 ); + printk("sign in h2c cmd:%x, 0x284=%x\n", cmd, RTL_R32(0x284)); + +#ifdef CONFIG_RTL_8198 + REG32(0xb8003000) |= BIT(16); // GIMR +#else + REG32(0xb8003000) |= BIT(9); // GIMR +#endif + + delay_ms(10); + } + + if(mode==0xb2) { + signin_h2c_cmd(priv, 0x0000, 0); // offload disable + RTL_W8(0x423, 0x0); // mac seq disable + RTL_W8(0x286, 0); // RW_RELEASE_ENABLE + RTL_W16(PCIE_CTRL_REG, 0x00ff ); + } + + //static unsigned int Buffer[9]; + + if(mode==0xa3) { + unsigned char tmp; + +#ifdef CONFIG_RTL_8198 + REG32(0xb8000044) |= BIT(24); //LEDPHASE4 + REG32(0xb8003500) &= ~(BIT(20)); //PABCD_CNR , gpio pin + REG32(0xb8003508) &= ~(BIT(20)); //PABCD_DIR + REG32(0xb8003518) &= (~(0x03 << 8)); + REG32(0xb8003518) |= (0x01 << 8); // PCD_IMR // enable interrupt in falling-edge + REG32(0xb8003000) |= BIT(16); // GIMR +#else + REG32(0xb8000040) |= 0x0c00; //LEDPHASE1 :GPIOB7 + REG32(0xb8003500) &= ~(BIT(15));; //PABCD_CNR , gpio pin + REG32(0xb8003508) &= ~(BIT(15)); //PABCD_DIR + REG32(0xb8003514) &= (~(0x03 << 30)); + REG32(0xb8003514) |= (0x01 << 30); // PAB_IMR // enable interrupt in falling-edge + REG32(0xb8003000) |= BIT(9); // GIMR + +#endif + // clear wake pin status +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + + REG32(0xb8b10044) = 0x8108; + tmp = RTL_R8(0x690); + if(tmp&1) { + tmp ^=0x1; + RTL_W8(0x690, tmp); + } + dprintf("0xb8b10044=%x,690=%x,3000=%x, 3514=%x\n", REG32(0xb8b10044), RTL_R8(0x690), REG32(0xb8003000),REG32(0xb8003514) ); + RTL_W8(0x690, tmp |0x1 ); + dprintf("0xb8b10044=%x,690=%x\n", REG32(0xb8b10044), RTL_R8(0x690) ); + } + + if(mode==0x5a) + PCIE_reset_procedure3(priv); + + //------------------------------------------------------------- + if(mode==0x010) { //L0->L1->L0 + tmp = REG32(0xb8b10044) &( ~(3)); //D0 + REG32(0xb8b10044) = tmp| (3); //D3 + REG32(0xb8b10044) = tmp| (0); //D0, wakeup + + while(1) { + if((REG32(linkstatus)&0x1f)==0x11) //wait to L0 + break; + } + + dprintf("DID/VID=%x\n", REG32(0xb8b10000)); + } + //------------------------------------------------------------- + if(mode==0x020) { //L0->L2->L0 + tmp = REG32(0xb8b10044) &( ~(3)); //D0 + + REG32(0xb8b10044) = tmp| (3); //D3 + delay_ms(100); + + REG32(0xb8b01008) |= (0x200); + delay_ms(100); + + //wakeup + REG32(CLK_MANAGE) &= ~(1<<12); //perst=0 off. + //dprintf("CLK_MANAGE=%x \n", REG32(CLK_MANAGE)); + delay_ms(100); + delay_ms(100); + delay_ms(100); + + REG32(CLK_MANAGE) |= (1<<12); //PERST=1 + //prom_printf("\nCLK_MANAGE(0x%x)=0x%x\n\n",CLK_MANAGE,READ_MEM32(CLK_MANAGE)); + + //4. PCIE PHY Reset + REG32(PCIE_PHY0) = 0x01; //bit7 PHY reset=0 bit0 Enable LTSSM=1 + REG32(PCIE_PHY0) = 0x81; //bit7 PHY reset=1 bit0 Enable LTSSM=1 + + while(1) { + if( (REG32(linkstatus)&0x1f)==0x11) + break; + } + + dprintf("DID/VID=%x\n", REG32(0xb8b10000)); + } + + dprintf("Link status=%x\n", READ_MEM32(linkstatus)&0x1f/*, READ_MEM32(linkstatus), REG32(linkstatus)*/ ); + +return 0; +} +#endif + + +void switch_to_1x1(struct rtl8192cd_priv *priv, int mode) +{ + + if(mode==IN) { + + priv->pshare->rf_phy_bb_backup[21]= RTL_R32(0x88c); + + priv->pshare->rf_phy_bb_backup[0]= RTL_R32(0x844); + priv->pshare->rf_phy_bb_backup[1]= RTL_R32(0x85c); + priv->pshare->rf_phy_bb_backup[2]= RTL_R32(0xe6c); + + priv->pshare->rf_phy_bb_backup[3]= RTL_R32(0xe70); + priv->pshare->rf_phy_bb_backup[4]= RTL_R32(0xe74); + priv->pshare->rf_phy_bb_backup[5]= RTL_R32(0xe78); + priv->pshare->rf_phy_bb_backup[6]= RTL_R32(0xe7c); + + priv->pshare->rf_phy_bb_backup[7] = RTL_R32(0xe80); + priv->pshare->rf_phy_bb_backup[8] = RTL_R32(0xe84); + priv->pshare->rf_phy_bb_backup[9] = RTL_R32(0xe88); + priv->pshare->rf_phy_bb_backup[10]= RTL_R32(0xe8c); + + priv->pshare->rf_phy_bb_backup[11]= RTL_R32(0xed0); + priv->pshare->rf_phy_bb_backup[12]= RTL_R32(0xed4); + priv->pshare->rf_phy_bb_backup[13]= RTL_R32(0xed8); + priv->pshare->rf_phy_bb_backup[14]= RTL_R32(0xedc); + + priv->pshare->rf_phy_bb_backup[15]= RTL_R32(0xee0); + priv->pshare->rf_phy_bb_backup[16]= RTL_R32(0xeec); + + priv->pshare->rf_phy_bb_backup[17]= RTL_R32(0xc04); + priv->pshare->rf_phy_bb_backup[18]= RTL_R32(0xd04); + priv->pshare->rf_phy_bb_backup[19]= RTL_R32(0x90c); + priv->pshare->rf_phy_bb_backup[20]= RTL_R32(0x804); + priv->pshare->rf_phy_bb_backup[22]= RTL_R32(0xa04); + +#ifdef CONFIG_RTL_92D_SUPPORT + if ((GET_CHIP_VER(priv)==VERSION_8192D)) { + unsigned int mask = 0xB4FFFFFF, path=0x11; + if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_2G) { + mask = 0xDB3FFFFF; + path=0x22; + RTL_W8(0xa07, 0x45); + } + PHY_SetBBReg(priv, 0x85c, bMaskDWord, priv->pshare->rf_phy_bb_backup[1] & mask); + PHY_SetBBReg(priv, 0xe6c, bMaskDWord, priv->pshare->rf_phy_bb_backup[2] & mask); + + PHY_SetBBReg(priv, 0xe70, bMaskDWord, priv->pshare->rf_phy_bb_backup[3] & mask); + PHY_SetBBReg(priv, 0xe74, bMaskDWord, priv->pshare->rf_phy_bb_backup[4] & mask); + PHY_SetBBReg(priv, 0xe78, bMaskDWord, priv->pshare->rf_phy_bb_backup[5] & mask); + PHY_SetBBReg(priv, 0xe7c, bMaskDWord, priv->pshare->rf_phy_bb_backup[6] & mask); + + PHY_SetBBReg(priv, 0xe80, bMaskDWord, priv->pshare->rf_phy_bb_backup[7] & mask); + PHY_SetBBReg(priv, 0xe84, bMaskDWord, priv->pshare->rf_phy_bb_backup[8] & mask); + PHY_SetBBReg(priv, 0xe88, bMaskDWord, priv->pshare->rf_phy_bb_backup[9] & mask); + PHY_SetBBReg(priv, 0xe8c, bMaskDWord, priv->pshare->rf_phy_bb_backup[10] & mask); + + PHY_SetBBReg(priv, 0xed0, bMaskDWord, priv->pshare->rf_phy_bb_backup[11] & mask); + PHY_SetBBReg(priv, 0xed4, bMaskDWord, priv->pshare->rf_phy_bb_backup[12] & mask); + PHY_SetBBReg(priv, 0xed8, bMaskDWord, priv->pshare->rf_phy_bb_backup[13] & mask); + PHY_SetBBReg(priv, 0xedc, bMaskDWord, priv->pshare->rf_phy_bb_backup[14] & mask); + + PHY_SetBBReg(priv, 0xee0, bMaskDWord, priv->pshare->rf_phy_bb_backup[15] & mask); + PHY_SetBBReg(priv, 0xeec, bMaskDWord, priv->pshare->rf_phy_bb_backup[16] & mask); + + PHY_SetBBReg(priv, 0xc04, 0x000000ff, path); + PHY_SetBBReg(priv, 0xd04, 0x0000000f, path &0x01); + PHY_SetBBReg(priv, 0x90c, 0x000000ff, path); + PHY_SetBBReg(priv, 0x90c, 0x0ff00000, path); + + }else +#endif + { + PHY_SetBBReg(priv, 0x88c, 0x00c00000 , 0x3); + +#if 1 + // standby + PHY_SetBBReg(priv, 0x844, bMaskDWord, 0x00010000); +#else + // power off + PHY_SetBBReg(priv, 0x844, bMaskDWord, 0x00000000); +#endif + + PHY_SetBBReg(priv, 0x85c, bMaskDWord, 0x00db25a4); + PHY_SetBBReg(priv, 0xe6c, bMaskDWord, 0x20db25a4); + + PHY_SetBBReg(priv, 0xe70, bMaskDWord, 0x20db25a4); + PHY_SetBBReg(priv, 0xe74, bMaskDWord, 0x041b25a4); + PHY_SetBBReg(priv, 0xe78, bMaskDWord, 0x041b25a4); + PHY_SetBBReg(priv, 0xe7c, bMaskDWord, 0x041b25a4); + + PHY_SetBBReg(priv, 0xe80, bMaskDWord, 0x041b25a4); + PHY_SetBBReg(priv, 0xe84, bMaskDWord, 0x63db25a4); + PHY_SetBBReg(priv, 0xe88, bMaskDWord, 0x041b25a4); + PHY_SetBBReg(priv, 0xe8c, bMaskDWord, 0x20db25a4); + + PHY_SetBBReg(priv, 0xed0, bMaskDWord, 0x20db25a4); + PHY_SetBBReg(priv, 0xed4, bMaskDWord, 0x20db25a4); + PHY_SetBBReg(priv, 0xed8, bMaskDWord, 0x20db25a4); + PHY_SetBBReg(priv, 0xedc, bMaskDWord, 0x001b25a4); + + PHY_SetBBReg(priv, 0xee0, bMaskDWord, 0x001b25a4); + PHY_SetBBReg(priv, 0xeec, bMaskDWord, 0x24db25a4); + + PHY_SetBBReg(priv, 0xc04, 0x000000ff , 0x11); + PHY_SetBBReg(priv, 0xd04, 0x0000000f , 0x1); + PHY_SetBBReg(priv, 0x90c, 0x000000ff , 0x11); + PHY_SetBBReg(priv, 0x90c, 0x0ff00000 , 0x11); + + PHY_SetBBReg(priv, 0x804, 0x000000f , 0x1); + } + } else if(mode==OUT) { + +#ifdef CONFIG_RTL_92D_SUPPORT + if (!(GET_CHIP_VER(priv)==VERSION_8192D)) +#endif + { + PHY_SetBBReg(priv, 0x88c, bMaskDWord, priv->pshare->rf_phy_bb_backup[21]); + PHY_SetBBReg(priv, 0x844, bMaskDWord, priv->pshare->rf_phy_bb_backup[0]); + } + PHY_SetBBReg(priv, 0x85c, bMaskDWord, priv->pshare->rf_phy_bb_backup[1]); + PHY_SetBBReg(priv, 0xe6c, bMaskDWord, priv->pshare->rf_phy_bb_backup[2]); + + PHY_SetBBReg(priv, 0xe70, bMaskDWord, priv->pshare->rf_phy_bb_backup[3]); + PHY_SetBBReg(priv, 0xe74, bMaskDWord, priv->pshare->rf_phy_bb_backup[4]); + PHY_SetBBReg(priv, 0xe78, bMaskDWord, priv->pshare->rf_phy_bb_backup[5]); + PHY_SetBBReg(priv, 0xe7c, bMaskDWord, priv->pshare->rf_phy_bb_backup[6]); + + PHY_SetBBReg(priv, 0xe80, bMaskDWord, priv->pshare->rf_phy_bb_backup[7]); + PHY_SetBBReg(priv, 0xe84, bMaskDWord, priv->pshare->rf_phy_bb_backup[8]); + PHY_SetBBReg(priv, 0xe88, bMaskDWord, priv->pshare->rf_phy_bb_backup[9]); + PHY_SetBBReg(priv, 0xe8c, bMaskDWord, priv->pshare->rf_phy_bb_backup[10]); + + PHY_SetBBReg(priv, 0xed0, bMaskDWord, priv->pshare->rf_phy_bb_backup[11]); + PHY_SetBBReg(priv, 0xed4, bMaskDWord, priv->pshare->rf_phy_bb_backup[12]); + PHY_SetBBReg(priv, 0xed8, bMaskDWord, priv->pshare->rf_phy_bb_backup[13]); + PHY_SetBBReg(priv, 0xedc, bMaskDWord, priv->pshare->rf_phy_bb_backup[14]); + + PHY_SetBBReg(priv, 0xee0, bMaskDWord, priv->pshare->rf_phy_bb_backup[15]); + PHY_SetBBReg(priv, 0xeec, bMaskDWord, priv->pshare->rf_phy_bb_backup[16]); + + PHY_SetBBReg(priv, 0xc04, bMaskDWord , priv->pshare->rf_phy_bb_backup[17]); + PHY_SetBBReg(priv, 0xd04, bMaskDWord , priv->pshare->rf_phy_bb_backup[18]); + PHY_SetBBReg(priv, 0x90c, bMaskDWord , priv->pshare->rf_phy_bb_backup[19]); + PHY_SetBBReg(priv, 0xa04, bMaskDWord , priv->pshare->rf_phy_bb_backup[22]); + +#ifdef CONFIG_RTL_92D_SUPPORT + if (!(GET_CHIP_VER(priv)==VERSION_8192D)) +#endif + PHY_SetBBReg(priv, 0x804, bMaskDWord , priv->pshare->rf_phy_bb_backup[20]); + } +} + +#ifdef __LINUX_2_6__ +irqreturn_t +#else +void +#endif +gpio_wakeup_isr(int irq, void *dev_instance, struct pt_regs *regs); + +//const unsigned int CLK_MANAGE = 0xb8000010; +//const unsigned int SYS_PCIE_PHY0 =(0xb8000000 +0x50); +void PCIE_reset_procedure3(struct rtl8192cd_priv *priv) + +{ + + //PCIE Register + unsigned int PCIE_PHY0_REG, PCIE_PHY0, linkstatus, haddr; + int status=0, counter=0; + + if (GET_CHIP_VER(priv) == VERSION_8192D) + haddr = CFG_92D_SLOTH; + else + haddr = CFG_92C_SLOTH; + + PCIE_PHY0_REG = haddr + 0x1000; + PCIE_PHY0 = haddr + 0x1008; + linkstatus = haddr + 0x728; + + +#if 0 + REG32(CLK_MANAGE) &= ~(1<<12); //perst=0 off. + //dprintf("CLK_MANAGE=%x \n", REG32(CLK_MANAGE)); + delay_ms(3); + delay_ms(3); + + REG32(CLK_MANAGE) |= (1<<12); //PERST=1 + //prom_printf("\nCLK_MANAGE(0x%x)=0x%x\n\n",CLK_MANAGE,READ_MEM32(CLK_MANAGE)); + + //4. PCIE PHY Reset + REG32(PCIE_PHY0) = 0x01; //bit7 PHY reset=0 bit0 Enable LTSSM=1 + REG32(PCIE_PHY0) = 0x81; //bit7 PHY reset=1 bit0 + // + delay_ms(3); + +#else + do{ + //2.Active LX & PCIE Clock + REG32(CLK_MANAGE) &= (~(1<<11)); //enable active_pcie0 + delay_ms(2); + + //4. PCIE PHY Reset + REG32(PCIE_PHY0) = 0x1; //bit7 PHY reset=0 bit0 Enable LTSSM=1 + delay_ms(2); + + REG32(CLK_MANAGE) &= ~(1<<12); //perst=0 off. + delay_ms(5); + + REG32(PCIE_PHY0) = 0x81; //bit7 PHY reset=1 bit0 Enable LTSSM=1 + delay_ms(5); + + REG32(CLK_MANAGE) |= (1<<11); //enable active_pcie0 + + //--------------------------------------- + // 6. PCIE Device Reset + + delay_ms(5); + REG32(CLK_MANAGE) |= (1<<12); //PERST=1 + delay_ms(5); + status = REG32(linkstatus)&0x1f; + + if( status == 0x11 ) { + break; + }else { + delay_ms(100); +// printk("status=%x\n", status); + if( ++counter>1000) { +// panic_printk("PCIe reset fail!!!!\n"); + break; + } + } + }while(1); + + + +#endif + +// printk("PCIE_reset_procedure3\t devid=%x\n",REG32(0xb8b10000)); + +} + +#ifdef ASPM_ENABLE +void ASPM_on_off(struct rtl8192cd_priv *priv) +{ + unsigned long flags; + SAVE_INT_AND_CLI(flags); + unsigned int haddr, saddr; + if (GET_CHIP_VER(priv) == VERSION_8192D) { + haddr = CFG_92D_SLOTH; + saddr = CFG_92D_SLOTS; + } else { + haddr = CFG_92C_SLOTH; + saddr = CFG_92C_SLOTS; + } +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + + if(priv->pshare->rf_ft_var.power_save &ASPM_en) { + if(priv->pwr_state==L0) { + + REG32(haddr+ 0x70c) &= ~ ((0x7 <<27)|(0x7<<24)); + REG32(haddr+ 0x70c) |= ((3)<<27) | ((1)<<24); //L1=8us, L0s=2us + + REG32(haddr+ 0x80) &= ~(0x3); + REG32(saddr+ 0x80) &= ~(0x3); + REG32(haddr+ 0x80) |= 1; //L0s + REG32(saddr+ 0x80) |= 1; + + priv->pwr_state=ASPM_L0s_L1; + } + } else if(priv->pwr_state==ASPM_L0s_L1) { + REG32(haddr+ 0x80) &= ~(0x3); + REG32(saddr+ 0x80) &= ~(0x3); + priv->pwr_state=L0; + } + + RESTORE_INT(flags); +} +#endif + +#ifdef GPIO_WAKEPIN +int request_irq_for_wakeup_pin(struct net_device *dev) +{ +#ifdef NETDEV_NO_PRIV + struct rtl8192cd_priv *priv = ((struct rtl8192cd_priv *)netdev_priv(dev))->wlan_priv; +#else + struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)dev->priv; +#endif + unsigned int saddr; + + if (GET_CHIP_VER(priv) == VERSION_8192D) + saddr = CFG_92D_SLOTS; + else + saddr = CFG_92C_SLOTS; + +#ifdef CONFIG_RTL_8198 +// GPIO C4 + REG32(0xb8000044) |= BIT(24); //LEDPHASE4 + REG32(0xb8003500) &= ~(BIT(20)); //PABCD_CNR , gpio pin + REG32(0xb8003508) &= ~(BIT(20)); //PABCD_DIR + REG32(0xb8003518) &= (~(0x03 << 8)); + REG32(0xb8003518) |= (0x01 << 8); // PCD_IMR // enable interrupt in falling-edge + REG32(0xb8003000) |= BIT(16); // GIMR +#else +// GPIO B7 + REG32(0xb8000040) |= 0x0c00; //LEDPHASE1 :GPIOB7 + REG32(0xb8003500) &= ~(BIT(15));; //PABCD_CNR , gpio pin + REG32(0xb8003508) &= ~(BIT(15)); //PABCD_DIR + REG32(0xb8003514) &= (~(0x03 << 30)); + REG32(0xb8003514) |= (0x01 << 30); // PAB_IMR // enable interrupt in falling-edge + REG32(0xb8003000) |= BIT(9); // GIMR +#endif + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + + REG32(saddr+0x44) = 0x8108; // clear pme status + REG32(PABCD_ISR) = REG32(PABCD_ISR) ; // clear int status + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(0); +#endif + +#if defined(__LINUX_2_6__) + return request_irq(BSP_GPIO_ABCD_IRQ, gpio_wakeup_isr, IRQF_SHARED, "rtk_gpio", dev); +#else + return request_irq(1, gpio_wakeup_isr, SA_SHIRQ, "rtl_gpio", dev); +#endif +} +#endif + + +void init_pcie_power_saving(struct rtl8192cd_priv *priv) +{ + + unsigned int saddr; + if (GET_CHIP_VER(priv) == VERSION_8192D) + saddr = CFG_92D_SLOTS; + else + saddr = CFG_92C_SLOTS; + +// Jason : clk req +#if 0 + REG32(0xb9000354)=8; + REG32(0xb9000358)=0x30; +#endif + +#ifdef FIB_96C + if (REG32(SYSTEM_BASE ) == 0x80000001) { +#if defined(__LINUX_2_6__) +#else + extern void HostPCIe_SetPhyMdioWrite(unsigned int , unsigned int , unsigned short ); +#endif + HostPCIe_SetPhyMdioWrite(0, 8, 0x18d5); // 18dd -> 18d5 + HostPCIe_SetPhyMdioWrite(0, 0xd, 0x15a6); // 15b6 -> 15a6 + } +#endif + +// Jason , for ASPM read_reg + if ((GET_CHIP_VER(priv) == VERSION_8192C) || (GET_CHIP_VER(priv) == VERSION_8188C)) { + RTL_W16(0x354, 0x18e); + RTL_W16(0x358, 0x23); + + if ((GET_CHIP_VER(priv) == VERSION_8188C) ) { + RTL_W16(0x354, 0x20eb); + RTL_W16(0x358, 0x3d); + } + } + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + + REG32(saddr+ 0x80)|= 0x0100; + REG32(saddr+ 0x80)|= 0x43; + REG32(saddr+ 0x0778)|= BIT(5)<<8; + +#ifdef CONFIG_RTL_92C_SUPPORT + +// 92c backdoor + if ((GET_CHIP_VER(priv) == VERSION_8188C) || (GET_CHIP_VER(priv) == VERSION_8192C)) { + REG32(saddr+ 0x70c)|= BIT(7)<<24; + REG32(saddr+ 0x718)|= (BIT(3) | BIT(4))<<8; +// dprintf("70f=%x,719=%x\n", REG32(0xb8b1070f), REG32(0xb8b10719) ); + } +#endif + + RTL_W8(0x690, 0x2); // WoW + RTL_W8(0x302, 0x2); // sw L123 + RTL_W8(0x5, 0x0); // AFSM_PCIE + RTL_W16(PCIE_CTRL_REG, 0xff ); + +// RTL_W16(0x558, 0x040a); +// RTL_W16(0x100 , RTL_R16(0x100) | BIT(8)); // enable sw beacon + + if (IS_TEST_CHIP(priv)) { + priv->pshare->rf_ft_var.power_save &= (~ L2_en); + priv->pshare->rf_ft_var.power_save &= (~ASPM_en); + } else { + RTL_W8(0x08, RTL_R8(0x08) | BIT(3)); // WAKEPAN_EN + if(IS_UMC_A_CUT_88C(priv)) + priv->pshare->rf_ft_var.power_save &= (~ASPM_en); + + } +#ifdef ASPM_ENABLE + ASPM_on_off(priv); +#endif + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(0); +#endif + +} + + +int isPSConditionMatch(struct rtl8192cd_priv *priv) +{ + +// temporary disable Active ECO when 1 interfcae is disabled +#ifdef CONFIG_RTL_92D_DMDP + if( (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) && + (!IS_DRV_OPEN(((struct rtl8192cd_priv *)if_priv[1&(priv->pshare->wlandev_idx^1)])))) + return 0; +#endif + + if(!IS_DRV_OPEN(priv)) + return 1; + + if( (priv->assoc_num==0) + && (priv->pshare->rf_ft_var.power_save & (L1_en|L2_en)) +#ifdef MBSSID + && (!priv->pmib->miscEntry.vap_enable) +#endif +#ifdef WDS + && (!priv->pmib->dot11WdsInfo.wdsEnabled) +#endif +#ifdef UNIVERSAL_REPEATER + && (!IS_DRV_OPEN(GET_VXD_PRIV(priv))) +#endif +#ifdef CLIENT_MODE + && !((OPMODE & WIFI_STATION_STATE) ||(OPMODE & WIFI_ADHOC_STATE)) +#endif + ) + return 1; + else + return 0; + +} + +void PCIe_power_save_timer(unsigned long task_priv) +{ + struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv; + char force; + force = priv->ps_ctrl & 0x80; + priv->ps_ctrl &= 0x7f; + +#ifdef MP_TEST + if (priv->pshare->rf_ft_var.mp_specific) + return ; +#endif + + if(!IS_DRV_OPEN(priv)) + return; + + if(force==0) { +#ifdef CONFIG_RTL_92D_DMDP + if(isPSConditionMatch((struct rtl8192cd_priv *)if_priv[0]) && isPSConditionMatch((struct rtl8192cd_priv *)if_priv[1])) +#else + if(isPSConditionMatch(priv)) +#endif + { + if(priv->pwr_state !=L1 && priv->pwr_state !=L2) + { + if((priv->offload_ctrl>>7)&&(priv->offload_ctrl&1)==0) { + if (priv->pshare->rf_ft_var.power_save & L2_en) + priv->ps_ctrl = 0x21; + else + priv->ps_ctrl = 0x11; +#ifdef CONFIG_RTL_92D_DMDP + if((priv->pshare->wlandev_idx ==1) && + (!IS_DRV_OPEN(((struct rtl8192cd_priv *)if_priv[0]))) ) { + ((struct rtl8192cd_priv *)if_priv[0])->ps_ctrl = priv->ps_ctrl; + tasklet_schedule(&((struct rtl8192cd_priv *)if_priv[0])->pshare->ps_tasklet); + } else + if((priv->pshare->wlandev_idx ==0) && + ((!IS_DRV_OPEN(((struct rtl8192cd_priv *)if_priv[1]))) || (((struct rtl8192cd_priv *)if_priv[1])->offload_ctrl>>7))) +#endif + tasklet_schedule(&priv->pshare->ps_tasklet); + } else { + priv->offload_ctrl = 1; + RTL_W16(0x100 , RTL_R16(0x100) | BIT(8)); // enable sw beacon + mod_timer(&priv->ps_timer, jiffies + RTL_SECONDS_TO_JIFFIES(1)); + return; + } + } + }else { + priv->offload_ctrl = 0; + } + + }else { + if(priv->pwr_state == L0) + tasklet_schedule(&priv->pshare->ps_tasklet); + } + mod_timer(&priv->ps_timer, jiffies + POWER_DOWN_T0); + +#ifdef ASPM_ENABLE + ASPM_on_off(priv); +#endif + +} + +void setBaseAddressRegister(void) +{ + int tmp32=0, status; + while(++tmp32 < 100) { + REG32(0xb8b00004) = 0x00100007; + REG32(0xb8b10004) = 0x00100007; + REG32(0xb8b10010) = 0x18c00001; + REG32(0xb8b10018) = 0x19000004; + status = (REG32(0xb8b10010) ^ 0x18c00001) |( REG32(0xb8b10018) ^ 0x19000004); + if(!status) + break; + else { + printk("set BAR fail,%x\n", status); + printk("%x %x %x %x \n", + REG32(0xb8b00004) , REG32(0xb8b10004) ,REG32(0xb8b10010), REG32(0xb8b10018) ); + } + } ; +} + +void PCIe_power_save_tasklet(unsigned long task_priv) +{ + struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv; + char in_out, L1_L2; + unsigned int tmp32=0,status=0,portnum=0, page=0, ctr; + unsigned long flags; + + + unsigned int saddr, haddr; + if (GET_CHIP_VER(priv) == VERSION_8192D) { + saddr = CFG_92D_SLOTS; + haddr = CFG_92D_SLOTH; + + } else { + saddr = CFG_92C_SLOTS; + haddr = CFG_92C_SLOTH; + } + +#if defined(CONFIG_RTL_92D_SUPPORT) + portnum = RTL_USED_PCIE_SLOT; +#endif + + priv->ps_ctrl &= 0x7f; + in_out = priv->ps_ctrl & 0xf; + L1_L2 = (priv->ps_ctrl>>4) & 0x7; + +#if defined(CONFIG_RTL_92D_DMDP) + if((in_out== IN) && (priv->pshare->wlandev_idx ==0) && (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY)) { + struct rtl8192cd_priv *priv1 = ((struct rtl8192cd_priv *)if_priv[1]); + priv1->ps_ctrl = priv->ps_ctrl; + PCIe_power_save_tasklet((unsigned long )priv1); + } +#endif + + DEBUG_INFO("%s, %s, L%d\n", __FUNCTION__, (in_out==IN ? "in" : "out") , L1_L2); + + if( in_out == IN) { + SAVE_INT_AND_CLI(flags); + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); + + if(!IS_DRV_OPEN(priv)) { +#ifdef ASPM_ENABLE + if( priv->pwr_state==ASPM_L0s_L1) { + REG32(haddr+0x80) &= ~(0x3); + REG32(saddr+0x80) &= ~(0x3); + } +#endif + RTL_W8(0x302, 0x2); // sw L123 + RTL_W16(PCIE_CTRL_REG, 0xff00 ); + REG32(saddr+0x44) |= 0x8108; + + if (L1_L2 == L1) { + priv->pwr_state = L1; + } else { + RTL_W8(RSV_CTRL0, 0xe1); // reg lock, dis_prst + RTL_W8(RSV_CTRL0, 0xe1); + priv->pwr_state = L2; + } + RESTORE_INT(flags); + return; + } +#endif + RTL_W8(0x286, 4); + +#ifdef ASPM_ENABLE + if( priv->pwr_state==ASPM_L0s_L1) { + REG32(haddr+0x80) &= ~(0x3); + REG32(saddr+0x80) &= ~(0x3); + } +#endif + +// RTL_W8(0x286, 4); + RTL_W8(0x302, 0x2); // sw L123 + REG32(saddr+0x44) |= 0x8108; // clear pme status + + RTL_W16(0x4dc, priv->pshare->phw->seq); + RTL_W8(0x423, 0x7f); // mac seq + + if(priv->pshare->rf_ft_var.power_save&stop_dma_en) { + RTL_W16(PCIE_CTRL_REG, 0xff00 ); + delay_ms(1); + } +#ifdef PCIE_L2_ENABLE + if (L1_L2 == L2) { + int tx_head, tx_tail, q_num; + struct tx_desc *phdesc, *pdesc; + for(q_num=MGNT_QUEUE; q_num<BEACON_QUEUE; q_num++) { + tx_head = get_txhead(GET_HW(priv), q_num); + tx_tail = get_txtail(GET_HW(priv), q_num); + phdesc = get_txdesc(GET_HW(priv), q_num); + while (tx_tail != tx_head) { + pdesc = phdesc + (tx_tail); + pdesc->Dword0 &= set_desc(~TX_OWN); + tx_tail = (tx_tail + 1) % NUM_TX_DESC; + } + } +#ifdef SMP_SYNC + if (!priv->pshare->has_triggered_tx_tasklet) { + tasklet_schedule(&priv->pshare->tx_tasklet); + priv->pshare->has_triggered_tx_tasklet = 1; + } +#else + rtl8192cd_tx_dsr((unsigned long)priv); +#endif + rtl8192cd_rx_isr(priv); + } +#endif + if ((get_rf_mimo_mode(priv) == MIMO_2T2R) && (priv->pshare->rf_ft_var.power_save&_1x1_en)) + switch_to_1x1(priv, IN); + + page = ((priv->offload_ctrl)>>7)&0xff; + if(priv->pshare->rf_ft_var.power_save&offload_en) { + + if(GET_CHIP_VER(priv) != VERSION_8192D) + status |= signin_h2c_cmd(priv, _RSVDPAGE_CMD_ | page<<8, 0); + else + status |= signin_h2c_cmd(priv, _RSVDPAGE_CMD_ | BIT(7) | (page<<8), (page<<8)| (page) ); + + status |= signin_h2c_cmd(priv, _AP_OFFLOAD_CMD_ | (1<<8) |(HIDDEN_AP<<16) | ((GET_MIB(priv))->dot11OperationEntry.deny_any)<<24, 0 ); + DEBUG_INFO("%s, LINE:%d, h2c %x, %x, %x\n", __FUNCTION__, __LINE__, + (_RSVDPAGE_CMD_ | page<<8), (_RSVDPAGE_CMD_ | BIT(7) | (page<<8), (page<<8)| (page)), + (_AP_OFFLOAD_CMD_ | (1<<8) |(HIDDEN_AP<<16) | ((GET_MIB(priv))->dot11OperationEntry.deny_any)<<24) + ); + ctr=3000; + do { + delay_us(10); + page = RTL_R8(0x286) ; + if(page & 4) + break; + } while(ctr--); + if(status || !(page&4)) { + DEBUG_INFO("signin_h2c_cmd fail(ap offload), 286=%x\n", page); + if ((get_rf_mimo_mode(priv) == MIMO_2T2R) && (priv->pshare->rf_ft_var.power_save&_1x1_en)) + switch_to_1x1(priv, OUT); + RTL_W16(PCIE_CTRL_REG, 0xff); + RTL_W8(0x423, 0x0); // mac seq disable + RTL_W8(0x286, 0); + RESTORE_INT(flags); + return; + } + } + + if( L1_L2 == L1){ + +#ifdef CONFIG_RTL_92D_DMDP + if((priv->pshare->wlandev_idx) && (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) + && IS_DRV_OPEN(((struct rtl8192cd_priv *)if_priv[0]))) { + RESTORE_INT(flags); + return ; + } + Sw_PCIE_Func2(1); + tmp32 = REG32(saddr+0x44) &( ~(3)); + REG32(saddr+0x44) = tmp32| (3); //D3 + + if(!priv->pshare->wlandev_idx) + ((struct rtl8192cd_priv *)if_priv[1])->pwr_state = L1; + Sw_PCIE_Func2(0); + delay_ms(1); +#endif + priv->pwr_state = L1; + + tmp32= REG32(saddr+0x44) &( ~(3)); //D0 + REG32(saddr+0x44) = tmp32| (3); //D3 + //HostPCIe_SetPhyMdioWrite(0xd, 0x15a6); + printk("D3 hot -> L1\n"); + delay_ms(1); +#if 0 //saving more power + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0708); +#endif + } + RESTORE_INT(flags); + + +#ifdef PCIE_L2_ENABLE + if( L1_L2 == L2) { +#if 0 //saving more power leave L1 write + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0f0f); +#endif + RTL_W8(RSV_CTRL0, 0xe1); // reg lock, dis_prst + RTL_W8(RSV_CTRL0, 0xe1); + priv->pwr_state = L2; +#ifdef CONFIG_RTL_92D_DMDP + if(!priv->pshare->wlandev_idx) +#endif + REG32(haddr+0x1008) |= (0x200); + printk("PME turn off -> L2\n"); + } +#endif +#ifdef CONFIG_RTL_8198 + REG32(0xb8003000) |= BIT(16); // GIMR +#else + REG32(0xb8003000) |= BIT(9); // GIMR +#endif + } + else if(in_out==OUT) { +#ifdef PCIE_L2_ENABLE + if( L1_L2 == L2){ + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); + if(!priv->pshare->wlandev_idx ) +#endif + PCIE_reset_procedure3(priv); + setBaseAddressRegister(); + + SAVE_INT_AND_CLI(flags); + priv->pwr_state = L0; +#ifdef CONFIG_RTL_92D_DMDP + ((struct rtl8192cd_priv *)if_priv[1])->pwr_state = L0; +#endif + RTL_W8(RSV_CTRL0, 0x0); + tmp32 = 0; + while(1) { + if( !(RTL_R8(SPS0_CTRL) & BIT(3)) || (++tmp32 > 20) ) { + RTL_W8(SPS0_CTRL, 0x2b); + break; + } + } + DEBUG_INFO("SPS0_CTRL=%d !!\n", RTL_R8(SPS0_CTRL)); + } else +#endif + { + + SAVE_INT_AND_CLI(flags); + if( priv->pwr_state == L1) { + +#ifdef CONFIG_RTL_92D_DMDP + for(page=0; page<2; page++) { + Sw_PCIE_Func2(page); +#endif + ctr=3000; +#if 0 //saving more power, leave L1 write + HostPCIe_SetPhyMdioWrite(portnum, 0xf, 0x0f0f); +#endif + tmp32 = REG32(saddr+0x44) &( ~(3)); //D0 + do { + REG32(saddr+0x44) = tmp32| (0); //D0 + delay_us(1); + REG32(saddr+0x44) = tmp32| (0); //D0 + status = REG32(haddr+0x728)&0x1f; + if(status == 0x11) + break; + } while(ctr--); + + if(status != 0x11) + panic_printk("change to L0 fail!!!, status=%x, MAC0\n", status); + else +#ifdef CONFIG_RTL_92D_DMDP + ((struct rtl8192cd_priv *)if_priv[page])->pwr_state = L0; + } +#else + priv->pwr_state = L0; +#endif + } + } + + +#ifdef CONFIG_RTL_92D_DMDP + if((priv->pshare->wlandev_idx ==0) && (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY) && !IS_DRV_OPEN(priv) ) { + goto OEPN_MAC1; + } +#endif + + if(priv->pshare->rf_ft_var.power_save&offload_en) { + signin_h2c_cmd(priv, _AP_OFFLOAD_CMD_ , 0 ); // offload + delay_ms(1); + } + + if ((get_rf_mimo_mode(priv) == MIMO_2T2R) &&(priv->pshare->rf_ft_var.power_save&_1x1_en)) + switch_to_1x1(priv, OUT); +#ifdef PCIE_L2_ENABLE + if( L1_L2 == L2) { + priv->pshare->phw->cur_rx =0; +#ifdef DELAY_REFILL_RX_BUF + priv->pshare->phw->cur_rx_refill =0; +#endif + memset(&(priv->pshare->phw->txhead0), 0, sizeof(int)*12); + RTL_W32(BCNQ_DESA, priv->pshare->phw->tx_ringB_addr); + RTL_W32(MGQ_DESA, priv->pshare->phw->tx_ring0_addr); + RTL_W32(VOQ_DESA, priv->pshare->phw->tx_ring4_addr); + RTL_W32(VIQ_DESA, priv->pshare->phw->tx_ring3_addr); + RTL_W32(BEQ_DESA, priv->pshare->phw->tx_ring2_addr); + RTL_W32(BKQ_DESA, priv->pshare->phw->tx_ring1_addr); + RTL_W32(HQ_DESA, priv->pshare->phw->tx_ring5_addr); + RTL_W32(RX_DESA, priv->pshare->phw->ring_dma_addr); + } +#endif + if(priv->pshare->rf_ft_var.power_save&stop_dma_en) { + RTL_W16(PCIE_CTRL_REG, 0xff); + } + + // wait until FW stop parsing packet + ctr = 1000; + do { + if(!(RTL_R8(FWIMR) & FWIMR_RXDONE)) + break; + delay_us(100); + } while(ctr--) ; + if(!ctr) + DEBUG_ERR("stop offload fail\n"); + + RTL_W8(0x423, 0x0); // mac seq disable + RTL_W8(0x286, 0); // RW_RELEASE_ENABLE + RTL_W8(0x302, 0x3); // sw L123 + +#ifdef CONFIG_RTL_92D_DMDP + if((priv->pshare->wlandev_idx ==0) && (priv->pmib->dot11RFEntry.macPhyMode == DUALMAC_DUALPHY)) { + struct rtl8192cd_priv *priv1; +OEPN_MAC1: + priv1 = ((struct rtl8192cd_priv *)if_priv[1]); + if(IS_DRV_OPEN(priv1) ) { + priv1->ps_ctrl = priv->ps_ctrl; + PCIe_power_save_tasklet((unsigned long )priv1); + } + } +#endif + +#if defined(RX_TASKLET) + if(IS_DRV_OPEN(priv)) { + tasklet_hi_schedule(&priv->pshare->rx_tasklet); + } +#endif + +#ifdef ASPM_ENABLE + ASPM_on_off(priv); +#endif + RESTORE_INT(flags); + } +} + + +void PCIeWakeUp(struct rtl8192cd_priv *priv, unsigned int expTime) +{ + unsigned long flags; + SAVE_INT_AND_CLI(flags); + + if( (priv->pwr_state == L1) || (priv->pwr_state == L2)) { + + if (timer_pending(&priv->ps_timer)) + del_timer_sync(&priv->ps_timer); + +#ifdef CONFIG_RTL_92D_DMDP + if(priv->pshare->wlandev_idx ==1) { + struct rtl8192cd_priv *priv0= ((struct rtl8192cd_priv *)if_priv[0]); + PCIeWakeUp(priv0, expTime); + } else +#endif + { + priv->ps_ctrl = 0x82 | (priv->pwr_state<<4); + PCIe_power_save_tasklet((unsigned long)priv); + } + + mod_timer(&priv->ps_timer, jiffies + expTime); + priv->offload_ctrl =0; + } + RESTORE_INT(flags); +} + +#ifdef __LINUX_2_6__ +irqreturn_t +#else +void +#endif +gpio_wakeup_isr(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = NULL; + struct rtl8192cd_priv *priv = NULL; + + unsigned int saddr; + if (GET_CHIP_VER(priv) == VERSION_8192D) { + saddr = CFG_92D_SLOTS; + } else { + saddr = CFG_92C_SLOTS; + } + + dev = (struct net_device *)dev_instance; + priv = (struct rtl8192cd_priv *)dev->priv; + +#ifdef CONFIG_RTL_92D_DMDP + Sw_PCIE_Func2(priv->pshare->wlandev_idx); +#endif + + DEBUG_INFO("%s, PABCD_ISR=%x\t", dev->name, REG32(PABCD_ISR)); + REG32(PABCD_ISR) = REG32(PABCD_ISR) ; + DEBUG_INFO("\nPABCD_ISR=%x,0xb8100044=%x\n", REG32(PABCD_ISR), REG32(saddr+0x44)); + +#ifdef GPIO_WAKEPIN +#ifdef PCIE_POWER_SAVING_DEBUG + priv->firstPkt = 1; +#endif + if (timer_pending(&priv->ps_timer)) + del_timer_sync(&priv->ps_timer); + + if( priv->pwr_state == L1 || priv->pwr_state == L2) { + priv->ps_ctrl = 0x82 | (priv->pwr_state<<4); + PCIe_power_save_tasklet((unsigned long)priv); + } + + priv->offload_ctrl =0; + mod_timer(&priv->ps_timer, jiffies + (POWER_DOWN_T0)); + +#endif +#ifdef __LINUX_2_6__ + return IRQ_HANDLED; +#endif +} + + +void radio_off(struct rtl8192cd_priv *priv) +{ +#if 0 + extern void HostPCIe_Close(void); + printk("Radio Off======>\n"); + HostPCIe_Close(); +#endif +} +#endif + + +#ifdef EN_EFUSE +/*----------------------------------------------------------------------------- + * Function: efuse_PowerSwitch + * + * Overview: When we want to enable write operation, we should change to + * pwr on state. When we stop write, we should switch to 500k mode + * and disable LDO 2.5V. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/17/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void efuse_PowerSwitch(struct rtl8192cd_priv *priv, unsigned char PwrState) +{ + unsigned char tempval; + short tmpV16; + if (PwrState == TRUE) { + // 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid + tmpV16 = RTL_R16(SYS_ISO_CTRL); + if (!(tmpV16 & PWC_EV12V)) { + tmpV16 |= PWC_EV12V; + RTL_W16(SYS_ISO_CTRL, tmpV16); + } + // Reset: 0x0000h[28], default valid + tmpV16 = RTL_R16(REG_SYS_FUNC_EN); + if (!(tmpV16 & FEN_ELDR)) { + tmpV16 |= FEN_ELDR; + RTL_W16(REG_SYS_FUNC_EN, tmpV16); + } + // Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid + tmpV16 = RTL_R16(SYS_CLKR); + if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { + tmpV16 |= (LOADER_CLK_EN |ANA8M); + RTL_W16(SYS_CLKR, tmpV16); + } + // Enable LDO 2.5V before read/write action + tempval = RTL_R8(EFUSE_TEST+3); + RTL_W8(EFUSE_TEST+3, (tempval | 0x80)); + } else { + // Disable LDO 2.5V after read/write action + tempval = RTL_R8(EFUSE_TEST+3); + RTL_W8(EFUSE_TEST+3, (tempval & 0x7F)); + } +} /* efuse_PowerSwitch */ + + +static void ReadEFuseByte(struct rtl8192cd_priv *priv, unsigned short _offset, unsigned char *pbuf) +{ + unsigned int value32; + unsigned char readbyte; + unsigned short retry; + + //Write Address + RTL_W8(EFUSE_CTRL+1, (_offset & 0xff)); + readbyte = RTL_R8(EFUSE_CTRL+2); + RTL_W8(EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + //Write bit 32 0 + readbyte = RTL_R8(EFUSE_CTRL+3); + RTL_W8(EFUSE_CTRL+3, 0x72); //read cmd + //RTL_W8(EFUSE_CTRL+3, (readbyte & 0x7f)); + + //Check bit 32 read-ready + retry = 0; + value32 = RTL_R32(EFUSE_CTRL); + + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) { + value32 = RTL_R32(EFUSE_CTRL); + retry++; + } + *pbuf = (unsigned char)(value32 & 0xff); +} /* ReadEFuseByte */ + + +// +// Description: +// 1. Execute E-Fuse read byte operation according as map offset and +// save to E-Fuse table. +// 2. Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and successfully auto-load. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. +// 2. Add efuse utilization collect. +// 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 +// write addr must be after sec5. +// +static void ReadEFuse(struct rtl8192cd_priv *priv, unsigned short _offset, int _size_byte, unsigned char *pbuf) +{ + unsigned char efuseTbl[EFUSE_MAP_LEN]; + unsigned char rtemp8[1]; + unsigned short eFuse_Addr = 0; + unsigned char offset, wren, u1temp; + unsigned short i, j; + unsigned short eFuseWord[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; + unsigned short efuse_utilized = 0; + + // + // Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. + // + if ((_offset + _size_byte) > EFUSE_MAP_LEN) + {// total E-Fuse table is 128bytes + DEBUG_INFO("ReadEFuse(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte); + return; + } + + // 0. Refresh efuse init map as all oxFF. + for (i = 0; i < EFUSE_MAX_SECTION; i++) + for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) + eFuseWord[i][j] = 0xFFFF; + + // + // 1. Read the first byte to check if efuse is empty!!! + // + // + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + if (*rtemp8 != 0xFF) { + efuse_utilized++; + DEBUG_INFO("ReadEFuse, Addr=%x, %02x\n", eFuse_Addr, *rtemp8); + eFuse_Addr++; + } else { + //RTPRINT(FEEPROM, EFUSE_READ_ALL, ("EFUSE is empty efuse_Addr-%d efuse_data=%x\n", eFuse_Addr, *rtemp8)); + return; + } + + // + // 2. Read real efuse content. Filter PG header and every section data. + // + while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN)) + { + +#ifdef CONFIG_RTL_92D_SUPPORT + // Check PG header for section num. + if ((GET_CHIP_VER(priv) == VERSION_8192D) && (*rtemp8 & 0x1F) == 0x0F) //extended header + { + u1temp = ((*rtemp8 & 0xE0) >> 5); + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + if ((*rtemp8 & 0x0F) == 0x0F) { + eFuse_Addr++; + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN)) { + eFuse_Addr++; + } + continue; + } else { + offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; + wren = (*rtemp8 & 0x0F); + eFuse_Addr++; + } + } + else +#endif + { + offset = ((*rtemp8 >> 4) & 0x0f); + wren = (*rtemp8 & 0x0f); + } + + if (offset < EFUSE_MAX_SECTION) { + for (i=0; i<EFUSE_MAX_WORD_UNIT; i++) { + // Check word enable condition in the section + if (!(wren & 0x01)) { + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + DEBUG_INFO("ReadEFuse, Addr=%x, %02x\n", eFuse_Addr, *rtemp8); + eFuse_Addr++; + efuse_utilized++; + eFuseWord[offset][i] = (*rtemp8 & 0xff); + if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN) + break; + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + DEBUG_INFO("ReadEFuse, Addr=%x, %02x\n", eFuse_Addr, *rtemp8); + eFuse_Addr++; + efuse_utilized++; + eFuseWord[offset][i] |= (((UINT16)*rtemp8 << 8) & 0xff00); + if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN) + break; + } + wren >>= 1; + } + } + + // Read next PG header + ReadEFuseByte(priv, eFuse_Addr, rtemp8); + if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN)) { + efuse_utilized++; + DEBUG_INFO("ReadEFuse, Addr=%x, %02x\n", eFuse_Addr, *rtemp8); + eFuse_Addr++; + } + } + + // + // 3. Collect 16 sections and 4 word unit into Efuse map. + // + for (i=0; i<EFUSE_MAX_SECTION; i++) { + for (j=0; j<EFUSE_MAX_WORD_UNIT; j++) { + efuseTbl[(i<<3)+(j<<1)] = (eFuseWord[i][j] & 0xff); + efuseTbl[(i<<3)+(j<<1)+1] = ((eFuseWord[i][j] >> 8) & 0xff); + } + } + + // + // 4. Copy from Efuse map to output pointer memory!!! + // + for (i=0; i<_size_byte; i++) { + pbuf[i] = efuseTbl[_offset+i]; + } + + // + // 5. Calculate Efuse utilization. + // + //efuse_usage = (unsigned char)((efuse_utilized*100)/EFUSE_REAL_CONTENT_LEN); + priv->EfuseUsedBytes = efuse_utilized; + +} + + +/*----------------------------------------------------------------------------- + * Function: efuse_ReadAllMap + * + * Overview: Read All Efuse content + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/11/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void efuse_ReadAllMap(struct rtl8192cd_priv *priv, unsigned char *Efuse) +{ + // + // We must enable clock and LDO 2.5V otherwise, read all map will be fail!!!! + // + efuse_PowerSwitch(priv, TRUE); + ReadEFuse(priv, 0, EFUSE_MAP_LEN, Efuse); + efuse_PowerSwitch(priv, FALSE); +} + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowMapUpdate + * + * Overview: Transfer current EFUSE content to shadow init and modify map. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/13/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void EFUSE_ShadowMapUpdate(struct rtl8192cd_priv *priv) +{ +/* + if (priv->AutoloadFailFlag == TRUE ) { + DEBUG_INFO("AutoloadFailFlag=TRUE"); + memset((&priv->EfuseMap[EFUSE_INIT_MAP][0]), 0xFF, 128); + } else +*/ + { + efuse_ReadAllMap(priv, &priv->EfuseMap[EFUSE_INIT_MAP][0]); + } + + memcpy(&priv->EfuseMap[EFUSE_MODIFY_MAP][0], + &priv->EfuseMap[EFUSE_INIT_MAP][0], EFUSE_MAP_LEN); + +} + + +static int isPGValueValid(struct rtl8192cd_priv *priv, unsigned char *hwinfo) +{ + int j; +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + for (j=EEPROM_TxPowerCCK; j<EEPROM_TxPowerCCK+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + for (j=EEPROM_TxPowerHT40_1S; j<EEPROM_TxPowerHT40_1S+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + } +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D){ + for (j=EEPROM_2G_TxPowerCCK; j<EEPROM_2G_TxPowerCCK+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + for (j=EEPROM_2G_TxPowerHT40_1S; j<EEPROM_2G_TxPowerHT40_1S+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + for (j=EEPROM_5GL_TxPowerHT40_1S; j<EEPROM_5GL_TxPowerHT40_1S+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + for (j=EEPROM_5GM_TxPowerHT40_1S; j<EEPROM_5GM_TxPowerHT40_1S+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + for (j=EEPROM_5GH_TxPowerHT40_1S; j<EEPROM_5GH_TxPowerHT40_1S+3; j++) { + if (hwinfo[j] > 63) + return 0; + } + } +#endif + return 1; +} + + +void ReadTxPowerInfoFromHWPG(struct rtl8192cd_priv *priv) +{ + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + int i; + + if (!isPGValueValid(priv, hwinfo)) + return; + + if (/*priv->AutoloadFailFlag==FALSE &&*/ priv->pmib->efuseEntry.enable_efuse==1) { + u8 TxPwrCCK=0, TxPwrHT40_1S=0, TxPwrHT40_2SDiff=0, TxPwrHT20Diff=0, TxPwrOFDMDiff=0; +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv)!=VERSION_8192D){ + TxPwrCCK = EEPROM_TxPowerCCK; + TxPwrHT40_1S = EEPROM_TxPowerHT40_1S; + TxPwrHT40_2SDiff = EEPROM_TxPowerHT40_2SDiff; + TxPwrHT20Diff = EEPROM_TxPowerHT20Diff; + TxPwrOFDMDiff = EEPROM_TxPowerOFDMDiff; + } +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + // 2.4G Setting + TxPwrCCK = EEPROM_2G_TxPowerCCK; + TxPwrHT40_1S = EEPROM_2G_TxPowerHT40_1S; + TxPwrHT40_2SDiff = EEPROM_2G_TxPowerHT40_2SDiff; + TxPwrHT20Diff = EEPROM_2G_TxPowerHT20Diff; + TxPwrOFDMDiff = EEPROM_2G_TxPowerOFDMDiff; + + // 5G Setting + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S+3]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GL_TxPowerHT20Diff]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GL_TxPowerOFDMDiff]; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S+1]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S+4]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GL_TxPowerHT20Diff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GL_TxPowerOFDMDiff+1]; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S+2]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GL_TxPowerHT40_1S+5]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GL_TxPowerHT20Diff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GL_TxPowerOFDMDiff+2]; + } else { + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = 0; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = 0; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= 0; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = 0; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = 0; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S+3]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GM_TxPowerHT20Diff]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GM_TxPowerOFDMDiff]; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S+1]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S+4]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GM_TxPowerHT20Diff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GM_TxPowerOFDMDiff+1]; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S+2]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GM_TxPowerHT40_1S+5]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GM_TxPowerHT20Diff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GM_TxPowerOFDMDiff+2]; + } else { + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = 0; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = 0; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= 0; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = 0; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = 0; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S+3]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GH_TxPowerHT20Diff]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GH_TxPowerOFDMDiff]; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S+1]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S+4]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GH_TxPowerHT20Diff+1]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GH_TxPowerOFDMDiff+1]; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S+2]; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = hwinfo[EEPROM_5GH_TxPowerHT40_1S+5]; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = hwinfo[EEPROM_5GH_TxPowerHT20Diff+2]; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = hwinfo[EEPROM_5GH_TxPowerOFDMDiff+2]; + } else { + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = 0; + priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = 0; + + priv->pmib->dot11RFEntry.pwrdiff5GHT40_2S[i]= 0; + priv->pmib->dot11RFEntry.pwrdiff5GHT20[i] = 0; + priv->pmib->dot11RFEntry.pwrdiff5GOFDM[i] = 0; + } + } + } + } +#endif + + for (i=0; i<MAX_2G_CHANNEL_NUM; i++) { + if (i < 3) { + priv->pmib->dot11RFEntry.pwrlevelCCK_A[i]= hwinfo[TxPwrCCK]; + priv->pmib->dot11RFEntry.pwrlevelCCK_B[i]= hwinfo[TxPwrCCK+3]; + + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] = hwinfo[TxPwrHT40_1S]; + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] = hwinfo[TxPwrHT40_1S+3]; + + priv->pmib->dot11RFEntry.pwrdiffHT40_2S[i]= hwinfo[TxPwrHT40_2SDiff]; + priv->pmib->dot11RFEntry.pwrdiffHT20[i] = hwinfo[TxPwrHT20Diff]; + priv->pmib->dot11RFEntry.pwrdiffOFDM[i] = hwinfo[TxPwrOFDMDiff]; + + } else if (i < 9) { + priv->pmib->dot11RFEntry.pwrlevelCCK_A[i]= hwinfo[TxPwrCCK+1]; + priv->pmib->dot11RFEntry.pwrlevelCCK_B[i]= hwinfo[TxPwrCCK+4]; + + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] = hwinfo[TxPwrHT40_1S+1]; + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] = hwinfo[TxPwrHT40_1S+4]; + + priv->pmib->dot11RFEntry.pwrdiffHT40_2S[i]= hwinfo[TxPwrHT40_2SDiff+1]; + priv->pmib->dot11RFEntry.pwrdiffHT20[i] = hwinfo[TxPwrHT20Diff+1]; + priv->pmib->dot11RFEntry.pwrdiffOFDM[i] = hwinfo[TxPwrOFDMDiff+1]; + } else { + priv->pmib->dot11RFEntry.pwrlevelCCK_A[i]= hwinfo[TxPwrCCK+2]; + priv->pmib->dot11RFEntry.pwrlevelCCK_B[i]= hwinfo[TxPwrCCK+5]; + + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] = hwinfo[TxPwrHT40_1S+2]; + priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] = hwinfo[TxPwrHT40_1S+5]; + + priv->pmib->dot11RFEntry.pwrdiffHT40_2S[i]= hwinfo[TxPwrHT40_2SDiff+2]; + priv->pmib->dot11RFEntry.pwrdiffHT20[i] = hwinfo[TxPwrHT20Diff+2]; + priv->pmib->dot11RFEntry.pwrdiffOFDM[i] = hwinfo[TxPwrOFDMDiff+2]; + + } + } + DEBUG_INFO("EFUSE Autoload success!\n"); + } +} + + +static void ReadMacAddressFromEfuse(struct rtl8192cd_priv *priv) +{ + u8 efuse_MAC=0; +#ifdef __KERNEL__ + struct sockaddr addr; +#endif + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + efuse_MAC = EEPROM_MACADDRESS; + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pshare->wlandev_idx == 0) { + efuse_MAC = EEPROM_MAC0_MACADDRESS; + } else { + efuse_MAC = EEPROM_MAC1_MACADDRESS; + } +#else + efuse_MAC = EEPROM_MAC0_MACADDRESS; +#endif + } +#endif + + if (/*priv->AutoloadFailFlag==FALSE &&*/ priv->pmib->efuseEntry.enable_efuse == 1) { + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + unsigned char *efuse_mac = hwinfo + efuse_MAC; + unsigned char zero[] = {0, 0, 0, 0, 0, 0}, mac[6]; + + memcpy(mac, efuse_mac, MACADDRLEN); + /* printk("wlan%d EFUSE MAC [%02x:%02x:%02x:%02x:%02x:%02x]\n", priv->pshare->wlandev_idx, + *mac, *(mac+1), *(mac+2), *(mac+3), *(mac+4), *(mac+5)); */ +#if 0 + if(memcmp(mac, zero, MACADDRLEN) && !IS_MCAST(mac)) { +#ifdef __KERNEL__ + memcpy(addr.sa_data, mac, MACADDRLEN); + rtl8192cd_set_hwaddr(priv->dev, (void *)&addr); +#else + rtl8192cd_set_hwaddr(priv->dev, (void *)mac); +#endif + } +#else + if(!memcmp(mac, zero, MACADDRLEN) || IS_MCAST(mac)) { + memcpy(mac, zero, MACADDRLEN); + } + +#ifdef __KERNEL__ + memcpy(addr.sa_data, mac, MACADDRLEN); + rtl8192cd_set_hwaddr(priv->dev, (void *)&addr); +#else + rtl8192cd_set_hwaddr(priv->dev, (void *)mac); +#endif +#endif + } +} + + +void ReadThermalMeterFromEfuse(struct rtl8192cd_priv *priv) +{ + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + u8 efuse_Ther = 0; + + if (!priv->pmib->efuseEntry.enable_efuse) + return; + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + efuse_Ther = EEPROM_THERMAL_METER; + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + efuse_Ther = EEPROM_92D_THERMAL_METER; + } +#endif + + priv->pmib->dot11RFEntry.ther = (hwinfo[efuse_Ther] & 0x1f); //[4:0] + DEBUG_INFO("ThermalMeter = 0x%x\n", priv->pmib->dot11RFEntry.ther); + + if ((priv->pmib->dot11RFEntry.ther < 0x07) || (priv->pmib->dot11RFEntry.ther > 0x1d)) { + priv->pmib->dot11RFEntry.ther = 0; + } +} + + +#ifdef CONFIG_RTL_92D_SUPPORT + +void ReadCrystalCalibrationFromEfuse(struct rtl8192cd_priv *priv) +{ + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + + if (!priv->pmib->efuseEntry.enable_efuse) + return; + + priv->pmib->dot11RFEntry.xcap = (hwinfo[EEPROM_92D_XTAL_K]); //[7:0] +} + + +void ReadDeltaValFromEfuse(struct rtl8192cd_priv *priv) +{ + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + + if (!priv->pmib->efuseEntry.enable_efuse) + return; + + priv->pmib->dot11RFEntry.deltaIQK = (hwinfo[EEPROM_92D_IQK_DELTA] & 0x03); //[1:0] + priv->pmib->dot11RFEntry.deltaLCK = (hwinfo[EEPROM_92D_LCK_DELTA] & 0x0C) >> 2; //[3:2] +} + +void ReadTRSWPAPEFromEfuse(struct rtl8192cd_priv *priv) +{ + unsigned char *hwinfo = &(priv->EfuseMap[EFUSE_INIT_MAP][0]); + + if (!priv->pmib->efuseEntry.enable_efuse) + return; + + priv->pmib->dot11RFEntry.trsw_pape_C9 = (hwinfo[EEPROM_92D_TRSW_CTRL] & 0xff); + priv->pmib->dot11RFEntry.trsw_pape_CC = (hwinfo[EEPROM_92D_PAPE_CTRL] & 0xff); + + if (priv->pmib->dot11RFEntry.trsw_pape_C9 == 0xff) + priv->pmib->dot11RFEntry.trsw_pape_C9 = 0; +} + +#endif + + +// +// Description: +// Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. +// +// Assumption: +// 1. CR9346 regiser has verified. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +int ReadAdapterInfo8192CE(struct rtl8192cd_priv *priv) +{ + unsigned char tmpU1b; + tmpU1b = RTL_R8(CR9346); + + // To check system boot selection. + if (tmpU1b & CmdEERPOMSEL) { + DEBUG_INFO("Boot from EEPROM\n"); + } else { + DEBUG_INFO("Boot from EFUSE\n"); + } + + // To check autoload success or not. + if (tmpU1b & CmdEEPROM_En) { + DEBUG_INFO("Autoload OK!!\n"); + priv->AutoloadFailFlag=FALSE; +#if 0 + EFUSE_ShadowMapUpdate(priv); + ReadTxPowerInfoFromHWPG(priv); + ReadMacAddressFromEfuse(priv); +#endif + } else { // Auto load fail. + DEBUG_INFO("AutoLoad Fail reported from CR9346!!\n"); + priv->AutoloadFailFlag=TRUE; + } + EFUSE_ShadowMapUpdate(priv); + ReadTxPowerInfoFromHWPG(priv); + ReadThermalMeterFromEfuse(priv); + ReadMacAddressFromEfuse(priv); +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + ReadCrystalCalibrationFromEfuse(priv); + ReadDeltaValFromEfuse(priv); + ReadTRSWPAPEFromEfuse(priv); + } +#endif + + return 0; +} + + +static char FLASH_NAME_PARAM[][32] = { + "HW_TX_POWER_CCK_A", + "HW_TX_POWER_CCK_B", + "HW_TX_POWER_HT40_1S_A", + "HW_TX_POWER_HT40_1S_B", + "HW_TX_POWER_DIFF_HT40_2S", + "HW_TX_POWER_DIFF_HT20", + "HW_TX_POWER_DIFF_OFDM", + "HW_WLAN0_WLAN_ADDR", + "EFUSE_MAP0", + "EFUSE_MAP1", + "HW_11N_THER", +#ifdef CONFIG_RTL_92D_SUPPORT + "HW_TX_POWER_5G_HT40_1S_A", + "HW_TX_POWER_5G_HT40_1S_B", + "HW_TX_POWER_DIFF_5G_HT40_2S", + "HW_TX_POWER_DIFF_5G_HT20", + "HW_TX_POWER_DIFF_5G_OFDM", + "HW_11N_TRSWPAPE_C9", + "HW_11N_TRSWPAPE_CC", + "HW_11N_XCAP" +#endif +}; + +#define EFUSECMD_NUM_92C 11 +#define EFUSECMD_NUM_92D 19 + + +static int getEEPROMOffset(struct rtl8192cd_priv *priv, int type) +{ + int offset=0; + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + switch(type) { + case 0: offset = EEPROM_TxPowerCCK; + break; + case 1: offset = EEPROM_TxPowerCCK+3; + break; + case 2: offset = EEPROM_TxPowerHT40_1S; + break; + case 3: offset = EEPROM_TxPowerHT40_1S+3; + break; + case 4: offset = EEPROM_TxPowerHT40_2SDiff; + break; + case 5: offset = EEPROM_TxPowerHT20Diff; + break; + case 6: offset = EEPROM_TxPowerOFDMDiff; + break; + case 7: offset = EEPROM_MACADDRESS; + break; + case 10: offset = EEPROM_THERMAL_METER; + break; + default: + offset = -1; + panic_printk("NOT SUPPORT!!\n"); + break; + } + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + switch(type) { + case 0: offset = EEPROM_2G_TxPowerCCK; + break; + case 1: offset = EEPROM_2G_TxPowerCCK+3; + break; + case 2: offset = EEPROM_2G_TxPowerHT40_1S; + break; + case 3: offset = EEPROM_2G_TxPowerHT40_1S+3; + break; + case 4: offset = EEPROM_2G_TxPowerHT40_2SDiff; + break; + case 5: offset = EEPROM_2G_TxPowerHT20Diff; + break; + case 6: offset = EEPROM_2G_TxPowerOFDMDiff; + break; + case 7: +#ifdef CONFIG_RTL_92D_DMDP + if (priv->pshare->wlandev_idx == 1) + offset = EEPROM_MAC1_MACADDRESS; + else +#endif + offset = EEPROM_MAC0_MACADDRESS; + break; + case 8: offset = 0x00; + break; + case 9: offset = 0x32; + break; + case 10: offset = EEPROM_92D_THERMAL_METER; + break; + case 11: offset = EEPROM_5GL_TxPowerHT40_1S; + break; + case 12: offset = EEPROM_5GL_TxPowerHT40_1S+3; + break; + case 13: offset = EEPROM_5GL_TxPowerHT40_2SDiff; + break; + case 14: offset = EEPROM_5GL_TxPowerHT20Diff; + break; + case 15: offset = EEPROM_5GL_TxPowerOFDMDiff; + break; + case 16: offset = EEPROM_92D_TRSW_CTRL; + break; + case 17: offset = EEPROM_92D_PAPE_CTRL; + break; + case 18: offset = EEPROM_92D_XTAL_K; + break; + default: + offset = -1; + panic_printk("NOT SUPPORT!!\n"); + break; + } + } +#endif + return offset; +} + + +/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ +static UINT8 efuse_CalculateWordCnts( UINT8 word_en) +{ + UINT8 word_cnts = 0; + if(!(word_en & BIT(0))) word_cnts++; // 0 : write enable + if(!(word_en & BIT(1))) word_cnts++; + if(!(word_en & BIT(2))) word_cnts++; + if(!(word_en & BIT(3))) word_cnts++; + return word_cnts; +} // efuse_CalculateWordCnts + + +/*----------------------------------------------------------------------------- + * Function: efuse_GetCurrentSize + * + * Overview: Get current efuse size!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static UINT16 efuse_GetCurrentSize(struct rtl8192cd_priv *priv) +{ + INT32 bContinual = TRUE; + UINT16 efuse_addr = 0; + UINT8 hoffset=0,hworden=0; + UINT8 efuse_data,word_cnts=0; + + do { + ReadEFuseByte(priv, efuse_addr, &efuse_data) ; + if(efuse_data!=0xFF) + { + if((efuse_data&0x1F) == 0x0F) //extended header + { + hoffset = efuse_data; + efuse_addr++; + ReadEFuseByte(priv, efuse_addr ,&efuse_data); + if((efuse_data & 0x0F) == 0x0F) + { + efuse_addr++; + continue; + } + else + { + hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } + } + else + { + hoffset = (efuse_data>>4) & 0x0F; + hworden = efuse_data & 0x0F; + } + word_cnts = efuse_CalculateWordCnts(hworden); + //read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + } else { + bContinual = FALSE ; + } + } while (bContinual && (efuse_addr < EFUSE_REAL_CONTENT_LEN) ); + + return efuse_addr; + +} // efuse_GetCurrentSize} + + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataRead + * + * Overview: Read allowed word in current efuse section data. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * 11/21/2008 MHC Fix Write bug when we only enable late word. + * + *---------------------------------------------------------------------------*/ +static void efuse_WordEnableDataRead(UINT8 word_en, UINT8 *sourdata, UINT8 *targetdata) +{ + if (!(word_en&BIT(0))) { + targetdata[0] = sourdata[0]; + targetdata[1] = sourdata[1]; + } + if (!(word_en&BIT(1))) { + targetdata[2] = sourdata[2]; + targetdata[3] = sourdata[3]; + } + if (!(word_en&BIT(2))) { + targetdata[4] = sourdata[4]; + targetdata[5] = sourdata[5]; + } + if (!(word_en&BIT(3))) { + targetdata[6] = sourdata[6]; + targetdata[7] = sourdata[7]; + } +} // efuse_WordEnableDataRead + + +/*----------------------------------------------------------------------------- + * Function: efuse_PgPacketRead + * + * Overview: Receive dedicated Efuse are content. For92s, we support 16 + * area now. It will return 8 bytes content for every area. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize code Arch and assign as local API. + * + *---------------------------------------------------------------------------*/ +static INT32 efuse_PgPacketRead(struct rtl8192cd_priv *priv, UINT8 offset, UINT8 *data) +{ + UINT8 ReadState = PG_STATE_HEADER; + INT32 bContinual = TRUE, bDataEmpty = TRUE ; + UINT16 efuse_addr = 0; + UINT8 hoffset=0,hworden=0, efuse_data,word_cnts=0, tmpidx=0; + UINT8 tmpdata[8]; + UINT8 tmp_header; + + if(data==NULL) + return FALSE; + if(offset>15) + return FALSE; + + memset(data, 0xff, sizeof(UINT8)*PGPKT_DATA_SIZE); + memset(tmpdata, 0xff, sizeof(UINT8)*PGPKT_DATA_SIZE); + + // + // <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. + // Skip dummy parts to prevent unexpected data read from Efuse. + // By pass right now. 2009.02.19. + // + while(bContinual && (efuse_addr < EFUSE_REAL_CONTENT_LEN) ) { + //------- Header Read ------------- + if(ReadState & PG_STATE_HEADER) { + ReadEFuseByte(priv, efuse_addr ,&efuse_data); + if(efuse_data!=0xFF) + { + if((efuse_data & 0x1F) == 0x0F) + { + tmp_header = efuse_data; + efuse_addr++; + ReadEFuseByte(priv, efuse_addr ,&efuse_data); + if((efuse_data & 0x0F) != 0x0F) + { + hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } + else + { + efuse_addr++; + continue; + } + + } + else + { + hoffset = (efuse_data>>4) & 0x0F; + hworden = efuse_data & 0x0F; + } + word_cnts = efuse_CalculateWordCnts(hworden); + bDataEmpty = TRUE ; + + if(hoffset==offset){ + for(tmpidx = 0;tmpidx< word_cnts*2 ;tmpidx++){ + ReadEFuseByte(priv, efuse_addr+1+tmpidx ,&efuse_data); + tmpdata[tmpidx] = efuse_data; + if(efuse_data!=0xff){ + bDataEmpty = FALSE; + } + } + if(bDataEmpty==FALSE){ + ReadState = PG_STATE_DATA; + }else{//read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + } + else{//read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + } + else{ + bContinual = FALSE ; + } + } + //------- Data section Read ------------- + else if(ReadState & PG_STATE_DATA) { + efuse_WordEnableDataRead(hworden,tmpdata,data); + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + } + if( (data[0]==0xff) &&(data[1]==0xff) && (data[2]==0xff) && (data[3]==0xff) && + (data[4]==0xff) &&(data[5]==0xff) && (data[6]==0xff) && (data[7]==0xff)) + return FALSE; + else + return TRUE; + +} // efuse_PgPacketRead + + +/* 11/16/2008 MH Write one byte to reald Efuse. */ +static INT32 WriteEFuseByte(struct rtl8192cd_priv *priv, UINT16 addr, UINT8 data) +{ + UINT8 tmpidx = 0; + INT32 bResult; + UINT8 val8; + +// DEBUG_INFO("Addr = %x Data=%x\n", addr, data); + + // -----------------e-fuse reg ctrl --------------------------------- + //address + RTL_W8( EFUSE_CTRL+1, (UINT8)(addr&0xff)); + val8 = RTL_R8( EFUSE_CTRL+1); + RTL_W8( EFUSE_CTRL+2, (RTL_R8(EFUSE_CTRL+2)&0xFC )|(UINT8)((addr>>8)&0x03)); + RTL_W8( EFUSE_CTRL, data);//data +#if 1 + RTL_W8( EFUSE_CTRL+3, 0xF2 );//write cmd +#else + // use default program time 5000 ns + PlatformEFIOWrite4Byte(pAdapter, REG_EFUSE_CTRL, (PlatformEFIORead4Byte(pAdapter,REG_EFUSE_CTRL)|( EF_FLAG)));//write cmd +#endif + + while((0x80 & RTL_R8(EFUSE_CTRL+3)) && (tmpidx<100) ){ + tmpidx++; + } + + if(tmpidx<100) { + bResult = TRUE; + } else { + bResult = FALSE; + } + + return bResult; +} // + + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataWrite + * + * Overview: Write necessary word unit into current efuse section! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize Efuse operate flow!!. + * + *---------------------------------------------------------------------------*/ +static UINT8 efuse_WordEnableDataWrite(struct rtl8192cd_priv *priv, + UINT16 efuse_addr, UINT8 word_en, UINT8 *data) +{ + UINT16 tmpaddr = 0; + UINT16 start_addr = efuse_addr; + UINT8 badworden = 0x0F; + UINT8 tmpdata[8]; + + //memset(tmpdata,0xff,PGPKT_DATA_SIZE); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE); + DEBUG_INFO("word_en = %x efuse_addr=%x\n", word_en, efuse_addr); + + if(!(word_en&BIT(0))) { + tmpaddr = start_addr; + WriteEFuseByte(priv,start_addr++, data[0]); + WriteEFuseByte(priv,start_addr++, data[1]); + ReadEFuseByte(priv,tmpaddr, &tmpdata[0]); + ReadEFuseByte(priv,tmpaddr+1, &tmpdata[1]); + if((data[0]!=tmpdata[0])||(data[1]!=tmpdata[1])){ + badworden &= (~ BIT(0)); + } + } + if(!(word_en&BIT(1))) { + tmpaddr = start_addr; + WriteEFuseByte(priv,start_addr++, data[2]); + WriteEFuseByte(priv,start_addr++, data[3]); + ReadEFuseByte(priv,tmpaddr , &tmpdata[2]); + ReadEFuseByte(priv,tmpaddr+1, &tmpdata[3]); + if((data[2]!=tmpdata[2])||(data[3]!=tmpdata[3])){ + badworden &=( ~ BIT(1)); + } + } + if(!(word_en&BIT(2))) { + tmpaddr = start_addr; + WriteEFuseByte(priv,start_addr++, data[4]); + WriteEFuseByte(priv,start_addr++, data[5]); + ReadEFuseByte(priv,tmpaddr, &tmpdata[4]); + ReadEFuseByte(priv,tmpaddr+1, &tmpdata[5]); + if((data[4]!=tmpdata[4])||(data[5]!=tmpdata[5])){ + badworden &=( ~ BIT(2)); + } + } + if(!(word_en&BIT(3))) + { + tmpaddr = start_addr; + WriteEFuseByte(priv,start_addr++, data[6]); + WriteEFuseByte(priv,start_addr++, data[7]); + ReadEFuseByte(priv,tmpaddr, &tmpdata[6]); + ReadEFuseByte(priv,tmpaddr+1, &tmpdata[7]); + if((data[6]!=tmpdata[6])||(data[7]!=tmpdata[7])){ + badworden &=( ~ BIT(3)); + } + } + return badworden; +} // efuse_WordEnableDataWrite + + +// +// Description: +// This routine will calculate current shadow map that +// how much bytes needs to be updated. +// +// Assumption: +// We shall call this routine before programming physical Efuse content. +// +// Return Value: +// TRUE: Efuse has enough capacity to program. +// FALSE: Efuse do NOT has enough capacity to program. +// +// Created by Roger, 2008.04.21. +// +static int EFUSE_ShadowUpdateChk(struct rtl8192cd_priv *priv) +{ + UINT8 SectionIdx, i, Base; + UINT16 WordsNeed = 0, HdrNum = 0, TotalBytes = 0, EfuseUsed = 0; + UINT8 bWordChanged, bResult = TRUE; + + // Efuse contain total 16 sections. + for (SectionIdx = 0; SectionIdx < EFUSE_MAX_SECTION; SectionIdx++) { + Base = SectionIdx * 8; + bWordChanged = FALSE; + + // One section contain 4 words = 8 bytes. + for (i = 0; i < 8; i=i+2) { + if ((priv->EfuseMap[EFUSE_INIT_MAP][Base+i] != priv->EfuseMap[EFUSE_MODIFY_MAP][Base+i]) || + (priv->EfuseMap[EFUSE_INIT_MAP][Base+i+1] != priv->EfuseMap[EFUSE_MODIFY_MAP][Base+i+1])) { + WordsNeed++; + bWordChanged = TRUE; + } + } + + // We shall append Efuse header If any WORDs changed in this section. + if (bWordChanged == TRUE) + HdrNum++; + } + + TotalBytes = HdrNum + WordsNeed*2; + EfuseUsed = priv->EfuseUsedBytes; + + // Calculate whether updated map has enough capacity. + if ((TotalBytes + EfuseUsed) >= (EFUSE_REAL_CONTENT_LEN - EFUSE_OOB_PROTECT_BYTES)) + bResult = FALSE; + + DEBUG_INFO("EFUSE_ShadowUpdateChk(): TotalBytes(%#x), HdrNum(%#x), WordsNeed(%#x), EfuseUsed(%d)\n", + TotalBytes, HdrNum, WordsNeed, EfuseUsed); + + return bResult; +} + + +/*----------------------------------------------------------------------------- + * Function: efuse_PgPacketWrite + * + * Overview: Send A G package for different section in real efuse area. + * For 92S, One PG package contain 8 bytes content and 4 word + * unit. PG header = 0x[bit7-4=offset][bit3-0word enable] + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize code Arch and assign as local API. + * + *---------------------------------------------------------------------------*/ +static int efuse_PgPacketWrite(struct rtl8192cd_priv *priv, + UINT8 offset, UINT8 word_en, UINT8 *data) +{ + UINT8 WriteState = PG_STATE_HEADER; + INT32 bContinual = TRUE, bDataEmpty= TRUE, bResult = TRUE, bExtendedHeader = FALSE; + UINT16 efuse_addr = 0; + UINT8 efuse_data, pg_header = 0, pg_header_temp = 0; + + UINT8 tmp_word_cnts=0,target_word_cnts=0; + UINT8 tmp_header,match_word_en,tmp_word_en; + + PGPKT_STRUCT target_pkt; + PGPKT_STRUCT tmp_pkt; + + UINT8 originaldata[sizeof(UINT8)*8]; + UINT8 tmpindex = 0, badworden = 0x0F; + static INT32 repeat_times = 0; + + // + // <Roger_Notes> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. + // So we have to prevent unexpected data string connection, which will cause + // incorrect data auto-load from HW. The total size is equal or smaller than 498bytes + // (i.e., offset 0~497, and dummy 1bytes) expected after CP test. + // 2009.02.19. + // + if( efuse_GetCurrentSize(priv) >= (EFUSE_REAL_CONTENT_LEN-EFUSE_OOB_PROTECT_BYTES)) { + DEBUG_INFO ("efuse_PgPacketWrite error \n"); + return FALSE; + } + + // Init the 8 bytes content as 0xff + target_pkt.offset = offset; + target_pkt.word_en= word_en; + memset(target_pkt.data, 0xFF, sizeof(UINT8)*8); + + efuse_WordEnableDataRead(word_en,data,target_pkt.data); + target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); + + // + // <Roger_Notes> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. + // So we have to prevent unexpected data string connection, which will cause + // incorrect data auto-load from HW. Dummy 1bytes is additional. + // 2009.02.19. + // + while( bContinual && (efuse_addr < (EFUSE_REAL_CONTENT_LEN-EFUSE_OOB_PROTECT_BYTES)) ) { + if(WriteState==PG_STATE_HEADER) { + bDataEmpty=TRUE; + badworden = 0x0F; + //************ so ******************* + DEBUG_INFO("EFUSE PG_STATE_HEADER\n"); + ReadEFuseByte(priv, efuse_addr ,&efuse_data); + if (efuse_data!=0xFF) + { + if((efuse_data&0x1F) == 0x0F) //extended header + { + tmp_header = efuse_data; + efuse_addr++; + ReadEFuseByte(priv, efuse_addr ,&efuse_data); + if((efuse_data & 0x0F) == 0x0F) //wren fail + { + efuse_addr++; + continue; + } + else + { + tmp_pkt.offset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); + tmp_pkt.word_en = efuse_data & 0x0F; + } + } + else + { + tmp_header = efuse_data; + tmp_pkt.offset = (tmp_header>>4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + } + + tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); + + //************ so-1 ******************* + if(tmp_pkt.offset != target_pkt.offset) { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet +#ifdef EFUSE_ERROE_HANDLE + WriteState = PG_STATE_HEADER; +#endif + } else { + //************ so-2 ******************* + for(tmpindex=0 ; tmpindex<(tmp_word_cnts*2) ; tmpindex++) { + ReadEFuseByte(priv, (efuse_addr+1+tmpindex) ,&efuse_data); + if(efuse_data != 0xFF) + bDataEmpty = FALSE; + } + //************ so-2-1 ******************* + if(bDataEmpty ==FALSE) { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet +#ifdef EFUSE_ERROE_HANDLE + WriteState=PG_STATE_HEADER; +#endif + } else { + //************ so-2-2 ******************* + match_word_en = 0x0F; + if( !( (target_pkt.word_en&BIT(0))|(tmp_pkt.word_en&BIT(0)) )) { + match_word_en &= (~ BIT(0)); + } + if( !( (target_pkt.word_en&BIT(1))|(tmp_pkt.word_en&BIT(1)) )) { + match_word_en &= (~ BIT(1)); + } + if( !( (target_pkt.word_en&BIT(2))|(tmp_pkt.word_en&BIT(2)) )) { + match_word_en &= (~ BIT(2)); + } + if( !( (target_pkt.word_en&BIT(3))|(tmp_pkt.word_en&BIT(3)) )) { + match_word_en &= (~ BIT(3)); + } + + //************ so-2-2-A ******************* + if((match_word_en&0x0F)!=0x0F) { + badworden = efuse_WordEnableDataWrite(priv,efuse_addr+1, tmp_pkt.word_en ,target_pkt.data); + + //************ so-2-2-A-1 ******************* + if(0x0F != (badworden&0x0F)) { + UINT8 reorg_offset = offset; + UINT8 reorg_worden=badworden; + efuse_PgPacketWrite(priv,reorg_offset,reorg_worden,originaldata); + } + + tmp_word_en = 0x0F; + if( (target_pkt.word_en&BIT(0))^(match_word_en&BIT(0)) ) { + tmp_word_en &= (~ BIT(0)); + } + if( (target_pkt.word_en&BIT(1))^(match_word_en&BIT(1)) ) { + tmp_word_en &= (~ BIT(1)); + } + if( (target_pkt.word_en&BIT(2))^(match_word_en&BIT(2)) ) { + tmp_word_en &= (~ BIT(2)); + } + if( (target_pkt.word_en&BIT(3))^(match_word_en&BIT(3)) ) { + tmp_word_en &=(~ BIT(3)); + } + + //************ so-2-2-A-2 ******************* + if((tmp_word_en&0x0F)!=0x0F){ + //reorganize other pg packet + efuse_addr = efuse_GetCurrentSize(priv); + target_pkt.offset = offset; + target_pkt.word_en= tmp_word_en; + } else { + bContinual = FALSE; + } +#ifdef EFUSE_ERROE_HANDLE + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } +#endif + } + else{//************ so-2-2-B ******************* + //reorganize other pg packet + efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr + target_pkt.offset = offset; + target_pkt.word_en= target_pkt.word_en; +#ifdef EFUSE_ERROE_HANDLE + WriteState=PG_STATE_HEADER; +#endif + } + } + } + DEBUG_INFO("EFUSE PG_STATE_HEADER-1\n"); + }else { + //************ s1: header == oxff ******************* + bExtendedHeader = FALSE; + + if(target_pkt.offset >= EFUSE_MAX_SECTION_BASE) + { + pg_header = ((target_pkt.offset &0x07) << 5) | 0x0F; + + DEBUG_INFO("efuse_PgPacketWrite extended pg_header[2:0] |0x0F 0x%x \n", pg_header); + + WriteEFuseByte(priv,efuse_addr, pg_header); + ReadEFuseByte(priv,efuse_addr, &tmp_header); + + while(tmp_header == 0xFF) + { + DEBUG_INFO("efuse_PgPacketWrite extended pg_header[2:0] wirte fail \n"); + + repeat_times++; + + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + efuse_addr++; + break; + } + WriteEFuseByte(priv,efuse_addr, pg_header); + ReadEFuseByte(priv,efuse_addr, &tmp_header); + } + + if(!bContinual) + break; + + if(tmp_header == pg_header) + { + efuse_addr++; + pg_header_temp = pg_header; + pg_header = ((target_pkt.offset & 0x78) << 1 ) | target_pkt.word_en; + + DEBUG_INFO("efuse_PgPacketWrite extended pg_header[6:3] | worden 0x%x word_en 0x%x \n", pg_header); + + WriteEFuseByte(priv,efuse_addr, pg_header); + ReadEFuseByte(priv,efuse_addr, &tmp_header); + + while(tmp_header == 0xFF) + { + repeat_times++; + + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + break; + } + WriteEFuseByte(priv,efuse_addr, pg_header); + ReadEFuseByte(priv,efuse_addr, &tmp_header); + } + + if(!bContinual) + break; + + if((tmp_header & 0x0F) == 0x0F) //wren PG fail + { + repeat_times++; + + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + break; + } + else + { + efuse_addr++; + continue; + } + } + else if(pg_header != tmp_header) //offset PG fail + { + bExtendedHeader = TRUE; + tmp_pkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); + tmp_pkt.word_en= tmp_header & 0x0F; + tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); + } + } + else if ((tmp_header & 0x1F) == 0x0F) //wrong extended header + { + efuse_addr+=2; + continue; + } + } + else + { + pg_header = ((target_pkt.offset << 4)&0xf0) |target_pkt.word_en; + WriteEFuseByte(priv,efuse_addr, pg_header); + ReadEFuseByte(priv, efuse_addr, &tmp_header); + } + if(tmp_header == pg_header) { //************ s1-1******************* + WriteState = PG_STATE_DATA; + } else +#ifdef EFUSE_ERROE_HANDLE + if(tmp_header == 0xFF){//************ s1-3: if Write or read func doesn't work ******************* + //efuse_addr doesn't change + WriteState = PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } + } else +#endif + {//************ s1-2 : fixed the header procedure ******************* + if(!bExtendedHeader) + { + tmp_pkt.offset = (tmp_header>>4) & 0x0F; + tmp_pkt.word_en= tmp_header & 0x0F; + tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); + } + + //************ s1-2-A :cover the exist data ******************* + //memset(originaldata,0xff,sizeof(UINT8)*8); + memset(originaldata, 0xff, sizeof(UINT8)*8); + + if(efuse_PgPacketRead( priv, tmp_pkt.offset,originaldata)) { //check if data exist + badworden = efuse_WordEnableDataWrite(priv,efuse_addr+1,tmp_pkt.word_en,originaldata); + if(0x0F != (badworden&0x0F)) { + UINT8 reorg_offset = tmp_pkt.offset; + UINT8 reorg_worden=badworden; + efuse_PgPacketWrite(priv,reorg_offset,reorg_worden,originaldata); + efuse_addr = efuse_GetCurrentSize(priv); + } else { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + } + } else { + //************ s1-2-B: wrong address******************* + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + } + +#ifdef EFUSE_ERROE_HANDLE + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } +#endif + DEBUG_INFO("EFUSE PG_STATE_HEADER-2\n"); + } + + } + } + //write data state + else if(WriteState==PG_STATE_DATA) + { //************ s1-1 ******************* + DEBUG_INFO("EFUSE PG_STATE_DATA\n"); + badworden = 0x0f; + badworden = efuse_WordEnableDataWrite(priv,efuse_addr+1,target_pkt.word_en,target_pkt.data); + if((badworden&0x0F)==0x0F) { + //************ s1-1-A ******************* + bContinual =FALSE; + } else { + //reorganize other pg packet //************ s1-1-B ******************* + efuse_addr = efuse_addr + (2*target_word_cnts) +1;//next pg packet addr + //=========================== + target_pkt.offset = offset; + target_pkt.word_en= badworden; + target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); + //=========================== +#ifdef EFUSE_ERROE_HANDLE + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } +#endif + DEBUG_INFO("EFUSE PG_STATE_HEADER-3\n"); + } + } + } + + if(efuse_addr >= (EFUSE_REAL_CONTENT_LEN-EFUSE_OOB_PROTECT_BYTES)) { + DEBUG_INFO("efuse_PgPacketWrite(): efuse_addr(%#x) Out of size!!\n", efuse_addr); + } + + return TRUE; +} // efuse_PgPacketWrite + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowUpdate + * + * Overview: Compare init and modify map to update Efuse!!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * 12/11/2008 MHC 92SE PH workaround to prevent HW autoload fail. + * 12/30/2008 Roger Fix the bug that EFUSE will writed out-of boundary. + * 02/16/2009 Roger Revise PCIe autoload fail case and compatible with USB interface to + * overcome MP issue. + * + *---------------------------------------------------------------------------*/ +static int EFUSE_ShadowUpdate(struct rtl8192cd_priv *priv) +{ + UINT16 i, offset, base = 0; + UINT8 word_en = 0x0F; + + // + // <Roger_Notes> We have to check whether current Efuse capacity is big enough to program!! + // 2009.04.21. + // + if(!EFUSE_ShadowUpdateChk(priv)) { + // + // <Roger_Notes> We shall reload current Efuse all map and synchronize current modified + // map to prevent inconsistent Efuse content. + // 2009.04.21. + // + EFUSE_ShadowMapUpdate(priv); + DEBUG_INFO("<---EFUSE_ShadowUpdate(): Efuse out of capacity!!\n"); + return FALSE; + } + // For Efuse write action, we must enable LDO2.5V and 40MHZ clk. + efuse_PowerSwitch(priv,TRUE); + + // + // Efuse support 16 write are with PG header packet!!!! + // + for (offset = 0; offset < EFUSE_MAX_SECTION; offset++) { + // From section(0) to section(15) sequential write. + word_en = 0x0F; + base = offset * 8; + // + // Decide Word Enable Bit for the Efuse section + // One section contain 4 words = 8 bytes!!!!! + // + for (i = 0; i < 8; i++) { + if (priv->EfuseMap[EFUSE_INIT_MAP][base+i] != priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]) { + word_en &= ~(BIT(i/2)); + DEBUG_INFO("Section(%#x) Addr[%x] %x update to %x, Word_En=%02x\n", + offset, base+i, priv->EfuseMap[EFUSE_INIT_MAP][base+i], priv->EfuseMap[EFUSE_MODIFY_MAP][base+i],word_en); + } + } + + // + // This section will need to update, call Efuse real write section !!!! + // + if (word_en != 0x0F) { + UINT8 tmpdata[8]; + memcpy(tmpdata, (&priv->EfuseMap[EFUSE_MODIFY_MAP][base]), 8); + + // + // <Roger_Notes> Break programming process if efuse capacity is NOT available. + // 2009.04.20. + // + if(!efuse_PgPacketWrite(priv,(UINT8)offset,word_en,tmpdata)) { + DEBUG_INFO("EFUSE_ShadowUpdate(): PG section(%#x) fail!!\n", offset); + break; + } + } + } + + // For warm reboot, we must resume Efuse clock to 500K. + efuse_PowerSwitch(priv, FALSE); + + // + // <Roger_Notes> We update both init shadow map again and modified map + // while WPG do loading operation after previous programming. + // 2008.12.30. + // + EFUSE_ShadowMapUpdate(priv); + DEBUG_INFO ("<---EFUSE_ShadowUpdate()\n"); + return TRUE; +} // EFUSE_ShadowUpdate + + +static void shadowMapWrite(struct rtl8192cd_priv *priv, int type, char *value, unsigned char *hwinfo) +{ + int i, offset ; + offset = getEEPROMOffset(priv, type); + + if (offset<0) + return; + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + if (offset == EEPROM_MACADDRESS) { + for (i=0; i<MACADDRLEN; i++) { + get_array_val(hwinfo+offset+i, value+i*2, 2); + } + } else if (offset == EEPROM_THERMAL_METER) { + get_array_val(hwinfo+offset, value, 2); + } + else { + get_array_val(hwinfo+offset, value, 2); + get_array_val(hwinfo+offset+1, value+3*2, 2); + get_array_val(hwinfo+offset+2, value+9*2, 2); + } + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + if (offset == 0 || offset == 0x32) { + for (i=0; i<0x32; i++) { + get_array_val(hwinfo+offset+i, value+i*2, 2); + } + } else if (offset == EEPROM_MAC0_MACADDRESS || offset == EEPROM_MAC1_MACADDRESS) { + for (i=0; i<MACADDRLEN; i++) { + get_array_val(hwinfo+offset+i, value+i*2, 2); + } + } else if (offset == EEPROM_92D_THERMAL_METER || + offset == EEPROM_92D_TRSW_CTRL || + offset == EEPROM_92D_PAPE_CTRL || + offset == EEPROM_92D_XTAL_K ) { + get_array_val(hwinfo+offset, value, 2); + } else if ((offset == EEPROM_2G_TxPowerCCK) || + (offset == EEPROM_2G_TxPowerCCK+3) || + (offset == EEPROM_2G_TxPowerHT40_1S) || + (offset == EEPROM_2G_TxPowerHT40_1S+3) || + (offset == EEPROM_2G_TxPowerHT40_2SDiff) || + (offset == EEPROM_2G_TxPowerHT20Diff) || + (offset == EEPROM_2G_TxPowerOFDMDiff)) + { + get_array_val(hwinfo+offset, value, 2); + get_array_val(hwinfo+offset+1, value+3*2, 2); + get_array_val(hwinfo+offset+2, value+9*2, 2); + } else if (offset == EEPROM_5GL_TxPowerHT40_1S) { + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S, value+35*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S+1, value+45*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S+2, value+55*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S, value+99*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S+1, value+113*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S+2, value+127*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S, value+148*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S+1, value+154*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S+2, value+160*2, 2); + } else if (offset == EEPROM_5GL_TxPowerHT40_1S+3) { + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S+3, value+35*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S+4, value+45*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_1S+5, value+55*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S+3, value+99*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S+4, value+113*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_1S+5, value+127*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S+3, value+148*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S+4, value+154*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_1S+5, value+160*2, 2); + } else if (offset == EEPROM_5GL_TxPowerHT40_2SDiff) { + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_2SDiff, value+35*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_2SDiff+1, value+45*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT40_2SDiff+2, value+55*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_2SDiff, value+99*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_2SDiff+1, value+113*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT40_2SDiff+2, value+127*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_2SDiff, value+148*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_2SDiff+1, value+154*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT40_2SDiff+2, value+160*2, 2); + } else if (offset == EEPROM_5GL_TxPowerHT20Diff) { + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT20Diff, value+35*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT20Diff+1, value+45*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerHT20Diff+2, value+55*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT20Diff, value+99*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT20Diff+1, value+113*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerHT20Diff+2, value+127*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT20Diff, value+148*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT20Diff+1, value+154*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerHT20Diff+2, value+160*2, 2); + } else if (offset == EEPROM_5GL_TxPowerOFDMDiff) { + get_array_val(hwinfo+EEPROM_5GL_TxPowerOFDMDiff, value+35*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerOFDMDiff+1, value+45*2, 2); + get_array_val(hwinfo+EEPROM_5GL_TxPowerOFDMDiff+2, value+55*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerOFDMDiff, value+99*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerOFDMDiff+1, value+113*2, 2); + get_array_val(hwinfo+EEPROM_5GM_TxPowerOFDMDiff+2, value+127*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerOFDMDiff, value+148*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerOFDMDiff+1, value+154*2, 2); + get_array_val(hwinfo+EEPROM_5GH_TxPowerOFDMDiff+2, value+160*2, 2); + } + } +#endif +} + + +static int converToFlashFormat(struct rtl8192cd_priv *priv, unsigned char *out, unsigned char *hwinfo, int type) +{ + int i, offset, len=0; + offset = getEEPROMOffset(priv, type); + + if (offset < 0) + return 0; + + sprintf(out, "%s=", FLASH_NAME_PARAM[type]); + len += 1 + strlen(FLASH_NAME_PARAM[type]); + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) { + if (offset == EEPROM_MACADDRESS) { + for (i=0; i<MACADDRLEN; i++) { + sprintf(out+len, "%02x", hwinfo[offset+i]); + len += 2; + } + } else if (offset == EEPROM_THERMAL_METER) { + sprintf(out+len, "%02x", hwinfo[offset]); + len += 2; + } else { + for (i=0; i<MAX_2G_CHANNEL_NUM; i++) { + if (i < 3) { + sprintf(out+len, "%02x", hwinfo[offset]); + len += 2; + } else if (i < 9) { + sprintf(out+len, "%02x", hwinfo[offset+1]); + len += 2; + } else { + sprintf(out+len, "%02x", hwinfo[offset+2]); + len += 2; + } + } + } + } +#endif + +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) { + if (offset == EEPROM_MAC0_MACADDRESS || offset == EEPROM_MAC1_MACADDRESS) { + for (i=0; i<MACADDRLEN; i++) { + sprintf(out+len, "%02x", hwinfo[offset+i]); + len += 2; + } + } else if (offset == EEPROM_92D_THERMAL_METER || + offset == EEPROM_92D_TRSW_CTRL || + offset == EEPROM_92D_PAPE_CTRL || + offset == EEPROM_92D_XTAL_K ) { + sprintf(out+len, "%02x", hwinfo[offset]); + len += 2; + } else if ((offset == EEPROM_2G_TxPowerCCK) || + (offset == EEPROM_2G_TxPowerCCK+3) || + (offset == EEPROM_2G_TxPowerHT40_1S) || + (offset == EEPROM_2G_TxPowerHT40_1S+3) || + (offset == EEPROM_2G_TxPowerHT40_2SDiff) || + (offset == EEPROM_2G_TxPowerHT20Diff) || + (offset == EEPROM_2G_TxPowerOFDMDiff)) + { + for (i=0; i<MAX_2G_CHANNEL_NUM; i++) { + if (i < 3) { + sprintf(out+len, "%02x", hwinfo[offset]); + len += 2; + } else if (i < 9) { + sprintf(out+len, "%02x", hwinfo[offset+1]); + len += 2; + } else { + sprintf(out+len, "%02x", hwinfo[offset+2]); + len += 2; + } + } + } else if (offset == EEPROM_5GL_TxPowerHT40_1S) { + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S]); + len += 2; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S+1]); + len += 2; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S]); + len += 2; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S+1]); + len += 2; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S]); + len += 2; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S+1]); + len += 2; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } + else { + sprintf(out+len, "00"); + len += 2; + } + } + } else if (offset == EEPROM_5GL_TxPowerHT40_1S+3) { + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S+3]); + len += 2; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S+4]); + len += 2; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_1S+5]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S+3]); + len += 2; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S+4]); + len += 2; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_1S+5]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S+3]); + len += 2; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S+4]); + len += 2; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_1S+5]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } + else { + sprintf(out+len, "00"); + len += 2; + } + } + } else if (offset == EEPROM_5GL_TxPowerHT40_2SDiff) { + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff]); + len += 2; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff+1]); + len += 2; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT40_2SDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff]); + len += 2; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff+1]); + len += 2; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT40_2SDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff]); + len += 2; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff+1]); + len += 2; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT40_2SDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } + else { + sprintf(out+len, "00"); + len += 2; + } + } + } else if (offset == EEPROM_5GL_TxPowerHT20Diff) { + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT20Diff]); + len += 2; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT20Diff+1]); + len += 2; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerHT20Diff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT20Diff]); + len += 2; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT20Diff+1]); + len += 2; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerHT20Diff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT20Diff]); + len += 2; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT20Diff+1]); + len += 2; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerHT20Diff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } + else { + sprintf(out+len, "00"); + len += 2; + } + } + } else if (offset == EEPROM_5GL_TxPowerOFDMDiff) { + for (i=0; i<MAX_5G_CHANNEL_NUM; i++) { + if (i >= 35 && i <= 63) { // ch 36 ~ 64 + if (i >= 35 && i <= 43) { // ch 36 ~ 44 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerOFDMDiff]); + len += 2; + } else if (i >= 45 && i <= 53) { // ch 46 ~ 54 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerOFDMDiff+1]); + len += 2; + } else if (i >= 55 && i <= 63) { // ch 56 ~ 64 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GL_TxPowerOFDMDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 99 && i <= 139) { // ch 100 ~ 140 + if (i >= 99 && i <= 111) { // ch 100 ~ 112 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerOFDMDiff]); + len += 2; + } else if (i >= 113 && i <= 125) { // ch 114 ~ 126 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerOFDMDiff+1]); + len += 2; + } else if (i >= 127 && i <= 139) { // ch 128 ~ 140 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GM_TxPowerOFDMDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } else if (i >= 148 && i <= 164 ) { // ch 149 ~ 165 + if (i >= 148 && i <= 152) { // ch 149 ~ 153 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerOFDMDiff]); + len += 2; + } else if (i >= 154 && i <= 158) { // ch 155 ~ 159 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerOFDMDiff+1]); + len += 2; + } else if (i >= 160 && i <= 164) { // ch 161 ~ 165 + sprintf(out+len, "%02x", hwinfo[EEPROM_5GH_TxPowerOFDMDiff+2]); + len += 2; + } else { + sprintf(out+len, "00"); + len += 2; + } + } + else { + sprintf(out+len, "00"); + len += 2; + } + } + } + } +#endif + + out[len]='\0'; + return len+1; +} + + +int efuse_get(struct rtl8192cd_priv *priv, unsigned char *data) +{ + int j, len, para_num=0; + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) + para_num = EFUSECMD_NUM_92C; +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) + para_num = EFUSECMD_NUM_92D; +#endif + + for (j=0; j<para_num; j++) { + if (strcmp(data, FLASH_NAME_PARAM[j])==0) { + len = converToFlashFormat(priv, data, &(priv->EfuseMap[EFUSE_INIT_MAP][0]), j); + printk("%s\n", data); + return len; + } + } + return 0; +} + + +int efuse_set(struct rtl8192cd_priv *priv, unsigned char *data) +{ + char *val; + int j, para_num=0; + extern char *get_value_by_token(char *data, char *token); + +#ifdef CONFIG_RTL_92C_SUPPORT + if (GET_CHIP_VER(priv) != VERSION_8192D) + para_num = EFUSECMD_NUM_92C; +#endif +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8192D) + para_num = EFUSECMD_NUM_92D; +#endif + + for (j=0; j<para_num; j++) { + val = get_value_by_token((char *)data, FLASH_NAME_PARAM[j]); + if (val) { + printk("%s=[%s]\n", FLASH_NAME_PARAM[j], val+1); + shadowMapWrite(priv, j, val+1, &(priv->EfuseMap[EFUSE_MODIFY_MAP][0])); + } + } + return 0; +} + + +int efuse_sync(struct rtl8192cd_priv *priv, unsigned char *data) +{ + DEBUG_INFO("efuse sync\n"); + EFUSE_ShadowUpdate(priv); + return 0; +} +#endif // EN_EFUSE + + + +#ifdef SW_ANT_SWITCH + +// +// 20100514 Luke/Joseph: +// Add new function to reset antenna diversity state after link. +// + +void resetSwAntDivVariable(struct rtl8192cd_priv *priv) +{ + priv->pshare->RSSI_sum_R = 0; + priv->pshare->RSSI_cnt_R = 0; + priv->pshare->RSSI_sum_L = 0; + priv->pshare->RSSI_cnt_L = 0; + priv->pshare->TXByteCnt_R = 0; + priv->pshare->TXByteCnt_L = 0; + priv->pshare->RXByteCnt_R = 0; + priv->pshare->RXByteCnt_L = 0; + +} +void SwAntDivRestAfterLink(struct rtl8192cd_priv *priv) +{ + priv->pshare->RSSI_test = FALSE; + priv->pshare->DM_SWAT_Table.try_flag = SWAW_STEP_RESET; + memset(priv->pshare->DM_SWAT_Table.SelectAntennaMap, 0, sizeof(priv->pshare->DM_SWAT_Table.SelectAntennaMap)); + priv->pshare->DM_SWAT_Table.mapIndex = 0; + priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; + priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; + resetSwAntDivVariable(priv); +} + + +void dm_SW_AntennaSwitchInit(struct rtl8192cd_priv *priv) +{ + if (GET_CHIP_VER(priv) == VERSION_8188C) + priv->pshare->rf_ft_var.antSw_select = 0; + + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS:Init SW Antenna Switch\n")); + resetSwAntDivVariable(priv); + priv->pshare->DM_SWAT_Table.CurAntenna = Antenna_L; + priv->pshare->DM_SWAT_Table.try_flag = SWAW_STEP_RESET; + memset(priv->pshare->DM_SWAT_Table.SelectAntennaMap, 0, sizeof(priv->pshare->DM_SWAT_Table.SelectAntennaMap)); + priv->pshare->DM_SWAT_Table.mapIndex = 0; + + + RTL_W32(LEDCFG, RTL_R32(LEDCFG) | BIT(23) ); //enable LED[1:0] pin as ANTSEL + + if ( !priv->pshare->rf_ft_var.antSw_select) { + RTL_W32(rFPGA0_XAB_RFParameter, RTL_R32(rFPGA0_XAB_RFParameter) | BIT(13) ); //select ANTESEL from path A + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) | BIT(8)| BIT(9) ); // enable ANTSEL A as SW control + RTL_W32(rFPGA0_XA_RFInterfaceOE, (RTL_R32(rFPGA0_XA_RFInterfaceOE) & ~(BIT(8)|BIT(9)))| 0x01<<8 ); // 0x01: left antenna, 0x02: right antenna + } else { + RTL_W32(rFPGA0_XAB_RFParameter, RTL_R32(rFPGA0_XAB_RFParameter) & ~ BIT(13) ); //select ANTESEL from path B + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) | BIT(24)| BIT(25) ); // enable ANTSEL B as SW control + RTL_W32(rFPGA0_XB_RFInterfaceOE, (RTL_R32(rFPGA0_XB_RFInterfaceOE) & ~(BIT(8)|BIT(9)))| 0x01<<8 ); // 0x01: left antenna, 0x02: right antenna + } + RTL_W16(rFPGA0_TxInfo, (RTL_R16(rFPGA0_TxInfo)&0xf0ff) | BIT(8) ); // b11-b8=0001 + + // Move the timer initialization to InitializeVariables function. + //PlatformInitializeTimer(Adapter, &pMgntInfo->SwAntennaSwitchTimer, (RT_TIMER_CALL_BACK)dm_SW_AntennaSwitchCallback, NULL, "SwAntennaSwitchTimer"); +} +// +// 20100514 Luke/Joseph: +// Add new function for antenna diversity after link. +// This is the main function of antenna diversity after link. +// This function is called in HalDmWatchDog() and dm_SW_AntennaSwitchCallback(). +// HalDmWatchDog() calls this function with SWAW_STEP_PEAK to initialize the antenna test. +// In SWAW_STEP_PEAK, another antenna and a 500ms timer will be set for testing. +// After 500ms, dm_SW_AntennaSwitchCallback() calls this function to compare the signal just +// listened on the air with the RSSI of original antenna. +// It chooses the antenna with better RSSI. +// There is also a aged policy for error trying. Each error trying will cost more 5 seconds waiting +// penalty to get next try. +// +void dm_SW_AntennaSwitch(struct rtl8192cd_priv *priv, char Step) +{ + unsigned int curTxOkCnt, curRxOkCnt; + unsigned int CurByteCnt, PreByteCnt; + int Score_R=0, Score_L=0; + int RSSI_R, RSSI_L; + char nextAntenna=priv->pshare->DM_SWAT_Table.CurAntenna; + int i; + +//1 1. Determine which condition should turn off Antenna Diversity + +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) + return; +#endif + +// if(!(GET_CHIP_VER(priv) == VERSION_8188C) || !priv->pshare->rf_ft_var.antSw_enable) +// return; + + if((!priv->assoc_num) +#ifdef PCIE_POWER_SAVING + || (priv->pwr_state == L2) || (priv->pwr_state == L1) +#endif + ){ + SwAntDivRestAfterLink(priv); + return; + } + + // Handling step mismatch condition. + // Peak step is not finished at last time. Recover the variable and check again. + if( Step != priv->pshare->DM_SWAT_Table.try_flag) + { + SwAntDivRestAfterLink(priv); + } + +//1 2. Initialization: Select a assocaiated AP or STA as RSSI target + if(priv->pshare->DM_SWAT_Table.try_flag == SWAW_STEP_RESET) { +#ifdef CLIENT_MODE + if((OPMODE & (WIFI_STATION_STATE | WIFI_ASOC_STATE)) == (WIFI_STATION_STATE | WIFI_ASOC_STATE)) { + // Target: Infrastructure mode AP. + priv->pshare->RSSI_target = NULL; + } +#endif + resetSwAntDivVariable(priv); + priv->pshare->DM_SWAT_Table.try_flag = SWAW_STEP_PEAK; + return; + } + else { + +//1 3. Antenna Diversity + + //2 Calculate TX and RX OK bytes + + curTxOkCnt = priv->net_stats.tx_bytes - priv->pshare->lastTxOkCnt; + curRxOkCnt = priv->net_stats.rx_bytes - priv->pshare->lastRxOkCnt; + priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; + priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; + + //2 Try State + if(priv->pshare->DM_SWAT_Table.try_flag == SWAW_STEP_DETERMINE) { + //3 1. Seperately caculate TX and RX OK byte counter for ant A and B + if(priv->pshare->DM_SWAT_Table.CurAntenna == Antenna_R) { + priv->pshare->TXByteCnt_R += curTxOkCnt; + priv->pshare->RXByteCnt_R += curRxOkCnt; + } else { + priv->pshare->TXByteCnt_L += curTxOkCnt; + priv->pshare->RXByteCnt_L += curRxOkCnt; + } + + //3 2. Change anntena for testing + if(priv->pshare->DM_SWAT_Table.RSSI_Trying != 0) { + nextAntenna = (priv->pshare->DM_SWAT_Table.CurAntenna ) ^ Antenna_MAX; + priv->pshare->DM_SWAT_Table.RSSI_Trying--; + } + + //2 Try State End: Determine the best antenna + + if(priv->pshare->DM_SWAT_Table.RSSI_Trying==0) { + nextAntenna = priv->pshare->DM_SWAT_Table.CurAntenna; + priv->pshare->DM_SWAT_Table.mapIndex = (priv->pshare->DM_SWAT_Table.mapIndex+1)%SELANT_MAP_SIZE; + + //3 TP Mode: Determine the best antenna by throuhgput + if(priv->pshare->DM_SWAT_Table.TestMode == TP_MODE) { + + + + //3 (1) Saperately caculate total byte count for two antennas + if(priv->pshare->DM_SWAT_Table.CurAntenna == Antenna_R) { + CurByteCnt = (priv->pshare->TXByteCnt_R + (priv->pshare->RXByteCnt_R<<1)); + PreByteCnt = (priv->pshare->TXByteCnt_L + (priv->pshare->RXByteCnt_L<<1)); + } else { + CurByteCnt = (priv->pshare->TXByteCnt_L + (priv->pshare->RXByteCnt_L<<1)); + PreByteCnt = (priv->pshare->TXByteCnt_R + (priv->pshare->RXByteCnt_R<<1)); + } + + //3 (2) Throughput Normalization + if(priv->pshare->TrafficLoad == TRAFFIC_HIGH) + CurByteCnt >>=3; + else if(priv->pshare->TrafficLoad == TRAFFIC_LOW) + CurByteCnt >>=1; + + if(priv->pshare->DM_SWAT_Table.CurAntenna == Antenna_R) { + priv->pshare->DM_SWAT_Table.SelectAntennaMap[0][priv->pshare->DM_SWAT_Table.mapIndex] = PreByteCnt; + priv->pshare->DM_SWAT_Table.SelectAntennaMap[1][priv->pshare->DM_SWAT_Table.mapIndex] = CurByteCnt; + } else { + priv->pshare->DM_SWAT_Table.SelectAntennaMap[0][priv->pshare->DM_SWAT_Table.mapIndex] = CurByteCnt; + priv->pshare->DM_SWAT_Table.SelectAntennaMap[1][priv->pshare->DM_SWAT_Table.mapIndex] = PreByteCnt; + } + + Score_R = Score_L=0; + for (i= 0; i<SELANT_MAP_SIZE; i++) { + Score_L += priv->pshare->DM_SWAT_Table.SelectAntennaMap[0][i]; + Score_R += priv->pshare->DM_SWAT_Table.SelectAntennaMap[1][i]; + } + + nextAntenna = (Score_L > Score_R) ? Antenna_L : Antenna_R; + + if(priv->pshare->rf_ft_var.ant_dump&8) + panic_printk("Mode TP, select Ant%d, [Score1=%d,Score2=%d]\n", nextAntenna, Score_L, Score_R); + + } + + //3 RSSI Mode: Determine the best anntena by RSSI + else if(priv->pshare->DM_SWAT_Table.TestMode == RSSI_MODE) { + + //2 Saperately caculate average RSSI for two antennas + RSSI_L = RSSI_R = 0; + + if(priv->pshare->RSSI_cnt_R > 0) + RSSI_R = priv->pshare->RSSI_sum_R/priv->pshare->RSSI_cnt_R; + if(priv->pshare->RSSI_cnt_L > 0) + RSSI_L = priv->pshare->RSSI_sum_L/priv->pshare->RSSI_cnt_L; + + if(RSSI_L && RSSI_R ) + nextAntenna = (RSSI_L > RSSI_R) ? Antenna_L : Antenna_R; + + if(priv->pshare->rf_ft_var.ant_dump&8) + panic_printk("Mode RSSI, RSSI_R=%d(%d), RSSI_L=%d(%d), Ant=%d\n", + RSSI_R, priv->pshare->RSSI_cnt_R, RSSI_L, priv->pshare->RSSI_cnt_L, nextAntenna); + + } + + //3 Reset state + resetSwAntDivVariable(priv); + priv->pshare->DM_SWAT_Table.try_flag = SWAW_STEP_PEAK; + priv->pshare->RSSI_test = FALSE; + } + } + + //1 Normal State + else if(priv->pshare->DM_SWAT_Table.try_flag == SWAW_STEP_PEAK) { + + //3 Determine TP/RSSI mode by TRX OK count + if((curRxOkCnt+curTxOkCnt) > TP_MODE_THD) { + //2 Determine current traffic is high or low + if((curTxOkCnt+curRxOkCnt) > TRAFFIC_THRESHOLD) + priv->pshare->TrafficLoad = TRAFFIC_HIGH; + else + priv->pshare->TrafficLoad = TRAFFIC_LOW; + + priv->pshare->DM_SWAT_Table.RSSI_Trying = 10; + priv->pshare->DM_SWAT_Table.TestMode = TP_MODE; + } else { + + int idx = 0; + struct stat_info* pEntry = findNextSTA(priv, &idx); + priv->pshare->RSSI_target = NULL; + while(pEntry) { + if(pEntry && pEntry->expire_to) { + if(!priv->pshare->RSSI_target) + priv->pshare->RSSI_target = pEntry; + else if( pEntry->rssi < priv->pshare->RSSI_target->rssi ) + priv->pshare->RSSI_target = pEntry; + } + pEntry = findNextSTA(priv, &idx); + }; + + priv->pshare->DM_SWAT_Table.RSSI_Trying = 6; + priv->pshare->DM_SWAT_Table.TestMode = RSSI_MODE; + + if(priv->pshare->RSSI_target == NULL) { + SwAntDivRestAfterLink(priv); + return; + } + + //3 reset state + memset(priv->pshare->DM_SWAT_Table.SelectAntennaMap, 0, sizeof(priv->pshare->DM_SWAT_Table.SelectAntennaMap)); + } + + //3 Begin to enter Try State + nextAntenna = (priv->pshare->DM_SWAT_Table.CurAntenna ) ^ Antenna_MAX; + priv->pshare->DM_SWAT_Table.try_flag = SWAW_STEP_DETERMINE; + priv->pshare->RSSI_test = TRUE; + + //3 Reset variables + resetSwAntDivVariable(priv); + } + } + +//1 4.Change TRX antenna + if(nextAntenna != priv->pshare->DM_SWAT_Table.CurAntenna) { + if (!priv->pshare->rf_ft_var.antSw_select) + PHY_SetBBReg(priv, rFPGA0_XA_RFInterfaceOE, 0x300, nextAntenna); + else + PHY_SetBBReg(priv, rFPGA0_XB_RFInterfaceOE, 0x300, nextAntenna); + } + +//1 5.Reset Statistics + priv->pshare->DM_SWAT_Table.CurAntenna = nextAntenna; + +//1 6.Set next timer + + if(priv->pshare->DM_SWAT_Table.RSSI_Trying == 0) { + return; + } + + if(priv->pshare->DM_SWAT_Table.TestMode == RSSI_MODE) { + mod_timer(&priv->pshare->swAntennaSwitchTimer, jiffies +40); // 400 ms + } else if(priv->pshare->DM_SWAT_Table.TestMode == TP_MODE) { + + if(priv->pshare->TrafficLoad == TRAFFIC_HIGH) { + if(priv->pshare->DM_SWAT_Table.RSSI_Trying%2 == 0) + mod_timer(&priv->pshare->swAntennaSwitchTimer, jiffies + 1); // 10 ms + else + mod_timer(&priv->pshare->swAntennaSwitchTimer, jiffies + 8); // 80 ms + + } else if(priv->pshare->TrafficLoad == TRAFFIC_LOW) { + if(priv->pshare->DM_SWAT_Table.RSSI_Trying%2 == 0) + mod_timer(&priv->pshare->swAntennaSwitchTimer, jiffies + 4); // 40 ms + else + mod_timer(&priv->pshare->swAntennaSwitchTimer, jiffies + 8); // 80 ms + } + } + +} + + +void dm_SW_AntennaSwitchCallback(unsigned long task_priv) +{ + struct rtl8192cd_priv *priv = (struct rtl8192cd_priv*)task_priv; + unsigned long flags; + SAVE_INT_AND_CLI(flags); + dm_SW_AntennaSwitch(priv, SWAW_STEP_DETERMINE); + RESTORE_INT(flags); +} + +// +// 20100514 Luke/Joseph: +// This function is used to gather the RSSI information for antenna testing. +// It selects the RSSI of the peer STA that we want to know. +// +void dm_SWAW_RSSI_Check(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo) +{ + struct stat_info* pEntry = NULL; + pEntry = get_stainfo(priv, GetAddr2Ptr(get_pframe(pfrinfo))); + + if((priv->pshare->RSSI_target==NULL)||(priv->pshare->RSSI_target==pEntry)) { + //1 RSSI for SW Antenna Switch + if(priv->pshare->DM_SWAT_Table.CurAntenna == Antenna_R) + { + priv->pshare->RSSI_sum_R += pfrinfo->rssi; + priv->pshare->RSSI_cnt_R++; + } else { + priv->pshare->RSSI_sum_L += pfrinfo->rssi; + priv->pshare->RSSI_cnt_L++; + } + } +} + +#ifndef HW_ANT_SWITCH + +int diversity_antenna_select(struct rtl8192cd_priv *priv, unsigned char *data) +{ + int ant = _atoi(data, 16); +// if(GET_CHIP_VER(priv) != VERSION_8188C) +// return 0; + +#ifdef PCIE_POWER_SAVING + PCIeWakeUp(priv, POWER_DOWN_T0); +#endif + if(ant==Antenna_L || ant==Antenna_R) { + if (!priv->pshare->rf_ft_var.antSw_select) + PHY_SetBBReg(priv, rFPGA0_XA_RFInterfaceOE, 0x300, ant); + else + PHY_SetBBReg(priv, rFPGA0_XB_RFInterfaceOE, 0x300, ant); + priv->pshare->DM_SWAT_Table.CurAntenna = ant; + priv->pshare->rf_ft_var.antSw_enable = 0; + SwAntDivRestAfterLink(priv); + memset(priv->pshare->DM_SWAT_Table.SelectAntennaMap, 0, sizeof(priv->pshare->DM_SWAT_Table.SelectAntennaMap)); + return 1; + } else { + priv->pshare->rf_ft_var.antSw_enable = 1; + priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; + priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; + + return 0; + } +} +#endif +#endif +#if defined(HW_ANT_SWITCH) + +void dm_HW_AntennaSwitchInit(struct rtl8192cd_priv *priv) +{ +#ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable =0; +#endif + + if (GET_CHIP_VER(priv) == VERSION_8188C) + priv->pshare->rf_ft_var.antSw_select = 0; + if ( !priv->pshare->rf_ft_var.antSw_select) { + RTL_W32(rFPGA0_XAB_RFParameter, RTL_R32(rFPGA0_XAB_RFParameter) | BIT(13) ); //select ANTESEL from path A + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) & ~(BIT(8)| BIT(9)) ); // ANTSEL as HW control + RTL_W32(rFPGA0_XA_RFInterfaceOE, (RTL_R32(rFPGA0_XA_RFInterfaceOE) & ~(BIT(8)|BIT(9)))| 0x01<<8 ); // 0x01: left antenna, 0x02: right antenna + RTL_W8(0xc50, RTL_R8(0xc50) | BIT(7)); // Enable Hardware antenna switch + RTL_W32(0xc54, RTL_R32(0xc54) | BIT(23) ); // Decide final antenna by comparing 2 antennas' pwdb + } else { + RTL_W32(rFPGA0_XAB_RFParameter, RTL_R32(rFPGA0_XAB_RFParameter) & ~ BIT(13) ); //select ANTESEL from path B + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) & ~(BIT(24)| BIT(25)) ); // ANTSEL as HW control + RTL_W32(rFPGA0_XB_RFInterfaceOE, (RTL_R32(rFPGA0_XB_RFInterfaceOE) & ~(BIT(8)|BIT(9)))| 0x01<<8 ); // 0x01: left antenna, 0x02: right antenna + RTL_W8(0xc58, RTL_R8(0xc58) | BIT(7)); // Enable Hardware antenna switch + RTL_W32(0xc5C, RTL_R32(0xc5c) | BIT(23) ); // Decide final antenna by comparing 2 antennas' pwdb + } + + priv->pshare->rf_ft_var.CurAntenna = 0; + + RTL_W32(LEDCFG, RTL_R32(LEDCFG) | BIT(23) ); //enable LED[1:0] pin as ANTSEL + RTL_W16(0xca4, (RTL_R16(0xca4) & ~(0xfff))|0x0c0); // Pwdb threshold=12dB + RTL_W32(0x874, RTL_R32(0x874) & ~ BIT(23) ); // No update ANTSEL during GNT_BT=1 + RTL_W16(rFPGA0_TxInfo, (RTL_R16(rFPGA0_TxInfo)&0xf0ff) | BIT(8) ); // b11-b8=0001 + RTL_W32(0x80c, RTL_R32(0x80c) | BIT(21) ); // assign antenna by tx desc + + // CCK setting + RTL_W8(0xa01, RTL_R8(0xa01) | BIT(7)); // enable hw ant diversity + RTL_W8(0xa0c, (RTL_R8(0xa0c) & 0xe0) | 0x0f ); // b4=0, b3:0 = 1111 32 sample + RTL_W8(0xa11, RTL_R8(0xa11) | BIT(5)); // do not change default optional antenna + RTL_W8(0xa14, (RTL_R8(0xa14) & 0xe0) | 0x08 ); // default : optional = 1:1 + +} + +void setRxIdleAnt(struct rtl8192cd_priv *priv, char Ant) +{ + if(priv->pshare->rf_ft_var.CurAntenna != Ant) { + if(Ant) { + RTL_W32(0x858, 0x65a965a9); +// RTL_W8(0x6d8, RTL_R8(0x6d8) | BIT(6) ); + } + else { + RTL_W32(0x858, 0x569a569a); +// RTL_W8(0x6d8, RTL_R8(0x6d8) & (~ BIT(6))); + } + priv->pshare->rf_ft_var.CurAntenna = Ant; + } +} + + +void dm_STA_Ant_Select(struct rtl8192cd_priv *priv, struct stat_info *pstat) +{ + int ScoreA=0, ScoreB=0, i, nextAnt= pstat->CurAntenna, idleAnt=priv->pshare->rf_ft_var.CurAntenna; + + if((priv->pshare->rf_ft_var.CurAntenna & 0x80) + || ((pstat->hwRxAntSel[0] + pstat->hwRxAntSel[1])==0 && (pstat->cckPktCount[0] + pstat->cckPktCount[1])<10) ) + return; + + for(i=0; i<2; i++) { + if(pstat->cckPktCount[i]==0 && pstat->hwRxAntSel[i]==0) + pstat->AntRSSI[i] = 0; + } + + if(pstat->hwRxAntSel[0] || pstat->hwRxAntSel[1]) { + ScoreA = pstat->hwRxAntSel[0]; + ScoreB = pstat->hwRxAntSel[1]; + + if(ScoreA != ScoreB) { + if(ScoreA > ScoreB) + nextAnt = 0; + else + nextAnt = 1; + } + } else { + ScoreA = pstat->cckPktCount[0]; + ScoreB = pstat->cckPktCount[1]; + + if(ScoreA > 5*ScoreB) + nextAnt = 0; + else if(ScoreB > 5*ScoreA) + nextAnt = 1; + else if(ScoreA > ScoreB) + nextAnt = 1; + else if(ScoreB > ScoreA) + nextAnt = 0; + } + + pstat->CurAntenna = nextAnt; + + if(priv->pshare->rf_ft_var.ant_dump&2) { + panic_printk("id=%d, OFDM/CCK: (%d, %d/%d, %d), RSSI:(%d, %d), ant=%d, RxIdle=%d\n", + pstat->aid, + pstat->hwRxAntSel[1], + pstat->hwRxAntSel[0], + pstat->cckPktCount[1], + pstat->cckPktCount[0], + pstat->AntRSSI[1], + pstat->AntRSSI[0], + (pstat->CurAntenna==0 ? 2: 1) + ,((priv->pshare->rf_ft_var.CurAntenna&1)==0 ? 2 : 1) + ); + } + + if(pstat->AntRSSI[idleAnt]==0) + pstat->AntRSSI[idleAnt] = pstat->AntRSSI[idleAnt^1]; + +// reset variables + pstat->hwRxAntSel[1] = pstat->hwRxAntSel[0] =0; + pstat->cckPktCount[1]= pstat->cckPktCount[0] =0; + + +} + +void dm_HW_IdleAntennaSelect(struct rtl8192cd_priv *priv) +{ + struct stat_info *pstat, *pstat_min=NULL; + struct list_head *phead, *plist; + int rssi_min= 0xff, i; + + if(priv->pshare->rf_ft_var.CurAntenna & 0x80) + return; + + phead = &priv->asoc_list; + plist = phead->next; + + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + if((pstat->expire_to) && (pstat->AntRSSI[0] || pstat->AntRSSI[1])) { + int rssi = (pstat->AntRSSI[0] < pstat->AntRSSI[1]) ? pstat->AntRSSI[0] : pstat->AntRSSI[1]; + if((!pstat_min) || ( rssi < rssi_min) ) { + pstat_min = pstat; + rssi_min = rssi; + } + } + if (plist == plist->next) + break; + plist = plist->next; + }; + + if(pstat_min) + setRxIdleAnt(priv, pstat_min->CurAntenna); + + +#ifdef TX_SHORTCUT + if (!priv->pmib->dot11OperationEntry.disable_txsc) { + plist = phead->next; + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + if(pstat->expire_to) { + for (i=0; i<TX_SC_ENTRY_NUM; i++) { + struct tx_desc *pdesc= &(pstat->tx_sc_ent[i].hwdesc1); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + pdesc= &(pstat->tx_sc_ent[i].hwdesc2); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + } + } + + if (plist == plist->next) + break; + plist = plist->next; + }; + } +#endif + +} + + + +int diversity_antenna_select(struct rtl8192cd_priv *priv, unsigned char *data) +{ + int ant = _atoi(data, 16); + +#ifdef PCIE_POWER_SAVING + PCIeWakeUp(priv, POWER_DOWN_T0); +#endif + + if (ant==Antenna_L || ant==Antenna_R) { + if ( !priv->pshare->rf_ft_var.antSw_select) { + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) | BIT(8)| BIT(9) ); // ANTSEL A as SW control + RTL_W8(0xc50, RTL_R8(0xc50) & (~ BIT(7))); // rx OFDM SW control + PHY_SetBBReg(priv, rFPGA0_XA_RFInterfaceOE, 0x300, ant); + } else { + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) | BIT(24)| BIT(25) ); // ANTSEL B as HW control + PHY_SetBBReg(priv, rFPGA0_XB_RFInterfaceOE, 0x300, ant); + RTL_W8(0xc58, RTL_R8(0xc58) & (~ BIT(7))); // rx OFDM SW control + } + RTL_W8(0xa01, RTL_R8(0xa01) & (~ BIT(7))); // rx CCK SW control + RTL_W32(0x80c, RTL_R32(0x80c) & (~ BIT(21))); // select ant by tx desc + RTL_W32(0x858, 0x569a569a); + + priv->pshare->rf_ft_var.antHw_enable = 0; + priv->pshare->rf_ft_var.CurAntenna = (ant%2); + +#ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable = 0; + priv->pshare->DM_SWAT_Table.CurAntenna = ant; + priv->pshare->RSSI_test =0; +#endif + } + else if(ant==0){ + if ( !priv->pshare->rf_ft_var.antSw_select) { + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) & ~(BIT(8)| BIT(9)) ); + RTL_W8(0xc50, RTL_R8(0xc50) | BIT(7)); // OFDM HW control + } else { + RTL_W32(rFPGA0_XAB_RFInterfaceSW, RTL_R32(rFPGA0_XAB_RFInterfaceSW) & ~(BIT(24)| BIT(25)) ); + RTL_W8(0xc58, RTL_R8(0xc58) | BIT(7)); // OFDM HW control + } + + RTL_W8(0xa01, RTL_R8(0xa01) | BIT(7)); // CCK HW control + RTL_W32(0x80c, RTL_R32(0x80c) | BIT(21) ); // by tx desc + priv->pshare->rf_ft_var.CurAntenna = 0; + RTL_W32(0x858, 0x569a569a); + priv->pshare->rf_ft_var.antHw_enable = 1; +#ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable = 0; + priv->pshare->RSSI_test =0; +#endif + } +#ifdef SW_ANT_SWITCH + else if(ant==3) { + if(!priv->pshare->rf_ft_var.antSw_enable) { + dm_SW_AntennaSwitchInit(priv); + RTL_W32(0x858, 0x569a569a); + priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; + priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; + } + if ( !priv->pshare->rf_ft_var.antSw_select) + RTL_W8(0xc50, RTL_R8(0xc50) & (~ BIT(7))); // rx OFDM SW control + else + RTL_W8(0xc58, RTL_R8(0xc58) & (~ BIT(7))); // rx OFDM SW control + + RTL_W8(0xa01, RTL_R8(0xa01) & (~ BIT(7))); // rx CCK SW control + RTL_W32(0x80c, RTL_R32(0x80c) & (~ BIT(21))); // select ant by tx desc + priv->pshare->rf_ft_var.antHw_enable = 0; + priv->pshare->rf_ft_var.antSw_enable = 1; + + } +#endif + + return 1; +} + +#endif + + |