summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d538423)
raw | patch | inline | side by side (parent: d538423)
author | Ido Reis <idor@ti.com> | |
Sun, 22 Apr 2012 17:45:52 +0000 (20:45 +0300) | ||
committer | Ido Reis <idor@ti.com> | |
Sun, 13 May 2012 16:54:29 +0000 (19:54 +0300) |
pg2 is recognized with its unique chip id.
pg2 differ from pg1 in some control registers and addresses.
the difference in addressing in now maintained as a private struct
in the wl18xx_pric struct, that is assigned after recognizing the chip.
the yield workaround uses the specific struct to use the appropriate
addresses.
since pg2 suppose to work without the yield workaround, a new module
parameter is added, disable_yield_fix, that if assigned to true, the
workaround is discarded. default value is false.
Signed-off-by: Ido Reis <idor@ti.com>
pg2 differ from pg1 in some control registers and addresses.
the difference in addressing in now maintained as a private struct
in the wl18xx_pric struct, that is assigned after recognizing the chip.
the yield workaround uses the specific struct to use the appropriate
addresses.
since pg2 suppose to work without the yield workaround, a new module
parameter is added, disable_yield_fix, that if assigned to true, the
workaround is discarded. default value is false.
Signed-off-by: Ido Reis <idor@ti.com>
drivers/net/wireless/ti/wl18xx/main.c | patch | blob | history | |
drivers/net/wireless/ti/wl18xx/reg.h | patch | blob | history | |
drivers/net/wireless/ti/wl18xx/wl18xx.h | patch | blob | history |
index 31bd4766acf0ddc485c61d475123fd1fb546d84f..5cffbf901bfe2af2b7695e80304d40f4246ad930 100644 (file)
static int high_band_component = -1;
static int high_band_component_type = -1;
static int pwr_limit_reference_11_abg = -1;
+static bool disable_yield_fix = true;
static const u8 wl18xx_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
},
[PART_PHY_PDSP_WA] = {
.mem = { .start = 0x00940100, .size = 0x00000200 },
- .reg = { .start = 0x00953000, .size = 0x00012000 },
+ .reg = { .start = 0x00953000, .size = 0x00018000 },
.mem2 = { .start = 0x00000000, .size = 0x00000000 },
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
},
};
+static const struct wl18xx_phy_addresses wl18xx_phy_addresses_pg1 = {
+ .phy_hram_rd_en = WL18XX_PHY_HRAM_RD_EN_PER_RAM,
+ .pdsp_ctrl_reg = WL18XX_PDSP_CONTROL_REG_PG1,
+ .pdsp_ram = WL18XX_FDSP_RAM,
+ .prcm_bt_pwr_rst = WL18XX_PRCM_BT_PWR_RST,
+ .ip_sel_ov_en = WL18XX_IP_SEL_OV_EN,
+ .ip_ov_en = WL18XX_IP_OV_EN,
+};
+
+static const struct wl18xx_phy_addresses wl18xx_phy_addresses_pg2 = {
+ .phy_hram_rd_en = WL18XX_PHY_HRAM_RD_EN_PER_RAM,
+ .pdsp_ctrl_reg = WL18XX_PDSP_CONTROL_REG_PG2,
+ .pdsp_ram = WL18XX_FDSP_RAM,
+ .prcm_bt_pwr_rst = WL18XX_PRCM_BT_PWR_RST,
+ .ip_sel_ov_en = WL18XX_IP_SEL_OV_EN,
+ .ip_ov_en = WL18XX_IP_OV_EN,
+};
+
static const int wl18xx_rtable[REG_TABLE_LEN] = {
[REG_ECPU_CONTROL] = WL18XX_REG_ECPU_CONTROL,
[REG_INTERRUPT_NO_CLEAR] = WL18XX_REG_INTERRUPT_NO_CLEAR,
static int wl18xx_identify_chip(struct wl1271 *wl)
{
int ret = 0;
+ struct wl18xx_priv *priv = wl->priv;
switch (wl->chip.id) {
+ case CHIP_ID_185x_PG20:
+ wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
+ wl->chip.id);
+ wl->sr_fw_name = WL18XX_FW_NAME;
+ /* wl18xx uses the same firmware for PLT */
+ wl->plt_fw_name = WL18XX_FW_NAME;
+ wl->quirks |= WLCORE_QUIRK_NO_ELP |
+ WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED |
+ WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN;
+
+ memcpy(&priv->phy_addresses, &wl18xx_phy_addresses_pg2,
+ sizeof(struct wl18xx_phy_addresses));
+
+ /* TODO: need to blocksize alignment for RX/TX separately? */
+ break;
case CHIP_ID_185x_PG10:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)",
wl->chip.id);
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED |
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN;
+ memcpy(&priv->phy_addresses, &wl18xx_phy_addresses_pg1,
+ sizeof(struct wl18xx_phy_addresses));
+
/* PG 1.0 has some problems with MCS_13, so disable it */
wl->ht_cap.mcs.rx_mask[1] &= ~BIT(5);
static int wl18xx_pdsp_reset(struct wl1271 *wl)
{
int status;
+ struct wl18xx_priv *priv = wl->priv;
+ struct wl18xx_phy_addresses *phy_addr = &priv->phy_addresses;
wl1271_debug(DEBUG_BOOT, "reset PDSP");
- wl1271_write32(wl, WL18XX_PDSP_CONTROL_REG, WL18XX_PDSP_ENABLE);
- wl1271_write32(wl, WL18XX_PDSP_CONTROL_REG, WL18XX_PDSP_DISABLE);
- wl1271_write32(wl, WL18XX_PDSP_CONTROL_REG, WL18XX_PDSP_ENABLE);
- wl1271_write32(wl, WL18XX_PDSP_CONTROL_REG, WL18XX_PDSP_DISABLE);
+ wl1271_write32(wl, phy_addr->pdsp_ctrl_reg, WL18XX_PDSP_ENABLE);
+ wl1271_write32(wl, phy_addr->pdsp_ctrl_reg, WL18XX_PDSP_DISABLE);
+ wl1271_write32(wl, phy_addr->pdsp_ctrl_reg, WL18XX_PDSP_ENABLE);
+ wl1271_write32(wl, phy_addr->pdsp_ctrl_reg, WL18XX_PDSP_DISABLE);
/* validate PDSP reset */
- wl1271_write32(wl, WL18XX_FDSP_RAM, WL18XX_FDSP_RAM_VAL);
- status = wl1271_read32(wl, WL18XX_FDSP_RAM);
+ wl1271_write32(wl, phy_addr->pdsp_ram, WL18XX_FDSP_RAM_VAL);
+ status = wl1271_read32(wl, phy_addr->pdsp_ram);
if (status == WL18XX_FDSP_RAM_VAL) {
wl1271_debug(DEBUG_BOOT, "OCP bridge ready");
return 0;
static int wl18xx_phy_core_reset(struct wl1271 *wl)
{
int ocp_state;
+ struct wl18xx_priv *priv = wl->priv;
+ struct wl18xx_phy_addresses *phy_addr = &priv->phy_addresses;
wl1271_debug(DEBUG_BOOT, "reset wl phy core");
wlcore_set_partition(wl, &wl->ptable[PART_PHY_PDSP_WA]);
- ocp_state = wl1271_read32(wl, WL18XX_PHY_HRAM_RD_EN_PER_RAM);
+ ocp_state = wl1271_read32(wl, phy_addr->phy_hram_rd_en);
if (!ocp_state)
return -EIO;
wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
- wl18xx_top_reg_write(wl, WL18XX_IP_SEL_OV_EN, WL18XX_WL_PHY_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_OV_EN, WL18XX_WL_PHY_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_sel_ov_en, WL18XX_WL_PHY_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_ov_en, WL18XX_WL_PHY_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_SEL_OV_EN, WL18XX_RM_OVERRIDE);
- wl18xx_top_reg_write(wl, WL18XX_IP_OV_EN, WL18XX_RM_OVERRIDE);
+ wl18xx_top_reg_write(wl, phy_addr->ip_sel_ov_en, WL18XX_RM_OVERRIDE);
+ wl18xx_top_reg_write(wl, phy_addr->ip_ov_en, WL18XX_RM_OVERRIDE);
return -EAGAIN;
}
static int wl18xx_bt_core_reset(struct wl1271 *wl)
{
int ocp_state, status;
+ struct wl18xx_priv *priv = wl->priv;
+ struct wl18xx_phy_addresses *phy_addr = &priv->phy_addresses;
wl1271_debug(DEBUG_BOOT, "reset bt core");
wlcore_set_partition(wl, &wl->ptable[PART_PHY_PDSP_WA]);
- ocp_state = wl1271_read32(wl, WL18XX_PHY_HRAM_RD_EN_PER_RAM);
+ ocp_state = wl1271_read32(wl, phy_addr->phy_hram_rd_en);
if (!ocp_state)
return -EIO;
wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
/* check if BT is disabled */
- status = wl18xx_top_reg_read(wl, WL18XX_PRCM_BT_PWR_RST);
+ status = wl18xx_top_reg_read(wl, phy_addr->prcm_bt_pwr_rst);
if (status != 0)
return -EACCES;
- wl18xx_top_reg_write(wl, WL18XX_IP_SEL_OV_EN, WL18XX_WL_PHY_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_OV_EN, WL18XX_BT_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_sel_ov_en, WL18XX_WL_PHY_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_ov_en, WL18XX_BT_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_SEL_OV_EN, WL18XX_BT_WL_PHY_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_OV_EN, WL18XX_BT_WL_PHY_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_sel_ov_en,
+ WL18XX_BT_WL_PHY_PWR_REQ);
+ wl18xx_top_reg_write(wl, phy_addr->ip_ov_en, WL18XX_BT_WL_PHY_PWR_REQ);
- wl18xx_top_reg_write(wl, WL18XX_IP_SEL_OV_EN, WL18XX_RM_OVERRIDE);
- wl18xx_top_reg_write(wl, WL18XX_IP_OV_EN, WL18XX_RM_OVERRIDE);
+ wl18xx_top_reg_write(wl, phy_addr->ip_sel_ov_en, WL18XX_RM_OVERRIDE);
+ wl18xx_top_reg_write(wl, phy_addr->ip_ov_en, WL18XX_RM_OVERRIDE);
return -EAGAIN;
}
static int wl18xx_release_ocp_bridge(struct wl1271 *wl)
{
int ocp_state, i, status;
+ struct wl18xx_priv *priv = wl->priv;
+ struct wl18xx_phy_addresses *phy_addr = &priv->phy_addresses;
wl1271_debug(DEBUG_BOOT, "release OCP bridge");
}
wlcore_set_partition(wl, &wl->ptable[PART_PHY_PDSP_WA]);
- ocp_state = wl1271_read32(wl, WL18XX_PHY_HRAM_RD_EN_PER_RAM);
+ ocp_state = wl1271_read32(wl, phy_addr->phy_hram_rd_en);
if (ocp_state == WL18XX_H_RAM_ENABLED)
goto out;
static int wl18xx_pre_boot(struct wl1271 *wl)
{
wl18xx_set_clk(wl);
+ int ret;
+
+ if (wl->chip.id == CHIP_ID_185x_PG20) {
+ if (disable_yield_fix)
+ goto elp_wakeup;
+ ret = wl18xx_release_ocp_bridge(wl);
+ if (ret < 0)
+ return ret;
+ }
if (wl->chip.id == CHIP_ID_185x_PG10) {
- int ret = wl18xx_release_ocp_bridge(wl);
+ ret = wl18xx_release_ocp_bridge(wl);
if (ret < 0)
return ret;
}
+elp_wakeup:
/* Continue the ELP wake up sequence */
wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
"(default is 0xc8)");
+module_param(disable_yield_fix, bool, S_IRUSR);
+MODULE_PARM_DESC(disable_yield_fix, "disable yield issue workaround: bool "
+ "(default is false)");
+
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_FIRMWARE(WL18XX_FW_NAME);
index 010ef07896d7a063d868fc85f7d8e67d87b25506..3bb5b7c17a1f8247a6a1ebab606a5ac96fb919d0 100644 (file)
#define WL18XX_PHY_INIT_MEM_ADDR 0x80926000
-#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
-#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
-#define WL18XX_WGCM_REGS_BASE (WL18XX_REGISTERS_BASE + 0x03000)
+#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
+#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
+#define WL18XX_WGCM_REGS_BASE (WL18XX_REGISTERS_BASE + 0x03000)
#define WL18XX_ENC_BASE (WL18XX_REGISTERS_BASE + 0x04000)
-#define WL18XX_INTERRUPT_BASE (WL18XX_REGISTERS_BASE + 0x05000)
+#define WL18XX_INTERRUPT_BASE (WL18XX_REGISTERS_BASE + 0x05000)
#define WL18XX_UART_BASE (WL18XX_REGISTERS_BASE + 0x06000)
#define WL18XX_WELP_BASE (WL18XX_REGISTERS_BASE + 0x07000)
-#define WL18XX_TCP_CKSM_BASE (WL18XX_REGISTERS_BASE + 0x08000)
+#define WL18XX_TCP_CKSM_BASE (WL18XX_REGISTERS_BASE + 0x08000)
#define WL18XX_FIFO_BASE (WL18XX_REGISTERS_BASE + 0x09000)
-#define WL18XX_OCP_BRIDGE_BASE (WL18XX_REGISTERS_BASE + 0x0A000)
+#define WL18XX_OCP_BRIDGE_BASE (WL18XX_REGISTERS_BASE + 0x0A000)
#define WL18XX_PMAC_RX_BASE (WL18XX_REGISTERS_BASE + 0x14800)
-#define WL18XX_PMAC_ACM_BASE (WL18XX_REGISTERS_BASE + 0x14C00)
+#define WL18XX_PMAC_ACM_BASE (WL18XX_REGISTERS_BASE + 0x14C00)
#define WL18XX_PMAC_TX_BASE (WL18XX_REGISTERS_BASE + 0x15000)
-#define WL18XX_PMAC_CSR_BASE (WL18XX_REGISTERS_BASE + 0x15400)
+#define WL18XX_PMAC_CSR_BASE (WL18XX_REGISTERS_BASE + 0x15400)
#define WL18XX_REG_ECPU_CONTROL (WL18XX_REGISTERS_BASE + 0x02004)
#define WL18XX_REG_INTERRUPT_NO_CLEAR (WL18XX_REGISTERS_BASE + 0x050E8)
#define WL18XX_FW_STATUS_ADDR 0x50F8
#define CHIP_ID_185x_PG10 (0x06030101)
+#define CHIP_ID_185x_PG20 (0x06030111)
/* wl18xx OCP bridge */
#define WL18XX_PHY_HRAM_RD_EN_PER_RAM 0x0095380C
-#define WL18XX_PDSP_CONTROL_REG 0x00964400
-#define WL18XX_FDSP_RAM 0x00940100
-#define WL18XX_FDSP_RAM_VAL 0xA5A5A5A5
+#define WL18XX_PDSP_CONTROL_REG_PG1 0x00964400
+#define WL18XX_PDSP_CONTROL_REG_PG2 0x00968400
+#define WL18XX_FDSP_RAM 0x00940100
#define WL18XX_PRCM_BT_PWR_RST 0xA0240A
#define WL18XX_IP_SEL_OV_EN 0xA021FE
#define WL18XX_IP_OV_EN 0xA021FC
+
+#define WL18XX_FDSP_RAM_VAL 0xA5A5A5A5
#define WL18XX_WL_PHY_PWR_REQ 0x400
#define WL18XX_BT_PWR_REQ 0x7800
#define WL18XX_BT_WL_PHY_PWR_REQ 0x7C00
+
#define WL18XX_RM_OVERRIDE 0
#define WL18XX_H_RAM_ENABLED 0x3F
#define WL18XX_PDSP_ENABLE 0x00000007
index 34e202bc2bb33ac90b95e8dc051e0d39ca9dc5d2..8829e918dfea88565acdd469640959105cf05cad 100644 (file)
#define WL18XX_CMD_MAX_SIZE 740
+struct wl18xx_phy_addresses {
+ u32 phy_hram_rd_en;
+ u32 pdsp_ctrl_reg;
+ u32 pdsp_ram;
+ u32 prcm_bt_pwr_rst;
+ u32 ip_sel_ov_en;
+ u32 ip_ov_en;
+};
+
struct wl18xx_priv {
/* buffer for sending commands to FW */
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
u8 last_fw_rls_idx;
u8 board_type;
+
+ struct wl18xx_phy_addresses phy_addresses;
};
#define WL18XX_FW_MAX_TX_STATUS_DESC 33