blob: 0243562630657098d5b3f05802500f5d151c8704 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026
27#include "wl1271_acx.h"
28#include "wl1271_reg.h"
29#include "wl1271_boot.h"
30#include "wl1271_spi.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020031#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032#include "wl1271_event.h"
33
34static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
35 [PART_DOWN] = {
36 .mem = {
37 .start = 0x00000000,
38 .size = 0x000177c0
39 },
40 .reg = {
41 .start = REGISTERS_BASE,
42 .size = 0x00008800
43 },
Juuso Oikarinen451de972009-10-12 15:08:46 +030044 .mem2 = {
45 .start = 0x00000000,
46 .size = 0x00000000
47 },
48 .mem3 = {
49 .start = 0x00000000,
50 .size = 0x00000000
51 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052 },
53
54 [PART_WORK] = {
55 .mem = {
56 .start = 0x00040000,
57 .size = 0x00014fc0
58 },
59 .reg = {
60 .start = REGISTERS_BASE,
Juuso Oikarinen451de972009-10-12 15:08:46 +030061 .size = 0x0000a000
62 },
63 .mem2 = {
64 .start = 0x003004f8,
65 .size = 0x00000004
66 },
67 .mem3 = {
68 .start = 0x00040404,
69 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030070 },
71 },
72
73 [PART_DRPW] = {
74 .mem = {
75 .start = 0x00040000,
76 .size = 0x00014fc0
77 },
78 .reg = {
79 .start = DRPW_BASE,
80 .size = 0x00006000
Juuso Oikarinen451de972009-10-12 15:08:46 +030081 },
82 .mem2 = {
83 .start = 0x00000000,
84 .size = 0x00000000
85 },
86 .mem3 = {
87 .start = 0x00000000,
88 .size = 0x00000000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030089 }
90 }
91};
92
93static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
94{
95 u32 cpu_ctrl;
96
97 /* 10.5.0 run the firmware (I) */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020098 cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030099
100 /* 10.5.1 run the firmware (II) */
101 cpu_ctrl |= flag;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200102 wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300103}
104
105static void wl1271_boot_fw_version(struct wl1271 *wl)
106{
107 struct wl1271_static_data static_data;
108
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200109 wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
110 false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300111
112 strncpy(wl->chip.fw_ver, static_data.fw_version,
113 sizeof(wl->chip.fw_ver));
114
115 /* make sure the string is NULL-terminated */
116 wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0';
117}
118
119static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
120 size_t fw_data_len, u32 dest)
121{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300122 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300123 int addr, chunk_num, partition_limit;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300124 u8 *p, *chunk;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300125
126 /* whal_FwCtrl_LoadFwImageSm() */
127
128 wl1271_debug(DEBUG_BOOT, "starting firmware upload");
129
Luciano Coelho73d0a132009-08-11 11:58:27 +0300130 wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
131 fw_data_len, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300132
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300133 if ((fw_data_len % 4) != 0) {
134 wl1271_error("firmware length not multiple of four");
135 return -EIO;
136 }
137
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300138 chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300139 if (!chunk) {
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300140 wl1271_error("allocation for firmware upload chunk failed");
141 return -ENOMEM;
142 }
143
Juuso Oikarinen451de972009-10-12 15:08:46 +0300144 memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
145 partition.mem.start = dest;
146 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300147
148 /* 10.1 set partition limit and chunk num */
149 chunk_num = 0;
150 partition_limit = part_table[PART_DOWN].mem.size;
151
152 while (chunk_num < fw_data_len / CHUNK_SIZE) {
153 /* 10.2 update partition, if needed */
154 addr = dest + (chunk_num + 2) * CHUNK_SIZE;
155 if (addr > partition_limit) {
156 addr = dest + chunk_num * CHUNK_SIZE;
157 partition_limit = chunk_num * CHUNK_SIZE +
158 part_table[PART_DOWN].mem.size;
Juuso Oikarinen451de972009-10-12 15:08:46 +0300159 partition.mem.start = addr;
160 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300161 }
162
163 /* 10.3 upload the chunk */
164 addr = dest + chunk_num * CHUNK_SIZE;
165 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300166 memcpy(chunk, p, CHUNK_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300167 wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
168 p, addr);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200169 wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300170
171 chunk_num++;
172 }
173
174 /* 10.4 upload the last chunk */
175 addr = dest + chunk_num * CHUNK_SIZE;
176 p = buf + chunk_num * CHUNK_SIZE;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300177 memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
Luciano Coelho73d0a132009-08-11 11:58:27 +0300178 wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300179 fw_data_len % CHUNK_SIZE, p, addr);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200180 wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300181
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300182 kfree(chunk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300183 return 0;
184}
185
186static int wl1271_boot_upload_firmware(struct wl1271 *wl)
187{
188 u32 chunks, addr, len;
Juuso Oikarinened3177882009-10-13 12:47:57 +0300189 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300190 u8 *fw;
191
192 fw = wl->fw;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300193 chunks = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300194 fw += sizeof(u32);
195
196 wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
197
198 while (chunks--) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300199 addr = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300200 fw += sizeof(u32);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300201 len = be32_to_cpup((__be32 *) fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300202 fw += sizeof(u32);
203
204 if (len > 300000) {
205 wl1271_info("firmware chunk too long: %u", len);
206 return -EINVAL;
207 }
208 wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
209 chunks, addr, len);
Juuso Oikarinened3177882009-10-13 12:47:57 +0300210 ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
211 if (ret != 0)
212 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300213 fw += len;
214 }
215
Juuso Oikarinened3177882009-10-13 12:47:57 +0300216 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300217}
218
219static int wl1271_boot_upload_nvs(struct wl1271 *wl)
220{
221 size_t nvs_len, burst_len;
222 int i;
223 u32 dest_addr, val;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200224 u8 *nvs_ptr, *nvs_aligned;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300225
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200226 if (wl->nvs == NULL)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300227 return -ENODEV;
228
Luciano Coelho8cf5e8e2009-12-11 15:40:53 +0200229 /* only the first part of the NVS needs to be uploaded */
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200230 nvs_len = sizeof(wl->nvs->nvs);
231 nvs_ptr = (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300232
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300233 /*
234 * Layout before the actual NVS tables:
235 * 1 byte : burst length.
236 * 2 bytes: destination address.
237 * n bytes: data to burst copy.
238 *
239 * This is ended by a 0 length, then the NVS tables.
240 */
241
242 /* FIXME: Do we need to check here whether the LSB is 1? */
243 while (nvs_ptr[0]) {
244 burst_len = nvs_ptr[0];
245 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
246
247 /* FIXME: Due to our new wl1271_translate_reg_addr function,
248 we need to add the REGISTER_BASE to the destination */
249 dest_addr += REGISTERS_BASE;
250
251 /* We move our pointer to the data */
252 nvs_ptr += 3;
253
254 for (i = 0; i < burst_len; i++) {
255 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
256 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
257
258 wl1271_debug(DEBUG_BOOT,
259 "nvs burst write 0x%x: 0x%x",
260 dest_addr, val);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200261 wl1271_write32(wl, dest_addr, val);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300262
263 nvs_ptr += 4;
264 dest_addr += 4;
265 }
266 }
267
268 /*
269 * We've reached the first zero length, the first NVS table
270 * is 7 bytes further.
271 */
272 nvs_ptr += 7;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200273 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300274 nvs_len = ALIGN(nvs_len, 4);
275
276 /* FIXME: The driver sets the partition here, but this is not needed,
277 since it sets to the same one as currently in use */
278 /* Now we must set the partition correctly */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300279 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300280
281 /* Copy the NVS tables to a new block to ensure alignment */
Luciano Coelho6f8434a2010-02-18 13:25:45 +0200282 /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
283 that our NVS files have three extra zeros here. I'm not sure whether
284 the problem is in our NVS generation or we should really jumpt these
285 3 bytes here */
286 nvs_ptr += 3;
287
288 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
289 (!nvs_aligned) return -ENOMEM;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300290
291 /* And finally we upload the NVS tables */
292 /* FIXME: In wl1271, we upload everything at once.
293 No endianness handling needed here?! The ref driver doesn't do
294 anything about it at this point */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200295 wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300296
297 kfree(nvs_aligned);
298 return 0;
299}
300
301static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
302{
303 enable_irq(wl->irq);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200304 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
305 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
306 wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300307}
308
309static int wl1271_boot_soft_reset(struct wl1271 *wl)
310{
311 unsigned long timeout;
312 u32 boot_data;
313
314 /* perform soft reset */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200315 wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300316
317 /* SOFT_RESET is self clearing */
318 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
319 while (1) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200320 boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300321 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
322 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
323 break;
324
325 if (time_after(jiffies, timeout)) {
326 /* 1.2 check pWhalBus->uSelfClearTime if the
327 * timeout was reached */
328 wl1271_error("soft reset timeout");
329 return -1;
330 }
331
332 udelay(SOFT_RESET_STALL_TIME);
333 }
334
335 /* disable Rx/Tx */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200336 wl1271_write32(wl, ENABLE, 0x0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300337
338 /* disable auto calibration on start*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200339 wl1271_write32(wl, SPARE_A2, 0xffff);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300340
341 return 0;
342}
343
344static int wl1271_boot_run_firmware(struct wl1271 *wl)
345{
346 int loop, ret;
347 u32 chip_id, interrupt;
348
349 wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
350
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200351 chip_id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352
353 wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
354
355 if (chip_id != wl->chip.id) {
356 wl1271_error("chip id doesn't match after firmware boot");
357 return -EIO;
358 }
359
360 /* wait for init to complete */
361 loop = 0;
362 while (loop++ < INIT_LOOP) {
363 udelay(INIT_LOOP_DELAY);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200364 interrupt = wl1271_read32(wl, 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) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200373 wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
374 WL1271_ACX_INTR_INIT_COMPLETE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300375 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 */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200386 wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
388 /* get hardware config event mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200389 wl->event_box_addr = wl1271_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
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200462 wl1271_write32(wl, PLL_PARAMETERS, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200464 pause = wl1271_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;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200473 wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474
475 /* Continue the ELP wake up sequence */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200476 wl1271_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);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200486 clk = wl1271_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;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200492 wl1271_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 */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200497 wl1271_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
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200512 wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200514 tmp = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515
516 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
517
518 /* 6. read the EEPROM parameters */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200519 tmp = wl1271_read32(wl, SCR_PAD2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300520
521 ret = wl1271_boot_write_irq_polarity(wl);
522 if (ret < 0)
523 goto out;
524
525 /* FIXME: Need to check whether this is really what we want */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200526 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
527 WL1271_ACX_ALL_EVENTS_VECTOR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528
529 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
530 * to upload_fw) */
531
532 ret = wl1271_boot_upload_firmware(wl);
533 if (ret < 0)
534 goto out;
535
536 /* 10.5 start firmware */
537 ret = wl1271_boot_run_firmware(wl);
538 if (ret < 0)
539 goto out;
540
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300541 /* Enable firmware interrupts now */
542 wl1271_boot_enable_interrupts(wl);
543
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544 /* set the wl1271 default filters */
545 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
546 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
547
548 wl1271_event_mbox_config(wl);
549
550out:
551 return ret;
552}