Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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