blob: 2be76ee42bb9b2a4aeda9a40a5ac46153fa97fe0 [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"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020030#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030031#include "wl1271_event.h"
32
33static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
34 [PART_DOWN] = {
35 .mem = {
36 .start = 0x00000000,
37 .size = 0x000177c0
38 },
39 .reg = {
40 .start = REGISTERS_BASE,
41 .size = 0x00008800
42 },
Juuso Oikarinen451de972009-10-12 15:08:46 +030043 .mem2 = {
44 .start = 0x00000000,
45 .size = 0x00000000
46 },
47 .mem3 = {
48 .start = 0x00000000,
49 .size = 0x00000000
50 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030051 },
52
53 [PART_WORK] = {
54 .mem = {
55 .start = 0x00040000,
56 .size = 0x00014fc0
57 },
58 .reg = {
59 .start = REGISTERS_BASE,
Juuso Oikarinen451de972009-10-12 15:08:46 +030060 .size = 0x0000a000
61 },
62 .mem2 = {
63 .start = 0x003004f8,
64 .size = 0x00000004
65 },
66 .mem3 = {
67 .start = 0x00040404,
68 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030069 },
70 },
71
72 [PART_DRPW] = {
73 .mem = {
74 .start = 0x00040000,
75 .size = 0x00014fc0
76 },
77 .reg = {
78 .start = DRPW_BASE,
79 .size = 0x00006000
Juuso Oikarinen451de972009-10-12 15:08:46 +030080 },
81 .mem2 = {
82 .start = 0x00000000,
83 .size = 0x00000000
84 },
85 .mem3 = {
86 .start = 0x00000000,
87 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030088 }
89 }
90};
91
92static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
93{
94 u32 cpu_ctrl;
95
96 /* 10.5.0 run the firmware (I) */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020097 cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030098
99 /* 10.5.1 run the firmware (II) */
100 cpu_ctrl |= flag;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200101 wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300102}
103
104static void wl1271_boot_fw_version(struct wl1271 *wl)
105{
106 struct wl1271_static_data static_data;
107
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200108 wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
109 false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300110
111 strncpy(wl->chip.fw_ver, static_data.fw_version,
112 sizeof(wl->chip.fw_ver));
113
114 /* make sure the string is NULL-terminated */
115 wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0';
116}
117
118static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
119 size_t fw_data_len, u32 dest)
120{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300121 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300122 int addr, chunk_num, partition_limit;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300123 u8 *p, *chunk;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300124
125 /* whal_FwCtrl_LoadFwImageSm() */
126
127 wl1271_debug(DEBUG_BOOT, "starting firmware upload");
128
Luciano Coelho73d0a132009-08-11 11:58:27 +0300129 wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
130 fw_data_len, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300131
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300132 if ((fw_data_len % 4) != 0) {
133 wl1271_error("firmware length not multiple of four");
134 return -EIO;
135 }
136
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300137 chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300138 if (!chunk) {
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300139 wl1271_error("allocation for firmware upload chunk failed");
140 return -ENOMEM;
141 }
142
Juuso Oikarinen451de972009-10-12 15:08:46 +0300143 memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
144 partition.mem.start = dest;
145 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300146
147 /* 10.1 set partition limit and chunk num */
148 chunk_num = 0;
149 partition_limit = part_table[PART_DOWN].mem.size;
150
151 while (chunk_num < fw_data_len / CHUNK_SIZE) {
152 /* 10.2 update partition, if needed */
153 addr = dest + (chunk_num + 2) * CHUNK_SIZE;
154 if (addr > partition_limit) {
155 addr = dest + chunk_num * CHUNK_SIZE;
156 partition_limit = chunk_num * CHUNK_SIZE +
157 part_table[PART_DOWN].mem.size;
Juuso Oikarinen451de972009-10-12 15:08:46 +0300158 partition.mem.start = addr;
159 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300160 }
161
162 /* 10.3 upload the chunk */
163 addr = dest + chunk_num * CHUNK_SIZE;
164 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300165 memcpy(chunk, p, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300166 wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
167 p, addr);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200168 wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300169
170 chunk_num++;
171 }
172
173 /* 10.4 upload the last chunk */
174 addr = dest + chunk_num * CHUNK_SIZE;
175 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300176 memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
Luciano Coelho73d0a132009-08-11 11:58:27 +0300177 wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300178 fw_data_len % CHUNK_SIZE, p, addr);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200179 wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300180
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300181 kfree(chunk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300182 return 0;
183}
184
185static int wl1271_boot_upload_firmware(struct wl1271 *wl)
186{
187 u32 chunks, addr, len;
Juuso Oikarinened3177882009-10-13 12:47:57 +0300188 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300189 u8 *fw;
190
191 fw = wl->fw;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300192 chunks = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300193 fw += sizeof(u32);
194
195 wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
196
197 while (chunks--) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300198 addr = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300199 fw += sizeof(u32);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300200 len = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300201 fw += sizeof(u32);
202
203 if (len > 300000) {
204 wl1271_info("firmware chunk too long: %u", len);
205 return -EINVAL;
206 }
207 wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
208 chunks, addr, len);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300209 ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
210 if (ret != 0)
211 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300212 fw += len;
213 }
214
Juuso Oikarinened3177882009-10-13 12:47:57 +0300215 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300216}
217
218static int wl1271_boot_upload_nvs(struct wl1271 *wl)
219{
220 size_t nvs_len, burst_len;
221 int i;
222 u32 dest_addr, val;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200223 u8 *nvs_ptr, *nvs_aligned;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300224
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200225 if (wl->nvs == NULL)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300226 return -ENODEV;
227
Luciano Coelho8cf5e8e2009-12-11 15:40:53 +0200228 /* only the first part of the NVS needs to be uploaded */
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200229 nvs_len = sizeof(wl->nvs->nvs);
230 nvs_ptr = (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300232 /*
233 * Layout before the actual NVS tables:
234 * 1 byte : burst length.
235 * 2 bytes: destination address.
236 * n bytes: data to burst copy.
237 *
238 * This is ended by a 0 length, then the NVS tables.
239 */
240
241 /* FIXME: Do we need to check here whether the LSB is 1? */
242 while (nvs_ptr[0]) {
243 burst_len = nvs_ptr[0];
244 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
245
246 /* FIXME: Due to our new wl1271_translate_reg_addr function,
247 we need to add the REGISTER_BASE to the destination */
248 dest_addr += REGISTERS_BASE;
249
250 /* We move our pointer to the data */
251 nvs_ptr += 3;
252
253 for (i = 0; i < burst_len; i++) {
254 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
255 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
256
257 wl1271_debug(DEBUG_BOOT,
258 "nvs burst write 0x%x: 0x%x",
259 dest_addr, val);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200260 wl1271_write32(wl, dest_addr, val);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300261
262 nvs_ptr += 4;
263 dest_addr += 4;
264 }
265 }
266
267 /*
268 * We've reached the first zero length, the first NVS table
269 * is 7 bytes further.
270 */
271 nvs_ptr += 7;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200272 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300273 nvs_len = ALIGN(nvs_len, 4);
274
275 /* FIXME: The driver sets the partition here, but this is not needed,
276 since it sets to the same one as currently in use */
277 /* Now we must set the partition correctly */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300278 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300279
280 /* Copy the NVS tables to a new block to ensure alignment */
Luciano Coelho6f8434a2010-02-18 13:25:45 +0200281 /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
282 that our NVS files have three extra zeros here. I'm not sure whether
283 the problem is in our NVS generation or we should really jumpt these
284 3 bytes here */
285 nvs_ptr += 3;
286
287 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
288 (!nvs_aligned) return -ENOMEM;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300289
290 /* And finally we upload the NVS tables */
291 /* FIXME: In wl1271, we upload everything at once.
292 No endianness handling needed here?! The ref driver doesn't do
293 anything about it at this point */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200294 wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300295
296 kfree(nvs_aligned);
297 return 0;
298}
299
300static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
301{
302 enable_irq(wl->irq);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200303 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
304 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
305 wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300306}
307
308static int wl1271_boot_soft_reset(struct wl1271 *wl)
309{
310 unsigned long timeout;
311 u32 boot_data;
312
313 /* perform soft reset */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200314 wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, 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) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200319 boot_data = wl1271_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 */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200335 wl1271_write32(wl, ENABLE, 0x0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300336
337 /* disable auto calibration on start*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200338 wl1271_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
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200350 chip_id = wl1271_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);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200363 interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300364
365 if (interrupt == 0xffffffff) {
366 wl1271_error("error reading hardware complete "
367 "init indication");
368 return -EIO;
369 }
370 /* check that ACX_INTR_INIT_COMPLETE is enabled */
371 else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200372 wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
373 WL1271_ACX_INTR_INIT_COMPLETE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374 break;
375 }
376 }
377
Luciano Coelhoe7d17cf2009-10-29 13:20:04 +0200378 if (loop > INIT_LOOP) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300379 wl1271_error("timeout waiting for the hardware to "
380 "complete initialization");
381 return -EIO;
382 }
383
384 /* get hardware config command mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200385 wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386
387 /* get hardware config event mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200388 wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300389
390 /* set the working partition to its "running" mode offset */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300391 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392
393 wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
394 wl->cmd_box_addr, wl->event_box_addr);
395
396 wl1271_boot_fw_version(wl);
397
398 /*
399 * in case of full asynchronous mode the firmware event must be
400 * ready to receive event from the command mailbox
401 */
402
Juuso Oikarinenbe823e52009-10-08 21:56:36 +0300403 /* unmask required mbox events */
404 wl->event_mask = BSS_LOSE_EVENT_ID |
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200405 SCAN_COMPLETE_EVENT_ID |
406 PS_REPORT_EVENT_ID;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407
408 ret = wl1271_event_unmask(wl);
409 if (ret < 0) {
410 wl1271_error("EVENT mask setting failed");
411 return ret;
412 }
413
414 wl1271_event_mbox_config(wl);
415
416 /* firmware startup completed */
417 return 0;
418}
419
420static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
421{
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300422 u32 polarity;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300424 polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425
426 /* We use HIGH polarity, so unset the LOW bit */
427 polarity &= ~POLARITY_LOW;
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300428 wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429
430 return 0;
431}
432
433int wl1271_boot(struct wl1271 *wl)
434{
435 int ret = 0;
436 u32 tmp, clk, pause;
437
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300438 if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
439 /* ref clk: 19.2/38.4/38.4-XTAL */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440 clk = 0x3;
441 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
442 /* ref clk: 26/52 */
443 clk = 0x5;
444
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300445 if (REF_CLOCK != 0) {
446 u16 val;
447 /* Set clock type */
448 val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
449 val &= FREF_CLK_TYPE_BITS;
450 val |= CLK_REQ_PRCM;
451 wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
452 } else {
453 u16 val;
454 /* Set clock polarity */
455 val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
456 val &= FREF_CLK_POLARITY_BITS;
457 val |= CLK_REQ_OUTN_SEL;
458 wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
459 }
460
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200461 wl1271_write32(wl, PLL_PARAMETERS, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200463 pause = wl1271_read32(wl, PLL_PARAMETERS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
465 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
466
467 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
468 * WU_COUNTER_PAUSE_VAL instead of
469 * 0x3ff (magic number ). How does
470 * this work?! */
471 pause |= WU_COUNTER_PAUSE_VAL;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200472 wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
474 /* Continue the ELP wake up sequence */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200475 wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476 udelay(500);
477
Juuso Oikarinen451de972009-10-12 15:08:46 +0300478 wl1271_set_partition(wl, &part_table[PART_DRPW]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300479
480 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
481 to be used by DRPw FW. The RTRIM value will be added by the FW
482 before taking DRPw out of reset */
483
484 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200485 clk = wl1271_read32(wl, DRPW_SCRATCH_START);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
487 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
488
489 /* 2 */
490 clk |= (REF_CLOCK << 1) << 4;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200491 wl1271_write32(wl, DRPW_SCRATCH_START, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492
Juuso Oikarinen451de972009-10-12 15:08:46 +0300493 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300494
495 /* Disable interrupts */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200496 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300497
498 ret = wl1271_boot_soft_reset(wl);
499 if (ret < 0)
500 goto out;
501
502 /* 2. start processing NVS file */
503 ret = wl1271_boot_upload_nvs(wl);
504 if (ret < 0)
505 goto out;
506
507 /* write firmware's last address (ie. it's length) to
508 * ACX_EEPROMLESS_IND_REG */
509 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
510
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200511 wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200513 tmp = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514
515 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
516
517 /* 6. read the EEPROM parameters */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200518 tmp = wl1271_read32(wl, SCR_PAD2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519
520 ret = wl1271_boot_write_irq_polarity(wl);
521 if (ret < 0)
522 goto out;
523
524 /* FIXME: Need to check whether this is really what we want */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200525 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
526 WL1271_ACX_ALL_EVENTS_VECTOR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527
528 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
529 * to upload_fw) */
530
531 ret = wl1271_boot_upload_firmware(wl);
532 if (ret < 0)
533 goto out;
534
535 /* 10.5 start firmware */
536 ret = wl1271_boot_run_firmware(wl);
537 if (ret < 0)
538 goto out;
539
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300540 /* Enable firmware interrupts now */
541 wl1271_boot_enable_interrupts(wl);
542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 /* set the wl1271 default filters */
544 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
545 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
546
547 wl1271_event_mbox_config(wl);
548
549out:
550 return ret;
551}