boot.c 20.5 KB
Newer Older
L
Luciano Coelho 已提交
1 2 3
/*
 * This file is part of wl1271
 *
4
 * Copyright (C) 2008-2010 Nokia Corporation
L
Luciano Coelho 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

24
#include <linux/slab.h>
25
#include <linux/wl12xx.h>
L
Luciano Coelho 已提交
26

S
Shahar Levi 已提交
27 28 29 30 31
#include "acx.h"
#include "reg.h"
#include "boot.h"
#include "io.h"
#include "event.h"
32
#include "rx.h"
L
Luciano Coelho 已提交
33 34 35 36 37 38 39 40 41 42 43

static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
	[PART_DOWN] = {
		.mem = {
			.start = 0x00000000,
			.size  = 0x000177c0
		},
		.reg = {
			.start = REGISTERS_BASE,
			.size  = 0x00008800
		},
44 45 46 47 48 49 50 51
		.mem2 = {
			.start = 0x00000000,
			.size  = 0x00000000
		},
		.mem3 = {
			.start = 0x00000000,
			.size  = 0x00000000
		},
L
Luciano Coelho 已提交
52 53 54 55 56 57 58 59 60
	},

	[PART_WORK] = {
		.mem = {
			.start = 0x00040000,
			.size  = 0x00014fc0
		},
		.reg = {
			.start = REGISTERS_BASE,
61 62 63 64 65 66 67 68 69
			.size  = 0x0000a000
		},
		.mem2 = {
			.start = 0x003004f8,
			.size  = 0x00000004
		},
		.mem3 = {
			.start = 0x00040404,
			.size  = 0x00000000
L
Luciano Coelho 已提交
70 71 72 73 74 75 76 77 78 79 80
		},
	},

	[PART_DRPW] = {
		.mem = {
			.start = 0x00040000,
			.size  = 0x00014fc0
		},
		.reg = {
			.start = DRPW_BASE,
			.size  = 0x00006000
81 82 83 84 85 86 87 88
		},
		.mem2 = {
			.start = 0x00000000,
			.size  = 0x00000000
		},
		.mem3 = {
			.start = 0x00000000,
			.size  = 0x00000000
L
Luciano Coelho 已提交
89 90 91 92 93 94 95 96 97
		}
	}
};

static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{
	u32 cpu_ctrl;

	/* 10.5.0 run the firmware (I) */
T
Teemu Paasikivi 已提交
98
	cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
L
Luciano Coelho 已提交
99 100 101

	/* 10.5.1 run the firmware (II) */
	cpu_ctrl |= flag;
T
Teemu Paasikivi 已提交
102
	wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
L
Luciano Coelho 已提交
103 104
}

L
Levi, Shahar 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
static void wl1271_parse_fw_ver(struct wl1271 *wl)
{
	int ret;

	ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
		     &wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
		     &wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
		     &wl->chip.fw_ver[4]);

	if (ret != 5) {
		wl1271_warning("fw version incorrect value");
		memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
		return;
	}
}

L
Luciano Coelho 已提交
121 122 123 124
static void wl1271_boot_fw_version(struct wl1271 *wl)
{
	struct wl1271_static_data static_data;

T
Teemu Paasikivi 已提交
125 126
	wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
		    false);
L
Luciano Coelho 已提交
127

L
Levi, Shahar 已提交
128 129
	strncpy(wl->chip.fw_ver_str, static_data.fw_version,
		sizeof(wl->chip.fw_ver_str));
L
Luciano Coelho 已提交
130 131

	/* make sure the string is NULL-terminated */
L
Levi, Shahar 已提交
132 133 134
	wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';

	wl1271_parse_fw_ver(wl);
L
Luciano Coelho 已提交
135 136 137 138 139
}

static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
					     size_t fw_data_len, u32 dest)
{
140
	struct wl1271_partition_set partition;
L
Luciano Coelho 已提交
141
	int addr, chunk_num, partition_limit;
142
	u8 *p, *chunk;
L
Luciano Coelho 已提交
143 144 145 146 147

	/* whal_FwCtrl_LoadFwImageSm() */

	wl1271_debug(DEBUG_BOOT, "starting firmware upload");

148 149
	wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
		     fw_data_len, CHUNK_SIZE);
L
Luciano Coelho 已提交
150 151 152 153 154 155

	if ((fw_data_len % 4) != 0) {
		wl1271_error("firmware length not multiple of four");
		return -EIO;
	}

156
	chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
157
	if (!chunk) {
158 159 160 161
		wl1271_error("allocation for firmware upload chunk failed");
		return -ENOMEM;
	}

