0001
0002
0003
0004
0005
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <linux/clk-provider.h>
0009 #include <linux/clk/tegra.h>
0010 #include <linux/device.h>
0011 #include <linux/module.h>
0012 #include <linux/io.h>
0013 #include <linux/slab.h>
0014
0015 #include "clk.h"
0016
0017 #define CLK_SOURCE_EMC 0x19c
0018 #define CLK_SOURCE_EMC_2X_CLK_SRC GENMASK(31, 29)
0019 #define CLK_SOURCE_EMC_MC_EMC_SAME_FREQ BIT(16)
0020 #define CLK_SOURCE_EMC_2X_CLK_DIVISOR GENMASK(7, 0)
0021
0022 #define CLK_SRC_PLLM 0
0023 #define CLK_SRC_PLLC 1
0024 #define CLK_SRC_PLLP 2
0025 #define CLK_SRC_CLK_M 3
0026 #define CLK_SRC_PLLM_UD 4
0027 #define CLK_SRC_PLLMB_UD 5
0028 #define CLK_SRC_PLLMB 6
0029 #define CLK_SRC_PLLP_UD 7
0030
0031 struct tegra210_clk_emc {
0032 struct clk_hw hw;
0033 void __iomem *regs;
0034
0035 struct tegra210_clk_emc_provider *provider;
0036
0037 struct clk *parents[8];
0038 };
0039
0040 static inline struct tegra210_clk_emc *
0041 to_tegra210_clk_emc(struct clk_hw *hw)
0042 {
0043 return container_of(hw, struct tegra210_clk_emc, hw);
0044 }
0045
0046 static const char *tegra210_clk_emc_parents[] = {
0047 "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb_ud",
0048 "pll_mb", "pll_p_ud",
0049 };
0050
0051 static u8 tegra210_clk_emc_get_parent(struct clk_hw *hw)
0052 {
0053 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
0054 u32 value;
0055 u8 src;
0056
0057 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC);
0058 src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, value);
0059
0060 return src;
0061 }
0062
0063 static unsigned long tegra210_clk_emc_recalc_rate(struct clk_hw *hw,
0064 unsigned long parent_rate)
0065 {
0066 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
0067 u32 value, div;
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 parent_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
0080
0081 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC);
0082
0083 div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, value);
0084 div += 2;
0085
0086 return DIV_ROUND_UP(parent_rate * 2, div);
0087 }
0088
0089 static long tegra210_clk_emc_round_rate(struct clk_hw *hw, unsigned long rate,
0090 unsigned long *prate)
0091 {
0092 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
0093 struct tegra210_clk_emc_provider *provider = emc->provider;
0094 unsigned int i;
0095
0096 if (!provider || !provider->configs || provider->num_configs == 0)
0097 return clk_hw_get_rate(hw);
0098
0099 for (i = 0; i < provider->num_configs; i++) {
0100 if (provider->configs[i].rate >= rate)
0101 return provider->configs[i].rate;
0102 }
0103
0104 return provider->configs[i - 1].rate;
0105 }
0106
0107 static struct clk *tegra210_clk_emc_find_parent(struct tegra210_clk_emc *emc,
0108 u8 index)
0109 {
0110 struct clk_hw *parent = clk_hw_get_parent_by_index(&emc->hw, index);
0111 const char *name = clk_hw_get_name(parent);
0112
0113
0114
0115 return __clk_lookup(name);
0116 }
0117
0118 static int tegra210_clk_emc_set_rate(struct clk_hw *hw, unsigned long rate,
0119 unsigned long parent_rate)
0120 {
0121 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
0122 struct tegra210_clk_emc_provider *provider = emc->provider;
0123 struct tegra210_clk_emc_config *config;
0124 struct device *dev = provider->dev;
0125 struct clk_hw *old, *new, *parent;
0126 u8 old_idx, new_idx, index;
0127 struct clk *clk;
0128 unsigned int i;
0129 int err;
0130
0131 if (!provider->configs || provider->num_configs == 0)
0132 return -EINVAL;
0133
0134 for (i = 0; i < provider->num_configs; i++) {
0135 if (provider->configs[i].rate >= rate) {
0136 config = &provider->configs[i];
0137 break;
0138 }
0139 }
0140
0141 if (i == provider->num_configs)
0142 config = &provider->configs[i - 1];
0143
0144 old_idx = tegra210_clk_emc_get_parent(hw);
0145 new_idx = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value);
0146
0147 old = clk_hw_get_parent_by_index(hw, old_idx);
0148 new = clk_hw_get_parent_by_index(hw, new_idx);
0149
0150
0151 if (config->parent_rate != clk_hw_get_rate(old)) {
0152
0153 if (new_idx == old_idx) {
0154
0155 switch (new_idx) {
0156 case CLK_SRC_PLLM:
0157 new_idx = CLK_SRC_PLLMB;
0158 break;
0159
0160 case CLK_SRC_PLLM_UD:
0161 new_idx = CLK_SRC_PLLMB_UD;
0162 break;
0163
0164 case CLK_SRC_PLLMB_UD:
0165 new_idx = CLK_SRC_PLLM_UD;
0166 break;
0167
0168 case CLK_SRC_PLLMB:
0169 new_idx = CLK_SRC_PLLM;
0170 break;
0171 }
0172
0173
0174
0175
0176
0177 if (WARN_ON(new_idx == old_idx))
0178 return -EINVAL;
0179
0180 new = clk_hw_get_parent_by_index(hw, new_idx);
0181 }
0182
0183 index = new_idx;
0184 parent = new;
0185 } else {
0186 index = old_idx;
0187 parent = old;
0188 }
0189
0190 clk = tegra210_clk_emc_find_parent(emc, index);
0191 if (IS_ERR(clk)) {
0192 err = PTR_ERR(clk);
0193 dev_err(dev, "failed to get parent clock for index %u: %d\n",
0194 index, err);
0195 return err;
0196 }
0197
0198
0199 if (clk_get_rate(clk) != config->parent_rate) {
0200 err = clk_set_rate(clk, config->parent_rate);
0201 if (err < 0) {
0202 dev_err(dev, "failed to set rate %lu Hz for %pC: %d\n",
0203 config->parent_rate, clk, err);
0204 return err;
0205 }
0206 }
0207
0208
0209 if (parent != old) {
0210 err = clk_prepare_enable(clk);
0211 if (err < 0) {
0212 dev_err(dev, "failed to enable parent clock %pC: %d\n",
0213 clk, err);
0214 return err;
0215 }
0216 }
0217
0218
0219 config->value &= ~CLK_SOURCE_EMC_2X_CLK_SRC;
0220 config->value |= FIELD_PREP(CLK_SOURCE_EMC_2X_CLK_SRC, index);
0221
0222
0223
0224
0225
0226 err = provider->set_rate(dev, config);
0227 if (err < 0) {
0228 dev_err(dev, "failed to set EMC rate to %lu Hz: %d\n", rate,
0229 err);
0230
0231
0232
0233
0234
0235 if (parent != old)
0236 clk_disable_unprepare(clk);
0237
0238 return err;
0239 }
0240
0241
0242 if (parent != old) {
0243 clk = tegra210_clk_emc_find_parent(emc, old_idx);
0244 if (IS_ERR(clk)) {
0245 err = PTR_ERR(clk);
0246 dev_err(dev,
0247 "failed to get parent clock for index %u: %d\n",
0248 old_idx, err);
0249 return err;
0250 }
0251
0252 clk_hw_reparent(hw, parent);
0253 clk_disable_unprepare(clk);
0254 }
0255
0256 return err;
0257 }
0258
0259 static const struct clk_ops tegra210_clk_emc_ops = {
0260 .get_parent = tegra210_clk_emc_get_parent,
0261 .recalc_rate = tegra210_clk_emc_recalc_rate,
0262 .round_rate = tegra210_clk_emc_round_rate,
0263 .set_rate = tegra210_clk_emc_set_rate,
0264 };
0265
0266 struct clk *tegra210_clk_register_emc(struct device_node *np,
0267 void __iomem *regs)
0268 {
0269 struct tegra210_clk_emc *emc;
0270 struct clk_init_data init;
0271 struct clk *clk;
0272
0273 emc = kzalloc(sizeof(*emc), GFP_KERNEL);
0274 if (!emc)
0275 return ERR_PTR(-ENOMEM);
0276
0277 emc->regs = regs;
0278
0279 init.name = "emc";
0280 init.ops = &tegra210_clk_emc_ops;
0281 init.flags = CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE;
0282 init.parent_names = tegra210_clk_emc_parents;
0283 init.num_parents = ARRAY_SIZE(tegra210_clk_emc_parents);
0284 emc->hw.init = &init;
0285
0286 clk = clk_register(NULL, &emc->hw);
0287 if (IS_ERR(clk)) {
0288 kfree(emc);
0289 return clk;
0290 }
0291
0292 return clk;
0293 }
0294
0295 int tegra210_clk_emc_attach(struct clk *clk,
0296 struct tegra210_clk_emc_provider *provider)
0297 {
0298 struct clk_hw *hw = __clk_get_hw(clk);
0299 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
0300 struct device *dev = provider->dev;
0301 unsigned int i;
0302 int err;
0303
0304 if (!try_module_get(provider->owner))
0305 return -ENODEV;
0306
0307 for (i = 0; i < provider->num_configs; i++) {
0308 struct tegra210_clk_emc_config *config = &provider->configs[i];
0309 struct clk_hw *parent;
0310 bool same_freq;
0311 u8 div, src;
0312
0313 div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, config->value);
0314 src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value);
0315
0316
0317 if (div & 0x1) {
0318 dev_err(dev, "invalid odd divider %u for rate %lu Hz\n",
0319 div, config->rate);
0320 err = -EINVAL;
0321 goto put;
0322 }
0323
0324 same_freq = config->value & CLK_SOURCE_EMC_MC_EMC_SAME_FREQ;
0325
0326 if (same_freq != config->same_freq) {
0327 dev_err(dev,
0328 "ambiguous EMC to MC ratio for rate %lu Hz\n",
0329 config->rate);
0330 err = -EINVAL;
0331 goto put;
0332 }
0333
0334 parent = clk_hw_get_parent_by_index(hw, src);
0335 config->parent = src;
0336
0337 if (src == CLK_SRC_PLLM || src == CLK_SRC_PLLM_UD) {
0338 config->parent_rate = config->rate * (1 + div / 2);
0339 } else {
0340 unsigned long rate = config->rate * (1 + div / 2);
0341
0342 config->parent_rate = clk_hw_get_rate(parent);
0343
0344 if (config->parent_rate != rate) {
0345 dev_err(dev,
0346 "rate %lu Hz does not match input\n",
0347 config->rate);
0348 err = -EINVAL;
0349 goto put;
0350 }
0351 }
0352 }
0353
0354 emc->provider = provider;
0355
0356 return 0;
0357
0358 put:
0359 module_put(provider->owner);
0360 return err;
0361 }
0362 EXPORT_SYMBOL_GPL(tegra210_clk_emc_attach);
0363
0364 void tegra210_clk_emc_detach(struct clk *clk)
0365 {
0366 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(__clk_get_hw(clk));
0367
0368 module_put(emc->provider->owner);
0369 emc->provider = NULL;
0370 }
0371 EXPORT_SYMBOL_GPL(tegra210_clk_emc_detach);