18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * R7S9210 Clock Pulse Generator / Module Standby 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on r8a7795-cpg-mssr.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2018 Chris Brandt 88c2ecf20Sopenharmony_ci * Copyright (C) 2018 Renesas Electronics Corp. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <dt-bindings/clock/r7s9210-cpg-mssr.h> 168c2ecf20Sopenharmony_ci#include "renesas-cpg-mssr.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define CPG_FRQCR 0x00 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic u8 cpg_mode; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Internal Clock ratio table */ 238c2ecf20Sopenharmony_cistatic const struct { 248c2ecf20Sopenharmony_ci unsigned int i; 258c2ecf20Sopenharmony_ci unsigned int g; 268c2ecf20Sopenharmony_ci unsigned int b; 278c2ecf20Sopenharmony_ci unsigned int p1; 288c2ecf20Sopenharmony_ci /* p0 is always 32 */; 298c2ecf20Sopenharmony_ci} ratio_tab[5] = { /* I, G, B, P1 */ 308c2ecf20Sopenharmony_ci { 2, 4, 8, 16}, /* FRQCR = 0x012 */ 318c2ecf20Sopenharmony_ci { 4, 4, 8, 16}, /* FRQCR = 0x112 */ 328c2ecf20Sopenharmony_ci { 8, 4, 8, 16}, /* FRQCR = 0x212 */ 338c2ecf20Sopenharmony_ci { 16, 8, 16, 16}, /* FRQCR = 0x322 */ 348c2ecf20Sopenharmony_ci { 16, 16, 32, 32}, /* FRQCR = 0x333 */ 358c2ecf20Sopenharmony_ci }; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cienum rz_clk_types { 388c2ecf20Sopenharmony_ci CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM, 398c2ecf20Sopenharmony_ci CLK_TYPE_RZA_PLL, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum clk_ids { 438c2ecf20Sopenharmony_ci /* Core Clock Outputs exported to DT */ 448c2ecf20Sopenharmony_ci LAST_DT_CORE_CLK = R7S9210_CLK_P0, 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* External Input Clocks */ 478c2ecf20Sopenharmony_ci CLK_EXTAL, 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Internal Core Clocks */ 508c2ecf20Sopenharmony_ci CLK_MAIN, 518c2ecf20Sopenharmony_ci CLK_PLL, 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Module Clocks */ 548c2ecf20Sopenharmony_ci MOD_CLK_BASE 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct cpg_core_clk r7s9210_early_core_clks[] = { 588c2ecf20Sopenharmony_ci /* External Clock Inputs */ 598c2ecf20Sopenharmony_ci DEF_INPUT("extal", CLK_EXTAL), 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Internal Core Clocks */ 628c2ecf20Sopenharmony_ci DEF_BASE(".main", CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL), 638c2ecf20Sopenharmony_ci DEF_BASE(".pll", CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN), 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Core Clock Outputs */ 668c2ecf20Sopenharmony_ci DEF_FIXED("p1c", R7S9210_CLK_P1C, CLK_PLL, 16, 1), 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const struct mssr_mod_clk r7s9210_early_mod_clks[] __initconst = { 708c2ecf20Sopenharmony_ci DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C), 718c2ecf20Sopenharmony_ci DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C), 728c2ecf20Sopenharmony_ci DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C), 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct cpg_core_clk r7s9210_core_clks[] = { 768c2ecf20Sopenharmony_ci /* Core Clock Outputs */ 778c2ecf20Sopenharmony_ci DEF_FIXED("i", R7S9210_CLK_I, CLK_PLL, 2, 1), 788c2ecf20Sopenharmony_ci DEF_FIXED("g", R7S9210_CLK_G, CLK_PLL, 4, 1), 798c2ecf20Sopenharmony_ci DEF_FIXED("b", R7S9210_CLK_B, CLK_PLL, 8, 1), 808c2ecf20Sopenharmony_ci DEF_FIXED("p1", R7S9210_CLK_P1, CLK_PLL, 16, 1), 818c2ecf20Sopenharmony_ci DEF_FIXED("p0", R7S9210_CLK_P0, CLK_PLL, 32, 1), 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = { 858c2ecf20Sopenharmony_ci DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C), 868c2ecf20Sopenharmony_ci DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C), 878c2ecf20Sopenharmony_ci DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C), 888c2ecf20Sopenharmony_ci DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C), 898c2ecf20Sopenharmony_ci DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C), 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci DEF_MOD_STB("usb1", 60, R7S9210_CLK_B), 928c2ecf20Sopenharmony_ci DEF_MOD_STB("usb0", 61, R7S9210_CLK_B), 938c2ecf20Sopenharmony_ci DEF_MOD_STB("ether1", 64, R7S9210_CLK_B), 948c2ecf20Sopenharmony_ci DEF_MOD_STB("ether0", 65, R7S9210_CLK_B), 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci DEF_MOD_STB("spibsc", 83, R7S9210_CLK_P1), 978c2ecf20Sopenharmony_ci DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1), 988c2ecf20Sopenharmony_ci DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1), 998c2ecf20Sopenharmony_ci DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1), 1008c2ecf20Sopenharmony_ci DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1), 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci DEF_MOD_STB("spi2", 95, R7S9210_CLK_P1), 1038c2ecf20Sopenharmony_ci DEF_MOD_STB("spi1", 96, R7S9210_CLK_P1), 1048c2ecf20Sopenharmony_ci DEF_MOD_STB("spi0", 97, R7S9210_CLK_P1), 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci DEF_MOD_STB("sdhi11", 100, R7S9210_CLK_B), 1078c2ecf20Sopenharmony_ci DEF_MOD_STB("sdhi10", 101, R7S9210_CLK_B), 1088c2ecf20Sopenharmony_ci DEF_MOD_STB("sdhi01", 102, R7S9210_CLK_B), 1098c2ecf20Sopenharmony_ci DEF_MOD_STB("sdhi00", 103, R7S9210_CLK_B), 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* The clock dividers in the table vary based on DT and register settings */ 1138c2ecf20Sopenharmony_cistatic void __init r7s9210_update_clk_table(struct clk *extal_clk, 1148c2ecf20Sopenharmony_ci void __iomem *base) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci int i; 1178c2ecf20Sopenharmony_ci u16 frqcr; 1188c2ecf20Sopenharmony_ci u8 index; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* If EXTAL is above 12MHz, then we know it is Mode 1 */ 1218c2ecf20Sopenharmony_ci if (clk_get_rate(extal_clk) > 12000000) 1228c2ecf20Sopenharmony_ci cpg_mode = 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci frqcr = readl(base + CPG_FRQCR) & 0xFFF; 1258c2ecf20Sopenharmony_ci if (frqcr == 0x012) 1268c2ecf20Sopenharmony_ci index = 0; 1278c2ecf20Sopenharmony_ci else if (frqcr == 0x112) 1288c2ecf20Sopenharmony_ci index = 1; 1298c2ecf20Sopenharmony_ci else if (frqcr == 0x212) 1308c2ecf20Sopenharmony_ci index = 2; 1318c2ecf20Sopenharmony_ci else if (frqcr == 0x322) 1328c2ecf20Sopenharmony_ci index = 3; 1338c2ecf20Sopenharmony_ci else if (frqcr == 0x333) 1348c2ecf20Sopenharmony_ci index = 4; 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci BUG_ON(1); /* Illegal FRQCR value */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) { 1398c2ecf20Sopenharmony_ci switch (r7s9210_core_clks[i].id) { 1408c2ecf20Sopenharmony_ci case R7S9210_CLK_I: 1418c2ecf20Sopenharmony_ci r7s9210_core_clks[i].div = ratio_tab[index].i; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case R7S9210_CLK_G: 1448c2ecf20Sopenharmony_ci r7s9210_core_clks[i].div = ratio_tab[index].g; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case R7S9210_CLK_B: 1478c2ecf20Sopenharmony_ci r7s9210_core_clks[i].div = ratio_tab[index].b; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case R7S9210_CLK_P1: 1508c2ecf20Sopenharmony_ci case R7S9210_CLK_P1C: 1518c2ecf20Sopenharmony_ci r7s9210_core_clks[i].div = ratio_tab[index].p1; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case R7S9210_CLK_P0: 1548c2ecf20Sopenharmony_ci r7s9210_core_clks[i].div = 32; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic struct clk * __init rza2_cpg_clk_register(struct device *dev, 1618c2ecf20Sopenharmony_ci const struct cpg_core_clk *core, const struct cpg_mssr_info *info, 1628c2ecf20Sopenharmony_ci struct clk **clks, void __iomem *base, 1638c2ecf20Sopenharmony_ci struct raw_notifier_head *notifiers) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct clk *parent; 1668c2ecf20Sopenharmony_ci unsigned int mult = 1; 1678c2ecf20Sopenharmony_ci unsigned int div = 1; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci parent = clks[core->parent]; 1708c2ecf20Sopenharmony_ci if (IS_ERR(parent)) 1718c2ecf20Sopenharmony_ci return ERR_CAST(parent); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci switch (core->id) { 1748c2ecf20Sopenharmony_ci case CLK_MAIN: 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci case CLK_PLL: 1788c2ecf20Sopenharmony_ci if (cpg_mode) 1798c2ecf20Sopenharmony_ci mult = 44; /* Divider 1 is 1/2 */ 1808c2ecf20Sopenharmony_ci else 1818c2ecf20Sopenharmony_ci mult = 88; /* Divider 1 is 1 */ 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci default: 1858c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (core->id == CLK_MAIN) 1898c2ecf20Sopenharmony_ci r7s9210_update_clk_table(parent, base); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return clk_register_fixed_factor(NULL, core->name, 1928c2ecf20Sopenharmony_ci __clk_get_name(parent), 0, mult, div); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciconst struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = { 1968c2ecf20Sopenharmony_ci /* Early Clocks */ 1978c2ecf20Sopenharmony_ci .early_core_clks = r7s9210_early_core_clks, 1988c2ecf20Sopenharmony_ci .num_early_core_clks = ARRAY_SIZE(r7s9210_early_core_clks), 1998c2ecf20Sopenharmony_ci .early_mod_clks = r7s9210_early_mod_clks, 2008c2ecf20Sopenharmony_ci .num_early_mod_clks = ARRAY_SIZE(r7s9210_early_mod_clks), 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Core Clocks */ 2038c2ecf20Sopenharmony_ci .core_clks = r7s9210_core_clks, 2048c2ecf20Sopenharmony_ci .num_core_clks = ARRAY_SIZE(r7s9210_core_clks), 2058c2ecf20Sopenharmony_ci .last_dt_core_clk = LAST_DT_CORE_CLK, 2068c2ecf20Sopenharmony_ci .num_total_core_clks = MOD_CLK_BASE, 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Module Clocks */ 2098c2ecf20Sopenharmony_ci .mod_clks = r7s9210_mod_clks, 2108c2ecf20Sopenharmony_ci .num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks), 2118c2ecf20Sopenharmony_ci .num_hw_mod_clks = 11 * 32, /* includes STBCR0 which doesn't exist */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Callbacks */ 2148c2ecf20Sopenharmony_ci .cpg_clk_register = rza2_cpg_clk_register, 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* RZ/A2 has Standby Control Registers */ 2178c2ecf20Sopenharmony_ci .reg_layout = CLK_REG_LAYOUT_RZ_A, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void __init r7s9210_cpg_mssr_early_init(struct device_node *np) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci cpg_mssr_early_init(np, &r7s9210_cpg_mssr_info); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciCLK_OF_DECLARE_DRIVER(cpg_mstp_clks, "renesas,r7s9210-cpg-mssr", 2268c2ecf20Sopenharmony_ci r7s9210_cpg_mssr_early_init); 227