brintos

brintos / linux-shallow public Read only

0
0
Text · 9.7 KiB · aa54dbd Raw
371 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2012  Realtek Corporation.*/3 4#include "../wifi.h"5#include "../pci.h"6#include "../base.h"7#include "../efuse.h"8#include "def.h"9#include "reg.h"10#include "fw_common.h"11 12bool rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)13{14	return !!(rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY);15}16EXPORT_SYMBOL_GPL(rtl92d_is_fw_downloaded);17 18void rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)19{20	struct rtl_priv *rtlpriv = rtl_priv(hw);21	u8 tmp;22 23	if (enable) {24		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);25		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);26		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);27		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);28		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);29		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);30	} else {31		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);32		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);33		/* Reserved for fw extension.34		 * 0x81[7] is used for mac0 status ,35		 * so don't write this reg here36		 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);37		 */38	}39}40EXPORT_SYMBOL_GPL(rtl92d_enable_fw_download);41 42void rtl92d_write_fw(struct ieee80211_hw *hw,43		     enum version_8192d version, u8 *buffer, u32 size)44{45	struct rtl_priv *rtlpriv = rtl_priv(hw);46	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));47	u8 *bufferptr = buffer;48	u32 pagenums, remainsize;49	u32 page, offset;50 51	rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);52 53	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)54		rtl_fill_dummy(bufferptr, &size);55 56	pagenums = size / FW_8192D_PAGE_SIZE;57	remainsize = size % FW_8192D_PAGE_SIZE;58 59	if (pagenums > 8)60		pr_err("Page numbers should not greater then 8\n");61 62	for (page = 0; page < pagenums; page++) {63		offset = page * FW_8192D_PAGE_SIZE;64		rtl_fw_page_write(hw, page, (bufferptr + offset),65				  FW_8192D_PAGE_SIZE);66	}67 68	if (remainsize) {69		offset = pagenums * FW_8192D_PAGE_SIZE;70		page = pagenums;71		rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);72	}73}74EXPORT_SYMBOL_GPL(rtl92d_write_fw);75 76int rtl92d_fw_free_to_go(struct ieee80211_hw *hw)77{78	struct rtl_priv *rtlpriv = rtl_priv(hw);79	u32 counter = 0;80	u32 value32;81 82	do {83		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);84	} while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&85		 (!(value32 & FWDL_CHKSUM_RPT)));86 87	if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {88		pr_err("chksum report fail! REG_MCUFWDL:0x%08x\n",89		       value32);90		return -EIO;91	}92 93	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);94	value32 |= MCUFWDL_RDY;95	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);96 97	return 0;98}99EXPORT_SYMBOL_GPL(rtl92d_fw_free_to_go);100 101#define RTL_USB_DELAY_FACTOR		60102 103void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)104{105	struct rtl_priv *rtlpriv = rtl_priv(hw);106	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);107	u8 u1b_tmp;108	u8 delay = 100;109 110	if (rtlhal->interface == INTF_USB) {111		delay *= RTL_USB_DELAY_FACTOR;112 113		rtl_write_byte(rtlpriv, REG_FSIMR, 0);114 115		/* We need to disable other HRCV INT to influence 8051 reset. */116		rtl_write_byte(rtlpriv, REG_FWIMR, 0x20);117 118		/* Close mask to prevent incorrect FW write operation. */119		rtl_write_byte(rtlpriv, REG_FTIMR, 0);120	}121 122	/* Set (REG_HMETFR + 3) to  0x20 is reset 8051 */123	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);124 125	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);126 127	while (u1b_tmp & (FEN_CPUEN >> 8)) {128		delay--;129		if (delay == 0)130			break;131		udelay(50);132		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);133	}134 135	if (rtlhal->interface == INTF_USB) {136		if ((u1b_tmp & (FEN_CPUEN >> 8)) && delay == 0)137			rtl_write_byte(rtlpriv, REG_FWIMR, 0);138	}139 140	WARN_ONCE((delay <= 0), "rtl8192de: 8051 reset failed!\n");141	rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,142		"=====> 8051 reset success (%d)\n", delay);143}144EXPORT_SYMBOL_GPL(rtl92d_firmware_selfreset);145 146int rtl92d_fw_init(struct ieee80211_hw *hw)147{148	struct rtl_priv *rtlpriv = rtl_priv(hw);149	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));150	u32 counter;151 152	rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n");153	/* polling for FW ready */154	counter = 0;155	do {156		if (rtlhal->interfaceindex == 0) {157			if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &158			    MAC0_READY) {159				rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,160					"Polling FW ready success!! REG_MCUFWDL: 0x%x\n",161					rtl_read_byte(rtlpriv,162						      FW_MAC0_READY));163				return 0;164			}165			udelay(5);166		} else {167			if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &168			    MAC1_READY) {169				rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,170					"Polling FW ready success!! REG_MCUFWDL: 0x%x\n",171					rtl_read_byte(rtlpriv,172						      FW_MAC1_READY));173				return 0;174			}175			udelay(5);176		}177	} while (counter++ < POLLING_READY_TIMEOUT_COUNT);178 179	if (rtlhal->interfaceindex == 0) {180		rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,181			"Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",182			rtl_read_byte(rtlpriv, FW_MAC0_READY));183	} else {184		rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,185			"Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",186			rtl_read_byte(rtlpriv, FW_MAC1_READY));187	}188	rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,189		"Polling FW ready fail!! REG_MCUFWDL:0x%08x\n",190		rtl_read_dword(rtlpriv, REG_MCUFWDL));191	return -1;192}193EXPORT_SYMBOL_GPL(rtl92d_fw_init);194 195static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)196{197	struct rtl_priv *rtlpriv = rtl_priv(hw);198	u8 val_hmetfr;199	bool result = false;200 201	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);202	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)203		result = true;204	return result;205}206 207void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,208			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)209{210	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));211	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));212	struct rtl_priv *rtlpriv = rtl_priv(hw);213	u8 boxcontent[4], boxextcontent[2];214	u16 box_reg = 0, box_extreg = 0;215	u8 wait_writeh2c_limmit = 100;216	bool bwrite_success = false;217	u8 wait_h2c_limmit = 100;218	u32 h2c_waitcounter = 0;219	bool isfw_read = false;220	unsigned long flag;221	u8 u1b_tmp;222	u8 boxnum;223	u8 idx;224 225	if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {226		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,227			"Return as RF is off!!!\n");228		return;229	}230 231	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");232 233	while (true) {234		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);235		if (rtlhal->h2c_setinprogress) {236			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,237				"H2C set in progress! Wait to set..element_id(%d)\n",238				element_id);239 240			while (rtlhal->h2c_setinprogress) {241				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,242						       flag);243				h2c_waitcounter++;244				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,245					"Wait 100 us (%d times)...\n",246					h2c_waitcounter);247				udelay(100);248 249				if (h2c_waitcounter > 1000)250					return;251 252				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,253						  flag);254			}255			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);256		} else {257			rtlhal->h2c_setinprogress = true;258			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);259			break;260		}261	}262 263	while (!bwrite_success) {264		wait_writeh2c_limmit--;265		if (wait_writeh2c_limmit == 0) {266			pr_err("Write H2C fail because no trigger for FW INT!\n");267			break;268		}269 270		boxnum = rtlhal->last_hmeboxnum;271		if (boxnum > 3) {272			pr_err("boxnum %#x too big\n", boxnum);273			break;274		}275 276		box_reg = REG_HMEBOX_0 + boxnum * SIZE_OF_REG_HMEBOX;277		box_extreg = REG_HMEBOX_EXT_0 + boxnum * SIZE_OF_REG_HMEBOX_EXT;278 279		isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);280		while (!isfw_read) {281			wait_h2c_limmit--;282			if (wait_h2c_limmit == 0) {283				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,284					"Waiting too long for FW read clear HMEBox(%d)!\n",285					boxnum);286				break;287			}288 289			udelay(10);290 291			isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);292			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);293			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,294				"Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",295				boxnum, u1b_tmp);296		}297 298		if (!isfw_read) {299			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,300				"Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",301				boxnum);302			break;303		}304 305		memset(boxcontent, 0, sizeof(boxcontent));306		memset(boxextcontent, 0, sizeof(boxextcontent));307		boxcontent[0] = element_id;308 309		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,310			"Write element_id box_reg(%4x) = %2x\n",311			box_reg, element_id);312 313		switch (cmd_len) {314		case 1 ... 3:315			/* BOX:      | ID | A0 | A1 | A2 |316			 * BOX_EXT:  --- N/A ------317			 */318			boxcontent[0] &= ~BIT(7);319			memcpy(boxcontent + 1, cmdbuffer, cmd_len);320 321			for (idx = 0; idx < 4; idx++)322				rtl_write_byte(rtlpriv, box_reg + idx,323					       boxcontent[idx]);324			break;325		case 4 ... 5:326			/* * ID ext = ID | BIT(7)327			 * BOX:      | ID ext | A2 | A3 | A4 |328			 * BOX_EXT:  | A0     | A1 |329			 */330			boxcontent[0] |= BIT(7);331			memcpy(boxextcontent, cmdbuffer, 2);332			memcpy(boxcontent + 1, cmdbuffer + 2, cmd_len - 2);333 334			for (idx = 0; idx < 2; idx++)335				rtl_write_byte(rtlpriv, box_extreg + idx,336					       boxextcontent[idx]);337 338			for (idx = 0; idx < 4; idx++)339				rtl_write_byte(rtlpriv, box_reg + idx,340					       boxcontent[idx]);341			break;342		default:343			pr_err("switch case %#x not processed\n", cmd_len);344			break;345		}346 347		bwrite_success = true;348		rtlhal->last_hmeboxnum = boxnum + 1;349		if (rtlhal->last_hmeboxnum == 4)350			rtlhal->last_hmeboxnum = 0;351 352		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,353			"pHalData->last_hmeboxnum  = %d\n",354			rtlhal->last_hmeboxnum);355	}356	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);357	rtlhal->h2c_setinprogress = false;358	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);359	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");360}361EXPORT_SYMBOL_GPL(rtl92d_fill_h2c_cmd);362 363void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)364{365	u8 u1_joinbssrpt_parm[1] = {0};366 367	u1_joinbssrpt_parm[0] = mstatus;368	rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);369}370EXPORT_SYMBOL_GPL(rtl92d_set_fw_joinbss_report_cmd);371