Linux-Devicetree Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
@ 2019-11-27  4:59 Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 01/11] dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids Sowjanya Komatineni
                   ` (11 more replies)
  0 siblings, 12 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
are currently registered by Tegra clock driver using clk_regiser_mux and
clk_register_gate which performs direct Tegra PMC register access.

When Tegra PMC is in secure mode, any access from non-secure world will
not go through.

This patch series adds these Tegra PMC clocks and blink controls to Tegra
PMC driver with PMC as clock provider and removed them from Tegra clock
driver. This also adds PMC specific clock id's to use in device tree and
removed clock ids of PMC clock from Tegra clock driver.

This series also includes patch to update clock provider from tegra_car
to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 from PMC.

[v2]:	Changes between v1 and v2 are
	- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
	  blink controls to Tegra PMC driver and removing clk-tegra-pmc.
	- feedback related to pmc clocks in Tegra PMC driver from v1
	- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
	  by the clock driver using helper functions from Tegra PMC.

 	  Note:
	  To use helper functions from PMC driver, PMC early init need to
	  happen prior to using helper functions and these helper functions are
	  for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
	  clock registration which happen in clock_init prior to Tegra PMC
	  probe.
	  Moving PLLM/PLLE clocks registration to happen after Tegra PMC
	  impacts other clocks EMC, MC and corresponding tegra_emc_init and
	  tegra_mc_init.
	  This implementation of configuring PMC registers thru helper
	  functions in clock driver needs proper changes across PMC, Clock,
	  EMC and MC inits to have it work across all Tegra platforms.

	  Currently PLLM Override is not enabled in the bootloader so proper
	  patches for this fix will be taken care separately.

[v1]:	v1 includes patches for below fixes.
	- adding clk_out_1, clk_out_2, clk_out_3, blink controls to Tegra PMC
	  driver and removing clk-tegra-pmc.
	- updated clock provider from tegra_car to pmc in the device tree
	  tegra210-smaug.dts that uses clk_out_2.
	- Added helper functions in PMC driver for WB0 PLLM overrides and PLLE
	  IDDQ programming to use by clock driver and updated clock driver to
	  use these helper functions and removed direct PMC access from clock
	  driver and all pmc base address references in clock driver.


Sowjanya Komatineni (11):
  dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids
  soc: tegra: Add Tegra PMC clock registrations into PMC driver
  dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control
  soc: pmc: Add blink output clock registration to Tegra PMC
  clk: tegra: Remove tegra_pmc_clk_init along with clk ids
  dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  arm: tegra: Add clock-cells property to Tegra PMC
  arm64: tegra: Add clock-cells property to Tegra pmc
  dt-bindings: Add Tegra PMC clock configuration bindings
  arm64: tegra: smaug: Change clk_out_2 provider from tegra_car to pmc
  ASoC: nau8825: change Tegra clk_out_2 provider from tegra_car to pmc

 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      |  45 ++-
 .../devicetree/bindings/sound/nau8825.txt          |   2 +-
 arch/arm/boot/dts/tegra114.dtsi                    |   4 +-
 arch/arm/boot/dts/tegra124.dtsi                    |   4 +-
 arch/arm/boot/dts/tegra20.dtsi                     |   4 +-
 arch/arm/boot/dts/tegra30.dtsi                     |   4 +-
 arch/arm64/boot/dts/nvidia/tegra132.dtsi           |   4 +-
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |   2 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |   2 +
 arch/arm64/boot/dts/nvidia/tegra210-smaug.dts      |   2 +-
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           |   2 +
 drivers/clk/tegra/Makefile                         |   1 -
 drivers/clk/tegra/clk-id.h                         |   7 -
 drivers/clk/tegra/clk-tegra-pmc.c                  | 122 -------
 drivers/clk/tegra/clk-tegra114.c                   |  11 -
 drivers/clk/tegra/clk-tegra124.c                   |  27 +-
 drivers/clk/tegra/clk-tegra20.c                    |   4 -
 drivers/clk/tegra/clk-tegra210.c                   |  11 -
 drivers/clk/tegra/clk-tegra30.c                    |  12 -
 drivers/clk/tegra/clk.h                            |   1 -
 drivers/soc/tegra/pmc.c                            | 379 +++++++++++++++++++++
 include/dt-bindings/clock/tegra114-car.h           |  14 +-
 include/dt-bindings/clock/tegra124-car-common.h    |  14 +-
 include/dt-bindings/clock/tegra20-car.h            |   2 +-
 include/dt-bindings/clock/tegra210-car.h           |  14 +-
 include/dt-bindings/clock/tegra30-car.h            |  14 +-
 include/dt-bindings/soc/tegra-pmc.h                |  19 ++
 27 files changed, 501 insertions(+), 226 deletions(-)
 delete mode 100644 drivers/clk/tegra/clk-tegra-pmc.c
 create mode 100644 include/dt-bindings/soc/tegra-pmc.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 01/11] dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra PMC has clk_out_1, clk_out_2, clk_out_3 clocks and each of
these clocks has mux and a gate as a part of PMC controller.

This patch adds ids for each of these PMC clock mux and gates to
use with the devicetree.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 include/dt-bindings/soc/tegra-pmc.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 include/dt-bindings/soc/tegra-pmc.h

diff --git a/include/dt-bindings/soc/tegra-pmc.h b/include/dt-bindings/soc/tegra-pmc.h
new file mode 100644
index 000000000000..705ee8083070
--- /dev/null
+++ b/include/dt-bindings/soc/tegra-pmc.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_SOC_TEGRA_PMC_H
+#define _DT_BINDINGS_SOC_TEGRA_PMC_H
+
+#define TEGRA_PMC_CLK_OUT_1_MUX		0
+#define TEGRA_PMC_CLK_OUT_1		1
+#define TEGRA_PMC_CLK_OUT_2_MUX		2
+#define TEGRA_PMC_CLK_OUT_2		3
+#define TEGRA_PMC_CLK_OUT_3_MUX		4
+#define TEGRA_PMC_CLK_OUT_3		5
+
+#define TEGRA_PMC_CLK_MAX		6
+
+#endif	/* _DT_BINDINGS_SOC_TEGRA_PMC_H */
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 01/11] dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27 14:32   ` Dmitry Osipenko
                     ` (2 more replies)
  2019-11-27  4:59 ` [PATCH v2 03/11] dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control Sowjanya Komatineni
                   ` (9 subsequent siblings)
  11 siblings, 3 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
mux and gate for each of these clocks.

Currently these PMC clocks are registered by Tegra clock driver using
clk_register_mux and clk_register_gate by passing PMC base address
and register offsets and PMC programming for these clocks happens
through direct PMC access by the clock driver.

With this, when PMC is in secure mode any direct PMC access from the
non-secure world does not go through and these clocks will not be
functional.

This patch adds these clocks registration with PMC as a clock provider
for these clocks. clk_ops callback implementations for these clocks
uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
in secure mode and non-secure mode.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 330 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index ea0e11a09c12..a353f6d0a832 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -13,6 +13,9 @@
 
 #include <linux/arm-smccc.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/clk-conf.h>
 #include <linux/clk/tegra.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
@@ -48,6 +51,7 @@
 #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
 #include <dt-bindings/gpio/tegra186-gpio.h>
 #include <dt-bindings/gpio/tegra194-gpio.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 #define PMC_CNTRL			0x0
 #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
@@ -100,6 +104,7 @@
 #define PMC_WAKE2_STATUS		0x168
 #define PMC_SW_WAKE2_STATUS		0x16c
 
+#define PMC_CLK_OUT_CNTRL		0x1a8
 #define PMC_SENSOR_CTRL			0x1b0
 #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
 #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
@@ -155,6 +160,91 @@
 #define  TEGRA_SMC_PMC_READ	0xaa
 #define  TEGRA_SMC_PMC_WRITE	0xbb
 
+struct pmc_clk_mux {
+	struct clk_hw	hw;
+	unsigned long	offs;
+	u32		mask;
+	u32		shift;
+};
+
+#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
+
+struct pmc_clk_gate {
+	struct clk_hw	hw;
+	unsigned long	offs;
+	u32		shift;
+};
+
+#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
+
+struct pmc_clk_init_data {
+	char *mux_name;
+	char *gate_name;
+	const char **parents;
+	int num_parents;
+	int mux_id;
+	int gate_id;
+	char *dev_name;
+	u8 mux_shift;
+	u8 gate_shift;
+	u8 init_parent_index;
+	int init_state;
+};
+
+static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
+	"clk_m_div4", "extern1",
+};
+
+static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
+	"clk_m_div4", "extern2",
+};
+
+static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
+	"clk_m_div4", "extern3",
+};
+
+static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
+	{
+		.mux_name = "clk_out_1_mux",
+		.gate_name = "clk_out_1",
+		.parents = clk_out1_parents,
+		.num_parents = ARRAY_SIZE(clk_out1_parents),
+		.mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
+		.gate_id = TEGRA_PMC_CLK_OUT_1,
+		.dev_name = "extern1",
+		.mux_shift = 6,
+		.gate_shift = 2,
+		.init_parent_index = 3,
+		.init_state = 1,
+	},
+	{
+		.mux_name = "clk_out_2_mux",
+		.gate_name = "clk_out_2",
+		.parents = clk_out2_parents,
+		.num_parents = ARRAY_SIZE(clk_out2_parents),
+		.mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
+		.gate_id = TEGRA_PMC_CLK_OUT_2,
+		.dev_name = "extern2",
+		.mux_shift = 14,
+		.gate_shift = 10,
+		.init_parent_index = 0,
+		.init_state = 0,
+	},
+	{
+		.mux_name = "clk_out_3_mux",
+		.gate_name = "clk_out_3",
+		.parents = clk_out3_parents,
+		.num_parents = ARRAY_SIZE(clk_out3_parents),
+		.mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
+		.gate_id = TEGRA_PMC_CLK_OUT_3,
+		.dev_name = "extern3",
+		.mux_shift = 22,
+		.gate_shift = 18,
+		.init_parent_index = 0,
+		.init_state = 0,
+	},
+};
+
 struct tegra_powergate {
 	struct generic_pm_domain genpd;
 	struct tegra_pmc *pmc;
@@ -254,6 +344,9 @@ struct tegra_pmc_soc {
 	 */
 	const struct tegra_wake_event *wake_events;
 	unsigned int num_wake_events;
+
+	struct pmc_clk_init_data *pmc_clks_data;
+	unsigned int num_pmc_clks;
 };
 
 static const char * const tegra186_reset_sources[] = {
@@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
 	return NOTIFY_OK;
 }
 
+static void pmc_clk_fence_udelay(u32 offset)
+{
+	tegra_pmc_readl(pmc, offset);
+	/* pmc clk propagation delay 2 us */
+	udelay(2);
+}
+
+static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
+{
+	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 val;
+
+	val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
+	val &= mux->mask;
+
+	if (val >= num_parents)
+		return -EINVAL;
+
+	return val;
+}
+
+static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
+	u32 val;
+
+	val = tegra_pmc_readl(pmc, mux->offs);
+	val &= ~(mux->mask << mux->shift);
+	val |= index << mux->shift;
+	tegra_pmc_writel(pmc, val, mux->offs);
+	pmc_clk_fence_udelay(mux->offs);
+
+	return 0;
+}
+
+static const struct clk_ops pmc_clk_mux_ops = {
+	.get_parent = pmc_clk_mux_get_parent,
+	.set_parent = pmc_clk_mux_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk *
+tegra_pmc_clk_mux_register(const char *name, const char * const *parent_names,
+			   int num_parents, unsigned long flags,
+			   unsigned long offset, u32 shift, u32 mask)
+{
+	struct clk_init_data init;
+	struct pmc_clk_mux *mux;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &pmc_clk_mux_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = flags;
+
+	mux->hw.init = &init;
+	mux->offs = offset;
+	mux->mask = mask;
+	mux->shift = shift;
+
+	return clk_register(NULL, &mux->hw);
+}
+
+static int pmc_clk_is_enabled(struct clk_hw *hw)
+{
+	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
+
+	return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
+}
+
+static void pmc_clk_set_state(struct clk_hw *hw, int state)
+{
+	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
+	u32 val;
+
+	val = tegra_pmc_readl(pmc, gate->offs);
+	val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
+	tegra_pmc_writel(pmc, val, gate->offs);
+	pmc_clk_fence_udelay(gate->offs);
+}
+
+static int pmc_clk_enable(struct clk_hw *hw)
+{
+	pmc_clk_set_state(hw, 1);
+
+	return 0;
+}
+
+static void pmc_clk_disable(struct clk_hw *hw)
+{
+	pmc_clk_set_state(hw, 0);
+}
+
+static const struct clk_ops pmc_clk_gate_ops = {
+	.is_enabled = pmc_clk_is_enabled,
+	.enable = pmc_clk_enable,
+	.disable = pmc_clk_disable,
+};
+
+static struct clk *
+tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
+			    unsigned long flags, unsigned long offset,
+			    u32 shift)
+{
+	struct clk_init_data init;
+	struct pmc_clk_gate *gate;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &pmc_clk_gate_ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.flags = flags;
+
+	gate->hw.init = &init;
+	gate->offs = offset;
+	gate->shift = shift;
+
+	return clk_register(NULL, &gate->hw);
+}
+
+static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
+				     struct device_node *np)
+{
+	struct clk *clkmux, *clk, *parent;
+	struct clk_onecell_data *clk_data;
+	unsigned int num_clks;
+	int i, ret;
+
+	/* each pmc clock output has a mux and a gate */
+	num_clks = pmc->soc->num_pmc_clks * 2;
+
+	if (!num_clks)
+		return;
+
+	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX, sizeof(*clk_data->clks),
+				 GFP_KERNEL);
+	if (!clk_data->clks)
+		goto free_clkdata;
+
+	clk_data->clk_num = num_clks;
+
+	for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
+		struct pmc_clk_init_data *data;
+
+		data = pmc->soc->pmc_clks_data + i;
+
+		clkmux = tegra_pmc_clk_mux_register(data->mux_name,
+						    data->parents,
+						    data->num_parents,
+						    CLK_SET_RATE_NO_REPARENT |
+						    CLK_SET_RATE_PARENT,
+						    PMC_CLK_OUT_CNTRL,
+						    data->mux_shift, 3);
+		if (IS_ERR(clkmux))
+			goto free_clks;
+
+		clk_data->clks[data->mux_id] = clkmux;
+
+		clk = tegra_pmc_clk_gate_register(data->gate_name,
+						  data->mux_name,
+						  CLK_SET_RATE_PARENT,
+						  PMC_CLK_OUT_CNTRL,
+						  data->gate_shift);
+		if (IS_ERR(clk))
+			goto free_clks;
+
+		clk_data->clks[data->gate_id] = clk;
+
+		ret = clk_set_parent(clk, clkmux);
+		if (ret < 0) {
+			pr_err("failed to set parent of %s to %s\n",
+			       __func__, __clk_get_name(clk),
+			       __clk_get_name(clkmux));
+		}
+
+		clk_register_clkdev(clk, data->dev_name, data->gate_name);
+
+		/* configure initial clock parent and state */
+		parent = clk_get_sys(data->gate_name,
+				     data->parents[data->init_parent_index]);
+		if (!IS_ERR(parent)) {
+			ret = clk_set_parent(clkmux, parent);
+			if (ret < 0) {
+				pr_err("failed to set parent of %s to %s\n",
+				       __func__, __clk_get_name(clkmux),
+				       __clk_get_name(parent));
+				WARN_ON(1);
+			}
+		}
+
+		if (data->init_state) {
+			if (clk_prepare_enable(clk)) {
+				pr_err("failed to enable %s\n", __func__,
+				       __clk_get_name(clk));
+				WARN_ON(1);
+			}
+		}
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+
+	return;
+
+free_clks:
+	kfree(clk_data->clks);
+free_clkdata:
+	kfree(clk_data);
+}
+
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
 	void __iomem *base;
@@ -2281,6 +2596,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 	pmc->base = base;
 	mutex_unlock(&pmc->powergates_lock);
 
+	tegra_pmc_clock_register(pmc, pdev->dev.of_node);
 	platform_set_drvdata(pdev, pmc);
 
 	return 0;
@@ -2422,6 +2738,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
 	.num_reset_sources = 0,
 	.reset_levels = NULL,
 	.num_reset_levels = 0,
+	.pmc_clks_data = NULL,
+	.num_pmc_clks = 0,
 };
 
 static const char * const tegra30_powergates[] = {
@@ -2469,6 +2787,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
 	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
 	.reset_levels = NULL,
 	.num_reset_levels = 0,
+	.pmc_clks_data = tegra_pmc_clks_data,
+	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
 };
 
 static const char * const tegra114_powergates[] = {
@@ -2520,6 +2840,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
 	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
 	.reset_levels = NULL,
 	.num_reset_levels = 0,
+	.pmc_clks_data = tegra_pmc_clks_data,
+	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
 };
 
 static const char * const tegra124_powergates[] = {
@@ -2631,6 +2953,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
 	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
 	.reset_levels = NULL,
 	.num_reset_levels = 0,
+	.pmc_clks_data = tegra_pmc_clks_data,
+	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
 };
 
 static const char * const tegra210_powergates[] = {
@@ -2745,6 +3069,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.num_reset_levels = 0,
 	.num_wake_events = ARRAY_SIZE(tegra210_wake_events),
 	.wake_events = tegra210_wake_events,
+	.pmc_clks_data = tegra_pmc_clks_data,
+	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
 };
 
 #define TEGRA186_IO_PAD_TABLE(_pad)					     \
@@ -2874,6 +3200,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
 	.num_wake_events = ARRAY_SIZE(tegra186_wake_events),
 	.wake_events = tegra186_wake_events,
+	.pmc_clks_data = NULL,
+	.num_pmc_clks = 0,
 };
 
 static const struct tegra_io_pad_soc tegra194_io_pads[] = {
@@ -2991,6 +3319,8 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
 	.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
 	.num_wake_events = ARRAY_SIZE(tegra194_wake_events),
 	.wake_events = tegra194_wake_events,
+	.pmc_clks_data = NULL,
+	.num_pmc_clks = 0,
 };
 
 static const struct of_device_id tegra_pmc_match[] = {
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 03/11] dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 01/11] dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC Sowjanya Komatineni
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra PMC has a blinking control to output 32 KHz clock to blink
pin.

This patch adds id for this blink control to use for enabling or
disabling the blink output through devicetree.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 include/dt-bindings/soc/tegra-pmc.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/dt-bindings/soc/tegra-pmc.h b/include/dt-bindings/soc/tegra-pmc.h
index 705ee8083070..6fe28516017e 100644
--- a/include/dt-bindings/soc/tegra-pmc.h
+++ b/include/dt-bindings/soc/tegra-pmc.h
@@ -12,7 +12,8 @@
 #define TEGRA_PMC_CLK_OUT_2		3
 #define TEGRA_PMC_CLK_OUT_3_MUX		4
 #define TEGRA_PMC_CLK_OUT_3		5
+#define TEGRA_PMC_CLK_BLINK		6
 
-#define TEGRA_PMC_CLK_MAX		6
+#define TEGRA_PMC_CLK_MAX		7
 
 #endif	/* _DT_BINDINGS_SOC_TEGRA_PMC_H */
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (2 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 03/11] dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-28 13:07   ` Dmitry Osipenko
  2019-11-27  4:59 ` [PATCH v2 05/11] clk: tegra: Remove tegra_pmc_clk_init along with clk ids Sowjanya Komatineni
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra PMC has blink control to output 32 Khz clock out to Tegra
blink pin. Blink pad DPD state and enable controls are part of
Tegra PMC register space.

Currently Tegra clock driver registers blink control by passing
PMC address and register offset to clk_register_gate which performs
direct PMC access during clk_ops and with this when PMC is in secure
mode, any access from non-secure world does not go through.

This patch adds blink control registration to the Tegra PMC driver
using PMC specific clock gate operations that use tegra_pmc_readl
and tegra_pmc_writel to support both secure mode and non-secure
mode PMC register access.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a353f6d0a832..1cfb7797dbd5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -61,12 +61,15 @@
 #define  PMC_CNTRL_SYSCLK_OE		BIT(11) /* system clock enable */
 #define  PMC_CNTRL_SYSCLK_POLARITY	BIT(10) /* sys clk polarity */
 #define  PMC_CNTRL_PWRREQ_POLARITY	BIT(8)
+#define  PMC_CNTRL_BLINK_EN		BIT(7)
 #define  PMC_CNTRL_MAIN_RST		BIT(4)
 
 #define PMC_WAKE_MASK			0x0c
 #define PMC_WAKE_LEVEL			0x10
 #define PMC_WAKE_STATUS			0x14
 #define PMC_SW_WAKE_STATUS		0x18
+#define PMC_DPD_PADS_ORIDE		0x1c
+#define  PMC_DPD_PADS_ORIDE_BLINK	BIT(20)
 
 #define DPD_SAMPLE			0x020
 #define  DPD_SAMPLE_ENABLE		BIT(0)
@@ -79,6 +82,7 @@
 
 #define PWRGATE_STATUS			0x38
 
+#define TEGRA210_PMC_BLINK_TIMER	0x40
 #define PMC_IMPL_E_33V_PWR		0x40
 
 #define PMC_PWR_DET			0x48
@@ -347,6 +351,8 @@ struct tegra_pmc_soc {
 
 	struct pmc_clk_init_data *pmc_clks_data;
 	unsigned int num_pmc_clks;
+	bool has_blink_output;
+	bool blink_init_state;
 };
 
 static const char * const tegra186_reset_sources[] = {
@@ -2396,6 +2402,9 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
 	/* each pmc clock output has a mux and a gate */
 	num_clks = pmc->soc->num_pmc_clks * 2;
 
+	if (pmc->soc->has_blink_output)
+		num_clks += 1;
+
 	if (!num_clks)
 		return;
 
@@ -2468,6 +2477,34 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
 		}
 	}
 
+	if (pmc->soc->has_blink_output) {
+		tegra_pmc_writel(pmc, 0x0, TEGRA210_PMC_BLINK_TIMER);
+		clk = tegra_pmc_clk_gate_register("blink_override",
+						  "clk_32k", 0,
+						  PMC_DPD_PADS_ORIDE,
+						  PMC_DPD_PADS_ORIDE_BLINK);
+		if (IS_ERR(clk))
+			goto free_clks;
+
+		clk = tegra_pmc_clk_gate_register("blink",
+						  "blink_override", 0,
+						  PMC_CNTRL,
+						  PMC_CNTRL_BLINK_EN);
+		if (IS_ERR(clk))
+			goto free_clks;
+
+		clk_data->clks[TEGRA_PMC_CLK_BLINK] = clk;
+		clk_register_clkdev(clk, "blink", NULL);
+
+		if (pmc->soc->blink_init_state) {
+			if (clk_prepare_enable(clk)) {
+				pr_err("%s: Failed to enable %s\n", __func__,
+				       __clk_get_name(clk));
+				WARN_ON(1);
+			}
+		}
+	}
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
 
 	return;
@@ -2740,6 +2777,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
 	.num_reset_levels = 0,
 	.pmc_clks_data = NULL,
 	.num_pmc_clks = 0,
+	.has_blink_output = true,
+	.blink_init_state = true,
 };
 
 static const char * const tegra30_powergates[] = {
@@ -2789,6 +2828,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
 	.num_reset_levels = 0,
 	.pmc_clks_data = tegra_pmc_clks_data,
 	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
+	.has_blink_output = true,
+	.blink_init_state = true,
 };
 
 static const char * const tegra114_powergates[] = {
@@ -2842,6 +2883,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
 	.num_reset_levels = 0,
 	.pmc_clks_data = tegra_pmc_clks_data,
 	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
+	.has_blink_output = true,
+	.blink_init_state = false,
 };
 
 static const char * const tegra124_powergates[] = {
@@ -2955,6 +2998,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
 	.num_reset_levels = 0,
 	.pmc_clks_data = tegra_pmc_clks_data,
 	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
+	.has_blink_output = true,
+	.blink_init_state = false,
 };
 
 static const char * const tegra210_powergates[] = {
@@ -3071,6 +3116,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.wake_events = tegra210_wake_events,
 	.pmc_clks_data = tegra_pmc_clks_data,
 	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
+	.has_blink_output = true,
+	.blink_init_state = false,
 };
 
 #define TEGRA186_IO_PAD_TABLE(_pad)					     \
@@ -3202,6 +3249,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.wake_events = tegra186_wake_events,
 	.pmc_clks_data = NULL,
 	.num_pmc_clks = 0,
+	.has_blink_output = false,
 };
 
 static const struct tegra_io_pad_soc tegra194_io_pads[] = {
@@ -3321,6 +3369,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
 	.wake_events = tegra194_wake_events,
 	.pmc_clks_data = NULL,
 	.num_pmc_clks = 0,
+	.has_blink_output = false,
 };
 
 static const struct of_device_id tegra_pmc_match[] = {
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 05/11] clk: tegra: Remove tegra_pmc_clk_init along with clk ids
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (3 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings Sowjanya Komatineni
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Current Tegra clock driver registers PMC clocks clk_out_1, clk_out_2,
clk_out_3 and blink output in tegra_pmc_init() which does direct Tegra
PMC access during clk_ops and these PMC register read and write access
will not happen when PMC is in secure mode.

Any direct PMC register access from non-secure world will not go
through and all the PMC clocks and blink control are done in Tegra PMC
driver with PMC as clock provider.

This patch removes tegra_pmc_clk_init along with corresponding clk ids
from Tegra clock driver.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 drivers/clk/tegra/Makefile        |   1 -
 drivers/clk/tegra/clk-id.h        |   7 ---
 drivers/clk/tegra/clk-tegra-pmc.c | 122 --------------------------------------
 drivers/clk/tegra/clk-tegra114.c  |  11 ----
 drivers/clk/tegra/clk-tegra124.c  |  27 +++------
 drivers/clk/tegra/clk-tegra20.c   |   4 --
 drivers/clk/tegra/clk-tegra210.c  |  11 ----
 drivers/clk/tegra/clk-tegra30.c   |  12 ----
 drivers/clk/tegra/clk.h           |   1 -
 9 files changed, 7 insertions(+), 189 deletions(-)
 delete mode 100644 drivers/clk/tegra/clk-tegra-pmc.c

diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index df966ca06788..1f7c30f87ece 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -12,7 +12,6 @@ obj-y					+= clk-sdmmc-mux.o
 obj-y					+= clk-super.o
 obj-y					+= clk-tegra-audio.o
 obj-y					+= clk-tegra-periph.o
-obj-y					+= clk-tegra-pmc.o
 obj-y					+= clk-tegra-fixed.o
 obj-y					+= clk-tegra-super-gen4.o
 obj-$(CONFIG_TEGRA_CLK_EMC)		+= clk-emc.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index c4faebd32760..5913357a8000 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -32,7 +32,6 @@ enum clk_id {
 	tegra_clk_audio4,
 	tegra_clk_audio4_2x,
 	tegra_clk_audio4_mux,
-	tegra_clk_blink,
 	tegra_clk_bsea,
 	tegra_clk_bsev,
 	tegra_clk_cclk_g,
@@ -46,12 +45,6 @@ enum clk_id {
 	tegra_clk_clk_m,
 	tegra_clk_clk_m_div2,
 	tegra_clk_clk_m_div4,
-	tegra_clk_clk_out_1,
-	tegra_clk_clk_out_1_mux,
-	tegra_clk_clk_out_2,
-	tegra_clk_clk_out_2_mux,
-	tegra_clk_clk_out_3,
-	tegra_clk_clk_out_3_mux,
 	tegra_clk_cml0,
 	tegra_clk_cml1,
 	tegra_clk_csi,
diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c
deleted file mode 100644
index bec3e008335f..000000000000
--- a/drivers/clk/tegra/clk-tegra-pmc.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012, 2013, NVIDIA CORPORATION.  All rights reserved.
- */
-
-#include <linux/io.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/export.h>
-#include <linux/clk/tegra.h>
-
-#include "clk.h"
-#include "clk-id.h"
-
-#define PMC_CLK_OUT_CNTRL 0x1a8
-#define PMC_DPD_PADS_ORIDE 0x1c
-#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
-#define PMC_CTRL 0
-#define PMC_CTRL_BLINK_ENB 7
-#define PMC_BLINK_TIMER 0x40
-
-struct pmc_clk_init_data {
-	char *mux_name;
-	char *gate_name;
-	const char **parents;
-	int num_parents;
-	int mux_id;
-	int gate_id;
-	char *dev_name;
-	u8 mux_shift;
-	u8 gate_shift;
-};
-
-#define PMC_CLK(_num, _mux_shift, _gate_shift)\
-	{\
-		.mux_name = "clk_out_" #_num "_mux",\
-		.gate_name = "clk_out_" #_num,\
-		.parents = clk_out ##_num ##_parents,\
-		.num_parents = ARRAY_SIZE(clk_out ##_num ##_parents),\
-		.mux_id = tegra_clk_clk_out_ ##_num ##_mux,\
-		.gate_id = tegra_clk_clk_out_ ##_num,\
-		.dev_name = "extern" #_num,\
-		.mux_shift = _mux_shift,\
-		.gate_shift = _gate_shift,\
-	}
-
-static DEFINE_SPINLOCK(clk_out_lock);
-
-static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern1",
-};
-
-static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern2",
-};
-
-static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
-	"clk_m_div4", "extern3",
-};
-
-static struct pmc_clk_init_data pmc_clks[] = {
-	PMC_CLK(1, 6, 2),
-	PMC_CLK(2, 14, 10),
-	PMC_CLK(3, 22, 18),
-};
-
-void __init tegra_pmc_clk_init(void __iomem *pmc_base,
-				struct tegra_clk *tegra_clks)
-{
-	struct clk *clk;
-	struct clk **dt_clk;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) {
-		struct pmc_clk_init_data *data;
-
-		data = pmc_clks + i;
-
-		dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks);
-		if (!dt_clk)
-			continue;
-
-		clk = clk_register_mux(NULL, data->mux_name, data->parents,
-				data->num_parents,
-				CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
-				pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift,
-				3, 0, &clk_out_lock);
-		*dt_clk = clk;
-
-
-		dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks);
-		if (!dt_clk)
-			continue;
-
-		clk = clk_register_gate(NULL, data->gate_name, data->mux_name,
-					CLK_SET_RATE_PARENT,
-					pmc_base + PMC_CLK_OUT_CNTRL,
-					data->gate_shift, 0, &clk_out_lock);
-		*dt_clk = clk;
-		clk_register_clkdev(clk, data->dev_name, data->gate_name);
-	}
-
-	/* blink */
-	writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
-	clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
-				pmc_base + PMC_DPD_PADS_ORIDE,
-				PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
-
-	dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks);
-	if (!dt_clk)
-		return;
-
-	clk = clk_register_gate(NULL, "blink", "blink_override", 0,
-				pmc_base + PMC_CTRL,
-				PMC_CTRL_BLINK_ENB, 0, NULL);
-	clk_register_clkdev(clk, "blink", NULL);
-	*dt_clk = clk;
-}
-
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 4efcaaf51b3a..36ba1eb3dbe0 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -778,10 +778,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3] = { .dt_id = TEGRA114_CLK_AUDIO3, .present = true },
 	[tegra_clk_audio4] = { .dt_id = TEGRA114_CLK_AUDIO4, .present = true },
 	[tegra_clk_spdif] = { .dt_id = TEGRA114_CLK_SPDIF, .present = true },
-	[tegra_clk_clk_out_1] = { .dt_id = TEGRA114_CLK_CLK_OUT_1, .present = true },
-	[tegra_clk_clk_out_2] = { .dt_id = TEGRA114_CLK_CLK_OUT_2, .present = true },
-	[tegra_clk_clk_out_3] = { .dt_id = TEGRA114_CLK_CLK_OUT_3, .present = true },
-	[tegra_clk_blink] = { .dt_id = TEGRA114_CLK_BLINK, .present = true },
 	[tegra_clk_xusb_host_src] = { .dt_id = TEGRA114_CLK_XUSB_HOST_SRC, .present = true },
 	[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true },
 	[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true },
@@ -803,9 +799,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3_mux] = { .dt_id = TEGRA114_CLK_AUDIO3_MUX, .present = true },
 	[tegra_clk_audio4_mux] = { .dt_id = TEGRA114_CLK_AUDIO4_MUX, .present = true },
 	[tegra_clk_spdif_mux] = { .dt_id = TEGRA114_CLK_SPDIF_MUX, .present = true },
-	[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_1_MUX, .present = true },
-	[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_2_MUX, .present = true },
-	[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_3_MUX, .present = true },
 	[tegra_clk_dsia_mux] = { .dt_id = TEGRA114_CLK_DSIA_MUX, .present = true },
 	[tegra_clk_dsib_mux] = { .dt_id = TEGRA114_CLK_DSIB_MUX, .present = true },
 	[tegra_clk_cec] = { .dt_id = TEGRA114_CLK_CEC, .present = true },
@@ -866,7 +859,6 @@ static struct tegra_devclk devclks[] __initdata = {
 	{ .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA114_CLK_EXTERN1 },
 	{ .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA114_CLK_EXTERN2 },
 	{ .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA114_CLK_EXTERN3 },
-	{ .con_id = "blink", .dt_id = TEGRA114_CLK_BLINK },
 	{ .con_id = "cclk_g", .dt_id = TEGRA114_CLK_CCLK_G },
 	{ .con_id = "cclk_lp", .dt_id = TEGRA114_CLK_CCLK_LP },
 	{ .con_id = "sclk", .dt_id = TEGRA114_CLK_SCLK },
@@ -1156,8 +1148,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{ TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 },
 	{ TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 },
 	{ TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 },
-	{ TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1 },
-	{ TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1 },
 	{ TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
@@ -1359,7 +1349,6 @@ static void __init tegra114_clock_init(struct device_node *np)
 	tegra_audio_clk_init(clk_base, pmc_base, tegra114_clks,
 			     tegra114_audio_plls,
 			     ARRAY_SIZE(tegra114_audio_plls), 24000000);
-	tegra_pmc_clk_init(pmc_base, tegra114_clks);
 	tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks,
 					&pll_x_params);
 
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index b3110d5b5a6c..24532d70e469 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -902,10 +902,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3] = { .dt_id = TEGRA124_CLK_AUDIO3, .present = true },
 	[tegra_clk_audio4] = { .dt_id = TEGRA124_CLK_AUDIO4, .present = true },
 	[tegra_clk_spdif] = { .dt_id = TEGRA124_CLK_SPDIF, .present = true },
-	[tegra_clk_clk_out_1] = { .dt_id = TEGRA124_CLK_CLK_OUT_1, .present = true },
-	[tegra_clk_clk_out_2] = { .dt_id = TEGRA124_CLK_CLK_OUT_2, .present = true },
-	[tegra_clk_clk_out_3] = { .dt_id = TEGRA124_CLK_CLK_OUT_3, .present = true },
-	[tegra_clk_blink] = { .dt_id = TEGRA124_CLK_BLINK, .present = true },
 	[tegra_clk_xusb_host_src] = { .dt_id = TEGRA124_CLK_XUSB_HOST_SRC, .present = true },
 	[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true },
 	[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true },
@@ -931,9 +927,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3_mux] = { .dt_id = TEGRA124_CLK_AUDIO3_MUX, .present = true },
 	[tegra_clk_audio4_mux] = { .dt_id = TEGRA124_CLK_AUDIO4_MUX, .present = true },
 	[tegra_clk_spdif_mux] = { .dt_id = TEGRA124_CLK_SPDIF_MUX, .present = true },
-	[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true },
-	[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true },
-	[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true },
 	[tegra_clk_cec] = { .dt_id = TEGRA124_CLK_CEC, .present = true },
 };
 
@@ -991,7 +984,6 @@ static struct tegra_devclk devclks[] __initdata = {
 	{ .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA124_CLK_EXTERN1 },
 	{ .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA124_CLK_EXTERN2 },
 	{ .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA124_CLK_EXTERN3 },
-	{ .con_id = "blink", .dt_id = TEGRA124_CLK_BLINK },
 	{ .con_id = "cclk_g", .dt_id = TEGRA124_CLK_CCLK_G },
 	{ .con_id = "cclk_lp", .dt_id = TEGRA124_CLK_CCLK_LP },
 	{ .con_id = "sclk", .dt_id = TEGRA124_CLK_SCLK },
@@ -1301,8 +1293,6 @@ static struct tegra_clk_init_table common_init_table[] __initdata = {
 	{ TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 },
 	{ TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 },
 	{ TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 },
-	{ TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1 },
-	{ TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1 },
 	{ TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
@@ -1457,11 +1447,9 @@ static void __init tegra132_clock_apply_init_table(void)
  * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132
  * @np: struct device_node * of the DT node for the SoC CAR IP block
  *
- * Register most of the clocks controlled by the CAR IP block, along
- * with a few clocks controlled by the PMC IP block.  Everything in
- * this function should be common to Tegra124 and Tegra132.  XXX The
- * PMC clock initialization should probably be moved to PMC-specific
- * driver code.  No return value.
+ * Register most of the clocks controlled by the CAR IP block.
+ * Everything in this function should be common to Tegra124 and Tegra132.
+ * No return value.
  */
 static void __init tegra124_132_clock_init_pre(struct device_node *np)
 {
@@ -1504,7 +1492,6 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np)
 	tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks,
 			     tegra124_audio_plls,
 			     ARRAY_SIZE(tegra124_audio_plls), 24576000);
-	tegra_pmc_clk_init(pmc_base, tegra124_clks);
 
 	/* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */
 	plld_base = readl(clk_base + PLLD_BASE);
@@ -1516,11 +1503,11 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np)
  * tegra124_132_clock_init_post - clock initialization postamble for T124/T132
  * @np: struct device_node * of the DT node for the SoC CAR IP block
  *
- * Register most of the along with a few clocks controlled by the PMC
- * IP block.  Everything in this function should be common to Tegra124
+ * Register most of the clocks controlled by the CAR IP block.
+ * Everything in this function should be common to Tegra124
  * and Tegra132.  This function must be called after
- * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will
- * not be set.  No return value.
+ * tegra124_132_clock_init_pre(), otherwise clk_base will not be set.
+ * No return value.
  */
 static void __init tegra124_132_clock_init_post(struct device_node *np)
 {
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 4d8222f5c638..fe536f1d770d 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -458,7 +458,6 @@ static struct tegra_devclk devclks[] __initdata = {
 	{ .con_id = "cdev1", .dt_id = TEGRA20_CLK_CDEV1 },
 	{ .con_id = "cdev2", .dt_id = TEGRA20_CLK_CDEV2 },
 	{ .con_id = "clk_32k", .dt_id = TEGRA20_CLK_CLK_32K },
-	{ .con_id = "blink", .dt_id = TEGRA20_CLK_BLINK },
 	{ .con_id = "clk_m", .dt_id = TEGRA20_CLK_CLK_M },
 	{ .con_id = "pll_ref", .dt_id = TEGRA20_CLK_PLL_REF },
 	{ .dev_id = "tegra20-i2s.0", .dt_id = TEGRA20_CLK_I2S1 },
@@ -537,7 +536,6 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_csi] = { .dt_id = TEGRA20_CLK_CSI, .present = true },
 	[tegra_clk_isp] = { .dt_id = TEGRA20_CLK_ISP, .present = true },
 	[tegra_clk_clk_32k] = { .dt_id = TEGRA20_CLK_CLK_32K, .present = true },
-	[tegra_clk_blink] = { .dt_id = TEGRA20_CLK_BLINK, .present = true },
 	[tegra_clk_hclk] = { .dt_id = TEGRA20_CLK_HCLK, .present = true },
 	[tegra_clk_pclk] = { .dt_id = TEGRA20_CLK_PCLK, .present = true },
 	[tegra_clk_pll_p_out1] = { .dt_id = TEGRA20_CLK_PLL_P_OUT1, .present = true },
@@ -1034,7 +1032,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{ TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 },
 	{ TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 },
 	{ TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 },
-	{ TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 },
 	{ TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 },
@@ -1148,7 +1145,6 @@ static void __init tegra20_clock_init(struct device_node *np)
 	tegra_super_clk_gen4_init(clk_base, pmc_base, tegra20_clks, NULL);
 	tegra20_periph_clk_init();
 	tegra20_audio_clk_init();
-	tegra_pmc_clk_init(pmc_base, tegra20_clks);
 
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX);
 
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 762cd186f714..af5119481d54 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -2417,10 +2417,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true },
 	[tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true },
 	[tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true },
-	[tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true },
-	[tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true },
-	[tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true },
-	[tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true },
 	[tegra_clk_xusb_gate] = { .dt_id = TEGRA210_CLK_XUSB_GATE, .present = true },
 	[tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true },
 	[tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true },
@@ -2452,9 +2448,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true },
 	[tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true },
 	[tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true },
-	[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true },
-	[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true },
-	[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true },
 	[tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true },
 	[tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true },
 	[tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true },
@@ -2543,7 +2536,6 @@ static struct tegra_devclk devclks[] __initdata = {
 	{ .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 },
 	{ .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 },
 	{ .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 },
-	{ .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK },
 	{ .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G },
 	{ .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP },
 	{ .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK },
@@ -3451,8 +3443,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{ TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 },
 	{ TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 },
 	{ TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 },
-	{ TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1 },
-	{ TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1 },
 	{ TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
@@ -3693,7 +3683,6 @@ static void __init tegra210_clock_init(struct device_node *np)
 	tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
 			     tegra210_audio_plls,
 			     ARRAY_SIZE(tegra210_audio_plls), 24576000);
-	tegra_pmc_clk_init(pmc_base, tegra210_clks);
 
 	/* For Tegra210, PLLD is the only source for DSIA & DSIB */
 	value = readl(clk_base + PLLD_BASE);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index c8bc18e4d7e5..24599ed2e6ff 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -572,7 +572,6 @@ static struct tegra_devclk devclks[] __initdata = {
 	{ .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA30_CLK_EXTERN1 },
 	{ .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA30_CLK_EXTERN2 },
 	{ .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA30_CLK_EXTERN3 },
-	{ .con_id = "blink", .dt_id = TEGRA30_CLK_BLINK },
 	{ .con_id = "cclk_g", .dt_id = TEGRA30_CLK_CCLK_G },
 	{ .con_id = "cclk_lp", .dt_id = TEGRA30_CLK_CCLK_LP },
 	{ .con_id = "sclk", .dt_id = TEGRA30_CLK_SCLK },
@@ -711,13 +710,6 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_audio3_2x] = { .dt_id = TEGRA30_CLK_AUDIO3_2X, .present = true },
 	[tegra_clk_audio4_2x] = { .dt_id = TEGRA30_CLK_AUDIO4_2X, .present = true },
 	[tegra_clk_spdif_2x] = { .dt_id = TEGRA30_CLK_SPDIF_2X, .present = true },
-	[tegra_clk_clk_out_1] = { .dt_id = TEGRA30_CLK_CLK_OUT_1, .present = true },
-	[tegra_clk_clk_out_2] = { .dt_id = TEGRA30_CLK_CLK_OUT_2, .present = true },
-	[tegra_clk_clk_out_3] = { .dt_id = TEGRA30_CLK_CLK_OUT_3, .present = true },
-	[tegra_clk_blink] = { .dt_id = TEGRA30_CLK_BLINK, .present = true },
-	[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_1_MUX, .present = true },
-	[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_2_MUX, .present = true },
-	[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_3_MUX, .present = true },
 	[tegra_clk_hclk] = { .dt_id = TEGRA30_CLK_HCLK, .present = true },
 	[tegra_clk_pclk] = { .dt_id = TEGRA30_CLK_PCLK, .present = true },
 	[tegra_clk_i2s0] = { .dt_id = TEGRA30_CLK_I2S0, .present = true },
@@ -1230,9 +1222,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{ TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 },
 	{ TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 },
 	{ TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 },
-	{ TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0 },
-	{ TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1 },
-	{ TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1 },
 	{ TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
 	{ TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
@@ -1364,7 +1353,6 @@ static void __init tegra30_clock_init(struct device_node *np)
 	tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks,
 			     tegra30_audio_plls,
 			     ARRAY_SIZE(tegra30_audio_plls), 24000000);
-	tegra_pmc_clk_init(pmc_base, tegra30_clks);
 
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX);
 
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 416a6b09f6a3..2c9a68302e02 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -854,7 +854,6 @@ void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base,
 			struct tegra_clk *tegra_clks,
 			struct tegra_clk_pll_params *pll_params);
 
-void tegra_pmc_clk_init(void __iomem *pmc_base, struct tegra_clk *tegra_clks);
 void tegra_fixed_clk_init(struct tegra_clk *tegra_clks);
 int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
 		       unsigned long *input_freqs, unsigned int num,
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (4 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 05/11] clk: tegra: Remove tegra_pmc_clk_init along with clk ids Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27  4:59 ` [PATCH v2 07/11] arm: tegra: Add clock-cells property to Tegra PMC Sowjanya Komatineni
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

clk_out_1, clk_out_2, clk_out_3, blink are part of Tegra pmc clocks.

This patch removes ids for these clocks from Tegra clock dt-bindings.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 include/dt-bindings/clock/tegra114-car.h        | 14 +++++++-------
 include/dt-bindings/clock/tegra124-car-common.h | 14 +++++++-------
 include/dt-bindings/clock/tegra20-car.h         |  2 +-
 include/dt-bindings/clock/tegra210-car.h        | 14 +++++++-------
 include/dt-bindings/clock/tegra30-car.h         | 14 +++++++-------
 5 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
index bb5c2c999c05..9175cd0571b5 100644
--- a/include/dt-bindings/clock/tegra114-car.h
+++ b/include/dt-bindings/clock/tegra114-car.h
@@ -270,10 +270,10 @@
 #define TEGRA114_CLK_AUDIO3 242
 #define TEGRA114_CLK_AUDIO4 243
 #define TEGRA114_CLK_SPDIF 244
-#define TEGRA114_CLK_CLK_OUT_1 245
-#define TEGRA114_CLK_CLK_OUT_2 246
-#define TEGRA114_CLK_CLK_OUT_3 247
-#define TEGRA114_CLK_BLINK 248
+/* 245 */
+/* 246 */
+/* 247 */
+/* 248 */
 /* 249 */
 /* 250 */
 /* 251 */
@@ -333,9 +333,9 @@
 #define TEGRA114_CLK_AUDIO3_MUX 303
 #define TEGRA114_CLK_AUDIO4_MUX 304
 #define TEGRA114_CLK_SPDIF_MUX 305
-#define TEGRA114_CLK_CLK_OUT_1_MUX 306
-#define TEGRA114_CLK_CLK_OUT_2_MUX 307
-#define TEGRA114_CLK_CLK_OUT_3_MUX 308
+/* 306 */
+/* 307 */
+/* 308 */
 #define TEGRA114_CLK_DSIA_MUX 309
 #define TEGRA114_CLK_DSIB_MUX 310
 #define TEGRA114_CLK_XUSB_SS_DIV2 311
diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
index 0c4f5be0a742..90a0c5e7eb5f 100644
--- a/include/dt-bindings/clock/tegra124-car-common.h
+++ b/include/dt-bindings/clock/tegra124-car-common.h
@@ -269,10 +269,10 @@
 #define TEGRA124_CLK_AUDIO3 242
 #define TEGRA124_CLK_AUDIO4 243
 #define TEGRA124_CLK_SPDIF 244
-#define TEGRA124_CLK_CLK_OUT_1 245
-#define TEGRA124_CLK_CLK_OUT_2 246
-#define TEGRA124_CLK_CLK_OUT_3 247
-#define TEGRA124_CLK_BLINK 248
+/* 245 */
+/* 246 */
+/* 247 */
+/* 248 */
 /* 249 */
 /* 250 */
 /* 251 */
@@ -332,9 +332,9 @@
 #define TEGRA124_CLK_AUDIO3_MUX 303
 #define TEGRA124_CLK_AUDIO4_MUX 304
 #define TEGRA124_CLK_SPDIF_MUX 305
-#define TEGRA124_CLK_CLK_OUT_1_MUX 306
-#define TEGRA124_CLK_CLK_OUT_2_MUX 307
-#define TEGRA124_CLK_CLK_OUT_3_MUX 308
+/* 306 */
+/* 307 */
+/* 308 */
 /* 309 */
 /* 310 */
 #define TEGRA124_CLK_SOR0_LVDS 311 /* deprecated */
diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
index b21a0eb32921..fe541f627965 100644
--- a/include/dt-bindings/clock/tegra20-car.h
+++ b/include/dt-bindings/clock/tegra20-car.h
@@ -131,7 +131,7 @@
 #define TEGRA20_CLK_CCLK 108
 #define TEGRA20_CLK_HCLK 109
 #define TEGRA20_CLK_PCLK 110
-#define TEGRA20_CLK_BLINK 111
+/* 111 */
 #define TEGRA20_CLK_PLL_A 112
 #define TEGRA20_CLK_PLL_A_OUT0 113
 #define TEGRA20_CLK_PLL_C 114
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
index 44f60623f99b..a3d8d3e75728 100644
--- a/include/dt-bindings/clock/tegra210-car.h
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -304,10 +304,10 @@
 #define TEGRA210_CLK_AUDIO3 274
 #define TEGRA210_CLK_AUDIO4 275
 #define TEGRA210_CLK_SPDIF 276
-#define TEGRA210_CLK_CLK_OUT_1 277
-#define TEGRA210_CLK_CLK_OUT_2 278
-#define TEGRA210_CLK_CLK_OUT_3 279
-#define TEGRA210_CLK_BLINK 280
+/* 277 */
+/* 278 */
+/* 279 */
+/* 280 */
 #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */
 #define TEGRA210_CLK_SOR0_OUT 281
 #define TEGRA210_CLK_SOR1_OUT 282
@@ -386,9 +386,9 @@
 #define TEGRA210_CLK_AUDIO3_MUX 353
 #define TEGRA210_CLK_AUDIO4_MUX 354
 #define TEGRA210_CLK_SPDIF_MUX 355
-#define TEGRA210_CLK_CLK_OUT_1_MUX 356
-#define TEGRA210_CLK_CLK_OUT_2_MUX 357
-#define TEGRA210_CLK_CLK_OUT_3_MUX 358
+/* 356 */
+/* 357 */
+/* 358 */
 #define TEGRA210_CLK_DSIA_MUX 359
 #define TEGRA210_CLK_DSIB_MUX 360
 /* 361 */
diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
index 3c90f1535551..20ef2462d9e1 100644
--- a/include/dt-bindings/clock/tegra30-car.h
+++ b/include/dt-bindings/clock/tegra30-car.h
@@ -230,11 +230,11 @@
 #define TEGRA30_CLK_AUDIO3 204
 #define TEGRA30_CLK_AUDIO4 205
 #define TEGRA30_CLK_SPDIF 206
-#define TEGRA30_CLK_CLK_OUT_1 207 /* (extern1) */
-#define TEGRA30_CLK_CLK_OUT_2 208 /* (extern2) */
-#define TEGRA30_CLK_CLK_OUT_3 209 /* (extern3) */
+/* 207 */
+/* 208 */
+/* 209 */
 #define TEGRA30_CLK_SCLK 210
-#define TEGRA30_CLK_BLINK 211
+/* 211 */
 #define TEGRA30_CLK_CCLK_G 212
 #define TEGRA30_CLK_CCLK_LP 213
 #define TEGRA30_CLK_TWD 214
@@ -260,9 +260,9 @@
 /* 297 */
 /* 298 */
 /* 299 */
-#define TEGRA30_CLK_CLK_OUT_1_MUX 300
-#define TEGRA30_CLK_CLK_OUT_2_MUX 301
-#define TEGRA30_CLK_CLK_OUT_3_MUX 302
+/* 300 */
+/* 301 */
+/* 302 */
 #define TEGRA30_CLK_AUDIO0_MUX 303
 #define TEGRA30_CLK_AUDIO1_MUX 304
 #define TEGRA30_CLK_AUDIO2_MUX 305
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 07/11] arm: tegra: Add clock-cells property to Tegra PMC
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (5 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 08/11] arm64: tegra: Add clock-cells property to Tegra pmc Sowjanya Komatineni
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra PMC has 3 clocks clk_out_1, clk_out_2, clk_out_3 with mux and gate
for each of these clocks and Tegra PMC is the clock provider for these
clocks.

This patch adds #clock-cells property with 1 clock specifier to
the Tegra PMC node in device tree.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 arch/arm/boot/dts/tegra114.dtsi | 4 +++-
 arch/arm/boot/dts/tegra124.dtsi | 4 +++-
 arch/arm/boot/dts/tegra20.dtsi  | 4 +++-
 arch/arm/boot/dts/tegra30.dtsi  | 4 +++-
 4 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 0d7a6327e404..b8f12f24f314 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -4,6 +4,7 @@
 #include <dt-bindings/memory/tegra114-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra114";
@@ -514,11 +515,12 @@
 		status = "disabled";
 	};
 
-	pmc@7000e400 {
+	pmc: pmc@7000e400 {
 		compatible = "nvidia,tegra114-pmc";
 		reg = <0x7000e400 0x400>;
 		clocks = <&tegra_car TEGRA114_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 	};
 
 	fuse@7000f800 {
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 413bfb981de8..d0802c4ae3bf 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -6,6 +6,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/reset/tegra124-car.h>
 #include <dt-bindings/thermal/tegra124-soctherm.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra124";
@@ -595,11 +596,12 @@
 		clocks = <&tegra_car TEGRA124_CLK_RTC>;
 	};
 
-	pmc@7000e400 {
+	pmc: pmc@7000e400 {
 		compatible = "nvidia,tegra124-pmc";
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 	};
 
 	fuse@7000f800 {
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 9c58e7fcf5c0..85a64747bec6 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -4,6 +4,7 @@
 #include <dt-bindings/memory/tegra20-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra20";
@@ -608,11 +609,12 @@
 		status = "disabled";
 	};
 
-	pmc@7000e400 {
+	pmc: pmc@7000e400 {
 		compatible = "nvidia,tegra20-pmc";
 		reg = <0x7000e400 0x400>;
 		clocks = <&tegra_car TEGRA20_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 	};
 
 	mc: memory-controller@7000f000 {
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 55ae050042ce..4d5e9d0001d3 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -4,6 +4,7 @@
 #include <dt-bindings/memory/tegra30-mc.h>
 #include <dt-bindings/pinctrl/pinctrl-tegra.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra30";
@@ -714,11 +715,12 @@
 		status = "disabled";
 	};
 
-	pmc@7000e400 {
+	pmc: pmc@7000e400 {
 		compatible = "nvidia,tegra30-pmc";
 		reg = <0x7000e400 0x400>;
 		clocks = <&tegra_car TEGRA30_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 	};
 
 	mc: memory-controller@7000f000 {
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 08/11] arm64: tegra: Add clock-cells property to Tegra pmc
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (6 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 07/11] arm: tegra: Add clock-cells property to Tegra PMC Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 09/11] dt-bindings: Add Tegra PMC clock configuration bindings Sowjanya Komatineni
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra pmc has 3 clocks clk_out_1, clk_out_2, clk_out_3 with mux and gate
for each of these clocks as part of pmc and Tegra pmc is the clock provider
for these clocks.

These clock ids are part of pmc dt-bindings.

This patch includes pmc dt-bindings and adds #clock-cells propert
 with 1 clock specifier to Tegra pmc node.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra132.dtsi | 4 +++-
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 2 ++
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 ++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 2 ++
 4 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
index 631a7f77c386..5bdb4a6a6b90 100644
--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi
@@ -6,6 +6,7 @@
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/tegra124-soctherm.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra132", "nvidia,tegra124";
@@ -577,11 +578,12 @@
 		clock-names = "rtc";
 	};
 
-	pmc@7000e400 {
+	pmc: pmc@7000e400 {
 		compatible = "nvidia,tegra124-pmc";
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA124_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 	};
 
 	fuse@7000f800 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 7893d78a0fb6..627108ce2f56 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -8,6 +8,7 @@
 #include <dt-bindings/power/tegra186-powergate.h>
 #include <dt-bindings/reset/tegra186-reset.h>
 #include <dt-bindings/thermal/tegra186-bpmp-thermal.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra186";
@@ -670,6 +671,7 @@
 		      <0 0x0c390000 0 0x10000>;
 		reg-names = "pmc", "wake", "aotag", "scratch";
 
+		#clock-cells = <1>;
 		#interrupt-cells = <2>;
 		interrupt-controller;
 
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 11220d97adb8..37dc19f49e4f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -7,6 +7,7 @@
 #include <dt-bindings/power/tegra194-powergate.h>
 #include <dt-bindings/reset/tegra194-reset.h>
 #include <dt-bindings/thermal/tegra194-bpmp-thermal.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra194";
@@ -799,6 +800,7 @@
 			      <0x0c3a0000 0x10000>;
 			reg-names = "pmc", "wake", "aotag", "scratch", "misc";
 
+			#clock-cells = <1>;
 			#interrupt-cells = <2>;
 			interrupt-controller;
 		};
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 48c63256ba7f..0d0432d3b37a 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -7,6 +7,7 @@
 #include <dt-bindings/reset/tegra210-car.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/tegra124-soctherm.h>
+#include <dt-bindings/soc/tegra-pmc.h>
 
 / {
 	compatible = "nvidia,tegra210";
@@ -780,6 +781,7 @@
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 		#interrupt-cells = <2>;
 		interrupt-controller;
 
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 09/11] dt-bindings: Add Tegra PMC clock configuration bindings
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (7 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 08/11] arm64: tegra: Add clock-cells property to Tegra pmc Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 10/11] arm64: tegra: smaug: Change clk_out_2 provider from tegra_car to pmc Sowjanya Komatineni
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Document clock bindings for pmc clocks clk_out_1, clk_out_2 and clk_out_3.
These clocks are part of Tegra PMC block and pmc node is the provider for
these clocks.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 .../bindings/arm/tegra/nvidia,tegra20-pmc.txt      | 45 +++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
index cb12f33a247f..7e0069b87bc2 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -21,6 +21,10 @@ Required properties:
 - clock-names : Must include the following entries:
   "pclk" (The Tegra clock of that name),
   "clk32k_in" (The 32KHz clock input to Tegra).
+- #clock-cells : Should be 1 for Tegra30 and higher.
+  In clock consumers, this cell represents the PMC clock ID.
+  The assignments may be found in header file
+  <dt-bindings/soc/tegra-pmc.h>.
 
 Optional properties:
 - nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
@@ -80,11 +84,12 @@ Optional nodes:
 Example:
 
 / SoC dts including file
-pmc@7000f400 {
+pmc: pmc@7000f400 {
 	compatible = "nvidia,tegra20-pmc";
 	reg = <0x7000e400 0x400>;
 	clocks = <&tegra_car 110>, <&clk32k_in>;
 	clock-names = "pclk", "clk32k_in";
+	#clock-cells = <1>;
 	nvidia,invert-interrupt;
 	nvidia,suspend-mode = <1>;
 	nvidia,cpu-pwr-good-time = <2000>;
@@ -171,6 +176,7 @@ Example:
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 
 		powergates {
 			pd_audio: aud {
@@ -260,6 +266,7 @@ Pad configuration state example:
 		reg = <0x0 0x7000e400 0x0 0x400>;
 		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
 		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
 
 		...
 
@@ -298,3 +305,39 @@ Pinctrl client example:
 		pinctrl-1 = <&hdmi_on>;
 		pinctrl-names = "hdmi-on", "hdmi-off";
 	};
+
+== Clock Control ==
+
+Tegra PMC has 3 clocks clk_1, clk_2 and clk_3. Each of these clocks has
+source selection and enable/disable gate.
+Parent/source for these clocks can be either of clk_m, clk_m_div2, clk_m_div4,
+or extern clock from Tegra CAR module.
+
+Clock configuration example:
+	pmc: pmc@7000e400 {
+		compatible = "nvidia,tegra210-pmc";
+		reg = <0x0 0x7000e400 0x0 0x400>;
+		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
+		clock-names = "pclk", "clk32k_in";
+		#clock-cells = <1>;
+	};
+
+Clock consumer example:
+	host1x@50000000 {
+		...
+		vi@54080000 {
+		...
+		assigned-clocks = <&pmc TEGRA_PMC_CLK_OUT_3_MUX>;
+		assigned-clock-parents = <&tegra_car TEGRA210_CLK_EXTERN3>;
+		};
+		...
+	};
+	...
+	i2c@7000c500 {
+		cam_sensor {
+		...
+		clocks = <&pmc TEGRA_PMC_CLK_OUT_3>;
+		clock-names = "mclk";
+		...
+		};
+	};
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 10/11] arm64: tegra: smaug: Change clk_out_2 provider from tegra_car to pmc
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (8 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 09/11] dt-bindings: Add Tegra PMC clock configuration bindings Sowjanya Komatineni
@ 2019-11-27  4:59 ` Sowjanya Komatineni
  2019-11-27  4:59 ` [PATCH v2 11/11] ASoC: nau8825: change Tegra " Sowjanya Komatineni
  2019-11-27 14:31 ` [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Dmitry Osipenko
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

clk_out_2 is the clocks from Tegra PMC block with clock source and state
control part of Tegra PMC.

Tegra pmc node is the provider for these clocks.

This patch changes clk_out_2 provider to pmc and uses corresponding pmc
clock id for clk_out_2.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra210-smaug.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
index 72c7a04ac1df..4376c38d78f4 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
@@ -1592,7 +1592,7 @@
 			reg = <0x1a>;
 			interrupt-parent = <&gpio>;
 			interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>;
-			clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+			clocks = <&pmc TEGRA_PMC_CLK_OUT_2>;
 			clock-names = "mclk";
 
 			nuvoton,jkdet-enable;
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 11/11] ASoC: nau8825: change Tegra clk_out_2 provider from tegra_car to pmc
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (9 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 10/11] arm64: tegra: smaug: Change clk_out_2 provider from tegra_car to pmc Sowjanya Komatineni
@ 2019-11-27  4:59 ` " Sowjanya Komatineni
  2019-11-27 14:31 ` [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Dmitry Osipenko
  11 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27  4:59 UTC (permalink / raw)
  To: skomatineni, thierry.reding, jonathanh, digetx, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

Tegra clk_out_1, clk_out_2, and clk_out_3 are part of PMC block and pmc is
the provider for these clocks.

Update bindings document to use pmc as clock provider for clk_out_2 and
change id to pmc clock id.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 Documentation/devicetree/bindings/sound/nau8825.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt
index d16d96839bcb..487eb9574ee2 100644
--- a/Documentation/devicetree/bindings/sound/nau8825.txt
+++ b/Documentation/devicetree/bindings/sound/nau8825.txt
@@ -101,5 +101,5 @@ Example:
       nuvoton,crosstalk-enable;
 
       clock-names = "mclk";
-      clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+      clocks = <&pmc TEGRA_PMC_CLK_OUT_2>;
   };
-- 
2.7.4


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
                   ` (10 preceding siblings ...)
  2019-11-27  4:59 ` [PATCH v2 11/11] ASoC: nau8825: change Tegra " Sowjanya Komatineni
@ 2019-11-27 14:31 ` Dmitry Osipenko
  2019-11-27 17:02   ` Sowjanya Komatineni
  2019-11-28 12:26   ` Thierry Reding
  11 siblings, 2 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-27 14:31 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
> are currently registered by Tegra clock driver using clk_regiser_mux and
> clk_register_gate which performs direct Tegra PMC register access.
> 
> When Tegra PMC is in secure mode, any access from non-secure world will
> not go through.
> 
> This patch series adds these Tegra PMC clocks and blink controls to Tegra
> PMC driver with PMC as clock provider and removed them from Tegra clock
> driver. This also adds PMC specific clock id's to use in device tree and
> removed clock ids of PMC clock from Tegra clock driver.
> 
> This series also includes patch to update clock provider from tegra_car
> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 from PMC.
> 
> [v2]:	Changes between v1 and v2 are
> 	- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
> 	  blink controls to Tegra PMC driver and removing clk-tegra-pmc.
> 	- feedback related to pmc clocks in Tegra PMC driver from v1
> 	- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
> 	  by the clock driver using helper functions from Tegra PMC.
> 
>  	  Note:
> 	  To use helper functions from PMC driver, PMC early init need to
> 	  happen prior to using helper functions and these helper functions are
> 	  for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
> 	  clock registration which happen in clock_init prior to Tegra PMC
> 	  probe.
> 	  Moving PLLM/PLLE clocks registration to happen after Tegra PMC
> 	  impacts other clocks EMC, MC and corresponding tegra_emc_init and
> 	  tegra_mc_init.
> 	  This implementation of configuring PMC registers thru helper
> 	  functions in clock driver needs proper changes across PMC, Clock,
> 	  EMC and MC inits to have it work across all Tegra platforms.
> 
> 	  Currently PLLM Override is not enabled in the bootloader so proper
> 	  patches for this fix will be taken care separately.

Hello Sowjanya,

Could you please clarify what do you mean by "PLLM Override not enabled
in bootloader"?

There is T124 Nyan Big Chromebook which is supported in upstream kernel,
it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
which has the PLLM Override set by bootloader as well. It's not clear to
me whether this patch series is supposed to break these devices. If the
breakage is the case here, then I'm afraid you can't postpone supporting
the PLLM Override and a full-featured implementation is needed.

I briefly tried to test this series on T30 and this time it doesn't hang
on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
chip uses the Blink clock source and the clock should be enabled by the
MMC core because this is how DT part looks like:

brcm_wifi_pwrseq: wifi-pwrseq {
	compatible = "mmc-pwrseq-simple";
	clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
	clock-names = "ext_clock";
	reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
	post-power-on-delay-ms = <300>;
	power-off-delay-us = <300>;
};

BTW, I  tried this series on a T20 device which also uses the Blink
clock for WiFi card and it works. So looks like this patchset has some
problem in regards to the T30 PMC clocks implementation.

[snip]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
@ 2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 15:14   ` Dmitry Osipenko
  2 siblings, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-27 14:32 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
> mux and gate for each of these clocks.
> 
> Currently these PMC clocks are registered by Tegra clock driver using
> clk_register_mux and clk_register_gate by passing PMC base address
> and register offsets and PMC programming for these clocks happens
> through direct PMC access by the clock driver.
> 
> With this, when PMC is in secure mode any direct PMC access from the
> non-secure world does not go through and these clocks will not be
> functional.
> 
> This patch adds these clocks registration with PMC as a clock provider
> for these clocks. clk_ops callback implementations for these clocks
> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
> in secure mode and non-secure mode.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 330 insertions(+)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index ea0e11a09c12..a353f6d0a832 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -13,6 +13,9 @@
>  
>  #include <linux/arm-smccc.h>
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/clk-conf.h>
>  #include <linux/clk/tegra.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -48,6 +51,7 @@
>  #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>  #include <dt-bindings/gpio/tegra186-gpio.h>
>  #include <dt-bindings/gpio/tegra194-gpio.h>
> +#include <dt-bindings/soc/tegra-pmc.h>
>  
>  #define PMC_CNTRL			0x0
>  #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
> @@ -100,6 +104,7 @@
>  #define PMC_WAKE2_STATUS		0x168
>  #define PMC_SW_WAKE2_STATUS		0x16c
>  
> +#define PMC_CLK_OUT_CNTRL		0x1a8
>  #define PMC_SENSOR_CTRL			0x1b0
>  #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
>  #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
> @@ -155,6 +160,91 @@
>  #define  TEGRA_SMC_PMC_READ	0xaa
>  #define  TEGRA_SMC_PMC_WRITE	0xbb
>  
> +struct pmc_clk_mux {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		mask;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
> +
> +struct pmc_clk_gate {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
> +
> +struct pmc_clk_init_data {
> +	char *mux_name;
> +	char *gate_name;
> +	const char **parents;
> +	int num_parents;
> +	int mux_id;
> +	int gate_id;
> +	char *dev_name;
> +	u8 mux_shift;
> +	u8 gate_shift;
> +	u8 init_parent_index;
> +	int init_state;
> +};
> +
> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern1",
> +};
> +
> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern2",
> +};
> +
> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern3",
> +};
> +
> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {

const?

[snip]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
  2019-11-27 14:32   ` Dmitry Osipenko
@ 2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 15:14   ` Dmitry Osipenko
  2 siblings, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-27 14:32 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
> mux and gate for each of these clocks.
> 
> Currently these PMC clocks are registered by Tegra clock driver using
> clk_register_mux and clk_register_gate by passing PMC base address
> and register offsets and PMC programming for these clocks happens
> through direct PMC access by the clock driver.
> 
> With this, when PMC is in secure mode any direct PMC access from the
> non-secure world does not go through and these clocks will not be
> functional.
> 
> This patch adds these clocks registration with PMC as a clock provider
> for these clocks. clk_ops callback implementations for these clocks
> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
> in secure mode and non-secure mode.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 330 insertions(+)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index ea0e11a09c12..a353f6d0a832 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -13,6 +13,9 @@
>  
>  #include <linux/arm-smccc.h>
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/clk-conf.h>
>  #include <linux/clk/tegra.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -48,6 +51,7 @@
>  #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>  #include <dt-bindings/gpio/tegra186-gpio.h>
>  #include <dt-bindings/gpio/tegra194-gpio.h>
> +#include <dt-bindings/soc/tegra-pmc.h>
>  
>  #define PMC_CNTRL			0x0
>  #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
> @@ -100,6 +104,7 @@
>  #define PMC_WAKE2_STATUS		0x168
>  #define PMC_SW_WAKE2_STATUS		0x16c
>  
> +#define PMC_CLK_OUT_CNTRL		0x1a8
>  #define PMC_SENSOR_CTRL			0x1b0
>  #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
>  #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
> @@ -155,6 +160,91 @@
>  #define  TEGRA_SMC_PMC_READ	0xaa
>  #define  TEGRA_SMC_PMC_WRITE	0xbb
>  
> +struct pmc_clk_mux {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		mask;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
> +
> +struct pmc_clk_gate {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
> +
> +struct pmc_clk_init_data {
> +	char *mux_name;
> +	char *gate_name;
> +	const char **parents;
> +	int num_parents;
> +	int mux_id;
> +	int gate_id;
> +	char *dev_name;
> +	u8 mux_shift;
> +	u8 gate_shift;
> +	u8 init_parent_index;
> +	int init_state;
> +};
> +
> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern1",
> +};
> +
> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern2",
> +};
> +
> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern3",
> +};
> +
> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
> +	{
> +		.mux_name = "clk_out_1_mux",
> +		.gate_name = "clk_out_1",
> +		.parents = clk_out1_parents,
> +		.num_parents = ARRAY_SIZE(clk_out1_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_1,
> +		.dev_name = "extern1",
> +		.mux_shift = 6,
> +		.gate_shift = 2,
> +		.init_parent_index = 3,
> +		.init_state = 1,
> +	},
> +	{
> +		.mux_name = "clk_out_2_mux",
> +		.gate_name = "clk_out_2",
> +		.parents = clk_out2_parents,
> +		.num_parents = ARRAY_SIZE(clk_out2_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_2,
> +		.dev_name = "extern2",
> +		.mux_shift = 14,
> +		.gate_shift = 10,
> +		.init_parent_index = 0,
> +		.init_state = 0,
> +	},
> +	{
> +		.mux_name = "clk_out_3_mux",
> +		.gate_name = "clk_out_3",
> +		.parents = clk_out3_parents,
> +		.num_parents = ARRAY_SIZE(clk_out3_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_3,
> +		.dev_name = "extern3",
> +		.mux_shift = 22,
> +		.gate_shift = 18,
> +		.init_parent_index = 0,
> +		.init_state = 0,
> +	},
> +};
> +
>  struct tegra_powergate {
>  	struct generic_pm_domain genpd;
>  	struct tegra_pmc *pmc;
> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>  	 */
>  	const struct tegra_wake_event *wake_events;
>  	unsigned int num_wake_events;
> +
> +	struct pmc_clk_init_data *pmc_clks_data;
> +	unsigned int num_pmc_clks;
>  };
>  
>  static const char * const tegra186_reset_sources[] = {
> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
>  	return NOTIFY_OK;
>  }
>  
> +static void pmc_clk_fence_udelay(u32 offset)
> +{
> +	tegra_pmc_readl(pmc, offset);
> +	/* pmc clk propagation delay 2 us */
> +	udelay(2);
> +}
> +
> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
> +{
> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
> +	val &= mux->mask;
> +
> +	if (val >= num_parents)
> +		return -EINVAL;
> +
> +	return val;
> +}
> +
> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, mux->offs);
> +	val &= ~(mux->mask << mux->shift);
> +	val |= index << mux->shift;
> +	tegra_pmc_writel(pmc, val, mux->offs);
> +	pmc_clk_fence_udelay(mux->offs);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops pmc_clk_mux_ops = {
> +	.get_parent = pmc_clk_mux_get_parent,
> +	.set_parent = pmc_clk_mux_set_parent,
> +	.determine_rate = __clk_mux_determine_rate,
> +};
> +
> +static struct clk *
> +tegra_pmc_clk_mux_register(const char *name, const char * const *parent_names,
> +			   int num_parents, unsigned long flags,
> +			   unsigned long offset, u32 shift, u32 mask)
> +{
> +	struct clk_init_data init;
> +	struct pmc_clk_mux *mux;
> +
> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pmc_clk_mux_ops;
> +	init.parent_names = parent_names;
> +	init.num_parents = num_parents;
> +	init.flags = flags;
> +
> +	mux->hw.init = &init;
> +	mux->offs = offset;
> +	mux->mask = mask;
> +	mux->shift = shift;
> +
> +	return clk_register(NULL, &mux->hw);
> +}
> +
> +static int pmc_clk_is_enabled(struct clk_hw *hw)
> +{
> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
> +
> +	return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
> +}
> +
> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
> +{
> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, gate->offs);
> +	val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
> +	tegra_pmc_writel(pmc, val, gate->offs);
> +	pmc_clk_fence_udelay(gate->offs);
> +}
> +
> +static int pmc_clk_enable(struct clk_hw *hw)
> +{
> +	pmc_clk_set_state(hw, 1);
> +
> +	return 0;
> +}
> +
> +static void pmc_clk_disable(struct clk_hw *hw)
> +{
> +	pmc_clk_set_state(hw, 0);
> +}
> +
> +static const struct clk_ops pmc_clk_gate_ops = {
> +	.is_enabled = pmc_clk_is_enabled,
> +	.enable = pmc_clk_enable,
> +	.disable = pmc_clk_disable,
> +};
> +
> +static struct clk *
> +tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
> +			    unsigned long flags, unsigned long offset,
> +			    u32 shift)
> +{
> +	struct clk_init_data init;
> +	struct pmc_clk_gate *gate;
> +
> +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +	if (!gate)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pmc_clk_gate_ops;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +	init.flags = flags;
> +
> +	gate->hw.init = &init;
> +	gate->offs = offset;
> +	gate->shift = shift;
> +
> +	return clk_register(NULL, &gate->hw);
> +}
> +
> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
> +				     struct device_node *np)
> +{
> +	struct clk *clkmux, *clk, *parent;
> +	struct clk_onecell_data *clk_data;
> +	unsigned int num_clks;
> +	int i, ret;
> +
> +	/* each pmc clock output has a mux and a gate */
> +	num_clks = pmc->soc->num_pmc_clks * 2;
> +
> +	if (!num_clks)
> +		return;
> +
> +	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
> +	if (!clk_data)
> +		return;
> +
> +	clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX, sizeof(*clk_data->clks),
> +				 GFP_KERNEL);
> +	if (!clk_data->clks)
> +		goto free_clkdata;
> +
> +	clk_data->clk_num = num_clks;
> +
> +	for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
> +		struct pmc_clk_init_data *data;
> +
> +		data = pmc->soc->pmc_clks_data + i;
> +
> +		clkmux = tegra_pmc_clk_mux_register(data->mux_name,
> +						    data->parents,
> +						    data->num_parents,
> +						    CLK_SET_RATE_NO_REPARENT |
> +						    CLK_SET_RATE_PARENT,
> +						    PMC_CLK_OUT_CNTRL,
> +						    data->mux_shift, 3);
> +		if (IS_ERR(clkmux))
> +			goto free_clks;
> +
> +		clk_data->clks[data->mux_id] = clkmux;
> +
> +		clk = tegra_pmc_clk_gate_register(data->gate_name,
> +						  data->mux_name,
> +						  CLK_SET_RATE_PARENT,
> +						  PMC_CLK_OUT_CNTRL,
> +						  data->gate_shift);
> +		if (IS_ERR(clk))
> +			goto free_clks;
> +
> +		clk_data->clks[data->gate_id] = clk;
> +
> +		ret = clk_set_parent(clk, clkmux);
> +		if (ret < 0) {
> +			pr_err("failed to set parent of %s to %s\n",
> +			       __func__, __clk_get_name(clk),
> +			       __clk_get_name(clkmux));
> +		}
> +
> +		clk_register_clkdev(clk, data->dev_name, data->gate_name);
> +
> +		/* configure initial clock parent and state */
> +		parent = clk_get_sys(data->gate_name,
> +				     data->parents[data->init_parent_index]);
> +		if (!IS_ERR(parent)) {
> +			ret = clk_set_parent(clkmux, parent);
> +			if (ret < 0) {
> +				pr_err("failed to set parent of %s to %s\n",
> +				       __func__, __clk_get_name(clkmux),
> +				       __clk_get_name(parent));
> +				WARN_ON(1);
> +			}
> +		}
> +
> +		if (data->init_state) {
> +			if (clk_prepare_enable(clk)) {
> +				pr_err("failed to enable %s\n", __func__,
> +				       __clk_get_name(clk));
> +				WARN_ON(1);
> +			}
> +		}
> +	}

In file included from ./include/linux/printk.h:7,
                 from ./include/linux/kernel.h:15,
                 from ./include/linux/clk.h:13,
                 from drivers/soc/tegra/pmc.c:15:
drivers/soc/tegra/pmc.c: In function ‘tegra_pmc_clock_register’:
./include/linux/kern_levels.h:5:18: warning: too many arguments for
format [-Wformat-extra-args]
    5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
      |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro ‘KERN_SOH’
   11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
      |                  ^~~~~~~~
./include/linux/printk.h:304:9: note: in expansion of macro ‘KERN_ERR’
  304 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
      |         ^~~~~~~~
drivers/soc/tegra/pmc.c:2451:4: note: in expansion of macro ‘pr_err’
 2451 |    pr_err("failed to set parent of %s to %s\n",
      |    ^~~~~~
./include/linux/kern_levels.h:5:18: warning: too many arguments for
format [-Wformat-extra-args]
    5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
      |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro ‘KERN_SOH’
   11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
      |                  ^~~~~~~~
./include/linux/printk.h:304:9: note: in expansion of macro ‘KERN_ERR’
  304 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
      |         ^~~~~~~~
drivers/soc/tegra/pmc.c:2464:5: note: in expansion of macro ‘pr_err’
 2464 |     pr_err("failed to set parent of %s to %s\n",
      |     ^~~~~~
./include/linux/kern_levels.h:5:18: warning: too many arguments for
format [-Wformat-extra-args]
    5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
      |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro ‘KERN_SOH’
   11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
      |                  ^~~~~~~~
./include/linux/printk.h:304:9: note: in expansion of macro ‘KERN_ERR’
  304 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
      |         ^~~~~~~~
drivers/soc/tegra/pmc.c:2473:5: note: in expansion of macro ‘pr_err’
 2473 |     pr_err("failed to enable %s\n", __func__,
      |


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  2019-11-27  4:59 ` [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings Sowjanya Komatineni
@ 2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 17:06     ` Sowjanya Komatineni
  2019-11-28 12:18     ` Thierry Reding
  0 siblings, 2 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-27 14:32 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> clk_out_1, clk_out_2, clk_out_3, blink are part of Tegra pmc clocks.
> 
> This patch removes ids for these clocks from Tegra clock dt-bindings.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  include/dt-bindings/clock/tegra114-car.h        | 14 +++++++-------
>  include/dt-bindings/clock/tegra124-car-common.h | 14 +++++++-------
>  include/dt-bindings/clock/tegra20-car.h         |  2 +-
>  include/dt-bindings/clock/tegra210-car.h        | 14 +++++++-------
>  include/dt-bindings/clock/tegra30-car.h         | 14 +++++++-------
>  5 files changed, 29 insertions(+), 29 deletions(-)
> 
> diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
> index bb5c2c999c05..9175cd0571b5 100644
> --- a/include/dt-bindings/clock/tegra114-car.h
> +++ b/include/dt-bindings/clock/tegra114-car.h
> @@ -270,10 +270,10 @@
>  #define TEGRA114_CLK_AUDIO3 242
>  #define TEGRA114_CLK_AUDIO4 243
>  #define TEGRA114_CLK_SPDIF 244
> -#define TEGRA114_CLK_CLK_OUT_1 245
> -#define TEGRA114_CLK_CLK_OUT_2 246
> -#define TEGRA114_CLK_CLK_OUT_3 247
> -#define TEGRA114_CLK_BLINK 248
> +/* 245 */
> +/* 246 */
> +/* 247 */
> +/* 248 */
>  /* 249 */
>  /* 250 */
>  /* 251 */
> @@ -333,9 +333,9 @@
>  #define TEGRA114_CLK_AUDIO3_MUX 303
>  #define TEGRA114_CLK_AUDIO4_MUX 304
>  #define TEGRA114_CLK_SPDIF_MUX 305
> -#define TEGRA114_CLK_CLK_OUT_1_MUX 306
> -#define TEGRA114_CLK_CLK_OUT_2_MUX 307
> -#define TEGRA114_CLK_CLK_OUT_3_MUX 308
> +/* 306 */
> +/* 307 */
> +/* 308 */
>  #define TEGRA114_CLK_DSIA_MUX 309
>  #define TEGRA114_CLK_DSIB_MUX 310
>  #define TEGRA114_CLK_XUSB_SS_DIV2 311
> diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
> index 0c4f5be0a742..90a0c5e7eb5f 100644
> --- a/include/dt-bindings/clock/tegra124-car-common.h
> +++ b/include/dt-bindings/clock/tegra124-car-common.h
> @@ -269,10 +269,10 @@
>  #define TEGRA124_CLK_AUDIO3 242
>  #define TEGRA124_CLK_AUDIO4 243
>  #define TEGRA124_CLK_SPDIF 244
> -#define TEGRA124_CLK_CLK_OUT_1 245
> -#define TEGRA124_CLK_CLK_OUT_2 246
> -#define TEGRA124_CLK_CLK_OUT_3 247
> -#define TEGRA124_CLK_BLINK 248
> +/* 245 */
> +/* 246 */
> +/* 247 */
> +/* 248 */
>  /* 249 */
>  /* 250 */
>  /* 251 */
> @@ -332,9 +332,9 @@
>  #define TEGRA124_CLK_AUDIO3_MUX 303
>  #define TEGRA124_CLK_AUDIO4_MUX 304
>  #define TEGRA124_CLK_SPDIF_MUX 305
> -#define TEGRA124_CLK_CLK_OUT_1_MUX 306
> -#define TEGRA124_CLK_CLK_OUT_2_MUX 307
> -#define TEGRA124_CLK_CLK_OUT_3_MUX 308
> +/* 306 */
> +/* 307 */
> +/* 308 */
>  /* 309 */
>  /* 310 */
>  #define TEGRA124_CLK_SOR0_LVDS 311 /* deprecated */
> diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
> index b21a0eb32921..fe541f627965 100644
> --- a/include/dt-bindings/clock/tegra20-car.h
> +++ b/include/dt-bindings/clock/tegra20-car.h
> @@ -131,7 +131,7 @@
>  #define TEGRA20_CLK_CCLK 108
>  #define TEGRA20_CLK_HCLK 109
>  #define TEGRA20_CLK_PCLK 110
> -#define TEGRA20_CLK_BLINK 111
> +/* 111 */
>  #define TEGRA20_CLK_PLL_A 112
>  #define TEGRA20_CLK_PLL_A_OUT0 113
>  #define TEGRA20_CLK_PLL_C 114
> diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
> index 44f60623f99b..a3d8d3e75728 100644
> --- a/include/dt-bindings/clock/tegra210-car.h
> +++ b/include/dt-bindings/clock/tegra210-car.h
> @@ -304,10 +304,10 @@
>  #define TEGRA210_CLK_AUDIO3 274
>  #define TEGRA210_CLK_AUDIO4 275
>  #define TEGRA210_CLK_SPDIF 276
> -#define TEGRA210_CLK_CLK_OUT_1 277
> -#define TEGRA210_CLK_CLK_OUT_2 278
> -#define TEGRA210_CLK_CLK_OUT_3 279
> -#define TEGRA210_CLK_BLINK 280
> +/* 277 */
> +/* 278 */
> +/* 279 */
> +/* 280 */
>  #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */
>  #define TEGRA210_CLK_SOR0_OUT 281
>  #define TEGRA210_CLK_SOR1_OUT 282
> @@ -386,9 +386,9 @@
>  #define TEGRA210_CLK_AUDIO3_MUX 353
>  #define TEGRA210_CLK_AUDIO4_MUX 354
>  #define TEGRA210_CLK_SPDIF_MUX 355
> -#define TEGRA210_CLK_CLK_OUT_1_MUX 356
> -#define TEGRA210_CLK_CLK_OUT_2_MUX 357
> -#define TEGRA210_CLK_CLK_OUT_3_MUX 358
> +/* 356 */
> +/* 357 */
> +/* 358 */
>  #define TEGRA210_CLK_DSIA_MUX 359
>  #define TEGRA210_CLK_DSIB_MUX 360
>  /* 361 */
> diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
> index 3c90f1535551..20ef2462d9e1 100644
> --- a/include/dt-bindings/clock/tegra30-car.h
> +++ b/include/dt-bindings/clock/tegra30-car.h
> @@ -230,11 +230,11 @@
>  #define TEGRA30_CLK_AUDIO3 204
>  #define TEGRA30_CLK_AUDIO4 205
>  #define TEGRA30_CLK_SPDIF 206
> -#define TEGRA30_CLK_CLK_OUT_1 207 /* (extern1) */
> -#define TEGRA30_CLK_CLK_OUT_2 208 /* (extern2) */
> -#define TEGRA30_CLK_CLK_OUT_3 209 /* (extern3) */
> +/* 207 */
> +/* 208 */
> +/* 209 */
>  #define TEGRA30_CLK_SCLK 210
> -#define TEGRA30_CLK_BLINK 211
> +/* 211 */
>  #define TEGRA30_CLK_CCLK_G 212
>  #define TEGRA30_CLK_CCLK_LP 213
>  #define TEGRA30_CLK_TWD 214
> @@ -260,9 +260,9 @@
>  /* 297 */
>  /* 298 */
>  /* 299 */
> -#define TEGRA30_CLK_CLK_OUT_1_MUX 300
> -#define TEGRA30_CLK_CLK_OUT_2_MUX 301
> -#define TEGRA30_CLK_CLK_OUT_3_MUX 302
> +/* 300 */
> +/* 301 */
> +/* 302 */
>  #define TEGRA30_CLK_AUDIO0_MUX 303
>  #define TEGRA30_CLK_AUDIO1_MUX 304
>  #define TEGRA30_CLK_AUDIO2_MUX 305
> 

This a device-tree ABI breakage and I'm not sure that it's okay to break
older device-trees (Pixel C Smaug board), maybe some kind of fallback is
needed.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
  2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 14:32   ` Dmitry Osipenko
@ 2019-11-27 15:14   ` Dmitry Osipenko
  2019-11-27 22:57     ` Sowjanya Komatineni
  2 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-27 15:14 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
> mux and gate for each of these clocks.
> 
> Currently these PMC clocks are registered by Tegra clock driver using
> clk_register_mux and clk_register_gate by passing PMC base address
> and register offsets and PMC programming for these clocks happens
> through direct PMC access by the clock driver.
> 
> With this, when PMC is in secure mode any direct PMC access from the
> non-secure world does not go through and these clocks will not be
> functional.
> 
> This patch adds these clocks registration with PMC as a clock provider
> for these clocks. clk_ops callback implementations for these clocks
> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
> in secure mode and non-secure mode.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 330 insertions(+)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index ea0e11a09c12..a353f6d0a832 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -13,6 +13,9 @@
>  
>  #include <linux/arm-smccc.h>
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/clk-conf.h>
>  #include <linux/clk/tegra.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -48,6 +51,7 @@
>  #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>  #include <dt-bindings/gpio/tegra186-gpio.h>
>  #include <dt-bindings/gpio/tegra194-gpio.h>
> +#include <dt-bindings/soc/tegra-pmc.h>
>  
>  #define PMC_CNTRL			0x0
>  #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
> @@ -100,6 +104,7 @@
>  #define PMC_WAKE2_STATUS		0x168
>  #define PMC_SW_WAKE2_STATUS		0x16c
>  
> +#define PMC_CLK_OUT_CNTRL		0x1a8
>  #define PMC_SENSOR_CTRL			0x1b0
>  #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
>  #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
> @@ -155,6 +160,91 @@
>  #define  TEGRA_SMC_PMC_READ	0xaa
>  #define  TEGRA_SMC_PMC_WRITE	0xbb
>  
> +struct pmc_clk_mux {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		mask;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
> +
> +struct pmc_clk_gate {
> +	struct clk_hw	hw;
> +	unsigned long	offs;
> +	u32		shift;
> +};
> +
> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
> +
> +struct pmc_clk_init_data {
> +	char *mux_name;
> +	char *gate_name;
> +	const char **parents;
> +	int num_parents;
> +	int mux_id;
> +	int gate_id;
> +	char *dev_name;
> +	u8 mux_shift;
> +	u8 gate_shift;
> +	u8 init_parent_index;
> +	int init_state;
> +};
> +
> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern1",
> +};
> +
> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern2",
> +};
> +
> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
> +	"clk_m_div4", "extern3",
> +};
> +
> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
> +	{
> +		.mux_name = "clk_out_1_mux",
> +		.gate_name = "clk_out_1",
> +		.parents = clk_out1_parents,
> +		.num_parents = ARRAY_SIZE(clk_out1_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_1,
> +		.dev_name = "extern1",
> +		.mux_shift = 6,
> +		.gate_shift = 2,
> +		.init_parent_index = 3,
> +		.init_state = 1,
> +	},
> +	{
> +		.mux_name = "clk_out_2_mux",
> +		.gate_name = "clk_out_2",
> +		.parents = clk_out2_parents,
> +		.num_parents = ARRAY_SIZE(clk_out2_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_2,
> +		.dev_name = "extern2",
> +		.mux_shift = 14,
> +		.gate_shift = 10,
> +		.init_parent_index = 0,
> +		.init_state = 0,
> +	},
> +	{
> +		.mux_name = "clk_out_3_mux",
> +		.gate_name = "clk_out_3",
> +		.parents = clk_out3_parents,
> +		.num_parents = ARRAY_SIZE(clk_out3_parents),
> +		.mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
> +		.gate_id = TEGRA_PMC_CLK_OUT_3,
> +		.dev_name = "extern3",
> +		.mux_shift = 22,
> +		.gate_shift = 18,
> +		.init_parent_index = 0,
> +		.init_state = 0,
> +	},
> +};
> +
>  struct tegra_powergate {
>  	struct generic_pm_domain genpd;
>  	struct tegra_pmc *pmc;
> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>  	 */
>  	const struct tegra_wake_event *wake_events;
>  	unsigned int num_wake_events;
> +
> +	struct pmc_clk_init_data *pmc_clks_data;
> +	unsigned int num_pmc_clks;
>  };
>  
>  static const char * const tegra186_reset_sources[] = {
> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
>  	return NOTIFY_OK;
>  }
>  
> +static void pmc_clk_fence_udelay(u32 offset)
> +{
> +	tegra_pmc_readl(pmc, offset);
> +	/* pmc clk propagation delay 2 us */
> +	udelay(2);
> +}
> +
> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
> +{
> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
> +	val &= mux->mask;
> +
> +	if (val >= num_parents)
> +		return -EINVAL;
> +
> +	return val;
> +}
> +
> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, mux->offs);
> +	val &= ~(mux->mask << mux->shift);
> +	val |= index << mux->shift;
> +	tegra_pmc_writel(pmc, val, mux->offs);
> +	pmc_clk_fence_udelay(mux->offs);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops pmc_clk_mux_ops = {
> +	.get_parent = pmc_clk_mux_get_parent,
> +	.set_parent = pmc_clk_mux_set_parent,
> +	.determine_rate = __clk_mux_determine_rate,
> +};
> +
> +static struct clk *
> +tegra_pmc_clk_mux_register(const char *name, const char * const *parent_names,
> +			   int num_parents, unsigned long flags,
> +			   unsigned long offset, u32 shift, u32 mask)
> +{
> +	struct clk_init_data init;
> +	struct pmc_clk_mux *mux;
> +
> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pmc_clk_mux_ops;
> +	init.parent_names = parent_names;
> +	init.num_parents = num_parents;
> +	init.flags = flags;
> +
> +	mux->hw.init = &init;
> +	mux->offs = offset;
> +	mux->mask = mask;
> +	mux->shift = shift;
> +
> +	return clk_register(NULL, &mux->hw);
> +}
> +
> +static int pmc_clk_is_enabled(struct clk_hw *hw)
> +{
> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
> +
> +	return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
> +}
> +
> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
> +{
> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
> +	u32 val;
> +
> +	val = tegra_pmc_readl(pmc, gate->offs);
> +	val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
> +	tegra_pmc_writel(pmc, val, gate->offs);
> +	pmc_clk_fence_udelay(gate->offs);
> +}
> +
> +static int pmc_clk_enable(struct clk_hw *hw)
> +{
> +	pmc_clk_set_state(hw, 1);
> +
> +	return 0;
> +}
> +
> +static void pmc_clk_disable(struct clk_hw *hw)
> +{
> +	pmc_clk_set_state(hw, 0);
> +}
> +
> +static const struct clk_ops pmc_clk_gate_ops = {
> +	.is_enabled = pmc_clk_is_enabled,
> +	.enable = pmc_clk_enable,
> +	.disable = pmc_clk_disable,
> +};
> +
> +static struct clk *
> +tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
> +			    unsigned long flags, unsigned long offset,
> +			    u32 shift)
> +{
> +	struct clk_init_data init;
> +	struct pmc_clk_gate *gate;
> +
> +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +	if (!gate)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pmc_clk_gate_ops;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +	init.flags = flags;
> +
> +	gate->hw.init = &init;
> +	gate->offs = offset;
> +	gate->shift = shift;
> +
> +	return clk_register(NULL, &gate->hw);
> +}
> +
> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
> +				     struct device_node *np)
> +{
> +	struct clk *clkmux, *clk, *parent;
> +	struct clk_onecell_data *clk_data;
> +	unsigned int num_clks;
> +	int i, ret;
> +
> +	/* each pmc clock output has a mux and a gate */
> +	num_clks = pmc->soc->num_pmc_clks * 2;
> +
> +	if (!num_clks)
> +		return;
> +
> +	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
> +	if (!clk_data)
> +		return;
> +
> +	clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX, sizeof(*clk_data->clks),
> +				 GFP_KERNEL);
> +	if (!clk_data->clks)
> +		goto free_clkdata;
> +
> +	clk_data->clk_num = num_clks;
> +
> +	for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
> +		struct pmc_clk_init_data *data;
> +
> +		data = pmc->soc->pmc_clks_data + i;
> +
> +		clkmux = tegra_pmc_clk_mux_register(data->mux_name,
> +						    data->parents,
> +						    data->num_parents,
> +						    CLK_SET_RATE_NO_REPARENT |
> +						    CLK_SET_RATE_PARENT,
> +						    PMC_CLK_OUT_CNTRL,
> +						    data->mux_shift, 3);
> +		if (IS_ERR(clkmux))
> +			goto free_clks;
> +
> +		clk_data->clks[data->mux_id] = clkmux;
> +
> +		clk = tegra_pmc_clk_gate_register(data->gate_name,
> +						  data->mux_name,
> +						  CLK_SET_RATE_PARENT,
> +						  PMC_CLK_OUT_CNTRL,
> +						  data->gate_shift);
> +		if (IS_ERR(clk))
> +			goto free_clks;
> +
> +		clk_data->clks[data->gate_id] = clk;
> +
> +		ret = clk_set_parent(clk, clkmux);
> +		if (ret < 0) {
> +			pr_err("failed to set parent of %s to %s\n",
> +			       __func__, __clk_get_name(clk),
> +			       __clk_get_name(clkmux));
> +		}
> +
> +		clk_register_clkdev(clk, data->dev_name, data->gate_name);
> +
> +		/* configure initial clock parent and state */
> +		parent = clk_get_sys(data->gate_name,
> +				     data->parents[data->init_parent_index]);
> +		if (!IS_ERR(parent)) {
> +			ret = clk_set_parent(clkmux, parent);
> +			if (ret < 0) {
> +				pr_err("failed to set parent of %s to %s\n",
> +				       __func__, __clk_get_name(clkmux),
> +				       __clk_get_name(parent));
> +				WARN_ON(1);
> +			}
> +		}
> +
> +		if (data->init_state) {
> +			if (clk_prepare_enable(clk)) {
> +				pr_err("failed to enable %s\n", __func__,
> +				       __clk_get_name(clk));
> +				WARN_ON(1);

Should be a bit better to move the WARN_ON to the end of errors handling
in order to catch all possible errors:

@@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
tegra_pmc *pmc,
        return;

 free_clks:
+       WARN_ON(1);
        kfree(clk_data->clks);
 free_clkdata:
        kfree(clk_data);

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-27 14:31 ` [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Dmitry Osipenko
@ 2019-11-27 17:02   ` Sowjanya Komatineni
  2019-11-27 21:38     ` Sowjanya Komatineni
  2019-11-28 12:26   ` Thierry Reding
  1 sibling, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27 17:02 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel


On 11/27/19 6:31 AM, Dmitry Osipenko wrote:
> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>> are currently registered by Tegra clock driver using clk_regiser_mux and
>> clk_register_gate which performs direct Tegra PMC register access.
>>
>> When Tegra PMC is in secure mode, any access from non-secure world will
>> not go through.
>>
>> This patch series adds these Tegra PMC clocks and blink controls to Tegra
>> PMC driver with PMC as clock provider and removed them from Tegra clock
>> driver. This also adds PMC specific clock id's to use in device tree and
>> removed clock ids of PMC clock from Tegra clock driver.
>>
>> This series also includes patch to update clock provider from tegra_car
>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 from PMC.
>>
>> [v2]:	Changes between v1 and v2 are
>> 	- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>> 	  blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>> 	- feedback related to pmc clocks in Tegra PMC driver from v1
>> 	- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
>> 	  by the clock driver using helper functions from Tegra PMC.
>>
>>   	  Note:
>> 	  To use helper functions from PMC driver, PMC early init need to
>> 	  happen prior to using helper functions and these helper functions are
>> 	  for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
>> 	  clock registration which happen in clock_init prior to Tegra PMC
>> 	  probe.
>> 	  Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>> 	  impacts other clocks EMC, MC and corresponding tegra_emc_init and
>> 	  tegra_mc_init.
>> 	  This implementation of configuring PMC registers thru helper
>> 	  functions in clock driver needs proper changes across PMC, Clock,
>> 	  EMC and MC inits to have it work across all Tegra platforms.
>>
>> 	  Currently PLLM Override is not enabled in the bootloader so proper
>> 	  patches for this fix will be taken care separately.
> Hello Sowjanya,
>
> Could you please clarify what do you mean by "PLLM Override not enabled
> in bootloader"?
>
> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
> which has the PLLM Override set by bootloader as well. It's not clear to
> me whether this patch series is supposed to break these devices. If the
> breakage is the case here, then I'm afraid you can't postpone supporting
> the PLLM Override and a full-featured implementation is needed.

Hi Dmitry,

Secure boot currently is enabled only on Tegra210 and Tegra210 
bootloader doesn't enable PLLM override.

So PLLM override/PLLE IDDQ being in clock driver currently will not 
break on any of existing Tegra platforms.

>
> I briefly tried to test this series on T30 and this time it doesn't hang
> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
> chip uses the Blink clock source and the clock should be enabled by the
> MMC core because this is how DT part looks like:
>
> brcm_wifi_pwrseq: wifi-pwrseq {
> 	compatible = "mmc-pwrseq-simple";
> 	clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
> 	clock-names = "ext_clock";
> 	reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
> 	post-power-on-delay-ms = <300>;
> 	power-off-delay-us = <300>;
> };
>
> BTW, I  tried this series on a T20 device which also uses the Blink
> clock for WiFi card and it works. So looks like this patchset has some
> problem in regards to the T30 PMC clocks implementation.
>
> [snip]

Blink init state is set to true for both Tegra20 and Tegra30 and all go 
through the same blink programming sequence.

Will try to add more debug messages to dump registers and will test 
blink through device tree on T30 and will get back...



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  2019-11-27 14:32   ` Dmitry Osipenko
@ 2019-11-27 17:06     ` Sowjanya Komatineni
  2019-11-28 12:18     ` Thierry Reding
  1 sibling, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27 17:06 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 11/27/19 6:32 AM, Dmitry Osipenko wrote:
> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>> clk_out_1, clk_out_2, clk_out_3, blink are part of Tegra pmc clocks.
>>
>> This patch removes ids for these clocks from Tegra clock dt-bindings.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   include/dt-bindings/clock/tegra114-car.h        | 14 +++++++-------
>>   include/dt-bindings/clock/tegra124-car-common.h | 14 +++++++-------
>>   include/dt-bindings/clock/tegra20-car.h         |  2 +-
>>   include/dt-bindings/clock/tegra210-car.h        | 14 +++++++-------
>>   include/dt-bindings/clock/tegra30-car.h         | 14 +++++++-------
>>   5 files changed, 29 insertions(+), 29 deletions(-)
>>
>> diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
>> index bb5c2c999c05..9175cd0571b5 100644
>> --- a/include/dt-bindings/clock/tegra114-car.h
>> +++ b/include/dt-bindings/clock/tegra114-car.h
>> @@ -270,10 +270,10 @@
>>   #define TEGRA114_CLK_AUDIO3 242
>>   #define TEGRA114_CLK_AUDIO4 243
>>   #define TEGRA114_CLK_SPDIF 244
>> -#define TEGRA114_CLK_CLK_OUT_1 245
>> -#define TEGRA114_CLK_CLK_OUT_2 246
>> -#define TEGRA114_CLK_CLK_OUT_3 247
>> -#define TEGRA114_CLK_BLINK 248
>> +/* 245 */
>> +/* 246 */
>> +/* 247 */
>> +/* 248 */
>>   /* 249 */
>>   /* 250 */
>>   /* 251 */
>> @@ -333,9 +333,9 @@
>>   #define TEGRA114_CLK_AUDIO3_MUX 303
>>   #define TEGRA114_CLK_AUDIO4_MUX 304
>>   #define TEGRA114_CLK_SPDIF_MUX 305
>> -#define TEGRA114_CLK_CLK_OUT_1_MUX 306
>> -#define TEGRA114_CLK_CLK_OUT_2_MUX 307
>> -#define TEGRA114_CLK_CLK_OUT_3_MUX 308
>> +/* 306 */
>> +/* 307 */
>> +/* 308 */
>>   #define TEGRA114_CLK_DSIA_MUX 309
>>   #define TEGRA114_CLK_DSIB_MUX 310
>>   #define TEGRA114_CLK_XUSB_SS_DIV2 311
>> diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
>> index 0c4f5be0a742..90a0c5e7eb5f 100644
>> --- a/include/dt-bindings/clock/tegra124-car-common.h
>> +++ b/include/dt-bindings/clock/tegra124-car-common.h
>> @@ -269,10 +269,10 @@
>>   #define TEGRA124_CLK_AUDIO3 242
>>   #define TEGRA124_CLK_AUDIO4 243
>>   #define TEGRA124_CLK_SPDIF 244
>> -#define TEGRA124_CLK_CLK_OUT_1 245
>> -#define TEGRA124_CLK_CLK_OUT_2 246
>> -#define TEGRA124_CLK_CLK_OUT_3 247
>> -#define TEGRA124_CLK_BLINK 248
>> +/* 245 */
>> +/* 246 */
>> +/* 247 */
>> +/* 248 */
>>   /* 249 */
>>   /* 250 */
>>   /* 251 */
>> @@ -332,9 +332,9 @@
>>   #define TEGRA124_CLK_AUDIO3_MUX 303
>>   #define TEGRA124_CLK_AUDIO4_MUX 304
>>   #define TEGRA124_CLK_SPDIF_MUX 305
>> -#define TEGRA124_CLK_CLK_OUT_1_MUX 306
>> -#define TEGRA124_CLK_CLK_OUT_2_MUX 307
>> -#define TEGRA124_CLK_CLK_OUT_3_MUX 308
>> +/* 306 */
>> +/* 307 */
>> +/* 308 */
>>   /* 309 */
>>   /* 310 */
>>   #define TEGRA124_CLK_SOR0_LVDS 311 /* deprecated */
>> diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
>> index b21a0eb32921..fe541f627965 100644
>> --- a/include/dt-bindings/clock/tegra20-car.h
>> +++ b/include/dt-bindings/clock/tegra20-car.h
>> @@ -131,7 +131,7 @@
>>   #define TEGRA20_CLK_CCLK 108
>>   #define TEGRA20_CLK_HCLK 109
>>   #define TEGRA20_CLK_PCLK 110
>> -#define TEGRA20_CLK_BLINK 111
>> +/* 111 */
>>   #define TEGRA20_CLK_PLL_A 112
>>   #define TEGRA20_CLK_PLL_A_OUT0 113
>>   #define TEGRA20_CLK_PLL_C 114
>> diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
>> index 44f60623f99b..a3d8d3e75728 100644
>> --- a/include/dt-bindings/clock/tegra210-car.h
>> +++ b/include/dt-bindings/clock/tegra210-car.h
>> @@ -304,10 +304,10 @@
>>   #define TEGRA210_CLK_AUDIO3 274
>>   #define TEGRA210_CLK_AUDIO4 275
>>   #define TEGRA210_CLK_SPDIF 276
>> -#define TEGRA210_CLK_CLK_OUT_1 277
>> -#define TEGRA210_CLK_CLK_OUT_2 278
>> -#define TEGRA210_CLK_CLK_OUT_3 279
>> -#define TEGRA210_CLK_BLINK 280
>> +/* 277 */
>> +/* 278 */
>> +/* 279 */
>> +/* 280 */
>>   #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */
>>   #define TEGRA210_CLK_SOR0_OUT 281
>>   #define TEGRA210_CLK_SOR1_OUT 282
>> @@ -386,9 +386,9 @@
>>   #define TEGRA210_CLK_AUDIO3_MUX 353
>>   #define TEGRA210_CLK_AUDIO4_MUX 354
>>   #define TEGRA210_CLK_SPDIF_MUX 355
>> -#define TEGRA210_CLK_CLK_OUT_1_MUX 356
>> -#define TEGRA210_CLK_CLK_OUT_2_MUX 357
>> -#define TEGRA210_CLK_CLK_OUT_3_MUX 358
>> +/* 356 */
>> +/* 357 */
>> +/* 358 */
>>   #define TEGRA210_CLK_DSIA_MUX 359
>>   #define TEGRA210_CLK_DSIB_MUX 360
>>   /* 361 */
>> diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
>> index 3c90f1535551..20ef2462d9e1 100644
>> --- a/include/dt-bindings/clock/tegra30-car.h
>> +++ b/include/dt-bindings/clock/tegra30-car.h
>> @@ -230,11 +230,11 @@
>>   #define TEGRA30_CLK_AUDIO3 204
>>   #define TEGRA30_CLK_AUDIO4 205
>>   #define TEGRA30_CLK_SPDIF 206
>> -#define TEGRA30_CLK_CLK_OUT_1 207 /* (extern1) */
>> -#define TEGRA30_CLK_CLK_OUT_2 208 /* (extern2) */
>> -#define TEGRA30_CLK_CLK_OUT_3 209 /* (extern3) */
>> +/* 207 */
>> +/* 208 */
>> +/* 209 */
>>   #define TEGRA30_CLK_SCLK 210
>> -#define TEGRA30_CLK_BLINK 211
>> +/* 211 */
>>   #define TEGRA30_CLK_CCLK_G 212
>>   #define TEGRA30_CLK_CCLK_LP 213
>>   #define TEGRA30_CLK_TWD 214
>> @@ -260,9 +260,9 @@
>>   /* 297 */
>>   /* 298 */
>>   /* 299 */
>> -#define TEGRA30_CLK_CLK_OUT_1_MUX 300
>> -#define TEGRA30_CLK_CLK_OUT_2_MUX 301
>> -#define TEGRA30_CLK_CLK_OUT_3_MUX 302
>> +/* 300 */
>> +/* 301 */
>> +/* 302 */
>>   #define TEGRA30_CLK_AUDIO0_MUX 303
>>   #define TEGRA30_CLK_AUDIO1_MUX 304
>>   #define TEGRA30_CLK_AUDIO2_MUX 305
>>
> This a device-tree ABI breakage and I'm not sure that it's okay to break
> older device-trees (Pixel C Smaug board), maybe some kind of fallback is
> needed.

As provider itself changed from tegra_car to pmc, all platform 
device-trees using CLK_OUT_1/2/3 ids from Tegra car should be moved to 
PMC and use PMC clock ids.

Based on upstream device tree search, I only see samsung t210 device 
tree currently using CLK_OUT_2. So updated that as part of this series.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-27 17:02   ` Sowjanya Komatineni
@ 2019-11-27 21:38     ` Sowjanya Komatineni
  2019-11-28 13:06       ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27 21:38 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel


On 11/27/19 9:02 AM, Sowjanya Komatineni wrote:
>
> On 11/27/19 6:31 AM, Dmitry Osipenko wrote:
>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>>> are currently registered by Tegra clock driver using clk_regiser_mux 
>>> and
>>> clk_register_gate which performs direct Tegra PMC register access.
>>>
>>> When Tegra PMC is in secure mode, any access from non-secure world will
>>> not go through.
>>>
>>> This patch series adds these Tegra PMC clocks and blink controls to 
>>> Tegra
>>> PMC driver with PMC as clock provider and removed them from Tegra clock
>>> driver. This also adds PMC specific clock id's to use in device tree 
>>> and
>>> removed clock ids of PMC clock from Tegra clock driver.
>>>
>>> This series also includes patch to update clock provider from tegra_car
>>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 
>>> from PMC.
>>>
>>> [v2]:    Changes between v1 and v2 are
>>>     - v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>>>       blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>>>     - feedback related to pmc clocks in Tegra PMC driver from v1
>>>     - Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC 
>>> programming
>>>       by the clock driver using helper functions from Tegra PMC.
>>>
>>>         Note:
>>>       To use helper functions from PMC driver, PMC early init need to
>>>       happen prior to using helper functions and these helper 
>>> functions are
>>>       for PLLM Override and PLLE IDDQ programming in PMC during 
>>> PLLM/PLLE
>>>       clock registration which happen in clock_init prior to Tegra PMC
>>>       probe.
>>>       Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>>>       impacts other clocks EMC, MC and corresponding tegra_emc_init and
>>>       tegra_mc_init.
>>>       This implementation of configuring PMC registers thru helper
>>>       functions in clock driver needs proper changes across PMC, Clock,
>>>       EMC and MC inits to have it work across all Tegra platforms.
>>>
>>>       Currently PLLM Override is not enabled in the bootloader so 
>>> proper
>>>       patches for this fix will be taken care separately.
>> Hello Sowjanya,
>>
>> Could you please clarify what do you mean by "PLLM Override not enabled
>> in bootloader"?
>>
>> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
>> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
>> which has the PLLM Override set by bootloader as well. It's not clear to
>> me whether this patch series is supposed to break these devices. If the
>> breakage is the case here, then I'm afraid you can't postpone supporting
>> the PLLM Override and a full-featured implementation is needed.
>
> Hi Dmitry,
>
> Secure boot currently is enabled only on Tegra210 and Tegra210 
> bootloader doesn't enable PLLM override.
>
> So PLLM override/PLLE IDDQ being in clock driver currently will not 
> break on any of existing Tegra platforms.
>
>>
>> I briefly tried to test this series on T30 and this time it doesn't hang
>> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
>> chip uses the Blink clock source and the clock should be enabled by the
>> MMC core because this is how DT part looks like:
>>
>> brcm_wifi_pwrseq: wifi-pwrseq {
>>     compatible = "mmc-pwrseq-simple";
>>     clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
>>     clock-names = "ext_clock";
>>     reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
>>     post-power-on-delay-ms = <300>;
>>     power-off-delay-us = <300>;
>> };
>>
>> BTW, I  tried this series on a T20 device which also uses the Blink
>> clock for WiFi card and it works. So looks like this patchset has some
>> problem in regards to the T30 PMC clocks implementation.
>>
>> [snip]
>
> Blink init state is set to true for both Tegra20 and Tegra30 and all 
> go through the same blink programming sequence.
>
> Will try to add more debug messages to dump registers and will test 
> blink through device tree on T30 and will get back...
>
>
define value for BLINK uses BIT macro instead of just position. Will fix 
this in v3.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27 15:14   ` Dmitry Osipenko
@ 2019-11-27 22:57     ` Sowjanya Komatineni
  2019-11-28 13:25       ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-11-27 22:57 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
>> mux and gate for each of these clocks.
>>
>> Currently these PMC clocks are registered by Tegra clock driver using
>> clk_register_mux and clk_register_gate by passing PMC base address
>> and register offsets and PMC programming for these clocks happens
>> through direct PMC access by the clock driver.
>>
>> With this, when PMC is in secure mode any direct PMC access from the
>> non-secure world does not go through and these clocks will not be
>> functional.
>>
>> This patch adds these clocks registration with PMC as a clock provider
>> for these clocks. clk_ops callback implementations for these clocks
>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
>> in secure mode and non-secure mode.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/soc/tegra/pmc.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 330 insertions(+)
>>
>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>> index ea0e11a09c12..a353f6d0a832 100644
>> --- a/drivers/soc/tegra/pmc.c
>> +++ b/drivers/soc/tegra/pmc.c
>> @@ -13,6 +13,9 @@
>>   
>>   #include <linux/arm-smccc.h>
>>   #include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/clk-conf.h>
>>   #include <linux/clk/tegra.h>
>>   #include <linux/debugfs.h>
>>   #include <linux/delay.h>
>> @@ -48,6 +51,7 @@
>>   #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>   #include <dt-bindings/gpio/tegra186-gpio.h>
>>   #include <dt-bindings/gpio/tegra194-gpio.h>
>> +#include <dt-bindings/soc/tegra-pmc.h>
>>   
>>   #define PMC_CNTRL			0x0
>>   #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
>> @@ -100,6 +104,7 @@
>>   #define PMC_WAKE2_STATUS		0x168
>>   #define PMC_SW_WAKE2_STATUS		0x16c
>>   
>> +#define PMC_CLK_OUT_CNTRL		0x1a8
>>   #define PMC_SENSOR_CTRL			0x1b0
>>   #define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
>>   #define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)
>> @@ -155,6 +160,91 @@
>>   #define  TEGRA_SMC_PMC_READ	0xaa
>>   #define  TEGRA_SMC_PMC_WRITE	0xbb
>>   
>> +struct pmc_clk_mux {
>> +	struct clk_hw	hw;
>> +	unsigned long	offs;
>> +	u32		mask;
>> +	u32		shift;
>> +};
>> +
>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
>> +
>> +struct pmc_clk_gate {
>> +	struct clk_hw	hw;
>> +	unsigned long	offs;
>> +	u32		shift;
>> +};
>> +
>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
>> +
>> +struct pmc_clk_init_data {
>> +	char *mux_name;
>> +	char *gate_name;
>> +	const char **parents;
>> +	int num_parents;
>> +	int mux_id;
>> +	int gate_id;
>> +	char *dev_name;
>> +	u8 mux_shift;
>> +	u8 gate_shift;
>> +	u8 init_parent_index;
>> +	int init_state;
>> +};
>> +
>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>> +	"clk_m_div4", "extern1",
>> +};
>> +
>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>> +	"clk_m_div4", "extern2",
>> +};
>> +
>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>> +	"clk_m_div4", "extern3",
>> +};
>> +
>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>> +	{
>> +		.mux_name = "clk_out_1_mux",
>> +		.gate_name = "clk_out_1",
>> +		.parents = clk_out1_parents,
>> +		.num_parents = ARRAY_SIZE(clk_out1_parents),
>> +		.mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>> +		.gate_id = TEGRA_PMC_CLK_OUT_1,
>> +		.dev_name = "extern1",
>> +		.mux_shift = 6,
>> +		.gate_shift = 2,
>> +		.init_parent_index = 3,
>> +		.init_state = 1,
>> +	},
>> +	{
>> +		.mux_name = "clk_out_2_mux",
>> +		.gate_name = "clk_out_2",
>> +		.parents = clk_out2_parents,
>> +		.num_parents = ARRAY_SIZE(clk_out2_parents),
>> +		.mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>> +		.gate_id = TEGRA_PMC_CLK_OUT_2,
>> +		.dev_name = "extern2",
>> +		.mux_shift = 14,
>> +		.gate_shift = 10,
>> +		.init_parent_index = 0,
>> +		.init_state = 0,
>> +	},
>> +	{
>> +		.mux_name = "clk_out_3_mux",
>> +		.gate_name = "clk_out_3",
>> +		.parents = clk_out3_parents,
>> +		.num_parents = ARRAY_SIZE(clk_out3_parents),
>> +		.mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>> +		.gate_id = TEGRA_PMC_CLK_OUT_3,
>> +		.dev_name = "extern3",
>> +		.mux_shift = 22,
>> +		.gate_shift = 18,
>> +		.init_parent_index = 0,
>> +		.init_state = 0,
>> +	},
>> +};
>> +
>>   struct tegra_powergate {
>>   	struct generic_pm_domain genpd;
>>   	struct tegra_pmc *pmc;
>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>   	 */
>>   	const struct tegra_wake_event *wake_events;
>>   	unsigned int num_wake_events;
>> +
>> +	struct pmc_clk_init_data *pmc_clks_data;
>> +	unsigned int num_pmc_clks;
>>   };
>>   
>>   static const char * const tegra186_reset_sources[] = {
>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
>>   	return NOTIFY_OK;
>>   }
>>   
>> +static void pmc_clk_fence_udelay(u32 offset)
>> +{
>> +	tegra_pmc_readl(pmc, offset);
>> +	/* pmc clk propagation delay 2 us */
>> +	udelay(2);
>> +}
>> +
>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>> +{
>> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>> +	int num_parents = clk_hw_get_num_parents(hw);
>> +	u32 val;
>> +
>> +	val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>> +	val &= mux->mask;
>> +
>> +	if (val >= num_parents)
>> +		return -EINVAL;
>> +
>> +	return val;
>> +}
>> +
>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>> +{
>> +	struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>> +	u32 val;
>> +
>> +	val = tegra_pmc_readl(pmc, mux->offs);
>> +	val &= ~(mux->mask << mux->shift);
>> +	val |= index << mux->shift;
>> +	tegra_pmc_writel(pmc, val, mux->offs);
>> +	pmc_clk_fence_udelay(mux->offs);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct clk_ops pmc_clk_mux_ops = {
>> +	.get_parent = pmc_clk_mux_get_parent,
>> +	.set_parent = pmc_clk_mux_set_parent,
>> +	.determine_rate = __clk_mux_determine_rate,
>> +};
>> +
>> +static struct clk *
>> +tegra_pmc_clk_mux_register(const char *name, const char * const *parent_names,
>> +			   int num_parents, unsigned long flags,
>> +			   unsigned long offset, u32 shift, u32 mask)
>> +{
>> +	struct clk_init_data init;
>> +	struct pmc_clk_mux *mux;
>> +
>> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>> +	if (!mux)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	init.name = name;
>> +	init.ops = &pmc_clk_mux_ops;
>> +	init.parent_names = parent_names;
>> +	init.num_parents = num_parents;
>> +	init.flags = flags;
>> +
>> +	mux->hw.init = &init;
>> +	mux->offs = offset;
>> +	mux->mask = mask;
>> +	mux->shift = shift;
>> +
>> +	return clk_register(NULL, &mux->hw);
>> +}
>> +
>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>> +{
>> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>> +
>> +	return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
>> +}
>> +
>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>> +{
>> +	struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>> +	u32 val;
>> +
>> +	val = tegra_pmc_readl(pmc, gate->offs);
>> +	val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
>> +	tegra_pmc_writel(pmc, val, gate->offs);
>> +	pmc_clk_fence_udelay(gate->offs);
>> +}
>> +
>> +static int pmc_clk_enable(struct clk_hw *hw)
>> +{
>> +	pmc_clk_set_state(hw, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static void pmc_clk_disable(struct clk_hw *hw)
>> +{
>> +	pmc_clk_set_state(hw, 0);
>> +}
>> +
>> +static const struct clk_ops pmc_clk_gate_ops = {
>> +	.is_enabled = pmc_clk_is_enabled,
>> +	.enable = pmc_clk_enable,
>> +	.disable = pmc_clk_disable,
>> +};
>> +
>> +static struct clk *
>> +tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
>> +			    unsigned long flags, unsigned long offset,
>> +			    u32 shift)
>> +{
>> +	struct clk_init_data init;
>> +	struct pmc_clk_gate *gate;
>> +
>> +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>> +	if (!gate)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	init.name = name;
>> +	init.ops = &pmc_clk_gate_ops;
>> +	init.parent_names = &parent_name;
>> +	init.num_parents = 1;
>> +	init.flags = flags;
>> +
>> +	gate->hw.init = &init;
>> +	gate->offs = offset;
>> +	gate->shift = shift;
>> +
>> +	return clk_register(NULL, &gate->hw);
>> +}
>> +
>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>> +				     struct device_node *np)
>> +{
>> +	struct clk *clkmux, *clk, *parent;
>> +	struct clk_onecell_data *clk_data;
>> +	unsigned int num_clks;
>> +	int i, ret;
>> +
>> +	/* each pmc clock output has a mux and a gate */
>> +	num_clks = pmc->soc->num_pmc_clks * 2;
>> +
>> +	if (!num_clks)
>> +		return;
>> +
>> +	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>> +	if (!clk_data)
>> +		return;
>> +
>> +	clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX, sizeof(*clk_data->clks),
>> +				 GFP_KERNEL);
>> +	if (!clk_data->clks)
>> +		goto free_clkdata;
>> +
>> +	clk_data->clk_num = num_clks;
>> +
>> +	for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>> +		struct pmc_clk_init_data *data;
>> +
>> +		data = pmc->soc->pmc_clks_data + i;
>> +
>> +		clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>> +						    data->parents,
>> +						    data->num_parents,
>> +						    CLK_SET_RATE_NO_REPARENT |
>> +						    CLK_SET_RATE_PARENT,
>> +						    PMC_CLK_OUT_CNTRL,
>> +						    data->mux_shift, 3);
>> +		if (IS_ERR(clkmux))
>> +			goto free_clks;
>> +
>> +		clk_data->clks[data->mux_id] = clkmux;
>> +
>> +		clk = tegra_pmc_clk_gate_register(data->gate_name,
>> +						  data->mux_name,
>> +						  CLK_SET_RATE_PARENT,
>> +						  PMC_CLK_OUT_CNTRL,
>> +						  data->gate_shift);
>> +		if (IS_ERR(clk))
>> +			goto free_clks;
>> +
>> +		clk_data->clks[data->gate_id] = clk;
>> +
>> +		ret = clk_set_parent(clk, clkmux);
>> +		if (ret < 0) {
>> +			pr_err("failed to set parent of %s to %s\n",
>> +			       __func__, __clk_get_name(clk),
>> +			       __clk_get_name(clkmux));
>> +		}
>> +
>> +		clk_register_clkdev(clk, data->dev_name, data->gate_name);
>> +
>> +		/* configure initial clock parent and state */
>> +		parent = clk_get_sys(data->gate_name,
>> +				     data->parents[data->init_parent_index]);
>> +		if (!IS_ERR(parent)) {
>> +			ret = clk_set_parent(clkmux, parent);
>> +			if (ret < 0) {
>> +				pr_err("failed to set parent of %s to %s\n",
>> +				       __func__, __clk_get_name(clkmux),
>> +				       __clk_get_name(parent));
>> +				WARN_ON(1);
>> +			}
>> +		}
>> +
>> +		if (data->init_state) {
>> +			if (clk_prepare_enable(clk)) {
>> +				pr_err("failed to enable %s\n", __func__,
>> +				       __clk_get_name(clk));
>> +				WARN_ON(1);
> Should be a bit better to move the WARN_ON to the end of errors handling
> in order to catch all possible errors:
>
> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
> tegra_pmc *pmc,
>          return;
>
>   free_clks:
> +       WARN_ON(1);
>          kfree(clk_data->clks);
>   free_clkdata:
>          kfree(clk_data);

Reason I had WARN_ON right during clk_set_parent failure is to have the 
loop continue for subsequence pmc clocks registration instead of 
terminating all pmc clocks registration.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  2019-11-27 14:32   ` Dmitry Osipenko
  2019-11-27 17:06     ` Sowjanya Komatineni
@ 2019-11-28 12:18     ` Thierry Reding
  2019-11-28 13:07       ` Dmitry Osipenko
  1 sibling, 1 reply; 44+ messages in thread
From: Thierry Reding @ 2019-11-28 12:18 UTC (permalink / raw)
  To: Dmitry Osipenko, Jon Hunter
  Cc: Sowjanya Komatineni, mperttunen, gregkh, sboyd, tglx, robh+dt,
	mark.rutland, allison, pdeschrijver, pgaikwad, mturquette,
	horms+renesas, Jisheng.Zhang, krzk, arnd, spujar, josephl,
	vidyas, daniel.lezcano, mmaddireddy, markz, devicetree,
	linux-clk, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6846 bytes --]

On Wed, Nov 27, 2019 at 05:32:30PM +0300, Dmitry Osipenko wrote:
> 27.11.2019 07:59, Sowjanya Komatineni пишет:
> > clk_out_1, clk_out_2, clk_out_3, blink are part of Tegra pmc clocks.
> > 
> > This patch removes ids for these clocks from Tegra clock dt-bindings.
> > 
> > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> > ---
> >  include/dt-bindings/clock/tegra114-car.h        | 14 +++++++-------
> >  include/dt-bindings/clock/tegra124-car-common.h | 14 +++++++-------
> >  include/dt-bindings/clock/tegra20-car.h         |  2 +-
> >  include/dt-bindings/clock/tegra210-car.h        | 14 +++++++-------
> >  include/dt-bindings/clock/tegra30-car.h         | 14 +++++++-------
> >  5 files changed, 29 insertions(+), 29 deletions(-)
> > 
> > diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
> > index bb5c2c999c05..9175cd0571b5 100644
> > --- a/include/dt-bindings/clock/tegra114-car.h
> > +++ b/include/dt-bindings/clock/tegra114-car.h
> > @@ -270,10 +270,10 @@
> >  #define TEGRA114_CLK_AUDIO3 242
> >  #define TEGRA114_CLK_AUDIO4 243
> >  #define TEGRA114_CLK_SPDIF 244
> > -#define TEGRA114_CLK_CLK_OUT_1 245
> > -#define TEGRA114_CLK_CLK_OUT_2 246
> > -#define TEGRA114_CLK_CLK_OUT_3 247
> > -#define TEGRA114_CLK_BLINK 248
> > +/* 245 */
> > +/* 246 */
> > +/* 247 */
> > +/* 248 */
> >  /* 249 */
> >  /* 250 */
> >  /* 251 */
> > @@ -333,9 +333,9 @@
> >  #define TEGRA114_CLK_AUDIO3_MUX 303
> >  #define TEGRA114_CLK_AUDIO4_MUX 304
> >  #define TEGRA114_CLK_SPDIF_MUX 305
> > -#define TEGRA114_CLK_CLK_OUT_1_MUX 306
> > -#define TEGRA114_CLK_CLK_OUT_2_MUX 307
> > -#define TEGRA114_CLK_CLK_OUT_3_MUX 308
> > +/* 306 */
> > +/* 307 */
> > +/* 308 */
> >  #define TEGRA114_CLK_DSIA_MUX 309
> >  #define TEGRA114_CLK_DSIB_MUX 310
> >  #define TEGRA114_CLK_XUSB_SS_DIV2 311
> > diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
> > index 0c4f5be0a742..90a0c5e7eb5f 100644
> > --- a/include/dt-bindings/clock/tegra124-car-common.h
> > +++ b/include/dt-bindings/clock/tegra124-car-common.h
> > @@ -269,10 +269,10 @@
> >  #define TEGRA124_CLK_AUDIO3 242
> >  #define TEGRA124_CLK_AUDIO4 243
> >  #define TEGRA124_CLK_SPDIF 244
> > -#define TEGRA124_CLK_CLK_OUT_1 245
> > -#define TEGRA124_CLK_CLK_OUT_2 246
> > -#define TEGRA124_CLK_CLK_OUT_3 247
> > -#define TEGRA124_CLK_BLINK 248
> > +/* 245 */
> > +/* 246 */
> > +/* 247 */
> > +/* 248 */
> >  /* 249 */
> >  /* 250 */
> >  /* 251 */
> > @@ -332,9 +332,9 @@
> >  #define TEGRA124_CLK_AUDIO3_MUX 303
> >  #define TEGRA124_CLK_AUDIO4_MUX 304
> >  #define TEGRA124_CLK_SPDIF_MUX 305
> > -#define TEGRA124_CLK_CLK_OUT_1_MUX 306
> > -#define TEGRA124_CLK_CLK_OUT_2_MUX 307
> > -#define TEGRA124_CLK_CLK_OUT_3_MUX 308
> > +/* 306 */
> > +/* 307 */
> > +/* 308 */
> >  /* 309 */
> >  /* 310 */
> >  #define TEGRA124_CLK_SOR0_LVDS 311 /* deprecated */
> > diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
> > index b21a0eb32921..fe541f627965 100644
> > --- a/include/dt-bindings/clock/tegra20-car.h
> > +++ b/include/dt-bindings/clock/tegra20-car.h
> > @@ -131,7 +131,7 @@
> >  #define TEGRA20_CLK_CCLK 108
> >  #define TEGRA20_CLK_HCLK 109
> >  #define TEGRA20_CLK_PCLK 110
> > -#define TEGRA20_CLK_BLINK 111
> > +/* 111 */
> >  #define TEGRA20_CLK_PLL_A 112
> >  #define TEGRA20_CLK_PLL_A_OUT0 113
> >  #define TEGRA20_CLK_PLL_C 114
> > diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
> > index 44f60623f99b..a3d8d3e75728 100644
> > --- a/include/dt-bindings/clock/tegra210-car.h
> > +++ b/include/dt-bindings/clock/tegra210-car.h
> > @@ -304,10 +304,10 @@
> >  #define TEGRA210_CLK_AUDIO3 274
> >  #define TEGRA210_CLK_AUDIO4 275
> >  #define TEGRA210_CLK_SPDIF 276
> > -#define TEGRA210_CLK_CLK_OUT_1 277
> > -#define TEGRA210_CLK_CLK_OUT_2 278
> > -#define TEGRA210_CLK_CLK_OUT_3 279
> > -#define TEGRA210_CLK_BLINK 280
> > +/* 277 */
> > +/* 278 */
> > +/* 279 */
> > +/* 280 */
> >  #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */
> >  #define TEGRA210_CLK_SOR0_OUT 281
> >  #define TEGRA210_CLK_SOR1_OUT 282
> > @@ -386,9 +386,9 @@
> >  #define TEGRA210_CLK_AUDIO3_MUX 353
> >  #define TEGRA210_CLK_AUDIO4_MUX 354
> >  #define TEGRA210_CLK_SPDIF_MUX 355
> > -#define TEGRA210_CLK_CLK_OUT_1_MUX 356
> > -#define TEGRA210_CLK_CLK_OUT_2_MUX 357
> > -#define TEGRA210_CLK_CLK_OUT_3_MUX 358
> > +/* 356 */
> > +/* 357 */
> > +/* 358 */
> >  #define TEGRA210_CLK_DSIA_MUX 359
> >  #define TEGRA210_CLK_DSIB_MUX 360
> >  /* 361 */
> > diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
> > index 3c90f1535551..20ef2462d9e1 100644
> > --- a/include/dt-bindings/clock/tegra30-car.h
> > +++ b/include/dt-bindings/clock/tegra30-car.h
> > @@ -230,11 +230,11 @@
> >  #define TEGRA30_CLK_AUDIO3 204
> >  #define TEGRA30_CLK_AUDIO4 205
> >  #define TEGRA30_CLK_SPDIF 206
> > -#define TEGRA30_CLK_CLK_OUT_1 207 /* (extern1) */
> > -#define TEGRA30_CLK_CLK_OUT_2 208 /* (extern2) */
> > -#define TEGRA30_CLK_CLK_OUT_3 209 /* (extern3) */
> > +/* 207 */
> > +/* 208 */
> > +/* 209 */
> >  #define TEGRA30_CLK_SCLK 210
> > -#define TEGRA30_CLK_BLINK 211
> > +/* 211 */
> >  #define TEGRA30_CLK_CCLK_G 212
> >  #define TEGRA30_CLK_CCLK_LP 213
> >  #define TEGRA30_CLK_TWD 214
> > @@ -260,9 +260,9 @@
> >  /* 297 */
> >  /* 298 */
> >  /* 299 */
> > -#define TEGRA30_CLK_CLK_OUT_1_MUX 300
> > -#define TEGRA30_CLK_CLK_OUT_2_MUX 301
> > -#define TEGRA30_CLK_CLK_OUT_3_MUX 302
> > +/* 300 */
> > +/* 301 */
> > +/* 302 */
> >  #define TEGRA30_CLK_AUDIO0_MUX 303
> >  #define TEGRA30_CLK_AUDIO1_MUX 304
> >  #define TEGRA30_CLK_AUDIO2_MUX 305
> > 
> 
> This a device-tree ABI breakage and I'm not sure that it's okay to break
> older device-trees (Pixel C Smaug board), maybe some kind of fallback is
> needed.

The Smaug support was never really official. I don't think anybody uses
upstream on it "for real" because there's a very limited set of features
that we do support. My understanding is that there is a community around
Pixel C that runs their own forks with some more features and they have
occasionally upstreamed bits and pieces of that.

So given how far behind we are with Smaug, I don't think breaking ABI
stability is really a problem in this case.

Jon, we used to have a Smaug system in our internal upstream testing,
but that's no longer the case. If we ever were to reinstate that
testing, updating the DTB shouldn't be a problem, right? My recollection
is that updating the DTB was always done hand in hand with the kernel
update.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-27 14:31 ` [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Dmitry Osipenko
  2019-11-27 17:02   ` Sowjanya Komatineni
@ 2019-11-28 12:26   ` Thierry Reding
  2019-11-28 13:10     ` Dmitry Osipenko
  1 sibling, 1 reply; 44+ messages in thread
From: Thierry Reding @ 2019-11-28 12:26 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Sowjanya Komatineni, jonathanh, mperttunen, sboyd, gregkh, tglx,
	robh+dt, mark.rutland, allison, pdeschrijver, pgaikwad,
	mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd, spujar,
	josephl, vidyas, daniel.lezcano, mmaddireddy, markz, devicetree,
	linux-clk, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4608 bytes --]

On Wed, Nov 27, 2019 at 05:31:34PM +0300, Dmitry Osipenko wrote:
> 27.11.2019 07:59, Sowjanya Komatineni пишет:
> > Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
> > are currently registered by Tegra clock driver using clk_regiser_mux and
> > clk_register_gate which performs direct Tegra PMC register access.
> > 
> > When Tegra PMC is in secure mode, any access from non-secure world will
> > not go through.
> > 
> > This patch series adds these Tegra PMC clocks and blink controls to Tegra
> > PMC driver with PMC as clock provider and removed them from Tegra clock
> > driver. This also adds PMC specific clock id's to use in device tree and
> > removed clock ids of PMC clock from Tegra clock driver.
> > 
> > This series also includes patch to update clock provider from tegra_car
> > to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 from PMC.
> > 
> > [v2]:	Changes between v1 and v2 are
> > 	- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
> > 	  blink controls to Tegra PMC driver and removing clk-tegra-pmc.
> > 	- feedback related to pmc clocks in Tegra PMC driver from v1
> > 	- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
> > 	  by the clock driver using helper functions from Tegra PMC.
> > 
> >  	  Note:
> > 	  To use helper functions from PMC driver, PMC early init need to
> > 	  happen prior to using helper functions and these helper functions are
> > 	  for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
> > 	  clock registration which happen in clock_init prior to Tegra PMC
> > 	  probe.
> > 	  Moving PLLM/PLLE clocks registration to happen after Tegra PMC
> > 	  impacts other clocks EMC, MC and corresponding tegra_emc_init and
> > 	  tegra_mc_init.
> > 	  This implementation of configuring PMC registers thru helper
> > 	  functions in clock driver needs proper changes across PMC, Clock,
> > 	  EMC and MC inits to have it work across all Tegra platforms.
> > 
> > 	  Currently PLLM Override is not enabled in the bootloader so proper
> > 	  patches for this fix will be taken care separately.
> 
> Hello Sowjanya,
> 
> Could you please clarify what do you mean by "PLLM Override not enabled
> in bootloader"?
> 
> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
> which has the PLLM Override set by bootloader as well. It's not clear to
> me whether this patch series is supposed to break these devices. If the
> breakage is the case here, then I'm afraid you can't postpone supporting
> the PLLM Override and a full-featured implementation is needed.

For some more background on why we chose to take this shortcut for now:
Sowjanya was looking at the full-featured implementation and that ended
up being a can of worms. The problem is that there are various inter-
dependencies between the PLLM override and the MC/EMC clocks.

Unfortunately we depend a lot on the explicit ordering of driver probe,
especially during early boot, so this started to get very complicated,
very quickly.

The bottom line was basically that we would need to move a whole bunch
of clocks to register at a very late point in time and support deferred
probe throughout in order to make it all work together nicely. Sowjanya
had a crack at that, and while the system ended up booting, there were a
number of errors from the MC and IOMMU drivers.

At the end, we decided to take a look at that separately because, as was
mentioned earlier, the PLLM override is not used on platforms where the
PMC is locked down, so the existing PLLM override code is going to
continue to work fine on the platforms where it's currently used.

Thierry

> I briefly tried to test this series on T30 and this time it doesn't hang
> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
> chip uses the Blink clock source and the clock should be enabled by the
> MMC core because this is how DT part looks like:
> 
> brcm_wifi_pwrseq: wifi-pwrseq {
> 	compatible = "mmc-pwrseq-simple";
> 	clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
> 	clock-names = "ext_clock";
> 	reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
> 	post-power-on-delay-ms = <300>;
> 	power-off-delay-us = <300>;
> };
> 
> BTW, I  tried this series on a T20 device which also uses the Blink
> clock for WiFi card and it works. So looks like this patchset has some
> problem in regards to the T30 PMC clocks implementation.
> 
> [snip]

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-27 21:38     ` Sowjanya Komatineni
@ 2019-11-28 13:06       ` Dmitry Osipenko
  2019-12-02 17:09         ` Dmitry Osipenko
  2019-12-02 18:47         ` Sowjanya Komatineni
  0 siblings, 2 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-28 13:06 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel

28.11.2019 00:38, Sowjanya Komatineni пишет:
> 
> On 11/27/19 9:02 AM, Sowjanya Komatineni wrote:
>>
>> On 11/27/19 6:31 AM, Dmitry Osipenko wrote:
>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>>>> are currently registered by Tegra clock driver using clk_regiser_mux
>>>> and
>>>> clk_register_gate which performs direct Tegra PMC register access.
>>>>
>>>> When Tegra PMC is in secure mode, any access from non-secure world will
>>>> not go through.
>>>>
>>>> This patch series adds these Tegra PMC clocks and blink controls to
>>>> Tegra
>>>> PMC driver with PMC as clock provider and removed them from Tegra clock
>>>> driver. This also adds PMC specific clock id's to use in device tree
>>>> and
>>>> removed clock ids of PMC clock from Tegra clock driver.
>>>>
>>>> This series also includes patch to update clock provider from tegra_car
>>>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2
>>>> from PMC.
>>>>
>>>> [v2]:    Changes between v1 and v2 are
>>>>     - v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>>>>       blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>>>>     - feedback related to pmc clocks in Tegra PMC driver from v1
>>>>     - Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC
>>>> programming
>>>>       by the clock driver using helper functions from Tegra PMC.
>>>>
>>>>         Note:
>>>>       To use helper functions from PMC driver, PMC early init need to
>>>>       happen prior to using helper functions and these helper
>>>> functions are
>>>>       for PLLM Override and PLLE IDDQ programming in PMC during
>>>> PLLM/PLLE
>>>>       clock registration which happen in clock_init prior to Tegra PMC
>>>>       probe.
>>>>       Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>>>>       impacts other clocks EMC, MC and corresponding tegra_emc_init and
>>>>       tegra_mc_init.
>>>>       This implementation of configuring PMC registers thru helper
>>>>       functions in clock driver needs proper changes across PMC, Clock,
>>>>       EMC and MC inits to have it work across all Tegra platforms.
>>>>
>>>>       Currently PLLM Override is not enabled in the bootloader so
>>>> proper
>>>>       patches for this fix will be taken care separately.
>>> Hello Sowjanya,
>>>
>>> Could you please clarify what do you mean by "PLLM Override not enabled
>>> in bootloader"?
>>>
>>> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
>>> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
>>> which has the PLLM Override set by bootloader as well. It's not clear to
>>> me whether this patch series is supposed to break these devices. If the
>>> breakage is the case here, then I'm afraid you can't postpone supporting
>>> the PLLM Override and a full-featured implementation is needed.
>>
>> Hi Dmitry,
>>
>> Secure boot currently is enabled only on Tegra210 and Tegra210
>> bootloader doesn't enable PLLM override.
>>
>> So PLLM override/PLLE IDDQ being in clock driver currently will not
>> break on any of existing Tegra platforms.
>>
>>>
>>> I briefly tried to test this series on T30 and this time it doesn't hang
>>> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
>>> chip uses the Blink clock source and the clock should be enabled by the
>>> MMC core because this is how DT part looks like:
>>>
>>> brcm_wifi_pwrseq: wifi-pwrseq {
>>>     compatible = "mmc-pwrseq-simple";
>>>     clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
>>>     clock-names = "ext_clock";
>>>     reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
>>>     post-power-on-delay-ms = <300>;
>>>     power-off-delay-us = <300>;
>>> };
>>>
>>> BTW, I  tried this series on a T20 device which also uses the Blink
>>> clock for WiFi card and it works. So looks like this patchset has some
>>> problem in regards to the T30 PMC clocks implementation.
>>>
>>> [snip]
>>
>> Blink init state is set to true for both Tegra20 and Tegra30 and all
>> go through the same blink programming sequence.
>>
>> Will try to add more debug messages to dump registers and will test
>> blink through device tree on T30 and will get back...
>>
>>
> define value for BLINK uses BIT macro instead of just position. Will fix
> this in v3.

Thanks, will try v3 once it will be ready.

I took a look through the T20 board's schematics and seems it doesn't
use the Blink clock for the WiFi, instead it uses 32k source directly
from PMU. While T30 board schematics tells that  32k comes out from the
Tegra chip.

BTW, I'm curious what's the reason for having Blink clock always-ON on
T20/30, any insights? Looks like it's just some relic from old clk
driver and it should be safe to drop the always-ON.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC
  2019-11-27  4:59 ` [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC Sowjanya Komatineni
@ 2019-11-28 13:07   ` Dmitry Osipenko
  0 siblings, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-28 13:07 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

27.11.2019 07:59, Sowjanya Komatineni пишет:
> Tegra PMC has blink control to output 32 Khz clock out to Tegra
> blink pin. Blink pad DPD state and enable controls are part of
> Tegra PMC register space.
> 
> Currently Tegra clock driver registers blink control by passing
> PMC address and register offset to clk_register_gate which performs
> direct PMC access during clk_ops and with this when PMC is in secure
> mode, any access from non-secure world does not go through.
> 
> This patch adds blink control registration to the Tegra PMC driver
> using PMC specific clock gate operations that use tegra_pmc_readl
> and tegra_pmc_writel to support both secure mode and non-secure
> mode PMC register access.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/soc/tegra/pmc.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 49 insertions(+)
> 
> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
> index a353f6d0a832..1cfb7797dbd5 100644
> --- a/drivers/soc/tegra/pmc.c
> +++ b/drivers/soc/tegra/pmc.c
> @@ -61,12 +61,15 @@
>  #define  PMC_CNTRL_SYSCLK_OE		BIT(11) /* system clock enable */
>  #define  PMC_CNTRL_SYSCLK_POLARITY	BIT(10) /* sys clk polarity */
>  #define  PMC_CNTRL_PWRREQ_POLARITY	BIT(8)
> +#define  PMC_CNTRL_BLINK_EN		BIT(7)
>  #define  PMC_CNTRL_MAIN_RST		BIT(4)
>  
>  #define PMC_WAKE_MASK			0x0c
>  #define PMC_WAKE_LEVEL			0x10
>  #define PMC_WAKE_STATUS			0x14
>  #define PMC_SW_WAKE_STATUS		0x18
> +#define PMC_DPD_PADS_ORIDE		0x1c
> +#define  PMC_DPD_PADS_ORIDE_BLINK	BIT(20)
>  
>  #define DPD_SAMPLE			0x020
>  #define  DPD_SAMPLE_ENABLE		BIT(0)
> @@ -79,6 +82,7 @@
>  
>  #define PWRGATE_STATUS			0x38
>  
> +#define TEGRA210_PMC_BLINK_TIMER	0x40

This register is common for all Tegra SoCs, therefore TEGRA210_ prefix
isn't needed.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
  2019-11-28 12:18     ` Thierry Reding
@ 2019-11-28 13:07       ` Dmitry Osipenko
  0 siblings, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-28 13:07 UTC (permalink / raw)
  To: Thierry Reding, Jon Hunter
  Cc: Sowjanya Komatineni, mperttunen, gregkh, sboyd, tglx, robh+dt,
	mark.rutland, allison, pdeschrijver, pgaikwad, mturquette,
	horms+renesas, Jisheng.Zhang, krzk, arnd, spujar, josephl,
	vidyas, daniel.lezcano, mmaddireddy, markz, devicetree,
	linux-clk, linux-tegra, linux-kernel

28.11.2019 15:18, Thierry Reding пишет:
> On Wed, Nov 27, 2019 at 05:32:30PM +0300, Dmitry Osipenko wrote:
>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>> clk_out_1, clk_out_2, clk_out_3, blink are part of Tegra pmc clocks.
>>>
>>> This patch removes ids for these clocks from Tegra clock dt-bindings.
>>>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>  include/dt-bindings/clock/tegra114-car.h        | 14 +++++++-------
>>>  include/dt-bindings/clock/tegra124-car-common.h | 14 +++++++-------
>>>  include/dt-bindings/clock/tegra20-car.h         |  2 +-
>>>  include/dt-bindings/clock/tegra210-car.h        | 14 +++++++-------
>>>  include/dt-bindings/clock/tegra30-car.h         | 14 +++++++-------
>>>  5 files changed, 29 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
>>> index bb5c2c999c05..9175cd0571b5 100644
>>> --- a/include/dt-bindings/clock/tegra114-car.h
>>> +++ b/include/dt-bindings/clock/tegra114-car.h
>>> @@ -270,10 +270,10 @@
>>>  #define TEGRA114_CLK_AUDIO3 242
>>>  #define TEGRA114_CLK_AUDIO4 243
>>>  #define TEGRA114_CLK_SPDIF 244
>>> -#define TEGRA114_CLK_CLK_OUT_1 245
>>> -#define TEGRA114_CLK_CLK_OUT_2 246
>>> -#define TEGRA114_CLK_CLK_OUT_3 247
>>> -#define TEGRA114_CLK_BLINK 248
>>> +/* 245 */
>>> +/* 246 */
>>> +/* 247 */
>>> +/* 248 */
>>>  /* 249 */
>>>  /* 250 */
>>>  /* 251 */
>>> @@ -333,9 +333,9 @@
>>>  #define TEGRA114_CLK_AUDIO3_MUX 303
>>>  #define TEGRA114_CLK_AUDIO4_MUX 304
>>>  #define TEGRA114_CLK_SPDIF_MUX 305
>>> -#define TEGRA114_CLK_CLK_OUT_1_MUX 306
>>> -#define TEGRA114_CLK_CLK_OUT_2_MUX 307
>>> -#define TEGRA114_CLK_CLK_OUT_3_MUX 308
>>> +/* 306 */
>>> +/* 307 */
>>> +/* 308 */
>>>  #define TEGRA114_CLK_DSIA_MUX 309
>>>  #define TEGRA114_CLK_DSIB_MUX 310
>>>  #define TEGRA114_CLK_XUSB_SS_DIV2 311
>>> diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h
>>> index 0c4f5be0a742..90a0c5e7eb5f 100644
>>> --- a/include/dt-bindings/clock/tegra124-car-common.h
>>> +++ b/include/dt-bindings/clock/tegra124-car-common.h
>>> @@ -269,10 +269,10 @@
>>>  #define TEGRA124_CLK_AUDIO3 242
>>>  #define TEGRA124_CLK_AUDIO4 243
>>>  #define TEGRA124_CLK_SPDIF 244
>>> -#define TEGRA124_CLK_CLK_OUT_1 245
>>> -#define TEGRA124_CLK_CLK_OUT_2 246
>>> -#define TEGRA124_CLK_CLK_OUT_3 247
>>> -#define TEGRA124_CLK_BLINK 248
>>> +/* 245 */
>>> +/* 246 */
>>> +/* 247 */
>>> +/* 248 */
>>>  /* 249 */
>>>  /* 250 */
>>>  /* 251 */
>>> @@ -332,9 +332,9 @@
>>>  #define TEGRA124_CLK_AUDIO3_MUX 303
>>>  #define TEGRA124_CLK_AUDIO4_MUX 304
>>>  #define TEGRA124_CLK_SPDIF_MUX 305
>>> -#define TEGRA124_CLK_CLK_OUT_1_MUX 306
>>> -#define TEGRA124_CLK_CLK_OUT_2_MUX 307
>>> -#define TEGRA124_CLK_CLK_OUT_3_MUX 308
>>> +/* 306 */
>>> +/* 307 */
>>> +/* 308 */
>>>  /* 309 */
>>>  /* 310 */
>>>  #define TEGRA124_CLK_SOR0_LVDS 311 /* deprecated */
>>> diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
>>> index b21a0eb32921..fe541f627965 100644
>>> --- a/include/dt-bindings/clock/tegra20-car.h
>>> +++ b/include/dt-bindings/clock/tegra20-car.h
>>> @@ -131,7 +131,7 @@
>>>  #define TEGRA20_CLK_CCLK 108
>>>  #define TEGRA20_CLK_HCLK 109
>>>  #define TEGRA20_CLK_PCLK 110
>>> -#define TEGRA20_CLK_BLINK 111
>>> +/* 111 */
>>>  #define TEGRA20_CLK_PLL_A 112
>>>  #define TEGRA20_CLK_PLL_A_OUT0 113
>>>  #define TEGRA20_CLK_PLL_C 114
>>> diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
>>> index 44f60623f99b..a3d8d3e75728 100644
>>> --- a/include/dt-bindings/clock/tegra210-car.h
>>> +++ b/include/dt-bindings/clock/tegra210-car.h
>>> @@ -304,10 +304,10 @@
>>>  #define TEGRA210_CLK_AUDIO3 274
>>>  #define TEGRA210_CLK_AUDIO4 275
>>>  #define TEGRA210_CLK_SPDIF 276
>>> -#define TEGRA210_CLK_CLK_OUT_1 277
>>> -#define TEGRA210_CLK_CLK_OUT_2 278
>>> -#define TEGRA210_CLK_CLK_OUT_3 279
>>> -#define TEGRA210_CLK_BLINK 280
>>> +/* 277 */
>>> +/* 278 */
>>> +/* 279 */
>>> +/* 280 */
>>>  #define TEGRA210_CLK_SOR0_LVDS 281 /* deprecated */
>>>  #define TEGRA210_CLK_SOR0_OUT 281
>>>  #define TEGRA210_CLK_SOR1_OUT 282
>>> @@ -386,9 +386,9 @@
>>>  #define TEGRA210_CLK_AUDIO3_MUX 353
>>>  #define TEGRA210_CLK_AUDIO4_MUX 354
>>>  #define TEGRA210_CLK_SPDIF_MUX 355
>>> -#define TEGRA210_CLK_CLK_OUT_1_MUX 356
>>> -#define TEGRA210_CLK_CLK_OUT_2_MUX 357
>>> -#define TEGRA210_CLK_CLK_OUT_3_MUX 358
>>> +/* 356 */
>>> +/* 357 */
>>> +/* 358 */
>>>  #define TEGRA210_CLK_DSIA_MUX 359
>>>  #define TEGRA210_CLK_DSIB_MUX 360
>>>  /* 361 */
>>> diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
>>> index 3c90f1535551..20ef2462d9e1 100644
>>> --- a/include/dt-bindings/clock/tegra30-car.h
>>> +++ b/include/dt-bindings/clock/tegra30-car.h
>>> @@ -230,11 +230,11 @@
>>>  #define TEGRA30_CLK_AUDIO3 204
>>>  #define TEGRA30_CLK_AUDIO4 205
>>>  #define TEGRA30_CLK_SPDIF 206
>>> -#define TEGRA30_CLK_CLK_OUT_1 207 /* (extern1) */
>>> -#define TEGRA30_CLK_CLK_OUT_2 208 /* (extern2) */
>>> -#define TEGRA30_CLK_CLK_OUT_3 209 /* (extern3) */
>>> +/* 207 */
>>> +/* 208 */
>>> +/* 209 */
>>>  #define TEGRA30_CLK_SCLK 210
>>> -#define TEGRA30_CLK_BLINK 211
>>> +/* 211 */
>>>  #define TEGRA30_CLK_CCLK_G 212
>>>  #define TEGRA30_CLK_CCLK_LP 213
>>>  #define TEGRA30_CLK_TWD 214
>>> @@ -260,9 +260,9 @@
>>>  /* 297 */
>>>  /* 298 */
>>>  /* 299 */
>>> -#define TEGRA30_CLK_CLK_OUT_1_MUX 300
>>> -#define TEGRA30_CLK_CLK_OUT_2_MUX 301
>>> -#define TEGRA30_CLK_CLK_OUT_3_MUX 302
>>> +/* 300 */
>>> +/* 301 */
>>> +/* 302 */
>>>  #define TEGRA30_CLK_AUDIO0_MUX 303
>>>  #define TEGRA30_CLK_AUDIO1_MUX 304
>>>  #define TEGRA30_CLK_AUDIO2_MUX 305
>>>
>>
>> This a device-tree ABI breakage and I'm not sure that it's okay to break
>> older device-trees (Pixel C Smaug board), maybe some kind of fallback is
>> needed.
> 
> The Smaug support was never really official. I don't think anybody uses
> upstream on it "for real" because there's a very limited set of features
> that we do support. My understanding is that there is a community around
> Pixel C that runs their own forks with some more features and they have
> occasionally upstreamed bits and pieces of that.
> 
> So given how far behind we are with Smaug, I don't think breaking ABI
> stability is really a problem in this case.
> 
> Jon, we used to have a Smaug system in our internal upstream testing,
> but that's no longer the case. If we ever were to reinstate that
> testing, updating the DTB shouldn't be a problem, right? My recollection
> is that updating the DTB was always done hand in hand with the kernel
> update.

IIRC, T210 doesn't have support for SoC audio driver yet in upstream
kernel and thus Smaug only defined the audio codec in the device-tree,
which never got utilized.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-28 12:26   ` Thierry Reding
@ 2019-11-28 13:10     ` Dmitry Osipenko
  0 siblings, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-28 13:10 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Sowjanya Komatineni, jonathanh, mperttunen, sboyd, gregkh, tglx,
	robh+dt, mark.rutland, allison, pdeschrijver, pgaikwad,
	mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd, spujar,
	josephl, vidyas, daniel.lezcano, mmaddireddy, markz, devicetree,
	linux-clk, linux-tegra, linux-kernel

28.11.2019 15:26, Thierry Reding пишет:
> On Wed, Nov 27, 2019 at 05:31:34PM +0300, Dmitry Osipenko wrote:
>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>>> are currently registered by Tegra clock driver using clk_regiser_mux and
>>> clk_register_gate which performs direct Tegra PMC register access.
>>>
>>> When Tegra PMC is in secure mode, any access from non-secure world will
>>> not go through.
>>>
>>> This patch series adds these Tegra PMC clocks and blink controls to Tegra
>>> PMC driver with PMC as clock provider and removed them from Tegra clock
>>> driver. This also adds PMC specific clock id's to use in device tree and
>>> removed clock ids of PMC clock from Tegra clock driver.
>>>
>>> This series also includes patch to update clock provider from tegra_car
>>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2 from PMC.
>>>
>>> [v2]:	Changes between v1 and v2 are
>>> 	- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>>> 	  blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>>> 	- feedback related to pmc clocks in Tegra PMC driver from v1
>>> 	- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
>>> 	  by the clock driver using helper functions from Tegra PMC.
>>>
>>>  	  Note:
>>> 	  To use helper functions from PMC driver, PMC early init need to
>>> 	  happen prior to using helper functions and these helper functions are
>>> 	  for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
>>> 	  clock registration which happen in clock_init prior to Tegra PMC
>>> 	  probe.
>>> 	  Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>>> 	  impacts other clocks EMC, MC and corresponding tegra_emc_init and
>>> 	  tegra_mc_init.
>>> 	  This implementation of configuring PMC registers thru helper
>>> 	  functions in clock driver needs proper changes across PMC, Clock,
>>> 	  EMC and MC inits to have it work across all Tegra platforms.
>>>
>>> 	  Currently PLLM Override is not enabled in the bootloader so proper
>>> 	  patches for this fix will be taken care separately.
>>
>> Hello Sowjanya,
>>
>> Could you please clarify what do you mean by "PLLM Override not enabled
>> in bootloader"?
>>
>> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
>> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
>> which has the PLLM Override set by bootloader as well. It's not clear to
>> me whether this patch series is supposed to break these devices. If the
>> breakage is the case here, then I'm afraid you can't postpone supporting
>> the PLLM Override and a full-featured implementation is needed.
> 
> For some more background on why we chose to take this shortcut for now:
> Sowjanya was looking at the full-featured implementation and that ended
> up being a can of worms. The problem is that there are various inter-
> dependencies between the PLLM override and the MC/EMC clocks.
> 
> Unfortunately we depend a lot on the explicit ordering of driver probe,
> especially during early boot, so this started to get very complicated,
> very quickly.
> 
> The bottom line was basically that we would need to move a whole bunch
> of clocks to register at a very late point in time and support deferred
> probe throughout in order to make it all work together nicely. Sowjanya
> had a crack at that, and while the system ended up booting, there were a
> number of errors from the MC and IOMMU drivers.
> 
> At the end, we decided to take a look at that separately because, as was
> mentioned earlier, the PLLM override is not used on platforms where the
> PMC is locked down, so the existing PLLM override code is going to
> continue to work fine on the platforms where it's currently used.
> 
> Thierry

Thank you and Sowjanya for the clarification.

[snip]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-27 22:57     ` Sowjanya Komatineni
@ 2019-11-28 13:25       ` Dmitry Osipenko
  2019-12-02 20:09         ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-11-28 13:25 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

28.11.2019 01:57, Sowjanya Komatineni пишет:
> 
> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
>>> mux and gate for each of these clocks.
>>>
>>> Currently these PMC clocks are registered by Tegra clock driver using
>>> clk_register_mux and clk_register_gate by passing PMC base address
>>> and register offsets and PMC programming for these clocks happens
>>> through direct PMC access by the clock driver.
>>>
>>> With this, when PMC is in secure mode any direct PMC access from the
>>> non-secure world does not go through and these clocks will not be
>>> functional.
>>>
>>> This patch adds these clocks registration with PMC as a clock provider
>>> for these clocks. clk_ops callback implementations for these clocks
>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
>>> in secure mode and non-secure mode.
>>>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/soc/tegra/pmc.c | 330
>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 330 insertions(+)
>>>
>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>> index ea0e11a09c12..a353f6d0a832 100644
>>> --- a/drivers/soc/tegra/pmc.c
>>> +++ b/drivers/soc/tegra/pmc.c
>>> @@ -13,6 +13,9 @@
>>>     #include <linux/arm-smccc.h>
>>>   #include <linux/clk.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/clkdev.h>
>>> +#include <linux/clk/clk-conf.h>
>>>   #include <linux/clk/tegra.h>
>>>   #include <linux/debugfs.h>
>>>   #include <linux/delay.h>
>>> @@ -48,6 +51,7 @@
>>>   #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>   #include <dt-bindings/gpio/tegra186-gpio.h>
>>>   #include <dt-bindings/gpio/tegra194-gpio.h>
>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>     #define PMC_CNTRL            0x0
>>>   #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>> polarity */
>>> @@ -100,6 +104,7 @@
>>>   #define PMC_WAKE2_STATUS        0x168
>>>   #define PMC_SW_WAKE2_STATUS        0x16c
>>>   +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>   #define PMC_SENSOR_CTRL            0x1b0
>>>   #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>   #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>> @@ -155,6 +160,91 @@
>>>   #define  TEGRA_SMC_PMC_READ    0xaa
>>>   #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>   +struct pmc_clk_mux {
>>> +    struct clk_hw    hw;
>>> +    unsigned long    offs;
>>> +    u32        mask;
>>> +    u32        shift;
>>> +};
>>> +
>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
>>> +
>>> +struct pmc_clk_gate {
>>> +    struct clk_hw    hw;
>>> +    unsigned long    offs;
>>> +    u32        shift;
>>> +};
>>> +
>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
>>> +
>>> +struct pmc_clk_init_data {
>>> +    char *mux_name;
>>> +    char *gate_name;
>>> +    const char **parents;
>>> +    int num_parents;
>>> +    int mux_id;
>>> +    int gate_id;
>>> +    char *dev_name;
>>> +    u8 mux_shift;
>>> +    u8 gate_shift;
>>> +    u8 init_parent_index;
>>> +    int init_state;
>>> +};
>>> +
>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>> +    "clk_m_div4", "extern1",
>>> +};
>>> +
>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>> +    "clk_m_div4", "extern2",
>>> +};
>>> +
>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>> +    "clk_m_div4", "extern3",
>>> +};
>>> +
>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>> +    {
>>> +        .mux_name = "clk_out_1_mux",
>>> +        .gate_name = "clk_out_1",
>>> +        .parents = clk_out1_parents,
>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>> +        .dev_name = "extern1",
>>> +        .mux_shift = 6,
>>> +        .gate_shift = 2,
>>> +        .init_parent_index = 3,
>>> +        .init_state = 1,
>>> +    },
>>> +    {
>>> +        .mux_name = "clk_out_2_mux",
>>> +        .gate_name = "clk_out_2",
>>> +        .parents = clk_out2_parents,
>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>> +        .dev_name = "extern2",
>>> +        .mux_shift = 14,
>>> +        .gate_shift = 10,
>>> +        .init_parent_index = 0,
>>> +        .init_state = 0,
>>> +    },
>>> +    {
>>> +        .mux_name = "clk_out_3_mux",
>>> +        .gate_name = "clk_out_3",
>>> +        .parents = clk_out3_parents,
>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>> +        .dev_name = "extern3",
>>> +        .mux_shift = 22,
>>> +        .gate_shift = 18,
>>> +        .init_parent_index = 0,
>>> +        .init_state = 0,
>>> +    },
>>> +};
>>> +
>>>   struct tegra_powergate {
>>>       struct generic_pm_domain genpd;
>>>       struct tegra_pmc *pmc;
>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>        */
>>>       const struct tegra_wake_event *wake_events;
>>>       unsigned int num_wake_events;
>>> +
>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>> +    unsigned int num_pmc_clks;
>>>   };
>>>     static const char * const tegra186_reset_sources[] = {
>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>> notifier_block *nb,
>>>       return NOTIFY_OK;
>>>   }
>>>   +static void pmc_clk_fence_udelay(u32 offset)
>>> +{
>>> +    tegra_pmc_readl(pmc, offset);
>>> +    /* pmc clk propagation delay 2 us */
>>> +    udelay(2);
>>> +}
>>> +
>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>> +{
>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>> +    u32 val;
>>> +
>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>> +    val &= mux->mask;
>>> +
>>> +    if (val >= num_parents)
>>> +        return -EINVAL;
>>> +
>>> +    return val;
>>> +}
>>> +
>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>> +{
>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>> +    u32 val;
>>> +
>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>> +    val &= ~(mux->mask << mux->shift);
>>> +    val |= index << mux->shift;
>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>> +    pmc_clk_fence_udelay(mux->offs);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>> +    .get_parent = pmc_clk_mux_get_parent,
>>> +    .set_parent = pmc_clk_mux_set_parent,
>>> +    .determine_rate = __clk_mux_determine_rate,
>>> +};
>>> +
>>> +static struct clk *
>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>> *parent_names,
>>> +               int num_parents, unsigned long flags,
>>> +               unsigned long offset, u32 shift, u32 mask)
>>> +{
>>> +    struct clk_init_data init;
>>> +    struct pmc_clk_mux *mux;
>>> +
>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>> +    if (!mux)
>>> +        return ERR_PTR(-ENOMEM);
>>> +
>>> +    init.name = name;
>>> +    init.ops = &pmc_clk_mux_ops;
>>> +    init.parent_names = parent_names;
>>> +    init.num_parents = num_parents;
>>> +    init.flags = flags;
>>> +
>>> +    mux->hw.init = &init;
>>> +    mux->offs = offset;
>>> +    mux->mask = mask;
>>> +    mux->shift = shift;
>>> +
>>> +    return clk_register(NULL, &mux->hw);
>>> +}
>>> +
>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>> +{
>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>> +
>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
>>> +}
>>> +
>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>> +{
>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>> +    u32 val;
>>> +
>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>> +    val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>> +    pmc_clk_fence_udelay(gate->offs);
>>> +}
>>> +
>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>> +{
>>> +    pmc_clk_set_state(hw, 1);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>> +{
>>> +    pmc_clk_set_state(hw, 0);
>>> +}
>>> +
>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>> +    .is_enabled = pmc_clk_is_enabled,
>>> +    .enable = pmc_clk_enable,
>>> +    .disable = pmc_clk_disable,
>>> +};
>>> +
>>> +static struct clk *
>>> +tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
>>> +                unsigned long flags, unsigned long offset,
>>> +                u32 shift)
>>> +{
>>> +    struct clk_init_data init;
>>> +    struct pmc_clk_gate *gate;
>>> +
>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>> +    if (!gate)
>>> +        return ERR_PTR(-ENOMEM);
>>> +
>>> +    init.name = name;
>>> +    init.ops = &pmc_clk_gate_ops;
>>> +    init.parent_names = &parent_name;
>>> +    init.num_parents = 1;
>>> +    init.flags = flags;
>>> +
>>> +    gate->hw.init = &init;
>>> +    gate->offs = offset;
>>> +    gate->shift = shift;
>>> +
>>> +    return clk_register(NULL, &gate->hw);
>>> +}
>>> +
>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>> +                     struct device_node *np)
>>> +{
>>> +    struct clk *clkmux, *clk, *parent;
>>> +    struct clk_onecell_data *clk_data;
>>> +    unsigned int num_clks;
>>> +    int i, ret;
>>> +
>>> +    /* each pmc clock output has a mux and a gate */
>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>> +
>>> +    if (!num_clks)
>>> +        return;
>>> +
>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>> +    if (!clk_data)
>>> +        return;
>>> +
>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>> sizeof(*clk_data->clks),
>>> +                 GFP_KERNEL);
>>> +    if (!clk_data->clks)
>>> +        goto free_clkdata;
>>> +
>>> +    clk_data->clk_num = num_clks;
>>> +
>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>> +        struct pmc_clk_init_data *data;
>>> +
>>> +        data = pmc->soc->pmc_clks_data + i;
>>> +
>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>> +                            data->parents,
>>> +                            data->num_parents,
>>> +                            CLK_SET_RATE_NO_REPARENT |
>>> +                            CLK_SET_RATE_PARENT,
>>> +                            PMC_CLK_OUT_CNTRL,
>>> +                            data->mux_shift, 3);
>>> +        if (IS_ERR(clkmux))
>>> +            goto free_clks;
>>> +
>>> +        clk_data->clks[data->mux_id] = clkmux;
>>> +
>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>> +                          data->mux_name,
>>> +                          CLK_SET_RATE_PARENT,
>>> +                          PMC_CLK_OUT_CNTRL,
>>> +                          data->gate_shift);
>>> +        if (IS_ERR(clk))
>>> +            goto free_clks;
>>> +
>>> +        clk_data->clks[data->gate_id] = clk;
>>> +
>>> +        ret = clk_set_parent(clk, clkmux);
>>> +        if (ret < 0) {
>>> +            pr_err("failed to set parent of %s to %s\n",
>>> +                   __func__, __clk_get_name(clk),
>>> +                   __clk_get_name(clkmux));
>>> +        }
>>> +
>>> +        clk_register_clkdev(clk, data->dev_name, data->gate_name);
>>> +
>>> +        /* configure initial clock parent and state */
>>> +        parent = clk_get_sys(data->gate_name,
>>> +                     data->parents[data->init_parent_index]);
>>> +        if (!IS_ERR(parent)) {
>>> +            ret = clk_set_parent(clkmux, parent);
>>> +            if (ret < 0) {
>>> +                pr_err("failed to set parent of %s to %s\n",
>>> +                       __func__, __clk_get_name(clkmux),
>>> +                       __clk_get_name(parent));
>>> +                WARN_ON(1);
>>> +            }
>>> +        }
>>> +
>>> +        if (data->init_state) {
>>> +            if (clk_prepare_enable(clk)) {
>>> +                pr_err("failed to enable %s\n", __func__,
>>> +                       __clk_get_name(clk));
>>> +                WARN_ON(1);

Alternatively you could write it like this:

	err = clk_prepare_enable(clk);

	WARN_ON(err, "failed to enable %s: %d\n",
		__clk_get_name(clk), err);

>> Should be a bit better to move the WARN_ON to the end of errors handling
>> in order to catch all possible errors:
>>
>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>> tegra_pmc *pmc,
>>          return;
>>
>>   free_clks:
>> +       WARN_ON(1);
>>          kfree(clk_data->clks);
>>   free_clkdata:
>>          kfree(clk_data);
> 
> Reason I had WARN_ON right during clk_set_parent failure is to have the
> loop continue for subsequence pmc clocks registration instead of
> terminating all pmc clocks registration.

Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least (IMO).

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-28 13:06       ` Dmitry Osipenko
@ 2019-12-02 17:09         ` Dmitry Osipenko
  2019-12-02 18:47         ` Sowjanya Komatineni
  1 sibling, 0 replies; 44+ messages in thread
From: Dmitry Osipenko @ 2019-12-02 17:09 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel

28.11.2019 16:06, Dmitry Osipenko пишет:
> 28.11.2019 00:38, Sowjanya Komatineni пишет:
>>
>> On 11/27/19 9:02 AM, Sowjanya Komatineni wrote:
>>>
>>> On 11/27/19 6:31 AM, Dmitry Osipenko wrote:
>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>>>>> are currently registered by Tegra clock driver using clk_regiser_mux
>>>>> and
>>>>> clk_register_gate which performs direct Tegra PMC register access.
>>>>>
>>>>> When Tegra PMC is in secure mode, any access from non-secure world will
>>>>> not go through.
>>>>>
>>>>> This patch series adds these Tegra PMC clocks and blink controls to
>>>>> Tegra
>>>>> PMC driver with PMC as clock provider and removed them from Tegra clock
>>>>> driver. This also adds PMC specific clock id's to use in device tree
>>>>> and
>>>>> removed clock ids of PMC clock from Tegra clock driver.
>>>>>
>>>>> This series also includes patch to update clock provider from tegra_car
>>>>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2
>>>>> from PMC.
>>>>>
>>>>> [v2]:    Changes between v1 and v2 are
>>>>>     - v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>>>>>       blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>>>>>     - feedback related to pmc clocks in Tegra PMC driver from v1
>>>>>     - Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC
>>>>> programming
>>>>>       by the clock driver using helper functions from Tegra PMC.
>>>>>
>>>>>         Note:
>>>>>       To use helper functions from PMC driver, PMC early init need to
>>>>>       happen prior to using helper functions and these helper
>>>>> functions are
>>>>>       for PLLM Override and PLLE IDDQ programming in PMC during
>>>>> PLLM/PLLE
>>>>>       clock registration which happen in clock_init prior to Tegra PMC
>>>>>       probe.
>>>>>       Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>>>>>       impacts other clocks EMC, MC and corresponding tegra_emc_init and
>>>>>       tegra_mc_init.
>>>>>       This implementation of configuring PMC registers thru helper
>>>>>       functions in clock driver needs proper changes across PMC, Clock,
>>>>>       EMC and MC inits to have it work across all Tegra platforms.
>>>>>
>>>>>       Currently PLLM Override is not enabled in the bootloader so
>>>>> proper
>>>>>       patches for this fix will be taken care separately.
>>>> Hello Sowjanya,
>>>>
>>>> Could you please clarify what do you mean by "PLLM Override not enabled
>>>> in bootloader"?
>>>>
>>>> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
>>>> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
>>>> which has the PLLM Override set by bootloader as well. It's not clear to
>>>> me whether this patch series is supposed to break these devices. If the
>>>> breakage is the case here, then I'm afraid you can't postpone supporting
>>>> the PLLM Override and a full-featured implementation is needed.
>>>
>>> Hi Dmitry,
>>>
>>> Secure boot currently is enabled only on Tegra210 and Tegra210
>>> bootloader doesn't enable PLLM override.
>>>
>>> So PLLM override/PLLE IDDQ being in clock driver currently will not
>>> break on any of existing Tegra platforms.
>>>
>>>>
>>>> I briefly tried to test this series on T30 and this time it doesn't hang
>>>> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
>>>> chip uses the Blink clock source and the clock should be enabled by the
>>>> MMC core because this is how DT part looks like:
>>>>
>>>> brcm_wifi_pwrseq: wifi-pwrseq {
>>>>     compatible = "mmc-pwrseq-simple";
>>>>     clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
>>>>     clock-names = "ext_clock";
>>>>     reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
>>>>     post-power-on-delay-ms = <300>;
>>>>     power-off-delay-us = <300>;
>>>> };
>>>>
>>>> BTW, I  tried this series on a T20 device which also uses the Blink
>>>> clock for WiFi card and it works. So looks like this patchset has some
>>>> problem in regards to the T30 PMC clocks implementation.
>>>>
>>>> [snip]
>>>
>>> Blink init state is set to true for both Tegra20 and Tegra30 and all
>>> go through the same blink programming sequence.
>>>
>>> Will try to add more debug messages to dump registers and will test
>>> blink through device tree on T30 and will get back...
>>>
>>>
>> define value for BLINK uses BIT macro instead of just position. Will fix
>> this in v3.
> 
> Thanks, will try v3 once it will be ready.
> 
> I took a look through the T20 board's schematics and seems it doesn't
> use the Blink clock for the WiFi, instead it uses 32k source directly
> from PMU. While T30 board schematics tells that  32k comes out from the
> Tegra chip.

That was wrong, both T20 and T30 are identical in regards to the clk32k
wiring. I'm not sure what's difference between T20 and T30 that made
WiFi card not to work without the blink clock on T30, maybe it's a WiFi
chip difference.

> BTW, I'm curious what's the reason for having Blink clock always-ON on
> T20/30, any insights? Looks like it's just some relic from old clk
> driver and it should be safe to drop the always-ON.
> 


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver
  2019-11-28 13:06       ` Dmitry Osipenko
  2019-12-02 17:09         ` Dmitry Osipenko
@ 2019-12-02 18:47         ` Sowjanya Komatineni
  1 sibling, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-02 18:47 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, sboyd
  Cc: gregkh, tglx, robh+dt, mark.rutland, allison, pdeschrijver,
	pgaikwad, mturquette, horms+renesas, Jisheng.Zhang, krzk, arnd,
	spujar, josephl, vidyas, daniel.lezcano, mmaddireddy, markz,
	devicetree, linux-clk, linux-tegra, linux-kernel


On 11/28/19 5:06 AM, Dmitry Osipenko wrote:
> 28.11.2019 00:38, Sowjanya Komatineni пишет:
>> On 11/27/19 9:02 AM, Sowjanya Komatineni wrote:
>>> On 11/27/19 6:31 AM, Dmitry Osipenko wrote:
>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>> Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
>>>>> are currently registered by Tegra clock driver using clk_regiser_mux
>>>>> and
>>>>> clk_register_gate which performs direct Tegra PMC register access.
>>>>>
>>>>> When Tegra PMC is in secure mode, any access from non-secure world will
>>>>> not go through.
>>>>>
>>>>> This patch series adds these Tegra PMC clocks and blink controls to
>>>>> Tegra
>>>>> PMC driver with PMC as clock provider and removed them from Tegra clock
>>>>> driver. This also adds PMC specific clock id's to use in device tree
>>>>> and
>>>>> removed clock ids of PMC clock from Tegra clock driver.
>>>>>
>>>>> This series also includes patch to update clock provider from tegra_car
>>>>> to pmc in the device tree tegra210-smaug.dts that uses clk_out_2
>>>>> from PMC.
>>>>>
>>>>> [v2]:    Changes between v1 and v2 are
>>>>>      - v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
>>>>>        blink controls to Tegra PMC driver and removing clk-tegra-pmc.
>>>>>      - feedback related to pmc clocks in Tegra PMC driver from v1
>>>>>      - Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC
>>>>> programming
>>>>>        by the clock driver using helper functions from Tegra PMC.
>>>>>
>>>>>          Note:
>>>>>        To use helper functions from PMC driver, PMC early init need to
>>>>>        happen prior to using helper functions and these helper
>>>>> functions are
>>>>>        for PLLM Override and PLLE IDDQ programming in PMC during
>>>>> PLLM/PLLE
>>>>>        clock registration which happen in clock_init prior to Tegra PMC
>>>>>        probe.
>>>>>        Moving PLLM/PLLE clocks registration to happen after Tegra PMC
>>>>>        impacts other clocks EMC, MC and corresponding tegra_emc_init and
>>>>>        tegra_mc_init.
>>>>>        This implementation of configuring PMC registers thru helper
>>>>>        functions in clock driver needs proper changes across PMC, Clock,
>>>>>        EMC and MC inits to have it work across all Tegra platforms.
>>>>>
>>>>>        Currently PLLM Override is not enabled in the bootloader so
>>>>> proper
>>>>>        patches for this fix will be taken care separately.
>>>> Hello Sowjanya,
>>>>
>>>> Could you please clarify what do you mean by "PLLM Override not enabled
>>>> in bootloader"?
>>>>
>>>> There is T124 Nyan Big Chromebook which is supported in upstream kernel,
>>>> it has PLLM Override set by bootloader. I also have T30 Nexus 7 tablet
>>>> which has the PLLM Override set by bootloader as well. It's not clear to
>>>> me whether this patch series is supposed to break these devices. If the
>>>> breakage is the case here, then I'm afraid you can't postpone supporting
>>>> the PLLM Override and a full-featured implementation is needed.
>>> Hi Dmitry,
>>>
>>> Secure boot currently is enabled only on Tegra210 and Tegra210
>>> bootloader doesn't enable PLLM override.
>>>
>>> So PLLM override/PLLE IDDQ being in clock driver currently will not
>>> break on any of existing Tegra platforms.
>>>
>>>> I briefly tried to test this series on T30 and this time it doesn't hang
>>>> on boot, but somehow WiFi MMC card detection is broken. AFAIK, the WiFi
>>>> chip uses the Blink clock source and the clock should be enabled by the
>>>> MMC core because this is how DT part looks like:
>>>>
>>>> brcm_wifi_pwrseq: wifi-pwrseq {
>>>>      compatible = "mmc-pwrseq-simple";
>>>>      clocks = <&pmc TEGRA_PMC_CLK_BLINK>;
>>>>      clock-names = "ext_clock";
>>>>      reset-gpios =  <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
>>>>      post-power-on-delay-ms = <300>;
>>>>      power-off-delay-us = <300>;
>>>> };
>>>>
>>>> BTW, I  tried this series on a T20 device which also uses the Blink
>>>> clock for WiFi card and it works. So looks like this patchset has some
>>>> problem in regards to the T30 PMC clocks implementation.
>>>>
>>>> [snip]
>>> Blink init state is set to true for both Tegra20 and Tegra30 and all
>>> go through the same blink programming sequence.
>>>
>>> Will try to add more debug messages to dump registers and will test
>>> blink through device tree on T30 and will get back...
>>>
>>>
>> define value for BLINK uses BIT macro instead of just position. Will fix
>> this in v3.
> Thanks, will try v3 once it will be ready.
>
> I took a look through the T20 board's schematics and seems it doesn't
> use the Blink clock for the WiFi, instead it uses 32k source directly
> from PMU. While T30 board schematics tells that  32k comes out from the
> Tegra chip.
>
> BTW, I'm curious what's the reason for having Blink clock always-ON on
> T20/30, any insights? Looks like it's just some relic from old clk
> driver and it should be safe to drop the always-ON.

T30 cardhu uses 32K from Tegra to WIFI but its only needed to be on 
during WIFI power up sequence and not required to be on during boot.

I had it enabled as existing clock driver enables it default and dont 
want to break things if it was left ON intentionally.

Peter/Thierry, Any reason 32K from Blink is enabled to be ON during 
clock init for T20/T30 in clock-tegra-pmc driver?

Based on the design T30 uses this for WIFI and WIFI driver should be 
handling this clock enable/disable during power up/down sequence,

so we don't have to enable it default during boot right?


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-11-28 13:25       ` Dmitry Osipenko
@ 2019-12-02 20:09         ` Sowjanya Komatineni
  2019-12-02 21:50           ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-02 20:09 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
>>>> mux and gate for each of these clocks.
>>>>
>>>> Currently these PMC clocks are registered by Tegra clock driver using
>>>> clk_register_mux and clk_register_gate by passing PMC base address
>>>> and register offsets and PMC programming for these clocks happens
>>>> through direct PMC access by the clock driver.
>>>>
>>>> With this, when PMC is in secure mode any direct PMC access from the
>>>> non-secure world does not go through and these clocks will not be
>>>> functional.
>>>>
>>>> This patch adds these clocks registration with PMC as a clock provider
>>>> for these clocks. clk_ops callback implementations for these clocks
>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC programming
>>>> in secure mode and non-secure mode.
>>>>
>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>> ---
>>>>    drivers/soc/tegra/pmc.c | 330
>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    1 file changed, 330 insertions(+)
>>>>
>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>> --- a/drivers/soc/tegra/pmc.c
>>>> +++ b/drivers/soc/tegra/pmc.c
>>>> @@ -13,6 +13,9 @@
>>>>      #include <linux/arm-smccc.h>
>>>>    #include <linux/clk.h>
>>>> +#include <linux/clk-provider.h>
>>>> +#include <linux/clkdev.h>
>>>> +#include <linux/clk/clk-conf.h>
>>>>    #include <linux/clk/tegra.h>
>>>>    #include <linux/debugfs.h>
>>>>    #include <linux/delay.h>
>>>> @@ -48,6 +51,7 @@
>>>>    #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>    #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>    #include <dt-bindings/gpio/tegra194-gpio.h>
>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>      #define PMC_CNTRL            0x0
>>>>    #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>> polarity */
>>>> @@ -100,6 +104,7 @@
>>>>    #define PMC_WAKE2_STATUS        0x168
>>>>    #define PMC_SW_WAKE2_STATUS        0x16c
>>>>    +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>    #define PMC_SENSOR_CTRL            0x1b0
>>>>    #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>>    #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>> @@ -155,6 +160,91 @@
>>>>    #define  TEGRA_SMC_PMC_READ    0xaa
>>>>    #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>    +struct pmc_clk_mux {
>>>> +    struct clk_hw    hw;
>>>> +    unsigned long    offs;
>>>> +    u32        mask;
>>>> +    u32        shift;
>>>> +};
>>>> +
>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
>>>> +
>>>> +struct pmc_clk_gate {
>>>> +    struct clk_hw    hw;
>>>> +    unsigned long    offs;
>>>> +    u32        shift;
>>>> +};
>>>> +
>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw)
>>>> +
>>>> +struct pmc_clk_init_data {
>>>> +    char *mux_name;
>>>> +    char *gate_name;
>>>> +    const char **parents;
>>>> +    int num_parents;
>>>> +    int mux_id;
>>>> +    int gate_id;
>>>> +    char *dev_name;
>>>> +    u8 mux_shift;
>>>> +    u8 gate_shift;
>>>> +    u8 init_parent_index;
>>>> +    int init_state;
>>>> +};
>>>> +
>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>> +    "clk_m_div4", "extern1",
>>>> +};
>>>> +
>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>> +    "clk_m_div4", "extern2",
>>>> +};
>>>> +
>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>> +    "clk_m_div4", "extern3",
>>>> +};
>>>> +
>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>> +    {
>>>> +        .mux_name = "clk_out_1_mux",
>>>> +        .gate_name = "clk_out_1",
>>>> +        .parents = clk_out1_parents,
>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>> +        .dev_name = "extern1",
>>>> +        .mux_shift = 6,
>>>> +        .gate_shift = 2,
>>>> +        .init_parent_index = 3,
>>>> +        .init_state = 1,
>>>> +    },
>>>> +    {
>>>> +        .mux_name = "clk_out_2_mux",
>>>> +        .gate_name = "clk_out_2",
>>>> +        .parents = clk_out2_parents,
>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>> +        .dev_name = "extern2",
>>>> +        .mux_shift = 14,
>>>> +        .gate_shift = 10,
>>>> +        .init_parent_index = 0,
>>>> +        .init_state = 0,
>>>> +    },
>>>> +    {
>>>> +        .mux_name = "clk_out_3_mux",
>>>> +        .gate_name = "clk_out_3",
>>>> +        .parents = clk_out3_parents,
>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>> +        .dev_name = "extern3",
>>>> +        .mux_shift = 22,
>>>> +        .gate_shift = 18,
>>>> +        .init_parent_index = 0,
>>>> +        .init_state = 0,
>>>> +    },
>>>> +};
>>>> +
>>>>    struct tegra_powergate {
>>>>        struct generic_pm_domain genpd;
>>>>        struct tegra_pmc *pmc;
>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>         */
>>>>        const struct tegra_wake_event *wake_events;
>>>>        unsigned int num_wake_events;
>>>> +
>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>> +    unsigned int num_pmc_clks;
>>>>    };
>>>>      static const char * const tegra186_reset_sources[] = {
>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>> notifier_block *nb,
>>>>        return NOTIFY_OK;
>>>>    }
>>>>    +static void pmc_clk_fence_udelay(u32 offset)
>>>> +{
>>>> +    tegra_pmc_readl(pmc, offset);
>>>> +    /* pmc clk propagation delay 2 us */
>>>> +    udelay(2);
>>>> +}
>>>> +
>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>> +{
>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>> +    u32 val;
>>>> +
>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>> +    val &= mux->mask;
>>>> +
>>>> +    if (val >= num_parents)
>>>> +        return -EINVAL;
>>>> +
>>>> +    return val;
>>>> +}
>>>> +
>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>> +{
>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>> +    u32 val;
>>>> +
>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>> +    val &= ~(mux->mask << mux->shift);
>>>> +    val |= index << mux->shift;
>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>> +};
>>>> +
>>>> +static struct clk *
>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>> *parent_names,
>>>> +               int num_parents, unsigned long flags,
>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>> +{
>>>> +    struct clk_init_data init;
>>>> +    struct pmc_clk_mux *mux;
>>>> +
>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>> +    if (!mux)
>>>> +        return ERR_PTR(-ENOMEM);
>>>> +
>>>> +    init.name = name;
>>>> +    init.ops = &pmc_clk_mux_ops;
>>>> +    init.parent_names = parent_names;
>>>> +    init.num_parents = num_parents;
>>>> +    init.flags = flags;
>>>> +
>>>> +    mux->hw.init = &init;
>>>> +    mux->offs = offset;
>>>> +    mux->mask = mask;
>>>> +    mux->shift = shift;
>>>> +
>>>> +    return clk_register(NULL, &mux->hw);
>>>> +}
>>>> +
>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>> +{
>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>> +
>>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0;
>>>> +}
>>>> +
>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>> +{
>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>> +    u32 val;
>>>> +
>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>> +    val = state ? (val | BIT(gate->shift)) : (val & ~BIT(gate->shift));
>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>> +}
>>>> +
>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>> +{
>>>> +    pmc_clk_set_state(hw, 1);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>> +{
>>>> +    pmc_clk_set_state(hw, 0);
>>>> +}
>>>> +
>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>> +    .enable = pmc_clk_enable,
>>>> +    .disable = pmc_clk_disable,
>>>> +};
>>>> +
>>>> +static struct clk *
>>>> +tegra_pmc_clk_gate_register(const char *name, const char *parent_name,
>>>> +                unsigned long flags, unsigned long offset,
>>>> +                u32 shift)
>>>> +{
>>>> +    struct clk_init_data init;
>>>> +    struct pmc_clk_gate *gate;
>>>> +
>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>> +    if (!gate)
>>>> +        return ERR_PTR(-ENOMEM);
>>>> +
>>>> +    init.name = name;
>>>> +    init.ops = &pmc_clk_gate_ops;
>>>> +    init.parent_names = &parent_name;
>>>> +    init.num_parents = 1;
>>>> +    init.flags = flags;
>>>> +
>>>> +    gate->hw.init = &init;
>>>> +    gate->offs = offset;
>>>> +    gate->shift = shift;
>>>> +
>>>> +    return clk_register(NULL, &gate->hw);
>>>> +}
>>>> +
>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>> +                     struct device_node *np)
>>>> +{
>>>> +    struct clk *clkmux, *clk, *parent;
>>>> +    struct clk_onecell_data *clk_data;
>>>> +    unsigned int num_clks;
>>>> +    int i, ret;
>>>> +
>>>> +    /* each pmc clock output has a mux and a gate */
>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>> +
>>>> +    if (!num_clks)
>>>> +        return;
>>>> +
>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>> +    if (!clk_data)
>>>> +        return;
>>>> +
>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>> sizeof(*clk_data->clks),
>>>> +                 GFP_KERNEL);
>>>> +    if (!clk_data->clks)
>>>> +        goto free_clkdata;
>>>> +
>>>> +    clk_data->clk_num = num_clks;
>>>> +
>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>> +        struct pmc_clk_init_data *data;
>>>> +
>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>> +
>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>> +                            data->parents,
>>>> +                            data->num_parents,
>>>> +                            CLK_SET_RATE_NO_REPARENT |
>>>> +                            CLK_SET_RATE_PARENT,
>>>> +                            PMC_CLK_OUT_CNTRL,
>>>> +                            data->mux_shift, 3);
>>>> +        if (IS_ERR(clkmux))
>>>> +            goto free_clks;
>>>> +
>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>> +
>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>> +                          data->mux_name,
>>>> +                          CLK_SET_RATE_PARENT,
>>>> +                          PMC_CLK_OUT_CNTRL,
>>>> +                          data->gate_shift);
>>>> +        if (IS_ERR(clk))
>>>> +            goto free_clks;
>>>> +
>>>> +        clk_data->clks[data->gate_id] = clk;
>>>> +
>>>> +        ret = clk_set_parent(clk, clkmux);
>>>> +        if (ret < 0) {
>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>> +                   __func__, __clk_get_name(clk),
>>>> +                   __clk_get_name(clkmux));
>>>> +        }
>>>> +
>>>> +        clk_register_clkdev(clk, data->dev_name, data->gate_name);
>>>> +
>>>> +        /* configure initial clock parent and state */
>>>> +        parent = clk_get_sys(data->gate_name,
>>>> +                     data->parents[data->init_parent_index]);
>>>> +        if (!IS_ERR(parent)) {
>>>> +            ret = clk_set_parent(clkmux, parent);
>>>> +            if (ret < 0) {
>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>> +                       __func__, __clk_get_name(clkmux),
>>>> +                       __clk_get_name(parent));
>>>> +                WARN_ON(1);
>>>> +            }
>>>> +        }
>>>> +
>>>> +        if (data->init_state) {
>>>> +            if (clk_prepare_enable(clk)) {
>>>> +                pr_err("failed to enable %s\n", __func__,
>>>> +                       __clk_get_name(clk));
>>>> +                WARN_ON(1);
> Alternatively you could write it like this:
>
> 	err = clk_prepare_enable(clk);
>
> 	WARN_ON(err, "failed to enable %s: %d\n",
> 		__clk_get_name(clk), err);
>
>>> Should be a bit better to move the WARN_ON to the end of errors handling
>>> in order to catch all possible errors:
>>>
>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>> tegra_pmc *pmc,
>>>           return;
>>>
>>>    free_clks:
>>> +       WARN_ON(1);
>>>           kfree(clk_data->clks);
>>>    free_clkdata:
>>>           kfree(clk_data);
>> Reason I had WARN_ON right during clk_set_parent failure is to have the
>> loop continue for subsequence pmc clocks registration instead of
>> terminating all pmc clocks registration.
> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least (IMO).

Hi Dmitry, Just want to be clear on the above comment. Are you 
suggesting to add additional WARN_ON at the end?

Thought WARN_ON right during corresponding clock failure with warn 
message showing clock names will be clear and also other clocks still 
should be registered.

To add additional WARN_ON at the end need to track status of each clock 
and use that to as warn condition.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-02 20:09         ` Sowjanya Komatineni
@ 2019-12-02 21:50           ` Dmitry Osipenko
  2019-12-02 22:58             ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-12-02 21:50 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

02.12.2019 23:09, Sowjanya Komatineni пишет:
> 
> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
>>>>> mux and gate for each of these clocks.
>>>>>
>>>>> Currently these PMC clocks are registered by Tegra clock driver using
>>>>> clk_register_mux and clk_register_gate by passing PMC base address
>>>>> and register offsets and PMC programming for these clocks happens
>>>>> through direct PMC access by the clock driver.
>>>>>
>>>>> With this, when PMC is in secure mode any direct PMC access from the
>>>>> non-secure world does not go through and these clocks will not be
>>>>> functional.
>>>>>
>>>>> This patch adds these clocks registration with PMC as a clock provider
>>>>> for these clocks. clk_ops callback implementations for these clocks
>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>> programming
>>>>> in secure mode and non-secure mode.
>>>>>
>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>> ---
>>>>>    drivers/soc/tegra/pmc.c | 330
>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>    1 file changed, 330 insertions(+)
>>>>>
>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>> @@ -13,6 +13,9 @@
>>>>>      #include <linux/arm-smccc.h>
>>>>>    #include <linux/clk.h>
>>>>> +#include <linux/clk-provider.h>
>>>>> +#include <linux/clkdev.h>
>>>>> +#include <linux/clk/clk-conf.h>
>>>>>    #include <linux/clk/tegra.h>
>>>>>    #include <linux/debugfs.h>
>>>>>    #include <linux/delay.h>
>>>>> @@ -48,6 +51,7 @@
>>>>>    #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>    #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>    #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>      #define PMC_CNTRL            0x0
>>>>>    #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>> polarity */
>>>>> @@ -100,6 +104,7 @@
>>>>>    #define PMC_WAKE2_STATUS        0x168
>>>>>    #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>    +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>    #define PMC_SENSOR_CTRL            0x1b0
>>>>>    #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>>>    #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>>> @@ -155,6 +160,91 @@
>>>>>    #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>    #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>    +struct pmc_clk_mux {
>>>>> +    struct clk_hw    hw;
>>>>> +    unsigned long    offs;
>>>>> +    u32        mask;
>>>>> +    u32        shift;
>>>>> +};
>>>>> +
>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
>>>>> +
>>>>> +struct pmc_clk_gate {
>>>>> +    struct clk_hw    hw;
>>>>> +    unsigned long    offs;
>>>>> +    u32        shift;
>>>>> +};
>>>>> +
>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>> pmc_clk_gate, hw)
>>>>> +
>>>>> +struct pmc_clk_init_data {
>>>>> +    char *mux_name;
>>>>> +    char *gate_name;
>>>>> +    const char **parents;
>>>>> +    int num_parents;
>>>>> +    int mux_id;
>>>>> +    int gate_id;
>>>>> +    char *dev_name;
>>>>> +    u8 mux_shift;
>>>>> +    u8 gate_shift;
>>>>> +    u8 init_parent_index;
>>>>> +    int init_state;
>>>>> +};
>>>>> +
>>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>>> +    "clk_m_div4", "extern1",
>>>>> +};
>>>>> +
>>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>>> +    "clk_m_div4", "extern2",
>>>>> +};
>>>>> +
>>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>>> +    "clk_m_div4", "extern3",
>>>>> +};
>>>>> +
>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>> +    {
>>>>> +        .mux_name = "clk_out_1_mux",
>>>>> +        .gate_name = "clk_out_1",
>>>>> +        .parents = clk_out1_parents,
>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>> +        .dev_name = "extern1",
>>>>> +        .mux_shift = 6,
>>>>> +        .gate_shift = 2,
>>>>> +        .init_parent_index = 3,
>>>>> +        .init_state = 1,
>>>>> +    },
>>>>> +    {
>>>>> +        .mux_name = "clk_out_2_mux",
>>>>> +        .gate_name = "clk_out_2",
>>>>> +        .parents = clk_out2_parents,
>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>> +        .dev_name = "extern2",
>>>>> +        .mux_shift = 14,
>>>>> +        .gate_shift = 10,
>>>>> +        .init_parent_index = 0,
>>>>> +        .init_state = 0,
>>>>> +    },
>>>>> +    {
>>>>> +        .mux_name = "clk_out_3_mux",
>>>>> +        .gate_name = "clk_out_3",
>>>>> +        .parents = clk_out3_parents,
>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>> +        .dev_name = "extern3",
>>>>> +        .mux_shift = 22,
>>>>> +        .gate_shift = 18,
>>>>> +        .init_parent_index = 0,
>>>>> +        .init_state = 0,
>>>>> +    },
>>>>> +};
>>>>> +
>>>>>    struct tegra_powergate {
>>>>>        struct generic_pm_domain genpd;
>>>>>        struct tegra_pmc *pmc;
>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>         */
>>>>>        const struct tegra_wake_event *wake_events;
>>>>>        unsigned int num_wake_events;
>>>>> +
>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>> +    unsigned int num_pmc_clks;
>>>>>    };
>>>>>      static const char * const tegra186_reset_sources[] = {
>>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>>> notifier_block *nb,
>>>>>        return NOTIFY_OK;
>>>>>    }
>>>>>    +static void pmc_clk_fence_udelay(u32 offset)
>>>>> +{
>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>> +    /* pmc clk propagation delay 2 us */
>>>>> +    udelay(2);
>>>>> +}
>>>>> +
>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>> +{
>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>> +    u32 val;
>>>>> +
>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>> +    val &= mux->mask;
>>>>> +
>>>>> +    if (val >= num_parents)
>>>>> +        return -EINVAL;
>>>>> +
>>>>> +    return val;
>>>>> +}
>>>>> +
>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>> +{
>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>> +    u32 val;
>>>>> +
>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>> +    val |= index << mux->shift;
>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>> +};
>>>>> +
>>>>> +static struct clk *
>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>> *parent_names,
>>>>> +               int num_parents, unsigned long flags,
>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>> +{
>>>>> +    struct clk_init_data init;
>>>>> +    struct pmc_clk_mux *mux;
>>>>> +
>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>> +    if (!mux)
>>>>> +        return ERR_PTR(-ENOMEM);
>>>>> +
>>>>> +    init.name = name;
>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>> +    init.parent_names = parent_names;
>>>>> +    init.num_parents = num_parents;
>>>>> +    init.flags = flags;
>>>>> +
>>>>> +    mux->hw.init = &init;
>>>>> +    mux->offs = offset;
>>>>> +    mux->mask = mask;
>>>>> +    mux->shift = shift;
>>>>> +
>>>>> +    return clk_register(NULL, &mux->hw);
>>>>> +}
>>>>> +
>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>> +{
>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>> +
>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1
>>>>> : 0;
>>>>> +}
>>>>> +
>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>> +{
>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>> +    u32 val;
>>>>> +
>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>> ~BIT(gate->shift));
>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>> +}
>>>>> +
>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>> +{
>>>>> +    pmc_clk_set_state(hw, 1);
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>> +{
>>>>> +    pmc_clk_set_state(hw, 0);
>>>>> +}
>>>>> +
>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>> +    .enable = pmc_clk_enable,
>>>>> +    .disable = pmc_clk_disable,
>>>>> +};
>>>>> +
>>>>> +static struct clk *
>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>> *parent_name,
>>>>> +                unsigned long flags, unsigned long offset,
>>>>> +                u32 shift)
>>>>> +{
>>>>> +    struct clk_init_data init;
>>>>> +    struct pmc_clk_gate *gate;
>>>>> +
>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>> +    if (!gate)
>>>>> +        return ERR_PTR(-ENOMEM);
>>>>> +
>>>>> +    init.name = name;
>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>> +    init.parent_names = &parent_name;
>>>>> +    init.num_parents = 1;
>>>>> +    init.flags = flags;
>>>>> +
>>>>> +    gate->hw.init = &init;
>>>>> +    gate->offs = offset;
>>>>> +    gate->shift = shift;
>>>>> +
>>>>> +    return clk_register(NULL, &gate->hw);
>>>>> +}
>>>>> +
>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>> +                     struct device_node *np)
>>>>> +{
>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>> +    struct clk_onecell_data *clk_data;
>>>>> +    unsigned int num_clks;
>>>>> +    int i, ret;
>>>>> +
>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>> +
>>>>> +    if (!num_clks)
>>>>> +        return;
>>>>> +
>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>> +    if (!clk_data)
>>>>> +        return;
>>>>> +
>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>> sizeof(*clk_data->clks),
>>>>> +                 GFP_KERNEL);
>>>>> +    if (!clk_data->clks)
>>>>> +        goto free_clkdata;
>>>>> +
>>>>> +    clk_data->clk_num = num_clks;
>>>>> +
>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>> +        struct pmc_clk_init_data *data;
>>>>> +
>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>> +
>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>> +                            data->parents,
>>>>> +                            data->num_parents,
>>>>> +                            CLK_SET_RATE_NO_REPARENT |
>>>>> +                            CLK_SET_RATE_PARENT,
>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>> +                            data->mux_shift, 3);
>>>>> +        if (IS_ERR(clkmux))
>>>>> +            goto free_clks;
>>>>> +
>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>> +
>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>> +                          data->mux_name,
>>>>> +                          CLK_SET_RATE_PARENT,
>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>> +                          data->gate_shift);
>>>>> +        if (IS_ERR(clk))
>>>>> +            goto free_clks;
>>>>> +
>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>> +
>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>> +        if (ret < 0) {
>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>> +                   __func__, __clk_get_name(clk),
>>>>> +                   __clk_get_name(clkmux));
>>>>> +        }
>>>>> +
>>>>> +        clk_register_clkdev(clk, data->dev_name, data->gate_name);
>>>>> +
>>>>> +        /* configure initial clock parent and state */
>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>> +                     data->parents[data->init_parent_index]);

Couldn't the default parent be defined using "assigned clock" in a
device-tree? Please see "Assigned clock parents and rates" in the doc.

https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt

Then you could simply use of_clk_set_defaults(pmc->dev->of_node, true).

>>>>> +        if (!IS_ERR(parent)) {
>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>> +            if (ret < 0) {
>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>> +                       __clk_get_name(parent));
>>>>> +                WARN_ON(1);
>>>>> +            }
>>>>> +        }
>>>>> +
>>>>> +        if (data->init_state) {
>>>>> +            if (clk_prepare_enable(clk)) {
>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>> +                       __clk_get_name(clk));
>>>>> +                WARN_ON(1);
>> Alternatively you could write it like this:
>>
>>     err = clk_prepare_enable(clk);
>>
>>     WARN_ON(err, "failed to enable %s: %d\n",
>>         __clk_get_name(clk), err);
>>
>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>> handling
>>>> in order to catch all possible errors:
>>>>
>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>> tegra_pmc *pmc,
>>>>           return;
>>>>
>>>>    free_clks:
>>>> +       WARN_ON(1);
>>>>           kfree(clk_data->clks);
>>>>    free_clkdata:
>>>>           kfree(clk_data);
>>> Reason I had WARN_ON right during clk_set_parent failure is to have the
>>> loop continue for subsequence pmc clocks registration instead of
>>> terminating all pmc clocks registration.
>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least
>> (IMO).
> Hi Dmitry, Just want to be clear on the above comment. Are you
> suggesting to add additional WARN_ON at the end?

Yes, it was my suggestion.

> Thought WARN_ON right during corresponding clock failure with warn
> message showing clock names will be clear and also other clocks still
> should be registered.
> 
> To add additional WARN_ON at the end need to track status of each clock
> and use that to as warn condition.

You could add a warning/error message to every point of failure.

Primarily, it is important not to miss a error. Secondarily, it is
important to make diagnostic message meaningful.

Realistically, I doubt that this chunk of code will ever fail once it is
known to work well. So it will be nice to have a more detailed
diagnostics (just in a case), but it shouldn't be a must.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-02 21:50           ` Dmitry Osipenko
@ 2019-12-02 22:58             ` Sowjanya Komatineni
  2019-12-02 23:10               ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-02 22:58 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 with
>>>>>> mux and gate for each of these clocks.
>>>>>>
>>>>>> Currently these PMC clocks are registered by Tegra clock driver using
>>>>>> clk_register_mux and clk_register_gate by passing PMC base address
>>>>>> and register offsets and PMC programming for these clocks happens
>>>>>> through direct PMC access by the clock driver.
>>>>>>
>>>>>> With this, when PMC is in secure mode any direct PMC access from the
>>>>>> non-secure world does not go through and these clocks will not be
>>>>>> functional.
>>>>>>
>>>>>> This patch adds these clocks registration with PMC as a clock provider
>>>>>> for these clocks. clk_ops callback implementations for these clocks
>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>> programming
>>>>>> in secure mode and non-secure mode.
>>>>>>
>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>> ---
>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>     1 file changed, 330 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>> @@ -13,6 +13,9 @@
>>>>>>       #include <linux/arm-smccc.h>
>>>>>>     #include <linux/clk.h>
>>>>>> +#include <linux/clk-provider.h>
>>>>>> +#include <linux/clkdev.h>
>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>     #include <linux/clk/tegra.h>
>>>>>>     #include <linux/debugfs.h>
>>>>>>     #include <linux/delay.h>
>>>>>> @@ -48,6 +51,7 @@
>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>       #define PMC_CNTRL            0x0
>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>> polarity */
>>>>>> @@ -100,6 +104,7 @@
>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>>>> @@ -155,6 +160,91 @@
>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>     +struct pmc_clk_mux {
>>>>>> +    struct clk_hw    hw;
>>>>>> +    unsigned long    offs;
>>>>>> +    u32        mask;
>>>>>> +    u32        shift;
>>>>>> +};
>>>>>> +
>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct pmc_clk_mux, hw)
>>>>>> +
>>>>>> +struct pmc_clk_gate {
>>>>>> +    struct clk_hw    hw;
>>>>>> +    unsigned long    offs;
>>>>>> +    u32        shift;
>>>>>> +};
>>>>>> +
>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>> pmc_clk_gate, hw)
>>>>>> +
>>>>>> +struct pmc_clk_init_data {
>>>>>> +    char *mux_name;
>>>>>> +    char *gate_name;
>>>>>> +    const char **parents;
>>>>>> +    int num_parents;
>>>>>> +    int mux_id;
>>>>>> +    int gate_id;
>>>>>> +    char *dev_name;
>>>>>> +    u8 mux_shift;
>>>>>> +    u8 gate_shift;
>>>>>> +    u8 init_parent_index;
>>>>>> +    int init_state;
>>>>>> +};
>>>>>> +
>>>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>>>> +    "clk_m_div4", "extern1",
>>>>>> +};
>>>>>> +
>>>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>>>> +    "clk_m_div4", "extern2",
>>>>>> +};
>>>>>> +
>>>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>>>> +    "clk_m_div4", "extern3",
>>>>>> +};
>>>>>> +
>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>> +    {
>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>> +        .gate_name = "clk_out_1",
>>>>>> +        .parents = clk_out1_parents,
>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>> +        .dev_name = "extern1",
>>>>>> +        .mux_shift = 6,
>>>>>> +        .gate_shift = 2,
>>>>>> +        .init_parent_index = 3,
>>>>>> +        .init_state = 1,
>>>>>> +    },
>>>>>> +    {
>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>> +        .gate_name = "clk_out_2",
>>>>>> +        .parents = clk_out2_parents,
>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>> +        .dev_name = "extern2",
>>>>>> +        .mux_shift = 14,
>>>>>> +        .gate_shift = 10,
>>>>>> +        .init_parent_index = 0,
>>>>>> +        .init_state = 0,
>>>>>> +    },
>>>>>> +    {
>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>> +        .gate_name = "clk_out_3",
>>>>>> +        .parents = clk_out3_parents,
>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>> +        .dev_name = "extern3",
>>>>>> +        .mux_shift = 22,
>>>>>> +        .gate_shift = 18,
>>>>>> +        .init_parent_index = 0,
>>>>>> +        .init_state = 0,
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>>>>     struct tegra_powergate {
>>>>>>         struct generic_pm_domain genpd;
>>>>>>         struct tegra_pmc *pmc;
>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>          */
>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>         unsigned int num_wake_events;
>>>>>> +
>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>> +    unsigned int num_pmc_clks;
>>>>>>     };
>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>>>> notifier_block *nb,
>>>>>>         return NOTIFY_OK;
>>>>>>     }
>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>> +{
>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>> +    udelay(2);
>>>>>> +}
>>>>>> +
>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>> +{
>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>> +    u32 val;
>>>>>> +
>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>> +    val &= mux->mask;
>>>>>> +
>>>>>> +    if (val >= num_parents)
>>>>>> +        return -EINVAL;
>>>>>> +
>>>>>> +    return val;
>>>>>> +}
>>>>>> +
>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>> +{
>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>> +    u32 val;
>>>>>> +
>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>> +    val |= index << mux->shift;
>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk *
>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>> *parent_names,
>>>>>> +               int num_parents, unsigned long flags,
>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>> +{
>>>>>> +    struct clk_init_data init;
>>>>>> +    struct pmc_clk_mux *mux;
>>>>>> +
>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>> +    if (!mux)
>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>> +
>>>>>> +    init.name = name;
>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>> +    init.parent_names = parent_names;
>>>>>> +    init.num_parents = num_parents;
>>>>>> +    init.flags = flags;
>>>>>> +
>>>>>> +    mux->hw.init = &init;
>>>>>> +    mux->offs = offset;
>>>>>> +    mux->mask = mask;
>>>>>> +    mux->shift = shift;
>>>>>> +
>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>> +}
>>>>>> +
>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>> +{
>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>> +
>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1
>>>>>> : 0;
>>>>>> +}
>>>>>> +
>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>> +{
>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>> +    u32 val;
>>>>>> +
>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>> ~BIT(gate->shift));
>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>> +}
>>>>>> +
>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>> +{
>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>> +{
>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>> +}
>>>>>> +
>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>> +    .enable = pmc_clk_enable,
>>>>>> +    .disable = pmc_clk_disable,
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk *
>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>> *parent_name,
>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>> +                u32 shift)
>>>>>> +{
>>>>>> +    struct clk_init_data init;
>>>>>> +    struct pmc_clk_gate *gate;
>>>>>> +
>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>> +    if (!gate)
>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>> +
>>>>>> +    init.name = name;
>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>> +    init.parent_names = &parent_name;
>>>>>> +    init.num_parents = 1;
>>>>>> +    init.flags = flags;
>>>>>> +
>>>>>> +    gate->hw.init = &init;
>>>>>> +    gate->offs = offset;
>>>>>> +    gate->shift = shift;
>>>>>> +
>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>> +}
>>>>>> +
>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>> +                     struct device_node *np)
>>>>>> +{
>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>> +    unsigned int num_clks;
>>>>>> +    int i, ret;
>>>>>> +
>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>> +
>>>>>> +    if (!num_clks)
>>>>>> +        return;
>>>>>> +
>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>> +    if (!clk_data)
>>>>>> +        return;
>>>>>> +
>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>> sizeof(*clk_data->clks),
>>>>>> +                 GFP_KERNEL);
>>>>>> +    if (!clk_data->clks)
>>>>>> +        goto free_clkdata;
>>>>>> +
>>>>>> +    clk_data->clk_num = num_clks;
>>>>>> +
>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>> +        struct pmc_clk_init_data *data;
>>>>>> +
>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>> +
>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>> +                            data->parents,
>>>>>> +                            data->num_parents,
>>>>>> +                            CLK_SET_RATE_NO_REPARENT |
>>>>>> +                            CLK_SET_RATE_PARENT,
>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>> +                            data->mux_shift, 3);
>>>>>> +        if (IS_ERR(clkmux))
>>>>>> +            goto free_clks;
>>>>>> +
>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>> +
>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>> +                          data->mux_name,
>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>> +                          data->gate_shift);
>>>>>> +        if (IS_ERR(clk))
>>>>>> +            goto free_clks;
>>>>>> +
>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>> +
>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>> +        if (ret < 0) {
>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>> +                   __clk_get_name(clkmux));
>>>>>> +        }
>>>>>> +
>>>>>> +        clk_register_clkdev(clk, data->dev_name, data->gate_name);
>>>>>> +
>>>>>> +        /* configure initial clock parent and state */
>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>> +                     data->parents[data->init_parent_index]);
> Couldn't the default parent be defined using "assigned clock" in a
> device-tree? Please see "Assigned clock parents and rates" in the doc.
>
> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Then you could simply use of_clk_set_defaults(pmc->dev->of_node, true).

Yes, of_clk_add_provider() does of_clk_set_defaults which sets based on 
assigned parents and clock rates.

This need device tree to specify assigned clock parent properties. Will 
update device tree and remove init parent from the driver.

>
>>>>>> +        if (!IS_ERR(parent)) {
>>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>>> +            if (ret < 0) {
>>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>>> +                       __clk_get_name(parent));
>>>>>> +                WARN_ON(1);
>>>>>> +            }
>>>>>> +        }
>>>>>> +
>>>>>> +        if (data->init_state) {
>>>>>> +            if (clk_prepare_enable(clk)) {
>>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>>> +                       __clk_get_name(clk));
>>>>>> +                WARN_ON(1);
>>> Alternatively you could write it like this:
>>>
>>>      err = clk_prepare_enable(clk);
>>>
>>>      WARN_ON(err, "failed to enable %s: %d\n",
>>>          __clk_get_name(clk), err);
>>>
>>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>>> handling
>>>>> in order to catch all possible errors:
>>>>>
>>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>>> tegra_pmc *pmc,
>>>>>            return;
>>>>>
>>>>>     free_clks:
>>>>> +       WARN_ON(1);
>>>>>            kfree(clk_data->clks);
>>>>>     free_clkdata:
>>>>>            kfree(clk_data);
>>>> Reason I had WARN_ON right during clk_set_parent failure is to have the
>>>> loop continue for subsequence pmc clocks registration instead of
>>>> terminating all pmc clocks registration.
>>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least
>>> (IMO).
>> Hi Dmitry, Just want to be clear on the above comment. Are you
>> suggesting to add additional WARN_ON at the end?
> Yes, it was my suggestion.
>
>> Thought WARN_ON right during corresponding clock failure with warn
>> message showing clock names will be clear and also other clocks still
>> should be registered.
>>
>> To add additional WARN_ON at the end need to track status of each clock
>> and use that to as warn condition.
> You could add a warning/error message to every point of failure.
>
> Primarily, it is important not to miss a error. Secondarily, it is
> important to make diagnostic message meaningful.
>
> Realistically, I doubt that this chunk of code will ever fail once it is
> known to work well. So it will be nice to have a more detailed
> diagnostics (just in a case), but it shouldn't be a must.

OK, Will add additional WARN message "failed registering PMC clocks" at 
the end.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-02 22:58             ` Sowjanya Komatineni
@ 2019-12-02 23:10               ` Sowjanya Komatineni
  2019-12-02 23:14                 ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-02 23:10 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>
> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, clk_out_3 
>>>>>>> with
>>>>>>> mux and gate for each of these clocks.
>>>>>>>
>>>>>>> Currently these PMC clocks are registered by Tegra clock driver 
>>>>>>> using
>>>>>>> clk_register_mux and clk_register_gate by passing PMC base address
>>>>>>> and register offsets and PMC programming for these clocks happens
>>>>>>> through direct PMC access by the clock driver.
>>>>>>>
>>>>>>> With this, when PMC is in secure mode any direct PMC access from 
>>>>>>> the
>>>>>>> non-secure world does not go through and these clocks will not be
>>>>>>> functional.
>>>>>>>
>>>>>>> This patch adds these clocks registration with PMC as a clock 
>>>>>>> provider
>>>>>>> for these clocks. clk_ops callback implementations for these clocks
>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>> programming
>>>>>>> in secure mode and non-secure mode.
>>>>>>>
>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>> ---
>>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>     1 file changed, 330 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>       #include <linux/arm-smccc.h>
>>>>>>>     #include <linux/clk.h>
>>>>>>> +#include <linux/clk-provider.h>
>>>>>>> +#include <linux/clkdev.h>
>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>     #include <linux/clk/tegra.h>
>>>>>>>     #include <linux/debugfs.h>
>>>>>>>     #include <linux/delay.h>
>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>       #define PMC_CNTRL            0x0
>>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>> polarity */
>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>     +struct pmc_clk_mux {
>>>>>>> +    struct clk_hw    hw;
>>>>>>> +    unsigned long    offs;
>>>>>>> +    u32        mask;
>>>>>>> +    u32        shift;
>>>>>>> +};
>>>>>>> +
>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct 
>>>>>>> pmc_clk_mux, hw)
>>>>>>> +
>>>>>>> +struct pmc_clk_gate {
>>>>>>> +    struct clk_hw    hw;
>>>>>>> +    unsigned long    offs;
>>>>>>> +    u32        shift;
>>>>>>> +};
>>>>>>> +
>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>> pmc_clk_gate, hw)
>>>>>>> +
>>>>>>> +struct pmc_clk_init_data {
>>>>>>> +    char *mux_name;
>>>>>>> +    char *gate_name;
>>>>>>> +    const char **parents;
>>>>>>> +    int num_parents;
>>>>>>> +    int mux_id;
>>>>>>> +    int gate_id;
>>>>>>> +    char *dev_name;
>>>>>>> +    u8 mux_shift;
>>>>>>> +    u8 gate_shift;
>>>>>>> +    u8 init_parent_index;
>>>>>>> +    int init_state;
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>> +    {
>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>> +        .parents = clk_out1_parents,
>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>> +        .dev_name = "extern1",
>>>>>>> +        .mux_shift = 6,
>>>>>>> +        .gate_shift = 2,
>>>>>>> +        .init_parent_index = 3,
>>>>>>> +        .init_state = 1,
>>>>>>> +    },
>>>>>>> +    {
>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>> +        .parents = clk_out2_parents,
>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>> +        .dev_name = "extern2",
>>>>>>> +        .mux_shift = 14,
>>>>>>> +        .gate_shift = 10,
>>>>>>> +        .init_parent_index = 0,
>>>>>>> +        .init_state = 0,
>>>>>>> +    },
>>>>>>> +    {
>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>> +        .parents = clk_out3_parents,
>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>> +        .dev_name = "extern3",
>>>>>>> +        .mux_shift = 22,
>>>>>>> +        .gate_shift = 18,
>>>>>>> +        .init_parent_index = 0,
>>>>>>> +        .init_state = 0,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>>     struct tegra_powergate {
>>>>>>>         struct generic_pm_domain genpd;
>>>>>>>         struct tegra_pmc *pmc;
>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>          */
>>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>>         unsigned int num_wake_events;
>>>>>>> +
>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>     };
>>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>>>>> notifier_block *nb,
>>>>>>>         return NOTIFY_OK;
>>>>>>>     }
>>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>> +{
>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>> +    udelay(2);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>> +{
>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>> +    u32 val;
>>>>>>> +
>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>> +    val &= mux->mask;
>>>>>>> +
>>>>>>> +    if (val >= num_parents)
>>>>>>> +        return -EINVAL;
>>>>>>> +
>>>>>>> +    return val;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>> +{
>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>> +    u32 val;
>>>>>>> +
>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>> +    val |= index << mux->shift;
>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>> +
>>>>>>> +    return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk *
>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>> *parent_names,
>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>> +{
>>>>>>> +    struct clk_init_data init;
>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>> +
>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>> +    if (!mux)
>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>> +
>>>>>>> +    init.name = name;
>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>> +    init.parent_names = parent_names;
>>>>>>> +    init.num_parents = num_parents;
>>>>>>> +    init.flags = flags;
>>>>>>> +
>>>>>>> +    mux->hw.init = &init;
>>>>>>> +    mux->offs = offset;
>>>>>>> +    mux->mask = mask;
>>>>>>> +    mux->shift = shift;
>>>>>>> +
>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>> +{
>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>> +
>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1
>>>>>>> : 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>> +{
>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>> +    u32 val;
>>>>>>> +
>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>> ~BIT(gate->shift));
>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>> +{
>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>> +
>>>>>>> +    return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>> +{
>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk *
>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>> *parent_name,
>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>> +                u32 shift)
>>>>>>> +{
>>>>>>> +    struct clk_init_data init;
>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>> +
>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>> +    if (!gate)
>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>> +
>>>>>>> +    init.name = name;
>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>> +    init.parent_names = &parent_name;
>>>>>>> +    init.num_parents = 1;
>>>>>>> +    init.flags = flags;
>>>>>>> +
>>>>>>> +    gate->hw.init = &init;
>>>>>>> +    gate->offs = offset;
>>>>>>> +    gate->shift = shift;
>>>>>>> +
>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>> +}
>>>>>>> +
>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>> +                     struct device_node *np)
>>>>>>> +{
>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>> +    unsigned int num_clks;
>>>>>>> +    int i, ret;
>>>>>>> +
>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>> +
>>>>>>> +    if (!num_clks)
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>> +    if (!clk_data)
>>>>>>> +        return;
>>>>>>> +
>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>> sizeof(*clk_data->clks),
>>>>>>> +                 GFP_KERNEL);
>>>>>>> +    if (!clk_data->clks)
>>>>>>> +        goto free_clkdata;
>>>>>>> +
>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>> +
>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>> +
>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>> +
>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>> +                            data->parents,
>>>>>>> +                            data->num_parents,
>>>>>>> +                            CLK_SET_RATE_NO_REPARENT |
>>>>>>> +                            CLK_SET_RATE_PARENT,
>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>> +                            data->mux_shift, 3);
>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>> +            goto free_clks;
>>>>>>> +
>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>> +
>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>> +                          data->mux_name,
>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>> +                          data->gate_shift);
>>>>>>> +        if (IS_ERR(clk))
>>>>>>> +            goto free_clks;
>>>>>>> +
>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>> +
>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>> +        if (ret < 0) {
>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        clk_register_clkdev(clk, data->dev_name, data->gate_name);
>>>>>>> +
>>>>>>> +        /* configure initial clock parent and state */
>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>> + data->parents[data->init_parent_index]);
>> Couldn't the default parent be defined using "assigned clock" in a
>> device-tree? Please see "Assigned clock parents and rates" in the doc.
>>
>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt 
>>
>>
>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node, true).
>
> Yes, of_clk_add_provider() does of_clk_set_defaults which sets based 
> on assigned parents and clock rates.
>
> This need device tree to specify assigned clock parent properties. 
> Will update device tree and remove init parent from the driver.
>
assigned-clock properties should be set in consumer node of these clocks 
and currently these clocks are not used yet.

So will just remove init parent from driver and when these clocks are 
used device tree can be updated in corresponding consumer node with 
these properties.

>>
>>>>>>> +        if (!IS_ERR(parent)) {
>>>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>>>> +            if (ret < 0) {
>>>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>>>> +                       __clk_get_name(parent));
>>>>>>> +                WARN_ON(1);
>>>>>>> +            }
>>>>>>> +        }
>>>>>>> +
>>>>>>> +        if (data->init_state) {
>>>>>>> +            if (clk_prepare_enable(clk)) {
>>>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>>>> +                       __clk_get_name(clk));
>>>>>>> +                WARN_ON(1);
>>>> Alternatively you could write it like this:
>>>>
>>>>      err = clk_prepare_enable(clk);
>>>>
>>>>      WARN_ON(err, "failed to enable %s: %d\n",
>>>>          __clk_get_name(clk), err);
>>>>
>>>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>>>> handling
>>>>>> in order to catch all possible errors:
>>>>>>
>>>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>>>> tegra_pmc *pmc,
>>>>>>            return;
>>>>>>
>>>>>>     free_clks:
>>>>>> +       WARN_ON(1);
>>>>>>            kfree(clk_data->clks);
>>>>>>     free_clkdata:
>>>>>>            kfree(clk_data);
>>>>> Reason I had WARN_ON right during clk_set_parent failure is to 
>>>>> have the
>>>>> loop continue for subsequence pmc clocks registration instead of
>>>>> terminating all pmc clocks registration.
>>>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least
>>>> (IMO).
>>> Hi Dmitry, Just want to be clear on the above comment. Are you
>>> suggesting to add additional WARN_ON at the end?
>> Yes, it was my suggestion.
>>
>>> Thought WARN_ON right during corresponding clock failure with warn
>>> message showing clock names will be clear and also other clocks still
>>> should be registered.
>>>
>>> To add additional WARN_ON at the end need to track status of each clock
>>> and use that to as warn condition.
>> You could add a warning/error message to every point of failure.
>>
>> Primarily, it is important not to miss a error. Secondarily, it is
>> important to make diagnostic message meaningful.
>>
>> Realistically, I doubt that this chunk of code will ever fail once it is
>> known to work well. So it will be nice to have a more detailed
>> diagnostics (just in a case), but it shouldn't be a must.
>
> OK, Will add additional WARN message "failed registering PMC clocks" 
> at the end.
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-02 23:10               ` Sowjanya Komatineni
@ 2019-12-02 23:14                 ` Sowjanya Komatineni
  2019-12-03  0:07                   ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-02 23:14 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>
> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>
>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, 
>>>>>>>> clk_out_3 with
>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>
>>>>>>>> Currently these PMC clocks are registered by Tegra clock driver 
>>>>>>>> using
>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base address
>>>>>>>> and register offsets and PMC programming for these clocks happens
>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>
>>>>>>>> With this, when PMC is in secure mode any direct PMC access 
>>>>>>>> from the
>>>>>>>> non-secure world does not go through and these clocks will not be
>>>>>>>> functional.
>>>>>>>>
>>>>>>>> This patch adds these clocks registration with PMC as a clock 
>>>>>>>> provider
>>>>>>>> for these clocks. clk_ops callback implementations for these 
>>>>>>>> clocks
>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>> programming
>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>
>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>> ---
>>>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>     1 file changed, 330 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>       #include <linux/arm-smccc.h>
>>>>>>>>     #include <linux/clk.h>
>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>     #include <linux/clk/tegra.h>
>>>>>>>>     #include <linux/debugfs.h>
>>>>>>>>     #include <linux/delay.h>
>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>       #define PMC_CNTRL            0x0
>>>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>>> polarity */
>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE    BIT(2)
>>>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>     +struct pmc_clk_mux {
>>>>>>>> +    struct clk_hw    hw;
>>>>>>>> +    unsigned long    offs;
>>>>>>>> +    u32        mask;
>>>>>>>> +    u32        shift;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct 
>>>>>>>> pmc_clk_mux, hw)
>>>>>>>> +
>>>>>>>> +struct pmc_clk_gate {
>>>>>>>> +    struct clk_hw    hw;
>>>>>>>> +    unsigned long    offs;
>>>>>>>> +    u32        shift;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>> pmc_clk_gate, hw)
>>>>>>>> +
>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>> +    char *mux_name;
>>>>>>>> +    char *gate_name;
>>>>>>>> +    const char **parents;
>>>>>>>> +    int num_parents;
>>>>>>>> +    int mux_id;
>>>>>>>> +    int gate_id;
>>>>>>>> +    char *dev_name;
>>>>>>>> +    u8 mux_shift;
>>>>>>>> +    u8 gate_shift;
>>>>>>>> +    u8 init_parent_index;
>>>>>>>> +    int init_state;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>> +    {
>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>> +        .dev_name = "extern1",
>>>>>>>> +        .mux_shift = 6,
>>>>>>>> +        .gate_shift = 2,
>>>>>>>> +        .init_parent_index = 3,
>>>>>>>> +        .init_state = 1,
>>>>>>>> +    },
>>>>>>>> +    {
>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>> +        .dev_name = "extern2",
>>>>>>>> +        .mux_shift = 14,
>>>>>>>> +        .gate_shift = 10,
>>>>>>>> +        .init_parent_index = 0,
>>>>>>>> +        .init_state = 0,
>>>>>>>> +    },
>>>>>>>> +    {
>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>> +        .dev_name = "extern3",
>>>>>>>> +        .mux_shift = 22,
>>>>>>>> +        .gate_shift = 18,
>>>>>>>> +        .init_parent_index = 0,
>>>>>>>> +        .init_state = 0,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>     struct tegra_powergate {
>>>>>>>>         struct generic_pm_domain genpd;
>>>>>>>>         struct tegra_pmc *pmc;
>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>          */
>>>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>>>         unsigned int num_wake_events;
>>>>>>>> +
>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>     };
>>>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>>>>>> notifier_block *nb,
>>>>>>>>         return NOTIFY_OK;
>>>>>>>>     }
>>>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>> +{
>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>> +    udelay(2);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>> +{
>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>> +    u32 val;
>>>>>>>> +
>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>> +    val &= mux->mask;
>>>>>>>> +
>>>>>>>> +    if (val >= num_parents)
>>>>>>>> +        return -EINVAL;
>>>>>>>> +
>>>>>>>> +    return val;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>>> +{
>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>> +    u32 val;
>>>>>>>> +
>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>> +    val |= index << mux->shift;
>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>> +
>>>>>>>> +    return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk *
>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>>> *parent_names,
>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>> +{
>>>>>>>> +    struct clk_init_data init;
>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>> +
>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>> +    if (!mux)
>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>> +
>>>>>>>> +    init.name = name;
>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>> +    init.flags = flags;
>>>>>>>> +
>>>>>>>> +    mux->hw.init = &init;
>>>>>>>> +    mux->offs = offset;
>>>>>>>> +    mux->mask = mask;
>>>>>>>> +    mux->shift = shift;
>>>>>>>> +
>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>> +{
>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>> +
>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) 
>>>>>>>> ? 1
>>>>>>>> : 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>> +{
>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>> +    u32 val;
>>>>>>>> +
>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>> ~BIT(gate->shift));
>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>> +{
>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>> +
>>>>>>>> +    return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>> +{
>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk *
>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>> *parent_name,
>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>> +                u32 shift)
>>>>>>>> +{
>>>>>>>> +    struct clk_init_data init;
>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>> +
>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>> +    if (!gate)
>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>> +
>>>>>>>> +    init.name = name;
>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>> +    init.num_parents = 1;
>>>>>>>> +    init.flags = flags;
>>>>>>>> +
>>>>>>>> +    gate->hw.init = &init;
>>>>>>>> +    gate->offs = offset;
>>>>>>>> +    gate->shift = shift;
>>>>>>>> +
>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>> +                     struct device_node *np)
>>>>>>>> +{
>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>> +    unsigned int num_clks;
>>>>>>>> +    int i, ret;
>>>>>>>> +
>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>> +
>>>>>>>> +    if (!num_clks)
>>>>>>>> +        return;
>>>>>>>> +
>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>> +    if (!clk_data)
>>>>>>>> +        return;
>>>>>>>> +
>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>> +                 GFP_KERNEL);
>>>>>>>> +    if (!clk_data->clks)
>>>>>>>> +        goto free_clkdata;
>>>>>>>> +
>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>> +
>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>> +
>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>> +
>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>> +                            data->parents,
>>>>>>>> +                            data->num_parents,
>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>> +                            CLK_SET_RATE_PARENT,
>>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>>> +                            data->mux_shift, 3);
>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>> +            goto free_clks;
>>>>>>>> +
>>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>>> +
>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>> +                          data->mux_name,
>>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>>> +                          data->gate_shift);
>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>> +            goto free_clks;
>>>>>>>> +
>>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>>> +
>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>> +        if (ret < 0) {
>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>>> +        }
>>>>>>>> +
>>>>>>>> +        clk_register_clkdev(clk, data->dev_name, 
>>>>>>>> data->gate_name);
>>>>>>>> +
>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>> + data->parents[data->init_parent_index]);
>>> Couldn't the default parent be defined using "assigned clock" in a
>>> device-tree? Please see "Assigned clock parents and rates" in the doc.
>>>
>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt 
>>>
>>>
>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node, true).
>>
>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets based 
>> on assigned parents and clock rates.
>>
>> This need device tree to specify assigned clock parent properties. 
>> Will update device tree and remove init parent from the driver.
>>
> assigned-clock properties should be set in consumer node of these 
> clocks and currently these clocks are not used yet.
>
> So will just remove init parent from driver and when these clocks are 
> used device tree can be updated in corresponding consumer node with 
> these properties.
>
How about default ON/OFF init state for the clocks? I see assigned-clock 
properties for parent and rate only.

But based on existing clock-tegra-pmc driver, I see clk_out_1 is default 
enabled with extern1 parent for T30 thru T210 platforms.

Peter/Thierry, What was the reason we enable clk_out_1 right from the 
clock registration?

>>>
>>>>>>>> +        if (!IS_ERR(parent)) {
>>>>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>>>>> +            if (ret < 0) {
>>>>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>>>>> +                       __clk_get_name(parent));
>>>>>>>> +                WARN_ON(1);
>>>>>>>> +            }
>>>>>>>> +        }
>>>>>>>> +
>>>>>>>> +        if (data->init_state) {
>>>>>>>> +            if (clk_prepare_enable(clk)) {
>>>>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>>>>> +                       __clk_get_name(clk));
>>>>>>>> +                WARN_ON(1);
>>>>> Alternatively you could write it like this:
>>>>>
>>>>>      err = clk_prepare_enable(clk);
>>>>>
>>>>>      WARN_ON(err, "failed to enable %s: %d\n",
>>>>>          __clk_get_name(clk), err);
>>>>>
>>>>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>>>>> handling
>>>>>>> in order to catch all possible errors:
>>>>>>>
>>>>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>>>>> tegra_pmc *pmc,
>>>>>>>            return;
>>>>>>>
>>>>>>>     free_clks:
>>>>>>> +       WARN_ON(1);
>>>>>>>            kfree(clk_data->clks);
>>>>>>>     free_clkdata:
>>>>>>>            kfree(clk_data);
>>>>>> Reason I had WARN_ON right during clk_set_parent failure is to 
>>>>>> have the
>>>>>> loop continue for subsequence pmc clocks registration instead of
>>>>>> terminating all pmc clocks registration.
>>>>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the least
>>>>> (IMO).
>>>> Hi Dmitry, Just want to be clear on the above comment. Are you
>>>> suggesting to add additional WARN_ON at the end?
>>> Yes, it was my suggestion.
>>>
>>>> Thought WARN_ON right during corresponding clock failure with warn
>>>> message showing clock names will be clear and also other clocks still
>>>> should be registered.
>>>>
>>>> To add additional WARN_ON at the end need to track status of each 
>>>> clock
>>>> and use that to as warn condition.
>>> You could add a warning/error message to every point of failure.
>>>
>>> Primarily, it is important not to miss a error. Secondarily, it is
>>> important to make diagnostic message meaningful.
>>>
>>> Realistically, I doubt that this chunk of code will ever fail once 
>>> it is
>>> known to work well. So it will be nice to have a more detailed
>>> diagnostics (just in a case), but it shouldn't be a must.
>>
>> OK, Will add additional WARN message "failed registering PMC clocks" 
>> at the end.
>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-02 23:14                 ` Sowjanya Komatineni
@ 2019-12-03  0:07                   ` Sowjanya Komatineni
  2019-12-03 16:45                     ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-03  0:07 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>
> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>
>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>
>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, 
>>>>>>>>> clk_out_3 with
>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>
>>>>>>>>> Currently these PMC clocks are registered by Tegra clock 
>>>>>>>>> driver using
>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base 
>>>>>>>>> address
>>>>>>>>> and register offsets and PMC programming for these clocks happens
>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>
>>>>>>>>> With this, when PMC is in secure mode any direct PMC access 
>>>>>>>>> from the
>>>>>>>>> non-secure world does not go through and these clocks will not be
>>>>>>>>> functional.
>>>>>>>>>
>>>>>>>>> This patch adds these clocks registration with PMC as a clock 
>>>>>>>>> provider
>>>>>>>>> for these clocks. clk_ops callback implementations for these 
>>>>>>>>> clocks
>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>> programming
>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>> ---
>>>>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>     1 file changed, 330 insertions(+)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>       #include <linux/arm-smccc.h>
>>>>>>>>>     #include <linux/clk.h>
>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>     #include <linux/clk/tegra.h>
>>>>>>>>>     #include <linux/debugfs.h>
>>>>>>>>>     #include <linux/delay.h>
>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>       #define PMC_CNTRL            0x0
>>>>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>>>> polarity */
>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST    BIT(1)
>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>     +struct pmc_clk_mux {
>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>> +    unsigned long    offs;
>>>>>>>>> +    u32        mask;
>>>>>>>>> +    u32        shift;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct 
>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>> +
>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>> +    unsigned long    offs;
>>>>>>>>> +    u32        shift;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>> +
>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>> +    char *mux_name;
>>>>>>>>> +    char *gate_name;
>>>>>>>>> +    const char **parents;
>>>>>>>>> +    int num_parents;
>>>>>>>>> +    int mux_id;
>>>>>>>>> +    int gate_id;
>>>>>>>>> +    char *dev_name;
>>>>>>>>> +    u8 mux_shift;
>>>>>>>>> +    u8 gate_shift;
>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>> +    int init_state;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>> +    {
>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>> +        .init_state = 1,
>>>>>>>>> +    },
>>>>>>>>> +    {
>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>> +        .init_state = 0,
>>>>>>>>> +    },
>>>>>>>>> +    {
>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>> +        .init_state = 0,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>     struct tegra_powergate {
>>>>>>>>>         struct generic_pm_domain genpd;
>>>>>>>>>         struct tegra_pmc *pmc;
>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>          */
>>>>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>>>>         unsigned int num_wake_events;
>>>>>>>>> +
>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>     };
>>>>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>>>>> @@ -2163,6 +2256,228 @@ static int tegra_pmc_clk_notify_cb(struct
>>>>>>>>> notifier_block *nb,
>>>>>>>>>         return NOTIFY_OK;
>>>>>>>>>     }
>>>>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>> +{
>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>> +    udelay(2);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>> +{
>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>> +    u32 val;
>>>>>>>>> +
>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>> +    val &= mux->mask;
>>>>>>>>> +
>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>> +        return -EINVAL;
>>>>>>>>> +
>>>>>>>>> +    return val;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>>>> +{
>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>> +    u32 val;
>>>>>>>>> +
>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>> +
>>>>>>>>> +    return 0;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk *
>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>>>> *parent_names,
>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>> +{
>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>> +
>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>> +    if (!mux)
>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>> +
>>>>>>>>> +    init.name = name;
>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>> +    init.flags = flags;
>>>>>>>>> +
>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>> +    mux->offs = offset;
>>>>>>>>> +    mux->mask = mask;
>>>>>>>>> +    mux->shift = shift;
>>>>>>>>> +
>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>> +{
>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>> +
>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & 
>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>> : 0;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>> +{
>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>> +    u32 val;
>>>>>>>>> +
>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>> +{
>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>> +
>>>>>>>>> +    return 0;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>> +{
>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk *
>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>> *parent_name,
>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>> +                u32 shift)
>>>>>>>>> +{
>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>> +
>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>> +    if (!gate)
>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>> +
>>>>>>>>> +    init.name = name;
>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>> +    init.flags = flags;
>>>>>>>>> +
>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>> +    gate->offs = offset;
>>>>>>>>> +    gate->shift = shift;
>>>>>>>>> +
>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>> +                     struct device_node *np)
>>>>>>>>> +{
>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>> +    int i, ret;
>>>>>>>>> +
>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>> +
>>>>>>>>> +    if (!num_clks)
>>>>>>>>> +        return;
>>>>>>>>> +
>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>> +    if (!clk_data)
>>>>>>>>> +        return;
>>>>>>>>> +
>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>> +        goto free_clkdata;
>>>>>>>>> +
>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>> +
>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>> +
>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>> +
>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>> +                            data->parents,
>>>>>>>>> +                            data->num_parents,
>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>> +                            CLK_SET_RATE_PARENT,
>>>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>>>> +                            data->mux_shift, 3);
>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>> +            goto free_clks;
>>>>>>>>> +
>>>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>> +
>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>> +                          data->mux_name,
>>>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>>>> +                          data->gate_shift);
>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>> +            goto free_clks;
>>>>>>>>> +
>>>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>>>> +
>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>> +        if (ret < 0) {
>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name, 
>>>>>>>>> data->gate_name);
>>>>>>>>> +
>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>> + data->parents[data->init_parent_index]);
>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>> device-tree? Please see "Assigned clock parents and rates" in the doc.
>>>>
>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt 
>>>>
>>>>
>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node, 
>>>> true).
>>>
>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets based 
>>> on assigned parents and clock rates.
>>>
>>> This need device tree to specify assigned clock parent properties. 
>>> Will update device tree and remove init parent from the driver.
>>>
>> assigned-clock properties should be set in consumer node of these 
>> clocks and currently these clocks are not used yet.
>>
>> So will just remove init parent from driver and when these clocks are 
>> used device tree can be updated in corresponding consumer node with 
>> these properties.
>>
> How about default ON/OFF init state for the clocks? I see 
> assigned-clock properties for parent and rate only.
>
> But based on existing clock-tegra-pmc driver, I see clk_out_1 is 
> default enabled with extern1 parent for T30 thru T210 platforms.
>
> Peter/Thierry, What was the reason we enable clk_out_1 right from the 
> clock registration?
>
clk_out_1 is for audio and its not required to be enabled during the 
boot and audio driver can enable/disable it.

same with blink 32khz which is used for WIFI. WIFI driver can 
enable/disable during power up/down sequence and technically as per 
design we dont need to have it always on right from the boot.

So can remove out clocks init states from driver once thierry also agree 
on this.

>>>>
>>>>>>>>> +        if (!IS_ERR(parent)) {
>>>>>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>>>>>> +            if (ret < 0) {
>>>>>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>>>>>> +                       __clk_get_name(parent));
>>>>>>>>> +                WARN_ON(1);
>>>>>>>>> +            }
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        if (data->init_state) {
>>>>>>>>> +            if (clk_prepare_enable(clk)) {
>>>>>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>>>>>> +                       __clk_get_name(clk));
>>>>>>>>> +                WARN_ON(1);
>>>>>> Alternatively you could write it like this:
>>>>>>
>>>>>>      err = clk_prepare_enable(clk);
>>>>>>
>>>>>>      WARN_ON(err, "failed to enable %s: %d\n",
>>>>>>          __clk_get_name(clk), err);
>>>>>>
>>>>>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>>>>>> handling
>>>>>>>> in order to catch all possible errors:
>>>>>>>>
>>>>>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>>>>>> tegra_pmc *pmc,
>>>>>>>>            return;
>>>>>>>>
>>>>>>>>     free_clks:
>>>>>>>> +       WARN_ON(1);
>>>>>>>>            kfree(clk_data->clks);
>>>>>>>>     free_clkdata:
>>>>>>>>            kfree(clk_data);
>>>>>>> Reason I had WARN_ON right during clk_set_parent failure is to 
>>>>>>> have the
>>>>>>> loop continue for subsequence pmc clocks registration instead of
>>>>>>> terminating all pmc clocks registration.
>>>>>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the 
>>>>>> least
>>>>>> (IMO).
>>>>> Hi Dmitry, Just want to be clear on the above comment. Are you
>>>>> suggesting to add additional WARN_ON at the end?
>>>> Yes, it was my suggestion.
>>>>
>>>>> Thought WARN_ON right during corresponding clock failure with warn
>>>>> message showing clock names will be clear and also other clocks still
>>>>> should be registered.
>>>>>
>>>>> To add additional WARN_ON at the end need to track status of each 
>>>>> clock
>>>>> and use that to as warn condition.
>>>> You could add a warning/error message to every point of failure.
>>>>
>>>> Primarily, it is important not to miss a error. Secondarily, it is
>>>> important to make diagnostic message meaningful.
>>>>
>>>> Realistically, I doubt that this chunk of code will ever fail once 
>>>> it is
>>>> known to work well. So it will be nice to have a more detailed
>>>> diagnostics (just in a case), but it shouldn't be a must.
>>>
>>> OK, Will add additional WARN message "failed registering PMC clocks" 
>>> at the end.
>>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-03  0:07                   ` Sowjanya Komatineni
@ 2019-12-03 16:45                     ` Sowjanya Komatineni
  2019-12-04 13:39                       ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-03 16:45 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>
> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>
>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>
>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>
>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2, 
>>>>>>>>>> clk_out_3 with
>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>
>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock 
>>>>>>>>>> driver using
>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base 
>>>>>>>>>> address
>>>>>>>>>> and register offsets and PMC programming for these clocks 
>>>>>>>>>> happens
>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>
>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access 
>>>>>>>>>> from the
>>>>>>>>>> non-secure world does not go through and these clocks will 
>>>>>>>>>> not be
>>>>>>>>>> functional.
>>>>>>>>>>
>>>>>>>>>> This patch adds these clocks registration with PMC as a clock 
>>>>>>>>>> provider
>>>>>>>>>> for these clocks. clk_ops callback implementations for these 
>>>>>>>>>> clocks
>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>> programming
>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>> ---
>>>>>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>     1 file changed, 330 insertions(+)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>       #include <linux/arm-smccc.h>
>>>>>>>>>>     #include <linux/clk.h>
>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>     #include <linux/clk/tegra.h>
>>>>>>>>>>     #include <linux/debugfs.h>
>>>>>>>>>>     #include <linux/delay.h>
>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>       #define PMC_CNTRL            0x0
>>>>>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>>>>> polarity */
>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>     +struct pmc_clk_mux {
>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>> +    u32        mask;
>>>>>>>>>> +    u32        shift;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct 
>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>> +
>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>> +    u32        shift;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>> +
>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>> +    char *mux_name;
>>>>>>>>>> +    char *gate_name;
>>>>>>>>>> +    const char **parents;
>>>>>>>>>> +    int num_parents;
>>>>>>>>>> +    int mux_id;
>>>>>>>>>> +    int gate_id;
>>>>>>>>>> +    char *dev_name;
>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>> +    int init_state;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m", 
>>>>>>>>>> "clk_m_div2",
>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m", 
>>>>>>>>>> "clk_m_div2",
>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m", 
>>>>>>>>>> "clk_m_div2",
>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>> +    {
>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>> +    },
>>>>>>>>>> +    {
>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>> +    },
>>>>>>>>>> +    {
>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>> +    },
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>>     struct tegra_powergate {
>>>>>>>>>>         struct generic_pm_domain genpd;
>>>>>>>>>>         struct tegra_pmc *pmc;
>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>          */
>>>>>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>>>>>         unsigned int num_wake_events;
>>>>>>>>>> +
>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>     };
>>>>>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int 
>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>         return NOTIFY_OK;
>>>>>>>>>>     }
>>>>>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>> +{
>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>> +    udelay(2);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>> +{
>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>> +    u32 val;
>>>>>>>>>> +
>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>> +
>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>> +
>>>>>>>>>> +    return val;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>>>>> +{
>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>> +    u32 val;
>>>>>>>>>> +
>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>> +
>>>>>>>>>> +    return 0;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static struct clk *
>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>>>>> *parent_names,
>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>> +{
>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>> +
>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>> +    if (!mux)
>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>> +
>>>>>>>>>> +    init.name = name;
>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>> +
>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>> +
>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>> +{
>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>> +
>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) & 
>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>> : 0;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>> +{
>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>> +    u32 val;
>>>>>>>>>> +
>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>> +{
>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>> +
>>>>>>>>>> +    return 0;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>> +{
>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static struct clk *
>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>> *parent_name,
>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>> +                u32 shift)
>>>>>>>>>> +{
>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>> +
>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>> +    if (!gate)
>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>> +
>>>>>>>>>> +    init.name = name;
>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>> +
>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>> +
>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>> +{
>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>> +    int i, ret;
>>>>>>>>>> +
>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>> +
>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>> +        return;
>>>>>>>>>> +
>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>> +        return;
>>>>>>>>>> +
>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>> +
>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>> +
>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>> +
>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>> +
>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>> +                            data->parents,
>>>>>>>>>> + data->num_parents,
>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>>>>> +                            data->mux_shift, 3);
>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>> +            goto free_clks;
>>>>>>>>>> +
>>>>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>> +
>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>> +                          data->mux_name,
>>>>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>>>>> +                          data->gate_shift);
>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>> +            goto free_clks;
>>>>>>>>>> +
>>>>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>>>>> +
>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name, 
>>>>>>>>>> data->gate_name);
>>>>>>>>>> +
>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>> device-tree? Please see "Assigned clock parents and rates" in the 
>>>>> doc.
>>>>>
>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt 
>>>>>
>>>>>
>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node, 
>>>>> true).
>>>>
>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets 
>>>> based on assigned parents and clock rates.
>>>>
>>>> This need device tree to specify assigned clock parent properties. 
>>>> Will update device tree and remove init parent from the driver.
>>>>
>>> assigned-clock properties should be set in consumer node of these 
>>> clocks and currently these clocks are not used yet.
>>>
>>> So will just remove init parent from driver and when these clocks 
>>> are used device tree can be updated in corresponding consumer node 
>>> with these properties.
>>>
>> How about default ON/OFF init state for the clocks? I see 
>> assigned-clock properties for parent and rate only.
>>
>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is 
>> default enabled with extern1 parent for T30 thru T210 platforms.
>>
>> Peter/Thierry, What was the reason we enable clk_out_1 right from the 
>> clock registration?
>>
> clk_out_1 is for audio and its not required to be enabled during the 
> boot and audio driver can enable/disable it.
>
> same with blink 32khz which is used for WIFI. WIFI driver can 
> enable/disable during power up/down sequence and technically as per 
> design we dont need to have it always on right from the boot.
>
> So can remove out clocks init states from driver once thierry also 
> agree on this.
>
Hi Dmitry,

Looking at audio driver, it doesn't take care of mclk which is from 
clk_out_1 and expects mclk to be always on.

So probably we should have this init state enables in pmc driver for 
32Khz and clk_out's to not break existing functionality.

Regarding using assigned-clock properties for init parent and removing 
init parent from driver, it also needs consumer node in device tree to 
be updated to specify assigned-clock properties for default/init parent.

This breaks device tree ABI as prior Tegra210 supports audio driver.


>>>>>>>>>> +        if (!IS_ERR(parent)) {
>>>>>>>>>> +            ret = clk_set_parent(clkmux, parent);
>>>>>>>>>> +            if (ret < 0) {
>>>>>>>>>> +                pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>> +                       __func__, __clk_get_name(clkmux),
>>>>>>>>>> +                       __clk_get_name(parent));
>>>>>>>>>> +                WARN_ON(1);
>>>>>>>>>> +            }
>>>>>>>>>> +        }
>>>>>>>>>> +
>>>>>>>>>> +        if (data->init_state) {
>>>>>>>>>> +            if (clk_prepare_enable(clk)) {
>>>>>>>>>> +                pr_err("failed to enable %s\n", __func__,
>>>>>>>>>> +                       __clk_get_name(clk));
>>>>>>>>>> +                WARN_ON(1);
>>>>>>> Alternatively you could write it like this:
>>>>>>>
>>>>>>>      err = clk_prepare_enable(clk);
>>>>>>>
>>>>>>>      WARN_ON(err, "failed to enable %s: %d\n",
>>>>>>>          __clk_get_name(clk), err);
>>>>>>>
>>>>>>>>> Should be a bit better to move the WARN_ON to the end of errors
>>>>>>>>> handling
>>>>>>>>> in order to catch all possible errors:
>>>>>>>>>
>>>>>>>>> @@ -2510,6 +2510,7 @@ static void tegra_pmc_clock_register(struct
>>>>>>>>> tegra_pmc *pmc,
>>>>>>>>>            return;
>>>>>>>>>
>>>>>>>>>     free_clks:
>>>>>>>>> +       WARN_ON(1);
>>>>>>>>>            kfree(clk_data->clks);
>>>>>>>>>     free_clkdata:
>>>>>>>>>            kfree(clk_data);
>>>>>>>> Reason I had WARN_ON right during clk_set_parent failure is to 
>>>>>>>> have the
>>>>>>>> loop continue for subsequence pmc clocks registration instead of
>>>>>>>> terminating all pmc clocks registration.
>>>>>>> Ah, okay. Nevertheless this WARN_ON in the end shouldn't be the 
>>>>>>> least
>>>>>>> (IMO).
>>>>>> Hi Dmitry, Just want to be clear on the above comment. Are you
>>>>>> suggesting to add additional WARN_ON at the end?
>>>>> Yes, it was my suggestion.
>>>>>
>>>>>> Thought WARN_ON right during corresponding clock failure with warn
>>>>>> message showing clock names will be clear and also other clocks 
>>>>>> still
>>>>>> should be registered.
>>>>>>
>>>>>> To add additional WARN_ON at the end need to track status of each 
>>>>>> clock
>>>>>> and use that to as warn condition.
>>>>> You could add a warning/error message to every point of failure.
>>>>>
>>>>> Primarily, it is important not to miss a error. Secondarily, it is
>>>>> important to make diagnostic message meaningful.
>>>>>
>>>>> Realistically, I doubt that this chunk of code will ever fail once 
>>>>> it is
>>>>> known to work well. So it will be nice to have a more detailed
>>>>> diagnostics (just in a case), but it shouldn't be a must.
>>>>
>>>> OK, Will add additional WARN message "failed registering PMC 
>>>> clocks" at the end.
>>>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-03 16:45                     ` Sowjanya Komatineni
@ 2019-12-04 13:39                       ` Dmitry Osipenko
  2019-12-04 16:02                         ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-12-04 13:39 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

03.12.2019 19:45, Sowjanya Komatineni пишет:
> 
> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>
>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>
>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>
>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>
>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>
>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>> driver using
>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>> address
>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>> happens
>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>
>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>> from the
>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>> not be
>>>>>>>>>>> functional.
>>>>>>>>>>>
>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>> provider
>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>> clocks
>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>> programming
>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>> ---
>>>>>>>>>>>     drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>     1 file changed, 330 insertions(+)
>>>>>>>>>>>
>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>       #include <linux/arm-smccc.h>
>>>>>>>>>>>     #include <linux/clk.h>
>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>     #include <linux/clk/tegra.h>
>>>>>>>>>>>     #include <linux/debugfs.h>
>>>>>>>>>>>     #include <linux/delay.h>
>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>     #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>     #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>     #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>       #define PMC_CNTRL            0x0
>>>>>>>>>>>     #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>>>>>> polarity */
>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>     #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>     #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>>>>>     +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>>>>>     #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>>>>>     #define  PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>     #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>     #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>     #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>     +struct pmc_clk_mux {
>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>> +
>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>> +
>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>> +    int init_state;
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>> +    {
>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>> +    },
>>>>>>>>>>> +    {
>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>> +    },
>>>>>>>>>>> +    {
>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>> +    },
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>>     struct tegra_powergate {
>>>>>>>>>>>         struct generic_pm_domain genpd;
>>>>>>>>>>>         struct tegra_pmc *pmc;
>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>          */
>>>>>>>>>>>         const struct tegra_wake_event *wake_events;
>>>>>>>>>>>         unsigned int num_wake_events;
>>>>>>>>>>> +
>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>     };
>>>>>>>>>>>       static const char * const tegra186_reset_sources[] = {
>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>         return NOTIFY_OK;
>>>>>>>>>>>     }
>>>>>>>>>>>     +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>> +{
>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>> +    u32 val;
>>>>>>>>>>> +
>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>> +
>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>> +
>>>>>>>>>>> +    return val;
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>> +    u32 val;
>>>>>>>>>>> +
>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>> +
>>>>>>>>>>> +    return 0;
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static struct clk *
>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>>>>>> *parent_names,
>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>> +
>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>> +
>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>> +
>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>> +
>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>> +
>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>> : 0;
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>> +    u32 val;
>>>>>>>>>>> +
>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>> +{
>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>> +
>>>>>>>>>>> +    return 0;
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>> +{
>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>> +};
>>>>>>>>>>> +
>>>>>>>>>>> +static struct clk *
>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>> *parent_name,
>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>> +
>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>> +
>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>> +
>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>> +
>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>> +{
>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>> +
>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>> +
>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>> +        return;
>>>>>>>>>>> +
>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>> +        return;
>>>>>>>>>>> +
>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>> +
>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>> +
>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>> +
>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>> +
>>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>> +                            data->parents,
>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>>>>>> +                            data->mux_shift, 3);
>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>> +
>>>>>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>> +
>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>> +                          data->mux_name,
>>>>>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>>>>>> +                          data->gate_shift);
>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>> +
>>>>>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>> +
>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>>>>>> +        }
>>>>>>>>>>> +
>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>> data->gate_name);
>>>>>>>>>>> +
>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>>> device-tree? Please see "Assigned clock parents and rates" in the
>>>>>> doc.
>>>>>>
>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>
>>>>>>
>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>> true).
>>>>>
>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>> based on assigned parents and clock rates.
>>>>>
>>>>> This need device tree to specify assigned clock parent properties.
>>>>> Will update device tree and remove init parent from the driver.
>>>>>
>>>> assigned-clock properties should be set in consumer node of these
>>>> clocks and currently these clocks are not used yet.
>>>>
>>>> So will just remove init parent from driver and when these clocks
>>>> are used device tree can be updated in corresponding consumer node
>>>> with these properties.
>>>>
>>> How about default ON/OFF init state for the clocks? I see
>>> assigned-clock properties for parent and rate only.
>>>
>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>
>>> Peter/Thierry, What was the reason we enable clk_out_1 right from the
>>> clock registration?
>>>
>> clk_out_1 is for audio and its not required to be enabled during the
>> boot and audio driver can enable/disable it.
>>
>> same with blink 32khz which is used for WIFI. WIFI driver can
>> enable/disable during power up/down sequence and technically as per
>> design we dont need to have it always on right from the boot.
>>
>> So can remove out clocks init states from driver once thierry also
>> agree on this.
>>
> Hi Dmitry,
> 
> Looking at audio driver, it doesn't take care of mclk which is from
> clk_out_1 and expects mclk to be always on.
> 
> So probably we should have this init state enables in pmc driver for
> 32Khz and clk_out's to not break existing functionality.

Hello Sowjanya,

IIUC, it's a bug in the device-trees and sound's MCLK actually should be
set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the case,
then the device-trees need to be fixed.

> Regarding using assigned-clock properties for init parent and removing
> init parent from driver, it also needs consumer node in device tree to
> be updated to specify assigned-clock properties for default/init parent.
> 
> This breaks device tree ABI as prior Tegra210 supports audio driver.

So it's the sound node which should have had the assigned clocks in
device-tree in order to define route for the audio MCLK clock from CaR
to PMC.

Given that the audio clocks configuration is the same for all of the
currently supported boards, I think it will be better to remove the
entire audio clocks initialization from the clk drivers and move it all
to the audio driver. It could be something like this:

int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
			  struct device *dev)
{
	...

	if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) &&
	    tegra_get_chip_id() > TEGRA20) {
		clk_extern1 = clk_get(dev, "extern1");
		...
		clk_set_parent(clk_extern1, clk_pll_a_out0);
		...
		clk_put(data->clk_cdev1);

		data->clk_cdev1 = clk_out_1;
	}
	...

So now the old device-trees will cointinue to work and new could have
the assigned-clocks and set MCLK to CLK_OUT_1.

[snip]

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 13:39                       ` Dmitry Osipenko
@ 2019-12-04 16:02                         ` Sowjanya Komatineni
  2019-12-04 20:08                           ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-04 16:02 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>
>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>> driver using
>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>> address
>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>> happens
>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>
>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>> from the
>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>> not be
>>>>>>>>>>>> functional.
>>>>>>>>>>>>
>>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>>> provider
>>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>>> clocks
>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>>> programming
>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>
>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>> ---
>>>>>>>>>>>>      drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>      1 file changed, 330 insertions(+)
>>>>>>>>>>>>
>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>        #include <linux/arm-smccc.h>
>>>>>>>>>>>>      #include <linux/clk.h>
>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>      #include <linux/clk/tegra.h>
>>>>>>>>>>>>      #include <linux/debugfs.h>
>>>>>>>>>>>>      #include <linux/delay.h>
>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>      #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>        #define PMC_CNTRL            0x0
>>>>>>>>>>>>      #define  PMC_CNTRL_INTR_POLARITY    BIT(17) /* inverts INTR
>>>>>>>>>>>> polarity */
>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>      #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>      #define PMC_SW_WAKE2_STATUS        0x16c
>>>>>>>>>>>>      +#define PMC_CLK_OUT_CNTRL        0x1a8
>>>>>>>>>>>>      #define PMC_SENSOR_CTRL            0x1b0
>>>>>>>>>>>>      #define  PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>      #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>      +struct pmc_clk_mux {
>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>> +
>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>> +
>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>> +    },
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>> +    },
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>> +    },
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>>      struct tegra_powergate {
>>>>>>>>>>>>          struct generic_pm_domain genpd;
>>>>>>>>>>>>          struct tegra_pmc *pmc;
>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>           */
>>>>>>>>>>>>          const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>          unsigned int num_wake_events;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>      };
>>>>>>>>>>>>        static const char * const tegra186_reset_sources[] = {
>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>          return NOTIFY_OK;
>>>>>>>>>>>>      }
>>>>>>>>>>>>      +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return val;
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 index)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * const
>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>> +
>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>> : 0;
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>> +};
>>>>>>>>>>>> +
>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>> +
>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>> +        return;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>> +        return;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>> +
>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>> +                            data->parents,
>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>> +                            PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>> +                            data->mux_shift, 3);
>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>> +                          data->mux_name,
>>>>>>>>>>>> +                          CLK_SET_RATE_PARENT,
>>>>>>>>>>>> +                          PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>> +                          data->gate_shift);
>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>> +                   __clk_get_name(clkmux));
>>>>>>>>>>>> +        }
>>>>>>>>>>>> +
>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>> +
>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>>>> device-tree? Please see "Assigned clock parents and rates" in the
>>>>>>> doc.
>>>>>>>
>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>>
>>>>>>>
>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>> true).
>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>> based on assigned parents and clock rates.
>>>>>>
>>>>>> This need device tree to specify assigned clock parent properties.
>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>
>>>>> assigned-clock properties should be set in consumer node of these
>>>>> clocks and currently these clocks are not used yet.
>>>>>
>>>>> So will just remove init parent from driver and when these clocks
>>>>> are used device tree can be updated in corresponding consumer node
>>>>> with these properties.
>>>>>
>>>> How about default ON/OFF init state for the clocks? I see
>>>> assigned-clock properties for parent and rate only.
>>>>
>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>
>>>> Peter/Thierry, What was the reason we enable clk_out_1 right from the
>>>> clock registration?
>>>>
>>> clk_out_1 is for audio and its not required to be enabled during the
>>> boot and audio driver can enable/disable it.
>>>
>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>> enable/disable during power up/down sequence and technically as per
>>> design we dont need to have it always on right from the boot.
>>>
>>> So can remove out clocks init states from driver once thierry also
>>> agree on this.
>>>
>> Hi Dmitry,
>>
>> Looking at audio driver, it doesn't take care of mclk which is from
>> clk_out_1 and expects mclk to be always on.
>>
>> So probably we should have this init state enables in pmc driver for
>> 32Khz and clk_out's to not break existing functionality.
> Hello Sowjanya,
>
> IIUC, it's a bug in the device-trees and sound's MCLK actually should be
> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the case,
> then the device-trees need to be fixed.

OK, will have this in v3

>> Regarding using assigned-clock properties for init parent and removing
>> init parent from driver, it also needs consumer node in device tree to
>> be updated to specify assigned-clock properties for default/init parent.
>>
>> This breaks device tree ABI as prior Tegra210 supports audio driver.
> So it's the sound node which should have had the assigned clocks in
> device-tree in order to define route for the audio MCLK clock from CaR
> to PMC.
>
> Given that the audio clocks configuration is the same for all of the
> currently supported boards, I think it will be better to remove the
> entire audio clocks initialization from the clk drivers and move it all
> to the audio driver. It could be something like this:
>
> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
> 			  struct device *dev)
> {
> 	...
>
> 	if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) &&
> 	    tegra_get_chip_id() > TEGRA20) {
> 		clk_extern1 = clk_get(dev, "extern1");
> 		...
> 		clk_set_parent(clk_extern1, clk_pll_a_out0);
> 		...
> 		clk_put(data->clk_cdev1);
>
> 		data->clk_cdev1 = clk_out_1;
> 	}
> 	...
>
> So now the old device-trees will cointinue to work and new could have
> the assigned-clocks and set MCLK to CLK_OUT_1.
>
> [snip]

Will update clk-tegra, pmc and audio driver to move init state 
configuration for extern1 and clk_out_1 into audio driver and will use 
assigned clock properties in device tree.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 16:02                         ` Sowjanya Komatineni
@ 2019-12-04 20:08                           ` Sowjanya Komatineni
  2019-12-04 20:28                             ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-04 20:08 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/4/19 8:02 AM, Sowjanya Komatineni wrote:
>
> On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
>> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>> driver using
>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>> address
>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>> happens
>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>
>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>> from the
>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>> not be
>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>
>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>>>> provider
>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>>>> clocks
>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>>>> programming
>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>>      drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>      1 file changed, 330 insertions(+)
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c 
>>>>>>>>>>>>> b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>>        #include <linux/arm-smccc.h>
>>>>>>>>>>>>>      #include <linux/clk.h>
>>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>>      #include <linux/clk/tegra.h>
>>>>>>>>>>>>>      #include <linux/debugfs.h>
>>>>>>>>>>>>>      #include <linux/delay.h>
>>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>>      #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>>        #define PMC_CNTRL            0x0
>>>>>>>>>>>>>      #define  PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR
>>>>>>>>>>>>> polarity */
>>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>>      #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>>      #define PMC_SW_WAKE2_STATUS 0x16c
>>>>>>>>>>>>>      +#define PMC_CLK_OUT_CNTRL 0x1a8
>>>>>>>>>>>>>      #define PMC_SENSOR_CTRL 0x1b0
>>>>>>>>>>>>>      #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>>      #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>>      +struct pmc_clk_mux {
>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>>> +    {
>>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>>> +    },
>>>>>>>>>>>>> +    {
>>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>> +    },
>>>>>>>>>>>>> +    {
>>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>> +    },
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>>      struct tegra_powergate {
>>>>>>>>>>>>>          struct generic_pm_domain genpd;
>>>>>>>>>>>>>          struct tegra_pmc *pmc;
>>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>>           */
>>>>>>>>>>>>>          const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>>          unsigned int num_wake_events;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>>      };
>>>>>>>>>>>>>        static const char * const tegra186_reset_sources[] = {
>>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>>          return NOTIFY_OK;
>>>>>>>>>>>>>      }
>>>>>>>>>>>>>      +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return val;
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8 
>>>>>>>>>>>>> index)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char * 
>>>>>>>>>>>>> const
>>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>>> : 0;
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>>> +};
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>>> +}
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>>> +{
>>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>>> + data->parents,
>>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>> + data->mux_shift, 3);
>>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> + clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>>> + data->mux_name,
>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>> + data->gate_shift);
>>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> + clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>>> + __clk_get_name(clkmux));
>>>>>>>>>>>>> +        }
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>>>>> device-tree? Please see "Assigned clock parents and rates" in the
>>>>>>>> doc.
>>>>>>>>
>>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt 
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>>> true).
>>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>>> based on assigned parents and clock rates.
>>>>>>>
>>>>>>> This need device tree to specify assigned clock parent properties.
>>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>>
>>>>>> assigned-clock properties should be set in consumer node of these
>>>>>> clocks and currently these clocks are not used yet.
>>>>>>
>>>>>> So will just remove init parent from driver and when these clocks
>>>>>> are used device tree can be updated in corresponding consumer node
>>>>>> with these properties.
>>>>>>
>>>>> How about default ON/OFF init state for the clocks? I see
>>>>> assigned-clock properties for parent and rate only.
>>>>>
>>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>>
>>>>> Peter/Thierry, What was the reason we enable clk_out_1 right from the
>>>>> clock registration?
>>>>>
>>>> clk_out_1 is for audio and its not required to be enabled during the
>>>> boot and audio driver can enable/disable it.
>>>>
>>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>>> enable/disable during power up/down sequence and technically as per
>>>> design we dont need to have it always on right from the boot.
>>>>
>>>> So can remove out clocks init states from driver once thierry also
>>>> agree on this.
>>>>
>>> Hi Dmitry,
>>>
>>> Looking at audio driver, it doesn't take care of mclk which is from
>>> clk_out_1 and expects mclk to be always on.
>>>
>>> So probably we should have this init state enables in pmc driver for
>>> 32Khz and clk_out's to not break existing functionality.
>> Hello Sowjanya,
>>
>> IIUC, it's a bug in the device-trees and sound's MCLK actually should be
>> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the case,
>> then the device-trees need to be fixed.
>
> OK, will have this in v3

Actually if we change mclk to use clk_out_1, then it will break with old 
device trees.

Currently clk_out_1 parent is set to extern1 as init state by the clock 
driver and device tree for sound node is using extern1 as mclk works and 
extern1 itself has enable and disable. But yes implementation wise, its 
incorrect as mclk should really be clk_out_1.

Now, with moving clk_out_1 to tegra PMC, pmc is the clock provider and 
if we now change the device tree to use CLK_OUT_1 as mclk then it will 
break old device tree.

>
>>> Regarding using assigned-clock properties for init parent and removing
>>> init parent from driver, it also needs consumer node in device tree to
>>> be updated to specify assigned-clock properties for default/init 
>>> parent.
>>>
>>> This breaks device tree ABI as prior Tegra210 supports audio driver.
>> So it's the sound node which should have had the assigned clocks in
>> device-tree in order to define route for the audio MCLK clock from CaR
>> to PMC.
>>
>> Given that the audio clocks configuration is the same for all of the
>> currently supported boards, I think it will be better to remove the
>> entire audio clocks initialization from the clk drivers and move it all
>> to the audio driver. It could be something like this:
>>
>> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
>>               struct device *dev)
>> {
>>     ...
>>
>>     if (!of_find_property(dev->of_node, "assigned-clock-parents", 
>> NULL) &&
>>         tegra_get_chip_id() > TEGRA20) {
>>         clk_extern1 = clk_get(dev, "extern1");
>>         ...
>>         clk_set_parent(clk_extern1, clk_pll_a_out0);
>>         ...
>>         clk_put(data->clk_cdev1);
>>
>>         data->clk_cdev1 = clk_out_1;
>>     }
>>     ...
>>
>> So now the old device-trees will cointinue to work and new could have
>> the assigned-clocks and set MCLK to CLK_OUT_1.
>>
>> [snip]
>
> Will update clk-tegra, pmc and audio driver to move init state 
> configuration for extern1 and clk_out_1 into audio driver and will use 
> assigned clock properties in device tree.
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 20:08                           ` Sowjanya Komatineni
@ 2019-12-04 20:28                             ` Dmitry Osipenko
  2019-12-04 20:33                               ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-12-04 20:28 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

04.12.2019 23:08, Sowjanya Komatineni пишет:
> 
> On 12/4/19 8:02 AM, Sowjanya Komatineni wrote:
>>
>> On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
>>> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>>>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>>> driver using
>>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>>> address
>>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>>> happens
>>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>>> from the
>>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>>> not be
>>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>>>>> provider
>>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>>>>> clocks
>>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>>>>> programming
>>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>      drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>>      1 file changed, 330 insertions(+)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>> b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>>>        #include <linux/arm-smccc.h>
>>>>>>>>>>>>>>      #include <linux/clk.h>
>>>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>>>      #include <linux/clk/tegra.h>
>>>>>>>>>>>>>>      #include <linux/debugfs.h>
>>>>>>>>>>>>>>      #include <linux/delay.h>
>>>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>>>      #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>>>      #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>>>        #define PMC_CNTRL            0x0
>>>>>>>>>>>>>>      #define  PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR
>>>>>>>>>>>>>> polarity */
>>>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>>>      #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>>>      #define PMC_SW_WAKE2_STATUS 0x16c
>>>>>>>>>>>>>>      +#define PMC_CLK_OUT_CNTRL 0x1a8
>>>>>>>>>>>>>>      #define PMC_SENSOR_CTRL 0x1b0
>>>>>>>>>>>>>>      #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>>>      #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>>>      #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>>>      +struct pmc_clk_mux {
>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>      struct tegra_powergate {
>>>>>>>>>>>>>>          struct generic_pm_domain genpd;
>>>>>>>>>>>>>>          struct tegra_pmc *pmc;
>>>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>>>           */
>>>>>>>>>>>>>>          const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>>>          unsigned int num_wake_events;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>>>      };
>>>>>>>>>>>>>>        static const char * const tegra186_reset_sources[] = {
>>>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>>>          return NOTIFY_OK;
>>>>>>>>>>>>>>      }
>>>>>>>>>>>>>>      +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return val;
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8
>>>>>>>>>>>>>> index)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char *
>>>>>>>>>>>>>> const
>>>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>>>> : 0;
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>>>> + data->parents,
>>>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>> + data->mux_shift, 3);
>>>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> + clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>>>> + data->mux_name,
>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>> + data->gate_shift);
>>>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> + clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>>>> + __clk_get_name(clkmux));
>>>>>>>>>>>>>> +        }
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>>>>>> device-tree? Please see "Assigned clock parents and rates" in the
>>>>>>>>> doc.
>>>>>>>>>
>>>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>>>> true).
>>>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>>>> based on assigned parents and clock rates.
>>>>>>>>
>>>>>>>> This need device tree to specify assigned clock parent properties.
>>>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>>>
>>>>>>> assigned-clock properties should be set in consumer node of these
>>>>>>> clocks and currently these clocks are not used yet.
>>>>>>>
>>>>>>> So will just remove init parent from driver and when these clocks
>>>>>>> are used device tree can be updated in corresponding consumer node
>>>>>>> with these properties.
>>>>>>>
>>>>>> How about default ON/OFF init state for the clocks? I see
>>>>>> assigned-clock properties for parent and rate only.
>>>>>>
>>>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>>>
>>>>>> Peter/Thierry, What was the reason we enable clk_out_1 right from the
>>>>>> clock registration?
>>>>>>
>>>>> clk_out_1 is for audio and its not required to be enabled during the
>>>>> boot and audio driver can enable/disable it.
>>>>>
>>>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>>>> enable/disable during power up/down sequence and technically as per
>>>>> design we dont need to have it always on right from the boot.
>>>>>
>>>>> So can remove out clocks init states from driver once thierry also
>>>>> agree on this.
>>>>>
>>>> Hi Dmitry,
>>>>
>>>> Looking at audio driver, it doesn't take care of mclk which is from
>>>> clk_out_1 and expects mclk to be always on.
>>>>
>>>> So probably we should have this init state enables in pmc driver for
>>>> 32Khz and clk_out's to not break existing functionality.
>>> Hello Sowjanya,
>>>
>>> IIUC, it's a bug in the device-trees and sound's MCLK actually should be
>>> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the case,
>>> then the device-trees need to be fixed.
>>
>> OK, will have this in v3
> 
> Actually if we change mclk to use clk_out_1, then it will break with old
> device trees.
> 
> Currently clk_out_1 parent is set to extern1 as init state by the clock
> driver and device tree for sound node is using extern1 as mclk works and
> extern1 itself has enable and disable. But yes implementation wise, its
> incorrect as mclk should really be clk_out_1.
> 
> Now, with moving clk_out_1 to tegra PMC, pmc is the clock provider and
> if we now change the device tree to use CLK_OUT_1 as mclk then it will
> break old device tree.

There souldn't be any problem with enabling CLK_OUT_1 by the audio
driver itself (in the code) if an old device-tree is detected.

	clk_out_1 = clk_get(dev, "clk_out_1");
	clk_set_parent(clk_out_1, clk_extern1);
	...
	data->clk_cdev1 = clk_out_1;

Maybe it will be even better to compare clocks for detection of an older DT:

	if (tegra_get_chip_id() > TEGRA20 &&
	    clk_is_match(data->clk_cdev1, clk_extern1)) {
	...

>>>> Regarding using assigned-clock properties for init parent and removing
>>>> init parent from driver, it also needs consumer node in device tree to
>>>> be updated to specify assigned-clock properties for default/init
>>>> parent.
>>>>
>>>> This breaks device tree ABI as prior Tegra210 supports audio driver.
>>> So it's the sound node which should have had the assigned clocks in
>>> device-tree in order to define route for the audio MCLK clock from CaR
>>> to PMC.
>>>
>>> Given that the audio clocks configuration is the same for all of the
>>> currently supported boards, I think it will be better to remove the
>>> entire audio clocks initialization from the clk drivers and move it all
>>> to the audio driver. It could be something like this:
>>>
>>> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
>>>               struct device *dev)
>>> {
>>>     ...
>>>
>>>     if (!of_find_property(dev->of_node, "assigned-clock-parents",
>>> NULL) &&
>>>         tegra_get_chip_id() > TEGRA20) {
>>>         clk_extern1 = clk_get(dev, "extern1");
>>>         ...
>>>         clk_set_parent(clk_extern1, clk_pll_a_out0);
>>>         ...
>>>         clk_put(data->clk_cdev1);
>>>
>>>         data->clk_cdev1 = clk_out_1;
>>>     }
>>>     ...
>>>
>>> So now the old device-trees will cointinue to work and new could have
>>> the assigned-clocks and set MCLK to CLK_OUT_1.
>>>
>>> [snip]
>>
>> Will update clk-tegra, pmc and audio driver to move init state
>> configuration for extern1 and clk_out_1 into audio driver and will use
>> assigned clock properties in device tree.
>>


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 20:28                             ` Dmitry Osipenko
@ 2019-12-04 20:33                               ` Sowjanya Komatineni
  2019-12-04 21:12                                 ` Dmitry Osipenko
  0 siblings, 1 reply; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-04 20:33 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/4/19 12:28 PM, Dmitry Osipenko wrote:
> 04.12.2019 23:08, Sowjanya Komatineni пишет:
>> On 12/4/19 8:02 AM, Sowjanya Komatineni wrote:
>>> On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
>>>> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>>>>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>>>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>>>> driver using
>>>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>>>> address
>>>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>>>> happens
>>>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>>>> from the
>>>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>>>> not be
>>>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>>>>>> provider
>>>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>>>>>> clocks
>>>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>>>>>> programming
>>>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>       drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>>>       1 file changed, 330 insertions(+)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>> b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>>>>         #include <linux/arm-smccc.h>
>>>>>>>>>>>>>>>       #include <linux/clk.h>
>>>>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>>>>       #include <linux/clk/tegra.h>
>>>>>>>>>>>>>>>       #include <linux/debugfs.h>
>>>>>>>>>>>>>>>       #include <linux/delay.h>
>>>>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>>>>       #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>>>>       #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>>>>       #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>>>>         #define PMC_CNTRL            0x0
>>>>>>>>>>>>>>>       #define  PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR
>>>>>>>>>>>>>>> polarity */
>>>>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>>>>       #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>>>>       #define PMC_SW_WAKE2_STATUS 0x16c
>>>>>>>>>>>>>>>       +#define PMC_CLK_OUT_CNTRL 0x1a8
>>>>>>>>>>>>>>>       #define PMC_SENSOR_CTRL 0x1b0
>>>>>>>>>>>>>>>       #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>>>>       #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>>>>       #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>>>>       #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>>>>       +struct pmc_clk_mux {
>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>       struct tegra_powergate {
>>>>>>>>>>>>>>>           struct generic_pm_domain genpd;
>>>>>>>>>>>>>>>           struct tegra_pmc *pmc;
>>>>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>>>>            */
>>>>>>>>>>>>>>>           const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>>>>           unsigned int num_wake_events;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>>>>       };
>>>>>>>>>>>>>>>         static const char * const tegra186_reset_sources[] = {
>>>>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>>>>>       }
>>>>>>>>>>>>>>>       +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return val;
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8
>>>>>>>>>>>>>>> index)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char *
>>>>>>>>>>>>>>> const
>>>>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>>>>> : 0;
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int state)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
>>>>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        clkmux = tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>>>>> + data->parents,
>>>>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>> + data->mux_shift, 3);
>>>>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> + clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>>>>> + data->mux_name,
>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>> + data->gate_shift);
>>>>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> + clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>>>>> + __clk_get_name(clkmux));
>>>>>>>>>>>>>>> +        }
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>>>>> Couldn't the default parent be defined using "assigned clock" in a
>>>>>>>>>> device-tree? Please see "Assigned clock parents and rates" in the
>>>>>>>>>> doc.
>>>>>>>>>>
>>>>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>>>>> true).
>>>>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>>>>> based on assigned parents and clock rates.
>>>>>>>>>
>>>>>>>>> This need device tree to specify assigned clock parent properties.
>>>>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>>>>
>>>>>>>> assigned-clock properties should be set in consumer node of these
>>>>>>>> clocks and currently these clocks are not used yet.
>>>>>>>>
>>>>>>>> So will just remove init parent from driver and when these clocks
>>>>>>>> are used device tree can be updated in corresponding consumer node
>>>>>>>> with these properties.
>>>>>>>>
>>>>>>> How about default ON/OFF init state for the clocks? I see
>>>>>>> assigned-clock properties for parent and rate only.
>>>>>>>
>>>>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>>>>
>>>>>>> Peter/Thierry, What was the reason we enable clk_out_1 right from the
>>>>>>> clock registration?
>>>>>>>
>>>>>> clk_out_1 is for audio and its not required to be enabled during the
>>>>>> boot and audio driver can enable/disable it.
>>>>>>
>>>>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>>>>> enable/disable during power up/down sequence and technically as per
>>>>>> design we dont need to have it always on right from the boot.
>>>>>>
>>>>>> So can remove out clocks init states from driver once thierry also
>>>>>> agree on this.
>>>>>>
>>>>> Hi Dmitry,
>>>>>
>>>>> Looking at audio driver, it doesn't take care of mclk which is from
>>>>> clk_out_1 and expects mclk to be always on.
>>>>>
>>>>> So probably we should have this init state enables in pmc driver for
>>>>> 32Khz and clk_out's to not break existing functionality.
>>>> Hello Sowjanya,
>>>>
>>>> IIUC, it's a bug in the device-trees and sound's MCLK actually should be
>>>> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the case,
>>>> then the device-trees need to be fixed.
>>> OK, will have this in v3
>> Actually if we change mclk to use clk_out_1, then it will break with old
>> device trees.
>>
>> Currently clk_out_1 parent is set to extern1 as init state by the clock
>> driver and device tree for sound node is using extern1 as mclk works and
>> extern1 itself has enable and disable. But yes implementation wise, its
>> incorrect as mclk should really be clk_out_1.
>>
>> Now, with moving clk_out_1 to tegra PMC, pmc is the clock provider and
>> if we now change the device tree to use CLK_OUT_1 as mclk then it will
>> break old device tree.
> There souldn't be any problem with enabling CLK_OUT_1 by the audio
> driver itself (in the code) if an old device-tree is detected.
>
> 	clk_out_1 = clk_get(dev, "clk_out_1");
> 	clk_set_parent(clk_out_1, clk_extern1);
> 	...
> 	data->clk_cdev1 = clk_out_1;
>
> Maybe it will be even better to compare clocks for detection of an older DT:
>
> 	if (tegra_get_chip_id() > TEGRA20 &&
> 	    clk_is_match(data->clk_cdev1, clk_extern1)) {
> 	...
>
we can do parent init in audio driver which is not an issue.

But I was saying we can keep extern1 as mclk in device tree instead of 
changing to clk_out_1 from pmc as it will break old device tree becasue 
we moved clk_out_1 from clock driver to pmc driver.

once we do init parent in audio driver, we still can use extern1 as mclk 
in device tree.

mclk -> clk_out_1 -> extern1 -> plla_out0 -> plla

with init of clk_out_1 parent to extern1, mclk can use extern1 handle 
for rate/enable/disable clk operations

>>>>> Regarding using assigned-clock properties for init parent and removing
>>>>> init parent from driver, it also needs consumer node in device tree to
>>>>> be updated to specify assigned-clock properties for default/init
>>>>> parent.
>>>>>
>>>>> This breaks device tree ABI as prior Tegra210 supports audio driver.
>>>> So it's the sound node which should have had the assigned clocks in
>>>> device-tree in order to define route for the audio MCLK clock from CaR
>>>> to PMC.
>>>>
>>>> Given that the audio clocks configuration is the same for all of the
>>>> currently supported boards, I think it will be better to remove the
>>>> entire audio clocks initialization from the clk drivers and move it all
>>>> to the audio driver. It could be something like this:
>>>>
>>>> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
>>>>                struct device *dev)
>>>> {
>>>>      ...
>>>>
>>>>      if (!of_find_property(dev->of_node, "assigned-clock-parents",
>>>> NULL) &&
>>>>          tegra_get_chip_id() > TEGRA20) {
>>>>          clk_extern1 = clk_get(dev, "extern1");
>>>>          ...
>>>>          clk_set_parent(clk_extern1, clk_pll_a_out0);
>>>>          ...
>>>>          clk_put(data->clk_cdev1);
>>>>
>>>>          data->clk_cdev1 = clk_out_1;
>>>>      }
>>>>      ...
>>>>
>>>> So now the old device-trees will cointinue to work and new could have
>>>> the assigned-clocks and set MCLK to CLK_OUT_1.
>>>>
>>>> [snip]
>>> Will update clk-tegra, pmc and audio driver to move init state
>>> configuration for extern1 and clk_out_1 into audio driver and will use
>>> assigned clock properties in device tree.
>>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 20:33                               ` Sowjanya Komatineni
@ 2019-12-04 21:12                                 ` Dmitry Osipenko
  2019-12-04 21:26                                   ` Sowjanya Komatineni
  0 siblings, 1 reply; 44+ messages in thread
From: Dmitry Osipenko @ 2019-12-04 21:12 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mperttunen,
	gregkh, sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel

04.12.2019 23:33, Sowjanya Komatineni пишет:
> 
> On 12/4/19 12:28 PM, Dmitry Osipenko wrote:
>> 04.12.2019 23:08, Sowjanya Komatineni пишет:
>>> On 12/4/19 8:02 AM, Sowjanya Komatineni wrote:
>>>> On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
>>>>> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>>>>>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>>>>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>>>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>>>>> driver using
>>>>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>>>>> address
>>>>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>>>>> happens
>>>>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>>>>> from the
>>>>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>>>>> not be
>>>>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a
>>>>>>>>>>>>>>>> clock
>>>>>>>>>>>>>>>> provider
>>>>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for
>>>>>>>>>>>>>>>> these
>>>>>>>>>>>>>>>> clocks
>>>>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports
>>>>>>>>>>>>>>>> PMC
>>>>>>>>>>>>>>>> programming
>>>>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>       drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>>>>       1 file changed, 330 insertions(+)
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>> b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>>>>>         #include <linux/arm-smccc.h>
>>>>>>>>>>>>>>>>       #include <linux/clk.h>
>>>>>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>>>>>       #include <linux/clk/tegra.h>
>>>>>>>>>>>>>>>>       #include <linux/debugfs.h>
>>>>>>>>>>>>>>>>       #include <linux/delay.h>
>>>>>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>>>>>       #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>>>>>       #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>>>>>       #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>>>>>         #define PMC_CNTRL            0x0
>>>>>>>>>>>>>>>>       #define  PMC_CNTRL_INTR_POLARITY BIT(17) /*
>>>>>>>>>>>>>>>> inverts INTR
>>>>>>>>>>>>>>>> polarity */
>>>>>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>>>>>       #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>>>>>       #define PMC_SW_WAKE2_STATUS 0x16c
>>>>>>>>>>>>>>>>       +#define PMC_CLK_OUT_CNTRL 0x1a8
>>>>>>>>>>>>>>>>       #define PMC_SENSOR_CTRL 0x1b0
>>>>>>>>>>>>>>>>       #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>>>>>       #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>>>>>       #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>>>>>       #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>>>>>       +struct pmc_clk_mux {
>>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>       struct tegra_powergate {
>>>>>>>>>>>>>>>>           struct generic_pm_domain genpd;
>>>>>>>>>>>>>>>>           struct tegra_pmc *pmc;
>>>>>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>>>>>            */
>>>>>>>>>>>>>>>>           const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>>>>>           unsigned int num_wake_events;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>>>>>       };
>>>>>>>>>>>>>>>>         static const char * const
>>>>>>>>>>>>>>>> tegra186_reset_sources[] = {
>>>>>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>>>>>>       }
>>>>>>>>>>>>>>>>       +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return val;
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8
>>>>>>>>>>>>>>>> index)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char *
>>>>>>>>>>>>>>>> const
>>>>>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>>>>>> : 0;
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int
>>>>>>>>>>>>>>>> state)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc
>>>>>>>>>>>>>>>> *pmc,
>>>>>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        clkmux =
>>>>>>>>>>>>>>>> tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>>>>>> + data->parents,
>>>>>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>>> + data->mux_shift, 3);
>>>>>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> + clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>>>>>> + data->mux_name,
>>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>>> + data->gate_shift);
>>>>>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> + clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>>>>>> + __clk_get_name(clkmux));
>>>>>>>>>>>>>>>> +        }
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>>>>>> Couldn't the default parent be defined using "assigned clock"
>>>>>>>>>>> in a
>>>>>>>>>>> device-tree? Please see "Assigned clock parents and rates" in
>>>>>>>>>>> the
>>>>>>>>>>> doc.
>>>>>>>>>>>
>>>>>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>>>>>> true).
>>>>>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>>>>>> based on assigned parents and clock rates.
>>>>>>>>>>
>>>>>>>>>> This need device tree to specify assigned clock parent
>>>>>>>>>> properties.
>>>>>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>>>>>
>>>>>>>>> assigned-clock properties should be set in consumer node of these
>>>>>>>>> clocks and currently these clocks are not used yet.
>>>>>>>>>
>>>>>>>>> So will just remove init parent from driver and when these clocks
>>>>>>>>> are used device tree can be updated in corresponding consumer node
>>>>>>>>> with these properties.
>>>>>>>>>
>>>>>>>> How about default ON/OFF init state for the clocks? I see
>>>>>>>> assigned-clock properties for parent and rate only.
>>>>>>>>
>>>>>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>>>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>>>>>
>>>>>>>> Peter/Thierry, What was the reason we enable clk_out_1 right
>>>>>>>> from the
>>>>>>>> clock registration?
>>>>>>>>
>>>>>>> clk_out_1 is for audio and its not required to be enabled during the
>>>>>>> boot and audio driver can enable/disable it.
>>>>>>>
>>>>>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>>>>>> enable/disable during power up/down sequence and technically as per
>>>>>>> design we dont need to have it always on right from the boot.
>>>>>>>
>>>>>>> So can remove out clocks init states from driver once thierry also
>>>>>>> agree on this.
>>>>>>>
>>>>>> Hi Dmitry,
>>>>>>
>>>>>> Looking at audio driver, it doesn't take care of mclk which is from
>>>>>> clk_out_1 and expects mclk to be always on.
>>>>>>
>>>>>> So probably we should have this init state enables in pmc driver for
>>>>>> 32Khz and clk_out's to not break existing functionality.
>>>>> Hello Sowjanya,
>>>>>
>>>>> IIUC, it's a bug in the device-trees and sound's MCLK actually
>>>>> should be
>>>>> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the
>>>>> case,
>>>>> then the device-trees need to be fixed.
>>>> OK, will have this in v3
>>> Actually if we change mclk to use clk_out_1, then it will break with old
>>> device trees.
>>>
>>> Currently clk_out_1 parent is set to extern1 as init state by the clock
>>> driver and device tree for sound node is using extern1 as mclk works and
>>> extern1 itself has enable and disable. But yes implementation wise, its
>>> incorrect as mclk should really be clk_out_1.
>>>
>>> Now, with moving clk_out_1 to tegra PMC, pmc is the clock provider and
>>> if we now change the device tree to use CLK_OUT_1 as mclk then it will
>>> break old device tree.
>> There souldn't be any problem with enabling CLK_OUT_1 by the audio
>> driver itself (in the code) if an old device-tree is detected.
>>
>>     clk_out_1 = clk_get(dev, "clk_out_1");
>>     clk_set_parent(clk_out_1, clk_extern1);
>>     ...
>>     data->clk_cdev1 = clk_out_1;
>>
>> Maybe it will be even better to compare clocks for detection of an
>> older DT:
>>
>>     if (tegra_get_chip_id() > TEGRA20 &&
>>         clk_is_match(data->clk_cdev1, clk_extern1)) {
>>     ...
>>
> we can do parent init in audio driver which is not an issue.
> 
> But I was saying we can keep extern1 as mclk in device tree instead of
> changing to clk_out_1 from pmc as it will break old device tree becasue
> we moved clk_out_1 from clock driver to pmc driver.
> 
> once we do init parent in audio driver, we still can use extern1 as mclk
> in device tree.
> 
> mclk -> clk_out_1 -> extern1 -> plla_out0 -> plla
> 
> with init of clk_out_1 parent to extern1, mclk can use extern1 handle
> for rate/enable/disable clk operations

It should be okay to fallback to extern1 for a backwards compatibility
of the new DT with older kernels.

@@ -192,8 +192,14 @@ int tegra_asoc_utils_init(struct
tegra_asoc_utils_data *data,
        data->clk_cdev1 = clk_get(dev, "mclk");
        if (IS_ERR(data->clk_cdev1)) {
                dev_err(data->dev, "Can't retrieve clk cdev1\n");
-               ret = PTR_ERR(data->clk_cdev1);
-               goto err_put_pll_a_out0;
+
+               data->clk_cdev1 = clk_get_sys("clk_out_1", "extern1");
+               if (IS_ERR(data->clk_cdev1)) {
+                       ret = PTR_ERR(data->clk_cdev1);
+                       goto err_put_pll_a_out0;
+               }
+
+               dev_err(data->dev, "Falling back to extern1\n");
        }

        ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);

This change should be a standalone patch and it should be requsted for
backporting into stable kernels.

>>>>>> Regarding using assigned-clock properties for init parent and
>>>>>> removing
>>>>>> init parent from driver, it also needs consumer node in device
>>>>>> tree to
>>>>>> be updated to specify assigned-clock properties for default/init
>>>>>> parent.
>>>>>>
>>>>>> This breaks device tree ABI as prior Tegra210 supports audio driver.
>>>>> So it's the sound node which should have had the assigned clocks in
>>>>> device-tree in order to define route for the audio MCLK clock from CaR
>>>>> to PMC.
>>>>>
>>>>> Given that the audio clocks configuration is the same for all of the
>>>>> currently supported boards, I think it will be better to remove the
>>>>> entire audio clocks initialization from the clk drivers and move it
>>>>> all
>>>>> to the audio driver. It could be something like this:
>>>>>
>>>>> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
>>>>>                struct device *dev)
>>>>> {
>>>>>      ...
>>>>>
>>>>>      if (!of_find_property(dev->of_node, "assigned-clock-parents",
>>>>> NULL) &&
>>>>>          tegra_get_chip_id() > TEGRA20) {
>>>>>          clk_extern1 = clk_get(dev, "extern1");
>>>>>          ...
>>>>>          clk_set_parent(clk_extern1, clk_pll_a_out0);
>>>>>          ...
>>>>>          clk_put(data->clk_cdev1);
>>>>>
>>>>>          data->clk_cdev1 = clk_out_1;
>>>>>      }
>>>>>      ...
>>>>>
>>>>> So now the old device-trees will cointinue to work and new could have
>>>>> the assigned-clocks and set MCLK to CLK_OUT_1.
>>>>>
>>>>> [snip]
>>>> Will update clk-tegra, pmc and audio driver to move init state
>>>> configuration for extern1 and clk_out_1 into audio driver and will use
>>>> assigned clock properties in device tree.
>>>>


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver
  2019-12-04 21:12                                 ` Dmitry Osipenko
@ 2019-12-04 21:26                                   ` Sowjanya Komatineni
  0 siblings, 0 replies; 44+ messages in thread
From: Sowjanya Komatineni @ 2019-12-04 21:26 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, mperttunen, gregkh,
	sboyd, tglx, robh+dt, mark.rutland
  Cc: allison, pdeschrijver, pgaikwad, mturquette, horms+renesas,
	Jisheng.Zhang, krzk, arnd, spujar, josephl, vidyas,
	daniel.lezcano, mmaddireddy, markz, devicetree, linux-clk,
	linux-tegra, linux-kernel


On 12/4/19 1:12 PM, Dmitry Osipenko wrote:
> 04.12.2019 23:33, Sowjanya Komatineni пишет:
>> On 12/4/19 12:28 PM, Dmitry Osipenko wrote:
>>> 04.12.2019 23:08, Sowjanya Komatineni пишет:
>>>> On 12/4/19 8:02 AM, Sowjanya Komatineni wrote:
>>>>> On 12/4/19 5:39 AM, Dmitry Osipenko wrote:
>>>>>> 03.12.2019 19:45, Sowjanya Komatineni пишет:
>>>>>>> On 12/2/19 4:07 PM, Sowjanya Komatineni wrote:
>>>>>>>> On 12/2/19 3:14 PM, Sowjanya Komatineni wrote:
>>>>>>>>> On 12/2/19 3:10 PM, Sowjanya Komatineni wrote:
>>>>>>>>>> On 12/2/19 2:58 PM, Sowjanya Komatineni wrote:
>>>>>>>>>>> On 12/2/19 1:50 PM, Dmitry Osipenko wrote:
>>>>>>>>>>>> 02.12.2019 23:09, Sowjanya Komatineni пишет:
>>>>>>>>>>>>> On 11/28/19 5:25 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>>> 28.11.2019 01:57, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>>> On 11/27/19 7:14 AM, Dmitry Osipenko wrote:
>>>>>>>>>>>>>>>> 27.11.2019 07:59, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>>>>>> clk_out_3 with
>>>>>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>>>>>> driver using
>>>>>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>>>>>> address
>>>>>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>>>>>> happens
>>>>>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>>>>>> from the
>>>>>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>>>>>> not be
>>>>>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a
>>>>>>>>>>>>>>>>> clock
>>>>>>>>>>>>>>>>> provider
>>>>>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for
>>>>>>>>>>>>>>>>> these
>>>>>>>>>>>>>>>>> clocks
>>>>>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports
>>>>>>>>>>>>>>>>> PMC
>>>>>>>>>>>>>>>>> programming
>>>>>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>        drivers/soc/tegra/pmc.c | 330
>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>>>>>        1 file changed, 330 insertions(+)
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> diff --git a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>>> b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>>> index ea0e11a09c12..a353f6d0a832 100644
>>>>>>>>>>>>>>>>> --- a/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>>> +++ b/drivers/soc/tegra/pmc.c
>>>>>>>>>>>>>>>>> @@ -13,6 +13,9 @@
>>>>>>>>>>>>>>>>>          #include <linux/arm-smccc.h>
>>>>>>>>>>>>>>>>>        #include <linux/clk.h>
>>>>>>>>>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>>>>>>>>>> +#include <linux/clkdev.h>
>>>>>>>>>>>>>>>>> +#include <linux/clk/clk-conf.h>
>>>>>>>>>>>>>>>>>        #include <linux/clk/tegra.h>
>>>>>>>>>>>>>>>>>        #include <linux/debugfs.h>
>>>>>>>>>>>>>>>>>        #include <linux/delay.h>
>>>>>>>>>>>>>>>>> @@ -48,6 +51,7 @@
>>>>>>>>>>>>>>>>>        #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
>>>>>>>>>>>>>>>>>        #include <dt-bindings/gpio/tegra186-gpio.h>
>>>>>>>>>>>>>>>>>        #include <dt-bindings/gpio/tegra194-gpio.h>
>>>>>>>>>>>>>>>>> +#include <dt-bindings/soc/tegra-pmc.h>
>>>>>>>>>>>>>>>>>          #define PMC_CNTRL            0x0
>>>>>>>>>>>>>>>>>        #define  PMC_CNTRL_INTR_POLARITY BIT(17) /*
>>>>>>>>>>>>>>>>> inverts INTR
>>>>>>>>>>>>>>>>> polarity */
>>>>>>>>>>>>>>>>> @@ -100,6 +104,7 @@
>>>>>>>>>>>>>>>>>        #define PMC_WAKE2_STATUS        0x168
>>>>>>>>>>>>>>>>>        #define PMC_SW_WAKE2_STATUS 0x16c
>>>>>>>>>>>>>>>>>        +#define PMC_CLK_OUT_CNTRL 0x1a8
>>>>>>>>>>>>>>>>>        #define PMC_SENSOR_CTRL 0x1b0
>>>>>>>>>>>>>>>>>        #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
>>>>>>>>>>>>>>>>>        #define  PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
>>>>>>>>>>>>>>>>> @@ -155,6 +160,91 @@
>>>>>>>>>>>>>>>>>        #define  TEGRA_SMC_PMC_READ    0xaa
>>>>>>>>>>>>>>>>>        #define  TEGRA_SMC_PMC_WRITE    0xbb
>>>>>>>>>>>>>>>>>        +struct pmc_clk_mux {
>>>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>>>> +    u32        mask;
>>>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +#define to_pmc_clk_mux(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>>>> pmc_clk_mux, hw)
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +struct pmc_clk_gate {
>>>>>>>>>>>>>>>>> +    struct clk_hw    hw;
>>>>>>>>>>>>>>>>> +    unsigned long    offs;
>>>>>>>>>>>>>>>>> +    u32        shift;
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +#define to_pmc_clk_gate(_hw) container_of(_hw, struct
>>>>>>>>>>>>>>>>> pmc_clk_gate, hw)
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +struct pmc_clk_init_data {
>>>>>>>>>>>>>>>>> +    char *mux_name;
>>>>>>>>>>>>>>>>> +    char *gate_name;
>>>>>>>>>>>>>>>>> +    const char **parents;
>>>>>>>>>>>>>>>>> +    int num_parents;
>>>>>>>>>>>>>>>>> +    int mux_id;
>>>>>>>>>>>>>>>>> +    int gate_id;
>>>>>>>>>>>>>>>>> +    char *dev_name;
>>>>>>>>>>>>>>>>> +    u8 mux_shift;
>>>>>>>>>>>>>>>>> +    u8 gate_shift;
>>>>>>>>>>>>>>>>> +    u8 init_parent_index;
>>>>>>>>>>>>>>>>> +    int init_state;
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static const char *clk_out1_parents[] = { "clk_m",
>>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern1",
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static const char *clk_out2_parents[] = { "clk_m",
>>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern2",
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static const char *clk_out3_parents[] = { "clk_m",
>>>>>>>>>>>>>>>>> "clk_m_div2",
>>>>>>>>>>>>>>>>> +    "clk_m_div4", "extern3",
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static struct pmc_clk_init_data tegra_pmc_clks_data[] = {
>>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_1_mux",
>>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_1",
>>>>>>>>>>>>>>>>> +        .parents = clk_out1_parents,
>>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out1_parents),
>>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_1_MUX,
>>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_1,
>>>>>>>>>>>>>>>>> +        .dev_name = "extern1",
>>>>>>>>>>>>>>>>> +        .mux_shift = 6,
>>>>>>>>>>>>>>>>> +        .gate_shift = 2,
>>>>>>>>>>>>>>>>> +        .init_parent_index = 3,
>>>>>>>>>>>>>>>>> +        .init_state = 1,
>>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_2_mux",
>>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_2",
>>>>>>>>>>>>>>>>> +        .parents = clk_out2_parents,
>>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out2_parents),
>>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_2_MUX,
>>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_2,
>>>>>>>>>>>>>>>>> +        .dev_name = "extern2",
>>>>>>>>>>>>>>>>> +        .mux_shift = 14,
>>>>>>>>>>>>>>>>> +        .gate_shift = 10,
>>>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>>>>> +        .mux_name = "clk_out_3_mux",
>>>>>>>>>>>>>>>>> +        .gate_name = "clk_out_3",
>>>>>>>>>>>>>>>>> +        .parents = clk_out3_parents,
>>>>>>>>>>>>>>>>> +        .num_parents = ARRAY_SIZE(clk_out3_parents),
>>>>>>>>>>>>>>>>> +        .mux_id = TEGRA_PMC_CLK_OUT_3_MUX,
>>>>>>>>>>>>>>>>> +        .gate_id = TEGRA_PMC_CLK_OUT_3,
>>>>>>>>>>>>>>>>> +        .dev_name = "extern3",
>>>>>>>>>>>>>>>>> +        .mux_shift = 22,
>>>>>>>>>>>>>>>>> +        .gate_shift = 18,
>>>>>>>>>>>>>>>>> +        .init_parent_index = 0,
>>>>>>>>>>>>>>>>> +        .init_state = 0,
>>>>>>>>>>>>>>>>> +    },
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>        struct tegra_powergate {
>>>>>>>>>>>>>>>>>            struct generic_pm_domain genpd;
>>>>>>>>>>>>>>>>>            struct tegra_pmc *pmc;
>>>>>>>>>>>>>>>>> @@ -254,6 +344,9 @@ struct tegra_pmc_soc {
>>>>>>>>>>>>>>>>>             */
>>>>>>>>>>>>>>>>>            const struct tegra_wake_event *wake_events;
>>>>>>>>>>>>>>>>>            unsigned int num_wake_events;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    struct pmc_clk_init_data *pmc_clks_data;
>>>>>>>>>>>>>>>>> +    unsigned int num_pmc_clks;
>>>>>>>>>>>>>>>>>        };
>>>>>>>>>>>>>>>>>          static const char * const
>>>>>>>>>>>>>>>>> tegra186_reset_sources[] = {
>>>>>>>>>>>>>>>>> @@ -2163,6 +2256,228 @@ static int
>>>>>>>>>>>>>>>>> tegra_pmc_clk_notify_cb(struct
>>>>>>>>>>>>>>>>> notifier_block *nb,
>>>>>>>>>>>>>>>>>            return NOTIFY_OK;
>>>>>>>>>>>>>>>>>        }
>>>>>>>>>>>>>>>>>        +static void pmc_clk_fence_udelay(u32 offset)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    tegra_pmc_readl(pmc, offset);
>>>>>>>>>>>>>>>>> +    /* pmc clk propagation delay 2 us */
>>>>>>>>>>>>>>>>> +    udelay(2);
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static u8 pmc_clk_mux_get_parent(struct clk_hw *hw)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>>>> +    int num_parents = clk_hw_get_num_parents(hw);
>>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs) >> mux->shift;
>>>>>>>>>>>>>>>>> +    val &= mux->mask;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    if (val >= num_parents)
>>>>>>>>>>>>>>>>> +        return -EINVAL;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return val;
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static int pmc_clk_mux_set_parent(struct clk_hw *hw, u8
>>>>>>>>>>>>>>>>> index)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux = to_pmc_clk_mux(hw);
>>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, mux->offs);
>>>>>>>>>>>>>>>>> +    val &= ~(mux->mask << mux->shift);
>>>>>>>>>>>>>>>>> +    val |= index << mux->shift;
>>>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, mux->offs);
>>>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(mux->offs);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_mux_ops = {
>>>>>>>>>>>>>>>>> +    .get_parent = pmc_clk_mux_get_parent,
>>>>>>>>>>>>>>>>> +    .set_parent = pmc_clk_mux_set_parent,
>>>>>>>>>>>>>>>>> +    .determine_rate = __clk_mux_determine_rate,
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>>>> +tegra_pmc_clk_mux_register(const char *name, const char *
>>>>>>>>>>>>>>>>> const
>>>>>>>>>>>>>>>>> *parent_names,
>>>>>>>>>>>>>>>>> +               int num_parents, unsigned long flags,
>>>>>>>>>>>>>>>>> +               unsigned long offset, u32 shift, u32 mask)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>>>> +    struct pmc_clk_mux *mux;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    mux = kzalloc(sizeof(*mux), GFP_KERNEL);
>>>>>>>>>>>>>>>>> +    if (!mux)
>>>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_mux_ops;
>>>>>>>>>>>>>>>>> +    init.parent_names = parent_names;
>>>>>>>>>>>>>>>>> +    init.num_parents = num_parents;
>>>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    mux->hw.init = &init;
>>>>>>>>>>>>>>>>> +    mux->offs = offset;
>>>>>>>>>>>>>>>>> +    mux->mask = mask;
>>>>>>>>>>>>>>>>> +    mux->shift = shift;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return clk_register(NULL, &mux->hw);
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static int pmc_clk_is_enabled(struct clk_hw *hw)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return tegra_pmc_readl(pmc, gate->offs) &
>>>>>>>>>>>>>>>>> BIT(gate->shift) ? 1
>>>>>>>>>>>>>>>>> : 0;
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static void pmc_clk_set_state(struct clk_hw *hw, int
>>>>>>>>>>>>>>>>> state)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate = to_pmc_clk_gate(hw);
>>>>>>>>>>>>>>>>> +    u32 val;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    val = tegra_pmc_readl(pmc, gate->offs);
>>>>>>>>>>>>>>>>> +    val = state ? (val | BIT(gate->shift)) : (val &
>>>>>>>>>>>>>>>>> ~BIT(gate->shift));
>>>>>>>>>>>>>>>>> +    tegra_pmc_writel(pmc, val, gate->offs);
>>>>>>>>>>>>>>>>> +    pmc_clk_fence_udelay(gate->offs);
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static int pmc_clk_enable(struct clk_hw *hw)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 1);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return 0;
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static void pmc_clk_disable(struct clk_hw *hw)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    pmc_clk_set_state(hw, 0);
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>>>>>> +    .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>>>>>> +    .enable = pmc_clk_enable,
>>>>>>>>>>>>>>>>> +    .disable = pmc_clk_disable,
>>>>>>>>>>>>>>>>> +};
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static struct clk *
>>>>>>>>>>>>>>>>> +tegra_pmc_clk_gate_register(const char *name, const char
>>>>>>>>>>>>>>>>> *parent_name,
>>>>>>>>>>>>>>>>> +                unsigned long flags, unsigned long offset,
>>>>>>>>>>>>>>>>> +                u32 shift)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct clk_init_data init;
>>>>>>>>>>>>>>>>> +    struct pmc_clk_gate *gate;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>>>>>>>>>>>>>>>>> +    if (!gate)
>>>>>>>>>>>>>>>>> +        return ERR_PTR(-ENOMEM);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    init.name = name;
>>>>>>>>>>>>>>>>> +    init.ops = &pmc_clk_gate_ops;
>>>>>>>>>>>>>>>>> +    init.parent_names = &parent_name;
>>>>>>>>>>>>>>>>> +    init.num_parents = 1;
>>>>>>>>>>>>>>>>> +    init.flags = flags;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    gate->hw.init = &init;
>>>>>>>>>>>>>>>>> +    gate->offs = offset;
>>>>>>>>>>>>>>>>> +    gate->shift = shift;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    return clk_register(NULL, &gate->hw);
>>>>>>>>>>>>>>>>> +}
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +static void tegra_pmc_clock_register(struct tegra_pmc
>>>>>>>>>>>>>>>>> *pmc,
>>>>>>>>>>>>>>>>> +                     struct device_node *np)
>>>>>>>>>>>>>>>>> +{
>>>>>>>>>>>>>>>>> +    struct clk *clkmux, *clk, *parent;
>>>>>>>>>>>>>>>>> +    struct clk_onecell_data *clk_data;
>>>>>>>>>>>>>>>>> +    unsigned int num_clks;
>>>>>>>>>>>>>>>>> +    int i, ret;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    /* each pmc clock output has a mux and a gate */
>>>>>>>>>>>>>>>>> +    num_clks = pmc->soc->num_pmc_clks * 2;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    if (!num_clks)
>>>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>>>>>>>>>>>>>>>>> +    if (!clk_data)
>>>>>>>>>>>>>>>>> +        return;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    clk_data->clks = kcalloc(TEGRA_PMC_CLK_MAX,
>>>>>>>>>>>>>>>>> sizeof(*clk_data->clks),
>>>>>>>>>>>>>>>>> +                 GFP_KERNEL);
>>>>>>>>>>>>>>>>> +    if (!clk_data->clks)
>>>>>>>>>>>>>>>>> +        goto free_clkdata;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    clk_data->clk_num = num_clks;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +    for (i = 0; i < pmc->soc->num_pmc_clks; i++) {
>>>>>>>>>>>>>>>>> +        struct pmc_clk_init_data *data;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        data = pmc->soc->pmc_clks_data + i;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        clkmux =
>>>>>>>>>>>>>>>>> tegra_pmc_clk_mux_register(data->mux_name,
>>>>>>>>>>>>>>>>> + data->parents,
>>>>>>>>>>>>>>>>> + data->num_parents,
>>>>>>>>>>>>>>>>> + CLK_SET_RATE_NO_REPARENT |
>>>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>>>> + data->mux_shift, 3);
>>>>>>>>>>>>>>>>> +        if (IS_ERR(clkmux))
>>>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> + clk_data->clks[data->mux_id] = clkmux;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        clk = tegra_pmc_clk_gate_register(data->gate_name,
>>>>>>>>>>>>>>>>> + data->mux_name,
>>>>>>>>>>>>>>>>> + CLK_SET_RATE_PARENT,
>>>>>>>>>>>>>>>>> + PMC_CLK_OUT_CNTRL,
>>>>>>>>>>>>>>>>> + data->gate_shift);
>>>>>>>>>>>>>>>>> +        if (IS_ERR(clk))
>>>>>>>>>>>>>>>>> +            goto free_clks;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> + clk_data->clks[data->gate_id] = clk;
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        ret = clk_set_parent(clk, clkmux);
>>>>>>>>>>>>>>>>> +        if (ret < 0) {
>>>>>>>>>>>>>>>>> +            pr_err("failed to set parent of %s to %s\n",
>>>>>>>>>>>>>>>>> +                   __func__, __clk_get_name(clk),
>>>>>>>>>>>>>>>>> + __clk_get_name(clkmux));
>>>>>>>>>>>>>>>>> +        }
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        clk_register_clkdev(clk, data->dev_name,
>>>>>>>>>>>>>>>>> data->gate_name);
>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>> +        /* configure initial clock parent and state */
>>>>>>>>>>>>>>>>> +        parent = clk_get_sys(data->gate_name,
>>>>>>>>>>>>>>>>> + data->parents[data->init_parent_index]);
>>>>>>>>>>>> Couldn't the default parent be defined using "assigned clock"
>>>>>>>>>>>> in a
>>>>>>>>>>>> device-tree? Please see "Assigned clock parents and rates" in
>>>>>>>>>>>> the
>>>>>>>>>>>> doc.
>>>>>>>>>>>>
>>>>>>>>>>>> https://www.kernel.org/doc/Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Then you could simply use of_clk_set_defaults(pmc->dev->of_node,
>>>>>>>>>>>> true).
>>>>>>>>>>> Yes, of_clk_add_provider() does of_clk_set_defaults which sets
>>>>>>>>>>> based on assigned parents and clock rates.
>>>>>>>>>>>
>>>>>>>>>>> This need device tree to specify assigned clock parent
>>>>>>>>>>> properties.
>>>>>>>>>>> Will update device tree and remove init parent from the driver.
>>>>>>>>>>>
>>>>>>>>>> assigned-clock properties should be set in consumer node of these
>>>>>>>>>> clocks and currently these clocks are not used yet.
>>>>>>>>>>
>>>>>>>>>> So will just remove init parent from driver and when these clocks
>>>>>>>>>> are used device tree can be updated in corresponding consumer node
>>>>>>>>>> with these properties.
>>>>>>>>>>
>>>>>>>>> How about default ON/OFF init state for the clocks? I see
>>>>>>>>> assigned-clock properties for parent and rate only.
>>>>>>>>>
>>>>>>>>> But based on existing clock-tegra-pmc driver, I see clk_out_1 is
>>>>>>>>> default enabled with extern1 parent for T30 thru T210 platforms.
>>>>>>>>>
>>>>>>>>> Peter/Thierry, What was the reason we enable clk_out_1 right
>>>>>>>>> from the
>>>>>>>>> clock registration?
>>>>>>>>>
>>>>>>>> clk_out_1 is for audio and its not required to be enabled during the
>>>>>>>> boot and audio driver can enable/disable it.
>>>>>>>>
>>>>>>>> same with blink 32khz which is used for WIFI. WIFI driver can
>>>>>>>> enable/disable during power up/down sequence and technically as per
>>>>>>>> design we dont need to have it always on right from the boot.
>>>>>>>>
>>>>>>>> So can remove out clocks init states from driver once thierry also
>>>>>>>> agree on this.
>>>>>>>>
>>>>>>> Hi Dmitry,
>>>>>>>
>>>>>>> Looking at audio driver, it doesn't take care of mclk which is from
>>>>>>> clk_out_1 and expects mclk to be always on.
>>>>>>>
>>>>>>> So probably we should have this init state enables in pmc driver for
>>>>>>> 32Khz and clk_out's to not break existing functionality.
>>>>>> Hello Sowjanya,
>>>>>>
>>>>>> IIUC, it's a bug in the device-trees and sound's MCLK actually
>>>>>> should be
>>>>>> set to CLK_OUT_1 of PMC instead of CaR's EXTPERIPH1. If that's the
>>>>>> case,
>>>>>> then the device-trees need to be fixed.
>>>>> OK, will have this in v3
>>>> Actually if we change mclk to use clk_out_1, then it will break with old
>>>> device trees.
>>>>
>>>> Currently clk_out_1 parent is set to extern1 as init state by the clock
>>>> driver and device tree for sound node is using extern1 as mclk works and
>>>> extern1 itself has enable and disable. But yes implementation wise, its
>>>> incorrect as mclk should really be clk_out_1.
>>>>
>>>> Now, with moving clk_out_1 to tegra PMC, pmc is the clock provider and
>>>> if we now change the device tree to use CLK_OUT_1 as mclk then it will
>>>> break old device tree.
>>> There souldn't be any problem with enabling CLK_OUT_1 by the audio
>>> driver itself (in the code) if an old device-tree is detected.
>>>
>>>      clk_out_1 = clk_get(dev, "clk_out_1");
>>>      clk_set_parent(clk_out_1, clk_extern1);
>>>      ...
>>>      data->clk_cdev1 = clk_out_1;
>>>
>>> Maybe it will be even better to compare clocks for detection of an
>>> older DT:
>>>
>>>      if (tegra_get_chip_id() > TEGRA20 &&
>>>          clk_is_match(data->clk_cdev1, clk_extern1)) {
>>>      ...
>>>
>> we can do parent init in audio driver which is not an issue.
>>
>> But I was saying we can keep extern1 as mclk in device tree instead of
>> changing to clk_out_1 from pmc as it will break old device tree becasue
>> we moved clk_out_1 from clock driver to pmc driver.
>>
>> once we do init parent in audio driver, we still can use extern1 as mclk
>> in device tree.
>>
>> mclk -> clk_out_1 -> extern1 -> plla_out0 -> plla
>>
>> with init of clk_out_1 parent to extern1, mclk can use extern1 handle
>> for rate/enable/disable clk operations
> It should be okay to fallback to extern1 for a backwards compatibility
> of the new DT with older kernels.
>
> @@ -192,8 +192,14 @@ int tegra_asoc_utils_init(struct
> tegra_asoc_utils_data *data,
>          data->clk_cdev1 = clk_get(dev, "mclk");
>          if (IS_ERR(data->clk_cdev1)) {
>                  dev_err(data->dev, "Can't retrieve clk cdev1\n");
> -               ret = PTR_ERR(data->clk_cdev1);
> -               goto err_put_pll_a_out0;
> +
> +               data->clk_cdev1 = clk_get_sys("clk_out_1", "extern1");
> +               if (IS_ERR(data->clk_cdev1)) {
> +                       ret = PTR_ERR(data->clk_cdev1);
> +                       goto err_put_pll_a_out0;
> +               }
> +
> +               dev_err(data->dev, "Falling back to extern1\n");
>          }
>
>          ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
>
> This change should be a standalone patch and it should be requsted for
> backporting into stable kernels.

ok will add fallback. yes will request this patch for backporting.

Thanks dmitry.

>>>>>>> Regarding using assigned-clock properties for init parent and
>>>>>>> removing
>>>>>>> init parent from driver, it also needs consumer node in device
>>>>>>> tree to
>>>>>>> be updated to specify assigned-clock properties for default/init
>>>>>>> parent.
>>>>>>>
>>>>>>> This breaks device tree ABI as prior Tegra210 supports audio driver.
>>>>>> So it's the sound node which should have had the assigned clocks in
>>>>>> device-tree in order to define route for the audio MCLK clock from CaR
>>>>>> to PMC.
>>>>>>
>>>>>> Given that the audio clocks configuration is the same for all of the
>>>>>> currently supported boards, I think it will be better to remove the
>>>>>> entire audio clocks initialization from the clk drivers and move it
>>>>>> all
>>>>>> to the audio driver. It could be something like this:
>>>>>>
>>>>>> int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
>>>>>>                 struct device *dev)
>>>>>> {
>>>>>>       ...
>>>>>>
>>>>>>       if (!of_find_property(dev->of_node, "assigned-clock-parents",
>>>>>> NULL) &&
>>>>>>           tegra_get_chip_id() > TEGRA20) {
>>>>>>           clk_extern1 = clk_get(dev, "extern1");
>>>>>>           ...
>>>>>>           clk_set_parent(clk_extern1, clk_pll_a_out0);
>>>>>>           ...
>>>>>>           clk_put(data->clk_cdev1);
>>>>>>
>>>>>>           data->clk_cdev1 = clk_out_1;
>>>>>>       }
>>>>>>       ...
>>>>>>
>>>>>> So now the old device-trees will cointinue to work and new could have
>>>>>> the assigned-clocks and set MCLK to CLK_OUT_1.
>>>>>>
>>>>>> [snip]
>>>>> Will update clk-tegra, pmc and audio driver to move init state
>>>>> configuration for extern1 and clk_out_1 into audio driver and will use
>>>>> assigned clock properties in device tree.
>>>>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, back to index

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-27  4:59 [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 01/11] dt-bindings: soc: tegra-pmc: Add Tegra PMC clock ids Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 02/11] soc: tegra: Add Tegra PMC clock registrations into PMC driver Sowjanya Komatineni
2019-11-27 14:32   ` Dmitry Osipenko
2019-11-27 14:32   ` Dmitry Osipenko
2019-11-27 15:14   ` Dmitry Osipenko
2019-11-27 22:57     ` Sowjanya Komatineni
2019-11-28 13:25       ` Dmitry Osipenko
2019-12-02 20:09         ` Sowjanya Komatineni
2019-12-02 21:50           ` Dmitry Osipenko
2019-12-02 22:58             ` Sowjanya Komatineni
2019-12-02 23:10               ` Sowjanya Komatineni
2019-12-02 23:14                 ` Sowjanya Komatineni
2019-12-03  0:07                   ` Sowjanya Komatineni
2019-12-03 16:45                     ` Sowjanya Komatineni
2019-12-04 13:39                       ` Dmitry Osipenko
2019-12-04 16:02                         ` Sowjanya Komatineni
2019-12-04 20:08                           ` Sowjanya Komatineni
2019-12-04 20:28                             ` Dmitry Osipenko
2019-12-04 20:33                               ` Sowjanya Komatineni
2019-12-04 21:12                                 ` Dmitry Osipenko
2019-12-04 21:26                                   ` Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 03/11] dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 04/11] soc: pmc: Add blink output clock registration to Tegra PMC Sowjanya Komatineni
2019-11-28 13:07   ` Dmitry Osipenko
2019-11-27  4:59 ` [PATCH v2 05/11] clk: tegra: Remove tegra_pmc_clk_init along with clk ids Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 06/11] dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings Sowjanya Komatineni
2019-11-27 14:32   ` Dmitry Osipenko
2019-11-27 17:06     ` Sowjanya Komatineni
2019-11-28 12:18     ` Thierry Reding
2019-11-28 13:07       ` Dmitry Osipenko
2019-11-27  4:59 ` [PATCH v2 07/11] arm: tegra: Add clock-cells property to Tegra PMC Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 08/11] arm64: tegra: Add clock-cells property to Tegra pmc Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 09/11] dt-bindings: Add Tegra PMC clock configuration bindings Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 10/11] arm64: tegra: smaug: Change clk_out_2 provider from tegra_car to pmc Sowjanya Komatineni
2019-11-27  4:59 ` [PATCH v2 11/11] ASoC: nau8825: change Tegra " Sowjanya Komatineni
2019-11-27 14:31 ` [PATCH v2 00/11] Move PMC clocks into Tegra PMC driver Dmitry Osipenko
2019-11-27 17:02   ` Sowjanya Komatineni
2019-11-27 21:38     ` Sowjanya Komatineni
2019-11-28 13:06       ` Dmitry Osipenko
2019-12-02 17:09         ` Dmitry Osipenko
2019-12-02 18:47         ` Sowjanya Komatineni
2019-11-28 12:26   ` Thierry Reding
2019-11-28 13:10     ` Dmitry Osipenko

Linux-Devicetree Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-devicetree/0 linux-devicetree/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-devicetree linux-devicetree/ https://lore.kernel.org/linux-devicetree \
		devicetree@vger.kernel.org
	public-inbox-index linux-devicetree

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-devicetree


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git