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