Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for ARCH_MXC platforms
From: Shawn Guo @ 2019-07-22  3:19 UTC (permalink / raw)
  To: Anson Huang
  Cc: mark.rutland@arm.com, Aisheng Dong, Peng Fan, festevam@gmail.com,
	Jacky Bai, devicetree@vger.kernel.org, sboyd@kernel.org,
	catalin.marinas@arm.com, s.hauer@pengutronix.de,
	linux-kernel@vger.kernel.org, Daniel Baluta,
	linux-clk@vger.kernel.org, robh+dt@kernel.org, dl-linux-imx,
	kernel@pengutronix.de, Leonard Crestez, will@kernel.org, mturqu
In-Reply-To: <AM6PR0402MB39113A76EE8A63F9C9F589C1F5C40@AM6PR0402MB3911.eurprd04.prod.outlook.com>

On Mon, Jul 22, 2019 at 02:15:10AM +0000, Anson Huang wrote:
> Hi, Shawn
> 
> > On Mon, Jun 24, 2019 at 02:35:10AM +0000, Anson Huang wrote:
> > > Hi, Shawn
> > >
> > > > -----Original Message-----
> > > > From: Shawn Guo <shawnguo@kernel.org>
> > > > Sent: Monday, June 24, 2019 10:27 AM
> > > > To: Anson Huang <anson.huang@nxp.com>
> > > > Cc: mark.rutland@arm.com; Aisheng Dong <aisheng.dong@nxp.com>;
> > Peng
> > > > Fan <peng.fan@nxp.com>; festevam@gmail.com; Jacky Bai
> > > > <ping.bai@nxp.com>; devicetree@vger.kernel.org; sboyd@kernel.org;
> > > > catalin.marinas@arm.com; s.hauer@pengutronix.de; linux-
> > > > kernel@vger.kernel.org; Daniel Baluta <daniel.baluta@nxp.com>;
> > > > linux- clk@vger.kernel.org; robh+dt@kernel.org; dl-linux-imx <linux-
> > > > imx@nxp.com>; kernel@pengutronix.de; Leonard Crestez
> > > > <leonard.crestez@nxp.com>; will@kernel.org; mturquette@baylibre.com;
> > > > linux-arm-kernel@lists.infradead.org; Abel Vesa <abel.vesa@nxp.com>
> > > > Subject: Re: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for
> > > > ARCH_MXC platforms
> > > >
> > > > On Mon, Jun 24, 2019 at 10:22:01AM +0800, Shawn Guo wrote:
> > > > > On Fri, Jun 21, 2019 at 03:07:17PM +0800, Anson.Huang@nxp.com
> > wrote:
> > > > > > From: Anson Huang <Anson.Huang@nxp.com>
> > > > > >
> > > > > > ARCH_MXC platforms needs system counter as broadcast timer to
> > > > > > support cpuidle, enable it by default.
> > > > > >
> > > > > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > > > > > ---
> > > > > >  arch/arm64/Kconfig.platforms | 1 +
> > > > > >  1 file changed, 1 insertion(+)
> > > > > >
> > > > > > diff --git a/arch/arm64/Kconfig.platforms
> > > > > > b/arch/arm64/Kconfig.platforms index 4778c77..f5e623f 100644
> > > > > > --- a/arch/arm64/Kconfig.platforms
> > > > > > +++ b/arch/arm64/Kconfig.platforms
> > > > > > @@ -173,6 +173,7 @@ config ARCH_MXC
> > > > > >  	select PM
> > > > > >  	select PM_GENERIC_DOMAINS
> > > > > >  	select SOC_BUS
> > > > > > +	select TIMER_IMX_SYS_CTR
> > > > >
> > > > > Where is that driver?
> > > >
> > > > Okay, just found it in the mailbox.  They seem to be sent in the wrong
> > order.
> > > > Really, you should send this series only after the driver lands on mainline.
> > >
> > > OK, just noticed that mainline does NOT have it, since I did it based on next
> > tree.
> > > I will resend the patch series after the system counter driver landing on
> > mainline.
> > 
> > I just picked the series up, so no need to resend.
> 
> Something changed for this series, the system counter clock related implementation
> are changed after some comments from maintainer, so I think you should picked up
> below patch series instead, and drop this series,
> 
> https://patchwork.kernel.org/patch/11037953/

Okay, dropped clk and dts patches.  arch/arm64/Kconfig.platforms one is kept.

Shawn

^ permalink raw reply

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
From: Sowjanya Komatineni @ 2019-07-22  3:17 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <042f4b43-7b9c-533d-2548-d903b34363da@nvidia.com>


On 7/21/19 3:39 PM, Sowjanya Komatineni wrote:
>
> On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> This patch has a fix to enable PLLP branches to CPU before changing
>>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>>
>>> During system suspend entry and exit, CPU source will be switched
>>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>>> the switch.
>>>
>>> On system resume, warmboot code enables PLLP branches to CPU and
>>> powers up the CPU with PLLP clock source.
>>>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>>   drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>>   drivers/clk/tegra/clk.h                  |  4 ++++
>>>   3 files changed, 17 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-super.c 
>>> b/drivers/clk/tegra/clk-super.c
>>> index 39ef31b46df5..d73c587e4853 100644
>>> --- a/drivers/clk/tegra/clk-super.c
>>> +++ b/drivers/clk/tegra/clk-super.c
>>> @@ -28,6 +28,9 @@
>>>   #define super_state_to_src_shift(m, s) ((m->width * s))
>>>   #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>>   +#define CCLK_SRC_PLLP_OUT0 4
>>> +#define CCLK_SRC_PLLP_OUT4 5
>>> +
>>>   static u8 clk_super_get_parent(struct clk_hw *hw)
>>>   {
>>>       struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw 
>>> *hw, u8 index)
>>>           if (index == mux->div2_index)
>>>               index = mux->pllx_index;
>>>       }
>>> +
>>> +    /*
>>> +     * Enable PLLP branches to CPU before selecting PLLP source
>>> +     */
>>> +    if ((mux->flags & TEGRA_CPU_CLK) &&
>>> +        ((index == CCLK_SRC_PLLP_OUT0) || (index == 
>>> CCLK_SRC_PLLP_OUT4)))
>>> +        tegra_clk_set_pllp_out_cpu(true);
>> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
>> switching from PLLP?
> PLLP may be used for other CPU clusters.

Though to avoid flag and check needed to make sure other CPU is not 
using before disabling PLLP branch to CPU.

But leaving it enabled shouldn't impact much as clock source mux is 
after this in design anyway.

But can add as well if its clear that way.

