Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ea417ae authored by Shahar Levi's avatar Shahar Levi Committed by Luciano Coelho
Browse files

wl12xx: 1281/1283 support - New boot sequence



Boot sequence support FREF clock and TCXO clock.
WL128x has two clocks input - TCXO and FREF.
TCXO is the main clock of the device, while FREF is used to sync
between the GPS and the cellular modem.
Auto-detection checks where TCXO is 32.736MHz or 16.368MHz, in that
case the FREF will be used as the WLAN/BT main clock.

[Use clock enumeration as defined in linux/wl12xx.h; remove
unnecessary else block in wl128x_switch_fref; remove unnecessary
change in main.c; remove some unnecessary debug prints and comments;
fix potential use of uninitialized value (pll_config) -- Luca]

Signed-off-by: default avatarShahar Levi <shahar_levi@ti.com>
Reviewed-by: default avatarLuciano Coelho <coelho@ti.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent bc765bf3
Loading
Loading
Loading
Loading
+175 −8
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 */

#include <linux/slab.h>
#include <linux/wl12xx.h>

#include "acx.h"
#include "reg.h"
@@ -520,24 +521,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl)
		wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
}

/* uploads NVS and firmware */
int wl1271_load_firmware(struct wl1271 *wl)
/*
 * WL128x has two clocks input - TCXO and FREF.
 * TCXO is the main clock of the device, while FREF is used to sync
 * between the GPS and the cellular modem.
 * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
 * as the WLAN/BT main clock.
 */
static int wl128x_switch_fref(struct wl1271 *wl, bool *is_ref_clk)
{
	int ret = 0;
	u32 tmp, clk, pause;
	u16 sys_clk_cfg_val;

	/* if working on XTAL-only mode go directly to TCXO TO FREF SWITCH */
	if ((wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) ||
	    (wl->ref_clock == CONF_REF_CLK_26_M_XTAL))
		return true;

	/* Read clock source FREF or TCXO */
	sys_clk_cfg_val = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG);

	if (sys_clk_cfg_val & PRCM_CM_EN_MUX_WLAN_FREF) {
		/* if bit 3 is set - working with FREF clock */
		wl1271_debug(DEBUG_BOOT, "working with FREF clock, skip"
			     " to FREF");

		*is_ref_clk = true;
	} else {
		/* if bit 3 is clear - working with TCXO clock */
		wl1271_debug(DEBUG_BOOT, "working with TCXO clock");

		/* TCXO to FREF switch, check TXCO clock config */
		if ((wl->tcxo_clock != WL12XX_TCXOCLOCK_16_368) &&
		    (wl->tcxo_clock != WL12XX_TCXOCLOCK_32_736)) {
			/*
			 * not 16.368Mhz and not 32.736Mhz - skip to
			 * configure ELP stage
			 */
			wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:"
				     " TcxoRefClk=%d - not 16.368Mhz and not"
				     " 32.736Mhz - skip to configure ELP"
				     " stage", wl->tcxo_clock);

			*is_ref_clk = false;
		} else {
			wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:"
				     "TcxoRefClk=%d - 16.368Mhz or 32.736Mhz"
				     " - TCXO to FREF switch",
				     wl->tcxo_clock);

			return true;
		}
	}

	return false;
}

static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk)
{
	if (wl128x_switch_fref(wl, is_ref_clk)) {
		wl1271_debug(DEBUG_BOOT, "XTAL-only mode go directly to"
					 " TCXO TO FREF SWITCH");
		/* TCXO to FREF switch - for PG2.0 */
		wl1271_top_reg_write(wl, WL_SPARE_REG,
				     WL_SPARE_MASK_8526);

		wl1271_top_reg_write(wl, SYS_CLK_CFG_REG,
			WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);

		*is_ref_clk = true;
		mdelay(15);
	}

	/* Set bit 2 in spare register to avoid illegal access */
	wl1271_top_reg_write(wl, WL_SPARE_REG, WL_SPARE_VAL);

	/* working with TCXO clock */
	if ((*is_ref_clk == false) &&
	    ((wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8) ||
	     (wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6))) {
		wl1271_debug(DEBUG_BOOT, "16_8_M or 33_6_M TCXO detected");

		/* Manually Configure MCS PLL settings PG2.0 Only */
		wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
		wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
		wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG,
				     MCS_PLL_CONFIG_REG_VAL);
	} else {
		int pll_config;
		u16 mcs_pll_config_val;

		/*
		 * Configure MCS PLL settings to FREF Freq
		 * Set the values that determine the time elapse since the PLL's
		 * get their enable signal until the lock indication is set
		 */
		wl1271_top_reg_write(wl, PLL_LOCK_COUNTERS_REG,
			PLL_LOCK_COUNTERS_COEX | PLL_LOCK_COUNTERS_MCS);

		mcs_pll_config_val = wl1271_top_reg_read(wl,
						 MCS_PLL_CONFIG_REG);
		/*
		 * Set the MCS PLL input frequency value according to the
		 * reference clock value detected/read
		 */
		if (*is_ref_clk == false) {
			if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_19_2) ||
			    (wl->tcxo_clock == WL12XX_TCXOCLOCK_38_4))
				pll_config = 1;
			else if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_26)
				 ||
				 (wl->tcxo_clock == WL12XX_TCXOCLOCK_52))
				pll_config = 2;
			else
				return -EINVAL;
		} else {
			if ((wl->ref_clock == CONF_REF_CLK_19_2_E) ||
			    (wl->ref_clock == CONF_REF_CLK_38_4_E))
				pll_config = 1;
			else if ((wl->ref_clock == CONF_REF_CLK_26_E) ||
				 (wl->ref_clock == CONF_REF_CLK_52_E))
				pll_config = 2;
			else
				return -EINVAL;
		}

		mcs_pll_config_val |= (pll_config << (MCS_SEL_IN_FREQ_SHIFT)) &
				      (MCS_SEL_IN_FREQ_MASK);
		wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG,
				     mcs_pll_config_val);
	}

	return 0;
}

