1065fe720SThierry Bultel // SPDX-License-Identifier: GPL-2.0 2065fe720SThierry Bultel /* 3065fe720SThierry Bultel * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset 4065fe720SThierry Bultel * 5065fe720SThierry Bultel * Copyright (C) 2025 Renesas Electronics Corp. 6065fe720SThierry Bultel * 7065fe720SThierry Bultel */ 8065fe720SThierry Bultel 9065fe720SThierry Bultel #include <linux/bitfield.h> 10065fe720SThierry Bultel #include <linux/clk-provider.h> 11065fe720SThierry Bultel #include <linux/device.h> 12065fe720SThierry Bultel #include <linux/init.h> 13065fe720SThierry Bultel #include <linux/kernel.h> 14065fe720SThierry Bultel 15065fe720SThierry Bultel #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h> 168b8ca279SLad Prabhakar #include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h> 17065fe720SThierry Bultel #include "renesas-cpg-mssr.h" 18065fe720SThierry Bultel 19065fe720SThierry Bultel #define RZT2H_REG_BLOCK_SHIFT 11 20065fe720SThierry Bultel #define RZT2H_REG_OFFSET_MASK GENMASK(10, 0) 21065fe720SThierry Bultel #define RZT2H_REG_CONF(block, offset) (((block) << RZT2H_REG_BLOCK_SHIFT) | \ 22065fe720SThierry Bultel ((offset) & RZT2H_REG_OFFSET_MASK)) 23065fe720SThierry Bultel 24065fe720SThierry Bultel #define RZT2H_REG_BLOCK(x) ((x) >> RZT2H_REG_BLOCK_SHIFT) 25065fe720SThierry Bultel #define RZT2H_REG_OFFSET(x) ((x) & RZT2H_REG_OFFSET_MASK) 26065fe720SThierry Bultel 27065fe720SThierry Bultel #define SCKCR RZT2H_REG_CONF(0, 0x00) 28065fe720SThierry Bultel #define SCKCR2 RZT2H_REG_CONF(1, 0x04) 29065fe720SThierry Bultel #define SCKCR3 RZT2H_REG_CONF(0, 0x08) 30065fe720SThierry Bultel 31065fe720SThierry Bultel #define OFFSET_MASK GENMASK(31, 20) 32065fe720SThierry Bultel #define SHIFT_MASK GENMASK(19, 12) 33065fe720SThierry Bultel #define WIDTH_MASK GENMASK(11, 8) 34065fe720SThierry Bultel 35065fe720SThierry Bultel #define CONF_PACK(offset, shift, width) \ 36065fe720SThierry Bultel (FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \ 37065fe720SThierry Bultel FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \ 38065fe720SThierry Bultel FIELD_PREP_CONST(WIDTH_MASK, (width))) 39065fe720SThierry Bultel 40065fe720SThierry Bultel #define GET_SHIFT(val) FIELD_GET(SHIFT_MASK, val) 41065fe720SThierry Bultel #define GET_WIDTH(val) FIELD_GET(WIDTH_MASK, val) 42065fe720SThierry Bultel #define GET_REG_OFFSET(val) FIELD_GET(OFFSET_MASK, val) 43065fe720SThierry Bultel 44065fe720SThierry Bultel #define DIVCA55C0 CONF_PACK(SCKCR2, 8, 1) 45065fe720SThierry Bultel #define DIVCA55C1 CONF_PACK(SCKCR2, 9, 1) 46065fe720SThierry Bultel #define DIVCA55C2 CONF_PACK(SCKCR2, 10, 1) 47065fe720SThierry Bultel #define DIVCA55C3 CONF_PACK(SCKCR2, 11, 1) 48065fe720SThierry Bultel #define DIVCA55S CONF_PACK(SCKCR2, 12, 1) 49065fe720SThierry Bultel 50065fe720SThierry Bultel #define DIVSCI0ASYNC CONF_PACK(SCKCR3, 6, 2) 51065fe720SThierry Bultel 52065fe720SThierry Bultel #define SEL_PLL CONF_PACK(SCKCR, 22, 1) 53065fe720SThierry Bultel 54065fe720SThierry Bultel 55065fe720SThierry Bultel enum rzt2h_clk_types { 56065fe720SThierry Bultel CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */ 57065fe720SThierry Bultel CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */ 58065fe720SThierry Bultel }; 59065fe720SThierry Bultel 60065fe720SThierry Bultel #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ 61065fe720SThierry Bultel DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \ 62065fe720SThierry Bultel .parent = _parent, .dtable = _dtable, .flag = 0) 63065fe720SThierry Bultel #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \ 64065fe720SThierry Bultel DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \ 65065fe720SThierry Bultel .parent_names = _parent_names, .num_parents = _num_parents, \ 66065fe720SThierry Bultel .flag = 0, .mux_flags = _mux_flags) 67065fe720SThierry Bultel 68065fe720SThierry Bultel enum clk_ids { 69065fe720SThierry Bultel /* Core Clock Outputs exported to DT */ 70*09d50e09SLad Prabhakar LAST_DT_CORE_CLK = R9A09G077_SDHI_CLKHS, 71065fe720SThierry Bultel 72065fe720SThierry Bultel /* External Input Clocks */ 73065fe720SThierry Bultel CLK_EXTAL, 74065fe720SThierry Bultel 75065fe720SThierry Bultel /* Internal Core Clocks */ 76065fe720SThierry Bultel CLK_LOCO, 77065fe720SThierry Bultel CLK_PLL0, 78065fe720SThierry Bultel CLK_PLL1, 79*09d50e09SLad Prabhakar CLK_PLL2, 80065fe720SThierry Bultel CLK_PLL4, 81065fe720SThierry Bultel CLK_SEL_CLK_PLL0, 82065fe720SThierry Bultel CLK_SEL_CLK_PLL1, 83*09d50e09SLad Prabhakar CLK_SEL_CLK_PLL2, 84065fe720SThierry Bultel CLK_SEL_CLK_PLL4, 85065fe720SThierry Bultel CLK_PLL4D1, 86065fe720SThierry Bultel CLK_SCI0ASYNC, 87065fe720SThierry Bultel 88065fe720SThierry Bultel /* Module Clocks */ 89065fe720SThierry Bultel MOD_CLK_BASE, 90065fe720SThierry Bultel }; 91065fe720SThierry Bultel 92065fe720SThierry Bultel static const struct clk_div_table dtable_1_2[] = { 93065fe720SThierry Bultel {0, 2}, 94065fe720SThierry Bultel {1, 1}, 95065fe720SThierry Bultel {0, 0}, 96065fe720SThierry Bultel }; 97065fe720SThierry Bultel 98065fe720SThierry Bultel static const struct clk_div_table dtable_24_25_30_32[] = { 99065fe720SThierry Bultel {0, 32}, 100065fe720SThierry Bultel {1, 30}, 101065fe720SThierry Bultel {2, 25}, 102065fe720SThierry Bultel {3, 24}, 103065fe720SThierry Bultel {0, 0}, 104065fe720SThierry Bultel }; 105065fe720SThierry Bultel 106065fe720SThierry Bultel /* Mux clock tables */ 107065fe720SThierry Bultel 108065fe720SThierry Bultel static const char * const sel_clk_pll0[] = { ".loco", ".pll0" }; 109065fe720SThierry Bultel static const char * const sel_clk_pll1[] = { ".loco", ".pll1" }; 110*09d50e09SLad Prabhakar static const char * const sel_clk_pll2[] = { ".loco", ".pll2" }; 111065fe720SThierry Bultel static const char * const sel_clk_pll4[] = { ".loco", ".pll4" }; 112065fe720SThierry Bultel 113065fe720SThierry Bultel static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { 114065fe720SThierry Bultel /* External Clock Inputs */ 115065fe720SThierry Bultel DEF_INPUT("extal", CLK_EXTAL), 116065fe720SThierry Bultel 117065fe720SThierry Bultel /* Internal Core Clocks */ 118065fe720SThierry Bultel DEF_RATE(".loco", CLK_LOCO, 1000 * 1000), 119065fe720SThierry Bultel DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48), 120065fe720SThierry Bultel DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40), 121*09d50e09SLad Prabhakar DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 1, 32), 122065fe720SThierry Bultel DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96), 123065fe720SThierry Bultel 124065fe720SThierry Bultel DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL, 125065fe720SThierry Bultel sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY), 126065fe720SThierry Bultel DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL, 127065fe720SThierry Bultel sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY), 128*09d50e09SLad Prabhakar DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL, 129*09d50e09SLad Prabhakar sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY), 130065fe720SThierry Bultel DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL, 131065fe720SThierry Bultel sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY), 132065fe720SThierry Bultel 133065fe720SThierry Bultel DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1), 134065fe720SThierry Bultel DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC, 135065fe720SThierry Bultel dtable_24_25_30_32), 136065fe720SThierry Bultel 137065fe720SThierry Bultel /* Core output clk */ 138065fe720SThierry Bultel DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0, 139065fe720SThierry Bultel dtable_1_2), 140065fe720SThierry Bultel DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1, 141065fe720SThierry Bultel dtable_1_2), 142065fe720SThierry Bultel DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2, 143065fe720SThierry Bultel dtable_1_2), 144065fe720SThierry Bultel DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3, 145065fe720SThierry Bultel dtable_1_2), 146065fe720SThierry Bultel DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S, 147065fe720SThierry Bultel dtable_1_2), 148065fe720SThierry Bultel DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1), 149065fe720SThierry Bultel DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1), 150275e2b54SLad Prabhakar DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1), 151*09d50e09SLad Prabhakar DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1), 152*09d50e09SLad Prabhakar DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1), 153065fe720SThierry Bultel }; 154065fe720SThierry Bultel 155065fe720SThierry Bultel static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { 156065fe720SThierry Bultel DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC), 157*09d50e09SLad Prabhakar DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM), 158*09d50e09SLad Prabhakar DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM), 159065fe720SThierry Bultel }; 160065fe720SThierry Bultel 161065fe720SThierry Bultel static struct clk * __init 162065fe720SThierry Bultel r9a09g077_cpg_div_clk_register(struct device *dev, 163065fe720SThierry Bultel const struct cpg_core_clk *core, 164065fe720SThierry Bultel void __iomem *addr, struct cpg_mssr_pub *pub) 165065fe720SThierry Bultel { 166065fe720SThierry Bultel const struct clk *parent; 167065fe720SThierry Bultel const char *parent_name; 168065fe720SThierry Bultel struct clk_hw *clk_hw; 169065fe720SThierry Bultel 170065fe720SThierry Bultel parent = pub->clks[core->parent]; 171065fe720SThierry Bultel if (IS_ERR(parent)) 172065fe720SThierry Bultel return ERR_CAST(parent); 173065fe720SThierry Bultel 174065fe720SThierry Bultel parent_name = __clk_get_name(parent); 175065fe720SThierry Bultel 176065fe720SThierry Bultel if (core->dtable) 177065fe720SThierry Bultel clk_hw = clk_hw_register_divider_table(dev, core->name, 178065fe720SThierry Bultel parent_name, 0, 179065fe720SThierry Bultel addr, 180065fe720SThierry Bultel GET_SHIFT(core->conf), 181065fe720SThierry Bultel GET_WIDTH(core->conf), 182065fe720SThierry Bultel core->flag, 183065fe720SThierry Bultel core->dtable, 184065fe720SThierry Bultel &pub->rmw_lock); 185065fe720SThierry Bultel else 186065fe720SThierry Bultel clk_hw = clk_hw_register_divider(dev, core->name, 187065fe720SThierry Bultel parent_name, 0, 188065fe720SThierry Bultel addr, 189065fe720SThierry Bultel GET_SHIFT(core->conf), 190065fe720SThierry Bultel GET_WIDTH(core->conf), 191065fe720SThierry Bultel core->flag, &pub->rmw_lock); 192065fe720SThierry Bultel 193065fe720SThierry Bultel if (IS_ERR(clk_hw)) 194065fe720SThierry Bultel return ERR_CAST(clk_hw); 195065fe720SThierry Bultel 196065fe720SThierry Bultel return clk_hw->clk; 197065fe720SThierry Bultel 198065fe720SThierry Bultel } 199065fe720SThierry Bultel 200065fe720SThierry Bultel static struct clk * __init 201065fe720SThierry Bultel r9a09g077_cpg_mux_clk_register(struct device *dev, 202065fe720SThierry Bultel const struct cpg_core_clk *core, 203065fe720SThierry Bultel void __iomem *addr, struct cpg_mssr_pub *pub) 204065fe720SThierry Bultel { 205065fe720SThierry Bultel struct clk_hw *clk_hw; 206065fe720SThierry Bultel 207065fe720SThierry Bultel clk_hw = devm_clk_hw_register_mux(dev, core->name, 208065fe720SThierry Bultel core->parent_names, core->num_parents, 209065fe720SThierry Bultel core->flag, 210065fe720SThierry Bultel addr, 211065fe720SThierry Bultel GET_SHIFT(core->conf), 212065fe720SThierry Bultel GET_WIDTH(core->conf), 213065fe720SThierry Bultel core->mux_flags, &pub->rmw_lock); 214065fe720SThierry Bultel if (IS_ERR(clk_hw)) 215065fe720SThierry Bultel return ERR_CAST(clk_hw); 216065fe720SThierry Bultel 217065fe720SThierry Bultel return clk_hw->clk; 218065fe720SThierry Bultel } 219065fe720SThierry Bultel 220065fe720SThierry Bultel static struct clk * __init 221065fe720SThierry Bultel r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, 222065fe720SThierry Bultel const struct cpg_mssr_info *info, 223065fe720SThierry Bultel struct cpg_mssr_pub *pub) 224065fe720SThierry Bultel { 225065fe720SThierry Bultel u32 offset = GET_REG_OFFSET(core->conf); 226065fe720SThierry Bultel void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0; 227065fe720SThierry Bultel void __iomem *addr = base + RZT2H_REG_OFFSET(offset); 228065fe720SThierry Bultel 229065fe720SThierry Bultel switch (core->type) { 230065fe720SThierry Bultel case CLK_TYPE_RZT2H_DIV: 231065fe720SThierry Bultel return r9a09g077_cpg_div_clk_register(dev, core, addr, pub); 232065fe720SThierry Bultel case CLK_TYPE_RZT2H_MUX: 233065fe720SThierry Bultel return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub); 234065fe720SThierry Bultel default: 235065fe720SThierry Bultel return ERR_PTR(-EINVAL); 236065fe720SThierry Bultel } 237065fe720SThierry Bultel } 238065fe720SThierry Bultel 239065fe720SThierry Bultel const struct cpg_mssr_info r9a09g077_cpg_mssr_info = { 240065fe720SThierry Bultel /* Core Clocks */ 241065fe720SThierry Bultel .core_clks = r9a09g077_core_clks, 242065fe720SThierry Bultel .num_core_clks = ARRAY_SIZE(r9a09g077_core_clks), 243065fe720SThierry Bultel .last_dt_core_clk = LAST_DT_CORE_CLK, 244065fe720SThierry Bultel .num_total_core_clks = MOD_CLK_BASE, 245065fe720SThierry Bultel 246065fe720SThierry Bultel /* Module Clocks */ 247065fe720SThierry Bultel .mod_clks = r9a09g077_mod_clks, 248065fe720SThierry Bultel .num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks), 249065fe720SThierry Bultel .num_hw_mod_clks = 14 * 32, 250065fe720SThierry Bultel 251065fe720SThierry Bultel .reg_layout = CLK_REG_LAYOUT_RZ_T2H, 252065fe720SThierry Bultel .cpg_clk_register = r9a09g077_cpg_clk_register, 253065fe720SThierry Bultel }; 254