162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2018-2019  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "main.h"
662306a36Sopenharmony_ci#include "mac.h"
762306a36Sopenharmony_ci#include "reg.h"
862306a36Sopenharmony_ci#include "fw.h"
962306a36Sopenharmony_ci#include "debug.h"
1062306a36Sopenharmony_ci#include "sdio.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_civoid rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
1362306a36Sopenharmony_ci			 u8 primary_ch_idx)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	u8 txsc40 = 0, txsc20 = 0;
1662306a36Sopenharmony_ci	u32 value32;
1762306a36Sopenharmony_ci	u8 value8;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	txsc20 = primary_ch_idx;
2062306a36Sopenharmony_ci	if (bw == RTW_CHANNEL_WIDTH_80) {
2162306a36Sopenharmony_ci		if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST)
2262306a36Sopenharmony_ci			txsc40 = RTW_SC_40_UPPER;
2362306a36Sopenharmony_ci		else
2462306a36Sopenharmony_ci			txsc40 = RTW_SC_40_LOWER;
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_DATA_SC,
2762306a36Sopenharmony_ci		   BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40));
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL);
3062306a36Sopenharmony_ci	value32 &= ~BIT_RFMOD;
3162306a36Sopenharmony_ci	switch (bw) {
3262306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_80:
3362306a36Sopenharmony_ci		value32 |= BIT_RFMOD_80M;
3462306a36Sopenharmony_ci		break;
3562306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_40:
3662306a36Sopenharmony_ci		value32 |= BIT_RFMOD_40M;
3762306a36Sopenharmony_ci		break;
3862306a36Sopenharmony_ci	case RTW_CHANNEL_WIDTH_20:
3962306a36Sopenharmony_ci	default:
4062306a36Sopenharmony_ci		break;
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
4562306a36Sopenharmony_ci		return;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL);
4862306a36Sopenharmony_ci	value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL);
4962306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_AFE_CTRL1, value32);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED);
5262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_CCK_CHECK);
5562306a36Sopenharmony_ci	value8 = value8 & ~BIT_CHECK_CCK_EN;
5662306a36Sopenharmony_ci	if (IS_CH_5G_BAND(channel))
5762306a36Sopenharmony_ci		value8 |= BIT_CHECK_CCK_EN;
5862306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CCK_CHECK, value8);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_set_channel_mac);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned int retry;
6562306a36Sopenharmony_ci	u32 value32;
6662306a36Sopenharmony_ci	u8 value8;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_RSV_CTRL, 0);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev)) {
7162306a36Sopenharmony_ci		if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO)
7262306a36Sopenharmony_ci			rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL);
7362306a36Sopenharmony_ci		else
7462306a36Sopenharmony_ci			rtw_write8(rtwdev, REG_LDO_SWR_CTRL, SPS_SEL);
7562306a36Sopenharmony_ci		return 0;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	switch (rtw_hci_type(rtwdev)) {
7962306a36Sopenharmony_ci	case RTW_HCI_TYPE_PCIE:
8062306a36Sopenharmony_ci		rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_USB_SUS_DIS);
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	case RTW_HCI_TYPE_SDIO:
8362306a36Sopenharmony_ci		rtw_write8_clr(rtwdev, REG_SDIO_HSUS_CTRL, BIT_HCI_SUS_REQ);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		for (retry = 0; retry < RTW_PWR_POLLING_CNT; retry++) {
8662306a36Sopenharmony_ci			if (rtw_read8(rtwdev, REG_SDIO_HSUS_CTRL) & BIT_HCI_RESUME_RDY)
8762306a36Sopenharmony_ci				break;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci			usleep_range(10, 50);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		if (retry == RTW_PWR_POLLING_CNT) {
9362306a36Sopenharmony_ci			rtw_err(rtwdev, "failed to poll REG_SDIO_HSUS_CTRL[1]");
9462306a36Sopenharmony_ci			return -ETIMEDOUT;
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		if (rtw_sdio_is_sdio30_supported(rtwdev))
9862306a36Sopenharmony_ci			rtw_write8_set(rtwdev, REG_HCI_OPT_CTRL + 2,
9962306a36Sopenharmony_ci				       BIT_SDIO_PAD_E5 >> 16);
10062306a36Sopenharmony_ci		else
10162306a36Sopenharmony_ci			rtw_write8_clr(rtwdev, REG_HCI_OPT_CTRL + 2,
10262306a36Sopenharmony_ci				       BIT_SDIO_PAD_E5 >> 16);
10362306a36Sopenharmony_ci		break;
10462306a36Sopenharmony_ci	case RTW_HCI_TYPE_USB:
10562306a36Sopenharmony_ci		break;
10662306a36Sopenharmony_ci	default:
10762306a36Sopenharmony_ci		return -EINVAL;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* config PIN Mux */
11162306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_PAD_CTRL1);
11262306a36Sopenharmony_ci	value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL;
11362306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_PAD_CTRL1, value32);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_LED_CFG);
11662306a36Sopenharmony_ci	value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN);
11762306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_LED_CFG, value32);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG);
12062306a36Sopenharmony_ci	value32 |= BIT_WLRFE_4_5_EN;
12162306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* disable BB/RF */
12462306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
12562306a36Sopenharmony_ci	value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST);
12662306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_RF_CTRL);
12962306a36Sopenharmony_ci	value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN);
13062306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_RF_CTRL, value8);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_WLRF1);
13362306a36Sopenharmony_ci	value32 &= ~BIT_WLRF1_BBRF_EN;
13462306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_WLRF1, value32);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic bool do_pwr_poll_cmd(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	u32 val;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	target &= mask;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return read_poll_timeout_atomic(rtw_read8, val, (val & mask) == target,
14662306a36Sopenharmony_ci					50, 50 * RTW_PWR_POLLING_CNT, false,
14762306a36Sopenharmony_ci					rtwdev, addr) == 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev,
15162306a36Sopenharmony_ci			       const struct rtw_pwr_seq_cmd *cmd)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	u8 value;
15462306a36Sopenharmony_ci	u32 offset;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (cmd->base == RTW_PWR_ADDR_SDIO)
15762306a36Sopenharmony_ci		offset = cmd->offset | SDIO_LOCAL_OFFSET;
15862306a36Sopenharmony_ci	else
15962306a36Sopenharmony_ci		offset = cmd->offset;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value))
16262306a36Sopenharmony_ci		return 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) != RTW_HCI_TYPE_PCIE)
16562306a36Sopenharmony_ci		goto err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* if PCIE, toggle BIT_PFM_WOWL and try again */
16862306a36Sopenharmony_ci	value = rtw_read8(rtwdev, REG_SYS_PW_CTRL);
16962306a36Sopenharmony_ci	if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D)
17062306a36Sopenharmony_ci		rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL);
17162306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL);
17262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_SYS_PW_CTRL, value & ~BIT_PFM_WOWL);
17362306a36Sopenharmony_ci	if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D)
17462306a36Sopenharmony_ci		rtw_write8(rtwdev, REG_SYS_PW_CTRL, value | BIT_PFM_WOWL);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (do_pwr_poll_cmd(rtwdev, offset, cmd->mask, cmd->value))
17762306a36Sopenharmony_ci		return 0;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cierr:
18062306a36Sopenharmony_ci	rtw_err(rtwdev, "failed to poll offset=0x%x mask=0x%x value=0x%x\n",
18162306a36Sopenharmony_ci		offset, cmd->mask, cmd->value);
18262306a36Sopenharmony_ci	return -EBUSY;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask,
18662306a36Sopenharmony_ci				  u8 cut_mask,
18762306a36Sopenharmony_ci				  const struct rtw_pwr_seq_cmd *cmd)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	const struct rtw_pwr_seq_cmd *cur_cmd;
19062306a36Sopenharmony_ci	u32 offset;
19162306a36Sopenharmony_ci	u8 value;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	for (cur_cmd = cmd; cur_cmd->cmd != RTW_PWR_CMD_END; cur_cmd++) {
19462306a36Sopenharmony_ci		if (!(cur_cmd->intf_mask & intf_mask) ||
19562306a36Sopenharmony_ci		    !(cur_cmd->cut_mask & cut_mask))
19662306a36Sopenharmony_ci			continue;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		switch (cur_cmd->cmd) {
19962306a36Sopenharmony_ci		case RTW_PWR_CMD_WRITE:
20062306a36Sopenharmony_ci			offset = cur_cmd->offset;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci			if (cur_cmd->base == RTW_PWR_ADDR_SDIO)
20362306a36Sopenharmony_ci				offset |= SDIO_LOCAL_OFFSET;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci			value = rtw_read8(rtwdev, offset);
20662306a36Sopenharmony_ci			value &= ~cur_cmd->mask;
20762306a36Sopenharmony_ci			value |= (cur_cmd->value & cur_cmd->mask);
20862306a36Sopenharmony_ci			rtw_write8(rtwdev, offset, value);
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		case RTW_PWR_CMD_POLLING:
21162306a36Sopenharmony_ci			if (rtw_pwr_cmd_polling(rtwdev, cur_cmd))
21262306a36Sopenharmony_ci				return -EBUSY;
21362306a36Sopenharmony_ci			break;
21462306a36Sopenharmony_ci		case RTW_PWR_CMD_DELAY:
21562306a36Sopenharmony_ci			if (cur_cmd->value == RTW_PWR_DELAY_US)
21662306a36Sopenharmony_ci				udelay(cur_cmd->offset);
21762306a36Sopenharmony_ci			else
21862306a36Sopenharmony_ci				mdelay(cur_cmd->offset);
21962306a36Sopenharmony_ci			break;
22062306a36Sopenharmony_ci		case RTW_PWR_CMD_READ:
22162306a36Sopenharmony_ci			break;
22262306a36Sopenharmony_ci		default:
22362306a36Sopenharmony_ci			return -EINVAL;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
23162306a36Sopenharmony_ci			      const struct rtw_pwr_seq_cmd **cmd_seq)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u8 cut_mask;
23462306a36Sopenharmony_ci	u8 intf_mask;
23562306a36Sopenharmony_ci	u8 cut;
23662306a36Sopenharmony_ci	u32 idx = 0;
23762306a36Sopenharmony_ci	const struct rtw_pwr_seq_cmd *cmd;
23862306a36Sopenharmony_ci	int ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	cut = rtwdev->hal.cut_version;
24162306a36Sopenharmony_ci	cut_mask = cut_version_to_mask(cut);
24262306a36Sopenharmony_ci	switch (rtw_hci_type(rtwdev)) {
24362306a36Sopenharmony_ci	case RTW_HCI_TYPE_PCIE:
24462306a36Sopenharmony_ci		intf_mask = RTW_PWR_INTF_PCI_MSK;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	case RTW_HCI_TYPE_USB:
24762306a36Sopenharmony_ci		intf_mask = RTW_PWR_INTF_USB_MSK;
24862306a36Sopenharmony_ci		break;
24962306a36Sopenharmony_ci	case RTW_HCI_TYPE_SDIO:
25062306a36Sopenharmony_ci		intf_mask = RTW_PWR_INTF_SDIO_MSK;
25162306a36Sopenharmony_ci		break;
25262306a36Sopenharmony_ci	default:
25362306a36Sopenharmony_ci		return -EINVAL;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	do {
25762306a36Sopenharmony_ci		cmd = cmd_seq[idx];
25862306a36Sopenharmony_ci		if (!cmd)
25962306a36Sopenharmony_ci			break;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd);
26262306a36Sopenharmony_ci		if (ret)
26362306a36Sopenharmony_ci			return ret;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		idx++;
26662306a36Sopenharmony_ci	} while (1);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return 0;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
27462306a36Sopenharmony_ci	const struct rtw_pwr_seq_cmd **pwr_seq;
27562306a36Sopenharmony_ci	u32 imr = 0;
27662306a36Sopenharmony_ci	u8 rpwm;
27762306a36Sopenharmony_ci	bool cur_pwr;
27862306a36Sopenharmony_ci	int ret;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev)) {
28162306a36Sopenharmony_ci		rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* Check FW still exist or not */
28462306a36Sopenharmony_ci		if (rtw_read16(rtwdev, REG_MCUFW_CTRL) == 0xC078) {
28562306a36Sopenharmony_ci			rpwm = (rpwm ^ BIT_RPWM_TOGGLE) & BIT_RPWM_TOGGLE;
28662306a36Sopenharmony_ci			rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, rpwm);
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (rtw_read8(rtwdev, REG_CR) == 0xea)
29162306a36Sopenharmony_ci		cur_pwr = false;
29262306a36Sopenharmony_ci	else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB &&
29362306a36Sopenharmony_ci		 (rtw_read8(rtwdev, REG_SYS_STATUS1 + 1) & BIT(0)))
29462306a36Sopenharmony_ci		cur_pwr = false;
29562306a36Sopenharmony_ci	else
29662306a36Sopenharmony_ci		cur_pwr = true;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (pwr_on == cur_pwr)
29962306a36Sopenharmony_ci		return -EALREADY;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) {
30262306a36Sopenharmony_ci		imr = rtw_read32(rtwdev, REG_SDIO_HIMR);
30362306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_SDIO_HIMR, 0);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (!pwr_on)
30762306a36Sopenharmony_ci		clear_bit(RTW_FLAG_POWERON, rtwdev->flags);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq;
31062306a36Sopenharmony_ci	ret = rtw_pwr_seq_parser(rtwdev, pwr_seq);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO)
31362306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_SDIO_HIMR, imr);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (!ret && pwr_on)
31662306a36Sopenharmony_ci		set_bit(RTW_FLAG_POWERON, rtwdev->flags);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return ret;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	u8 sys_func_en = rtwdev->chip->sys_func_en;
32462306a36Sopenharmony_ci	u8 value8;
32562306a36Sopenharmony_ci	u32 value, tmp;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	value = rtw_read32(rtwdev, REG_CPU_DMEM_CON);
32862306a36Sopenharmony_ci	value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN;
32962306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_CPU_DMEM_CON, value);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en);
33262306a36Sopenharmony_ci	value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C;
33362306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR_EXT + 3, value8);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* disable boot-from-flash for driver's DL FW */
33662306a36Sopenharmony_ci	tmp = rtw_read32(rtwdev, REG_MCUFW_CTRL);
33762306a36Sopenharmony_ci	if (tmp & BIT_BOOT_FSPI_EN) {
33862306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_MCUFW_CTRL, tmp & (~BIT_BOOT_FSPI_EN));
33962306a36Sopenharmony_ci		value = rtw_read32(rtwdev, REG_GPIO_MUXCFG) & (~BIT_FSPI_EN);
34062306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_GPIO_MUXCFG, value);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return 0;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR, 0xff);
34962306a36Sopenharmony_ci	mdelay(2);
35062306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0x7f);
35162306a36Sopenharmony_ci	mdelay(2);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_SYS_CLKR, BIT_WAKEPAD_EN);
35462306a36Sopenharmony_ci	rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_CR, 0x2ff);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
36462306a36Sopenharmony_ci		return __rtw_mac_init_system_cfg_legacy(rtwdev);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return __rtw_mac_init_system_cfg(rtwdev);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciint rtw_mac_power_on(struct rtw_dev *rtwdev)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	int ret = 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ret = rtw_mac_pre_system_cfg(rtwdev);
37462306a36Sopenharmony_ci	if (ret)
37562306a36Sopenharmony_ci		goto err;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	ret = rtw_mac_power_switch(rtwdev, true);
37862306a36Sopenharmony_ci	if (ret == -EALREADY) {
37962306a36Sopenharmony_ci		rtw_mac_power_switch(rtwdev, false);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		ret = rtw_mac_pre_system_cfg(rtwdev);
38262306a36Sopenharmony_ci		if (ret)
38362306a36Sopenharmony_ci			goto err;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		ret = rtw_mac_power_switch(rtwdev, true);
38662306a36Sopenharmony_ci		if (ret)
38762306a36Sopenharmony_ci			goto err;
38862306a36Sopenharmony_ci	} else if (ret) {
38962306a36Sopenharmony_ci		goto err;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	ret = rtw_mac_init_system_cfg(rtwdev);
39362306a36Sopenharmony_ci	if (ret)
39462306a36Sopenharmony_ci		goto err;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return 0;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cierr:
39962306a36Sopenharmony_ci	rtw_err(rtwdev, "mac power on failed");
40062306a36Sopenharmony_ci	return ret;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_civoid rtw_mac_power_off(struct rtw_dev *rtwdev)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	rtw_mac_power_switch(rtwdev, false);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic bool check_firmware_size(const u8 *data, u32 size)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data;
41162306a36Sopenharmony_ci	u32 dmem_size;
41262306a36Sopenharmony_ci	u32 imem_size;
41362306a36Sopenharmony_ci	u32 emem_size;
41462306a36Sopenharmony_ci	u32 real_size;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	dmem_size = le32_to_cpu(fw_hdr->dmem_size);
41762306a36Sopenharmony_ci	imem_size = le32_to_cpu(fw_hdr->imem_size);
41862306a36Sopenharmony_ci	emem_size = (fw_hdr->mem_usage & BIT(4)) ?
41962306a36Sopenharmony_ci		    le32_to_cpu(fw_hdr->emem_size) : 0;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	dmem_size += FW_HDR_CHKSUM_SIZE;
42262306a36Sopenharmony_ci	imem_size += FW_HDR_CHKSUM_SIZE;
42362306a36Sopenharmony_ci	emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0;
42462306a36Sopenharmony_ci	real_size = FW_HDR_SIZE + dmem_size + imem_size + emem_size;
42562306a36Sopenharmony_ci	if (real_size != size)
42662306a36Sopenharmony_ci		return false;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return true;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void wlan_cpu_enable(struct rtw_dev *rtwdev, bool enable)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	if (enable) {
43462306a36Sopenharmony_ci		/* cpu io interface enable */
43562306a36Sopenharmony_ci		rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		/* cpu enable */
43862306a36Sopenharmony_ci		rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
43962306a36Sopenharmony_ci	} else {
44062306a36Sopenharmony_ci		/* cpu io interface disable */
44162306a36Sopenharmony_ci		rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		/* cpu disable */
44462306a36Sopenharmony_ci		rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT_WLMCU_IOIF);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci#define DLFW_RESTORE_REG_NUM 6
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void download_firmware_reg_backup(struct rtw_dev *rtwdev,
45162306a36Sopenharmony_ci					 struct rtw_backup_info *bckp)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	u8 tmp;
45462306a36Sopenharmony_ci	u8 bckp_idx = 0;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* set HIQ to hi priority */
45762306a36Sopenharmony_ci	bckp[bckp_idx].len = 1;
45862306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_TXDMA_PQ_MAP + 1;
45962306a36Sopenharmony_ci	bckp[bckp_idx].val = rtw_read8(rtwdev, REG_TXDMA_PQ_MAP + 1);
46062306a36Sopenharmony_ci	bckp_idx++;
46162306a36Sopenharmony_ci	tmp = RTW_DMA_MAPPING_HIGH << 6;
46262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_TXDMA_PQ_MAP + 1, tmp);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* DLFW only use HIQ, map HIQ to hi priority */
46562306a36Sopenharmony_ci	bckp[bckp_idx].len = 1;
46662306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_CR;
46762306a36Sopenharmony_ci	bckp[bckp_idx].val = rtw_read8(rtwdev, REG_CR);
46862306a36Sopenharmony_ci	bckp_idx++;
46962306a36Sopenharmony_ci	bckp[bckp_idx].len = 4;
47062306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_H2CQ_CSR;
47162306a36Sopenharmony_ci	bckp[bckp_idx].val = BIT_H2CQ_FULL;
47262306a36Sopenharmony_ci	bckp_idx++;
47362306a36Sopenharmony_ci	tmp = BIT_HCI_TXDMA_EN | BIT_TXDMA_EN;
47462306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR, tmp);
47562306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Config hi priority queue and public priority queue page number */
47862306a36Sopenharmony_ci	bckp[bckp_idx].len = 2;
47962306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_FIFOPAGE_INFO_1;
48062306a36Sopenharmony_ci	bckp[bckp_idx].val = rtw_read16(rtwdev, REG_FIFOPAGE_INFO_1);
48162306a36Sopenharmony_ci	bckp_idx++;
48262306a36Sopenharmony_ci	bckp[bckp_idx].len = 4;
48362306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_RQPN_CTRL_2;
48462306a36Sopenharmony_ci	bckp[bckp_idx].val = rtw_read32(rtwdev, REG_RQPN_CTRL_2) | BIT_LD_RQPN;
48562306a36Sopenharmony_ci	bckp_idx++;
48662306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200);
48762306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO)
49062306a36Sopenharmony_ci		rtw_read32(rtwdev, REG_SDIO_FREE_TXPG);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Disable beacon related functions */
49362306a36Sopenharmony_ci	tmp = rtw_read8(rtwdev, REG_BCN_CTRL);
49462306a36Sopenharmony_ci	bckp[bckp_idx].len = 1;
49562306a36Sopenharmony_ci	bckp[bckp_idx].reg = REG_BCN_CTRL;
49662306a36Sopenharmony_ci	bckp[bckp_idx].val = tmp;
49762306a36Sopenharmony_ci	bckp_idx++;
49862306a36Sopenharmony_ci	tmp = (u8)((tmp & (~BIT_EN_BCN_FUNCTION)) | BIT_DIS_TSF_UDT);
49962306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_BCN_CTRL, tmp);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	WARN(bckp_idx != DLFW_RESTORE_REG_NUM, "wrong backup number\n");
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic void download_firmware_reset_platform(struct rtw_dev *rtwdev)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	rtw_write8_clr(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16);
50762306a36Sopenharmony_ci	rtw_write8_clr(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8);
50862306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_CPU_DMEM_CON + 2, BIT_WL_PLATFORM_RST >> 16);
50962306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_SYS_CLK_CTRL + 1, BIT_CPU_CLK_EN >> 8);
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic void download_firmware_reg_restore(struct rtw_dev *rtwdev,
51362306a36Sopenharmony_ci					  struct rtw_backup_info *bckp,
51462306a36Sopenharmony_ci					  u8 bckp_num)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	rtw_restore_reg(rtwdev, bckp, bckp_num);
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci#define TX_DESC_SIZE 48
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int send_firmware_pkt_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
52262306a36Sopenharmony_ci				       const u8 *data, u32 size)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	u8 *buf;
52562306a36Sopenharmony_ci	int ret;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	buf = kmemdup(data, size, GFP_KERNEL);
52862306a36Sopenharmony_ci	if (!buf)
52962306a36Sopenharmony_ci		return -ENOMEM;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ret = rtw_fw_write_data_rsvd_page(rtwdev, pg_addr, buf, size);
53262306a36Sopenharmony_ci	kfree(buf);
53362306a36Sopenharmony_ci	return ret;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic int
53762306a36Sopenharmony_cisend_firmware_pkt(struct rtw_dev *rtwdev, u16 pg_addr, const u8 *data, u32 size)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	int ret;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB &&
54262306a36Sopenharmony_ci	    !((size + TX_DESC_SIZE) & (512 - 1)))
54362306a36Sopenharmony_ci		size += 1;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	ret = send_firmware_pkt_rsvd_page(rtwdev, pg_addr, data, size);
54662306a36Sopenharmony_ci	if (ret)
54762306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to download rsvd page\n");
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return ret;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int
55362306a36Sopenharmony_ciiddma_enable(struct rtw_dev *rtwdev, u32 src, u32 dst, u32 ctrl)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_DDMA_CH0SA, src);
55662306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_DDMA_CH0DA, dst);
55762306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_DDMA_CH0CTRL, ctrl);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0))
56062306a36Sopenharmony_ci		return -EBUSY;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return 0;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic int iddma_download_firmware(struct rtw_dev *rtwdev, u32 src, u32 dst,
56662306a36Sopenharmony_ci				   u32 len, u8 first)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	u32 ch0_ctrl = BIT_DDMACH0_CHKSUM_EN | BIT_DDMACH0_OWN;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0))
57162306a36Sopenharmony_ci		return -EBUSY;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	ch0_ctrl |= len & BIT_MASK_DDMACH0_DLEN;
57462306a36Sopenharmony_ci	if (!first)
57562306a36Sopenharmony_ci		ch0_ctrl |= BIT_DDMACH0_CHKSUM_CONT;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (iddma_enable(rtwdev, src, dst, ch0_ctrl))
57862306a36Sopenharmony_ci		return -EBUSY;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ciint rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	u32 ch0_ctrl = BIT_DDMACH0_OWN | BIT_DDMACH0_DDMA_MODE;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_DDMA_CH0CTRL, BIT_DDMACH0_OWN, 0)) {
58862306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_FW, "busy to start ddma\n");
58962306a36Sopenharmony_ci		return -EBUSY;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	ch0_ctrl |= size & BIT_MASK_DDMACH0_DLEN;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (iddma_enable(rtwdev, ocp_src, OCPBASE_RXBUF_FW_88XX, ch0_ctrl)) {
59562306a36Sopenharmony_ci		rtw_dbg(rtwdev, RTW_DBG_FW, "busy to complete ddma\n");
59662306a36Sopenharmony_ci		return -EBUSY;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic bool
60362306a36Sopenharmony_cicheck_fw_checksum(struct rtw_dev *rtwdev, u32 addr)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	u8 fw_ctrl;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	fw_ctrl = rtw_read8(rtwdev, REG_MCUFW_CTRL);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (rtw_read32(rtwdev, REG_DDMA_CH0CTRL) & BIT_DDMACH0_CHKSUM_STS) {
61062306a36Sopenharmony_ci		if (addr < OCPBASE_DMEM_88XX) {
61162306a36Sopenharmony_ci			fw_ctrl |= BIT_IMEM_DW_OK;
61262306a36Sopenharmony_ci			fw_ctrl &= ~BIT_IMEM_CHKSUM_OK;
61362306a36Sopenharmony_ci			rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
61462306a36Sopenharmony_ci		} else {
61562306a36Sopenharmony_ci			fw_ctrl |= BIT_DMEM_DW_OK;
61662306a36Sopenharmony_ci			fw_ctrl &= ~BIT_DMEM_CHKSUM_OK;
61762306a36Sopenharmony_ci			rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		rtw_err(rtwdev, "invalid fw checksum\n");
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		return false;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (addr < OCPBASE_DMEM_88XX) {
62662306a36Sopenharmony_ci		fw_ctrl |= (BIT_IMEM_DW_OK | BIT_IMEM_CHKSUM_OK);
62762306a36Sopenharmony_ci		rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
62862306a36Sopenharmony_ci	} else {
62962306a36Sopenharmony_ci		fw_ctrl |= (BIT_DMEM_DW_OK | BIT_DMEM_CHKSUM_OK);
63062306a36Sopenharmony_ci		rtw_write8(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return true;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int
63762306a36Sopenharmony_cidownload_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data,
63862306a36Sopenharmony_ci			 u32 src, u32 dst, u32 size)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
64162306a36Sopenharmony_ci	u32 desc_size = chip->tx_pkt_desc_sz;
64262306a36Sopenharmony_ci	u8 first_part;
64362306a36Sopenharmony_ci	u32 mem_offset;
64462306a36Sopenharmony_ci	u32 residue_size;
64562306a36Sopenharmony_ci	u32 pkt_size;
64662306a36Sopenharmony_ci	u32 max_size = 0x1000;
64762306a36Sopenharmony_ci	u32 val;
64862306a36Sopenharmony_ci	int ret;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	mem_offset = 0;
65162306a36Sopenharmony_ci	first_part = 1;
65262306a36Sopenharmony_ci	residue_size = size;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	val = rtw_read32(rtwdev, REG_DDMA_CH0CTRL);
65562306a36Sopenharmony_ci	val |= BIT_DDMACH0_RESET_CHKSUM_STS;
65662306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_DDMA_CH0CTRL, val);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	while (residue_size) {
65962306a36Sopenharmony_ci		if (residue_size >= max_size)
66062306a36Sopenharmony_ci			pkt_size = max_size;
66162306a36Sopenharmony_ci		else
66262306a36Sopenharmony_ci			pkt_size = residue_size;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		ret = send_firmware_pkt(rtwdev, (u16)(src >> 7),
66562306a36Sopenharmony_ci					data + mem_offset, pkt_size);
66662306a36Sopenharmony_ci		if (ret)
66762306a36Sopenharmony_ci			return ret;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		ret = iddma_download_firmware(rtwdev, OCPBASE_TXBUF_88XX +
67062306a36Sopenharmony_ci					      src + desc_size,
67162306a36Sopenharmony_ci					      dst + mem_offset, pkt_size,
67262306a36Sopenharmony_ci					      first_part);
67362306a36Sopenharmony_ci		if (ret)
67462306a36Sopenharmony_ci			return ret;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		first_part = 0;
67762306a36Sopenharmony_ci		mem_offset += pkt_size;
67862306a36Sopenharmony_ci		residue_size -= pkt_size;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (!check_fw_checksum(rtwdev, dst))
68262306a36Sopenharmony_ci		return -EINVAL;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic int
68862306a36Sopenharmony_cistart_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data;
69162306a36Sopenharmony_ci	const u8 *cur_fw;
69262306a36Sopenharmony_ci	u16 val;
69362306a36Sopenharmony_ci	u32 imem_size;
69462306a36Sopenharmony_ci	u32 dmem_size;
69562306a36Sopenharmony_ci	u32 emem_size;
69662306a36Sopenharmony_ci	u32 addr;
69762306a36Sopenharmony_ci	int ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	dmem_size = le32_to_cpu(fw_hdr->dmem_size);
70062306a36Sopenharmony_ci	imem_size = le32_to_cpu(fw_hdr->imem_size);
70162306a36Sopenharmony_ci	emem_size = (fw_hdr->mem_usage & BIT(4)) ?
70262306a36Sopenharmony_ci		    le32_to_cpu(fw_hdr->emem_size) : 0;
70362306a36Sopenharmony_ci	dmem_size += FW_HDR_CHKSUM_SIZE;
70462306a36Sopenharmony_ci	imem_size += FW_HDR_CHKSUM_SIZE;
70562306a36Sopenharmony_ci	emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	val = (u16)(rtw_read16(rtwdev, REG_MCUFW_CTRL) & 0x3800);
70862306a36Sopenharmony_ci	val |= BIT_MCUFWDL_EN;
70962306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_MCUFW_CTRL, val);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	cur_fw = data + FW_HDR_SIZE;
71262306a36Sopenharmony_ci	addr = le32_to_cpu(fw_hdr->dmem_addr);
71362306a36Sopenharmony_ci	addr &= ~BIT(31);
71462306a36Sopenharmony_ci	ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size);
71562306a36Sopenharmony_ci	if (ret)
71662306a36Sopenharmony_ci		return ret;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	cur_fw = data + FW_HDR_SIZE + dmem_size;
71962306a36Sopenharmony_ci	addr = le32_to_cpu(fw_hdr->imem_addr);
72062306a36Sopenharmony_ci	addr &= ~BIT(31);
72162306a36Sopenharmony_ci	ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size);
72262306a36Sopenharmony_ci	if (ret)
72362306a36Sopenharmony_ci		return ret;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (emem_size) {
72662306a36Sopenharmony_ci		cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size;
72762306a36Sopenharmony_ci		addr = le32_to_cpu(fw_hdr->emem_addr);
72862306a36Sopenharmony_ci		addr &= ~BIT(31);
72962306a36Sopenharmony_ci		ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr,
73062306a36Sopenharmony_ci					       emem_size);
73162306a36Sopenharmony_ci		if (ret)
73262306a36Sopenharmony_ci			return ret;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic int download_firmware_validate(struct rtw_dev *rtwdev)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	u32 fw_key;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, FW_READY_MASK, FW_READY)) {
74362306a36Sopenharmony_ci		fw_key = rtw_read32(rtwdev, REG_FW_DBG7) & FW_KEY_MASK;
74462306a36Sopenharmony_ci		if (fw_key == ILLEGAL_KEY_GROUP)
74562306a36Sopenharmony_ci			rtw_err(rtwdev, "invalid fw key\n");
74662306a36Sopenharmony_ci		return -EINVAL;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return 0;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic void download_firmware_end_flow(struct rtw_dev *rtwdev)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	u16 fw_ctrl;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_TXDMA_STATUS, BTI_PAGE_OVF);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Check IMEM & DMEM checksum is OK or not */
75962306a36Sopenharmony_ci	fw_ctrl = rtw_read16(rtwdev, REG_MCUFW_CTRL);
76062306a36Sopenharmony_ci	if ((fw_ctrl & BIT_CHECK_SUM_OK) != BIT_CHECK_SUM_OK)
76162306a36Sopenharmony_ci		return;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	fw_ctrl = (fw_ctrl | BIT_FW_DW_RDY) & ~BIT_MCUFWDL_EN;
76462306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_MCUFW_CTRL, fw_ctrl);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int __rtw_download_firmware(struct rtw_dev *rtwdev,
76862306a36Sopenharmony_ci				   struct rtw_fw_state *fw)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct rtw_backup_info bckp[DLFW_RESTORE_REG_NUM];
77162306a36Sopenharmony_ci	const u8 *data = fw->firmware->data;
77262306a36Sopenharmony_ci	u32 size = fw->firmware->size;
77362306a36Sopenharmony_ci	u32 ltecoex_bckp;
77462306a36Sopenharmony_ci	int ret;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (!check_firmware_size(data, size))
77762306a36Sopenharmony_ci		return -EINVAL;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (!ltecoex_read_reg(rtwdev, 0x38, &ltecoex_bckp))
78062306a36Sopenharmony_ci		return -EBUSY;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	wlan_cpu_enable(rtwdev, false);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	download_firmware_reg_backup(rtwdev, bckp);
78562306a36Sopenharmony_ci	download_firmware_reset_platform(rtwdev);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	ret = start_download_firmware(rtwdev, data, size);
78862306a36Sopenharmony_ci	if (ret)
78962306a36Sopenharmony_ci		goto dlfw_fail;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	download_firmware_reg_restore(rtwdev, bckp, DLFW_RESTORE_REG_NUM);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	download_firmware_end_flow(rtwdev);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	wlan_cpu_enable(rtwdev, true);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) {
79862306a36Sopenharmony_ci		ret = -EBUSY;
79962306a36Sopenharmony_ci		goto dlfw_fail;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ret = download_firmware_validate(rtwdev);
80362306a36Sopenharmony_ci	if (ret)
80462306a36Sopenharmony_ci		goto dlfw_fail;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	/* reset desc and index */
80762306a36Sopenharmony_ci	rtw_hci_setup(rtwdev);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	rtwdev->h2c.last_box_num = 0;
81062306a36Sopenharmony_ci	rtwdev->h2c.seq = 0;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return 0;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cidlfw_fail:
81762306a36Sopenharmony_ci	/* Disable FWDL_EN */
81862306a36Sopenharmony_ci	rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
81962306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT_FEN_CPUEN);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return ret;
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	int try;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	if (en) {
82962306a36Sopenharmony_ci		wlan_cpu_enable(rtwdev, false);
83062306a36Sopenharmony_ci		wlan_cpu_enable(rtwdev, true);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		for (try = 0; try < 10; try++) {
83562306a36Sopenharmony_ci			if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_MCUFWDL_EN)
83662306a36Sopenharmony_ci				goto fwdl_ready;
83762306a36Sopenharmony_ci			rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
83862306a36Sopenharmony_ci			msleep(20);
83962306a36Sopenharmony_ci		}
84062306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to check fw download ready\n");
84162306a36Sopenharmony_cifwdl_ready:
84262306a36Sopenharmony_ci		rtw_write32_clr(rtwdev, REG_MCUFW_CTRL, BIT_ROM_DLEN);
84362306a36Sopenharmony_ci	} else {
84462306a36Sopenharmony_ci		rtw_write8_clr(rtwdev, REG_MCUFW_CTRL, BIT_MCUFWDL_EN);
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic void
84962306a36Sopenharmony_ciwrite_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	u32 val32;
85262306a36Sopenharmony_ci	u32 block_nr;
85362306a36Sopenharmony_ci	u32 remain_size;
85462306a36Sopenharmony_ci	u32 write_addr = FW_START_ADDR_LEGACY;
85562306a36Sopenharmony_ci	const __le32 *ptr = (const __le32 *)data;
85662306a36Sopenharmony_ci	u32 block;
85762306a36Sopenharmony_ci	__le32 remain_data = 0;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	block_nr = size >> DLFW_BLK_SIZE_SHIFT_LEGACY;
86062306a36Sopenharmony_ci	remain_size = size & (DLFW_BLK_SIZE_LEGACY - 1);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
86362306a36Sopenharmony_ci	val32 &= ~BIT_ROM_PGE;
86462306a36Sopenharmony_ci	val32 |= (page << BIT_SHIFT_ROM_PGE) & BIT_ROM_PGE;
86562306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_MCUFW_CTRL, val32);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	for (block = 0; block < block_nr; block++) {
86862306a36Sopenharmony_ci		rtw_write32(rtwdev, write_addr, le32_to_cpu(*ptr));
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		write_addr += DLFW_BLK_SIZE_LEGACY;
87162306a36Sopenharmony_ci		ptr++;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (remain_size) {
87562306a36Sopenharmony_ci		memcpy(&remain_data, ptr, remain_size);
87662306a36Sopenharmony_ci		rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data));
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int
88162306a36Sopenharmony_cidownload_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	u32 page;
88462306a36Sopenharmony_ci	u32 total_page;
88562306a36Sopenharmony_ci	u32 last_page_size;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	data += sizeof(struct rtw_fw_hdr_legacy);
88862306a36Sopenharmony_ci	size -= sizeof(struct rtw_fw_hdr_legacy);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	total_page = size >> DLFW_PAGE_SIZE_SHIFT_LEGACY;
89162306a36Sopenharmony_ci	last_page_size = size & (DLFW_PAGE_SIZE_LEGACY - 1);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	for (page = 0; page < total_page; page++) {
89662306a36Sopenharmony_ci		write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY);
89762306a36Sopenharmony_ci		data += DLFW_PAGE_SIZE_LEGACY;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci	if (last_page_size)
90062306a36Sopenharmony_ci		write_firmware_page(rtwdev, page, data, last_page_size);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) {
90362306a36Sopenharmony_ci		rtw_err(rtwdev, "failed to check download firmware report\n");
90462306a36Sopenharmony_ci		return -EINVAL;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return 0;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic int download_firmware_validate_legacy(struct rtw_dev *rtwdev)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	u32 val32;
91362306a36Sopenharmony_ci	int try;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
91662306a36Sopenharmony_ci	val32 |= BIT_MCUFWDL_RDY;
91762306a36Sopenharmony_ci	val32 &= ~BIT_WINTINI_RDY;
91862306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_MCUFW_CTRL, val32);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	wlan_cpu_enable(rtwdev, false);
92162306a36Sopenharmony_ci	wlan_cpu_enable(rtwdev, true);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	for (try = 0; try < 10; try++) {
92462306a36Sopenharmony_ci		val32 = rtw_read32(rtwdev, REG_MCUFW_CTRL);
92562306a36Sopenharmony_ci		if ((val32 & FW_READY_LEGACY) == FW_READY_LEGACY)
92662306a36Sopenharmony_ci			return 0;
92762306a36Sopenharmony_ci		msleep(20);
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	rtw_err(rtwdev, "failed to validate firmware\n");
93162306a36Sopenharmony_ci	return -EINVAL;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev,
93562306a36Sopenharmony_ci					  struct rtw_fw_state *fw)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	int ret = 0;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	en_download_firmware_legacy(rtwdev, true);
94062306a36Sopenharmony_ci	ret = download_firmware_legacy(rtwdev, fw->firmware->data, fw->firmware->size);
94162306a36Sopenharmony_ci	en_download_firmware_legacy(rtwdev, false);
94262306a36Sopenharmony_ci	if (ret)
94362306a36Sopenharmony_ci		goto out;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	ret = download_firmware_validate_legacy(rtwdev);
94662306a36Sopenharmony_ci	if (ret)
94762306a36Sopenharmony_ci		goto out;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* reset desc and index */
95062306a36Sopenharmony_ci	rtw_hci_setup(rtwdev);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	rtwdev->h2c.last_box_num = 0;
95362306a36Sopenharmony_ci	rtwdev->h2c.seq = 0;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ciout:
95862306a36Sopenharmony_ci	return ret;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic
96262306a36Sopenharmony_ciint _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
96562306a36Sopenharmony_ci		return __rtw_download_firmware_legacy(rtwdev, fw);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	return __rtw_download_firmware(rtwdev, fw);
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ciint rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	int ret;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	ret = _rtw_download_firmware(rtwdev, fw);
97562306a36Sopenharmony_ci	if (ret)
97662306a36Sopenharmony_ci		return ret;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE &&
97962306a36Sopenharmony_ci	    rtwdev->chip->id == RTW_CHIP_TYPE_8821C)
98062306a36Sopenharmony_ci		rtw_fw_set_recover_bt_device(rtwdev);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	return 0;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn;
98862306a36Sopenharmony_ci	u32 prio_queues = 0;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (queues & BIT(IEEE80211_AC_VO))
99162306a36Sopenharmony_ci		prio_queues |= BIT(rqpn->dma_map_vo);
99262306a36Sopenharmony_ci	if (queues & BIT(IEEE80211_AC_VI))
99362306a36Sopenharmony_ci		prio_queues |= BIT(rqpn->dma_map_vi);
99462306a36Sopenharmony_ci	if (queues & BIT(IEEE80211_AC_BE))
99562306a36Sopenharmony_ci		prio_queues |= BIT(rqpn->dma_map_be);
99662306a36Sopenharmony_ci	if (queues & BIT(IEEE80211_AC_BK))
99762306a36Sopenharmony_ci		prio_queues |= BIT(rqpn->dma_map_bk);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	return prio_queues;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev,
100362306a36Sopenharmony_ci				       u32 prio_queue, bool drop)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
100662306a36Sopenharmony_ci	const struct rtw_prioq_addr *addr;
100762306a36Sopenharmony_ci	bool wsize;
100862306a36Sopenharmony_ci	u16 avail_page, rsvd_page;
100962306a36Sopenharmony_ci	int i;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (prio_queue >= RTW_DMA_MAPPING_MAX)
101262306a36Sopenharmony_ci		return;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	addr = &chip->prioq_addrs->prio[prio_queue];
101562306a36Sopenharmony_ci	wsize = chip->prioq_addrs->wsize;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* check if all of the reserved pages are available for 100 msecs */
101862306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
101962306a36Sopenharmony_ci		rsvd_page = wsize ? rtw_read16(rtwdev, addr->rsvd) :
102062306a36Sopenharmony_ci				     rtw_read8(rtwdev, addr->rsvd);
102162306a36Sopenharmony_ci		avail_page = wsize ? rtw_read16(rtwdev, addr->avail) :
102262306a36Sopenharmony_ci				      rtw_read8(rtwdev, addr->avail);
102362306a36Sopenharmony_ci		if (rsvd_page == avail_page)
102462306a36Sopenharmony_ci			return;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		msleep(20);
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	/* priority queue is still not empty, throw a warning,
103062306a36Sopenharmony_ci	 *
103162306a36Sopenharmony_ci	 * Note that if we want to flush the tx queue when having a lot of
103262306a36Sopenharmony_ci	 * traffic (ex, 100Mbps up), some of the packets could be dropped.
103362306a36Sopenharmony_ci	 * And it requires like ~2secs to flush the full priority queue.
103462306a36Sopenharmony_ci	 */
103562306a36Sopenharmony_ci	if (!drop)
103662306a36Sopenharmony_ci		rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev,
104062306a36Sopenharmony_ci				      u32 prio_queues, bool drop)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	u32 q;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	for (q = 0; q < RTW_DMA_MAPPING_MAX; q++)
104562306a36Sopenharmony_ci		if (prio_queues & BIT(q))
104662306a36Sopenharmony_ci			__rtw_mac_flush_prio_queue(rtwdev, q, drop);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_civoid rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	u32 prio_queues = 0;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* If all of the hardware queues are requested to flush,
105462306a36Sopenharmony_ci	 * or the priority queues are not mapped yet,
105562306a36Sopenharmony_ci	 * flush all of the priority queues
105662306a36Sopenharmony_ci	 */
105762306a36Sopenharmony_ci	if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn)
105862306a36Sopenharmony_ci		prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1;
105962306a36Sopenharmony_ci	else
106062306a36Sopenharmony_ci		prio_queues = get_priority_queues(rtwdev, queues);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic int txdma_queue_mapping(struct rtw_dev *rtwdev)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
106862306a36Sopenharmony_ci	const struct rtw_rqpn *rqpn = NULL;
106962306a36Sopenharmony_ci	u16 txdma_pq_map = 0;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	switch (rtw_hci_type(rtwdev)) {
107262306a36Sopenharmony_ci	case RTW_HCI_TYPE_PCIE:
107362306a36Sopenharmony_ci		rqpn = &chip->rqpn_table[1];
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci	case RTW_HCI_TYPE_USB:
107662306a36Sopenharmony_ci		if (rtwdev->hci.bulkout_num == 2)
107762306a36Sopenharmony_ci			rqpn = &chip->rqpn_table[2];
107862306a36Sopenharmony_ci		else if (rtwdev->hci.bulkout_num == 3)
107962306a36Sopenharmony_ci			rqpn = &chip->rqpn_table[3];
108062306a36Sopenharmony_ci		else if (rtwdev->hci.bulkout_num == 4)
108162306a36Sopenharmony_ci			rqpn = &chip->rqpn_table[4];
108262306a36Sopenharmony_ci		else
108362306a36Sopenharmony_ci			return -EINVAL;
108462306a36Sopenharmony_ci		break;
108562306a36Sopenharmony_ci	case RTW_HCI_TYPE_SDIO:
108662306a36Sopenharmony_ci		rqpn = &chip->rqpn_table[0];
108762306a36Sopenharmony_ci		break;
108862306a36Sopenharmony_ci	default:
108962306a36Sopenharmony_ci		return -EINVAL;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	rtwdev->fifo.rqpn = rqpn;
109362306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi);
109462306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg);
109562306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk);
109662306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be);
109762306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi);
109862306a36Sopenharmony_ci	txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo);
109962306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR, 0);
110262306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE);
110362306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev))
110462306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) {
110762306a36Sopenharmony_ci		rtw_read32(rtwdev, REG_SDIO_FREE_TXPG);
110862306a36Sopenharmony_ci		rtw_write32(rtwdev, REG_SDIO_TX_CTRL, 0);
110962306a36Sopenharmony_ci	} else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) {
111062306a36Sopenharmony_ci		rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_ARBBW_EN);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return 0;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic int set_trx_fifo_info(struct rtw_dev *rtwdev)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
111962306a36Sopenharmony_ci	struct rtw_fifo_conf *fifo = &rtwdev->fifo;
112062306a36Sopenharmony_ci	u16 cur_pg_addr;
112162306a36Sopenharmony_ci	u8 csi_buf_pg_num = chip->csi_buf_pg_num;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	/* config rsvd page num */
112462306a36Sopenharmony_ci	fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num;
112562306a36Sopenharmony_ci	fifo->txff_pg_num = chip->txff_size >> 7;
112662306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
112762306a36Sopenharmony_ci		fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num;
112862306a36Sopenharmony_ci	else
112962306a36Sopenharmony_ci		fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num +
113062306a36Sopenharmony_ci				   RSVD_PG_H2C_EXTRAINFO_NUM +
113162306a36Sopenharmony_ci				   RSVD_PG_H2C_STATICINFO_NUM +
113262306a36Sopenharmony_ci				   RSVD_PG_H2CQ_NUM +
113362306a36Sopenharmony_ci				   RSVD_PG_CPU_INSTRUCTION_NUM +
113462306a36Sopenharmony_ci				   RSVD_PG_FW_TXBUF_NUM +
113562306a36Sopenharmony_ci				   csi_buf_pg_num;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (fifo->rsvd_pg_num > fifo->txff_pg_num)
113862306a36Sopenharmony_ci		return -ENOMEM;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	fifo->acq_pg_num = fifo->txff_pg_num - fifo->rsvd_pg_num;
114162306a36Sopenharmony_ci	fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	cur_pg_addr = fifo->txff_pg_num;
114462306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev)) {
114562306a36Sopenharmony_ci		cur_pg_addr -= csi_buf_pg_num;
114662306a36Sopenharmony_ci		fifo->rsvd_csibuf_addr = cur_pg_addr;
114762306a36Sopenharmony_ci		cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM;
114862306a36Sopenharmony_ci		fifo->rsvd_fw_txbuf_addr = cur_pg_addr;
114962306a36Sopenharmony_ci		cur_pg_addr -= RSVD_PG_CPU_INSTRUCTION_NUM;
115062306a36Sopenharmony_ci		fifo->rsvd_cpu_instr_addr = cur_pg_addr;
115162306a36Sopenharmony_ci		cur_pg_addr -= RSVD_PG_H2CQ_NUM;
115262306a36Sopenharmony_ci		fifo->rsvd_h2cq_addr = cur_pg_addr;
115362306a36Sopenharmony_ci		cur_pg_addr -= RSVD_PG_H2C_STATICINFO_NUM;
115462306a36Sopenharmony_ci		fifo->rsvd_h2c_sta_info_addr = cur_pg_addr;
115562306a36Sopenharmony_ci		cur_pg_addr -= RSVD_PG_H2C_EXTRAINFO_NUM;
115662306a36Sopenharmony_ci		fifo->rsvd_h2c_info_addr = cur_pg_addr;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	cur_pg_addr -= fifo->rsvd_drv_pg_num;
115962306a36Sopenharmony_ci	fifo->rsvd_drv_addr = cur_pg_addr;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (fifo->rsvd_boundary != fifo->rsvd_drv_addr) {
116262306a36Sopenharmony_ci		rtw_err(rtwdev, "wrong rsvd driver address\n");
116362306a36Sopenharmony_ci		return -EINVAL;
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	return 0;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int __priority_queue_cfg(struct rtw_dev *rtwdev,
117062306a36Sopenharmony_ci				const struct rtw_page_table *pg_tbl,
117162306a36Sopenharmony_ci				u16 pubq_num)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
117462306a36Sopenharmony_ci	struct rtw_fifo_conf *fifo = &rtwdev->fifo;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num);
117762306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num);
117862306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_3, pg_tbl->nq_num);
117962306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_4, pg_tbl->exq_num);
118062306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_INFO_5, pubq_num);
118162306a36Sopenharmony_ci	rtw_write32_set(rtwdev, REG_RQPN_CTRL_2, BIT_LD_RQPN);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2, fifo->rsvd_boundary);
118462306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL + 2, BIT_EN_WR_FREE_TAIL >> 16);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_BCNQ_BDNY_V1, fifo->rsvd_boundary);
118762306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2 + 2, fifo->rsvd_boundary);
118862306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_BCNQ1_BDNY_V1, fifo->rsvd_boundary);
118962306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_RXFF_BNDY, chip->rxff_size - C2H_PKT_BUF - 1);
119062306a36Sopenharmony_ci	rtw_write8_set(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_AUTO_LLT_V1, BIT_AUTO_INIT_LLT_V1, 0))
119362306a36Sopenharmony_ci		return -EBUSY;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_CR + 3, 0);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	return 0;
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev,
120162306a36Sopenharmony_ci				       const struct rtw_page_table *pg_tbl,
120262306a36Sopenharmony_ci				       u16 pubq_num)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
120562306a36Sopenharmony_ci	struct rtw_fifo_conf *fifo = &rtwdev->fifo;
120662306a36Sopenharmony_ci	u32 val32;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num);
120962306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_RQPN_NPQ, val32);
121062306a36Sopenharmony_ci	val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num);
121162306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_RQPN, val32);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary);
121462306a36Sopenharmony_ci	rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, chip->rxff_size - REPORT_BUF - 1);
121562306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary);
121662306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary);
121762306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary);
121862306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	rtw_write32_set(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	if (!check_hw_ready(rtwdev, REG_AUTO_LLT, BIT_AUTO_INIT_LLT, 0))
122362306a36Sopenharmony_ci		return -EBUSY;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return 0;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int priority_queue_cfg(struct rtw_dev *rtwdev)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
123162306a36Sopenharmony_ci	struct rtw_fifo_conf *fifo = &rtwdev->fifo;
123262306a36Sopenharmony_ci	const struct rtw_page_table *pg_tbl = NULL;
123362306a36Sopenharmony_ci	u16 pubq_num;
123462306a36Sopenharmony_ci	int ret;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	ret = set_trx_fifo_info(rtwdev);
123762306a36Sopenharmony_ci	if (ret)
123862306a36Sopenharmony_ci		return ret;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	switch (rtw_hci_type(rtwdev)) {
124162306a36Sopenharmony_ci	case RTW_HCI_TYPE_PCIE:
124262306a36Sopenharmony_ci		pg_tbl = &chip->page_table[1];
124362306a36Sopenharmony_ci		break;
124462306a36Sopenharmony_ci	case RTW_HCI_TYPE_USB:
124562306a36Sopenharmony_ci		if (rtwdev->hci.bulkout_num == 2)
124662306a36Sopenharmony_ci			pg_tbl = &chip->page_table[2];
124762306a36Sopenharmony_ci		else if (rtwdev->hci.bulkout_num == 3)
124862306a36Sopenharmony_ci			pg_tbl = &chip->page_table[3];
124962306a36Sopenharmony_ci		else if (rtwdev->hci.bulkout_num == 4)
125062306a36Sopenharmony_ci			pg_tbl = &chip->page_table[4];
125162306a36Sopenharmony_ci		else
125262306a36Sopenharmony_ci			return -EINVAL;
125362306a36Sopenharmony_ci		break;
125462306a36Sopenharmony_ci	case RTW_HCI_TYPE_SDIO:
125562306a36Sopenharmony_ci		pg_tbl = &chip->page_table[0];
125662306a36Sopenharmony_ci		break;
125762306a36Sopenharmony_ci	default:
125862306a36Sopenharmony_ci		return -EINVAL;
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num -
126262306a36Sopenharmony_ci		   pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num;
126362306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
126462306a36Sopenharmony_ci		return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num);
126562306a36Sopenharmony_ci	else
126662306a36Sopenharmony_ci		return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num);
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic int init_h2c(struct rtw_dev *rtwdev)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct rtw_fifo_conf *fifo = &rtwdev->fifo;
127262306a36Sopenharmony_ci	u8 value8;
127362306a36Sopenharmony_ci	u32 value32;
127462306a36Sopenharmony_ci	u32 h2cq_addr;
127562306a36Sopenharmony_ci	u32 h2cq_size;
127662306a36Sopenharmony_ci	u32 h2cq_free;
127762306a36Sopenharmony_ci	u32 wp, rp;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	if (rtw_chip_wcpu_11n(rtwdev))
128062306a36Sopenharmony_ci		return 0;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT;
128362306a36Sopenharmony_ci	h2cq_size = RSVD_PG_H2CQ_NUM << TX_PAGE_SIZE_SHIFT;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_H2C_HEAD);
128662306a36Sopenharmony_ci	value32 = (value32 & 0xFFFC0000) | h2cq_addr;
128762306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_H2C_HEAD, value32);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_H2C_READ_ADDR);
129062306a36Sopenharmony_ci	value32 = (value32 & 0xFFFC0000) | h2cq_addr;
129162306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_H2C_READ_ADDR, value32);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	value32 = rtw_read32(rtwdev, REG_H2C_TAIL);
129462306a36Sopenharmony_ci	value32 &= 0xFFFC0000;
129562306a36Sopenharmony_ci	value32 |= (h2cq_addr + h2cq_size);
129662306a36Sopenharmony_ci	rtw_write32(rtwdev, REG_H2C_TAIL, value32);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_H2C_INFO);
129962306a36Sopenharmony_ci	value8 = (u8)((value8 & 0xFC) | 0x01);
130062306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_H2C_INFO, value8);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_H2C_INFO);
130362306a36Sopenharmony_ci	value8 = (u8)((value8 & 0xFB) | 0x04);
130462306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_H2C_INFO, value8);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	value8 = rtw_read8(rtwdev, REG_TXDMA_OFFSET_CHK + 1);
130762306a36Sopenharmony_ci	value8 = (u8)((value8 & 0x7f) | 0x80);
130862306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_TXDMA_OFFSET_CHK + 1, value8);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	wp = rtw_read32(rtwdev, REG_H2C_PKT_WRITEADDR) & 0x3FFFF;
131162306a36Sopenharmony_ci	rp = rtw_read32(rtwdev, REG_H2C_PKT_READADDR) & 0x3FFFF;
131262306a36Sopenharmony_ci	h2cq_free = wp >= rp ? h2cq_size - (wp - rp) : rp - wp;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (h2cq_size != h2cq_free) {
131562306a36Sopenharmony_ci		rtw_err(rtwdev, "H2C queue mismatch\n");
131662306a36Sopenharmony_ci		return -EINVAL;
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return 0;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic int rtw_init_trx_cfg(struct rtw_dev *rtwdev)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	int ret;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	ret = txdma_queue_mapping(rtwdev);
132762306a36Sopenharmony_ci	if (ret)
132862306a36Sopenharmony_ci		return ret;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	ret = priority_queue_cfg(rtwdev);
133162306a36Sopenharmony_ci	if (ret)
133262306a36Sopenharmony_ci		return ret;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	ret = init_h2c(rtwdev);
133562306a36Sopenharmony_ci	if (ret)
133662306a36Sopenharmony_ci		return ret;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	return 0;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic int rtw_drv_info_cfg(struct rtw_dev *rtwdev)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	u8 value8;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE);
134662306a36Sopenharmony_ci	if (rtw_chip_wcpu_11ac(rtwdev)) {
134762306a36Sopenharmony_ci		value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1);
134862306a36Sopenharmony_ci		value8 &= 0xF0;
134962306a36Sopenharmony_ci		/* For rxdesc len = 0 issue */
135062306a36Sopenharmony_ci		value8 |= 0xF;
135162306a36Sopenharmony_ci		rtw_write8(rtwdev, REG_TRXFF_BNDY + 1, value8);
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci	rtw_write32_set(rtwdev, REG_RCR, BIT_APP_PHYSTS);
135462306a36Sopenharmony_ci	rtw_write32_clr(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, BIT(8) | BIT(9));
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return 0;
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ciint rtw_mac_init(struct rtw_dev *rtwdev)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	const struct rtw_chip_info *chip = rtwdev->chip;
136262306a36Sopenharmony_ci	int ret;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	ret = rtw_init_trx_cfg(rtwdev);
136562306a36Sopenharmony_ci	if (ret)
136662306a36Sopenharmony_ci		return ret;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	ret = chip->ops->mac_init(rtwdev);
136962306a36Sopenharmony_ci	if (ret)
137062306a36Sopenharmony_ci		return ret;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ret = rtw_drv_info_cfg(rtwdev);
137362306a36Sopenharmony_ci	if (ret)
137462306a36Sopenharmony_ci		return ret;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	rtw_hci_interface_cfg(rtwdev);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	return 0;
137962306a36Sopenharmony_ci}
1380