1 /*
2  * Copyright (c) 2023 EPAM Systems
3  * Copyright (c) 2023 IoT.bzh
4  *
5  * r8a779f0 Clock Pulse Generator / Module Standby and Software Reset
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #define DT_DRV_COMPAT renesas_r8a779f0_cpg_mssr
11 
12 #include <errno.h>
13 #include <zephyr/arch/cpu.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h>
16 #include <zephyr/dt-bindings/clock/renesas_cpg_mssr.h>
17 #include <zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h>
18 #include <zephyr/irq.h>
19 #include "clock_control_renesas_cpg_mssr.h"
20 
21 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_DECLARE(clock_control_rcar);
24 
25 #define R8A779F0_CLK_SD0_STOP_BIT 8
26 #define R8A779F0_CLK_SD0_DIV_MASK 0x3
27 #define R8A779F0_CLK_SD0_DIV_SHIFT 0
28 
29 #define R8A779F0_CLK_SD0H_STOP_BIT 9
30 #define R8A779F0_CLK_SD0H_DIV_MASK 0x7
31 #define R8A779F0_CLK_SD0H_DIV_SHIFT 2
32 
33 #define R8A779F0_CLK_SDSRC_DIV_MASK 0x3
34 #define R8A779F0_CLK_SDSRC_DIV_SHIFT 29
35 
36 struct r8a779f0_cpg_mssr_cfg {
37 	DEVICE_MMIO_ROM; /* Must be first */
38 };
39 
40 struct r8a779f0_cpg_mssr_data {
41 	struct rcar_cpg_mssr_data cmn; /* Must be first */
42 };
43 
44 enum clk_ids {
45 	/* Core Clock Outputs exported to DT */
46 	LAST_DT_CORE_CLK = R8A779F0_CLK_OSC,
47 
48 	/* Internal Core Clocks */
49 	CLK_PLL5,
50 	CLK_SDSRC,
51 };
52 
53 /* NOTE: the array MUST be sorted by module field */
54 static struct cpg_clk_info_table core_props[] = {
55 	RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_S0D12_PER, RCAR_CPG_NONE, RCAR_CPG_NONE,
56 				RCAR_CPG_KHZ(66660)),
57 
58 	RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE,
59 				RCAR_CPG_KHZ(16660)),
60 
61 	RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_SD0H, 0x0870, CLK_SDSRC, RCAR_CPG_NONE),
62 	RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_SD0, 0x0870, R8A779F0_CLK_SD0H, RCAR_CPG_NONE),
63 
64 	RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_SASYNCPERD1, RCAR_CPG_NONE, RCAR_CPG_NONE,
65 				266666666),
66 
67 	RCAR_CORE_CLK_INFO_ITEM(CLK_PLL5, RCAR_CPG_NONE, RCAR_CPG_NONE, RCAR_CPG_MHZ(3200)),
68 	RCAR_CORE_CLK_INFO_ITEM(CLK_SDSRC, 0x08A4, CLK_PLL5, RCAR_CPG_NONE),
69 };
70 
71 /* NOTE: the array MUST be sorted by module field */
72 static struct cpg_clk_info_table mod_props[] = {
73 	RCAR_MOD_CLK_INFO_ITEM(514, R8A779F0_CLK_SASYNCPERD1),
74 	RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER),
75 	RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER),
76 
77 	RCAR_MOD_CLK_INFO_ITEM(706, R8A779F0_CLK_SD0),
78 
79 	RCAR_MOD_CLK_INFO_ITEM(915, R8A779F0_CLK_CL16M),
80 };
81 
r8a779f0_cpg_enable_disable_core(const struct device * dev,struct cpg_clk_info_table * clk_info,uint32_t enable)82 static int r8a779f0_cpg_enable_disable_core(const struct device *dev,
83 					    struct cpg_clk_info_table *clk_info, uint32_t enable)
84 {
85 	int ret = 0;
86 	uint32_t reg;
87 
88 	switch (clk_info->module) {
89 	case R8A779F0_CLK_SD0:
90 		reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset);
91 		reg &= ~(1 << R8A779F0_CLK_SD0_STOP_BIT);
92 		reg |= (!enable << R8A779F0_CLK_SD0_STOP_BIT);
93 		break;
94 	case R8A779F0_CLK_SD0H:
95 		reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset);
96 		reg &= ~(1 << R8A779F0_CLK_SD0H_STOP_BIT);
97 		reg |= (!enable << R8A779F0_CLK_SD0H_STOP_BIT);
98 		break;
99 	default:
100 		ret = -ENOTSUP;
101 		break;
102 	}
103 
104 	if (!ret) {
105 		rcar_cpg_write(DEVICE_MMIO_GET(dev), clk_info->offset, reg);
106 	}
107 	return ret;
108 }
109 
r8a779f0_cpg_core_clock_endisable(const struct device * dev,struct rcar_cpg_clk * clk,bool enable)110 static int r8a779f0_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk,
111 					     bool enable)
112 {
113 	struct cpg_clk_info_table *clk_info;
114 	struct r8a779f0_cpg_mssr_data *data = dev->data;
115 	k_spinlock_key_t key;
116 
117 	clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module);
118 	if (!clk_info) {
119 		return -EINVAL;
120 	}
121 
122 	if (enable) {
123 		if (clk->rate > 0) {
124 			int ret;
125 			uintptr_t rate = clk->rate;
126 
127 			ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk,
128 						(clock_control_subsys_rate_t)rate);
129 			if (ret < 0) {
130 				return ret;
131 			}
132 		}
133 	}
134 
135 	key = k_spin_lock(&data->cmn.lock);
136 	r8a779f0_cpg_enable_disable_core(dev, clk_info, enable);
137 	k_spin_unlock(&data->cmn.lock, key);
138 
139 	return 0;
140 }
141 
r8a779f0_cpg_mssr_start_stop(const struct device * dev,clock_control_subsys_t sys,bool enable)142 int r8a779f0_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable)
143 {
144 	struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys;
145 	int ret;
146 
147 	if (!dev || !sys) {
148 		return -EINVAL;
149 	}
150 
151 	if (clk->domain == CPG_MOD) {
152 		struct r8a779f0_cpg_mssr_data *data = dev->data;
153 		k_spinlock_key_t key;
154 
155 		key = k_spin_lock(&data->cmn.lock);
156 		ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable);
157 		k_spin_unlock(&data->cmn.lock, key);
158 	} else if (clk->domain == CPG_CORE) {
159 		ret = r8a779f0_cpg_core_clock_endisable(dev, clk, enable);
160 	} else {
161 		ret = -EINVAL;
162 	}
163 
164 	return ret;
165 }
166 
r8a779f0_get_div_helper(uint32_t reg_val,uint32_t module)167 static uint32_t r8a779f0_get_div_helper(uint32_t reg_val, uint32_t module)
168 {
169 	switch (module) {
170 	case R8A779F0_CLK_S0D12_PER:
171 	case R8A779F0_CLK_CL16M:
172 		return 1;
173 	case CLK_SDSRC:
174 		reg_val >>= R8A779F0_CLK_SDSRC_DIV_SHIFT;
175 		reg_val &= R8A779F0_CLK_SDSRC_DIV_MASK;
176 		/*  setting of 3 is prohibited */
177 		if (reg_val < 3) {
178 			/* real divider is in range 4 - 6 */
179 			return reg_val + 4;
180 		}
181 
182 		LOG_WRN("SDSRC clock has an incorrect divider value: %u", reg_val);
183 		return RCAR_CPG_NONE;
184 	case R8A779F0_CLK_SD0H:
185 		reg_val >>= R8A779F0_CLK_SD0H_DIV_SHIFT;
186 		reg_val &= R8A779F0_CLK_SD0H_DIV_MASK;
187 		/* setting of value bigger than 4 is prohibited */
188 		if (reg_val < 5) {
189 			return (1 << reg_val);
190 		}
191 
192 		LOG_WRN("SD0H clock has an incorrect divider value: %u", reg_val);
193 		return RCAR_CPG_NONE;
194 	case R8A779F0_CLK_SD0:
195 		/* convert only two possible values 0,1 to 2,4 */
196 		return (1 << ((reg_val & R8A779F0_CLK_SD0_DIV_MASK) + 1));
197 	default:
198 		return RCAR_CPG_NONE;
199 	}
200 }
201 
r8a779f0_set_rate_helper(uint32_t module,uint32_t * divider,uint32_t * div_mask)202 static int r8a779f0_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask)
203 {
204 	switch (module) {
205 	case CLK_SDSRC:
206 		/* divider has to be in range 4-6 */
207 		if (*divider > 3 && *divider < 7) {
208 			/* we can write to register value in range 0-2 */
209 			*divider -= 4;
210 			*divider <<= R8A779F0_CLK_SDSRC_DIV_SHIFT;
211 			*div_mask = R8A779F0_CLK_SDSRC_DIV_MASK << R8A779F0_CLK_SDSRC_DIV_SHIFT;
212 			return 0;
213 		}
214 		return -EINVAL;
215 	case R8A779F0_CLK_SD0:
216 		/* possible to have only 2 or 4 */
217 		if (*divider == 2 || *divider == 4) {
218 			/* convert 2/4 to 0/1 */
219 			*divider >>= 2;
220 			*div_mask = R8A779F0_CLK_SD0_DIV_MASK << R8A779F0_CLK_SD0_DIV_SHIFT;
221 			return 0;
222 		}
223 		return -EINVAL;
224 	case R8A779F0_CLK_SD0H:
225 		/* divider should be power of two number and last possible value 16 */
226 		if (!is_power_of_two(*divider) || *divider > 16) {
227 			return -EINVAL;
228 		}
229 		/* 1,2,4,8,16 have to be converted to 0,1,2,3,4 and then shifted */
230 		*divider = (find_lsb_set(*divider) - 1) << R8A779F0_CLK_SD0H_DIV_SHIFT;
231 		*div_mask = R8A779F0_CLK_SD0H_DIV_MASK << R8A779F0_CLK_SD0H_DIV_SHIFT;
232 		return 0;
233 	default:
234 		return -ENOTSUP;
235 	}
236 }
237 
r8a779f0_cpg_mssr_start(const struct device * dev,clock_control_subsys_t sys)238 static int r8a779f0_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys)
239 {
240 	return r8a779f0_cpg_mssr_start_stop(dev, sys, true);
241 }
242 
r8a779f0_cpg_mssr_stop(const struct device * dev,clock_control_subsys_t sys)243 static int r8a779f0_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys)
244 {
245 	return r8a779f0_cpg_mssr_start_stop(dev, sys, false);
246 }
247 
r8a779f0_cpg_mssr_init(const struct device * dev)248 static int r8a779f0_cpg_mssr_init(const struct device *dev)
249 {
250 	DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
251 
252 	rcar_cpg_build_clock_relationship(dev);
253 	rcar_cpg_update_all_in_out_freq(dev);
254 	return 0;
255 }
256 
257 static DEVICE_API(clock_control, r8a779f0_cpg_mssr_api) = {
258 	.on = r8a779f0_cpg_mssr_start,
259 	.off = r8a779f0_cpg_mssr_stop,
260 	.get_rate = rcar_cpg_get_rate,
261 	.set_rate = rcar_cpg_set_rate,
262 };
263 
264 #define R8A779F0_MSSR_INIT(inst)							\
265 	static struct r8a779f0_cpg_mssr_cfg cpg_mssr##inst##_cfg = {		\
266 		DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)),			\
267 	};									\
268 										\
269 	static struct r8a779f0_cpg_mssr_data cpg_mssr##inst##_data = {		\
270 		.cmn.clk_info_table[CPG_CORE] = core_props,			\
271 		.cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props),	\
272 		.cmn.clk_info_table[CPG_MOD] = mod_props,			\
273 		.cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props),	\
274 		.cmn.get_div_helper = r8a779f0_get_div_helper,			\
275 		.cmn.set_rate_helper = r8a779f0_set_rate_helper			\
276 	};									\
277 										\
278 	DEVICE_DT_INST_DEFINE(inst,						\
279 			      &r8a779f0_cpg_mssr_init,				\
280 			      NULL,						\
281 			      &cpg_mssr##inst##_data,				\
282 			      &cpg_mssr##inst##_cfg,				\
283 			      PRE_KERNEL_1,					\
284 			      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,		\
285 			      &r8a779f0_cpg_mssr_api);
286 
287 DT_INST_FOREACH_STATUS_OKAY(R8A779F0_MSSR_INIT)
288