clk.c revision 9f0030c8ad0ce357e8fc8c71ec6b4958041afccf
1/* 2 * Copyright (c) 2012, 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/clk.h> 18#include <linux/clk-provider.h> 19#include <linux/of.h> 20#include <linux/clk/tegra.h> 21#include <linux/reset-controller.h> 22#include <linux/tegra-soc.h> 23 24#include "clk.h" 25 26#define CLK_OUT_ENB_L 0x010 27#define CLK_OUT_ENB_H 0x014 28#define CLK_OUT_ENB_U 0x018 29#define CLK_OUT_ENB_V 0x360 30#define CLK_OUT_ENB_W 0x364 31#define CLK_OUT_ENB_X 0x280 32#define CLK_OUT_ENB_SET_L 0x320 33#define CLK_OUT_ENB_CLR_L 0x324 34#define CLK_OUT_ENB_SET_H 0x328 35#define CLK_OUT_ENB_CLR_H 0x32c 36#define CLK_OUT_ENB_SET_U 0x330 37#define CLK_OUT_ENB_CLR_U 0x334 38#define CLK_OUT_ENB_SET_V 0x440 39#define CLK_OUT_ENB_CLR_V 0x444 40#define CLK_OUT_ENB_SET_W 0x448 41#define CLK_OUT_ENB_CLR_W 0x44c 42#define CLK_OUT_ENB_SET_X 0x284 43#define CLK_OUT_ENB_CLR_X 0x288 44 45#define RST_DEVICES_L 0x004 46#define RST_DEVICES_H 0x008 47#define RST_DEVICES_U 0x00C 48#define RST_DFLL_DVCO 0x2F4 49#define RST_DEVICES_V 0x358 50#define RST_DEVICES_W 0x35C 51#define RST_DEVICES_X 0x28C 52#define RST_DEVICES_SET_L 0x300 53#define RST_DEVICES_CLR_L 0x304 54#define RST_DEVICES_SET_H 0x308 55#define RST_DEVICES_CLR_H 0x30c 56#define RST_DEVICES_SET_U 0x310 57#define RST_DEVICES_CLR_U 0x314 58#define RST_DEVICES_SET_V 0x430 59#define RST_DEVICES_CLR_V 0x434 60#define RST_DEVICES_SET_W 0x438 61#define RST_DEVICES_CLR_W 0x43c 62#define RST_DEVICES_SET_X 0x290 63#define RST_DEVICES_CLR_X 0x294 64 65/* Global data of Tegra CPU CAR ops */ 66static struct tegra_cpu_car_ops dummy_car_ops; 67struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops; 68 69int *periph_clk_enb_refcnt; 70static int periph_banks; 71static struct clk **clks; 72static int clk_num; 73static struct clk_onecell_data clk_data; 74 75static struct tegra_clk_periph_regs periph_regs[] = { 76 [0] = { 77 .enb_reg = CLK_OUT_ENB_L, 78 .enb_set_reg = CLK_OUT_ENB_SET_L, 79 .enb_clr_reg = CLK_OUT_ENB_CLR_L, 80 .rst_reg = RST_DEVICES_L, 81 .rst_set_reg = RST_DEVICES_SET_L, 82 .rst_clr_reg = RST_DEVICES_CLR_L, 83 }, 84 [1] = { 85 .enb_reg = CLK_OUT_ENB_H, 86 .enb_set_reg = CLK_OUT_ENB_SET_H, 87 .enb_clr_reg = CLK_OUT_ENB_CLR_H, 88 .rst_reg = RST_DEVICES_H, 89 .rst_set_reg = RST_DEVICES_SET_H, 90 .rst_clr_reg = RST_DEVICES_CLR_H, 91 }, 92 [2] = { 93 .enb_reg = CLK_OUT_ENB_U, 94 .enb_set_reg = CLK_OUT_ENB_SET_U, 95 .enb_clr_reg = CLK_OUT_ENB_CLR_U, 96 .rst_reg = RST_DEVICES_U, 97 .rst_set_reg = RST_DEVICES_SET_U, 98 .rst_clr_reg = RST_DEVICES_CLR_U, 99 }, 100 [3] = { 101 .enb_reg = CLK_OUT_ENB_V, 102 .enb_set_reg = CLK_OUT_ENB_SET_V, 103 .enb_clr_reg = CLK_OUT_ENB_CLR_V, 104 .rst_reg = RST_DEVICES_V, 105 .rst_set_reg = RST_DEVICES_SET_V, 106 .rst_clr_reg = RST_DEVICES_CLR_V, 107 }, 108 [4] = { 109 .enb_reg = CLK_OUT_ENB_W, 110 .enb_set_reg = CLK_OUT_ENB_SET_W, 111 .enb_clr_reg = CLK_OUT_ENB_CLR_W, 112 .rst_reg = RST_DEVICES_W, 113 .rst_set_reg = RST_DEVICES_SET_W, 114 .rst_clr_reg = RST_DEVICES_CLR_W, 115 }, 116 [5] = { 117 .enb_reg = CLK_OUT_ENB_X, 118 .enb_set_reg = CLK_OUT_ENB_SET_X, 119 .enb_clr_reg = CLK_OUT_ENB_CLR_X, 120 .rst_reg = RST_DEVICES_X, 121 .rst_set_reg = RST_DEVICES_SET_X, 122 .rst_clr_reg = RST_DEVICES_CLR_X, 123 }, 124}; 125 126static void __iomem *clk_base; 127 128static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev, 129 unsigned long id) 130{ 131 /* 132 * If peripheral is on the APB bus then we must read the APB bus to 133 * flush the write operation in apb bus. This will avoid peripheral 134 * access after disabling clock. Since the reset driver has no 135 * knowledge of which reset IDs represent which devices, simply do 136 * this all the time. 137 */ 138 tegra_read_chipid(); 139 140 writel_relaxed(BIT(id % 32), 141 clk_base + periph_regs[id / 32].rst_set_reg); 142 143 return 0; 144} 145 146static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, 147 unsigned long id) 148{ 149 writel_relaxed(BIT(id % 32), 150 clk_base + periph_regs[id / 32].rst_clr_reg); 151 152 return 0; 153} 154 155struct tegra_clk_periph_regs *get_reg_bank(int clkid) 156{ 157 int reg_bank = clkid / 32; 158 159 if (reg_bank < periph_banks) 160 return &periph_regs[reg_bank]; 161 else { 162 WARN_ON(1); 163 return NULL; 164 } 165} 166 167struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks) 168{ 169 clk_base = regs; 170 171 if (WARN_ON(banks > ARRAY_SIZE(periph_regs))) 172 return NULL; 173 174 periph_clk_enb_refcnt = kzalloc(32 * banks * 175 sizeof(*periph_clk_enb_refcnt), GFP_KERNEL); 176 if (!periph_clk_enb_refcnt) 177 return NULL; 178 179 periph_banks = banks; 180 181 clks = kzalloc(num * sizeof(struct clk *), GFP_KERNEL); 182 if (!clks) 183 kfree(periph_clk_enb_refcnt); 184 185 clk_num = num; 186 187 return clks; 188} 189 190void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, 191 struct clk *clks[], int clk_max) 192{ 193 struct clk *clk; 194 195 for (; dup_list->clk_id < clk_max; dup_list++) { 196 clk = clks[dup_list->clk_id]; 197 dup_list->lookup.clk = clk; 198 clkdev_add(&dup_list->lookup); 199 } 200} 201 202void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, 203 struct clk *clks[], int clk_max) 204{ 205 struct clk *clk; 206 207 for (; tbl->clk_id < clk_max; tbl++) { 208 clk = clks[tbl->clk_id]; 209 if (IS_ERR_OR_NULL(clk)) 210 return; 211 212 if (tbl->parent_id < clk_max) { 213 struct clk *parent = clks[tbl->parent_id]; 214 if (clk_set_parent(clk, parent)) { 215 pr_err("%s: Failed to set parent %s of %s\n", 216 __func__, __clk_get_name(parent), 217 __clk_get_name(clk)); 218 WARN_ON(1); 219 } 220 } 221 222 if (tbl->rate) 223 if (clk_set_rate(clk, tbl->rate)) { 224 pr_err("%s: Failed to set rate %lu of %s\n", 225 __func__, tbl->rate, 226 __clk_get_name(clk)); 227 WARN_ON(1); 228 } 229 230 if (tbl->state) 231 if (clk_prepare_enable(clk)) { 232 pr_err("%s: Failed to enable %s\n", __func__, 233 __clk_get_name(clk)); 234 WARN_ON(1); 235 } 236 } 237} 238 239static struct reset_control_ops rst_ops = { 240 .assert = tegra_clk_rst_assert, 241 .deassert = tegra_clk_rst_deassert, 242}; 243 244static struct reset_controller_dev rst_ctlr = { 245 .ops = &rst_ops, 246 .owner = THIS_MODULE, 247 .of_reset_n_cells = 1, 248}; 249 250void __init tegra_add_of_provider(struct device_node *np) 251{ 252 int i; 253 254 for (i = 0; i < clk_num; i++) { 255 if (IS_ERR(clks[i])) { 256 pr_err 257 ("Tegra clk %d: register failed with %ld\n", 258 i, PTR_ERR(clks[i])); 259 } 260 if (!clks[i]) 261 clks[i] = ERR_PTR(-EINVAL); 262 } 263 264 clk_data.clks = clks; 265 clk_data.clk_num = clk_num; 266 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 267 268 rst_ctlr.of_node = np; 269 rst_ctlr.nr_resets = clk_num * 32; 270 reset_controller_register(&rst_ctlr); 271} 272 273void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num) 274{ 275 int i; 276 277 for (i = 0; i < num; i++, dev_clks++) 278 clk_register_clkdev(clks[dev_clks->dt_id], dev_clks->con_id, 279 dev_clks->dev_id); 280 281 for (i = 0; i < clk_num; i++) { 282 if (!IS_ERR_OR_NULL(clks[i])) 283 clk_register_clkdev(clks[i], __clk_get_name(clks[i]), 284 "tegra-clk-debug"); 285 } 286} 287 288struct clk ** __init tegra_lookup_dt_id(int clk_id, 289 struct tegra_clk *tegra_clk) 290{ 291 if (tegra_clk[clk_id].present) 292 return &clks[tegra_clk[clk_id].dt_id]; 293 else 294 return NULL; 295} 296 297tegra_clk_apply_init_table_func tegra_clk_apply_init_table; 298 299void __init tegra_clocks_apply_init_table(void) 300{ 301 if (!tegra_clk_apply_init_table) 302 return; 303 304 tegra_clk_apply_init_table(); 305} 306