12f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo/*
280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo * This file is part of wl1251
32f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
42f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Copyright (C) 2008 Nokia Corporation
52f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
62f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is free software; you can redistribute it and/or
72f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * modify it under the terms of the GNU General Public License
82f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * version 2 as published by the Free Software Foundation.
92f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
102f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is distributed in the hope that it will be useful, but
112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of
122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * General Public License for more details.
142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * You should have received a copy of the GNU General Public License
162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * along with this program; if not, write to the Free Software
172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
182f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 02110-1301 USA
192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
202f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo */
212f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
249bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "reg.h"
259bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "boot.h"
269bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "io.h"
279bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "spi.h"
289bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "event.h"
299bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "acx.h"
302f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
3180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valovoid wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
322f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
3380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
3480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
3780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_boot_soft_reset(struct wl1251 *wl)
382f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
392f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	unsigned long timeout;
402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	u32 boot_data;
412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
422f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* perform soft reset */
4380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
442f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
452f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* SOFT_RESET is self clearing */
462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	while (1) {
4880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
4980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
502f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
512f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			break;
522f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		if (time_after(jiffies, timeout)) {
542f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			/* 1.2 check pWhalBus->uSelfClearTime if the
552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			 * timeout was reached */
5680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo			wl1251_error("soft reset timeout");
572f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			return -1;
582f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		}
592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		udelay(SOFT_RESET_STALL_TIME);
612f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* disable Rx/Tx */
6480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ENABLE, 0x0);
652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* disable auto calibration on start*/
6780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, SPARE_A2, 0xffff);
682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
702f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
7280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_boot_init_seq(struct wl1251 *wl)
732f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
752f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
762f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #1: INTEGER_DIVIDER
782f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #2: FRACTIONAL_DIVIDER
792f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #3: ATTN_BB
802f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #4: ALPHA_BB
812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #5: STOP_TIME_BB
822f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * col #6: BB_PLL_LOOP_FILTER
832f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
842f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = {
852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
862f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		{   83, 87381,  0xB, 5, 0xF00,  3}, /* REF_FREQ_19_2*/
872f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		{   61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/
882f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		{   41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/
892f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		{   40, 0,      0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/
902f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		{   47, 162280, 0xC, 6, 0x2760, 1}  /* REF_FREQ_33_6        */
912f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	};
922f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
932f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* read NVS params */
9480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
9580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
962f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
972f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* read ELP_CMD */
9880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
9980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
1002f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1012f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
1022f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	ref_freq = scr_pad6 & 0x000000FF;
10380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
1042f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
10580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
1062f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1072f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1082f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
1092f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
11080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
1112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set the clock detect feature to work in the restart wu procedure
1142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * (ELP_CFG_MODE[14]) and Select the clock source type
1152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * (ELP_CFG_MODE[13:12])
1162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
11880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
1192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1202f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
1212f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	elp_cmd |= 0x00000040;
12280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
1232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1242f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* PG 1.2: Set the BB PLL stable time to be 1000usec
1252f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * (PLL_STABLE_TIME) */
12680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
1272f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1282f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* PG 1.2: read clock request time */
12980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
1302f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1312f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1322f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * PG 1.2: set the clock request time to be ref_clk_settling_time -
1332f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * 1ms = 4ms
1342f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (init_data > 0x21)
1362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		tmp = init_data - 0x21;
1372f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	else
1382f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		tmp = 0;
13980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
1402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set BB PLL configurations in RF AFE */
14280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
1432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1442f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set RF_AFE_REG_5 */
14580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x003058d4, 0x50);
1462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set RF_AFE_CTRL_REG_2 */
14880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305948, 0x11c001);
1492f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1502f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1512f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * change RF PLL and BB PLL divider for VCO clock and adjust VCO
1522f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * bais current(RF_AFE_REG_13)
1532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
15480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x003058f4, 0x1e);
1552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1562f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set BB PLL configurations */
1572f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
15880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305840, tmp);
1592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set fractional divider according to Appendix C-BB PLL
1612f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * Calculations
1622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
16480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305844, tmp);
1652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set the initial data for the sigma delta */
16780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305848, 0x3039);
1682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1702f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set the accumulator attenuation value, calibration loop1
1712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and
1722f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * the VCO gain
1732f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
1752f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		(LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
17680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305854, tmp);
1772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1782f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1792f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set the calibration stop time after holdoff time expires and set
1802f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * settling time HOLD_OFF_TIME_BB
1812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1822f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
18380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x00305858, tmp);
1842f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1862f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
1872f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * constant leakage current to linearize PFD to 0uA -
1882f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * BB_ILOOPF[7:3]
1892f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
1902f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
19180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x003058f8, tmp);
1922f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1932f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
1942f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set regulator output voltage for n divider to
1952f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2],
1962f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
1972f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
1982f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
19980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, 0x003058f0, 0x29);
2002f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2012f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* enable restart wakeup sequence (ELP_CMD[0]) */
20280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
2032f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2042f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* restart sequence completed */
2052f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	udelay(2000);
2062f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2072f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
2082f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
2092f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
2110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
2120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	u32 cpu_ctrl;
2130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.5.0 run the firmware (I) */
2150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
2160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.5.1 run the firmware (II) */
2180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	cpu_ctrl &= ~flag;
2190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
2200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
2210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
22280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_boot_run_firmware(struct wl1251 *wl)
2232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
2242f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int loop, ret;
2251ab36d68e37faa431d99a07cbfb477a48879934eJohn W. Linville	u32 chip_id, acx_intr;
2262f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
2282f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
22980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
2302f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
23180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
2322f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (chip_id != wl->chip_id) {
23480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_error("chip id doesn't match after firmware boot");
2352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return -EIO;
2362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
2372f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2382f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* wait for init to complete */
2392f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	loop = 0;
2402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	while (loop++ < INIT_LOOP) {
2412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		udelay(INIT_LOOP_DELAY);
2421ab36d68e37faa431d99a07cbfb477a48879934eJohn W. Linville		acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
2432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2441ab36d68e37faa431d99a07cbfb477a48879934eJohn W. Linville		if (acx_intr == 0xffffffff) {
24580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo			wl1251_error("error reading hardware complete "
2462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				     "init indication");
2472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			return -EIO;
2482f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		}
2492f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		/* check that ACX_INTR_INIT_COMPLETE is enabled */
2501ab36d68e37faa431d99a07cbfb477a48879934eJohn W. Linville		else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) {
25180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo			wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
2520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					   WL1251_ACX_INTR_INIT_COMPLETE);
2532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			break;
2542f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		}
2552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
2562f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
257e8a4a6df7397eb3b43ad3139d3fe9b41df70d6b0Roel Kluin	if (loop > INIT_LOOP) {
25880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_error("timeout waiting for the hardware to "
2592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo			     "complete initialization");
2602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return -EIO;
2612f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
2622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* get hardware config command mail box */
26480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
2652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* get hardware config event mail box */
26780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
2682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* set the working partition to its "running" mode offset */
2700e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START,
2710e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_WORK_MEM_SIZE,
2720e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_WORK_REG_START,
2730e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_WORK_REG_SIZE);
2742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
27580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
2762f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		     wl->cmd_box_addr, wl->event_box_addr);
2772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2780e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver));
2790d1c38398fa8cd478a229b4428fb511f813376e8Luciano Coelho
2802f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/*
2812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * in case of full asynchronous mode the firmware event must be
2822f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 * ready to receive event from the command mailbox
2832f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	 */
2842f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* enable gpio interrupts */
286b5ed9c1b6f8fcb2d2315f12599fd5808f7933f16Bob Copeland	wl1251_enable_interrupts(wl);
2872f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
2880e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Enable target's interrupts */
2890e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
2900e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		WL1251_ACX_INTR_RX1_DATA |
2910e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		WL1251_ACX_INTR_TX_RESULT |
2920e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		WL1251_ACX_INTR_EVENT_A |
2930e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		WL1251_ACX_INTR_EVENT_B |
2940e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		WL1251_ACX_INTR_INIT_COMPLETE;
2950e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_boot_target_enable_interrupts(wl);
2962f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
297a1590f2404d1c8d16f8ceed4fccc32ab9831e484Janne Ylalehto	wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID |
298a1590f2404d1c8d16f8ceed4fccc32ab9831e484Janne Ylalehto		SYNCHRONIZATION_TIMEOUT_EVENT_ID |
299a1590f2404d1c8d16f8ceed4fccc32ab9831e484Janne Ylalehto		ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
300a1590f2404d1c8d16f8ceed4fccc32ab9831e484Janne Ylalehto		ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
301a1590f2404d1c8d16f8ceed4fccc32ab9831e484Janne Ylalehto		REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
3027273b9700b74e8c26b612207aea47effb0e530bfGrazvydas Ignotas		BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID;
3032f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
30480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_event_unmask(wl);
3052f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0) {
30680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_error("EVENT mask setting failed");
3072f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
3082f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
3092f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
31080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	wl1251_event_mbox_config(wl);
3112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
3122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* firmware startup completed */
3132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
3142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
3150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic int wl1251_boot_upload_firmware(struct wl1251 *wl)
3170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
3180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int addr, chunk_num, partition_limit;
319c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	size_t fw_data_len, len;
320c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	u8 *p, *buf;
3210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* whal_FwCtrl_LoadFwImageSm() */
3230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
3250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		     wl1251_reg_read32(wl, CHIP_ID_B));
3260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.0 check firmware length and set partition */
3280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	fw_data_len =  (wl->fw[4] << 24) | (wl->fw[5] << 16) |
3290e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		(wl->fw[6] << 8) | (wl->fw[7]);
3300e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3310e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
3320e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		CHUNK_SIZE);
3330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3340e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if ((fw_data_len % 4) != 0) {
3350e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("firmware length not multiple of four");
3360e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return -EIO;
3370e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
3380e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
339c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	buf = kmalloc(CHUNK_SIZE, GFP_KERNEL);
340c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	if (!buf) {
341c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		wl1251_error("allocation for firmware upload chunk failed");
342c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		return -ENOMEM;
343c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	}
344c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo
3450e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
3460e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_MEM_SIZE,
3470e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_REG_START,
3480e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_REG_SIZE);
3490e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3500e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.1 set partition limit and chunk num */
3510e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	chunk_num = 0;
3520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	partition_limit = WL1251_PART_DOWN_MEM_SIZE;
3530e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3540e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	while (chunk_num < fw_data_len / CHUNK_SIZE) {
3550e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		/* 10.2 update partition, if needed */
3560e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		addr = WL1251_PART_DOWN_MEM_START +
3570e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(chunk_num + 2) * CHUNK_SIZE;
3580e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		if (addr > partition_limit) {
3590e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			addr = WL1251_PART_DOWN_MEM_START +
3600e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				chunk_num * CHUNK_SIZE;
3610e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			partition_limit = chunk_num * CHUNK_SIZE +
3620e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				WL1251_PART_DOWN_MEM_SIZE;
3630e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			wl1251_set_partition(wl,
3640e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					     addr,
3650e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					     WL1251_PART_DOWN_MEM_SIZE,
3660e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					     WL1251_PART_DOWN_REG_START,
3670e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					     WL1251_PART_DOWN_REG_SIZE);
3680e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		}
3690e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3700e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		/* 10.3 upload the chunk */
3710e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
3720e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
3730e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
3740e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     p, addr);
375c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo
376c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		/* need to copy the chunk for dma */
377c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		len = CHUNK_SIZE;
378c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		memcpy(buf, p, len);
379c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		wl1251_mem_write(wl, addr, buf, len);
3800e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3810e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		chunk_num++;
3820e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
3830e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3840e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.4 upload the last chunk */
3850e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
3860e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
387c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo
388c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	/* need to copy the chunk for dma */
389c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	len = fw_data_len % CHUNK_SIZE;
390c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	memcpy(buf, p, len);
391c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo
3920e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
393c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo		     len, p, addr);
394c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	wl1251_mem_write(wl, addr, buf, len);
395c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo
396c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4Kalle Valo	kfree(buf);
3970e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3980e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
3990e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
4000e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4010e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic int wl1251_boot_upload_nvs(struct wl1251 *wl)
4020e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
4030e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	size_t nvs_len, nvs_bytes_written, burst_len;
4040e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int nvs_start, i;
4050e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	u32 dest_addr, val;
4060e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	u8 *nvs_ptr, *nvs;
4070e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4080e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs = wl->nvs;
4090e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (nvs == NULL)
4100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return -ENODEV;
4110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_ptr = nvs;
4130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_len = wl->nvs_len;
4150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_start = wl->fw_len;
4160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/*
4180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * Layout before the actual NVS tables:
4190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * 1 byte : burst length.
4200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * 2 bytes: destination address.
4210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * n bytes: data to burst copy.
4220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 *
4230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * This is ended by a 0 length, then the NVS tables.
4240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 */
4250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	while (nvs_ptr[0]) {
4270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		burst_len = nvs_ptr[0];
4280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
4290e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4300e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		/* We move our pointer to the data */
4310e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		nvs_ptr += 3;
4320e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		for (i = 0; i < burst_len; i++) {
4340e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
4350e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
4360e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4370e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			wl1251_debug(DEBUG_BOOT,
4380e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				     "nvs burst write 0x%x: 0x%x",
4390e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				     dest_addr, val);
4400e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			wl1251_mem_write32(wl, dest_addr, val);
4410e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4420e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			nvs_ptr += 4;
4430e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			dest_addr += 4;
4440e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		}
4450e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
4460e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4470e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/*
4480e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * We've reached the first zero length, the first NVS table
4490e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * is 7 bytes further.
4500e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 */
4510e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_ptr += 7;
4520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_len -= nvs_ptr - nvs;
4530e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_len = ALIGN(nvs_len, 4);
4540e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4550e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Now we must set the partition correctly */
4560e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_set_partition(wl, nvs_start,
4570e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_MEM_SIZE,
4580e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_REG_START,
4590e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     WL1251_PART_DOWN_REG_SIZE);
4600e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4610e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* And finally we upload the NVS tables */
4620e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	nvs_bytes_written = 0;
4630e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	while (nvs_bytes_written < nvs_len) {
4640e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
4650e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
4660e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4670e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_debug(DEBUG_BOOT,
4680e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     "nvs write table 0x%x: 0x%x",
4690e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			     nvs_start, val);
4700e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_mem_write32(wl, nvs_start, val);
4710e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4720e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		nvs_ptr += 4;
4730e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		nvs_bytes_written += 4;
4740e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		nvs_start += 4;
4750e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
4760e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4770e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
4780e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
4790e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4800e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valoint wl1251_boot(struct wl1251 *wl)
4810e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
4820e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int ret = 0, minor_minor_e2_ver;
4830e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	u32 tmp, boot_data;
4840e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
485bcd64e0c20eafe6a3976c248833d5d8bcccdf0d9Bob Copeland	/* halt embedded ARM CPU while loading firmware */
486bcd64e0c20eafe6a3976c248833d5d8bcccdf0d9Bob Copeland	wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT);
487bcd64e0c20eafe6a3976c248833d5d8bcccdf0d9Bob Copeland
4880e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_boot_soft_reset(wl);
4890e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
4900e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
4910e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4920e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 2. start processing NVS file */
493c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis	if (wl->use_eeprom) {
494c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR);
4951e3f7ac81ef81f25d8d8d902b73d884f97e6aa21Grazvydas Ignotas		/* Wait for EEPROM NVS burst read to complete */
4961e3f7ac81ef81f25d8d8d902b73d884f97e6aa21Grazvydas Ignotas		msleep(40);
497c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM);
498c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis	} else {
499c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		ret = wl1251_boot_upload_nvs(wl);
500c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		if (ret < 0)
501c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis			goto out;
502c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis
503c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		/* write firmware's last address (ie. it's length) to
504c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		 * ACX_EEPROMLESS_IND_REG */
505c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis		wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
506c95cf3d09adc9afe7816a13a920b6df36062a3feDavid-John Willis	}
5070e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5080e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 6. read the EEPROM parameters */
5090e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	tmp = wl1251_reg_read32(wl, SCR_PAD2);
5100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 7. read bootdata */
5120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
5130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
5140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	tmp = wl1251_reg_read32(wl, SCR_PAD3);
5150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 8. check bootdata and call restart sequence */
5170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
5180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
5190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
5210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		     "minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
5220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		     wl->boot_attr.radio_type, wl->boot_attr.major,
5230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		     wl->boot_attr.minor, minor_minor_e2_ver);
5240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_boot_init_seq(wl);
5260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
5270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
5280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5290e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 9. NVS processing done */
5300e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
5310e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5320e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
5330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5340e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10. check that ECPU_CONTROL_HALT bits are set in
5350e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 * pWhalBus->uBootData and start uploading firmware
5360e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	 */
5370e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if ((boot_data & ECPU_CONTROL_HALT) == 0) {
5380e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
5390e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		ret = -EIO;
5400e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
5410e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
5420e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5430e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_boot_upload_firmware(wl);
5440e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
5450e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
5460e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5470e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* 10.5 start firmware */
5480e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_boot_run_firmware(wl);
5490e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
5500e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
5510e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
5520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valoout:
5530e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return ret;
5540e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
555