Devicetree
 help / color / mirror / Atom feed
* [PATCH v9 01/15] clk: tegra20/30: Add custom EMC clock implementation
From: Dmitry Osipenko @ 2019-07-30 16:56 UTC (permalink / raw)
  To: Rob Herring, Michael Turquette, Joseph Lo, Thierry Reding,
	Jonathan Hunter, Peter De Schrijver, Prashant Gaikwad,
	Stephen Boyd
  Cc: devicetree, linux-clk, linux-tegra, linux-kernel
In-Reply-To: <20190730165618.10122-1-digetx@gmail.com>

A proper External Memory Controller clock rounding and parent selection
functionality is required by the EMC drivers, it is not available using
the generic clock implementation because only the Memory Controller driver
is aware of what clock rates are actually available for a particular
device. EMC drivers will have to register a Tegra-specific CLK-API
callback which will perform rounding of a requested rate. EMC clock users
won't be able to request EMC clock by getting -EPROBE_DEFER until EMC
driver is probed and the callback is set up.

The functionality is somewhat similar to the clk-emc.c which serves
Tegra124+ SoCs. The later HW generations support more parent clock sources
and the HW configuration / integration with the EMC drivers differs a tad
from the older gens, hence it's not really worth to try to squash
everything into a single source file.

Acked-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/Makefile          |   2 +
 drivers/clk/tegra/clk-tegra20-emc.c | 293 ++++++++++++++++++++++++++++
 drivers/clk/tegra/clk-tegra20.c     |  55 ++----
 drivers/clk/tegra/clk-tegra30.c     |  38 ++--
 drivers/clk/tegra/clk.h             |   3 +
 include/linux/clk/tegra.h           |  11 ++
 6 files changed, 350 insertions(+), 52 deletions(-)
 create mode 100644 drivers/clk/tegra/clk-tegra20-emc.c

diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index 4812e45c2214..df966ca06788 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -17,7 +17,9 @@ obj-y					+= clk-tegra-fixed.o
 obj-y					+= clk-tegra-super-gen4.o
 obj-$(CONFIG_TEGRA_CLK_EMC)		+= clk-emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += clk-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= clk-tegra20-emc.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)         += clk-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= clk-tegra20-emc.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= clk-tegra114.o
 obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= clk-tegra124.o
 obj-$(CONFIG_TEGRA_CLK_DFLL)		+= clk-tegra124-dfll-fcpu.o
diff --git a/drivers/clk/tegra/clk-tegra20-emc.c b/drivers/clk/tegra/clk-tegra20-emc.c
new file mode 100644
index 000000000000..03bf0009a33c
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra20-emc.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on drivers/clk/tegra/clk-emc.c
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author: Dmitry Osipenko <digetx@gmail.com>
+ * Copyright (C) 2019 GRATE-DRIVER project
+ */
+
+#define pr_fmt(fmt)	"tegra-emc-clk: " fmt
+
+#include <linux/bits.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/tegra.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK	GENMASK(7, 0)
+#define CLK_SOURCE_EMC_2X_CLK_SRC_MASK		GENMASK(31, 30)
+#define CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT		30
+
+#define MC_EMC_SAME_FREQ	BIT(16)
+#define USE_PLLM_UD		BIT(29)
+
+#define EMC_SRC_PLL_M		0
+#define EMC_SRC_PLL_C		1
+#define EMC_SRC_PLL_P		2
+#define EMC_SRC_CLK_M		3
+
+static const char * const emc_parent_clk_names[] = {
+	"pll_m", "pll_c", "pll_p", "clk_m",
+};
+
+struct tegra_clk_emc {
+	struct clk_hw hw;
+	void __iomem *reg;
+	bool mc_same_freq;
+	bool want_low_jitter;
+
+	tegra20_clk_emc_round_cb *round_cb;
+	void *cb_arg;
+};
+
+static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
+{
+	return container_of(hw, struct tegra_clk_emc, hw);
+}
+
+static unsigned long emc_recalc_rate(struct clk_hw *hw,
+				     unsigned long parent_rate)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+	u32 val, div;
+
+	val = readl_relaxed(emc->reg);
+	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
+
+	return DIV_ROUND_UP(parent_rate * 2, div + 2);
+}
+
+static u8 emc_get_parent(struct clk_hw *hw)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+
+	return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
+}
+
+static int emc_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+	u32 val, div;
+
+	val = readl_relaxed(emc->reg);
+	val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
+	val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
+
+	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
+
+	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
+		val |= USE_PLLM_UD;
+	else
+		val &= ~USE_PLLM_UD;
+
+	if (emc->mc_same_freq)
+		val |= MC_EMC_SAME_FREQ;
+	else
+		val &= ~MC_EMC_SAME_FREQ;
+
+	writel_relaxed(val, emc->reg);
+
+	fence_udelay(1, emc->reg);
+
+	return 0;
+}
+
+static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long parent_rate)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+	unsigned int index;
+	u32 val, div;
+
+	div = div_frac_get(rate, parent_rate, 8, 1, 0);
+
+	val = readl_relaxed(emc->reg);
+	val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
+	val |= div;
+
+	index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
+
+	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
+		val |= USE_PLLM_UD;
+	else
+		val &= ~USE_PLLM_UD;
+
+	if (emc->mc_same_freq)
+		val |= MC_EMC_SAME_FREQ;
+	else
+		val &= ~MC_EMC_SAME_FREQ;
+
+	writel_relaxed(val, emc->reg);
+
+	fence_udelay(1, emc->reg);
+
+	return 0;
+}
+
+static int emc_set_rate_and_parent(struct clk_hw *hw,
+				   unsigned long rate,
+				   unsigned long parent_rate,
+				   u8 index)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+	u32 val, div;
+
+	div = div_frac_get(rate, parent_rate, 8, 1, 0);
+
+	val = readl_relaxed(emc->reg);
+
+	val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
+	val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
+
+	val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
+	val |= div;
+
+	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
+		val |= USE_PLLM_UD;
+	else
+		val &= ~USE_PLLM_UD;
+
+	if (emc->mc_same_freq)
+		val |= MC_EMC_SAME_FREQ;
+	else
+		val &= ~MC_EMC_SAME_FREQ;
+
+	writel_relaxed(val, emc->reg);
+
+	fence_udelay(1, emc->reg);
+
+	return 0;
+}
+
+static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
+	struct clk_hw *parent_hw;
+	unsigned long divided_rate;
+	unsigned long parent_rate;
+	unsigned int i;
+	long emc_rate;
+	int div;
+
+	emc_rate = emc->round_cb(req->rate, req->min_rate, req->max_rate,
+				 emc->cb_arg);
+	if (emc_rate < 0)
+		return emc_rate;
+
+	for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
+		parent_hw = clk_hw_get_parent_by_index(hw, i);
+
+		if (req->best_parent_hw == parent_hw)
+			parent_rate = req->best_parent_rate;
+		else
+			parent_rate = clk_hw_get_rate(parent_hw);
+
+		if (emc_rate > parent_rate)
+			continue;
+
+		div = div_frac_get(emc_rate, parent_rate, 8, 1, 0);
+		divided_rate = DIV_ROUND_UP(parent_rate * 2, div + 2);
+
+		if (divided_rate != emc_rate)
+			continue;
+
+		req->best_parent_rate = parent_rate;
+		req->best_parent_hw = parent_hw;
+		req->rate = emc_rate;
+		break;
+	}
+
+	if (i == ARRAY_SIZE(emc_parent_clk_names)) {
+		pr_err_once("can't find parent for rate %lu emc_rate %lu\n",
+			    req->rate, emc_rate);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct clk_ops tegra_clk_emc_ops = {
+	.recalc_rate = emc_recalc_rate,
+	.get_parent = emc_get_parent,
+	.set_parent = emc_set_parent,
+	.set_rate = emc_set_rate,
+	.set_rate_and_parent = emc_set_rate_and_parent,
+	.determine_rate = emc_determine_rate,
+};
+
+void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
+					void *cb_arg)
+{
+	struct clk *clk = __clk_lookup("emc");
+	struct tegra_clk_emc *emc;
+	struct clk_hw *hw;
+
+	if (clk) {
+		hw = __clk_get_hw(clk);
+		emc = to_tegra_clk_emc(hw);
+
+		emc->round_cb = round_cb;
+		emc->cb_arg = cb_arg;
+	}
+}
+
+bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
+{
+	return to_tegra_clk_emc(emc_hw)->round_cb != NULL;
+}
+
+struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter)
+{
+	struct tegra_clk_emc *emc;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	emc = kzalloc(sizeof(*emc), GFP_KERNEL);
+	if (!emc)
+		return NULL;
+
+	/*
+	 * EMC stands for External Memory Controller.
+	 *
+	 * We don't want EMC clock to be disabled ever by gating its
+	 * parent and whatnot because system is busted immediately in that
+	 * case, hence the clock is marked as critical.
+	 */
+	init.name = "emc";
+	init.ops = &tegra_clk_emc_ops;
+	init.flags = CLK_IS_CRITICAL;
+	init.parent_names = emc_parent_clk_names;
+	init.num_parents = ARRAY_SIZE(emc_parent_clk_names);
+
+	emc->reg = ioaddr;
+	emc->hw.init = &init;
+	emc->want_low_jitter = low_jitter;
+
+	clk = clk_register(NULL, &emc->hw);
+	if (IS_ERR(clk)) {
+		kfree(emc);
+		return NULL;
+	}
+
+	return clk;
+}
+
+int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
+{
+	struct tegra_clk_emc *emc;
+	struct clk_hw *hw;
+
+	if (!emc_clk)
+		return -EINVAL;
+
+	hw = __clk_get_hw(emc_clk);
+	emc = to_tegra_clk_emc(hw);
+	emc->mc_same_freq = same;
+
+	return 0;
+}
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index bcd871134f45..cceefbd67a3b 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -130,8 +130,6 @@ static struct cpu_clk_suspend_context {
 static void __iomem *clk_base;
 static void __iomem *pmc_base;
 
-static DEFINE_SPINLOCK(emc_lock);
-
 #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,	\
 			    _clk_num, _gate_flags, _clk_id)	\
 	TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset,	\
@@ -760,7 +758,6 @@ static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
 static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
 static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c",
 					 "clk_m" };
-static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
 
 static struct tegra_periph_init_data tegra_periph_clk_list[] = {
 	TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents,     CLK_SOURCE_I2S1,   11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1),
@@ -787,41 +784,6 @@ static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
 	TEGRA_INIT_DATA_NODIV("disp2",	mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26,  0, TEGRA20_CLK_DISP2),
 };
 
-static void __init tegra20_emc_clk_init(void)
-{
-	const u32 use_pllm_ud = BIT(29);
-	struct clk *clk;
-	u32 emc_reg;
-
-	clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-			       ARRAY_SIZE(mux_pllmcp_clkm),
-			       CLK_SET_RATE_NO_REPARENT,
-			       clk_base + CLK_SOURCE_EMC,
-			       30, 2, 0, &emc_lock);
-
-	clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
-				    &emc_lock);
-	clks[TEGRA20_CLK_MC] = clk;
-
-	/* un-divided pll_m_out0 is currently unsupported */
-	emc_reg = readl_relaxed(clk_base + CLK_SOURCE_EMC);
-	if (emc_reg & use_pllm_ud) {
-		pr_err("%s: un-divided PllM_out0 used as clock source\n",
-		       __func__);
-		return;
-	}
-
-	/*
-	 * Note that 'emc_mux' source and 'emc' rate shouldn't be changed at
-	 * the same time due to a HW bug, this won't happen because we're
-	 * defining 'emc_mux' and 'emc' as distinct clocks.
-	 */
-	clk = tegra_clk_register_divider("emc", "emc_mux",
-				clk_base + CLK_SOURCE_EMC, CLK_IS_CRITICAL,
-				TEGRA_DIVIDER_INT, 0, 8, 1, &emc_lock);
-	clks[TEGRA20_CLK_EMC] = clk;
-}
-
 static void __init tegra20_periph_clk_init(void)
 {
 	struct tegra_periph_init_data *data;
@@ -835,7 +797,13 @@ static void __init tegra20_periph_clk_init(void)
 	clks[TEGRA20_CLK_AC97] = clk;
 
 	/* emc */
-	tegra20_emc_clk_init();
+	clk = tegra20_clk_register_emc(clk_base + CLK_SOURCE_EMC, false);
+
+	clks[TEGRA20_CLK_EMC] = clk;
+
+	clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
+				    NULL);
+	clks[TEGRA20_CLK_MC] = clk;
 
 	/* dsi */
 	clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0,
@@ -1115,6 +1083,8 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
 	if (IS_ERR(clk))
 		return clk;
 
+	hw = __clk_get_hw(clk);
+
 	/*
 	 * Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent
 	 * clock is created by the pinctrl driver. It is possible for clk user
@@ -1124,13 +1094,16 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
 	 */
 	if (clkspec->args[0] == TEGRA20_CLK_CDEV1 ||
 	    clkspec->args[0] == TEGRA20_CLK_CDEV2) {
-		hw = __clk_get_hw(clk);
-
 		parent_hw = clk_hw_get_parent(hw);
 		if (!parent_hw)
 			return ERR_PTR(-EPROBE_DEFER);
 	}
 
