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