1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-09-26 19:04:54 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

587 lines
14 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/types.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <apusys_device.h>
#include <common/mdla_driver.h>
#include <common/mdla_device.h>
#include <utilities/mdla_debug.h>
#include <utilities/mdla_util.h>
#include <utilities/mdla_profile.h>
#include <platform/mdla_plat_api.h>
struct mdla_pmu_result {
u16 cmd_len;
u16 cmd_id;
u32 pmu_val[MDLA_PMU_COUNTERS + 1]; /* global counter + PMU counter*/
};
/* platform */
u32 mdla_util_get_core_num(void)
{
return mdla_plat_get_core_num();
}
u32 mdla_util_get_ip_version(void)
{
return get_major_num(mdla_plat_get_version());
}
const struct of_device_id *mdla_util_get_device_id(void)
{
return mdla_plat_get_device();
}
int mdla_util_plat_init(struct platform_device *pdev)
{
if (mdla_plat_init(pdev) != 0)
return -1;
mdla_dbg_fs_setup(&pdev->dev);
if (mdla_plat_micro_p_support())
return 1;
//mdla_drv_create_device_node(&pdev->dev);
mdla_prof_init(mdla_plat_get_prof_ver());
return 0;
}
void mdla_util_plat_deinit(struct platform_device *pdev)
{
if (!mdla_plat_micro_p_support()) {
mdla_prof_deinit();
mdla_drv_destroy_device_node();
}
mdla_plat_deinit(pdev);
}
/* pmu */
static void mdla_util_dummy_cnt_save(u32 a0, struct mdla_pmu_info *a1) {}
static void mdla_util_dummy_cnt_read(u32 a0, u32 *a1) {}
static void mdla_util_dummy_cnt_clr(struct mdla_pmu_info *pmu) {}
static u32 mdla_util_dummy_get_num_evt(u32 a0, int a1)
{
return 0;
}
static void mdla_util_dummy_set_num_evt(u32 a0, int a1, int a2) {}
static void mdla_util_dummy_set_mode(struct mdla_pmu_info *a0, u32 a1) {}
static int mdla_util_dummy_get_mode(struct mdla_pmu_info *a0)
{
return 0;
}
static u64 mdla_util_dummy_get_addr(struct mdla_pmu_info *a0)
{
return 0;
}
static u32 mdla_util_dummy_get_val(struct mdla_pmu_info *a0)
{
return 0;
}
static u16 mdla_util_dummy_get_cmdcnt(struct mdla_pmu_info *a0)
{
return 0;
}
static u32 mdla_util_dummy_get_data(struct mdla_pmu_info *a0, u32 a1)
{
return 0;
}
static void mdla_util_dummy_ops(u32 a0) {}
static void mdla_util_dummy_exec(u32 a0, u16 a1) {}
static struct mdla_pmu_info *mdla_util_dummy_get_info(u32 a0, u16 a1)
{
return NULL;
}
static void mdla_util_dummy_set_evt(struct mdla_pmu_info *a0,
u32 a1, u32 a2)
{
}
static int mdla_util_dummy_prepare(struct mdla_dev *mdla_info,
struct apusys_cmd_handle *apusys_hd, u16 priority)
{
return 0;
}
static struct mdla_util_pmu_ops pmu_ops = {
.reg_counter_save = mdla_util_dummy_cnt_save,
.reg_counter_read = mdla_util_dummy_cnt_read,
.clr_counter_variable = mdla_util_dummy_cnt_clr,
.clr_cycle_variable = mdla_util_dummy_cnt_clr,
.get_num_evt = mdla_util_dummy_get_num_evt,
.set_num_evt = mdla_util_dummy_set_num_evt,
.set_percmd_mode = mdla_util_dummy_set_mode,
.get_curr_mode = mdla_util_dummy_get_mode,
.get_perf_end = mdla_util_dummy_get_val,
.get_perf_cycle = mdla_util_dummy_get_val,
.get_perf_cmdid = mdla_util_dummy_get_cmdcnt,
.get_perf_cmdcnt = mdla_util_dummy_get_cmdcnt,
.get_counter = mdla_util_dummy_get_data,
.reset_counter = mdla_util_dummy_ops,
.disable_counter = mdla_util_dummy_ops,
.enable_counter = mdla_util_dummy_ops,
.reset = mdla_util_dummy_ops,
.write_evt_exec = mdla_util_dummy_exec,
.reset_write_evt_exec = mdla_util_dummy_exec,
.get_hnd_evt = mdla_util_dummy_get_data,
.get_hnd_evt_num = mdla_util_dummy_get_val,
.get_hnd_mode = mdla_util_dummy_get_val,
.get_hnd_buf_addr = mdla_util_dummy_get_addr,
.get_hnd_buf_size = mdla_util_dummy_get_val,
.set_evt_handle = mdla_util_dummy_set_evt,
.get_info = mdla_util_dummy_get_info,
.apu_cmd_prepare = mdla_util_dummy_prepare,
};
struct mdla_util_pmu_ops *mdla_util_pmu_ops_get(void)
{
return &pmu_ops;
}
/* apusys pmu */
static bool mdla_util_pmu_addr_is_invalid(struct apusys_cmd_handle *apusys_hd)
{
if (apusys_hd->num_cmdbufs < CMD_PMU_BUF_0_IDX + 1)
return true;
if (!apusys_hd->cmdbufs[CMD_PMU_INFO_IDX].kva ||
!apusys_hd->cmdbufs[CMD_PMU_BUF_0_IDX].kva)
return true;
if (apusys_hd->multicore_total == 2) {
if ((apusys_hd->num_cmdbufs < CMD_PMU_BUF_1_IDX + 1) ||
!apusys_hd->cmdbufs[CMD_PMU_BUF_1_IDX].kva) {
return true;
}
mdla_pmu_debug("pmu kva: buf0 = %08llx, buf1 = %08llx\n",
(u64)apusys_hd->cmdbufs[CMD_PMU_BUF_0_IDX].kva,
(u64)apusys_hd->cmdbufs[CMD_PMU_BUF_1_IDX].kva);
} else {
mdla_pmu_debug("pmu kva: buf0 = %08llx\n",
(u64)apusys_hd->cmdbufs[CMD_PMU_BUF_0_IDX].kva);
}
return false;
}
static bool apusys_pmu_support;
void mdla_util_pmu_cmd_timer(bool enable)
{
/* Not support polling pmu data with per cmd mode yet */
}
/* initial local variable and extract pmu setting from input */
int mdla_util_apu_pmu_handle(struct mdla_dev *mdla_info,
struct apusys_cmd_handle *apusys_hd, u16 priority)
{
int i, pmu_mode;
u32 evt, evt_num;
struct mdla_pmu_info *pmu;
u32 core_id;
core_id = mdla_info->mdla_id;
pmu = pmu_ops.get_info(core_id, priority);
if (!pmu) {
mdla_err("%s: No pmu info device\n", __func__);
return -1;
}
pmu_ops.clr_counter_variable(pmu);
pmu_ops.clr_cycle_variable(pmu);
if (mdla_prof_use_dbgfs_pmu_event(mdla_info->mdla_id)) {
pmu_ops.set_num_evt(core_id,
priority, MDLA_PMU_COUNTERS);
for (i = 0; i < MDLA_PMU_COUNTERS; i++) {
evt = mdla_dbg_read_u32(FS_C1 + i);
pmu_ops.set_evt_handle(pmu, i,
(evt & 0x1f0000) | (evt & 0xf));
}
return 0;
}
if (!apusys_pmu_support)
return -1;
if (mdla_util_pmu_addr_is_invalid(apusys_hd)) {
for (i = 0; i < MDLA_PMU_COUNTERS; i++)
pmu_ops.set_evt_handle(pmu, i, COUNTER_CLEAR);
return -1;
}
if (pmu_ops.apu_cmd_prepare(mdla_info, apusys_hd, priority))
return -1;
pmu_mode = pmu_ops.get_curr_mode(pmu);
evt_num = pmu_ops.get_hnd_evt_num(pmu);
/* save to local variable */
pmu_ops.set_percmd_mode(pmu, pmu_mode);
pmu_ops.set_num_evt(core_id, priority,
evt_num);
mdla_pmu_debug("PMU number_of_event:%d, mode: %d\n",
evt_num,
pmu_mode);
for (i = 0; i < evt_num; i++) {
evt = pmu_ops.get_hnd_evt(pmu, i);
pmu_ops.set_evt_handle(pmu, i,
((evt & 0x1f00) << 8) | (evt & 0xf));
}
return 0;
}
void mdla_util_apu_pmu_update(struct mdla_dev *mdla_info,
struct apusys_cmd_handle *apusys_hd, u16 priority)
{
int i;
struct mdla_pmu_result result;
void *base = NULL, *desc = NULL, *src = NULL;
int sz = 0;
//int event_num = 0;
int offset = 0;
//u16 final_len = 0;
u16 loop_count;
u32 core_id;
struct mdla_pmu_info *pmu;
if (!apusys_pmu_support)
return;
/* FIXME: NOT always upload pmu info to NN? */
if (mdla_prof_use_dbgfs_pmu_event(mdla_info->mdla_id))
return;
if (mdla_util_pmu_addr_is_invalid(apusys_hd))
return;
core_id = mdla_info->mdla_id;
pmu = pmu_ops.get_info(core_id, priority);
if (!pmu) {
mdla_err("%s: no pmu info device(core:%d, prio:%d)\n",
__func__, core_id, priority);
return;
}
//loop_count = pmu->pmu_hnd->number_of_event;
loop_count = pmu_ops.get_hnd_evt_num(pmu);
//event_num = loop_count + 1;
//result.cmd_len = pmu->data.l_cmd_cnt;
result.cmd_len = pmu_ops.get_perf_cmdcnt(pmu);
result.cmd_id = pmu_ops.get_perf_cmdid(pmu);
if (pmu_ops.get_curr_mode(pmu) == PER_CMD) {
mdla_util_pmu_cmd_timer(false);
result.pmu_val[0] = pmu_ops.get_perf_end(pmu);
} else {
result.pmu_val[0] = pmu_ops.get_perf_cycle(pmu);
}
mdla_pmu_debug("global counter:%08x\n", result.pmu_val[0]);
for (i = 1; i < loop_count; i++) {
result.pmu_val[i] =
pmu_ops.get_counter(pmu, i);
mdla_pmu_debug("event %d cnt :%08x\n",
i, result.pmu_val[i]);
}
mdla_pmu_debug("mode: %d, cmd_len: %d, cmd_id: %d\n",
pmu_ops.get_hnd_mode(pmu),
result.cmd_len, result.cmd_id);
sz = sizeof(struct mdla_pmu_result) - sizeof(u16);
base = (void *)pmu_ops.get_hnd_buf_addr(pmu);
if (result.cmd_len)
offset = sizeof(u16) + (result.cmd_len - 1) * sz;
else
return;
/* update command length */
((struct mdla_pmu_result *)base)->cmd_len = result.cmd_len;
if (pmu_ops.get_hnd_buf_size(pmu) < offset + sz)
return;
/* update current command pmu result */
desc = (void *)(base + offset);
src = (void *)&(result.cmd_id);
memcpy(desc, src, sz);
if (result.cmd_id == mdla_info->max_cmd_id) {
if (unlikely(mdla_dbg_read_u32(FS_KLOG) & MDLA_DBG_PMU)) {
struct mdla_pmu_result check;
memset((void *)&check, 0, sizeof(struct mdla_pmu_result));
check.cmd_len = ((struct mdla_pmu_result *)base)->cmd_len;
memcpy((void *)&(check.cmd_id), desc, sz);
mdla_pmu_debug("[-] check cmd_len: %d\n", check.cmd_len);
mdla_pmu_debug("[-] check offset: %d\n", offset);
mdla_pmu_debug("[-] check cmd_id: %d\n", check.cmd_id);
mdla_pmu_debug("[-] check cmd_val[1]: %08x\n", check.pmu_val[1]);
}
}
}
void mdla_util_apusys_pmu_support(bool enable)
{
apusys_pmu_support = enable;
}
/* IO operation */
static struct mdla_reg_ctl *mdla_reg_control;
static void *apu_conn_top;
static void *infracfg_ao_top;
static u32 mdla_util_dummy_core_r(u32 i, u32 ofs) { return 0; }
static void mdla_util_dummy_core_w(u32 i, u32 ofs, u32 val) {}
static u32 mdla_util_dummy_r(u32 ofs) { return 0; }
static void mdla_util_dummy_w(u32 ofs, u32 val) {}
static struct mdla_util_io_ops io_ops = {
.cfg = { .read = mdla_util_dummy_core_r,
.write = mdla_util_dummy_core_w,
.set_b = mdla_util_dummy_core_w,
.clr_b = mdla_util_dummy_core_w},
.cmde = { .read = mdla_util_dummy_core_r,
.write = mdla_util_dummy_core_w,
.set_b = mdla_util_dummy_core_w,
.clr_b = mdla_util_dummy_core_w},
.biu = { .read = mdla_util_dummy_core_r,
.write = mdla_util_dummy_core_w,
.set_b = mdla_util_dummy_core_w,
.clr_b = mdla_util_dummy_core_w},
.apu_conn = { .read = mdla_util_dummy_r,
.write = mdla_util_dummy_w,
.set_b = mdla_util_dummy_w,
.clr_b = mdla_util_dummy_w},
.infra_cfg = { .read = mdla_util_dummy_r,
.write = mdla_util_dummy_w,
.set_b = mdla_util_dummy_w,
.clr_b = mdla_util_dummy_w},
};
const struct mdla_util_io_ops *mdla_util_io_ops_get(void)
{
return &io_ops;
}
static inline void reg_set(void *base, u32 offset, u32 value)
{
iowrite32(ioread32(base + offset) | value, base + offset);
}
static inline void reg_clr(void *base, u32 offset, u32 value)
{
iowrite32(ioread32(base + offset) & (~value), base + offset);
}
static u32 mdla_cfg_read(u32 id, u32 offset)
{
if (unlikely(core_id_is_invalid(id)))
return 0;
return ioread32(mdla_reg_control[id].apu_mdla_config_top + offset);
}
static void mdla_cfg_write(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
iowrite32(value, mdla_reg_control[id].apu_mdla_config_top + offset);
}
static void mdla_cfg_set_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_set(mdla_reg_control[id].apu_mdla_config_top, offset, value);
}
static void mdla_cfg_clr_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_clr(mdla_reg_control[id].apu_mdla_config_top, offset, value);
}
static u32 mdla_reg_read(u32 id, u32 offset)
{
if (unlikely(core_id_is_invalid(id)))
return 0;
return ioread32(mdla_reg_control[id].apu_mdla_cmde_mreg_top + offset);
}
static void mdla_reg_write(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
iowrite32(value, mdla_reg_control[id].apu_mdla_cmde_mreg_top + offset);
}
static void mdla_reg_set_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_set(mdla_reg_control[id].apu_mdla_cmde_mreg_top, offset, value);
}
static void mdla_reg_clr_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_clr(mdla_reg_control[id].apu_mdla_cmde_mreg_top, offset, value);
}
static u32 mdla_biu_read(u32 id, u32 offset)
{
if (unlikely(core_id_is_invalid(id)))
return 0;
return ioread32(mdla_reg_control[id].apu_mdla_biu_top + offset);
}
static void mdla_biu_write(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
iowrite32(value, mdla_reg_control[id].apu_mdla_biu_top + offset);
}
static void mdla_biu_set_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_set(mdla_reg_control[id].apu_mdla_biu_top, offset, value);
}
static void mdla_biu_clr_b(u32 id, u32 offset, u32 value)
{
if (unlikely(core_id_is_invalid(id)))
return;
reg_clr(mdla_reg_control[id].apu_mdla_biu_top, offset, value);
}
static u32 mdla_apu_conn_read(u32 offset)
{
return ioread32(apu_conn_top + offset);
}
static void mdla_apu_conn_write(u32 offset, u32 value)
{
iowrite32(value, apu_conn_top + offset);
}
static void mdla_apu_conn_set_b(u32 offset, u32 value)
{
reg_set(apu_conn_top, offset, value);
}
static void mdla_apu_conn_clr_b(u32 offset, u32 value)
{
reg_clr(apu_conn_top, offset, value);
}
static u32 mdla_infracfg_ao_read(u32 offset)
{
return ioread32(infracfg_ao_top + offset);
}
static void mdla_infracfg_ao_write(u32 offset, u32 value)
{
iowrite32(value, infracfg_ao_top + offset);
}
static void mdla_infracfg_ao_set_b(u32 offset, u32 value)
{
reg_set(infracfg_ao_top, offset, value);
}
static void mdla_infracfg_ao_clr_b(u32 offset, u32 value)
{
reg_clr(infracfg_ao_top, offset, value);
}
void mdla_util_io_set_addr(struct mdla_reg_ctl *reg_ctl)
{
if (reg_ctl == NULL)
return;
mdla_reg_control = reg_ctl;
io_ops.cfg.read = mdla_cfg_read;
io_ops.cfg.write = mdla_cfg_write;
io_ops.cfg.set_b = mdla_cfg_set_b;
io_ops.cfg.clr_b = mdla_cfg_clr_b;
io_ops.cmde.read = mdla_reg_read;
io_ops.cmde.write = mdla_reg_write;
io_ops.cmde.set_b = mdla_reg_set_b;
io_ops.cmde.clr_b = mdla_biu_clr_b;
io_ops.biu.read = mdla_biu_read;
io_ops.biu.write = mdla_biu_write;
io_ops.biu.set_b = mdla_biu_set_b;
io_ops.biu.clr_b = mdla_reg_clr_b;
}
void mdla_util_io_set_extra_addr(int type,
void *addr1, void *addr2, void *addr3)
{
switch (type) {
case EXTRA_ADDR_V1P0:
apu_conn_top = addr1;
infracfg_ao_top = addr2;
break;
case EXTRA_ADDR_V1PX:
apu_conn_top = addr1;
break;
default:
return;
}
if (apu_conn_top) {
io_ops.apu_conn.read = mdla_apu_conn_read;
io_ops.apu_conn.write = mdla_apu_conn_write;
io_ops.apu_conn.set_b = mdla_apu_conn_set_b;
io_ops.apu_conn.clr_b = mdla_apu_conn_clr_b;
}
if (infracfg_ao_top) {
io_ops.infra_cfg.read = mdla_infracfg_ao_read;
io_ops.infra_cfg.write = mdla_infracfg_ao_write;
io_ops.infra_cfg.set_b = mdla_infracfg_ao_set_b;
io_ops.infra_cfg.clr_b = mdla_infracfg_ao_clr_b;
}
}