boot.c 11.4 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>
26
#include <linux/export.h>
L
Luciano Coelho 已提交
27

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

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

	/* 10.5.0 run the firmware (I) */
41
	cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL);
L
Luciano Coelho 已提交
42 43 44

	/* 10.5.1 run the firmware (II) */
	cpu_ctrl |= flag;
45
	wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
L
Luciano Coelho 已提交
46 47
}

48
static int wlcore_parse_fw_ver(struct wl1271 *wl)
L
Levi, Shahar 已提交
49 50 51 52 53 54 55 56 57 58 59
{
	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));
60
		return -EINVAL;
L
Levi, Shahar 已提交
61
	}
62

63 64 65 66 67
	ret = wlcore_identify_fw(wl);
	if (ret < 0)
		return ret;

	return 0;
L
Levi, Shahar 已提交
68 69
}

70
static int wlcore_boot_fw_version(struct wl1271 *wl)
L
Luciano Coelho 已提交
71
{
72
	struct wl1271_static_data *static_data;
73
	int ret;
L
Luciano Coelho 已提交
74

75
	static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
76
	if (!static_data) {
77 78
		wl1271_error("Couldn't allocate memory for static data!");
		return -ENOMEM;
79 80 81
	}

	wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
T
Teemu Paasikivi 已提交
82
		    false);
L
Luciano Coelho 已提交
83

84
	strncpy(wl->chip.fw_ver_str, static_data->fw_version,
L
Levi, Shahar 已提交
85
		sizeof(wl->chip.fw_ver_str));
L
Luciano Coelho 已提交
86

87 88
	kfree(static_data);

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

92 93 94 95 96
	ret = wlcore_parse_fw_ver(wl);
	if (ret < 0)
		return ret;

	return 0;
L
Luciano Coelho 已提交
97 98 99 100 101
}

static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
					     size_t fw_data_len, u32 dest)
{
102
	struct wlcore_partition_set partition;
L
Luciano Coelho 已提交
103
	int addr, chunk_num, partition_limit;
104
	u8 *p, *chunk;
L
Luciano Coelho 已提交
105 106 107 108 109

	/* whal_FwCtrl_LoadFwImageSm() */

	wl1271_debug(DEBUG_BOOT, "starting firmware upload");

110 111
	wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
		     fw_data_len, CHUNK_SIZE);
L
Luciano Coelho 已提交
112 113 114 115 116 117

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

118
	chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
119
	if (!chunk) {
120 121 122 123
		wl1271_error("allocation for firmware upload chunk failed");
		return -ENOMEM;
	}

124
	memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
125
	partition.mem.start = dest;
126
	wlcore_set_partition(wl, &partition);
L
Luciano Coelho 已提交
127 128 129

	/* 10.1 set partition limit and chunk num */
	chunk_num = 0;
130
	partition_limit = wl->ptable[PART_DOWN].mem.size;
L
Luciano Coelho 已提交
131 132 133 134 135 136 137

	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 +
138
				wl->ptable[PART_DOWN].mem.size;
139
			partition.mem.start = addr;
140
			wlcore_set_partition(wl, &partition);
L
Luciano Coelho 已提交
141 142 143 144 145
		}

		/* 10.3 upload the chunk */
		addr = dest + chunk_num * CHUNK_SIZE;
		p = buf + chunk_num * CHUNK_SIZE;
146
		memcpy(chunk, p, CHUNK_SIZE);
L
Luciano Coelho 已提交
147 148
		wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
			     p, addr);
T
Teemu Paasikivi 已提交
149
		wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
L
Luciano Coelho 已提交
150 151 152 153 154 155 156

		chunk_num++;
	}

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

162
	kfree(chunk);
L
Luciano Coelho 已提交
163 164 165
	return 0;
}

166
int wlcore_boot_upload_firmware(struct wl1271 *wl)
L
Luciano Coelho 已提交
167 168
{
	u32 chunks, addr, len;
169
	int ret = 0;
L
Luciano Coelho 已提交
170 171 172
	u8 *fw;

	fw = wl->fw;
L
Luciano Coelho 已提交
173
	chunks = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
174 175 176 177 178
	fw += sizeof(u32);

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

	while (chunks--) {
L
Luciano Coelho 已提交
179
		addr = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
180
		fw += sizeof(u32);
L
Luciano Coelho 已提交
181
		len = be32_to_cpup((__be32 *) fw);
L
Luciano Coelho 已提交
182 183 184 185 186 187 188 189
		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);
190 191 192
		ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
		if (ret != 0)
			break;
L
Luciano Coelho 已提交
193 194 195
		fw += len;
	}

196
	return ret;
L
Luciano Coelho 已提交
197
}
198
EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware);
L
Luciano Coelho 已提交
199

200
int wlcore_boot_upload_nvs(struct wl1271 *wl)
L
Luciano Coelho 已提交
201 202 203 204
{
	size_t nvs_len, burst_len;
	int i;
	u32 dest_addr, val;
205
	u8 *nvs_ptr, *nvs_aligned;
L
Luciano Coelho 已提交
206

207
	if (wl->nvs == NULL)
L
Luciano Coelho 已提交
208 209
		return -ENODEV;

210
	if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
211 212 213 214 215 216 217 218 219
		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) {
220
			if (nvs->general_params.dual_mode_select)
221 222
				wl->enable_11a = true;
		}
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237
		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;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
	} else {
		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;
		}

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

259
	/* update current MAC address to NVS */
