1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset 4 * 5 * Copyright (C) 2025 Renesas Electronics Corp. 6 * 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/clk-provider.h> 11 #include <linux/device.h> 12 #include <linux/init.h> 13 #include <linux/kernel.h> 14 15 #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h> 16 #include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h> 17 #include "renesas-cpg-mssr.h" 18 19 #define RZT2H_REG_BLOCK_SHIFT 11 20 #define RZT2H_REG_OFFSET_MASK GENMASK(10, 0) 21 #define RZT2H_REG_CONF(block, offset) (((block) << RZT2H_REG_BLOCK_SHIFT) | \ 22 ((offset) & RZT2H_REG_OFFSET_MASK)) 23 24 #define RZT2H_REG_BLOCK(x) ((x) >> RZT2H_REG_BLOCK_SHIFT) 25 #define RZT2H_REG_OFFSET(x) ((x) & RZT2H_REG_OFFSET_MASK) 26 27 #define SCKCR RZT2H_REG_CONF(0, 0x00) 28 #define SCKCR2 RZT2H_REG_CONF(1, 0x04) 29 #define SCKCR3 RZT2H_REG_CONF(0, 0x08) 30 31 #define OFFSET_MASK GENMASK(31, 20) 32 #define SHIFT_MASK GENMASK(19, 12) 33 #define WIDTH_MASK GENMASK(11, 8) 34 35 #define CONF_PACK(offset, shift, width) \ 36 (FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \ 37 FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \ 38 FIELD_PREP_CONST(WIDTH_MASK, (width))) 39 40 #define GET_SHIFT(val) FIELD_GET(SHIFT_MASK, val) 41 #define GET_WIDTH(val) FIELD_GET(WIDTH_MASK, val) 42 #define GET_REG_OFFSET(val) FIELD_GET(OFFSET_MASK, val) 43 44 #define DIVCA55C0 CONF_PACK(SCKCR2, 8, 1) 45 #define DIVCA55C1 CONF_PACK(SCKCR2, 9, 1) 46 #define DIVCA55C2 CONF_PACK(SCKCR2, 10, 1) 47 #define DIVCA55C3 CONF_PACK(SCKCR2, 11, 1) 48 #define DIVCA55S CONF_PACK(SCKCR2, 12, 1) 49 #define DIVSCI5ASYNC CONF_PACK(SCKCR2, 18, 2) 50 51 #define DIVSCI0ASYNC CONF_PACK(SCKCR3, 6, 2) 52 #define DIVSCI1ASYNC CONF_PACK(SCKCR3, 8, 2) 53 #define DIVSCI2ASYNC CONF_PACK(SCKCR3, 10, 2) 54 #define DIVSCI3ASYNC CONF_PACK(SCKCR3, 12, 2) 55 #define DIVSCI4ASYNC CONF_PACK(SCKCR3, 14, 2) 56 57 #define SEL_PLL CONF_PACK(SCKCR, 22, 1) 58 59 60 enum rzt2h_clk_types { 61 CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */ 62 CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */ 63 }; 64 65 #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ 66 DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \ 67 .parent = _parent, .dtable = _dtable, .flag = 0) 68 #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \ 69 DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \ 70 .parent_names = _parent_names, .num_parents = _num_parents, \ 71 .flag = 0, .mux_flags = _mux_flags) 72 73 enum clk_ids { 74 /* Core Clock Outputs exported to DT */ 75 LAST_DT_CORE_CLK = R9A09G077_ETCLKE, 76 77 /* External Input Clocks */ 78 CLK_EXTAL, 79 80 /* Internal Core Clocks */ 81 CLK_LOCO, 82 CLK_PLL0, 83 CLK_PLL1, 84 CLK_PLL2, 85 CLK_PLL4, 86 CLK_SEL_CLK_PLL0, 87 CLK_SEL_CLK_PLL1, 88 CLK_SEL_CLK_PLL2, 89 CLK_SEL_CLK_PLL4, 90 CLK_PLL4D1, 91 CLK_SCI0ASYNC, 92 CLK_SCI1ASYNC, 93 CLK_SCI2ASYNC, 94 CLK_SCI3ASYNC, 95 CLK_SCI4ASYNC, 96 CLK_SCI5ASYNC, 97 98 /* Module Clocks */ 99 MOD_CLK_BASE, 100 }; 101 102 static const struct clk_div_table dtable_1_2[] = { 103 {0, 2}, 104 {1, 1}, 105 {0, 0}, 106 }; 107 108 static const struct clk_div_table dtable_24_25_30_32[] = { 109 {0, 32}, 110 {1, 30}, 111 {2, 25}, 112 {3, 24}, 113 {0, 0}, 114 }; 115 116 /* Mux clock tables */ 117 118 static const char * const sel_clk_pll0[] = { ".loco", ".pll0" }; 119 static const char * const sel_clk_pll1[] = { ".loco", ".pll1" }; 120 static const char * const sel_clk_pll2[] = { ".loco", ".pll2" }; 121 static const char * const sel_clk_pll4[] = { ".loco", ".pll4" }; 122 123 static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { 124 /* External Clock Inputs */ 125 DEF_INPUT("extal", CLK_EXTAL), 126 127 /* Internal Core Clocks */ 128 DEF_RATE(".loco", CLK_LOCO, 1000 * 1000), 129 DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48), 130 DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40), 131 DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 1, 32), 132 DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96), 133 134 DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL, 135 sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY), 136 DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL, 137 sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY), 138 DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL, 139 sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY), 140 DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL, 141 sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY), 142 143 DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1), 144 DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC, 145 dtable_24_25_30_32), 146 DEF_DIV(".sci1async", CLK_SCI1ASYNC, CLK_PLL4D1, DIVSCI1ASYNC, 147 dtable_24_25_30_32), 148 DEF_DIV(".sci2async", CLK_SCI2ASYNC, CLK_PLL4D1, DIVSCI2ASYNC, 149 dtable_24_25_30_32), 150 DEF_DIV(".sci3async", CLK_SCI3ASYNC, CLK_PLL4D1, DIVSCI3ASYNC, 151 dtable_24_25_30_32), 152 DEF_DIV(".sci4async", CLK_SCI4ASYNC, CLK_PLL4D1, DIVSCI4ASYNC, 153 dtable_24_25_30_32), 154 DEF_DIV(".sci5async", CLK_SCI5ASYNC, CLK_PLL4D1, DIVSCI5ASYNC, 155 dtable_24_25_30_32), 156 157 /* Core output clk */ 158 DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0, 159 dtable_1_2), 160 DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1, 161 dtable_1_2), 162 DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2, 163 dtable_1_2), 164 DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3, 165 dtable_1_2), 166 DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S, 167 dtable_1_2), 168 DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1), 169 DEF_FIXED("PCLKH", R9A09G077_CLK_PCLKH, CLK_SEL_CLK_PLL1, 4, 1), 170 DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1), 171 DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1), 172 DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1), 173 DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1), 174 DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1), 175 DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1), 176 DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1), 177 DEF_FIXED("ETCLKB", R9A09G077_ETCLKB, CLK_SEL_CLK_PLL1, 8, 1), 178 DEF_FIXED("ETCLKC", R9A09G077_ETCLKC, CLK_SEL_CLK_PLL1, 10, 1), 179 DEF_FIXED("ETCLKD", R9A09G077_ETCLKD, CLK_SEL_CLK_PLL1, 20, 1), 180 DEF_FIXED("ETCLKE", R9A09G077_ETCLKE, CLK_SEL_CLK_PLL1, 40, 1), 181 }; 182 183 static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { 184 DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC), 185 DEF_MOD("sci1fck", 9, CLK_SCI1ASYNC), 186 DEF_MOD("sci2fck", 10, CLK_SCI2ASYNC), 187 DEF_MOD("sci3fck", 11, CLK_SCI3ASYNC), 188 DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC), 189 DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL), 190 DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL), 191 DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM), 192 DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM), 193 DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM), 194 DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM), 195 DEF_MOD("gmac1", 416, R9A09G077_CLK_PCLKAM), 196 DEF_MOD("gmac2", 417, R9A09G077_CLK_PCLKAM), 197 DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC), 198 DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL), 199 DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM), 200 DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM), 201 }; 202 203 static struct clk * __init 204 r9a09g077_cpg_div_clk_register(struct device *dev, 205 const struct cpg_core_clk *core, 206 void __iomem *addr, struct cpg_mssr_pub *pub) 207 { 208 const struct clk *parent; 209 const char *parent_name; 210 struct clk_hw *clk_hw; 211 212 parent = pub->clks[core->parent]; 213 if (IS_ERR(parent)) 214 return ERR_CAST(parent); 215 216 parent_name = __clk_get_name(parent); 217 218 if (core->dtable) 219 clk_hw = clk_hw_register_divider_table(dev, core->name, 220 parent_name, 0, 221 addr, 222 GET_SHIFT(core->conf), 223 GET_WIDTH(core->conf), 224 core->flag, 225 core->dtable, 226 &pub->rmw_lock); 227 else 228 clk_hw = clk_hw_register_divider(dev, core->name, 229 parent_name, 0, 230 addr, 231 GET_SHIFT(core->conf), 232 GET_WIDTH(core->conf), 233 core->flag, &pub->rmw_lock); 234 235 if (IS_ERR(clk_hw)) 236 return ERR_CAST(clk_hw); 237 238 return clk_hw->clk; 239 240 } 241 242 static struct clk * __init 243 r9a09g077_cpg_mux_clk_register(struct device *dev, 244 const struct cpg_core_clk *core, 245 void __iomem *addr, struct cpg_mssr_pub *pub) 246 { 247 struct clk_hw *clk_hw; 248 249 clk_hw = devm_clk_hw_register_mux(dev, core->name, 250 core->parent_names, core->num_parents, 251 core->flag, 252 addr, 253 GET_SHIFT(core->conf), 254 GET_WIDTH(core->conf), 255 core->mux_flags, &pub->rmw_lock); 256 if (IS_ERR(clk_hw)) 257 return ERR_CAST(clk_hw); 258 259 return clk_hw->clk; 260 } 261 262 static struct clk * __init 263 r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, 264 const struct cpg_mssr_info *info, 265 struct cpg_mssr_pub *pub) 266 { 267 u32 offset = GET_REG_OFFSET(core->conf); 268 void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0; 269 void __iomem *addr = base + RZT2H_REG_OFFSET(offset); 270 271 switch (core->type) { 272 case CLK_TYPE_RZT2H_DIV: 273 return r9a09g077_cpg_div_clk_register(dev, core, addr, pub); 274 case CLK_TYPE_RZT2H_MUX: 275 return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub); 276 default: 277 return ERR_PTR(-EINVAL); 278 } 279 } 280 281 const struct cpg_mssr_info r9a09g077_cpg_mssr_info = { 282 /* Core Clocks */ 283 .core_clks = r9a09g077_core_clks, 284 .num_core_clks = ARRAY_SIZE(r9a09g077_core_clks), 285 .last_dt_core_clk = LAST_DT_CORE_CLK, 286 .num_total_core_clks = MOD_CLK_BASE, 287 288 /* Module Clocks */ 289 .mod_clks = r9a09g077_mod_clks, 290 .num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks), 291 .num_hw_mod_clks = 14 * 32, 292 293 .reg_layout = CLK_REG_LAYOUT_RZ_T2H, 294 .cpg_clk_register = r9a09g077_cpg_clk_register, 295 }; 296