1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 NVIDIA CORPORATION. All rights reserved. 4 * 5 * based on clk-mux.c 6 * 7 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 8 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> 9 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 10 * 11 */ 12 13 #include <linux/clk-provider.h> 14 #include <linux/err.h> 15 #include <linux/types.h> 16 17 #include "clk.h" 18 19 #define DIV_MASK GENMASK(7, 0) 20 #define MUX_SHIFT 29 21 #define MUX_MASK GENMASK(MUX_SHIFT + 2, MUX_SHIFT) 22 #define SDMMC_MUL 2 23 24 #define get_max_div(d) DIV_MASK 25 #define get_div_field(val) ((val) & DIV_MASK) 26 #define get_mux_field(val) (((val) & MUX_MASK) >> MUX_SHIFT) 27 28 static const char * const mux_sdmmc_parents[] = { 29 "pll_p", "pll_c4_out2", "pll_c4_out0", "pll_c4_out1", "clk_m" 30 }; 31 32 static const u8 mux_lj_idx[] = { 33 [0] = 0, [1] = 1, [2] = 2, [3] = 5, [4] = 6 34 }; 35 36 static const u8 mux_non_lj_idx[] = { 37 [0] = 0, [1] = 3, [2] = 7, [3] = 4, [4] = 6 38 }; 39 40 static u8 clk_sdmmc_mux_get_parent(struct clk_hw *hw) 41 { 42 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 43 int num_parents, i; 44 u32 src, val; 45 const u8 *mux_idx; 46 47 num_parents = clk_hw_get_num_parents(hw); 48 49 val = readl_relaxed(sdmmc_mux->reg); 50 src = get_mux_field(val); 51 if (get_div_field(val)) 52 mux_idx = mux_non_lj_idx; 53 else 54 mux_idx = mux_lj_idx; 55 56 for (i = 0; i < num_parents; i++) { 57 if (mux_idx[i] == src) 58 return i; 59 } 60 61 WARN(1, "Unknown parent selector %d\n", src); 62 63 return 0; 64 } 65 66 static int clk_sdmmc_mux_set_parent(struct clk_hw *hw, u8 index) 67 { 68 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 69 u32 val; 70 71 72 val = readl_relaxed(sdmmc_mux->reg); 73 if (get_div_field(val)) 74 index = mux_non_lj_idx[index]; 75 else 76 index = mux_lj_idx[index]; 77 78 val &= ~MUX_MASK; 79 val |= index << MUX_SHIFT; 80 81 writel(val, sdmmc_mux->reg); 82 83 return 0; 84 } 85 86 static unsigned long clk_sdmmc_mux_recalc_rate(struct clk_hw *hw, 87 unsigned long parent_rate) 88 { 89 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 90 u32 val; 91 int div; 92 u64 rate = parent_rate; 93 94 val = readl_relaxed(sdmmc_mux->reg); 95 div = get_div_field(val); 96 97 div += SDMMC_MUL; 98 99 rate *= SDMMC_MUL; 100 rate += div - 1; 101 do_div(rate, div); 102 103 return rate; 104 } 105 106 static int clk_sdmmc_mux_determine_rate(struct clk_hw *hw, 107 struct clk_rate_request *req) 108 { 109 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 110 int div; 111 unsigned long output_rate = req->best_parent_rate; 112 113 req->rate = max(req->rate, req->min_rate); 114 req->rate = min(req->rate, req->max_rate); 115 116 if (!req->rate) 117 return output_rate; 118 119 div = div_frac_get(req->rate, output_rate, 8, 1, sdmmc_mux->div_flags); 120 if (div < 0) 121 div = 0; 122 123 if (sdmmc_mux->div_flags & TEGRA_DIVIDER_ROUND_UP) 124 req->rate = DIV_ROUND_UP(output_rate * SDMMC_MUL, 125 div + SDMMC_MUL); 126 else 127 req->rate = output_rate * SDMMC_MUL / (div + SDMMC_MUL); 128 129 return 0; 130 } 131 132 static int clk_sdmmc_mux_set_rate(struct clk_hw *hw, unsigned long rate, 133 unsigned long parent_rate) 134 { 135 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 136 int div; 137 unsigned long flags = 0; 138 u32 val; 139 u8 src; 140 141 div = div_frac_get(rate, parent_rate, 8, 1, sdmmc_mux->div_flags); 142 if (div < 0) 143 return div; 144 145 if (sdmmc_mux->lock) 146 spin_lock_irqsave(sdmmc_mux->lock, flags); 147 148 src = clk_sdmmc_mux_get_parent(hw); 149 if (div) 150 src = mux_non_lj_idx[src]; 151 else 152 src = mux_lj_idx[src]; 153 154 val = src << MUX_SHIFT; 155 val |= div; 156 writel(val, sdmmc_mux->reg); 157 fence_udelay(2, sdmmc_mux->reg); 158 159 if (sdmmc_mux->lock) 160 spin_unlock_irqrestore(sdmmc_mux->lock, flags); 161 162 return 0; 163 } 164 165 static int clk_sdmmc_mux_is_enabled(struct clk_hw *hw) 166 { 167 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 168 const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; 169 struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; 170 171 __clk_hw_set_clk(gate_hw, hw); 172 173 return gate_ops->is_enabled(gate_hw); 174 } 175 176 static int clk_sdmmc_mux_enable(struct clk_hw *hw) 177 { 178 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 179 const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; 180 struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; 181 182 __clk_hw_set_clk(gate_hw, hw); 183 184 return gate_ops->enable(gate_hw); 185 } 186 187 static void clk_sdmmc_mux_disable(struct clk_hw *hw) 188 { 189 struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); 190 const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; 191 struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; 192 193 gate_ops->disable(gate_hw); 194 } 195 196 static const struct clk_ops tegra_clk_sdmmc_mux_ops = { 197 .get_parent = clk_sdmmc_mux_get_parent, 198 .set_parent = clk_sdmmc_mux_set_parent, 199 .determine_rate = clk_sdmmc_mux_determine_rate, 200 .recalc_rate = clk_sdmmc_mux_recalc_rate, 201 .set_rate = clk_sdmmc_mux_set_rate, 202 .is_enabled = clk_sdmmc_mux_is_enabled, 203 .enable = clk_sdmmc_mux_enable, 204 .disable = clk_sdmmc_mux_disable, 205 }; 206 207 struct clk *tegra_clk_register_sdmmc_mux_div(const char *name, 208 void __iomem *clk_base, u32 offset, u32 clk_num, u8 div_flags, 209 unsigned long flags, void *lock) 210 { 211 struct clk *clk; 212 struct clk_init_data init; 213 const struct tegra_clk_periph_regs *bank; 214 struct tegra_sdmmc_mux *sdmmc_mux; 215 216 init.ops = &tegra_clk_sdmmc_mux_ops; 217 init.name = name; 218 init.flags = flags; 219 init.parent_names = mux_sdmmc_parents; 220 init.num_parents = ARRAY_SIZE(mux_sdmmc_parents); 221 222 bank = get_reg_bank(clk_num); 223 if (!bank) 224 return ERR_PTR(-EINVAL); 225 226 sdmmc_mux = kzalloc(sizeof(*sdmmc_mux), GFP_KERNEL); 227 if (!sdmmc_mux) 228 return ERR_PTR(-ENOMEM); 229 230 /* Data in .init is copied by clk_register(), so stack variable OK */ 231 sdmmc_mux->hw.init = &init; 232 sdmmc_mux->reg = clk_base + offset; 233 sdmmc_mux->lock = lock; 234 sdmmc_mux->gate.clk_base = clk_base; 235 sdmmc_mux->gate.regs = bank; 236 sdmmc_mux->gate.enable_refcnt = periph_clk_enb_refcnt; 237 sdmmc_mux->gate.clk_num = clk_num; 238 sdmmc_mux->gate.flags = TEGRA_PERIPH_ON_APB; 239 sdmmc_mux->div_flags = div_flags; 240 sdmmc_mux->gate_ops = &tegra_clk_periph_gate_ops; 241 242 clk = clk_register(NULL, &sdmmc_mux->hw); 243 if (IS_ERR(clk)) { 244 kfree(sdmmc_mux); 245 return clk; 246 } 247 248 sdmmc_mux->gate.hw.clk = clk; 249 250 return clk; 251 } 252