1 /*
2 * Renesas SCP/MCP Software
3 * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights
4 * reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <clock_sd_devices.h>
10 #include <mmio.h>
11
12 #include <mod_clock.h>
13 #include <mod_rcar_sd_clock.h>
14 #include <mod_rcar_system.h>
15
16 #include <fwk_assert.h>
17 #include <fwk_element.h>
18 #include <fwk_mm.h>
19 #include <fwk_module.h>
20 #include <fwk_module_idx.h>
21 #include <fwk_status.h>
22
23 #include <stdint.h>
24 #include <stdlib.h>
25
26 static struct rcar_sd_clock_ctx module_ctx;
27
28 /*
29 * Static helper functions
30 */
get_rate_entry(struct rcar_sd_clock_dev_ctx * ctx,uint64_t target_rate,struct mod_rcar_sd_clock_rate ** entry)31 static int get_rate_entry(
32 struct rcar_sd_clock_dev_ctx *ctx,
33 uint64_t target_rate,
34 struct mod_rcar_sd_clock_rate **entry)
35 {
36 struct mod_rcar_sd_clock_rate *rate_entry;
37 uint32_t cnt;
38 if (ctx == NULL)
39 return FWK_E_PARAM;
40 if (entry == NULL)
41 return FWK_E_PARAM;
42
43 /* Perform a binary search to find the entry matching the requested rate */
44 if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_CONTINUOUS) {
45 if ((ctx->rate_table[0] > target_rate) &&
46 (ctx->rate_table[1] < target_rate))
47 return FWK_E_PARAM;
48 rate_entry = (struct mod_rcar_sd_clock_rate *)ctx->config->rate_table;
49 *entry = rate_entry;
50 } else {
51 for (cnt = 0; cnt < ctx->config->rate_count; cnt++) {
52 if (ctx->rate_table[cnt] == target_rate)
53 break;
54 }
55
56 if (cnt >= ctx->config->rate_count)
57 return FWK_E_PARAM;
58 *entry = (struct mod_rcar_sd_clock_rate *)&ctx->config->rate_table[cnt];
59 }
60 return FWK_SUCCESS;
61 }
62
do_sd_clock_set_rate(fwk_id_t dev_id,uint64_t rate)63 static int do_sd_clock_set_rate(fwk_id_t dev_id, uint64_t rate)
64 {
65 int status;
66 struct rcar_sd_clock_dev_ctx *ctx;
67 struct mod_rcar_sd_clock_rate *rate_entry;
68 uint32_t value;
69
70 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
71
72 status = get_rate_entry(ctx, rate, &rate_entry);
73 if (status != FWK_SUCCESS)
74 return status;
75
76 switch (ctx->config->type) {
77 case MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE:
78 return FWK_E_SUPPORT;
79 case MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE:
80 if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_DISCRETE) {
81 value = mmio_read_32(ctx->config->control_reg);
82 value &= (~rate_entry->divider_mask);
83 value |= rate_entry->divider;
84 mmio_write_32(ctx->config->control_reg, value);
85 } else {
86 value = mmio_read_32(ctx->config->control_reg);
87 value &= (~CPG_CON_MASK);
88 value |= (CPG_CON_MAX - (rate / ctx->rate_table[2])) & CPG_CON_MASK;
89 mmio_write_32(ctx->config->control_reg, value);
90 }
91 break;
92 default:
93 return FWK_E_SUPPORT;
94 }
95
96 ctx->current_rate = rate;
97
98 return FWK_SUCCESS;
99 }
100
101 /*
102 * Clock driver API functions
103 */
sd_clock_set_rate(fwk_id_t dev_id,uint64_t rate,enum mod_clock_round_mode round_mode)104 static int sd_clock_set_rate(
105 fwk_id_t dev_id,
106 uint64_t rate,
107 enum mod_clock_round_mode round_mode)
108 {
109 struct rcar_sd_clock_dev_ctx *ctx;
110
111 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
112
113 if (!ctx->initialized)
114 return FWK_E_INIT;
115
116 if (ctx->current_state == MOD_CLOCK_STATE_STOPPED)
117 return FWK_E_PWRSTATE;
118
119 return do_sd_clock_set_rate(dev_id, rate);
120 }
121
sd_clock_get_rate(fwk_id_t dev_id,uint64_t * rate)122 static int sd_clock_get_rate(fwk_id_t dev_id, uint64_t *rate)
123 {
124 struct rcar_sd_clock_dev_ctx *ctx;
125
126 if (rate == NULL)
127 return FWK_E_PARAM;
128
129 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
130
131 *rate = ctx->current_rate;
132
133 return FWK_SUCCESS;
134 }
135
sd_clock_get_rate_from_index(fwk_id_t dev_id,unsigned int rate_index,uint64_t * rate)136 static int sd_clock_get_rate_from_index(
137 fwk_id_t dev_id,
138 unsigned int rate_index,
139 uint64_t *rate)
140 {
141 struct rcar_sd_clock_dev_ctx *ctx;
142
143 if (rate == NULL)
144 return FWK_E_PARAM;
145
146 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
147
148 if (rate_index >= ctx->config->rate_count)
149 return FWK_E_PARAM;
150
151 *rate = ctx->rate_table[rate_index];
152 return FWK_SUCCESS;
153 }
154
sd_clock_set_state(fwk_id_t dev_id,enum mod_clock_state target_state)155 static int sd_clock_set_state(
156 fwk_id_t dev_id,
157 enum mod_clock_state target_state)
158 {
159 struct rcar_sd_clock_dev_ctx *ctx;
160 uint32_t value;
161
162 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
163
164 /* No operation if the HW doesn't allow clock state change */
165 if (!ctx->config->stop_clk)
166 return FWK_SUCCESS;
167
168 value = mmio_read_32(ctx->config->control_reg);
169 if (MOD_CLOCK_STATE_RUNNING == target_state)
170 value &= ~(BIT(ctx->config->stop_clk_bit));
171 else
172 value |= BIT(ctx->config->stop_clk_bit);
173
174 mmio_write_32(ctx->config->control_reg, value);
175
176 ctx->current_state = target_state;
177
178 return FWK_SUCCESS;
179 }
180
sd_clock_get_state(fwk_id_t dev_id,enum mod_clock_state * state)181 static int sd_clock_get_state(fwk_id_t dev_id, enum mod_clock_state *state)
182 {
183 struct rcar_sd_clock_dev_ctx *ctx;
184
185 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
186 *state = ctx->current_state;
187 return FWK_SUCCESS;
188 }
sd_clock_get_range(fwk_id_t dev_id,struct mod_clock_range * range)189 static int sd_clock_get_range(fwk_id_t dev_id, struct mod_clock_range *range)
190 {
191 struct rcar_sd_clock_dev_ctx *ctx;
192
193 if (range == NULL)
194 return FWK_E_PARAM;
195
196 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id);
197
198 range->rate_type = ctx->config->rate_type;
199 if (ctx->config->rate_count > 0) {
200 if (MOD_CLOCK_RATE_TYPE_CONTINUOUS == range->rate_type) {
201 /* SCMI_CLOCK_RATE_FORMAT_RANGE */
202 range->min = ctx->rate_table[0];
203 range->max = ctx->rate_table[1];
204 range->step = ctx->rate_table[2];
205 } else {
206 /* SCMI_CLOCK_RATE_FORMAT_LIST */
207 range->min = ctx->rate_table[0];
208 range->max = ctx->rate_table[ctx->config->rate_count - 1];
209 }
210 }
211 range->rate_count = ctx->config->rate_count;
212
213 return FWK_SUCCESS;
214 }
215
sd_clock_hw_initial_set_state(fwk_id_t element_id,struct rcar_sd_clock_dev_ctx * ctx)216 static int sd_clock_hw_initial_set_state(
217 fwk_id_t element_id,
218 struct rcar_sd_clock_dev_ctx *ctx)
219 {
220 uint32_t i = 0;
221 uint32_t value = 0;
222 uint32_t div_value = 0;
223 uint64_t rate = 0;
224
225 switch (ctx->config->type) {
226 case MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE:
227 ctx->current_state = MOD_CLOCK_STATE_RUNNING;
228 div_value = ctx->config->div;
229 break;
230 case MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE:
231 /* Maintain clock supply at startup. */
232 ctx->current_state = MOD_CLOCK_STATE_RUNNING;
233 if (ctx->config->stop_clk) {
234 if (mmio_read_32(ctx->config->control_reg) &
235 BIT(ctx->config->stop_clk_bit))
236 ctx->current_state = MOD_CLOCK_STATE_STOPPED;
237 }
238 /* Holds clock frequency at startup. */
239 if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_DISCRETE) {
240 value = mmio_read_32(ctx->config->control_reg);
241 value &= ctx->config->rate_table[0].divider_mask;
242 for (i = 0; i < ctx->config->rate_count; i++) {
243 if (value == ctx->config->rate_table[i].divider) {
244 div_value = ctx->config->rate_table[i].divider_num;
245 break;
246 }
247 }
248 } else {
249 value = mmio_read_32(ctx->config->control_reg);
250 value &= (CPG_CON_MASK);
251 div_value = (value + 1);
252 }
253 break;
254 default:
255 return FWK_E_SUPPORT;
256 }
257 ctx->current_rate = module_ctx.parent_clk[ctx->config->parent] / div_value;
258
259 if (ctx->config->need_hardware_init) {
260 rate = module_ctx.parent_clk[ctx->config->parent] / ctx->config->div;
261 do_sd_clock_set_rate(element_id, rate);
262 }
263
264 return FWK_SUCCESS;
265 }
266
sd_clock_resume(void)267 static int sd_clock_resume(void)
268 {
269 fwk_id_t element_id =
270 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, CLK_ID_SD_START);
271 struct rcar_sd_clock_dev_ctx *ctx;
272 uint32_t sd_id = 0;
273 int ret = FWK_SUCCESS;
274
275 for (sd_id = CLK_ID_SD_START; sd_id < CLK_ID_SD_END; sd_id++) {
276 element_id.element.element_idx = sd_id;
277 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id);
278
279 ret = sd_clock_hw_initial_set_state(element_id, ctx);
280 if (ret != FWK_SUCCESS)
281 break;
282 }
283 return ret;
284 }
285
286 static const struct mod_rcar_clock_drv_api api_clock = {
287 .set_rate = sd_clock_set_rate,
288 .get_rate = sd_clock_get_rate,
289 .get_rate_from_index = sd_clock_get_rate_from_index,
290 .set_state = sd_clock_set_state,
291 .get_state = sd_clock_get_state,
292 .get_range = sd_clock_get_range,
293 };
294
295 static const struct mod_rcar_system_drv_api api_system = {
296 .resume = sd_clock_resume,
297 };
298
299 /*
300 * Framework handler functions
301 */
302
r8a7795_cpg_pll1_init(uint32_t ext_rate)303 static int r8a7795_cpg_pll1_init(uint32_t ext_rate)
304 {
305 const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
306 uint32_t saved_mode;
307 saved_mode = mmio_read_32(RCAR_MODEMR);
308 cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(saved_mode)];
309 return (ext_rate * cpg_pll_config->pll1_mult / cpg_pll_config->pll1_div);
310 }
311
r8a7795_cpg_init(uint32_t ext_rate)312 static int r8a7795_cpg_init(uint32_t ext_rate)
313 {
314 const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
315 uint32_t saved_mode;
316 saved_mode = mmio_read_32(RCAR_MODEMR);
317 cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(saved_mode)];
318 return (ext_rate / cpg_pll_config->osc_prediv);
319 }
320
sd_clock_init(fwk_id_t module_id,unsigned int element_count,const void * data)321 static int sd_clock_init(
322 fwk_id_t module_id,
323 unsigned int element_count,
324 const void *data)
325 {
326 struct mod_ext_clock_rate *ext;
327 module_ctx.dev_count = element_count;
328
329 if (element_count == 0)
330 return FWK_SUCCESS;
331
332 module_ctx.dev_ctx_table =
333 fwk_mm_calloc(element_count, sizeof(struct rcar_sd_clock_dev_ctx));
334 if (module_ctx.dev_ctx_table == NULL)
335 return FWK_E_NOMEM;
336
337 /* Parent clock calculation. */
338 ext = (struct mod_ext_clock_rate *)data;
339 module_ctx.parent_clk[CLK_EXTAL] = ext->ext_clk_rate;
340 module_ctx.parent_clk[CLK_OSC_EXTAL] = r8a7795_cpg_init(ext->ext_clk_rate);
341 module_ctx.parent_clk[CLK_PLL1] = r8a7795_cpg_pll1_init(ext->ext_clk_rate);
342 module_ctx.parent_clk[CLK_PLL1_DIV2] = module_ctx.parent_clk[CLK_PLL1] / 2;
343 module_ctx.parent_clk[CLK_PLL1_DIV4] = module_ctx.parent_clk[CLK_PLL1] / 4;
344 ;
345 module_ctx.parent_clk[CLK_S0] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 2;
346 module_ctx.parent_clk[CLK_S1] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 3;
347 module_ctx.parent_clk[CLK_S2] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 4;
348 module_ctx.parent_clk[CLK_S3] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 6;
349 module_ctx.parent_clk[CLK_SDSRC] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 2;
350
351 return FWK_SUCCESS;
352 }
353
sd_clock_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)354 static int sd_clock_element_init(
355 fwk_id_t element_id,
356 unsigned int sub_element_count,
357 const void *data)
358 {
359 struct rcar_sd_clock_dev_ctx *ctx;
360 const struct mod_rcar_sd_clock_dev_config *dev_config = data;
361 unsigned int i;
362 uint64_t current_rate;
363 uint64_t last_rate = 0;
364
365 if (!fwk_module_is_valid_element_id(element_id))
366 return FWK_E_PARAM;
367
368 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id);
369 ctx->config = dev_config;
370
371 if (ctx->config->rate_count > 0) {
372 ctx->rate_table =
373 fwk_mm_calloc(ctx->config->rate_count, sizeof(uint64_t));
374 if (ctx->rate_table == NULL)
375 return FWK_E_NOMEM;
376
377 for (i = 0; i < ctx->config->rate_count; i++)
378 ctx->rate_table[i] = module_ctx.parent_clk[ctx->config->parent] /
379 ctx->config->rate_table[i].divider_num;
380 }
381
382 /* Verify that the rate entries in the device's lookup table are ordered */
383 if (dev_config->rate_type == MOD_CLOCK_RATE_TYPE_CONTINUOUS) {
384 if (ctx->rate_table[0] > ctx->rate_table[1])
385 return FWK_E_DATA;
386 } else {
387 i = 0;
388 while (i < dev_config->rate_count) {
389 current_rate = ctx->rate_table[i];
390
391 /* The rate entries must be in ascending order */
392 if (current_rate < last_rate)
393 return FWK_E_DATA;
394
395 last_rate = current_rate;
396 i++;
397 }
398 }
399
400 ctx->initialized = true;
401
402 return FWK_SUCCESS;
403 }
404
sd_clock_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)405 static int sd_clock_process_bind_request(
406 fwk_id_t source_id,
407 fwk_id_t target_id,
408 fwk_id_t api_id,
409 const void **api)
410 {
411
412 switch (fwk_id_get_api_idx(api_id)) {
413 case MOD_RCAR_CLOCK_API_TYPE_SYSTEM:
414 *api = &api_system;
415 break;
416 default:
417 *api = &api_clock;
418 break;
419 }
420
421 return FWK_SUCCESS;
422 }
423
sd_clock_start(fwk_id_t id)424 static int sd_clock_start(fwk_id_t id)
425 {
426 int ret = FWK_SUCCESS;
427
428 /* for Not Module */
429 if (!fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
430 return ret;
431
432 ret = sd_clock_resume();
433 return ret;
434 }
435
436 const struct fwk_module module_rcar_sd_clock = {
437 .type = FWK_MODULE_TYPE_DRIVER,
438 .api_count = MOD_RCAR_CLOCK_API_COUNT,
439 .event_count = 0,
440 .init = sd_clock_init,
441 .element_init = sd_clock_element_init,
442 .process_bind_request = sd_clock_process_bind_request,
443 .start = sd_clock_start,
444 };
445