boot.c 11.4 KB
Newer Older
1
2
3
/*
 * This file is part of wl1271
 *
4
 * Copyright (C) 2008-2010 Nokia Corporation
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>
27

28
#include "debug.h"
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"
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);
42
43
44

	/* 10.5.1 run the firmware (II) */
	cpu_ctrl |= flag;
45
	wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
46
47
}

48
static int wlcore_parse_fw_ver(struct wl1271 *wl)
Levi, Shahar's avatar
Levi, Shahar committed
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;
Levi, Shahar's avatar
Levi, Shahar committed
61
	}
62

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

	return 0;
Levi, Shahar's avatar
Levi, Shahar committed
68
69
}

70
static int wlcore_boot_fw_version(struct wl1271 *wl)
71
{
72
	struct wl1271_static_data *static_data;
73
	int ret;
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),
Teemu Paasikivi's avatar
Teemu Paasikivi committed
82
		    false);
83

84
	strncpy(wl->chip.fw_ver_str, static_data->fw_version,
Levi, Shahar's avatar
Levi, Shahar committed
85
		sizeof(wl->chip.fw_ver_str));
86

87
88
	kfree(static_data);

89
	/* make sure the string is NULL-terminated */
Levi, Shahar's avatar
Levi, Shahar committed
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;
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;
103
	int addr, chunk_num, partition_limit;
104
	u8 *p, *chunk;
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);
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);
127
128
129

	/* 10.1 set partition limit and chunk num */
	chunk_num = 0;
130
	partition_limit = wl->ptable[PART_DOWN].mem.size;
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);
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);
147
148
		wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
			     p, addr);
Teemu Paasikivi's avatar
Teemu Paasikivi committed
149
		wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
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",
159
		     fw_data_len % CHUNK_SIZE, p, addr);
Teemu Paasikivi's avatar
Teemu Paasikivi committed
160
	wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
161

162
	kfree(chunk);
163
164
165
	return 0;
}

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

	fw = wl->fw;
Luciano Coelho's avatar
Luciano Coelho committed
173
	chunks = be32_to_cpup((__be32 *) fw);
174
175
176
177
178
	fw += sizeof(u32);

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

	while (chunks--) {
Luciano Coelho's avatar
Luciano Coelho committed
179
		addr = be32_to_cpup((__be32 *) fw);
180
		fw += sizeof(u32);
Luciano Coelho's avatar
Luciano Coelho committed
181
		len = be32_to_cpup((__be32 *) fw);
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;
193
194
195
		fw += len;
	}

196
	return ret;
197
}
198
EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware);
199

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

207
	if (wl->nvs == NULL)
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
	}
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

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;
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;

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);
Teemu Paasikivi's avatar
Teemu Paasikivi committed
301
			wl1271_write32(wl, dest_addr, val);
302
303
304
305

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

		if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
			goto out_badnvs;
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.
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;
325
326

	/* Now we must set the partition correctly */
327
	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
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;
333
334

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

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

out_badnvs:
	wl1271_error("nvs data is malformed");
	return -EILSEQ;
344
}
345
EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
346

347
int wlcore_boot_run_firmware(struct wl1271 *wl)
348
349
{
	int loop, ret;
350
	u32 chip_id, intr;
351

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

355
356
	wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);

357
	chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B);
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);
371

372
		if (intr == 0xffffffff) {
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);
381
382
383
384
			break;
		}
	}

Luciano Coelho's avatar
Luciano Coelho committed
385
	if (loop > INIT_LOOP) {
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);
393

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

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);
399

400
401
	wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
402

403
404
405
406
407
	ret = wlcore_boot_fw_version(wl);
	if (ret < 0) {
		wl1271_error("couldn't boot firmware");
		return ret;
	}
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
		SCAN_COMPLETE_EVENT_ID |
417
		ROLE_STOP_COMPLETE_EVENT_ID |
418
		RSSI_SNR_TRIGGER_0_EVENT_ID |
419
		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
420
421
		SOFT_GEMINI_SENSE_EVENT_ID |
		PERIODIC_SCAN_REPORT_EVENT_ID |
422
423
424
425
426
427
		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 |
428
429
		MAX_TX_RETRY_EVENT_ID |
		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
430

431
432
433
434
435
436
	ret = wl1271_event_unmask(wl);
	if (ret < 0) {
		wl1271_error("EVENT mask setting failed");
		return ret;
	}

437
438
	/* set the working partition to its "running" mode offset */
	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
439
440
441
442

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