blob: e1770c9fbda19be7c42a63ad7eb1a11182147386 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
*
* Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <mtk_hnat/hnat.h>
#include <pce/netsys.h>
#include "tops/hpdma.h"
#include "tops/internal.h"
#include "tops/mcu.h"
#include "tops/netsys.h"
#include "tops/tdma.h"
#include "tops/trm.h"
/* Netsys dump length */
#define FE_BASE_LEN (0x2900)
#define PPE_DEFAULT_ENTRY_SIZE (0x400)
static int netsys_trm_hw_dump(void *dst, u32 ofs, u32 len);
struct netsys_hw {
void __iomem *base;
u32 ppe_num;
};
static struct netsys_hw netsys;
static struct trm_config netsys_trm_configs[] = {
{
TRM_CFG_EN("netsys-fe",
FE_BASE, FE_BASE_LEN,
0x0, FE_BASE_LEN,
0)
},
};
static struct trm_hw_config netsys_trm_hw_cfg = {
.trm_cfgs = netsys_trm_configs,
.cfg_len = ARRAY_SIZE(netsys_trm_configs),
.trm_hw_dump = netsys_trm_hw_dump,
};
static inline void netsys_write(u32 reg, u32 val)
{
writel(val, netsys.base + reg);
}
static inline void netsys_set(u32 reg, u32 mask)
{
setbits(netsys.base + reg, mask);
}
static inline void netsys_clr(u32 reg, u32 mask)
{
clrbits(netsys.base + reg, mask);
}
static inline void netsys_rmw(u32 reg, u32 mask, u32 val)
{
clrsetbits(netsys.base + reg, mask, val);
}
static inline u32 netsys_read(u32 reg)
{
return readl(netsys.base + reg);
}
static int netsys_trm_hw_dump(void *dst, u32 start_addr, u32 len)
{
u32 ofs;
if (unlikely(!dst))
return -ENODEV;
for (ofs = 0; len > 0; len -= 0x4, ofs += 0x4)
writel(netsys_read(start_addr + ofs), dst + ofs);
return 0;
}
static inline void ppe_rmw(enum pse_port ppe, u32 reg, u32 mask, u32 val)
{
if (ppe == PSE_PORT_PPE0)
netsys_rmw(PPE0_BASE + reg, mask, val);
else if (ppe == PSE_PORT_PPE1)
netsys_rmw(PPE1_BASE + reg, mask, val);
else if (ppe == PSE_PORT_PPE2)
netsys_rmw(PPE2_BASE + reg, mask, val);
}
static inline u32 ppe_read(enum pse_port ppe, u32 reg)
{
if (ppe == PSE_PORT_PPE0)
return netsys_read(PPE0_BASE + reg);
else if (ppe == PSE_PORT_PPE1)
return netsys_read(PPE1_BASE + reg);
else if (ppe == PSE_PORT_PPE2)
return netsys_read(PPE2_BASE + reg);
return 0;
}
u32 mtk_tops_netsys_ppe_get_num(void)
{
return netsys.ppe_num;
}
u32 mtk_tops_netsys_ppe_get_max_entry_num(u32 ppe_id)
{
u32 tbl_entry_num;
enum pse_port ppe;
if (ppe_id == 0)
ppe = PSE_PORT_PPE0;
else if (ppe_id == 1)
ppe = PSE_PORT_PPE1;
else if (ppe_id == 2)
ppe = PSE_PORT_PPE2;
else
return PPE_DEFAULT_ENTRY_SIZE << 5; /* max entry count */
tbl_entry_num = ppe_read(ppe, PPE_TBL_CFG);
if (tbl_entry_num > 5)
return PPE_DEFAULT_ENTRY_SIZE << 5;
return PPE_DEFAULT_ENTRY_SIZE << tbl_entry_num;
}
static int mtk_tops_netsys_base_init(struct platform_device *pdev)
{
struct device_node *fe_mem = NULL;
struct resource res;
int ret = 0;
fe_mem = of_parse_phandle(pdev->dev.of_node, "fe_mem", 0);
if (!fe_mem) {
TOPS_ERR("can not find fe_mem node\n");
return -ENODEV;
}
if (of_address_to_resource(fe_mem, 0, &res)) {
ret = -ENXIO;
goto out;
}
netsys.base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
if (!netsys.base) {
ret = -ENOMEM;
goto out;
}
out:
of_node_put(fe_mem);
return ret;
}
static int mtk_tops_netsys_ppe_num_init(struct platform_device *pdev)
{
struct device_node *hnat = NULL;
u32 val = 0;
int ret = 0;
hnat = of_parse_phandle(pdev->dev.of_node, "hnat", 0);
if (!hnat) {
TOPS_ERR("can not find hnat node\n");
return -ENODEV;
}
ret = of_property_read_u32(hnat, "mtketh-ppe-num", &val);
if (ret)
netsys.ppe_num = 1;
else
netsys.ppe_num = val;
of_node_put(hnat);
return 0;
}
int mtk_tops_netsys_init(struct platform_device *pdev)
{
int ret;
ret = mtk_tops_netsys_base_init(pdev);
if (ret)
return ret;
ret = mtk_tops_netsys_ppe_num_init(pdev);
if (ret)
return ret;
ret = mtk_trm_hw_config_register(TRM_NETSYS, &netsys_trm_hw_cfg);
if (ret)
return ret;
return ret;
}
void mtk_tops_netsys_deinit(struct platform_device *pdev)
{
mtk_trm_hw_config_unregister(TRM_NETSYS, &netsys_trm_hw_cfg);
}