diff --git a/drivers/platform/tegra/Makefile b/drivers/platform/tegra/Makefile index c7b8f3fa..bcb0cbc4 100644 --- a/drivers/platform/tegra/Makefile +++ b/drivers/platform/tegra/Makefile @@ -8,6 +8,7 @@ obj-m += tegra-bootloader-debug.o tegra-cactmon-objs := cactmon.o tegra-cactmon-objs += actmon_common.o obj-m += tegra-cactmon.o +obj-m += tegra-cactmon-mc-all.o obj-m += tegra-fsicom.o obj-m += mce/ diff --git a/drivers/platform/tegra/tegra-cactmon-mc-all.c b/drivers/platform/tegra/tegra-cactmon-mc-all.c new file mode 100644 index 00000000..86874d70 --- /dev/null +++ b/drivers/platform/tegra/tegra-cactmon-mc-all.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 NVIDIA CORPORATION. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CENTRAL_ACTMON_CTRL_REG 0x0 +#define CENTRAL_ACTMON_MC_ALL_AVG_COUNT_REG 0x124 +#define CENTRAL_ACTMON_CTRL_SOURCE(v) ((v & (0x3 << 8)) >> 8) +#define CENTRAL_ACTMON_CTRL_SAMPLE_TICK(v) ((v & (0x1 << 10)) >> 10) +#define CENTRAL_ACTMON_CTRL_SAMPLE_PERIOD(v) ((v & (0xff << 0)) >> 0) + +struct central_actmon { + struct device *dev; + struct clk *clk; + unsigned long rate; + void __iomem *regs; + struct dentry *debugfs; +}; + +static u32 cactmon_readl(struct central_actmon *cactmon, u32 offset) +{ + return readl(cactmon->regs+offset); +} + +static u32 __central_actmon_sample_period_get(struct central_actmon *cactmon) +{ + u32 val, source, sample_tick, sample_period; + + val = cactmon_readl(cactmon, CENTRAL_ACTMON_CTRL_REG); + + source = CENTRAL_ACTMON_CTRL_SOURCE(val); + sample_period = CENTRAL_ACTMON_CTRL_SAMPLE_PERIOD(val) + 1; + + if (source == 1) { + sample_period *= 1; + } else if (source == 0) { + sample_period *= 1000; + } else { + sample_tick = CENTRAL_ACTMON_CTRL_SAMPLE_TICK(val); + sample_period *= sample_tick ? 65536 : 256; + sample_period = (sample_period * 1000) / (cactmon->rate / 1000); + } + + return sample_period; +} + +static int central_actmon_sample_period_get(void *data, u64 *val) +{ + struct central_actmon *cactmon = (struct central_actmon *)data; + + *val = (u64) __central_actmon_sample_period_get(cactmon); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(central_actmon_sample_period_fops, + central_actmon_sample_period_get, NULL, + "%lld\n"); + +static int central_actmon_mc_all_get(void *data, u64 *val) +{ + struct central_actmon *cactmon = (struct central_actmon *)data; + u32 sample_period_usec, mc_all_actives; + + sample_period_usec = __central_actmon_sample_period_get(cactmon); + + mc_all_actives = cactmon_readl(cactmon, CENTRAL_ACTMON_MC_ALL_AVG_COUNT_REG); + + *val = mc_all_actives * 1000 / sample_period_usec; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(central_actmon_mc_all_fops, + central_actmon_mc_all_get, NULL, + "%lld\n"); + +static void central_actmon_debugfs_init(struct central_actmon *cactmon) +{ + cactmon->debugfs = debugfs_create_dir("cactmon", NULL); + + debugfs_create_file("sample_period_usec", 0444, cactmon->debugfs, cactmon, + ¢ral_actmon_sample_period_fops); + debugfs_create_file("mc_all", 0444, cactmon->debugfs, cactmon, + ¢ral_actmon_mc_all_fops); +} + +static int central_actmon_probe(struct platform_device *pdev) +{ + struct central_actmon *cactmon; + + cactmon = devm_kzalloc(&pdev->dev, sizeof(*cactmon), GFP_KERNEL); + if (!cactmon) + return -ENOMEM; + + cactmon->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(cactmon->regs)) + return PTR_ERR(cactmon->regs); + + cactmon->clk = devm_clk_get(&pdev->dev, "actmon"); + if (IS_ERR(cactmon->clk)) + return dev_err_probe(&pdev->dev, + PTR_ERR(cactmon->clk), + "failed to get actmon clock\n"); + cactmon->rate = clk_get_rate(cactmon->clk); + + cactmon->dev = &pdev->dev; + platform_set_drvdata(pdev, cactmon); + + central_actmon_debugfs_init(cactmon); + + return 0; +} + +static int central_actmon_remove(struct platform_device *pdev) +{ + struct central_actmon *cactmon = platform_get_drvdata(pdev); + + debugfs_remove_recursive(cactmon->debugfs); + + return 0; +} + + +static const struct of_device_id central_actmon_of_match[] = { + { .compatible = "nvidia,tegra234-cactmon-mc-all", .data = NULL, }, + {}, +}; +MODULE_DEVICE_TABLE(of, central_actmon_of_match); + +static struct platform_driver central_actmon_driver = { + .probe = central_actmon_probe, + .remove = central_actmon_remove, + .driver = { + .name = "tegra-cactmon-mc-all", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(central_actmon_of_match), + }, +}; +module_platform_driver(central_actmon_driver); + +MODULE_DESCRIPTION("Tegra MC_ALL Central Activity Monitor"); +MODULE_AUTHOR("Johnny Liu "); +MODULE_LICENSE("GPL v2");