454 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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/of_platform.h>13#include <linux/clk/tegra.h>14#include <linux/platform_device.h>15#include <linux/pm_runtime.h>16#include <linux/reset-controller.h>17#include <linux/string_helpers.h>18 19#include <soc/tegra/fuse.h>20 21#include "clk.h"22 23/* Global data of Tegra CPU CAR ops */24static struct device_node *tegra_car_np;25static struct tegra_cpu_car_ops dummy_car_ops;26struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops;27 28int *periph_clk_enb_refcnt;29static int periph_banks;30static u32 *periph_state_ctx;31static struct clk **clks;32static int clk_num;33static struct clk_onecell_data clk_data;34 35/* Handlers for SoC-specific reset lines */36static int (*special_reset_assert)(unsigned long);37static int (*special_reset_deassert)(unsigned long);38static unsigned int num_special_reset;39 40static const struct tegra_clk_periph_regs periph_regs[] = {41 [0] = {42 .enb_reg = CLK_OUT_ENB_L,43 .enb_set_reg = CLK_OUT_ENB_SET_L,44 .enb_clr_reg = CLK_OUT_ENB_CLR_L,45 .rst_reg = RST_DEVICES_L,46 .rst_set_reg = RST_DEVICES_SET_L,47 .rst_clr_reg = RST_DEVICES_CLR_L,48 },49 [1] = {50 .enb_reg = CLK_OUT_ENB_H,51 .enb_set_reg = CLK_OUT_ENB_SET_H,52 .enb_clr_reg = CLK_OUT_ENB_CLR_H,53 .rst_reg = RST_DEVICES_H,54 .rst_set_reg = RST_DEVICES_SET_H,55 .rst_clr_reg = RST_DEVICES_CLR_H,56 },57 [2] = {58 .enb_reg = CLK_OUT_ENB_U,59 .enb_set_reg = CLK_OUT_ENB_SET_U,60 .enb_clr_reg = CLK_OUT_ENB_CLR_U,61 .rst_reg = RST_DEVICES_U,62 .rst_set_reg = RST_DEVICES_SET_U,63 .rst_clr_reg = RST_DEVICES_CLR_U,64 },65 [3] = {66 .enb_reg = CLK_OUT_ENB_V,67 .enb_set_reg = CLK_OUT_ENB_SET_V,68 .enb_clr_reg = CLK_OUT_ENB_CLR_V,69 .rst_reg = RST_DEVICES_V,70 .rst_set_reg = RST_DEVICES_SET_V,71 .rst_clr_reg = RST_DEVICES_CLR_V,72 },73 [4] = {74 .enb_reg = CLK_OUT_ENB_W,75 .enb_set_reg = CLK_OUT_ENB_SET_W,76 .enb_clr_reg = CLK_OUT_ENB_CLR_W,77 .rst_reg = RST_DEVICES_W,78 .rst_set_reg = RST_DEVICES_SET_W,79 .rst_clr_reg = RST_DEVICES_CLR_W,80 },81 [5] = {82 .enb_reg = CLK_OUT_ENB_X,83 .enb_set_reg = CLK_OUT_ENB_SET_X,84 .enb_clr_reg = CLK_OUT_ENB_CLR_X,85 .rst_reg = RST_DEVICES_X,86 .rst_set_reg = RST_DEVICES_SET_X,87 .rst_clr_reg = RST_DEVICES_CLR_X,88 },89 [6] = {90 .enb_reg = CLK_OUT_ENB_Y,91 .enb_set_reg = CLK_OUT_ENB_SET_Y,92 .enb_clr_reg = CLK_OUT_ENB_CLR_Y,93 .rst_reg = RST_DEVICES_Y,94 .rst_set_reg = RST_DEVICES_SET_Y,95 .rst_clr_reg = RST_DEVICES_CLR_Y,96 },97};98 99static void __iomem *clk_base;100 101static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev,102 unsigned long id)103{104 /*105 * If peripheral is on the APB bus then we must read the APB bus to106 * flush the write operation in apb bus. This will avoid peripheral107 * access after disabling clock. Since the reset driver has no108 * knowledge of which reset IDs represent which devices, simply do109 * this all the time.110 */111 tegra_read_chipid();112 113 if (id < periph_banks * 32) {114 writel_relaxed(BIT(id % 32),115 clk_base + periph_regs[id / 32].rst_set_reg);116 return 0;117 } else if (id < periph_banks * 32 + num_special_reset) {118 return special_reset_assert(id);119 }120 121 return -EINVAL;122}123 124static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev,125 unsigned long id)126{127 if (id < periph_banks * 32) {128 writel_relaxed(BIT(id % 32),129 clk_base + periph_regs[id / 32].rst_clr_reg);130 return 0;131 } else if (id < periph_banks * 32 + num_special_reset) {132 return special_reset_deassert(id);133 }134 135 return -EINVAL;136}137 138static int tegra_clk_rst_reset(struct reset_controller_dev *rcdev,139 unsigned long id)140{141 int err;142 143 err = tegra_clk_rst_assert(rcdev, id);144 if (err)145 return err;146 147 udelay(1);148 149 return tegra_clk_rst_deassert(rcdev, id);150}151 152const struct tegra_clk_periph_regs *get_reg_bank(int clkid)153{154 int reg_bank = clkid / 32;155 156 if (reg_bank < periph_banks)157 return &periph_regs[reg_bank];158 else {159 WARN_ON(1);160 return NULL;161 }162}163 164void tegra_clk_set_pllp_out_cpu(bool enable)165{166 u32 val;167 168 val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);169 if (enable)170 val |= CLK_ENB_PLLP_OUT_CPU;171 else172 val &= ~CLK_ENB_PLLP_OUT_CPU;173 174 writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);175}176 177void tegra_clk_periph_suspend(void)178{179 unsigned int i, idx;180 181 idx = 0;182 for (i = 0; i < periph_banks; i++, idx++)183 periph_state_ctx[idx] =184 readl_relaxed(clk_base + periph_regs[i].enb_reg);185 186 for (i = 0; i < periph_banks; i++, idx++)187 periph_state_ctx[idx] =188 readl_relaxed(clk_base + periph_regs[i].rst_reg);189}190 191void tegra_clk_periph_resume(void)192{193 unsigned int i, idx;194 195 idx = 0;196 for (i = 0; i < periph_banks; i++, idx++)197 writel_relaxed(periph_state_ctx[idx],198 clk_base + periph_regs[i].enb_reg);199 /*200 * All non-boot peripherals will be in reset state on resume.201 * Wait for 5us of reset propagation delay before de-asserting202 * the peripherals based on the saved context.203 */204 fence_udelay(5, clk_base);205 206 for (i = 0; i < periph_banks; i++, idx++)207 writel_relaxed(periph_state_ctx[idx],208 clk_base + periph_regs[i].rst_reg);209 210 fence_udelay(2, clk_base);211}212 213static int tegra_clk_periph_ctx_init(int banks)214{215 periph_state_ctx = kcalloc(2 * banks, sizeof(*periph_state_ctx),216 GFP_KERNEL);217 if (!periph_state_ctx)218 return -ENOMEM;219 220 return 0;221}222 223struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)224{225 clk_base = regs;226 227 if (WARN_ON(banks > ARRAY_SIZE(periph_regs)))228 return NULL;229 230 periph_clk_enb_refcnt = kcalloc(32 * banks,231 sizeof(*periph_clk_enb_refcnt),232 GFP_KERNEL);233 if (!periph_clk_enb_refcnt)234 return NULL;235 236 periph_banks = banks;237 238 clks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);239 if (!clks) {240 kfree(periph_clk_enb_refcnt);241 return NULL;242 }243 244 clk_num = num;245 246 if (IS_ENABLED(CONFIG_PM_SLEEP)) {247 if (tegra_clk_periph_ctx_init(banks)) {248 kfree(periph_clk_enb_refcnt);249 kfree(clks);250 return NULL;251 }252 }253 254 return clks;255}256 257void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,258 struct clk *clks[], int clk_max)259{260 struct clk *clk;261 262 for (; dup_list->clk_id < clk_max; dup_list++) {263 clk = clks[dup_list->clk_id];264 dup_list->lookup.clk = clk;265 clkdev_add(&dup_list->lookup);266 }267}268 269void tegra_init_from_table(struct tegra_clk_init_table *tbl,270 struct clk *clks[], int clk_max)271{272 struct clk *clk;273 274 for (; tbl->clk_id < clk_max; tbl++) {275 clk = clks[tbl->clk_id];276 if (IS_ERR_OR_NULL(clk)) {277 pr_err("%s: invalid entry %ld in clks array for id %d\n",278 __func__, PTR_ERR(clk), tbl->clk_id);279 WARN_ON(1);280 281 continue;282 }283 284 if (tbl->parent_id < clk_max) {285 struct clk *parent = clks[tbl->parent_id];286 if (clk_set_parent(clk, parent)) {287 pr_err("%s: Failed to set parent %s of %s\n",288 __func__, __clk_get_name(parent),289 __clk_get_name(clk));290 WARN_ON(1);291 }292 }293 294 if (tbl->rate)295 if (clk_set_rate(clk, tbl->rate)) {296 pr_err("%s: Failed to set rate %lu of %s\n",297 __func__, tbl->rate,298 __clk_get_name(clk));299 WARN_ON(1);300 }301 302 if (tbl->state)303 if (clk_prepare_enable(clk)) {304 pr_err("%s: Failed to enable %s\n", __func__,305 __clk_get_name(clk));306 WARN_ON(1);307 }308 }309}310 311static const struct reset_control_ops rst_ops = {312 .assert = tegra_clk_rst_assert,313 .deassert = tegra_clk_rst_deassert,314 .reset = tegra_clk_rst_reset,315};316 317static struct reset_controller_dev rst_ctlr = {318 .ops = &rst_ops,319 .owner = THIS_MODULE,320 .of_reset_n_cells = 1,321};322 323void __init tegra_add_of_provider(struct device_node *np,324 void *clk_src_onecell_get)325{326 int i;327 328 tegra_car_np = np;329 330 for (i = 0; i < clk_num; i++) {331 if (IS_ERR(clks[i])) {332 pr_err333 ("Tegra clk %d: register failed with %ld\n",334 i, PTR_ERR(clks[i]));335 }336 if (!clks[i])337 clks[i] = ERR_PTR(-EINVAL);338 }339 340 clk_data.clks = clks;341 clk_data.clk_num = clk_num;342 of_clk_add_provider(np, clk_src_onecell_get, &clk_data);343 344 rst_ctlr.of_node = np;345 rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;346 reset_controller_register(&rst_ctlr);347}348 349void __init tegra_init_special_resets(unsigned int num,350 int (*assert)(unsigned long),351 int (*deassert)(unsigned long))352{353 num_special_reset = num;354 special_reset_assert = assert;355 special_reset_deassert = deassert;356}357 358void tegra_register_devclks(struct tegra_devclk *dev_clks, int num)359{360 int i;361 362 for (i = 0; i < num; i++, dev_clks++)363 clk_register_clkdev(clks[dev_clks->dt_id], dev_clks->con_id,364 dev_clks->dev_id);365 366 for (i = 0; i < clk_num; i++) {367 if (!IS_ERR_OR_NULL(clks[i]))368 clk_register_clkdev(clks[i], __clk_get_name(clks[i]),369 "tegra-clk-debug");370 }371}372 373struct clk ** __init tegra_lookup_dt_id(int clk_id,374 struct tegra_clk *tegra_clk)375{376 if (tegra_clk[clk_id].present)377 return &clks[tegra_clk[clk_id].dt_id];378 else379 return NULL;380}381 382static struct device_node *tegra_clk_get_of_node(struct clk_hw *hw)383{384 struct device_node *np;385 char *node_name;386 387 node_name = kstrdup_and_replace(hw->init->name, '_', '-', GFP_KERNEL);388 if (!node_name)389 return NULL;390 391 for_each_child_of_node(tegra_car_np, np) {392 if (!strcmp(np->name, node_name))393 break;394 }395 396 kfree(node_name);397 398 return np;399}400 401struct clk *tegra_clk_dev_register(struct clk_hw *hw)402{403 struct platform_device *pdev, *parent;404 const char *dev_name = NULL;405 struct device *dev = NULL;406 struct device_node *np;407 408 np = tegra_clk_get_of_node(hw);409 410 if (!of_device_is_available(np))411 goto put_node;412 413 dev_name = kasprintf(GFP_KERNEL, "tegra_clk_%s", hw->init->name);414 if (!dev_name)415 goto put_node;416 417 parent = of_find_device_by_node(tegra_car_np);418 if (parent) {419 pdev = of_platform_device_create(np, dev_name, &parent->dev);420 put_device(&parent->dev);421 422 if (!pdev) {423 pr_err("%s: failed to create device for %pOF\n",424 __func__, np);425 goto free_name;426 }427 428 dev = &pdev->dev;429 pm_runtime_enable(dev);430 } else {431 WARN(1, "failed to find device for %pOF\n", tegra_car_np);432 }433 434free_name:435 kfree(dev_name);436put_node:437 of_node_put(np);438 439 return clk_register(dev, hw);440}441 442tegra_clk_apply_init_table_func tegra_clk_apply_init_table;443 444static int __init tegra_clocks_apply_init_table(void)445{446 if (!tegra_clk_apply_init_table)447 return 0;448 449 tegra_clk_apply_init_table();450 451 return 0;452}453arch_initcall(tegra_clocks_apply_init_table);454