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-provider.h> 19#include <linux/of.h> 20#include <linux/of_address.h> 21#include <linux/delay.h> 22#include <linux/export.h> 23#include <linux/clk/tegra.h> 24 25#include "clk.h" 26#include "clk-id.h" 27 28#define PLLX_BASE 0xe0 29#define PLLX_MISC 0xe4 30#define PLLX_MISC2 0x514 31#define PLLX_MISC3 0x518 32 33#define CCLKG_BURST_POLICY 0x368 34#define CCLKLP_BURST_POLICY 0x370 35#define SCLK_BURST_POLICY 0x028 36#define SYSTEM_CLK_RATE 0x030 37 38static DEFINE_SPINLOCK(sysrate_lock); 39 40static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", 41 "pll_p", "pll_p_out2", "unused", 42 "clk_32k", "pll_m_out1" }; 43 44static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", 45 "pll_p", "pll_p_out4", "unused", 46 "unused", "pll_x", "unused", "unused", 47 "unused", "unused", "unused", "unused", 48 "dfllCPU_out" }; 49 50static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", 51 "pll_p", "pll_p_out4", "unused", 52 "unused", "pll_x", "pll_x_out0" }; 53 54static void __init tegra_sclk_init(void __iomem *clk_base, 55 struct tegra_clk *tegra_clks) 56{ 57 struct clk *clk; 58 struct clk **dt_clk; 59 60 /* SCLK */ 61 dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); 62 if (dt_clk) { 63 clk = tegra_clk_register_super_mux("sclk", sclk_parents, 64 ARRAY_SIZE(sclk_parents), 65 CLK_SET_RATE_PARENT, 66 clk_base + SCLK_BURST_POLICY, 67 0, 4, 0, 0, NULL); 68 *dt_clk = clk; 69 } 70 71 /* HCLK */ 72 dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks); 73 if (dt_clk) { 74 clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, 75 clk_base + SYSTEM_CLK_RATE, 4, 2, 0, 76 &sysrate_lock); 77 clk = clk_register_gate(NULL, "hclk", "hclk_div", 78 CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 79 clk_base + SYSTEM_CLK_RATE, 80 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); 81 *dt_clk = clk; 82 } 83 84 /* PCLK */ 85 dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks); 86 if (!dt_clk) 87 return; 88 89 clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, 90 clk_base + SYSTEM_CLK_RATE, 0, 2, 0, 91 &sysrate_lock); 92 clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | 93 CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, 94 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); 95 *dt_clk = clk; 96} 97 98void __init tegra_super_clk_gen4_init(void __iomem *clk_base, 99 void __iomem *pmc_base, 100 struct tegra_clk *tegra_clks, 101 struct tegra_clk_pll_params *params) 102{ 103 struct clk *clk; 104 struct clk **dt_clk; 105 106 /* CCLKG */ 107 dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks); 108 if (dt_clk) { 109 clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, 110 ARRAY_SIZE(cclk_g_parents), 111 CLK_SET_RATE_PARENT, 112 clk_base + CCLKG_BURST_POLICY, 113 0, 4, 0, 0, NULL); 114 *dt_clk = clk; 115 } 116 117 /* CCLKLP */ 118 dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks); 119 if (dt_clk) { 120 clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, 121 ARRAY_SIZE(cclk_lp_parents), 122 CLK_SET_RATE_PARENT, 123 clk_base + CCLKLP_BURST_POLICY, 124 TEGRA_DIVIDER_2, 4, 8, 9, NULL); 125 *dt_clk = clk; 126 } 127 128 tegra_sclk_init(clk_base, tegra_clks); 129 130#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) 131 /* PLLX */ 132 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks); 133 if (!dt_clk) 134 return; 135 136 clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, 137 pmc_base, CLK_IGNORE_UNUSED, params, NULL); 138 *dt_clk = clk; 139 140 /* PLLX_OUT0 */ 141 142 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks); 143 if (!dt_clk) 144 return; 145 clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", 146 CLK_SET_RATE_PARENT, 1, 2); 147 *dt_clk = clk; 148#endif 149} 150 151