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 "table.h"
10#include "r8192E_firmware.h"
11#include "r8192E_cmdpkt.h"
12#include <linux/firmware.h>
13
14static bool _rtl92e_wait_for_fw(struct net_device *dev, u32 mask, u32 timeout)
15{
16 unsigned long deadline = jiffies + msecs_to_jiffies(m: timeout);
17
18 while (time_before(jiffies, deadline)) {
19 if (rtl92e_readl(dev, x: CPU_GEN) & mask)
20 return true;
21 mdelay(2);
22 }
23 return false;
24}
25
26static 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, timeout: 200)) {
31 netdev_err(dev, format: "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, x: CPU_GEN);
37 rtl92e_writeb(dev, x: CPU_GEN, y: (CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff);
38 mdelay(1);
39
40 if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, timeout: 200)) {
41 netdev_err(dev, format: "Firmware boot failed.\n");
42 return false;
43 }
44
45 netdev_dbg(dev, "Download Firmware: Boot ready!\n");
46
47 return true;
48}
49
50static 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->fw_info;
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, timeout: 20);
78 if (rt_status)
79 pfirmware->status = FW_STATUS_5_READY;
80 break;
81 default:
82 rt_status = false;
83 netdev_dbg(dev, "Unknown firmware status");
84 break;
85 }
86
87 return rt_status;
88}
89
90static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob,
91 const char *name, u8 padding)
92{
93 const struct firmware *fw;
94 int rc, i;
95 bool ret = true;
96
97 rc = request_firmware(fw: &fw, name, device: &dev->dev);
98 if (rc < 0)
99 return false;
100
101 if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) {
102 netdev_err(dev, format: "Firmware image %s too big for the device.\n",
103 name);
104 ret = false;
105 goto out;
106 }
107
108 if (padding)
109 memset(blob->data, 0, padding);
110 if (fw->size % 4)
111 memset(blob->data + padding + fw->size, 0, 4);
112 memcpy(blob->data + padding, fw->data, fw->size);
113
114 blob->size = round_up(fw->size, 4) + padding;
115
116 /* Swap endian - firmware is packaged in invalid endiannes*/
117 for (i = padding; i < blob->size; i += 4) {
118 u32 *data = (u32 *)(blob->data + i);
119 *data = swab32p(p: data);
120 }
121out:
122 release_firmware(fw);
123 return ret;
124}
125
126bool rtl92e_init_fw(struct net_device *dev)
127{
128 struct r8192_priv *priv = rtllib_priv(dev);
129 bool rt_status = true;
130
131 u32 file_length = 0;
132 u8 *mapped_file = NULL;
133 u8 i = 0;
134 enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
135 enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
136
137 struct rt_firmware *pfirmware = priv->fw_info;
138
139 netdev_dbg(dev, " PlatformInitFirmware()==>\n");
140
141 if (pfirmware->status == FW_STATUS_0_INIT) {
142 rst_opt = OPT_SYSTEM_RESET;
143 starting_state = FW_INIT_STEP0_BOOT;
144
145 } else if (pfirmware->status == FW_STATUS_5_READY) {
146 rst_opt = OPT_FIRMWARE_RESET;
147 starting_state = FW_INIT_STEP2_DATA;
148 }
149
150 for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) {
151 if (rst_opt == OPT_SYSTEM_RESET) {
152 if (pfirmware->blobs[i].size == 0) {
153 const char *fw_name[3] = {
154 RTL8192E_BOOT_IMG_FW,
155 RTL8192E_MAIN_IMG_FW,
156 RTL8192E_DATA_IMG_FW
157 };
158 int pad = 0;
159
160 if (i == FW_INIT_STEP1_MAIN)
161 pad = 128;
162
163 if (!_rtl92e_fw_prepare(dev,
164 blob: &pfirmware->blobs[i],
165 name: fw_name[i],
166 padding: pad))
167 goto download_firmware_fail;
168 }
169 }
170
171 mapped_file = pfirmware->blobs[i].data;
172 file_length = pfirmware->blobs[i].size;
173
174 rt_status = rtl92e_send_cmd_pkt(dev, type: DESC_PACKET_TYPE_INIT,
175 data: mapped_file, len: file_length);
176 if (!rt_status)
177 goto download_firmware_fail;
178
179 if (!_rtl92e_fw_check_ready(dev, load_fw_status: i))
180 goto download_firmware_fail;
181 }
182
183 netdev_dbg(dev, "Firmware Download Success\n");
184 return rt_status;
185
186download_firmware_fail:
187 netdev_err(dev, format: "%s: Failed to initialize firmware.\n", __func__);
188 return false;
189}
190

source code of linux/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c