+	if (clkspec->args[0] == TEGRA20_CLK_EMC) {
+		if (!tegra20_clk_emc_driver_available(hw))
+			return ERR_PTR(-EPROBE_DEFER);
+	}
+
 	return clk;
 }
 
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 7b4c6a488527..95b0e4a16dd5 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -151,7 +151,6 @@ static unsigned long input_freq;
 
 static DEFINE_SPINLOCK(cml_lock);
 static DEFINE_SPINLOCK(pll_d_lock);
-static DEFINE_SPINLOCK(emc_lock);
 
 #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,	\
 			    _clk_num, _gate_flags, _clk_id)	\
@@ -808,7 +807,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true },
 	[tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true },
 	[tegra_clk_cec] = { .dt_id = TEGRA30_CLK_CEC, .present = true },
-	[tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = true },
+	[tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = false },
 };
 
 static const char *pll_e_parents[] = { "pll_ref", "pll_p" };
@@ -995,7 +994,6 @@ static void __init tegra30_super_clk_init(void)
 static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p",
 					 "clk_m" };
 static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
-static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
 static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p",
 					   "clk_m" };
 static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" };
@@ -1044,14 +1042,12 @@ static void __init tegra30_periph_clk_init(void)
 	clks[TEGRA30_CLK_AFI] = clk;
 
 	/* emc */
-	clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-			       ARRAY_SIZE(mux_pllmcp_clkm),
-			       CLK_SET_RATE_NO_REPARENT,
-			       clk_base + CLK_SOURCE_EMC,
-			       30, 2, 0, &emc_lock);
+	clk = tegra20_clk_register_emc(clk_base + CLK_SOURCE_EMC, true);
+
+	clks[TEGRA30_CLK_EMC] = clk;
 
-	clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
-				    &emc_lock);
+	clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
+				    NULL);
 	clks[TEGRA30_CLK_MC] = clk;
 
 	/* cml0 */
@@ -1302,6 +1298,26 @@ static struct tegra_audio_clk_info tegra30_audio_plls[] = {
 	{ "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_p_out1" },
 };
 
+static struct clk *tegra30_clk_src_onecell_get(struct of_phandle_args *clkspec,
+					       void *data)
+{
+	struct clk_hw *hw;
+	struct clk *clk;
+
+	clk = of_clk_src_onecell_get(clkspec, data);
+	if (IS_ERR(clk))
+		return clk;
+
+	hw = __clk_get_hw(clk);
+
+	if (clkspec->args[0] == TEGRA30_CLK_EMC) {
+		if (!tegra20_clk_emc_driver_available(hw))
+			return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return clk;
+}
+
 static void __init tegra30_clock_init(struct device_node *np)
 {
 	struct device_node *node;
@@ -1345,7 +1361,7 @@ static void __init tegra30_clock_init(struct device_node *np)
 
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX);
 
-	tegra_add_of_provider(np, of_clk_src_onecell_get);
+	tegra_add_of_provider(np, tegra30_clk_src_onecell_get);
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
 	tegra_clk_apply_init_table = tegra30_clock_apply_init_table;
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index a4fbf55930aa..f81c10654aa9 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -842,4 +842,7 @@ int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
 		udelay(delay);		\
 	} while (0)
 
+bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw);
+struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter);
+
 #endif /* TEGRA_CLK_H */
diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h
index cf0f2cb5e109..2b1b35240074 100644
--- a/include/linux/clk/tegra.h
+++ b/include/linux/clk/tegra.h
@@ -132,4 +132,15 @@ extern void tegra210_put_utmipll_in_iddq(void);
 extern void tegra210_put_utmipll_out_iddq(void);
 extern int tegra210_clk_handle_mbist_war(unsigned int id);
 
+struct clk;
+
+typedef long (tegra20_clk_emc_round_cb)(unsigned long rate,
+					unsigned long min_rate,
+					unsigned long max_rate,
+					void *arg);
+
+void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
+					void *cb_arg);
+int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same);
+
 #endif /* __LINUX_CLK_TEGRA_H_ */
-- 
2.22.0

^ permalink raw reply related

* [PATCH v9 00/15] memory: tegra: Introduce Tegra30 EMC driver
From: Dmitry Osipenko @ 2019-07-30 16:56 UTC (permalink / raw)
  To: Rob Herring, Michael Turquette, Joseph Lo, Thierry Reding,
	Jonathan Hunter, Peter De Schrijver, Prashant Gaikwad,
	Stephen Boyd
  Cc: devicetree, linux-clk, linux-tegra, linux-kernel

Hello,

This series introduces driver for the External Memory Controller (EMC)
found on Tegra30 chips, it controls the external DRAM on the board. The
purpose of this driver is to program memory timing for external memory on
the EMC clock rate change. The driver was tested using the ACTMON devfreq
driver that performs memory frequency scaling based on memory-usage load.

Changelog:

v9: - Fixed memory corruption bug that was uncovered after introducing
      some extra optimizations to the devfreq driver that allows CPU
      to stay longer in the LP2 cpuidle state. The corruption is caused by
      a very late AUTO-REFRESH re-enabling due to a possible schedule on
      waiting for clk-change completion, the re-enabling is now a part of
      "EMC exec-after-clkchange" hardware sequence.

    - Added "type: object" to T124 MC YAML, that was missed in v8 by accident.

v8: - Added two new patches:

        memory: tegra20-emc: Increase handshake timeout
        memory: tegra20-emc: wait_for_completion_timeout() doesn't return error

      Turned out that memory-clk handshake may take much more time under
      some circumstances. The second patch is a minor cleanup. The same
      changes are also applied to the Terga30 EMC driver addition-patch.

      The pattern-properties of YAML bindings gained "type: object", for
      consistency.

v7: - Addressed review comments that were made by Rob Herring to v6 by
      removing old Terga30 Memory Controller binding once it's converted
      to YAML, by using explicit patterns for the sub-nodes and specifying
      min/max clock rates in the YAML.

    - Two patches that were added in v6 are removed from the series:

        clk: tegra20: emc: Add tegra20_clk_emc_on_pllp()
        ARM: tegra30: cpuidle: Don't enter LP2 on CPU0 when EMC runs off PLLP

      Because the problem with the PLLP is resolved now, turned out it was
      a bug in the CPU-suspend code.

    - The "Introduce Tegra30 EMC driver" patch got a fix for the "Same Freq"
      bit typo, it's a bit 27 and not 16.

v6: - Tegra124 Memory Controller binding factored out into standalone
      binding because it requires to specify MC_EMEM_ARB_MISC1 for EMEM
      programming, which is not required for Tegra30. This makes the
      upstream MC registers specification to match downstream exactly,
      easing porting of boards memory timings configuration to upstream.

    - Tegra30/124 Memory Controller binding converted to YAML.

    - Tegra30 External Memory Controller binding now is in YAML format.

    - Added workaround for hanging during LP2 when EMC runs off PLLP on
      Tegra30 in this new patches:

        clk: tegra20: emc: Add tegra20_clk_emc_on_pllp()
        ARM: tegra30: cpuidle: Don't enter LP2 on CPU0 when EMC runs off PLLP

    - Added info message to the Tegra20/30 EMC drivers, telling about
      RAM code and a number of available timings:

        memory: tegra20-emc: Print a brief info message about the timings

v5: - Addressed review comments that were made by Thierry Reding to v4 by
      adding appropriate copyrights to the source code headers and making
      Tegra30 EMC driver to use common Tegra20 CLK API directly instead
      of having a dummy-proxy functions specifically for Tegra30.

    - Addressed review comments that were made by Stephen Boyd to v4 by
      rewording commit message of the "Add custom EMC clock implementation"
      patch and adding clarifying comment (to that patch as well) which
      tells why EMC is a critical clock.

    - Added suspend-resume to Tegra30 EMC driver to error out if EMC driver
      is in a "bad state" as it will likely cause a hang on entering suspend.

    - Dropped patch "tegra20-emc: Replace clk_get_sys with devm_clk_get"
      because the replaced clocks are actually should be removed altogether
      in the "Drop setting EMC rate to max on probe" patch and that was
      missed by an accident.

    - Added "tegra20-emc: Pre-configure debug register" patch which ensures
      that inappropriate HW debug features are disabled at a probe time.
      The same change is also made in the "Introduce Tegra30 EMC driver"
      patch.

    - Added ACKs to the patches from Peter De Schrijver that he gave to v4
      since all of the v5 changes are actually very minor.

v4: - Addressed review comments that were made by Peter De Schrijver to v3
      by adding fence_udelay() after writes in the "Add custom EMC clock
      implementation" patch.

    - Added two new minor patches:

        memory: tegra: Ensure timing control debug features are disabled
        memory: tegra: Consolidate registers definition into one place

      The first one is needed to ensure that EMC driver will work
      properly regardless of hardware configuration left after boot.
      The second patch is just a minor code cleanup.

    - The "Introduce Tegra30 EMC driver" got also few very minor changes.
      Now every possible error case is handled, nothing is ignored.
      The EMC_DBG register is explicitly initialized during probe to be
      on the safe side.

v3: - Addressed review comments that were made by Stephen Boyd to v2 by
      adding explicit typing for the callback variable, by including
      "clk-provider.h" directly in the code and by dropping __clk_lookup
      usage where possible.

    - Added more patches into this series:

        memory: tegra20-emc: Drop setting EMC rate to max on probe
        memory: tegra20-emc: Adapt for clock driver changes
        memory: tegra20-emc: Include io.h instead of iopoll.h
        memory: tegra20-emc: Replace clk_get_sys with devm_clk_get

      Initially I was going to include these patches into other patchset,
      but changed my mind after rearranging things a tad. The "Adapt for
      clock driver changes" patch is directly related to the clock changes
      done in the first patch of this series, the rest are minor cleanups
      that are fine to include here as well.

    - Added some more words to the commit message of "Add binding for NVIDIA
      Tegra30 External Memory Controller" patch, clarifying why common DDR
      timing device-tree form isn't suitable for Tegra30.

    - The Tegra30 EMC driver now explicitly selects the registers access
      mode (EMC_DBG mux), not relying on the setting left from bootloader.

v2: - Added support for changing MC clock diver configuration based on
      Memory Controller (MC) configuration which is part of the memory
      timing.

    - Merged the "Add custom EMC clock implementation" patch into this
      series because the "Introduce Tegra30 EMC driver" patch directly
      depends on it. Please note that Tegra20 EMC driver will need to be
      adapted for the clock changes as well, I'll send out the Tegra20
      patches after this series will be applied because of some other
      dependencies (devfreq) and because the temporary breakage won't
      be critical (driver will just error out on probe).

    - EMC driver now performs MC configuration validation by checking
      that the number of MC / EMC timings matches and that the timings
      rate is the same.

    - EMC driver now supports timings that want to change the MC clock
      configuration.

    - Other minor prettifying changes of the code.

Dmitry Osipenko (15):
  clk: tegra20/30: Add custom EMC clock implementation
  memory: tegra20-emc: Drop setting EMC rate to max on probe
  memory: tegra20-emc: Adapt for clock driver changes
  memory: tegra20-emc: Include io.h instead of iopoll.h
  memory: tegra20-emc: Pre-configure debug register
  memory: tegra20-emc: Print a brief info message about the timings
  memory: tegra20-emc: Increase handshake timeout
  memory: tegra20-emc: wait_for_completion_timeout() doesn't return
    error
  dt-bindings: memory: tegra30: Convert to Tegra124 YAML
  dt-bindings: memory: Add binding for NVIDIA Tegra30 Memory Controller
  dt-bindings: memory: Add binding for NVIDIA Tegra30 External Memory
    Controller
  memory: tegra: Introduce Tegra30 EMC driver
  memory: tegra: Ensure timing control debug features are disabled
  memory: tegra: Consolidate registers definition into common header
  ARM: dts: tegra30: Add External Memory Controller node

 .../nvidia,tegra124-mc.yaml                   |  158 +++
 .../nvidia,tegra30-emc.yaml                   |  341 +++++
 .../memory-controllers/nvidia,tegra30-mc.txt  |  123 --
 .../memory-controllers/nvidia,tegra30-mc.yaml |  173 +++
 arch/arm/boot/dts/tegra30.dtsi                |    9 +
 drivers/clk/tegra/Makefile                    |    2 +
 drivers/clk/tegra/clk-tegra20-emc.c           |  293 ++++
 drivers/clk/tegra/clk-tegra20.c               |   55 +-
 drivers/clk/tegra/clk-tegra30.c               |   38 +-
 drivers/clk/tegra/clk.h                       |    3 +
 drivers/memory/tegra/Kconfig                  |   10 +
 drivers/memory/tegra/Makefile                 |    1 +
 drivers/memory/tegra/mc.c                     |   42 +-
 drivers/memory/tegra/mc.h                     |   74 +-
 drivers/memory/tegra/tegra124.c               |   20 -
 drivers/memory/tegra/tegra20-emc.c            |  134 +-
 drivers/memory/tegra/tegra30-emc.c            | 1229 +++++++++++++++++
 drivers/memory/tegra/tegra30.c                |   23 +
 include/linux/clk/tegra.h                     |   11 +
 include/soc/tegra/mc.h                        |    2 +-
 20 files changed, 2428 insertions(+), 313 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml
 create mode 100644 Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml
 delete mode 100644 Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt
 create mode 100644 Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml
 create mode 100644 drivers/clk/tegra/clk-tegra20-emc.c
 create mode 100644 drivers/memory/tegra/tegra30-emc.c