static int wl127x_boot_clk(struct wl1271 *wl)
{
	u32 pause;
	u32 clk;

	wl1271_boot_hw_version(wl);

	if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4)
	if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
	    wl->ref_clock == CONF_REF_CLK_38_4_E ||
	    wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
		/* ref clk: 19.2/38.4/38.4-XTAL */
		clk = 0x3;
	else if (wl->ref_clock == 1 || wl->ref_clock == 3)
	else if (wl->ref_clock == CONF_REF_CLK_26_E ||
		 wl->ref_clock == CONF_REF_CLK_52_E)
		/* ref clk: 26/52 */
		clk = 0x5;
	else
		return -EINVAL;

	if (wl->ref_clock != 0) {
	if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
		u16 val;
		/* Set clock type (open drain) */
		val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -567,6 +703,26 @@ int wl1271_load_firmware(struct wl1271 *wl)
	pause |= WU_COUNTER_PAUSE_VAL;
	wl1271_write32(wl, WU_COUNTER_PAUSE, pause);

	return 0;
}

/* uploads NVS and firmware */
int wl1271_load_firmware(struct wl1271 *wl)
{
	int ret = 0;
	u32 tmp, clk;
	bool is_ref_clk = false;

	if (wl->chip.id == CHIP_ID_1283_PG20) {
		ret = wl128x_boot_clk(wl, &is_ref_clk);
		if (ret < 0)
			goto out;
	} else {
		ret = wl127x_boot_clk(wl);
		if (ret < 0)
			goto out;
	}

	/* Continue the ELP wake up sequence */
	wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
	udelay(500);
@@ -582,7 +738,15 @@ int wl1271_load_firmware(struct wl1271 *wl)

	wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);

	if (wl->chip.id == CHIP_ID_1283_PG20) {
		if (is_ref_clk == false)
			clk |= ((wl->tcxo_clock & 0x3) << 1) << 4;
		else
			clk |= ((wl->ref_clock & 0x3) << 1) << 4;
	} else {
		clk |= (wl->ref_clock << 1) << 4;
	}

	wl1271_write32(wl, DRPW_SCRATCH_START, clk);

	wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -615,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl)
	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
	 * to upload_fw) */

	if (wl->chip.id == CHIP_ID_1283_PG20)
		wl1271_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);

	ret = wl1271_boot_upload_firmware(wl);
	if (ret < 0)
		goto out;
+1 −0
Original line number Diff line number Diff line
@@ -255,6 +255,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,

	wl->irq = wlan_data->irq;
	wl->ref_clock = wlan_data->board_ref_clock;
	wl->tcxo_clock = wlan_data->board_tcxo_clock;

	ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+1 −0
Original line number Diff line number Diff line
@@ -421,6 +421,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,

	wl->irq = wlan_data->irq;
	wl->ref_clock = wlan_data->board_ref_clock;
	wl->tcxo_clock = wlan_data->board_tcxo_clock;

	sdio_set_drvdata(func, wl_test);

+1 −0
Original line number Diff line number Diff line
@@ -401,6 +401,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
	}

	wl->ref_clock = pdata->board_ref_clock;
	wl->tcxo_clock = pdata->board_tcxo_clock;

	wl->irq = spi->irq;
	if (wl->irq < 0) {
+1 −0
Original line number Diff line number Diff line
@@ -535,6 +535,7 @@ struct wl1271 {
	u8 ba_rx_bitmap;

	u32 block_size;
	int tcxo_clock;

	/*
	 * AP-mode - links indexed by HLID. The global and broadcast links