blob: 7acef88df1fea07b8ef06d42ad8f49e090cedfc6 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Luciano Coelho2f826f52010-03-26 12:53:21 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
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"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020029#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030030#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) */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020096 cpu_ctrl = wl1271_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;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200100 wl1271_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
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200107 wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
108 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);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200167 wl1271_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);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200178 wl1271_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
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200231 /* update current MAC address to NVS */
232 nvs_ptr[11] = wl->mac_addr[0];
233 nvs_ptr[10] = wl->mac_addr[1];
234 nvs_ptr[6] = wl->mac_addr[2];
235 nvs_ptr[5] = wl->mac_addr[3];
236 nvs_ptr[4] = wl->mac_addr[4];
237 nvs_ptr[3] = wl->mac_addr[5];
238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300239 /*
240 * Layout before the actual NVS tables:
241 * 1 byte : burst length.
242 * 2 bytes: destination address.
243 * n bytes: data to burst copy.
244 *
245 * This is ended by a 0 length, then the NVS tables.
246 */
247
248 /* FIXME: Do we need to check here whether the LSB is 1? */
249 while (nvs_ptr[0]) {
250 burst_len = nvs_ptr[0];
251 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
252
253 /* FIXME: Due to our new wl1271_translate_reg_addr function,
254 we need to add the REGISTER_BASE to the destination */
255 dest_addr += REGISTERS_BASE;
256
257 /* We move our pointer to the data */
258 nvs_ptr += 3;
259
260 for (i = 0; i < burst_len; i++) {
261 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
262 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
263
264 wl1271_debug(DEBUG_BOOT,
265 "nvs burst write 0x%x: 0x%x",
266 dest_addr, val);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200267 wl1271_write32(wl, dest_addr, val);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300268
269 nvs_ptr += 4;
270 dest_addr += 4;
271 }
272 }
273
274 /*
275 * We've reached the first zero length, the first NVS table
276 * is 7 bytes further.
277 */
278 nvs_ptr += 7;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200279 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300280 nvs_len = ALIGN(nvs_len, 4);
281
282 /* FIXME: The driver sets the partition here, but this is not needed,
283 since it sets to the same one as currently in use */
284 /* Now we must set the partition correctly */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300285 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300286
287 /* Copy the NVS tables to a new block to ensure alignment */
Luciano Coelho6f8434a2010-02-18 13:25:45 +0200288 /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
289 that our NVS files have three extra zeros here. I'm not sure whether
290 the problem is in our NVS generation or we should really jumpt these
291 3 bytes here */
292 nvs_ptr += 3;
293
294 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
295 (!nvs_aligned) return -ENOMEM;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300296
297 /* And finally we upload the NVS tables */
298 /* FIXME: In wl1271, we upload everything at once.
299 No endianness handling needed here?! The ref driver doesn't do
300 anything about it at this point */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200301 wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300302
303 kfree(nvs_aligned);
304 return 0;
305}
306
307static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
308{
Teemu Paasikivi54f7e502010-02-22 08:38:22 +0200309 wl1271_enable_interrupts(wl);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200310 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
311 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
312 wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300313}
314
315static int wl1271_boot_soft_reset(struct wl1271 *wl)
316{
317 unsigned long timeout;
318 u32 boot_data;
319
320 /* perform soft reset */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200321 wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300322
323 /* SOFT_RESET is self clearing */
324 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
325 while (1) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200326 boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300327 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
328 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
329 break;
330
331 if (time_after(jiffies, timeout)) {
332 /* 1.2 check pWhalBus->uSelfClearTime if the
333 * timeout was reached */
334 wl1271_error("soft reset timeout");
335 return -1;
336 }
337
338 udelay(SOFT_RESET_STALL_TIME);
339 }
340
341 /* disable Rx/Tx */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200342 wl1271_write32(wl, ENABLE, 0x0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300343
344 /* disable auto calibration on start*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200345 wl1271_write32(wl, SPARE_A2, 0xffff);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300346
347 return 0;
348}
349
350static int wl1271_boot_run_firmware(struct wl1271 *wl)
351{
352 int loop, ret;
353 u32 chip_id, interrupt;
354
355 wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
356
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200357 chip_id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300358
359 wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
360
361 if (chip_id != wl->chip.id) {
362 wl1271_error("chip id doesn't match after firmware boot");
363 return -EIO;
364 }
365
366 /* wait for init to complete */
367 loop = 0;
368 while (loop++ < INIT_LOOP) {
369 udelay(INIT_LOOP_DELAY);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200370 interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300371
372 if (interrupt == 0xffffffff) {
373 wl1271_error("error reading hardware complete "
374 "init indication");
375 return -EIO;
376 }
377 /* check that ACX_INTR_INIT_COMPLETE is enabled */
378 else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200379 wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
380 WL1271_ACX_INTR_INIT_COMPLETE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381 break;
382 }
383 }
384
Luciano Coelhoe7d17cf2009-10-29 13:20:04 +0200385 if (loop > INIT_LOOP) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386 wl1271_error("timeout waiting for the hardware to "
387 "complete initialization");
388 return -EIO;
389 }
390
391 /* get hardware config command mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200392 wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300393
394 /* get hardware config event mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200395 wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396
397 /* set the working partition to its "running" mode offset */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300398 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399
400 wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
401 wl->cmd_box_addr, wl->event_box_addr);
402
403 wl1271_boot_fw_version(wl);
404
405 /*
406 * in case of full asynchronous mode the firmware event must be
407 * ready to receive event from the command mailbox
408 */
409
Juuso Oikarinenbe823e52009-10-08 21:56:36 +0300410 /* unmask required mbox events */
411 wl->event_mask = BSS_LOSE_EVENT_ID |
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200412 SCAN_COMPLETE_EVENT_ID |
Luciano Coelho99d84c12010-03-26 12:53:20 +0200413 PS_REPORT_EVENT_ID |
Luciano Coelho2f826f52010-03-26 12:53:21 +0200414 JOIN_EVENT_COMPLETE_ID |
415 DISCONNECT_EVENT_COMPLETE_ID;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300416
417 ret = wl1271_event_unmask(wl);
418 if (ret < 0) {
419 wl1271_error("EVENT mask setting failed");
420 return ret;
421 }
422
423 wl1271_event_mbox_config(wl);
424
425 /* firmware startup completed */
426 return 0;
427}
428
429static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
430{
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300431 u32 polarity;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300433 polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300434
435 /* We use HIGH polarity, so unset the LOW bit */
436 polarity &= ~POLARITY_LOW;
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300437 wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300438
439 return 0;
440}
441
442int wl1271_boot(struct wl1271 *wl)
443{
444 int ret = 0;
445 u32 tmp, clk, pause;
446
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300447 if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
448 /* ref clk: 19.2/38.4/38.4-XTAL */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449 clk = 0x3;
450 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
451 /* ref clk: 26/52 */
452 clk = 0x5;
453
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300454 if (REF_CLOCK != 0) {
455 u16 val;
Juuso Oikarinen9d4e5bb2010-03-26 12:53:15 +0200456 /* Set clock type (open drain) */
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300457 val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
458 val &= FREF_CLK_TYPE_BITS;
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300459 wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
Juuso Oikarinen9d4e5bb2010-03-26 12:53:15 +0200460
461 /* Set clock pull mode (no pull) */
462 val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
463 val |= NO_PULL;
464 wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300465 } else {
466 u16 val;
467 /* Set clock polarity */
468 val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
469 val &= FREF_CLK_POLARITY_BITS;
470 val |= CLK_REQ_OUTN_SEL;
471 wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
472 }
473
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200474 wl1271_write32(wl, PLL_PARAMETERS, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200476 pause = wl1271_read32(wl, PLL_PARAMETERS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477
478 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
479
480 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
481 * WU_COUNTER_PAUSE_VAL instead of
482 * 0x3ff (magic number ). How does
483 * this work?! */
484 pause |= WU_COUNTER_PAUSE_VAL;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200485 wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
487 /* Continue the ELP wake up sequence */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200488 wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300489 udelay(500);
490
Juuso Oikarinen451de972009-10-12 15:08:46 +0300491 wl1271_set_partition(wl, &part_table[PART_DRPW]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492
493 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
494 to be used by DRPw FW. The RTRIM value will be added by the FW
495 before taking DRPw out of reset */
496
497 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200498 clk = wl1271_read32(wl, DRPW_SCRATCH_START);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499
500 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
501
502 /* 2 */
503 clk |= (REF_CLOCK << 1) << 4;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200504 wl1271_write32(wl, DRPW_SCRATCH_START, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505
Juuso Oikarinen451de972009-10-12 15:08:46 +0300506 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300507
508 /* Disable interrupts */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200509 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
511 ret = wl1271_boot_soft_reset(wl);
512 if (ret < 0)
513 goto out;
514
515 /* 2. start processing NVS file */
516 ret = wl1271_boot_upload_nvs(wl);
517 if (ret < 0)
518 goto out;
519
520 /* write firmware's last address (ie. it's length) to
521 * ACX_EEPROMLESS_IND_REG */
522 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
523
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200524 wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200526 tmp = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527
528 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
529
530 /* 6. read the EEPROM parameters */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200531 tmp = wl1271_read32(wl, SCR_PAD2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300532
533 ret = wl1271_boot_write_irq_polarity(wl);
534 if (ret < 0)
535 goto out;
536
537 /* FIXME: Need to check whether this is really what we want */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200538 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
539 WL1271_ACX_ALL_EVENTS_VECTOR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300540
541 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
542 * to upload_fw) */
543
544 ret = wl1271_boot_upload_firmware(wl);
545 if (ret < 0)
546 goto out;
547
548 /* 10.5 start firmware */
549 ret = wl1271_boot_run_firmware(wl);
550 if (ret < 0)
551 goto out;
552
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300553 /* Enable firmware interrupts now */
554 wl1271_boot_enable_interrupts(wl);
555
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556 /* set the wl1271 default filters */
557 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
558 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
559
560 wl1271_event_mbox_config(wl);
561
562out:
563 return ret;
564}