xref: /rk3399_ARM-atf/plat/rockchip/common/scmi/rockchip_common_clock.c (revision 04b2fb42b171e3fbf2ef823558ac5b0119663dc7)
1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause
2*036935a8SXiaoDong Huang /*
3*036935a8SXiaoDong Huang  * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
4*036935a8SXiaoDong Huang  */
5*036935a8SXiaoDong Huang 
6*036935a8SXiaoDong Huang #include <assert.h>
7*036935a8SXiaoDong Huang #include <errno.h>
8*036935a8SXiaoDong Huang 
9*036935a8SXiaoDong Huang #include <drivers/scmi.h>
10*036935a8SXiaoDong Huang #include <lib/mmio.h>
11*036935a8SXiaoDong Huang #include <platform_def.h>
12*036935a8SXiaoDong Huang 
13*036935a8SXiaoDong Huang #include <plat_private.h>
14*036935a8SXiaoDong Huang #include <scmi_clock.h>
15*036935a8SXiaoDong Huang 
16*036935a8SXiaoDong Huang #define MUX_ADDR_INFO			0
17*036935a8SXiaoDong Huang #define MUX_SHIFT_INFO			1
18*036935a8SXiaoDong Huang #define MUX_WIDTH_INFO			2
19*036935a8SXiaoDong Huang #define DIV_ADDR_INFO			3
20*036935a8SXiaoDong Huang #define DIV_SHIFT_INFO			4
21*036935a8SXiaoDong Huang #define DIV_WIDTH_INFO			5
22*036935a8SXiaoDong Huang #define GATE_ADDR_INFO			6
23*036935a8SXiaoDong Huang #define GATE_SHIFT_INFO			7
24*036935a8SXiaoDong Huang 
25*036935a8SXiaoDong Huang #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
26*036935a8SXiaoDong Huang 
27*036935a8SXiaoDong Huang #define abs(x) ({						\
28*036935a8SXiaoDong Huang 		long ret;					\
29*036935a8SXiaoDong Huang 		if (sizeof(x) == sizeof(long)) {		\
30*036935a8SXiaoDong Huang 			long __x = (x);				\
31*036935a8SXiaoDong Huang 			ret = (__x < 0) ? -__x : __x;		\
32*036935a8SXiaoDong Huang 		} else {					\
33*036935a8SXiaoDong Huang 			int __x = (x);				\
34*036935a8SXiaoDong Huang 			ret = (__x < 0) ? -__x : __x;		\
35*036935a8SXiaoDong Huang 		}						\
36*036935a8SXiaoDong Huang 		ret;						\
37*036935a8SXiaoDong Huang 	})
38*036935a8SXiaoDong Huang 
clk_scmi_common_get_parent_rate(rk_scmi_clock_t * clock,int id)39*036935a8SXiaoDong Huang static unsigned long clk_scmi_common_get_parent_rate(rk_scmi_clock_t *clock,
40*036935a8SXiaoDong Huang 						     int id)
41*036935a8SXiaoDong Huang {
42*036935a8SXiaoDong Huang 	rk_scmi_clock_t *p_clock;
43*036935a8SXiaoDong Huang 
44*036935a8SXiaoDong Huang 	if (clock->is_dynamic_prate != 0) {
45*036935a8SXiaoDong Huang 		p_clock = rockchip_scmi_get_clock(0, clock->parent_table[id]);
46*036935a8SXiaoDong Huang 		if (p_clock == NULL)
47*036935a8SXiaoDong Huang 			return 0;
48*036935a8SXiaoDong Huang 		if ((p_clock->clk_ops != NULL) && (p_clock->clk_ops->get_rate != NULL))
49*036935a8SXiaoDong Huang 			return  p_clock->clk_ops->get_rate(p_clock);
50*036935a8SXiaoDong Huang 		else
51*036935a8SXiaoDong Huang 			return 0;
52*036935a8SXiaoDong Huang 	} else {
53*036935a8SXiaoDong Huang 		return clock->parent_table[id];
54*036935a8SXiaoDong Huang 	}
55*036935a8SXiaoDong Huang }
56*036935a8SXiaoDong Huang 
clk_scmi_common_get_rate(rk_scmi_clock_t * clock)57*036935a8SXiaoDong Huang unsigned long clk_scmi_common_get_rate(rk_scmi_clock_t *clock)
58*036935a8SXiaoDong Huang {
59*036935a8SXiaoDong Huang 	unsigned long parent_rate, sel, div;
60*036935a8SXiaoDong Huang 
61*036935a8SXiaoDong Huang 	sel = mmio_read_32(clock->info[MUX_ADDR_INFO]) >>
62*036935a8SXiaoDong Huang 	      clock->info[MUX_SHIFT_INFO];
63*036935a8SXiaoDong Huang 	sel = sel & (BIT(clock->info[MUX_WIDTH_INFO]) - 1);
64*036935a8SXiaoDong Huang 	div = mmio_read_32(clock->info[DIV_ADDR_INFO]) >>
65*036935a8SXiaoDong Huang 	      clock->info[DIV_SHIFT_INFO];
66*036935a8SXiaoDong Huang 	div = div & (BIT(clock->info[DIV_WIDTH_INFO]) - 1);
67*036935a8SXiaoDong Huang 	parent_rate = clk_scmi_common_get_parent_rate(clock, sel);
68*036935a8SXiaoDong Huang 
69*036935a8SXiaoDong Huang 	return parent_rate / (div + 1);
70*036935a8SXiaoDong Huang }
71*036935a8SXiaoDong Huang 
clk_scmi_common_set_rate(rk_scmi_clock_t * clock,unsigned long rate)72*036935a8SXiaoDong Huang int clk_scmi_common_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
73*036935a8SXiaoDong Huang {
74*036935a8SXiaoDong Huang 	unsigned long parent_rate, now, best_rate = 0;
75*036935a8SXiaoDong Huang 	int i = 0, sel_mask, div_mask, best_sel = 0, best_div = 0, div;
76*036935a8SXiaoDong Huang 
77*036935a8SXiaoDong Huang 	if ((rate == 0) ||
78*036935a8SXiaoDong Huang 	    (clock->info[MUX_WIDTH_INFO] == 0 && clock->info[DIV_WIDTH_INFO] == 0))
79*036935a8SXiaoDong Huang 		return SCMI_INVALID_PARAMETERS;
80*036935a8SXiaoDong Huang 
81*036935a8SXiaoDong Huang 	sel_mask = BIT(clock->info[MUX_WIDTH_INFO]) - 1;
82*036935a8SXiaoDong Huang 	div_mask = BIT(clock->info[DIV_WIDTH_INFO]) - 1;
83*036935a8SXiaoDong Huang 	if (clock->info[MUX_WIDTH_INFO] == 0) {
84*036935a8SXiaoDong Huang 		parent_rate = clk_scmi_common_get_parent_rate(clock, 0);
85*036935a8SXiaoDong Huang 		div = DIV_ROUND_UP(parent_rate, rate);
86*036935a8SXiaoDong Huang 		if (div > div_mask + 1)
87*036935a8SXiaoDong Huang 			div = div_mask + 1;
88*036935a8SXiaoDong Huang 		mmio_write_32(clock->info[DIV_ADDR_INFO],
89*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(div - 1, div_mask,
90*036935a8SXiaoDong Huang 					      clock->info[DIV_SHIFT_INFO]));
91*036935a8SXiaoDong Huang 	} else if (clock->info[DIV_WIDTH_INFO] == 0) {
92*036935a8SXiaoDong Huang 		for (i = 0; i <= sel_mask; i++) {
93*036935a8SXiaoDong Huang 			parent_rate = clk_scmi_common_get_parent_rate(clock, i);
94*036935a8SXiaoDong Huang 			now = parent_rate;
95*036935a8SXiaoDong Huang 			if (abs(rate - now) < abs(rate - best_rate)) {
96*036935a8SXiaoDong Huang 				best_rate = now;
97*036935a8SXiaoDong Huang 				best_sel = i;
98*036935a8SXiaoDong Huang 			}
99*036935a8SXiaoDong Huang 		}
100*036935a8SXiaoDong Huang 		if (best_rate == 0)
101*036935a8SXiaoDong Huang 			best_sel = 0;
102*036935a8SXiaoDong Huang 		mmio_write_32(clock->info[MUX_ADDR_INFO],
103*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(best_sel, sel_mask,
104*036935a8SXiaoDong Huang 					      clock->info[MUX_SHIFT_INFO]));
105*036935a8SXiaoDong Huang 	} else {
106*036935a8SXiaoDong Huang 		for (i = 0; i <= sel_mask; i++) {
107*036935a8SXiaoDong Huang 			parent_rate = clk_scmi_common_get_parent_rate(clock, i);
108*036935a8SXiaoDong Huang 			div = DIV_ROUND_UP(parent_rate, rate);
109*036935a8SXiaoDong Huang 			if (div > div_mask + 1)
110*036935a8SXiaoDong Huang 				div = div_mask + 1;
111*036935a8SXiaoDong Huang 			now = parent_rate / div;
112*036935a8SXiaoDong Huang 			if (abs(rate - now) < abs(rate - best_rate)) {
113*036935a8SXiaoDong Huang 				best_rate = now;
114*036935a8SXiaoDong Huang 				best_div = div;
115*036935a8SXiaoDong Huang 				best_sel = i;
116*036935a8SXiaoDong Huang 			}
117*036935a8SXiaoDong Huang 		}
118*036935a8SXiaoDong Huang 		if (best_rate == 0) {
119*036935a8SXiaoDong Huang 			best_div = div_mask + 1;
120*036935a8SXiaoDong Huang 			best_sel = 0;
121*036935a8SXiaoDong Huang 		}
122*036935a8SXiaoDong Huang 
123*036935a8SXiaoDong Huang 		mmio_write_32(clock->info[DIV_ADDR_INFO],
124*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(div_mask, div_mask,
125*036935a8SXiaoDong Huang 					      clock->info[DIV_SHIFT_INFO]));
126*036935a8SXiaoDong Huang 		mmio_write_32(clock->info[MUX_ADDR_INFO],
127*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(best_sel, sel_mask,
128*036935a8SXiaoDong Huang 					      clock->info[MUX_SHIFT_INFO]));
129*036935a8SXiaoDong Huang 		mmio_write_32(clock->info[DIV_ADDR_INFO],
130*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(best_div - 1, div_mask,
131*036935a8SXiaoDong Huang 					      clock->info[DIV_SHIFT_INFO]));
132*036935a8SXiaoDong Huang 	}
133*036935a8SXiaoDong Huang 	return 0;
134*036935a8SXiaoDong Huang }
135*036935a8SXiaoDong Huang 
clk_scmi_common_set_status(rk_scmi_clock_t * clock,bool status)136*036935a8SXiaoDong Huang int clk_scmi_common_set_status(rk_scmi_clock_t *clock, bool status)
137*036935a8SXiaoDong Huang {
138*036935a8SXiaoDong Huang 	mmio_write_32(clock->info[GATE_ADDR_INFO],
139*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(!status, 0x1U,
140*036935a8SXiaoDong Huang 				      clock->info[GATE_SHIFT_INFO]));
141*036935a8SXiaoDong Huang 
142*036935a8SXiaoDong Huang 	return 0;
143*036935a8SXiaoDong Huang }
144