-- 
2.22.0

^ permalink raw reply

* Re: [PATCH net-next v4 0/4] enetc: Add mdio bus driver for the PCIe MDIO endpoint
From: David Miller @ 2019-07-30 16:53 UTC (permalink / raw)
  To: claudiu.manoil
  Cc: andrew, robh+dt, leoyang.li, alexandru.marginean, netdev,
	devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20190730.094436.855806617449032791.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Tue, 30 Jul 2019 09:44:36 -0700 (PDT)

> From: Claudiu Manoil <claudiu.manoil@nxp.com>
> Date: Tue, 30 Jul 2019 12:45:15 +0300
> 
>> First patch fixes a sparse issue and cleans up accessors to avoid
>> casting to __iomem.
>> Second patch just registers the PCIe endpoint device containing
>> the MDIO registers as a standalone MDIO bus driver, to allow
>> an alternative way to control the MDIO bus.  The same code used
>> by the ENETC ports (eth controllers) to manage MDIO via local
>> registers applies and is reused.
>> 
>> Bindings are provided for the new MDIO node, similarly to ENETC
>> port nodes bindings.
>> 
>> Last patch enables the ENETC port 1 and its RGMII PHY on the
>> LS1028A QDS board, where the MDIO muxing configuration relies
>> on the MDIO support provided in the first patch.
>  ...
> 
> Series applied, thank you.

Actually this doesn't compile, I had to revert:

In file included from ./include/linux/phy.h:20,
                 from ./include/linux/of_mdio.h:11,
                 from drivers/net/ethernet/freescale/enetc/enetc_mdio.c:5:
drivers/net/ethernet/freescale/enetc/enetc_mdio.c:284:26: error: ‘enetc_mdio_id_table’ undeclared here (not in a function); did you mean ‘enetc_pci_mdio_id_table’?
 MODULE_DEVICE_TABLE(pci, enetc_mdio_id_table);
                          ^~~~~~~~~~~~~~~~~~~
./include/linux/module.h:230:15: note: in definition of macro ‘MODULE_DEVICE_TABLE’
 extern typeof(name) __mod_##type##__##name##_device_table  \
               ^~~~
./include/linux/module.h:230:21: error: ‘__mod_pci__enetc_mdio_id_table_device_table’ aliased to undefined symbol ‘enetc_mdio_id_table’
 extern typeof(name) __mod_##type##__##name##_device_table  \
                     ^~~~~~
drivers/net/ethernet/freescale/enetc/enetc_mdio.c:284:1: note: in expansion of macro ‘MODULE_DEVICE_TABLE’
 MODULE_DEVICE_TABLE(pci, enetc_mdio_id_table);
 ^~~~~~~~~~~~~~~~~~~

^ permalink raw reply

* Re: [PATCH net-next v4 0/4] enetc: Add mdio bus driver for the PCIe MDIO endpoint
From: David Miller @ 2019-07-30 16:44 UTC (permalink / raw)
  To: claudiu.manoil
  Cc: andrew, robh+dt, leoyang.li, alexandru.marginean, netdev,
	devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <1564479919-18835-1-git-send-email-claudiu.manoil@nxp.com>

From: Claudiu Manoil <claudiu.manoil@nxp.com>
Date: Tue, 30 Jul 2019 12:45:15 +0300

> First patch fixes a sparse issue and cleans up accessors to avoid
> casting to __iomem.
> Second patch just registers the PCIe endpoint device containing
> the MDIO registers as a standalone MDIO bus driver, to allow
> an alternative way to control the MDIO bus.  The same code used
> by the ENETC ports (eth controllers) to manage MDIO via local
> registers applies and is reused.
> 
> Bindings are provided for the new MDIO node, similarly to ENETC
> port nodes bindings.
> 
> Last patch enables the ENETC port 1 and its RGMII PHY on the
> LS1028A QDS board, where the MDIO muxing configuration relies
> on the MDIO support provided in the first patch.
 ...

Series applied, thank you.

^ permalink raw reply

* Re: [PATCH v4 0/3] Introduce Bandwidth OPPs for interconnects
From: Sibi Sankar @ 2019-07-30 16:43 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Viresh Kumar, Georgi Djakov, Rob Herring, Mark Rutland,
	Viresh Kumar, Nishanth Menon, Stephen Boyd, Rafael J. Wysocki,
	Vincent Guittot, Sweeney, Sean, David Dai, adharmap,
	Rajendra Nayak, Bjorn Andersson, Evan Green, Android Kernel Team,
	Linux PM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <CAGETcx_BpJswxA4AGARogZ1xRJPqm=_zTOZq1xJ2vgx+DUYsqQ@mail.gmail.com>

On 7/30/19 11:23 AM, Saravana Kannan wrote:
> On Mon, Jul 29, 2019 at 10:28 PM Sibi Sankar <sibis@codeaurora.org> wrote:
>>
>> Hey Viresh,
>>
>> On 7/30/19 8:16 AM, Viresh Kumar wrote:
>>> On 29-07-19, 13:16, Saravana Kannan wrote:
>>>> Sibi might be working on doing that for the SDM845 CPUfreq driver.
>>>> Georgi could also change his GPU driver use case to use this BW OPP
>>>> table and required-opps.
>>>>
>>>> The problem is that people don't want to start using this until we
>>>> decide on the DT representation. So it's like a chicken and egg
>>>> situation.
>>>
>>> Yeah, I agree to that.
>>>
>>> @Georgi and @Sibi: This is your chance to speak up about the proposal
>>> from Saravana and if you find anything wrong with them. And specially
>>> that it is mostly about interconnects here, I would like to have an
>>> explicit Ack from Georgi on this.
>>>
>>> And if you guys are all okay about this then please at least commit
>>> that you will convert your stuff based on this in coming days.
>>
>> I've been using both Saravana's and Georgi's series for a while
>> now to scale DDR and L3 on SDM845. There is currently no consensus
>> as to where the votes are to be actuated from, hence couldn't post
>> anything out.
>>
>> DCVS based on Saravana's series + passive governor:
>> https://github.com/QuinAsura/linux/tree/lnext-072619-SK-series
> 
> Thanks Sibi! You might want to convert your patches so that until the
> passive governor is ready, you just look up the required opps and vote
> for BW directly from the cpufreq driver. Once devfreq governor is
> ready, you can switch to it.

Sure I'll do that.

> 
> -Saravana
> 
>>
>> DCVS based on Georgi's series: (I had already posted this out)
>> https://github.com/QuinAsura/linux/tree/lnext-072619-GJ-series
>>
>> --
>> Qualcomm Innovation Center, Inc.
>> Qualcomm Innovation Center, Inc, is a member of Code Aurora Forum,
>> a Linux Foundation Collaborative Project

-- 
Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc, is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 2/3] arm64: dts: qcom: pms405: remove reduandant properties
From: Amit Kucheria @ 2019-07-30 16:36 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Andy Gross, linux-arm-msm, Bjorn Andersson, Rob Herring,
	Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <20190725135150.9972-3-vkoul@kernel.org>

On Thu, Jul 25, 2019 at 7:23 PM Vinod Koul <vkoul@kernel.org> wrote:
>
> pms405@1 nodes specified unnecessary #address-cells/#size-cells but the
> subnodes dont have "ranges" or "reg" so remove it
>
> arch/arm64/boot/dts/qcom/pms405.dtsi:141.21-150.4: Warning (avoid_unnecessary_addr_size): /soc@0/spmi@200f000/pms405@1: unnecessary #address-cells/#size-cells without "ranges" or child "reg" property
>
> Signed-off-by: Vinod Koul <vkoul@kernel.org>

Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>

