xref: /openbmc/linux/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  // SPDX-License-Identifier: GPL-2.0
2  /* Copyright(c) 2009-2014  Realtek Corporation.*/
3  
4  #include "../wifi.h"
5  #include "../pci.h"
6  #include "../base.h"
7  #include "../efuse.h"
8  #include "fw_common.h"
9  #include <linux/module.h>
10  
rtl8723_enable_fw_download(struct ieee80211_hw * hw,bool enable)11  void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable)
12  {
13  	struct rtl_priv *rtlpriv = rtl_priv(hw);
14  	u8 tmp;
15  
16  	if (enable) {
17  		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
18  		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
19  			       tmp | 0x04);
20  
21  		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
22  		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
23  
24  		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
25  		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
26  	} else {
27  		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
28  		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
29  
30  		rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
31  	}
32  }
33  EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download);
34  
rtl8723_write_fw(struct ieee80211_hw * hw,enum version_8723e version,u8 * buffer,u32 size,u8 max_page)35  void rtl8723_write_fw(struct ieee80211_hw *hw,
36  		      enum version_8723e version,
37  		      u8 *buffer, u32 size, u8 max_page)
38  {
39  	struct rtl_priv *rtlpriv = rtl_priv(hw);
40  	u8 *bufferptr = buffer;
41  	u32 page_nums, remain_size;
42  	u32 page, offset;
43  
44  	rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
45  
46  	rtl_fill_dummy(bufferptr, &size);
47  
48  	page_nums = size / FW_8192C_PAGE_SIZE;
49  	remain_size = size % FW_8192C_PAGE_SIZE;
50  
51  	if (page_nums > max_page) {
52  		pr_err("Page numbers should not greater than %d\n",
53  		       max_page);
54  	}
55  	for (page = 0; page < page_nums; page++) {
56  		offset = page * FW_8192C_PAGE_SIZE;
57  		rtl_fw_page_write(hw, page, (bufferptr + offset),
58  				  FW_8192C_PAGE_SIZE);
59  	}
60  
61  	if (remain_size) {
62  		offset = page_nums * FW_8192C_PAGE_SIZE;
63  		page = page_nums;
64  		rtl_fw_page_write(hw, page, (bufferptr + offset), remain_size);
65  	}
66  	rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
67  }
68  EXPORT_SYMBOL_GPL(rtl8723_write_fw);
69  
rtl8723ae_firmware_selfreset(struct ieee80211_hw * hw)70  void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
71  {
72  	u8 u1b_tmp;
73  	u8 delay = 100;
74  	struct rtl_priv *rtlpriv = rtl_priv(hw);
75  
76  	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
77  	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
78  
79  	while (u1b_tmp & BIT(2)) {
80  		delay--;
81  		if (delay == 0)
82  			break;
83  		udelay(50);
84  		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
85  	}
86  	if (delay == 0) {
87  		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
88  		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
89  			       u1b_tmp&(~BIT(2)));
90  	}
91  }
92  EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
93  
rtl8723be_firmware_selfreset(struct ieee80211_hw * hw)94  void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw)
95  {
96  	u8 u1b_tmp;
97  	struct rtl_priv *rtlpriv = rtl_priv(hw);
98  
99  	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
100  	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
101  
102  	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
103  	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
104  	udelay(50);
105  
106  	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
107  	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
108  
109  	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
110  	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
111  
112  	rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
113  		"_8051Reset8723be(): 8051 reset success .\n");
114  }
115  EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
116  
rtl8723_fw_free_to_go(struct ieee80211_hw * hw,bool is_8723be,int max_count)117  int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
118  			  int max_count)
119  {
120  	struct rtl_priv *rtlpriv = rtl_priv(hw);
121  	int err = -EIO;
122  	u32 counter = 0;
123  	u32 value32;
124  
125  	do {
126  		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
127  	} while ((counter++ < max_count) &&
128  		 (!(value32 & FWDL_CHKSUM_RPT)));
129  
130  	if (counter >= max_count) {
131  		pr_err("chksum report fail ! REG_MCUFWDL:0x%08x .\n",
132  		       value32);
133  		goto exit;
134  	}
135  	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
136  	value32 &= ~WINTINI_RDY;
137  	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
138  
139  	if (is_8723be)
140  		rtl8723be_firmware_selfreset(hw);
141  	counter = 0;
142  
143  	do {
144  		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
145  		if (value32 & WINTINI_RDY) {
146  			rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,
147  				"Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
148  				value32);
149  			err = 0;
150  			goto exit;
151  		}
152  
153  		mdelay(FW_8192C_POLLING_DELAY);
154  
155  	} while (counter++ < max_count);
156  
157  	pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
158  	       value32);
159  
160  exit:
161  	return err;
162  }
163  EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
164  
rtl8723_download_fw(struct ieee80211_hw * hw,bool is_8723be,int max_count)165  int rtl8723_download_fw(struct ieee80211_hw *hw,
166  			bool is_8723be, int max_count)
167  {
168  	struct rtl_priv *rtlpriv = rtl_priv(hw);
169  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
170  	struct rtlwifi_firmware_header *pfwheader;
171  	u8 *pfwdata;
172  	u32 fwsize;
173  	int err;
174  	enum version_8723e version = rtlhal->version;
175  	int max_page;
176  
177  	if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
178  		return 1;
179  
180  	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
181  	rtlhal->fw_version = le16_to_cpu(pfwheader->version);
182  	rtlhal->fw_subversion = pfwheader->subversion;
183  	pfwdata = rtlhal->pfirmware;
184  	fwsize = rtlhal->fwsize;
185  
186  	if (!is_8723be)
187  		max_page = 6;
188  	else
189  		max_page = 8;
190  	if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
191  		rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
192  			"Firmware Version(%d), Signature(%#x), Size(%d)\n",
193  			pfwheader->version, pfwheader->signature,
194  			(int)sizeof(struct rtlwifi_firmware_header));
195  
196  		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
197  		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
198  	}
199  
200  	if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
201  		if (is_8723be)
202  			rtl8723be_firmware_selfreset(hw);
203  		else
204  			rtl8723ae_firmware_selfreset(hw);
205  		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
206  	}
207  	rtl8723_enable_fw_download(hw, true);
208  	rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);
209  	rtl8723_enable_fw_download(hw, false);
210  
211  	err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
212  	if (err)
213  		pr_err("Firmware is not ready to run!\n");
214  	return 0;
215  }
216  EXPORT_SYMBOL_GPL(rtl8723_download_fw);
217  
218