[PATCH v5 09/10] clk: tegra: Implement clocks for Tegra114
Prashant Gaikwad
pgaikwad at nvidia.com
Mon Feb 4 18:08:55 EST 2013
On Friday 01 February 2013 03:48 PM, Peter De Schrijver wrote:
> Implement most clocks for Tegra114. The super clocks for the CPU complex
> are still missing and will be implemented in a future version.
>
> Signed-off-by: Peter De Schrijver <pdeschrijver at nvidia.com>
> ---
> drivers/clk/tegra/Makefile | 1 +
> drivers/clk/tegra/clk-tegra114.c | 2002 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 2003 insertions(+), 0 deletions(-)
> create mode 100644 drivers/clk/tegra/clk-tegra114.c
>
> diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
> index 2b41b0f..f49fac2 100644
> --- a/drivers/clk/tegra/Makefile
> +++ b/drivers/clk/tegra/Makefile
> @@ -9,3 +9,4 @@ obj-y += clk-super.o
>
> obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
> obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
> +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> new file mode 100644
> index 0000000..f8165d2
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -0,0 +1,2002 @@
> +/*
> + * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/delay.h>
> +#include <linux/clk/tegra.h>
> +
> +#include "clk.h"
> +
> +#define RST_DEVICES_L 0x004
> +#define RST_DEVICES_H 0x008
> +#define RST_DEVICES_U 0x00C
> +#define RST_DEVICES_V 0x358
> +#define RST_DEVICES_W 0x35C
> +#define RST_DEVICES_X 0x28C
> +#define RST_DEVICES_SET_L 0x300
> +#define RST_DEVICES_CLR_L 0x304
> +#define RST_DEVICES_SET_H 0x308
> +#define RST_DEVICES_CLR_H 0x30c
> +#define RST_DEVICES_SET_U 0x310
> +#define RST_DEVICES_CLR_U 0x314
> +#define RST_DEVICES_SET_V 0x430
> +#define RST_DEVICES_CLR_V 0x434
> +#define RST_DEVICES_SET_W 0x438
> +#define RST_DEVICES_CLR_W 0x43c
> +#define RST_DEVICES_NUM 5
RST_DEVICES_SET/CLR_X?
> +
> +#define CLK_OUT_ENB_L 0x010
> +#define CLK_OUT_ENB_H 0x014
> +#define CLK_OUT_ENB_U 0x018
> +#define CLK_OUT_ENB_V 0x360
> +#define CLK_OUT_ENB_W 0x364
> +#define CLK_OUT_ENB_X 0x280
> +#define CLK_OUT_ENB_SET_L 0x320
> +#define CLK_OUT_ENB_CLR_L 0x324
> +#define CLK_OUT_ENB_SET_H 0x328
> +#define CLK_OUT_ENB_CLR_H 0x32c
> +#define CLK_OUT_ENB_SET_U 0x330
> +#define CLK_OUT_ENB_CLR_U 0x334
> +#define CLK_OUT_ENB_SET_V 0x440
> +#define CLK_OUT_ENB_CLR_V 0x444
> +#define CLK_OUT_ENB_SET_W 0x448
> +#define CLK_OUT_ENB_CLR_W 0x44c
> +#define CLK_OUT_ENB_SET_X 0x284
> +#define CLK_OUT_ENB_CLR_X 0x288
> +#define CLK_OUT_ENB_NUM 6
<snip>
> +
> + /* dsia */
> + clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
> + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
> + clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
> + clks[dsia_mux] = clk;
> + clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
> + 0, 48, &periph_h_regs,
> + periph_clk_enb_refcnt);
> + clk_register_clkdev(clk, "dsia", "tegradc.0");
> + clks[dsia] = clk;
> +
> + /* dsib */
> + clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
> + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
> + clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
> + clks[dsib_mux] = clk;
> + clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
> + 0, 82, &periph_u_regs,
> + periph_clk_enb_refcnt);
> + clk_register_clkdev(clk, "dsib", "tegradc.1");
> + clks[dsib] = clk;
> +
Can we use periph no div clock here for dsia and dsib?
> + /* xusb_hs_src */
> + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
> + val |= BIT(25); /* always select PLLU_60M */
> + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
> +
> + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
> + 1, 1);
> + clks[xusb_hs_src] = clk;
> +
With device tree we can directly use pll_u_60M, no need to register
clock with fixed factor 1.
Same comment for dis1-fixed, dsi2-fixed and mipi-cal-fast clocks.
> + /* xusb_host */
> + clk = tegra_clk_register_periph_gate("xusb_host", "xusb_host_src", 0,
> + clk_base, 0, 89, &periph_u_regs,
> + periph_clk_enb_refcnt);
> + clk_register_clkdev(clk, "tegra_xhci", "host");
> + clks[xusb_host] = clk;
> +
> + /* xusb_ss */
> + clk = tegra_clk_register_periph_gate("xusb_ss", "xusb_ss_src", 0,
> + clk_base, 0, 156, &periph_w_regs,
> + periph_clk_enb_refcnt);
> + clk_register_clkdev(clk, "tegra_xhci", "ss");
> + clks[xusb_host] = clk;
> +
> + /* xusb_dev */
> + clk = tegra_clk_register_periph_gate("xusb_dev", "xusb_dev_src", 0,
> + clk_base, 0, 95, &periph_u_regs,
> + periph_clk_enb_refcnt);
> + clk_register_clkdev(clk, "tegra_xhci", "dev");
clks[xusb_dev] = clk;
> +
> + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
> + data = &tegra_periph_clk_list[i];
> + clk = tegra_clk_register_periph(data->name, data->parent_names,
> + data->num_parents, &data->periph,
> + clk_base, data->offset, data->flags);
> + clk_register_clkdev(clk, data->con_id, data->dev_id);
> + clks[data->clk_id] = clk;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) {
> + data = &tegra_periph_nodiv_clk_list[i];
> + clk = tegra_clk_register_periph_nodiv(data->name,
> + data->parent_names, data->num_parents,
> + &data->periph, clk_base, data->offset);
> + clk_register_clkdev(clk, data->con_id, data->dev_id);
> + clks[data->clk_id] = clk;
> + }
> +}
> +
> +static struct tegra_cpu_car_ops tegra114_cpu_car_ops;
> +
> +static const struct of_device_id pmc_match[] __initconst = {
> + { .compatible = "nvidia,tegra114-pmc" },
> + {},
> +};
> +
> +static __initdata struct tegra_clk_init_table init_table[] = {
> + {uartd, pll_p, 408000000, 1},
> + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
> +};
> +
> +void __init tegra114_clock_init(struct device_node *np)
> +{
> + struct device_node *node;
> + int i;
> +
> + clk_base = of_iomap(np, 0);
> + if (!clk_base) {
> + pr_err("ioremap tegra114 CAR failed\n");
> + return;
> + }
> +
> + node = of_find_matching_node(NULL, pmc_match);
> + if (!node) {
> + pr_err("Failed to find pmc node\n");
> + WARN_ON(1);
> + return;
> + }
> +
> + pmc_base = of_iomap(node, 0);
> + if (!pmc_base) {
> + pr_err("Can't map pmc registers\n");
> + WARN_ON(1);
> + return;
> + }
> +
> + if (tegra114_osc_clk_init(clk_base) < 0)
> + return;
> +
> + tegra114_fixed_clk_init(clk_base);
> + tegra114_pll_init(clk_base, pmc_base);
> + tegra114_periph_clk_init(clk_base);
> + tegra114_audio_clk_init(clk_base);
> + tegra114_pmc_clk_init(pmc_base);
> +
> + for (i = 0; i < ARRAY_SIZE(clks); i++) {
> + if (IS_ERR(clks[i])) {
> + pr_err
> + ("Tegra114 clk %d: register failed with %ld\n",
> + i, PTR_ERR(clks[i]));
> + }
> + if (!clks[i])
> + clks[i] = ERR_PTR(-EINVAL);
> + }
> +
> + clk_data.clks = clks;
> + clk_data.clk_num = ARRAY_SIZE(clks);
> + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +
> + tegra_init_from_table(init_table, clks, clk_max);
> +
> + tegra_cpu_car_ops = &tegra114_cpu_car_ops;
> +}
>
More information about the devicetree-discuss
mailing list