xref: /rk3399_ARM-atf/drivers/ti/clk/ti_clk_pllctrl.c (revision a28114d66a6d43db4accef5fd5d6dab6c059e584)
1*28c06333SKamlesh Gurudasani /*
2*28c06333SKamlesh Gurudasani  * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com
3*28c06333SKamlesh Gurudasani  *
4*28c06333SKamlesh Gurudasani  * SPDX-License-Identifier: BSD-3-Clause
5*28c06333SKamlesh Gurudasani  */
6*28c06333SKamlesh Gurudasani 
7*28c06333SKamlesh Gurudasani /*
8*28c06333SKamlesh Gurudasani  * TI PLL Control Driver
9*28c06333SKamlesh Gurudasani  *
10*28c06333SKamlesh Gurudasani  * This driver provides low-level control for PLL enable/disable and lock
11*28c06333SKamlesh Gurudasani  * status monitoring. It manages PLL control registers including PLLEN
12*28c06333SKamlesh Gurudasani  * (PLL enable), PLLENSRC (enable source select), and PLLSTAT (lock status).
13*28c06333SKamlesh Gurudasani  * The driver also implements mux functionality for PLL bypass/lock-based
14*28c06333SKamlesh Gurudasani  * clock path selection.
15*28c06333SKamlesh Gurudasani  */
16*28c06333SKamlesh Gurudasani 
17*28c06333SKamlesh Gurudasani #include <assert.h>
18*28c06333SKamlesh Gurudasani 
19*28c06333SKamlesh Gurudasani #include <lib/mmio.h>
20*28c06333SKamlesh Gurudasani 
21*28c06333SKamlesh Gurudasani #include <ti_clk_pllctrl.h>
22*28c06333SKamlesh Gurudasani #include <ti_container_of.h>
23*28c06333SKamlesh Gurudasani 
24*28c06333SKamlesh Gurudasani #define PLLCTRL_PLLCTRL			0x100U
25*28c06333SKamlesh Gurudasani #define PLLCTRL_PLLCTRL_PLLEN		BIT(0)
26*28c06333SKamlesh Gurudasani #define PLLCTRL_PLLCTRL_PLLENSRC	BIT(5)
27*28c06333SKamlesh Gurudasani 
28*28c06333SKamlesh Gurudasani #define PLLCTRL_PLLSTAT			0x13cU
29*28c06333SKamlesh Gurudasani #define PLLCTRL_PLLSTAT_LOCK		BIT(1)
30*28c06333SKamlesh Gurudasani 
ti_clk_pllctrl_mux_get_parent(struct ti_clk * clkp)31*28c06333SKamlesh Gurudasani static const struct ti_clk_parent *ti_clk_pllctrl_mux_get_parent(struct ti_clk *clkp)
32*28c06333SKamlesh Gurudasani {
33*28c06333SKamlesh Gurudasani 	const struct ti_clk_data_mux *mux;
34*28c06333SKamlesh Gurudasani 	const struct ti_clk_data_mux_reg *reg;
35*28c06333SKamlesh Gurudasani 	const struct ti_clk_parent *parent = NULL;
36*28c06333SKamlesh Gurudasani 	uint32_t reg_val;
37*28c06333SKamlesh Gurudasani 
38*28c06333SKamlesh Gurudasani 	assert(clkp != NULL);
39*28c06333SKamlesh Gurudasani 
40*28c06333SKamlesh Gurudasani 	mux = ti_container_of(clkp->data, const struct ti_clk_data_mux, data);
41*28c06333SKamlesh Gurudasani 	reg = ti_container_of(mux, const struct ti_clk_data_mux_reg, data_mux);
42*28c06333SKamlesh Gurudasani 
43*28c06333SKamlesh Gurudasani 	reg_val = (uint32_t)mmio_read_32(reg->reg + PLLCTRL_PLLCTRL);
44*28c06333SKamlesh Gurudasani 	if ((reg_val & PLLCTRL_PLLCTRL_PLLENSRC) != 0U) {
45*28c06333SKamlesh Gurudasani 		/* When set, mux is controlled by lock state of PLL */
46*28c06333SKamlesh Gurudasani 		reg_val = (uint32_t)mmio_read_32(reg->reg + PLLCTRL_PLLSTAT);
47*28c06333SKamlesh Gurudasani 		if ((reg_val & PLLCTRL_PLLSTAT_LOCK) != 0U) {
48*28c06333SKamlesh Gurudasani 			/* PLL is locked */
49*28c06333SKamlesh Gurudasani 			parent = &mux->parents[1];
50*28c06333SKamlesh Gurudasani 		} else {
51*28c06333SKamlesh Gurudasani 			/* PLL is in bypass */
52*28c06333SKamlesh Gurudasani 			parent = &mux->parents[0];
53*28c06333SKamlesh Gurudasani 		}
54*28c06333SKamlesh Gurudasani 	} else {
55*28c06333SKamlesh Gurudasani 		/* When cleaned, mux is controlled by PLLEN bit */
56*28c06333SKamlesh Gurudasani 		if ((reg_val & PLLCTRL_PLLCTRL_PLLEN) != 0U) {
57*28c06333SKamlesh Gurudasani 			/* Use pll clock */
58*28c06333SKamlesh Gurudasani 			parent = &mux->parents[1];
59*28c06333SKamlesh Gurudasani 		} else {
60*28c06333SKamlesh Gurudasani 			/* Use bypass clock */
61*28c06333SKamlesh Gurudasani 			parent = &mux->parents[0];
62*28c06333SKamlesh Gurudasani 		}
63*28c06333SKamlesh Gurudasani 	}
64*28c06333SKamlesh Gurudasani 
65*28c06333SKamlesh Gurudasani 	/* If div is 0, parent clock is not connected */
66*28c06333SKamlesh Gurudasani 	if ((parent != NULL) && (parent->div == 0U)) {
67*28c06333SKamlesh Gurudasani 		parent = NULL;
68*28c06333SKamlesh Gurudasani 	}
69*28c06333SKamlesh Gurudasani 
70*28c06333SKamlesh Gurudasani 	return parent;
71*28c06333SKamlesh Gurudasani }
72*28c06333SKamlesh Gurudasani 
73*28c06333SKamlesh Gurudasani const struct ti_clk_drv_mux ti_clk_drv_pllctrl_mux_reg_ro = {
74*28c06333SKamlesh Gurudasani 	.get_parent = ti_clk_pllctrl_mux_get_parent,
75*28c06333SKamlesh Gurudasani };
76