GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / staging / rtl8192e / rtl8192e / r8192E_firmware.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
4  *
5  * Contact Information: wlanfae <wlanfae@realtek.com>
6  */
7 #include "rtl_core.h"
8 #include "r8192E_hw.h"
9 #include "r8192E_hwimg.h"
10 #include "r8192E_firmware.h"
11 #include "r8192E_cmdpkt.h"
12 #include <linux/firmware.h>
13
14 static bool _rtl92e_wait_for_fw(struct net_device *dev, u32 mask, u32 timeout)
15 {
16         unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
17
18         while (time_before(jiffies, deadline)) {
19                 if (rtl92e_readl(dev, CPU_GEN) & mask)
20                         return true;
21                 mdelay(2);
22         }
23         return false;
24 }
25
26 static bool _rtl92e_fw_boot_cpu(struct net_device *dev)
27 {
28         u32             CPU_status = 0;
29
30         if (!_rtl92e_wait_for_fw(dev, CPU_GEN_PUT_CODE_OK, 200)) {
31                 netdev_err(dev, "Firmware download failed.\n");
32                 return false;
33         }
34         netdev_dbg(dev, "Download Firmware: Put code ok!\n");
35
36         CPU_status = rtl92e_readl(dev, CPU_GEN);
37         rtl92e_writeb(dev, CPU_GEN, (CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff);
38         mdelay(1);
39
40         if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, 200)) {
41                 netdev_err(dev, "Firmware boot failed.\n");
42                 return false;
43         }
44
45         netdev_dbg(dev, "Download Firmware: Boot ready!\n");
46
47         return true;
48 }
49
50 static bool _rtl92e_fw_check_ready(struct net_device *dev,
51                                    u8 load_fw_status)
52 {
53         struct r8192_priv *priv = rtllib_priv(dev);
54         struct rt_firmware *pfirmware = priv->pFirmware;
55         bool rt_status  = true;
56
57         switch (load_fw_status) {
58         case FW_INIT_STEP0_BOOT:
59                 pfirmware->status = FW_STATUS_1_MOVE_BOOT_CODE;
60                 break;
61
62         case FW_INIT_STEP1_MAIN:
63                 pfirmware->status = FW_STATUS_2_MOVE_MAIN_CODE;
64
65                 rt_status = _rtl92e_fw_boot_cpu(dev);
66                 if (rt_status)
67                         pfirmware->status = FW_STATUS_3_TURNON_CPU;
68                 else
69                         netdev_dbg(dev, "_rtl92e_fw_boot_cpu fail!\n");
70
71                 break;
72
73         case FW_INIT_STEP2_DATA:
74                 pfirmware->status = FW_STATUS_4_MOVE_DATA_CODE;
75                 mdelay(1);
76
77                 rt_status = _rtl92e_wait_for_fw(dev, CPU_GEN_FIRM_RDY, 20);
78                 if (rt_status)
79                         pfirmware->status = FW_STATUS_5_READY;
80                 else
81                         RT_TRACE(COMP_FIRMWARE,
82                                  "_rtl92e_is_fw_ready fail(%d)!\n",
83                                  rt_status);
84                 break;
85         default:
86                 rt_status = false;
87                 netdev_dbg(dev, "Unknown firmware status");
88                 break;
89         }
90
91         return rt_status;
92 }
93
94 static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob,
95                                const char *name, u8 padding)
96 {
97         const struct firmware *fw;
98         int rc, i;
99         bool ret = true;
100
101         rc = reject_firmware(&fw, name, &dev->dev);
102         if (rc < 0)
103                 return false;
104
105         if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) {
106                 netdev_err(dev, "Firmware image %s too big for the device.\n",
107                            name);
108                 ret = false;
109                 goto out;
110         }
111
112         if (padding)
113                 memset(blob->data, 0, padding);
114         if (fw->size % 4)
115                 memset(blob->data + padding + fw->size, 0, 4);
116         memcpy(blob->data + padding, fw->data, fw->size);
117
118         blob->size = round_up(fw->size, 4) + padding;
119
120         /* Swap endian - firmware is packaged in invalid endiannes*/
121         for (i = padding; i < blob->size; i += 4) {
122                 u32 *data = (u32 *)(blob->data + i);
123                 *data = swab32p(data);
124         }
125 out:
126         release_firmware(fw);
127         return ret;
128 }
129
130 bool rtl92e_init_fw(struct net_device *dev)
131 {
132         struct r8192_priv *priv = rtllib_priv(dev);
133         bool                    rt_status = true;
134
135         u32     file_length = 0;
136         u8      *mapped_file = NULL;
137         u8      i = 0;
138         enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
139         enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
140
141         struct rt_firmware *pfirmware = priv->pFirmware;
142
143         netdev_dbg(dev, " PlatformInitFirmware()==>\n");
144
145         if (pfirmware->status == FW_STATUS_0_INIT) {
146                 rst_opt = OPT_SYSTEM_RESET;
147                 starting_state = FW_INIT_STEP0_BOOT;
148
149         } else if (pfirmware->status == FW_STATUS_5_READY) {
150                 rst_opt = OPT_FIRMWARE_RESET;
151                 starting_state = FW_INIT_STEP2_DATA;
152         } else {
153                 RT_TRACE(COMP_FIRMWARE,
154                          "PlatformInitFirmware: undefined firmware state\n");
155         }
156
157         for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) {
158                 if (rst_opt == OPT_SYSTEM_RESET) {
159                         if (pfirmware->blobs[i].size == 0) {
160                                 const char *fw_name[3] = {
161                                         RTL8192E_BOOT_IMG_FW,
162                                         RTL8192E_MAIN_IMG_FW,
163                                         RTL8192E_DATA_IMG_FW
164                                 };
165                                 int pad = 0;
166
167                                 if (i == FW_INIT_STEP1_MAIN)
168                                         pad = 128;
169
170                                 if (!_rtl92e_fw_prepare(dev,
171                                                         &pfirmware->blobs[i],
172                                                         fw_name[i],
173                                                         pad))
174                                         goto download_firmware_fail;
175                         }
176                 }
177
178                 mapped_file = pfirmware->blobs[i].data;
179                 file_length = pfirmware->blobs[i].size;
180
181                 rt_status = rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_INIT,
182                                                 mapped_file, file_length);
183                 if (!rt_status)
184                         goto download_firmware_fail;
185
186                 if (!_rtl92e_fw_check_ready(dev, i))
187                         goto download_firmware_fail;
188         }
189
190         netdev_dbg(dev, "Firmware Download Success\n");
191         return rt_status;
192
193 download_firmware_fail:
194         netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__);
195         return false;
196 }