162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/platform_device.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1062306a36Sopenharmony_ci#include <linux/skbuff.h>
1162306a36Sopenharmony_ci#include <linux/of_platform.h>
1262306a36Sopenharmony_ci#include <linux/of_address.h>
1362306a36Sopenharmony_ci#include <linux/of_reserved_mem.h>
1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1562306a36Sopenharmony_ci#include <linux/debugfs.h>
1662306a36Sopenharmony_ci#include <linux/soc/mediatek/mtk_wed.h>
1762306a36Sopenharmony_ci#include <net/flow_offload.h>
1862306a36Sopenharmony_ci#include <net/pkt_cls.h>
1962306a36Sopenharmony_ci#include "mtk_eth_soc.h"
2062306a36Sopenharmony_ci#include "mtk_wed_regs.h"
2162306a36Sopenharmony_ci#include "mtk_wed.h"
2262306a36Sopenharmony_ci#include "mtk_ppe.h"
2362306a36Sopenharmony_ci#include "mtk_wed_wo.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define MTK_PCIE_BASE(n)		(0x1a143000 + (n) * 0x2000)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define MTK_WED_PKT_SIZE		1900
2862306a36Sopenharmony_ci#define MTK_WED_BUF_SIZE		2048
2962306a36Sopenharmony_ci#define MTK_WED_BUF_PER_PAGE		(PAGE_SIZE / 2048)
3062306a36Sopenharmony_ci#define MTK_WED_RX_RING_SIZE		1536
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define MTK_WED_TX_RING_SIZE		2048
3362306a36Sopenharmony_ci#define MTK_WED_WDMA_RING_SIZE		1024
3462306a36Sopenharmony_ci#define MTK_WED_MAX_GROUP_SIZE		0x100
3562306a36Sopenharmony_ci#define MTK_WED_VLD_GROUP_SIZE		0x40
3662306a36Sopenharmony_ci#define MTK_WED_PER_GROUP_PKT		128
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define MTK_WED_FBUF_SIZE		128
3962306a36Sopenharmony_ci#define MTK_WED_MIOD_CNT		16
4062306a36Sopenharmony_ci#define MTK_WED_FB_CMD_CNT		1024
4162306a36Sopenharmony_ci#define MTK_WED_RRO_QUE_CNT		8192
4262306a36Sopenharmony_ci#define MTK_WED_MIOD_ENTRY_CNT		128
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct mtk_wed_hw *hw_list[2];
4562306a36Sopenharmony_cistatic DEFINE_MUTEX(hw_lock);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct mtk_wed_flow_block_priv {
4862306a36Sopenharmony_ci	struct mtk_wed_hw *hw;
4962306a36Sopenharmony_ci	struct net_device *dev;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void
5362306a36Sopenharmony_ciwed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	regmap_update_bits(dev->hw->regs, reg, mask | val, val);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void
5962306a36Sopenharmony_ciwed_set(struct mtk_wed_device *dev, u32 reg, u32 mask)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return wed_m32(dev, reg, 0, mask);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void
6562306a36Sopenharmony_ciwed_clr(struct mtk_wed_device *dev, u32 reg, u32 mask)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	return wed_m32(dev, reg, mask, 0);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void
7162306a36Sopenharmony_ciwdma_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	wdma_w32(dev, reg, (wdma_r32(dev, reg) & ~mask) | val);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic void
7762306a36Sopenharmony_ciwdma_set(struct mtk_wed_device *dev, u32 reg, u32 mask)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	wdma_m32(dev, reg, 0, mask);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic void
8362306a36Sopenharmony_ciwdma_clr(struct mtk_wed_device *dev, u32 reg, u32 mask)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	wdma_m32(dev, reg, mask, 0);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic u32
8962306a36Sopenharmony_ciwifi_r32(struct mtk_wed_device *dev, u32 reg)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return readl(dev->wlan.base + reg);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void
9562306a36Sopenharmony_ciwifi_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	writel(val, dev->wlan.base + reg);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic u32
10162306a36Sopenharmony_cimtk_wed_read_reset(struct mtk_wed_device *dev)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	return wed_r32(dev, MTK_WED_RESET);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic u32
10762306a36Sopenharmony_cimtk_wdma_read_reset(struct mtk_wed_device *dev)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int
11362306a36Sopenharmony_cimtk_wdma_rx_reset(struct mtk_wed_device *dev)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	u32 status, mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
11662306a36Sopenharmony_ci	int i, ret;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
11962306a36Sopenharmony_ci	ret = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
12062306a36Sopenharmony_ci				 !(status & mask), 0, 10000);
12162306a36Sopenharmony_ci	if (ret)
12262306a36Sopenharmony_ci		dev_err(dev->hw->dev, "rx reset failed\n");
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
12562306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
12862306a36Sopenharmony_ci		if (dev->rx_wdma[i].desc)
12962306a36Sopenharmony_ci			continue;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		wdma_w32(dev,
13262306a36Sopenharmony_ci			 MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return ret;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void
13962306a36Sopenharmony_cimtk_wdma_tx_reset(struct mtk_wed_device *dev)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	u32 status, mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
14262306a36Sopenharmony_ci	int i;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
14562306a36Sopenharmony_ci	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
14662306a36Sopenharmony_ci			       !(status & mask), 0, 10000))
14762306a36Sopenharmony_ci		dev_err(dev->hw->dev, "tx reset failed\n");
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
15062306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
15362306a36Sopenharmony_ci		wdma_w32(dev,
15462306a36Sopenharmony_ci			 MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic void
15862306a36Sopenharmony_cimtk_wed_reset(struct mtk_wed_device *dev, u32 mask)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	u32 status;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RESET, mask);
16362306a36Sopenharmony_ci	if (readx_poll_timeout(mtk_wed_read_reset, dev, status,
16462306a36Sopenharmony_ci			       !(status & mask), 0, 1000))
16562306a36Sopenharmony_ci		WARN_ON_ONCE(1);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic u32
16962306a36Sopenharmony_cimtk_wed_wo_read_status(struct mtk_wed_device *dev)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	return wed_r32(dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_WO_STATUS);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void
17562306a36Sopenharmony_cimtk_wed_wo_reset(struct mtk_wed_device *dev)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct mtk_wed_wo *wo = dev->hw->wed_wo;
17862306a36Sopenharmony_ci	u8 state = MTK_WED_WO_STATE_DISABLE;
17962306a36Sopenharmony_ci	void __iomem *reg;
18062306a36Sopenharmony_ci	u32 val;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	mtk_wdma_tx_reset(dev);
18362306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_WED);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
18662306a36Sopenharmony_ci				 MTK_WED_WO_CMD_CHANGE_STATE, &state,
18762306a36Sopenharmony_ci				 sizeof(state), false))
18862306a36Sopenharmony_ci		return;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (readx_poll_timeout(mtk_wed_wo_read_status, dev, val,
19162306a36Sopenharmony_ci			       val == MTK_WED_WOIF_DISABLE_DONE,
19262306a36Sopenharmony_ci			       100, MTK_WOCPU_TIMEOUT))
19362306a36Sopenharmony_ci		dev_err(dev->hw->dev, "failed to disable wed-wo\n");
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	reg = ioremap(MTK_WED_WO_CPU_MCUSYS_RESET_ADDR, 4);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	val = readl(reg);
19862306a36Sopenharmony_ci	switch (dev->hw->index) {
19962306a36Sopenharmony_ci	case 0:
20062306a36Sopenharmony_ci		val |= MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK;
20162306a36Sopenharmony_ci		writel(val, reg);
20262306a36Sopenharmony_ci		val &= ~MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK;
20362306a36Sopenharmony_ci		writel(val, reg);
20462306a36Sopenharmony_ci		break;
20562306a36Sopenharmony_ci	case 1:
20662306a36Sopenharmony_ci		val |= MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK;
20762306a36Sopenharmony_ci		writel(val, reg);
20862306a36Sopenharmony_ci		val &= ~MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK;
20962306a36Sopenharmony_ci		writel(val, reg);
21062306a36Sopenharmony_ci		break;
21162306a36Sopenharmony_ci	default:
21262306a36Sopenharmony_ci		break;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	iounmap(reg);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_civoid mtk_wed_fe_reset(void)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	int i;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mutex_lock(&hw_lock);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
22462306a36Sopenharmony_ci		struct mtk_wed_hw *hw = hw_list[i];
22562306a36Sopenharmony_ci		struct mtk_wed_device *dev;
22662306a36Sopenharmony_ci		int err;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		if (!hw)
22962306a36Sopenharmony_ci			break;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		dev = hw->wed_dev;
23262306a36Sopenharmony_ci		if (!dev || !dev->wlan.reset)
23362306a36Sopenharmony_ci			continue;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		/* reset callback blocks until WLAN reset is completed */
23662306a36Sopenharmony_ci		err = dev->wlan.reset(dev);
23762306a36Sopenharmony_ci		if (err)
23862306a36Sopenharmony_ci			dev_err(dev->dev, "wlan reset failed: %d\n", err);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_civoid mtk_wed_fe_reset_complete(void)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	int i;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	mutex_lock(&hw_lock);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
25162306a36Sopenharmony_ci		struct mtk_wed_hw *hw = hw_list[i];
25262306a36Sopenharmony_ci		struct mtk_wed_device *dev;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		if (!hw)
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		dev = hw->wed_dev;
25862306a36Sopenharmony_ci		if (!dev || !dev->wlan.reset_complete)
25962306a36Sopenharmony_ci			continue;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		dev->wlan.reset_complete(dev);
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic struct mtk_wed_hw *
26862306a36Sopenharmony_cimtk_wed_assign(struct mtk_wed_device *dev)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct mtk_wed_hw *hw;
27162306a36Sopenharmony_ci	int i;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
27462306a36Sopenharmony_ci		hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)];
27562306a36Sopenharmony_ci		if (!hw)
27662306a36Sopenharmony_ci			return NULL;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		if (!hw->wed_dev)
27962306a36Sopenharmony_ci			goto out;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (hw->version == 1)
28262306a36Sopenharmony_ci			return NULL;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		/* MT7986 WED devices do not have any pcie slot restrictions */
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci	/* MT7986 PCIE or AXI */
28762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
28862306a36Sopenharmony_ci		hw = hw_list[i];
28962306a36Sopenharmony_ci		if (hw && !hw->wed_dev)
29062306a36Sopenharmony_ci			goto out;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return NULL;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciout:
29662306a36Sopenharmony_ci	hw->wed_dev = dev;
29762306a36Sopenharmony_ci	return hw;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int
30162306a36Sopenharmony_cimtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct mtk_wdma_desc *desc;
30462306a36Sopenharmony_ci	dma_addr_t desc_phys;
30562306a36Sopenharmony_ci	void **page_list;
30662306a36Sopenharmony_ci	int token = dev->wlan.token_start;
30762306a36Sopenharmony_ci	int ring_size;
30862306a36Sopenharmony_ci	int n_pages;
30962306a36Sopenharmony_ci	int i, page_idx;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
31262306a36Sopenharmony_ci	n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
31562306a36Sopenharmony_ci	if (!page_list)
31662306a36Sopenharmony_ci		return -ENOMEM;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	dev->tx_buf_ring.size = ring_size;
31962306a36Sopenharmony_ci	dev->tx_buf_ring.pages = page_list;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
32262306a36Sopenharmony_ci				  &desc_phys, GFP_KERNEL);
32362306a36Sopenharmony_ci	if (!desc)
32462306a36Sopenharmony_ci		return -ENOMEM;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	dev->tx_buf_ring.desc = desc;
32762306a36Sopenharmony_ci	dev->tx_buf_ring.desc_phys = desc_phys;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
33062306a36Sopenharmony_ci		dma_addr_t page_phys, buf_phys;
33162306a36Sopenharmony_ci		struct page *page;
33262306a36Sopenharmony_ci		void *buf;
33362306a36Sopenharmony_ci		int s;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		page = __dev_alloc_pages(GFP_KERNEL, 0);
33662306a36Sopenharmony_ci		if (!page)
33762306a36Sopenharmony_ci			return -ENOMEM;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE,
34062306a36Sopenharmony_ci					 DMA_BIDIRECTIONAL);
34162306a36Sopenharmony_ci		if (dma_mapping_error(dev->hw->dev, page_phys)) {
34262306a36Sopenharmony_ci			__free_page(page);
34362306a36Sopenharmony_ci			return -ENOMEM;
34462306a36Sopenharmony_ci		}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		page_list[page_idx++] = page;
34762306a36Sopenharmony_ci		dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
34862306a36Sopenharmony_ci					DMA_BIDIRECTIONAL);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		buf = page_to_virt(page);
35162306a36Sopenharmony_ci		buf_phys = page_phys;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
35462306a36Sopenharmony_ci			u32 txd_size;
35562306a36Sopenharmony_ci			u32 ctrl;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci			txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci			desc->buf0 = cpu_to_le32(buf_phys);
36062306a36Sopenharmony_ci			desc->buf1 = cpu_to_le32(buf_phys + txd_size);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci			if (dev->hw->version == 1)
36362306a36Sopenharmony_ci				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
36462306a36Sopenharmony_ci				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
36562306a36Sopenharmony_ci						  MTK_WED_BUF_SIZE - txd_size) |
36662306a36Sopenharmony_ci				       MTK_WDMA_DESC_CTRL_LAST_SEG1;
36762306a36Sopenharmony_ci			else
36862306a36Sopenharmony_ci				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
36962306a36Sopenharmony_ci				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
37062306a36Sopenharmony_ci						  MTK_WED_BUF_SIZE - txd_size) |
37162306a36Sopenharmony_ci				       MTK_WDMA_DESC_CTRL_LAST_SEG0;
37262306a36Sopenharmony_ci			desc->ctrl = cpu_to_le32(ctrl);
37362306a36Sopenharmony_ci			desc->info = 0;
37462306a36Sopenharmony_ci			desc++;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			buf += MTK_WED_BUF_SIZE;
37762306a36Sopenharmony_ci			buf_phys += MTK_WED_BUF_SIZE;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE,
38162306a36Sopenharmony_ci					   DMA_BIDIRECTIONAL);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void
38862306a36Sopenharmony_cimtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc;
39162306a36Sopenharmony_ci	void **page_list = dev->tx_buf_ring.pages;
39262306a36Sopenharmony_ci	int page_idx;
39362306a36Sopenharmony_ci	int i;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (!page_list)
39662306a36Sopenharmony_ci		return;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!desc)
39962306a36Sopenharmony_ci		goto free_pagelist;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	for (i = 0, page_idx = 0; i < dev->tx_buf_ring.size;
40262306a36Sopenharmony_ci	     i += MTK_WED_BUF_PER_PAGE) {
40362306a36Sopenharmony_ci		void *page = page_list[page_idx++];
40462306a36Sopenharmony_ci		dma_addr_t buf_addr;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci		if (!page)
40762306a36Sopenharmony_ci			break;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		buf_addr = le32_to_cpu(desc[i].buf0);
41062306a36Sopenharmony_ci		dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
41162306a36Sopenharmony_ci			       DMA_BIDIRECTIONAL);
41262306a36Sopenharmony_ci		__free_page(page);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	dma_free_coherent(dev->hw->dev, dev->tx_buf_ring.size * sizeof(*desc),
41662306a36Sopenharmony_ci			  desc, dev->tx_buf_ring.desc_phys);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cifree_pagelist:
41962306a36Sopenharmony_ci	kfree(page_list);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int
42362306a36Sopenharmony_cimtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct mtk_rxbm_desc *desc;
42662306a36Sopenharmony_ci	dma_addr_t desc_phys;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	dev->rx_buf_ring.size = dev->wlan.rx_nbuf;
42962306a36Sopenharmony_ci	desc = dma_alloc_coherent(dev->hw->dev,
43062306a36Sopenharmony_ci				  dev->wlan.rx_nbuf * sizeof(*desc),
43162306a36Sopenharmony_ci				  &desc_phys, GFP_KERNEL);
43262306a36Sopenharmony_ci	if (!desc)
43362306a36Sopenharmony_ci		return -ENOMEM;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	dev->rx_buf_ring.desc = desc;
43662306a36Sopenharmony_ci	dev->rx_buf_ring.desc_phys = desc_phys;
43762306a36Sopenharmony_ci	dev->wlan.init_rx_buf(dev, dev->wlan.rx_npkt);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return 0;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void
44362306a36Sopenharmony_cimtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (!desc)
44862306a36Sopenharmony_ci		return;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	dev->wlan.release_rx_buf(dev);
45162306a36Sopenharmony_ci	dma_free_coherent(dev->hw->dev, dev->rx_buf_ring.size * sizeof(*desc),
45262306a36Sopenharmony_ci			  desc, dev->rx_buf_ring.desc_phys);
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void
45662306a36Sopenharmony_cimtk_wed_rx_buffer_hw_init(struct mtk_wed_device *dev)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RX_BM_RX_DMAD,
45962306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RX_BM_RX_DMAD_SDL0, dev->wlan.rx_size));
46062306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RX_BM_BASE, dev->rx_buf_ring.desc_phys);
46162306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RX_BM_INIT_PTR, MTK_WED_RX_BM_INIT_SW_TAIL |
46262306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RX_BM_SW_TAIL, dev->wlan.rx_npkt));
46362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RX_BM_DYN_ALLOC_TH,
46462306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff));
46562306a36Sopenharmony_ci	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void
46962306a36Sopenharmony_cimtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	if (!ring->desc)
47262306a36Sopenharmony_ci		return;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	dma_free_coherent(dev->hw->dev, ring->size * ring->desc_size,
47562306a36Sopenharmony_ci			  ring->desc, ring->desc_phys);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void
47962306a36Sopenharmony_cimtk_wed_free_rx_rings(struct mtk_wed_device *dev)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	mtk_wed_free_rx_buffer(dev);
48262306a36Sopenharmony_ci	mtk_wed_free_ring(dev, &dev->rro.ring);
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic void
48662306a36Sopenharmony_cimtk_wed_free_tx_rings(struct mtk_wed_device *dev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	int i;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
49162306a36Sopenharmony_ci		mtk_wed_free_ring(dev, &dev->tx_ring[i]);
49262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
49362306a36Sopenharmony_ci		mtk_wed_free_ring(dev, &dev->rx_wdma[i]);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void
49762306a36Sopenharmony_cimtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (dev->hw->version == 1)
50262306a36Sopenharmony_ci		mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
50362306a36Sopenharmony_ci	else
50462306a36Sopenharmony_ci		mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
50562306a36Sopenharmony_ci			MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH |
50662306a36Sopenharmony_ci			MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
50762306a36Sopenharmony_ci			MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (!dev->hw->num_flows)
51062306a36Sopenharmony_ci		mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_EXT_INT_MASK, en ? mask : 0);
51362306a36Sopenharmony_ci	wed_r32(dev, MTK_WED_EXT_INT_MASK);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void
51762306a36Sopenharmony_cimtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	if (enable) {
52062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
52162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TXP_DW1,
52262306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
52362306a36Sopenharmony_ci	} else {
52462306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TXP_DW1,
52562306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100));
52662306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci#define MTK_WFMDA_RX_DMA_EN	BIT(2)
53162306a36Sopenharmony_cistatic void
53262306a36Sopenharmony_cimtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	u32 val;
53562306a36Sopenharmony_ci	int i;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!(dev->rx_ring[idx].flags & MTK_WED_RING_CONFIGURED))
53862306a36Sopenharmony_ci		return; /* queue is not configured by mt76 */
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
54162306a36Sopenharmony_ci		u32 cur_idx;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		cur_idx = wed_r32(dev,
54462306a36Sopenharmony_ci				  MTK_WED_WPDMA_RING_RX_DATA(idx) +
54562306a36Sopenharmony_ci				  MTK_WED_RING_OFS_CPU_IDX);
54662306a36Sopenharmony_ci		if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
54762306a36Sopenharmony_ci			break;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		usleep_range(100000, 200000);
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (i == 3) {
55362306a36Sopenharmony_ci		dev_err(dev->hw->dev, "rx dma enable failed\n");
55462306a36Sopenharmony_ci		return;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	val = wifi_r32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base) |
55862306a36Sopenharmony_ci	      MTK_WFMDA_RX_DMA_EN;
55962306a36Sopenharmony_ci	wifi_w32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base, val);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void
56362306a36Sopenharmony_cimtk_wed_dma_disable(struct mtk_wed_device *dev)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
56662306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
56762306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_GLO_CFG,
57262306a36Sopenharmony_ci		MTK_WED_GLO_CFG_TX_DMA_EN |
57362306a36Sopenharmony_ci		MTK_WED_GLO_CFG_RX_DMA_EN);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	wdma_clr(dev, MTK_WDMA_GLO_CFG,
57662306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
57762306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
57862306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (dev->hw->version == 1) {
58162306a36Sopenharmony_ci		regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
58262306a36Sopenharmony_ci		wdma_clr(dev, MTK_WDMA_GLO_CFG,
58362306a36Sopenharmony_ci			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
58462306a36Sopenharmony_ci	} else {
58562306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
58662306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
58762306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
59062306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RX_DRV_EN);
59162306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
59262306a36Sopenharmony_ci			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	mtk_wed_set_512_support(dev, false);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void
59962306a36Sopenharmony_cimtk_wed_stop(struct mtk_wed_device *dev)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	mtk_wed_set_ext_int(dev, false);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
60462306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
60562306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
60662306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
60762306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (dev->hw->version == 1)
61062306a36Sopenharmony_ci		return;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
61362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic void
61762306a36Sopenharmony_cimtk_wed_deinit(struct mtk_wed_device *dev)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	mtk_wed_stop(dev);
62062306a36Sopenharmony_ci	mtk_wed_dma_disable(dev);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL,
62362306a36Sopenharmony_ci		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
62462306a36Sopenharmony_ci		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
62562306a36Sopenharmony_ci		MTK_WED_CTRL_WED_TX_BM_EN |
62662306a36Sopenharmony_ci		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (dev->hw->version == 1)
62962306a36Sopenharmony_ci		return;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL,
63262306a36Sopenharmony_ci		MTK_WED_CTRL_RX_ROUTE_QM_EN |
63362306a36Sopenharmony_ci		MTK_WED_CTRL_WED_RX_BM_EN |
63462306a36Sopenharmony_ci		MTK_WED_CTRL_RX_RRO_QM_EN);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic void
63862306a36Sopenharmony_ci__mtk_wed_detach(struct mtk_wed_device *dev)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct mtk_wed_hw *hw = dev->hw;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	mtk_wed_deinit(dev);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	mtk_wdma_rx_reset(dev);
64562306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_WED);
64662306a36Sopenharmony_ci	mtk_wed_free_tx_buffer(dev);
64762306a36Sopenharmony_ci	mtk_wed_free_tx_rings(dev);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (mtk_wed_get_rx_capa(dev)) {
65062306a36Sopenharmony_ci		if (hw->wed_wo)
65162306a36Sopenharmony_ci			mtk_wed_wo_reset(dev);
65262306a36Sopenharmony_ci		mtk_wed_free_rx_rings(dev);
65362306a36Sopenharmony_ci		if (hw->wed_wo)
65462306a36Sopenharmony_ci			mtk_wed_wo_deinit(hw);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
65862306a36Sopenharmony_ci		struct device_node *wlan_node;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		wlan_node = dev->wlan.pci_dev->dev.of_node;
66162306a36Sopenharmony_ci		if (of_dma_is_coherent(wlan_node) && hw->hifsys)
66262306a36Sopenharmony_ci			regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
66362306a36Sopenharmony_ci					   BIT(hw->index), BIT(hw->index));
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if ((!hw_list[!hw->index] || !hw_list[!hw->index]->wed_dev) &&
66762306a36Sopenharmony_ci	    hw->eth->dma_dev != hw->eth->dev)
66862306a36Sopenharmony_ci		mtk_eth_set_dma_device(hw->eth, hw->eth->dev);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	memset(dev, 0, sizeof(*dev));
67162306a36Sopenharmony_ci	module_put(THIS_MODULE);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	hw->wed_dev = NULL;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic void
67762306a36Sopenharmony_cimtk_wed_detach(struct mtk_wed_device *dev)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	mutex_lock(&hw_lock);
68062306a36Sopenharmony_ci	__mtk_wed_detach(dev);
68162306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci#define PCIE_BASE_ADDR0		0x11280000
68562306a36Sopenharmony_cistatic void
68662306a36Sopenharmony_cimtk_wed_bus_init(struct mtk_wed_device *dev)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	switch (dev->wlan.bus_type) {
68962306a36Sopenharmony_ci	case MTK_WED_BUS_PCIE: {
69062306a36Sopenharmony_ci		struct device_node *np = dev->hw->eth->dev->of_node;
69162306a36Sopenharmony_ci		struct regmap *regs;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		regs = syscon_regmap_lookup_by_phandle(np,
69462306a36Sopenharmony_ci						       "mediatek,wed-pcie");
69562306a36Sopenharmony_ci		if (IS_ERR(regs))
69662306a36Sopenharmony_ci			break;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		regmap_update_bits(regs, 0, BIT(0), BIT(0));
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
70162306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		/* pcie interrupt control: pola/source selection */
70462306a36Sopenharmony_ci		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
70562306a36Sopenharmony_ci			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
70662306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
70762306a36Sopenharmony_ci		wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
71062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		/* pcie interrupt status trigger register */
71362306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
71462306a36Sopenharmony_ci		wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		/* pola setting */
71762306a36Sopenharmony_ci		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
71862306a36Sopenharmony_ci			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
71962306a36Sopenharmony_ci		break;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci	case MTK_WED_BUS_AXI:
72262306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
72362306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_SIG_SRC |
72462306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0));
72562306a36Sopenharmony_ci		break;
72662306a36Sopenharmony_ci	default:
72762306a36Sopenharmony_ci		break;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void
73262306a36Sopenharmony_cimtk_wed_set_wpdma(struct mtk_wed_device *dev)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	if (dev->hw->version == 1) {
73562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
73662306a36Sopenharmony_ci	} else {
73762306a36Sopenharmony_ci		mtk_wed_bus_init(dev);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int);
74062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask);
74162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
74262306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree);
74362306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
74462306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx);
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic void
74962306a36Sopenharmony_cimtk_wed_hw_init_early(struct mtk_wed_device *dev)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	u32 mask, set;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	mtk_wed_deinit(dev);
75462306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_WED);
75562306a36Sopenharmony_ci	mtk_wed_set_wpdma(dev);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
75862306a36Sopenharmony_ci	       MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
75962306a36Sopenharmony_ci	       MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
76062306a36Sopenharmony_ci	set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
76162306a36Sopenharmony_ci	      MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
76262306a36Sopenharmony_ci	      MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
76362306a36Sopenharmony_ci	wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (dev->hw->version == 1) {
76662306a36Sopenharmony_ci		u32 offset = dev->hw->index ? 0x04000400 : 0;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		wdma_set(dev, MTK_WDMA_GLO_CFG,
76962306a36Sopenharmony_ci			 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
77062306a36Sopenharmony_ci			 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES |
77162306a36Sopenharmony_ci			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
77462306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset);
77562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
77662306a36Sopenharmony_ci			MTK_PCIE_BASE(dev->hw->index));
77762306a36Sopenharmony_ci	} else {
77862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy);
77962306a36Sopenharmony_ci		wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT);
78062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_OFFSET0,
78162306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_INTS,
78262306a36Sopenharmony_ci				   MTK_WDMA_INT_STATUS) |
78362306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_CFG,
78462306a36Sopenharmony_ci				   MTK_WDMA_GLO_CFG));
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_OFFSET1,
78762306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WDMA_OFST1_TX_CTRL,
78862306a36Sopenharmony_ci				   MTK_WDMA_RING_TX(0)) |
78962306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WDMA_OFST1_RX_CTRL,
79062306a36Sopenharmony_ci				   MTK_WDMA_RING_RX(0)));
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int
79562306a36Sopenharmony_cimtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
79662306a36Sopenharmony_ci		       int size)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	ring->desc = dma_alloc_coherent(dev->hw->dev,
79962306a36Sopenharmony_ci					size * sizeof(*ring->desc),
80062306a36Sopenharmony_ci					&ring->desc_phys, GFP_KERNEL);
80162306a36Sopenharmony_ci	if (!ring->desc)
80262306a36Sopenharmony_ci		return -ENOMEM;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	ring->desc_size = sizeof(*ring->desc);
80562306a36Sopenharmony_ci	ring->size = size;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci#define MTK_WED_MIOD_COUNT	(MTK_WED_MIOD_ENTRY_CNT * MTK_WED_MIOD_CNT)
81162306a36Sopenharmony_cistatic int
81262306a36Sopenharmony_cimtk_wed_rro_alloc(struct mtk_wed_device *dev)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct reserved_mem *rmem;
81562306a36Sopenharmony_ci	struct device_node *np;
81662306a36Sopenharmony_ci	int index;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	index = of_property_match_string(dev->hw->node, "memory-region-names",
81962306a36Sopenharmony_ci					 "wo-dlm");
82062306a36Sopenharmony_ci	if (index < 0)
82162306a36Sopenharmony_ci		return index;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	np = of_parse_phandle(dev->hw->node, "memory-region", index);
82462306a36Sopenharmony_ci	if (!np)
82562306a36Sopenharmony_ci		return -ENODEV;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	rmem = of_reserved_mem_lookup(np);
82862306a36Sopenharmony_ci	of_node_put(np);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (!rmem)
83162306a36Sopenharmony_ci		return -ENODEV;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	dev->rro.miod_phys = rmem->base;
83462306a36Sopenharmony_ci	dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring,
83762306a36Sopenharmony_ci				      MTK_WED_RRO_QUE_CNT);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic int
84162306a36Sopenharmony_cimtk_wed_rro_cfg(struct mtk_wed_device *dev)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct mtk_wed_wo *wo = dev->hw->wed_wo;
84462306a36Sopenharmony_ci	struct {
84562306a36Sopenharmony_ci		struct {
84662306a36Sopenharmony_ci			__le32 base;
84762306a36Sopenharmony_ci			__le32 cnt;
84862306a36Sopenharmony_ci			__le32 unit;
84962306a36Sopenharmony_ci		} ring[2];
85062306a36Sopenharmony_ci		__le32 wed;
85162306a36Sopenharmony_ci		u8 version;
85262306a36Sopenharmony_ci	} req = {
85362306a36Sopenharmony_ci		.ring[0] = {
85462306a36Sopenharmony_ci			.base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE),
85562306a36Sopenharmony_ci			.cnt = cpu_to_le32(MTK_WED_MIOD_CNT),
85662306a36Sopenharmony_ci			.unit = cpu_to_le32(MTK_WED_MIOD_ENTRY_CNT),
85762306a36Sopenharmony_ci		},
85862306a36Sopenharmony_ci		.ring[1] = {
85962306a36Sopenharmony_ci			.base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE +
86062306a36Sopenharmony_ci					    MTK_WED_MIOD_COUNT),
86162306a36Sopenharmony_ci			.cnt = cpu_to_le32(MTK_WED_FB_CMD_CNT),
86262306a36Sopenharmony_ci			.unit = cpu_to_le32(4),
86362306a36Sopenharmony_ci		},
86462306a36Sopenharmony_ci	};
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
86762306a36Sopenharmony_ci				    MTK_WED_WO_CMD_WED_CFG,
86862306a36Sopenharmony_ci				    &req, sizeof(req), true);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic void
87262306a36Sopenharmony_cimtk_wed_rro_hw_init(struct mtk_wed_device *dev)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_MIOD_CFG,
87562306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RROQM_MIOD_MID_DW, 0x70 >> 2) |
87662306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RROQM_MIOD_MOD_DW, 0x10 >> 2) |
87762306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RROQM_MIOD_ENTRY_DW,
87862306a36Sopenharmony_ci			   MTK_WED_MIOD_ENTRY_CNT >> 2));
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL0, dev->rro.miod_phys);
88162306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL1,
88262306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RROQM_MIOD_CNT, MTK_WED_MIOD_CNT));
88362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL0, dev->rro.fdbk_phys);
88462306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL1,
88562306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RROQM_FDBK_CNT, MTK_WED_FB_CMD_CNT));
88662306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL2, 0);
88762306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQ_BASE_L, dev->rro.ring.desc_phys);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	wed_set(dev, MTK_WED_RROQM_RST_IDX,
89062306a36Sopenharmony_ci		MTK_WED_RROQM_RST_IDX_MIOD |
89162306a36Sopenharmony_ci		MTK_WED_RROQM_RST_IDX_FDBK);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
89462306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL2, MTK_WED_MIOD_CNT - 1);
89562306a36Sopenharmony_ci	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN);
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic void
89962306a36Sopenharmony_cimtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_RESET, MTK_WED_RESET_RX_ROUTE_QM);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	for (;;) {
90462306a36Sopenharmony_ci		usleep_range(100, 200);
90562306a36Sopenharmony_ci		if (!(wed_r32(dev, MTK_WED_RESET) & MTK_WED_RESET_RX_ROUTE_QM))
90662306a36Sopenharmony_ci			break;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/* configure RX_ROUTE_QM */
91062306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
91162306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
91262306a36Sopenharmony_ci	wed_set(dev, MTK_WED_RTQM_GLO_CFG,
91362306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
91462306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
91562306a36Sopenharmony_ci	/* enable RX_ROUTE_QM */
91662306a36Sopenharmony_ci	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic void
92062306a36Sopenharmony_cimtk_wed_hw_init(struct mtk_wed_device *dev)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	if (dev->init_done)
92362306a36Sopenharmony_ci		return;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	dev->init_done = true;
92662306a36Sopenharmony_ci	mtk_wed_set_ext_int(dev, false);
92762306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_TX_BM_CTRL,
92862306a36Sopenharmony_ci		MTK_WED_TX_BM_CTRL_PAUSE |
92962306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
93062306a36Sopenharmony_ci			   dev->tx_buf_ring.size / 128) |
93162306a36Sopenharmony_ci		FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
93262306a36Sopenharmony_ci			   MTK_WED_TX_RING_SIZE / 256));
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (dev->hw->version == 1) {
93962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_BM_TKID,
94062306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
94162306a36Sopenharmony_ci				   dev->wlan.token_start) |
94262306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
94362306a36Sopenharmony_ci				   dev->wlan.token_start +
94462306a36Sopenharmony_ci				   dev->wlan.nbuf - 1));
94562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
94662306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
94762306a36Sopenharmony_ci			MTK_WED_TX_BM_DYN_THR_HI);
94862306a36Sopenharmony_ci	} else {
94962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_BM_TKID_V2,
95062306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
95162306a36Sopenharmony_ci				   dev->wlan.token_start) |
95262306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
95362306a36Sopenharmony_ci				   dev->wlan.token_start +
95462306a36Sopenharmony_ci				   dev->wlan.nbuf - 1));
95562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
95662306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
95762306a36Sopenharmony_ci			MTK_WED_TX_BM_DYN_THR_HI_V2);
95862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
95962306a36Sopenharmony_ci			MTK_WED_TX_TKID_CTRL_PAUSE |
96062306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
96162306a36Sopenharmony_ci				   dev->tx_buf_ring.size / 128) |
96262306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
96362306a36Sopenharmony_ci				   dev->tx_buf_ring.size / 128));
96462306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
96562306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
96662306a36Sopenharmony_ci			MTK_WED_TX_TKID_DYN_THR_HI);
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (dev->hw->version == 1) {
97262306a36Sopenharmony_ci		wed_set(dev, MTK_WED_CTRL,
97362306a36Sopenharmony_ci			MTK_WED_CTRL_WED_TX_BM_EN |
97462306a36Sopenharmony_ci			MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
97562306a36Sopenharmony_ci	} else {
97662306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
97762306a36Sopenharmony_ci		/* rx hw init */
97862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
97962306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
98062306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
98162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		mtk_wed_rx_buffer_hw_init(dev);
98462306a36Sopenharmony_ci		mtk_wed_rro_hw_init(dev);
98562306a36Sopenharmony_ci		mtk_wed_route_qm_hw_init(dev);
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic void
99262306a36Sopenharmony_cimtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	void *head = (void *)ring->desc;
99562306a36Sopenharmony_ci	int i;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
99862306a36Sopenharmony_ci		struct mtk_wdma_desc *desc;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size);
100162306a36Sopenharmony_ci		desc->buf0 = 0;
100262306a36Sopenharmony_ci		if (tx)
100362306a36Sopenharmony_ci			desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
100462306a36Sopenharmony_ci		else
100562306a36Sopenharmony_ci			desc->ctrl = cpu_to_le32(MTK_WFDMA_DESC_CTRL_TO_HOST);
100662306a36Sopenharmony_ci		desc->buf1 = 0;
100762306a36Sopenharmony_ci		desc->info = 0;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic u32
101262306a36Sopenharmony_cimtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	return !!(wed_r32(dev, reg) & mask);
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int
101862306a36Sopenharmony_cimtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	int sleep = 15000;
102162306a36Sopenharmony_ci	int timeout = 100 * sleep;
102262306a36Sopenharmony_ci	u32 val;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
102562306a36Sopenharmony_ci				 timeout, false, dev, reg, mask);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic int
102962306a36Sopenharmony_cimtk_wed_rx_reset(struct mtk_wed_device *dev)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct mtk_wed_wo *wo = dev->hw->wed_wo;
103262306a36Sopenharmony_ci	u8 val = MTK_WED_WO_STATE_SER_RESET;
103362306a36Sopenharmony_ci	int i, ret;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
103662306a36Sopenharmony_ci				   MTK_WED_WO_CMD_CHANGE_STATE, &val,
103762306a36Sopenharmony_ci				   sizeof(val), true);
103862306a36Sopenharmony_ci	if (ret)
103962306a36Sopenharmony_ci		return ret;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
104262306a36Sopenharmony_ci	ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
104362306a36Sopenharmony_ci				MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
104462306a36Sopenharmony_ci	if (ret) {
104562306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
104662306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
104762306a36Sopenharmony_ci	} else {
104862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
104962306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
105062306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
105362306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
105462306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
105562306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
105662306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
105762306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* reset rro qm */
106362306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN);
106462306a36Sopenharmony_ci	ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
106562306a36Sopenharmony_ci				MTK_WED_CTRL_RX_RRO_QM_BUSY);
106662306a36Sopenharmony_ci	if (ret) {
106762306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_RX_RRO_QM);
106862306a36Sopenharmony_ci	} else {
106962306a36Sopenharmony_ci		wed_set(dev, MTK_WED_RROQM_RST_IDX,
107062306a36Sopenharmony_ci			MTK_WED_RROQM_RST_IDX_MIOD |
107162306a36Sopenharmony_ci			MTK_WED_RROQM_RST_IDX_FDBK);
107262306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* reset route qm */
107662306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
107762306a36Sopenharmony_ci	ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
107862306a36Sopenharmony_ci				MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
107962306a36Sopenharmony_ci	if (ret)
108062306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
108162306a36Sopenharmony_ci	else
108262306a36Sopenharmony_ci		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
108362306a36Sopenharmony_ci			MTK_WED_RTQM_Q_RST);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* reset tx wdma */
108662306a36Sopenharmony_ci	mtk_wdma_tx_reset(dev);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	/* reset tx wdma drv */
108962306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
109062306a36Sopenharmony_ci	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
109162306a36Sopenharmony_ci			  MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
109262306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* reset wed rx dma */
109562306a36Sopenharmony_ci	ret = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
109662306a36Sopenharmony_ci				MTK_WED_GLO_CFG_RX_DMA_BUSY);
109762306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_RX_DMA_EN);
109862306a36Sopenharmony_ci	if (ret) {
109962306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
110062306a36Sopenharmony_ci	} else {
110162306a36Sopenharmony_ci		struct mtk_eth *eth = dev->hw->eth;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		if (mtk_is_netsys_v2_or_greater(eth))
110462306a36Sopenharmony_ci			wed_set(dev, MTK_WED_RESET_IDX,
110562306a36Sopenharmony_ci				MTK_WED_RESET_IDX_RX_V2);
110662306a36Sopenharmony_ci		else
110762306a36Sopenharmony_ci			wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
110862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RESET_IDX, 0);
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/* reset rx bm */
111262306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
111362306a36Sopenharmony_ci	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
111462306a36Sopenharmony_ci			  MTK_WED_CTRL_WED_RX_BM_BUSY);
111562306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	/* wo change to enable state */
111862306a36Sopenharmony_ci	val = MTK_WED_WO_STATE_ENABLE;
111962306a36Sopenharmony_ci	ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
112062306a36Sopenharmony_ci				   MTK_WED_WO_CMD_CHANGE_STATE, &val,
112162306a36Sopenharmony_ci				   sizeof(val), true);
112262306a36Sopenharmony_ci	if (ret)
112362306a36Sopenharmony_ci		return ret;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* wed_rx_ring_reset */
112662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++) {
112762306a36Sopenharmony_ci		if (!dev->rx_ring[i].desc)
112862306a36Sopenharmony_ci			continue;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		mtk_wed_ring_reset(&dev->rx_ring[i], MTK_WED_RX_RING_SIZE,
113162306a36Sopenharmony_ci				   false);
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci	mtk_wed_free_rx_buffer(dev);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic void
113962306a36Sopenharmony_cimtk_wed_reset_dma(struct mtk_wed_device *dev)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	bool busy = false;
114262306a36Sopenharmony_ci	u32 val;
114362306a36Sopenharmony_ci	int i;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) {
114662306a36Sopenharmony_ci		if (!dev->tx_ring[i].desc)
114762306a36Sopenharmony_ci			continue;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE,
115062306a36Sopenharmony_ci				   true);
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* 1. reset WED tx DMA */
115462306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_EN);
115562306a36Sopenharmony_ci	busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
115662306a36Sopenharmony_ci				 MTK_WED_GLO_CFG_TX_DMA_BUSY);
115762306a36Sopenharmony_ci	if (busy) {
115862306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
115962306a36Sopenharmony_ci	} else {
116062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
116162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RESET_IDX, 0);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/* 2. reset WDMA rx DMA */
116562306a36Sopenharmony_ci	busy = !!mtk_wdma_rx_reset(dev);
116662306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
116762306a36Sopenharmony_ci	if (!busy)
116862306a36Sopenharmony_ci		busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
116962306a36Sopenharmony_ci					 MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (busy) {
117262306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
117362306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
117462306a36Sopenharmony_ci	} else {
117562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
117662306a36Sopenharmony_ci			MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
117762306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
118062306a36Sopenharmony_ci			MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
118362306a36Sopenharmony_ci			MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE);
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* 3. reset WED WPDMA tx */
118762306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
119062306a36Sopenharmony_ci		val = wed_r32(dev, MTK_WED_TX_BM_INTF);
119162306a36Sopenharmony_ci		if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
119262306a36Sopenharmony_ci			break;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
119662306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_BM_EN);
119762306a36Sopenharmony_ci	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	/* 4. reset WED WPDMA tx */
120062306a36Sopenharmony_ci	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
120162306a36Sopenharmony_ci				 MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
120262306a36Sopenharmony_ci	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
120362306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
120462306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
120562306a36Sopenharmony_ci	if (!busy)
120662306a36Sopenharmony_ci		busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
120762306a36Sopenharmony_ci					 MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (busy) {
121062306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
121162306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
121262306a36Sopenharmony_ci		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
121362306a36Sopenharmony_ci	} else {
121462306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
121562306a36Sopenharmony_ci			MTK_WED_WPDMA_RESET_IDX_TX |
121662306a36Sopenharmony_ci			MTK_WED_WPDMA_RESET_IDX_RX);
121762306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0);
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	dev->init_done = false;
122162306a36Sopenharmony_ci	if (dev->hw->version == 1)
122262306a36Sopenharmony_ci		return;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (!busy) {
122562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_WPDMA_IDX_RX);
122662306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RESET_IDX, 0);
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	mtk_wed_rx_reset(dev);
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic int
123362306a36Sopenharmony_cimtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
123462306a36Sopenharmony_ci		   int size, u32 desc_size, bool tx)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size,
123762306a36Sopenharmony_ci					&ring->desc_phys, GFP_KERNEL);
123862306a36Sopenharmony_ci	if (!ring->desc)
123962306a36Sopenharmony_ci		return -ENOMEM;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	ring->desc_size = desc_size;
124262306a36Sopenharmony_ci	ring->size = size;
124362306a36Sopenharmony_ci	mtk_wed_ring_reset(ring, size, tx);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	return 0;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic int
124962306a36Sopenharmony_cimtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
125062306a36Sopenharmony_ci			   bool reset)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
125362306a36Sopenharmony_ci	struct mtk_wed_ring *wdma;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	if (idx >= ARRAY_SIZE(dev->rx_wdma))
125662306a36Sopenharmony_ci		return -EINVAL;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	wdma = &dev->rx_wdma[idx];
125962306a36Sopenharmony_ci	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
126062306a36Sopenharmony_ci					 desc_size, true))
126162306a36Sopenharmony_ci		return -ENOMEM;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
126462306a36Sopenharmony_ci		 wdma->desc_phys);
126562306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT,
126662306a36Sopenharmony_ci		 size);
126762306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
127062306a36Sopenharmony_ci		wdma->desc_phys);
127162306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT,
127262306a36Sopenharmony_ci		size);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	return 0;
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic int
127862306a36Sopenharmony_cimtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
127962306a36Sopenharmony_ci			   bool reset)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
128262306a36Sopenharmony_ci	struct mtk_wed_ring *wdma;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	if (idx >= ARRAY_SIZE(dev->tx_wdma))
128562306a36Sopenharmony_ci		return -EINVAL;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	wdma = &dev->tx_wdma[idx];
128862306a36Sopenharmony_ci	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
128962306a36Sopenharmony_ci					 desc_size, true))
129062306a36Sopenharmony_ci		return -ENOMEM;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
129362306a36Sopenharmony_ci		 wdma->desc_phys);
129462306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
129562306a36Sopenharmony_ci		 size);
129662306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
129762306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (reset)
130062306a36Sopenharmony_ci		mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (!idx)  {
130362306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE,
130462306a36Sopenharmony_ci			wdma->desc_phys);
130562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_COUNT,
130662306a36Sopenharmony_ci			size);
130762306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_CPU_IDX,
130862306a36Sopenharmony_ci			0);
130962306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_DMA_IDX,
131062306a36Sopenharmony_ci			0);
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	return 0;
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic void
131762306a36Sopenharmony_cimtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
131862306a36Sopenharmony_ci		  u32 reason, u32 hash)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct mtk_eth *eth = dev->hw->eth;
132162306a36Sopenharmony_ci	struct ethhdr *eh;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (!skb)
132462306a36Sopenharmony_ci		return;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	if (reason != MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
132762306a36Sopenharmony_ci		return;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	skb_set_mac_header(skb, 0);
133062306a36Sopenharmony_ci	eh = eth_hdr(skb);
133162306a36Sopenharmony_ci	skb->protocol = eh->h_proto;
133262306a36Sopenharmony_ci	mtk_ppe_check_skb(eth->ppe[dev->hw->index], skb, hash);
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic void
133662306a36Sopenharmony_cimtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	u32 wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* wed control cr set */
134162306a36Sopenharmony_ci	wed_set(dev, MTK_WED_CTRL,
134262306a36Sopenharmony_ci		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
134362306a36Sopenharmony_ci		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
134462306a36Sopenharmony_ci		MTK_WED_CTRL_WED_TX_BM_EN |
134562306a36Sopenharmony_ci		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (dev->hw->version == 1) {
134862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
134962306a36Sopenharmony_ci			MTK_WED_PCIE_INT_TRIGGER_STATUS);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER,
135262306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_TRIGGER_RX_DONE |
135362306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_TRIGGER_TX_DONE);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
135662306a36Sopenharmony_ci	} else {
135762306a36Sopenharmony_ci		wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
135862306a36Sopenharmony_ci					GENMASK(1, 0));
135962306a36Sopenharmony_ci		/* initail tx interrupt trigger */
136062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
136162306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
136262306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR |
136362306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN |
136462306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR |
136562306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG,
136662306a36Sopenharmony_ci				   dev->wlan.tx_tbit[0]) |
136762306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG,
136862306a36Sopenharmony_ci				   dev->wlan.tx_tbit[1]));
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci		/* initail txfree interrupt trigger */
137162306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE,
137262306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN |
137362306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR |
137462306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
137562306a36Sopenharmony_ci				   dev->wlan.txfree_tbit));
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
137862306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_RX0_EN |
137962306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
138062306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_RX1_EN |
138162306a36Sopenharmony_ci			MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
138262306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
138362306a36Sopenharmony_ci				   dev->wlan.rx_tbit[0]) |
138462306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
138562306a36Sopenharmony_ci				   dev->wlan.rx_tbit[1]));
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
138862306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
138962306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL,
139062306a36Sopenharmony_ci				   dev->wdma_idx));
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask);
139662306a36Sopenharmony_ci	wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask);
139762306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
139862306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic void
140262306a36Sopenharmony_cimtk_wed_dma_enable(struct mtk_wed_device *dev)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	wed_set(dev, MTK_WED_GLO_CFG,
140762306a36Sopenharmony_ci		MTK_WED_GLO_CFG_TX_DMA_EN |
140862306a36Sopenharmony_ci		MTK_WED_GLO_CFG_RX_DMA_EN);
140962306a36Sopenharmony_ci	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
141062306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
141162306a36Sopenharmony_ci		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
141262306a36Sopenharmony_ci	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
141362306a36Sopenharmony_ci		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	wdma_set(dev, MTK_WDMA_GLO_CFG,
141662306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
141762306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
141862306a36Sopenharmony_ci		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (dev->hw->version == 1) {
142162306a36Sopenharmony_ci		wdma_set(dev, MTK_WDMA_GLO_CFG,
142262306a36Sopenharmony_ci			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
142362306a36Sopenharmony_ci	} else {
142462306a36Sopenharmony_ci		int i;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WPDMA_CTRL,
142762306a36Sopenharmony_ci			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
143062306a36Sopenharmony_ci			MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
143162306a36Sopenharmony_ci			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
143462306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
143562306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
143862306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
143962306a36Sopenharmony_ci			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
144262306a36Sopenharmony_ci			MTK_WED_WPDMA_RX_D_RX_DRV_EN |
144362306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
144462306a36Sopenharmony_ci			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
144562306a36Sopenharmony_ci				   0x2));
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		for (i = 0; i < MTK_WED_RX_QUEUES; i++)
144862306a36Sopenharmony_ci			mtk_wed_check_wfdma_rx_fill(dev, i);
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic void
145362306a36Sopenharmony_cimtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	int i;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (mtk_wed_get_rx_capa(dev) && mtk_wed_rx_buffer_alloc(dev))
145862306a36Sopenharmony_ci		return;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
146162306a36Sopenharmony_ci		if (!dev->rx_wdma[i].desc)
146262306a36Sopenharmony_ci			mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	mtk_wed_hw_init(dev);
146562306a36Sopenharmony_ci	mtk_wed_configure_irq(dev, irq_mask);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	mtk_wed_set_ext_int(dev, true);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (dev->hw->version == 1) {
147062306a36Sopenharmony_ci		u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
147162306a36Sopenharmony_ci			  FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
147262306a36Sopenharmony_ci				     dev->hw->index);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
147562306a36Sopenharmony_ci		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
147662306a36Sopenharmony_ci	} else {
147762306a36Sopenharmony_ci		/* driver set mid ready and only once */
147862306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_EXT_INT_MASK1,
147962306a36Sopenharmony_ci			MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
148062306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_EXT_INT_MASK2,
148162306a36Sopenharmony_ci			MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci		wed_r32(dev, MTK_WED_EXT_INT_MASK1);
148462306a36Sopenharmony_ci		wed_r32(dev, MTK_WED_EXT_INT_MASK2);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci		if (mtk_wed_rro_cfg(dev))
148762306a36Sopenharmony_ci			return;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	mtk_wed_dma_enable(dev);
149462306a36Sopenharmony_ci	dev->running = true;
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic int
149862306a36Sopenharmony_cimtk_wed_attach(struct mtk_wed_device *dev)
149962306a36Sopenharmony_ci	__releases(RCU)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	struct mtk_wed_hw *hw;
150262306a36Sopenharmony_ci	struct device *device;
150362306a36Sopenharmony_ci	int ret = 0;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
150662306a36Sopenharmony_ci			 "mtk_wed_attach without holding the RCU read lock");
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE &&
150962306a36Sopenharmony_ci	     pci_domain_nr(dev->wlan.pci_dev->bus) > 1) ||
151062306a36Sopenharmony_ci	    !try_module_get(THIS_MODULE))
151162306a36Sopenharmony_ci		ret = -ENODEV;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	rcu_read_unlock();
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (ret)
151662306a36Sopenharmony_ci		return ret;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	mutex_lock(&hw_lock);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	hw = mtk_wed_assign(dev);
152162306a36Sopenharmony_ci	if (!hw) {
152262306a36Sopenharmony_ci		module_put(THIS_MODULE);
152362306a36Sopenharmony_ci		ret = -ENODEV;
152462306a36Sopenharmony_ci		goto unlock;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE
152862306a36Sopenharmony_ci		? &dev->wlan.pci_dev->dev
152962306a36Sopenharmony_ci		: &dev->wlan.platform_dev->dev;
153062306a36Sopenharmony_ci	dev_info(device, "attaching wed device %d version %d\n",
153162306a36Sopenharmony_ci		 hw->index, hw->version);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	dev->hw = hw;
153462306a36Sopenharmony_ci	dev->dev = hw->dev;
153562306a36Sopenharmony_ci	dev->irq = hw->irq;
153662306a36Sopenharmony_ci	dev->wdma_idx = hw->index;
153762306a36Sopenharmony_ci	dev->version = hw->version;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (hw->eth->dma_dev == hw->eth->dev &&
154062306a36Sopenharmony_ci	    of_dma_is_coherent(hw->eth->dev->of_node))
154162306a36Sopenharmony_ci		mtk_eth_set_dma_device(hw->eth, hw->dev);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	ret = mtk_wed_tx_buffer_alloc(dev);
154462306a36Sopenharmony_ci	if (ret)
154562306a36Sopenharmony_ci		goto out;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	if (mtk_wed_get_rx_capa(dev)) {
154862306a36Sopenharmony_ci		ret = mtk_wed_rro_alloc(dev);
154962306a36Sopenharmony_ci		if (ret)
155062306a36Sopenharmony_ci			goto out;
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	mtk_wed_hw_init_early(dev);
155462306a36Sopenharmony_ci	if (hw->version == 1) {
155562306a36Sopenharmony_ci		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
155662306a36Sopenharmony_ci				   BIT(hw->index), 0);
155762306a36Sopenharmony_ci	} else {
155862306a36Sopenharmony_ci		dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
155962306a36Sopenharmony_ci		ret = mtk_wed_wo_init(hw);
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ciout:
156262306a36Sopenharmony_ci	if (ret) {
156362306a36Sopenharmony_ci		dev_err(dev->hw->dev, "failed to attach wed device\n");
156462306a36Sopenharmony_ci		__mtk_wed_detach(dev);
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ciunlock:
156762306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	return ret;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic int
157362306a36Sopenharmony_cimtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs,
157462306a36Sopenharmony_ci		      bool reset)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	struct mtk_wed_ring *ring = &dev->tx_ring[idx];
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	/*
157962306a36Sopenharmony_ci	 * Tx ring redirection:
158062306a36Sopenharmony_ci	 * Instead of configuring the WLAN PDMA TX ring directly, the WLAN
158162306a36Sopenharmony_ci	 * driver allocated DMA ring gets configured into WED MTK_WED_RING_TX(n)
158262306a36Sopenharmony_ci	 * registers.
158362306a36Sopenharmony_ci	 *
158462306a36Sopenharmony_ci	 * WED driver posts its own DMA ring as WLAN PDMA TX and configures it
158562306a36Sopenharmony_ci	 * into MTK_WED_WPDMA_RING_TX(n) registers.
158662306a36Sopenharmony_ci	 * It gets filled with packets picked up from WED TX ring and from
158762306a36Sopenharmony_ci	 * WDMA RX.
158862306a36Sopenharmony_ci	 */
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring)))
159162306a36Sopenharmony_ci		return -EINVAL;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
159462306a36Sopenharmony_ci					 sizeof(*ring->desc), true))
159562306a36Sopenharmony_ci		return -ENOMEM;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
159862306a36Sopenharmony_ci				       reset))
159962306a36Sopenharmony_ci		return -ENOMEM;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	ring->reg_base = MTK_WED_RING_TX(idx);
160262306a36Sopenharmony_ci	ring->wpdma = regs;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	/* WED -> WPDMA */
160562306a36Sopenharmony_ci	wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
160662306a36Sopenharmony_ci	wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_TX_RING_SIZE);
160762306a36Sopenharmony_ci	wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_CPU_IDX, 0);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
161062306a36Sopenharmony_ci		ring->desc_phys);
161162306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
161262306a36Sopenharmony_ci		MTK_WED_TX_RING_SIZE);
161362306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	return 0;
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_cistatic int
161962306a36Sopenharmony_cimtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	struct mtk_wed_ring *ring = &dev->txfree_ring;
162262306a36Sopenharmony_ci	int i, index = dev->hw->version == 1;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/*
162562306a36Sopenharmony_ci	 * For txfree event handling, the same DMA ring is shared between WED
162662306a36Sopenharmony_ci	 * and WLAN. The WLAN driver accesses the ring index registers through
162762306a36Sopenharmony_ci	 * WED
162862306a36Sopenharmony_ci	 */
162962306a36Sopenharmony_ci	ring->reg_base = MTK_WED_RING_RX(index);
163062306a36Sopenharmony_ci	ring->wpdma = regs;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	for (i = 0; i < 12; i += 4) {
163362306a36Sopenharmony_ci		u32 val = readl(regs + i);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_RING_RX(index) + i, val);
163662306a36Sopenharmony_ci		wed_w32(dev, MTK_WED_WPDMA_RING_RX(index) + i, val);
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	return 0;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic int
164362306a36Sopenharmony_cimtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs,
164462306a36Sopenharmony_ci		      bool reset)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	struct mtk_wed_ring *ring = &dev->rx_ring[idx];
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring)))
164962306a36Sopenharmony_ci		return -EINVAL;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
165262306a36Sopenharmony_ci					 sizeof(*ring->desc), false))
165362306a36Sopenharmony_ci		return -ENOMEM;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
165662306a36Sopenharmony_ci				       reset))
165762306a36Sopenharmony_ci		return -ENOMEM;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	ring->reg_base = MTK_WED_RING_RX_DATA(idx);
166062306a36Sopenharmony_ci	ring->wpdma = regs;
166162306a36Sopenharmony_ci	ring->flags |= MTK_WED_RING_CONFIGURED;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/* WPDMA ->  WED */
166462306a36Sopenharmony_ci	wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
166562306a36Sopenharmony_ci	wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_RX_RING_SIZE);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_RING_RX_DATA(idx) + MTK_WED_RING_OFS_BASE,
166862306a36Sopenharmony_ci		ring->desc_phys);
166962306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_WPDMA_RING_RX_DATA(idx) + MTK_WED_RING_OFS_COUNT,
167062306a36Sopenharmony_ci		MTK_WED_RX_RING_SIZE);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	return 0;
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic u32
167662306a36Sopenharmony_cimtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (dev->hw->version == 1)
168162306a36Sopenharmony_ci		ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
168262306a36Sopenharmony_ci	else
168362306a36Sopenharmony_ci		ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
168462306a36Sopenharmony_ci			    MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH |
168562306a36Sopenharmony_ci			    MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
168662306a36Sopenharmony_ci			    MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
168962306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
169062306a36Sopenharmony_ci	val &= ext_mask;
169162306a36Sopenharmony_ci	if (!dev->hw->num_flows)
169262306a36Sopenharmony_ci		val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
169362306a36Sopenharmony_ci	if (val && net_ratelimit())
169462306a36Sopenharmony_ci		pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	val = wed_r32(dev, MTK_WED_INT_STATUS);
169762306a36Sopenharmony_ci	val &= mask;
169862306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_INT_STATUS, val); /* ACK */
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return val;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic void
170462306a36Sopenharmony_cimtk_wed_irq_set_mask(struct mtk_wed_device *dev, u32 mask)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	if (!dev->running)
170762306a36Sopenharmony_ci		return;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	mtk_wed_set_ext_int(dev, !!mask);
171062306a36Sopenharmony_ci	wed_w32(dev, MTK_WED_INT_MASK, mask);
171162306a36Sopenharmony_ci}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ciint mtk_wed_flow_add(int index)
171462306a36Sopenharmony_ci{
171562306a36Sopenharmony_ci	struct mtk_wed_hw *hw = hw_list[index];
171662306a36Sopenharmony_ci	int ret;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (!hw || !hw->wed_dev)
171962306a36Sopenharmony_ci		return -ENODEV;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	if (hw->num_flows) {
172262306a36Sopenharmony_ci		hw->num_flows++;
172362306a36Sopenharmony_ci		return 0;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	mutex_lock(&hw_lock);
172762306a36Sopenharmony_ci	if (!hw->wed_dev) {
172862306a36Sopenharmony_ci		ret = -ENODEV;
172962306a36Sopenharmony_ci		goto out;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	ret = hw->wed_dev->wlan.offload_enable(hw->wed_dev);
173362306a36Sopenharmony_ci	if (!ret)
173462306a36Sopenharmony_ci		hw->num_flows++;
173562306a36Sopenharmony_ci	mtk_wed_set_ext_int(hw->wed_dev, true);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ciout:
173862306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	return ret;
174162306a36Sopenharmony_ci}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_civoid mtk_wed_flow_remove(int index)
174462306a36Sopenharmony_ci{
174562306a36Sopenharmony_ci	struct mtk_wed_hw *hw = hw_list[index];
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (!hw)
174862306a36Sopenharmony_ci		return;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	if (--hw->num_flows)
175162306a36Sopenharmony_ci		return;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	mutex_lock(&hw_lock);
175462306a36Sopenharmony_ci	if (!hw->wed_dev)
175562306a36Sopenharmony_ci		goto out;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	hw->wed_dev->wlan.offload_disable(hw->wed_dev);
175862306a36Sopenharmony_ci	mtk_wed_set_ext_int(hw->wed_dev, true);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ciout:
176162306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_cistatic int
176562306a36Sopenharmony_cimtk_wed_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	struct mtk_wed_flow_block_priv *priv = cb_priv;
176862306a36Sopenharmony_ci	struct flow_cls_offload *cls = type_data;
176962306a36Sopenharmony_ci	struct mtk_wed_hw *hw = priv->hw;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (!tc_can_offload(priv->dev))
177262306a36Sopenharmony_ci		return -EOPNOTSUPP;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (type != TC_SETUP_CLSFLOWER)
177562306a36Sopenharmony_ci		return -EOPNOTSUPP;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	return mtk_flow_offload_cmd(hw->eth, cls, hw->index);
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_cistatic int
178162306a36Sopenharmony_cimtk_wed_setup_tc_block(struct mtk_wed_hw *hw, struct net_device *dev,
178262306a36Sopenharmony_ci		       struct flow_block_offload *f)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	struct mtk_wed_flow_block_priv *priv;
178562306a36Sopenharmony_ci	static LIST_HEAD(block_cb_list);
178662306a36Sopenharmony_ci	struct flow_block_cb *block_cb;
178762306a36Sopenharmony_ci	struct mtk_eth *eth = hw->eth;
178862306a36Sopenharmony_ci	flow_setup_cb_t *cb;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	if (!eth->soc->offload_version)
179162306a36Sopenharmony_ci		return -EOPNOTSUPP;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
179462306a36Sopenharmony_ci		return -EOPNOTSUPP;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	cb = mtk_wed_setup_tc_block_cb;
179762306a36Sopenharmony_ci	f->driver_block_list = &block_cb_list;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	switch (f->command) {
180062306a36Sopenharmony_ci	case FLOW_BLOCK_BIND:
180162306a36Sopenharmony_ci		block_cb = flow_block_cb_lookup(f->block, cb, dev);
180262306a36Sopenharmony_ci		if (block_cb) {
180362306a36Sopenharmony_ci			flow_block_cb_incref(block_cb);
180462306a36Sopenharmony_ci			return 0;
180562306a36Sopenharmony_ci		}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
180862306a36Sopenharmony_ci		if (!priv)
180962306a36Sopenharmony_ci			return -ENOMEM;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci		priv->hw = hw;
181262306a36Sopenharmony_ci		priv->dev = dev;
181362306a36Sopenharmony_ci		block_cb = flow_block_cb_alloc(cb, dev, priv, NULL);
181462306a36Sopenharmony_ci		if (IS_ERR(block_cb)) {
181562306a36Sopenharmony_ci			kfree(priv);
181662306a36Sopenharmony_ci			return PTR_ERR(block_cb);
181762306a36Sopenharmony_ci		}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci		flow_block_cb_incref(block_cb);
182062306a36Sopenharmony_ci		flow_block_cb_add(block_cb, f);
182162306a36Sopenharmony_ci		list_add_tail(&block_cb->driver_list, &block_cb_list);
182262306a36Sopenharmony_ci		return 0;
182362306a36Sopenharmony_ci	case FLOW_BLOCK_UNBIND:
182462306a36Sopenharmony_ci		block_cb = flow_block_cb_lookup(f->block, cb, dev);
182562306a36Sopenharmony_ci		if (!block_cb)
182662306a36Sopenharmony_ci			return -ENOENT;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		if (!flow_block_cb_decref(block_cb)) {
182962306a36Sopenharmony_ci			flow_block_cb_remove(block_cb, f);
183062306a36Sopenharmony_ci			list_del(&block_cb->driver_list);
183162306a36Sopenharmony_ci			kfree(block_cb->cb_priv);
183262306a36Sopenharmony_ci		}
183362306a36Sopenharmony_ci		return 0;
183462306a36Sopenharmony_ci	default:
183562306a36Sopenharmony_ci		return -EOPNOTSUPP;
183662306a36Sopenharmony_ci	}
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_cistatic int
184062306a36Sopenharmony_cimtk_wed_setup_tc(struct mtk_wed_device *wed, struct net_device *dev,
184162306a36Sopenharmony_ci		 enum tc_setup_type type, void *type_data)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	struct mtk_wed_hw *hw = wed->hw;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (hw->version < 2)
184662306a36Sopenharmony_ci		return -EOPNOTSUPP;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	switch (type) {
184962306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
185062306a36Sopenharmony_ci	case TC_SETUP_FT:
185162306a36Sopenharmony_ci		return mtk_wed_setup_tc_block(hw, dev, type_data);
185262306a36Sopenharmony_ci	default:
185362306a36Sopenharmony_ci		return -EOPNOTSUPP;
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_civoid mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
185862306a36Sopenharmony_ci		    void __iomem *wdma, phys_addr_t wdma_phy,
185962306a36Sopenharmony_ci		    int index)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	static const struct mtk_wed_ops wed_ops = {
186262306a36Sopenharmony_ci		.attach = mtk_wed_attach,
186362306a36Sopenharmony_ci		.tx_ring_setup = mtk_wed_tx_ring_setup,
186462306a36Sopenharmony_ci		.rx_ring_setup = mtk_wed_rx_ring_setup,
186562306a36Sopenharmony_ci		.txfree_ring_setup = mtk_wed_txfree_ring_setup,
186662306a36Sopenharmony_ci		.msg_update = mtk_wed_mcu_msg_update,
186762306a36Sopenharmony_ci		.start = mtk_wed_start,
186862306a36Sopenharmony_ci		.stop = mtk_wed_stop,
186962306a36Sopenharmony_ci		.reset_dma = mtk_wed_reset_dma,
187062306a36Sopenharmony_ci		.reg_read = wed_r32,
187162306a36Sopenharmony_ci		.reg_write = wed_w32,
187262306a36Sopenharmony_ci		.irq_get = mtk_wed_irq_get,
187362306a36Sopenharmony_ci		.irq_set_mask = mtk_wed_irq_set_mask,
187462306a36Sopenharmony_ci		.detach = mtk_wed_detach,
187562306a36Sopenharmony_ci		.ppe_check = mtk_wed_ppe_check,
187662306a36Sopenharmony_ci		.setup_tc = mtk_wed_setup_tc,
187762306a36Sopenharmony_ci	};
187862306a36Sopenharmony_ci	struct device_node *eth_np = eth->dev->of_node;
187962306a36Sopenharmony_ci	struct platform_device *pdev;
188062306a36Sopenharmony_ci	struct mtk_wed_hw *hw;
188162306a36Sopenharmony_ci	struct regmap *regs;
188262306a36Sopenharmony_ci	int irq;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	if (!np)
188562306a36Sopenharmony_ci		return;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	pdev = of_find_device_by_node(np);
188862306a36Sopenharmony_ci	if (!pdev)
188962306a36Sopenharmony_ci		goto err_of_node_put;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	get_device(&pdev->dev);
189262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
189362306a36Sopenharmony_ci	if (irq < 0)
189462306a36Sopenharmony_ci		goto err_put_device;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	regs = syscon_regmap_lookup_by_phandle(np, NULL);
189762306a36Sopenharmony_ci	if (IS_ERR(regs))
189862306a36Sopenharmony_ci		goto err_put_device;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	mutex_lock(&hw_lock);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (WARN_ON(hw_list[index]))
190562306a36Sopenharmony_ci		goto unlock;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
190862306a36Sopenharmony_ci	if (!hw)
190962306a36Sopenharmony_ci		goto unlock;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	hw->node = np;
191262306a36Sopenharmony_ci	hw->regs = regs;
191362306a36Sopenharmony_ci	hw->eth = eth;
191462306a36Sopenharmony_ci	hw->dev = &pdev->dev;
191562306a36Sopenharmony_ci	hw->wdma_phy = wdma_phy;
191662306a36Sopenharmony_ci	hw->wdma = wdma;
191762306a36Sopenharmony_ci	hw->index = index;
191862306a36Sopenharmony_ci	hw->irq = irq;
191962306a36Sopenharmony_ci	hw->version = mtk_is_netsys_v1(eth) ? 1 : 2;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (hw->version == 1) {
192262306a36Sopenharmony_ci		hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
192362306a36Sopenharmony_ci				"mediatek,pcie-mirror");
192462306a36Sopenharmony_ci		hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
192562306a36Sopenharmony_ci				"mediatek,hifsys");
192662306a36Sopenharmony_ci		if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) {
192762306a36Sopenharmony_ci			kfree(hw);
192862306a36Sopenharmony_ci			goto unlock;
192962306a36Sopenharmony_ci		}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci		if (!index) {
193262306a36Sopenharmony_ci			regmap_write(hw->mirror, 0, 0);
193362306a36Sopenharmony_ci			regmap_write(hw->mirror, 4, 0);
193462306a36Sopenharmony_ci		}
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	mtk_wed_hw_add_debugfs(hw);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	hw_list[index] = hw;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	return;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ciunlock:
194662306a36Sopenharmony_ci	mutex_unlock(&hw_lock);
194762306a36Sopenharmony_cierr_put_device:
194862306a36Sopenharmony_ci	put_device(&pdev->dev);
194962306a36Sopenharmony_cierr_of_node_put:
195062306a36Sopenharmony_ci	of_node_put(np);
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_civoid mtk_wed_exit(void)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	int i;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	rcu_assign_pointer(mtk_soc_wed_ops, NULL);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	synchronize_rcu();
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
196262306a36Sopenharmony_ci		struct mtk_wed_hw *hw;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		hw = hw_list[i];
196562306a36Sopenharmony_ci		if (!hw)
196662306a36Sopenharmony_ci			continue;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		hw_list[i] = NULL;
196962306a36Sopenharmony_ci		debugfs_remove(hw->debugfs_dir);
197062306a36Sopenharmony_ci		put_device(hw->dev);
197162306a36Sopenharmony_ci		of_node_put(hw->node);
197262306a36Sopenharmony_ci		kfree(hw);
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci}
1975