blob: fb3090c3ed1561f4c3a77c709d52172eb1201ddf [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/gpio.h>
25
26#include "wl1271_acx.h"
27#include "wl1271_reg.h"
28#include "wl1271_boot.h"
29#include "wl1271_spi.h"
30#include "wl1271_event.h"
31
32static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
33 [PART_DOWN] = {
34 .mem = {
35 .start = 0x00000000,
36 .size = 0x000177c0
37 },
38 .reg = {
39 .start = REGISTERS_BASE,
40 .size = 0x00008800
41 },
Juuso Oikarinen451de972009-10-12 15:08:46 +030042 .mem2 = {
43 .start = 0x00000000,
44 .size = 0x00000000
45 },
46 .mem3 = {
47 .start = 0x00000000,
48 .size = 0x00000000
49 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050 },
51
52 [PART_WORK] = {
53 .mem = {
54 .start = 0x00040000,
55 .size = 0x00014fc0
56 },
57 .reg = {
58 .start = REGISTERS_BASE,
Juuso Oikarinen451de972009-10-12 15:08:46 +030059 .size = 0x0000a000
60 },
61 .mem2 = {
62 .start = 0x003004f8,
63 .size = 0x00000004
64 },
65 .mem3 = {
66 .start = 0x00040404,
67 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030068 },
69 },
70
71 [PART_DRPW] = {
72 .mem = {
73 .start = 0x00040000,
74 .size = 0x00014fc0
75 },
76 .reg = {
77 .start = DRPW_BASE,
78 .size = 0x00006000
Juuso Oikarinen451de972009-10-12 15:08:46 +030079 },
80 .mem2 = {
81 .start = 0x00000000,
82 .size = 0x00000000
83 },
84 .mem3 = {
85 .start = 0x00000000,
86 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030087 }
88 }
89};
90
91static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
92{
93 u32 cpu_ctrl;
94
95 /* 10.5.0 run the firmware (I) */
Juuso Oikarinen74621412009-10-12 15:08:54 +030096 cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030097
98 /* 10.5.1 run the firmware (II) */
99 cpu_ctrl |= flag;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300100 wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300101}
102
103static void wl1271_boot_fw_version(struct wl1271 *wl)
104{
105 struct wl1271_static_data static_data;
106
Juuso Oikarinen74621412009-10-12 15:08:54 +0300107 wl1271_spi_read(wl, wl->cmd_box_addr,
108 &static_data, sizeof(static_data), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300109
110 strncpy(wl->chip.fw_ver, static_data.fw_version,
111 sizeof(wl->chip.fw_ver));
112
113 /* make sure the string is NULL-terminated */
114 wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0';
115}
116
117static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
118 size_t fw_data_len, u32 dest)
119{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300120 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300121 int addr, chunk_num, partition_limit;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300122 u8 *p, *chunk;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300123
124 /* whal_FwCtrl_LoadFwImageSm() */
125
126 wl1271_debug(DEBUG_BOOT, "starting firmware upload");
127
Luciano Coelho73d0a132009-08-11 11:58:27 +0300128 wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
129 fw_data_len, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300130
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300131 if ((fw_data_len % 4) != 0) {
132 wl1271_error("firmware length not multiple of four");
133 return -EIO;
134 }
135
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300136 chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300137 if (!chunk) {
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300138 wl1271_error("allocation for firmware upload chunk failed");
139 return -ENOMEM;
140 }
141
Juuso Oikarinen451de972009-10-12 15:08:46 +0300142 memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
143 partition.mem.start = dest;
144 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300145
146 /* 10.1 set partition limit and chunk num */
147 chunk_num = 0;
148 partition_limit = part_table[PART_DOWN].mem.size;
149
150 while (chunk_num < fw_data_len / CHUNK_SIZE) {
151 /* 10.2 update partition, if needed */
152 addr = dest + (chunk_num + 2) * CHUNK_SIZE;
153 if (addr > partition_limit) {
154 addr = dest + chunk_num * CHUNK_SIZE;
155 partition_limit = chunk_num * CHUNK_SIZE +
156 part_table[PART_DOWN].mem.size;
Juuso Oikarinen451de972009-10-12 15:08:46 +0300157 partition.mem.start = addr;
158 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300159 }
160
161 /* 10.3 upload the chunk */
162 addr = dest + chunk_num * CHUNK_SIZE;
163 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300164 memcpy(chunk, p, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300165 wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
166 p, addr);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300167 wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300168
169 chunk_num++;
170 }
171
172 /* 10.4 upload the last chunk */
173 addr = dest + chunk_num * CHUNK_SIZE;
174 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300175 memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
Luciano Coelho73d0a132009-08-11 11:58:27 +0300176 wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300177 fw_data_len % CHUNK_SIZE, p, addr);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300178 wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300179
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300180 kfree(chunk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300181 return 0;
182}
183
184static int wl1271_boot_upload_firmware(struct wl1271 *wl)
185{
186 u32 chunks, addr, len;
Juuso Oikarinened3177882009-10-13 12:47:57 +0300187 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300188 u8 *fw;
189
190 fw = wl->fw;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300191 chunks = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300192 fw += sizeof(u32);
193
194 wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
195
196 while (chunks--) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300197 addr = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300198 fw += sizeof(u32);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300199 len = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300200 fw += sizeof(u32);
201
202 if (len > 300000) {
203 wl1271_info("firmware chunk too long: %u", len);
204 return -EINVAL;
205 }
206 wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
207 chunks, addr, len);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300208 ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
209 if (ret != 0)
210 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300211 fw += len;
212 }
213
Juuso Oikarinened3177882009-10-13 12:47:57 +0300214 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300215}
216
217static int wl1271_boot_upload_nvs(struct wl1271 *wl)
218{
219 size_t nvs_len, burst_len;
220 int i;
221 u32 dest_addr, val;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200222 u8 *nvs_ptr, *nvs_aligned;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300223
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200224 if (wl->nvs == NULL)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300225 return -ENODEV;
226
Luciano Coelho8cf5e8e2009-12-11 15:40:53 +0200227 /* only the first part of the NVS needs to be uploaded */
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200228 nvs_len = sizeof(wl->nvs->nvs);
229 nvs_ptr = (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300231 /*
232 * Layout before the actual NVS tables:
233 * 1 byte : burst length.
234 * 2 bytes: destination address.
235 * n bytes: data to burst copy.
236 *
237 * This is ended by a 0 length, then the NVS tables.
238 */
239
240 /* FIXME: Do we need to check here whether the LSB is 1? */
241 while (nvs_ptr[0]) {
242 burst_len = nvs_ptr[0];
243 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
244
245 /* FIXME: Due to our new wl1271_translate_reg_addr function,
246 we need to add the REGISTER_BASE to the destination */
247 dest_addr += REGISTERS_BASE;
248
249 /* We move our pointer to the data */
250 nvs_ptr += 3;
251
252 for (i = 0; i < burst_len; i++) {
253 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
254 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
255
256 wl1271_debug(DEBUG_BOOT,
257 "nvs burst write 0x%x: 0x%x",
258 dest_addr, val);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300259 wl1271_spi_write32(wl, dest_addr, val);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300260
261 nvs_ptr += 4;
262 dest_addr += 4;
263 }
264 }
265
266 /*
267 * We've reached the first zero length, the first NVS table
268 * is 7 bytes further.
269 */
270 nvs_ptr += 7;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200271 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300272 nvs_len = ALIGN(nvs_len, 4);
273
274 /* FIXME: The driver sets the partition here, but this is not needed,
275 since it sets to the same one as currently in use */
276 /* Now we must set the partition correctly */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300277 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300278
279 /* Copy the NVS tables to a new block to ensure alignment */
Luciano Coelho6f8434a2010-02-18 13:25:45 +0200280 /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
281 that our NVS files have three extra zeros here. I'm not sure whether
282 the problem is in our NVS generation or we should really jumpt these
283 3 bytes here */
284 nvs_ptr += 3;
285
286 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
287 (!nvs_aligned) return -ENOMEM;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300288
289 /* And finally we upload the NVS tables */
290 /* FIXME: In wl1271, we upload everything at once.
291 No endianness handling needed here?! The ref driver doesn't do
292 anything about it at this point */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300293 wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300294
295 kfree(nvs_aligned);
296 return 0;
297}
298
299static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
300{
301 enable_irq(wl->irq);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300302 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300303 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Juuso Oikarinen74621412009-10-12 15:08:54 +0300304 wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300305}
306
307static int wl1271_boot_soft_reset(struct wl1271 *wl)
308{
309 unsigned long timeout;
310 u32 boot_data;
311
312 /* perform soft reset */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300313 wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
314 ACX_SLV_SOFT_RESET_BIT);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300315
316 /* SOFT_RESET is self clearing */
317 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
318 while (1) {
Juuso Oikarinen74621412009-10-12 15:08:54 +0300319 boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300320 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
321 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
322 break;
323
324 if (time_after(jiffies, timeout)) {
325 /* 1.2 check pWhalBus->uSelfClearTime if the
326 * timeout was reached */
327 wl1271_error("soft reset timeout");
328 return -1;
329 }
330
331 udelay(SOFT_RESET_STALL_TIME);
332 }
333
334 /* disable Rx/Tx */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300335 wl1271_spi_write32(wl, ENABLE, 0x0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300336
337 /* disable auto calibration on start*/
Juuso Oikarinen74621412009-10-12 15:08:54 +0300338 wl1271_spi_write32(wl, SPARE_A2, 0xffff);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300339
340 return 0;
341}
342
343static int wl1271_boot_run_firmware(struct wl1271 *wl)
344{
345 int loop, ret;
346 u32 chip_id, interrupt;
347
348 wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
349
Juuso Oikarinen74621412009-10-12 15:08:54 +0300350 chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300351
352 wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
353
354 if (chip_id != wl->chip.id) {
355 wl1271_error("chip id doesn't match after firmware boot");
356 return -EIO;
357 }
358
359 /* wait for init to complete */
360 loop = 0;
361 while (loop++ < INIT_LOOP) {
362 udelay(INIT_LOOP_DELAY);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300363 interrupt = wl1271_spi_read32(wl,
364 ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300365
366 if (interrupt == 0xffffffff) {
367 wl1271_error("error reading hardware complete "
368 "init indication");
369 return -EIO;
370 }
371 /* check that ACX_INTR_INIT_COMPLETE is enabled */
372 else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
Juuso Oikarinen74621412009-10-12 15:08:54 +0300373 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374 WL1271_ACX_INTR_INIT_COMPLETE);
375 break;
376 }
377 }
378
Luciano Coelhoe7d17cf2009-10-29 13:20:04 +0200379 if (loop > INIT_LOOP) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300380 wl1271_error("timeout waiting for the hardware to "
381 "complete initialization");
382 return -EIO;
383 }
384
385 /* get hardware config command mail box */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300386 wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
388 /* get hardware config event mail box */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300389 wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300390
391 /* set the working partition to its "running" mode offset */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300392 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300393
394 wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
395 wl->cmd_box_addr, wl->event_box_addr);
396
397 wl1271_boot_fw_version(wl);
398
399 /*
400 * in case of full asynchronous mode the firmware event must be
401 * ready to receive event from the command mailbox
402 */
403
Juuso Oikarinenbe823e52009-10-08 21:56:36 +0300404 /* unmask required mbox events */
405 wl->event_mask = BSS_LOSE_EVENT_ID |
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200406 SCAN_COMPLETE_EVENT_ID |
407 PS_REPORT_EVENT_ID;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300408
409 ret = wl1271_event_unmask(wl);
410 if (ret < 0) {
411 wl1271_error("EVENT mask setting failed");
412 return ret;
413 }
414
415 wl1271_event_mbox_config(wl);
416
417 /* firmware startup completed */
418 return 0;
419}
420
421static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
422{
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300423 u32 polarity;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300425 polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300426
427 /* We use HIGH polarity, so unset the LOW bit */
428 polarity &= ~POLARITY_LOW;
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300429 wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430
431 return 0;
432}
433
434int wl1271_boot(struct wl1271 *wl)
435{
436 int ret = 0;
437 u32 tmp, clk, pause;
438
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300439 if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
440 /* ref clk: 19.2/38.4/38.4-XTAL */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 clk = 0x3;
442 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
443 /* ref clk: 26/52 */
444 clk = 0x5;
445
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300446 if (REF_CLOCK != 0) {
447 u16 val;
448 /* Set clock type */
449 val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
450 val &= FREF_CLK_TYPE_BITS;
451 val |= CLK_REQ_PRCM;
452 wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
453 } else {
454 u16 val;
455 /* Set clock polarity */
456 val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
457 val &= FREF_CLK_POLARITY_BITS;
458 val |= CLK_REQ_OUTN_SEL;
459 wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
460 }
461
Juuso Oikarinen74621412009-10-12 15:08:54 +0300462 wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
Juuso Oikarinen74621412009-10-12 15:08:54 +0300464 pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
467
468 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
469 * WU_COUNTER_PAUSE_VAL instead of
470 * 0x3ff (magic number ). How does
471 * this work?! */
472 pause |= WU_COUNTER_PAUSE_VAL;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300473 wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474
475 /* Continue the ELP wake up sequence */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300476 wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477 udelay(500);
478
Juuso Oikarinen451de972009-10-12 15:08:46 +0300479 wl1271_set_partition(wl, &part_table[PART_DRPW]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480
481 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
482 to be used by DRPw FW. The RTRIM value will be added by the FW
483 before taking DRPw out of reset */
484
485 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
Juuso Oikarinen74621412009-10-12 15:08:54 +0300486 clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
489
490 /* 2 */
491 clk |= (REF_CLOCK << 1) << 4;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300492 wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493
Juuso Oikarinen451de972009-10-12 15:08:46 +0300494 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300495
496 /* Disable interrupts */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300497 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498
499 ret = wl1271_boot_soft_reset(wl);
500 if (ret < 0)
501 goto out;
502
503 /* 2. start processing NVS file */
504 ret = wl1271_boot_upload_nvs(wl);
505 if (ret < 0)
506 goto out;
507
508 /* write firmware's last address (ie. it's length) to
509 * ACX_EEPROMLESS_IND_REG */
510 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
511
Juuso Oikarinen74621412009-10-12 15:08:54 +0300512 wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
513 ACX_EEPROMLESS_IND_REG);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514
Juuso Oikarinen74621412009-10-12 15:08:54 +0300515 tmp = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300516
517 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
518
519 /* 6. read the EEPROM parameters */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300520 tmp = wl1271_spi_read32(wl, SCR_PAD2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521
522 ret = wl1271_boot_write_irq_polarity(wl);
523 if (ret < 0)
524 goto out;
525
526 /* FIXME: Need to check whether this is really what we want */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300527 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528 WL1271_ACX_ALL_EVENTS_VECTOR);
529
530 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
531 * to upload_fw) */
532
533 ret = wl1271_boot_upload_firmware(wl);
534 if (ret < 0)
535 goto out;
536
537 /* 10.5 start firmware */
538 ret = wl1271_boot_run_firmware(wl);
539 if (ret < 0)
540 goto out;
541
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300542 /* Enable firmware interrupts now */
543 wl1271_boot_enable_interrupts(wl);
544
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300545 /* set the wl1271 default filters */
546 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
547 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
548
549 wl1271_event_mbox_config(wl);
550
551out:
552 return ret;
553}