1*065fe720SThierry Bultel // SPDX-License-Identifier: GPL-2.0 2*065fe720SThierry Bultel /* 3*065fe720SThierry Bultel * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset 4*065fe720SThierry Bultel * 5*065fe720SThierry Bultel * Copyright (C) 2025 Renesas Electronics Corp. 6*065fe720SThierry Bultel * 7*065fe720SThierry Bultel */ 8*065fe720SThierry Bultel 9*065fe720SThierry Bultel #include <linux/bitfield.h> 10*065fe720SThierry Bultel #include <linux/clk-provider.h> 11*065fe720SThierry Bultel #include <linux/device.h> 12*065fe720SThierry Bultel #include <linux/init.h> 13*065fe720SThierry Bultel #include <linux/kernel.h> 14*065fe720SThierry Bultel 15*065fe720SThierry Bultel #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h> 16*065fe720SThierry Bultel #include "renesas-cpg-mssr.h" 17*065fe720SThierry Bultel 18*065fe720SThierry Bultel #define RZT2H_REG_BLOCK_SHIFT 11 19*065fe720SThierry Bultel #define RZT2H_REG_OFFSET_MASK GENMASK(10, 0) 20*065fe720SThierry Bultel #define RZT2H_REG_CONF(block, offset) (((block) << RZT2H_REG_BLOCK_SHIFT) | \ 21*065fe720SThierry Bultel ((offset) & RZT2H_REG_OFFSET_MASK)) 22*065fe720SThierry Bultel 23*065fe720SThierry Bultel #define RZT2H_REG_BLOCK(x) ((x) >> RZT2H_REG_BLOCK_SHIFT) 24*065fe720SThierry Bultel #define RZT2H_REG_OFFSET(x) ((x) & RZT2H_REG_OFFSET_MASK) 25*065fe720SThierry Bultel 26*065fe720SThierry Bultel #define SCKCR RZT2H_REG_CONF(0, 0x00) 27*065fe720SThierry Bultel #define SCKCR2 RZT2H_REG_CONF(1, 0x04) 28*065fe720SThierry Bultel #define SCKCR3 RZT2H_REG_CONF(0, 0x08) 29*065fe720SThierry Bultel 30*065fe720SThierry Bultel #define OFFSET_MASK GENMASK(31, 20) 31*065fe720SThierry Bultel #define SHIFT_MASK GENMASK(19, 12) 32*065fe720SThierry Bultel #define WIDTH_MASK GENMASK(11, 8) 33*065fe720SThierry Bultel 34*065fe720SThierry Bultel #define CONF_PACK(offset, shift, width) \ 35*065fe720SThierry Bultel (FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \ 36*065fe720SThierry Bultel FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \ 37*065fe720SThierry Bultel FIELD_PREP_CONST(WIDTH_MASK, (width))) 38*065fe720SThierry Bultel 39*065fe720SThierry Bultel #define GET_SHIFT(val) FIELD_GET(SHIFT_MASK, val) 40*065fe720SThierry Bultel #define GET_WIDTH(val) FIELD_GET(WIDTH_MASK, val) 41*065fe720SThierry Bultel #define GET_REG_OFFSET(val) FIELD_GET(OFFSET_MASK, val) 42*065fe720SThierry Bultel 43*065fe720SThierry Bultel #define DIVCA55C0 CONF_PACK(SCKCR2, 8, 1) 44*065fe720SThierry Bultel #define DIVCA55C1 CONF_PACK(SCKCR2, 9, 1) 45*065fe720SThierry Bultel #define DIVCA55C2 CONF_PACK(SCKCR2, 10, 1) 46*065fe720SThierry Bultel #define DIVCA55C3 CONF_PACK(SCKCR2, 11, 1) 47*065fe720SThierry Bultel #define DIVCA55S CONF_PACK(SCKCR2, 12, 1) 48*065fe720SThierry Bultel 49*065fe720SThierry Bultel #define DIVSCI0ASYNC CONF_PACK(SCKCR3, 6, 2) 50*065fe720SThierry Bultel 51*065fe720SThierry Bultel #define SEL_PLL CONF_PACK(SCKCR, 22, 1) 52*065fe720SThierry Bultel 53*065fe720SThierry Bultel 54*065fe720SThierry Bultel enum rzt2h_clk_types { 55*065fe720SThierry Bultel CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */ 56*065fe720SThierry Bultel CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */ 57*065fe720SThierry Bultel }; 58*065fe720SThierry Bultel 59*065fe720SThierry Bultel #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ 60*065fe720SThierry Bultel DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \ 61*065fe720SThierry Bultel .parent = _parent, .dtable = _dtable, .flag = 0) 62*065fe720SThierry Bultel #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \ 63*065fe720SThierry Bultel DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \ 64*065fe720SThierry Bultel .parent_names = _parent_names, .num_parents = _num_parents, \ 65*065fe720SThierry Bultel .flag = 0, .mux_flags = _mux_flags) 66*065fe720SThierry Bultel 67*065fe720SThierry Bultel enum clk_ids { 68*065fe720SThierry Bultel /* Core Clock Outputs exported to DT */ 69*065fe720SThierry Bultel LAST_DT_CORE_CLK = R9A09G077_CLK_PCLKM, 70*065fe720SThierry Bultel 71*065fe720SThierry Bultel /* External Input Clocks */ 72*065fe720SThierry Bultel CLK_EXTAL, 73*065fe720SThierry Bultel 74*065fe720SThierry Bultel /* Internal Core Clocks */ 75*065fe720SThierry Bultel CLK_LOCO, 76*065fe720SThierry Bultel CLK_PLL0, 77*065fe720SThierry Bultel CLK_PLL1, 78*065fe720SThierry Bultel CLK_PLL4, 79*065fe720SThierry Bultel CLK_SEL_CLK_PLL0, 80*065fe720SThierry Bultel CLK_SEL_CLK_PLL1, 81*065fe720SThierry Bultel CLK_SEL_CLK_PLL4, 82*065fe720SThierry Bultel CLK_PLL4D1, 83*065fe720SThierry Bultel CLK_SCI0ASYNC, 84*065fe720SThierry Bultel 85*065fe720SThierry Bultel /* Module Clocks */ 86*065fe720SThierry Bultel MOD_CLK_BASE, 87*065fe720SThierry Bultel }; 88*065fe720SThierry Bultel 89*065fe720SThierry Bultel static const struct clk_div_table dtable_1_2[] = { 90*065fe720SThierry Bultel {0, 2}, 91*065fe720SThierry Bultel {1, 1}, 92*065fe720SThierry Bultel {0, 0}, 93*065fe720SThierry Bultel }; 94*065fe720SThierry Bultel 95*065fe720SThierry Bultel static const struct clk_div_table dtable_24_25_30_32[] = { 96*065fe720SThierry Bultel {0, 32}, 97*065fe720SThierry Bultel {1, 30}, 98*065fe720SThierry Bultel {2, 25}, 99*065fe720SThierry Bultel {3, 24}, 100*065fe720SThierry Bultel {0, 0}, 101*065fe720SThierry Bultel }; 102*065fe720SThierry Bultel 103*065fe720SThierry Bultel /* Mux clock tables */ 104*065fe720SThierry Bultel 105*065fe720SThierry Bultel static const char * const sel_clk_pll0[] = { ".loco", ".pll0" }; 106*065fe720SThierry Bultel static const char * const sel_clk_pll1[] = { ".loco", ".pll1" }; 107*065fe720SThierry Bultel static const char * const sel_clk_pll4[] = { ".loco", ".pll4" }; 108*065fe720SThierry Bultel 109*065fe720SThierry Bultel static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { 110*065fe720SThierry Bultel /* External Clock Inputs */ 111*065fe720SThierry Bultel DEF_INPUT("extal", CLK_EXTAL), 112*065fe720SThierry Bultel 113*065fe720SThierry Bultel /* Internal Core Clocks */ 114*065fe720SThierry Bultel DEF_RATE(".loco", CLK_LOCO, 1000 * 1000), 115*065fe720SThierry Bultel DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48), 116*065fe720SThierry Bultel DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40), 117*065fe720SThierry Bultel DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96), 118*065fe720SThierry Bultel 119*065fe720SThierry Bultel DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL, 120*065fe720SThierry Bultel sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY), 121*065fe720SThierry Bultel DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL, 122*065fe720SThierry Bultel sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY), 123*065fe720SThierry Bultel DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL, 124*065fe720SThierry Bultel sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY), 125*065fe720SThierry Bultel 126*065fe720SThierry Bultel DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1), 127*065fe720SThierry Bultel DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC, 128*065fe720SThierry Bultel dtable_24_25_30_32), 129*065fe720SThierry Bultel 130*065fe720SThierry Bultel /* Core output clk */ 131*065fe720SThierry Bultel DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0, 132*065fe720SThierry Bultel dtable_1_2), 133*065fe720SThierry Bultel DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1, 134*065fe720SThierry Bultel dtable_1_2), 135*065fe720SThierry Bultel DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2, 136*065fe720SThierry Bultel dtable_1_2), 137*065fe720SThierry Bultel DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3, 138*065fe720SThierry Bultel dtable_1_2), 139*065fe720SThierry Bultel DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S, 140*065fe720SThierry Bultel dtable_1_2), 141*065fe720SThierry Bultel DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1), 142*065fe720SThierry Bultel DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1), 143*065fe720SThierry Bultel }; 144*065fe720SThierry Bultel 145*065fe720SThierry Bultel static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { 146*065fe720SThierry Bultel DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC), 147*065fe720SThierry Bultel }; 148*065fe720SThierry Bultel 149*065fe720SThierry Bultel static struct clk * __init 150*065fe720SThierry Bultel r9a09g077_cpg_div_clk_register(struct device *dev, 151*065fe720SThierry Bultel const struct cpg_core_clk *core, 152*065fe720SThierry Bultel void __iomem *addr, struct cpg_mssr_pub *pub) 153*065fe720SThierry Bultel { 154*065fe720SThierry Bultel const struct clk *parent; 155*065fe720SThierry Bultel const char *parent_name; 156*065fe720SThierry Bultel struct clk_hw *clk_hw; 157*065fe720SThierry Bultel 158*065fe720SThierry Bultel parent = pub->clks[core->parent]; 159*065fe720SThierry Bultel if (IS_ERR(parent)) 160*065fe720SThierry Bultel return ERR_CAST(parent); 161*065fe720SThierry Bultel 162*065fe720SThierry Bultel parent_name = __clk_get_name(parent); 163*065fe720SThierry Bultel 164*065fe720SThierry Bultel if (core->dtable) 165*065fe720SThierry Bultel clk_hw = clk_hw_register_divider_table(dev, core->name, 166*065fe720SThierry Bultel parent_name, 0, 167*065fe720SThierry Bultel addr, 168*065fe720SThierry Bultel GET_SHIFT(core->conf), 169*065fe720SThierry Bultel GET_WIDTH(core->conf), 170*065fe720SThierry Bultel core->flag, 171*065fe720SThierry Bultel core->dtable, 172*065fe720SThierry Bultel &pub->rmw_lock); 173*065fe720SThierry Bultel else 174*065fe720SThierry Bultel clk_hw = clk_hw_register_divider(dev, core->name, 175*065fe720SThierry Bultel parent_name, 0, 176*065fe720SThierry Bultel addr, 177*065fe720SThierry Bultel GET_SHIFT(core->conf), 178*065fe720SThierry Bultel GET_WIDTH(core->conf), 179*065fe720SThierry Bultel core->flag, &pub->rmw_lock); 180*065fe720SThierry Bultel 181*065fe720SThierry Bultel if (IS_ERR(clk_hw)) 182*065fe720SThierry Bultel return ERR_CAST(clk_hw); 183*065fe720SThierry Bultel 184*065fe720SThierry Bultel return clk_hw->clk; 185*065fe720SThierry Bultel 186*065fe720SThierry Bultel } 187*065fe720SThierry Bultel 188*065fe720SThierry Bultel static struct clk * __init 189*065fe720SThierry Bultel r9a09g077_cpg_mux_clk_register(struct device *dev, 190*065fe720SThierry Bultel const struct cpg_core_clk *core, 191*065fe720SThierry Bultel void __iomem *addr, struct cpg_mssr_pub *pub) 192*065fe720SThierry Bultel { 193*065fe720SThierry Bultel struct clk_hw *clk_hw; 194*065fe720SThierry Bultel 195*065fe720SThierry Bultel clk_hw = devm_clk_hw_register_mux(dev, core->name, 196*065fe720SThierry Bultel core->parent_names, core->num_parents, 197*065fe720SThierry Bultel core->flag, 198*065fe720SThierry Bultel addr, 199*065fe720SThierry Bultel GET_SHIFT(core->conf), 200*065fe720SThierry Bultel GET_WIDTH(core->conf), 201*065fe720SThierry Bultel core->mux_flags, &pub->rmw_lock); 202*065fe720SThierry Bultel if (IS_ERR(clk_hw)) 203*065fe720SThierry Bultel return ERR_CAST(clk_hw); 204*065fe720SThierry Bultel 205*065fe720SThierry Bultel return clk_hw->clk; 206*065fe720SThierry Bultel } 207*065fe720SThierry Bultel 208*065fe720SThierry Bultel static struct clk * __init 209*065fe720SThierry Bultel r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, 210*065fe720SThierry Bultel const struct cpg_mssr_info *info, 211*065fe720SThierry Bultel struct cpg_mssr_pub *pub) 212*065fe720SThierry Bultel { 213*065fe720SThierry Bultel u32 offset = GET_REG_OFFSET(core->conf); 214*065fe720SThierry Bultel void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0; 215*065fe720SThierry Bultel void __iomem *addr = base + RZT2H_REG_OFFSET(offset); 216*065fe720SThierry Bultel 217*065fe720SThierry Bultel switch (core->type) { 218*065fe720SThierry Bultel case CLK_TYPE_RZT2H_DIV: 219*065fe720SThierry Bultel return r9a09g077_cpg_div_clk_register(dev, core, addr, pub); 220*065fe720SThierry Bultel case CLK_TYPE_RZT2H_MUX: 221*065fe720SThierry Bultel return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub); 222*065fe720SThierry Bultel default: 223*065fe720SThierry Bultel return ERR_PTR(-EINVAL); 224*065fe720SThierry Bultel } 225*065fe720SThierry Bultel } 226*065fe720SThierry Bultel 227*065fe720SThierry Bultel const struct cpg_mssr_info r9a09g077_cpg_mssr_info = { 228*065fe720SThierry Bultel /* Core Clocks */ 229*065fe720SThierry Bultel .core_clks = r9a09g077_core_clks, 230*065fe720SThierry Bultel .num_core_clks = ARRAY_SIZE(r9a09g077_core_clks), 231*065fe720SThierry Bultel .last_dt_core_clk = LAST_DT_CORE_CLK, 232*065fe720SThierry Bultel .num_total_core_clks = MOD_CLK_BASE, 233*065fe720SThierry Bultel 234*065fe720SThierry Bultel /* Module Clocks */ 235*065fe720SThierry Bultel .mod_clks = r9a09g077_mod_clks, 236*065fe720SThierry Bultel .num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks), 237*065fe720SThierry Bultel .num_hw_mod_clks = 14 * 32, 238*065fe720SThierry Bultel 239*065fe720SThierry Bultel .reg_layout = CLK_REG_LAYOUT_RZ_T2H, 240*065fe720SThierry Bultel .cpg_clk_register = r9a09g077_cpg_clk_register, 241*065fe720SThierry Bultel }; 242