162 163 164
	memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
	partition.mem.start = dest;
	wl1271_set_partition(wl, &partition);
L
Luciano Coelho 已提交
165 166 167 168 169 170 171 172 173 174 175 176

	/* 10.1 set partition limit and chunk num */
	chunk_num = 0;
	partition_limit = part_table[PART_DOWN].mem.size;

	while (chunk_num < fw_data_len / CHUNK_SIZE) {
		/* 10.2 update partition, if needed */
		addr = dest + (chunk_num + 2) * CHUNK_SIZE;
		if (addr > partition_limit) {
			addr = dest + chunk_num * CHUNK_SIZE;
			partition_limit = chunk_num * CHUNK_SIZE +
				part_table[PART_DOWN].mem.size;
177 178
			partition.mem.start = addr;
			wl1271_set_partition(wl, &partition);
L
Luciano Coelho 已提交
179 180 181 182 183
		}

		/* 10.3 upload the chunk */
		addr = dest + chunk_num * CHUNK_SIZE;
		p = buf + chunk_num * CHUNK_SIZE;
184
		memcpy(chunk, p, CHUNK_SIZE);
L
Luciano Coelho 已提交
185 186
		wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
			     p, addr);
T
Teemu Paasikivi 已提交
187
		wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
L
Luciano Coelho 已提交
188 189 190 191 192 193 194

		chunk_num++;
	}

	/* 10.4 upload the last chunk */
	addr = dest + chunk_num * CHUNK_SIZE;
	p = buf + chunk_num * CHUNK_SIZE;
195
	memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
196
	wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
L
Luciano Coelho 已提交
197
		     fw_data_len % CHUNK_SIZE, p, addr);
T
Teemu Paasikivi 已提交
198
	wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
L
Luciano Coelho 已提交
199

200
	kfree(chunk);
L
Luciano Coelho 已提交
201 202 203 204 205 206
	return 0;
}

static int wl1271_boot_upload_firmware(struct wl1271 *wl)
{
	u32 chunks, addr, len;
207
	int ret = 0;
L
Luciano Coelho 已提交
208 209 210
	u8 *fw;

	fw = wl->fw;
L
Luciano Coelho 已提交
211
	chunks = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
212 213 214 215 216
	fw += sizeof(u32);

	wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);

	while (chunks--) {
L
Luciano Coelho 已提交
217
		addr = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
218
		fw += sizeof(u32);
L
Luciano Coelho 已提交
219
		len = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
220 221 222 223 224 225 226 227
		fw += sizeof(u32);

		if (len > 300000) {
			wl1271_info("firmware chunk too long: %u", len);
			return -EINVAL;
		}
		wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
			     chunks, addr, len);
228 229 230
		ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
		if (ret != 0)
			break;
L
Luciano Coelho 已提交
231 232 233
		fw += len;
	}

234
	return ret;
L
Luciano Coelho 已提交
235 236 237 238 239 240 241
}

static int wl1271_boot_upload_nvs(struct wl1271 *wl)
{
	size_t nvs_len, burst_len;
	int i;
	u32 dest_addr, val;
242
	u8 *nvs_ptr, *nvs_aligned;
L
Luciano Coelho 已提交
243

244
	if (wl->nvs == NULL)
L
Luciano Coelho 已提交
245 246
		return -ENODEV;

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
	if (wl->chip.id == CHIP_ID_1283_PG20) {
		struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;

		if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
			if (nvs->general_params.dual_mode_select)
				wl->enable_11a = true;
		} else {
			wl1271_error("nvs size is not as expected: %zu != %zu",
				     wl->nvs_len,
				     sizeof(struct wl128x_nvs_file));
			kfree(wl->nvs);
			wl->nvs = NULL;
			wl->nvs_len = 0;
			return -EILSEQ;
		}
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
		/* only the first part of the NVS needs to be uploaded */
		nvs_len = sizeof(nvs->nvs);
		nvs_ptr = (u8 *)nvs->nvs;

	} else {
		struct wl1271_nvs_file *nvs =
			(struct wl1271_nvs_file *)wl->nvs;
		/*
		 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
		 * band configurations) can be removed when those NVS files stop
		 * floating around.
		 */
		if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
		    wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
			/* for now 11a is unsupported in AP mode */
			if (wl->bss_type != BSS_TYPE_AP_BSS &&
			    nvs->general_params.dual_mode_select)
				wl->enable_11a = true;
		}
