diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 0c3f0a0a..429c2c78 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -3,3 +3,4 @@ obj-m += cpuidle-tegra-auto.o obj-m += cpuidle-debugfs.o +obj-m += cpuidle-cg-disable-t264.o diff --git a/drivers/cpuidle/cpuidle-cg-disable-t264.c b/drivers/cpuidle/cpuidle-cg-disable-t264.c new file mode 100644 index 00000000..a1c80ebc --- /dev/null +++ b/drivers/cpuidle/cpuidle-cg-disable-t264.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. + * + * Module to disable Clock-Gating on WFI for T264. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#define CCPLEX_SOCKET0_MMI0_BASE 0x8130000000 +#define CCPLEX_SOCKET0_MMIO_SIZE 0x3fffff + +/* Two cores to a cluster */ +#define T264_CORE_OFFSET(cl) ((cl % 2) * 0x8) +/* Two clusters to a switch */ +#define T264_CLUSTER_OFFSET(cl) (((cl % 4) / 2) * 0x1000) +/* Four switches in the system */ +#define T264_SWITCH_OFFSET(cl) ((cl / 4) * 0x100000) +/* Determine the per-core CG Disable Register */ +/* coreN_archcg_clken */ +#define T264_CG_DISABLE_REG(base, cl) \ + (base + T264_SWITCH_OFFSET(cl) + T264_CLUSTER_OFFSET(cl) \ + + T264_CORE_OFFSET(cl) + 0x218) + +static void __iomem *ccplex_mmio_base; + +static void __iomem *get_t264_cg_disable_reg(void __iomem *base, int core) +{ + return T264_CG_DISABLE_REG(base, core); +} + +static int cg_disable_write(void *data, u64 val) +{ + void __iomem *reg = (void __iomem *) data; + + if (val == 0) { + writel(0x00, reg); + } else { + writel(0x3, reg); + } + + return 0; +} + +static int cg_disable_read(void *data, u64 *val) +{ + void __iomem *reg = (void __iomem *) data; + u64 regval; + + regval = readl(reg); + + if (regval == 0) { + *val = 0; + } else { + *val = 1; + } + + return 0; +} + + +DEFINE_SIMPLE_ATTRIBUTE(idle_state_fops, cg_disable_read, cg_disable_write, "%llu\n"); + +static struct dentry *cpuidle_cg_disable_node; + +static int init_debugfs(void) +{ + int cpu; + + cpuidle_cg_disable_node = debugfs_create_dir("cpuidle_cg_disable", NULL); + if (!cpuidle_cg_disable_node) + goto err_out; + + for_each_possible_cpu(cpu) { + /* Size = 7 = cpu (3) + %d (3 from max 1000 cores) + \n (1) */ + char str_buf[7]; + struct dentry *debugfs_dir; + + snprintf(str_buf, 7, "cpu%d", cpu); + debugfs_dir = debugfs_create_dir(str_buf, cpuidle_cg_disable_node); + if (!debugfs_dir) { + goto err_out; + } + debugfs_create_file("disable_cg", 0600, + debugfs_dir, (void *) get_t264_cg_disable_reg(ccplex_mmio_base, cpu), + &idle_state_fops); + } + + return 0; + +err_out: + pr_err("%s: Couldn't create debugfs node for cpuidle\n", __func__); + debugfs_remove_recursive(cpuidle_cg_disable_node); + return -ENOMEM; +} + +static int __init cpuidle_cg_disable_probe(void) +{ + int error; + + /* Set up the IO Mapping */ + ccplex_mmio_base = ioremap(CCPLEX_SOCKET0_MMI0_BASE, CCPLEX_SOCKET0_MMIO_SIZE); + if (IS_ERR(ccplex_mmio_base)) { + error = PTR_ERR(ccplex_mmio_base); + goto mapping_err_out; + } + error = init_debugfs(); + if (error) { + goto debugfs_err_out; + } + return 0; + +mapping_err_out: + pr_err("%s: Couldn't map the CPU's mmcrab registers\n", __func__); + +debugfs_err_out: + return error; +} + +static void __exit cpuidle_cg_disable_remove(void) +{ + debugfs_remove_recursive(cpuidle_cg_disable_node); + iounmap(ccplex_mmio_base); +} + +module_init(cpuidle_cg_disable_probe); +module_exit(cpuidle_cg_disable_remove); + +MODULE_AUTHOR("Ishan Shah "); +MODULE_DESCRIPTION("clock gating disable driver"); +MODULE_LICENSE("GPL");