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