// SPDX-License-Identifier: GPL-2.0 /* * R7S9210 Clock Pulse Generator / Module Standby * * Based on r8a7795-cpg-mssr.c * * Copyright (C) 2018 Chris Brandt * Copyright (C) 2018 Renesas Electronics Corp. * */ #include #include #include #include #include "renesas-cpg-mssr.h" #define CPG_FRQCR 0x00 static u8 cpg_mode; /* Internal Clock ratio table */ static const struct { unsigned int i; unsigned int g; unsigned int b; unsigned int p1; /* p0 is always 32 */; } ratio_tab[5] = { /* I, G, B, P1 */ { 2, 4, 8, 16}, /* FRQCR = 0x012 */ { 4, 4, 8, 16}, /* FRQCR = 0x112 */ { 8, 4, 8, 16}, /* FRQCR = 0x212 */ { 16, 8, 16, 16}, /* FRQCR = 0x322 */ { 16, 16, 32, 32}, /* FRQCR = 0x333 */ }; enum rz_clk_types { CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM, CLK_TYPE_RZA_PLL, }; enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R7S9210_CLK_P0, /* External Input Clocks */ CLK_EXTAL, /* Internal Core Clocks */ CLK_MAIN, CLK_PLL, /* Module Clocks */ MOD_CLK_BASE }; static struct cpg_core_clk r7s9210_early_core_clks[] = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), /* Internal Core Clocks */ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL), DEF_BASE(".pll", CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN), /* Core Clock Outputs */ DEF_FIXED("p1c", R7S9210_CLK_P1C, CLK_PLL, 16, 1), }; static const struct mssr_mod_clk r7s9210_early_mod_clks[] __initconst = { DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C), DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C), DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C), }; static struct cpg_core_clk r7s9210_core_clks[] = { /* Core Clock Outputs */ DEF_FIXED("i", R7S9210_CLK_I, CLK_PLL, 2, 1), DEF_FIXED("g", R7S9210_CLK_G, CLK_PLL, 4, 1), DEF_FIXED("b", R7S9210_CLK_B, CLK_PLL, 8, 1), DEF_FIXED("p1", R7S9210_CLK_P1, CLK_PLL, 16, 1), DEF_FIXED("p0", R7S9210_CLK_P0, CLK_PLL, 32, 1), }; static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = { DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C), DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C), DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C), DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C), DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C), DEF_MOD_STB("usb1", 60, R7S9210_CLK_B), DEF_MOD_STB("usb0", 61, R7S9210_CLK_B), DEF_MOD_STB("ether1", 64, R7S9210_CLK_B), DEF_MOD_STB("ether0", 65, R7S9210_CLK_B), DEF_MOD_STB("spibsc", 83, R7S9210_CLK_P1), DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1), DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1), DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1), DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1), DEF_MOD_STB("spi2", 95, R7S9210_CLK_P1), DEF_MOD_STB("spi1", 96, R7S9210_CLK_P1), DEF_MOD_STB("spi0", 97, R7S9210_CLK_P1), DEF_MOD_STB("sdhi11", 100, R7S9210_CLK_B), DEF_MOD_STB("sdhi10", 101, R7S9210_CLK_B), DEF_MOD_STB("sdhi01", 102, R7S9210_CLK_B), DEF_MOD_STB("sdhi00", 103, R7S9210_CLK_B), }; /* The clock dividers in the table vary based on DT and register settings */ static void __init r7s9210_update_clk_table(struct clk *extal_clk, void __iomem *base) { int i; u16 frqcr; u8 index; /* If EXTAL is above 12MHz, then we know it is Mode 1 */ if (clk_get_rate(extal_clk) > 12000000) cpg_mode = 1; frqcr = readl(base + CPG_FRQCR) & 0xFFF; if (frqcr == 0x012) index = 0; else if (frqcr == 0x112) index = 1; else if (frqcr == 0x212) index = 2; else if (frqcr == 0x322) index = 3; else if (frqcr == 0x333) index = 4; else BUG_ON(1); /* Illegal FRQCR value */ for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) { switch (r7s9210_core_clks[i].id) { case R7S9210_CLK_I: r7s9210_core_clks[i].div = ratio_tab[index].i; break; case R7S9210_CLK_G: r7s9210_core_clks[i].div = ratio_tab[index].g; break; case R7S9210_CLK_B: r7s9210_core_clks[i].div = ratio_tab[index].b; break; case R7S9210_CLK_P1: case R7S9210_CLK_P1C: r7s9210_core_clks[i].div = ratio_tab[index].p1; break; case R7S9210_CLK_P0: r7s9210_core_clks[i].div = 32; break; } } } static struct clk * __init rza2_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, struct clk **clks, void __iomem *base, struct raw_notifier_head *notifiers) { struct clk *parent; unsigned int mult = 1; unsigned int div = 1; parent = clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); switch (core->id) { case CLK_MAIN: break; case CLK_PLL: if (cpg_mode) mult = 44; /* Divider 1 is 1/2 */ else mult = 88; /* Divider 1 is 1 */ break; default: return ERR_PTR(-EINVAL); } if (core->id == CLK_MAIN) r7s9210_update_clk_table(parent, base); return clk_register_fixed_factor(NULL, core->name, __clk_get_name(parent), 0, mult, div); } const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = { /* Early Clocks */ .early_core_clks = r7s9210_early_core_clks, .num_early_core_clks = ARRAY_SIZE(r7s9210_early_core_clks), .early_mod_clks = r7s9210_early_mod_clks, .num_early_mod_clks = ARRAY_SIZE(r7s9210_early_mod_clks), /* Core Clocks */ .core_clks = r7s9210_core_clks, .num_core_clks = ARRAY_SIZE(r7s9210_core_clks), .last_dt_core_clk = LAST_DT_CORE_CLK, .num_total_core_clks = MOD_CLK_BASE, /* Module Clocks */ .mod_clks = r7s9210_mod_clks, .num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks), .num_hw_mod_clks = 11 * 32, /* includes STBCR0 which doesn't exist */ /* Callbacks */ .cpg_clk_register = rza2_cpg_clk_register, /* RZ/A2 has Standby Control Registers */ .reg_layout = CLK_REG_LAYOUT_RZ_A, }; static void __init r7s9210_cpg_mssr_early_init(struct device_node *np) { cpg_mssr_early_init(np, &r7s9210_cpg_mssr_info); } CLK_OF_DECLARE_DRIVER(cpg_mstp_clks, "renesas,r7s9210-cpg-mssr", r7s9210_cpg_mssr_early_init);