drivers/cpufreq/tegra194-cpufreq.c

Source file repositories/reference/linux-study-clean/drivers/cpufreq/tegra194-cpufreq.c

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/tegra194-cpufreq.c
Extension
.c
Size
23290 bytes
Lines
829
Domain
Driver Families
Bucket
drivers/cpufreq
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct tegra_cpu_data {
	u32 cpuid;
	u32 clusterid;
	void __iomem *freq_core_reg;
};

struct tegra_cpu_ctr {
	u32 cpu;
	u32 coreclk_cnt, last_coreclk_cnt;
	u32 refclk_cnt, last_refclk_cnt;
};

struct read_counters_work {
	struct work_struct work;
	struct tegra_cpu_ctr c;
};

struct tegra_cpufreq_ops {
	void (*read_counters)(struct tegra_cpu_ctr *c);
	void (*set_cpu_ndiv)(struct cpufreq_policy *policy, u64 ndiv);
	void (*get_cpu_cluster_id)(u32 cpu, u32 *cpuid, u32 *clusterid);
	int (*get_cpu_ndiv)(u32 cpu, u32 cpuid, u32 clusterid, u64 *ndiv);
};

struct tegra_cpufreq_soc {
	struct tegra_cpufreq_ops *ops;
	int maxcpus_per_cluster;
	unsigned int num_clusters;
	phys_addr_t actmon_cntr_base;
	u32 refclk_delta_min;
};

struct tegra194_cpufreq_data {
	void __iomem *regs;
	struct cpufreq_frequency_table **bpmp_luts;
	const struct tegra_cpufreq_soc *soc;
	bool icc_dram_bw_scaling;
	struct tegra_cpu_data *cpu_data;
};

static struct workqueue_struct *read_counters_wq;

static int tegra_cpufreq_set_bw(struct cpufreq_policy *policy, unsigned long freq_khz)
{
	struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
	struct dev_pm_opp *opp;
	struct device *dev;
	int ret;

	dev = get_cpu_device(policy->cpu);
	if (!dev)
		return -ENODEV;

	opp = dev_pm_opp_find_freq_exact(dev, freq_khz * KHZ, true);
	if (IS_ERR(opp))
		return PTR_ERR(opp);

	ret = dev_pm_opp_set_opp(dev, opp);
	if (ret)
		data->icc_dram_bw_scaling = false;

	dev_pm_opp_put(opp);
	return ret;
}

static void tegra_get_cpu_mpidr(void *mpidr)
{
	*((u64 *)mpidr) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
}

static void tegra234_get_cpu_cluster_id(u32 cpu, u32 *cpuid, u32 *clusterid)
{
	u64 mpidr;

	smp_call_function_single(cpu, tegra_get_cpu_mpidr, &mpidr, true);

	if (cpuid)
		*cpuid = MPIDR_AFFINITY_LEVEL(mpidr, 1);
	if (clusterid)
		*clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 2);
}

static int tegra234_get_cpu_ndiv(u32 cpu, u32 cpuid, u32 clusterid, u64 *ndiv)
{
	struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();

	*ndiv = readl(data->cpu_data[cpu].freq_core_reg) & NDIV_MASK;

	return 0;
}

Annotation

Implementation Notes