void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
				void __iomem *pmc_base,
				struct tegra_clk *tegra_clks,
				struct tegra_clk_pll_params *params)
{
	struct clk *clk;
	struct clk **dt_clk;

	/* CCLKG */
	dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
	if (dt_clk) {
		clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
					ARRAY_SIZE(cclk_g_parents),
					CLK_SET_RATE_PARENT,
					clk_base + CCLKG_BURST_POLICY,
					0, 4, 0, 0, NULL);
		*dt_clk = clk;
	}

	/* CCLKLP */
	dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
	if (dt_clk) {
		clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
					ARRAY_SIZE(cclk_lp_parents),
					CLK_SET_RATE_PARENT,
					clk_base + CCLKLP_BURST_POLICY,
					TEGRA_DIVIDER_2, 4, 8, 9, NULL);
		*dt_clk = clk;
	}

	tegra_sclk_init(clk_base, tegra_clks);

#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
	/* PLLX */
	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
	if (!dt_clk)
		return;

	clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base,
			pmc_base, CLK_IGNORE_UNUSED, params, NULL);
	*dt_clk = clk;

	/* PLLX_OUT0 */

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks);
	if (!dt_clk)
		return;
	clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x",
					CLK_SET_RATE_PARENT, 1, 2);
	*dt_clk = clk;
#endif
}
void __init tegra_pmc_clk_init(void __iomem *pmc_base,
				struct tegra_clk *tegra_clks)
{
	struct clk *clk;
	struct clk **dt_clk;
	int i;

	for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) {
		struct pmc_clk_init_data *data;

		data = pmc_clks + i;

		dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = clk_register_mux(NULL, data->mux_name, data->parents,
				data->num_parents, CLK_SET_RATE_NO_REPARENT,
				pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift,
				3, 0, &clk_out_lock);
		*dt_clk = clk;


		dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = clk_register_gate(NULL, data->gate_name, data->mux_name,
					0, pmc_base + PMC_CLK_OUT_CNTRL,
					data->gate_shift, 0, &clk_out_lock);
		*dt_clk = clk;
		clk_register_clkdev(clk, data->dev_name, data->gate_name);
	}

	/* blink */
	writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
	clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
				pmc_base + PMC_DPD_PADS_ORIDE,
				PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);

	dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks);
	if (!dt_clk)
		return;

	clk = clk_register_gate(NULL, "blink", "blink_override", 0,
				pmc_base + PMC_CTRL,
				PMC_CTRL_BLINK_ENB, 0, NULL);
	clk_register_clkdev(clk, "blink", NULL);
	*dt_clk = clk;
}
static void __init periph_clk_init(void __iomem *clk_base,
				struct tegra_clk *tegra_clks)
{
	int i;
	struct clk *clk;
	struct clk **dt_clk;

	for (i = 0; i < ARRAY_SIZE(periph_clks); i++) {
		struct tegra_clk_periph_regs *bank;
		struct tegra_periph_init_data *data;

		data = periph_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		bank = get_reg_bank(data->periph.gate.clk_num);
		if (!bank)
			continue;

		data->periph.gate.regs = bank;
		clk = tegra_clk_register_periph(data->name,
			data->p.parent_names, data->num_parents,
			&data->periph, clk_base, data->offset,
			data->flags);
		*dt_clk = clk;
	}
}
static void __init div_clk_init(void __iomem *clk_base,
				struct tegra_clk *tegra_clks)
{
	int i;
	struct clk *clk;
	struct clk **dt_clk;

	for (i = 0; i < ARRAY_SIZE(div_clks); i++) {
		struct tegra_periph_init_data *data;

		data = div_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = tegra_clk_register_divider(data->name,
				data->p.parent_name, clk_base + data->offset,
				data->flags, data->periph.divider.flags,
				data->periph.divider.shift,
				data->periph.divider.width,
				data->periph.divider.frac_width,
				data->periph.divider.lock);
		*dt_clk = clk;
	}
}
Beispiel #5
0
static void __init periph_clk_init(void __iomem *clk_base,
				struct tegra_clk *tegra_clks)
{
	int i;
	struct clk *clk;
	struct clk **dt_clk;

	for (i = 0; i < ARRAY_SIZE(periph_clks); i++) {
		const struct tegra_clk_periph_regs *bank;
		struct tegra_periph_init_data *data;

		data = periph_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		bank = get_reg_bank(data->periph.gate.clk_num);
		if (!bank)
			continue;

		data->periph.gate.regs = bank;
		clk = tegra_clk_register_periph_data(clk_base, data);
		*dt_clk = clk;
	}
}
static void __init tegra_sclk_init(void __iomem *clk_base,
				struct tegra_clk *tegra_clks)
{
	struct clk *clk;
	struct clk **dt_clk;

	/* SCLK */
	dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
	if (dt_clk) {
		clk = tegra_clk_register_super_mux("sclk", sclk_parents,
						ARRAY_SIZE(sclk_parents),
						CLK_SET_RATE_PARENT,
						clk_base + SCLK_BURST_POLICY,
						0, 4, 0, 0, NULL);
		*dt_clk = clk;
	}

