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