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