>>>       val &= ~((super_state_to_src_mask(mux)) << shift);
>>>       val |= (index & (super_state_to_src_mask(mux))) << shift;
>>>   diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c 
>>> b/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> index cdfe7c9697e1..cd208d0eca2a 100644
>>> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
>>> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void 
>>> __iomem *clk_base,
>>>                       gen_info->num_cclk_g_parents,
>>>                       CLK_SET_RATE_PARENT,
>>>                       clk_base + CCLKG_BURST_POLICY,
>>> -                    0, 4, 8, 0, NULL);
>>> +                    TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>>           } else {
>>>               clk = tegra_clk_register_super_mux("cclk_g",
>>>                       gen_info->cclk_g_parents,
>>> @@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void 
>>> __iomem *clk_base,
>>>                       gen_info->num_cclk_lp_parents,
>>>                       CLK_SET_RATE_PARENT,
>>>                       clk_base + CCLKLP_BURST_POLICY,
>>> -                    0, 4, 8, 0, NULL);
>>> +                    TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>>           } else {
>>>               clk = tegra_clk_register_super_mux("cclk_lp",
>>>                       gen_info->cclk_lp_parents,
>>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>>> index ac6de3a0b91f..c357b49e49b0 100644
>>> --- a/drivers/clk/tegra/clk.h
>>> +++ b/drivers/clk/tegra/clk.h
>>> @@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void 
>>> __iomem *clk_base,
>>>    * Flags:
>>>    * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag 
>>> indicates
>>>    *     that this is LP cluster clock.
>>> + * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. 
>>> To use PLLP
>>> + * for CPU clock source, need to enable PLLP branches to CPU by 
>>> setting the
>>> + * additional bit PLLP_OUT_CPU for gen5 super clock.
>>>    */
>>>   struct tegra_clk_super_mux {
>>>       struct clk_hw    hw;
>>> @@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
>>>   #define to_clk_super_mux(_hw) container_of(_hw, struct 
>>> tegra_clk_super_mux, hw)
>>>     #define TEGRA_DIVIDER_2 BIT(0)
>>> +#define TEGRA_CPU_CLK    BIT(1)
>> I'd name this TEGRA210_CPU_CLK for clarity.
>>
>>>   extern const struct clk_ops tegra_clk_super_ops;
>>>   struct clk *tegra_clk_register_super_mux(const char *name,
>>>
>> Will be better to move the tegra_clk_set_pllp_out_cpu() definition into
>> this patch, otherwise this looks inconsistent for reviewer.
> ok, Will move to this patch

^ permalink raw reply

* Re: [PATCH V5 3/5] arm64: dts: imx8mm: Add system counter node
From: Shawn Guo @ 2019-07-22  3:15 UTC (permalink / raw)
  To: Anson.Huang
  Cc: catalin.marinas, will, robh+dt, mark.rutland, s.hauer, kernel,
	festevam, linux-imx, daniel.lezcano, tglx, leonard.crestez,
	aisheng.dong, daniel.baluta, ping.bai, l.stach, abel.vesa,
	andrew.smirnov, ccaione, angus, agx, linux-arm-kernel,
	linux-kernel, devicetree
In-Reply-To: <20190710063056.35689-3-Anson.Huang@nxp.com>

On Wed, Jul 10, 2019 at 02:30:54PM +0800, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> Add i.MX8MM system counter node to enable timer-imx-sysctr
> broadcast timer driver.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Do I need to wait for patch #1 landing before I apply #3 ~ #5, or can
they be applied independently (no breaking on anything)?

Shawn

> ---
> Changes since V4:
> 	- update the clock info using fixed clock node;
> 	- correct the reg range;
> 	- update the interrupt number as the system counter driver ONLY uses 1 irq now.
> ---
>  arch/arm64/boot/dts/freescale/imx8mm.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
> index b5637f8..8cf7f34 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
> @@ -560,6 +560,14 @@
>  				#pwm-cells = <2>;
>  				status = "disabled";
>  			};
> +
> +			system_counter: timer@306a0000 {
> +				compatible = "nxp,sysctr-timer";
> +				reg = <0x306a0000 0x20000>;
> +				interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
> +				clocks = <&osc_24m>;
> +				clock-names = "per";
> +			};
>  		};
>  
>  		aips3: bus@30800000 {
> -- 
> 2.7.4
> 

^ permalink raw reply

* Re: [PATCH V5 2/5] arm64: Enable TIMER_IMX_SYS_CTR for ARCH_MXC platforms
From: Shawn Guo @ 2019-07-22  3:12 UTC (permalink / raw)
  To: Anson.Huang
  Cc: catalin.marinas, will, robh+dt, mark.rutland, s.hauer, kernel,
	festevam, linux-imx, daniel.lezcano, tglx, leonard.crestez,
	aisheng.dong, daniel.baluta, ping.bai, l.stach, abel.vesa,
	andrew.smirnov, ccaione, angus, agx, linux-arm-kernel,
	linux-kernel, devicetree
In-Reply-To: <20190710063056.35689-2-Anson.Huang@nxp.com>

On Wed, Jul 10, 2019 at 02:30:53PM +0800, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> ARCH_MXC platforms needs system counter as broadcast timer
> to support cpuidle, enable it by default.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

This one is identical to what I just picked up from v4 series, right?

Shawn

^ permalink raw reply

* [PATCH 3/3] remoteproc: ingenic: Added remoteproc driver
From: Paul Cercueil @ 2019-07-22  2:31 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Rob Herring, Mark Rutland
  Cc: linux-remoteproc, devicetree, linux-kernel, od, Paul Cercueil
In-Reply-To: <20190722023140.14701-1-paul@crapouillou.net>

This driver is used to boot, communicate with and load firmwares to the
MIPS co-processor found in the VPU hardware of the JZ47xx SoCs from
Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/remoteproc/Kconfig         |   8 +
 drivers/remoteproc/Makefile        |   1 +
 drivers/remoteproc/ingenic_rproc.c | 302 +++++++++++++++++++++++++++++
 3 files changed, 311 insertions(+)
 create mode 100644 drivers/remoteproc/ingenic_rproc.c

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 28ed306982f7..a0be40e2098d 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -214,6 +214,14 @@ config STM32_RPROC
 
 	  This can be either built-in or a loadable module.
 
+config INGENIC_RPROC
+	tristate "Ingenic JZ47xx VPU remoteproc support"
+	depends on MIPS || COMPILE_TEST
+	help
+	  Say y or m here to support the VPU in the JZ47xx SoCs from Ingenic.
+	  This can be either built-in or a loadable module.
+	  If unsure say N.
+
 endif # REMOTEPROC
 
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 00f09e658cb3..6eb0137abbc7 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -10,6 +10,7 @@ remoteproc-y				+= remoteproc_sysfs.o
 remoteproc-y				+= remoteproc_virtio.o
 remoteproc-y				+= remoteproc_elf_loader.o
 obj-$(CONFIG_IMX_REMOTEPROC)		+= imx_rproc.o
+obj-$(CONFIG_INGENIC_RPROC)			+= ingenic_rproc.o
 obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
 obj-$(CONFIG_WKUP_M3_RPROC)		+= wkup_m3_rproc.o
 obj-$(CONFIG_DA8XX_REMOTEPROC)		+= da8xx_remoteproc.o
diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c
new file mode 100644
index 000000000000..a4963158bdd3
--- /dev/null
+++ b/drivers/remoteproc/ingenic_rproc.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ingenic JZ47xx remoteproc driver
+ * Copyright 2019, Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+
+#include "remoteproc_internal.h"
+
+#define REG_AUX_CTRL		0x0
+#define REG_AUX_MSG_ACK		0x10
+#define REG_AUX_MSG		0x14
+#define REG_CORE_MSG_ACK	0x18
+#define REG_CORE_MSG		0x1C
+
+#define AUX_CTRL_SLEEP		BIT(31)
+#define AUX_CTRL_MSG_IRQ_EN	BIT(3)
+#define AUX_CTRL_NMI_RESETS	BIT(2)
+#define AUX_CTRL_NMI		BIT(1)
+#define AUX_CTRL_SW_RESET	BIT(0)
+
+struct vpu_mem_map {
+	const char *name;
+	unsigned int da;
+	bool direct_io;
+};
+
+struct vpu_mem_info {
+	const struct vpu_mem_map *map;
+	unsigned long len;
+	void __iomem *base;
+};
+
+static const struct vpu_mem_map vpu_mem_map[] = {
+	{ "tcsm0", 0x132b0000, true },
+	{ "tcsm1", 0xf4000000 },
+	{ "sram",  0x132f0000 },
+};
+
+/* Device data */
+struct vpu {
+	int irq;
+	struct clk *vpu_clk;
+	struct clk *aux_clk;
+	void __iomem *aux_base;
+	struct vpu_mem_info mem_info[ARRAY_SIZE(vpu_mem_map)];
+	struct device *dev;
+};
+
+static int ingenic_rproc_prepare(struct rproc *rproc)
+{
+	struct vpu *vpu = rproc->priv;
+	int ret;
+
+	ret = clk_prepare_enable(vpu->vpu_clk);
+	if (ret) {
+		dev_err(vpu->dev, "Unable to start VPU clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(vpu->aux_clk);
+	if (ret) {
+		dev_err(vpu->dev, "Unable to start AUX clock: %d\n", ret);
+		goto err_disable_vpu_clk;
+	}
+
+	return 0;
+
+err_disable_vpu_clk:
+	clk_disable_unprepare(vpu->vpu_clk);
+	return ret;
+}
+
+static void ingenic_rproc_unprepare(struct rproc *rproc)
+{
+	struct vpu *vpu = rproc->priv;
+
+	clk_disable_unprepare(vpu->aux_clk);
+	clk_disable_unprepare(vpu->vpu_clk);
+}
+
+static int ingenic_rproc_start(struct rproc *rproc)
+{
+	struct vpu *vpu = rproc->priv;
+	u32 ctrl;
+
+	enable_irq(vpu->irq);
+
+	/* Reset the AUX and enable message IRQ */
+	ctrl = AUX_CTRL_NMI_RESETS | AUX_CTRL_NMI | AUX_CTRL_MSG_IRQ_EN;
+	writel(ctrl, vpu->aux_base + REG_AUX_CTRL);
+
+	return 0;
+}
+
+static int ingenic_rproc_stop(struct rproc *rproc)
+{
+	struct vpu *vpu = rproc->priv;
+
+	/* Keep AUX in reset mode */
+	writel(AUX_CTRL_SW_RESET, vpu->aux_base + REG_AUX_CTRL);
+
+	disable_irq_nosync(vpu->irq);
+
+	return 0;
+}
+
+static void ingenic_rproc_kick(struct rproc *rproc, int vqid)
+{
+	struct vpu *vpu = rproc->priv;
+
+	writel(vqid, vpu->aux_base + REG_CORE_MSG);
+}
+
+static void *ingenic_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+	struct vpu *vpu = rproc->priv;
+	void __iomem *va = NULL;
+	unsigned int i;
+
+	if (len <= 0)
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(vpu_mem_map); i++) {
+		const struct vpu_mem_info *info = &vpu->mem_info[i];
+		const struct vpu_mem_map *map = info->map;
+
+		if (da >= map->da && (da + len) < (map->da + info->len)) {
+			va = info->base + (da - map->da);
+			break;
+		}
+	}
+
+	return (__force void *)va;
+}
+
+static struct rproc_ops ingenic_rproc_ops = {
+	.prepare = ingenic_rproc_prepare,
+	.unprepare = ingenic_rproc_unprepare,
+	.start = ingenic_rproc_start,
+	.stop = ingenic_rproc_stop,
+	.kick = ingenic_rproc_kick,
+	.da_to_va = ingenic_rproc_da_to_va,
+};
+
+static irqreturn_t vpu_interrupt(int irq, void *data)
+{
+	struct rproc *rproc = data;
+	struct vpu *vpu = rproc->priv;
+	u32 vring;
+
+	vring = readl(vpu->aux_base + REG_AUX_MSG);
+
+	/* Ack the interrupt */
+	writel(0, vpu->aux_base + REG_AUX_MSG_ACK);
+
+	return rproc_vq_interrupt(rproc, vring);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ingenic_rproc_of_matches[] = {
+	{ .compatible = "ingenic,jz4770-vpu-rproc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ingenic_rproc_of_matches);
+#endif
+
+static void ingenic_rproc_free(void *rproc)
+{
+	rproc_free(rproc);
+}
+
+static void ingenic_rproc_unregister(void *rproc)
+{
+	rproc_del(rproc);
+	rproc_shutdown(rproc);
+}
+
+static int ingenic_rproc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *mem;
+	struct rproc *rproc;
+	struct vpu *vpu;
+	unsigned int i;
+	int ret;
+
+	rproc = rproc_alloc(dev, "ingenic-vpu",
+			    &ingenic_rproc_ops, NULL, sizeof(*vpu));
+	if (!rproc)
+		return -ENOMEM;
+
+	ret = devm_add_action_or_reset(dev, ingenic_rproc_free, rproc);
+	if (ret) {
+		dev_err(dev, "Unable to add action");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, rproc);
+	vpu = rproc->priv;
+	vpu->dev = &pdev->dev;
+
+	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aux");
+	vpu->aux_base = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(vpu->aux_base)) {
+		dev_err(dev, "Failed to ioremap");
+		return PTR_ERR(vpu->aux_base);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vpu_mem_map); i++) {
+		mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   vpu_mem_map[i].name);
+
+		if (vpu_mem_map[i].direct_io) {
+			/*
+			 * Handle shared memories that cannot be iomapped.
+			 * They can be read or written directly through their
+			 * physical address.
+			 */
+			if (!devm_request_mem_region(dev, mem->start,
+						     resource_size(mem),
+						     dev_name(dev))) {
+				dev_err(dev, "Unable to request memory region");
+				return -EBUSY;
+			}
+
+			vpu->mem_info[i].base = (void __iomem *)mem->start;
+		} else {
+			vpu->mem_info[i].base = devm_ioremap_resource(dev, mem);
+			if (IS_ERR(vpu->mem_info[i].base)) {
+				ret = PTR_ERR(vpu->mem_info[i].base);
+				dev_err(dev, "Failed to ioremap");
+				return ret;
+			}
+		}
+
+		vpu->mem_info[i].len = resource_size(mem);
+		vpu->mem_info[i].map = &vpu_mem_map[i];
+	}
+
+	vpu->vpu_clk = devm_clk_get(dev, "vpu");
+	if (IS_ERR(vpu->vpu_clk)) {
+		dev_err(dev, "Failed to get VPU clock");
+		return PTR_ERR(vpu->vpu_clk);
+	}
+
+	vpu->aux_clk = devm_clk_get(dev, "aux");
+	if (IS_ERR(vpu->aux_clk)) {
+		dev_err(dev, "Failed to get AUX clock");
+		return PTR_ERR(vpu->aux_clk);
+	}
+
+	vpu->irq = platform_get_irq(pdev, 0);
+	if (vpu->irq < 0) {
+		dev_err(dev, "Failed to get platform IRQ");
+		return vpu->irq;
+	}
+
+	ret = devm_request_irq(dev, vpu->irq, vpu_interrupt, 0, "VPU", rproc);
+	if (ret < 0) {
+		dev_err(dev, "Failed to request IRQ");
+		return ret;
+	}
+
+	disable_irq_nosync(vpu->irq);
+
+	ret = rproc_add(rproc);
+	if (ret) {
+		dev_err(dev, "Failed to register remote processor");
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev, ingenic_rproc_unregister, rproc);
+	if (ret) {
+		dev_err(dev, "Unable to add action");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver ingenic_rproc_driver = {
+	.probe = ingenic_rproc_probe,
+	.driver = {
+		.name = "ingenic-vpu",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(ingenic_rproc_of_matches),
+	},
+};
+module_platform_driver(ingenic_rproc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ47xx Remote Processor control driver");
-- 
2.21.0.593.g511ec345e18

^ permalink raw reply related

* [PATCH 2/3] remoteproc: Add prepare/unprepare callbacks
From: Paul Cercueil @ 2019-07-22  2:31 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Rob Herring, Mark Rutland
  Cc: linux-remoteproc, devicetree, linux-kernel, od, Paul Cercueil
In-Reply-To: <20190722023140.14701-1-paul@crapouillou.net>

The .prepare() callback is called before the firmware is loaded to
memory. This is useful for instance in the case where some setup is
required for the memory to be accessible.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/remoteproc/remoteproc_core.c | 16 +++++++++++++++-
 include/linux/remoteproc.h           |  4 ++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 3c5fbbbfb0f1..68faad3ef0c1 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1300,11 +1300,19 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
 	struct device *dev = &rproc->dev;
 	int ret;
 
+	if (rproc->ops->prepare) {
+		ret = rproc->ops->prepare(rproc);
+		if (ret) {
+			dev_err(dev, "Failed to prepare rproc: %d\n", ret);
+			return ret;
+		}
+	}
+
 	/* load the ELF segments to memory */
 	ret = rproc_load_segments(rproc, fw);
 	if (ret) {
 		dev_err(dev, "Failed to load program segments: %d\n", ret);
-		return ret;
+		goto unprepare_rproc;
 	}
 
 	/*
@@ -1355,6 +1363,9 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
 	rproc_unprepare_subdevices(rproc);
 reset_table_ptr:
 	rproc->table_ptr = rproc->cached_table;
+unprepare_rproc:
+	if (rproc->ops->unprepare)
+		rproc->ops->unprepare(rproc);
 
 	return ret;
 }
@@ -1484,6 +1495,9 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
 
 	rproc->state = RPROC_OFFLINE;
 
+	if (rproc->ops->unprepare)
+		rproc->ops->unprepare(rproc);
+
 	dev_info(dev, "stopped remote processor %s\n", rproc->name);
 
 	return 0;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..be65c2a92c58 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -355,6 +355,8 @@ enum rsc_handling_status {
 
 /**
  * struct rproc_ops - platform-specific device handlers
+ * @prepare:	prepare the device for power up (before the firmware is loaded)
+ * @unprepare:	unprepare the device after it is stopped
  * @start:	power on the device and boot it
  * @stop:	power off the device
  * @kick:	kick a virtqueue (virtqueue id given as a parameter)
@@ -371,6 +373,8 @@ enum rsc_handling_status {
  * @get_boot_addr:	get boot address to entry point specified in firmware
  */
 struct rproc_ops {
+	int (*prepare)(struct rproc *rproc);
+	void (*unprepare)(struct rproc *rproc);
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-- 
2.21.0.593.g511ec345e18

^ permalink raw reply related

* [PATCH 1/3] dt-bindings: Document JZ47xx VPU auxiliary processor
From: Paul Cercueil @ 2019-07-22  2:31 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Rob Herring, Mark Rutland
  Cc: linux-remoteproc, devicetree, linux-kernel, od, Paul Cercueil

Inside the Video Processing Unit (VPU) of the recent JZ47xx SoCs from
Ingenic is a second Xburst MIPS CPU very similar to the main core.
This document describes the devicetree bindings for this auxiliary
processor.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/remoteproc/ingenic,vpu.txt       | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/remoteproc/ingenic,vpu.txt

diff --git a/Documentation/devicetree/bindings/remoteproc/ingenic,vpu.txt b/Documentation/devicetree/bindings/remoteproc/ingenic,vpu.txt
new file mode 100644
index 000000000000..fde86ad5a008
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/ingenic,vpu.txt
@@ -0,0 +1,36 @@
+* Ingenic JZ47xx auxiliary processor
+
+Inside the Video Processing Unit (VPU) of the recent JZ47xx SoCs from Ingenic
+is a second Xburst MIPS CPU very similar to the main core.
+This document describes the devicetree bindings for this auxiliary processor.
+
+Required properties:
+- compatible: Should be "ingenic,jz4770-vpu-rproc"
+- reg: Must contain the registers location and length for:
+  * the auxiliary processor,
+  * the Tightly Coupled Shared Memory 0 (TCSM0),
+  * the Tightly Coupled Shared Memory 1 (TCSM1),
+  * the shared SRAM.
+- reg-names: Must contain "aux", "tcsm0", "tcsm1", "sram".
+- clocks: Clock specifier for the AUX and VPU clocks.
+- clock-names: Must contain "aux", "vpu".
+- interrupts: Interrupt specifier for the VPU hardware block.
+
+Example:
+
+vpu: cpu@132a0000 {
+	compatible = "ingenic,jz4770-vpu-rproc";
+
+	reg = <0x132a0000 0x20 /* AUX */
+		   0xf4000000 0x4000 /* TCSM0 */
+		   0x132c0000 0xc000 /* TCSM1 */
+		   0x132f0000 0x7000 /* SRAM */
+	>;
+	reg-names = "aux", "tcsm0", "tcsm1", "sram";
+
+	clocks = <&cgu JZ4770_CLK_AUX>, <&cgu JZ4770_CLK_VPU>;
+	clock-names = "aux", "vpu";
+
+	interrupt-parent = <&cpuintc>;
+	interrupts = <3>;
+};
-- 
2.21.0.593.g511ec345e18

^ permalink raw reply related

* RE: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for ARCH_MXC platforms
From: Anson Huang @ 2019-07-22  2:15 UTC (permalink / raw)
  To: Shawn Guo
  Cc: mark.rutland@arm.com, Aisheng Dong, Peng Fan, Jacky Bai,
	will@kernel.org, devicetree@vger.kernel.org, sboyd@kernel.org,
	catalin.marinas@arm.com, s.hauer@pengutronix.de,
	linux-kernel@vger.kernel.org, Daniel Baluta,
	mturquette@baylibre.com, robh+dt@kernel.org, dl-linux-imx,
	kernel@pengutronix.de, Leonard Crestez, festevam@gmail.com,
	linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190722020026.GQ3738@dragon>

Hi, Shawn

> On Mon, Jun 24, 2019 at 02:35:10AM +0000, Anson Huang wrote:
> > Hi, Shawn
> >
> > > -----Original Message-----
> > > From: Shawn Guo <shawnguo@kernel.org>
> > > Sent: Monday, June 24, 2019 10:27 AM
> > > To: Anson Huang <anson.huang@nxp.com>
> > > Cc: mark.rutland@arm.com; Aisheng Dong <aisheng.dong@nxp.com>;
> Peng
> > > Fan <peng.fan@nxp.com>; festevam@gmail.com; Jacky Bai
> > > <ping.bai@nxp.com>; devicetree@vger.kernel.org; sboyd@kernel.org;
> > > catalin.marinas@arm.com; s.hauer@pengutronix.de; linux-
> > > kernel@vger.kernel.org; Daniel Baluta <daniel.baluta@nxp.com>;
> > > linux- clk@vger.kernel.org; robh+dt@kernel.org; dl-linux-imx <linux-
> > > imx@nxp.com>; kernel@pengutronix.de; Leonard Crestez
> > > <leonard.crestez@nxp.com>; will@kernel.org; mturquette@baylibre.com;
> > > linux-arm-kernel@lists.infradead.org; Abel Vesa <abel.vesa@nxp.com>
> > > Subject: Re: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for
> > > ARCH_MXC platforms
> > >
> > > On Mon, Jun 24, 2019 at 10:22:01AM +0800, Shawn Guo wrote:
> > > > On Fri, Jun 21, 2019 at 03:07:17PM +0800, Anson.Huang@nxp.com
> wrote:
> > > > > From: Anson Huang <Anson.Huang@nxp.com>
> > > > >
> > > > > ARCH_MXC platforms needs system counter as broadcast timer to
> > > > > support cpuidle, enable it by default.
> > > > >
> > > > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > > > > ---
> > > > >  arch/arm64/Kconfig.platforms | 1 +
> > > > >  1 file changed, 1 insertion(+)
> > > > >
> > > > > diff --git a/arch/arm64/Kconfig.platforms
> > > > > b/arch/arm64/Kconfig.platforms index 4778c77..f5e623f 100644
> > > > > --- a/arch/arm64/Kconfig.platforms
> > > > > +++ b/arch/arm64/Kconfig.platforms
> > > > > @@ -173,6 +173,7 @@ config ARCH_MXC
> > > > >  	select PM
> > > > >  	select PM_GENERIC_DOMAINS
> > > > >  	select SOC_BUS
> > > > > +	select TIMER_IMX_SYS_CTR
> > > >
> > > > Where is that driver?
> > >
> > > Okay, just found it in the mailbox.  They seem to be sent in the wrong
> order.
> > > Really, you should send this series only after the driver lands on mainline.
> >
> > OK, just noticed that mainline does NOT have it, since I did it based on next
> tree.
> > I will resend the patch series after the system counter driver landing on
> mainline.
> 
> I just picked the series up, so no need to resend.

Something changed for this series, the system counter clock related implementation
are changed after some comments from maintainer, so I think you should picked up
below patch series instead, and drop this series,

https://patchwork.kernel.org/patch/11037953/

thanks,
Anson

^ permalink raw reply

* Re: [PATCH v2] arm64: dts: fsl: pico-pi: Add a device tree for the PICO-PI-IMX8M
From: Shawn Guo @ 2019-07-22  2:03 UTC (permalink / raw)
  To: Andra Danciu
  Cc: robh+dt, mark.rutland, leoyang.li, Fabio Estevam, aisheng.dong,
	l.stach, angus, vabhav.sharma, pankaj.bansal, bhaskar.upadhaya,
	ping.bai, Manivannan Sadhasivam, Richard Hu, devicetree,
	linux-kernel, matti.vaittinen, linux-imx, Daniel Baluta
In-Reply-To: <CAJNLGszB239AHpD+kRCPRWZaToTYHiq5YUHRjfRwTqknwHMdMA@mail.gmail.com>

On Thu, Jul 18, 2019 at 02:12:10PM +0300, Andra Danciu wrote:
...
> > > +     pmic: pmic@4b {
> > > +             reg = <0x4b>;
> > > +             compatible = "rohm,bd71837";
> > > +             /* PMIC BD71837 PMIC_nINT GPIO1_IO12 */
> > > +             pinctrl-0 = <&pinctrl_pmic>;
> > > +             gpio_intr = <&gpio1 3 GPIO_ACTIVE_LOW>;
> >
> > Where is the bindings for this property?
> Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt

I do not see property 'gpio_intr' in there.

Shawn

^ permalink raw reply

* Re: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for ARCH_MXC platforms
From: Shawn Guo @ 2019-07-22  2:00 UTC (permalink / raw)
  To: Anson Huang
  Cc: mark.rutland@arm.com, Aisheng Dong, Peng Fan, festevam@gmail.com,
	Jacky Bai, devicetree@vger.kernel.org, sboyd@kernel.org,
	catalin.marinas@arm.com, s.hauer@pengutronix.de,
	linux-kernel@vger.kernel.org, Daniel Baluta,
	linux-clk@vger.kernel.org, robh+dt@kernel.org, dl-linux-imx,
	kernel@pengutronix.de, Leonard Crestez, will@kernel.org, mturqu
In-Reply-To: <DB3PR0402MB39162662C69B45BDB948D002F5E00@DB3PR0402MB3916.eurprd04.prod.outlook.com>

On Mon, Jun 24, 2019 at 02:35:10AM +0000, Anson Huang wrote:
> Hi, Shawn
> 
> > -----Original Message-----
> > From: Shawn Guo <shawnguo@kernel.org>
> > Sent: Monday, June 24, 2019 10:27 AM
> > To: Anson Huang <anson.huang@nxp.com>
> > Cc: mark.rutland@arm.com; Aisheng Dong <aisheng.dong@nxp.com>; Peng
> > Fan <peng.fan@nxp.com>; festevam@gmail.com; Jacky Bai
> > <ping.bai@nxp.com>; devicetree@vger.kernel.org; sboyd@kernel.org;
> > catalin.marinas@arm.com; s.hauer@pengutronix.de; linux-
> > kernel@vger.kernel.org; Daniel Baluta <daniel.baluta@nxp.com>; linux-
> > clk@vger.kernel.org; robh+dt@kernel.org; dl-linux-imx <linux-
> > imx@nxp.com>; kernel@pengutronix.de; Leonard Crestez
> > <leonard.crestez@nxp.com>; will@kernel.org; mturquette@baylibre.com;
> > linux-arm-kernel@lists.infradead.org; Abel Vesa <abel.vesa@nxp.com>
> > Subject: Re: [PATCH 1/4] arm64: Enable TIMER_IMX_SYS_CTR for ARCH_MXC
> > platforms
> > 
> > On Mon, Jun 24, 2019 at 10:22:01AM +0800, Shawn Guo wrote:
> > > On Fri, Jun 21, 2019 at 03:07:17PM +0800, Anson.Huang@nxp.com wrote:
> > > > From: Anson Huang <Anson.Huang@nxp.com>
> > > >
> > > > ARCH_MXC platforms needs system counter as broadcast timer to
> > > > support cpuidle, enable it by default.
> > > >
> > > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > > > ---
> > > >  arch/arm64/Kconfig.platforms | 1 +
> > > >  1 file changed, 1 insertion(+)
> > > >
> > > > diff --git a/arch/arm64/Kconfig.platforms
> > > > b/arch/arm64/Kconfig.platforms index 4778c77..f5e623f 100644
> > > > --- a/arch/arm64/Kconfig.platforms
> > > > +++ b/arch/arm64/Kconfig.platforms
> > > > @@ -173,6 +173,7 @@ config ARCH_MXC
> > > >  	select PM
> > > >  	select PM_GENERIC_DOMAINS
> > > >  	select SOC_BUS
> > > > +	select TIMER_IMX_SYS_CTR
> > >
> > > Where is that driver?
> > 
> > Okay, just found it in the mailbox.  They seem to be sent in the wrong order.
> > Really, you should send this series only after the driver lands on mainline.
> 
> OK, just noticed that mainline does NOT have it, since I did it based on next tree.
> I will resend the patch series after the system counter driver landing on mainline.

I just picked the series up, so no need to resend.

Shawn

^ permalink raw reply

* Re: [PATCH V5 1/5] dt-bindings: imx: Add clock binding doc for i.MX8MN
From: Shawn Guo @ 2019-07-22  1:50 UTC (permalink / raw)
  To: Anson.Huang
  Cc: mturquette, sboyd, robh+dt, mark.rutland, s.hauer, kernel,
	festevam, catalin.marinas, will.deacon, maxime.ripard, olof,
	horms+renesas, jagan, leonard.crestez, bjorn.andersson, dinguyen,
	enric.balletbo, aisheng.dong, ping.bai, abel.vesa, l.stach,
	peng.fan, linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	Linux-imx
In-Reply-To: <20190619055247.35771-1-Anson.Huang@nxp.com>

On Wed, Jun 19, 2019 at 01:52:43PM +0800, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> Add the clock binding doc for i.MX8MN.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Applied all, thanks.

^ permalink raw reply

* Re: [TRIVIAL PATCH] of: per-file dtc preprocessor flags
From: Masahiro Yamada @ 2019-07-22  1:43 UTC (permalink / raw)
  To: Eugeniy Paltsev
  Cc: Alexey Brodkin, linux-snps-arc@lists.infradead.org,
	michal.lkml@markovi.net, linux-kbuild@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	Vineet.Gupta1@synopsys.com
In-Reply-To: <b2f24f32fead8bc9f282d2beb77d58ed3b98850c.camel@synopsys.com>

On Sun, Jul 21, 2019 at 12:38 AM Eugeniy Paltsev
<Eugeniy.Paltsev@synopsys.com> wrote:
>
> Hi Masahiro,
>
> On Sat, 2019-07-20 at 11:40 +0900, Masahiro Yamada wrote:
> > On Sat, Jul 20, 2019 at 4:28 AM Eugeniy Paltsev
> > <Eugeniy.Paltsev@synopsys.com> wrote:
> > > As of today we are able to pass custom flags to dtc compiler but not
> > > to dtc preprocessor.
> > > This ability is required for including some board-specific header files.
> > > It allows us to pass defined constants to dts without their duplication
> > > in several places.
> >
> > How to use this option in a useful way?
> >
> > I see a bunch of defined constants under include/dt-bindings/.
> >
> > If you are talking about code duplication across architectures,
> > you can include arm dtsi from arm64 dts, or vice versa.
> > This was made possible by the symbolic links
> > in scripts/dtc/include-prefixes/.
> >
> > Could you please elaborate your issues if you cannot solve them
> > by the current strategy?
> >
>
> Here is the example:
>
> We have several FPGA-based boards (haps_hs, haps_hs_idu,...) which are involved
> in SW and HW automated verification. For some tests we randomize physical memory
> location so we patch 'CONFIG_LINUX_RAM_BASE' kconfig variable and 'memory' node in
> device tree. We want to keep number of patches as less as possible (to avoid
> conflicts on their applying) so we want to avoid duplication and pass
> 'CONFIG_LINUX_RAM_BASE' directly to dts by including it from
> 'include/generated/autoconf.h':
>
> ----------------------------->8------------------------------------
> memory {
>         device_type = "memory";
> -               /* CONFIG_LINUX_RAM_BASE needs to match low mem start */
> -               reg = <0x80000000 0x20000000>;  /* 512 */
> +               reg = <CONFIG_LINUX_RAM_BASE 0x20000000>;      /* 512 */



So, we need the kernel configuration to build DT?

I am scared with this idea.

I believe DT files should be able to be compiled
irrespective of the .config because they are
re-used for other projects.

devicetree-rebasing is a subset of the kernel tree
that collects DT.

If you upstream that patch, this will be broken, at least.

git://git.kernel.org/pub/scm/linux/kernel/git/devicetree/devicetree-rebasing.git



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* Re: [v5 1/2] dt-bindings: gpio: aspeed: Add SGPIO support
From: Andrew Jeffery @ 2019-07-22  1:42 UTC (permalink / raw)
  To: Linus Walleij, Hongwei Zhang
  Cc: open list:GPIO SUBSYSTEM, Joel Stanley,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-aspeed, Bartosz Golaszewski, Rob Herring, Mark Rutland,
	linux-kernel@vger.kernel.org, Linux ARM
In-Reply-To: <CACRpkdYhVoP75ZDfASW+DH5yf-a5diitiXsh7eLsJx5hsTC9sQ@mail.gmail.com>



On Sat, 20 Jul 2019, at 17:43, Linus Walleij wrote:
> Hi Hongwei,
> 
> after looking close at the driver and bindings I have this feeback:
> 
> On Fri, Jul 19, 2019 at 9:25 PM Hongwei Zhang <hongweiz@ami.com> wrote:
> 
> +- reg                  : Address and length of the register set for the device
> 
> This 0x100 range may look simple but in the driver it looks like
> this:
> 
> +static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
> +       {
> +               .val_regs = 0x0000,
> +               .rdata_reg = 0x0070,
> +               .irq_regs = 0x0004,
> +               .names = { "A", "B", "C", "D" },
> +       },
> +       {
> +               .val_regs = 0x001C,
> +               .rdata_reg = 0x0074,
> +               .irq_regs = 0x0020,
> +               .names = { "E", "F", "G", "H" },
> +       },
> +       {
> +               .val_regs = 0x0038,
> +               .rdata_reg = 0x0078,
> +               .irq_regs = 0x003C,
> +               .names = { "I", "J" },
> +       },
> +};
> 
> So first break this into up to 10 different instances with one device
> per bank instead.
> 
> For each device:
> 
> reg = <0x1e780200 4>, <x1e780204 ..>, <0x1e780270 ..>;
> reg-names = "val", "irq", "rdata";
> 
> This way you use the device tree features for locating the
> register offsets instead of hard-coding it into the driver,
> which will make the driver simpler.
> 
> > +- ngpios               : number of GPIO pins to serialise.
> > +                         (should be multiple of 8, up to 80 pins)
> 
> This is wrong. This should be split into 10 different devices providing
> 8 GPIO lines each. The "ngpios" is not intended to subdivide
> banks, but for the case where you use say bits 0..11 of 32 bits in
> a register by setting ngpios to 12.
> 
> I see that they use the same clock divider and the same interrupt,
> but this is better to partition into a separate clock divider driver
> and up to 10 instances of GPIO devices with 8 GPIOs each.
> 
> I also see that they use the same interrupt. This is fine, in your
> driver just grab a shared IRQ and all the IRQ handlers will be
> traversed. This is a well known pattern for all operating systems.
> 
> > +- clocks                : A phandle to the APB clock for SGPM clock division
> > +
> > +- bus-frequency                : SGPM CLK frequency
> 
> I see that there is a common clock control register in offset 0x54.
> 
> Split this out to a separate clock driver that provides a divided clock
> that all GPIO blocks can get, no matter if you use 1, 2 .. 10 of these
> blocks.
> 
> The fact that these GPIO banks and the clock register is in the same
> memory range does not really matter. Split up the memory range in
> on reg = per GPIO chip and one reg for the clock.

The issue that I see with this is that the SGPIO bus clock configuration
is not the only field in the SGPIO control register - it also contains the
number of GPIOs the bus should output along with a bus enable bit.
The clock, and particularly the number of GPIOs (due to the nature
of the SGPIO bus) both need to be configured before we set the
enable bit (or obviously all can be done simultaneously).

I'll explore some of the options below (it's a bit train-of-thought,
hopefully it makes sense):

If the clock driver owns the control register, it also needs to know how
many GPIOs we want to emit on the bus. This seems like an awkward
configuration parameter for a clock driver.

To avoid the weird parameter we could protect the control register
with a lock shared between the clock driver and the SGPIO driver. This
way the SGPIO driver could have the ngpios parameter, and request
the clock after its written the ngpios value to the control register. A
regmap would be useful here to avoid the resource clash and it also
provides the required lock.

However, you're also going down the path of splitting the driver such
that there's one instance per bank. With this approach we need to
solve two problems: Accounting for the total number of GPIOs, and
only enabling the bus after the last bank has had its driver probed.

The accounting might be handled by accumulating the number of
GPIOs in each bank in the control register itself, e.g. the driver
implementation does something like:

spin_lock(...)
ctrl = ioread32(...)
ngpios = FIELD_GET(ASPEED_SGPIO_CTRL_NGPIOS, ctrl);
ngpios += 8;
ctrl &= ~ASPEED_SGPIO_CTRL_NGPIOS;
ctrl |= FIELD_PREP(ASPEED_SGPIO_CTRL_NGPIOS, ngpios);
iowrite32(ctrl, ...);
spin_unlock(...);

This works on cold boot of the device when the ngpios field is set to
zero due to reset, however will fail on subsequent warm reboots if
the GPIO IP block is protected from reset by the SoC's watchdog
configuration: the field will not be zeroed in this case, and the
value of the field is represented by `NR_BOOTS * NR_GPIOS`,
which is incorrect. To do this correctly I guess we would need some
other global state held in the driver implementation (zeroed when
the kernel is loaded), and write the incremented value to the control
register on each probe() invocation.

However, that aside, we can't simply enable the bus in the clock
enable callback if enable is called per-bank, as it is called once on
the first request with further requests simply refcounted as you
mentioned. This is exactly the behaviour we can't tolerate with the
bus: it must only be enabled after the last GPIO bank is registered,
when we know the total number of GPIOs to emit. So we can only
call clk_prepare_enable() after the last bank is probed, or in the
probe() of the last bank if the driver has some way to tell it is the
last instance. In my mind per-bank clock management makes the
implementation more involved than it should be, and isn't really
reflective of what the clk subsystem is trying to achieve (violates
clk_prepare()/clk_enable() post conditions, or boils down to just
calling devm_clk_get() in probe() with no further action, which 
seems kinda pointless).

Having a separate clk implementation whose instance is requested
once by a monolithic SGPIO driver matches how the hardware is
designed. However, given the issue of sharing the register with the
GPIO count, in my opinion it seems to make more sense to leave the
driver design as is and minimise the accidental complexity
introduced by the behavioural mismatch of the clk abstraction
and the addition of locking where it wasn't previously necessary.

Interested in your thoughts.

Andrew

^ permalink raw reply

* Re: [PATCH v2 6/8] PCI: al: Add support for DW based driver type
From: Benjamin Herrenschmidt @ 2019-07-22  0:47 UTC (permalink / raw)
  To: Chocron, Jonathan, jingoohan1@gmail.com, mark.rutland@arm.com,
	lorenzo.pieralisi@arm.com, Gustavo.Pimentel@synopsys.com,
	bhelgaas@google.com, robh+dt@kernel.org
  Cc: linux-kernel@vger.kernel.org, Woodhouse, David, Hanoch, Uri,
	devicetree@vger.kernel.org, Wasserstrom, Barak, Saidi, Ali,
	Hawa, Hanna, Shenhar, Talel, Krupnik, Ronen,
	linux-pci@vger.kernel.org
In-Reply-To: <d323007c6bf14cb9f90a497a26b66dac151164fc.camel@amazon.com>

On Sun, 2019-07-21 at 15:08 +0000, Chocron, Jonathan wrote:
> > Please sort the variables following the reverse tree order.
> > 
> 
> Done. 
> 
> I'd think that it would make sense to group variables which have a
> common characteristic (e.g. resources read from the DT), even if it
> mildly breaks the convention (as long as the general frame is longest
> to shortest). Does this sound ok?
> 
> BTW, I couldn't find any documentation regarding the reverse-tree
> convention, do you have a pointer to some?

It's a complete stupidity that people who have nothing better to
comment about keep throwing at you when you are trying to get stuff
working.

Yes, we should avoid ugly stuff such as

	int rc;
	struct something_very_long foo;

But this definitely should come second to saner ordering such as the
one you propose of grouping related things together. At least IMHO.

You'll notice that the kernel these days attract way more people
interested in commenting to death on various minor points of coding
style than actual worthwhile technical comments on the code.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 22:48 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <9c844d55-0bc0-471c-6c49-1febe799ebf2@gmail.com>


On 7/21/19 3:09 PM, Dmitry Osipenko wrote:
> 22.07.2019 1:03, Dmitry Osipenko пишет:
>> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>>> This patch adds support for Tegra pinctrl driver suspend and resume.
>>>
>>> During suspend, context of all pinctrl registers are stored and
>>> on resume they are all restored to have all the pinmux and pad
>>> configuration for normal operation.
>>>
>>> Acked-by: Thierry Reding <treding@nvidia.com>
>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>>> ---
>>>   drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>>>   drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>>>   2 files changed, 62 insertions(+)
>>>
>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> index 186ef98e7b2b..e3a237534281 100644
>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>>> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>>   	}
>>>   }
>>>   
>>> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
>>> +					  unsigned int bank_id)
>>> +{
>>> +	struct platform_device *pdev = to_platform_device(dev);
>>> +	struct resource *res;
>>> +
>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
>>> +
>>> +	return resource_size(res) / 4;
>>> +}
>>> +
>>> +static int tegra_pinctrl_suspend(struct device *dev)
>>> +{
>>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>>> +	u32 *backup_regs = pmx->backup_regs;
>>> +	u32 *regs;
>>> +	size_t bank_size;
>>> +	unsigned int i, k;
>>> +
>>> +	for (i = 0; i < pmx->nbanks; i++) {
>>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>>> +		regs = pmx->regs[i];
>>> +		for (k = 0; k < bank_size; k++)
>>> +			*backup_regs++ = readl_relaxed(regs++);
>>> +	}
>>> +
>>> +	return pinctrl_force_sleep(pmx->pctl);
>>> +}
>>> +
>>> +static int tegra_pinctrl_resume(struct device *dev)
>>> +{
>>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>>> +	u32 *backup_regs = pmx->backup_regs;
>>> +	u32 *regs;
>>> +	size_t bank_size;
>>> +	unsigned int i, k;
>>> +
>>> +	for (i = 0; i < pmx->nbanks; i++) {
>>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>>> +		regs = pmx->regs[i];
>>> +		for (k = 0; k < bank_size; k++)
>>> +			writel_relaxed(*backup_regs++, regs++);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +const struct dev_pm_ops tegra_pinctrl_pm = {
>>> +	.suspend = &tegra_pinctrl_suspend,
>>> +	.resume = &tegra_pinctrl_resume
>>> +};
>>> +
>>>   static bool gpio_node_has_range(const char *compatible)
>>>   {
>>>   	struct device_node *np;
>>> @@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   	int i;
>>>   	const char **group_pins;
>>>   	int fn, gn, gfn;
>>> +	unsigned long backup_regs_size = 0;
>>>   
>>>   	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
>>>   	if (!pmx)
>>> @@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>>>   		if (!res)
>>>   			break;
>>> +		backup_regs_size += resource_size(res);
>>>   	}
>>>   	pmx->nbanks = i;
>>>   
>>> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   	if (!pmx->regs)
>>>   		return -ENOMEM;
>>>   
>>> +	pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
>>> +					GFP_KERNEL);
>>> +	if (!pmx->backup_regs)
>>> +		return -ENOMEM;
>>> +
>>>   	for (i = 0; i < pmx->nbanks; i++) {
>>>   		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>>>   		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
>>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> index 105309774079..0fc82eea9cf1 100644
>>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
>>> @@ -17,6 +17,7 @@ struct tegra_pmx {
>>>   
>>>   	int nbanks;
>>>   	void __iomem **regs;
>>> +	u32 *backup_regs;
>>>   };
>>>   
>>>   enum tegra_pinconf_param {
>>> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>>>   	bool drvtype_in_mux;
>>>   };
>>>   
>>> +extern const struct dev_pm_ops tegra_pinctrl_pm;
>>> +
>>>   int tegra_pinctrl_probe(struct platform_device *pdev,
>>>   			const struct tegra_pinctrl_soc_data *soc_data);
>>>   #endif
>>>
>> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
>>
> BTW, you should remove Thierry's ACK from all patches that were modified
> if he didn't re-ACK the new version.
>
> Also, it looks to me that you're manually adding versioning to the
> patches because git usually uses lowercase for 'v'. You could use "git
> format-patch -v6 ..".


ok, Reg. version I am using git format-patch --subject-prefix='PATCH V6'

will change to lower case v

^ permalink raw reply

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
From: Sowjanya Komatineni @ 2019-07-21 22:47 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <ba402ed3-0e6f-26ce-ac0a-8048babb50ca@gmail.com>


On 7/21/19 2:44 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch implements save and restore of PLL context.
>>
>> During system suspend, core power goes off and looses the settings
>> of the Tegra CAR controller registers.
>>
>> So during suspend entry pll rate is stored and on resume it is
>> restored back along with its state.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>>   drivers/clk/tegra/clk-tegra210.c |   2 +-
>>   drivers/clk/tegra/clk.h          |  10 +++-
>>   3 files changed, 99 insertions(+), 34 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 1583f5fc992f..f136964e6c44 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -1008,6 +1008,59 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
>>   	return rate;
>>   }
>>   
>> +void tegra_clk_sync_state_pll(struct clk_hw *hw)
>> +{
>> +	if (!__clk_get_enable_count(hw->clk))
>> +		clk_pll_disable(hw);
>> +	else
>> +		clk_pll_enable(hw);
>> +}
>> +
>> +static int tegra_clk_pll_save_context(struct clk_hw *hw)
>> +{
>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +	u32 val = 0;
>> +
>> +	pll->rate = clk_hw_get_rate(hw);
>> +
>> +	if (pll->params->flags & TEGRA_PLLMB)
>> +		val = pll_readl_base(pll);
>> +	else if (pll->params->flags & TEGRA_PLLRE)
>> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
>> +
>> +	pll->pllbase_ctx = val;
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
>> +{
>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +	struct clk_hw *parent = clk_hw_get_parent(hw);
>> +	unsigned long parent_rate = clk_hw_get_rate(parent);
>> +	u32 val;
>> +
>> +	if (clk_pll_is_enabled(hw))
>> +		return;
>> +
>> +	if (pll->params->flags & TEGRA_PLLMB) {
>> +		pll_writel_base(pll->pllbase_ctx, pll);
>> +	} else if (pll->params->flags & TEGRA_PLLRE) {
>> +		val = pll_readl_base(pll);
>> +		val &= ~(divp_mask_shifted(pll));
>> +		pll_writel_base(pll->pllbase_ctx | val, pll);
>> +	}
>> +
>> +	if (pll->params->set_defaults)
>> +		pll->params->set_defaults(pll);
>> +
>> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
>> +
>> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
>> +	if (!(pll->params->flags & TEGRA_PLLX))
>> +		tegra_clk_sync_state_pll(hw);
>> +}
>> +
>>   const struct clk_ops tegra_clk_pll_ops = {
>>   	.is_enabled = clk_pll_is_enabled,
>>   	.enable = clk_pll_enable,
>> @@ -1015,6 +1068,8 @@ const struct clk_ops tegra_clk_pll_ops = {
>>   	.recalc_rate = clk_pll_recalc_rate,
>>   	.round_rate = clk_pll_round_rate,
>>   	.set_rate = clk_pll_set_rate,
>> +	.save_context = tegra_clk_pll_save_context,
>> +	.restore_context = tegra_clk_pll_restore_context,
>>   };
>>   
>>   const struct clk_ops tegra_clk_plle_ops = {
>> @@ -1802,6 +1857,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
>>   
>>   	return ret;
>>   }
>> +
>> +static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll)
>> +{
>> +	u32 val, val_aux;
>> +
>> +	/* ensure parent is set to pll_ref */
>> +	val = pll_readl_base(pll);
>> +	val_aux = pll_readl(pll->params->aux_reg, pll);
>> +
>> +	if (val & PLL_BASE_ENABLE) {
>> +		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
>> +		    (val_aux & PLLE_AUX_PLLP_SEL))
>> +			WARN(1, "pll_e enabled with unsupported parent %s\n",
>> +			     (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
>> +			     "pll_re_vco");
>> +	} else {
>> +		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
>> +		pll_writel(val_aux, pll->params->aux_reg, pll);
>> +		fence_udelay(1, pll->clk_base);
>> +	}
>> +}
>>   #endif
>>   
>>   static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
>> @@ -2214,27 +2290,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
>>   {
>>   	struct tegra_clk_pll *pll;
>>   	struct clk *clk;
>> -	u32 val, val_aux;
>>   
>>   	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
>>   	if (IS_ERR(pll))
>>   		return ERR_CAST(pll);
>>   
>> -	/* ensure parent is set to pll_re_vco */
>> -
>> -	val = pll_readl_base(pll);
>> -	val_aux = pll_readl(pll_params->aux_reg, pll);
>> -
>> -	if (val & PLL_BASE_ENABLE) {
>> -		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
>> -			(val_aux & PLLE_AUX_PLLP_SEL))
>> -			WARN(1, "pll_e enabled with unsupported parent %s\n",
>> -			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
>> -					"pll_re_vco");
>> -	} else {
>> -		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
>> -		pll_writel(val_aux, pll_params->aux_reg, pll);
>> -	}
>> +	_clk_plle_tegra_init_parent(pll);
>>   
>>   	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
>>   				      &tegra_clk_plle_tegra114_ops);
>> @@ -2276,6 +2337,8 @@ static const struct clk_ops tegra_clk_pllss_ops = {
>>   	.recalc_rate = clk_pll_recalc_rate,
>>   	.round_rate = clk_pll_ramp_round_rate,
>>   	.set_rate = clk_pllxc_set_rate,
>> +	.save_context = tegra_clk_pll_save_context,
>> +	.restore_context = tegra_clk_pll_restore_context,
>>   };
>>   
>>   struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
>> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>>   		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>>   							     parent_rate);
>>   
>> +	pll_params->flags |= TEGRA_PLLRE;
>>   	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>>   	if (IS_ERR(pll))
>>   		return ERR_CAST(pll);
>> @@ -2520,11 +2584,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
>>   		spin_unlock_irqrestore(pll->lock, flags);
>>   }
>>   
>> +static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw)
>> +{
>> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
>> +
>> +	_clk_plle_tegra_init_parent(pll);
>> +}
>> +
>>   static const struct clk_ops tegra_clk_plle_tegra210_ops = {
>>   	.is_enabled =  clk_plle_tegra210_is_enabled,
>>   	.enable = clk_plle_tegra210_enable,
>>   	.disable = clk_plle_tegra210_disable,
>>   	.recalc_rate = clk_pll_recalc_rate,
>> +	.restore_context = tegra_clk_plle_t210_restore_context,
>>   };
>>   
>>   struct clk *tegra_clk_register_plle_tegra210(const char *name,
>> @@ -2535,27 +2607,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name,
>>   {
>>   	struct tegra_clk_pll *pll;
>>   	struct clk *clk;
>> -	u32 val, val_aux;
>>   
>>   	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
>>   	if (IS_ERR(pll))
>>   		return ERR_CAST(pll);
>>   
>> -	/* ensure parent is set to pll_re_vco */
>> -
>> -	val = pll_readl_base(pll);
>> -	val_aux = pll_readl(pll_params->aux_reg, pll);
>> -
>> -	if (val & PLLE_BASE_ENABLE) {
>> -		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
>> -			(val_aux & PLLE_AUX_PLLP_SEL))
>> -			WARN(1, "pll_e enabled with unsupported parent %s\n",
>> -			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
>> -					"pll_re_vco");
>> -	} else {
>> -		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
>> -		pll_writel(val_aux, pll_params->aux_reg, pll);
>> -	}
>> +	_clk_plle_tegra_init_parent(pll);
>>   
>>   	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
>>   				      &tegra_clk_plle_tegra210_ops);
>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index 4721ee030d1c..58397f93166c 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>>   	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>>   	.div_nmp = &pllx_nmp,
>>   	.freq_table = pll_x_freq_table,
>> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
>> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>>   	.dyn_ramp = tegra210_pllx_dyn_ramp,
>>   	.set_defaults = tegra210_pllx_set_defaults,
>>   	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index fb29a8c27873..8532f5150091 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>>    * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>>    *     flag indicated that it is PLLMB.
>>    * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
>> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
>> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>>    */
>>   struct tegra_clk_pll_params {
>>   	unsigned long	input_min;
>> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>>   #define TEGRA_MDIV_NEW BIT(11)
>>   #define TEGRA_PLLMB BIT(12)
>>   #define TEGRA_PLL_VCO_OUT BIT(13)
>> +#define TEGRA_PLLRE BIT(14)
>> +#define TEGRA_PLLX BIT(15)
>>   
>>   /**
>>    * struct tegra_clk_pll - Tegra PLL clock
>> @@ -310,6 +314,8 @@ struct tegra_clk_pll_params {
>>    * @pmc:	address of PMC, required to read override bits
>>    * @lock:	register lock
>>    * @params:	PLL parameters
>> + * @rate:	rate during system suspend and resume
>> + * @pllbase_ctx: pll base register value during suspend and resume
>>    */
>>   struct tegra_clk_pll {
>>   	struct clk_hw	hw;
>> @@ -317,6 +323,8 @@ struct tegra_clk_pll {
>>   	void __iomem	*pmc;
>>   	spinlock_t	*lock;
>>   	struct tegra_clk_pll_params	*params;
>> +	unsigned long	rate;
>> +	u32	pllbase_ctx;
>>   };
>>   
>>   #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
>> @@ -840,7 +848,7 @@ u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
>>   int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
>>   int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
>>   		 u8 frac_width, u8 flags);
>> -
>> +void tegra_clk_sync_state_pll(struct clk_hw *hw);
> Looks like this function isn't used anywhere other than this patch. Bug?

With all dfll sequence moved to right places in this patch, yes this can 
be collapsed within restore context itself.

Will change in next version

>>   /* Combined read fence with delay */
>>   #define fence_udelay(delay, reg)	\
>>

^ permalink raw reply

* Re: [PATCH V6 14/21] clk: tegra210: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 22:45 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <e683b417-66fb-38dc-c16b-dab616583a88@gmail.com>


On 7/21/19 2:38 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch adds support for clk: tegra210: suspend-resume.
>>
>> All the CAR controller settings are lost on suspend when core
>> power goes off.
>>
>> This patch has implementation for saving and restoring all PLLs
>> and clocks context during system suspend and resume to have the
>> clocks back to same state for normal operation.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-tegra210.c | 68 ++++++++++++++++++++++++++++++++++++++--
>>   drivers/clk/tegra/clk.c          | 14 +++++++++
>>   drivers/clk/tegra/clk.h          |  1 +
>>   3 files changed, 80 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> index 55a88c0824a5..68271873acc1 100644
>> --- a/drivers/clk/tegra/clk-tegra210.c
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>> @@ -9,6 +9,7 @@
>>   #include <linux/clkdev.h>
>>   #include <linux/of.h>
>>   #include <linux/of_address.h>
>> +#include <linux/syscore_ops.h>
>>   #include <linux/delay.h>
>>   #include <linux/export.h>
>>   #include <linux/mutex.h>
>> @@ -220,11 +221,15 @@
>>   #define CLK_M_DIVISOR_SHIFT 2
>>   #define CLK_M_DIVISOR_MASK 0x3
>>   
>> +#define CLK_MASK_ARM	0x44
>> +#define MISC_CLK_ENB	0x48
>> +
>>   #define RST_DFLL_DVCO 0x2f4
>>   #define DVFS_DFLL_RESET_SHIFT 0
>>   
>>   #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
>>   #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
>> +#define CPU_SOFTRST_CTRL 0x380
>>   
>>   #define LVL2_CLK_GATE_OVRA 0xf8
>>   #define LVL2_CLK_GATE_OVRC 0x3a0
>> @@ -2825,6 +2830,7 @@ static int tegra210_enable_pllu(void)
>>   	struct tegra_clk_pll_freq_table *fentry;
>>   	struct tegra_clk_pll pllu;
>>   	u32 reg;
>> +	int ret;
>>   
>>   	for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
>>   		if (fentry->input_rate == pll_ref_freq)
>> @@ -2853,9 +2859,8 @@ static int tegra210_enable_pllu(void)
>>   	reg |= PLL_ENABLE;
>>   	writel(reg, clk_base + PLLU_BASE);
>>   
>> -	readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
>> -					  reg & PLL_BASE_LOCK, 2, 1000);
>> -	if (!(reg & PLL_BASE_LOCK)) {
>> +	ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
>> +	if (ret) {
> Why this is needed? Was there a bug?
>
during resume pllu init is needed and to use same terga210_init_pllu, 
poll_timeout_atomic can't be used as its ony for atomic context.

So changed to use wait_for_mask which should work in both cases.

>>   		pr_err("Timed out waiting for PLL_U to lock\n");
>>   		return -ETIMEDOUT;
>>   	}
>> @@ -3288,6 +3293,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
>>   }
>>   
>>   #ifdef CONFIG_PM_SLEEP
>> +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
>> +#define car_writel(_val, _base, _off) \
>> +		writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
>> +
>> +static u32 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
>> +static u32 cpu_softrst_ctx[3];
>> +
>> +static int tegra210_clk_suspend(void)
>> +{
>> +	unsigned int i;
>> +
>> +	clk_save_context();
>> +
>> +	/*
>> +	 * save the bootloader configured clock registers SPARE_REG0,
>> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL
> Nit: Start all multi-line comments with a capital letter and put dot in
> the end of sentence.
>
>> +	 */
>> +	spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
>> +	misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
>> +	clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra210_clk_resume(void)
>> +{
>> +	unsigned int i;
>> +
>> +	tegra_clk_osc_resume(clk_base);
>> +
>> +	/*
>> +	 * restore the bootloader configured clock registers SPARE_REG0,
>> +	 * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
> Same here.
>
>> +	 */
>> +	writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
>> +	writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
>> +	writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
>> +		car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
>> +
>> +	fence_udelay(5, clk_base);
>> +
>> +	tegra210_init_pllu();
>> +	clk_restore_context();
>> +}
>> +
>>   static void tegra210_cpu_clock_suspend(void)
>>   {
>>   	/* switch coresite to clk_m, save off original source */
>> @@ -3303,6 +3358,11 @@ static void tegra210_cpu_clock_resume(void)
>>   }
>>   #endif
>>   
>> +static struct syscore_ops tegra_clk_syscore_ops = {
>> +	.suspend = tegra210_clk_suspend,
>> +	.resume = tegra210_clk_resume,
>> +};
>> +
>>   static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
>>   	.wait_for_reset	= tegra210_wait_cpu_in_reset,
>>   	.disable_clock	= tegra210_disable_cpu_clock,
>> @@ -3587,5 +3647,7 @@ static void __init tegra210_clock_init(struct device_node *np)
>>   	tegra210_mbist_clk_init();
>>   
>>   	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
>> +
>> +	register_syscore_ops(&tegra_clk_syscore_ops);
>>   }
>>   CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
>> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
>> index 573e3c967ae1..eb08047fd02f 100644
>> --- a/drivers/clk/tegra/clk.c
>> +++ b/drivers/clk/tegra/clk.c
>> @@ -23,6 +23,7 @@
>>   #define CLK_OUT_ENB_W			0x364
>>   #define CLK_OUT_ENB_X			0x280
>>   #define CLK_OUT_ENB_Y			0x298
>> +#define CLK_ENB_PLLP_OUT_CPU		BIT(31)
>>   #define CLK_OUT_ENB_SET_L		0x320
>>   #define CLK_OUT_ENB_CLR_L		0x324
>>   #define CLK_OUT_ENB_SET_H		0x328
>> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
>>   	}
>>   }
>>   
>> +void tegra_clk_set_pllp_out_cpu(bool enable)
>> +{
>> +	u32 val;
>> +
>> +	val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
>> +	if (enable)
>> +		val |= CLK_ENB_PLLP_OUT_CPU;
>> +	else
>> +		val &= ~CLK_ENB_PLLP_OUT_CPU;
>> +
>> +	writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
>> +}
>> +
>>   struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
>>   {
>>   	clk_base = regs;
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index 562a3ee2d537..0ffa763c755b 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -863,6 +863,7 @@ int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
>>   		 u8 frac_width, u8 flags);
>>   void tegra_clk_sync_state_pll(struct clk_hw *hw);
>>   void tegra_clk_osc_resume(void __iomem *clk_base);
>> +void tegra_clk_set_pllp_out_cpu(bool enable);
>>   
>>   /* Combined read fence with delay */
>>   #define fence_udelay(delay, reg)	\
>>

