1*23c8ebc9SAnirudh Srinivasan // SPDX-License-Identifier: GPL-2.0-only 2*23c8ebc9SAnirudh Srinivasan /* 3*23c8ebc9SAnirudh Srinivasan * Tenstorrent Atlantis PRCM Clock Driver 4*23c8ebc9SAnirudh Srinivasan * 5*23c8ebc9SAnirudh Srinivasan * Copyright (c) 2026 Tenstorrent 6*23c8ebc9SAnirudh Srinivasan */ 7*23c8ebc9SAnirudh Srinivasan 8*23c8ebc9SAnirudh Srinivasan #include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h> 9*23c8ebc9SAnirudh Srinivasan #include <linux/auxiliary_bus.h> 10*23c8ebc9SAnirudh Srinivasan #include <linux/bitfield.h> 11*23c8ebc9SAnirudh Srinivasan #include <linux/clk-provider.h> 12*23c8ebc9SAnirudh Srinivasan #include <linux/platform_device.h> 13*23c8ebc9SAnirudh Srinivasan #include <linux/regmap.h> 14*23c8ebc9SAnirudh Srinivasan #include <linux/slab.h> 15*23c8ebc9SAnirudh Srinivasan 16*23c8ebc9SAnirudh Srinivasan /* RCPU Clock Register Offsets */ 17*23c8ebc9SAnirudh Srinivasan #define PLL_RCPU_CFG_REG 0x0000 18*23c8ebc9SAnirudh Srinivasan #define PLL_NOCC_CFG_REG 0x0004 19*23c8ebc9SAnirudh Srinivasan #define NOCC_CLK_CFG_REG 0x0008 20*23c8ebc9SAnirudh Srinivasan #define RCPU_DIV_CFG_REG 0x000C 21*23c8ebc9SAnirudh Srinivasan #define RCPU_BLK_CG_REG 0x0014 22*23c8ebc9SAnirudh Srinivasan #define LSIO_BLK_CG_REG 0x0018 23*23c8ebc9SAnirudh Srinivasan #define PLL_RCPU_EN_REG 0x011C 24*23c8ebc9SAnirudh Srinivasan #define PLL_NOCC_EN_REG 0x0120 25*23c8ebc9SAnirudh Srinivasan #define BUS_CG_REG 0x01FC 26*23c8ebc9SAnirudh Srinivasan 27*23c8ebc9SAnirudh Srinivasan /* PLL Bit Definitions */ 28*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_EN_BIT BIT(0) 29*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_BYPASS_BIT BIT(1) 30*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_REFDIV_MASK GENMASK(7, 2) 31*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_REFDIV_SHIFT 2 32*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV1_MASK GENMASK(10, 8) 33*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV1_SHIFT 8 34*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV2_MASK GENMASK(13, 11) 35*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV2_SHIFT 11 36*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_FBDIV_MASK GENMASK(25, 14) 37*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_FBDIV_SHIFT 14 38*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_LKDT_BIT BIT(30) 39*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_LOCK_BIT BIT(31) 40*23c8ebc9SAnirudh Srinivasan #define PLL_LOCK_TIMEOUT_US 1000 41*23c8ebc9SAnirudh Srinivasan #define PLL_BYPASS_WAIT_US 500 42*23c8ebc9SAnirudh Srinivasan 43*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common { 44*23c8ebc9SAnirudh Srinivasan int clkid; 45*23c8ebc9SAnirudh Srinivasan struct regmap *regmap; 46*23c8ebc9SAnirudh Srinivasan struct clk_hw hw; 47*23c8ebc9SAnirudh Srinivasan }; 48*23c8ebc9SAnirudh Srinivasan 49*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_common * 50*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_common(struct clk_hw *hw) 51*23c8ebc9SAnirudh Srinivasan { 52*23c8ebc9SAnirudh Srinivasan return container_of(hw, struct atlantis_clk_common, hw); 53*23c8ebc9SAnirudh Srinivasan } 54*23c8ebc9SAnirudh Srinivasan 55*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux_config { 56*23c8ebc9SAnirudh Srinivasan u8 shift; 57*23c8ebc9SAnirudh Srinivasan u8 width; 58*23c8ebc9SAnirudh Srinivasan u32 reg_offset; 59*23c8ebc9SAnirudh Srinivasan }; 60*23c8ebc9SAnirudh Srinivasan 61*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux { 62*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 63*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux_config config; 64*23c8ebc9SAnirudh Srinivasan }; 65*23c8ebc9SAnirudh Srinivasan 66*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_config { 67*23c8ebc9SAnirudh Srinivasan u32 reg_offset; 68*23c8ebc9SAnirudh Srinivasan u32 enable; 69*23c8ebc9SAnirudh Srinivasan }; 70*23c8ebc9SAnirudh Srinivasan 71*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate { 72*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 73*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_config config; 74*23c8ebc9SAnirudh Srinivasan }; 75*23c8ebc9SAnirudh Srinivasan 76*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider_config { 77*23c8ebc9SAnirudh Srinivasan u8 shift; 78*23c8ebc9SAnirudh Srinivasan u8 width; 79*23c8ebc9SAnirudh Srinivasan u32 flags; 80*23c8ebc9SAnirudh Srinivasan u32 reg_offset; 81*23c8ebc9SAnirudh Srinivasan }; 82*23c8ebc9SAnirudh Srinivasan 83*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider { 84*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 85*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider_config config; 86*23c8ebc9SAnirudh Srinivasan }; 87*23c8ebc9SAnirudh Srinivasan 88*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll_config { 89*23c8ebc9SAnirudh Srinivasan u32 tbl_num; 90*23c8ebc9SAnirudh Srinivasan u32 reg_offset; 91*23c8ebc9SAnirudh Srinivasan u32 en_reg_offset; 92*23c8ebc9SAnirudh Srinivasan u32 cg_reg_offset; 93*23c8ebc9SAnirudh Srinivasan u32 cg_reg_enable; 94*23c8ebc9SAnirudh Srinivasan }; 95*23c8ebc9SAnirudh Srinivasan 96*23c8ebc9SAnirudh Srinivasan /* Models a PLL with Bypass Functionality and Enable Bit + an optional Gate Clock at it's output */ 97*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll { 98*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 99*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll_config config; 100*23c8ebc9SAnirudh Srinivasan }; 101*23c8ebc9SAnirudh Srinivasan 102*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared_config { 103*23c8ebc9SAnirudh Srinivasan u32 reg_offset; 104*23c8ebc9SAnirudh Srinivasan u32 enable; 105*23c8ebc9SAnirudh Srinivasan unsigned int *share_count; 106*23c8ebc9SAnirudh Srinivasan spinlock_t *refcount_lock; 107*23c8ebc9SAnirudh Srinivasan }; 108*23c8ebc9SAnirudh Srinivasan 109*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared { 110*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 111*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared_config config; 112*23c8ebc9SAnirudh Srinivasan }; 113*23c8ebc9SAnirudh Srinivasan 114*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor_config { 115*23c8ebc9SAnirudh Srinivasan unsigned int mult; 116*23c8ebc9SAnirudh Srinivasan unsigned int div; 117*23c8ebc9SAnirudh Srinivasan }; 118*23c8ebc9SAnirudh Srinivasan 119*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor { 120*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor_config config; 121*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common common; 122*23c8ebc9SAnirudh Srinivasan }; 123*23c8ebc9SAnirudh Srinivasan 124*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_mux *hw_to_atlantis_clk_mux(struct clk_hw *hw) 125*23c8ebc9SAnirudh Srinivasan { 126*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 127*23c8ebc9SAnirudh Srinivasan 128*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_mux, common); 129*23c8ebc9SAnirudh Srinivasan } 130*23c8ebc9SAnirudh Srinivasan 131*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_gate * 132*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate(struct clk_hw *hw) 133*23c8ebc9SAnirudh Srinivasan { 134*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 135*23c8ebc9SAnirudh Srinivasan 136*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_gate, common); 137*23c8ebc9SAnirudh Srinivasan } 138*23c8ebc9SAnirudh Srinivasan 139*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_divider * 140*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_divider(struct clk_hw *hw) 141*23c8ebc9SAnirudh Srinivasan { 142*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 143*23c8ebc9SAnirudh Srinivasan 144*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_divider, common); 145*23c8ebc9SAnirudh Srinivasan } 146*23c8ebc9SAnirudh Srinivasan 147*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_pll *hw_to_atlantis_pll(struct clk_hw *hw) 148*23c8ebc9SAnirudh Srinivasan { 149*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 150*23c8ebc9SAnirudh Srinivasan 151*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_pll, common); 152*23c8ebc9SAnirudh Srinivasan } 153*23c8ebc9SAnirudh Srinivasan 154*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_gate_shared * 155*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(struct clk_hw *hw) 156*23c8ebc9SAnirudh Srinivasan { 157*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 158*23c8ebc9SAnirudh Srinivasan 159*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_gate_shared, common); 160*23c8ebc9SAnirudh Srinivasan } 161*23c8ebc9SAnirudh Srinivasan 162*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_fixed_factor * 163*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_fixed_factor(struct clk_hw *hw) 164*23c8ebc9SAnirudh Srinivasan { 165*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); 166*23c8ebc9SAnirudh Srinivasan 167*23c8ebc9SAnirudh Srinivasan return container_of(common, struct atlantis_clk_fixed_factor, common); 168*23c8ebc9SAnirudh Srinivasan } 169*23c8ebc9SAnirudh Srinivasan 170*23c8ebc9SAnirudh Srinivasan static u8 atlantis_clk_mux_get_parent(struct clk_hw *hw) 171*23c8ebc9SAnirudh Srinivasan { 172*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); 173*23c8ebc9SAnirudh Srinivasan u32 val; 174*23c8ebc9SAnirudh Srinivasan 175*23c8ebc9SAnirudh Srinivasan regmap_read(mux->common.regmap, mux->config.reg_offset, &val); 176*23c8ebc9SAnirudh Srinivasan val >>= mux->config.shift; 177*23c8ebc9SAnirudh Srinivasan val &= (BIT(mux->config.width) - 1); 178*23c8ebc9SAnirudh Srinivasan 179*23c8ebc9SAnirudh Srinivasan return val; 180*23c8ebc9SAnirudh Srinivasan } 181*23c8ebc9SAnirudh Srinivasan 182*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_mux_set_parent(struct clk_hw *hw, u8 index) 183*23c8ebc9SAnirudh Srinivasan { 184*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); 185*23c8ebc9SAnirudh Srinivasan u32 val = index; 186*23c8ebc9SAnirudh Srinivasan 187*23c8ebc9SAnirudh Srinivasan return regmap_update_bits(mux->common.regmap, mux->config.reg_offset, 188*23c8ebc9SAnirudh Srinivasan (BIT(mux->config.width) - 1) << mux->config.shift, 189*23c8ebc9SAnirudh Srinivasan val << mux->config.shift); 190*23c8ebc9SAnirudh Srinivasan } 191*23c8ebc9SAnirudh Srinivasan 192*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_mux_determine_rate(struct clk_hw *hw, 193*23c8ebc9SAnirudh Srinivasan struct clk_rate_request *req) 194*23c8ebc9SAnirudh Srinivasan { 195*23c8ebc9SAnirudh Srinivasan return clk_mux_determine_rate_flags(hw, req, hw->init->flags); 196*23c8ebc9SAnirudh Srinivasan } 197*23c8ebc9SAnirudh Srinivasan 198*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_mux_ops = { 199*23c8ebc9SAnirudh Srinivasan .get_parent = atlantis_clk_mux_get_parent, 200*23c8ebc9SAnirudh Srinivasan .set_parent = atlantis_clk_mux_set_parent, 201*23c8ebc9SAnirudh Srinivasan .determine_rate = atlantis_clk_mux_determine_rate, 202*23c8ebc9SAnirudh Srinivasan }; 203*23c8ebc9SAnirudh Srinivasan 204*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_endisable(struct clk_hw *hw, int enable) 205*23c8ebc9SAnirudh Srinivasan { 206*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); 207*23c8ebc9SAnirudh Srinivasan 208*23c8ebc9SAnirudh Srinivasan if (enable) 209*23c8ebc9SAnirudh Srinivasan return regmap_set_bits(gate->common.regmap, 210*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 211*23c8ebc9SAnirudh Srinivasan gate->config.enable); 212*23c8ebc9SAnirudh Srinivasan else 213*23c8ebc9SAnirudh Srinivasan return regmap_clear_bits(gate->common.regmap, 214*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 215*23c8ebc9SAnirudh Srinivasan gate->config.enable); 216*23c8ebc9SAnirudh Srinivasan } 217*23c8ebc9SAnirudh Srinivasan 218*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_enable(struct clk_hw *hw) 219*23c8ebc9SAnirudh Srinivasan { 220*23c8ebc9SAnirudh Srinivasan return atlantis_clk_gate_endisable(hw, 1); 221*23c8ebc9SAnirudh Srinivasan } 222*23c8ebc9SAnirudh Srinivasan 223*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_disable(struct clk_hw *hw) 224*23c8ebc9SAnirudh Srinivasan { 225*23c8ebc9SAnirudh Srinivasan atlantis_clk_gate_endisable(hw, 0); 226*23c8ebc9SAnirudh Srinivasan } 227*23c8ebc9SAnirudh Srinivasan 228*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_is_enabled(struct clk_hw *hw) 229*23c8ebc9SAnirudh Srinivasan { 230*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); 231*23c8ebc9SAnirudh Srinivasan 232*23c8ebc9SAnirudh Srinivasan return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); 233*23c8ebc9SAnirudh Srinivasan } 234*23c8ebc9SAnirudh Srinivasan 235*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_gate_ops = { 236*23c8ebc9SAnirudh Srinivasan .enable = atlantis_clk_gate_enable, 237*23c8ebc9SAnirudh Srinivasan .disable = atlantis_clk_gate_disable, 238*23c8ebc9SAnirudh Srinivasan .is_enabled = atlantis_clk_gate_is_enabled, 239*23c8ebc9SAnirudh Srinivasan }; 240*23c8ebc9SAnirudh Srinivasan 241*23c8ebc9SAnirudh Srinivasan static unsigned long atlantis_clk_divider_recalc_rate(struct clk_hw *hw, 242*23c8ebc9SAnirudh Srinivasan unsigned long parent_rate) 243*23c8ebc9SAnirudh Srinivasan { 244*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider *divider = hw_to_atlantis_clk_divider(hw); 245*23c8ebc9SAnirudh Srinivasan u32 val; 246*23c8ebc9SAnirudh Srinivasan 247*23c8ebc9SAnirudh Srinivasan regmap_read(divider->common.regmap, divider->config.reg_offset, &val); 248*23c8ebc9SAnirudh Srinivasan 249*23c8ebc9SAnirudh Srinivasan val >>= divider->config.shift; 250*23c8ebc9SAnirudh Srinivasan val &= ((1 << (divider->config.width)) - 1); 251*23c8ebc9SAnirudh Srinivasan 252*23c8ebc9SAnirudh Srinivasan return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); 253*23c8ebc9SAnirudh Srinivasan } 254*23c8ebc9SAnirudh Srinivasan 255*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_divider_ops = { 256*23c8ebc9SAnirudh Srinivasan .recalc_rate = atlantis_clk_divider_recalc_rate, 257*23c8ebc9SAnirudh Srinivasan }; 258*23c8ebc9SAnirudh Srinivasan 259*23c8ebc9SAnirudh Srinivasan static unsigned long 260*23c8ebc9SAnirudh Srinivasan atlantis_clk_fixed_factor_recalc_rate(struct clk_hw *hw, 261*23c8ebc9SAnirudh Srinivasan unsigned long parent_rate) 262*23c8ebc9SAnirudh Srinivasan { 263*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor *factor = 264*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_fixed_factor(hw); 265*23c8ebc9SAnirudh Srinivasan unsigned long long rate; 266*23c8ebc9SAnirudh Srinivasan 267*23c8ebc9SAnirudh Srinivasan rate = (unsigned long long)parent_rate * factor->config.mult; 268*23c8ebc9SAnirudh Srinivasan do_div(rate, factor->config.div); 269*23c8ebc9SAnirudh Srinivasan 270*23c8ebc9SAnirudh Srinivasan return (unsigned long)rate; 271*23c8ebc9SAnirudh Srinivasan } 272*23c8ebc9SAnirudh Srinivasan 273*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_fixed_factor_ops = { 274*23c8ebc9SAnirudh Srinivasan .recalc_rate = atlantis_clk_fixed_factor_recalc_rate, 275*23c8ebc9SAnirudh Srinivasan }; 276*23c8ebc9SAnirudh Srinivasan 277*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_pll_is_enabled(struct clk_hw *hw) 278*23c8ebc9SAnirudh Srinivasan { 279*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 280*23c8ebc9SAnirudh Srinivasan u32 val, en_val, cg_val; 281*23c8ebc9SAnirudh Srinivasan 282*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 283*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); 284*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); 285*23c8ebc9SAnirudh Srinivasan 286*23c8ebc9SAnirudh Srinivasan /* Check if PLL is powered on, locked, not bypassed and Gate clk is enabled */ 287*23c8ebc9SAnirudh Srinivasan return !!(en_val & PLL_CFG_EN_BIT) && !!(val & PLL_CFG_LOCK_BIT) && 288*23c8ebc9SAnirudh Srinivasan (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && 289*23c8ebc9SAnirudh Srinivasan !(val & PLL_CFG_BYPASS_BIT); 290*23c8ebc9SAnirudh Srinivasan } 291*23c8ebc9SAnirudh Srinivasan 292*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_pll_enable(struct clk_hw *hw) 293*23c8ebc9SAnirudh Srinivasan { 294*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 295*23c8ebc9SAnirudh Srinivasan u32 val, en_val, cg_val; 296*23c8ebc9SAnirudh Srinivasan int ret; 297*23c8ebc9SAnirudh Srinivasan 298*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 299*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); 300*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); 301*23c8ebc9SAnirudh Srinivasan 302*23c8ebc9SAnirudh Srinivasan /* Check if PLL is already enabled, locked, not bypassed and Gate clk is enabled */ 303*23c8ebc9SAnirudh Srinivasan if ((en_val & PLL_CFG_EN_BIT) && (val & PLL_CFG_LOCK_BIT) && 304*23c8ebc9SAnirudh Srinivasan (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && 305*23c8ebc9SAnirudh Srinivasan !(val & PLL_CFG_BYPASS_BIT)) { 306*23c8ebc9SAnirudh Srinivasan return 0; 307*23c8ebc9SAnirudh Srinivasan } 308*23c8ebc9SAnirudh Srinivasan 309*23c8ebc9SAnirudh Srinivasan /* Step 1: Set bypass mode first */ 310*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 311*23c8ebc9SAnirudh Srinivasan PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); 312*23c8ebc9SAnirudh Srinivasan 313*23c8ebc9SAnirudh Srinivasan /* Step 2: Enable PLL (clear then set power bit) */ 314*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 315*23c8ebc9SAnirudh Srinivasan PLL_CFG_EN_BIT, 0); 316*23c8ebc9SAnirudh Srinivasan 317*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 318*23c8ebc9SAnirudh Srinivasan PLL_CFG_EN_BIT, PLL_CFG_EN_BIT); 319*23c8ebc9SAnirudh Srinivasan 320*23c8ebc9SAnirudh Srinivasan /* Step 3: Wait for PLL lock */ 321*23c8ebc9SAnirudh Srinivasan ret = regmap_read_poll_timeout(pll->common.regmap, 322*23c8ebc9SAnirudh Srinivasan pll->config.reg_offset, val, 323*23c8ebc9SAnirudh Srinivasan val & PLL_CFG_LOCK_BIT, 324*23c8ebc9SAnirudh Srinivasan PLL_BYPASS_WAIT_US, PLL_LOCK_TIMEOUT_US); 325*23c8ebc9SAnirudh Srinivasan if (ret) { 326*23c8ebc9SAnirudh Srinivasan pr_err("PLL failed to lock within timeout\n"); 327*23c8ebc9SAnirudh Srinivasan return ret; 328*23c8ebc9SAnirudh Srinivasan } 329*23c8ebc9SAnirudh Srinivasan 330*23c8ebc9SAnirudh Srinivasan /* Step 4: Switch from bypass to PLL output */ 331*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 332*23c8ebc9SAnirudh Srinivasan PLL_CFG_BYPASS_BIT, 0); 333*23c8ebc9SAnirudh Srinivasan 334*23c8ebc9SAnirudh Srinivasan /* Enable Gate clk at PLL Output */ 335*23c8ebc9SAnirudh Srinivasan return regmap_update_bits(pll->common.regmap, pll->config.cg_reg_offset, 336*23c8ebc9SAnirudh Srinivasan pll->config.cg_reg_enable, 337*23c8ebc9SAnirudh Srinivasan pll->config.cg_reg_enable); 338*23c8ebc9SAnirudh Srinivasan } 339*23c8ebc9SAnirudh Srinivasan 340*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_pll_disable(struct clk_hw *hw) 341*23c8ebc9SAnirudh Srinivasan { 342*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 343*23c8ebc9SAnirudh Srinivasan 344*23c8ebc9SAnirudh Srinivasan /* Step 1: Switch to bypass mode before disabling */ 345*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.reg_offset, 346*23c8ebc9SAnirudh Srinivasan PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); 347*23c8ebc9SAnirudh Srinivasan /* Step 2: Power down PLL */ 348*23c8ebc9SAnirudh Srinivasan regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, 349*23c8ebc9SAnirudh Srinivasan PLL_CFG_EN_BIT, 0); 350*23c8ebc9SAnirudh Srinivasan } 351*23c8ebc9SAnirudh Srinivasan 352*23c8ebc9SAnirudh Srinivasan static unsigned long atlantis_clk_pll_recalc_rate(struct clk_hw *hw, 353*23c8ebc9SAnirudh Srinivasan unsigned long parent_rate) 354*23c8ebc9SAnirudh Srinivasan { 355*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); 356*23c8ebc9SAnirudh Srinivasan 357*23c8ebc9SAnirudh Srinivasan u32 val, refdiv, fbdiv, postdiv1, postdiv2; 358*23c8ebc9SAnirudh Srinivasan u64 fout; 359*23c8ebc9SAnirudh Srinivasan 360*23c8ebc9SAnirudh Srinivasan regmap_read(pll->common.regmap, pll->config.reg_offset, &val); 361*23c8ebc9SAnirudh Srinivasan 362*23c8ebc9SAnirudh Srinivasan if (val & PLL_CFG_BYPASS_BIT) 363*23c8ebc9SAnirudh Srinivasan return parent_rate; 364*23c8ebc9SAnirudh Srinivasan 365*23c8ebc9SAnirudh Srinivasan refdiv = FIELD_GET(PLL_CFG_REFDIV_MASK, val); 366*23c8ebc9SAnirudh Srinivasan fbdiv = FIELD_GET(PLL_CFG_FBDIV_MASK, val); 367*23c8ebc9SAnirudh Srinivasan postdiv1 = FIELD_GET(PLL_CFG_POSTDIV1_MASK, val); 368*23c8ebc9SAnirudh Srinivasan postdiv2 = FIELD_GET(PLL_CFG_POSTDIV2_MASK, val); 369*23c8ebc9SAnirudh Srinivasan 370*23c8ebc9SAnirudh Srinivasan if (!refdiv) 371*23c8ebc9SAnirudh Srinivasan refdiv = 1; 372*23c8ebc9SAnirudh Srinivasan if (!postdiv1) 373*23c8ebc9SAnirudh Srinivasan postdiv1 = 1; 374*23c8ebc9SAnirudh Srinivasan if (!postdiv2) 375*23c8ebc9SAnirudh Srinivasan postdiv2 = 1; 376*23c8ebc9SAnirudh Srinivasan if (!fbdiv) 377*23c8ebc9SAnirudh Srinivasan return 0; 378*23c8ebc9SAnirudh Srinivasan 379*23c8ebc9SAnirudh Srinivasan fout = div64_u64((u64)parent_rate * fbdiv, 380*23c8ebc9SAnirudh Srinivasan refdiv * postdiv1 * postdiv2); 381*23c8ebc9SAnirudh Srinivasan 382*23c8ebc9SAnirudh Srinivasan return fout; 383*23c8ebc9SAnirudh Srinivasan } 384*23c8ebc9SAnirudh Srinivasan 385*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_pll_ops = { 386*23c8ebc9SAnirudh Srinivasan .enable = atlantis_clk_pll_enable, 387*23c8ebc9SAnirudh Srinivasan .disable = atlantis_clk_pll_disable, 388*23c8ebc9SAnirudh Srinivasan .recalc_rate = atlantis_clk_pll_recalc_rate, 389*23c8ebc9SAnirudh Srinivasan .is_enabled = atlantis_clk_pll_is_enabled, 390*23c8ebc9SAnirudh Srinivasan }; 391*23c8ebc9SAnirudh Srinivasan 392*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_shared_enable(struct clk_hw *hw) 393*23c8ebc9SAnirudh Srinivasan { 394*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared *gate = 395*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(hw); 396*23c8ebc9SAnirudh Srinivasan bool need_enable; 397*23c8ebc9SAnirudh Srinivasan 398*23c8ebc9SAnirudh Srinivasan scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 399*23c8ebc9SAnirudh Srinivasan { 400*23c8ebc9SAnirudh Srinivasan need_enable = (*gate->config.share_count)++ == 0; 401*23c8ebc9SAnirudh Srinivasan if (need_enable) { 402*23c8ebc9SAnirudh Srinivasan regmap_set_bits(gate->common.regmap, 403*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 404*23c8ebc9SAnirudh Srinivasan gate->config.enable); 405*23c8ebc9SAnirudh Srinivasan } 406*23c8ebc9SAnirudh Srinivasan } 407*23c8ebc9SAnirudh Srinivasan 408*23c8ebc9SAnirudh Srinivasan if (need_enable) { 409*23c8ebc9SAnirudh Srinivasan if (!regmap_test_bits(gate->common.regmap, 410*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 411*23c8ebc9SAnirudh Srinivasan gate->config.enable)) { 412*23c8ebc9SAnirudh Srinivasan pr_warn("%s: gate enable %d failed to enable\n", 413*23c8ebc9SAnirudh Srinivasan clk_hw_get_name(hw), gate->config.enable); 414*23c8ebc9SAnirudh Srinivasan return -EIO; 415*23c8ebc9SAnirudh Srinivasan } 416*23c8ebc9SAnirudh Srinivasan } 417*23c8ebc9SAnirudh Srinivasan 418*23c8ebc9SAnirudh Srinivasan return 0; 419*23c8ebc9SAnirudh Srinivasan } 420*23c8ebc9SAnirudh Srinivasan 421*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_shared_disable(struct clk_hw *hw) 422*23c8ebc9SAnirudh Srinivasan { 423*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared *gate = 424*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(hw); 425*23c8ebc9SAnirudh Srinivasan 426*23c8ebc9SAnirudh Srinivasan scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 427*23c8ebc9SAnirudh Srinivasan { 428*23c8ebc9SAnirudh Srinivasan if (WARN_ON(*gate->config.share_count == 0)) 429*23c8ebc9SAnirudh Srinivasan return; 430*23c8ebc9SAnirudh Srinivasan if (--(*gate->config.share_count) > 0) 431*23c8ebc9SAnirudh Srinivasan return; 432*23c8ebc9SAnirudh Srinivasan 433*23c8ebc9SAnirudh Srinivasan regmap_clear_bits(gate->common.regmap, 434*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 435*23c8ebc9SAnirudh Srinivasan gate->config.enable); 436*23c8ebc9SAnirudh Srinivasan } 437*23c8ebc9SAnirudh Srinivasan } 438*23c8ebc9SAnirudh Srinivasan 439*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_shared_is_enabled(struct clk_hw *hw) 440*23c8ebc9SAnirudh Srinivasan { 441*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared *gate = 442*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(hw); 443*23c8ebc9SAnirudh Srinivasan 444*23c8ebc9SAnirudh Srinivasan return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); 445*23c8ebc9SAnirudh Srinivasan } 446*23c8ebc9SAnirudh Srinivasan 447*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_shared_disable_unused(struct clk_hw *hw) 448*23c8ebc9SAnirudh Srinivasan { 449*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared *gate = 450*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(hw); 451*23c8ebc9SAnirudh Srinivasan 452*23c8ebc9SAnirudh Srinivasan scoped_guard(spinlock_irqsave, gate->config.refcount_lock) 453*23c8ebc9SAnirudh Srinivasan { 454*23c8ebc9SAnirudh Srinivasan if (*gate->config.share_count == 0) 455*23c8ebc9SAnirudh Srinivasan regmap_clear_bits(gate->common.regmap, 456*23c8ebc9SAnirudh Srinivasan gate->config.reg_offset, 457*23c8ebc9SAnirudh Srinivasan gate->config.enable); 458*23c8ebc9SAnirudh Srinivasan } 459*23c8ebc9SAnirudh Srinivasan } 460*23c8ebc9SAnirudh Srinivasan 461*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_gate_shared_ops = { 462*23c8ebc9SAnirudh Srinivasan .enable = atlantis_clk_gate_shared_enable, 463*23c8ebc9SAnirudh Srinivasan .disable = atlantis_clk_gate_shared_disable, 464*23c8ebc9SAnirudh Srinivasan .disable_unused = atlantis_clk_gate_shared_disable_unused, 465*23c8ebc9SAnirudh Srinivasan .is_enabled = atlantis_clk_gate_shared_is_enabled, 466*23c8ebc9SAnirudh Srinivasan }; 467*23c8ebc9SAnirudh Srinivasan 468*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, _cg_reg_offset, \ 469*23c8ebc9SAnirudh Srinivasan _cg_reg_enable) \ 470*23c8ebc9SAnirudh Srinivasan { \ 471*23c8ebc9SAnirudh Srinivasan .reg_offset = (_reg_offset), \ 472*23c8ebc9SAnirudh Srinivasan .en_reg_offset = (_en_reg_offset), \ 473*23c8ebc9SAnirudh Srinivasan .cg_reg_offset = (_cg_reg_offset), \ 474*23c8ebc9SAnirudh Srinivasan .cg_reg_enable = (_cg_reg_enable), \ 475*23c8ebc9SAnirudh Srinivasan } 476*23c8ebc9SAnirudh Srinivasan 477*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_PLL_DEFINE(_clkid, _name, _parent, _reg_offset, \ 478*23c8ebc9SAnirudh Srinivasan _en_reg_offset, _cg_reg_offset, _cg_reg_enable, \ 479*23c8ebc9SAnirudh Srinivasan _flags) \ 480*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_pll _name = { \ 481*23c8ebc9SAnirudh Srinivasan .config = ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, \ 482*23c8ebc9SAnirudh Srinivasan _cg_reg_offset, _cg_reg_enable), \ 483*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 484*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_PARENTS_DATA( \ 485*23c8ebc9SAnirudh Srinivasan #_name, _parent, &atlantis_clk_pll_ops, \ 486*23c8ebc9SAnirudh Srinivasan _flags) }, \ 487*23c8ebc9SAnirudh Srinivasan } 488*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset) \ 489*23c8ebc9SAnirudh Srinivasan { \ 490*23c8ebc9SAnirudh Srinivasan .shift = _shift, .width = _width, .reg_offset = _reg_offset \ 491*23c8ebc9SAnirudh Srinivasan } 492*23c8ebc9SAnirudh Srinivasan 493*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_MUX_DEFINE(_clkid, _name, _parents, _reg_offset, _shift, \ 494*23c8ebc9SAnirudh Srinivasan _width, _flags) \ 495*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_mux _name = { \ 496*23c8ebc9SAnirudh Srinivasan .config = ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset), \ 497*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 498*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_PARENTS_DATA( \ 499*23c8ebc9SAnirudh Srinivasan #_name, _parents, &atlantis_clk_mux_ops, \ 500*23c8ebc9SAnirudh Srinivasan _flags) } \ 501*23c8ebc9SAnirudh Srinivasan } 502*23c8ebc9SAnirudh Srinivasan 503*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_DIVIDER_CONFIG(_shift, _width, _flags, _reg_offset) \ 504*23c8ebc9SAnirudh Srinivasan { \ 505*23c8ebc9SAnirudh Srinivasan .shift = _shift, .width = _width, .flags = _flags, \ 506*23c8ebc9SAnirudh Srinivasan .reg_offset = _reg_offset \ 507*23c8ebc9SAnirudh Srinivasan } 508*23c8ebc9SAnirudh Srinivasan 509*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_DIVIDER_DEFINE(_clkid, _name, _parent, _reg_offset, _shift, \ 510*23c8ebc9SAnirudh Srinivasan _width, _divflags, _flags) \ 511*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_divider _name = { \ 512*23c8ebc9SAnirudh Srinivasan .config = ATLANTIS_DIVIDER_CONFIG(_shift, _width, _divflags, \ 513*23c8ebc9SAnirudh Srinivasan _reg_offset), \ 514*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 515*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_HW( \ 516*23c8ebc9SAnirudh Srinivasan #_name, &_parent.common.hw, \ 517*23c8ebc9SAnirudh Srinivasan &atlantis_clk_divider_ops, _flags) } \ 518*23c8ebc9SAnirudh Srinivasan } 519*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_CONFIG(_enable, _reg_offset) \ 520*23c8ebc9SAnirudh Srinivasan { \ 521*23c8ebc9SAnirudh Srinivasan .enable = _enable, .reg_offset = _reg_offset \ 522*23c8ebc9SAnirudh Srinivasan } 523*23c8ebc9SAnirudh Srinivasan 524*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_DEFINE(_clkid, _name, _parent, _reg_offset, _enable, \ 525*23c8ebc9SAnirudh Srinivasan _flags) \ 526*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_gate _name = { \ 527*23c8ebc9SAnirudh Srinivasan .config = ATLANTIS_GATE_CONFIG(_enable, _reg_offset), \ 528*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 529*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_HW( \ 530*23c8ebc9SAnirudh Srinivasan #_name, &_parent.common.hw, \ 531*23c8ebc9SAnirudh Srinivasan &atlantis_clk_gate_ops, _flags) } \ 532*23c8ebc9SAnirudh Srinivasan } 533*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, _share_count) \ 534*23c8ebc9SAnirudh Srinivasan { \ 535*23c8ebc9SAnirudh Srinivasan .reg_offset = _reg_offset, .enable = _enable, \ 536*23c8ebc9SAnirudh Srinivasan .share_count = _share_count, .refcount_lock = &refcount_lock \ 537*23c8ebc9SAnirudh Srinivasan } 538*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_SHARED_DEFINE(_clkid, _name, _parent, _reg_offset, \ 539*23c8ebc9SAnirudh Srinivasan _enable, _share_count, _flags) \ 540*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_gate_shared _name = { \ 541*23c8ebc9SAnirudh Srinivasan .config = ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, \ 542*23c8ebc9SAnirudh Srinivasan _share_count), \ 543*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 544*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_HW( \ 545*23c8ebc9SAnirudh Srinivasan #_name, &_parent.common.hw, \ 546*23c8ebc9SAnirudh Srinivasan &atlantis_clk_gate_shared_ops, _flags) } \ 547*23c8ebc9SAnirudh Srinivasan } 548*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_FIXED_FACTOR_DEFINE(_clkid, _name, _parent, _mult, _div, \ 549*23c8ebc9SAnirudh Srinivasan _flags) \ 550*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_fixed_factor _name = { \ 551*23c8ebc9SAnirudh Srinivasan .config = { .mult = _mult, .div = _div }, \ 552*23c8ebc9SAnirudh Srinivasan .common = { .clkid = _clkid, \ 553*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_HW( \ 554*23c8ebc9SAnirudh Srinivasan #_name, &_parent.common.hw, \ 555*23c8ebc9SAnirudh Srinivasan &atlantis_clk_fixed_factor_ops, _flags) } \ 556*23c8ebc9SAnirudh Srinivasan } 557*23c8ebc9SAnirudh Srinivasan 558*23c8ebc9SAnirudh Srinivasan static DEFINE_SPINLOCK(refcount_lock); /* Lock for refcount value accesses */ 559*23c8ebc9SAnirudh Srinivasan 560*23c8ebc9SAnirudh Srinivasan static const struct regmap_config atlantis_prcm_regmap_config = { 561*23c8ebc9SAnirudh Srinivasan .reg_bits = 32, 562*23c8ebc9SAnirudh Srinivasan .reg_stride = 4, 563*23c8ebc9SAnirudh Srinivasan .val_bits = 32, 564*23c8ebc9SAnirudh Srinivasan .max_register = 0xFFFC, 565*23c8ebc9SAnirudh Srinivasan .cache_type = REGCACHE_NONE, 566*23c8ebc9SAnirudh Srinivasan }; 567*23c8ebc9SAnirudh Srinivasan 568*23c8ebc9SAnirudh Srinivasan struct atlantis_prcm_data { 569*23c8ebc9SAnirudh Srinivasan struct clk_hw **hws; 570*23c8ebc9SAnirudh Srinivasan size_t num; 571*23c8ebc9SAnirudh Srinivasan const char *reset_name; 572*23c8ebc9SAnirudh Srinivasan }; 573*23c8ebc9SAnirudh Srinivasan 574*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data osc_24m_clk[] = { 575*23c8ebc9SAnirudh Srinivasan { .index = 0 }, 576*23c8ebc9SAnirudh Srinivasan }; 577*23c8ebc9SAnirudh Srinivasan 578*23c8ebc9SAnirudh Srinivasan ATLANTIS_PLL_DEFINE(CLK_RCPU_PLL, rcpu_pll_clk, osc_24m_clk, PLL_RCPU_CFG_REG, 579*23c8ebc9SAnirudh Srinivasan PLL_RCPU_EN_REG, BUS_CG_REG, 0, /* No Gate Clk at Output */ 580*23c8ebc9SAnirudh Srinivasan CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); 581*23c8ebc9SAnirudh Srinivasan 582*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data rcpu_root_parents[] = { 583*23c8ebc9SAnirudh Srinivasan { .index = 0 }, 584*23c8ebc9SAnirudh Srinivasan { .hw = &rcpu_pll_clk.common.hw }, 585*23c8ebc9SAnirudh Srinivasan }; 586*23c8ebc9SAnirudh Srinivasan 587*23c8ebc9SAnirudh Srinivasan ATLANTIS_MUX_DEFINE(CLK_RCPU_ROOT, rcpu_root_clk, rcpu_root_parents, 588*23c8ebc9SAnirudh Srinivasan RCPU_DIV_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT); 589*23c8ebc9SAnirudh Srinivasan 590*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV2, rcpu_div2_clk, rcpu_root_clk, 591*23c8ebc9SAnirudh Srinivasan RCPU_DIV_CFG_REG, 2, 4, 0, 0); 592*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV4, rcpu_div4_clk, rcpu_root_clk, 593*23c8ebc9SAnirudh Srinivasan RCPU_DIV_CFG_REG, 7, 4, 0, 0); 594*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_RTC, rcpu_rtc_clk, rcpu_div4_clk, 595*23c8ebc9SAnirudh Srinivasan RCPU_DIV_CFG_REG, 12, 6, 0, 0); 596*23c8ebc9SAnirudh Srinivasan 597*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SMNDMA0_ACLK, rcpu_dma0_clk, rcpu_div2_clk, 598*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(0), 0); 599*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SMNDMA1_ACLK, rcpu_dma1_clk, rcpu_div2_clk, 600*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(1), 0); 601*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_WDT0_PCLK, sl_wdt0_pclk, rcpu_div4_clk, 602*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(2), 0); 603*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_WDT1_PCLK, sl_wdt1_pclk, rcpu_div4_clk, 604*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(3), 0); 605*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_TIMER_PCLK, sl_timer_pclk, rcpu_div4_clk, 606*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(4), 0); 607*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_PVTC_PCLK, sl_pvtc_pclk, rcpu_div4_clk, 608*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(12), 0); 609*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_PMU_PCLK, sl_pmu_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, 610*23c8ebc9SAnirudh Srinivasan BIT(13), 0); 611*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_MAILBOX_HCLK, rcpu_ipc_clk, rcpu_div2_clk, 612*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(14), 0); 613*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_SPACC_HCLK, sec_spacc_hclk, rcpu_div2_clk, 614*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(26), 0); 615*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_OTP_HCLK, sec_otp_hclk, rcpu_div2_clk, 616*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(28), 0); 617*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_TRNG_PCLK, sec_trng_pclk, rcpu_div4_clk, 618*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(29), 0); 619*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_CRC_HCLK, sec_crc_hclk, rcpu_div2_clk, 620*23c8ebc9SAnirudh Srinivasan RCPU_BLK_CG_REG, BIT(30), 0); 621*23c8ebc9SAnirudh Srinivasan 622*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_HCLK, rcpu_smn_hclk, rcpu_div2_clk, 1, 1, 623*23c8ebc9SAnirudh Srinivasan 0); 624*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_AHB0_HCLK, rcpu_ahb0_hclk, rcpu_div2_clk, 1, 1, 625*23c8ebc9SAnirudh Srinivasan 0); 626*23c8ebc9SAnirudh Srinivasan 627*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_PCLK, rcpu_smn_pclk, rcpu_div4_clk, 1, 1, 628*23c8ebc9SAnirudh Srinivasan 0); 629*23c8ebc9SAnirudh Srinivasan 630*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_CLK, rcpu_smn_clk, rcpu_root_clk, 1, 1, 0); 631*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SCRATCHPAD_CLK, rcpu_scratchpad_aclk, 632*23c8ebc9SAnirudh Srinivasan rcpu_root_clk, 1, 1, 0); 633*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_CORE_CLK, rcpu_core_clk, rcpu_root_clk, 1, 634*23c8ebc9SAnirudh Srinivasan 1, 0); 635*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_ROM_CLK, rcpu_rom_aclk, rcpu_root_clk, 1, 636*23c8ebc9SAnirudh Srinivasan 1, 0); 637*23c8ebc9SAnirudh Srinivasan 638*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_fixed_factor 639*23c8ebc9SAnirudh Srinivasan otp_load_clk = { .config = { .mult = 1, .div = 1 }, 640*23c8ebc9SAnirudh Srinivasan .common = { 641*23c8ebc9SAnirudh Srinivasan .clkid = CLK_OTP_LOAD_CLK, 642*23c8ebc9SAnirudh Srinivasan .hw.init = CLK_HW_INIT_PARENTS_DATA( 643*23c8ebc9SAnirudh Srinivasan "otp_load_clk", osc_24m_clk, 644*23c8ebc9SAnirudh Srinivasan &atlantis_clk_fixed_factor_ops, 645*23c8ebc9SAnirudh Srinivasan CLK_SET_RATE_NO_REPARENT), 646*23c8ebc9SAnirudh Srinivasan } }; 647*23c8ebc9SAnirudh Srinivasan 648*23c8ebc9SAnirudh Srinivasan ATLANTIS_PLL_DEFINE(CLK_NOC_PLL, nocc_pll_clk, osc_24m_clk, PLL_NOCC_CFG_REG, 649*23c8ebc9SAnirudh Srinivasan PLL_NOCC_EN_REG, BUS_CG_REG, BIT(0), 650*23c8ebc9SAnirudh Srinivasan CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); 651*23c8ebc9SAnirudh Srinivasan 652*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data nocc_mux_parents[] = { 653*23c8ebc9SAnirudh Srinivasan { .index = 0 }, 654*23c8ebc9SAnirudh Srinivasan { .hw = &nocc_pll_clk.common.hw }, 655*23c8ebc9SAnirudh Srinivasan }; 656*23c8ebc9SAnirudh Srinivasan 657*23c8ebc9SAnirudh Srinivasan ATLANTIS_MUX_DEFINE(CLK_NOCC_CLK, nocc_clk, nocc_mux_parents, NOCC_CLK_CFG_REG, 658*23c8ebc9SAnirudh Srinivasan 0, 1, CLK_SET_RATE_NO_REPARENT); 659*23c8ebc9SAnirudh Srinivasan 660*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV2, nocc_div2_clk, nocc_clk, 661*23c8ebc9SAnirudh Srinivasan NOCC_CLK_CFG_REG, 1, 4, 0, 0); 662*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV4, nocc_div4_clk, nocc_clk, 663*23c8ebc9SAnirudh Srinivasan NOCC_CLK_CFG_REG, 5, 4, 0, 0); 664*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_RTC, nocc_rtc_clk, nocc_div4_clk, 665*23c8ebc9SAnirudh Srinivasan NOCC_CLK_CFG_REG, 9, 6, 0, 0); 666*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_CAN, nocc_can_clk, nocc_clk, NOCC_CLK_CFG_REG, 667*23c8ebc9SAnirudh Srinivasan 15, 4, 0, 0); 668*23c8ebc9SAnirudh Srinivasan 669*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_qspi; 670*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_SCLK, lsio_qspi_sclk, nocc_clk, 671*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); 672*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_HCLK, lsio_qspi_hclk, nocc_div2_clk, 673*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); 674*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C0_PCLK, lsio_i2c0_pclk, nocc_div4_clk, 675*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(1), 0); 676*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C1_PCLK, lsio_i2c1_pclk, nocc_div4_clk, 677*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(2), 0); 678*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C2_PCLK, lsio_i2c2_pclk, nocc_div4_clk, 679*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(3), 0); 680*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C3_PCLK, lsio_i2c3_pclk, nocc_div4_clk, 681*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(4), 0); 682*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C4_PCLK, lsio_i2c4_pclk, nocc_div4_clk, 683*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(5), 0); 684*23c8ebc9SAnirudh Srinivasan 685*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART0_PCLK, lsio_uart0_pclk, nocc_div4_clk, 686*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(6), 0); 687*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART1_PCLK, lsio_uart1_pclk, nocc_div4_clk, 688*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(7), 0); 689*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART2_PCLK, lsio_uart2_pclk, nocc_div4_clk, 690*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(8), 0); 691*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART3_PCLK, lsio_uart3_pclk, nocc_div4_clk, 692*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(9), 0); 693*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART4_PCLK, lsio_uart4_pclk, nocc_div4_clk, 694*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(10), 0); 695*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI0_PCLK, lsio_spi0_pclk, nocc_div4_clk, 696*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(11), 0); 697*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI1_PCLK, lsio_spi1_pclk, nocc_div4_clk, 698*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(12), 0); 699*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI2_PCLK, lsio_spi2_pclk, nocc_div4_clk, 700*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(13), 0); 701*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI3_PCLK, lsio_spi3_pclk, nocc_div4_clk, 702*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(14), 0); 703*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_GPIO_PCLK, lsio_gpio_pclk, nocc_div4_clk, 704*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(15), 0); 705*23c8ebc9SAnirudh Srinivasan 706*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_can0; 707*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_HCLK, lsio_can0_hclk, nocc_div2_clk, 708*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); 709*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_CLK, lsio_can0_clk, nocc_can_clk, 710*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); 711*23c8ebc9SAnirudh Srinivasan 712*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_can1; 713*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_HCLK, lsio_can1_hclk, nocc_div2_clk, 714*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); 715*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_CLK, lsio_can1_clk, nocc_can_clk, 716*23c8ebc9SAnirudh Srinivasan LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); 717*23c8ebc9SAnirudh Srinivasan 718*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN0_TIMER_CLK, lsio_can0_timer_clk, 719*23c8ebc9SAnirudh Srinivasan nocc_rtc_clk, 1, 1, 0); 720*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN1_TIMER_CLK, lsio_can1_timer_clk, 721*23c8ebc9SAnirudh Srinivasan nocc_rtc_clk, 1, 1, 0); 722*23c8ebc9SAnirudh Srinivasan 723*23c8ebc9SAnirudh Srinivasan static struct clk_hw *atlantis_rcpu_clks[] = { 724*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_PLL] = &rcpu_pll_clk.common.hw, 725*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_ROOT] = &rcpu_root_clk.common.hw, 726*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_DIV2] = &rcpu_div2_clk.common.hw, 727*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_DIV4] = &rcpu_div4_clk.common.hw, 728*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_RTC] = &rcpu_rtc_clk.common.hw, 729*23c8ebc9SAnirudh Srinivasan [CLK_SMNDMA0_ACLK] = &rcpu_dma0_clk.common.hw, 730*23c8ebc9SAnirudh Srinivasan [CLK_SMNDMA1_ACLK] = &rcpu_dma1_clk.common.hw, 731*23c8ebc9SAnirudh Srinivasan [CLK_WDT0_PCLK] = &sl_wdt0_pclk.common.hw, 732*23c8ebc9SAnirudh Srinivasan [CLK_WDT1_PCLK] = &sl_wdt1_pclk.common.hw, 733*23c8ebc9SAnirudh Srinivasan [CLK_TIMER_PCLK] = &sl_timer_pclk.common.hw, 734*23c8ebc9SAnirudh Srinivasan [CLK_PVTC_PCLK] = &sl_pvtc_pclk.common.hw, 735*23c8ebc9SAnirudh Srinivasan [CLK_PMU_PCLK] = &sl_pmu_pclk.common.hw, 736*23c8ebc9SAnirudh Srinivasan [CLK_MAILBOX_HCLK] = &rcpu_ipc_clk.common.hw, 737*23c8ebc9SAnirudh Srinivasan [CLK_SEC_SPACC_HCLK] = &sec_spacc_hclk.common.hw, 738*23c8ebc9SAnirudh Srinivasan [CLK_SEC_OTP_HCLK] = &sec_otp_hclk.common.hw, 739*23c8ebc9SAnirudh Srinivasan [CLK_TRNG_PCLK] = &sec_trng_pclk.common.hw, 740*23c8ebc9SAnirudh Srinivasan [CLK_SEC_CRC_HCLK] = &sec_crc_hclk.common.hw, 741*23c8ebc9SAnirudh Srinivasan [CLK_SMN_HCLK] = &rcpu_smn_hclk.common.hw, 742*23c8ebc9SAnirudh Srinivasan [CLK_AHB0_HCLK] = &rcpu_ahb0_hclk.common.hw, 743*23c8ebc9SAnirudh Srinivasan [CLK_SMN_PCLK] = &rcpu_smn_pclk.common.hw, 744*23c8ebc9SAnirudh Srinivasan [CLK_SMN_CLK] = &rcpu_smn_clk.common.hw, 745*23c8ebc9SAnirudh Srinivasan [CLK_SCRATCHPAD_CLK] = &rcpu_scratchpad_aclk.common.hw, 746*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_CORE_CLK] = &rcpu_core_clk.common.hw, 747*23c8ebc9SAnirudh Srinivasan [CLK_RCPU_ROM_CLK] = &rcpu_rom_aclk.common.hw, 748*23c8ebc9SAnirudh Srinivasan [CLK_OTP_LOAD_CLK] = &otp_load_clk.common.hw, 749*23c8ebc9SAnirudh Srinivasan [CLK_NOC_PLL] = &nocc_pll_clk.common.hw, 750*23c8ebc9SAnirudh Srinivasan [CLK_NOCC_CLK] = &nocc_clk.common.hw, 751*23c8ebc9SAnirudh Srinivasan [CLK_NOCC_DIV2] = &nocc_div2_clk.common.hw, 752*23c8ebc9SAnirudh Srinivasan [CLK_NOCC_DIV4] = &nocc_div4_clk.common.hw, 753*23c8ebc9SAnirudh Srinivasan [CLK_NOCC_RTC] = &nocc_rtc_clk.common.hw, 754*23c8ebc9SAnirudh Srinivasan [CLK_NOCC_CAN] = &nocc_can_clk.common.hw, 755*23c8ebc9SAnirudh Srinivasan [CLK_QSPI_SCLK] = &lsio_qspi_sclk.common.hw, 756*23c8ebc9SAnirudh Srinivasan [CLK_QSPI_HCLK] = &lsio_qspi_hclk.common.hw, 757*23c8ebc9SAnirudh Srinivasan [CLK_I2C0_PCLK] = &lsio_i2c0_pclk.common.hw, 758*23c8ebc9SAnirudh Srinivasan [CLK_I2C1_PCLK] = &lsio_i2c1_pclk.common.hw, 759*23c8ebc9SAnirudh Srinivasan [CLK_I2C2_PCLK] = &lsio_i2c2_pclk.common.hw, 760*23c8ebc9SAnirudh Srinivasan [CLK_I2C3_PCLK] = &lsio_i2c3_pclk.common.hw, 761*23c8ebc9SAnirudh Srinivasan [CLK_I2C4_PCLK] = &lsio_i2c4_pclk.common.hw, 762*23c8ebc9SAnirudh Srinivasan [CLK_UART0_PCLK] = &lsio_uart0_pclk.common.hw, 763*23c8ebc9SAnirudh Srinivasan [CLK_UART1_PCLK] = &lsio_uart1_pclk.common.hw, 764*23c8ebc9SAnirudh Srinivasan [CLK_UART2_PCLK] = &lsio_uart2_pclk.common.hw, 765*23c8ebc9SAnirudh Srinivasan [CLK_UART3_PCLK] = &lsio_uart3_pclk.common.hw, 766*23c8ebc9SAnirudh Srinivasan [CLK_UART4_PCLK] = &lsio_uart4_pclk.common.hw, 767*23c8ebc9SAnirudh Srinivasan [CLK_SPI0_PCLK] = &lsio_spi0_pclk.common.hw, 768*23c8ebc9SAnirudh Srinivasan [CLK_SPI1_PCLK] = &lsio_spi1_pclk.common.hw, 769*23c8ebc9SAnirudh Srinivasan [CLK_SPI2_PCLK] = &lsio_spi2_pclk.common.hw, 770*23c8ebc9SAnirudh Srinivasan [CLK_SPI3_PCLK] = &lsio_spi3_pclk.common.hw, 771*23c8ebc9SAnirudh Srinivasan [CLK_GPIO_PCLK] = &lsio_gpio_pclk.common.hw, 772*23c8ebc9SAnirudh Srinivasan [CLK_CAN0_HCLK] = &lsio_can0_hclk.common.hw, 773*23c8ebc9SAnirudh Srinivasan [CLK_CAN0_CLK] = &lsio_can0_clk.common.hw, 774*23c8ebc9SAnirudh Srinivasan [CLK_CAN1_HCLK] = &lsio_can1_hclk.common.hw, 775*23c8ebc9SAnirudh Srinivasan [CLK_CAN1_CLK] = &lsio_can1_clk.common.hw, 776*23c8ebc9SAnirudh Srinivasan [CLK_CAN0_TIMER_CLK] = &lsio_can0_timer_clk.common.hw, 777*23c8ebc9SAnirudh Srinivasan [CLK_CAN1_TIMER_CLK] = &lsio_can1_timer_clk.common.hw, 778*23c8ebc9SAnirudh Srinivasan }; 779*23c8ebc9SAnirudh Srinivasan 780*23c8ebc9SAnirudh Srinivasan static const struct atlantis_prcm_data atlantis_prcm_rcpu_data = { 781*23c8ebc9SAnirudh Srinivasan .hws = atlantis_rcpu_clks, 782*23c8ebc9SAnirudh Srinivasan .num = ARRAY_SIZE(atlantis_rcpu_clks), 783*23c8ebc9SAnirudh Srinivasan .reset_name = "rcpu-reset" 784*23c8ebc9SAnirudh Srinivasan }; 785*23c8ebc9SAnirudh Srinivasan 786*23c8ebc9SAnirudh Srinivasan static int atlantis_prcm_clocks_register(struct device *dev, 787*23c8ebc9SAnirudh Srinivasan struct regmap *regmap, 788*23c8ebc9SAnirudh Srinivasan const struct atlantis_prcm_data *data) 789*23c8ebc9SAnirudh Srinivasan { 790*23c8ebc9SAnirudh Srinivasan struct clk_hw_onecell_data *clk_data; 791*23c8ebc9SAnirudh Srinivasan int i, ret; 792*23c8ebc9SAnirudh Srinivasan size_t num_clks = data->num; 793*23c8ebc9SAnirudh Srinivasan 794*23c8ebc9SAnirudh Srinivasan clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num), 795*23c8ebc9SAnirudh Srinivasan GFP_KERNEL); 796*23c8ebc9SAnirudh Srinivasan if (!clk_data) 797*23c8ebc9SAnirudh Srinivasan return -ENOMEM; 798*23c8ebc9SAnirudh Srinivasan 799*23c8ebc9SAnirudh Srinivasan for (i = 0; i < data->num; i++) { 800*23c8ebc9SAnirudh Srinivasan struct clk_hw *hw = data->hws[i]; 801*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common *common = 802*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_common(hw); 803*23c8ebc9SAnirudh Srinivasan common->regmap = regmap; 804*23c8ebc9SAnirudh Srinivasan 805*23c8ebc9SAnirudh Srinivasan ret = devm_clk_hw_register(dev, hw); 806*23c8ebc9SAnirudh Srinivasan if (ret) 807*23c8ebc9SAnirudh Srinivasan return ret; 808*23c8ebc9SAnirudh Srinivasan 809*23c8ebc9SAnirudh Srinivasan clk_data->hws[common->clkid] = hw; 810*23c8ebc9SAnirudh Srinivasan } 811*23c8ebc9SAnirudh Srinivasan 812*23c8ebc9SAnirudh Srinivasan clk_data->num = num_clks; 813*23c8ebc9SAnirudh Srinivasan 814*23c8ebc9SAnirudh Srinivasan return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); 815*23c8ebc9SAnirudh Srinivasan } 816*23c8ebc9SAnirudh Srinivasan 817*23c8ebc9SAnirudh Srinivasan static int atlantis_prcm_probe(struct platform_device *pdev) 818*23c8ebc9SAnirudh Srinivasan { 819*23c8ebc9SAnirudh Srinivasan const struct atlantis_prcm_data *data; 820*23c8ebc9SAnirudh Srinivasan struct auxiliary_device *reset_adev; 821*23c8ebc9SAnirudh Srinivasan struct regmap *regmap; 822*23c8ebc9SAnirudh Srinivasan void __iomem *base; 823*23c8ebc9SAnirudh Srinivasan struct device *dev = &pdev->dev; 824*23c8ebc9SAnirudh Srinivasan int ret; 825*23c8ebc9SAnirudh Srinivasan 826*23c8ebc9SAnirudh Srinivasan base = devm_platform_ioremap_resource(pdev, 0); 827*23c8ebc9SAnirudh Srinivasan if (IS_ERR(base)) 828*23c8ebc9SAnirudh Srinivasan return dev_err_probe(dev, PTR_ERR(base), 829*23c8ebc9SAnirudh Srinivasan "Failed to map registers\n"); 830*23c8ebc9SAnirudh Srinivasan 831*23c8ebc9SAnirudh Srinivasan regmap = devm_regmap_init_mmio(dev, base, &atlantis_prcm_regmap_config); 832*23c8ebc9SAnirudh Srinivasan if (IS_ERR(regmap)) 833*23c8ebc9SAnirudh Srinivasan return dev_err_probe(dev, PTR_ERR(regmap), 834*23c8ebc9SAnirudh Srinivasan "Failed to init regmap\n"); 835*23c8ebc9SAnirudh Srinivasan 836*23c8ebc9SAnirudh Srinivasan data = of_device_get_match_data(dev); 837*23c8ebc9SAnirudh Srinivasan 838*23c8ebc9SAnirudh Srinivasan ret = atlantis_prcm_clocks_register(dev, regmap, data); 839*23c8ebc9SAnirudh Srinivasan if (ret) 840*23c8ebc9SAnirudh Srinivasan return dev_err_probe(dev, ret, "failed to register clocks\n"); 841*23c8ebc9SAnirudh Srinivasan 842*23c8ebc9SAnirudh Srinivasan reset_adev = devm_auxiliary_device_create(dev, data->reset_name, NULL); 843*23c8ebc9SAnirudh Srinivasan if (!reset_adev) 844*23c8ebc9SAnirudh Srinivasan return dev_err_probe(dev, -ENODEV, "failed to register resets\n"); 845*23c8ebc9SAnirudh Srinivasan 846*23c8ebc9SAnirudh Srinivasan return 0; 847*23c8ebc9SAnirudh Srinivasan } 848*23c8ebc9SAnirudh Srinivasan 849*23c8ebc9SAnirudh Srinivasan static const struct of_device_id atlantis_prcm_of_match[] = { 850*23c8ebc9SAnirudh Srinivasan { 851*23c8ebc9SAnirudh Srinivasan .compatible = "tenstorrent,atlantis-prcm-rcpu", 852*23c8ebc9SAnirudh Srinivasan .data = &atlantis_prcm_rcpu_data, 853*23c8ebc9SAnirudh Srinivasan }, 854*23c8ebc9SAnirudh Srinivasan {} 855*23c8ebc9SAnirudh Srinivasan 856*23c8ebc9SAnirudh Srinivasan }; 857*23c8ebc9SAnirudh Srinivasan MODULE_DEVICE_TABLE(of, atlantis_prcm_of_match); 858*23c8ebc9SAnirudh Srinivasan 859*23c8ebc9SAnirudh Srinivasan static struct platform_driver atlantis_prcm_driver = { 860*23c8ebc9SAnirudh Srinivasan .probe = atlantis_prcm_probe, 861*23c8ebc9SAnirudh Srinivasan .driver = { 862*23c8ebc9SAnirudh Srinivasan .name = "atlantis-prcm", 863*23c8ebc9SAnirudh Srinivasan .of_match_table = atlantis_prcm_of_match, 864*23c8ebc9SAnirudh Srinivasan }, 865*23c8ebc9SAnirudh Srinivasan }; 866*23c8ebc9SAnirudh Srinivasan module_platform_driver(atlantis_prcm_driver); 867*23c8ebc9SAnirudh Srinivasan 868*23c8ebc9SAnirudh Srinivasan MODULE_DESCRIPTION("Tenstorrent Atlantis PRCM Clock Controller Driver"); 869*23c8ebc9SAnirudh Srinivasan MODULE_AUTHOR("Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>"); 870*23c8ebc9SAnirudh Srinivasan MODULE_LICENSE("GPL"); 871