1*9952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2de4f30fdSPeter De Schrijver /* 3de4f30fdSPeter De Schrijver * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. 4de4f30fdSPeter De Schrijver */ 5de4f30fdSPeter De Schrijver 6de4f30fdSPeter De Schrijver #include <linux/io.h> 7de4f30fdSPeter De Schrijver #include <linux/clk-provider.h> 8de4f30fdSPeter De Schrijver #include <linux/of.h> 9de4f30fdSPeter De Schrijver #include <linux/of_address.h> 10de4f30fdSPeter De Schrijver #include <linux/delay.h> 11de4f30fdSPeter De Schrijver #include <linux/export.h> 12de4f30fdSPeter De Schrijver #include <linux/clk/tegra.h> 13de4f30fdSPeter De Schrijver 14de4f30fdSPeter De Schrijver #include "clk.h" 15de4f30fdSPeter De Schrijver #include "clk-id.h" 16de4f30fdSPeter De Schrijver 17de4f30fdSPeter De Schrijver #define OSC_CTRL 0x50 18de4f30fdSPeter De Schrijver #define OSC_CTRL_OSC_FREQ_SHIFT 28 19de4f30fdSPeter De Schrijver #define OSC_CTRL_PLL_REF_DIV_SHIFT 26 20de4f30fdSPeter De Schrijver 2163cc5a4dSThierry Reding int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, 2263cc5a4dSThierry Reding unsigned long *input_freqs, unsigned int num, 2363cc5a4dSThierry Reding unsigned int clk_m_div, unsigned long *osc_freq, 24de4f30fdSPeter De Schrijver unsigned long *pll_ref_freq) 25de4f30fdSPeter De Schrijver { 2663cc5a4dSThierry Reding struct clk *clk, *osc; 27de4f30fdSPeter De Schrijver struct clk **dt_clk; 28de4f30fdSPeter De Schrijver u32 val, pll_ref_div; 29de4f30fdSPeter De Schrijver unsigned osc_idx; 30de4f30fdSPeter De Schrijver 31de4f30fdSPeter De Schrijver val = readl_relaxed(clk_base + OSC_CTRL); 32de4f30fdSPeter De Schrijver osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT; 33de4f30fdSPeter De Schrijver 34de4f30fdSPeter De Schrijver if (osc_idx < num) 35de4f30fdSPeter De Schrijver *osc_freq = input_freqs[osc_idx]; 36de4f30fdSPeter De Schrijver else 37de4f30fdSPeter De Schrijver *osc_freq = 0; 38de4f30fdSPeter De Schrijver 39de4f30fdSPeter De Schrijver if (!*osc_freq) { 40de4f30fdSPeter De Schrijver WARN_ON(1); 41de4f30fdSPeter De Schrijver return -EINVAL; 42de4f30fdSPeter De Schrijver } 43de4f30fdSPeter De Schrijver 44f6da46a3SStephen Boyd osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq); 4563cc5a4dSThierry Reding 4663cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks); 47de4f30fdSPeter De Schrijver if (!dt_clk) 48de4f30fdSPeter De Schrijver return 0; 49de4f30fdSPeter De Schrijver 5063cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "clk_m", "osc", 5163cc5a4dSThierry Reding 0, 1, clk_m_div); 52de4f30fdSPeter De Schrijver *dt_clk = clk; 53de4f30fdSPeter De Schrijver 54de4f30fdSPeter De Schrijver /* pll_ref */ 55de4f30fdSPeter De Schrijver val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; 56de4f30fdSPeter De Schrijver pll_ref_div = 1 << val; 5763cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, clks); 58de4f30fdSPeter De Schrijver if (!dt_clk) 59de4f30fdSPeter De Schrijver return 0; 60de4f30fdSPeter De Schrijver 6163cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "pll_ref", "osc", 62de4f30fdSPeter De Schrijver 0, 1, pll_ref_div); 63de4f30fdSPeter De Schrijver *dt_clk = clk; 64de4f30fdSPeter De Schrijver 65de4f30fdSPeter De Schrijver if (pll_ref_freq) 66de4f30fdSPeter De Schrijver *pll_ref_freq = *osc_freq / pll_ref_div; 67de4f30fdSPeter De Schrijver 68de4f30fdSPeter De Schrijver return 0; 69de4f30fdSPeter De Schrijver } 70de4f30fdSPeter De Schrijver 71de4f30fdSPeter De Schrijver void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) 72de4f30fdSPeter De Schrijver { 73de4f30fdSPeter De Schrijver struct clk *clk; 74de4f30fdSPeter De Schrijver struct clk **dt_clk; 75de4f30fdSPeter De Schrijver 76de4f30fdSPeter De Schrijver /* clk_32k */ 77de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks); 78de4f30fdSPeter De Schrijver if (dt_clk) { 79f6da46a3SStephen Boyd clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768); 80de4f30fdSPeter De Schrijver *dt_clk = clk; 81de4f30fdSPeter De Schrijver } 82de4f30fdSPeter De Schrijver 83de4f30fdSPeter De Schrijver /* clk_m_div2 */ 84de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks); 85de4f30fdSPeter De Schrijver if (dt_clk) { 86de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", 87de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 2); 88de4f30fdSPeter De Schrijver *dt_clk = clk; 89de4f30fdSPeter De Schrijver } 90de4f30fdSPeter De Schrijver 91de4f30fdSPeter De Schrijver /* clk_m_div4 */ 92de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks); 93de4f30fdSPeter De Schrijver if (dt_clk) { 94de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", 95de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 4); 96de4f30fdSPeter De Schrijver *dt_clk = clk; 97de4f30fdSPeter De Schrijver } 98de4f30fdSPeter De Schrijver } 99