drivers/cpufreq/mediatek-cpufreq-hw.c

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

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/mediatek-cpufreq-hw.c
Extension
.c
Size
11229 bytes
Lines
443
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 mtk_cpufreq_priv {
	struct device *dev;
	const struct mtk_cpufreq_variant *variant;
	void __iomem *fdvfs;
};

struct mtk_cpufreq_domain {
	struct mtk_cpufreq_priv *parent;
	struct cpufreq_frequency_table *table;
	void __iomem *reg_bases[REG_ARRAY_SIZE];
	struct resource *res;
	void __iomem *base;
	int nr_opp;
};

struct mtk_cpufreq_variant {
	int (*init)(struct mtk_cpufreq_priv *priv);
	const u16 reg_offsets[REG_ARRAY_SIZE];
	const bool is_hybrid_dvfs;
};

static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = {
	.reg_offsets = {
		[REG_FREQ_LUT_TABLE]	= 0x0,
		[REG_FREQ_ENABLE]	= 0x84,
		[REG_FREQ_PERF_STATE]	= 0x88,
		[REG_FREQ_HW_STATE]	= 0x8c,
		[REG_EM_POWER_TBL]	= 0x90,
		[REG_FREQ_LATENCY]	= 0x110,
	},
};

static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv)
{
	priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL);
	if (IS_ERR(priv->fdvfs))
		return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs),
				     "failed to get fdvfs iomem\n");

	return 0;
}

static const struct mtk_cpufreq_variant cpufreq_mtk_mt8196_variant = {
	.init = mtk_cpufreq_hw_mt8196_init,
	.reg_offsets = {
		[REG_FREQ_LUT_TABLE]	= 0x0,
		[REG_FREQ_ENABLE]	= 0x84,
		[REG_FREQ_PERF_STATE]	= 0x88,
		[REG_FREQ_HW_STATE]	= 0x8c,
		[REG_EM_POWER_TBL]	= 0x90,
		[REG_FREQ_LATENCY]	= 0x114,
	},
	.is_hybrid_dvfs = true,
};

static int __maybe_unused
mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
			  unsigned long *KHz)
{
	struct mtk_cpufreq_domain *data;
	struct cpufreq_policy *policy;
	int i;

	policy = cpufreq_cpu_get_raw(cpu_dev->id);
	if (!policy)
		return -EINVAL;

	data = policy->driver_data;

	for (i = 0; i < data->nr_opp; i++) {
		if (data->table[i].frequency < *KHz)
			break;
	}
	i--;

	*KHz = data->table[i].frequency;
	/* Provide micro-Watts value to the Energy Model */
	*uW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
			    i * LUT_ROW_SIZE);

	return 0;
}

static void mtk_cpufreq_hw_fdvfs_switch(unsigned int target_freq,
					struct cpufreq_policy *policy)
{
	struct mtk_cpufreq_domain *data = policy->driver_data;
	struct mtk_cpufreq_priv *priv = data->parent;
	unsigned int cpu;

Annotation

Implementation Notes