1 /** @file firmware_load.c
2 *
3 * @brief This file provides firmware download related API
4 *
5 * Copyright 2021-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #if (CONFIG_XZ_DECOMPRESSION)
12 #include <xz.h>
13 #include <decompress.h>
14 #endif /* CONFIG_XZ_DECOMPRESSION */
15
16 #include <wmlog.h>
17 /* Additional WMSDK header files */
18 #include "type_decls.h"
19 #include "firmware_dnld.h"
20 #include "fwdnld_intf_abs.h"
21
22 static const uint8_t *conn_fw;
23
24 /* remove this after mlan integration complete */
25 enum
26 {
27 FWDNLD_STATUS_FAILURE = 0xffffffff,
28 FWDNLD_STATUS_SUCCESS = 0,
29 FWDNLD_STATUS_SKIP,
30 FWDNLD_CARD_NOT_DETECTED = 3,
31 FWDNLD_STATUS_FW_DNLD_FAILED,
32 FWDNLD_STATUS_FW_NOT_DETECTED = 5,
33 FWDNLD_STATUS_FW_NOT_READY,
34 FWDNLD_STATUS_FW_XZ_FAILED,
35 FWDNLD_CARD_CMD_TIMEOUT
36 };
37
conn_download_normal_fw(const t_u8 * connfw_dl,t_u32 firmwarelen,fwdnld_intf_t * intf)38 static int32_t conn_download_normal_fw(const t_u8 *connfw_dl, t_u32 firmwarelen, fwdnld_intf_t *intf)
39 {
40 t_u32 offset = 0;
41 int32_t ret = FWDNLD_STATUS_FAILURE;
42 t_u32 remaining_len = firmwarelen;
43 uint32_t len = 0;
44
45 if (firmwarelen <= 0)
46 {
47 return ret;
48 }
49
50 if (intf->intf_s.fwdnld_intf_send)
51 {
52 ret = intf->intf_s.fwdnld_intf_send(intf, (const void *)(connfw_dl + offset), remaining_len, &len);
53 }
54
55 return ret;
56 }
57
58 #if (CONFIG_XZ_DECOMPRESSION)
conn_download_decomp_fw(t_u8 * wlanfw_xz,t_u32 firmwarelen,t_u32 ioport)59 int32_t conn_download_decomp_fw(t_u8 *wlanfw_xz, t_u32 firmwarelen, t_u32 ioport)
60 {
61 t_u32 tx_blocks = 0, txlen = 0, buflen = 0;
62 t_u16 len = 0;
63 t_u32 offset = 0;
64 t_u32 tries = 0;
65 uint32_t resp;
66 uint32_t outbuf_len;
67 uint8_t *loutbuf = NULL :
68
69 loutbuf = wifi_get_sdio_outbuf(&outbuf_len);
70 (void)memset(loutbuf, 0, outbuf_len);
71
72 #define SBUF_SIZE 2048
73 int ret;
74 struct xz_buf stream;
75 uint32_t retlen, readlen = 0;
76 #if !CONFIG_MEM_POOLS
77 t_u8 *sbuf = (t_u8 *)OSA_MemoryAllocate(SBUF_SIZE);
78 #else
79 t_u8 *sbuf = (t_u8 *)OSA_MemoryPoolAllocate(buf_2048_MemoryPool);
80 #endif
81 if (sbuf == NULL)
82 {
83 fwdnld_io_e("Allocation failed");
84 return FWDNLD_STATUS_FAILURE;
85 }
86
87 xz_uncompress_init(&stream, sbuf, loutbuf);
88
89 do
90 {
91 /* Read CARD_STATUS_REG (0X30) FN =1 */
92 for (tries = 0; tries < MAX_POLL_TRIES; tries++)
93 {
94 if (wlan_card_status(DN_LD_CARD_RDY | CARD_IO_READY) == true)
95 {
96 len = wlan_card_read_f1_base_regs();
97 }
98 else
99 {
100 fwdnld_io_e("Error in wlan_card_status()");
101 break;
102 }
103
104 if (len)
105 break;
106 }
107
108 if (!len)
109 {
110 fwdnld_io_e("Card timeout %s:%d", __func__, __LINE__);
111 break;
112 }
113 else if (len > WLAN_UPLD_SIZE)
114 {
115 fwdnld_io_e("FW Download Failure. Invalid len");
116 xz_uncompress_end();
117 #if !CONFIG_MEM_POOLS
118 OSA_MemoryFree(sbuf);
119 #else
120 OSA_MemoryPoolFree(buf_2048_MemoryPool, sbuf);
121 #endif
122 return FWDNLD_STATUS_FW_DNLD_FAILED;
123 }
124
125 txlen = len;
126
127 do
128 {
129 if (stream.in_pos == stream.in_size)
130 {
131 readlen = MIN(SBUF_SIZE, firmwarelen);
132 (void)memcpy((void *)sbuf, (const void *)(wlanfw_xz + offset), readlen);
133 offset += readlen;
134 firmwarelen -= readlen;
135 }
136 ret = xz_uncompress_stream(&stream, sbuf, readlen, loutbuf, txlen, &retlen);
137
138 if (ret == XZ_STREAM_END)
139 {
140 txlen = retlen;
141 break;
142 }
143 else if (ret != XZ_OK)
144 {
145 fwdnld_io_e("Decompression failed:%d", ret);
146 break;
147 }
148 } while (retlen == 0);
149
150 calculate_sdio_write_params(txlen, &tx_blocks, &buflen);
151
152 sdio_drv_write(ioport, 1, tx_blocks, buflen, (t_u8 *)loutbuf, &resp);
153
154 if (ret == XZ_STREAM_END)
155 {
156 fwdnld_io_d("Decompression successful");
157 break;
158 }
159 else if (ret != XZ_OK)
160 {
161 fwdnld_io_e("Exit:%d", ret);
162 break;
163 }
164 len = 0;
165 } while (1);
166
167 xz_uncompress_end();
168 #if !CONFIG_MEM_POOLS
169 OSA_MemoryFree(sbuf);
170 #else
171 OSA_MemoryPoolFree(buf_2048_MemoryPool, sbuf);
172 #endif
173
174 if (ret == XZ_OK || ret == XZ_STREAM_END)
175 return FWDNLD_STATUS_SUCCESS;
176 else
177 return FWDNLD_STATUS_FW_XZ_FAILED;
178 }
179
180 #endif /* CONFIG_XZ_DECOMPRESSION */
181
182 /*
183 * Download firmware to the card through SDIO.
184 * The firmware is stored in Flash.
185 * in param intf returned from the interface init
186 */
firmware_download(const uint8_t * fw_start_addr,const size_t size,void * interface,uint8_t fw_reload)187 int32_t firmware_download(const uint8_t *fw_start_addr, const size_t size, void *interface, uint8_t fw_reload)
188 {
189 t_u32 firmwarelen;
190 int32_t ret = FWDNLD_STATUS_SUCCESS;
191 fwdnld_intf_t *intf = (fwdnld_intf_t *)interface;
192
193 if (size == 0)
194 {
195 return ret;
196 }
197
198 if (intf->intf_s.fwdnld_intf_prepare)
199 {
200 ret = intf->intf_s.fwdnld_intf_prepare(intf, NULL);
201 if (ret != FWDNLD_STATUS_SUCCESS)
202 {
203 return ret;
204 }
205 }
206
207 #if (CONFIG_WIFI_IND_DNLD)
208 if ((fw_reload != 0) && (intf->intf_s.fwdnld_intf_check_reload))
209 {
210 ret = intf->intf_s.fwdnld_intf_check_reload(intf, fw_reload);
211 if (ret != FWDNLD_STATUS_SUCCESS)
212 {
213 return ret;
214 }
215 }
216 #endif
217
218 conn_fw = fw_start_addr;
219
220 fwdnld_io_d("Start copying connectivity firmware from 0x%x", (t_u32)conn_fw);
221
222 firmwarelen = size;
223 /*Making this section as #if 00 for now, as the decopress and
224 * verification of compression etc funcitons are not present*/
225 #if (CONFIG_XZ_DECOMPRESSION)
226 t_u8 buffer[6];
227
228 (void)memcpy((void *)buffer, (const void *)conn_fw, sizeof(buffer));
229
230 /* See if image is XZ compressed or not */
231 if (verify_xz_header(buffer) == WM_SUCCESS)
232 {
233 fwdnld_io_d(
234 "XZ Compressed image found, start decompression,"
235 " len: %d",
236 firmwarelen);
237 ret = conn_download_decomp_fw(conn_fw, firmwarelen, ioport_g);
238 }
239 else
240 #endif /* CONFIG_XZ_DECOMPRESSION */
241 {
242 fwdnld_io_d(
243 "Un-compressed image found, start download,"
244 " len: %d",
245 firmwarelen);
246 ret = conn_download_normal_fw(conn_fw, firmwarelen, intf);
247 }
248
249 if (ret != FWDNLD_STATUS_SUCCESS)
250 {
251 return FWDNLD_STATUS_FAILURE;
252 }
253 if (intf->intf_s.fwdnld_intf_check_ready)
254 {
255 return intf->intf_s.fwdnld_intf_check_ready(intf, NULL);
256 }
257 return ret;
258 }
259