2009-08-06 16:25:28 +03:00
/*
* This file is part of wl1271
*
* Copyright ( C ) 2008 - 2009 Nokia Corporation
*
* Contact : Luciano Coelho < luciano . coelho @ nokia . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*
*/
# include <linux/gpio.h>
# include "wl1271_acx.h"
# include "wl1271_reg.h"
# include "wl1271_boot.h"
2010-02-18 13:25:55 +02:00
# include "wl1271_io.h"
2009-08-06 16:25:28 +03:00
# include "wl1271_event.h"
static struct wl1271_partition_set part_table [ PART_TABLE_LEN ] = {
[ PART_DOWN ] = {
. mem = {
. start = 0x00000000 ,
. size = 0x000177c0
} ,
. reg = {
. start = REGISTERS_BASE ,
. size = 0x00008800
} ,
2009-10-12 15:08:46 +03:00
. mem2 = {
. start = 0x00000000 ,
. size = 0x00000000
} ,
. mem3 = {
. start = 0x00000000 ,
. size = 0x00000000
} ,
2009-08-06 16:25:28 +03:00
} ,
[ PART_WORK ] = {
. mem = {
. start = 0x00040000 ,
. size = 0x00014fc0
} ,
. reg = {
. start = REGISTERS_BASE ,
2009-10-12 15:08:46 +03:00
. size = 0x0000a000
} ,
. mem2 = {
. start = 0x003004f8 ,
. size = 0x00000004
} ,
. mem3 = {
. start = 0x00040404 ,
. size = 0x00000000
2009-08-06 16:25:28 +03:00
} ,
} ,
[ PART_DRPW ] = {
. mem = {
. start = 0x00040000 ,
. size = 0x00014fc0
} ,
. reg = {
. start = DRPW_BASE ,
. size = 0x00006000
2009-10-12 15:08:46 +03:00
} ,
. mem2 = {
. start = 0x00000000 ,
. size = 0x00000000
} ,
. mem3 = {
. start = 0x00000000 ,
. size = 0x00000000
2009-08-06 16:25:28 +03:00
}
}
} ;
static void wl1271_boot_set_ecpu_ctrl ( struct wl1271 * wl , u32 flag )
{
u32 cpu_ctrl ;
/* 10.5.0 run the firmware (I) */
2010-02-18 13:25:55 +02:00
cpu_ctrl = wl1271_read32 ( wl , ACX_REG_ECPU_CONTROL ) ;
2009-08-06 16:25:28 +03:00
/* 10.5.1 run the firmware (II) */
cpu_ctrl | = flag ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_ECPU_CONTROL , cpu_ctrl ) ;
2009-08-06 16:25:28 +03:00
}
static void wl1271_boot_fw_version ( struct wl1271 * wl )
{
struct wl1271_static_data static_data ;
2010-02-18 13:25:55 +02:00
wl1271_read ( wl , wl - > cmd_box_addr , & static_data , sizeof ( static_data ) ,
false ) ;
2009-08-06 16:25:28 +03:00
strncpy ( wl - > chip . fw_ver , static_data . fw_version ,
sizeof ( wl - > chip . fw_ver ) ) ;
/* make sure the string is NULL-terminated */
wl - > chip . fw_ver [ sizeof ( wl - > chip . fw_ver ) - 1 ] = ' \0 ' ;
}
static int wl1271_boot_upload_firmware_chunk ( struct wl1271 * wl , void * buf ,
size_t fw_data_len , u32 dest )
{
2009-10-12 15:08:46 +03:00
struct wl1271_partition_set partition ;
2009-08-06 16:25:28 +03:00
int addr , chunk_num , partition_limit ;
2009-10-08 21:56:32 +03:00
u8 * p , * chunk ;
2009-08-06 16:25:28 +03:00
/* whal_FwCtrl_LoadFwImageSm() */
wl1271_debug ( DEBUG_BOOT , " starting firmware upload " ) ;
2009-08-11 11:58:27 +03:00
wl1271_debug ( DEBUG_BOOT , " fw_data_len %zd chunk_size %d " ,
fw_data_len , CHUNK_SIZE ) ;
2009-08-06 16:25:28 +03:00
if ( ( fw_data_len % 4 ) ! = 0 ) {
wl1271_error ( " firmware length not multiple of four " ) ;
return - EIO ;
}
2009-10-08 21:56:32 +03:00
chunk = kmalloc ( CHUNK_SIZE , GFP_KERNEL ) ;
2009-10-13 12:47:57 +03:00
if ( ! chunk ) {
2009-10-08 21:56:32 +03:00
wl1271_error ( " allocation for firmware upload chunk failed " ) ;
return - ENOMEM ;
}
2009-10-12 15:08:46 +03:00
memcpy ( & partition , & part_table [ PART_DOWN ] , sizeof ( partition ) ) ;
partition . mem . start = dest ;
wl1271_set_partition ( wl , & partition ) ;
2009-08-06 16:25:28 +03:00
/* 10.1 set partition limit and chunk num */
chunk_num = 0 ;
partition_limit = part_table [ PART_DOWN ] . mem . size ;
while ( chunk_num < fw_data_len / CHUNK_SIZE ) {
/* 10.2 update partition, if needed */
addr = dest + ( chunk_num + 2 ) * CHUNK_SIZE ;
if ( addr > partition_limit ) {
addr = dest + chunk_num * CHUNK_SIZE ;
partition_limit = chunk_num * CHUNK_SIZE +
part_table [ PART_DOWN ] . mem . size ;
2009-10-12 15:08:46 +03:00
partition . mem . start = addr ;
wl1271_set_partition ( wl , & partition ) ;
2009-08-06 16:25:28 +03:00
}
/* 10.3 upload the chunk */
addr = dest + chunk_num * CHUNK_SIZE ;
p = buf + chunk_num * CHUNK_SIZE ;
2009-10-08 21:56:32 +03:00
memcpy ( chunk , p , CHUNK_SIZE ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " uploading fw chunk 0x%p to 0x%x " ,
p , addr ) ;
2010-02-18 13:25:55 +02:00
wl1271_write ( wl , addr , chunk , CHUNK_SIZE , false ) ;
2009-08-06 16:25:28 +03:00
chunk_num + + ;
}
/* 10.4 upload the last chunk */
addr = dest + chunk_num * CHUNK_SIZE ;
p = buf + chunk_num * CHUNK_SIZE ;
2009-10-08 21:56:32 +03:00
memcpy ( chunk , p , fw_data_len % CHUNK_SIZE ) ;
2009-08-11 11:58:27 +03:00
wl1271_debug ( DEBUG_BOOT , " uploading fw last chunk (%zd B) 0x%p to 0x%x " ,
2009-08-06 16:25:28 +03:00
fw_data_len % CHUNK_SIZE , p , addr ) ;
2010-02-18 13:25:55 +02:00
wl1271_write ( wl , addr , chunk , fw_data_len % CHUNK_SIZE , false ) ;
2009-08-06 16:25:28 +03:00
2009-10-08 21:56:32 +03:00
kfree ( chunk ) ;
2009-08-06 16:25:28 +03:00
return 0 ;
}
static int wl1271_boot_upload_firmware ( struct wl1271 * wl )
{
u32 chunks , addr , len ;
2009-10-13 12:47:57 +03:00
int ret = 0 ;
2009-08-06 16:25:28 +03:00
u8 * fw ;
fw = wl - > fw ;
2009-10-15 10:33:29 +03:00
chunks = be32_to_cpup ( ( __be32 * ) fw ) ;
2009-08-06 16:25:28 +03:00
fw + = sizeof ( u32 ) ;
wl1271_debug ( DEBUG_BOOT , " firmware chunks to be uploaded: %u " , chunks ) ;
while ( chunks - - ) {
2009-10-15 10:33:29 +03:00
addr = be32_to_cpup ( ( __be32 * ) fw ) ;
2009-08-06 16:25:28 +03:00
fw + = sizeof ( u32 ) ;
2009-10-15 10:33:29 +03:00
len = be32_to_cpup ( ( __be32 * ) fw ) ;
2009-08-06 16:25:28 +03:00
fw + = sizeof ( u32 ) ;
if ( len > 300000 ) {
wl1271_info ( " firmware chunk too long: %u " , len ) ;
return - EINVAL ;
}
wl1271_debug ( DEBUG_BOOT , " chunk %d addr 0x%x len %u " ,
chunks , addr , len ) ;
2009-10-13 12:47:57 +03:00
ret = wl1271_boot_upload_firmware_chunk ( wl , fw , len , addr ) ;
if ( ret ! = 0 )
break ;
2009-08-06 16:25:28 +03:00
fw + = len ;
}
2009-10-13 12:47:57 +03:00
return ret ;
2009-08-06 16:25:28 +03:00
}
static int wl1271_boot_upload_nvs ( struct wl1271 * wl )
{
size_t nvs_len , burst_len ;
int i ;
u32 dest_addr , val ;
2010-02-18 13:25:42 +02:00
u8 * nvs_ptr , * nvs_aligned ;
2009-08-06 16:25:28 +03:00
2010-02-18 13:25:42 +02:00
if ( wl - > nvs = = NULL )
2009-08-06 16:25:28 +03:00
return - ENODEV ;
2009-12-11 15:40:53 +02:00
/* only the first part of the NVS needs to be uploaded */
2010-02-18 13:25:42 +02:00
nvs_len = sizeof ( wl - > nvs - > nvs ) ;
nvs_ptr = ( u8 * ) wl - > nvs - > nvs ;
2009-08-06 16:25:28 +03:00
/*
* Layout before the actual NVS tables :
* 1 byte : burst length .
* 2 bytes : destination address .
* n bytes : data to burst copy .
*
* This is ended by a 0 length , then the NVS tables .
*/
/* FIXME: Do we need to check here whether the LSB is 1? */
while ( nvs_ptr [ 0 ] ) {
burst_len = nvs_ptr [ 0 ] ;
dest_addr = ( nvs_ptr [ 1 ] & 0xfe ) | ( ( u32 ) ( nvs_ptr [ 2 ] < < 8 ) ) ;
/* FIXME: Due to our new wl1271_translate_reg_addr function,
we need to add the REGISTER_BASE to the destination */
dest_addr + = REGISTERS_BASE ;
/* We move our pointer to the data */
nvs_ptr + = 3 ;
for ( i = 0 ; i < burst_len ; i + + ) {
val = ( nvs_ptr [ 0 ] | ( nvs_ptr [ 1 ] < < 8 )
| ( nvs_ptr [ 2 ] < < 16 ) | ( nvs_ptr [ 3 ] < < 24 ) ) ;
wl1271_debug ( DEBUG_BOOT ,
" nvs burst write 0x%x: 0x%x " ,
dest_addr , val ) ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , dest_addr , val ) ;
2009-08-06 16:25:28 +03:00
nvs_ptr + = 4 ;
dest_addr + = 4 ;
}
}
/*
* We ' ve reached the first zero length , the first NVS table
* is 7 bytes further .
*/
nvs_ptr + = 7 ;
2010-02-18 13:25:42 +02:00
nvs_len - = nvs_ptr - ( u8 * ) wl - > nvs - > nvs ;
2009-08-06 16:25:28 +03:00
nvs_len = ALIGN ( nvs_len , 4 ) ;
/* FIXME: The driver sets the partition here, but this is not needed,
since it sets to the same one as currently in use */
/* Now we must set the partition correctly */
2009-10-12 15:08:46 +03:00
wl1271_set_partition ( wl , & part_table [ PART_WORK ] ) ;
2009-08-06 16:25:28 +03:00
/* Copy the NVS tables to a new block to ensure alignment */
2010-02-18 13:25:45 +02:00
/* FIXME: We jump 3 more bytes before uploading the NVS. It seems
that our NVS files have three extra zeros here . I ' m not sure whether
the problem is in our NVS generation or we should really jumpt these
3 bytes here */
nvs_ptr + = 3 ;
nvs_aligned = kmemdup ( nvs_ptr , nvs_len , GFP_KERNEL ) ; if
( ! nvs_aligned ) return - ENOMEM ;
2009-08-06 16:25:28 +03:00
/* And finally we upload the NVS tables */
/* FIXME: In wl1271, we upload everything at once.
No endianness handling needed here ? ! The ref driver doesn ' t do
anything about it at this point */
2010-02-18 13:25:55 +02:00
wl1271_write ( wl , CMD_MBOX_ADDRESS , nvs_aligned , nvs_len , false ) ;
2009-08-06 16:25:28 +03:00
kfree ( nvs_aligned ) ;
return 0 ;
}
static void wl1271_boot_enable_interrupts ( struct wl1271 * wl )
{
2010-02-22 08:38:22 +02:00
wl1271_enable_interrupts ( wl ) ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_INTERRUPT_MASK ,
WL1271_ACX_INTR_ALL & ~ ( WL1271_INTR_MASK ) ) ;
wl1271_write32 ( wl , HI_CFG , HI_CFG_DEF_VAL ) ;
2009-08-06 16:25:28 +03:00
}
static int wl1271_boot_soft_reset ( struct wl1271 * wl )
{
unsigned long timeout ;
u32 boot_data ;
/* perform soft reset */
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_SLV_SOFT_RESET , ACX_SLV_SOFT_RESET_BIT ) ;
2009-08-06 16:25:28 +03:00
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies ( SOFT_RESET_MAX_TIME ) ;
while ( 1 ) {
2010-02-18 13:25:55 +02:00
boot_data = wl1271_read32 ( wl , ACX_REG_SLV_SOFT_RESET ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " soft reset bootdata 0x%x " , boot_data ) ;
if ( ( boot_data & ACX_SLV_SOFT_RESET_BIT ) = = 0 )
break ;
if ( time_after ( jiffies , timeout ) ) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
wl1271_error ( " soft reset timeout " ) ;
return - 1 ;
}
udelay ( SOFT_RESET_STALL_TIME ) ;
}
/* disable Rx/Tx */
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ENABLE , 0x0 ) ;
2009-08-06 16:25:28 +03:00
/* disable auto calibration on start*/
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , SPARE_A2 , 0xffff ) ;
2009-08-06 16:25:28 +03:00
return 0 ;
}
static int wl1271_boot_run_firmware ( struct wl1271 * wl )
{
int loop , ret ;
u32 chip_id , interrupt ;
wl1271_boot_set_ecpu_ctrl ( wl , ECPU_CONTROL_HALT ) ;
2010-02-18 13:25:55 +02:00
chip_id = wl1271_read32 ( wl , CHIP_ID_B ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " chip id after firmware boot: 0x%x " , chip_id ) ;
if ( chip_id ! = wl - > chip . id ) {
wl1271_error ( " chip id doesn't match after firmware boot " ) ;
return - EIO ;
}
/* wait for init to complete */
loop = 0 ;
while ( loop + + < INIT_LOOP ) {
udelay ( INIT_LOOP_DELAY ) ;
2010-02-18 13:25:55 +02:00
interrupt = wl1271_read32 ( wl , ACX_REG_INTERRUPT_NO_CLEAR ) ;
2009-08-06 16:25:28 +03:00
if ( interrupt = = 0xffffffff ) {
wl1271_error ( " error reading hardware complete "
" init indication " ) ;
return - EIO ;
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if ( interrupt & WL1271_ACX_INTR_INIT_COMPLETE ) {
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_INTERRUPT_ACK ,
WL1271_ACX_INTR_INIT_COMPLETE ) ;
2009-08-06 16:25:28 +03:00
break ;
}
}
2009-10-29 13:20:04 +02:00
if ( loop > INIT_LOOP ) {
2009-08-06 16:25:28 +03:00
wl1271_error ( " timeout waiting for the hardware to "
" complete initialization " ) ;
return - EIO ;
}
/* get hardware config command mail box */
2010-02-18 13:25:55 +02:00
wl - > cmd_box_addr = wl1271_read32 ( wl , REG_COMMAND_MAILBOX_PTR ) ;
2009-08-06 16:25:28 +03:00
/* get hardware config event mail box */
2010-02-18 13:25:55 +02:00
wl - > event_box_addr = wl1271_read32 ( wl , REG_EVENT_MAILBOX_PTR ) ;
2009-08-06 16:25:28 +03:00
/* set the working partition to its "running" mode offset */
2009-10-12 15:08:46 +03:00
wl1271_set_partition ( wl , & part_table [ PART_WORK ] ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_MAILBOX , " cmd_box_addr 0x%x event_box_addr 0x%x " ,
wl - > cmd_box_addr , wl - > event_box_addr ) ;
wl1271_boot_fw_version ( wl ) ;
/*
* in case of full asynchronous mode the firmware event must be
* ready to receive event from the command mailbox
*/
2009-10-08 21:56:36 +03:00
/* unmask required mbox events */
wl - > event_mask = BSS_LOSE_EVENT_ID |
2009-11-02 20:22:11 +02:00
SCAN_COMPLETE_EVENT_ID |
PS_REPORT_EVENT_ID ;
2009-08-06 16:25:28 +03:00
ret = wl1271_event_unmask ( wl ) ;
if ( ret < 0 ) {
wl1271_error ( " EVENT mask setting failed " ) ;
return ret ;
}
wl1271_event_mbox_config ( wl ) ;
/* firmware startup completed */
return 0 ;
}
static int wl1271_boot_write_irq_polarity ( struct wl1271 * wl )
{
2009-10-12 15:08:48 +03:00
u32 polarity ;
2009-08-06 16:25:28 +03:00
2009-10-12 15:08:48 +03:00
polarity = wl1271_top_reg_read ( wl , OCP_REG_POLARITY ) ;
2009-08-06 16:25:28 +03:00
/* We use HIGH polarity, so unset the LOW bit */
polarity & = ~ POLARITY_LOW ;
2009-10-12 15:08:48 +03:00
wl1271_top_reg_write ( wl , OCP_REG_POLARITY , polarity ) ;
2009-08-06 16:25:28 +03:00
return 0 ;
}
int wl1271_boot ( struct wl1271 * wl )
{
int ret = 0 ;
u32 tmp , clk , pause ;
2009-10-12 15:08:49 +03:00
if ( REF_CLOCK = = 0 | | REF_CLOCK = = 2 | | REF_CLOCK = = 4 )
/* ref clk: 19.2/38.4/38.4-XTAL */
2009-08-06 16:25:28 +03:00
clk = 0x3 ;
else if ( REF_CLOCK = = 1 | | REF_CLOCK = = 3 )
/* ref clk: 26/52 */
clk = 0x5 ;
2009-10-12 15:08:49 +03:00
if ( REF_CLOCK ! = 0 ) {
u16 val ;
/* Set clock type */
val = wl1271_top_reg_read ( wl , OCP_REG_CLK_TYPE ) ;
val & = FREF_CLK_TYPE_BITS ;
val | = CLK_REQ_PRCM ;
wl1271_top_reg_write ( wl , OCP_REG_CLK_TYPE , val ) ;
} else {
u16 val ;
/* Set clock polarity */
val = wl1271_top_reg_read ( wl , OCP_REG_CLK_POLARITY ) ;
val & = FREF_CLK_POLARITY_BITS ;
val | = CLK_REQ_OUTN_SEL ;
wl1271_top_reg_write ( wl , OCP_REG_CLK_POLARITY , val ) ;
}
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , PLL_PARAMETERS , clk ) ;
2009-08-06 16:25:28 +03:00
2010-02-18 13:25:55 +02:00
pause = wl1271_read32 ( wl , PLL_PARAMETERS ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " pause1 0x%x " , pause ) ;
pause & = ~ ( WU_COUNTER_PAUSE_VAL ) ; /* FIXME: This should probably be
* WU_COUNTER_PAUSE_VAL instead of
* 0x3ff ( magic number ) . How does
* this work ? ! */
pause | = WU_COUNTER_PAUSE_VAL ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , WU_COUNTER_PAUSE , pause ) ;
2009-08-06 16:25:28 +03:00
/* Continue the ELP wake up sequence */
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , WELP_ARM_COMMAND , WELP_ARM_COMMAND_VAL ) ;
2009-08-06 16:25:28 +03:00
udelay ( 500 ) ;
2009-10-12 15:08:46 +03:00
wl1271_set_partition ( wl , & part_table [ PART_DRPW ] ) ;
2009-08-06 16:25:28 +03:00
/* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW . The RTRIM value will be added by the FW
before taking DRPw out of reset */
wl1271_debug ( DEBUG_BOOT , " DRPW_SCRATCH_START %08x " , DRPW_SCRATCH_START ) ;
2010-02-18 13:25:55 +02:00
clk = wl1271_read32 ( wl , DRPW_SCRATCH_START ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " clk2 0x%x " , clk ) ;
/* 2 */
clk | = ( REF_CLOCK < < 1 ) < < 4 ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , DRPW_SCRATCH_START , clk ) ;
2009-08-06 16:25:28 +03:00
2009-10-12 15:08:46 +03:00
wl1271_set_partition ( wl , & part_table [ PART_WORK ] ) ;
2009-08-06 16:25:28 +03:00
/* Disable interrupts */
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_INTERRUPT_MASK , WL1271_ACX_INTR_ALL ) ;
2009-08-06 16:25:28 +03:00
ret = wl1271_boot_soft_reset ( wl ) ;
if ( ret < 0 )
goto out ;
/* 2. start processing NVS file */
ret = wl1271_boot_upload_nvs ( wl ) ;
if ( ret < 0 )
goto out ;
/* write firmware's last address (ie. it's length) to
* ACX_EEPROMLESS_IND_REG */
wl1271_debug ( DEBUG_BOOT , " ACX_EEPROMLESS_IND_REG " ) ;
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_EEPROMLESS_IND_REG , ACX_EEPROMLESS_IND_REG ) ;
2009-08-06 16:25:28 +03:00
2010-02-18 13:25:55 +02:00
tmp = wl1271_read32 ( wl , CHIP_ID_B ) ;
2009-08-06 16:25:28 +03:00
wl1271_debug ( DEBUG_BOOT , " chip id 0x%x " , tmp ) ;
/* 6. read the EEPROM parameters */
2010-02-18 13:25:55 +02:00
tmp = wl1271_read32 ( wl , SCR_PAD2 ) ;
2009-08-06 16:25:28 +03:00
ret = wl1271_boot_write_irq_polarity ( wl ) ;
if ( ret < 0 )
goto out ;
/* FIXME: Need to check whether this is really what we want */
2010-02-18 13:25:55 +02:00
wl1271_write32 ( wl , ACX_REG_INTERRUPT_MASK ,
WL1271_ACX_ALL_EVENTS_VECTOR ) ;
2009-08-06 16:25:28 +03:00
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw ) */
ret = wl1271_boot_upload_firmware ( wl ) ;
if ( ret < 0 )
goto out ;
/* 10.5 start firmware */
ret = wl1271_boot_run_firmware ( wl ) ;
if ( ret < 0 )
goto out ;
2009-10-13 12:47:45 +03:00
/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts ( wl ) ;
2009-08-06 16:25:28 +03:00
/* set the wl1271 default filters */
wl - > rx_config = WL1271_DEFAULT_RX_CONFIG ;
wl - > rx_filter = WL1271_DEFAULT_RX_FILTER ;
wl1271_event_mbox_config ( wl ) ;
out :
return ret ;
}