blob: f36430b0336d87d3c118962f0e573132ef7afa07 [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>
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"
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
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200232 /* update current MAC address to NVS */
233 nvs_ptr[11] = wl->mac_addr[0];
234 nvs_ptr[10] = wl->mac_addr[1];
235 nvs_ptr[6] = wl->mac_addr[2];
236 nvs_ptr[5] = wl->mac_addr[3];
237 nvs_ptr[4] = wl->mac_addr[4];
238 nvs_ptr[3] = wl->mac_addr[5];
239
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300240 /*
241 * Layout before the actual NVS tables:
242 * 1 byte : burst length.
243 * 2 bytes: destination address.
244 * n bytes: data to burst copy.
245 *
246 * This is ended by a 0 length, then the NVS tables.
247 */
248
249 /* FIXME: Do we need to check here whether the LSB is 1? */
250 while (nvs_ptr[0]) {
251 burst_len = nvs_ptr[0];
252 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
253
254 /* FIXME: Due to our new wl1271_translate_reg_addr function,
255 we need to add the REGISTER_BASE to the destination */
256 dest_addr += REGISTERS_BASE;
257
258 /* We move our pointer to the data */
259 nvs_ptr += 3;
260
261 for (i = 0; i < burst_len; i++) {
262 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
263 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
264
265 wl1271_debug(DEBUG_BOOT,
266 "nvs burst write 0x%x: 0x%x",
267 dest_addr, val);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200268 wl1271_write32(wl, dest_addr, val);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300269
270 nvs_ptr += 4;
271 dest_addr += 4;
272 }
273 }
274
275 /*
276 * We've reached the first zero length, the first NVS table
277 * is 7 bytes further.
278 */
279 nvs_ptr += 7;
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200280 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300281 nvs_len = ALIGN(nvs_len, 4);
282
283 /* FIXME: The driver sets the partition here, but this is not needed,
284 since it sets to the same one as currently in use */
285 /* Now we must set the partition correctly */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300286 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300287
288 /* Copy the NVS tables to a new block to ensure alignment */
Luciano Coelho6f8434a2010-02-18 13:25:45 +0200289 /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
290 that our NVS files have three extra zeros here. I'm not sure whether
291 the problem is in our NVS generation or we should really jumpt these
292 3 bytes here */
293 nvs_ptr += 3;
294
295 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
296 (!nvs_aligned) return -ENOMEM;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300297
298 /* And finally we upload the NVS tables */
299 /* FIXME: In wl1271, we upload everything at once.
300 No endianness handling needed here?! The ref driver doesn't do
301 anything about it at this point */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200302 wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300303
304 kfree(nvs_aligned);
305 return 0;
306}
307
308static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
309{
Teemu Paasikivi54f7e502010-02-22 08:38:22 +0200310 wl1271_enable_interrupts(wl);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200311 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
312 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
313 wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300314}
315
316static int wl1271_boot_soft_reset(struct wl1271 *wl)
317{
318 unsigned long timeout;
319 u32 boot_data;
320
321 /* perform soft reset */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200322 wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300323
324 /* SOFT_RESET is self clearing */
325 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
326 while (1) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200327 boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300328 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
329 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
330 break;
331
332 if (time_after(jiffies, timeout)) {
333 /* 1.2 check pWhalBus->uSelfClearTime if the
334 * timeout was reached */
335 wl1271_error("soft reset timeout");
336 return -1;
337 }
338
339 udelay(SOFT_RESET_STALL_TIME);
340 }
341
342 /* disable Rx/Tx */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200343 wl1271_write32(wl, ENABLE, 0x0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300344
345 /* disable auto calibration on start*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200346 wl1271_write32(wl, SPARE_A2, 0xffff);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300347
348 return 0;
349}
350
351static int wl1271_boot_run_firmware(struct wl1271 *wl)
352{
353 int loop, ret;
Luciano Coelho23a7a512010-04-28 09:50:02 +0300354 u32 chip_id, intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300355
356 wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
357
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200358 chip_id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300359
360 wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
361
362 if (chip_id != wl->chip.id) {
363 wl1271_error("chip id doesn't match after firmware boot");
364 return -EIO;
365 }
366
367 /* wait for init to complete */
368 loop = 0;
369 while (loop++ < INIT_LOOP) {
370 udelay(INIT_LOOP_DELAY);
Luciano Coelho23a7a512010-04-28 09:50:02 +0300371 intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300372
Luciano Coelho23a7a512010-04-28 09:50:02 +0300373 if (intr == 0xffffffff) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374 wl1271_error("error reading hardware complete "
375 "init indication");
376 return -EIO;
377 }
378 /* check that ACX_INTR_INIT_COMPLETE is enabled */
Luciano Coelho23a7a512010-04-28 09:50:02 +0300379 else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200380 wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
381 WL1271_ACX_INTR_INIT_COMPLETE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382 break;
383 }
384 }
385
Luciano Coelhoe7d17cf2009-10-29 13:20:04 +0200386 if (loop > INIT_LOOP) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387 wl1271_error("timeout waiting for the hardware to "
388 "complete initialization");
389 return -EIO;
390 }
391
392 /* get hardware config command mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200393 wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300394
395 /* get hardware config event mail box */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200396 wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397
398 /* set the working partition to its "running" mode offset */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300399 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400
401 wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
402 wl->cmd_box_addr, wl->event_box_addr);
403
404 wl1271_boot_fw_version(wl);
405
406 /*
407 * in case of full asynchronous mode the firmware event must be
408 * ready to receive event from the command mailbox
409 */
410
Juuso Oikarinenbe823e52009-10-08 21:56:36 +0300411 /* unmask required mbox events */
412 wl->event_mask = BSS_LOSE_EVENT_ID |
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200413 SCAN_COMPLETE_EVENT_ID |
Luciano Coelho99d84c12010-03-26 12:53:20 +0200414 PS_REPORT_EVENT_ID |
Luciano Coelho2f826f52010-03-26 12:53:21 +0200415 JOIN_EVENT_COMPLETE_ID |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300416 DISCONNECT_EVENT_COMPLETE_ID |
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300417 RSSI_SNR_TRIGGER_0_EVENT_ID |
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300418 PSPOLL_DELIVERY_FAILURE_EVENT_ID |
419 SOFT_GEMINI_SENSE_EVENT_ID;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420
421 ret = wl1271_event_unmask(wl);
422 if (ret < 0) {
423 wl1271_error("EVENT mask setting failed");
424 return ret;
425 }
426
427 wl1271_event_mbox_config(wl);
428
429 /* firmware startup completed */
430 return 0;
431}
432
433static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
434{
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300435 u32 polarity;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300437 polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300438
439 /* We use HIGH polarity, so unset the LOW bit */
440 polarity &= ~POLARITY_LOW;
Juuso Oikarinene8768ee2009-10-12 15:08:48 +0300441 wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442
443 return 0;
444}
445
Juuso Oikarinend717fd62010-05-07 11:38:58 +0300446static void wl1271_boot_hw_version(struct wl1271 *wl)
447{
448 u32 fuse;
449
450 fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
451 fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
452
453 wl->hw_pg_ver = (s8)fuse;
454}
455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456int wl1271_boot(struct wl1271 *wl)
457{
458 int ret = 0;
459 u32 tmp, clk, pause;
460
Juuso Oikarinend717fd62010-05-07 11:38:58 +0300461 wl1271_boot_hw_version(wl);
462
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300463 if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
464 /* ref clk: 19.2/38.4/38.4-XTAL */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465 clk = 0x3;
466 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
467 /* ref clk: 26/52 */
468 clk = 0x5;
469
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300470 if (REF_CLOCK != 0) {
471 u16 val;
Juuso Oikarinen9d4e5bb2010-03-26 12:53:15 +0200472 /* Set clock type (open drain) */
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300473 val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
474 val &= FREF_CLK_TYPE_BITS;
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300475 wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
Juuso Oikarinen9d4e5bb2010-03-26 12:53:15 +0200476
477 /* Set clock pull mode (no pull) */
478 val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
479 val |= NO_PULL;
480 wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
Juuso Oikarinen284134e2009-10-12 15:08:49 +0300481 } else {
482 u16 val;
483 /* Set clock polarity */
484 val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
485 val &= FREF_CLK_POLARITY_BITS;
486 val |= CLK_REQ_OUTN_SEL;
487 wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
488 }
489
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200490 wl1271_write32(wl, PLL_PARAMETERS, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300491
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200492 pause = wl1271_read32(wl, PLL_PARAMETERS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493
494 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
495
496 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
497 * WU_COUNTER_PAUSE_VAL instead of
498 * 0x3ff (magic number ). How does
499 * this work?! */
500 pause |= WU_COUNTER_PAUSE_VAL;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200501 wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502
503 /* Continue the ELP wake up sequence */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200504 wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505 udelay(500);
506
Juuso Oikarinen451de972009-10-12 15:08:46 +0300507 wl1271_set_partition(wl, &part_table[PART_DRPW]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300508
509 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
510 to be used by DRPw FW. The RTRIM value will be added by the FW
511 before taking DRPw out of reset */
512
513 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200514 clk = wl1271_read32(wl, DRPW_SCRATCH_START);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515
516 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
517
518 /* 2 */
519 clk |= (REF_CLOCK << 1) << 4;
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200520 wl1271_write32(wl, DRPW_SCRATCH_START, clk);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521
Juuso Oikarinen451de972009-10-12 15:08:46 +0300522 wl1271_set_partition(wl, &part_table[PART_WORK]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523
524 /* Disable interrupts */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200525 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526
527 ret = wl1271_boot_soft_reset(wl);
528 if (ret < 0)
529 goto out;
530
531 /* 2. start processing NVS file */
532 ret = wl1271_boot_upload_nvs(wl);
533 if (ret < 0)
534 goto out;
535
536 /* write firmware's last address (ie. it's length) to
537 * ACX_EEPROMLESS_IND_REG */
538 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
539
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200540 wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300541
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200542 tmp = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543
544 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
545
546 /* 6. read the EEPROM parameters */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200547 tmp = wl1271_read32(wl, SCR_PAD2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300548
549 ret = wl1271_boot_write_irq_polarity(wl);
550 if (ret < 0)
551 goto out;
552
553 /* FIXME: Need to check whether this is really what we want */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200554 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
555 WL1271_ACX_ALL_EVENTS_VECTOR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556
557 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
558 * to upload_fw) */
559
560 ret = wl1271_boot_upload_firmware(wl);
561 if (ret < 0)
562 goto out;
563
564 /* 10.5 start firmware */
565 ret = wl1271_boot_run_firmware(wl);
566 if (ret < 0)
567 goto out;
568
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300569 /* Enable firmware interrupts now */
570 wl1271_boot_enable_interrupts(wl);
571
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300572 /* set the wl1271 default filters */
573 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
574 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
575
576 wl1271_event_mbox_config(wl);
577
578out:
579 return ret;
580}