2 * This file is part of wl1271
4 * Copyright (C) 2008-2009 Nokia Corporation
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
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.
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.
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
24 #include <linux/gpio.h>
26 #include "wl1271_acx.h"
27 #include "wl1271_reg.h"
28 #include "wl1271_boot.h"
29 #include "wl1271_spi.h"
30 #include "wl1271_event.h"
32 static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
39 .start = REGISTERS_BASE,
50 .start = REGISTERS_BASE,
67 static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
71 /* 10.5.0 run the firmware (I) */
72 cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL);
74 /* 10.5.1 run the firmware (II) */
76 wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
79 static void wl1271_boot_fw_version(struct wl1271 *wl)
81 struct wl1271_static_data static_data;
83 wl1271_spi_mem_read(wl, wl->cmd_box_addr,
84 &static_data, sizeof(static_data));
86 strncpy(wl->chip.fw_ver, static_data.fw_version,
87 sizeof(wl->chip.fw_ver));
89 /* make sure the string is NULL-terminated */
90 wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0';
93 static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
94 size_t fw_data_len, u32 dest)
96 int addr, chunk_num, partition_limit;
99 /* whal_FwCtrl_LoadFwImageSm() */
101 wl1271_debug(DEBUG_BOOT, "starting firmware upload");
103 wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len,
107 if ((fw_data_len % 4) != 0) {
108 wl1271_error("firmware length not multiple of four");
112 wl1271_set_partition(wl, dest,
113 part_table[PART_DOWN].mem.size,
114 part_table[PART_DOWN].reg.start,
115 part_table[PART_DOWN].reg.size);
117 /* 10.1 set partition limit and chunk num */
119 partition_limit = part_table[PART_DOWN].mem.size;
121 while (chunk_num < fw_data_len / CHUNK_SIZE) {
122 /* 10.2 update partition, if needed */
123 addr = dest + (chunk_num + 2) * CHUNK_SIZE;
124 if (addr > partition_limit) {
125 addr = dest + chunk_num * CHUNK_SIZE;
126 partition_limit = chunk_num * CHUNK_SIZE +
127 part_table[PART_DOWN].mem.size;
129 /* FIXME: Over 80 chars! */
130 wl1271_set_partition(wl,
132 part_table[PART_DOWN].mem.size,
133 part_table[PART_DOWN].reg.start,
134 part_table[PART_DOWN].reg.size);
137 /* 10.3 upload the chunk */
138 addr = dest + chunk_num * CHUNK_SIZE;
139 p = buf + chunk_num * CHUNK_SIZE;
140 wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
142 wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE);
147 /* 10.4 upload the last chunk */
148 addr = dest + chunk_num * CHUNK_SIZE;
149 p = buf + chunk_num * CHUNK_SIZE;
150 wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x",
151 fw_data_len % CHUNK_SIZE, p, addr);
152 wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
157 static int wl1271_boot_upload_firmware(struct wl1271 *wl)
159 u32 chunks, addr, len;
163 chunks = be32_to_cpup((u32 *) fw);
166 wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
169 addr = be32_to_cpup((u32 *) fw);
171 len = be32_to_cpup((u32 *) fw);
175 wl1271_info("firmware chunk too long: %u", len);
178 wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
180 wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
187 static int wl1271_boot_upload_nvs(struct wl1271 *wl)
189 size_t nvs_len, burst_len;
192 u8 *nvs_ptr, *nvs, *nvs_aligned;
200 nvs_len = wl->nvs_len;
202 /* Update the device MAC address into the nvs */
203 nvs[11] = wl->mac_addr[0];
204 nvs[10] = wl->mac_addr[1];
205 nvs[6] = wl->mac_addr[2];
206 nvs[5] = wl->mac_addr[3];
207 nvs[4] = wl->mac_addr[4];
208 nvs[3] = wl->mac_addr[5];
211 * Layout before the actual NVS tables:
212 * 1 byte : burst length.
213 * 2 bytes: destination address.
214 * n bytes: data to burst copy.
216 * This is ended by a 0 length, then the NVS tables.
219 /* FIXME: Do we need to check here whether the LSB is 1? */
221 burst_len = nvs_ptr[0];
222 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
224 /* FIXME: Due to our new wl1271_translate_reg_addr function,
225 we need to add the REGISTER_BASE to the destination */
226 dest_addr += REGISTERS_BASE;
228 /* We move our pointer to the data */
231 for (i = 0; i < burst_len; i++) {
232 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
233 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
235 wl1271_debug(DEBUG_BOOT,
236 "nvs burst write 0x%x: 0x%x",
238 wl1271_reg_write32(wl, dest_addr, val);
246 * We've reached the first zero length, the first NVS table
247 * is 7 bytes further.
250 nvs_len -= nvs_ptr - nvs;
251 nvs_len = ALIGN(nvs_len, 4);
253 /* FIXME: The driver sets the partition here, but this is not needed,
254 since it sets to the same one as currently in use */
255 /* Now we must set the partition correctly */
256 wl1271_set_partition(wl,
257 part_table[PART_WORK].mem.start,
258 part_table[PART_WORK].mem.size,
259 part_table[PART_WORK].reg.start,
260 part_table[PART_WORK].reg.size);
262 /* Copy the NVS tables to a new block to ensure alignment */
263 nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
265 /* And finally we upload the NVS tables */
266 /* FIXME: In wl1271, we upload everything at once.
267 No endianness handling needed here?! The ref driver doesn't do
268 anything about it at this point */
269 wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);
275 static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
278 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK));
279 wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
282 static int wl1271_boot_soft_reset(struct wl1271 *wl)
284 unsigned long timeout;
287 /* perform soft reset */
288 wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
290 /* SOFT_RESET is self clearing */
291 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
293 boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
294 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
295 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
298 if (time_after(jiffies, timeout)) {
299 /* 1.2 check pWhalBus->uSelfClearTime if the
300 * timeout was reached */
301 wl1271_error("soft reset timeout");
305 udelay(SOFT_RESET_STALL_TIME);
309 wl1271_reg_write32(wl, ENABLE, 0x0);
311 /* disable auto calibration on start*/
312 wl1271_reg_write32(wl, SPARE_A2, 0xffff);
317 static int wl1271_boot_run_firmware(struct wl1271 *wl)
320 u32 chip_id, interrupt;
322 wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
324 chip_id = wl1271_reg_read32(wl, CHIP_ID_B);
326 wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
328 if (chip_id != wl->chip.id) {
329 wl1271_error("chip id doesn't match after firmware boot");
333 /* wait for init to complete */
335 while (loop++ < INIT_LOOP) {
336 udelay(INIT_LOOP_DELAY);
337 interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
339 if (interrupt == 0xffffffff) {
340 wl1271_error("error reading hardware complete "
344 /* check that ACX_INTR_INIT_COMPLETE is enabled */
345 else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
346 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
347 WL1271_ACX_INTR_INIT_COMPLETE);
352 if (loop >= INIT_LOOP) {
353 wl1271_error("timeout waiting for the hardware to "
354 "complete initialization");
358 /* get hardware config command mail box */
359 wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
361 /* get hardware config event mail box */
362 wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
364 /* set the working partition to its "running" mode offset */
365 wl1271_set_partition(wl,
366 part_table[PART_WORK].mem.start,
367 part_table[PART_WORK].mem.size,
368 part_table[PART_WORK].reg.start,
369 part_table[PART_WORK].reg.size);
371 wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
372 wl->cmd_box_addr, wl->event_box_addr);
374 wl1271_boot_fw_version(wl);
377 * in case of full asynchronous mode the firmware event must be
378 * ready to receive event from the command mailbox
381 /* enable gpio interrupts */
382 wl1271_boot_enable_interrupts(wl);
384 /* unmask all mbox events */
385 wl->event_mask = 0xffffffff;
387 ret = wl1271_event_unmask(wl);
389 wl1271_error("EVENT mask setting failed");
393 wl1271_event_mbox_config(wl);
395 /* firmware startup completed */
399 static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
401 u32 polarity, status, i;
403 wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
404 wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
406 /* Wait until the command is complete (ie. bit 18 is set) */
407 for (i = 0; i < OCP_CMD_LOOP; i++) {
408 polarity = wl1271_reg_read32(wl, OCP_DATA_READ);
409 if (polarity & OCP_READY_MASK)
412 if (i == OCP_CMD_LOOP) {
413 wl1271_error("OCP command timeout!");
417 status = polarity & OCP_STATUS_MASK;
418 if (status != OCP_STATUS_OK) {
419 wl1271_error("OCP command failed (%d)", status);
423 /* We use HIGH polarity, so unset the LOW bit */
424 polarity &= ~POLARITY_LOW;
426 wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
427 wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity);
428 wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
433 int wl1271_boot(struct wl1271 *wl)
438 if (REF_CLOCK == 0 || REF_CLOCK == 2)
439 /* ref clk: 19.2/38.4 */
441 else if (REF_CLOCK == 1 || REF_CLOCK == 3)
445 wl1271_reg_write32(wl, PLL_PARAMETERS, clk);
447 pause = wl1271_reg_read32(wl, PLL_PARAMETERS);
449 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
451 pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
452 * WU_COUNTER_PAUSE_VAL instead of
453 * 0x3ff (magic number ). How does
455 pause |= WU_COUNTER_PAUSE_VAL;
456 wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause);
458 /* Continue the ELP wake up sequence */
459 wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
462 wl1271_set_partition(wl,
463 part_table[PART_DRPW].mem.start,
464 part_table[PART_DRPW].mem.size,
465 part_table[PART_DRPW].reg.start,
466 part_table[PART_DRPW].reg.size);
468 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
469 to be used by DRPw FW. The RTRIM value will be added by the FW
470 before taking DRPw out of reset */
472 wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
473 clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START);
475 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
478 clk |= (REF_CLOCK << 1) << 4;
479 wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk);
481 wl1271_set_partition(wl,
482 part_table[PART_WORK].mem.start,
483 part_table[PART_WORK].mem.size,
484 part_table[PART_WORK].reg.start,
485 part_table[PART_WORK].reg.size);
487 /* Disable interrupts */
488 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
490 ret = wl1271_boot_soft_reset(wl);
494 /* 2. start processing NVS file */
495 ret = wl1271_boot_upload_nvs(wl);
499 /* write firmware's last address (ie. it's length) to
500 * ACX_EEPROMLESS_IND_REG */
501 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
503 wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
505 tmp = wl1271_reg_read32(wl, CHIP_ID_B);
507 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
509 /* 6. read the EEPROM parameters */
510 tmp = wl1271_reg_read32(wl, SCR_PAD2);
512 ret = wl1271_boot_write_irq_polarity(wl);
516 /* FIXME: Need to check whether this is really what we want */
517 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
518 WL1271_ACX_ALL_EVENTS_VECTOR);
520 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
523 ret = wl1271_boot_upload_firmware(wl);
527 /* 10.5 start firmware */
528 ret = wl1271_boot_run_firmware(wl);
532 /* set the wl1271 default filters */
533 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
534 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
536 wl1271_event_mbox_config(wl);