Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: renesas: cpg-mssr: Add R7S9210 support

Add support for the R7S9210 (RZ/A2) Clock Pulse Generator and Module
Standby.

The Module Standby HW in the RZ/A series is very close to R-Car HW, except
for how the registers are laid out.
The MSTP registers are only 8-bits wide, there are no status registers
(MSTPSR), and the register offsets are a little different. Since the RZ/A
hardware manuals refer to these registers as the Standby Control Registers,
we'll use that name to distinguish the RZ/A type from the R-Car type.

Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
Acked-by: Rob Herring <robh@kernel.org> # DT bits
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

authored by

Chris Brandt and committed by
Geert Uytterhoeven
fde35c9c 6207ba04

+300 -14
+3 -2
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
··· 13 13 14 14 Required Properties: 15 15 - compatible: Must be one of: 16 + - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2) 16 17 - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) 17 18 - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) 18 19 - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C) ··· 37 36 - clocks: References to external parent clocks, one entry for each entry in 38 37 clock-names 39 38 - clock-names: List of external parent clock names. Valid names are: 40 - - "extal" (r8a7743, r8a7745, r8a77470, r8a774a1, r8a7790, r8a7791, 41 - r8a7792, r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, 39 + - "extal" (r7s9210, r8a7743, r8a7745, r8a77470, r8a774a1, r8a7790, 40 + r8a7791, r8a7792, r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, 42 41 r8a77970, r8a77980, r8a77990, r8a77995) 43 42 - "extalr" (r8a774a1, r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) 44 43 - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793,
+5
drivers/clk/renesas/Kconfig
··· 3 3 default y if ARCH_RENESAS 4 4 select CLK_EMEV2 if ARCH_EMEV2 5 5 select CLK_RZA1 if ARCH_R7S72100 6 + select CLK_R7S9210 if ARCH_R7S9210 6 7 select CLK_R8A73A4 if ARCH_R8A73A4 7 8 select CLK_R8A7740 if ARCH_R8A7740 8 9 select CLK_R8A7743 if ARCH_R8A7743 ··· 46 45 config CLK_RZA1 47 46 bool "RZ/A1H clock support" if COMPILE_TEST 48 47 select CLK_RENESAS_CPG_MSTP 48 + 49 + config CLK_R7S9210 50 + bool "RZ/A2 clock support" if COMPILE_TEST 51 + select CLK_RENESAS_CPG_MSSR 49 52 50 53 config CLK_R8A73A4 51 54 bool "R-Mobile APE6 clock support" if COMPILE_TEST
+1
drivers/clk/renesas/Makefile
··· 2 2 # SoC 3 3 obj-$(CONFIG_CLK_EMEV2) += clk-emev2.o 4 4 obj-$(CONFIG_CLK_RZA1) += clk-rz.o 5 + obj-$(CONFIG_CLK_R7S9210) += r7s9210-cpg-mssr.o 5 6 obj-$(CONFIG_CLK_R8A73A4) += clk-r8a73a4.o 6 7 obj-$(CONFIG_CLK_R8A7740) += clk-r8a7740.o 7 8 obj-$(CONFIG_CLK_R8A7743) += r8a7743-cpg-mssr.o
+189
drivers/clk/renesas/r7s9210-cpg-mssr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * R7S9210 Clock Pulse Generator / Module Standby 4 + * 5 + * Based on r8a7795-cpg-mssr.c 6 + * 7 + * Copyright (C) 2018 Chris Brandt 8 + * Copyright (C) 2018 Renesas Electronics Corp. 9 + * 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/clk-provider.h> 14 + #include <dt-bindings/clock/r7s9210-cpg-mssr.h> 15 + #include "renesas-cpg-mssr.h" 16 + 17 + #define CPG_FRQCR 0x00 18 + 19 + static u8 cpg_mode; 20 + 21 + /* Internal Clock ratio table */ 22 + static const struct { 23 + unsigned int i; 24 + unsigned int g; 25 + unsigned int b; 26 + unsigned int p1; 27 + /* p0 is always 32 */; 28 + } ratio_tab[5] = { /* I, G, B, P1 */ 29 + { 2, 4, 8, 16}, /* FRQCR = 0x012 */ 30 + { 4, 4, 8, 16}, /* FRQCR = 0x112 */ 31 + { 8, 4, 8, 16}, /* FRQCR = 0x212 */ 32 + { 16, 8, 16, 16}, /* FRQCR = 0x322 */ 33 + { 16, 16, 32, 32}, /* FRQCR = 0x333 */ 34 + }; 35 + 36 + enum rz_clk_types { 37 + CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM, 38 + CLK_TYPE_RZA_PLL, 39 + }; 40 + 41 + enum clk_ids { 42 + /* Core Clock Outputs exported to DT */ 43 + LAST_DT_CORE_CLK = R7S9210_CLK_P0, 44 + 45 + /* External Input Clocks */ 46 + CLK_EXTAL, 47 + 48 + /* Internal Core Clocks */ 49 + CLK_MAIN, 50 + CLK_PLL, 51 + 52 + /* Module Clocks */ 53 + MOD_CLK_BASE 54 + }; 55 + 56 + static struct cpg_core_clk r7s9210_core_clks[] = { 57 + /* External Clock Inputs */ 58 + DEF_INPUT("extal", CLK_EXTAL), 59 + 60 + /* Internal Core Clocks */ 61 + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL), 62 + DEF_BASE(".pll", CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN), 63 + 64 + /* Core Clock Outputs */ 65 + DEF_FIXED("i", R7S9210_CLK_I, CLK_PLL, 2, 1), 66 + DEF_FIXED("g", R7S9210_CLK_G, CLK_PLL, 4, 1), 67 + DEF_FIXED("b", R7S9210_CLK_B, CLK_PLL, 8, 1), 68 + DEF_FIXED("p1", R7S9210_CLK_P1, CLK_PLL, 16, 1), 69 + DEF_FIXED("p1c", R7S9210_CLK_P1C, CLK_PLL, 16, 1), 70 + DEF_FIXED("p0", R7S9210_CLK_P0, CLK_PLL, 32, 1), 71 + }; 72 + 73 + static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = { 74 + DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C), 75 + DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C), 76 + DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C), 77 + 78 + DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C), 79 + DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C), 80 + DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C), 81 + DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C), 82 + DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C), 83 + 84 + DEF_MOD_STB("ether1", 64, R7S9210_CLK_B), 85 + DEF_MOD_STB("ether0", 65, R7S9210_CLK_B), 86 + 87 + DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1), 88 + DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1), 89 + DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1), 90 + DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1), 91 + 92 + }; 93 + 94 + struct clk * __init rza2_cpg_clk_register(struct device *dev, 95 + const struct cpg_core_clk *core, const struct cpg_mssr_info *info, 96 + struct clk **clks, void __iomem *base, 97 + struct raw_notifier_head *notifiers) 98 + { 99 + struct clk *parent; 100 + unsigned int mult = 1; 101 + unsigned int div = 1; 102 + u16 frqcr; 103 + u8 index; 104 + int i; 105 + 106 + parent = clks[core->parent]; 107 + if (IS_ERR(parent)) 108 + return ERR_CAST(parent); 109 + 110 + switch (core->id) { 111 + case CLK_MAIN: 112 + break; 113 + 114 + case CLK_PLL: 115 + if (cpg_mode) 116 + mult = 44; /* Divider 1 is 1/2 */ 117 + else 118 + mult = 88; /* Divider 1 is 1 */ 119 + break; 120 + 121 + default: 122 + return ERR_PTR(-EINVAL); 123 + } 124 + 125 + /* Adjust the dividers based on the current FRQCR setting */ 126 + if (core->id == CLK_MAIN) { 127 + 128 + /* If EXTAL is above 12MHz, then we know it is Mode 1 */ 129 + if (clk_get_rate(parent) > 12000000) 130 + cpg_mode = 1; 131 + 132 + frqcr = clk_readl(base + CPG_FRQCR) & 0xFFF; 133 + if (frqcr == 0x012) 134 + index = 0; 135 + else if (frqcr == 0x112) 136 + index = 1; 137 + else if (frqcr == 0x212) 138 + index = 2; 139 + else if (frqcr == 0x322) 140 + index = 3; 141 + else if (frqcr == 0x333) 142 + index = 4; 143 + else 144 + BUG_ON(1); /* Illegal FRQCR value */ 145 + 146 + for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) { 147 + switch (r7s9210_core_clks[i].id) { 148 + case R7S9210_CLK_I: 149 + r7s9210_core_clks[i].div = ratio_tab[index].i; 150 + break; 151 + case R7S9210_CLK_G: 152 + r7s9210_core_clks[i].div = ratio_tab[index].g; 153 + break; 154 + case R7S9210_CLK_B: 155 + r7s9210_core_clks[i].div = ratio_tab[index].b; 156 + break; 157 + case R7S9210_CLK_P1: 158 + case R7S9210_CLK_P1C: 159 + r7s9210_core_clks[i].div = ratio_tab[index].p1; 160 + break; 161 + case R7S9210_CLK_P0: 162 + r7s9210_core_clks[i].div = 32; 163 + break; 164 + } 165 + } 166 + } 167 + 168 + return clk_register_fixed_factor(NULL, core->name, 169 + __clk_get_name(parent), 0, mult, div); 170 + } 171 + 172 + const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = { 173 + /* Core Clocks */ 174 + .core_clks = r7s9210_core_clks, 175 + .num_core_clks = ARRAY_SIZE(r7s9210_core_clks), 176 + .last_dt_core_clk = LAST_DT_CORE_CLK, 177 + .num_total_core_clks = MOD_CLK_BASE, 178 + 179 + /* Module Clocks */ 180 + .mod_clks = r7s9210_mod_clks, 181 + .num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks), 182 + .num_hw_mod_clks = 11 * 32, /* includes STBCR0 which doesn't exist */ 183 + 184 + /* Callbacks */ 185 + .cpg_clk_register = rza2_cpg_clk_register, 186 + 187 + /* RZ/A2 has Standby Control Registers */ 188 + .stbyctrl = true, 189 + };
+69 -12
drivers/clk/renesas/renesas-cpg-mssr.c
··· 73 73 74 74 #define SMSTPCR(i) smstpcr[i] 75 75 76 + /* 77 + * Standby Control Register offsets (RZ/A) 78 + * Base address is FRQCR register 79 + */ 80 + 81 + static const u16 stbcr[] = { 82 + 0xFFFF/*dummy*/, 0x010, 0x014, 0x410, 0x414, 0x418, 0x41C, 0x420, 83 + 0x424, 0x428, 0x42C, 84 + }; 85 + 86 + #define STBCR(i) stbcr[i] 76 87 77 88 /* 78 89 * Software Reset Register offsets ··· 121 110 * @notifiers: Notifier chain to save/restore clock state for system resume 122 111 * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control 123 112 * @smstpcr_saved[].val: Saved values of SMSTPCR[] 113 + * @stbyctrl: This device has Standby Control Registers 124 114 */ 125 115 struct cpg_mssr_priv { 126 116 #ifdef CONFIG_RESET_CONTROLLER ··· 135 123 unsigned int num_core_clks; 136 124 unsigned int num_mod_clks; 137 125 unsigned int last_dt_core_clk; 126 + bool stbyctrl; 138 127 139 128 struct raw_notifier_head notifiers; 140 129 struct { ··· 175 162 enable ? "ON" : "OFF"); 176 163 spin_lock_irqsave(&priv->rmw_lock, flags); 177 164 178 - value = readl(priv->base + SMSTPCR(reg)); 179 - if (enable) 180 - value &= ~bitmask; 181 - else 182 - value |= bitmask; 183 - writel(value, priv->base + SMSTPCR(reg)); 165 + if (priv->stbyctrl) { 166 + value = readb(priv->base + STBCR(reg)); 167 + if (enable) 168 + value &= ~bitmask; 169 + else 170 + value |= bitmask; 171 + writeb(value, priv->base + STBCR(reg)); 172 + 173 + /* dummy read to ensure write has completed */ 174 + readb(priv->base + STBCR(reg)); 175 + barrier_data(priv->base + STBCR(reg)); 176 + } else { 177 + value = readl(priv->base + SMSTPCR(reg)); 178 + if (enable) 179 + value &= ~bitmask; 180 + else 181 + value |= bitmask; 182 + writel(value, priv->base + SMSTPCR(reg)); 183 + } 184 184 185 185 spin_unlock_irqrestore(&priv->rmw_lock, flags); 186 186 187 - if (!enable) 187 + if (!enable || priv->stbyctrl) 188 188 return 0; 189 189 190 190 for (i = 1000; i > 0; --i) { ··· 231 205 struct cpg_mssr_priv *priv = clock->priv; 232 206 u32 value; 233 207 234 - value = readl(priv->base + MSTPSR(clock->index / 32)); 208 + if (priv->stbyctrl) 209 + value = readb(priv->base + STBCR(clock->index / 32)); 210 + else 211 + value = readl(priv->base + MSTPSR(clock->index / 32)); 235 212 236 213 return !(value & BIT(clock->index % 32)); 237 214 } ··· 255 226 unsigned int idx; 256 227 const char *type; 257 228 struct clk *clk; 229 + int range_check; 258 230 259 231 switch (clkspec->args[0]) { 260 232 case CPG_CORE: ··· 270 240 271 241 case CPG_MOD: 272 242 type = "module"; 273 - idx = MOD_CLK_PACK(clkidx); 274 - if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) { 243 + if (priv->stbyctrl) { 244 + idx = MOD_CLK_PACK_10(clkidx); 245 + range_check = 7 - (clkidx % 10); 246 + } else { 247 + idx = MOD_CLK_PACK(clkidx); 248 + range_check = 31 - (clkidx % 100); 249 + } 250 + if (range_check < 0 || idx >= priv->num_mod_clks) { 275 251 dev_err(dev, "Invalid %s clock index %u\n", type, 276 252 clkidx); 277 253 return ERR_PTR(-EINVAL); ··· 682 646 683 647 684 648 static const struct of_device_id cpg_mssr_match[] = { 649 + #ifdef CONFIG_CLK_R7S9210 650 + { 651 + .compatible = "renesas,r7s9210-cpg-mssr", 652 + .data = &r7s9210_cpg_mssr_info, 653 + }, 654 + #endif 685 655 #ifdef CONFIG_CLK_R8A7743 686 656 { 687 657 .compatible = "renesas,r8a7743-cpg-mssr", ··· 833 791 if (!mask) 834 792 continue; 835 793 836 - oldval = readl(priv->base + SMSTPCR(reg)); 794 + if (priv->stbyctrl) 795 + oldval = readb(priv->base + STBCR(reg)); 796 + else 797 + oldval = readl(priv->base + SMSTPCR(reg)); 837 798 newval = oldval & ~mask; 838 799 newval |= priv->smstpcr_saved[reg].val & mask; 839 800 if (newval == oldval) 840 801 continue; 841 802 842 - writel(newval, priv->base + SMSTPCR(reg)); 803 + if (priv->stbyctrl) { 804 + writeb(newval, priv->base + STBCR(reg)); 805 + /* dummy read to ensure write has completed */ 806 + readb(priv->base + STBCR(reg)); 807 + barrier_data(priv->base + STBCR(reg)); 808 + continue; 809 + } else 810 + writel(newval, priv->base + SMSTPCR(reg)); 843 811 844 812 /* Wait until enabled clocks are really enabled */ 845 813 mask &= ~priv->smstpcr_saved[reg].val; ··· 921 869 priv->num_mod_clks = info->num_hw_mod_clks; 922 870 priv->last_dt_core_clk = info->last_dt_core_clk; 923 871 RAW_INIT_NOTIFIER_HEAD(&priv->notifiers); 872 + priv->stbyctrl = info->stbyctrl; 924 873 925 874 for (i = 0; i < nclks; i++) 926 875 clks[i] = ERR_PTR(-ENOENT); ··· 946 893 info->num_core_pm_clks); 947 894 if (error) 948 895 return error; 896 + 897 + /* Reset Controller not supported for Standby Control SoCs */ 898 + if (info->stbyctrl) 899 + return 0; 949 900 950 901 error = cpg_mssr_reset_controller_register(priv); 951 902 if (error)
+13
drivers/clk/renesas/renesas-cpg-mssr.h
··· 78 78 #define DEF_MOD(_name, _mod, _parent...) \ 79 79 { .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent } 80 80 81 + /* Convert from sparse base-10 to packed index space */ 82 + #define MOD_CLK_PACK_10(x) ((x / 10) * 32 + (x % 10)) 83 + 84 + #define MOD_CLK_ID_10(x) (MOD_CLK_BASE + MOD_CLK_PACK_10(x)) 85 + 86 + #define DEF_MOD_STB(_name, _mod, _parent...) \ 87 + { .name = _name, .id = MOD_CLK_ID_10(_mod), .parent = _parent } 81 88 82 89 struct device_node; 83 90 ··· 110 103 * 111 104 * @init: Optional callback to perform SoC-specific initialization 112 105 * @cpg_clk_register: Optional callback to handle special Core Clock types 106 + * 107 + * @stbyctrl: This device has Standby Control Registers which are 8-bits 108 + * wide, no status registers (MSTPSR) and have different address 109 + * offsets. 113 110 */ 114 111 115 112 struct cpg_mssr_info { ··· 122 111 unsigned int num_core_clks; 123 112 unsigned int last_dt_core_clk; 124 113 unsigned int num_total_core_clks; 114 + bool stbyctrl; 125 115 126 116 /* Module Clocks */ 127 117 const struct mssr_mod_clk *mod_clks; ··· 146 134 struct raw_notifier_head *notifiers); 147 135 }; 148 136 137 + extern const struct cpg_mssr_info r7s9210_cpg_mssr_info; 149 138 extern const struct cpg_mssr_info r8a7743_cpg_mssr_info; 150 139 extern const struct cpg_mssr_info r8a7745_cpg_mssr_info; 151 140 extern const struct cpg_mssr_info r8a77470_cpg_mssr_info;
+20
include/dt-bindings/clock/r7s9210-cpg-mssr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 2 + * 3 + * Copyright (C) 2018 Renesas Electronics Corp. 4 + * 5 + */ 6 + 7 + #ifndef __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__ 8 + #define __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__ 9 + 10 + #include <dt-bindings/clock/renesas-cpg-mssr.h> 11 + 12 + /* R7S9210 CPG Core Clocks */ 13 + #define R7S9210_CLK_I 0 14 + #define R7S9210_CLK_G 1 15 + #define R7S9210_CLK_B 2 16 + #define R7S9210_CLK_P1 3 17 + #define R7S9210_CLK_P1C 4 18 + #define R7S9210_CLK_P0 5 19 + 20 + #endif /* __DT_BINDINGS_CLOCK_R7S9210_CPG_MSSR_H__ */