wl1271: Rewrite hardware keep-alive handling
[deliverable/linux.git] / drivers / net / wireless / wl12xx / wl1271_boot.c
CommitLineData
f5fc0f86
LC
1/*
2 * This file is part of wl1271
3 *
2f826f55 4 * Copyright (C) 2008-2010 Nokia Corporation
f5fc0f86
LC
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"
7b048c52 29#include "wl1271_io.h"
f5fc0f86
LC
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 },
451de97a
JO
42 .mem2 = {
43 .start = 0x00000000,
44 .size = 0x00000000
45 },
46 .mem3 = {
47 .start = 0x00000000,
48 .size = 0x00000000
49 },
f5fc0f86
LC
50 },
51
52 [PART_WORK] = {
53 .mem = {
54 .start = 0x00040000,
55 .size = 0x00014fc0
56 },
57 .reg = {
58 .start = REGISTERS_BASE,
451de97a
JO
59 .size = 0x0000a000
60 },
61 .mem2 = {
62 .start = 0x003004f8,
63 .size = 0x00000004
64 },
65 .mem3 = {
66 .start = 0x00040404,
67 .size = 0x00000000
f5fc0f86
LC
68 },
69 },
70
71 [PART_DRPW] = {
72 .mem = {
73 .start = 0x00040000,
74 .size = 0x00014fc0
75 },
76 .reg = {
77 .start = DRPW_BASE,
78 .size = 0x00006000
451de97a
JO
79 },
80 .mem2 = {
81 .start = 0x00000000,
82 .size = 0x00000000
83 },
84 .mem3 = {
85 .start = 0x00000000,
86 .size = 0x00000000
f5fc0f86
LC
87 }
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) */
7b048c52 96 cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL);
f5fc0f86
LC
97
98 /* 10.5.1 run the firmware (II) */
99 cpu_ctrl |= flag;
7b048c52 100 wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
f5fc0f86
LC
101}
102
103static void wl1271_boot_fw_version(struct wl1271 *wl)
104{
105 struct wl1271_static_data static_data;
106
7b048c52
TP
107 wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
108 false);
f5fc0f86
LC
109
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{
451de97a 120 struct wl1271_partition_set partition;
f5fc0f86 121 int addr, chunk_num, partition_limit;
1fba4974 122 u8 *p, *chunk;
f5fc0f86
LC
123
124 /* whal_FwCtrl_LoadFwImageSm() */
125
126 wl1271_debug(DEBUG_BOOT, "starting firmware upload");
127
73d0a13c
LC
128 wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
129 fw_data_len, CHUNK_SIZE);
f5fc0f86 130
f5fc0f86
LC
131 if ((fw_data_len % 4) != 0) {
132 wl1271_error("firmware length not multiple of four");
133 return -EIO;
134 }
135
1fba4974 136 chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
ed317788 137 if (!chunk) {
1fba4974
JO
138 wl1271_error("allocation for firmware upload chunk failed");
139 return -ENOMEM;
140 }
141
451de97a
JO
142 memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
143 partition.mem.start = dest;
144 wl1271_set_partition(wl, &partition);
f5fc0f86
LC
145
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;
451de97a
JO
157 partition.mem.start = addr;
158 wl1271_set_partition(wl, &partition);
f5fc0f86
LC
159 }
160
161 /* 10.3 upload the chunk */
162 addr = dest + chunk_num * CHUNK_SIZE;
163 p = buf + chunk_num * CHUNK_SIZE;
1fba4974 164 memcpy(chunk, p, CHUNK_SIZE);
f5fc0f86
LC
165 wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
166 p, addr);
7b048c52 167 wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
f5fc0f86
LC
168
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;
1fba4974 175 memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
73d0a13c 176 wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
f5fc0f86 177 fw_data_len % CHUNK_SIZE, p, addr);
7b048c52 178 wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
f5fc0f86 179
1fba4974 180 kfree(chunk);
f5fc0f86
LC
181 return 0;
182}
183
184static int wl1271_boot_upload_firmware(struct wl1271 *wl)
185{
186 u32 chunks, addr, len;
ed317788 187 int ret = 0;
f5fc0f86
LC
188 u8 *fw;
189
190 fw = wl->fw;
d0f63b20 191 chunks = be32_to_cpup((__be32 *) fw);
f5fc0f86
LC
192 fw += sizeof(u32);
193
194 wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
195
196 while (chunks--) {
d0f63b20 197 addr = be32_to_cpup((__be32 *) fw);
f5fc0f86 198 fw += sizeof(u32);
d0f63b20 199 len = be32_to_cpup((__be32 *) fw);
f5fc0f86
LC
200 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);
ed317788
JO
208 ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
209 if (ret != 0)
210 break;
f5fc0f86
LC
211 fw += len;
212 }
213
ed317788 214 return ret;
f5fc0f86
LC
215}
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;
152ee6e0 222 u8 *nvs_ptr, *nvs_aligned;
f5fc0f86 223
152ee6e0 224 if (wl->nvs == NULL)
f5fc0f86
LC
225 return -ENODEV;
226
8cf5e8e5 227 /* only the first part of the NVS needs to be uploaded */
152ee6e0
JO
228 nvs_len = sizeof(wl->nvs->nvs);
229 nvs_ptr = (u8 *)wl->nvs->nvs;
f5fc0f86 230
1b72aecd
JO
231 /* 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
f5fc0f86
LC
239 /*
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);
7b048c52 267 wl1271_write32(wl, dest_addr, val);
f5fc0f86
LC
268
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;
152ee6e0 279 nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
f5fc0f86
LC
280 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 */
451de97a 285 wl1271_set_partition(wl, &part_table[PART_WORK]);
f5fc0f86
LC
286
287 /* Copy the NVS tables to a new block to ensure alignment */
6f8434a7
LC
288 /* 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;
f5fc0f86
LC
296
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 */
7b048c52 301 wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
f5fc0f86
LC
302
303 kfree(nvs_aligned);
304 return 0;
305}
306
307static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
308{
54f7e503 309 wl1271_enable_interrupts(wl);
7b048c52
TP
310 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);
f5fc0f86
LC
313}
314
315static int wl1271_boot_soft_reset(struct wl1271 *wl)
316{
317 unsigned long timeout;
318 u32 boot_data;
319
320 /* perform soft reset */
7b048c52 321 wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
f5fc0f86
LC
322
323 /* SOFT_RESET is self clearing */
324 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
325 while (1) {
7b048c52 326 boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
f5fc0f86
LC
327 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 */
7b048c52 342 wl1271_write32(wl, ENABLE, 0x0);
f5fc0f86
LC
343
344 /* disable auto calibration on start*/
7b048c52 345 wl1271_write32(wl, SPARE_A2, 0xffff);
f5fc0f86
LC
346
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
7b048c52 357 chip_id = wl1271_read32(wl, CHIP_ID_B);
f5fc0f86
LC
358
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);
7b048c52 370 interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
f5fc0f86
LC
371
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) {
7b048c52
TP
379 wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
380 WL1271_ACX_INTR_INIT_COMPLETE);
f5fc0f86
LC
381 break;
382 }
383 }
384
e7d17cf4 385 if (loop > INIT_LOOP) {
f5fc0f86
LC
386 wl1271_error("timeout waiting for the hardware to "
387 "complete initialization");
388 return -EIO;
389 }
390
391 /* get hardware config command mail box */
7b048c52 392 wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
f5fc0f86
LC
393
394 /* get hardware config event mail box */
7b048c52 395 wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
f5fc0f86
LC
396
397 /* set the working partition to its "running" mode offset */
451de97a 398 wl1271_set_partition(wl, &part_table[PART_WORK]);
f5fc0f86
LC
399
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
be823e5b
JO
410 /* unmask required mbox events */
411 wl->event_mask = BSS_LOSE_EVENT_ID |
19ad0715 412 SCAN_COMPLETE_EVENT_ID |
99d84c1d 413 PS_REPORT_EVENT_ID |
2f826f55 414 JOIN_EVENT_COMPLETE_ID |
00236aed
JO
415 DISCONNECT_EVENT_COMPLETE_ID |
416 RSSI_SNR_TRIGGER_0_EVENT_ID;
f5fc0f86
LC
417
418 ret = wl1271_event_unmask(wl);
419 if (ret < 0) {
420 wl1271_error("EVENT mask setting failed");
421 return ret;
422 }
423
424 wl1271_event_mbox_config(wl);
425
426 /* firmware startup completed */
427 return 0;
428}
429
430static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
431{
e8768eeb 432 u32 polarity;
f5fc0f86 433
e8768eeb 434 polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
f5fc0f86
LC
435
436 /* We use HIGH polarity, so unset the LOW bit */
437 polarity &= ~POLARITY_LOW;
e8768eeb 438 wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
f5fc0f86
LC
439
440 return 0;
441}
442
443int wl1271_boot(struct wl1271 *wl)
444{
445 int ret = 0;
446 u32 tmp, clk, pause;
447
284134eb
JO
448 if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
449 /* ref clk: 19.2/38.4/38.4-XTAL */
f5fc0f86
LC
450 clk = 0x3;
451 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
452 /* ref clk: 26/52 */
453 clk = 0x5;
454
284134eb
JO
455 if (REF_CLOCK != 0) {
456 u16 val;
9d4e5bb3 457 /* Set clock type (open drain) */
284134eb
JO
458 val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
459 val &= FREF_CLK_TYPE_BITS;
284134eb 460 wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
9d4e5bb3
JO
461
462 /* Set clock pull mode (no pull) */
463 val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
464 val |= NO_PULL;
465 wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
284134eb
JO
466 } else {
467 u16 val;
468 /* Set clock polarity */
469 val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
470 val &= FREF_CLK_POLARITY_BITS;
471 val |= CLK_REQ_OUTN_SEL;
472 wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
473 }
474
7b048c52 475 wl1271_write32(wl, PLL_PARAMETERS, clk);
f5fc0f86 476
7b048c52 477 pause = wl1271_read32(wl, PLL_PARAMETERS);
f5fc0f86
LC
478
479 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
480
481 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
482 * WU_COUNTER_PAUSE_VAL instead of
483 * 0x3ff (magic number ). How does
484 * this work?! */
485 pause |= WU_COUNTER_PAUSE_VAL;
7b048c52 486 wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
f5fc0f86
LC
487
488 /* Continue the ELP wake up sequence */
7b048c52 489 wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
f5fc0f86
LC
490 udelay(500);
491
451de97a 492 wl1271_set_partition(wl, &part_table[PART_DRPW]);
f5fc0f86
LC
493
494 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
495 to be used by DRPw FW. The RTRIM value will be added by the FW
496 before taking DRPw out of reset */
497
498 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
7b048c52 499 clk = wl1271_read32(wl, DRPW_SCRATCH_START);
f5fc0f86
LC
500
501 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
502
503 /* 2 */
504 clk |= (REF_CLOCK << 1) << 4;
7b048c52 505 wl1271_write32(wl, DRPW_SCRATCH_START, clk);
f5fc0f86 506
451de97a 507 wl1271_set_partition(wl, &part_table[PART_WORK]);
f5fc0f86
LC
508
509 /* Disable interrupts */
7b048c52 510 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
f5fc0f86
LC
511
512 ret = wl1271_boot_soft_reset(wl);
513 if (ret < 0)
514 goto out;
515
516 /* 2. start processing NVS file */
517 ret = wl1271_boot_upload_nvs(wl);
518 if (ret < 0)
519 goto out;
520
521 /* write firmware's last address (ie. it's length) to
522 * ACX_EEPROMLESS_IND_REG */
523 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
524
7b048c52 525 wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
f5fc0f86 526
7b048c52 527 tmp = wl1271_read32(wl, CHIP_ID_B);
f5fc0f86
LC
528
529 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
530
531 /* 6. read the EEPROM parameters */
7b048c52 532 tmp = wl1271_read32(wl, SCR_PAD2);
f5fc0f86
LC
533
534 ret = wl1271_boot_write_irq_polarity(wl);
535 if (ret < 0)
536 goto out;
537
538 /* FIXME: Need to check whether this is really what we want */
7b048c52
TP
539 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
540 WL1271_ACX_ALL_EVENTS_VECTOR);
f5fc0f86
LC
541
542 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
543 * to upload_fw) */
544
545 ret = wl1271_boot_upload_firmware(wl);
546 if (ret < 0)
547 goto out;
548
549 /* 10.5 start firmware */
550 ret = wl1271_boot_run_firmware(wl);
551 if (ret < 0)
552 goto out;
553
eb5b28d0
JO
554 /* Enable firmware interrupts now */
555 wl1271_boot_enable_interrupts(wl);
556
f5fc0f86
LC
557 /* set the wl1271 default filters */
558 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
559 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
560
561 wl1271_event_mbox_config(wl);
562
563out:
564 return ret;
565}
This page took 0.173855 seconds and 5 git commands to generate.