19952f691SThomas 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 20*50d4da9bSSowjanya Komatineni #define OSC_CTRL_MASK (0x3f2 | \ 21*50d4da9bSSowjanya Komatineni (0xf << OSC_CTRL_OSC_FREQ_SHIFT)) 22*50d4da9bSSowjanya Komatineni 23*50d4da9bSSowjanya Komatineni static u32 osc_ctrl_ctx; 24de4f30fdSPeter De Schrijver 2563cc5a4dSThierry Reding int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, 2663cc5a4dSThierry Reding unsigned long *input_freqs, unsigned int num, 2763cc5a4dSThierry Reding unsigned int clk_m_div, unsigned long *osc_freq, 28de4f30fdSPeter De Schrijver unsigned long *pll_ref_freq) 29de4f30fdSPeter De Schrijver { 3063cc5a4dSThierry Reding struct clk *clk, *osc; 31de4f30fdSPeter De Schrijver struct clk **dt_clk; 32de4f30fdSPeter De Schrijver u32 val, pll_ref_div; 33de4f30fdSPeter De Schrijver unsigned osc_idx; 34de4f30fdSPeter De Schrijver 35de4f30fdSPeter De Schrijver val = readl_relaxed(clk_base + OSC_CTRL); 36*50d4da9bSSowjanya Komatineni osc_ctrl_ctx = val & OSC_CTRL_MASK; 37de4f30fdSPeter De Schrijver osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT; 38de4f30fdSPeter De Schrijver 39de4f30fdSPeter De Schrijver if (osc_idx < num) 40de4f30fdSPeter De Schrijver *osc_freq = input_freqs[osc_idx]; 41de4f30fdSPeter De Schrijver else 42de4f30fdSPeter De Schrijver *osc_freq = 0; 43de4f30fdSPeter De Schrijver 44de4f30fdSPeter De Schrijver if (!*osc_freq) { 45de4f30fdSPeter De Schrijver WARN_ON(1); 46de4f30fdSPeter De Schrijver return -EINVAL; 47de4f30fdSPeter De Schrijver } 48de4f30fdSPeter De Schrijver 49f6da46a3SStephen Boyd osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq); 5063cc5a4dSThierry Reding 5163cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks); 52de4f30fdSPeter De Schrijver if (!dt_clk) 53de4f30fdSPeter De Schrijver return 0; 54de4f30fdSPeter De Schrijver 5563cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "clk_m", "osc", 5663cc5a4dSThierry Reding 0, 1, clk_m_div); 57de4f30fdSPeter De Schrijver *dt_clk = clk; 58de4f30fdSPeter De Schrijver 59de4f30fdSPeter De Schrijver /* pll_ref */ 60de4f30fdSPeter De Schrijver val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; 61de4f30fdSPeter De Schrijver pll_ref_div = 1 << val; 6263cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, clks); 63de4f30fdSPeter De Schrijver if (!dt_clk) 64de4f30fdSPeter De Schrijver return 0; 65de4f30fdSPeter De Schrijver 6663cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "pll_ref", "osc", 67de4f30fdSPeter De Schrijver 0, 1, pll_ref_div); 68de4f30fdSPeter De Schrijver *dt_clk = clk; 69de4f30fdSPeter De Schrijver 70de4f30fdSPeter De Schrijver if (pll_ref_freq) 71de4f30fdSPeter De Schrijver *pll_ref_freq = *osc_freq / pll_ref_div; 72de4f30fdSPeter De Schrijver 73de4f30fdSPeter De Schrijver return 0; 74de4f30fdSPeter De Schrijver } 75de4f30fdSPeter De Schrijver 76de4f30fdSPeter De Schrijver void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) 77de4f30fdSPeter De Schrijver { 78de4f30fdSPeter De Schrijver struct clk *clk; 79de4f30fdSPeter De Schrijver struct clk **dt_clk; 80de4f30fdSPeter De Schrijver 81de4f30fdSPeter De Schrijver /* clk_32k */ 82de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks); 83de4f30fdSPeter De Schrijver if (dt_clk) { 84f6da46a3SStephen Boyd clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768); 85de4f30fdSPeter De Schrijver *dt_clk = clk; 86de4f30fdSPeter De Schrijver } 87de4f30fdSPeter De Schrijver 88de4f30fdSPeter De Schrijver /* clk_m_div2 */ 89de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks); 90de4f30fdSPeter De Schrijver if (dt_clk) { 91de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", 92de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 2); 93de4f30fdSPeter De Schrijver *dt_clk = clk; 94de4f30fdSPeter De Schrijver } 95de4f30fdSPeter De Schrijver 96de4f30fdSPeter De Schrijver /* clk_m_div4 */ 97de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks); 98de4f30fdSPeter De Schrijver if (dt_clk) { 99de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", 100de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 4); 101de4f30fdSPeter De Schrijver *dt_clk = clk; 102de4f30fdSPeter De Schrijver } 103de4f30fdSPeter De Schrijver } 104*50d4da9bSSowjanya Komatineni 105*50d4da9bSSowjanya Komatineni void tegra_clk_osc_resume(void __iomem *clk_base) 106*50d4da9bSSowjanya Komatineni { 107*50d4da9bSSowjanya Komatineni u32 val; 108*50d4da9bSSowjanya Komatineni 109*50d4da9bSSowjanya Komatineni val = readl_relaxed(clk_base + OSC_CTRL) & ~OSC_CTRL_MASK; 110*50d4da9bSSowjanya Komatineni val |= osc_ctrl_ctx; 111*50d4da9bSSowjanya Komatineni writel_relaxed(val, clk_base + OSC_CTRL); 112*50d4da9bSSowjanya Komatineni fence_udelay(2, clk_base); 113*50d4da9bSSowjanya Komatineni } 114