> ---
>  arch/arm64/boot/dts/qcom/pms405.dtsi | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/pms405.dtsi b/arch/arm64/boot/dts/qcom/pms405.dtsi
> index 3c10cf04d26e..32678f7ce90d 100644
> --- a/arch/arm64/boot/dts/qcom/pms405.dtsi
> +++ b/arch/arm64/boot/dts/qcom/pms405.dtsi
> @@ -141,8 +141,6 @@
>         pms405_1: pms405@1 {
>                 compatible = "qcom,spmi-pmic";
>                 reg = <0x1 SPMI_USID>;
> -               #address-cells = <1>;
> -               #size-cells = <0>;
>
>                 pms405_spmi_regulators: regulators {
>                         compatible = "qcom,pms405-regulators";
> --
> 2.20.1
>

^ permalink raw reply

* Re: [PATCH 3/3] arm64: dts: qcom: qcs404: remove unit name for thermal trip points
From: Amit Kucheria @ 2019-07-30 16:36 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Andy Gross, linux-arm-msm, Bjorn Andersson, Rob Herring,
	Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <20190725135150.9972-4-vkoul@kernel.org>

On Thu, Jul 25, 2019 at 7:23 PM Vinod Koul <vkoul@kernel.org> wrote:
>
> The thermal trip points have unit name but no reg property, so we can
> remove them
>
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1080.31-1084.7: Warning (unit_address_vs_reg): /thermal-zones/aoss-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1095.33-1099.7: Warning (unit_address_vs_reg): /thermal-zones/q6-hvx-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1110.32-1114.7: Warning (unit_address_vs_reg): /thermal-zones/lpass-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1125.31-1129.7: Warning (unit_address_vs_reg): /thermal-zones/wlan-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1140.34-1144.7: Warning (unit_address_vs_reg): /thermal-zones/cluster-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1145.34-1149.7: Warning (unit_address_vs_reg): /thermal-zones/cluster-thermal/trips/trip-point@1: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1174.31-1178.7: Warning (unit_address_vs_reg): /thermal-zones/cpu0-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1179.31-1183.7: Warning (unit_address_vs_reg): /thermal-zones/cpu0-thermal/trips/trip-point@1: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1208.31-1212.7: Warning (unit_address_vs_reg): /thermal-zones/cpu1-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1213.31-1217.7: Warning (unit_address_vs_reg): /thermal-zones/cpu1-thermal/trips/trip-point@1: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1242.31-1246.7: Warning (unit_address_vs_reg): /thermal-zones/cpu2-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1247.31-1251.7: Warning (unit_address_vs_reg): /thermal-zones/cpu2-thermal/trips/trip-point@1: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1276.31-1280.7: Warning (unit_address_vs_reg): /thermal-zones/cpu3-thermal/trips/trip-point@0: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1281.31-1285.7: Warning (unit_address_vs_reg): /thermal-zones/cpu3-thermal/trips/trip-point@1: node has a unit name, but no reg property
> arch/arm64/boot/dts/qcom/qcs404.dtsi:1310.30-1314.7: Warning (unit_address_vs_reg): /thermal-zones/gpu-thermal/trips/trip-point@0: node has a unit name, but no reg property
>
> Signed-off-by: Vinod Koul <vkoul@kernel.org>

Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>

> ---
>  arch/arm64/boot/dts/qcom/qcs404.dtsi | 30 ++++++++++++++--------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> index 3d0789775009..6d91dae5aee0 100644
> --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
> +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> @@ -1077,7 +1077,7 @@
>                         thermal-sensors = <&tsens 0>;
>
>                         trips {
> -                               aoss_alert0: trip-point@0 {
> +                               aoss_alert0: trip-point0 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
> @@ -1092,7 +1092,7 @@
>                         thermal-sensors = <&tsens 1>;
>
>                         trips {
> -                               q6_hvx_alert0: trip-point@0 {
> +                               q6_hvx_alert0: trip-point0 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
> @@ -1107,7 +1107,7 @@
>                         thermal-sensors = <&tsens 2>;
>
>                         trips {
> -                               lpass_alert0: trip-point@0 {
> +                               lpass_alert0: trip-point0 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
> @@ -1122,7 +1122,7 @@
>                         thermal-sensors = <&tsens 3>;
>
>                         trips {
> -                               wlan_alert0: trip-point@0 {
> +                               wlan_alert0: trip-point0 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
> @@ -1137,12 +1137,12 @@
>                         thermal-sensors = <&tsens 4>;
>
>                         trips {
> -                               cluster_alert0: trip-point@0 {
> +                               cluster_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
>                                 };
> -                               cluster_alert1: trip-point@1 {
> +                               cluster_alert1: trip-point1 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "passive";
> @@ -1171,12 +1171,12 @@
>                         thermal-sensors = <&tsens 5>;
>
>                         trips {
> -                               cpu0_alert0: trip-point@0 {
> +                               cpu0_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
>                                 };
> -                               cpu0_alert1: trip-point@1 {
> +                               cpu0_alert1: trip-point1 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "passive";
> @@ -1205,12 +1205,12 @@
>                         thermal-sensors = <&tsens 6>;
>
>                         trips {
> -                               cpu1_alert0: trip-point@0 {
> +                               cpu1_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
>                                 };
> -                               cpu1_alert1: trip-point@1 {
> +                               cpu1_alert1: trip-point1 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "passive";
> @@ -1239,12 +1239,12 @@
>                         thermal-sensors = <&tsens 7>;
>
>                         trips {
> -                               cpu2_alert0: trip-point@0 {
> +                               cpu2_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
>                                 };
> -                               cpu2_alert1: trip-point@1 {
> +                               cpu2_alert1: trip-point1 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "passive";
> @@ -1273,12 +1273,12 @@
>                         thermal-sensors = <&tsens 8>;
>
>                         trips {
> -                               cpu3_alert0: trip-point@0 {
> +                               cpu3_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
>                                 };
> -                               cpu3_alert1: trip-point@1 {
> +                               cpu3_alert1: trip-point1 {
>                                         temperature = <105000>;
>                                         hysteresis = <2000>;
>                                         type = "passive";
> @@ -1307,7 +1307,7 @@
>                         thermal-sensors = <&tsens 9>;
>
>                         trips {
> -                               gpu_alert0: trip-point@0 {
> +                               gpu_alert0: trip-point0 {
>                                         temperature = <95000>;
>                                         hysteresis = <2000>;
>                                         type = "hot";
> --
> 2.20.1
>

^ permalink raw reply

* Re: [PATCH 1/3] arm64: dts: qcom: pms405: add unit name adc nodes
From: Amit Kucheria @ 2019-07-30 16:35 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Andy Gross, linux-arm-msm, Bjorn Andersson, Rob Herring,
	Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <20190725135150.9972-2-vkoul@kernel.org>

On Thu, Jul 25, 2019 at 7:23 PM Vinod Koul <vkoul@kernel.org> wrote:
>
> The adc nodes have reg property but were missing the unit name, so add
> that to fix these warnings:
>
> arch/arm64/boot/dts/qcom/pms405.dtsi:91.12-94.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/ref_gnd: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:96.14-99.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/vref_1p25: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:101.19-104.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/vph_pwr: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:106.13-109.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/die_temp: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:111.27-116.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/thermistor1: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:118.27-123.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/thermistor3: node has a reg or ranges property, but no unit name
> arch/arm64/boot/dts/qcom/pms405.dtsi:125.22-130.6: Warning (unit_address_vs_reg): /soc@0/spmi@200f000/pms405@0/adc@3100/xo_temp: node has a reg or ranges property, but no unit name
>
> Signed-off-by: Vinod Koul <vkoul@kernel.org>
> ---
>  arch/arm64/boot/dts/qcom/pms405.dtsi | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/pms405.dtsi b/arch/arm64/boot/dts/qcom/pms405.dtsi
> index 14240fedd916..3c10cf04d26e 100644
> --- a/arch/arm64/boot/dts/qcom/pms405.dtsi
> +++ b/arch/arm64/boot/dts/qcom/pms405.dtsi
> @@ -88,41 +88,41 @@
>                         #size-cells = <0>;
>                         #io-channel-cells = <1>;
>
> -                       ref_gnd {
> +                       ref_gnd@0 {
>                                 reg = <ADC5_REF_GND>;
>                                 qcom,pre-scaling = <1 1>;
>                         };
>
> -                       vref_1p25 {
> +                       vref_1p25@1 {
>                                 reg = <ADC5_1P25VREF>;
>                                 qcom,pre-scaling = <1 1>;
>                         };
>
> -                       pon_1: vph_pwr {
> +                       pon_1: vph_pwr@131 {
>                                 reg = <ADC5_VPH_PWR>;
>                                 qcom,pre-scaling = <1 3>;
>                         };
>
> -                       die_temp {
> +                       die_temp@6 {
>                                 reg = <ADC5_DIE_TEMP>;
>                                 qcom,pre-scaling = <1 1>;
>                         };
>
> -                       pa_therm1: thermistor1 {
> +                       pa_therm1: thermistor1@115 {

s/115/77 ?

>                                 reg = <ADC5_AMUX_THM1_100K_PU>;
>                                 qcom,ratiometric;
>                                 qcom,hw-settle-time = <200>;
>                                 qcom,pre-scaling = <1 1>;
>                         };
>
> -                       pa_therm3: thermistor3 {
> +                       pa_therm3: thermistor3@117 {

s/117/79 ?

>                                 reg = <ADC5_AMUX_THM3_100K_PU>;
>                                 qcom,ratiometric;
>                                 qcom,hw-settle-time = <200>;
>                                 qcom,pre-scaling = <1 1>;
>                         };
>
> -                       xo_therm: xo_temp {
> +                       xo_therm: xo_temp@114 {

s/114/76 ?

>                                 reg = <ADC5_XO_THERM_100K_PU>;
>                                 qcom,ratiometric;
>                                 qcom,hw-settle-time = <200>;
> --
> 2.20.1
>

^ permalink raw reply

* Re: [PATCH v3 2/2] ARM: dts: imx6ul-kontron-n6310: Add Kontron i.MX6UL N6310 SoM and boards
From: Fabio Estevam @ 2019-07-30 16:33 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, NXP Linux Team,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Schrempf Frieder
In-Reply-To: <20190729172007.3275-2-krzk@kernel.org>

Hi Krzysztof,

On Mon, Jul 29, 2019 at 2:20 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:

> --- a/Documentation/devicetree/bindings/eeprom/at25.txt
> +++ b/Documentation/devicetree/bindings/eeprom/at25.txt
> @@ -3,6 +3,7 @@ EEPROMs (SPI) compatible with Atmel at25.
>  Required properties:
>  - compatible : Should be "<vendor>,<type>", and generic value "atmel,at25".
>    Example "<vendor>,<type>" values:
> +    "anvo,anv32e61w"

This usually comes as a separate patch, but anyway:

Reviewed-by: Fabio Estevam <festevam@gmail.com>

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2 3/3] ASoC: TDA7802: Add turn-on diagnostic routine
From: Thomas Preston @ 2019-07-30 16:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Mark Rutland, devicetree, alsa-devel, Charles Keepax,
	Kuninori Morimoto, Kirill Marinushkin, Liam Girdwood,
	Marco Felsch, Annaliese McDermond, Takashi Iwai, Paul Cercueil,
	Vinod Koul, Rob Herring, Srinivas Kandagatla, Jerome Brunet,
	linux-kernel, Cheng-Yi Chiang
In-Reply-To: <20190730155027.GJ4264@sirena.org.uk>

On 30/07/2019 16:50, Mark Brown wrote:
> On Tue, Jul 30, 2019 at 04:25:56PM +0100, Thomas Preston wrote:
>> On 30/07/2019 15:19, Mark Brown wrote:
> 
>>> It is unclear what this mutex usefully protects, it only gets taken when
>>> writing to the debugfs file to trigger this diagnostic mode but doesn't
>>> do anything to control interactions with any other code path in the
>>> driver.
> 
>> If another process reads the debugfs node "diagnostic" while the turn-on 
>> diagnostic mode is running, this mutex prevents the second process
>> restarting the diagnostics.
> 
>> This is redundant if debugfs reads are atomic, but I don't think they are.
> 
> Like I say it's not just debugfs though, there's the standard driver
> interface too.
> 

Ah right, I understand. So if we run the turn-on diagnostics routine, there's
nothing stopping anyone from interacting with the device in other ways.

I guess there's no way to share that mutex with ALSA? In that case, it doesn't
matter if this mutex is there or not - this feature is incompatible. How
compatible do debugfs interfaces have to be? I was under the impression anything
goes. I would argue that the debugfs is better off for having the mutex so
that no one re-reads "diagnostic" within the 5s poll timeout.

Alternatively, this diagnostic feature could be handled with an external-handler
kcontrol SOC_SINGLE_EXT? I'm not sure if this is an atomic interface either.

What would be acceptable?

^ permalink raw reply

* Re: media: mtk-vcodec: Handle H264 error bitstreams
From: Mauro Carvalho Chehab @ 2019-07-30 16:15 UTC (permalink / raw)
  To: gtk_ruiwang
  Cc: devicetree, Yunfei Dong, Longfei Wang, linux-kernel, Tomasz Figa,
	Hans Verkuil, linux-mediatek, Matthias Brugger, Tiffany Lin,
	linux-arm-kernel, linux-media
In-Reply-To: <20190726085433.15612-1-gtk_ruiwang@mediatek.com>

Em Fri, 26 Jul 2019 16:54:33 +0800
<gtk_ruiwang@mediatek.com> escreveu:

> From: gtk_ruiwang <gtk_ruiwang@mediatek.com>

...

> Signed-off-by: gtk_ruiwang <gtk_ruiwang@mediatek.com>

Please use your real name on your SOB and at the From: line.

Thanks,
Mauro

^ permalink raw reply

* Re: [PATCH] ARM: DTS: vybrid: Update qspi node description for VF610 BK4 board
From: Lukasz Majewski @ 2019-07-30 16:04 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Shawn Guo, Sascha Hauer, Stefan Agner, Rob Herring, Mark Rutland,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel
In-Reply-To: <CAOMZO5AoSCDCMRKpkWQ=0PwiFG-O9doGaA31FRhDCGmNr7Xefg@mail.gmail.com>

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

Hi Fabio,

> Hi Lukasz,
> 
> On Tue, Jul 30, 2019 at 12:53 PM Lukasz Majewski <lukma@denx.de>
> wrote:
> 
> > Shall I refer to the original commit (which added this DTS)? Or the
> > original issue posted to linux-mtd [1] ?  
> 
> You can add a Fixes tag like this:
> 
> Fixes: a67d2c52a82f ("ARM: dts: Add support for Liebherr's BK4 device
> (vf610 based)")

Yes, the above is correct (as indicated [1]), but I was not sure if I
should also refer to the original post to linux-mtd ML.

Now it is clear - thanks :-)

Note:

[1] -
https://www.kernel.org/doc/html/v4.12/process/submitting-patches.html#reviewer-s-statement-of-oversight

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH] ARM: DTS: vybrid: Update qspi node description for VF610 BK4 board
From: Fabio Estevam @ 2019-07-30 16:01 UTC (permalink / raw)
  To: Lukasz Majewski
  Cc: Shawn Guo, Sascha Hauer, Stefan Agner, Rob Herring, Mark Rutland,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel
In-Reply-To: <20190730175336.382d833c@jawa>

Hi Lukasz,

On Tue, Jul 30, 2019 at 12:53 PM Lukasz Majewski <lukma@denx.de> wrote:

> Shall I refer to the original commit (which added this DTS)? Or the
> original issue posted to linux-mtd [1] ?

You can add a Fixes tag like this:

Fixes: a67d2c52a82f ("ARM: dts: Add support for Liebherr's BK4 device
(vf610 based)")

^ permalink raw reply

* Re: [PATCH] ARM: DTS: vybrid: Update qspi node description for VF610 BK4 board
From: Lukasz Majewski @ 2019-07-30 15:53 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Shawn Guo, Sascha Hauer, Stefan Agner, Rob Herring, Mark Rutland,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel
In-Reply-To: <CAOMZO5AxPHHobQQhq30fjLVeSroLdvdT0+GqCWi8it1ejhDONA@mail.gmail.com>

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

Hi Fabio,

> Hi Lukasz,
> 
> Subject line could be improved:
> 
> ARM: dts: vf610-bk4: Fix qspi node description
> 
> On Tue, Jul 30, 2019 at 12:06 PM Lukasz Majewski <lukma@denx.de>
> wrote:
> >
> > Before this change the device tree description of qspi node for
> > second memory on BK4 board was wrong (applicable to old, in-house
> > tunned fsl-quadspi.c driver).
> >
> > As a result this memory was not recognized correctly when used
> > with the new spi-fsl-qspi.c driver.
> >
> > From the dt-bindings:
> >
> > "Required SPI slave node properties:
> >   - reg: There are two buses (A and B) with two chip selects each.
> > This encodes to which bus and CS the flash is connected:
> > <0>: Bus A, CS 0
> > <1>: Bus A, CS 1
> > <2>: Bus B, CS 0
> > <3>: Bus B, CS 1"
> >
> > According to above with new driver the second SPI-NOR memory shall
> > have reg=<2> as it is connected to Bus B, CS 0.  
> 
> I am glad you got it working!
> 
> This looks very familiar with the suggestion I sent yesterday:
> http://lists.infradead.org/pipermail/linux-mtd/2019-July/090655.html
> 

Yes, indeed. Deepest apologizes for not adding credits. I will fix it
in v2.

> It is a good practice to give some credit to someone who has helped in
> finding the solution of your problem.
> 
> Adding a Suggested-by: Fabio Estevam <festevam@gmail.com> would be
> nice here.
> 
> This also needs a Fixes tag.

Shall I refer to the original commit (which added this DTS)? Or the
original issue posted to linux-mtd [1] ?

Note:

[1] - https://www.spinics.net/lists/linux-mtd/msg08114.html

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2 3/3] ASoC: TDA7802: Add turn-on diagnostic routine
From: Mark Brown @ 2019-07-30 15:50 UTC (permalink / raw)
  To: Thomas Preston
  Cc: Mark Rutland, devicetree, alsa-devel, Charles Keepax,
	Kuninori Morimoto, Kirill Marinushkin, Cheng-Yi Chiang,
	Marco Felsch, Takashi Iwai, Annaliese McDermond, Liam Girdwood,
	Paul Cercueil, Vinod Koul, Rob Herring, Srinivas Kandagatla,
	linux-kernel, Jerome Brunet
In-Reply-To: <45156592-a90f-b4f8-4d30-9631c03f1280@codethink.co.uk>

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

On Tue, Jul 30, 2019 at 04:25:56PM +0100, Thomas Preston wrote:
> On 30/07/2019 15:19, Mark Brown wrote:

> > It is unclear what this mutex usefully protects, it only gets taken when
> > writing to the debugfs file to trigger this diagnostic mode but doesn't
> > do anything to control interactions with any other code path in the
> > driver.

> If another process reads the debugfs node "diagnostic" while the turn-on 
> diagnostic mode is running, this mutex prevents the second process
> restarting the diagnostics.

> This is redundant if debugfs reads are atomic, but I don't think they are.

Like I say it's not just debugfs though, there's the standard driver
interface too.

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

^ permalink raw reply

* Re: [PATCH V13 12/12] PCI: tegra: Add Tegra194 PCIe support
From: Lorenzo Pieralisi @ 2019-07-30 15:49 UTC (permalink / raw)
  To: Vidya Sagar
  Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
	kishon, catalin.marinas, will.deacon, jingoohan1,
	gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
	linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
	sagar.tv
In-Reply-To: <be6367bc-08a0-762a-aae8-b3f0376d0e9a@nvidia.com>

On Tue, Jul 23, 2019 at 08:14:08PM +0530, Vidya Sagar wrote:
> On 7/16/2019 4:52 PM, Lorenzo Pieralisi wrote:
> > On Sat, Jul 13, 2019 at 12:34:34PM +0530, Vidya Sagar wrote:
> > 
> > [...]
> > 
> > > > > > > +static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
> > > > > > > +					  bool enable)
> > > > > > > +{
> > > > > > > +	struct mrq_uphy_response resp;
> > > > > > > +	struct tegra_bpmp_message msg;
> > > > > > > +	struct mrq_uphy_request req;
> > > > > > > +	int err;
> > > > > > > +
> > > > > > > +	if (pcie->cid == 5)
> > > > > > > +		return 0;
> > > > > > 
> > > > > > What's wrong with cid == 5 ? Explain please.
> > > > > Controller with ID=5 doesn't need any programming to enable it which is
> > > > > done here through calling firmware API.
> > > > > 
> > > > > > 
> > > > > > > +	memset(&req, 0, sizeof(req));
> > > > > > > +	memset(&resp, 0, sizeof(resp));
> > > > > > > +
> > > > > > > +	req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE;
> > > > > > > +	req.controller_state.pcie_controller = pcie->cid;
> > > > > > > +	req.controller_state.enable = enable;
> > > > > > > +
> > > > > > > +	memset(&msg, 0, sizeof(msg));
> > > > > > > +	msg.mrq = MRQ_UPHY;
> > > > > > > +	msg.tx.data = &req;
> > > > > > > +	msg.tx.size = sizeof(req);
> > > > > > > +	msg.rx.data = &resp;
> > > > > > > +	msg.rx.size = sizeof(resp);
> > > > > > > +
> > > > > > > +	if (irqs_disabled())
> > > > > > 
> > > > > > Can you explain to me what this check is meant to achieve please ?
> > > > > Firmware interface provides different APIs to be called when there are
> > > > > no interrupts enabled in the system (noirq context) and otherwise
> > > > > hence checking that situation here and calling appropriate API.
> > > > 
> > > > That's what I am questioning. Being called from {suspend/resume}_noirq()
> > > > callbacks (if that's the code path this check caters for) does not mean
> > > > irqs_disabled() == true.
> > > Agree.
> > > Actually, I got a hint of having this check from the following.
> > > Both tegra_bpmp_transfer_atomic() and tegra_bpmp_transfer() are indirectly
> > > called by APIs registered with .master_xfer() and .master_xfer_atomic() hooks of
> > > struct i2c_algorithm and the decision to call which one of these is made using the
> > > following check in i2c-core.h file.
> > > static inline bool i2c_in_atomic_xfer_mode(void)
> > > {
> > > 	return system_state > SYSTEM_RUNNING && irqs_disabled();
> > > }
> > > I think I should use this condition as is IIUC.
> > > Please let me know if there are any concerns with this.
> > 
> > It is not a concern, it is just that I don't understand how this code
> > can be called with IRQs disabled, if you can give me an execution path I
> > am happy to leave the check there. On top of that, when called from
> > suspend NOIRQ context, it is likely to use the blocking API (because
> > IRQs aren't disabled at CPU level) behind which there is most certainly
> > an IRQ required to wake the thread up and if the IRQ in question was
> > disabled in the suspend NOIRQ phase this code is likely to deadlock.
> > 
> > I want to make sure we can justify adding this check, I do not
> > want to add it because we think it can be needed when it may not
> > be needed at all (and it gets copy and pasted over and over again
> > in other drivers).
> I had a discussion internally about this and the prescribed usage of these APIs
> seem to be that
> use tegra_bpmp_transfer() in .probe() and other paths where interrupts are
> enabled as this API needs interrupts to be enabled for its working.
> Use tegra_bpmp_transfer_atomic() surrounded by local_irq_save()/local_irq_restore()
> in other paths where interrupt servicing is disabled.

Why tegra_bpmp_transfer_atomic() needs IRQs to be disabled ? And why
is it needed in this piece of code where IRQs are _never_ disabled
at CPU level ?

IRQs are enabled when you call a suspend_noirq() callback, so the
blocking API can be used as long as the IRQ descriptor backing
the IRQ that will wake-up the blocked call is marked as
IRQF_NO_SUSPEND.

The problem is not IRQs enabled/disabled at CPU level, the problem is
the IRQ descriptor of the IRQ required to handle the blocking BPMP call,
mark it as IRQF_NO_SUSPEND and remove the tegra_bpmp_transfer_atomic()
call from this code (or please give me a concrete example pinpointing
why it is needed).

Thanks,
Lorenzo

> I'll go ahead and make next patch series with this if this looks fine to you.
> 
> > 
> > > > Actually, if tegra_bpmp_transfer() requires IRQs to be enabled you may
> > > > even end up in a situation where that blocking call does not wake up
> > > > because the IRQ in question was disabled in the NOIRQ suspend/resume
> > > > phase.
> > > > 
> > > > [...]
> > > > 
> > > > > > > +static int tegra_pcie_dw_probe(struct platform_device *pdev)
> > > > > > > +{
> > > > > > > +	const struct tegra_pcie_soc *data;
> > > > > > > +	struct device *dev = &pdev->dev;
> > > > > > > +	struct resource *atu_dma_res;
> > > > > > > +	struct tegra_pcie_dw *pcie;
> > > > > > > +	struct resource *dbi_res;
> > > > > > > +	struct pcie_port *pp;
> > > > > > > +	struct dw_pcie *pci;
> > > > > > > +	struct phy **phys;
> > > > > > > +	char *name;
> > > > > > > +	int ret;
> > > > > > > +	u32 i;
> > > > > > > +
> > > > > > > +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> > > > > > > +	if (!pcie)
> > > > > > > +		return -ENOMEM;
> > > > > > > +
> > > > > > > +	pci = &pcie->pci;
> > > > > > > +	pci->dev = &pdev->dev;
> > > > > > > +	pci->ops = &tegra_dw_pcie_ops;
> > > > > > > +	pp = &pci->pp;
> > > > > > > +	pcie->dev = &pdev->dev;
> > > > > > > +
> > > > > > > +	data = (struct tegra_pcie_soc *)of_device_get_match_data(dev);
> > > > > > > +	if (!data)
> > > > > > > +		return -EINVAL;
> > > > > > > +	pcie->mode = (enum dw_pcie_device_mode)data->mode;
> > > > > > > +
> > > > > > > +	ret = tegra_pcie_dw_parse_dt(pcie);
> > > > > > > +	if (ret < 0) {
> > > > > > > +		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> > > > > > > +		return ret;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
> > > > > > > +	if (IS_ERR(pcie->pex_ctl_supply)) {
> > > > > > > +		dev_err(dev, "Failed to get regulator: %ld\n",
> > > > > > > +			PTR_ERR(pcie->pex_ctl_supply));
> > > > > > > +		return PTR_ERR(pcie->pex_ctl_supply);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pcie->core_clk = devm_clk_get(dev, "core");
> > > > > > > +	if (IS_ERR(pcie->core_clk)) {
> > > > > > > +		dev_err(dev, "Failed to get core clock: %ld\n",
> > > > > > > +			PTR_ERR(pcie->core_clk));
> > > > > > > +		return PTR_ERR(pcie->core_clk);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> > > > > > > +						      "appl");
> > > > > > > +	if (!pcie->appl_res) {
> > > > > > > +		dev_err(dev, "Failed to find \"appl\" region\n");
> > > > > > > +		return PTR_ERR(pcie->appl_res);
> > > > > > > +	}
> > > > > > > +	pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res);
> > > > > > > +	if (IS_ERR(pcie->appl_base))
> > > > > > > +		return PTR_ERR(pcie->appl_base);
> > > > > > > +
> > > > > > > +	pcie->core_apb_rst = devm_reset_control_get(dev, "apb");
> > > > > > > +	if (IS_ERR(pcie->core_apb_rst)) {
> > > > > > > +		dev_err(dev, "Failed to get APB reset: %ld\n",
> > > > > > > +			PTR_ERR(pcie->core_apb_rst));
> > > > > > > +		return PTR_ERR(pcie->core_apb_rst);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL);
> > > > > > > +	if (!phys)
> > > > > > > +		return PTR_ERR(phys);
> > > > > > > +
> > > > > > > +	for (i = 0; i < pcie->phy_count; i++) {
> > > > > > > +		name = kasprintf(GFP_KERNEL, "p2u-%u", i);
> > > > > > > +		if (!name) {
> > > > > > > +			dev_err(dev, "Failed to create P2U string\n");
> > > > > > > +			return -ENOMEM;
> > > > > > > +		}
> > > > > > > +		phys[i] = devm_phy_get(dev, name);
> > > > > > > +		kfree(name);
> > > > > > > +		if (IS_ERR(phys[i])) {
> > > > > > > +			ret = PTR_ERR(phys[i]);
> > > > > > > +			dev_err(dev, "Failed to get PHY: %d\n", ret);
> > > > > > > +			return ret;
> > > > > > > +		}
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pcie->phys = phys;
> > > > > > > +
> > > > > > > +	dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
> > > > > > > +	if (!dbi_res) {
> > > > > > > +		dev_err(dev, "Failed to find \"dbi\" region\n");
> > > > > > > +		return PTR_ERR(dbi_res);
> > > > > > > +	}
> > > > > > > +	pcie->dbi_res = dbi_res;
> > > > > > > +
> > > > > > > +	pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
> > > > > > > +	if (IS_ERR(pci->dbi_base))
> > > > > > > +		return PTR_ERR(pci->dbi_base);
> > > > > > > +
> > > > > > > +	/* Tegra HW locates DBI2 at a fixed offset from DBI */
> > > > > > > +	pci->dbi_base2 = pci->dbi_base + 0x1000;
> > > > > > > +
> > > > > > > +	atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> > > > > > > +						   "atu_dma");
> > > > > > > +	if (!atu_dma_res) {
> > > > > > > +		dev_err(dev, "Failed to find \"atu_dma\" region\n");
> > > > > > > +		return PTR_ERR(atu_dma_res);
> > > > > > > +	}
> > > > > > > +	pcie->atu_dma_res = atu_dma_res;
> > > > > > > +	pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
> > > > > > > +	if (IS_ERR(pci->atu_base))
> > > > > > > +		return PTR_ERR(pci->atu_base);
> > > > > > > +
> > > > > > > +	pcie->core_rst = devm_reset_control_get(dev, "core");
> > > > > > > +	if (IS_ERR(pcie->core_rst)) {
> > > > > > > +		dev_err(dev, "Failed to get core reset: %ld\n",
> > > > > > > +			PTR_ERR(pcie->core_rst));
> > > > > > > +		return PTR_ERR(pcie->core_rst);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pp->irq = platform_get_irq_byname(pdev, "intr");
> > > > > > > +	if (!pp->irq) {
> > > > > > > +		dev_err(dev, "Failed to get \"intr\" interrupt\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	ret = devm_request_irq(dev, pp->irq, tegra_pcie_irq_handler,
> > > > > > > +			       IRQF_SHARED, "tegra-pcie-intr", pcie);
> > > > > > > +	if (ret) {
> > > > > > > +		dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, ret);
> > > > > > > +		return ret;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	pcie->bpmp = tegra_bpmp_get(dev);
> > > > > > > +	if (IS_ERR(pcie->bpmp))
> > > > > > > +		return PTR_ERR(pcie->bpmp);
> > > > > > > +
> > > > > > > +	platform_set_drvdata(pdev, pcie);
> > > > > > > +
> > > > > > > +	if (pcie->mode == DW_PCIE_RC_TYPE) {
> > > > > > > +		ret = tegra_pcie_config_rp(pcie);
> > > > > > > +		if (ret && ret != -ENOMEDIUM)
> > > > > > > +			goto fail;
> > > > > > > +		else
> > > > > > > +			return 0;
> > > > > > 
> > > > > > So if the link is not up we still go ahead and make probe
> > > > > > succeed. What for ?
> > > > > We may need root port to be available to support hot-plugging of
> > > > > endpoint devices, so, we don't fail the probe.
> > > > 
> > > > We need it or we don't. If you do support hotplugging of endpoint
> > > > devices point me at the code, otherwise link up failure means
> > > > failure to probe.
> > > Currently hotplugging of endpoint is not supported, but it is one of
> > > the use cases that we may add support for in future.
> > 
> > You should elaborate on this, I do not understand what you mean,
> > either the root port(s) supports hotplug or it does not.
> > 
> > > But, why should we fail probe if link up doesn't happen? As such,
> > > nothing went wrong in terms of root port initialization right?  I
> > > checked other DWC based implementations and following are not failing
> > > the probe pci-dra7xx.c, pcie-armada8k.c, pcie-artpec6.c, pcie-histb.c,
> > > pcie-kirin.c, pcie-spear13xx.c, pci-exynos.c, pci-imx6.c,
> > > pci-keystone.c, pci-layerscape.c
> > > 
> > > Although following do fail the probe if link is not up.  pcie-qcom.c,
> > > pcie-uniphier.c, pci-meson.c
> > > 
> > > So, to me, it looks more like a choice we can make whether to fail the
> > > probe or not and in this case we are choosing not to fail.
> > 
> > I disagree. I had an offline chat with Bjorn and whether link-up should
> > fail the probe or not depends on whether the root port(s) is hotplug
> > capable or not and this in turn relies on the root port "Slot
> > implemented" bit in the PCI Express capabilities register.
> > 
> > It is a choice but it should be based on evidence.
> > 
> > Lorenzo
> With Bjorn's latest comment on top of this, I think we are good not to fail
> the probe here.
> 
> - Vidya Sagar
> > 
> 

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2 2/3] ASoC: Add codec driver for ST TDA7802
From: Thomas Preston @ 2019-07-30 15:49 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Mark Rutland, devicetree, alsa-devel, Marco Felsch,
	Kuninori Morimoto, Kirill Marinushkin, Cheng-Yi Chiang,
	linux-kernel, Nate Case, Takashi Iwai, Rob Herring, Liam Girdwood,
	Paul Cercueil, Vinod Koul, Mark Brown, Srinivas Kandagatla,
	Annaliese McDermond, Rob Duncan, Patrick Glaser, Jerome Brunet
In-Reply-To: <20190730123825.GG54126@ediswmail.ad.cirrus.com>

On 30/07/2019 13:38, Charles Keepax wrote:
> On Tue, Jul 30, 2019 at 01:09:36PM +0100, Thomas Preston wrote:
>> Add an I2C based codec driver for ST TDA7802 amplifier. The amplifier
>> supports 4 audio channels but can support up to 16 with multiple
>> devices.
>>
>> Signed-off-by: Thomas Preston <thomas.preston@codethink.co.uk>
>> Cc: Patrick Glaser <pglaser@tesla.com>
>> Cc: Rob Duncan <rduncan@tesla.com>
>> Cc: Nate Case <ncase@tesla.com>
>> ---
>> Changes since v1:
>> - Use ALSA kcontrol interface to expose device controls to userland
>> 	- Gain
>> 	- Channel diagnostic mode
>> 	- Impedance efficiency optimiser. I decided against setting this
>> 	  as a DT property since it seems like something that can be
>> 	  changed on the fly.
>> - Add regmap default values
>> 	- Channel unmute by default is added in a downstream patch.
>> 	- I'm not sure if I should keep this since they're all zero,
>> 	  although there are other drivers will all-zero reg_defaults.
>> - I believe the "//" style is used for SPDX headers in normal C source files.
>>   https://lwn.net/Articles/739183/
>> - Drop the "enable" sysfs device attribute.
>> - Don't set TDM format using magic numbers.
>> - Set sample rate using hw_params.
>> - Remove unecessary defines.
>> - Use DAPM to handle AMP_ON.
>> - Cosmetic fixups
>>
>>  sound/soc/codecs/Kconfig   |   6 +
>>  sound/soc/codecs/Makefile  |   2 +
>>  sound/soc/codecs/tda7802.c | 509 +++++++++++++++++++++++++++++++++++++
>>  3 files changed, 517 insertions(+)
>>  create mode 100644 sound/soc/codecs/tda7802.c
>>
>> +++ b/sound/soc/codecs/tda7802.c
>> @@ -0,0 +1,509 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * tda7802.c  --  codec driver for ST TDA7802
>> + *
>> + * Copyright (C) 2016-2019 Tesla Motors, Inc.
>> + */
> 
> Better to make the whole comment // see something like
> sound/soc/codecs/cs47l35.c for an example.
> 

I will update to "//" style. Is this a new standard? There aren't many
comments like that in 4.14 (my target kernel) - I can see a lot more
in 5.3.

My intention was:

1. Apply the SPDX rules to SPDX bit.     Documentation/process/license-rules.rst
2. Use multi-line comments for the rest. Documentation/process/coding-style.rst

>> +static int tda7802_set_bias_level(struct snd_soc_component *component,
>> +		enum snd_soc_bias_level level)
>> +{
>> +	const struct tda7802_priv *tda7802 =
>> +		snd_soc_component_get_drvdata(component);
>> +	struct snd_soc_dapm_context *dapm_context =
>> +			snd_soc_component_get_dapm(component);
>> +	const enum snd_soc_bias_level oldlevel =
>> +		snd_soc_dapm_get_bias_level(dapm_context);
>> +	int err = 0;
>> +
>> +	dev_dbg(component->dev, "%s level %d\n", __func__, level);
>> +
>> +	switch (level) {
>> +	case SND_SOC_BIAS_ON:
>> +		break;
>> +	case SND_SOC_BIAS_PREPARE:
>> +		break;
>> +	case SND_SOC_BIAS_STANDBY:
>> +		err = regulator_enable(tda7802->enable_reg);
>> +		if (err < 0) {
>> +			dev_err(component->dev, "Could not enable.\n");
>> +			return err;
>> +		}
>> +		dev_dbg(component->dev, "Regulator enabled\n");
>> +		msleep(ENABLE_DELAY_MS);
>> +
>> +		if (oldlevel == SND_SOC_BIAS_OFF) {
>> +			dev_dbg(component->dev, "Syncing regcache\n");
>> +			err = regcache_sync(component->regmap);
>> +			if (err < 0)
>> +				dev_err(component->dev,
>> +					"Could not sync regcache, %d\n", err);
> 
> If your doing a regcache_sync I would probably have expected to
> see calls to regcache_cache_only.
> 
> If the device needs syncing that implies the hardware registers
> have lost state, so there is little point in writing to them
> if they are unavailable/about to loose their state.
> 

Ah, from the comments I thought I only needed to call regcache_mark_dirty...

>> +		}
>> +		break;
>> +	case SND_SOC_BIAS_OFF:
>> +		regcache_mark_dirty(component->regmap);
>> +		err = regulator_disable(tda7802->enable_reg);
>> +		if (err < 0)
>> +			dev_err(component->dev, "Could not disable.\n");
>> +		break;
>> +	}
>> +
>> +	return err;
>> +}

So I think the correct order is:

device_off:
	regcache_cache_only
	power-off (enable)
	regcache_mark_dirty

device_on:
	power-on (enable)
	regcache_sync

I will double-check the register state is actually lost too. Fiddling
with the cache might be completely unnecessary.

Many thanks

^ permalink raw reply

* Re: [patch v4 1/5] AST2500 DMA UART driver
From: Greg KH @ 2019-07-30 15:47 UTC (permalink / raw)
  To: sudheer.v
  Cc: jslaby, joel, andrew, benh, robh+dt, mark.rutland,
	shivahshankar.shankarnarayanrao, sudheer.veliseti,
	sudheer veliseti, linux-kernel, linux-serial, devicetree,
	linux-aspeed
In-Reply-To: <1564147640-30753-2-git-send-email-open.sudheer@gmail.com>

On Fri, Jul 26, 2019 at 06:57:16PM +0530, sudheer.v wrote:
> From: sudheer veliseti <sudheer.open@gmail.com>
> 
> UART driver for Aspeed's bmc chip AST2500
> 
> Design approch:
> AST2500 has dedicated Uart DMA controller which has 12 sets of Tx and RX channels
> connected to UART controller directly.
> Since the DMA controller have dedicated buffers and registers,
> there would be little benifit in adding DMA framework overhead.
> So the software for DMA controller is included within the UART driver itself.
> 
> implementation details:
> 'struct ast_uart_port' is populated and registered with uart_core.
> code is organised into two layers UART-layer and DMA-Layer,both of them are
> in the same file.UART-layer requests Rx and Tx dma channels
> and registers callbacks with DMA controller software Layer
> Interrupt service routine for DMA controller is the crucial one for Handling all
> the tx and rx data. ISRs installed for individual uarts are just dummy,and are helpful 
> only to report any spurious interrupts in hardware.
> 
> 
> Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
> ---
> 
> Changes from v3->v4:
> - per port uart structures are registerd directly with uart core 
>   Instead of registering through 8250 Frame work,
>   ast_uart_port is registered using uart_add_one_port
> -SDMA_RX_FIX macro replaced with CONFIG_AST_UART_DMA_RX_INTERRUPT
> -ast_uart_sdma_isr : DMA interrupt handler code is improvised
> -replaced pr_debug with ftrace wherever appropriate
> -dev_err is used in all error return cases
> -uart driver structure ast25xx_uart_reg is modified
> -driver name changed to ast2500-uart-dma-drv
> -rx_timer initialisation and callback fn modified
> 
> Changes from v2->v3:
> -custom debug replaced by in kerenl dynamic debug: pr_debug 
> -change-logs added 
> 
> 
> .../tty/serial/8250/8250_ast2500_uart_dma.c   | 1901 +++++++++++++++++
>  1 file changed, 1901 insertions(+)
>  create mode 100644 drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> 
> diff --git a/drivers/tty/serial/8250/8250_ast2500_uart_dma.c b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> new file mode 100644
> index 000000000000..bc830d605372
> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> @@ -0,0 +1,1901 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  DMA UART Driver for ASPEED BMC chip: AST2500
> + *
> + *  Copyright (C) 2019 sudheer Kumar veliseti, Aspeed technology Inc.
> + *  <open.sudheer@gmail.com>

What was the copyright on the file you copied?  Please properly
attribute that here.


> + *
> + */
> +#include <linux/clk.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include "8250.h"
> +
> +#define SERIAL8250_CONSOLE NULL
> +#define TTY_AST_MAJOR 204
> +#define TTY_AST_MINOR 68

Where did you get this minor number from?

> +
> +#define DMA_BUFF_SIZE		0x1000
> +#define SDMA_RX_BUFF_SIZE	0x10000
> +#define PASS_LIMIT 256
> +#define UART_DMA_NR CONFIG_AST_NR_DMA_UARTS
> +#define AST_UART_SDMA_CH 12
> +
> +/* enum ast_uart_chan_op
> + * operation codes passed to the DMA code by the user, and also used
> + * to inform the current channel owner of any changes to the system state
> + */
> +enum ast_uart_chan_op {
> +	AST_UART_DMAOP_TRIGGER,
> +	AST_UART_DMAOP_STOP,
> +	AST_UART_DMAOP_PAUSE,
> +};
> +
> +/* ast_uart_dma_cbfn: buffer callback routinei type */
> +typedef void (*ast_uart_dma_cbfn)(void *dev_id, u16 len);
> +
> +struct ast_sdma_info {
> +	u8 ch_no;
> +	u8 direction;
> +	u8 enable;
> +	void *priv;
> +	char *sdma_virt_addr;
> +	dma_addr_t dma_phy_addr;
> +	/* cdriver callbacks */
> +	ast_uart_dma_cbfn callback_fn; /* buffer done callback */
> +};
> +
> +struct ast_sdma_ch {
> +	struct ast_sdma_info tx_dma_info[AST_UART_SDMA_CH];
> +	struct ast_sdma_info rx_dma_info[AST_UART_SDMA_CH];
> +};
> +
> +struct ast_sdma {
> +	void __iomem *reg_base;
> +	int dma_irq;
> +	struct ast_sdma_ch *dma_ch;
> +	struct regmap *map;
> +};
> +
> +#define UART_TX_SDMA_EN		0x00
> +#define UART_RX_SDMA_EN		0x04
> +#define UART_SDMA_CONF		0x08 /* Misc, Buffer size  */
> +#define UART_SDMA_TIMER		0x0C
> +#define UART_TX_SDMA_REST	0x20
> +#define UART_RX_SDMA_REST	0x24
> +#define UART_TX_SDMA_IER	0x30
> +#define UART_TX_SDMA_ISR	0x34
> +#define UART_RX_SDMA_IER	0x38
> +#define UART_RX_SDMA_ISR	0x3C
> +#define UART_TX_R_POINT(x)	(0x40 + ((x) * 0x20))
> +#define UART_TX_W_POINT(x)	(0x44 + ((x) * 0x20))
> +#define UART_TX_SDMA_ADDR(x)	(0x48 + ((x) * 0x20))
> +#define UART_RX_R_POINT(x)	(0x50 + ((x) * 0x20))
> +#define UART_RX_W_POINT(x)	(0x54 + ((x) * 0x20))
> +#define UART_RX_SDMA_ADDR(x)	(0x58 + ((x) * 0x20))
> +#define SDMA_CH_EN(x)		BIT(x)
> +
> +#define SDMA_TX_BUFF_SIZE_MASK	(0x3)
> +#define SDMA_SET_TX_BUFF_SIZE(x)(x)
> +#define SDMA_BUFF_SIZE_1KB	(0x0)
> +#define SDMA_BUFF_SIZE_4KB	(0x1)
> +#define SDMA_BUFF_SIZE_16KB	(0x2)
> +#define SDMA_BUFF_SIZE_64KB	(0x3)
> +#define SDMA_RX_BUFF_SIZE_MASK	(0x3 << 2)
> +#define SDMA_SET_RX_BUFF_SIZE(x)((x) << 2)
> +#define SDMA_TIMEOUT_DIS	BIT(4)
> +
> +#define UART_SDMA11_INT		BIT(11)
> +#define UART_SDMA10_INT		BIT(10)
> +#define UART_SDMA9_INT		BIT(9)
> +#define UART_SDMA8_INT		BIT(8)
> +#define UART_SDMA7_INT		BIT(7)
> +#define UART_SDMA6_INT		BIT(6)
> +#define UART_SDMA5_INT		BIT(5)
> +#define UART_SDMA4_INT		BIT(4)
> +#define UART_SDMA3_INT		BIT(3)
> +#define UART_SDMA2_INT		BIT(2)
> +#define UART_SDMA1_INT		BIT(1)
> +#define UART_SDMA0_INT		BIT(0)
> +
> +/*
> + * Configuration:
> + *   share_irqs - whether we pass IRQF_SHARED to request_irq().
> + *   This option is unsafe when used on edge-triggered interrupts.
> + */
> +static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
> +
> +static unsigned int nr_uarts = CONFIG_AST_RUNTIME_DMA_UARTS;
> +
> +struct ast_uart_port {
> +	struct uart_port port;
> +	unsigned short capabilities; /* port capabilities */
> +	unsigned short bugs;         /* port bugs */
> +	unsigned int tx_loadsz;      /* transmit fifo load size */
> +	unsigned char acr;
> +	unsigned char ier;
> +	unsigned char lcr;
> +	unsigned char mcr;
> +	unsigned char mcr_mask;  /* mask of user bits */
> +	unsigned char mcr_force; /* mask of forced bits */
> +	struct circ_buf rx_dma_buf;
> +	struct circ_buf tx_dma_buf;
> +	unsigned char dma_channel;
> +	dma_addr_t dma_rx_addr; /* Mapped ADMA descr. table */
> +	dma_addr_t dma_tx_addr; /* Mapped ADMA descr. table */
> +#ifdef CONFIG_AST_UART_DMA_RX_INTERRUPT
> +	struct tasklet_struct rx_tasklet;
> +#else
> +	struct timer_list rx_timer;
> +	unsigned int workaround;
> +#endif
> +	struct tasklet_struct tx_tasklet;
> +	spinlock_t lock;
> +	int tx_done;
> +	int tx_count;
> +	struct platform_device *ast_uart_pdev;
> +/*
> + * Some bits in registers are cleared on a read, so they must
> + * be saved whenever the register is read but the bits will not
> + * be immediately processed.
> + */
> +#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
> +	unsigned char lsr_saved_flags;
> +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
> +	unsigned char msr_saved_flags;
> +
> +	/*
> +	 * We provide a per-port pm hook.
> +	 */
> +	void (*pm)(struct uart_port *port, unsigned int state,
> +						 unsigned int old);
> +};
> +
> +static struct ast_uart_port ast_uart_ports[UART_DMA_NR];
> +
> +#define GET_DEV(ast_uart_port_priv_ptr)\
> +		(ast_uart_port_priv_ptr->ast_uart_pdev->dev)
> +
> +static inline struct ast_uart_port *
> +to_ast_dma_uart_port(struct uart_port *uart) {
> +	return container_of(uart, struct ast_uart_port, port);
> +}
> +
> +struct irq_info {
> +	spinlock_t lock;
> +	struct ast_uart_port *up;
> +};
> +
> +static struct irq_info ast_uart_irq[1];
> +static DEFINE_MUTEX(ast_uart_mutex);
> +
> +/*
> + * Here we define the default xmit fifo size used for each type of UART.
> + */
> +static const struct serial8250_config uart_config[] = {
> +	[PORT_UNKNOWN] = {
> +		.name		= "unknown",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_8250] = {
> +		.name		= "8250",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16450] = {
> +		.name		= "16450",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16550] = {
> +		.name		= "16550",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16550A] = {
> +		.name		= "16550A",
> +		.fifo_size	= 16,
> +		.tx_loadsz	= 16,
> +		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10
> +							| UART_FCR_DMA_SELECT,
> +		.flags		= UART_CAP_FIFO,
> +	},
> +};

I doubt you need all of these port types, right?  You only have one type
of device, please strip out _ALL_ of the unneeded code in here.  You did
a wholesale copy of the old driver, to get away with that you then need
to customize it to work properly with your hardware _AND_ take away all
code that is not needed for your hardware.

Lots of this file can be removed, please do so.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] dt-bindings: Fix generated example files getting added to schemas
From: Guido Günther @ 2019-07-30 15:42 UTC (permalink / raw)
  To: Rob Herring; +Cc: devicetree, linux-kernel
In-Reply-To: <20190730145935.26248-1-robh@kernel.org>

Hi,
On Tue, Jul 30, 2019 at 08:59:35AM -0600, Rob Herring wrote:
> Commit 837158b847a4 ("dt-bindings: Check the examples against the
> schemas") started generating YAML encoded DT files to validate the
> examples against the schema. When running 'make dt_binding_check' in
> tree after the 1st time, the generated example .dt.yaml files are
> mistakenly added to the list of schema files. Exclude *.example.dt.yaml
> files from the search for schema files.
> 
> Fixes: 837158b847a4 ("dt-bindings: Check the examples against the schemas")
> Reported-by: Guido Günther <agx@sigxcpu.org>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  Documentation/devicetree/bindings/Makefile | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile
> index 6b0dfd5c17ba..5138a2f6232a 100644
> --- a/Documentation/devicetree/bindings/Makefile
> +++ b/Documentation/devicetree/bindings/Makefile
> @@ -19,7 +19,9 @@ quiet_cmd_mk_schema = SCHEMA  $@
>  
>  DT_DOCS = $(shell \
>  	cd $(srctree)/$(src) && \
> -	find * \( -name '*.yaml' ! -name $(DT_TMP_SCHEMA) \) \
> +	find * \( -name '*.yaml' ! \
> +		-name $(DT_TMP_SCHEMA) ! \
> +		-name '*.example.dt.yaml' \) \
>  	)
>  
>  DT_SCHEMA_FILES ?= $(addprefix $(src)/,$(DT_DOCS))


this fixes checking twice in a row for me. Thanks!

Tested-by: Guido Günther <agx@sigxcpu.org>

 -- Guido

^ permalink raw reply

* Re: [PATCH 2/4] counter: new TI eQEP driver
From: David Lechner @ 2019-07-30 15:28 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-iio, linux-omap, devicetree, Rob Herring, Mark Rutland,
	Benoît Cousson, Tony Lindgren, William Breathitt Gray,
	Thierry Reding, linux-kernel, linux-pwm
In-Reply-To: <20190730123523.cjtmr3tpttn6r3pt@pengutronix.de>

On 7/30/19 7:35 AM, Uwe Kleine-König wrote:
> On Mon, Jul 22, 2019 at 10:45:36AM -0500, David Lechner wrote:
>> This adds a new counter driver for the Texas Instruments Enhanced
>> Quadrature Encoder Pulse (eQEP) module.
>>
>> Only very basic functionality is currently implemented - only enough to
>> be able to read the position. The actual device has many more features
>> which can be added to the driver on an as-needed basis.
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
>> ---
>>   MAINTAINERS               |   6 +
>>   drivers/counter/Kconfig   |  12 ++
>>   drivers/counter/Makefile  |   1 +
>>   drivers/counter/ti-eqep.c | 381 ++++++++++++++++++++++++++++++++++++++
>>   drivers/pwm/Kconfig       |   2 +-
> 
> It's not obvious why the change to drivers/pwm/Kconfig is needed. Can
> you please motivate that in the change log?

Will do. The short version is that it is needed for power management.

> 
> Best regards
> Uwe
> 

^ permalink raw reply

* Re: [PATCH 1/2] soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.
From: Thara Gopinath @ 2019-07-30 15:27 UTC (permalink / raw)
  To: Amit Kucheria
  Cc: linux-arm-msm, Andy Gross, Rob Herring, Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <CAHLCerO_5CUmdfdyogc0GwKPtPU4xYLU-FqzB8a8y07mnipTuw@mail.gmail.com>

Hi Amit,
Thanks for the review.

On 07/30/2019 08:43 AM, Amit Kucheria wrote:
> On Mon, Jul 29, 2019 at 10:03 PM Thara Gopinath
> <thara.gopinath@linaro.org> wrote:
>>
>> The AOSS QMP driver is extended to communicate with the additional
>> resources. These resources are then registered as cooling devices
>> with the thermal framework.
>>
>> Signed-off-by: Thara Gopinath <thara.gopinath@linaro.org>
>> ---
>>  drivers/soc/qcom/qcom_aoss.c | 129 +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 129 insertions(+)
>>
>> diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
>> index 5f88519..010877e 100644
>> --- a/drivers/soc/qcom/qcom_aoss.c
>> +++ b/drivers/soc/qcom/qcom_aoss.c
>> @@ -10,6 +10,8 @@
>>  #include <linux/module.h>
>>  #include <linux/platform_device.h>
>>  #include <linux/pm_domain.h>
>> +#include <linux/thermal.h>
>> +#include <linux/slab.h>
>>
>>  #define QMP_DESC_MAGIC                 0x0
>>  #define QMP_DESC_VERSION               0x4
>> @@ -40,6 +42,16 @@
>>  /* 64 bytes is enough to store the requests and provides padding to 4 bytes */
>>  #define QMP_MSG_LEN                    64
>>
>> +#define QMP_NUM_COOLING_RESOURCES      2
>> +
>> +static bool qmp_cdev_init_state = 1;
>> +
>> +struct qmp_cooling_device {
>> +       struct thermal_cooling_device *cdev;
>> +       struct qmp *qmp;
>> +       bool state;
>> +};
>> +
>>  /**
>>   * struct qmp - driver state for QMP implementation
>>   * @msgram: iomem referencing the message RAM used for communication
>> @@ -69,6 +81,7 @@ struct qmp {
>>
>>         struct clk_hw qdss_clk;
>>         struct genpd_onecell_data pd_data;
>> +       struct qmp_cooling_device *cooling_devs;
>>  };
>>
>>  struct qmp_pd {
>> @@ -385,6 +398,117 @@ static void qmp_pd_remove(struct qmp *qmp)
>>                 pm_genpd_remove(data->domains[i]);
>>  }
>>
>> +static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
>> +                                 unsigned long *state)
>> +{
>> +       *state = qmp_cdev_init_state;
>> +       return 0;
>> +}
>> +
>> +static int qmp_cdev_get_cur_state(struct thermal_cooling_device *cdev,
>> +                                 unsigned long *state)
>> +{
>> +       struct qmp_cooling_device *qmp_cdev = cdev->devdata;
>> +
>> +       *state = qmp_cdev->state;
>> +       return 0;
>> +}
>> +
>> +static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
>> +                                 unsigned long state)
>> +{
>> +       struct qmp_cooling_device *qmp_cdev = cdev->devdata;
>> +       char buf[QMP_MSG_LEN] = {};
>> +       bool cdev_state;
>> +       int ret;
>> +
>> +       /* Normalize state */
>> +       cdev_state = !!state;
>> +
>> +       if (qmp_cdev->state == state)
>> +               return 0;
>> +
>> +       snprintf(buf, sizeof(buf),
>> +                "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
>> +                       qmp_cdev->name,
> 
> This won't compile, there is no member "name" in qmp_cooling_device.

Yes! Sorry about that. I must have send  this from the wrong folder. I
have fixed this and send out another version. Also taken care of the
other comment below.

Regards
Thara
> 
>> +                       cdev_state ? "off" : "on");
>> +
>> +       ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
>> +
>> +       if (!ret)
>> +               qmp_cdev->state = cdev_state;
>> +
>> +       return ret;
>> +}
>> +
>> +static struct thermal_cooling_device_ops qmp_cooling_device_ops = {
>> +       .get_max_state = qmp_cdev_get_max_state,
>> +       .get_cur_state = qmp_cdev_get_cur_state,
>> +       .set_cur_state = qmp_cdev_set_cur_state,
>> +};
>> +
>> +static int qmp_cooling_device_add(struct qmp *qmp,
>> +                                 struct qmp_cooling_device *qmp_cdev,
>> +                                 struct device_node *node)
>> +{
>> +       char *cdev_name = (char *)node->name;
>> +
>> +       qmp_cdev->qmp = qmp;
>> +       qmp_cdev->state = qmp_cdev_init_state;
>> +       qmp_cdev->cdev = devm_thermal_of_cooling_device_register
>> +                               (qmp->dev, node,
>> +                               cdev_name,
>> +                               qmp_cdev, &qmp_cooling_device_ops);
>> +
>> +       if (IS_ERR(qmp_cdev->cdev))
>> +               dev_err(qmp->dev, "unable to register %s cooling device\n",
>> +                       cdev_name);
>> +
>> +       return PTR_ERR_OR_ZERO(qmp_cdev->cdev);
>> +}
>> +
>> +static int qmp_cooling_devices_register(struct qmp *qmp)
>> +{
>> +       struct device_node *np, *child;
>> +       int count = QMP_NUM_COOLING_RESOURCES;
>> +       int ret;
>> +
>> +       np = qmp->dev->of_node;
>> +
>> +       qmp->cooling_devs = devm_kcalloc(qmp->dev, count,
>> +                                        sizeof(*qmp->cooling_devs),
>> +                                        GFP_KERNEL);
>> +
>> +       if (!qmp->cooling_devs)
>> +               return -ENOMEM;
>> +
>> +       for_each_available_child_of_node(np, child) {
>> +               if (!of_find_property(child, "#cooling-cells", NULL))
>> +                       continue;
>> +               ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
>> +                                            child);
>> +               if (ret)
>> +                       goto uroll_cooling_devices;
> 
> unroll?
> 
>> +       }
>> +
>> +       return 0;
>> +
>> +uroll_cooling_devices:
>> +       while (--count >= 0)
>> +               thermal_cooling_device_unregister
>> +                       (qmp->cooling_devs[count].cdev);
>> +
>> +       return ret;
>> +}
>> +
>> +static void qmp_cooling_devices_remove(struct qmp *qmp)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < QMP_NUM_COOLING_RESOURCES; i++)
>> +               thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev);
>> +}
>> +
>>  static int qmp_probe(struct platform_device *pdev)
>>  {
>>         struct resource *res;
>> @@ -433,6 +557,10 @@ static int qmp_probe(struct platform_device *pdev)
>>         if (ret)
>>                 goto err_remove_qdss_clk;
>>
>> +       ret = qmp_cooling_devices_register(qmp);
>> +       if (ret)
>> +               dev_err(&pdev->dev, "failed to register aoss cooling devices\n");
>> +
>>         platform_set_drvdata(pdev, qmp);
>>
>>         return 0;
>> @@ -453,6 +581,7 @@ static int qmp_remove(struct platform_device *pdev)
>>
>>         qmp_qdss_clk_remove(qmp);
>>         qmp_pd_remove(qmp);
>> +       qmp_cooling_devices_remove(qmp);
>>
>>         qmp_close(qmp);
>>         mbox_free_channel(qmp->mbox_chan);
>> --
>> 2.1.4
>>

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2 3/3] ASoC: TDA7802: Add turn-on diagnostic routine
From: Thomas Preston @ 2019-07-30 15:27 UTC (permalink / raw)
  To: Mark Brown
  Cc: Mark Rutland, devicetree, alsa-devel, Charles Keepax,
	Kuninori Morimoto, Kirill Marinushkin, Liam Girdwood,
	Takashi Iwai, Marco Felsch, Annaliese McDermond, linux-kernel,
	Paul Cercueil, Vinod Koul, Rob Herring, Srinivas Kandagatla,
	Jerome Brunet, Cheng-Yi Chiang
In-Reply-To: <20190730142010.GG4264@sirena.org.uk>

On 30/07/2019 15:20, Mark Brown wrote:
> On Tue, Jul 30, 2019 at 03:04:19PM +0100, Thomas Preston wrote:
>> On 30/07/2019 13:41, Charles Keepax wrote:
> 
>>> This could probably be removed using regmap_multi_reg_write.
> 
>> The problem is that I want to retain the state of the other bits in those
>> registers. Maybe I should make a copy of the backed up state, set the bits
>> I want to off-device, then either:
> 
>> 1. Write the changes with regmap_multi_reg_write
>> 2. Write all six regs again (if my device doesn't support the multi_reg)
> 
> Or make this a regmap function, there's nothing device specific about
> it.
> 

I did wonder why regmap didn't have an multi-update function. If appropriate,
I will add this in.

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2 3/3] ASoC: TDA7802: Add turn-on diagnostic routine
From: Thomas Preston @ 2019-07-30 15:25 UTC (permalink / raw)
  To: Mark Brown
  Cc: Mark Rutland, devicetree, alsa-devel, Charles Keepax,
	Kuninori Morimoto, Kirill Marinushkin, Cheng-Yi Chiang,
	Marco Felsch, Takashi Iwai, Annaliese McDermond, Liam Girdwood,
	Paul Cercueil, Vinod Koul, Rob Herring, Srinivas Kandagatla,
	linux-kernel, Jerome Brunet
In-Reply-To: <20190730141935.GF4264@sirena.org.uk>

On 30/07/2019 15:19, Mark Brown wrote:
> On Tue, Jul 30, 2019 at 01:09:37PM +0100, Thomas Preston wrote:
> 
>> +	struct dentry *debugfs;
>> +	struct mutex diagnostic_mutex;
>> +};
> 
> It is unclear what this mutex usefully protects, it only gets taken when
> writing to the debugfs file to trigger this diagnostic mode but doesn't
> do anything to control interactions with any other code path in the
> driver.
> 

If another process reads the debugfs node "diagnostic" while the turn-on 
diagnostic mode is running, this mutex prevents the second process
restarting the diagnostics.

This is redundant if debugfs reads are atomic, but I don't think they are.


>> +static int run_turn_on_diagnostic(struct tda7802_priv *tda7802, u8 *status)
>> +{
>> +	struct device *dev = &tda7802->i2c->dev;
>> +	int err_status, err;
>> +	unsigned int val;
>> +	u8 state[NUM_IB];
> 
>> +	/* We must wait 20ms for device to settle, otherwise diagnostics will
>> +	 * not start and regmap poll will timeout.
>> +	 */
>> +	msleep(DIAGNOSTIC_SETTLE_MS);
> 
> The comment and define might go out of sync...
> 

Thanks, I will remove the 20ms but keep the comment here.

>> +	err = regmap_bulk_read(tda7802->regmap, TDA7802_DB1, status, 4);
>> +	if (err < 0) {
>> +		dev_err(dev, "Could not read channel status, %d\n", err);
>> +		goto diagnostic_restore;
>> +	}
> 
> ...but here we use a magic number for the array size :(
> 

Thanks, will update.

>> +static int tda7802_diagnostic_show(struct seq_file *f, void *p)
>> +{
>> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> 
> We neither use nor free buf?
> 
>> +static int tda7802_probe(struct snd_soc_component *component)
>> +{
>> +	struct tda7802_priv *tda7802 = snd_soc_component_get_drvdata(component);
>> +	struct device *dev = &tda7802->i2c->dev;
>> +	int err;
> 
> Why is this done at the component level?
> 

Argh my bad, a previous iteration required the buf and component. I missed
this, sorry for the noise.

Thanks for feedback, I'll go back and tend to all of this.

^ permalink raw reply

* [Patch v2 2/2] arm64: dts: qcom: Extend AOSS QMP node
From: Thara Gopinath @ 2019-07-30 15:24 UTC (permalink / raw)
  To: linux-arm-msm, agross, robh+dt, mark.rutland, bjorn.andersson,
	amit.kucheria, vinod.koul
  Cc: devicetree, linux-kernel
In-Reply-To: <1564500283-16038-1-git-send-email-thara.gopinath@linaro.org>

AOSS hosts resources that can be used to warm up the SoC.
Add nodes for these resources.

Signed-off-by: Thara Gopinath <thara.gopinath@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 4babff5..d0c0d4f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -2411,6 +2411,14 @@
 
 			#clock-cells = <0>;
 			#power-domain-cells = <1>;
+
+			cx_cdev: cx {
+				#cooling-cells = <2>;
+			};
+
+			ebi_cdev: ebi {
+				#cooling-cells = <2>;
+			};
 		};
 
 		spmi_bus: spmi@c440000 {
-- 
2.1.4

^ permalink raw reply related

* [Patch v2 1/2] soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.
From: Thara Gopinath @ 2019-07-30 15:24 UTC (permalink / raw)
  To: linux-arm-msm, agross, robh+dt, mark.rutland, bjorn.andersson,
	amit.kucheria, vinod.koul
  Cc: devicetree, linux-kernel
In-Reply-To: <1564500283-16038-1-git-send-email-thara.gopinath@linaro.org>

The AOSS QMP driver is extended to communicate with the additional
resources. These resources are then registered as cooling devices
with the thermal framework.

Signed-off-by: Thara Gopinath <thara.gopinath@linaro.org>
---
v1->v2:
        Added back name variable in qmp_cooling_device to fix the 
        compilation error.               
        Other minor naming changes as mentioned in review on the list.

 drivers/soc/qcom/qcom_aoss.c | 131 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index 5f88519..dc6201e 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -10,6 +10,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
+#include <linux/thermal.h>
+#include <linux/slab.h>
 
 #define QMP_DESC_MAGIC			0x0
 #define QMP_DESC_VERSION		0x4
@@ -40,6 +42,17 @@
 /* 64 bytes is enough to store the requests and provides padding to 4 bytes */
 #define QMP_MSG_LEN			64
 
+#define QMP_NUM_COOLING_RESOURCES	2
+
+static bool qmp_cdev_init_state = 1;
+
+struct qmp_cooling_device {
+	struct thermal_cooling_device *cdev;
+	struct qmp *qmp;
+	char *name;
+	bool state;
+};
+
 /**
  * struct qmp - driver state for QMP implementation
  * @msgram: iomem referencing the message RAM used for communication
@@ -69,6 +82,7 @@ struct qmp {
 
 	struct clk_hw qdss_clk;
 	struct genpd_onecell_data pd_data;
+	struct qmp_cooling_device *cooling_devs;
 };
 
 struct qmp_pd {
@@ -385,6 +399,118 @@ static void qmp_pd_remove(struct qmp *qmp)
 		pm_genpd_remove(data->domains[i]);
 }
 
+static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
+				  unsigned long *state)
+{
+	*state = qmp_cdev_init_state;
+	return 0;
+}
+
+static int qmp_cdev_get_cur_state(struct thermal_cooling_device *cdev,
+				  unsigned long *state)
+{
+	struct qmp_cooling_device *qmp_cdev = cdev->devdata;
+
+	*state = qmp_cdev->state;
+	return 0;
+}
+
+static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
+				  unsigned long state)
+{
+	struct qmp_cooling_device *qmp_cdev = cdev->devdata;
+	char buf[QMP_MSG_LEN] = {};
+	bool cdev_state;
+	int ret;
+
+	/* Normalize state */
+	cdev_state = !!state;
+
+	if (qmp_cdev->state == state)
+		return 0;
+
+	snprintf(buf, sizeof(buf),
+		 "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
+			qmp_cdev->name,
+			cdev_state ? "off" : "on");
+
+	ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
+
+	if (!ret)
+		qmp_cdev->state = cdev_state;
+
+	return ret;
+}
+
+static struct thermal_cooling_device_ops qmp_cooling_device_ops = {
+	.get_max_state = qmp_cdev_get_max_state,
+	.get_cur_state = qmp_cdev_get_cur_state,
+	.set_cur_state = qmp_cdev_set_cur_state,
+};
+
+static int qmp_cooling_device_add(struct qmp *qmp,
+				  struct qmp_cooling_device *qmp_cdev,
+				  struct device_node *node)
+{
+	char *cdev_name = (char *)node->name;
+
+	qmp_cdev->qmp = qmp;
+	qmp_cdev->state = qmp_cdev_init_state;
+	qmp_cdev->name = cdev_name;
+	qmp_cdev->cdev = devm_thermal_of_cooling_device_register
+				(qmp->dev, node,
+				cdev_name,
+				qmp_cdev, &qmp_cooling_device_ops);
+
+	if (IS_ERR(qmp_cdev->cdev))
+		dev_err(qmp->dev, "unable to register %s cooling device\n",
+			cdev_name);
+
+	return PTR_ERR_OR_ZERO(qmp_cdev->cdev);
+}
+
+static int qmp_cooling_devices_register(struct qmp *qmp)
+{
+	struct device_node *np, *child;
+	int count = QMP_NUM_COOLING_RESOURCES;
+	int ret;
+
+	np = qmp->dev->of_node;
+
+	qmp->cooling_devs = devm_kcalloc(qmp->dev, count,
+					 sizeof(*qmp->cooling_devs),
+					 GFP_KERNEL);
+
+	if (!qmp->cooling_devs)
+		return -ENOMEM;
+
+	for_each_available_child_of_node(np, child) {
+		if (!of_find_property(child, "#cooling-cells", NULL))
+			continue;
+		ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
+					     child);
+		if (ret)
+			goto uroll;
+	}
+
+	return 0;
+
+uroll:
+	while (--count >= 0)
+		thermal_cooling_device_unregister
+			(qmp->cooling_devs[count].cdev);
+
+	return ret;
+}
+
+static void qmp_cooling_devices_remove(struct qmp *qmp)
+{
+	int i;
+
+	for (i = 0; i < QMP_NUM_COOLING_RESOURCES; i++)
+		thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev);
+}
+
 static int qmp_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -433,6 +559,10 @@ static int qmp_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_remove_qdss_clk;
 
+	ret = qmp_cooling_devices_register(qmp);
+	if (ret)
+		dev_err(&pdev->dev, "failed to register aoss cooling devices\n");
+
 	platform_set_drvdata(pdev, qmp);
 
 	return 0;
@@ -453,6 +583,7 @@ static int qmp_remove(struct platform_device *pdev)
 
 	qmp_qdss_clk_remove(qmp);
 	qmp_pd_remove(qmp);
+	qmp_cooling_devices_remove(qmp);
 
 	qmp_close(qmp);
 	mbox_free_channel(qmp->mbox_chan);
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox