123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // 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 <linux/clk.h>
- #include <linux/clk-provider.h>
- #include <linux/io.h>
- #include <dt-bindings/clock/r7s9210-cpg-mssr.h>
- #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);
|