1/* 2 * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 17#include <linux/io.h> 18#include <linux/clk.h> 19#include <linux/clk-provider.h> 20#include <linux/of.h> 21#include <linux/of_address.h> 22#include <linux/delay.h> 23#include <linux/export.h> 24#include <linux/clk/tegra.h> 25 26#include "clk.h" 27#include "clk-id.h" 28 29#define PLLX_BASE 0xe0 30#define PLLX_MISC 0xe4 31#define PLLX_MISC2 0x514 32#define PLLX_MISC3 0x518 33 34#define CCLKG_BURST_POLICY 0x368 35#define CCLKLP_BURST_POLICY 0x370 36#define SCLK_BURST_POLICY 0x028 37#define SYSTEM_CLK_RATE 0x030 38 39static DEFINE_SPINLOCK(sysrate_lock); 40 41static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", 42 "pll_p", "pll_p_out2", "unused", 43 "clk_32k", "pll_m_out1" }; 44 45static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", 46 "pll_p", "pll_p_out4", "unused", 47 "unused", "pll_x" }; 48 49static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", 50 "pll_p", "pll_p_out4", "unused", 51 "unused", "pll_x", "pll_x_out0" }; 52 53static void __init tegra_sclk_init(void __iomem *clk_base, 54 struct tegra_clk *tegra_clks) 55{ 56 struct clk *clk; 57 struct clk **dt_clk; 58 59 /* SCLK */ 60 dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); 61 if (dt_clk) { 62 clk = tegra_clk_register_super_mux("sclk", sclk_parents, 63 ARRAY_SIZE(sclk_parents), 64 CLK_SET_RATE_PARENT, 65 clk_base + SCLK_BURST_POLICY, 66 0, 4, 0, 0, NULL); 67 *dt_clk = clk; 68 } 69 70 /* HCLK */ 71 dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks); 72 if (dt_clk) { 73 clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, 74 clk_base + SYSTEM_CLK_RATE, 4, 2, 0, 75 &sysrate_lock); 76 clk = clk_register_gate(NULL, "hclk", "hclk_div", 77 CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 78 clk_base + SYSTEM_CLK_RATE, 79 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); 80 *dt_clk = clk; 81 } 82 83 /* PCLK */ 84 dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks); 85 if (!dt_clk) 86 return; 87 88 clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, 89 clk_base + SYSTEM_CLK_RATE, 0, 2, 0, 90 &sysrate_lock); 91 clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | 92 CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, 93 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); 94 *dt_clk = clk; 95} 96 97void __init tegra_super_clk_gen4_init(void __iomem *clk_base, 98 void __iomem *pmc_base, 99 struct tegra_clk *tegra_clks, 100 struct tegra_clk_pll_params *params) 101{ 102 struct clk *clk; 103 struct clk **dt_clk; 104 105 /* CCLKG */ 106 dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks); 107 if (dt_clk) { 108 clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, 109 ARRAY_SIZE(cclk_g_parents), 110 CLK_SET_RATE_PARENT, 111 clk_base + CCLKG_BURST_POLICY, 112 0, 4, 0, 0, NULL); 113 *dt_clk = clk; 114 } 115 116 /* CCLKLP */ 117 dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks); 118 if (dt_clk) { 119 clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, 120 ARRAY_SIZE(cclk_lp_parents), 121 CLK_SET_RATE_PARENT, 122 clk_base + CCLKLP_BURST_POLICY, 123 TEGRA_DIVIDER_2, 4, 8, 9, NULL); 124 *dt_clk = clk; 125 } 126 127 tegra_sclk_init(clk_base, tegra_clks); 128 129#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) 130 /* PLLX */ 131 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks); 132 if (!dt_clk) 133 return; 134 135 clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, 136 pmc_base, CLK_IGNORE_UNUSED, params, NULL); 137 *dt_clk = clk; 138 139 /* PLLX_OUT0 */ 140 141 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks); 142 if (!dt_clk) 143 return; 144 clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", 145 CLK_SET_RATE_PARENT, 1, 2); 146 *dt_clk = clk; 147#endif 148} 149 150