1 /*
2  * Copyright (c) 2022 IoT.bzh
3  *
4  * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define DT_DRV_COMPAT renesas_r8a7795_cpg_mssr
10 
11 #include <errno.h>
12 #include <zephyr/arch/cpu.h>
13 #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h>
14 #include <zephyr/dt-bindings/clock/renesas_cpg_mssr.h>
15 #include <zephyr/dt-bindings/clock/r8a7795_cpg_mssr.h>
16 #include <zephyr/irq.h>
17 #include "clock_control_renesas_cpg_mssr.h"
18 #include <zephyr/logging/log.h>
19 
20 LOG_MODULE_DECLARE(clock_control_rcar);
21 
22 #define R8A7795_CLK_SD_STOP_BIT  8
23 #define R8A7795_CLK_SD_DIV_MASK  0x3
24 #define R8A7795_CLK_SD_DIV_SHIFT 0
25 
26 #define R8A7795_CLK_SDH_STOP_BIT  9
27 #define R8A7795_CLK_SDH_DIV_MASK  0x7
28 #define R8A7795_CLK_SDH_DIV_SHIFT 2
29 
30 #define R8A7795_CLK_CANFD_STOP_BIT 8
31 #define R8A7795_CLK_CANFD_DIV_MASK 0x3f
32 
33 struct r8a7795_cpg_mssr_config {
34 	DEVICE_MMIO_ROM; /* Must be first */
35 };
36 
37 struct r8a7795_cpg_mssr_data {
38 	struct rcar_cpg_mssr_data cmn; /* Must be first */
39 };
40 
41 /* NOTE: the array MUST be sorted by module field */
42 static struct cpg_clk_info_table core_props[] = {
43 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S3D4, RCAR_CPG_NONE, RCAR_CPG_NONE,
44 				RCAR_CPG_KHZ(66600)),
45 
46 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0H, 0x0074, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)),
47 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0, 0x0074, R8A7795_CLK_SD0H, RCAR_CPG_MHZ(800)),
48 
49 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD1H, 0x0078, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)),
50 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD1, 0x0078, R8A7795_CLK_SD1H, RCAR_CPG_MHZ(800)),
51 
52 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD2H, 0x0268, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)),
53 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD2, 0x0268, R8A7795_CLK_SD2H, RCAR_CPG_MHZ(800)),
54 
55 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD3H, 0x026C, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)),
56 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD3, 0x026C, R8A7795_CLK_SD3H, RCAR_CPG_MHZ(800)),
57 
58 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_CANFD, 0x0244, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)),
59 
60 	RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S0D12, RCAR_CPG_NONE, RCAR_CPG_NONE,
61 				RCAR_CPG_KHZ(66600)),
62 };
63 
64 /* NOTE: the array MUST be sorted by module field */
65 static struct cpg_clk_info_table mod_props[] = {
66 	RCAR_MOD_CLK_INFO_ITEM(310, R8A7795_CLK_S3D4),
67 
68 	RCAR_MOD_CLK_INFO_ITEM(311, R8A7795_CLK_SD3),
69 	RCAR_MOD_CLK_INFO_ITEM(312, R8A7795_CLK_SD2),
70 	RCAR_MOD_CLK_INFO_ITEM(313, R8A7795_CLK_SD1),
71 	RCAR_MOD_CLK_INFO_ITEM(314, R8A7795_CLK_SD0),
72 };
73 
r8a7795_cpg_enable_disable_core(const struct device * dev,struct cpg_clk_info_table * clk_info,uint32_t enable)74 static int r8a7795_cpg_enable_disable_core(const struct device *dev,
75 					   struct cpg_clk_info_table *clk_info, uint32_t enable)
76 {
77 	int ret = 0;
78 	uint32_t reg;
79 
80 	enable = !!enable;
81 
82 	switch (clk_info->module) {
83 	case R8A7795_CLK_SD0:
84 	case R8A7795_CLK_SD1:
85 	case R8A7795_CLK_SD2:
86 	case R8A7795_CLK_SD3:
87 		reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset);
88 		reg &= ~(1 << R8A7795_CLK_SD_STOP_BIT);
89 		reg |= (!enable << R8A7795_CLK_SD_STOP_BIT);
90 		break;
91 	case R8A7795_CLK_SD0H:
92 	case R8A7795_CLK_SD1H:
93 	case R8A7795_CLK_SD2H:
94 	case R8A7795_CLK_SD3H:
95 		reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset);
96 		reg &= ~(1 << R8A7795_CLK_SDH_STOP_BIT);
97 		reg |= (!enable << R8A7795_CLK_SDH_STOP_BIT);
98 		break;
99 	case R8A7795_CLK_CANFD:
100 		reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset);
101 		reg &= ~(1 << R8A7795_CLK_CANFD_STOP_BIT);
102 		reg |= (!enable << R8A7795_CLK_CANFD_STOP_BIT);
103 		break;
104 	default:
105 		ret = -ENOTSUP;
106 		break;
107 	}
108 
109 	if (!ret) {
110 		rcar_cpg_write(DEVICE_MMIO_GET(dev), clk_info->offset, reg);
111 	}
112 	return ret;
113 }
114 
r8a7795_cpg_core_clock_endisable(const struct device * dev,struct rcar_cpg_clk * clk,bool enable)115 static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk,
116 					    bool enable)
117 {
118 	struct cpg_clk_info_table *clk_info;
119 	struct r8a7795_cpg_mssr_data *data = dev->data;
120 	k_spinlock_key_t key;
121 
122 	clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module);
123 	if (!clk_info) {
124 		return -EINVAL;
125 	}
126 
127 	if (enable) {
128 		if (clk->rate > 0) {
129 			int ret;
130 			uintptr_t rate = clk->rate;
131 
132 			ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk,
133 						(clock_control_subsys_rate_t)rate);
134 			if (ret < 0) {
135 				return ret;
136 			}
137 		}
138 	}
139 
140 	key = k_spin_lock(&data->cmn.lock);
141 	r8a7795_cpg_enable_disable_core(dev, clk_info, enable);
142 	k_spin_unlock(&data->cmn.lock, key);
143 
144 	return 0;
145 }
146 
r8a7795_cpg_mssr_start_stop(const struct device * dev,clock_control_subsys_t sys,bool enable)147 static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys,
148 				       bool enable)
149 {
150 	struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys;
151 	int ret;
152 
153 	if (!dev || !sys) {
154 		return -EINVAL;
155 	}
156 
157 	if (clk->domain == CPG_MOD) {
158 		struct r8a7795_cpg_mssr_data *data = dev->data;
159 		k_spinlock_key_t key;
160 
161 		key = k_spin_lock(&data->cmn.lock);
162 		ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable);
163 		k_spin_unlock(&data->cmn.lock, key);
164 	} else if (clk->domain == CPG_CORE) {
165 		ret = r8a7795_cpg_core_clock_endisable(dev, clk, enable);
166 	} else {
167 		ret = -EINVAL;
168 	}
169 
170 	return ret;
171 }
172 
r8a7795_get_div_helper(uint32_t reg_val,uint32_t module)173 static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module)
174 {
175 	switch (module) {
176 	case R8A7795_CLK_SD0H:
177 	case R8A7795_CLK_SD1H:
178 	case R8A7795_CLK_SD2H:
179 	case R8A7795_CLK_SD3H:
180 		reg_val >>= R8A7795_CLK_SDH_DIV_SHIFT;
181 		/* setting of value bigger than 4 is prohibited */
182 		if ((reg_val & R8A7795_CLK_SDH_DIV_MASK) < 5) {
183 			return 1 << (reg_val & R8A7795_CLK_SDH_DIV_MASK);
184 		} else {
185 			return RCAR_CPG_NONE;
186 		}
187 	case R8A7795_CLK_SD0:
188 	case R8A7795_CLK_SD1:
189 	case R8A7795_CLK_SD2:
190 	case R8A7795_CLK_SD3:
191 		/* convert only two possible values 0,1 to 2,4 */
192 		return 1 << ((reg_val & R8A7795_CLK_SD_DIV_MASK) + 1);
193 	case R8A7795_CLK_CANFD:
194 		/* according to documentation, divider value stored in reg is equal to: val + 1 */
195 		return (reg_val & R8A7795_CLK_CANFD_DIV_MASK) + 1;
196 	case R8A7795_CLK_S3D4:
197 	case R8A7795_CLK_S0D12:
198 		return 1;
199 	default:
200 		return RCAR_CPG_NONE;
201 	}
202 }
203 
r8a7795_set_rate_helper(uint32_t module,uint32_t * divider,uint32_t * div_mask)204 static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask)
205 {
206 	switch (module) {
207 	case R8A7795_CLK_SD0:
208 	case R8A7795_CLK_SD1:
209 	case R8A7795_CLK_SD2:
210 	case R8A7795_CLK_SD3:
211 		/* possible to have only 2 or 4 */
212 		if (*divider == 2 || *divider == 4) {
213 			/* convert 2/4 to 0/1 */
214 			*divider >>= 2;
215 			*div_mask = R8A7795_CLK_SD_DIV_MASK << R8A7795_CLK_SD_DIV_SHIFT;
216 			return 0;
217 		} else {
218 			return -EINVAL;
219 		}
220 	case R8A7795_CLK_SD0H:
221 	case R8A7795_CLK_SD1H:
222 	case R8A7795_CLK_SD2H:
223 	case R8A7795_CLK_SD3H:
224 		/* divider should be power of two and max possible value 16 */
225 		if (!is_power_of_two(*divider) || *divider > 16) {
226 			return -EINVAL;
227 			break;
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) << R8A7795_CLK_SDH_DIV_SHIFT;
231 		*div_mask = R8A7795_CLK_SDH_DIV_MASK << R8A7795_CLK_SDH_DIV_SHIFT;
232 		return 0;
233 	case R8A7795_CLK_CANFD:
234 		/* according to documentation, divider value stored in reg is equal to: val + 1 */
235 		*divider -= 1;
236 		if (*divider <= R8A7795_CLK_CANFD_DIV_MASK) {
237 			*div_mask = R8A7795_CLK_CANFD_DIV_MASK;
238 			return 0;
239 		} else {
240 			return -EINVAL;
241 		}
242 	default:
243 		return -ENOTSUP;
244 	}
245 }
246 
r8a7795_cpg_mssr_start(const struct device * dev,clock_control_subsys_t sys)247 static int r8a7795_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys)
248 {
249 	return r8a7795_cpg_mssr_start_stop(dev, sys, true);
250 }
251 
r8a7795_cpg_mssr_stop(const struct device * dev,clock_control_subsys_t sys)252 static int r8a7795_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys)
253 {
254 	return r8a7795_cpg_mssr_start_stop(dev, sys, false);
255 }
256 
r8a7795_cpg_mssr_init(const struct device * dev)257 static int r8a7795_cpg_mssr_init(const struct device *dev)
258 {
259 	DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
260 
261 	rcar_cpg_build_clock_relationship(dev);
262 	rcar_cpg_update_all_in_out_freq(dev);
263 	return 0;
264 }
265 
266 static const struct clock_control_driver_api r8a7795_cpg_mssr_api = {
267 	.on = r8a7795_cpg_mssr_start,
268 	.off = r8a7795_cpg_mssr_stop,
269 	.get_rate = rcar_cpg_get_rate,
270 	.set_rate = rcar_cpg_set_rate,
271 };
272 
273 #define R8A7795_MSSR_INIT(inst)							  \
274 	static struct r8a7795_cpg_mssr_config r8a7795_cpg_mssr##inst##_config = { \
275 		DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)),			  \
276 	};									  \
277 										  \
278 	static struct r8a7795_cpg_mssr_data r8a7795_cpg_mssr##inst##_data = {	  \
279 		.cmn.clk_info_table[CPG_CORE] = core_props,			  \
280 		.cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props),	  \
281 		.cmn.clk_info_table[CPG_MOD] = mod_props,			  \
282 		.cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props),	  \
283 		.cmn.get_div_helper = r8a7795_get_div_helper,			  \
284 		.cmn.set_rate_helper = r8a7795_set_rate_helper			  \
285 	};									  \
286 										  \
287 	DEVICE_DT_INST_DEFINE(inst,						  \
288 			      r8a7795_cpg_mssr_init,				  \
289 			      NULL,						  \
290 			      &r8a7795_cpg_mssr##inst##_data,			  \
291 			      &r8a7795_cpg_mssr##inst##_config,			  \
292 			      PRE_KERNEL_1,					  \
293 			      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,		  \
294 			      &r8a7795_cpg_mssr_api);
295 
296 DT_INST_FOREACH_STATUS_OKAY(R8A7795_MSSR_INIT)
297