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(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
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, 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
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, 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, name, &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, "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(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							&pfirmware->blobs[i],
165							fw_name[i],
166							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, DESC_PACKET_TYPE_INIT,
175						mapped_file, file_length);
176		if (!rt_status)
177			goto download_firmware_fail;
178
179		if (!_rtl92e_fw_check_ready(dev, 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, "%s: Failed to initialize firmware.\n", __func__);
188	return false;
189}
190