282

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
		if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
		    (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
		     wl->enable_11a)) {
			wl1271_error("nvs size is not as expected: %zu != %zu",
				wl->nvs_len, sizeof(struct wl1271_nvs_file));
			kfree(wl->nvs);
			wl->nvs = NULL;
			wl->nvs_len = 0;
			return -EILSEQ;
		}

		/* only the first part of the NVS needs to be uploaded */
		nvs_len = sizeof(nvs->nvs);
		nvs_ptr = (u8 *) nvs->nvs;
	}
L
Luciano Coelho 已提交
298

299 300 301 302 303 304 305 306
	/* update current MAC address to NVS */
	nvs_ptr[11] = wl->mac_addr[0];
	nvs_ptr[10] = wl->mac_addr[1];
	nvs_ptr[6] = wl->mac_addr[2];
	nvs_ptr[5] = wl->mac_addr[3];
	nvs_ptr[4] = wl->mac_addr[4];
	nvs_ptr[3] = wl->mac_addr[5];

L
Luciano Coelho 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320
	/*
	 * Layout before the actual NVS tables:
	 * 1 byte : burst length.
	 * 2 bytes: destination address.
	 * n bytes: data to burst copy.
	 *
	 * This is ended by a 0 length, then the NVS tables.
	 */

	/* FIXME: Do we need to check here whether the LSB is 1? */
	while (nvs_ptr[0]) {
		burst_len = nvs_ptr[0];
		dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));

321 322 323 324
		/*
		 * Due to our new wl1271_translate_reg_addr function,
		 * we need to add the REGISTER_BASE to the destination
		 */
L
Luciano Coelho 已提交
325 326 327 328 329 330 331 332 333 334 335 336
		dest_addr += REGISTERS_BASE;

		/* We move our pointer to the data */
		nvs_ptr += 3;

		for (i = 0; i < burst_len; i++) {
			val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
			       | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));

			wl1271_debug(DEBUG_BOOT,
				     "nvs burst write 0x%x: 0x%x",
				     dest_addr, val);
T
Teemu Paasikivi 已提交
337
			wl1271_write32(wl, dest_addr, val);
L
Luciano Coelho 已提交
338 339 340 341 342 343 344 345

			nvs_ptr += 4;
			dest_addr += 4;
		}
	}

	/*
	 * We've reached the first zero length, the first NVS table
346
	 * is located at an aligned offset which is at least 7 bytes further.
347 348 349
	 * NOTE: The wl->nvs->nvs element must be first, in order to
	 * simplify the casting, we assume it is at the beginning of
	 * the wl->nvs structure.
L
Luciano Coelho 已提交
350
	 */
351 352 353
	nvs_ptr = (u8 *)wl->nvs +
			ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
L
Luciano Coelho 已提交
354 355

	/* Now we must set the partition correctly */
356
	wl1271_set_partition(wl, &part_table[PART_WORK]);
L
Luciano Coelho 已提交
357 358

	/* Copy the NVS tables to a new block to ensure alignment */
359 360 361
	nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
	if (!nvs_aligned)
		return -ENOMEM;
L
Luciano Coelho 已提交
362 363

	/* And finally we upload the NVS tables */
T
Teemu Paasikivi 已提交
364
	wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
L
Luciano Coelho 已提交
365 366 367 368 369 370 371

	kfree(nvs_aligned);
	return 0;
}

static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
372
	wl1271_enable_interrupts(wl);
T
Teemu Paasikivi 已提交
373 374 375
	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
		       WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
	wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
L
Luciano Coelho 已提交
376 377 378 379 380 381 382 383
}

static int wl1271_boot_soft_reset(struct wl1271 *wl)
{
	unsigned long timeout;
	u32 boot_data;

	/* perform soft reset */
T
Teemu Paasikivi 已提交
384
	wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
L
Luciano Coelho 已提交
385 386 387 388

	/* SOFT_RESET is self clearing */
	timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
	while (1) {
T
Teemu Paasikivi 已提交
389
		boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
L
Luciano Coelho 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
		wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
		if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
			break;

		if (time_after(jiffies, timeout)) {
			/* 1.2 check pWhalBus->uSelfClearTime if the
			 * timeout was reached */
			wl1271_error("soft reset timeout");
			return -1;
		}

		udelay(SOFT_RESET_STALL_TIME);
	}

	/* disable Rx/Tx */
T
Teemu Paasikivi 已提交
405
	wl1271_write32(wl, ENABLE, 0x0);
L
Luciano Coelho 已提交
406 407

	/* disable auto calibration on start*/
T
Teemu Paasikivi 已提交
408
	wl1271_write32(wl, SPARE_A2, 0xffff);
L
Luciano Coelho 已提交
409 410 411 412 413 414 415

	return 0;
}

static int wl1271_boot_run_firmware(struct wl1271 *wl)
{
	int loop, ret;
416
	u32 chip_id, intr;
L
Luciano Coelho 已提交
417 418 419

	wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);