	/* HCLK */
	dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks);
	if (dt_clk) {
		clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
				   clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
				   &sysrate_lock);
		clk = clk_register_gate(NULL, "hclk", "hclk_div",
				CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
				clk_base + SYSTEM_CLK_RATE,
				7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
		*dt_clk = clk;
	}

	/* PCLK */
	dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks);
	if (!dt_clk)
		return;

	clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
				   clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
				   &sysrate_lock);
	clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT |
				CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE,
				3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
	*dt_clk = clk;
}
static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
				struct tegra_clk *tegra_clks,
				struct tegra_clk_pll_params *pll_params)
{
	struct clk *clk;
	struct clk **dt_clk;
	int i;

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p, tegra_clks);
	if (dt_clk) {
		/* PLLP */
		clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base,
					pmc_base, 0, pll_params, NULL);
		clk_register_clkdev(clk, "pll_p", NULL);
		*dt_clk = clk;
	}

	for (i = 0; i < ARRAY_SIZE(pllp_out_clks); i++) {
		struct pll_out_data *data;

		data = pllp_out_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = tegra_clk_register_divider(data->div_name, "pll_p",
				clk_base + data->offset, 0, data->div_flags,
				data->div_shift, 8, 1, data->lock);
		clk = tegra_clk_register_pll_out(data->pll_out_name,
				data->div_name, clk_base + data->offset,
				data->rst_shift + 1, data->rst_shift,
				CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
				data->lock);
		*dt_clk = clk;
	}
}
static void __init gate_clk_init(void __iomem *clk_base,
				struct tegra_clk *tegra_clks)
{
	int i;
	struct clk *clk;
	struct clk **dt_clk;

	for (i = 0; i < ARRAY_SIZE(gate_clks); i++) {
		struct tegra_periph_init_data *data;

		data = gate_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = tegra_clk_register_periph_gate(data->name,
				data->p.parent_name, data->periph.gate.flags,
				clk_base, data->flags,
				data->periph.gate.clk_num,
				periph_clk_enb_refcnt);
		*dt_clk = clk;
	}
}
static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
				struct tegra_clk *tegra_clks,
				struct tegra_clk_pll_params *pll_params)
{
	struct clk *clk;
	struct clk **dt_clk;
	int i;

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p, tegra_clks);
	if (dt_clk) {
		/* PLLP */
		clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base,
					pmc_base, 0, pll_params, NULL);
		clk_register_clkdev(clk, "pll_p", NULL);
		*dt_clk = clk;
	}

	for (i = 0; i < ARRAY_SIZE(pllp_out_clks); i++) {
		struct pll_out_data *data;

		data = pllp_out_clks + i;

		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
		if (!dt_clk)
			continue;

		clk = tegra_clk_register_divider(data->div_name, "pll_p",
				clk_base + data->offset, 0, data->div_flags,
				data->div_shift, 8, 1, data->lock);
		clk = tegra_clk_register_pll_out(data->pll_out_name,
				data->div_name, clk_base + data->offset,
				data->rst_shift + 1, data->rst_shift,
				CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
				data->lock);
		*dt_clk = clk;
	}

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_cpu,
			tegra_clks);
	if (dt_clk) {
		/*
		 * Tegra210 has control on enabling/disabling PLLP branches to
		 * CPU, register a gate clock "pll_p_out_cpu" for this gating
		 * function and parent "pll_p_out4" to it, so when we are
		 * re-parenting CPU off from "pll_p_out4" the PLLP branching to
		 * CPU can be disabled automatically.
		 */
		clk = tegra_clk_register_divider("pll_p_out4_div",
				"pll_p_out_cpu", clk_base + PLLP_OUTB, 0, 0, 24,
				8, 1, &PLLP_OUTB_lock);

		dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out4_cpu, tegra_clks);
		if (dt_clk) {
			clk = tegra_clk_register_pll_out("pll_p_out4",
					"pll_p_out4_div", clk_base + PLLP_OUTB,
					17, 16, CLK_IGNORE_UNUSED |
					CLK_SET_RATE_PARENT, 0,
					&PLLP_OUTB_lock);
			*dt_clk = clk;
		}
	}

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_hsio, tegra_clks);
	if (dt_clk) {
		/* PLLP_OUT_HSIO */
		clk = clk_register_gate(NULL, "pll_p_out_hsio", "pll_p",
				CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
				clk_base + PLLP_MISC1, 29, 0, NULL);
		*dt_clk = clk;
	}

	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_xusb, tegra_clks);
	if (dt_clk) {
		/* PLLP_OUT_XUSB */
		clk = clk_register_gate(NULL, "pll_p_out_xusb",
				"pll_p_out_hsio", CLK_SET_RATE_PARENT |
				CLK_IGNORE_UNUSED, clk_base + PLLP_MISC1, 28, 0,
				NULL);
		clk_register_clkdev(clk, "pll_p_out_xusb", NULL);
		*dt_clk = clk;
	}
}