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