T
Teemu Paasikivi 已提交
420
	chip_id = wl1271_read32(wl, CHIP_ID_B);
L
Luciano Coelho 已提交
421 422 423 424 425 426 427 428 429 430 431 432

	wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);

	if (chip_id != wl->chip.id) {
		wl1271_error("chip id doesn't match after firmware boot");
		return -EIO;
	}

	/* wait for init to complete */
	loop = 0;
	while (loop++ < INIT_LOOP) {
		udelay(INIT_LOOP_DELAY);
433
		intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
L
Luciano Coelho 已提交
434

435
		if (intr == 0xffffffff) {
L
Luciano Coelho 已提交
436 437 438 439 440
			wl1271_error("error reading hardware complete "
				     "init indication");
			return -EIO;
		}
		/* check that ACX_INTR_INIT_COMPLETE is enabled */
441
		else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
T
Teemu Paasikivi 已提交
442 443
			wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
				       WL1271_ACX_INTR_INIT_COMPLETE);
L
Luciano Coelho 已提交
444 445 446 447
			break;
		}
	}

L
Luciano Coelho 已提交
448
	if (loop > INIT_LOOP) {
L
Luciano Coelho 已提交
449 450 451 452 453 454
		wl1271_error("timeout waiting for the hardware to "
			     "complete initialization");
		return -EIO;
	}

	/* get hardware config command mail box */
T
Teemu Paasikivi 已提交
455
	wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
L
Luciano Coelho 已提交
456 457

	/* get hardware config event mail box */
T
Teemu Paasikivi 已提交
458
	wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
459 460

	/* set the working partition to its "running" mode offset */
461
	wl1271_set_partition(wl, &part_table[PART_WORK]);
L
Luciano Coelho 已提交
462 463 464 465 466 467 468 469 470 471 472

	wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
		     wl->cmd_box_addr, wl->event_box_addr);

	wl1271_boot_fw_version(wl);

	/*
	 * in case of full asynchronous mode the firmware event must be
	 * ready to receive event from the command mailbox
	 */

473 474
	/* unmask required mbox events  */
	wl->event_mask = BSS_LOSE_EVENT_ID |
475
		SCAN_COMPLETE_EVENT_ID |
476
		PS_REPORT_EVENT_ID |
477
		JOIN_EVENT_COMPLETE_ID |
478
		DISCONNECT_EVENT_COMPLETE_ID |
479
		RSSI_SNR_TRIGGER_0_EVENT_ID |
480 481
		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
		SOFT_GEMINI_SENSE_EVENT_ID;
L
Luciano Coelho 已提交
482

483 484 485
	if (wl->bss_type == BSS_TYPE_AP_BSS)
		wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;

L
Luciano Coelho 已提交
486 487 488 489 490 491 492 493 494 495 496 497 498 499
	ret = wl1271_event_unmask(wl);
	if (ret < 0) {
		wl1271_error("EVENT mask setting failed");
		return ret;
	}

	wl1271_event_mbox_config(wl);

	/* firmware startup completed */
	return 0;
}

static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
{
500
	u32 polarity;
L
Luciano Coelho 已提交
501

502
	polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
L
Luciano Coelho 已提交
503 504 505

	/* We use HIGH polarity, so unset the LOW bit */
	polarity &= ~POLARITY_LOW;
506
	wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
L
Luciano Coelho 已提交
507 508 509 510

	return 0;
}

511 512 513 514 515 516 517 518
static void wl1271_boot_hw_version(struct wl1271 *wl)
{
	u32 fuse;

	fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
	fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;

	wl->hw_pg_ver = (s8)fuse;
519 520 521

	if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
		wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
522 523
}

524 525 526 527 528 529 530 531
/*
 * 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)
L
Luciano Coelho 已提交
532
{
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
	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;
L
Luciano Coelho 已提交
661

662 663
	wl1271_boot_hw_version(wl);

664 665 666
	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)
J
Juuso Oikarinen 已提交
667
		/* ref clk: 19.2/38.4/38.4-XTAL */
L
Luciano Coelho 已提交
668
		clk = 0x3;
669 670
	else if (wl->ref_clock == CONF_REF_CLK_26_E ||
		 wl->ref_clock == CONF_REF_CLK_52_E)
L
Luciano Coelho 已提交
671 672
		/* ref clk: 26/52 */
		clk = 0x5;
673 674
	else
		return -EINVAL;
L
Luciano Coelho 已提交
675

676
	if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
J
Juuso Oikarinen 已提交
677
		u16 val;
