From 7ad0b7b11b52e8898852f7fbc2c41d7c37d59809 Mon Sep 17 00:00:00 2001 From: Nicolas Royer Date: Sun, 27 Sep 2020 17:47:17 +0200 Subject: rcar/module: add rcar sd_clock module and config data Change-Id: I3c1d31d82a6bdd8ad490ff1f0e609d93ebcd5da0 Signed-off-by: Tsutomu Muroya Signed-off-by: Nicolas Royer --- .../rcar_sd_clock/include/mod_rcar_sd_clock.h | 271 +++++++++ product/rcar/module/rcar_sd_clock/src/Makefile | 11 + .../module/rcar_sd_clock/src/mod_rcar_sd_clock.c | 422 +++++++++++++ product/rcar/scp_ramfw/config_rcar_sd_clock.c | 658 +++++++++++++++++++++ 4 files changed, 1362 insertions(+) create mode 100644 product/rcar/module/rcar_sd_clock/include/mod_rcar_sd_clock.h create mode 100644 product/rcar/module/rcar_sd_clock/src/Makefile create mode 100644 product/rcar/module/rcar_sd_clock/src/mod_rcar_sd_clock.c create mode 100644 product/rcar/scp_ramfw/config_rcar_sd_clock.c diff --git a/product/rcar/module/rcar_sd_clock/include/mod_rcar_sd_clock.h b/product/rcar/module/rcar_sd_clock/include/mod_rcar_sd_clock.h new file mode 100644 index 00000000..8e3c45ce --- /dev/null +++ b/product/rcar/module/rcar_sd_clock/include/mod_rcar_sd_clock.h @@ -0,0 +1,271 @@ +/* + * Renesas SCP/MCP Software + * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_RCAR_SD_CLOCK_H +#define MOD_RCAR_SD_CLOCK_H + +#include +#include + +#include +#include + +#include + +#include + +/*! + * \addtogroup GroupRCARModule RCAR Product Modules + * @{ + */ + +/*! + * \defgroup GroupRCARSdClock SD clock + * @{ + */ + +/*! + * \brief Rate lookup entry. + */ +struct mod_rcar_sd_clock_rate { + /*! Divider used to obtain the rate value. */ + uint32_t divider_num; + /*! Value to be set for the divider. */ + uint32_t divider; + /*! Divider maskbit value. */ + uint32_t divider_mask; +}; + +/*! + * \brief Subsystem clock device configuration. + */ +struct mod_rcar_sd_clock_dev_config { + /*! The type of the clock device. */ + enum mod_rcar_clock_type type; + + /*! Pointer to the clock's control register. */ + volatile uint32_t const control_reg; + + /*! enable / disable bit position. */ + volatile bool stop_clk; + + /*! enable / disable bit position. */ + volatile uint32_t const stop_clk_bit; + + /*! Parent clock id. */ + uint32_t parent; + + /*! Required initialization Clock divider. */ + bool need_hardware_init; + + /*! Fixed Clock divider. */ + uint32_t div; + + /*! Fixed Clock divider. */ + uint32_t multi; + + /*! The type of rates the clock provides (discrete or continuous) */ + enum mod_clock_rate_type rate_type; + + /*! Pointer to the clock's rate lookup table. */ + const struct mod_rcar_sd_clock_rate *rate_table; + + /*! The number of rates in the rate lookup table. */ + uint32_t rate_count; +}; + +/*! + * @cond + */ + +/* Device context */ +struct rcar_sd_clock_dev_ctx { + bool initialized; + uint64_t current_rate; + uint64_t *rate_table; + enum mod_clock_state current_state; + const struct mod_rcar_sd_clock_dev_config *config; +}; + +/* Module context */ +struct rcar_sd_clock_ctx { + struct rcar_sd_clock_dev_ctx *dev_ctx_table; + unsigned int dev_count; + uint32_t parent_clk[CLOCK_PARENT_IDX_COUNT]; +}; + +struct rcar_gen3_cpg_pll_config { + char extal_div; + char pll1_mult; + char pll1_div; + char pll3_mult; + char pll3_div; + char osc_prediv; +}; + +/* control register */ +#define CPG_SD0CKCR (CPG_BASE + 0x0074) +#define CPG_SD1CKCR (CPG_BASE + 0x0078) +#define CPG_SD2CKCR (CPG_BASE + 0x0268) +#define CPG_SD3CKCR (CPG_BASE + 0x026C) +#define CPG_SDNCKCR_MASK 0x1F +#define CPG_SDNCKCR_SD_64 0x11 +#define CPG_SDNCKCR_SD_32 0xD +#define CPG_SDNCKCR_SD_16 0x9 +#define CPG_SDNCKCR_SD_8 0x5 +#define CPG_SDNCKCR_SD_4 0x1 +#define CPG_SDNCKCR_SD_2 0x0 + +#define CPG_CANFDCKCR (CPG_BASE + 0x0244) +#define CPG_CSI0CKCR (CPG_BASE + 0x000C) +#define CPG_MSOCKCR (CPG_BASE + 0x0014) +#define CPG_HDMICKCR (CPG_BASE + 0x0250) +#define CPG_CON_MASK 0x3F +#define CPG_CON_MAX 64 + +#define CPG_FRQCRB_ZTRFC_MASK 0xF00000 +#define CPG_FRQCRB_ZTRFC_24 0x800000 +#define CPG_FRQCRB_ZTRFC_18 0x700000 +#define CPG_FRQCRB_ZTRFC_16 0x600000 +#define CPG_FRQCRB_ZTRFC_12 0x500000 +#define CPG_FRQCRB_ZTRFC_8 0x400000 +#define CPG_FRQCRB_ZTRFC_6 0x300000 +#define CPG_FRQCRB_ZTFC_MASK 0xF0000 +#define CPG_FRQCRB_ZTFC_24 0x80000 +#define CPG_FRQCRB_ZTFC_18 0x70000 +#define CPG_FRQCRB_ZTFC_16 0x60000 +#define CPG_FRQCRB_ZTFC_12 0x50000 +#define CPG_FRQCRB_ZTFC_8 0x40000 +#define CPG_FRQCRB_ZTFC_6 0x30000 +#define CPG_FRQCRB_ZTFC_4 0x20000 +#define CPG_FRQCRB_ZTRD2FC_MASK 0xF +#define CPG_FRQCRB_ZTRD2FC_24 0x8 +#define CPG_FRQCRB_ZTRD2FC_18 0x7 +#define CPG_FRQCRB_ZTRD2FC_16 0x6 +#define CPG_FRQCRB_ZTRD2FC_12 0x5 + +#define CPG_PLL_CONFIG_INDEX(md) \ + ((((md)&BIT(14)) >> 11) | (((md)&BIT(13)) >> 11) | \ + (((md)&BIT(19)) >> 18) | (((md)&BIT(17)) >> 17)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] = { + /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */ + { + 1, + 192, + 1, + 192, + 1, + 16, + }, + { + 1, + 192, + 1, + 128, + 1, + 16, + }, + { 0, /* Prohibited setting */ }, + { + 1, + 192, + 1, + 192, + 1, + 16, + }, + { + 1, + 160, + 1, + 160, + 1, + 19, + }, + { + 1, + 160, + 1, + 106, + 1, + 19, + }, + { 0, /* Prohibited setting */ }, + { + 1, + 160, + 1, + 160, + 1, + 19, + }, + { + 1, + 128, + 1, + 128, + 1, + 24, + }, + { + 1, + 128, + 1, + 84, + 1, + 24, + }, + { 0, /* Prohibited setting */ }, + { + 1, + 128, + 1, + 128, + 1, + 24, + }, + { + 2, + 192, + 1, + 192, + 1, + 32, + }, + { + 2, + 192, + 1, + 128, + 1, + 32, + }, + { 0, /* Prohibited setting */ }, + { + 2, + 192, + 1, + 192, + 1, + 32, + }, +}; + +/*! + * @endcond + */ + +/*! + * @} + */ + +/*! + * @} + */ + +#endif /* MOD_RCAR_SD_CLOCK_H */ diff --git a/product/rcar/module/rcar_sd_clock/src/Makefile b/product/rcar/module/rcar_sd_clock/src/Makefile new file mode 100644 index 00000000..998cc590 --- /dev/null +++ b/product/rcar/module/rcar_sd_clock/src/Makefile @@ -0,0 +1,11 @@ +# +# Renesas SCP/MCP Software +# Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := RCAR SD Clock Driver +BS_LIB_SOURCES := mod_rcar_sd_clock.c + +include $(BS_DIR)/lib.mk diff --git a/product/rcar/module/rcar_sd_clock/src/mod_rcar_sd_clock.c b/product/rcar/module/rcar_sd_clock/src/mod_rcar_sd_clock.c new file mode 100644 index 00000000..a6bfc83d --- /dev/null +++ b/product/rcar/module/rcar_sd_clock/src/mod_rcar_sd_clock.c @@ -0,0 +1,422 @@ +/* + * Renesas SCP/MCP Software + * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct rcar_sd_clock_ctx module_ctx; + +/* + * Static helper functions + */ +static int get_rate_entry( + struct rcar_sd_clock_dev_ctx *ctx, + uint64_t target_rate, + struct mod_rcar_sd_clock_rate **entry) +{ + struct mod_rcar_sd_clock_rate *rate_entry; + uint32_t cnt; + if (ctx == NULL) + return FWK_E_PARAM; + if (entry == NULL) + return FWK_E_PARAM; + + /* Perform a binary search to find the entry matching the requested rate */ + if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_CONTINUOUS) { + if ((ctx->rate_table[0] > target_rate) && + (ctx->rate_table[1] < target_rate)) + return FWK_E_PARAM; + rate_entry = (struct mod_rcar_sd_clock_rate *)ctx->config->rate_table; + *entry = rate_entry; + } else { + for (cnt = 0; cnt < ctx->config->rate_count; cnt++) { + if (ctx->rate_table[cnt] == target_rate) + break; + } + + if (cnt >= ctx->config->rate_count) + return FWK_E_PARAM; + *entry = (struct mod_rcar_sd_clock_rate *)&ctx->config->rate_table[cnt]; + } + return FWK_SUCCESS; +} + +static int do_sd_clock_set_rate(fwk_id_t dev_id, uint64_t rate) +{ + int status; + struct rcar_sd_clock_dev_ctx *ctx; + struct mod_rcar_sd_clock_rate *rate_entry; + uint32_t value; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + + status = get_rate_entry(ctx, rate, &rate_entry); + if (status != FWK_SUCCESS) + return status; + + switch (ctx->config->type) { + case MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE: + return FWK_E_SUPPORT; + case MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE: + if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_DISCRETE) { + value = mmio_read_32(ctx->config->control_reg); + value &= (~rate_entry->divider_mask); + value |= rate_entry->divider; + mmio_write_32(ctx->config->control_reg, value); + } else { + value = mmio_read_32(ctx->config->control_reg); + value &= (~CPG_CON_MASK); + value |= (CPG_CON_MAX - (rate / ctx->rate_table[2])) & CPG_CON_MASK; + mmio_write_32(ctx->config->control_reg, value); + } + break; + default: + return FWK_E_SUPPORT; + } + + ctx->current_rate = rate; + + return FWK_SUCCESS; +} + +/* + * Clock driver API functions + */ +static int sd_clock_set_rate( + fwk_id_t dev_id, + uint64_t rate, + enum mod_clock_round_mode round_mode) +{ + struct rcar_sd_clock_dev_ctx *ctx; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + + if (!ctx->initialized) + return FWK_E_INIT; + + if (ctx->current_state == MOD_CLOCK_STATE_STOPPED) + return FWK_E_PWRSTATE; + + return do_sd_clock_set_rate(dev_id, rate); +} + +static int sd_clock_get_rate(fwk_id_t dev_id, uint64_t *rate) +{ + struct rcar_sd_clock_dev_ctx *ctx; + + if (rate == NULL) + return FWK_E_PARAM; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + + *rate = ctx->current_rate; + + return FWK_SUCCESS; +} + +static int sd_clock_get_rate_from_index( + fwk_id_t dev_id, + unsigned int rate_index, + uint64_t *rate) +{ + struct rcar_sd_clock_dev_ctx *ctx; + + if (rate == NULL) + return FWK_E_PARAM; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + + if (rate_index >= ctx->config->rate_count) + return FWK_E_PARAM; + + *rate = ctx->rate_table[rate_index]; + return FWK_SUCCESS; +} + +static int sd_clock_set_state( + fwk_id_t dev_id, + enum mod_clock_state target_state) +{ + struct rcar_sd_clock_dev_ctx *ctx; + uint32_t value; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + value = mmio_read_32(ctx->config->control_reg); + if (MOD_CLOCK_STATE_RUNNING == target_state) + value &= ~(BIT(ctx->config->stop_clk_bit)); + else + value |= BIT(ctx->config->stop_clk_bit); + + mmio_write_32(ctx->config->control_reg, value); + + ctx->current_state = target_state; + + return FWK_SUCCESS; +} + +static int sd_clock_get_state(fwk_id_t dev_id, enum mod_clock_state *state) +{ + struct rcar_sd_clock_dev_ctx *ctx; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + *state = ctx->current_state; + return FWK_SUCCESS; +} +static int sd_clock_get_range(fwk_id_t dev_id, struct mod_clock_range *range) +{ + struct rcar_sd_clock_dev_ctx *ctx; + + if (range == NULL) + return FWK_E_PARAM; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(dev_id); + + range->rate_type = ctx->config->rate_type; + if (ctx->config->rate_count > 0) { + if (MOD_CLOCK_RATE_TYPE_CONTINUOUS == range->rate_type) { + /* SCMI_CLOCK_RATE_FORMAT_RANGE */ + range->min = ctx->rate_table[0]; + range->max = ctx->rate_table[1]; + range->step = ctx->rate_table[2]; + } else { + /* SCMI_CLOCK_RATE_FORMAT_LIST */ + range->min = ctx->rate_table[0]; + range->max = ctx->rate_table[ctx->config->rate_count - 1]; + } + } + range->rate_count = ctx->config->rate_count; + + return FWK_SUCCESS; +} + +static int sd_clock_hw_initial_set_state( + fwk_id_t element_id, + struct rcar_sd_clock_dev_ctx *ctx) +{ + uint32_t i = 0; + uint32_t value = 0; + uint32_t div_value = 0; + uint64_t rate = 0; + + switch (ctx->config->type) { + case MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE: + ctx->current_state = MOD_CLOCK_STATE_RUNNING; + div_value = ctx->config->div; + break; + case MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE: + /* Maintain clock supply at startup. */ + ctx->current_state = MOD_CLOCK_STATE_RUNNING; + if (ctx->config->stop_clk) { + if (mmio_read_32(ctx->config->control_reg) & + BIT(ctx->config->stop_clk_bit)) + ctx->current_state = MOD_CLOCK_STATE_STOPPED; + } + /* Holds clock frequency at startup. */ + if (ctx->config->rate_type == MOD_CLOCK_RATE_TYPE_DISCRETE) { + value = mmio_read_32(ctx->config->control_reg); + value &= ctx->config->rate_table[0].divider_mask; + for (i = 0; i < ctx->config->rate_count; i++) { + if (value == ctx->config->rate_table[i].divider) { + div_value = ctx->config->rate_table[i].divider_num; + break; + } + } + } else { + value = mmio_read_32(ctx->config->control_reg); + value &= (CPG_CON_MASK); + div_value = (value + 1); + } + break; + default: + return FWK_E_SUPPORT; + } + ctx->current_rate = module_ctx.parent_clk[ctx->config->parent] / div_value; + + if (ctx->config->need_hardware_init) { + rate = module_ctx.parent_clk[ctx->config->parent] / ctx->config->div; + do_sd_clock_set_rate(element_id, rate); + } + + return FWK_SUCCESS; +} + +static int sd_clock_resume(void) +{ + fwk_id_t element_id = + FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, CLK_ID_SD_START); + struct rcar_sd_clock_dev_ctx *ctx; + uint32_t sd_id = 0; + int ret = FWK_SUCCESS; + + for (sd_id = CLK_ID_SD_START; sd_id < CLK_ID_SD_END; sd_id++) { + element_id.element.element_idx = sd_id; + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id); + + ret = sd_clock_hw_initial_set_state(element_id, ctx); + if (ret != FWK_SUCCESS) + break; + } + return ret; +} + +static const struct mod_rcar_clock_drv_api api_clock = { + .set_rate = sd_clock_set_rate, + .get_rate = sd_clock_get_rate, + .get_rate_from_index = sd_clock_get_rate_from_index, + .set_state = sd_clock_set_state, + .get_state = sd_clock_get_state, + .get_range = sd_clock_get_range, + .resume = sd_clock_resume, +}; + +/* + * Framework handler functions + */ + +static int r8a7795_cpg_pll1_init(uint32_t ext_rate) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + uint32_t saved_mode; + saved_mode = mmio_read_32(RCAR_MODEMR); + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(saved_mode)]; + return (ext_rate * cpg_pll_config->pll1_mult / cpg_pll_config->pll1_div); +} + +static int r8a7795_cpg_init(uint32_t ext_rate) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + uint32_t saved_mode; + saved_mode = mmio_read_32(RCAR_MODEMR); + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(saved_mode)]; + return (ext_rate / cpg_pll_config->osc_prediv); +} + +static int sd_clock_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + struct mod_ext_clock_rate *ext; + module_ctx.dev_count = element_count; + + if (element_count == 0) + return FWK_SUCCESS; + + module_ctx.dev_ctx_table = + fwk_mm_calloc(element_count, sizeof(struct rcar_sd_clock_dev_ctx)); + if (module_ctx.dev_ctx_table == NULL) + return FWK_E_NOMEM; + + /* Parent clock calculation. */ + ext = (struct mod_ext_clock_rate *)data; + module_ctx.parent_clk[CLK_EXTAL] = ext->ext_clk_rate; + module_ctx.parent_clk[CLK_OSC_EXTAL] = r8a7795_cpg_init(ext->ext_clk_rate); + module_ctx.parent_clk[CLK_PLL1] = r8a7795_cpg_pll1_init(ext->ext_clk_rate); + module_ctx.parent_clk[CLK_PLL1_DIV2] = module_ctx.parent_clk[CLK_PLL1] / 2; + module_ctx.parent_clk[CLK_PLL1_DIV4] = module_ctx.parent_clk[CLK_PLL1] / 4; + ; + module_ctx.parent_clk[CLK_S0] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 2; + module_ctx.parent_clk[CLK_S1] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 3; + module_ctx.parent_clk[CLK_S2] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 4; + module_ctx.parent_clk[CLK_S3] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 6; + module_ctx.parent_clk[CLK_SDSRC] = module_ctx.parent_clk[CLK_PLL1_DIV2] / 2; + + return FWK_SUCCESS; +} + +static int sd_clock_element_init( + fwk_id_t element_id, + unsigned int sub_element_count, + const void *data) +{ + struct rcar_sd_clock_dev_ctx *ctx; + const struct mod_rcar_sd_clock_dev_config *dev_config = data; + unsigned int i = 0; + uint64_t current_rate; + uint64_t last_rate = 0; + + if (!fwk_module_is_valid_element_id(element_id)) + return FWK_E_PARAM; + + ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id); + ctx->config = dev_config; + + if (ctx->config->rate_count > 0) { + ctx->rate_table = + fwk_mm_calloc(ctx->config->rate_count, sizeof(uint64_t)); + if (ctx->rate_table == NULL) + return FWK_E_NOMEM; + + for (i = 0; i < ctx->config->rate_count; i++) + ctx->rate_table[i] = module_ctx.parent_clk[ctx->config->parent] / + ctx->config->rate_table[i].divider_num; + } + + /* Verify that the rate entries in the device's lookup table are ordered */ + if (dev_config->rate_type == MOD_CLOCK_RATE_TYPE_CONTINUOUS) { + if (ctx->rate_table[0] > ctx->rate_table[1]) + return FWK_E_DATA; + } else { + i = 0; + while (i < dev_config->rate_count) { + current_rate = ctx->rate_table[i]; + + /* The rate entries must be in ascending order */ + if (current_rate < last_rate) + return FWK_E_DATA; + + last_rate = current_rate; + i++; + } + } + + ctx->initialized = true; + + return FWK_SUCCESS; +} + +static int sd_clock_process_bind_request( + fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + *api = &api_clock; + return FWK_SUCCESS; +} + +static int sd_clock_start(fwk_id_t id) +{ + int ret = FWK_SUCCESS; + ret = sd_clock_resume(); + return ret; +} + +const struct fwk_module module_rcar_sd_clock = { + .name = "SD Clock Driver", + .type = FWK_MODULE_TYPE_DRIVER, + .api_count = MOD_RCAR_CLOCK_API_COUNT, + .event_count = 0, + .init = sd_clock_init, + .element_init = sd_clock_element_init, + .process_bind_request = sd_clock_process_bind_request, + .start = sd_clock_start, +}; diff --git a/product/rcar/scp_ramfw/config_rcar_sd_clock.c b/product/rcar/scp_ramfw/config_rcar_sd_clock.c new file mode 100644 index 00000000..56639165 --- /dev/null +++ b/product/rcar/scp_ramfw/config_rcar_sd_clock.c @@ -0,0 +1,658 @@ +/* + * Renesas SCP/MCP Software + * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* + * Rate lookup tables + */ +static const struct mod_rcar_sd_clock_rate rate_table_sys_ztr[] = { + { + /* 1/24 */ + .divider_num = 24, + .divider = CPG_FRQCRB_ZTRFC_24, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, + { + /* 1/18 */ + .divider_num = 18, + .divider = CPG_FRQCRB_ZTRFC_18, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, + { + /* 1/16 */ + .divider_num = 16, + .divider = CPG_FRQCRB_ZTRFC_16, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, + { + /* 1/12 */ + .divider_num = 12, + .divider = CPG_FRQCRB_ZTRFC_12, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, + { + /* 1/8 */ + .divider_num = 8, + .divider = CPG_FRQCRB_ZTRFC_8, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, + { + /* 1/6 */ + .divider_num = 6, + .divider = CPG_FRQCRB_ZTRFC_6, + .divider_mask = CPG_FRQCRB_ZTRFC_MASK, + }, +}; + +static const struct mod_rcar_sd_clock_rate rate_table_sys_ztrd2[] = { + { + /* 1/24 */ + .divider_num = 24, + .divider = CPG_FRQCRB_ZTRD2FC_24, + .divider_mask = CPG_FRQCRB_ZTRD2FC_MASK, + }, + { + /* 1/18 */ + .divider_num = 18, + .divider = CPG_FRQCRB_ZTRD2FC_18, + .divider_mask = CPG_FRQCRB_ZTRD2FC_MASK, + }, + { + /* 1/16 */ + .divider_num = 16, + .divider = CPG_FRQCRB_ZTRD2FC_16, + .divider_mask = CPG_FRQCRB_ZTRD2FC_MASK, + }, + { + /* 1/12 */ + .divider_num = 12, + .divider = CPG_FRQCRB_ZTRD2FC_12, + .divider_mask = CPG_FRQCRB_ZTRD2FC_MASK, + }, +}; + +static const struct mod_rcar_sd_clock_rate rate_table_sys_zt[] = { + { + /* 1/24 */ + .divider_num = 24, + .divider = CPG_FRQCRB_ZTFC_24, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/18 */ + .divider_num = 18, + .divider = CPG_FRQCRB_ZTFC_18, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/16 */ + .divider_num = 16, + .divider = CPG_FRQCRB_ZTFC_16, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/12 */ + .divider_num = 12, + .divider = CPG_FRQCRB_ZTFC_12, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/8 */ + .divider_num = 8, + .divider = CPG_FRQCRB_ZTFC_8, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/6 */ + .divider_num = 6, + .divider = CPG_FRQCRB_ZTFC_6, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, + { + /* 1/4 */ + .divider_num = 4, + .divider = CPG_FRQCRB_ZTFC_4, + .divider_mask = CPG_FRQCRB_ZTFC_MASK, + }, +}; + +static const struct mod_rcar_sd_clock_rate rate_table_sys_sd[] = { + { + /* 1/64 */ + .divider_num = 64, + .divider = CPG_SDNCKCR_SD_64, + .divider_mask = CPG_SDNCKCR_MASK, + }, + { + /* 1/32 */ + .divider_num = 32, + .divider = CPG_SDNCKCR_SD_32, + .divider_mask = CPG_SDNCKCR_MASK, + }, + { + /* 1/16 */ + .divider_num = 16, + .divider = CPG_SDNCKCR_SD_16, + .divider_mask = CPG_SDNCKCR_MASK, + }, + { + /* 1/8 */ + .divider_num = 8, + .divider = CPG_SDNCKCR_SD_8, + .divider_mask = CPG_SDNCKCR_MASK, + }, + { + /* 1/4 */ + .divider_num = 4, + .divider = CPG_SDNCKCR_SD_4, + .divider_mask = CPG_SDNCKCR_MASK, + }, + { + /* 1/2 */ + .divider_num = 2, + .divider = CPG_SDNCKCR_SD_2, + .divider_mask = CPG_SDNCKCR_MASK, + }, +}; + +static const struct mod_rcar_sd_clock_rate rate_table_sys_ckcr[] = { + /* min rate*/ + { + .divider_num = 64, + }, + /* max rate*/ + { + .divider_num = 1, + }, + /* step rate*/ + { + .divider_num = 64, + }, +}; + +static const struct fwk_element pik_clock_element_table[] = { + { + .name = "ztr", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_FRQCRB, + .stop_clk = false, + .parent = CLK_PLL1_DIV2, + .div = 6, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_ztr, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ztr), + }), + }, + { + .name = "ztrd2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_FRQCRB, + .stop_clk = false, + .parent = CLK_PLL1_DIV2, + .div = 12, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_ztrd2, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ztrd2), + }), + }, + { + .name = "zt", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_FRQCRB, + .stop_clk = false, + .parent = CLK_PLL1_DIV2, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_zt, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_zt), + }), + }, + { + .name = "zx", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .control_reg = CPG_FRQCRB, + .parent = CLK_PLL1_DIV2, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 1, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d3", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 3, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d4", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d6", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 6, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d8", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 8, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0d12", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S0, + .div = 12, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s1d1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S1, + .div = 1, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s1d2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S1, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s1d4", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S1, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s2d1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S2, + .div = 1, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s2d2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S2, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s2d4", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S2, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s3d1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S3, + .div = 1, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s3d2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S3, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s3d4", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_S3, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "sd0", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_SD0CKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_SDSRC, + .need_hardware_init = true, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_sd, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_sd), + }), + }, + { + .name = "sd1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_SD1CKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_SDSRC, + .need_hardware_init = true, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_sd, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_sd), + }), + }, + { + .name = "sd2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_SD2CKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_SDSRC, + .need_hardware_init = true, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_sd, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_sd), + }), + }, + { + .name = "sd3", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_SD3CKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_SDSRC, + .need_hardware_init = true, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + .rate_table = rate_table_sys_sd, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_sd), + }), + }, + { + .name = "cl", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 48, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "cr", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV4, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "cp", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_EXTAL, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "cpex", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_EXTAL, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "canfd", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_CANFDCKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_PLL1_DIV4, + .div = 64, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_CONTINUOUS, + .rate_table = rate_table_sys_ckcr, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ckcr), + }), + }, + { + .name = "csi0", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_CSI0CKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_PLL1_DIV4, + .div = 64, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_CONTINUOUS, + .rate_table = rate_table_sys_ckcr, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ckcr), + }), + }, + { + .name = "mso", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_MSOCKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_PLL1_DIV4, + .div = 63, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_CONTINUOUS, + .rate_table = rate_table_sys_ckcr, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ckcr), + }), + }, + { + .name = "hdmi", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, + .control_reg = CPG_HDMICKCR, + .stop_clk = true, + .stop_clk_bit = 8, + .parent = CLK_PLL1_DIV4, + .div = 63, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_CONTINUOUS, + .rate_table = rate_table_sys_ckcr, + .rate_count = FWK_ARRAY_SIZE(rate_table_sys_ckcr), + }), + }, + { + .name = "osc", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_OSC_EXTAL, + .div = 8, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "r", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_OSC_EXTAL, + .div = 32, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s0", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s1", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 3, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s2", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 4, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "s3", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 6, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "sdsrc", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_PLL1_DIV2, + .div = 2, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { + .name = "rint", + .data = &((struct mod_rcar_sd_clock_dev_config){ + .type = MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, + .parent = CLK_OSC_EXTAL, + .div = 32, + .multi = 1, + .rate_type = MOD_CLOCK_RATE_TYPE_DISCRETE, + }), + }, + { 0 }, /* Termination description. */ +}; + +static const struct fwk_element *pik_clock_get_element_table(fwk_id_t module_id) +{ + return pik_clock_element_table; +} + +struct fwk_module_config config_rcar_sd_clock = { + .elements = FWK_MODULE_DYNAMIC_ELEMENTS(pik_clock_get_element_table), + .data = &((struct mod_ext_clock_rate){ + .ext_clk_rate = PLL_BASE_CLOCK, + }), +}; -- cgit v1.2.3