^ permalink raw reply

* Re: [PATCH V6 11/21] clk: tegra: clk-dfll: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-21 22:42 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <54e3237d-c6c2-2007-99b2-89c26004da47@gmail.com>


On 7/21/19 2:32 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch implements DFLL suspend and resume operation.
>>
>> During system suspend entry, CPU clock will switch CPU to safe
>> clock source of PLLP and disables DFLL clock output.
>>
>> DFLL driver suspend confirms DFLL disable state and errors out on
>> being active.
>>
>> DFLL is re-initialized during the DFLL driver resume as it goes
>> through complete reset during suspend entry.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-dfll.c               | 44 ++++++++++++++++++++++++++++++
>>   drivers/clk/tegra/clk-dfll.h               |  2 ++
>>   drivers/clk/tegra/clk-tegra124-dfll-fcpu.c |  1 +
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
>> index f8688c2ddf1a..7dcad4ccd0ae 100644
>> --- a/drivers/clk/tegra/clk-dfll.c
>> +++ b/drivers/clk/tegra/clk-dfll.c
>> @@ -1513,6 +1513,50 @@ static int dfll_init(struct tegra_dfll *td)
>>   	return ret;
>>   }
>>   
>> +/**
>> + * tegra_dfll_suspend - check DFLL is disabled
>> + * @dev: DFLL device *
>> + *
>> + * DFLL clock should be disabled by the CPUFreq driver. So, make
>> + * sure it is disabled and disable all clocks needed by the DFLL.
>> + */
>> +int tegra_dfll_suspend(struct device *dev)
>> +{
>> +	struct tegra_dfll *td = dev_get_drvdata(dev);
>> +
>> +	if (dfll_is_running(td)) {
>> +		dev_warn(td->dev, "failed disabling the dfll\n");
> Something like "dfll is enabled while shouldn't be\n" will be more
> informative.
>
> This is a error, hence dev_err().
>
>> +		return -EBUSY;
>> +	}
>> +
>> +	pm_runtime_disable(dev);
>> +
>> +	clk_unprepare(td->ref_clk);
>> +	clk_unprepare(td->soc_clk);
>> +	clk_unprepare(td->i2c_clk);
> Please don't do this, DFLL is already disabled if not running.

during resume dfll re-init sequence is same as dfll init so I am using 
existing dfll_init

which includes runtime_enable and clk_prepare.


Will create separate dfll_reinit then...

>> +	reset_control_assert(td->dvco_rst);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(tegra_dfll_suspend);
>> +
>> +/**
>> + * tegra_dfll_resume - reinitialize DFLL on resume
>> + * @pdev: DFLL instance
>> + *
>> + * Re-initialize DFLL on resume as it gets disabled and reset during
>> + * suspend entry. DFLL clock is enabled in closed loop mode later
>> + * and CPU frequency will be switched to DFLL output.
>> + */
>> +int tegra_dfll_resume(struct device *dev)
>> +{
>> +	struct tegra_dfll *td = dev_get_drvdata(dev);
>> +
>> +	return dfll_init(td);
> Just create dfll_reinit() variant.
>
>> +}
>> +EXPORT_SYMBOL(tegra_dfll_resume);
>> +
>>   /*
>>    * DT data fetch
>>    */
>> diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
>> index 1b14ebe7268b..fb209eb5f365 100644
>> --- a/drivers/clk/tegra/clk-dfll.h
>> +++ b/drivers/clk/tegra/clk-dfll.h
>> @@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
>>   struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
>>   int tegra_dfll_runtime_suspend(struct device *dev);
>>   int tegra_dfll_runtime_resume(struct device *dev);
>> +int tegra_dfll_suspend(struct device *dev);
>> +int tegra_dfll_resume(struct device *dev);
>>   
>>   #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
>> diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> index e84b6d52cbbd..2ac2679d696d 100644
>> --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
>> @@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
>>   static const struct dev_pm_ops tegra124_dfll_pm_ops = {
>>   	SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
>>   			   tegra_dfll_runtime_resume, NULL)
>> +	SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
>>   };
>>   
>>   static struct platform_driver tegra124_dfll_fcpu_driver = {
>>

^ permalink raw reply

* Re: [PATCH V6 09/21] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
From: Sowjanya Komatineni @ 2019-07-21 22:39 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <0c86cd7f-81b5-40c5-6f1e-796e8f13b522@gmail.com>


On 7/21/19 2:16 PM, Dmitry Osipenko wrote:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch has a fix to enable PLLP branches to CPU before changing
>> the CPU clusters clock source to PLLP for Gen5 Super clock.
>>
>> During system suspend entry and exit, CPU source will be switched
>> to PLLP and this needs PLLP branches to be enabled to CPU prior to
>> the switch.
>>
>> On system resume, warmboot code enables PLLP branches to CPU and
>> powers up the CPU with PLLP clock source.
>>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>   drivers/clk/tegra/clk-super.c            | 11 +++++++++++
>>   drivers/clk/tegra/clk-tegra-super-gen4.c |  4 ++--
>>   drivers/clk/tegra/clk.h                  |  4 ++++
>>   3 files changed, 17 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
>> index 39ef31b46df5..d73c587e4853 100644
>> --- a/drivers/clk/tegra/clk-super.c
>> +++ b/drivers/clk/tegra/clk-super.c
>> @@ -28,6 +28,9 @@
>>   #define super_state_to_src_shift(m, s) ((m->width * s))
>>   #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>>   
>> +#define CCLK_SRC_PLLP_OUT0 4
>> +#define CCLK_SRC_PLLP_OUT4 5
>> +
>>   static u8 clk_super_get_parent(struct clk_hw *hw)
>>   {
>>   	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
>> @@ -97,6 +100,14 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
>>   		if (index == mux->div2_index)
>>   			index = mux->pllx_index;
>>   	}
>> +
>> +	/*
>> +	 * Enable PLLP branches to CPU before selecting PLLP source
>> +	 */
>> +	if ((mux->flags & TEGRA_CPU_CLK) &&
>> +	    ((index == CCLK_SRC_PLLP_OUT0) || (index == CCLK_SRC_PLLP_OUT4)))
>> +		tegra_clk_set_pllp_out_cpu(true);
> Should somewhere here be tegra_clk_set_pllp_out_cpu(false) when
> switching from PLLP?
PLLP may be used for other CPU clusters.
>>   	val &= ~((super_state_to_src_mask(mux)) << shift);
>>   	val |= (index & (super_state_to_src_mask(mux))) << shift;
>>   
>> diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
>> index cdfe7c9697e1..cd208d0eca2a 100644
>> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
>> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
>> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>>   					gen_info->num_cclk_g_parents,
>>   					CLK_SET_RATE_PARENT,
>>   					clk_base + CCLKG_BURST_POLICY,
>> -					0, 4, 8, 0, NULL);
>> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>   		} else {
>>   			clk = tegra_clk_register_super_mux("cclk_g",
>>   					gen_info->cclk_g_parents,
>> @@ -201,7 +201,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
>>   					gen_info->num_cclk_lp_parents,
>>   					CLK_SET_RATE_PARENT,
>>   					clk_base + CCLKLP_BURST_POLICY,
>> -					0, 4, 8, 0, NULL);
>> +					TEGRA_CPU_CLK, 4, 8, 0, NULL);
>>   		} else {
>>   			clk = tegra_clk_register_super_mux("cclk_lp",
>>   					gen_info->cclk_lp_parents,
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index ac6de3a0b91f..c357b49e49b0 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -694,6 +694,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
>>    * Flags:
>>    * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
>>    *     that this is LP cluster clock.
>> + * TEGRA_CPU_CLK - This flag indicates this is CPU cluster clock. To use PLLP
>> + * for CPU clock source, need to enable PLLP branches to CPU by setting the
>> + * additional bit PLLP_OUT_CPU for gen5 super clock.
>>    */
>>   struct tegra_clk_super_mux {
>>   	struct clk_hw	hw;
>> @@ -710,6 +713,7 @@ struct tegra_clk_super_mux {
>>   #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
>>   
>>   #define TEGRA_DIVIDER_2 BIT(0)
>> +#define TEGRA_CPU_CLK	BIT(1)
> I'd name this TEGRA210_CPU_CLK for clarity.
>
>>   extern const struct clk_ops tegra_clk_super_ops;
>>   struct clk *tegra_clk_register_super_mux(const char *name,
>>
> Will be better to move the tegra_clk_set_pllp_out_cpu() definition into
> this patch, otherwise this looks inconsistent for reviewer.
ok, Will move to this patch

^ permalink raw reply

* Re: [PATCH V6 21/21] arm64: dts: tegra210-p3450: Jetson nano SC7 timings
From: Dmitry Osipenko @ 2019-07-21 22:25 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <1563738060-30213-22-git-send-email-skomatineni@nvidia.com>

21.07.2019 22:41, Sowjanya Komatineni пишет:
> This patch adds Jetson nano platform specific SC7 timing configuration
> in the device tree.

You should stat all names with a capital letter, hence "Jetson Nano" and
"Tegra" in all patches (commit title/message and code comments). When
unsure, just go to google and find how official name looks like.

> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> index 9d17ec707bce..b525e69c172a 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> +++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
> @@ -382,6 +382,13 @@
>  
>  	pmc@7000e400 {
>  		nvidia,invert-interrupt;
> +		nvidia,suspend-mode = <0>;
> +		nvidia,cpu-pwr-good-time = <0>;
> +		nvidia,cpu-pwr-off-time = <0>;
> +		nvidia,core-pwr-good-time = <4587 3876>;
> +		nvidia,core-pwr-off-time = <39065>;
> +		nvidia,core-power-req-active-high;
> +		nvidia,sys-clock-req-active-high;
>  	};
>  
>  	hda@70030000 {
> 

^ permalink raw reply

* Re: [PATCH V6 06/21] clk: tegra: pll: Save and restore pll context
From: Dmitry Osipenko @ 2019-07-21 22:21 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <1563738060-30213-7-git-send-email-skomatineni@nvidia.com>

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch implements save and restore of PLL context.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry pll rate is stored and on resume it is
> restored back along with its state.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll.c      | 121 ++++++++++++++++++++++++++++-----------
>  drivers/clk/tegra/clk-tegra210.c |   2 +-
>  drivers/clk/tegra/clk.h          |  10 +++-
>  3 files changed, 99 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1583f5fc992f..f136964e6c44 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1008,6 +1008,59 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
>  	return rate;
>  }
>  
> +void tegra_clk_sync_state_pll(struct clk_hw *hw)
> +{
> +	if (!__clk_get_enable_count(hw->clk))
> +		clk_pll_disable(hw);
> +	else
> +		clk_pll_enable(hw);
> +}
> +
> +static int tegra_clk_pll_save_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +	u32 val = 0;
> +
> +	pll->rate = clk_hw_get_rate(hw);

Again, clk_hw_get_rate() returns cached value. Why do you need to
duplicate it?

> +	if (pll->params->flags & TEGRA_PLLMB)
> +		val = pll_readl_base(pll);
> +	else if (pll->params->flags & TEGRA_PLLRE)
> +		val = pll_readl_base(pll) & divp_mask_shifted(pll);
> +
> +	pll->pllbase_ctx = val;
> +
> +	return 0;
> +}
> +
> +static void tegra_clk_pll_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +	u32 val;
> +
> +	if (clk_pll_is_enabled(hw))
> +		return;
> +
> +	if (pll->params->flags & TEGRA_PLLMB) {
> +		pll_writel_base(pll->pllbase_ctx, pll);
> +	} else if (pll->params->flags & TEGRA_PLLRE) {
> +		val = pll_readl_base(pll);
> +		val &= ~(divp_mask_shifted(pll));
> +		pll_writel_base(pll->pllbase_ctx | val, pll);
> +	}
> +
> +	if (pll->params->set_defaults)
> +		pll->params->set_defaults(pll);
> +
> +	clk_pll_set_rate(hw, pll->rate, parent_rate);
> +
> +	/* do not sync pllx state here. pllx is sync'd after dfll resume */
> +	if (!(pll->params->flags & TEGRA_PLLX))
> +		tegra_clk_sync_state_pll(hw);
> +}
> +
>  const struct clk_ops tegra_clk_pll_ops = {
>  	.is_enabled = clk_pll_is_enabled,
>  	.enable = clk_pll_enable,
> @@ -1015,6 +1068,8 @@ const struct clk_ops tegra_clk_pll_ops = {
>  	.recalc_rate = clk_pll_recalc_rate,
>  	.round_rate = clk_pll_round_rate,
>  	.set_rate = clk_pll_set_rate,
> +	.save_context = tegra_clk_pll_save_context,
> +	.restore_context = tegra_clk_pll_restore_context,
>  };
>  
>  const struct clk_ops tegra_clk_plle_ops = {
> @@ -1802,6 +1857,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
>  
>  	return ret;
>  }
> +
> +static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll)
> +{
> +	u32 val, val_aux;
> +
> +	/* ensure parent is set to pll_ref */
> +	val = pll_readl_base(pll);
> +	val_aux = pll_readl(pll->params->aux_reg, pll);
> +
> +	if (val & PLL_BASE_ENABLE) {
> +		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
> +		    (val_aux & PLLE_AUX_PLLP_SEL))
> +			WARN(1, "pll_e enabled with unsupported parent %s\n",
> +			     (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
> +			     "pll_re_vco");
> +	} else {
> +		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
> +		pll_writel(val_aux, pll->params->aux_reg, pll);
> +		fence_udelay(1, pll->clk_base);
> +	}
> +}
>  #endif
>  
>  static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
> @@ -2214,27 +2290,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
>  {
>  	struct tegra_clk_pll *pll;
>  	struct clk *clk;
> -	u32 val, val_aux;
>  
>  	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
>  	if (IS_ERR(pll))
>  		return ERR_CAST(pll);
>  
> -	/* ensure parent is set to pll_re_vco */
> -
> -	val = pll_readl_base(pll);
> -	val_aux = pll_readl(pll_params->aux_reg, pll);
> -
> -	if (val & PLL_BASE_ENABLE) {
> -		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
> -			(val_aux & PLLE_AUX_PLLP_SEL))
> -			WARN(1, "pll_e enabled with unsupported parent %s\n",
> -			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
> -					"pll_re_vco");
> -	} else {
> -		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
> -		pll_writel(val_aux, pll_params->aux_reg, pll);
> -	}
> +	_clk_plle_tegra_init_parent(pll);
>  
>  	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
>  				      &tegra_clk_plle_tegra114_ops);
> @@ -2276,6 +2337,8 @@ static const struct clk_ops tegra_clk_pllss_ops = {
>  	.recalc_rate = clk_pll_recalc_rate,
>  	.round_rate = clk_pll_ramp_round_rate,
>  	.set_rate = clk_pllxc_set_rate,
> +	.save_context = tegra_clk_pll_save_context,
> +	.restore_context = tegra_clk_pll_restore_context,
>  };
>  
>  struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
> @@ -2375,6 +2438,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
>  		pll_params->vco_min = pll_params->adjust_vco(pll_params,
>  							     parent_rate);
>  
> +	pll_params->flags |= TEGRA_PLLRE;
>  	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>  	if (IS_ERR(pll))
>  		return ERR_CAST(pll);
> @@ -2520,11 +2584,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
>  		spin_unlock_irqrestore(pll->lock, flags);
>  }
>  
> +static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll *pll = to_clk_pll(hw);
> +
> +	_clk_plle_tegra_init_parent(pll);
> +}
> +
>  static const struct clk_ops tegra_clk_plle_tegra210_ops = {
>  	.is_enabled =  clk_plle_tegra210_is_enabled,
>  	.enable = clk_plle_tegra210_enable,
>  	.disable = clk_plle_tegra210_disable,
>  	.recalc_rate = clk_pll_recalc_rate,
> +	.restore_context = tegra_clk_plle_t210_restore_context,
>  };
>  
>  struct clk *tegra_clk_register_plle_tegra210(const char *name,
> @@ -2535,27 +2607,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name,
>  {
>  	struct tegra_clk_pll *pll;
>  	struct clk *clk;
> -	u32 val, val_aux;
>  
>  	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
>  	if (IS_ERR(pll))
>  		return ERR_CAST(pll);
>  
> -	/* ensure parent is set to pll_re_vco */
> -
> -	val = pll_readl_base(pll);
> -	val_aux = pll_readl(pll_params->aux_reg, pll);
> -
> -	if (val & PLLE_BASE_ENABLE) {
> -		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
> -			(val_aux & PLLE_AUX_PLLP_SEL))
> -			WARN(1, "pll_e enabled with unsupported parent %s\n",
> -			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
> -					"pll_re_vco");
> -	} else {
> -		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
> -		pll_writel(val_aux, pll_params->aux_reg, pll);
> -	}
> +	_clk_plle_tegra_init_parent(pll);
>  
>  	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
>  				      &tegra_clk_plle_tegra210_ops);
> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index 4721ee030d1c..58397f93166c 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -1602,7 +1602,7 @@ static struct tegra_clk_pll_params pll_x_params = {
>  	.pdiv_tohw = pll_qlin_pdiv_to_hw,
>  	.div_nmp = &pllx_nmp,
>  	.freq_table = pll_x_freq_table,
> -	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
> +	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLLX,
>  	.dyn_ramp = tegra210_pllx_dyn_ramp,
>  	.set_defaults = tegra210_pllx_set_defaults,
>  	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index fb29a8c27873..8532f5150091 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -235,6 +235,8 @@ struct tegra_clk_pll;
>   * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
>   *     flag indicated that it is PLLMB.
>   * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
> + * TEGRA_PLLRE - Used to indicate that it is PLLRE.
> + * TEGRA_PLLX - Used to indicate that it is PLLX.
>   */
>  struct tegra_clk_pll_params {
>  	unsigned long	input_min;
> @@ -301,6 +303,8 @@ struct tegra_clk_pll_params {
>  #define TEGRA_MDIV_NEW BIT(11)
>  #define TEGRA_PLLMB BIT(12)
>  #define TEGRA_PLL_VCO_OUT BIT(13)
> +#define TEGRA_PLLRE BIT(14)
> +#define TEGRA_PLLX BIT(15)
>  
>  /**
>   * struct tegra_clk_pll - Tegra PLL clock
> @@ -310,6 +314,8 @@ struct tegra_clk_pll_params {
>   * @pmc:	address of PMC, required to read override bits
>   * @lock:	register lock
>   * @params:	PLL parameters
> + * @rate:	rate during system suspend and resume
> + * @pllbase_ctx: pll base register value during suspend and resume
>   */
>  struct tegra_clk_pll {
>  	struct clk_hw	hw;
> @@ -317,6 +323,8 @@ struct tegra_clk_pll {
>  	void __iomem	*pmc;
>  	spinlock_t	*lock;
>  	struct tegra_clk_pll_params	*params;
> +	unsigned long	rate;
> +	u32	pllbase_ctx;
>  };
>  
>  #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
> @@ -840,7 +848,7 @@ u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
>  int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
>  int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
>  		 u8 frac_width, u8 flags);
> -
> +void tegra_clk_sync_state_pll(struct clk_hw *hw);
>  
>  /* Combined read fence with delay */
>  #define fence_udelay(delay, reg)	\
> 

^ permalink raw reply

* Re: [PATCH V6 05/21] clk: tegra: pllout: Save and restore pllout context
From: Dmitry Osipenko @ 2019-07-21 22:18 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <1563738060-30213-6-git-send-email-skomatineni@nvidia.com>

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch implements save and restore of pllout context.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry the state of pllout is saved and on resume
> it is restored back to have pllout in same state as before suspend.
> 
> pllout rate is saved and restore in clock divider so it will be at
> same rate as before suspend when pllout state is restored.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-pll-out.c  | 28 ++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-tegra210.c |  3 ++-
>  drivers/clk/tegra/clk.h          |  9 +++++++++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
> index 35f2bf00e1e6..8f26a7e3e579 100644
> --- a/drivers/clk/tegra/clk-pll-out.c
> +++ b/drivers/clk/tegra/clk-pll-out.c
> @@ -69,10 +69,38 @@ static void clk_pll_out_disable(struct clk_hw *hw)
>  		spin_unlock_irqrestore(pll_out->lock, flags);
>  }
>  
> +static int tegra_clk_pll_out_save_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
> +
> +	if (pll_out->flags & TEGRA_PLLRE_OUT)
> +		pll_out->pllout_ctx = readl_relaxed(pll_out->reg);


> +	else
> +		pll_out->pllout_ctx = clk_hw_get_rate(hw);

This is unused?

> +	return 0;
> +}
> +
> +static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
> +
> +	if (pll_out->flags & TEGRA_PLLRE_OUT) {
> +		writel_relaxed(pll_out->pllout_ctx, pll_out->reg);
> +	} else {
> +		if (!__clk_get_enable_count(hw->clk))
> +			clk_pll_out_disable(hw);
> +		else
> +			clk_pll_out_enable(hw);
> +	}
> +}
> +
>  const struct clk_ops tegra_clk_pll_out_ops = {
>  	.is_enabled = clk_pll_out_is_enabled,
>  	.enable = clk_pll_out_enable,
>  	.disable = clk_pll_out_disable,
> +	.save_context = tegra_clk_pll_out_save_context,
> +	.restore_context = tegra_clk_pll_out_restore_context,
>  };
>  
>  struct clk *tegra_clk_register_pll_out(const char *name,
> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> index df172d5772d7..4721ee030d1c 100644
> --- a/drivers/clk/tegra/clk-tegra210.c
> +++ b/drivers/clk/tegra/clk-tegra210.c
> @@ -3200,7 +3200,8 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
>  					 8, 8, 1, NULL);
>  	clk = tegra_clk_register_pll_out("pll_re_out1", "pll_re_out1_div",
>  					 clk_base + PLLRE_OUT1, 1, 0,
> -					 CLK_SET_RATE_PARENT, 0, NULL);
> +					 CLK_SET_RATE_PARENT, TEGRA_PLLRE_OUT,
> +					 NULL);
>  	clks[TEGRA210_CLK_PLL_RE_OUT1] = clk;
>  
>  	/* PLLE */
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index 83623f5f55f3..fb29a8c27873 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -439,6 +439,12 @@ struct clk *tegra_clk_register_pllu_tegra210(const char *name,
>   * @rst_bit_idx:	bit to reset PLL divider
>   * @lock:		register lock
>   * @flags:		hardware-specific flags
> + * @pllout_ctx:		pllout context to save and restore during suspend
> + *			and resume
> + *
> + * Flags:
> + * TEGRA_PLLRE_OUT - This flag indicates that it is PLLRE_OUT and is used to
> + *		     identify PLLRE_OUT during clk_pll_out save and restore.
>   */
>  struct tegra_clk_pll_out {
>  	struct clk_hw	hw;
> @@ -447,8 +453,11 @@ struct tegra_clk_pll_out {
>  	u8		rst_bit_idx;
>  	spinlock_t	*lock;
>  	u8		flags;
> +	unsigned int	pllout_ctx;

u32

>  };
>  
> +#define TEGRA_PLLRE_OUT BIT(0)
> +
>  #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
>  
>  extern const struct clk_ops tegra_clk_pll_out_ops;
> 

^ permalink raw reply

* Re: [PATCH V6 04/21] clk: tegra: Save and restore divider rate
From: Dmitry Osipenko @ 2019-07-21 22:14 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <1563738060-30213-5-git-send-email-skomatineni@nvidia.com>

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch implements context save and restore for clock divider.
> 
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
> 
> So during suspend entry the context of clock divider is saved and
> on resume context is restored back for normal operation.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-divider.c | 23 +++++++++++++++++++++++
>  drivers/clk/tegra/clk.h         |  2 ++
>  2 files changed, 25 insertions(+)
> 
> diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
> index e76731fb7d69..ecb7ff9ce97e 100644
> --- a/drivers/clk/tegra/clk-divider.c
> +++ b/drivers/clk/tegra/clk-divider.c
> @@ -109,10 +109,33 @@ static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
>  	return 0;
>  }
>  
> +static int clk_divider_save_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +
> +	divider->rate = clk_frac_div_recalc_rate(hw, parent_rate);

I'm not sure what's the point of this, because clk_hw_get_rate() returns
cached value.

> +	return 0;
> +}
> +
> +static void clk_divider_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +
> +	if (clk_frac_div_set_rate(hw, divider->rate, parent_rate) < 0)
> +		WARN_ON(1);

