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