1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/io.h> 8 #include <linux/delay.h> 9 #include <linux/err.h> 10 #include <linux/slab.h> 11 #include <linux/clk-provider.h> 12 13 #include "clk.h" 14 15 #define SUPER_STATE_IDLE 0 16 #define SUPER_STATE_RUN 1 17 #define SUPER_STATE_IRQ 2 18 #define SUPER_STATE_FIQ 3 19 20 #define SUPER_STATE_SHIFT 28 21 #define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ 22 BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ 23 << SUPER_STATE_SHIFT) 24 25 #define SUPER_LP_DIV2_BYPASS (1 << 16) 26 27 #define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) 28 #define super_state_to_src_shift(m, s) ((m->width * s)) 29 #define super_state_to_src_mask(m) (((1 << m->width) - 1)) 30 31 static u8 clk_super_get_parent(struct clk_hw *hw) 32 { 33 struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); 34 u32 val, state; 35 u8 source, shift; 36 37 val = readl_relaxed(mux->reg); 38 39 state = val & SUPER_STATE_MASK; 40 41 BUG_ON((state != super_state(SUPER_STATE_RUN)) && 42 (state != super_state(SUPER_STATE_IDLE))); 43 shift = (state == super_state(SUPER_STATE_IDLE)) ? 44 super_state_to_src_shift(mux, SUPER_STATE_IDLE) : 45 super_state_to_src_shift(mux, SUPER_STATE_RUN); 46 47 source = (val >> shift) & super_state_to_src_mask(mux); 48 49 /* 50 * If LP_DIV2_BYPASS is not set and PLLX is current parent then 51 * PLLX/2 is the input source to CCLKLP. 52 */ 53 if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && 54 (source == mux->pllx_index)) 55 source = mux->div2_index; 56 57 return source; 58 } 59 60 static int clk_super_set_parent(struct clk_hw *hw, u8 index) 61 { 62 struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); 63 u32 val, state; 64 int err = 0; 65 u8 parent_index, shift; 66 unsigned long flags = 0; 67 68 if (mux->lock) 69 spin_lock_irqsave(mux->lock, flags); 70 71 val = readl_relaxed(mux->reg); 72 state = val & SUPER_STATE_MASK; 73 BUG_ON((state != super_state(SUPER_STATE_RUN)) && 74 (state != super_state(SUPER_STATE_IDLE))); 75 shift = (state == super_state(SUPER_STATE_IDLE)) ? 76 super_state_to_src_shift(mux, SUPER_STATE_IDLE) : 77 super_state_to_src_shift(mux, SUPER_STATE_RUN); 78 79 /* 80 * For LP mode super-clock switch between PLLX direct 81 * and divided-by-2 outputs is allowed only when other 82 * than PLLX clock source is current parent. 83 */ 84 if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || 85 (index == mux->pllx_index))) { 86 parent_index = clk_super_get_parent(hw); 87 if ((parent_index == mux->div2_index) || 88 (parent_index == mux->pllx_index)) { 89 err = -EINVAL; 90 goto out; 91 } 92 93 val ^= SUPER_LP_DIV2_BYPASS; 94 writel_relaxed(val, mux->reg); 95 udelay(2); 96 97 if (index == mux->div2_index) 98 index = mux->pllx_index; 99 } 100 val &= ~((super_state_to_src_mask(mux)) << shift); 101 val |= (index & (super_state_to_src_mask(mux))) << shift; 102 103 writel_relaxed(val, mux->reg); 104 udelay(2); 105 106 out: 107 if (mux->lock) 108 spin_unlock_irqrestore(mux->lock, flags); 109 110 return err; 111 } 112 113 static const struct clk_ops tegra_clk_super_mux_ops = { 114 .get_parent = clk_super_get_parent, 115 .set_parent = clk_super_set_parent, 116 }; 117 118 static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate, 119 unsigned long *parent_rate) 120 { 121 struct tegra_clk_super_mux *super = to_clk_super_mux(hw); 122 struct clk_hw *div_hw = &super->frac_div.hw; 123 124 __clk_hw_set_clk(div_hw, hw); 125 126 return super->div_ops->round_rate(div_hw, rate, parent_rate); 127 } 128 129 static unsigned long clk_super_recalc_rate(struct clk_hw *hw, 130 unsigned long parent_rate) 131 { 132 struct tegra_clk_super_mux *super = to_clk_super_mux(hw); 133 struct clk_hw *div_hw = &super->frac_div.hw; 134 135 __clk_hw_set_clk(div_hw, hw); 136 137 return super->div_ops->recalc_rate(div_hw, parent_rate); 138 } 139 140 static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate, 141 unsigned long parent_rate) 142 { 143 struct tegra_clk_super_mux *super = to_clk_super_mux(hw); 144 struct clk_hw *div_hw = &super->frac_div.hw; 145 146 __clk_hw_set_clk(div_hw, hw); 147 148 return super->div_ops->set_rate(div_hw, rate, parent_rate); 149 } 150 151 const struct clk_ops tegra_clk_super_ops = { 152 .get_parent = clk_super_get_parent, 153 .set_parent = clk_super_set_parent, 154 .set_rate = clk_super_set_rate, 155 .round_rate = clk_super_round_rate, 156 .recalc_rate = clk_super_recalc_rate, 157 }; 158 159 struct clk *tegra_clk_register_super_mux(const char *name, 160 const char **parent_names, u8 num_parents, 161 unsigned long flags, void __iomem *reg, u8 clk_super_flags, 162 u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) 163 { 164 struct tegra_clk_super_mux *super; 165 struct clk *clk; 166 struct clk_init_data init; 167 168 super = kzalloc(sizeof(*super), GFP_KERNEL); 169 if (!super) 170 return ERR_PTR(-ENOMEM); 171 172 init.name = name; 173 init.ops = &tegra_clk_super_mux_ops; 174 init.flags = flags; 175 init.parent_names = parent_names; 176 init.num_parents = num_parents; 177 178 super->reg = reg; 179 super->pllx_index = pllx_index; 180 super->div2_index = div2_index; 181 super->lock = lock; 182 super->width = width; 183 super->flags = clk_super_flags; 184 185 /* Data in .init is copied by clk_register(), so stack variable OK */ 186 super->hw.init = &init; 187 188 clk = clk_register(NULL, &super->hw); 189 if (IS_ERR(clk)) 190 kfree(super); 191 192 return clk; 193 } 194 195 struct clk *tegra_clk_register_super_clk(const char *name, 196 const char * const *parent_names, u8 num_parents, 197 unsigned long flags, void __iomem *reg, u8 clk_super_flags, 198 spinlock_t *lock) 199 { 200 struct tegra_clk_super_mux *super; 201 struct clk *clk; 202 struct clk_init_data init; 203 204 super = kzalloc(sizeof(*super), GFP_KERNEL); 205 if (!super) 206 return ERR_PTR(-ENOMEM); 207 208 init.name = name; 209 init.ops = &tegra_clk_super_ops; 210 init.flags = flags; 211 init.parent_names = parent_names; 212 init.num_parents = num_parents; 213 214 super->reg = reg; 215 super->lock = lock; 216 super->width = 4; 217 super->flags = clk_super_flags; 218 super->frac_div.reg = reg + 4; 219 super->frac_div.shift = 16; 220 super->frac_div.width = 8; 221 super->frac_div.frac_width = 1; 222 super->frac_div.lock = lock; 223 super->div_ops = &tegra_clk_frac_div_ops; 224 225 /* Data in .init is copied by clk_register(), so stack variable OK */ 226 super->hw.init = &init; 227 228 clk = clk_register(NULL, &super->hw); 229 if (IS_ERR(clk)) 230 kfree(super); 231 232 return clk; 233 } 234