drivers/clk/samsung/clk-exynos-arm64.c

Source file repositories/reference/linux-study-clean/drivers/clk/samsung/clk-exynos-arm64.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/samsung/clk-exynos-arm64.c
Extension
.c
Size
10048 bytes
Lines
383
Domain
Driver Families
Bucket
drivers/clk
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 exynos_arm64_cmu_data {
	struct samsung_clk_reg_dump *clk_save;
	unsigned int nr_clk_save;
	const struct samsung_clk_reg_dump *clk_suspend;
	unsigned int nr_clk_suspend;
	struct samsung_clk_reg_dump *clk_sysreg_save;
	unsigned int nr_clk_sysreg;

	struct clk *clk;
	struct clk **pclks;
	int nr_pclks;

	struct samsung_clk_provider *ctx;
};

/* Check if the register offset is a GATE register */
static bool is_gate_reg(unsigned long off)
{
	return off >= GATE_OFF_START && off <= GATE_OFF_END;
}

/* Check if the register offset is a PLL_CONx register */
static bool is_pll_conx_reg(unsigned long off)
{
	return off >= PLL_CON_OFF_START && off <= PLL_CON_OFF_END;
}

/* Check if the register offset is a PLL_CON1 register */
static bool is_pll_con1_reg(unsigned long off)
{
	return is_pll_conx_reg(off) && (off & 0xf) == 0x4 && !(off & 0x10);
}

/**
 * exynos_arm64_init_clocks - Set clocks initial configuration
 * @np:		CMU device tree node with "reg" property (CMU addr)
 * @cmu:	CMU data
 *
 * Set manual control mode for all gate and PLL clocks.
 */
static void __init exynos_arm64_init_clocks(struct device_node *np,
					    const struct samsung_cmu_info *cmu)
{
	const unsigned long *reg_offs = cmu->clk_regs;
	size_t reg_offs_len = cmu->nr_clk_regs;
	void __iomem *reg_base;
	bool init_auto;
	size_t i;

	reg_base = of_iomap(np, 0);
	if (!reg_base)
		panic("%s: failed to map registers\n", __func__);

	/* ensure compatibility with older DTs */
	if (cmu->auto_clock_gate && samsung_is_auto_capable(np))
		init_auto = true;
	else
		init_auto = false;

	if (cmu->option_offset && init_auto) {
		/*
		 * Enable the global automatic mode for the entire CMU.
		 * This overrides the individual HWACG bits in each of the
		 * individual gate, mux and qch registers.
		 */
		writel(CMU_OPT_GLOBAL_EN_AUTO_GATING,
		       reg_base + cmu->option_offset);
	}

	for (i = 0; i < reg_offs_len; ++i) {
		void __iomem *reg = reg_base + reg_offs[i];
		u32 val;

		if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
			writel(PLL_CON1_MANUAL, reg);
		} else if (is_gate_reg(reg_offs[i]) && !init_auto) {
			/*
			 * Setting GATE_MANUAL bit (which is described in TRM as
			 * reserved!) overrides the global CMU automatic mode
			 * option.
			 */
			val = readl(reg);
			val |= GATE_MANUAL;
			val &= ~GATE_ENABLE_HWACG;
			writel(val, reg);
		}
	}

	iounmap(reg_base);
}

Annotation

Implementation Notes