Hence this could be:

	unsigned long parent_rate = clk_hw_get_rate(parent);
	unsigned long rate = clk_hw_get_rate(hw);

	if (clk_frac_div_set_rate(hw, rate, parent_rate) < 0)
		WARN_ON(1);

> +}
> +
>  const struct clk_ops tegra_clk_frac_div_ops = {
>  	.recalc_rate = clk_frac_div_recalc_rate,
>  	.set_rate = clk_frac_div_set_rate,
>  	.round_rate = clk_frac_div_round_rate,
> +	.save_context = clk_divider_save_context,
> +	.restore_context = clk_divider_restore_context,
>  };
>  
>  struct clk *tegra_clk_register_divider(const char *name,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index 905bf1096558..83623f5f55f3 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -42,6 +42,7 @@ struct clk *tegra_clk_register_sync_source(const char *name,
>   * @width:	width of the divider bit field
>   * @frac_width:	width of the fractional bit field
>   * @lock:	register lock
> + * @rate:	rate during suspend and resume
>   *
>   * Flags:
>   * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value.
> @@ -62,6 +63,7 @@ struct tegra_clk_frac_div {
>  	u8		width;
>  	u8		frac_width;
>  	spinlock_t	*lock;
> +	unsigned long	rate;
>  };
>  
>  #define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw)
> 

^ permalink raw reply

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
From: Dmitry Osipenko @ 2019-07-21 22:09 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <d837e4e0-947b-2b90-c680-ab913e70e587@gmail.com>

22.07.2019 1:03, Dmitry Osipenko пишет:
> 21.07.2019 22:40, Sowjanya Komatineni пишет:
>> This patch adds support for Tegra pinctrl driver suspend and resume.
>>
>> During suspend, context of all pinctrl registers are stored and
>> on resume they are all restored to have all the pinmux and pad
>> configuration for normal operation.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>>  drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>>  drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>>  2 files changed, 62 insertions(+)
>>
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> index 186ef98e7b2b..e3a237534281 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
>> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>>  	}
>>  }
>>  
>> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
>> +					  unsigned int bank_id)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct resource *res;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
>> +
>> +	return resource_size(res) / 4;
>> +}
>> +
>> +static int tegra_pinctrl_suspend(struct device *dev)
>> +{
>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>> +	u32 *backup_regs = pmx->backup_regs;
>> +	u32 *regs;
>> +	size_t bank_size;
>> +	unsigned int i, k;
>> +
>> +	for (i = 0; i < pmx->nbanks; i++) {
>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>> +		regs = pmx->regs[i];
>> +		for (k = 0; k < bank_size; k++)
>> +			*backup_regs++ = readl_relaxed(regs++);
>> +	}
>> +
>> +	return pinctrl_force_sleep(pmx->pctl);
>> +}
>> +
>> +static int tegra_pinctrl_resume(struct device *dev)
>> +{
>> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
>> +	u32 *backup_regs = pmx->backup_regs;
>> +	u32 *regs;
>> +	size_t bank_size;
>> +	unsigned int i, k;
>> +
>> +	for (i = 0; i < pmx->nbanks; i++) {
>> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
>> +		regs = pmx->regs[i];
>> +		for (k = 0; k < bank_size; k++)
>> +			writel_relaxed(*backup_regs++, regs++);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +const struct dev_pm_ops tegra_pinctrl_pm = {
>> +	.suspend = &tegra_pinctrl_suspend,
>> +	.resume = &tegra_pinctrl_resume
>> +};
>> +
>>  static bool gpio_node_has_range(const char *compatible)
>>  {
>>  	struct device_node *np;
>> @@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>  	int i;
>>  	const char **group_pins;
>>  	int fn, gn, gfn;
>> +	unsigned long backup_regs_size = 0;
>>  
>>  	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
>>  	if (!pmx)
>> @@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>>  		if (!res)
>>  			break;
>> +		backup_regs_size += resource_size(res);
>>  	}
>>  	pmx->nbanks = i;
>>  
>> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>>  	if (!pmx->regs)
>>  		return -ENOMEM;
>>  
>> +	pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
>> +					GFP_KERNEL);
>> +	if (!pmx->backup_regs)
>> +		return -ENOMEM;
>> +
>>  	for (i = 0; i < pmx->nbanks; i++) {
>>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>>  		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
>> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> index 105309774079..0fc82eea9cf1 100644
>> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
>> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
>> @@ -17,6 +17,7 @@ struct tegra_pmx {
>>  
>>  	int nbanks;
>>  	void __iomem **regs;
>> +	u32 *backup_regs;
>>  };
>>  
>>  enum tegra_pinconf_param {
>> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>>  	bool drvtype_in_mux;
>>  };
>>  
>> +extern const struct dev_pm_ops tegra_pinctrl_pm;
>> +
>>  int tegra_pinctrl_probe(struct platform_device *pdev,
>>  			const struct tegra_pinctrl_soc_data *soc_data);
>>  #endif
>>
> 
> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> 

BTW, you should remove Thierry's ACK from all patches that were modified
if he didn't re-ACK the new version.

Also, it looks to me that you're manually adding versioning to the
patches because git usually uses lowercase for 'v'. You could use "git
format-patch -v6 ..".

^ permalink raw reply

* Re: [PATCH V6 02/21] pinctrl: tegra: Add suspend and resume support
From: Dmitry Osipenko @ 2019-07-21 22:03 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
	marc.zyngier, linus.walleij, stefan, mark.rutland
  Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
	josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
	robh+dt, devicetree
In-Reply-To: <1563738060-30213-3-git-send-email-skomatineni@nvidia.com>

21.07.2019 22:40, Sowjanya Komatineni пишет:
> This patch adds support for Tegra pinctrl driver suspend and resume.
> 
> During suspend, context of all pinctrl registers are stored and
> on resume they are all restored to have all the pinmux and pad
> configuration for normal operation.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
>  drivers/pinctrl/tegra/pinctrl-tegra.h |  3 ++
>  2 files changed, 62 insertions(+)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 186ef98e7b2b..e3a237534281 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
>  	}
>  }
>  
> +static size_t tegra_pinctrl_get_bank_size(struct device *dev,
> +					  unsigned int bank_id)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct resource *res;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
> +
> +	return resource_size(res) / 4;
> +}
> +
> +static int tegra_pinctrl_suspend(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	size_t bank_size;
> +	unsigned int i, k;
> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
> +		regs = pmx->regs[i];
> +		for (k = 0; k < bank_size; k++)
> +			*backup_regs++ = readl_relaxed(regs++);
> +	}
> +
> +	return pinctrl_force_sleep(pmx->pctl);
> +}
> +
> +static int tegra_pinctrl_resume(struct device *dev)
> +{
> +	struct tegra_pmx *pmx = dev_get_drvdata(dev);
> +	u32 *backup_regs = pmx->backup_regs;
> +	u32 *regs;
> +	size_t bank_size;
> +	unsigned int i, k;
> +
> +	for (i = 0; i < pmx->nbanks; i++) {
> +		bank_size = tegra_pinctrl_get_bank_size(dev, i);
> +		regs = pmx->regs[i];
> +		for (k = 0; k < bank_size; k++)
> +			writel_relaxed(*backup_regs++, regs++);
> +	}
> +
> +	return 0;
> +}
> +
> +const struct dev_pm_ops tegra_pinctrl_pm = {
> +	.suspend = &tegra_pinctrl_suspend,
> +	.resume = &tegra_pinctrl_resume
> +};
> +
>  static bool gpio_node_has_range(const char *compatible)
>  {
>  	struct device_node *np;
> @@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  	int i;
>  	const char **group_pins;
>  	int fn, gn, gfn;
> +	unsigned long backup_regs_size = 0;
>  
>  	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
>  	if (!pmx)
> @@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>  		if (!res)
>  			break;
> +		backup_regs_size += resource_size(res);
>  	}
>  	pmx->nbanks = i;
>  
> @@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
>  	if (!pmx->regs)
>  		return -ENOMEM;
>  
> +	pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
> +					GFP_KERNEL);
> +	if (!pmx->backup_regs)
> +		return -ENOMEM;
> +
>  	for (i = 0; i < pmx->nbanks; i++) {
>  		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
>  		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
> index 105309774079..0fc82eea9cf1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.h
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
> @@ -17,6 +17,7 @@ struct tegra_pmx {
>  
>  	int nbanks;
>  	void __iomem **regs;
> +	u32 *backup_regs;
>  };
>  
>  enum tegra_pinconf_param {
> @@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
>  	bool drvtype_in_mux;
>  };
>  
> +extern const struct dev_pm_ops tegra_pinctrl_pm;
> +
>  int tegra_pinctrl_probe(struct platform_device *pdev,
>  			const struct tegra_pinctrl_soc_data *soc_data);
>  #endif
> 

Reviewed-by: Dmitry Osipenko <digetx@gmail.com>

^ permalink raw reply


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