678
		/* Set clock type (open drain) */
J
Juuso Oikarinen 已提交
679 680 681
		val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
		val &= FREF_CLK_TYPE_BITS;
		wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
682 683 684 685 686

		/* Set clock pull mode (no pull) */
		val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
		val |= NO_PULL;
		wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
J
Juuso Oikarinen 已提交
687 688 689 690 691 692 693 694 695
	} else {
		u16 val;
		/* Set clock polarity */
		val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
		val &= FREF_CLK_POLARITY_BITS;
		val |= CLK_REQ_OUTN_SEL;
		wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
	}

T
Teemu Paasikivi 已提交
696
	wl1271_write32(wl, PLL_PARAMETERS, clk);
L
Luciano Coelho 已提交
697

T
Teemu Paasikivi 已提交
698
	pause = wl1271_read32(wl, PLL_PARAMETERS);
L
Luciano Coelho 已提交
699 700 701

	wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);

702
	pause &= ~(WU_COUNTER_PAUSE_VAL);
L
Luciano Coelho 已提交
703
	pause |= WU_COUNTER_PAUSE_VAL;
T
Teemu Paasikivi 已提交
704
	wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
L
Luciano Coelho 已提交
705

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
	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;
	}

L
Luciano Coelho 已提交
726
	/* Continue the ELP wake up sequence */
T
Teemu Paasikivi 已提交
727
	wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
L
Luciano Coelho 已提交
728 729
	udelay(500);

730
	wl1271_set_partition(wl, &part_table[PART_DRPW]);
L
Luciano Coelho 已提交
731 732 733 734 735 736

	/* Read-modify-write DRPW_SCRATCH_START register (see next state)
	   to be used by DRPw FW. The RTRIM value will be added by the FW
	   before taking DRPw out of reset */

	wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
T
Teemu Paasikivi 已提交
737
	clk = wl1271_read32(wl, DRPW_SCRATCH_START);
L
Luciano Coelho 已提交
738 739 740

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

741 742 743 744 745 746 747 748 749
	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;
	}

T
Teemu Paasikivi 已提交
750
	wl1271_write32(wl, DRPW_SCRATCH_START, clk);
L
Luciano Coelho 已提交
751

752
	wl1271_set_partition(wl, &part_table[PART_WORK]);
L
Luciano Coelho 已提交
753 754

	/* Disable interrupts */
T
Teemu Paasikivi 已提交
755
	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
L
Luciano Coelho 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769

	ret = wl1271_boot_soft_reset(wl);
	if (ret < 0)
		goto out;

	/* 2. start processing NVS file */
	ret = wl1271_boot_upload_nvs(wl);
	if (ret < 0)
		goto out;

	/* write firmware's last address (ie. it's length) to
	 * ACX_EEPROMLESS_IND_REG */
	wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");

T
Teemu Paasikivi 已提交
770
	wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
L
Luciano Coelho 已提交
771

T
Teemu Paasikivi 已提交
772
	tmp = wl1271_read32(wl, CHIP_ID_B);
L
Luciano Coelho 已提交
773 774 775 776

	wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);

	/* 6. read the EEPROM parameters */
T
Teemu Paasikivi 已提交
777
	tmp = wl1271_read32(wl, SCR_PAD2);
L
Luciano Coelho 已提交
778 779 780 781

	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
	 * to upload_fw) */

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

L
Luciano Coelho 已提交
785 786 787 788
	ret = wl1271_boot_upload_firmware(wl);
	if (ret < 0)
		goto out;

789 790 791 792 793 794 795 796 797 798 799 800 801 802
out:
	return ret;
}
EXPORT_SYMBOL_GPL(wl1271_load_firmware);

int wl1271_boot(struct wl1271 *wl)
{
	int ret;

	/* upload NVS and firmware */
	ret = wl1271_load_firmware(wl);
	if (ret)
		return ret;

L
Luciano Coelho 已提交
803 804 805 806 807
	/* 10.5 start firmware */
	ret = wl1271_boot_run_firmware(wl);
	if (ret < 0)
		goto out;

808 809 810 811 812 813 814
	ret = wl1271_boot_write_irq_polarity(wl);
	if (ret < 0)
		goto out;

	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
		       WL1271_ACX_ALL_EVENTS_VECTOR);

815 816 817
	/* Enable firmware interrupts now */
	wl1271_boot_enable_interrupts(wl);

L
Luciano Coelho 已提交
818
	/* set the wl1271 default filters */
819
	wl1271_set_default_filters(wl);
L
Luciano Coelho 已提交
820 821 822 823 824 825

	wl1271_event_mbox_config(wl);

out:
	return ret;
}