2 * Intel Wireless Multicomm 3200 WiFi driver
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
39 #include <linux/kernel.h>
40 #include <linux/firmware.h>
50 static const char fw_barker
[] = "*WESTOPFORNOONE*";
53 * @op_code: Op code we're looking for.
54 * @index: There can be several instances of the same opcode within
55 * the firmware. Index specifies which one we're looking for.
57 static int iwm_fw_op_offset(struct iwm_priv
*iwm
, const struct firmware
*fw
,
58 u16 op_code
, u32 index
)
60 int offset
= -EINVAL
, fw_offset
;
63 struct iwm_fw_hdr_rec
*rec
;
68 /* We first need to look for the firmware barker */
69 if (memcmp(fw_ptr
, fw_barker
, IWM_HDR_BARKER_LEN
)) {
70 IWM_ERR(iwm
, "No barker string in this FW\n");
74 if (fw
->size
< IWM_HDR_LEN
) {
75 IWM_ERR(iwm
, "FW is too small (%zu)\n", fw
->size
);
79 fw_offset
+= IWM_HDR_BARKER_LEN
;
81 while (fw_offset
< fw
->size
) {
82 rec
= (struct iwm_fw_hdr_rec
*)(fw_ptr
+ fw_offset
);
84 IWM_DBG_FW(iwm
, DBG
, "FW: op_code: 0x%x, len: %d @ 0x%x\n",
85 rec
->op_code
, rec
->len
, fw_offset
);
87 if (rec
->op_code
== IWM_HDR_REC_OP_INVALID
) {
88 IWM_DBG_FW(iwm
, DBG
, "Reached INVALID op code\n");
92 if (rec
->op_code
== op_code
) {
93 if (op_index
== index
) {
94 fw_offset
+= sizeof(struct iwm_fw_hdr_rec
);
101 fw_offset
+= sizeof(struct iwm_fw_hdr_rec
) + rec
->len
;
108 static int iwm_load_firmware_chunk(struct iwm_priv
*iwm
,
109 const struct firmware
*fw
,
110 struct iwm_fw_img_desc
*img_desc
)
112 struct iwm_udma_nonwifi_cmd target_cmd
;
117 IWM_DBG_FW(iwm
, INFO
, "Loading FW chunk: %d bytes @ 0x%x\n",
118 img_desc
->length
, img_desc
->address
);
120 target_cmd
.opcode
= UMAC_HDI_OUT_OPCODE_WRITE
;
121 target_cmd
.handle_by_hw
= 1;
126 chunk_size
= img_desc
->length
;
127 chunk_ptr
= fw
->data
+ img_desc
->offset
;
129 while (chunk_size
> 0) {
132 tmp_chunk_size
= min_t(u32
, chunk_size
,
133 IWM_MAX_NONWIFI_CMD_BUFF_SIZE
);
135 target_cmd
.addr
= cpu_to_le32(img_desc
->address
+
136 (chunk_ptr
- fw
->data
- img_desc
->offset
));
137 target_cmd
.op1_sz
= cpu_to_le32(tmp_chunk_size
);
139 IWM_DBG_FW(iwm
, DBG
, "\t%d bytes @ 0x%x\n",
140 tmp_chunk_size
, target_cmd
.addr
);
142 ret
= iwm_hal_send_target_cmd(iwm
, &target_cmd
, chunk_ptr
);
144 IWM_ERR(iwm
, "Couldn't load FW chunk\n");
148 chunk_size
-= tmp_chunk_size
;
149 chunk_ptr
+= tmp_chunk_size
;
155 * To load a fw image to the target, we basically go through the
156 * fw, looking for OP_MEM_DESC records. Once we found one, we
157 * pass it to iwm_load_firmware_chunk().
158 * The OP_MEM_DESC records contain the actuall memory chunk to be
159 * sent, but also the destination address.
161 static int iwm_load_img(struct iwm_priv
*iwm
, const char *img_name
)
163 const struct firmware
*fw
;
164 struct iwm_fw_img_desc
*img_desc
;
165 struct iwm_fw_img_ver
*ver
;
166 int ret
= 0, fw_offset
;
167 u32 opcode_idx
= 0, build_date
;
170 ret
= request_firmware(&fw
, img_name
, iwm_to_dev(iwm
));
172 IWM_ERR(iwm
, "Request firmware failed");
176 IWM_DBG_FW(iwm
, INFO
, "Start to load FW %s\n", img_name
);
179 fw_offset
= iwm_fw_op_offset(iwm
, fw
,
180 IWM_HDR_REC_OP_MEM_DESC
,
185 img_desc
= (struct iwm_fw_img_desc
*)(fw
->data
+ fw_offset
);
186 ret
= iwm_load_firmware_chunk(iwm
, fw
, img_desc
);
192 /* Read firmware version */
193 fw_offset
= iwm_fw_op_offset(iwm
, fw
, IWM_HDR_REC_OP_SW_VER
, 0);
197 ver
= (struct iwm_fw_img_ver
*)(fw
->data
+ fw_offset
);
200 fw_offset
= iwm_fw_op_offset(iwm
, fw
, IWM_HDR_REC_OP_BUILD_TAG
, 0);
204 build_tag
= (char *)(fw
->data
+ fw_offset
);
206 /* Read build date */
207 fw_offset
= iwm_fw_op_offset(iwm
, fw
, IWM_HDR_REC_OP_BUILD_DATE
, 0);
211 build_date
= *(u32
*)(fw
->data
+ fw_offset
);
213 IWM_INFO(iwm
, "%s:\n", img_name
);
214 IWM_INFO(iwm
, "\tVersion: %02X.%02X\n", ver
->major
, ver
->minor
);
215 IWM_INFO(iwm
, "\tBuild tag: %s\n", build_tag
);
216 IWM_INFO(iwm
, "\tBuild date: %x-%x-%x\n",
217 IWM_BUILD_YEAR(build_date
), IWM_BUILD_MONTH(build_date
),
218 IWM_BUILD_DAY(build_date
));
220 if (!strcmp(img_name
, iwm
->bus_ops
->umac_name
))
221 sprintf(iwm
->umac_version
, "%02X.%02X",
222 ver
->major
, ver
->minor
);
224 if (!strcmp(img_name
, iwm
->bus_ops
->lmac_name
))
225 sprintf(iwm
->lmac_version
, "%02X.%02X",
226 ver
->major
, ver
->minor
);
229 release_firmware(fw
);
234 static int iwm_load_umac(struct iwm_priv
*iwm
)
236 struct iwm_udma_nonwifi_cmd target_cmd
;
239 ret
= iwm_load_img(iwm
, iwm
->bus_ops
->umac_name
);
243 /* We've loaded the UMAC, we can tell the target to jump there */
244 target_cmd
.opcode
= UMAC_HDI_OUT_OPCODE_JUMP
;
245 target_cmd
.addr
= cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR
);
246 target_cmd
.op1_sz
= 0;
248 target_cmd
.handle_by_hw
= 0;
249 target_cmd
.resp
= 1 ;
252 ret
= iwm_hal_send_target_cmd(iwm
, &target_cmd
, NULL
);
254 IWM_ERR(iwm
, "Couldn't send JMP command\n");
259 static int iwm_load_lmac(struct iwm_priv
*iwm
, const char *img_name
)
263 ret
= iwm_load_img(iwm
, img_name
);
267 return iwm_send_umac_reset(iwm
,
268 cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN
), 0);
271 static int iwm_init_calib(struct iwm_priv
*iwm
, unsigned long cfg_bitmap
,
272 unsigned long expected_bitmap
, u8 rx_iq_cmd
)
274 /* Read RX IQ calibration result from EEPROM */
275 if (test_bit(rx_iq_cmd
, &cfg_bitmap
)) {
276 iwm_store_rxiq_calib_result(iwm
);
277 set_bit(PHY_CALIBRATE_RX_IQ_CMD
, &iwm
->calib_done_map
);
280 iwm_send_prio_table(iwm
);
281 iwm_send_init_calib_cfg(iwm
, cfg_bitmap
);
283 while (iwm
->calib_done_map
!= expected_bitmap
) {
284 if (iwm_notif_handle(iwm
, CALIBRATION_RES_NOTIFICATION
,
285 IWM_SRC_LMAC
, WAIT_NOTIF_TIMEOUT
)) {
286 IWM_DBG_FW(iwm
, DBG
, "Initial calibration timeout\n");
290 IWM_DBG_FW(iwm
, DBG
, "Got calibration result. calib_done_map: "
291 "0x%lx, expected calibrations: 0x%lx\n",
292 iwm
->calib_done_map
, expected_bitmap
);
299 * We currently have to load 3 FWs:
300 * 1) The UMAC (Upper MAC).
301 * 2) The calibration LMAC (Lower MAC).
302 * We then send the calibration init command, so that the device can
303 * run a first calibration round.
304 * 3) The operational LMAC, which replaces the calibration one when it's
305 * done with the first calibration round.
307 * Once those 3 FWs have been loaded, we send the periodic calibration
308 * command, and then the device is available for regular 802.11 operations.
310 int iwm_load_fw(struct iwm_priv
*iwm
)
312 unsigned long init_calib_map
, periodic_calib_map
;
313 unsigned long expected_calib_map
;
316 /* We first start downloading the UMAC */
317 ret
= iwm_load_umac(iwm
);
319 IWM_ERR(iwm
, "UMAC loading failed\n");
323 /* Handle UMAC_ALIVE notification */
324 ret
= iwm_notif_handle(iwm
, UMAC_NOTIFY_OPCODE_ALIVE
, IWM_SRC_UMAC
,
327 IWM_ERR(iwm
, "Handle UMAC_ALIVE failed: %d\n", ret
);
331 /* UMAC is alive, we can download the calibration LMAC */
332 ret
= iwm_load_lmac(iwm
, iwm
->bus_ops
->calib_lmac_name
);
334 IWM_ERR(iwm
, "Calibration LMAC loading failed\n");
338 /* Handle UMAC_INIT_COMPLETE notification */
339 ret
= iwm_notif_handle(iwm
, UMAC_NOTIFY_OPCODE_INIT_COMPLETE
,
340 IWM_SRC_UMAC
, WAIT_NOTIF_TIMEOUT
);
342 IWM_ERR(iwm
, "Handle INIT_COMPLETE failed for calibration "
347 /* Read EEPROM data */
348 ret
= iwm_eeprom_init(iwm
);
350 IWM_ERR(iwm
, "Couldn't init eeprom array\n");
354 init_calib_map
= iwm
->conf
.calib_map
& IWM_CALIB_MAP_INIT_MSK
;
355 expected_calib_map
= iwm
->conf
.expected_calib_map
&
356 IWM_CALIB_MAP_INIT_MSK
;
357 periodic_calib_map
= IWM_CALIB_MAP_PER_LMAC(iwm
->conf
.calib_map
);
359 ret
= iwm_init_calib(iwm
, init_calib_map
, expected_calib_map
,
360 CALIB_CFG_RX_IQ_IDX
);
362 /* Let's try the old way */
363 ret
= iwm_init_calib(iwm
, expected_calib_map
,
365 PHY_CALIBRATE_RX_IQ_CMD
);
367 IWM_ERR(iwm
, "Calibration result timeout\n");
372 /* Handle LMAC CALIBRATION_COMPLETE notification */
373 ret
= iwm_notif_handle(iwm
, CALIBRATION_COMPLETE_NOTIFICATION
,
374 IWM_SRC_LMAC
, WAIT_NOTIF_TIMEOUT
);
376 IWM_ERR(iwm
, "Wait for CALIBRATION_COMPLETE timeout\n");
380 IWM_INFO(iwm
, "LMAC calibration done: 0x%lx\n", iwm
->calib_done_map
);
382 iwm_send_umac_reset(iwm
, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET
), 1);
384 ret
= iwm_notif_handle(iwm
, UMAC_CMD_OPCODE_RESET
, IWM_SRC_UMAC
,
387 IWM_ERR(iwm
, "Wait for UMAC RESET timeout\n");
391 /* Download the operational LMAC */
392 ret
= iwm_load_lmac(iwm
, iwm
->bus_ops
->lmac_name
);
394 IWM_ERR(iwm
, "LMAC loading failed\n");
398 ret
= iwm_notif_handle(iwm
, UMAC_NOTIFY_OPCODE_INIT_COMPLETE
,
399 IWM_SRC_UMAC
, WAIT_NOTIF_TIMEOUT
);
401 IWM_ERR(iwm
, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret
);
405 iwm_send_prio_table(iwm
);
406 iwm_send_calib_results(iwm
);
407 iwm_send_periodic_calib_cfg(iwm
, periodic_calib_map
);
408 iwm_send_ct_kill_cfg(iwm
, iwm
->conf
.ct_kill_entry
,
409 iwm
->conf
.ct_kill_exit
);
414 iwm_eeprom_exit(iwm
);