aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1251_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_boot.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c256
1 files changed, 245 insertions, 11 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 8b50d44d8243..88e9cb0947d5 100644
--- a/drivers/net/wireless/wl12xx/wl1251_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -28,6 +28,7 @@
28#include "wl1251_io.h" 28#include "wl1251_io.h"
29#include "wl1251_spi.h" 29#include "wl1251_spi.h"
30#include "wl1251_event.h" 30#include "wl1251_event.h"
31#include "wl1251_acx.h"
31 32
32void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) 33void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
33{ 34{
@@ -208,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl)
208 return 0; 209 return 0;
209} 210}
210 211
212static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
213{
214 u32 cpu_ctrl;
215
216 /* 10.5.0 run the firmware (I) */
217 cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
218
219 /* 10.5.1 run the firmware (II) */
220 cpu_ctrl &= ~flag;
221 wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
222}
223
211int wl1251_boot_run_firmware(struct wl1251 *wl) 224int wl1251_boot_run_firmware(struct wl1251 *wl)
212{ 225{
213 int loop, ret; 226 int loop, ret;
214 u32 chip_id, interrupt; 227 u32 chip_id, interrupt;
215 228
216 wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); 229 wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
217 230
218 chip_id = wl1251_reg_read32(wl, CHIP_ID_B); 231 chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
219 232
220 wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); 233 wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
221 234
222 if (chip_id != wl->chip.id) { 235 if (chip_id != wl->chip_id) {
223 wl1251_error("chip id doesn't match after firmware boot"); 236 wl1251_error("chip id doesn't match after firmware boot");
224 return -EIO; 237 return -EIO;
225 } 238 }
@@ -236,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
236 return -EIO; 249 return -EIO;
237 } 250 }
238 /* check that ACX_INTR_INIT_COMPLETE is enabled */ 251 /* check that ACX_INTR_INIT_COMPLETE is enabled */
239 else if (interrupt & wl->chip.intr_init_complete) { 252 else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) {
240 wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, 253 wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
241 wl->chip.intr_init_complete); 254 WL1251_ACX_INTR_INIT_COMPLETE);
242 break; 255 break;
243 } 256 }
244 } 257 }
@@ -256,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
256 wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); 269 wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
257 270
258 /* set the working partition to its "running" mode offset */ 271 /* set the working partition to its "running" mode offset */
259 wl1251_set_partition(wl, 272 wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START,
260 wl->chip.p_table[PART_WORK].mem.start, 273 WL1251_PART_WORK_MEM_SIZE,
261 wl->chip.p_table[PART_WORK].mem.size, 274 WL1251_PART_WORK_REG_START,
262 wl->chip.p_table[PART_WORK].reg.start, 275 WL1251_PART_WORK_REG_SIZE);
263 wl->chip.p_table[PART_WORK].reg.size);
264 276
265 wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", 277 wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
266 wl->cmd_box_addr, wl->event_box_addr); 278 wl->cmd_box_addr, wl->event_box_addr);
267 279
268 wl->chip.op_fw_version(wl); 280 wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver));
269 281
270 /* 282 /*
271 * in case of full asynchronous mode the firmware event must be 283 * in case of full asynchronous mode the firmware event must be
@@ -275,7 +287,14 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
275 /* enable gpio interrupts */ 287 /* enable gpio interrupts */
276 wl1251_enable_interrupts(wl); 288 wl1251_enable_interrupts(wl);
277 289
278 wl->chip.op_target_enable_interrupts(wl); 290 /* Enable target's interrupts */
291 wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
292 WL1251_ACX_INTR_RX1_DATA |
293 WL1251_ACX_INTR_TX_RESULT |
294 WL1251_ACX_INTR_EVENT_A |
295 WL1251_ACX_INTR_EVENT_B |
296 WL1251_ACX_INTR_INIT_COMPLETE;
297 wl1251_boot_target_enable_interrupts(wl);
279 298
280 /* unmask all mbox events */ 299 /* unmask all mbox events */
281 wl->event_mask = 0xffffffff; 300 wl->event_mask = 0xffffffff;
@@ -291,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
291 /* firmware startup completed */ 310 /* firmware startup completed */
292 return 0; 311 return 0;
293} 312}
313
314static int wl1251_boot_upload_firmware(struct wl1251 *wl)
315{
316 int addr, chunk_num, partition_limit;
317 size_t fw_data_len;
318 u8 *p;
319
320 /* whal_FwCtrl_LoadFwImageSm() */
321
322 wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
323 wl1251_reg_read32(wl, CHIP_ID_B));
324
325 /* 10.0 check firmware length and set partition */
326 fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
327 (wl->fw[6] << 8) | (wl->fw[7]);
328
329 wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
330 CHUNK_SIZE);
331
332 if ((fw_data_len % 4) != 0) {
333 wl1251_error("firmware length not multiple of four");
334 return -EIO;
335 }
336
337 wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
338 WL1251_PART_DOWN_MEM_SIZE,
339 WL1251_PART_DOWN_REG_START,
340 WL1251_PART_DOWN_REG_SIZE);
341
342 /* 10.1 set partition limit and chunk num */
343 chunk_num = 0;
344 partition_limit = WL1251_PART_DOWN_MEM_SIZE;
345
346 while (chunk_num < fw_data_len / CHUNK_SIZE) {
347 /* 10.2 update partition, if needed */
348 addr = WL1251_PART_DOWN_MEM_START +
349 (chunk_num + 2) * CHUNK_SIZE;
350 if (addr > partition_limit) {
351 addr = WL1251_PART_DOWN_MEM_START +
352 chunk_num * CHUNK_SIZE;
353 partition_limit = chunk_num * CHUNK_SIZE +
354 WL1251_PART_DOWN_MEM_SIZE;
355 wl1251_set_partition(wl,
356 addr,
357 WL1251_PART_DOWN_MEM_SIZE,
358 WL1251_PART_DOWN_REG_START,
359 WL1251_PART_DOWN_REG_SIZE);
360 }
361
362 /* 10.3 upload the chunk */
363 addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
364 p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
365 wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
366 p, addr);
367 wl1251_mem_write(wl, addr, p, CHUNK_SIZE);
368
369 chunk_num++;
370 }
371
372 /* 10.4 upload the last chunk */
373 addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
374 p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
375 wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
376 fw_data_len % CHUNK_SIZE, p, addr);
377 wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
378
379 return 0;
380}
381
382static int wl1251_boot_upload_nvs(struct wl1251 *wl)
383{
384 size_t nvs_len, nvs_bytes_written, burst_len;
385 int nvs_start, i;
386 u32 dest_addr, val;
387 u8 *nvs_ptr, *nvs;
388
389 nvs = wl->nvs;
390 if (nvs == NULL)
391 return -ENODEV;
392
393 nvs_ptr = nvs;
394
395 nvs_len = wl->nvs_len;
396 nvs_start = wl->fw_len;
397
398 /*
399 * Layout before the actual NVS tables:
400 * 1 byte : burst length.
401 * 2 bytes: destination address.
402 * n bytes: data to burst copy.
403 *
404 * This is ended by a 0 length, then the NVS tables.
405 */
406
407 while (nvs_ptr[0]) {
408 burst_len = nvs_ptr[0];
409 dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
410
411 /* We move our pointer to the data */
412 nvs_ptr += 3;
413
414 for (i = 0; i < burst_len; i++) {
415 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
416 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
417
418 wl1251_debug(DEBUG_BOOT,
419 "nvs burst write 0x%x: 0x%x",
420 dest_addr, val);
421 wl1251_mem_write32(wl, dest_addr, val);
422
423 nvs_ptr += 4;
424 dest_addr += 4;
425 }
426 }
427
428 /*
429 * We've reached the first zero length, the first NVS table
430 * is 7 bytes further.
431 */
432 nvs_ptr += 7;
433 nvs_len -= nvs_ptr - nvs;
434 nvs_len = ALIGN(nvs_len, 4);
435
436 /* Now we must set the partition correctly */
437 wl1251_set_partition(wl, nvs_start,
438 WL1251_PART_DOWN_MEM_SIZE,
439 WL1251_PART_DOWN_REG_START,
440 WL1251_PART_DOWN_REG_SIZE);
441
442 /* And finally we upload the NVS tables */
443 nvs_bytes_written = 0;
444 while (nvs_bytes_written < nvs_len) {
445 val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
446 | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
447
448 val = cpu_to_le32(val);
449
450 wl1251_debug(DEBUG_BOOT,
451 "nvs write table 0x%x: 0x%x",
452 nvs_start, val);
453 wl1251_mem_write32(wl, nvs_start, val);
454
455 nvs_ptr += 4;
456 nvs_bytes_written += 4;
457 nvs_start += 4;
458 }
459
460 return 0;
461}
462
463int wl1251_boot(struct wl1251 *wl)
464{
465 int ret = 0, minor_minor_e2_ver;
466 u32 tmp, boot_data;
467
468 ret = wl1251_boot_soft_reset(wl);
469 if (ret < 0)
470 goto out;
471
472 /* 2. start processing NVS file */
473 ret = wl1251_boot_upload_nvs(wl);
474 if (ret < 0)
475 goto out;
476
477 /* write firmware's last address (ie. it's length) to
478 * ACX_EEPROMLESS_IND_REG */
479 wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
480
481 /* 6. read the EEPROM parameters */
482 tmp = wl1251_reg_read32(wl, SCR_PAD2);
483
484 /* 7. read bootdata */
485 wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
486 wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
487 tmp = wl1251_reg_read32(wl, SCR_PAD3);
488
489 /* 8. check bootdata and call restart sequence */
490 wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
491 minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
492
493 wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
494 "minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
495 wl->boot_attr.radio_type, wl->boot_attr.major,
496 wl->boot_attr.minor, minor_minor_e2_ver);
497
498 ret = wl1251_boot_init_seq(wl);
499 if (ret < 0)
500 goto out;
501
502 /* 9. NVS processing done */
503 boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
504
505 wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
506
507 /* 10. check that ECPU_CONTROL_HALT bits are set in
508 * pWhalBus->uBootData and start uploading firmware
509 */
510 if ((boot_data & ECPU_CONTROL_HALT) == 0) {
511 wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
512 ret = -EIO;
513 goto out;
514 }
515
516 ret = wl1251_boot_upload_firmware(wl);
517 if (ret < 0)
518 goto out;
519
520 /* 10.5 start firmware */
521 ret = wl1251_boot_run_firmware(wl);
522 if (ret < 0)
523 goto out;
524
525out:
526 return ret;
527}