260 261 262 263 264 265
	nvs_ptr[11] = wl->addresses[0].addr[0];
	nvs_ptr[10] = wl->addresses[0].addr[1];
	nvs_ptr[6] = wl->addresses[0].addr[2];
	nvs_ptr[5] = wl->addresses[0].addr[3];
	nvs_ptr[4] = wl->addresses[0].addr[4];
	nvs_ptr[3] = wl->addresses[0].addr[5];
266

L
Luciano Coelho 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280
	/*
	 * 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));

281 282
		/*
		 * Due to our new wl1271_translate_reg_addr function,
283 284
		 * we need to add the register partition start address
		 * to the destination
285
		 */
286
		dest_addr += wl->curr_part.reg.start;
L
Luciano Coelho 已提交
287 288 289 290 291

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

		for (i = 0; i < burst_len; i++) {
292 293 294
			if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
				goto out_badnvs;

L
Luciano Coelho 已提交
295 296 297 298 299 300
			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 已提交
301
			wl1271_write32(wl, dest_addr, val);
L
Luciano Coelho 已提交
302 303 304 305

			nvs_ptr += 4;
			dest_addr += 4;
		}
306 307 308

		if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
			goto out_badnvs;
L
Luciano Coelho 已提交
309 310 311 312
	}

	/*
	 * We've reached the first zero length, the first NVS table
313
	 * is located at an aligned offset which is at least 7 bytes further.
314 315 316
	 * 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 已提交
317
	 */
318 319
	nvs_ptr = (u8 *)wl->nvs +
			ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
320 321 322 323

	if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
		goto out_badnvs;

324
	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
L
Luciano Coelho 已提交
325 326

	/* Now we must set the partition correctly */
327
	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
L
Luciano Coelho 已提交
328 329

	/* Copy the NVS tables to a new block to ensure alignment */
330 331 332
	nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
	if (!nvs_aligned)
		return -ENOMEM;
L
Luciano Coelho 已提交
333 334

	/* And finally we upload the NVS tables */
335 336
	wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS,
			  nvs_aligned, nvs_len, false);
L
Luciano Coelho 已提交
337 338 339

	kfree(nvs_aligned);
	return 0;
340 341 342 343

out_badnvs:
	wl1271_error("nvs data is malformed");
	return -EILSEQ;
L
Luciano Coelho 已提交
344
}
345
EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
L
Luciano Coelho 已提交
346

347
int wlcore_boot_run_firmware(struct wl1271 *wl)
L
Luciano Coelho 已提交
348 349
{
	int loop, ret;
350
	u32 chip_id, intr;
L
Luciano Coelho 已提交
351

352 353 354
	/* Make sure we have the boot partition */
	wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);

L
Luciano Coelho 已提交
355 356
	wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);

357
	chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B);
L
Luciano Coelho 已提交
358 359 360 361 362 363 364 365 366 367 368 369

	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);
370
		intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
L
Luciano Coelho 已提交
371

372
		if (intr == 0xffffffff) {
L
Luciano Coelho 已提交
373 374 375 376 377
			wl1271_error("error reading hardware complete "
				     "init indication");
			return -EIO;
		}
		/* check that ACX_INTR_INIT_COMPLETE is enabled */
378
		else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
379 380
			wlcore_write_reg(wl, REG_INTERRUPT_ACK,
					 WL1271_ACX_INTR_INIT_COMPLETE);
L
Luciano Coelho 已提交
381 382 383 384
			break;
		}
	}

L
Luciano Coelho 已提交
385
	if (loop > INIT_LOOP) {
L
Luciano Coelho 已提交
386 387 388 389 390 391
		wl1271_error("timeout waiting for the hardware to "
			     "complete initialization");
		return -EIO;
	}

	/* get hardware config command mail box */
392
	wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR);
L
Luciano Coelho 已提交
393

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

L
Luciano Coelho 已提交
396
	/* get hardware config event mail box */
397 398
	wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR);
	wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
L
Luciano Coelho 已提交
399

400 401
	wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
L
Luciano Coelho 已提交
402

403 404 405 406 407
	ret = wlcore_boot_fw_version(wl);
	if (ret < 0) {
		wl1271_error("couldn't boot firmware");
		return ret;
	}
L
Luciano Coelho 已提交
408 409 410 411 412 413

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

414 415
	/* unmask required mbox events  */
	wl->event_mask = BSS_LOSE_EVENT_ID |
416
		REGAINED_BSS_EVENT_ID |
417
		SCAN_COMPLETE_EVENT_ID |
418
		ROLE_STOP_COMPLETE_EVENT_ID |
419
		RSSI_SNR_TRIGGER_0_EVENT_ID |
420
		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
421 422
		SOFT_GEMINI_SENSE_EVENT_ID |
		PERIODIC_SCAN_REPORT_EVENT_ID |
E
Eliad Peller 已提交
423 424 425 426 427 428
		PERIODIC_SCAN_COMPLETE_EVENT_ID |
		DUMMY_PACKET_EVENT_ID |
		PEER_REMOVE_COMPLETE_EVENT_ID |
		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
		INACTIVE_STA_EVENT_ID |
429 430
		MAX_TX_RETRY_EVENT_ID |
		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
431

L
Luciano Coelho 已提交
432 433 434 435 436 437
	ret = wl1271_event_unmask(wl);
	if (ret < 0) {
		wl1271_error("EVENT mask setting failed");
		return ret;
	}

438 439
	/* set the working partition to its "running" mode offset */
	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
L
Luciano Coelho 已提交
440 441 442 443

	/* firmware startup completed */
	return 0;
}
444
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);