brintos

brintos / linux-shallow public Read only

0
0
Text · 10.1 KiB · 1903734 Raw
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