From 04053f4d23a41b9383dcea4da302fd43f673afb3 Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 24 Jan 2019 16:47:00 -0800 Subject: [PATCH 01/16] clk: qcom: clk-rpmh: Add IPA clock support The clk-rpmh driver only supports on and off RPMh clock resources. Let's extend the driver by adding support for clocks that are managed by a different type of RPMh resource known as Bus Clock Manager(BCM). The BCM is a configurable shared resource aggregator that scales performance based on a set of frequency points. The Qualcomm IP Accelerator (IPA) clock is an example of a resource that is managed by the BCM and this a requirement from the IPA driver in order to scale its core clock. Signed-off-by: David Dai Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 146 ++++++++++++++++++++++++++ include/dt-bindings/clock/qcom,rpmh.h | 1 + 2 files changed, 147 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 9f4fc7773fb2..c3fd632af119 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -18,6 +18,31 @@ #define CLK_RPMH_ARC_EN_OFFSET 0 #define CLK_RPMH_VRM_EN_OFFSET 4 +#define BCM_TCS_CMD_COMMIT_MASK 0x40000000 +#define BCM_TCS_CMD_VALID_SHIFT 29 +#define BCM_TCS_CMD_VOTE_MASK 0x3fff +#define BCM_TCS_CMD_VOTE_SHIFT 0 + +#define BCM_TCS_CMD(valid, vote) \ + (BCM_TCS_CMD_COMMIT_MASK | \ + ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \ + ((vote & BCM_TCS_CMD_VOTE_MASK) \ + << BCM_TCS_CMD_VOTE_SHIFT)) + +/** + * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM) + * @unit: divisor used to convert Hz value to an RPMh msg + * @width: multiplier used to convert Hz value to an RPMh msg + * @vcd: virtual clock domain that this bcm belongs to + * @reserved: reserved to pad the struct + */ +struct bcm_db { + __le32 unit; + __le16 width; + u8 vcd; + u8 reserved; +}; + /** * struct clk_rpmh - individual rpmh clock data structure * @hw: handle between common and hardware-specific interfaces @@ -29,6 +54,7 @@ * @aggr_state: rpmh clock aggregated state * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh * @valid_state_mask: mask to determine the state of the rpmh clock + * @unit: divisor to convert rate to rpmh msg in magnitudes of Khz * @dev: device to which it is attached * @peer: pointer to the clock rpmh sibling */ @@ -42,6 +68,7 @@ struct clk_rpmh { u32 aggr_state; u32 last_sent_aggr_state; u32 valid_state_mask; + u32 unit; struct device *dev; struct clk_rpmh *peer; }; @@ -98,6 +125,17 @@ static DEFINE_MUTEX(rpmh_clk_lock); __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ CLK_RPMH_VRM_EN_OFFSET, 1, _div) +#define DEFINE_CLK_RPMH_BCM(_platform, _name, _res_name) \ + static struct clk_rpmh _platform##_##_name = { \ + .res_name = _res_name, \ + .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \ + .div = 1, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpmh_bcm_ops, \ + .name = #_name, \ + }, \ + } + static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) { return container_of(_hw, struct clk_rpmh, hw); @@ -210,6 +248,96 @@ static const struct clk_ops clk_rpmh_ops = { .recalc_rate = clk_rpmh_recalc_rate, }; +static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) +{ + struct tcs_cmd cmd = { 0 }; + u32 cmd_state; + int ret; + + mutex_lock(&rpmh_clk_lock); + + cmd_state = 0; + if (enable) { + cmd_state = 1; + if (c->aggr_state) + cmd_state = c->aggr_state; + } + + if (c->last_sent_aggr_state == cmd_state) { + mutex_unlock(&rpmh_clk_lock); + return 0; + } + + cmd.addr = c->res_addr; + cmd.data = BCM_TCS_CMD(enable, cmd_state); + + ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); + if (ret) { + dev_err(c->dev, "set active state of %s failed: (%d)\n", + c->res_name, ret); + mutex_unlock(&rpmh_clk_lock); + return ret; + } + + c->last_sent_aggr_state = cmd_state; + + mutex_unlock(&rpmh_clk_lock); + + return 0; +} + +static int clk_rpmh_bcm_prepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + return clk_rpmh_bcm_send_cmd(c, true); +}; + +static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + clk_rpmh_bcm_send_cmd(c, false); +}; + +static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + c->aggr_state = rate / c->unit; + /* + * Since any non-zero value sent to hw would result in enabling the + * clock, only send the value if the clock has already been prepared. + */ + if (clk_hw_is_prepared(hw)) + clk_rpmh_bcm_send_cmd(c, true); + + return 0; +}; + +static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return rate; +} + +static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + return c->aggr_state * c->unit; +} + +static const struct clk_ops clk_rpmh_bcm_ops = { + .prepare = clk_rpmh_bcm_prepare, + .unprepare = clk_rpmh_bcm_unprepare, + .set_rate = clk_rpmh_bcm_set_rate, + .round_rate = clk_rpmh_round_rate, + .recalc_rate = clk_rpmh_bcm_recalc_rate, +}; + /* Resource name must match resource id present in cmd-db. */ DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); @@ -217,6 +345,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); +DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, @@ -231,6 +360,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, + [RPMH_IPA_CLK] = &sdm845_ipa.hw, }; static const struct clk_rpmh_desc clk_rpmh_sdm845 = { @@ -267,6 +397,8 @@ static int clk_rpmh_probe(struct platform_device *pdev) for (i = 0; i < desc->num_clks; i++) { u32 res_addr; + size_t aux_data_len; + const struct bcm_db *data; rpmh_clk = to_clk_rpmh(hw_clks[i]); res_addr = cmd_db_read_addr(rpmh_clk->res_name); @@ -275,6 +407,20 @@ static int clk_rpmh_probe(struct platform_device *pdev) rpmh_clk->res_name); return -ENODEV; } + + data = cmd_db_read_aux_data(rpmh_clk->res_name, &aux_data_len); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + dev_err(&pdev->dev, + "error reading RPMh aux data for %s (%d)\n", + rpmh_clk->res_name, ret); + return ret; + } + + /* Convert unit from Khz to Hz */ + if (aux_data_len == sizeof(*data)) + rpmh_clk->unit = le32_to_cpu(data->unit) * 1000ULL; + rpmh_clk->res_addr += res_addr; rpmh_clk->dev = &pdev->dev; diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index f48fbd6f2095..edcab3f7b7d3 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -18,5 +18,6 @@ #define RPMH_RF_CLK2_A 9 #define RPMH_RF_CLK3 10 #define RPMH_RF_CLK3_A 11 +#define RPMH_IPA_CLK 12 #endif From c0189feeade0f02a6cdac3b27b5e9c52f9930fc2 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 11 Feb 2019 14:58:18 +0100 Subject: [PATCH 02/16] clk: clk-gpio: add support for sleeping GPIOs in gpio-gate-clk The current implementation of gpio-gate-clk enables/disables the clock using the GPIO in the ->enable() and ->disable() clock callbacks. This requires the GPIO to be configurable in atomic contexts. While it is the case for most memory-mapped GPIO controllers, it is not the case for GPIO expanders on I2C or SPI. This commit extends the gpio-gate-clk to check whether the GPIO calls require sleeping or not. If sleeping is not required, the current implementation based on ->enable()/->disable() is kept. However, if sleeping is needed, we instead implement the logic in the ->prepare() and ->unprepare() hooks. Thanks to this, a gate clock connected to a GPIO on a GPIO expander can be controlled with the existing driver. Signed-off-by: Thomas Petazzoni [sboyd@kernel.org: Mark clk ops static] Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 25eed3e0251f..c2f07f0d077c 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -58,6 +58,35 @@ const struct clk_ops clk_gpio_gate_ops = { }; EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); +static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value_cansleep(clk->gpiod, 1); + + return 0; +} + +static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value_cansleep(clk->gpiod, 0); +} + +static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value_cansleep(clk->gpiod); +} + +static const struct clk_ops clk_sleeping_gpio_gate_ops = { + .prepare = clk_sleeping_gpio_gate_prepare, + .unprepare = clk_sleeping_gpio_gate_unprepare, + .is_prepared = clk_sleeping_gpio_gate_is_prepared, +}; + /** * DOC: basic clock multiplexer which can be controlled with a gpio output * Traits of this clock: @@ -144,10 +173,16 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, const char *parent_name, struct gpio_desc *gpiod, unsigned long flags) { + const struct clk_ops *ops; + + if (gpiod_cansleep(gpiod)) + ops = &clk_sleeping_gpio_gate_ops; + else + ops = &clk_gpio_gate_ops; + return clk_register_gpio(dev, name, (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), gpiod, flags, - &clk_gpio_gate_ops); + (parent_name ? 1 : 0), gpiod, flags, ops); } EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate); From 749c9e553e1f063eb132a78d80225532cbfedb80 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:41 +0100 Subject: [PATCH 03/16] clk: stm32mp1: parent clocks update Fixes parent clock for axi, fdcan, sai and adc12 clocks. Fixes: e51d297e9a92 ("clk: stm32mp1: add Sub System clocks") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 6a31f7f434ce..be2ed35977ca 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -121,7 +121,7 @@ static const char * const cpu_src[] = { }; static const char * const axi_src[] = { - "ck_hsi", "ck_hse", "pll2_p", "pll3_p" + "ck_hsi", "ck_hse", "pll2_p" }; static const char * const per_src[] = { @@ -225,19 +225,19 @@ static const char * const usart6_src[] = { }; static const char * const fdcan_src[] = { - "ck_hse", "pll3_q", "pll4_q" + "ck_hse", "pll3_q", "pll4_q", "pll4_r" }; static const char * const sai_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per" + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" }; static const char * const sai2_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb" + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" }; static const char * const adc12_src[] = { - "pll4_q", "ck_per" + "pll4_r", "ck_per", "pll3_q" }; static const char * const dsi_src[] = { From 72cfd1ad1057f16fc614861b3c271597995e57ba Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:42 +0100 Subject: [PATCH 04/16] clk: stm32mp1: add CLK_SET_RATE_NO_REPARENT to Kernel clocks STM32MP1 clock IP offers lots of Kernel clocks that are shared by multiple IP's at the same time. Then boot loader applies a clock tree that allows to use all IP's at same time and with the maximum of performance. Not change parents on a change rate on kernel clocks ensures the integrity of the system. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index be2ed35977ca..e72079de83f4 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1286,10 +1286,11 @@ _clk_stm32_register_composite(struct device *dev, MGATE_MP1(_id, _name, _parent, _flags, _mgate) #define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ - COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\ - _MGATE_MP1(_mgate),\ - _MMUX(_mmux),\ - _NO_DIV) + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ + CLK_SET_RATE_NO_REPARENT | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) enum { G_SAI1, @@ -1952,7 +1953,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), - COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE, + COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, _NO_GATE, _MMUX(M_ETHCK), _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), From c488b24f862787dedbf2578e0bc622a74ac64f0f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:43 +0100 Subject: [PATCH 05/16] clk: stm32mp1: set ck_csi as critical clock ck_csi is used for IO compensation so it should be considered as "always-on" and kept on. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index e72079de83f4..f9b7d5e9491d 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1661,7 +1661,9 @@ static const struct clock_config stm32mp1_clock_cfg[] = { /* External / Internal Oscillators */ GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), - GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0), + /* ck_csi is used by IO compensation and should be critical */ + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, + RCC_OCENSETR, 4, 0), GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), From 140fc4e406fac420b978a0ef2ee1fe3c641a6ae4 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:44 +0100 Subject: [PATCH 06/16] clk: stm32mp1: fix mcu divider table index 8: ck_mcu is divided by 256 (not 512) Fixes: e51d297e9a92 ("clk: stm32mp1: add Sub System clocks") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index f9b7d5e9491d..8b4e01af4848 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -269,7 +269,7 @@ static const struct clk_div_table axi_div_table[] = { static const struct clk_div_table mcu_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, - { 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 }, + { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, { 0 }, }; From d3f2e33c875de5052e032a9eefa64c897a930ed1 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:45 +0100 Subject: [PATCH 07/16] clk: stm32mp1: fix HSI divider flag The divider of HSI (clk-hsi-div) is power of two divider. Fixes: 9bee94e7b7da ("clk: stm32mp1: Introduce STM32MP1 clock driver") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 8b4e01af4848..8958bc11ff05 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1656,8 +1656,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ - DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, - CLK_DIVIDER_READ_ONLY), + DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, + RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), /* External / Internal Oscillators */ GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), From f9b76fd24d0a0cd7b3d9309b93c36c9c32526b00 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:46 +0100 Subject: [PATCH 08/16] clk: stm32mp1: remove unnecessary CLK_DIVIDER_ALLOW_ZERO flag The divisor of ethptp_k and ck_hse_rtc clocks is: 'value register plus one'. Then CLK_DIVIDER_ALLOW_ZERO flag has no effect and is useless here. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 8958bc11ff05..ca987632564e 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1959,11 +1959,10 @@ static const struct clock_config stm32mp1_clock_cfg[] = { CLK_SET_RATE_NO_REPARENT, _NO_GATE, _MMUX(M_ETHCK), - _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), + _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), /* RTC clock */ - DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, - CLK_DIVIDER_ALLOW_ZERO), + DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, 0), COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, From 97621d22df60d7348826d2e4b0c349673faeb4b8 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:47 +0100 Subject: [PATCH 09/16] clk: stm32mp1: fix bit width of hse_rtc divider Fix the bit width of the hse rtc divider because it's off by one. Fixes: 2c87c9d33117 ("clk: stm32mp1: add RTC clock") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index ca987632564e..a0ae8dc16909 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1962,7 +1962,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), /* RTC clock */ - DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, 0), + DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0), COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, From 585fc46bd47a143ee7433768e298a7f94008e5f5 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:42:42 +0100 Subject: [PATCH 10/16] dt-bindings: clock: remove unused definition for stm32mp1 A copy of LTDC_PX and ETHCK_K (LTDC_K and ETHMAC_K) was introduced in stm32mp1 dt-bindings file by mistake. These bindings are not used and shouldn't be use to be conform with convention name of the stm32mp1 clock IP. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/stm32mp1-clks.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h index 90ec780bfc68..4cdaf135829c 100644 --- a/include/dt-bindings/clock/stm32mp1-clks.h +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -248,7 +248,4 @@ #define STM32MP1_LAST_CLK 232 -#define LTDC_K LTDC_PX -#define ETHMAC_K ETHCK_K - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ From fe6b580ec64cc8b32c4f5ee3db4a994471e1e4c1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 11 Feb 2019 13:09:26 +0530 Subject: [PATCH 11/16] clk: qcom: remove empty lines in clk-rcg.h Remove the redundant empty lines crept in. Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index e5eca8a1abe4..91336a030179 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -71,7 +71,6 @@ struct src_sel { * @freq_tbl: frequency table * @clkr: regmap clock handle * @lock: register lock - * */ struct clk_rcg { u32 ns_reg; @@ -107,7 +106,6 @@ extern const struct clk_ops clk_rcg_lcc_ops; * @freq_tbl: frequency table * @clkr: regmap clock handle * @lock: register lock - * */ struct clk_dyn_rcg { u32 ns_reg[2]; @@ -140,7 +138,6 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @clkr: regmap clock handle - * */ struct clk_rcg2 { u32 cmd_rcgr; From 96dc791d0b9e12f6374a80f00ad9304b9df2efee Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 11 Feb 2019 13:09:27 +0530 Subject: [PATCH 12/16] clk: qcom: clk-rcg2: Introduce a cfg offset for RCGs The RCG CFG/M/N/D register base could be at a different offset than the CMD register, so introduce a cfg_offset to identify the offset with respect to the CMD RCGR register. Signed-off-by: Taniya Das Signed-off-by: Anu Ramanathan Signed-off-by: Shawn Guo Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg.h | 2 ++ drivers/clk/qcom/clk-rcg2.c | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 91336a030179..c25b57c3cbc8 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -138,6 +138,7 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @clkr: regmap clock handle + * @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG */ struct clk_rcg2 { u32 cmd_rcgr; @@ -147,6 +148,7 @@ struct clk_rcg2 { const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; struct clk_regmap clkr; + u8 cfg_off; }; #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 6e3bd195d012..8c02bffe50df 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -41,6 +41,11 @@ #define N_REG 0xc #define D_REG 0x10 +#define RCG_CFG_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + CFG_REG) +#define RCG_M_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + M_REG) +#define RCG_N_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + N_REG) +#define RCG_D_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + D_REG) + /* Dynamic Frequency Scaling */ #define MAX_PERF_LEVEL 8 #define SE_CMD_DFSR_OFFSET 0x14 @@ -74,7 +79,7 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw) u32 cfg; int i, ret; - ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); if (ret) goto err; @@ -123,7 +128,7 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) int ret; u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + ret = regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), CFG_SRC_SEL_MASK, cfg); if (ret) return ret; @@ -162,13 +167,13 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); if (rcg->mnd_width) { mask = BIT(rcg->mnd_width) - 1; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m); + regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m); m &= mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n); + regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &n); n = ~n; n &= mask; n += m; @@ -263,17 +268,17 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) if (rcg->mnd_width && f->n) { mask = BIT(rcg->mnd_width) - 1; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + M_REG, mask, f->m); + RCG_M_OFFSET(rcg), mask, f->m); if (ret) return ret; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); + RCG_N_OFFSET(rcg), mask, ~(f->n - f->m)); if (ret) return ret; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + D_REG, mask, ~f->n); + RCG_D_OFFSET(rcg), mask, ~f->n); if (ret) return ret; } @@ -284,8 +289,7 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; if (rcg->mnd_width && f->n && (f->m != f->n)) cfg |= CFG_MODE_DUAL_EDGE; - - return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + return regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), mask, cfg); } From 9d575719ca9b8e177391addb2855be3911dc0d93 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 11 Feb 2019 13:09:28 +0530 Subject: [PATCH 13/16] clk: qcom: gcc-qcs404: Add cfg_offset for blsp1_uart3 clock The CFG/M/N/D registers are at an offset of 0x20 from the CMD register only for blsp1_uart3 clock, so add it for uart3 only. Signed-off-by: Taniya Das Signed-off-by: Anu Ramanathan Signed-off-by: Shawn Guo Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-qcs404.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index 64da032bb9ed..493e055299b4 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -678,6 +678,7 @@ static struct clk_rcg2 blsp1_uart3_apps_clk_src = { .cmd_rcgr = 0x4014, .mnd_width = 16, .hid_width = 5, + .cfg_off = 0x20, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, .clkr.hw.init = &(struct clk_init_data){ From 9831289f6f629b6aac4bd4491bc54dcebdc0b6ba Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 15 Jan 2019 09:03:35 +0530 Subject: [PATCH 14/16] clk: actions: Add configurable PLL delay S500 SoC requires configurable delay for different PLLs. Hence, add a separate macro for declaring a PLL with configurable delay and also modify the existing OWL_PLL_NO_PARENT macro to use default delay so that no need to modify the existing S700/S900 drivers. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-pll.c | 2 +- drivers/clk/actions/owl-pll.h | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c index 058e06d7099f..02437bdedf4d 100644 --- a/drivers/clk/actions/owl-pll.c +++ b/drivers/clk/actions/owl-pll.c @@ -179,7 +179,7 @@ static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate, regmap_write(common->regmap, pll_hw->reg, reg); - udelay(PLL_STABILITY_WAIT_US); + udelay(pll_hw->delay); return 0; } diff --git a/drivers/clk/actions/owl-pll.h b/drivers/clk/actions/owl-pll.h index 0aae30abd5dc..6fb0d45bb088 100644 --- a/drivers/clk/actions/owl-pll.h +++ b/drivers/clk/actions/owl-pll.h @@ -13,6 +13,8 @@ #include "owl-common.h" +#define OWL_PLL_DEF_DELAY 50 + /* last entry should have rate = 0 */ struct clk_pll_table { unsigned int val; @@ -27,6 +29,7 @@ struct owl_pll_hw { u8 width; u8 min_mul; u8 max_mul; + u8 delay; const struct clk_pll_table *table; }; @@ -36,7 +39,7 @@ struct owl_pll { }; #define OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, _max_mul, _table) \ + _width, _min_mul, _max_mul, _delay, _table) \ { \ .reg = _reg, \ .bfreq = _bfreq, \ @@ -45,6 +48,7 @@ struct owl_pll { .width = _width, \ .min_mul = _min_mul, \ .max_mul = _max_mul, \ + .delay = _delay, \ .table = _table, \ } @@ -52,8 +56,8 @@ struct owl_pll { _shift, _width, _min_mul, _max_mul, _table, _flags) \ struct owl_pll _struct = { \ .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, \ - _max_mul, _table), \ + _width, _min_mul, _max_mul, \ + OWL_PLL_DEF_DELAY, _table), \ .common = { \ .regmap = NULL, \ .hw.init = CLK_HW_INIT(_name, \ @@ -67,8 +71,23 @@ struct owl_pll { _shift, _width, _min_mul, _max_mul, _table, _flags) \ struct owl_pll _struct = { \ .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, \ - _max_mul, _table), \ + _width, _min_mul, _max_mul, \ + OWL_PLL_DEF_DELAY, _table), \ + .common = { \ + .regmap = NULL, \ + .hw.init = CLK_HW_INIT_NO_PARENT(_name, \ + &owl_pll_ops, \ + _flags), \ + }, \ + } + +#define OWL_PLL_NO_PARENT_DELAY(_struct, _name, _reg, _bfreq, _bit_idx, \ + _shift, _width, _min_mul, _max_mul, _delay, _table, \ + _flags) \ + struct owl_pll _struct = { \ + .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ + _width, _min_mul, _max_mul, \ + _delay, _table), \ .common = { \ .regmap = NULL, \ .hw.init = CLK_HW_INIT_NO_PARENT(_name, \ @@ -78,7 +97,6 @@ struct owl_pll { } #define mul_mask(m) ((1 << ((m)->width)) - 1) -#define PLL_STABILITY_WAIT_US (50) static inline struct owl_pll *hw_to_owl_pll(const struct clk_hw *hw) { From 0c8c53e033d278cad09a81ec1c46a401a6a6b1af Mon Sep 17 00:00:00 2001 From: Edgar Bernardi Righi Date: Tue, 15 Jan 2019 09:03:36 +0530 Subject: [PATCH 15/16] dt-bindings: clock: Add DT bindings for Actions Semi S500 CMU Add devicetree bindings for Actions Semi S500 Clock Management Unit. Signed-off-by: Edgar Bernardi Righi [Mani: Documented S500 CMU compatible] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring [sboyd@kernel.org: Fix SPDX comment style in header file] Signed-off-by: Stephen Boyd --- .../bindings/clock/actions,owl-cmu.txt | 7 +- include/dt-bindings/clock/actions,s500-cmu.h | 78 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 include/dt-bindings/clock/actions,s500-cmu.h diff --git a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt index 2ef86ae96df8..d19885b7c73f 100644 --- a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt +++ b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt @@ -2,13 +2,14 @@ The Actions Semi Owl Clock Management Unit generates and supplies clock to various controllers within the SoC. The clock binding described here is -applicable to S900 and S700 SoC's. +applicable to S900, S700 and S500 SoC's. Required Properties: - compatible: should be one of the following, "actions,s900-cmu" "actions,s700-cmu" + "actions,s500-cmu" - reg: physical base address of the controller and length of memory mapped region. - clocks: Reference to the parent clocks ("hosc", "losc") @@ -19,8 +20,8 @@ Each clock is assigned an identifier, and client nodes can use this identifier to specify the clock which they consume. All available clocks are defined as preprocessor macros in corresponding -dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be -used in device tree sources. +dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or +actions,s500-cmu.h header and can be used in device tree sources. External clocks: diff --git a/include/dt-bindings/clock/actions,s500-cmu.h b/include/dt-bindings/clock/actions,s500-cmu.h new file mode 100644 index 000000000000..030981cd2d56 --- /dev/null +++ b/include/dt-bindings/clock/actions,s500-cmu.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Device Tree binding constants for Actions Semi S500 Clock Management Unit + * + * Copyright (c) 2014 Actions Semi Inc. + * Copyright (c) 2018 LSI-TEC - Caninos Loucos + */ + +#ifndef __DT_BINDINGS_CLOCK_S500_CMU_H +#define __DT_BINDINGS_CLOCK_S500_CMU_H + +#define CLK_NONE 0 + +/* fixed rate clocks */ +#define CLK_LOSC 1 +#define CLK_HOSC 2 + +/* pll clocks */ +#define CLK_CORE_PLL 3 +#define CLK_DEV_PLL 4 +#define CLK_DDR_PLL 5 +#define CLK_NAND_PLL 6 +#define CLK_DISPLAY_PLL 7 +#define CLK_ETHERNET_PLL 8 +#define CLK_AUDIO_PLL 9 + +/* system clock */ +#define CLK_DEV 10 +#define CLK_H 11 +#define CLK_AHBPREDIV 12 +#define CLK_AHB 13 +#define CLK_DE 14 +#define CLK_BISP 15 +#define CLK_VCE 16 +#define CLK_VDE 17 + +/* peripheral device clock */ +#define CLK_TIMER 18 +#define CLK_I2C0 19 +#define CLK_I2C1 20 +#define CLK_I2C2 21 +#define CLK_I2C3 22 +#define CLK_PWM0 23 +#define CLK_PWM1 24 +#define CLK_PWM2 25 +#define CLK_PWM3 26 +#define CLK_PWM4 27 +#define CLK_PWM5 28 +#define CLK_SD0 29 +#define CLK_SD1 30 +#define CLK_SD2 31 +#define CLK_SENSOR0 32 +#define CLK_SENSOR1 33 +#define CLK_SPI0 34 +#define CLK_SPI1 35 +#define CLK_SPI2 36 +#define CLK_SPI3 37 +#define CLK_UART0 38 +#define CLK_UART1 39 +#define CLK_UART2 40 +#define CLK_UART3 41 +#define CLK_UART4 42 +#define CLK_UART5 43 +#define CLK_UART6 44 +#define CLK_DE1 45 +#define CLK_DE2 46 +#define CLK_I2SRX 47 +#define CLK_I2STX 48 +#define CLK_HDMI_AUDIO 49 +#define CLK_HDMI 50 +#define CLK_SPDIF 51 +#define CLK_NAND 52 +#define CLK_ECC 53 +#define CLK_RMII_REF 54 + +#define CLK_NR_CLKS (CLK_RMII_REF + 1) + +#endif /* __DT_BINDINGS_CLOCK_S500_CMU_H */ From ed6b4795ece45e43856f6a42571d477695173742 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 15 Jan 2019 09:03:39 +0530 Subject: [PATCH 16/16] clk: actions: Add clock driver for S500 SoC Add common clock driver for Actions Semi S500 SoC. Signed-off-by: Edgar Bernardi Righi [Mani: cleaned up the driver] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/Kconfig | 5 + drivers/clk/actions/Makefile | 1 + drivers/clk/actions/owl-s500.c | 525 +++++++++++++++++++++++++++++++++ 3 files changed, 531 insertions(+) create mode 100644 drivers/clk/actions/owl-s500.c diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig index 04f0a6355726..5b45ca35757e 100644 --- a/drivers/clk/actions/Kconfig +++ b/drivers/clk/actions/Kconfig @@ -9,6 +9,11 @@ if CLK_ACTIONS # SoC Drivers +config CLK_OWL_S500 + bool "Support for the Actions Semi OWL S500 clocks" + depends on ARCH_ACTIONS || COMPILE_TEST + default ARCH_ACTIONS + config CLK_OWL_S700 bool "Support for the Actions Semi OWL S700 clocks" depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile index ccfdf9781cef..a2588e55c790 100644 --- a/drivers/clk/actions/Makefile +++ b/drivers/clk/actions/Makefile @@ -10,5 +10,6 @@ clk-owl-y += owl-pll.o clk-owl-y += owl-reset.o # SoC support +obj-$(CONFIG_CLK_OWL_S500) += owl-s500.o obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c new file mode 100644 index 000000000000..e2007ac4d235 --- /dev/null +++ b/drivers/clk/actions/owl-s500.c @@ -0,0 +1,525 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Actions Semi Owl S500 SoC clock driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu + * + * Copyright (c) 2018 Linaro Ltd. + * Author: Manivannan Sadhasivam + * + * Copyright (c) 2018 LSI-TEC - Caninos Loucos + * Author: Edgar Bernardi Righi + */ + +#include +#include + +#include "owl-common.h" +#include "owl-composite.h" +#include "owl-divider.h" +#include "owl-factor.h" +#include "owl-fixed-factor.h" +#include "owl-gate.h" +#include "owl-mux.h" +#include "owl-pll.h" + +#include + +#define CMU_COREPLL (0x0000) +#define CMU_DEVPLL (0x0004) +#define CMU_DDRPLL (0x0008) +#define CMU_NANDPLL (0x000C) +#define CMU_DISPLAYPLL (0x0010) +#define CMU_AUDIOPLL (0x0014) +#define CMU_TVOUTPLL (0x0018) +#define CMU_BUSCLK (0x001C) +#define CMU_SENSORCLK (0x0020) +#define CMU_LCDCLK (0x0024) +#define CMU_DSICLK (0x0028) +#define CMU_CSICLK (0x002C) +#define CMU_DECLK (0x0030) +#define CMU_BISPCLK (0x0034) +#define CMU_BUSCLK1 (0x0038) +#define CMU_VDECLK (0x0040) +#define CMU_VCECLK (0x0044) +#define CMU_NANDCCLK (0x004C) +#define CMU_SD0CLK (0x0050) +#define CMU_SD1CLK (0x0054) +#define CMU_SD2CLK (0x0058) +#define CMU_UART0CLK (0x005C) +#define CMU_UART1CLK (0x0060) +#define CMU_UART2CLK (0x0064) +#define CMU_PWM4CLK (0x0068) +#define CMU_PWM5CLK (0x006C) +#define CMU_PWM0CLK (0x0070) +#define CMU_PWM1CLK (0x0074) +#define CMU_PWM2CLK (0x0078) +#define CMU_PWM3CLK (0x007C) +#define CMU_USBPLL (0x0080) +#define CMU_ETHERNETPLL (0x0084) +#define CMU_CVBSPLL (0x0088) +#define CMU_LENSCLK (0x008C) +#define CMU_GPU3DCLK (0x0090) +#define CMU_CORECTL (0x009C) +#define CMU_DEVCLKEN0 (0x00A0) +#define CMU_DEVCLKEN1 (0x00A4) +#define CMU_DEVRST0 (0x00A8) +#define CMU_DEVRST1 (0x00AC) +#define CMU_UART3CLK (0x00B0) +#define CMU_UART4CLK (0x00B4) +#define CMU_UART5CLK (0x00B8) +#define CMU_UART6CLK (0x00BC) +#define CMU_SSCLK (0x00C0) +#define CMU_DIGITALDEBUG (0x00D0) +#define CMU_ANALOGDEBUG (0x00D4) +#define CMU_COREPLLDEBUG (0x00D8) +#define CMU_DEVPLLDEBUG (0x00DC) +#define CMU_DDRPLLDEBUG (0x00E0) +#define CMU_NANDPLLDEBUG (0x00E4) +#define CMU_DISPLAYPLLDEBUG (0x00E8) +#define CMU_TVOUTPLLDEBUG (0x00EC) +#define CMU_DEEPCOLORPLLDEBUG (0x00F4) +#define CMU_AUDIOPLL_ETHPLLDEBUG (0x00F8) +#define CMU_CVBSPLLDEBUG (0x00FC) + +#define OWL_S500_COREPLL_DELAY (150) +#define OWL_S500_DDRPLL_DELAY (63) +#define OWL_S500_DEVPLL_DELAY (28) +#define OWL_S500_NANDPLL_DELAY (44) +#define OWL_S500_DISPLAYPLL_DELAY (57) +#define OWL_S500_ETHERNETPLL_DELAY (25) +#define OWL_S500_AUDIOPLL_DELAY (100) + +static const struct clk_pll_table clk_audio_pll_table[] = { + { 0, 45158400 }, { 1, 49152000 }, + { 0, 0 }, +}; + +/* pll clocks */ +static OWL_PLL_NO_PARENT_DELAY(ethernet_pll_clk, "ethernet_pll_clk", CMU_ETHERNETPLL, 500000000, 0, 0, 0, 0, 0, OWL_S500_ETHERNETPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(core_pll_clk, "core_pll_clk", CMU_COREPLL, 12000000, 9, 0, 8, 4, 134, OWL_S500_COREPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(ddr_pll_clk, "ddr_pll_clk", CMU_DDRPLL, 12000000, 8, 0, 8, 1, 67, OWL_S500_DDRPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(nand_pll_clk, "nand_pll_clk", CMU_NANDPLL, 6000000, 8, 0, 7, 2, 86, OWL_S500_NANDPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(display_pll_clk, "display_pll_clk", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 2, 126, OWL_S500_DISPLAYPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(dev_pll_clk, "dev_pll_clk", CMU_DEVPLL, 6000000, 8, 0, 7, 8, 126, OWL_S500_DEVPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(audio_pll_clk, "audio_pll_clk", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, OWL_S500_AUDIOPLL_DELAY, clk_audio_pll_table, CLK_IGNORE_UNUSED); + +static const char * const dev_clk_mux_p[] = { "hosc", "dev_pll_clk" }; +static const char * const bisp_clk_mux_p[] = { "display_pll_clk", "dev_clk" }; +static const char * const sensor_clk_mux_p[] = { "hosc", "bisp_clk" }; +static const char * const sd_clk_mux_p[] = { "dev_clk", "nand_pll_clk" }; +static const char * const pwm_clk_mux_p[] = { "losc", "hosc" }; +static const char * const ahbprediv_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" }; +static const char * const uart_clk_mux_p[] = { "hosc", "dev_pll_clk" }; +static const char * const de_clk_mux_p[] = { "display_pll_clk", "dev_clk" }; +static const char * const i2s_clk_mux_p[] = { "audio_pll_clk" }; +static const char * const hde_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" }; +static const char * const nand_clk_mux_p[] = { "nand_pll_clk", "display_pll_clk", "dev_clk", "ddr_pll_clk" }; + +static struct clk_factor_table sd_factor_table[] = { + /* bit0 ~ 4 */ + { 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 }, + { 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 }, + { 8, 1, 9 }, { 9, 1, 10 }, { 10, 1, 11 }, { 11, 1, 12 }, + { 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 }, + { 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 }, + { 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 }, + { 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 }, + { 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 }, + + /* bit8: /128 */ + { 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 }, + { 260, 1, 5 * 128 }, { 261, 1, 6 * 128 }, { 262, 1, 7 * 128 }, { 263, 1, 8 * 128 }, + { 264, 1, 9 * 128 }, { 265, 1, 10 * 128 }, { 266, 1, 11 * 128 }, { 267, 1, 12 * 128 }, + { 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 }, + { 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 }, + { 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 }, + { 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 }, + { 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 }, + { 0, 0, 0 }, +}; + +static struct clk_factor_table bisp_factor_table[] = { + { 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 }, + { 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 }, + { 0, 0, 0 }, +}; + +static struct clk_factor_table ahb_factor_table[] = { + { 1, 1, 2 }, { 2, 1, 3 }, + { 0, 0, 0 }, +}; + +static struct clk_div_table rmii_ref_div_table[] = { + { 0, 4 }, { 1, 10 }, + { 0, 0 }, +}; + +static struct clk_div_table i2s_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, + { 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 }, + { 8, 24 }, + { 0, 0 }, +}; + +static struct clk_div_table nand_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 }, + { 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 }, + { 0, 0 }, +}; + +/* mux clock */ +static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT); +static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT); + +/* gate clocks */ +static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi3_clk, "spi3_clk", "ahb_clk", CMU_DEVCLKEN1, 13, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0); +static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0); + +/* divider clocks */ +static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); +static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0); + +/* factor clocks */ +static OWL_FACTOR(ahb_clk, "ahb_clk", "h_clk", CMU_BUSCLK1, 2, 2, ahb_factor_table, 0, 0); +static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0); +static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0); + +/* composite clocks */ +static OWL_COMP_FACTOR(vce_clk, "vce_clk", hde_clk_mux_p, + OWL_MUX_HW(CMU_VCECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0), + OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p, + OWL_MUX_HW(CMU_VDECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0), + OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p, + OWL_MUX_HW(CMU_BISPCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(sensor0_clk, "sensor0_clk", sensor_clk_mux_p, + OWL_MUX_HW(CMU_SENSORCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_SENSORCLK, 0, 3, 0, bisp_factor_table), + CLK_IGNORE_UNUSED); + +static OWL_COMP_FACTOR(sensor1_clk, "sensor1_clk", sensor_clk_mux_p, + OWL_MUX_HW(CMU_SENSORCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_SENSORCLK, 8, 3, 0, bisp_factor_table), + CLK_IGNORE_UNUSED); + +static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD0CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 5, 0), + OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(sd1_clk, "sd1_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD1CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 6, 0), + OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(sd2_clk, "sd2_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD2CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 7, 0), + OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_DIV(pwm0_clk, "pwm0_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM0CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0), + OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm1_clk, "pwm1_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM1CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 24, 0), + OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm2_clk, "pwm2_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM2CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 25, 0), + OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm3_clk, "pwm3_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM3CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0), + OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm4_clk, "pwm4_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM4CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0), + OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm5_clk, "pwm5_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM5CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 0, 0), + OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_PASS(de_clk, "de_clk", de_clk_mux_p, + OWL_MUX_HW(CMU_DECLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0), + 0); + +static OWL_COMP_FIXED_FACTOR(i2c0_clk, "i2c0_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c1_clk, "i2c1_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 15, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c2_clk, "i2c2_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 30, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c3_clk, "i2c3_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0), + 1, 5, 0); + +static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART0CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART1CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 7, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART2CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART3CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART4CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART5CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART6CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(i2stx_clk, "i2stx_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 20, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(hdmia_clk, "hdmia_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(spdif_clk, "spdif_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 23, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 28, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(nand_clk, "nand_clk", nand_clk_mux_p, + OWL_MUX_HW(CMU_NANDCCLK, 8, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0), + OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 3, 0, nand_div_table), + CLK_SET_RATE_PARENT); + +static OWL_COMP_DIV(ecc_clk, "ecc_clk", nand_clk_mux_p, + OWL_MUX_HW(CMU_NANDCCLK, 8, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0), + OWL_DIVIDER_HW(CMU_NANDCCLK, 4, 3, 0, nand_div_table), + CLK_SET_RATE_PARENT); + +static struct owl_clk_common *s500_clks[] = { + ðernet_pll_clk.common, + &core_pll_clk.common, + &ddr_pll_clk.common, + &dev_pll_clk.common, + &nand_pll_clk.common, + &audio_pll_clk.common, + &display_pll_clk.common, + &dev_clk.common, + &timer_clk.common, + &i2c0_clk.common, + &i2c1_clk.common, + &i2c2_clk.common, + &i2c3_clk.common, + &uart0_clk.common, + &uart1_clk.common, + &uart2_clk.common, + &uart3_clk.common, + &uart4_clk.common, + &uart5_clk.common, + &uart6_clk.common, + &pwm0_clk.common, + &pwm1_clk.common, + &pwm2_clk.common, + &pwm3_clk.common, + &pwm4_clk.common, + &pwm5_clk.common, + &sensor0_clk.common, + &sensor1_clk.common, + &sd0_clk.common, + &sd1_clk.common, + &sd2_clk.common, + &bisp_clk.common, + &ahb_clk.common, + &ahbprediv_clk.common, + &h_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &spi2_clk.common, + &spi3_clk.common, + &rmii_ref_clk.common, + &de_clk.common, + &de1_clk.common, + &de2_clk.common, + &i2srx_clk.common, + &i2stx_clk.common, + &hdmia_clk.common, + &hdmi_clk.common, + &vce_clk.common, + &vde_clk.common, + &spdif_clk.common, + &nand_clk.common, + &ecc_clk.common, +}; + +static struct clk_hw_onecell_data s500_hw_clks = { + .hws = { + [CLK_ETHERNET_PLL] = ðernet_pll_clk.common.hw, + [CLK_CORE_PLL] = &core_pll_clk.common.hw, + [CLK_DDR_PLL] = &ddr_pll_clk.common.hw, + [CLK_NAND_PLL] = &nand_pll_clk.common.hw, + [CLK_DISPLAY_PLL] = &display_pll_clk.common.hw, + [CLK_DEV_PLL] = &dev_pll_clk.common.hw, + [CLK_AUDIO_PLL] = &audio_pll_clk.common.hw, + [CLK_TIMER] = &timer_clk.common.hw, + [CLK_DEV] = &dev_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_DE1] = &de1_clk.common.hw, + [CLK_DE2] = &de2_clk.common.hw, + [CLK_I2C0] = &i2c0_clk.common.hw, + [CLK_I2C1] = &i2c1_clk.common.hw, + [CLK_I2C2] = &i2c2_clk.common.hw, + [CLK_I2C3] = &i2c3_clk.common.hw, + [CLK_I2SRX] = &i2srx_clk.common.hw, + [CLK_I2STX] = &i2stx_clk.common.hw, + [CLK_UART0] = &uart0_clk.common.hw, + [CLK_UART1] = &uart1_clk.common.hw, + [CLK_UART2] = &uart2_clk.common.hw, + [CLK_UART3] = &uart3_clk.common.hw, + [CLK_UART4] = &uart4_clk.common.hw, + [CLK_UART5] = &uart5_clk.common.hw, + [CLK_UART6] = &uart6_clk.common.hw, + [CLK_PWM0] = &pwm0_clk.common.hw, + [CLK_PWM1] = &pwm1_clk.common.hw, + [CLK_PWM2] = &pwm2_clk.common.hw, + [CLK_PWM3] = &pwm3_clk.common.hw, + [CLK_PWM4] = &pwm4_clk.common.hw, + [CLK_PWM5] = &pwm5_clk.common.hw, + [CLK_SENSOR0] = &sensor0_clk.common.hw, + [CLK_SENSOR1] = &sensor1_clk.common.hw, + [CLK_SD0] = &sd0_clk.common.hw, + [CLK_SD1] = &sd1_clk.common.hw, + [CLK_SD2] = &sd2_clk.common.hw, + [CLK_BISP] = &bisp_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_SPI2] = &spi2_clk.common.hw, + [CLK_SPI3] = &spi3_clk.common.hw, + [CLK_AHB] = &ahb_clk.common.hw, + [CLK_H] = &h_clk.common.hw, + [CLK_AHBPREDIV] = &ahbprediv_clk.common.hw, + [CLK_RMII_REF] = &rmii_ref_clk.common.hw, + [CLK_HDMI_AUDIO] = &hdmia_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_VDE] = &vde_clk.common.hw, + [CLK_VCE] = &vce_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_ECC] = &ecc_clk.common.hw, + }, + .num = CLK_NR_CLKS, +}; + +static struct owl_clk_desc s500_clk_desc = { + .clks = s500_clks, + .num_clks = ARRAY_SIZE(s500_clks), + + .hw_clks = &s500_hw_clks, +}; + +static int s500_clk_probe(struct platform_device *pdev) +{ + struct owl_clk_desc *desc; + + desc = &s500_clk_desc; + owl_clk_regmap_init(pdev, desc); + + return owl_clk_probe(&pdev->dev, desc->hw_clks); +} + +static const struct of_device_id s500_clk_of_match[] = { + { .compatible = "actions,s500-cmu", }, + { /* sentinel */ } +}; + +static struct platform_driver s500_clk_driver = { + .probe = s500_clk_probe, + .driver = { + .name = "s500-cmu", + .of_match_table = s500_clk_of_match, + }, +}; + +static int __init s500_clk_init(void) +{ + return platform_driver_register(&s500_clk_driver); +} +core_initcall(s500_clk_init);