|
@@ -12,22 +12,14 @@
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
*/
|
|
|
|
|
|
-#include <linux/bug.h>
|
|
|
-#include <linux/clk.h>
|
|
|
-#include <linux/clk-provider.h>
|
|
|
#include <linux/device.h>
|
|
|
-#include <linux/err.h>
|
|
|
#include <linux/init.h>
|
|
|
-#include <linux/io.h>
|
|
|
#include <linux/kernel.h>
|
|
|
-#include <linux/of.h>
|
|
|
-#include <linux/slab.h>
|
|
|
|
|
|
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
|
|
|
|
|
|
#include "renesas-cpg-mssr.h"
|
|
|
-
|
|
|
-#define CPG_RCKCR 0x240
|
|
|
+#include "rcar-gen3-cpg.h"
|
|
|
|
|
|
enum clk_ids {
|
|
|
/* Core Clock Outputs exported to DT */
|
|
@@ -58,20 +50,6 @@ enum clk_ids {
|
|
|
MOD_CLK_BASE
|
|
|
};
|
|
|
|
|
|
-enum r8a7795_clk_types {
|
|
|
- CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
|
|
|
- CLK_TYPE_GEN3_PLL0,
|
|
|
- CLK_TYPE_GEN3_PLL1,
|
|
|
- CLK_TYPE_GEN3_PLL2,
|
|
|
- CLK_TYPE_GEN3_PLL3,
|
|
|
- CLK_TYPE_GEN3_PLL4,
|
|
|
- CLK_TYPE_GEN3_SD,
|
|
|
- CLK_TYPE_GEN3_R,
|
|
|
-};
|
|
|
-
|
|
|
-#define DEF_GEN3_SD(_name, _id, _parent, _offset) \
|
|
|
- DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
|
|
|
-
|
|
|
static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
|
|
|
/* External Clock Inputs */
|
|
|
DEF_INPUT("extal", CLK_EXTAL),
|
|
@@ -262,225 +240,6 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
|
|
|
MOD_CLK_ID(408), /* INTC-AP (GIC) */
|
|
|
};
|
|
|
|
|
|
-/* -----------------------------------------------------------------------------
|
|
|
- * SDn Clock
|
|
|
- *
|
|
|
- */
|
|
|
-#define CPG_SD_STP_HCK BIT(9)
|
|
|
-#define CPG_SD_STP_CK BIT(8)
|
|
|
-
|
|
|
-#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
|
|
|
-#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
|
|
|
-
|
|
|
-#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
|
|
|
-{ \
|
|
|
- .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
|
|
|
- ((stp_ck) ? CPG_SD_STP_CK : 0) | \
|
|
|
- ((sd_srcfc) << 2) | \
|
|
|
- ((sd_fc) << 0), \
|
|
|
- .div = (sd_div), \
|
|
|
-}
|
|
|
-
|
|
|
-struct sd_div_table {
|
|
|
- u32 val;
|
|
|
- unsigned int div;
|
|
|
-};
|
|
|
-
|
|
|
-struct sd_clock {
|
|
|
- struct clk_hw hw;
|
|
|
- void __iomem *reg;
|
|
|
- const struct sd_div_table *div_table;
|
|
|
- unsigned int div_num;
|
|
|
- unsigned int div_min;
|
|
|
- unsigned int div_max;
|
|
|
-};
|
|
|
-
|
|
|
-/* SDn divider
|
|
|
- * sd_srcfc sd_fc div
|
|
|
- * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
|
|
|
- *-------------------------------------------------------------------
|
|
|
- * 0 0 0 (1) 1 (4) 4
|
|
|
- * 0 0 1 (2) 1 (4) 8
|
|
|
- * 1 0 2 (4) 1 (4) 16
|
|
|
- * 1 0 3 (8) 1 (4) 32
|
|
|
- * 1 0 4 (16) 1 (4) 64
|
|
|
- * 0 0 0 (1) 0 (2) 2
|
|
|
- * 0 0 1 (2) 0 (2) 4
|
|
|
- * 1 0 2 (4) 0 (2) 8
|
|
|
- * 1 0 3 (8) 0 (2) 16
|
|
|
- * 1 0 4 (16) 0 (2) 32
|
|
|
- */
|
|
|
-static const struct sd_div_table cpg_sd_div_table[] = {
|
|
|
-/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
|
|
|
- CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
|
|
|
- CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
|
|
|
- CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
|
|
|
- CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
|
|
|
- CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
|
|
|
-};
|
|
|
-
|
|
|
-#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
|
|
|
-
|
|
|
-static int cpg_sd_clock_enable(struct clk_hw *hw)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
- u32 val, sd_fc;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- val = clk_readl(clock->reg);
|
|
|
-
|
|
|
- sd_fc = val & CPG_SD_FC_MASK;
|
|
|
- for (i = 0; i < clock->div_num; i++)
|
|
|
- if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
|
|
|
- break;
|
|
|
-
|
|
|
- if (i >= clock->div_num)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- val &= ~(CPG_SD_STP_MASK);
|
|
|
- val |= clock->div_table[i].val & CPG_SD_STP_MASK;
|
|
|
-
|
|
|
- clk_writel(val, clock->reg);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void cpg_sd_clock_disable(struct clk_hw *hw)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
-
|
|
|
- clk_writel(clk_readl(clock->reg) | CPG_SD_STP_MASK, clock->reg);
|
|
|
-}
|
|
|
-
|
|
|
-static int cpg_sd_clock_is_enabled(struct clk_hw *hw)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
-
|
|
|
- return !(clk_readl(clock->reg) & CPG_SD_STP_MASK);
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
|
|
|
- unsigned long parent_rate)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
- unsigned long rate = parent_rate;
|
|
|
- u32 val, sd_fc;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- val = clk_readl(clock->reg);
|
|
|
-
|
|
|
- sd_fc = val & CPG_SD_FC_MASK;
|
|
|
- for (i = 0; i < clock->div_num; i++)
|
|
|
- if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
|
|
|
- break;
|
|
|
-
|
|
|
- if (i >= clock->div_num)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div);
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock,
|
|
|
- unsigned long rate,
|
|
|
- unsigned long parent_rate)
|
|
|
-{
|
|
|
- unsigned int div;
|
|
|
-
|
|
|
- if (!rate)
|
|
|
- rate = 1;
|
|
|
-
|
|
|
- div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
|
|
-
|
|
|
- return clamp_t(unsigned int, div, clock->div_min, clock->div_max);
|
|
|
-}
|
|
|
-
|
|
|
-static long cpg_sd_clock_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
- unsigned long *parent_rate)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
- unsigned int div = cpg_sd_clock_calc_div(clock, rate, *parent_rate);
|
|
|
-
|
|
|
- return DIV_ROUND_CLOSEST(*parent_rate, div);
|
|
|
-}
|
|
|
-
|
|
|
-static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
- unsigned long parent_rate)
|
|
|
-{
|
|
|
- struct sd_clock *clock = to_sd_clock(hw);
|
|
|
- unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate);
|
|
|
- u32 val;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- for (i = 0; i < clock->div_num; i++)
|
|
|
- if (div == clock->div_table[i].div)
|
|
|
- break;
|
|
|
-
|
|
|
- if (i >= clock->div_num)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- val = clk_readl(clock->reg);
|
|
|
- val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK);
|
|
|
- val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK);
|
|
|
- clk_writel(val, clock->reg);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static const struct clk_ops cpg_sd_clock_ops = {
|
|
|
- .enable = cpg_sd_clock_enable,
|
|
|
- .disable = cpg_sd_clock_disable,
|
|
|
- .is_enabled = cpg_sd_clock_is_enabled,
|
|
|
- .recalc_rate = cpg_sd_clock_recalc_rate,
|
|
|
- .round_rate = cpg_sd_clock_round_rate,
|
|
|
- .set_rate = cpg_sd_clock_set_rate,
|
|
|
-};
|
|
|
-
|
|
|
-static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
|
|
|
- void __iomem *base,
|
|
|
- const char *parent_name)
|
|
|
-{
|
|
|
- struct clk_init_data init;
|
|
|
- struct sd_clock *clock;
|
|
|
- struct clk *clk;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
|
|
|
- if (!clock)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
-
|
|
|
- init.name = core->name;
|
|
|
- init.ops = &cpg_sd_clock_ops;
|
|
|
- init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
|
|
|
- init.parent_names = &parent_name;
|
|
|
- init.num_parents = 1;
|
|
|
-
|
|
|
- clock->reg = base + core->offset;
|
|
|
- clock->hw.init = &init;
|
|
|
- clock->div_table = cpg_sd_div_table;
|
|
|
- clock->div_num = ARRAY_SIZE(cpg_sd_div_table);
|
|
|
-
|
|
|
- clock->div_max = clock->div_table[0].div;
|
|
|
- clock->div_min = clock->div_max;
|
|
|
- for (i = 1; i < clock->div_num; i++) {
|
|
|
- clock->div_max = max(clock->div_max, clock->div_table[i].div);
|
|
|
- clock->div_min = min(clock->div_min, clock->div_table[i].div);
|
|
|
- }
|
|
|
-
|
|
|
- clk = clk_register(NULL, &clock->hw);
|
|
|
- if (IS_ERR(clk))
|
|
|
- kfree(clock);
|
|
|
-
|
|
|
- return clk;
|
|
|
-}
|
|
|
-
|
|
|
-#define CPG_PLL0CR 0x00d8
|
|
|
-#define CPG_PLL2CR 0x002c
|
|
|
-#define CPG_PLL4CR 0x01f4
|
|
|
|
|
|
/*
|
|
|
* CPG Clock Data
|
|
@@ -512,13 +271,7 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
|
|
|
(((md) & BIT(19)) >> 18) | \
|
|
|
(((md) & BIT(17)) >> 17))
|
|
|
|
|
|
-struct cpg_pll_config {
|
|
|
- unsigned int extal_div;
|
|
|
- unsigned int pll1_mult;
|
|
|
- unsigned int pll3_mult;
|
|
|
-};
|
|
|
-
|
|
|
-static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
|
|
|
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
|
|
|
/* EXTAL div PLL1 mult PLL3 mult */
|
|
|
{ 1, 192, 192, },
|
|
|
{ 1, 192, 128, },
|
|
@@ -538,112 +291,9 @@ static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
|
|
|
{ 2, 192, 192, },
|
|
|
};
|
|
|
|
|
|
-static const struct cpg_pll_config *cpg_pll_config __initdata;
|
|
|
-
|
|
|
-static
|
|
|
-struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
|
|
|
- const struct cpg_core_clk *core,
|
|
|
- const struct cpg_mssr_info *info,
|
|
|
- struct clk **clks,
|
|
|
- void __iomem *base)
|
|
|
-{
|
|
|
- const struct clk *parent;
|
|
|
- unsigned int mult = 1;
|
|
|
- unsigned int div = 1;
|
|
|
- u32 value;
|
|
|
-
|
|
|
- parent = clks[core->parent];
|
|
|
- if (IS_ERR(parent))
|
|
|
- return ERR_CAST(parent);
|
|
|
-
|
|
|
- switch (core->type) {
|
|
|
- case CLK_TYPE_GEN3_MAIN:
|
|
|
- div = cpg_pll_config->extal_div;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_PLL0:
|
|
|
- /*
|
|
|
- * PLL0 is a configurable multiplier clock. Register it as a
|
|
|
- * fixed factor clock for now as there's no generic multiplier
|
|
|
- * clock implementation and we currently have no need to change
|
|
|
- * the multiplier value.
|
|
|
- */
|
|
|
- value = readl(base + CPG_PLL0CR);
|
|
|
- mult = (((value >> 24) & 0x7f) + 1) * 2;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_PLL1:
|
|
|
- mult = cpg_pll_config->pll1_mult;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_PLL2:
|
|
|
- /*
|
|
|
- * PLL2 is a configurable multiplier clock. Register it as a
|
|
|
- * fixed factor clock for now as there's no generic multiplier
|
|
|
- * clock implementation and we currently have no need to change
|
|
|
- * the multiplier value.
|
|
|
- */
|
|
|
- value = readl(base + CPG_PLL2CR);
|
|
|
- mult = (((value >> 24) & 0x7f) + 1) * 2;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_PLL3:
|
|
|
- mult = cpg_pll_config->pll3_mult;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_PLL4:
|
|
|
- /*
|
|
|
- * PLL4 is a configurable multiplier clock. Register it as a
|
|
|
- * fixed factor clock for now as there's no generic multiplier
|
|
|
- * clock implementation and we currently have no need to change
|
|
|
- * the multiplier value.
|
|
|
- */
|
|
|
- value = readl(base + CPG_PLL4CR);
|
|
|
- mult = (((value >> 24) & 0x7f) + 1) * 2;
|
|
|
- break;
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_SD:
|
|
|
- return cpg_sd_clk_register(core, base, __clk_get_name(parent));
|
|
|
-
|
|
|
- case CLK_TYPE_GEN3_R:
|
|
|
- /* RINT is default. Only if EXTALR is populated, we switch to it */
|
|
|
- value = readl(base + CPG_RCKCR) & 0x3f;
|
|
|
-
|
|
|
- if (clk_get_rate(clks[CLK_EXTALR])) {
|
|
|
- parent = clks[CLK_EXTALR];
|
|
|
- value |= BIT(15);
|
|
|
- }
|
|
|
-
|
|
|
- writel(value, base + CPG_RCKCR);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- return ERR_PTR(-EINVAL);
|
|
|
- }
|
|
|
-
|
|
|
- return clk_register_fixed_factor(NULL, core->name,
|
|
|
- __clk_get_name(parent), 0, mult, div);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reset register definitions.
|
|
|
- */
|
|
|
-#define MODEMR 0xe6160060
|
|
|
-
|
|
|
-static u32 rcar_gen3_read_mode_pins(void)
|
|
|
-{
|
|
|
- void __iomem *modemr = ioremap_nocache(MODEMR, 4);
|
|
|
- u32 mode;
|
|
|
-
|
|
|
- BUG_ON(!modemr);
|
|
|
- mode = ioread32(modemr);
|
|
|
- iounmap(modemr);
|
|
|
-
|
|
|
- return mode;
|
|
|
-}
|
|
|
-
|
|
|
static int __init r8a7795_cpg_mssr_init(struct device *dev)
|
|
|
{
|
|
|
+ const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
|
|
|
u32 cpg_mode = rcar_gen3_read_mode_pins();
|
|
|
|
|
|
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
|
|
@@ -652,7 +302,7 @@ static int __init r8a7795_cpg_mssr_init(struct device *dev)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR);
|
|
|
}
|
|
|
|
|
|
const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
|
|
@@ -673,5 +323,5 @@ const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
|
|
|
|
|
|
/* Callbacks */
|
|
|
.init = r8a7795_cpg_mssr_init,
|
|
|
- .cpg_clk_register = r8a7795_cpg_clk_register,
|
|
|
+ .cpg_clk_register = rcar_gen3_cpg_clk_register,
|
|
|
};
|