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,
38 		      (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff));
39 	mdelay(1);
40 
41 	if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, 200)) {
42 		netdev_err(dev, "Firmware boot failed.\n");
43 		return false;
44 	}
45 
46 	netdev_dbg(dev, "Download Firmware: Boot ready!\n");
47 
48 	return true;
49 }
50 
51 static bool _rtl92e_fw_check_ready(struct net_device *dev,
52 				   u8 load_fw_status)
53 {
54 	struct r8192_priv *priv = rtllib_priv(dev);
55 	struct rt_firmware *pfirmware = priv->pFirmware;
56 	bool rt_status  = true;
57 
58 	switch (load_fw_status) {
59 	case FW_INIT_STEP0_BOOT:
60 		pfirmware->status = FW_STATUS_1_MOVE_BOOT_CODE;
61 		break;
62 
63 	case FW_INIT_STEP1_MAIN:
64 		pfirmware->status = FW_STATUS_2_MOVE_MAIN_CODE;
65 
66 		rt_status = _rtl92e_fw_boot_cpu(dev);
67 		if (rt_status)
68 			pfirmware->status = FW_STATUS_3_TURNON_CPU;
69 		else
70 			netdev_dbg(dev, "_rtl92e_fw_boot_cpu fail!\n");
71 
72 		break;
73 
74 	case FW_INIT_STEP2_DATA:
75 		pfirmware->status = FW_STATUS_4_MOVE_DATA_CODE;
76 		mdelay(1);
77 
78 		rt_status = _rtl92e_wait_for_fw(dev, CPU_GEN_FIRM_RDY, 20);
79 		if (rt_status)
80 			pfirmware->status = FW_STATUS_5_READY;
81 		else
82 			RT_TRACE(COMP_FIRMWARE,
83 				 "_rtl92e_is_fw_ready fail(%d)!\n",
84 				 rt_status);
85 		break;
86 	default:
87 		rt_status = false;
88 		netdev_dbg(dev, "Unknown firmware status");
89 		break;
90 	}
91 
92 	return rt_status;
93 }
94 
95 static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob,
96 			       const char *name, u8 padding)
97 {
98 	const struct firmware *fw;
99 	int rc, i;
100 	bool ret = true;
101 
102 	rc = request_firmware(&fw, name, &dev->dev);
103 	if (rc < 0)
104 		return false;
105 
106 	if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) {
107 		netdev_err(dev, "Firmware image %s too big for the device.\n",
108 			   name);
109 		ret = false;
110 		goto out;
111 	}
112 
113 	if (padding)
114 		memset(blob->data, 0, padding);
115 	if (fw->size % 4)
116 		memset(blob->data + padding + fw->size, 0, 4);
117 	memcpy(blob->data + padding, fw->data, fw->size);
118 
119 	blob->size = round_up(fw->size, 4) + padding;
120 
121 	/* Swap endian - firmware is packaged in invalid endiannes*/
122 	for (i = padding; i < blob->size; i += 4) {
123 		u32 *data = (u32 *)(blob->data + i);
124 		*data = swab32p(data);
125 	}
126 out:
127 	release_firmware(fw);
128 	return ret;
129 }
130 
131 bool rtl92e_init_fw(struct net_device *dev)
132 {
133 	struct r8192_priv *priv = rtllib_priv(dev);
134 	bool			rt_status = true;
135 
136 	u32	file_length = 0;
137 	u8	*mapped_file = NULL;
138 	u8	i = 0;
139 	enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
140 	enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
141 
142 	struct rt_firmware *pfirmware = priv->pFirmware;
143 
144 	netdev_dbg(dev, " PlatformInitFirmware()==>\n");
145 
146 	if (pfirmware->status == FW_STATUS_0_INIT) {
147 		rst_opt = OPT_SYSTEM_RESET;
148 		starting_state = FW_INIT_STEP0_BOOT;
149 
150 	} else if (pfirmware->status == FW_STATUS_5_READY) {
151 		rst_opt = OPT_FIRMWARE_RESET;
152 		starting_state = FW_INIT_STEP2_DATA;
153 	} else {
154 		RT_TRACE(COMP_FIRMWARE,
155 			 "PlatformInitFirmware: undefined firmware state\n");
156 	}
157 
158 	for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) {
159 		if (rst_opt == OPT_SYSTEM_RESET) {
160 			if (pfirmware->blobs[i].size == 0) {
161 				const char *fw_name[3] = {
162 					RTL8192E_BOOT_IMG_FW,
163 					RTL8192E_MAIN_IMG_FW,
164 					RTL8192E_DATA_IMG_FW
165 				};
166 				int pad = 0;
167 
168 				if (i == FW_INIT_STEP1_MAIN)
169 					pad = 128;
170 
171 				if (!_rtl92e_fw_prepare(dev,
172 							&pfirmware->blobs[i],
173 							fw_name[i],
174 							pad))
175 					goto download_firmware_fail;
176 			}
177 		}
178 
179 		mapped_file = pfirmware->blobs[i].data;
180 		file_length = pfirmware->blobs[i].size;
181 
182 		rt_status = rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_INIT,
183 						mapped_file, file_length);
184 		if (!rt_status)
185 			goto download_firmware_fail;
186 
187 		if (!_rtl92e_fw_check_ready(dev, i))
188 			goto download_firmware_fail;
189 	}
190 
191 	netdev_dbg(dev, "Firmware Download Success\n");
192 	return rt_status;
193 
194 download_firmware_fail:
195 	netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__);
196 	return false;
197 }
198