2 * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 /* Algorithmic part of the firmware download.
18 * To be included in the container file providing framework
21 #define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
22 #define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
23 #define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \
24 groupsize, buf, len, ascii) \
25 print_hex_dump_debug("DBG[ FW ]" prefix_str, \
26 prefix_type, rowsize, \
27 groupsize, buf, len, ascii)
29 #define FW_ADDR_CHECK(ioaddr, val, msg) do { \
30 ioaddr = wmi_buffer(wil, val); \
32 wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
39 * wil_fw_verify - verify firmware file validity
41 * perform various checks for the firmware file header.
42 * records are not validated.
44 * Return file size or negative error
46 static int wil_fw_verify(struct wil6210_priv
*wil
, const u8
*data
, size_t size
)
48 const struct wil_fw_record_head
*hdr
= (const void *)data
;
49 struct wil_fw_record_file_header fh
;
50 const struct wil_fw_record_file_header
*fh_
;
55 wil_err_fw(wil
, "image size not aligned: %zu\n", size
);
58 /* have enough data for the file header? */
59 if (size
< sizeof(*hdr
) + sizeof(fh
)) {
60 wil_err_fw(wil
, "file too short: %zu bytes\n", size
);
64 /* start with the file header? */
65 if (le16_to_cpu(hdr
->type
) != wil_fw_type_file_header
) {
66 wil_err_fw(wil
, "no file header\n");
71 fh_
= (struct wil_fw_record_file_header
*)&hdr
[1];
72 dlen
= le32_to_cpu(fh_
->data_len
);
74 wil_err_fw(wil
, "data length not aligned: %lu\n", (ulong
)dlen
);
78 wil_err_fw(wil
, "file truncated at %zu/%lu\n",
82 if (dlen
< sizeof(*hdr
) + sizeof(fh
)) {
83 wil_err_fw(wil
, "data length too short: %lu\n", (ulong
)dlen
);
88 if (le32_to_cpu(fh_
->signature
) != WIL_FW_SIGNATURE
) {
89 wil_err_fw(wil
, "bad header signature: 0x%08x\n",
90 le32_to_cpu(fh_
->signature
));
95 if (le32_to_cpu(fh_
->version
) > WIL_FW_FMT_VERSION
) {
96 wil_err_fw(wil
, "unsupported header version: %d\n",
97 le32_to_cpu(fh_
->version
));
101 /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
105 crc
= crc32_le(~0, (unsigned char const *)hdr
, sizeof(*hdr
));
106 crc
= crc32_le(crc
, (unsigned char const *)&fh
, sizeof(fh
));
107 crc
= crc32_le(crc
, (unsigned char const *)&fh_
[1],
108 dlen
- sizeof(*hdr
) - sizeof(fh
));
111 if (crc
!= le32_to_cpu(fh_
->crc
)) {
112 wil_err_fw(wil
, "checksum mismatch:"
113 " calculated for %lu bytes 0x%08x != 0x%08x\n",
114 (ulong
)dlen
, crc
, le32_to_cpu(fh_
->crc
));
121 static int fw_handle_comment(struct wil6210_priv
*wil
, const void *data
,
124 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET
, 16, 1, data
, size
, true);
129 static int fw_handle_data(struct wil6210_priv
*wil
, const void *data
,
132 const struct wil_fw_record_data
*d
= data
;
134 size_t s
= size
- sizeof(*d
);
136 if (size
< sizeof(*d
) + sizeof(u32
)) {
137 wil_err_fw(wil
, "data record too short: %zu\n", size
);
141 FW_ADDR_CHECK(dst
, d
->addr
, "address");
142 wil_dbg_fw(wil
, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d
->addr
),
144 wil_memcpy_toio_32(dst
, d
->data
, s
);
145 wmb(); /* finish before processing next record */
150 static int fw_handle_fill(struct wil6210_priv
*wil
, const void *data
,
153 const struct wil_fw_record_fill
*d
= data
;
156 size_t s
= (size_t)le32_to_cpu(d
->size
);
158 if (size
!= sizeof(*d
)) {
159 wil_err_fw(wil
, "bad size for fill record: %zu\n", size
);
163 if (s
< sizeof(u32
)) {
164 wil_err_fw(wil
, "fill size too short: %zu\n", s
);
168 if (s
% sizeof(u32
)) {
169 wil_err_fw(wil
, "fill size not aligned: %zu\n", s
);
173 FW_ADDR_CHECK(dst
, d
->addr
, "address");
175 v
= le32_to_cpu(d
->value
);
176 wil_dbg_fw(wil
, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
177 le32_to_cpu(d
->addr
), v
, s
);
178 wil_memset_toio_32(dst
, v
, s
);
179 wmb(); /* finish before processing next record */
184 static int fw_handle_file_header(struct wil6210_priv
*wil
, const void *data
,
187 const struct wil_fw_record_file_header
*d
= data
;
189 if (size
!= sizeof(*d
)) {
190 wil_err_fw(wil
, "file header length incorrect: %zu\n", size
);
194 wil_dbg_fw(wil
, "new file, ver. %d, %i bytes\n",
195 d
->version
, d
->data_len
);
196 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET
, 16, 1, d
->comment
,
197 sizeof(d
->comment
), true);
202 static int fw_handle_direct_write(struct wil6210_priv
*wil
, const void *data
,
205 const struct wil_fw_record_direct_write
*d
= data
;
206 const struct wil_fw_data_dwrite
*block
= d
->data
;
209 if (size
% sizeof(*block
)) {
210 wil_err_fw(wil
, "record size not aligned on %zu: %zu\n",
211 sizeof(*block
), size
);
214 n
= size
/ sizeof(*block
);
216 for (i
= 0; i
< n
; i
++) {
218 u32 m
= le32_to_cpu(block
[i
].mask
);
219 u32 v
= le32_to_cpu(block
[i
].value
);
222 FW_ADDR_CHECK(dst
, block
[i
].addr
, "address");
225 y
= (x
& m
) | (v
& ~m
);
226 wil_dbg_fw(wil
, "write [0x%08x] <== 0x%08x "
227 "(old 0x%08x val 0x%08x mask 0x%08x)\n",
228 le32_to_cpu(block
[i
].addr
), y
, x
, v
, m
);
230 wmb(); /* finish before processing next record */
236 static int gw_write(struct wil6210_priv
*wil
, void __iomem
*gwa_addr
,
237 void __iomem
*gwa_cmd
, void __iomem
*gwa_ctl
, u32 gw_cmd
,
243 writel(gw_cmd
, gwa_cmd
);
244 wmb(); /* finish before activate gw */
246 writel(WIL_FW_GW_CTL_RUN
, gwa_ctl
); /* activate gw */
248 udelay(1); /* typical time is few usec */
250 wil_err_fw(wil
, "gw timeout\n");
253 } while (readl(gwa_ctl
) & WIL_FW_GW_CTL_BUSY
); /* gw done? */
258 static int fw_handle_gateway_data(struct wil6210_priv
*wil
, const void *data
,
261 const struct wil_fw_record_gateway_data
*d
= data
;
262 const struct wil_fw_data_gw
*block
= d
->data
;
263 void __iomem
*gwa_addr
;
264 void __iomem
*gwa_val
;
265 void __iomem
*gwa_cmd
;
266 void __iomem
*gwa_ctl
;
270 if (size
< sizeof(*d
) + sizeof(*block
)) {
271 wil_err_fw(wil
, "gateway record too short: %zu\n", size
);
275 if ((size
- sizeof(*d
)) % sizeof(*block
)) {
276 wil_err_fw(wil
, "gateway record data size"
277 " not aligned on %zu: %zu\n",
278 sizeof(*block
), size
- sizeof(*d
));
281 n
= (size
- sizeof(*d
)) / sizeof(*block
);
283 gw_cmd
= le32_to_cpu(d
->command
);
285 wil_dbg_fw(wil
, "gw write record [%3d] blocks, cmd 0x%08x\n",
288 FW_ADDR_CHECK(gwa_addr
, d
->gateway_addr_addr
, "gateway_addr_addr");
289 FW_ADDR_CHECK(gwa_val
, d
->gateway_value_addr
, "gateway_value_addr");
290 FW_ADDR_CHECK(gwa_cmd
, d
->gateway_cmd_addr
, "gateway_cmd_addr");
291 FW_ADDR_CHECK(gwa_ctl
, d
->gateway_ctrl_address
, "gateway_ctrl_address");
293 wil_dbg_fw(wil
, "gw addresses: addr 0x%08x val 0x%08x"
294 " cmd 0x%08x ctl 0x%08x\n",
295 le32_to_cpu(d
->gateway_addr_addr
),
296 le32_to_cpu(d
->gateway_value_addr
),
297 le32_to_cpu(d
->gateway_cmd_addr
),
298 le32_to_cpu(d
->gateway_ctrl_address
));
300 for (i
= 0; i
< n
; i
++) {
302 u32 a
= le32_to_cpu(block
[i
].addr
);
303 u32 v
= le32_to_cpu(block
[i
].value
);
305 wil_dbg_fw(wil
, " gw write[%3d] [0x%08x] <== 0x%08x\n",
309 rc
= gw_write(wil
, gwa_addr
, gwa_cmd
, gwa_ctl
, gw_cmd
, a
);
317 static int fw_handle_gateway_data4(struct wil6210_priv
*wil
, const void *data
,
320 const struct wil_fw_record_gateway_data4
*d
= data
;
321 const struct wil_fw_data_gw4
*block
= d
->data
;
322 void __iomem
*gwa_addr
;
323 void __iomem
*gwa_val
[ARRAY_SIZE(block
->value
)];
324 void __iomem
*gwa_cmd
;
325 void __iomem
*gwa_ctl
;
329 if (size
< sizeof(*d
) + sizeof(*block
)) {
330 wil_err_fw(wil
, "gateway4 record too short: %zu\n", size
);
334 if ((size
- sizeof(*d
)) % sizeof(*block
)) {
335 wil_err_fw(wil
, "gateway4 record data size"
336 " not aligned on %zu: %zu\n",
337 sizeof(*block
), size
- sizeof(*d
));
340 n
= (size
- sizeof(*d
)) / sizeof(*block
);
342 gw_cmd
= le32_to_cpu(d
->command
);
344 wil_dbg_fw(wil
, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
347 FW_ADDR_CHECK(gwa_addr
, d
->gateway_addr_addr
, "gateway_addr_addr");
348 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
349 FW_ADDR_CHECK(gwa_val
[k
], d
->gateway_value_addr
[k
],
350 "gateway_value_addr");
351 FW_ADDR_CHECK(gwa_cmd
, d
->gateway_cmd_addr
, "gateway_cmd_addr");
352 FW_ADDR_CHECK(gwa_ctl
, d
->gateway_ctrl_address
, "gateway_ctrl_address");
354 wil_dbg_fw(wil
, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
355 le32_to_cpu(d
->gateway_addr_addr
),
356 le32_to_cpu(d
->gateway_cmd_addr
),
357 le32_to_cpu(d
->gateway_ctrl_address
));
358 wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE
, 16, 4,
359 d
->gateway_value_addr
, sizeof(d
->gateway_value_addr
),
362 for (i
= 0; i
< n
; i
++) {
364 u32 a
= le32_to_cpu(block
[i
].addr
);
365 u32 v
[ARRAY_SIZE(block
->value
)];
367 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
368 v
[k
] = le32_to_cpu(block
[i
].value
[k
]);
370 wil_dbg_fw(wil
, " gw4 write[%3d] [0x%08x] <==\n", i
, a
);
371 wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE
, 16, 4, v
,
374 for (k
= 0; k
< ARRAY_SIZE(block
->value
); k
++)
375 writel(v
[k
], gwa_val
[k
]);
376 rc
= gw_write(wil
, gwa_addr
, gwa_cmd
, gwa_ctl
, gw_cmd
, a
);
384 static const struct {
386 int (*handler
)(struct wil6210_priv
*wil
, const void *data
, size_t size
);
387 } wil_fw_handlers
[] = {
388 {wil_fw_type_comment
, fw_handle_comment
},
389 {wil_fw_type_data
, fw_handle_data
},
390 {wil_fw_type_fill
, fw_handle_fill
},
391 /* wil_fw_type_action */
392 /* wil_fw_type_verify */
393 {wil_fw_type_file_header
, fw_handle_file_header
},
394 {wil_fw_type_direct_write
, fw_handle_direct_write
},
395 {wil_fw_type_gateway_data
, fw_handle_gateway_data
},
396 {wil_fw_type_gateway_data4
, fw_handle_gateway_data4
},
399 static int wil_fw_handle_record(struct wil6210_priv
*wil
, int type
,
400 const void *data
, size_t size
)
404 for (i
= 0; i
< ARRAY_SIZE(wil_fw_handlers
); i
++) {
405 if (wil_fw_handlers
[i
].type
== type
)
406 return wil_fw_handlers
[i
].handler(wil
, data
, size
);
409 wil_err_fw(wil
, "unknown record type: %d\n", type
);
414 * wil_fw_load - load FW into device
416 * Load the FW and uCode code and data to the corresponding device
421 static int wil_fw_load(struct wil6210_priv
*wil
, const void *data
, size_t size
)
424 const struct wil_fw_record_head
*hdr
;
427 for (hdr
= data
;; hdr
= (const void *)hdr
+ s
, size
-= s
) {
428 if (size
< sizeof(*hdr
))
430 hdr_sz
= le32_to_cpu(hdr
->size
);
431 s
= sizeof(*hdr
) + hdr_sz
;
435 wil_err_fw(wil
, "unaligned record size: %zu\n",
439 rc
= wil_fw_handle_record(wil
, le16_to_cpu(hdr
->type
),
445 wil_err_fw(wil
, "unprocessed bytes: %zu\n", size
);
446 if (size
>= sizeof(*hdr
)) {
447 wil_err_fw(wil
, "Stop at offset %ld"
448 " record type %d [%zd bytes]\n",
449 (long)((const void *)hdr
- data
),
450 le16_to_cpu(hdr
->type
), hdr_sz
);
459 * wil_request_firmware - Request firmware and load to device
461 * Request firmware image from the file and load it to device
465 int wil_request_firmware(struct wil6210_priv
*wil
, const char *name
)
468 const struct firmware
*fw
;
472 rc
= request_firmware(&fw
, name
, wil_to_dev(wil
));
474 wil_err_fw(wil
, "Failed to load firmware %s\n", name
);
477 wil_dbg_fw(wil
, "Loading <%s>, %zu bytes\n", name
, fw
->size
);
479 for (sz
= fw
->size
, d
= fw
->data
; sz
; sz
-= rc1
, d
+= rc1
) {
480 rc1
= wil_fw_verify(wil
, d
, sz
);
485 rc
= wil_fw_load(wil
, d
, rc1
);
491 release_firmware(fw
);