Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 02/15] net: phy: adin: hook genphy_read_abilities() to get_features
From: Ardelean, Alexandru @ 2019-08-09 12:00 UTC (permalink / raw)
  To: hkallweit1@gmail.com, andrew@lunn.ch
  Cc: f.fainelli@gmail.com, mark.rutland@arm.com,
	devicetree@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, robh+dt@kernel.org,
	davem@davemloft.net
In-Reply-To: <eeda87c9-bdba-8ef7-6043-85a16bd2cfc2@gmail.com>

On Thu, 2019-08-08 at 21:32 +0200, Heiner Kallweit wrote:
> [External]
> 
> On 08.08.2019 17:24, Andrew Lunn wrote:
> > On Thu, Aug 08, 2019 at 03:30:13PM +0300, Alexandru Ardelean wrote:
> > > The ADIN PHYs can operate with Clause 45, however they are not typical for
> > > how phylib considers Clause 45 PHYs.
> > > 
> > > If the `features` field & the `get_features` hook are unspecified, and the
> > > device wants to operate via Clause 45, it would also try to read features
> > > via the `genphy_c45_pma_read_abilities()`, which will try to read PMA regs
> > > that are unsupported.
> > > 
> > > Hooking the `genphy_read_abilities()` function to the `get_features` hook
> > > will ensure that this does not happen and the PHY features are read
> > > correctly regardless of Clause 22 or Clause 45 operation.
> > 
> > I think we need to stop and think about a PHY which supports both C22
> > and C45.
> > 
> > How does bus enumeration work? Is it discovered twice?  I've always
> > considered phydev->is_c45 means everything is c45, not that some
> > registers can be accessed via c45. But the driver is mixing c22 and
> > c45. Does the driver actually require c45? Are some features which are
> > only accessibly via C45? What does C45 actually bring us for this
> > device?
> > 

Hmm, I can't answer [all] these questions.

These PHYs seem to be a bit different from the rest that I looked at in drivers/net/phy with regard to C45 & C22.
And C45 seems to be more/closer related to 10G PHYs [from what I can tell].

The ADIN PHYs can operate only in C22.
The only thing that is needed [and a bit special] is EEE, which [for C22] requires the translation layer to convert C45
reg addresses to internal C22 equivalent.

> genphy_c45_pma_read_abilities() is only called if phydev->is_c45 is set.
> And this flag means that the PHY complies with Clause 45 incl. all the
> standard devices like PMA. In the case here only some vendor-specific
> registers can be accessed via Clause 45 and therefore is_c45 shouldn't
> bet set. As a consequence this patch isn't needed.

ack, will drop patch

> 
> >      Andrew
> > 
> Heiner
> 

^ permalink raw reply

* Re: [PATCH v8 08/21] clk: tegra: periph: Add restore_context support
From: Dmitry Osipenko @ 2019-08-09 11:55 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, rjw, viresh.kumar, linux-pm
In-Reply-To: <1565308020-31952-9-git-send-email-skomatineni@nvidia.com>

09.08.2019 2:46, Sowjanya Komatineni пишет:
> This patch implements restore_context support for clk-periph and
> clk-sdmmc-mux clock operations to restore clock parent and rates
> on system resume.
> 
> During system suspend, core power goes off and looses the context
> of the Tegra clock controller registers.
> 
> So on system resume, clocks parent and rate are restored back to
> the context before suspend based on cached data.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/tegra/clk-periph.c    | 18 ++++++++++++++++++
>  drivers/clk/tegra/clk-sdmmc-mux.c | 12 ++++++++++++
>  2 files changed, 30 insertions(+)
> 
> diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
> index 58437da25156..c9d28cbadccc 100644
> --- a/drivers/clk/tegra/clk-periph.c
> +++ b/drivers/clk/tegra/clk-periph.c
> @@ -3,6 +3,7 @@
>   * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
>   */
>  
> +#include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/export.h>
>  #include <linux/slab.h>
> @@ -99,6 +100,20 @@ static void clk_periph_disable(struct clk_hw *hw)
>  	gate_ops->disable(gate_hw);
>  }
>  
> +static void clk_periph_restore_context(struct clk_hw *hw)
> +{
> +	struct tegra_clk_periph *periph = to_clk_periph(hw);
> +	const struct clk_ops *div_ops = periph->div_ops;
> +	struct clk_hw *div_hw = &periph->divider.hw;
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	int parent_id = clk_hw_get_parent_index(hw, parent);
> +
> +	if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
> +		div_ops->restore_context(div_hw);
> +
> +	clk_periph_set_parent(hw, parent_id);
> +}
> +
>  const struct clk_ops tegra_clk_periph_ops = {
>  	.get_parent = clk_periph_get_parent,
>  	.set_parent = clk_periph_set_parent,
> @@ -108,6 +123,7 @@ const struct clk_ops tegra_clk_periph_ops = {
>  	.is_enabled = clk_periph_is_enabled,
>  	.enable = clk_periph_enable,
>  	.disable = clk_periph_disable,
> +	.restore_context = clk_periph_restore_context,
>  };
>  
>  static const struct clk_ops tegra_clk_periph_nodiv_ops = {
> @@ -116,6 +132,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
>  	.is_enabled = clk_periph_is_enabled,
>  	.enable = clk_periph_enable,
>  	.disable = clk_periph_disable,
> +	.restore_context = clk_periph_restore_context,
>  };
>  
>  static const struct clk_ops tegra_clk_periph_no_gate_ops = {
> @@ -124,6 +141,7 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
>  	.recalc_rate = clk_periph_recalc_rate,
>  	.round_rate = clk_periph_round_rate,
>  	.set_rate = clk_periph_set_rate,
> +	.restore_context = clk_periph_restore_context,
>  };
>  
>  static struct clk *_tegra_clk_register_periph(const char *name,
> diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c
> index a5cd3e31dbae..8db48966b100 100644
> --- a/drivers/clk/tegra/clk-sdmmc-mux.c
> +++ b/drivers/clk/tegra/clk-sdmmc-mux.c
> @@ -194,6 +194,17 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
>  	gate_ops->disable(gate_hw);
>  }
>  
> +static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
> +{
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	unsigned long parent_rate = clk_hw_get_rate(parent);
> +	unsigned long rate = clk_hw_get_rate(hw);
> +	int parent_id = clk_hw_get_parent_index(hw, parent);
> +
> +	clk_sdmmc_mux_set_parent(hw, parent_id);
> +	clk_sdmmc_mux_set_rate(hw, rate, parent_rate);

For the periph clocks you're restoring rate at first and then the
parent, while here it's the other way around. I'm wondering if there is
any difference in practice and thus whether rate's divider need to be
set to a some safe value before switching to a new parent that has a
higher clock rate than the old parent.

> +}
> +
>  static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
>  	.get_parent = clk_sdmmc_mux_get_parent,
>  	.set_parent = clk_sdmmc_mux_set_parent,
> @@ -203,6 +214,7 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
>  	.is_enabled = clk_sdmmc_mux_is_enabled,
>  	.enable = clk_sdmmc_mux_enable,
>  	.disable = clk_sdmmc_mux_disable,
> +	.restore_context = clk_sdmmc_mux_restore_context,
>  };
>  
>  struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,
> 

^ permalink raw reply

* Re: [PATCH v8 07/21] clk: Add API to get index of the clock parent
From: Dmitry Osipenko @ 2019-08-09 11:49 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, rjw, viresh.kumar, linux-pm
In-Reply-To: <1565308020-31952-8-git-send-email-skomatineni@nvidia.com>

09.08.2019 2:46, Sowjanya Komatineni пишет:
> This patch adds an API clk_hw_get_parent_index to get index of the
> clock parent to use during the clock restore operations on system
> resume.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/clk/clk.c            | 17 +++++++++++++++++
>  include/linux/clk-provider.h |  1 +
>  2 files changed, 18 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index c0990703ce54..f26252e48f73 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -1643,6 +1643,23 @@ static int clk_fetch_parent_index(struct clk_core *core,
>  	return i;
>  }
>  
> +/**
> + * clk_hw_get_parent_index - return the index of parent clock
> + * @hw: clk_hw associated with the clk being consumed
> + * @parent_hw: clk_hw associated with the parent of clk
> + *
> + * Fetches and returns the index of parent clock.
> + * if hw or parent_hw is NULL, returns -EINVAL.
> + */
> +int clk_hw_get_parent_index(struct clk_hw *hw, struct clk_hw *parent_hw)
> +{
> +	if (!hw || !parent_hw)
> +		return -EINVAL;
> +
> +	return clk_fetch_parent_index(hw->core, parent_hw->core);
> +}
> +EXPORT_SYMBOL_GPL(clk_hw_get_parent_index);
> +
>  /*
>   * Update the orphan status of @core and all its children.
>   */
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 2ae7604783dd..477112946dd2 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -817,6 +817,7 @@ unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
>  struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
>  struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
>  					  unsigned int index);
> +int clk_hw_get_parent_index(struct clk_hw *hw, struct clk_hw *parent_hw);
>  unsigned int __clk_get_enable_count(struct clk *clk);
>  unsigned long clk_hw_get_rate(const struct clk_hw *hw);
>  unsigned long __clk_get_flags(struct clk *clk);
> 

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

^ permalink raw reply

* Re: [PATCH v8 02/21] pinctrl: tegra: Add write barrier after all pinctrl register writes
From: Dmitry Osipenko @ 2019-08-09 11:39 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, rjw, viresh.kumar, linux-pm
In-Reply-To: <1565308020-31952-3-git-send-email-skomatineni@nvidia.com>

09.08.2019 2:46, Sowjanya Komatineni пишет:
> This patch adds write barrier after all pinctrl register writes
> during resume to make sure all pinctrl changes are complete.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index 982ee634b3b1..f49fe29fb6df 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -677,6 +677,8 @@ static int tegra_pinctrl_resume(struct device *dev)
>  			writel_relaxed(*backup_regs++, regs++);
>  	}
>  
> +	/* make sure all the pinmux register writes are complete */
> +	wmb();
>  	return 0;
>  }
>  
> 

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

^ permalink raw reply

* Re: [PATCH v8 01/21] pinctrl: tegra: Fix write barrier placement in pmx_writel
From: Dmitry Osipenko @ 2019-08-09 11:38 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, rjw, viresh.kumar, linux-pm
In-Reply-To: <1565308020-31952-2-git-send-email-skomatineni@nvidia.com>

09.08.2019 2:46, Sowjanya Komatineni пишет:
> pmx_writel uses writel which inserts write barrier before the
> register write rather.
> 
> This patch has fix to replace writel with writel_relaxed followed
> by a write barrier to ensure write operation before the barrier
> is completed for successful pinctrl change.
> 
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  drivers/pinctrl/tegra/pinctrl-tegra.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
> index e3a237534281..982ee634b3b1 100644
> --- a/drivers/pinctrl/tegra/pinctrl-tegra.c
> +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
> @@ -32,7 +32,9 @@ static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
>  
>  static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
>  {
> -	writel(val, pmx->regs[bank] + reg);
> +	writel_relaxed(val, pmx->regs[bank] + reg);
> +	/* make sure pinmux register write completed */
> +	wmb();
>  }
>  
>  static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
> 

But this only ensures that CPU have sent the write to the APB BUS and
not that the write actually taken into effect? I'm a bit paranoid when
it comes to a cross-domain synchronization things.

Any ways it looks better than it was before.

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

^ permalink raw reply

* Re: [PATCH v8 05/21] clk: tegra: pll: Save and restore pll context
From: Dmitry Osipenko @ 2019-08-09 11:33 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, rjw, viresh.kumar, linux-pm
In-Reply-To: <1565308020-31952-6-git-send-email-skomatineni@nvidia.com>

09.08.2019 2:46, 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 context 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 | 88 ++++++++++++++++++++++++++++-----------------
>  drivers/clk/tegra/clk.h     |  2 ++
>  2 files changed, 58 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1583f5fc992f..e52add2bbdbb 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
>  	return rate;
>  }
>  
> +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);
> +	unsigned long rate = clk_hw_get_rate(hw);
> +	u32 val;
> +
> +	if (clk_pll_is_enabled(hw))
> +		return;
> +
> +	if (pll->params->set_defaults)
> +		pll->params->set_defaults(pll);
> +
> +	clk_pll_set_rate(hw, rate, parent_rate);
> +
> +	if (!__clk_get_enable_count(hw->clk))

What about orphaned clocks? Is enable_count > 0 for them?

> +		clk_pll_disable(hw);
> +	else
> +		clk_pll_enable(hw);
> +}

[snip]

^ permalink raw reply

* [PATCH] ARM: dts: imx7d: cl-som-imx7: add compatible for phy
From: André Draszik @ 2019-08-09 11:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: André Draszik, Ilya Ledvich, Igor Grinberg, Rob Herring,
	Mark Rutland, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, devicetree, linux-arm-kernel

While not strictly needed as "ethernet-phy-ieee802.3-c22"
is assumed by default if not given explicitly, having
the compatible string here makes it more clear what
this is and which driver handles this - an Ethernet
phy attached to mdio, handled by of_mdio.c

Signed-off-by: André Draszik <git@andred.net>
CC: Ilya Ledvich <ilya@compulab.co.il>
CC: Igor Grinberg <grinberg@compulab.co.il>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Shawn Guo <shawnguo@kernel.org>
CC: Sascha Hauer <s.hauer@pengutronix.de>
CC: Pengutronix Kernel Team <kernel@pengutronix.de>
CC: Fabio Estevam <festevam@gmail.com>
CC: NXP Linux Team <linux-imx@nxp.com>
CC: devicetree@vger.kernel.org
CC: linux-arm-kernel@lists.infradead.org
---
 arch/arm/boot/dts/imx7d-cl-som-imx7.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
index 62d5e9a4a781..7646284e13a7 100644
--- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
+++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
@@ -54,10 +54,12 @@
 		#size-cells = <0>;
 
 		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <0>;
 		};
 
 		ethphy1: ethernet-phy@1 {
+			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <1>;
 		};
 	};
-- 
2.20.1

^ permalink raw reply related

* [PATCH v2 6/6] arm64: defconfig: Enable configs for S32V234
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

From: Mihaela Martinas <Mihaela.Martinas@freescale.com>

Enable support for the S32V234 SoC, including the previously added UART
driver.

Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Adrian.Nitu <adrian.nitu@freescale.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/configs/defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0e58ef02880c..bb5aa95a8455 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -48,6 +48,7 @@ CONFIG_ARCH_MXC=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_S32=y
 CONFIG_ARCH_SEATTLE=y
 CONFIG_ARCH_STRATIX10=y
 CONFIG_ARCH_SYNQUACER=y
@@ -347,6 +348,8 @@ CONFIG_SERIAL_XILINX_PS_UART=y
 CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
 CONFIG_SERIAL_FSL_LPUART=y
 CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_SERIAL_FSL_LINFLEXUART=y
+CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y
 CONFIG_SERIAL_MVEBU_UART=y
 CONFIG_SERIAL_DEV_BUS=y
 CONFIG_VIRTIO_CONSOLE=y
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 5/6] tty: serial: Add linflexuart driver for S32V234
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

Introduce support for LINFlex driver, based on:
- the version of Freescale LPUART driver after commit b3e3bf2ef2c7 ("Merge
  4.0-rc7 into tty-next");
- commit abf1e0a98083 ("tty: serial: fsl_lpuart: lock port on console
  write").
In this basic version, the driver can be tested using initramfs and relies
on the clocks and pin muxing set up by U-Boot.

Remarks concerning the earlycon support:

- LinFlexD does not allow character transmissions in the INIT mode (see
  section 47.4.2.1 in the reference manual[1]). Therefore, a mutual
  exclusion between the first linflex_setup_watermark/linflex_set_termios
  executions and linflex_earlycon_putchar was employed and the characters
  normally sent to earlycon during initialization are kept in a buffer and
  sent afterwards.

- Empirically, character transmission is also forbidden within the last 1-2
  ms before entering the INIT mode, so we use an explicit timeout
  (PREINIT_DELAY) between linflex_earlycon_putchar and the first call to
  linflex_setup_watermark.

- U-Boot currently uses the UART FIFO mode, while this driver makes the
  transition to the buffer mode. Therefore, the earlycon putchar function
  matches the U-Boot behavior before initializations and the Linux behavior
  after.

[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Adrian.Nitu <adrian.nitu@freescale.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Ana Nedelcu <B56683@freescale.com>
Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Matthew Nunez <matthew.nunez@nxp.com>
[stefan-gabriel.mirea@nxp.com: Reduced for upstreaming and implemented
                               earlycon support]
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 .../admin-guide/kernel-parameters.txt         |   6 +
 drivers/tty/serial/Kconfig                    |  15 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/fsl_linflexuart.c          | 942 ++++++++++++++++++
 include/uapi/linux/serial_core.h              |   3 +
 5 files changed, 967 insertions(+)
 create mode 100644 drivers/tty/serial/fsl_linflexuart.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 46b826fcb5ad..4d545732aadc 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1090,6 +1090,12 @@
 			the framebuffer, pass the 'ram' option so that it is
 			mapped with the correct attributes.
 
+		linflex,<addr>
+			Use early console provided by Freescale LinFlex UART
+			serial driver for NXP S32V234 SoCs. A valid base
+			address must be provided, and the serial port must
+			already be setup and configured.
+
 	earlyprintk=	[X86,SH,ARM,M68k,S390]
 			earlyprintk=vga
 			earlyprintk=sclp
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index fd385c8c53a5..b4fa2f7c96bd 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1452,6 +1452,21 @@ config SERIAL_FSL_LPUART_CONSOLE
 	  If you have enabled the lpuart serial port on the Freescale SoCs,
 	  you can make it the console by answering Y to this option.
 
+config SERIAL_FSL_LINFLEXUART
+	tristate "Freescale linflexuart serial port support"
+	select SERIAL_CORE
+	help
+	  Support for the on-chip linflexuart on some Freescale SOCs.
+
+config SERIAL_FSL_LINFLEXUART_CONSOLE
+	bool "Console on Freescale linflexuart serial port"
+	depends on SERIAL_FSL_LINFLEXUART=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	help
+	  If you have enabled the linflexuart serial port on the Freescale
+	  SoCs, you can make it the console by answering Y to this option.
+
 config SERIAL_CONEXANT_DIGICOLOR
 	tristate "Conexant Digicolor CX92xxx USART serial port support"
 	depends on OF
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7cd7cabfa6c4..7a3d52a453b7 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
+obj-$(CONFIG_SERIAL_FSL_LINFLEXUART)	+= fsl_linflexuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
new file mode 100644
index 000000000000..26b9601a0952
--- /dev/null
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -0,0 +1,942 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Freescale linflexuart serial port driver
+ *
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#if defined(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE) && \
+	defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+
+/* All registers are 32-bit width */
+
+#define LINCR1	0x0000	/* LIN control register				*/
+#define LINIER	0x0004	/* LIN interrupt enable register		*/
+#define LINSR	0x0008	/* LIN status register				*/
+#define LINESR	0x000C	/* LIN error status register			*/
+#define UARTCR	0x0010	/* UART mode control register			*/
+#define UARTSR	0x0014	/* UART mode status register			*/
+#define LINTCSR	0x0018	/* LIN timeout control status register		*/
+#define LINOCR	0x001C	/* LIN output compare register			*/
+#define LINTOCR	0x0020	/* LIN timeout control register			*/
+#define LINFBRR	0x0024	/* LIN fractional baud rate register		*/
+#define LINIBRR	0x0028	/* LIN integer baud rate register		*/
+#define LINCFR	0x002C	/* LIN checksum field register			*/
+#define LINCR2	0x0030	/* LIN control register 2			*/
+#define BIDR	0x0034	/* Buffer identifier register			*/
+#define BDRL	0x0038	/* Buffer data register least significant	*/
+#define BDRM	0x003C	/* Buffer data register most significant	*/
+#define IFER	0x0040	/* Identifier filter enable register		*/
+#define IFMI	0x0044	/* Identifier filter match index		*/
+#define IFMR	0x0048	/* Identifier filter mode register		*/
+#define GCR	0x004C	/* Global control register			*/
+#define UARTPTO	0x0050	/* UART preset timeout register			*/
+#define UARTCTO	0x0054	/* UART current timeout register		*/
+
+/*
+ * Register field definitions
+ */
+
+#define LINFLEXD_LINCR1_INIT		BIT(0)
+#define LINFLEXD_LINCR1_MME		BIT(4)
+#define LINFLEXD_LINCR1_BF		BIT(7)
+
+#define LINFLEXD_LINSR_LINS_INITMODE	BIT(12)
+#define LINFLEXD_LINSR_LINS_MASK	(0xF << 12)
+
+#define LINFLEXD_LINIER_SZIE		BIT(15)
+#define LINFLEXD_LINIER_OCIE		BIT(14)
+#define LINFLEXD_LINIER_BEIE		BIT(13)
+#define LINFLEXD_LINIER_CEIE		BIT(12)
+#define LINFLEXD_LINIER_HEIE		BIT(11)
+#define LINFLEXD_LINIER_FEIE		BIT(8)
+#define LINFLEXD_LINIER_BOIE		BIT(7)
+#define LINFLEXD_LINIER_LSIE		BIT(6)
+#define LINFLEXD_LINIER_WUIE		BIT(5)
+#define LINFLEXD_LINIER_DBFIE		BIT(4)
+#define LINFLEXD_LINIER_DBEIETOIE	BIT(3)
+#define LINFLEXD_LINIER_DRIE		BIT(2)
+#define LINFLEXD_LINIER_DTIE		BIT(1)
+#define LINFLEXD_LINIER_HRIE		BIT(0)
+
+#define LINFLEXD_UARTCR_OSR_MASK	(0xF << 24)
+#define LINFLEXD_UARTCR_OSR(uartcr)	(((uartcr) \
+					& LINFLEXD_UARTCR_OSR_MASK) >> 24)
+
+#define LINFLEXD_UARTCR_ROSE		BIT(23)
+
+#define LINFLEXD_UARTCR_RFBM		BIT(9)
+#define LINFLEXD_UARTCR_TFBM		BIT(8)
+#define LINFLEXD_UARTCR_WL1		BIT(7)
+#define LINFLEXD_UARTCR_PC1		BIT(6)
+
+#define LINFLEXD_UARTCR_RXEN		BIT(5)
+#define LINFLEXD_UARTCR_TXEN		BIT(4)
+#define LINFLEXD_UARTCR_PC0		BIT(3)
+
+#define LINFLEXD_UARTCR_PCE		BIT(2)
+#define LINFLEXD_UARTCR_WL0		BIT(1)
+#define LINFLEXD_UARTCR_UART		BIT(0)
+
+#define LINFLEXD_UARTSR_SZF		BIT(15)
+#define LINFLEXD_UARTSR_OCF		BIT(14)
+#define LINFLEXD_UARTSR_PE3		BIT(13)
+#define LINFLEXD_UARTSR_PE2		BIT(12)
+#define LINFLEXD_UARTSR_PE1		BIT(11)
+#define LINFLEXD_UARTSR_PE0		BIT(10)
+#define LINFLEXD_UARTSR_RMB		BIT(9)
+#define LINFLEXD_UARTSR_FEF		BIT(8)
+#define LINFLEXD_UARTSR_BOF		BIT(7)
+#define LINFLEXD_UARTSR_RPS		BIT(6)
+#define LINFLEXD_UARTSR_WUF		BIT(5)
+#define LINFLEXD_UARTSR_4		BIT(4)
+
+#define LINFLEXD_UARTSR_TO		BIT(3)
+
+#define LINFLEXD_UARTSR_DRFRFE		BIT(2)
+#define LINFLEXD_UARTSR_DTFTFF		BIT(1)
+#define LINFLEXD_UARTSR_NF		BIT(0)
+#define LINFLEXD_UARTSR_PE		(LINFLEXD_UARTSR_PE0 |\
+					 LINFLEXD_UARTSR_PE1 |\
+					 LINFLEXD_UARTSR_PE2 |\
+					 LINFLEXD_UARTSR_PE3)
+
+#define LINFLEX_LDIV_MULTIPLIER		(16)
+
+#define DRIVER_NAME	"fsl-linflexuart"
+#define DEV_NAME	"ttyLF"
+#define UART_NR		4
+
+#define EARLYCON_BUFFER_INITIAL_CAP	8
+
+#define PREINIT_DELAY			2000 /* us */
+
+static const struct of_device_id linflex_dt_ids[] = {
+	{
+		.compatible = "fsl,s32-linflexuart",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, linflex_dt_ids);
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+static struct uart_port *earlycon_port;
+static bool linflex_earlycon_same_instance;
+static spinlock_t init_lock;
+static bool during_init;
+
+static struct {
+	char *content;
+	unsigned int len, cap;
+} earlycon_buf;
+#endif
+
+static void linflex_stop_tx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	ier = readl(port->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DTIE);
+	writel(ier, port->membase + LINIER);
+}
+
+static void linflex_stop_rx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	ier = readl(port->membase + LINIER);
+	writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+}
+
+static inline void linflex_transmit_buffer(struct uart_port *sport)
+{
+	struct circ_buf *xmit = &sport->state->xmit;
+	unsigned char c;
+	unsigned long status;
+
+	while (!uart_circ_empty(xmit)) {
+		c = xmit->buf[xmit->tail];
+		writeb(c, sport->membase + BDRL);
+
+		/* Waiting for data transmission completed. */
+		while (((status = readl(sport->membase + UARTSR)) &
+					LINFLEXD_UARTSR_DTFTFF) !=
+					LINFLEXD_UARTSR_DTFTFF)
+			;
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		sport->icount.tx++;
+
+		writel(status | LINFLEXD_UARTSR_DTFTFF,
+		       sport->membase + UARTSR);
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(sport);
+
+	if (uart_circ_empty(xmit))
+		linflex_stop_tx(sport);
+}
+
+static void linflex_start_tx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	linflex_transmit_buffer(port);
+	ier = readl(port->membase + LINIER);
+	writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+}
+
+static irqreturn_t linflex_txint(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	struct circ_buf *xmit = &sport->state->xmit;
+	unsigned long flags;
+	unsigned long status;
+
+	spin_lock_irqsave(&sport->lock, flags);
+
+	if (sport->x_char) {
+		writeb(sport->x_char, sport->membase + BDRL);
+
+		/* waiting for data transmission completed */
+		while (((status = readl(sport->membase + UARTSR)) &
+			LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF)
+			;
+
+		writel(status | LINFLEXD_UARTSR_DTFTFF,
+		       sport->membase + UARTSR);
+
+		goto out;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) {
+		linflex_stop_tx(sport);
+		goto out;
+	}
+
+	linflex_transmit_buffer(sport);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(sport);
+
+out:
+	spin_unlock_irqrestore(&sport->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t linflex_rxint(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	unsigned int flg;
+	struct tty_port *port = &sport->state->port;
+	unsigned long flags, status;
+	unsigned char rx;
+
+	spin_lock_irqsave(&sport->lock, flags);
+
+	status = readl(sport->membase + UARTSR);
+	while (status & LINFLEXD_UARTSR_RMB) {
+		rx = readb(sport->membase + BDRM);
+		flg = TTY_NORMAL;
+		sport->icount.rx++;
+
+		if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF |
+			      LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) {
+			if (status & LINFLEXD_UARTSR_SZF)
+				status |= LINFLEXD_UARTSR_SZF;
+			if (status & LINFLEXD_UARTSR_BOF)
+				status |= LINFLEXD_UARTSR_BOF;
+			if (status & LINFLEXD_UARTSR_FEF)
+				status |= LINFLEXD_UARTSR_FEF;
+			if (status & LINFLEXD_UARTSR_PE)
+				status |=  LINFLEXD_UARTSR_PE;
+		}
+
+		writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE,
+		       sport->membase + UARTSR);
+		status = readl(sport->membase + UARTSR);
+
+		if (uart_handle_sysrq_char(sport, (unsigned char)rx))
+			continue;
+
+#ifdef SUPPORT_SYSRQ
+			sport->sysrq = 0;
+#endif
+		tty_insert_flip_char(port, rx, flg);
+	}
+
+	spin_unlock_irqrestore(&sport->lock, flags);
+
+	tty_flip_buffer_push(port);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t linflex_int(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	unsigned long status;
+
+	status = readl(sport->membase + UARTSR);
+
+	if (status & LINFLEXD_UARTSR_DRFRFE)
+		linflex_rxint(irq, dev_id);
+	if (status & LINFLEXD_UARTSR_DTFTFF)
+		linflex_txint(irq, dev_id);
+
+	return IRQ_HANDLED;
+}
+
+/* return TIOCSER_TEMT when transmitter is not busy */
+static unsigned int linflex_tx_empty(struct uart_port *port)
+{
+	unsigned long status;
+
+	status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF;
+
+	return status ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int linflex_get_mctrl(struct uart_port *port)
+{
+	return 0;
+}
+
+static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void linflex_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void linflex_setup_watermark(struct uart_port *sport)
+{
+	unsigned long cr, ier, cr1;
+
+	/* Disable transmission/reception */
+	ier = readl(sport->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
+	writel(ier, sport->membase + LINIER);
+
+	cr = readl(sport->membase + UARTCR);
+	cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
+	writel(cr, sport->membase + UARTCR);
+
+	/* Enter initialization mode by setting INIT bit */
+
+	/* set the Linflex in master mode and activate by-pass filter */
+	cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME
+	      | LINFLEXD_LINCR1_INIT;
+	writel(cr1, sport->membase + LINCR1);
+
+	/* wait for init mode entry */
+	while ((readl(sport->membase + LINSR)
+		& LINFLEXD_LINSR_LINS_MASK)
+		!= LINFLEXD_LINSR_LINS_INITMODE)
+		;
+
+	/*
+	 *	UART = 0x1;		- Linflex working in UART mode
+	 *	TXEN = 0x1;		- Enable transmission of data now
+	 *	RXEn = 0x1;		- Receiver enabled
+	 *	WL0 = 0x1;		- 8 bit data
+	 *	PCE = 0x0;		- No parity
+	 */
+
+	/* set UART bit to allow writing other bits */
+	writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR);
+
+	cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN |
+	      LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
+
+	writel(cr, sport->membase + UARTCR);
+
+	cr1 &= ~(LINFLEXD_LINCR1_INIT);
+
+	writel(cr1, sport->membase + LINCR1);
+
+	ier = readl(sport->membase + LINIER);
+	ier |= LINFLEXD_LINIER_DRIE;
+	ier |= LINFLEXD_LINIER_DTIE;
+
+	writel(ier, sport->membase + LINIER);
+}
+
+static int linflex_startup(struct uart_port *port)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	linflex_setup_watermark(port);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
+			       DRIVER_NAME, port);
+
+	return ret;
+}
+
+static void linflex_shutdown(struct uart_port *port)
+{
+	unsigned long ier;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* disable interrupts */
+	ier = readl(port->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
+	writel(ier, port->membase + LINIER);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	devm_free_irq(port->dev, port->irq, port);
+}
+
+static void
+linflex_set_termios(struct uart_port *port, struct ktermios *termios,
+		    struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned long cr, old_cr, cr1;
+	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+	cr = readl(port->membase + UARTCR);
+	old_cr = cr;
+
+	/* Enter initialization mode by setting INIT bit */
+	cr1 = readl(port->membase + LINCR1);
+	cr1 |= LINFLEXD_LINCR1_INIT;
+	writel(cr1, port->membase + LINCR1);
+
+	/* wait for init mode entry */
+	while ((readl(port->membase + LINSR)
+		& LINFLEXD_LINSR_LINS_MASK)
+		!= LINFLEXD_LINSR_LINS_INITMODE)
+		;
+
+	/*
+	 * only support CS8 and CS7, and for CS7 must enable PE.
+	 * supported mode:
+	 *	- (7,e/o,1)
+	 *	- (8,n,1)
+	 *	- (8,e/o,1)
+	 */
+	/* enter the UART into configuration mode */
+
+	while ((termios->c_cflag & CSIZE) != CS8 &&
+	       (termios->c_cflag & CSIZE) != CS7) {
+		termios->c_cflag &= ~CSIZE;
+		termios->c_cflag |= old_csize;
+		old_csize = CS8;
+	}
+
+	if ((termios->c_cflag & CSIZE) == CS7) {
+		/* Word length: WL1WL0:00 */
+		cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0;
+	}
+
+	if ((termios->c_cflag & CSIZE) == CS8) {
+		/* Word length: WL1WL0:01 */
+		cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1;
+	}
+
+	if (termios->c_cflag & CMSPAR) {
+		if ((termios->c_cflag & CSIZE) != CS8) {
+			termios->c_cflag &= ~CSIZE;
+			termios->c_cflag |= CS8;
+		}
+		/* has a space/sticky bit */
+		cr |= LINFLEXD_UARTCR_WL0;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		termios->c_cflag &= ~CSTOPB;
+
+	/* parity must be enabled when CS7 to match 8-bits format */
+	if ((termios->c_cflag & CSIZE) == CS7)
+		termios->c_cflag |= PARENB;
+
+	if ((termios->c_cflag & PARENB)) {
+		cr |= LINFLEXD_UARTCR_PCE;
+		if (termios->c_cflag & PARODD)
+			cr = (cr | LINFLEXD_UARTCR_PC0) &
+			     (~LINFLEXD_UARTCR_PC1);
+		else
+			cr = cr & (~LINFLEXD_UARTCR_PC1 &
+				   ~LINFLEXD_UARTCR_PC0);
+	} else {
+		cr &= ~LINFLEXD_UARTCR_PCE;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->read_status_mask = 0;
+
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |=	(LINFLEXD_UARTSR_FEF |
+						 LINFLEXD_UARTSR_PE0 |
+						 LINFLEXD_UARTSR_PE1 |
+						 LINFLEXD_UARTSR_PE2 |
+						 LINFLEXD_UARTSR_PE3);
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= LINFLEXD_UARTSR_FEF;
+
+	/* characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
+		/*
+		 * if we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= LINFLEXD_UARTSR_BOF;
+	}
+
+	writel(cr, port->membase + UARTCR);
+
+	cr1 &= ~(LINFLEXD_LINCR1_INIT);
+
+	writel(cr1, port->membase + LINCR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *linflex_type(struct uart_port *port)
+{
+	return "FSL_LINFLEX";
+}
+
+static void linflex_release_port(struct uart_port *port)
+{
+	/* nothing to do */
+}
+
+static int linflex_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* configure/auto-configure the port */
+static void linflex_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_LINFLEXUART;
+}
+
+static const struct uart_ops linflex_pops = {
+	.tx_empty	= linflex_tx_empty,
+	.set_mctrl	= linflex_set_mctrl,
+	.get_mctrl	= linflex_get_mctrl,
+	.stop_tx	= linflex_stop_tx,
+	.start_tx	= linflex_start_tx,
+	.stop_rx	= linflex_stop_rx,
+	.break_ctl	= linflex_break_ctl,
+	.startup	= linflex_startup,
+	.shutdown	= linflex_shutdown,
+	.set_termios	= linflex_set_termios,
+	.type		= linflex_type,
+	.request_port	= linflex_request_port,
+	.release_port	= linflex_release_port,
+	.config_port	= linflex_config_port,
+};
+
+static struct uart_port *linflex_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+static void linflex_console_putchar(struct uart_port *port, int ch)
+{
+	unsigned long cr;
+
+	cr = readl(port->membase + UARTCR);
+
+	writeb(ch, port->membase + BDRL);
+
+	if (!(cr & LINFLEXD_UARTCR_TFBM))
+		while ((readl(port->membase + UARTSR) &
+					LINFLEXD_UARTSR_DTFTFF)
+				!= LINFLEXD_UARTSR_DTFTFF)
+			;
+	else
+		while (readl(port->membase + UARTSR) &
+					LINFLEXD_UARTSR_DTFTFF)
+			;
+
+	if (!(cr & LINFLEXD_UARTCR_TFBM)) {
+		writel((readl(port->membase + UARTSR) |
+					LINFLEXD_UARTSR_DTFTFF),
+					port->membase + UARTSR);
+	}
+}
+
+static void linflex_earlycon_putchar(struct uart_port *port, int ch)
+{
+	unsigned long flags;
+	char *ret;
+
+	if (!linflex_earlycon_same_instance) {
+		linflex_console_putchar(port, ch);
+		return;
+	}
+
+	spin_lock_irqsave(&init_lock, flags);
+	if (!during_init)
+		goto outside_init;
+
+	if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT)
+		goto init_release;
+
+	if (!earlycon_buf.cap) {
+		earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP,
+					       GFP_ATOMIC);
+		earlycon_buf.cap = earlycon_buf.content ?
+				   EARLYCON_BUFFER_INITIAL_CAP : 0;
+	} else if (earlycon_buf.len == earlycon_buf.cap) {
+		ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1,
+			       GFP_ATOMIC);
+		if (ret) {
+			earlycon_buf.content = ret;
+			earlycon_buf.cap <<= 1;
+		}
+	}
+
+	if (earlycon_buf.len < earlycon_buf.cap)
+		earlycon_buf.content[earlycon_buf.len++] = ch;
+
+	goto init_release;
+
+outside_init:
+	linflex_console_putchar(port, ch);
+init_release:
+	spin_unlock_irqrestore(&init_lock, flags);
+}
+
+static void linflex_string_write(struct uart_port *sport, const char *s,
+				 unsigned int count)
+{
+	unsigned long cr, ier = 0;
+
+	ier = readl(sport->membase + LINIER);
+	linflex_stop_tx(sport);
+
+	cr = readl(sport->membase + UARTCR);
+	cr |= (LINFLEXD_UARTCR_TXEN);
+	writel(cr, sport->membase + UARTCR);
+
+	uart_console_write(sport, s, count, linflex_console_putchar);
+
+	writel(ier, sport->membase + LINIER);
+}
+
+static void
+linflex_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *sport = linflex_ports[co->index];
+	unsigned long flags;
+	int locked = 1;
+
+	if (sport->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock_irqsave(&sport->lock, flags);
+	else
+		spin_lock_irqsave(&sport->lock, flags);
+
+	linflex_string_write(sport, s, count);
+
+	if (locked)
+		spin_unlock_irqrestore(&sport->lock, flags);
+}
+
+/*
+ * if the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+linflex_console_get_options(struct uart_port *sport, int *parity, int *bits)
+{
+	unsigned long cr;
+
+	cr = readl(sport->membase + UARTCR);
+	cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN;
+
+	if (!cr)
+		return;
+
+	/* ok, the port was enabled */
+
+	*parity = 'n';
+	if (cr & LINFLEXD_UARTCR_PCE) {
+		if (cr & LINFLEXD_UARTCR_PC0)
+			*parity = 'o';
+		else
+			*parity = 'e';
+	}
+
+	if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) {
+		if (cr & LINFLEXD_UARTCR_PCE)
+			*bits = 9;
+		else
+			*bits = 8;
+	}
+}
+
+static int __init linflex_console_setup(struct console *co, char *options)
+{
+	struct uart_port *sport;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+	int i;
+	unsigned long flags;
+	/*
+	 * check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports))
+		co->index = 0;
+
+	sport = linflex_ports[co->index];
+	if (!sport)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		linflex_console_get_options(sport, &parity, &bits);
+
+	if (earlycon_port && sport->mapbase == earlycon_port->mapbase) {
+		linflex_earlycon_same_instance = true;
+
+		spin_lock_irqsave(&init_lock, flags);
+		during_init = true;
+		spin_unlock_irqrestore(&init_lock, flags);
+
+		/* Workaround for character loss or output of many invalid
+		 * characters, when INIT mode is entered shortly after a
+		 * character has just been printed.
+		 */
+		udelay(PREINIT_DELAY);
+	}
+
+	linflex_setup_watermark(sport);
+
+	ret = uart_set_options(sport, co, baud, parity, bits, flow);
+
+	if (!linflex_earlycon_same_instance)
+		goto done;
+
+	spin_lock_irqsave(&init_lock, flags);
+
+	/* Emptying buffer */
+	if (earlycon_buf.len) {
+		for (i = 0; i < earlycon_buf.len; i++)
+			linflex_console_putchar(earlycon_port,
+				earlycon_buf.content[i]);
+
+		kfree(earlycon_buf.content);
+		earlycon_buf.len = 0;
+	}
+
+	during_init = false;
+	spin_unlock_irqrestore(&init_lock, flags);
+
+done:
+	return ret;
+}
+
+static struct uart_driver linflex_reg;
+static struct console linflex_console = {
+	.name		= DEV_NAME,
+	.write		= linflex_console_write,
+	.device		= uart_console_device,
+	.setup		= linflex_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &linflex_reg,
+};
+
+static void linflex_earlycon_write(struct console *con, const char *s,
+				   unsigned int n)
+{
+	struct earlycon_device *dev = con->data;
+
+	uart_console_write(&dev->port, s, n, linflex_earlycon_putchar);
+}
+
+static int __init linflex_early_console_setup(struct earlycon_device *device,
+					      const char *options)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = linflex_earlycon_write;
+	earlycon_port = &device->port;
+
+	return 0;
+}
+
+OF_EARLYCON_DECLARE(linflex, "fsl,s32-linflexuart",
+		    linflex_early_console_setup);
+
+#define LINFLEX_CONSOLE	(&linflex_console)
+#else
+#define LINFLEX_CONSOLE	NULL
+#endif
+
+static struct uart_driver linflex_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= DEV_NAME,
+	.nr		= ARRAY_SIZE(linflex_ports),
+	.cons		= LINFLEX_CONSOLE,
+};
+
+static int linflex_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct uart_port *sport;
+	struct resource *res;
+	int ret;
+
+	sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
+	if (!sport)
+		return -ENOMEM;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	if (ret >= UART_NR) {
+		dev_err(&pdev->dev, "driver limited to %d serial ports\n",
+			UART_NR);
+		return -ENOMEM;
+	}
+
+	sport->line = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	sport->mapbase = res->start;
+	sport->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sport->membase))
+		return PTR_ERR(sport->membase);
+
+	sport->dev = &pdev->dev;
+	sport->type = PORT_LINFLEXUART;
+	sport->iotype = UPIO_MEM;
+	sport->irq = platform_get_irq(pdev, 0);
+	sport->ops = &linflex_pops;
+	sport->flags = UPF_BOOT_AUTOCONF;
+
+	linflex_ports[sport->line] = sport;
+
+	platform_set_drvdata(pdev, sport);
+
+	ret = uart_add_one_port(&linflex_reg, sport);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int linflex_remove(struct platform_device *pdev)
+{
+	struct uart_port *sport = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&linflex_reg, sport);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int linflex_suspend(struct device *dev)
+{
+	struct uart_port *sport = dev_get_drvdata(dev);
+
+	uart_suspend_port(&linflex_reg, sport);
+
+	return 0;
+}
+
+static int linflex_resume(struct device *dev)
+{
+	struct uart_port *sport = dev_get_drvdata(dev);
+
+	uart_resume_port(&linflex_reg, sport);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume);
+
+static struct platform_driver linflex_driver = {
+	.probe		= linflex_probe,
+	.remove		= linflex_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= linflex_dt_ids,
+		.pm	= &linflex_pm_ops,
+	},
+};
+
+static int __init linflex_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&linflex_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&linflex_driver);
+	if (ret)
+		uart_unregister_driver(&linflex_reg);
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+	spin_lock_init(&init_lock);
+#endif
+
+	return ret;
+}
+
+static void __exit linflex_serial_exit(void)
+{
+	platform_driver_unregister(&linflex_driver);
+	uart_unregister_driver(&linflex_reg);
+}
+
+module_init(linflex_serial_init);
+module_exit(linflex_serial_exit);
+
+MODULE_DESCRIPTION("Freescale linflex serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 5642c05e0da0..25a3dead4473 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -293,4 +293,7 @@
 /* SiFive UART */
 #define PORT_SIFIVE_V0	120
 
+/* Freescale Linflex UART */
+#define PORT_LINFLEXUART	121
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 4/6] dt-bindings: serial: Document Freescale LINFlex UART
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

From: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>

Add documentation for the serial communication interface module (LINFlex),
found in two instances on S32V234.

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 .../bindings/serial/fsl,s32-linflexuart.txt   | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt

diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
new file mode 100644
index 000000000000..957ffeaca9f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
@@ -0,0 +1,24 @@
+* Freescale Linflex UART
+
+The LINFlexD controller implements several LIN protocol versions, as well as
+support for full-duplex UART communication through 8-bit and 9-bit frames. The
+Linflex UART driver enables operation only in UART mode.
+
+See chapter 47 ("LINFlexD") in the reference manual[1].
+
+Required properties:
+- compatible :
+  - "fsl,s32-linflexuart" for linflex configured in uart mode which
+  is compatible with the one integrated on S32V234 SoC
+- reg : Address and length of the register set for the device
+- interrupts : Should contain uart interrupt
+
+Example:
+uart0:serial@40053000 {
+	compatible = "fsl,s32-linflexuart";
+	reg = <0x0 0x40053000 0x0 0x1000>;
+	interrupts = <0 59 4>;
+	status = "disabled";
+};
+
+[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 3/6] arm64: dts: fsl: Add device tree for S32V234-EVB
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Dan Nica, Larisa Ileana Grigore
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

From: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>

Add initial version of device tree for S32V234-EVB, including nodes for the
4 Cortex-A53 cores, AIPS bus with UART modules, ARM architected timer and
Generic Interrupt Controller (GIC).

Keep SoC level separate from board level to let future boards with this SoC
share common properties, while the dts files will keep board-dependent
properties.

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Dan Nica <dan.nica@nxp.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |   2 +
 .../boot/dts/freescale/fsl-s32v234-evb.dts    |  24 ++++
 .../arm64/boot/dts/freescale/fsl-s32v234.dtsi | 130 ++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index c043aca66572..3af29b58a833 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -26,3 +26,5 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
+
+dtb-$(CONFIG_ARCH_S32) += fsl-s32v234-evb.dtb
diff --git a/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts b/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
new file mode 100644
index 000000000000..92bf6c5563a3
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ */
+
+/dts-v1/;
+#include "fsl-s32v234.dtsi"
+
+/ {
+	compatible = "fsl,s32v234-evb", "fsl,s32v234";
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi b/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
new file mode 100644
index 000000000000..6d686d3ba997
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+	model = "Freescale S32V234";
+	compatible = "fsl,s32v234";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x0>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster0_l2_cache>;
+		};
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x1>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster0_l2_cache>;
+		};
+		cpu2: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x100>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster1_l2_cache>;
+		};
+		cpu3: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x101>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster1_l2_cache>;
+		};
+
+		cluster0_l2_cache: l2-cache0 {
+			compatible = "cache";
+		};
+
+		cluster1_l2_cache: l2-cache1 {
+			compatible = "cache";
+		};
+	};
+
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		aips0: aips-bus@40000000 {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			interrupt-parent = <&gic>;
+			reg = <0x0 0x40000000 0x0 0x7D000>;
+			ranges;
+
+			uart0: serial@40053000 {
+				compatible = "fsl,s32-linflexuart";
+				reg = <0x0 0x40053000 0x0 0x1000>;
+				interrupts = <0 59 1>;
+				status = "disabled";
+			};
+		};
+
+		aips1: aips-bus@40080000 {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			interrupt-parent = <&gic>;
+			reg = <0x0 0x40080000 0x0 0x70000>;
+			ranges;
+
+			uart1: serial@400bc000 {
+				compatible = "fsl,s32-linflexuart";
+				reg = <0x0 0x400bc000 0x0 0x1000>;
+				interrupts = <0 60 1>;
+				status = "disabled";
+			};
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xf08>,
+			     <1 14 0xf08>,
+			     <1 11 0xf08>,
+			     <1 10 0xf08>;
+		/* clock-frequency might be modified by u-boot, depending on the
+		 * chip version.
+		 */
+		clock-frequency = <10000000>;
+	};
+
+	gic: interrupt-controller@7d001000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0 0x7d001000 0 0x1000>,
+		      <0 0x7d002000 0 0x2000>,
+		      <0 0x7d004000 0 0x2000>,
+		      <0 0x7d006000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+};
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 2/6] arm64: Introduce config for S32
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

From: Mihaela Martinas <Mihaela.Martinas@freescale.com>

Add configuration option for the Freescale S32 platform family in
Kconfig.platforms. For starters, the only SoC supported will be Treerunner
(S32V234), with a single execution target: the S32V234-EVB (rev 29288)
board.

Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/Kconfig.platforms | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 4778c775de1b..a9a6152d37eb 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -210,6 +210,11 @@ config ARCH_ROCKCHIP
 	  This enables support for the ARMv8 based Rockchip chipsets,
 	  like the RK3368.
 
+config ARCH_S32
+	bool "Freescale S32 SoC Family"
+	help
+	  This enables support for the Freescale S32 family of processors.
+
 config ARCH_SEATTLE
 	bool "AMD Seattle SoC Family"
 	help
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 1/6] dt-bindings: arm: fsl: Add the S32V234-EVB board
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Eddy Petrisor
In-Reply-To: <20190809112853.15846-1-stefan-gabriel.mirea@nxp.com>

From: Eddy Petrișor <eddy.petrisor@nxp.com>

Add entry for the NXP S32V234 Customer Evaluation Board to the board/SoC
bindings.

Signed-off-by: Eddy Petrișor <eddy.petrisor@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 7294ac36f4c0..597c563bdec9 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -309,4 +309,10 @@ properties:
               - fsl,ls2088a-rdb
           - const: fsl,ls2088a
 
+      - description: S32V234 based Boards
+        items:
+          - enum:
+              - fsl,s32v234-evb           # S32V234-EVB2 Customer Evaluation Board
+          - const: fsl,s32v234
+
 ...
-- 
2.22.0


^ permalink raw reply related

* [PATCH v2 0/6] Add initial support for S32V234-EVB
From: Stefan-gabriel Mirea @ 2019-08-09 11:29 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

Hello,

NXP's S32V234[1] ("Treerunner") vision microprocessors are targeted for
high-performance, computationally intensive vision and sensor fusion
applications that require automotive safety levels. They include leading
edge Camera Vision modules like APEX-2, ISP and GPU. The S32V234-EVB and
S32V234-SBC boards are available for customer evaluation.

The following patch series introduces minimal enablement support for the
NXP S32V234-EVB2[2] board, which leverages most of the SoC capabilities.
The series includes a driver for operating the on-chip LINFlexD controller
in UART mode.

In the future, we aim to submit multiple drivers upstream, which can be
found in the kernel of our Auto Linux BSP[3] ("ALB"), starting with basic
pinmuxing, clock and uSDHC drivers.

For validation, you can use the U-Boot bootloader in the ALB[4], which we
build and test with our patched version of the Linaro GCC 6.3.1 2017.05
toolchain for ARM 64-bit, with sources available on [5].

Changes in v2:
* Update the entry in fsl.yaml to apply to all S32V234 based boards;
* Add chosen node to dts, with a 'stdout-path' property for earlycon;
* Remove linflex_verify_port(), because it was only called from
  uart_set_info(), which was going to always fail at the "baud_base < 9600"
  check, as we are not using uartclk from uart_port yet;
* Fix compatible string used in OF_EARLYCON_DECLARE.

[1] https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/s32-automotive-platform/vision-processor-for-front-and-surround-view-camera-machine-learning-and-sensor-fusion:S32V234
[2] https://www.nxp.com/support/developer-resources/evaluation-and-development-boards/ultra-reliable-dev-platforms/s32v-mpus-platforms/s32v-vision-and-sensor-fusion-evaluation-system:S32V234EVB
[3] https://source.codeaurora.org/external/autobsps32/linux/
[4] https://source.codeaurora.org/external/autobsps32/u-boot/
[5] https://source.codeaurora.org/external/s32ds/compiler/gcc/

Eddy Petrișor (1):
  dt-bindings: arm: fsl: Add the S32V234-EVB board

Mihaela Martinas (2):
  arm64: Introduce config for S32
  arm64: defconfig: Enable configs for S32V234

Stefan-Gabriel Mirea (1):
  tty: serial: Add linflexuart driver for S32V234

Stoica Cosmin-Stefan (2):
  arm64: dts: fsl: Add device tree for S32V234-EVB
  dt-bindings: serial: Document Freescale LINFlex UART

 .../admin-guide/kernel-parameters.txt         |   6 +
 .../devicetree/bindings/arm/fsl.yaml          |   6 +
 .../bindings/serial/fsl,s32-linflexuart.txt   |  24 +
 arch/arm64/Kconfig.platforms                  |   5 +
 arch/arm64/boot/dts/freescale/Makefile        |   2 +
 .../boot/dts/freescale/fsl-s32v234-evb.dts    |  24 +
 .../arm64/boot/dts/freescale/fsl-s32v234.dtsi | 130 +++
 arch/arm64/configs/defconfig                  |   3 +
 drivers/tty/serial/Kconfig                    |  15 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/fsl_linflexuart.c          | 942 ++++++++++++++++++
 include/uapi/linux/serial_core.h              |   3 +
 12 files changed, 1161 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
 create mode 100644 drivers/tty/serial/fsl_linflexuart.c

-- 
2.22.0


^ permalink raw reply

* Re: [PATCH 06/19] irqchip/mmp: add missing chained_irq_{enter,exit}()
From: Marc Zyngier @ 2019-08-09 10:56 UTC (permalink / raw)
  To: Lubomir Rintel, Olof Johansson
  Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
	Kishon Vijay Abraham I, Russell King, Michael Turquette,
	Stephen Boyd, devicetree, linux-kernel, linux-arm-kernel,
	linux-clk
In-Reply-To: <20190809093158.7969-7-lkundrak@v3.sk>

On 09/08/2019 10:31, Lubomir Rintel wrote:
> The lack of chained_irq_exit() leaves the muxed interrupt masked on MMP3.
> For reasons unknown this is not a problem on MMP2.
> 
> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> ---
>  drivers/irqchip/irq-mmp.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
> index af9cba4a51c2e..cd8d2253f56d1 100644
> --- a/drivers/irqchip/irq-mmp.c
> +++ b/drivers/irqchip/irq-mmp.c
> @@ -13,6 +13,7 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/irqchip.h>
> +#include <linux/irqchip/chained_irq.h>
>  #include <linux/irqdomain.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> @@ -132,11 +133,14 @@ struct irq_chip icu_irq_chip = {
>  static void icu_mux_irq_demux(struct irq_desc *desc)
>  {
>  	unsigned int irq = irq_desc_get_irq(desc);
> +	struct irq_chip *chip = irq_get_chip(irq);

Consider using irq_desc_get_chip() instead, which avoids going through
the irq->desc again.

>  	struct irq_domain *domain;
>  	struct icu_chip_data *data;
>  	int i;
>  	unsigned long mask, status, n;
>  
> +	chained_irq_enter(chip, desc);
> +
>  	for (i = 1; i < max_icu_nr; i++) {
>  		if (irq == icu_data[i].cascade_irq) {
>  			domain = icu_data[i].domain;
> @@ -146,7 +150,7 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
>  	}
>  	if (i >= max_icu_nr) {
>  		pr_err("Spurious irq %d in MMP INTC\n", irq);
> -		return;
> +		goto out;
>  	}
>  
>  	mask = readl_relaxed(data->reg_mask);
> @@ -158,6 +162,9 @@ static void icu_mux_irq_demux(struct irq_desc *desc)
>  			generic_handle_irq(icu_data[i].virq_base + n);
>  		}
>  	}
> +
> +out:
> +	chained_irq_exit(chip, desc);
>  }
>  
>  static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
> 

Otherwise looks OK.

	M.
-- 
Jazz is not dead, it just smells funny...

^ permalink raw reply

* Re: [PATCH 1/6] dt-bindings: gpio: davinci: Add new compatible for J721E SoCs
From: Keerthy @ 2019-08-09 10:55 UTC (permalink / raw)
  To: Lokesh Vutla, Tero Kristo, Nishanth Menon, linus.walleij
  Cc: linux-gpio, Rob Herring, Linux ARM Mailing List,
	Device Tree Mailing List
In-Reply-To: <20190809082947.30590-2-lokeshvutla@ti.com>



On 09/08/19 1:59 PM, Lokesh Vutla wrote:
> J721e SoCs have same gpio IP as K2G davinci gpio. Add a new compatible to
> handle J721E SoCs.

Reviewed-by: Keerthy <j-keerthy@ti.com>

> 
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> ---
>   Documentation/devicetree/bindings/gpio/gpio-davinci.txt | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
> index bc6b4b62df83..cd91d61eac31 100644
> --- a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
> +++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt
> @@ -6,6 +6,7 @@ Required Properties:
>   						66AK2E SoCs
>   			"ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
>   			"ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654
> +			"ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs
>   
>   - reg: Physical base address of the controller and the size of memory mapped
>          registers.
> 

^ permalink raw reply

* [PATCH 2/2] ASoC: fsl_esai: Add new compatible string for imx6ull
From: Shengjiu Wang @ 2019-08-09 10:27 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	robh+dt, mark.rutland
  Cc: linuxppc-dev, linux-kernel, devicetree
In-Reply-To: <1565346467-5769-1-git-send-email-shengjiu.wang@nxp.com>

Add new compatible string "fsl,imx6ull-esai" in the binding document.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 Documentation/devicetree/bindings/sound/fsl,esai.txt | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index 5b9914367610..0e6e2166f76c 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -7,8 +7,11 @@ other DSPs. It has up to six transmitters and four receivers.
 
 Required properties:
 
-  - compatible		: Compatible list, must contain "fsl,imx35-esai" or
-			  "fsl,vf610-esai"
+  - compatible		: Compatible list, should contain one of the following
+			  compatibles:
+			  "fsl,imx35-esai",
+			  "fsl,vf610-esai",
+			  "fsl,imx6ull-esai",
 
   - reg			: Offset and length of the register set for the device.
 
-- 
2.21.0

^ permalink raw reply related

* [PATCH 1/2] ASoC: fsl_esai: Add compatible string for imx6ull
From: Shengjiu Wang @ 2019-08-09 10:27 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	robh+dt, mark.rutland
  Cc: linuxppc-dev, linux-kernel, devicetree

Add compatible string for imx6ull, from imx6ull platform,
the issue of channel swap after xrun is fixed in hardware.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/fsl_esai.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 10d2210c91ef..4b4a8e831e9e 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -920,6 +920,7 @@ static int fsl_esai_remove(struct platform_device *pdev)
 static const struct of_device_id fsl_esai_dt_ids[] = {
 	{ .compatible = "fsl,imx35-esai", },
 	{ .compatible = "fsl,vf610-esai", },
+	{ .compatible = "fsl,imx6ull-esai", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
-- 
2.21.0

^ permalink raw reply related

* Re: [PATCH 2/2] pwm: sprd: Add Spreadtrum PWM support
From: Baolin Wang @ 2019-08-09 10:06 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Thierry Reding, Rob Herring, Mark Rutland, Orson Zhai,
	Chunyan Zhang, Vincent Guittot, linux-pwm, DTML, LKML, kernel
In-Reply-To: <20190809091013.vguj4wty7qiab64t@pengutronix.de>

 Hi Uwe,

On Fri, 9 Aug 2019 at 17:10, Uwe Kleine-König
<u.kleine-koenig@pengutronix.de> wrote:
>
> On Thu, Aug 08, 2019 at 04:59:39PM +0800, Baolin Wang wrote:
> > From: Neo Hou <neo.hou@unisoc.com>
> >
> > This patch adds the Spreadtrum PWM support, which provides maximum 4
> > channels.
> >
> > Signed-off-by: Neo Hou <neo.hou@unisoc.com>
> > Co-developed-by: Baolin Wang <baolin.wang@linaro.org>
> > Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
> > ---
> >  drivers/pwm/Kconfig    |   10 ++
> >  drivers/pwm/Makefile   |    1 +
> >  drivers/pwm/pwm-sprd.c |  311 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 322 insertions(+)
> >  create mode 100644 drivers/pwm/pwm-sprd.c
> >
> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> > index a7e5751..4963b4d 100644
> > --- a/drivers/pwm/Kconfig
> > +++ b/drivers/pwm/Kconfig
> > @@ -423,6 +423,16 @@ config PWM_SPEAR
> >         To compile this driver as a module, choose M here: the module
> >         will be called pwm-spear.
> >
> > +config PWM_SPRD
> > +     tristate "Spreadtrum PWM support"
> > +     depends on ARCH_SPRD || COMPILE_TEST
>
> I think you need
>
>         depends on HAS_IOMEM

OK.

>
> > +     help
> > +       Generic PWM framework driver for the PWM controller on
> > +       Spreadtrum SoCs.
> > +
> > +       To compile this driver as a module, choose M here: the module
> > +       will be called pwm-sprd.
> > +
> >  config PWM_STI
> >       tristate "STiH4xx PWM support"
> >       depends on ARCH_STI
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 76b555b..26326ad 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)  += pwm-rockchip.o
> >  obj-$(CONFIG_PWM_SAMSUNG)    += pwm-samsung.o
> >  obj-$(CONFIG_PWM_SIFIVE)     += pwm-sifive.o
> >  obj-$(CONFIG_PWM_SPEAR)              += pwm-spear.o
> > +obj-$(CONFIG_PWM_SPRD)               += pwm-sprd.o
> >  obj-$(CONFIG_PWM_STI)                += pwm-sti.o
> >  obj-$(CONFIG_PWM_STM32)              += pwm-stm32.o
> >  obj-$(CONFIG_PWM_STM32_LP)   += pwm-stm32-lp.o
> > diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
> > new file mode 100644
> > index 0000000..f6fc793
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-sprd.c
> > @@ -0,0 +1,311 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2019 Spreadtrum Communications Inc.
>
> If there is a publicly available reference manual available, please add
> a link to it here.

Sure.

>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/math64.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pwm.h>
> > +
> > +#define SPRD_PWM_PRESCALE    0x0
> > +#define SPRD_PWM_MOD         0x4
> > +#define SPRD_PWM_DUTY                0x8
> > +#define SPRD_PWM_DIV         0xc
> > +#define SPRD_PWM_PAT_LOW     0x10
> > +#define SPRD_PWM_PAT_HIGH    0x14
> > +#define SPRD_PWM_ENABLE              0x18
> > +
> > +#define SPRD_PWM_MOD_MAX     GENMASK(7, 0)
> > +#define SPRD_PWM_REG_MSK     GENMASK(15, 0)
> > +#define SPRD_PWM_ENABLE_BIT  BIT(0)
> > +
> > +#define SPRD_PWM_NUM         4
> > +#define SPRD_PWM_REGS_SHIFT  5
> > +#define SPRD_PWM_NUM_CLKS    2
> > +#define SPRD_PWM_DEFAULT_CLK 26000000UL
> > +
> > +struct sprd_pwm_chn {
> > +     struct clk_bulk_data clks[SPRD_PWM_NUM_CLKS];
> > +     unsigned long clk_rate;
> > +     bool clk_enabled;
> > +};
> > +
> > +struct sprd_pwm_chip {
> > +     void __iomem *base;
> > +     struct device *dev;
> > +     struct pwm_chip chip;
> > +     int num_pwms;
> > +     struct sprd_pwm_chn chn[SPRD_PWM_NUM];
> > +};
> > +
> > +/* list of clocks required by PWM channels */
> > +static const char * const sprd_pwm_clks[] = {
> > +     "enable0", "pwm0",
> > +     "enable1", "pwm1",
> > +     "enable2", "pwm2",
> > +     "enable3", "pwm3",
> > +};
> > +
> > +static u32 sprd_pwm_read(struct sprd_pwm_chip *chip, u32 num, u32 reg)
>
> num is the channel id here? Then maybe "hwid" or "chanid" would be a
> better name. Or pass struct pwm_chip only?

Yes, will change to 'hwid'.

>
> Please (if you keep sprd_pwm_chip) rename chip to spc which is the name
> used in other places for structures of this type. "chip" is for struct
> pwm_chip.

Yes, sure.

>
> > +{
> > +     u32 offset = reg + (num << SPRD_PWM_REGS_SHIFT);
> > +
> > +     return readl_relaxed(chip->base + offset);
> > +}
> > +
> > +static void sprd_pwm_write(struct sprd_pwm_chip *chip, u32 num,
> > +                        u32 reg, u32 val)
> > +{
> > +     u32 offset = reg + (num << SPRD_PWM_REGS_SHIFT);
> > +
> > +     writel_relaxed(val, chip->base + offset);
> > +}
> > +
> > +static int sprd_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > +                        int duty_ns, int period_ns)
>
> Please implement .apply() instead of .config(), .enable() and
> .disable().

OK.

>
> > +{
> > +     struct sprd_pwm_chip *spc =
> > +             container_of(chip, struct sprd_pwm_chip, chip);
> > +     struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
> > +     u64 div, tmp;
> > +     u32 prescale, duty;
> > +     int ret;
> > +
> > +     /*
> > +      * NOTE: the clocks to PWM channel has to be enabled first before
> > +      * writing to the registers.
> > +      */
> > +     if (!chn->clk_enabled) {
> > +             ret = clk_bulk_prepare_enable(SPRD_PWM_NUM_CLKS, chn->clks);
>
> Do you really need to enable all 8 clocks to configure a single channel?

We have 4 channels, and each channel use 2 clocks, so here only enable
2 clocks, see SPRD_PWM_NUM_CLKS.

>
> > +             if (ret) {
> > +                     dev_err(spc->dev, "failed to enable pwm%u clock\n",
> > +                             pwm->hwpwm);
> > +                     return ret;
> > +             }
> > +
> > +             chn->clk_enabled = true;
> > +     }
> > +
> > +     duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns;
>
> @Baolin: until we're there that there are framework requirements how to
> round, please document at least how you do it here. Also describing the
> underlying concepts would be good for the driver reader.
>
> Something like:
>
> /*
>  * The hardware provides a counter that is feed by the source clock.
>  * The period length is (PRESCALE + 1) * MOD counter steps.
>  * The duty cycle length is (PRESCALE + 1) * DUTY counter steps.
>  *
>  * To keep the maths simple we're always using MOD = MOD_MAX.
>  * The value for PRESCALE is selected such that the resulting period
>  * gets the maximal length not bigger than the requested one with the
>  * given settings (MOD = MOD_MAX and input clock).
>  */

Yes, totally agree with you. I will add some documentation for our
controller's setting.

>
> @Thierry: having a framework guideline here would be good. Or still
> better a guideline and a debug setting that notices drivers stepping out
> of line.
>
> I assume using MOD = 0 is forbidden?
>
> > +     /*
> > +      * According to the datasheet, the period_ns calculation formula
> > +      * should be:
> > +      * period_ns = 10^9 * (prescale + 1) * mod / clk_rate
> > +      *
> > +      * Then we can get the prescale formula:
> > +      * prescale = (period_ns * clk_rate) / (10^9 * mod) -1
> > +      */
> > +     tmp = chn->clk_rate * period_ns;
> > +     div = 1000000000ULL * SPRD_PWM_MOD_MAX;
>
> Please use NSEC_PER_SEC instead of 1000000000ULL.

Sure.

>
> > +     prescale = div64_u64(tmp, div) - 1;
>
> If tmp is smaller than div you end up with prescale = 0xffffffff which
> should be catched. What if prescale > 0xffff?

Usually we can not meet this case, but you are right, the prescale has
a limit according to the register definition. So will add a validation
here.

>
> > +     sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, SPRD_PWM_MOD_MAX);
> > +     sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_DUTY, duty);
>
> You're losing precision here as you always use SPRD_PWM_MOD_MAX, right?
> (Just for my understanding, if this simpler approach is good enough
> here that's fine.)

Yes, SPRD_PWM_MOD_MAX is good enough.

>
> > +     sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PAT_LOW, SPRD_PWM_REG_MSK);
> > +     sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PAT_HIGH, SPRD_PWM_REG_MSK);
>
> Please describe these two registers in a short comment.

Sure.

>
> > +     sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PRESCALE, prescale);
>
> Is the configuration here atomic in the sense that the write of DUTY
> above only gets effective when PRESCALE is written? If not, please add

Yes.

> a describing paragraph at the top of the driver similar to what is
> written in pwm-sifive.c. When the PWM is already running before, how
> does a configuration change effects the output? Is the currently running
> period completed?

Anyway, I'll add some comments to explain how it works.

>
> > +static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
> > +                            struct pwm_state *state)
> > +{
> > +     struct sprd_pwm_chip *spc =
> > +             container_of(chip, struct sprd_pwm_chip, chip);
> > +     struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
> > +     u32 enabled, duty, prescale;
> > +     u64 tmp;
> > +     int ret;
> > +
> > +     ret = clk_bulk_prepare_enable(SPRD_PWM_NUM_CLKS, chn->clks);
> > +     if (ret) {
> > +             dev_err(spc->dev, "failed to enable pwm%u clocks\n",
> > +                     pwm->hwpwm);
> > +             return;
> > +     }
> > +
> > +     chn->clk_enabled = true;
> > +
> > +     duty = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_DUTY) & SPRD_PWM_REG_MSK;
> > +     prescale = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_PRESCALE) & SPRD_PWM_REG_MSK;
> > +     enabled = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE) & SPRD_PWM_ENABLE_BIT;
> > +
> > +     /*
> > +      * According to the datasheet, the period_ns and duty_ns calculation
> > +      * formula should be:
> > +      * period_ns = 10^9 * (prescale + 1) * mod / clk_rate
> > +      * duty_ns = 10^9 * (prescale + 1) * duty / clk_rate
> > +      */
> > +     tmp = (prescale + 1) * 1000000000ULL * SPRD_PWM_MOD_MAX;
> > +     state->period = div64_u64(tmp, chn->clk_rate);
>
> This is not idempotent. If you apply the configuration that is returned
> here this shouldn't result in a reconfiguration.

Since we may configure the  PWM in bootloader, so in kernel part we
should get current PWM state to avoid reconfiguration if state
configuration are same.

>
> > +     tmp = (prescale + 1) * 1000000000ULL * duty;
> > +     state->duty_cycle = div64_u64(tmp, chn->clk_rate);
> > +
> > +     state->enabled = !!enabled;
> > +
> > +     /* Disable PWM clocks if the PWM channel is not in enable state. */
> > +     if (!enabled) {
> > +             clk_bulk_disable_unprepare(SPRD_PWM_NUM_CLKS, chn->clks);
> > +             chn->clk_enabled = false;
> > +     }
> > +}
> > +
> > +static const struct pwm_ops sprd_pwm_ops = {
> > +     .config = sprd_pwm_config,
> > +     .enable = sprd_pwm_enable,
> > +     .disable = sprd_pwm_disable,
> > +     .get_state = sprd_pwm_get_state,
> > +     .owner = THIS_MODULE,
> > +};
> > +
> > +static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
> > +{
> > +     struct clk *clk_parent, *clk_pwm;
> > +     int ret, i, clk_index = 0;
> > +
> > +     clk_parent = devm_clk_get(spc->dev, "source");
> > +     if (IS_ERR(clk_parent)) {
> > +             dev_err(spc->dev, "failed to get source clock\n");
> > +             return PTR_ERR(clk_parent);
> > +     }
> > +
> > +     for (i = 0; i < SPRD_PWM_NUM; i++) {
> > +             struct sprd_pwm_chn *chn = &spc->chn[i];
> > +             int j;
> > +
> > +             for (j = 0; j < SPRD_PWM_NUM_CLKS; ++j)
> > +                     chn->clks[j].id = sprd_pwm_clks[clk_index++];
> > +
> > +             ret = devm_clk_bulk_get(spc->dev, SPRD_PWM_NUM_CLKS, chn->clks);
> > +             if (ret) {
> > +                     if (ret == -ENOENT)
> > +                             break;
>
> devm_clk_bulk_get_optional ? I'm sure you don't want to get all 8 clocks
> 8 times.

This is not optional, each channel has 2 required clocks, and we have
4 channels. (SPRD_PWM_NUM_CLKS == 2)

>
> > +
> > +                     dev_err(spc->dev, "failed to get channel clocks\n");
> > +                     return ret;
> > +             }
> > +
> > +             clk_pwm = chn->clks[1].clk;
>
> This 1 looks suspicious. Are you using all clocks provided in the dtb at
> all? You're not using i in the loop at all, this doesn't look right.

Like I said above, each channel has 2 clocks: enable clock and pwm
clock, the 2nd clock of each channel's bulk clocks is the pwm clock,
which is used to set the source clock. I know this's not easy to read,
so do you have any good suggestion?

>
> > +             if (!clk_set_parent(clk_pwm, clk_parent))
> > +                     chn->clk_rate = clk_get_rate(clk_pwm);
> > +             else
> > +                     chn->clk_rate = SPRD_PWM_DEFAULT_CLK;
>
> I don't know all the clock framework details, but I think there are
> better ways to ensure that a given clock is used as parent for another
> given clock. Please read the chapter about "Assigned clock parents and
> rates" in the clock bindings and check if this could be used for the
> purpose here and so simplify the driver.

Actually there are many other drivers set the parent clock like this,
and we want a default clock if failed to set the parent clock.

>
> > +     }
> > +
> > +     if (!i) {
> > +             dev_err(spc->dev, "no availbale PWM channels\n");
>
> s/availbale/available/

Sure.

>
> > +             return -EINVAL;
> > +     }
> > +
> > +     spc->num_pwms = i;
> > +
> > +     return 0;
> > +}
> > +
> > +static int sprd_pwm_probe(struct platform_device *pdev)
> > +{
> > +     struct sprd_pwm_chip *spc;
> > +     int ret;
> > +
> > +     spc = devm_kzalloc(&pdev->dev, sizeof(*spc), GFP_KERNEL);
> > +     if (!spc)
> > +             return -ENOMEM;
> > +
> > +     spc->base = devm_platform_ioremap_resource(pdev, 0);
> > +     if (IS_ERR(spc->base))
> > +             return PTR_ERR(spc->base);
> > +
> > +     spc->dev = &pdev->dev;
> > +     ret = sprd_pwm_clk_init(spc);
> > +     if (ret)
> > +             return ret;
> > +
> > +     spc->chip.dev = &pdev->dev;
> > +     spc->chip.ops = &sprd_pwm_ops;
> > +     spc->chip.base = -1;
> > +     spc->chip.npwm = spc->num_pwms;
> > +
> > +     ret = pwmchip_add(&spc->chip);
> > +     if (ret) {
> > +             dev_err(&pdev->dev, "failed to add PWM chip\n");
> > +             return ret;
> > +     }
> > +
> > +     platform_set_drvdata(pdev, spc);
>
> If you do this earlier you can simplify the last part of the driver to:
>
>         ret = pwmchip_add(&spc->chip);
>         if (ret)
>                 dev_err(&pdev->dev, "failed to add PWM chip\n");
>
>         return ret;

OK.

>
> > +     return 0;
> > +}
> > +
> > +static int sprd_pwm_remove(struct platform_device *pdev)
> > +{
> > +     struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
> > +     int i;
> > +
> > +     for (i = 0; i < spc->num_pwms; i++)
> > +             pwm_disable(&spc->chip.pwms[i]);
>
> This is wrong. You must not call pwm_disable here. It's the consumer's
> responsibility to disable the hardware.

Emm, I saw some drivers did like this, like pwm-spear.c.
Could you elaborate on what's the problem if the driver issues pwm_disable?

Very appreciated for your comments.

-- 
Baolin Wang
Best Regards

^ permalink raw reply

* Re: [PATCH 5/6] tty: serial: Add linflexuart driver for S32V234
From: Stefan-gabriel Mirea @ 2019-08-09  9:57 UTC (permalink / raw)
  To: Will Deacon
  Cc: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	shawnguo@kernel.org, Leo Li, jslaby@suse.com,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <20190809095338.d73fomq424gayf2b@willie-the-truck>

On 8/9/2019 12:53 PM, Will Deacon wrote:
> On Fri, Aug 09, 2019 at 09:45:40AM +0000, Stefan-gabriel Mirea wrote:
>> On 8/8/2019 8:17 PM, Will Deacon wrote:
>>> On Thu, Aug 08, 2019 at 12:47:00PM +0000, Stefan-gabriel Mirea wrote:
>>>> On 8/8/2019 11:08 AM, Will Deacon wrote:
>>>>> On Fri, Aug 02, 2019 at 07:47:23PM +0000, Stefan-gabriel Mirea wrote:
>>>>>> +             linflex,<addr>
>>>>>> +                     Use early console provided by Freescale LinFlex UART
>>>>>> +                     serial driver for NXP S32V234 SoCs. A valid base
>>>>>> +                     address must be provided, and the serial port must
>>>>>> +                     already be setup and configured.
>>>>>
>>>>> Why isn't earlycon= sufficient for this?
>>>>
>>>> "earlycon=" is not actually supported. I will fix this in the next
>>>> version by adding a /chosen/stdout-path to the dts. The compatible
>>>> string provided to OF_EARLYCON_DECLARE will also be changed from
>>>> "fsl,s32v234-linflexuart" to "fsl,s32-linflexuart" to match the one in
>>>> the device tree nodes. I missed this after importing a rename from our
>>>> codebase.
>>>>
>>>> Should I remove this addition from kernel-parameters.txt after that?
>>>
>>> Yes, if you can use earlycon instead, then you can drop your custom option
>>> entirely and therefore there's no need to document it either.
>>
>> Can you please clarify what you mean by "drop your custom option"? The
>> "linflex" option documented in the paragraph is the name of the
>> earlycon_id declared via "OF_EARLYCON_DECLARE(linflex, ...)". We have
>> not done anything particular to accept it in the parameter value.
> 
> My apologies, I completely misread your patch and thought your were adding
> a *new* kernel parameter. Having looked at the context, I now see you're
> adding a new earlycon option, which is what I was suggesting :)
> 
> By all means, please update the stdout-path, because then you can just pass
> "earlycon" and things will work as expected.

No problem, I will submit the new version soon. Thank you!

Regards,
Stefan

^ permalink raw reply

* Re: [PATCH 5/6] tty: serial: Add linflexuart driver for S32V234
From: Will Deacon @ 2019-08-09  9:53 UTC (permalink / raw)
  To: Stefan-gabriel Mirea
  Cc: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	shawnguo@kernel.org, Leo Li, jslaby@suse.com,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <VI1PR0402MB2863B3E3E2F93CBA8ADB96E5DFD60@VI1PR0402MB2863.eurprd04.prod.outlook.com>

On Fri, Aug 09, 2019 at 09:45:40AM +0000, Stefan-gabriel Mirea wrote:
> On 8/8/2019 8:17 PM, Will Deacon wrote:
> > On Thu, Aug 08, 2019 at 12:47:00PM +0000, Stefan-gabriel Mirea wrote:
> >> On 8/8/2019 11:08 AM, Will Deacon wrote:
> >>> On Fri, Aug 02, 2019 at 07:47:23PM +0000, Stefan-gabriel Mirea wrote:
> >>>> +             linflex,<addr>
> >>>> +                     Use early console provided by Freescale LinFlex UART
> >>>> +                     serial driver for NXP S32V234 SoCs. A valid base
> >>>> +                     address must be provided, and the serial port must
> >>>> +                     already be setup and configured.
> >>>
> >>> Why isn't earlycon= sufficient for this?
> >>
> >> "earlycon=" is not actually supported. I will fix this in the next
> >> version by adding a /chosen/stdout-path to the dts. The compatible
> >> string provided to OF_EARLYCON_DECLARE will also be changed from
> >> "fsl,s32v234-linflexuart" to "fsl,s32-linflexuart" to match the one in
> >> the device tree nodes. I missed this after importing a rename from our
> >> codebase.
> >>
> >> Should I remove this addition from kernel-parameters.txt after that?
> > 
> > Yes, if you can use earlycon instead, then you can drop your custom option
> > entirely and therefore there's no need to document it either.
> 
> Can you please clarify what you mean by "drop your custom option"? The
> "linflex" option documented in the paragraph is the name of the
> earlycon_id declared via "OF_EARLYCON_DECLARE(linflex, ...)". We have
> not done anything particular to accept it in the parameter value.

My apologies, I completely misread your patch and thought your were adding
a *new* kernel parameter. Having looked at the context, I now see you're
adding a new earlycon option, which is what I was suggesting :)

By all means, please update the stdout-path, because then you can just pass
"earlycon" and things will work as expected.

Will

^ permalink raw reply

* Re: [PATCH 5/6] tty: serial: Add linflexuart driver for S32V234
From: Stefan-gabriel Mirea @ 2019-08-09  9:45 UTC (permalink / raw)
  To: Will Deacon
  Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, corbet@lwn.net,
	gregkh@linuxfoundation.org, jslaby@suse.com,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Leo Li,
	Cosmin Stefan Stoica, robh+dt@kernel.org,
	linux-serial@vger.kernel.org, catalin.marinas@arm.com,
	shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org,
	Larisa Ileana Grigore
In-Reply-To: <20190808171711.nk7ljqkugtketu4q@willie-the-truck>

On 8/8/2019 8:17 PM, Will Deacon wrote:
> On Thu, Aug 08, 2019 at 12:47:00PM +0000, Stefan-gabriel Mirea wrote:
>> On 8/8/2019 11:08 AM, Will Deacon wrote:
>>> On Fri, Aug 02, 2019 at 07:47:23PM +0000, Stefan-gabriel Mirea wrote:
>>>> +             linflex,<addr>
>>>> +                     Use early console provided by Freescale LinFlex UART
>>>> +                     serial driver for NXP S32V234 SoCs. A valid base
>>>> +                     address must be provided, and the serial port must
>>>> +                     already be setup and configured.
>>>
>>> Why isn't earlycon= sufficient for this?
>>
>> "earlycon=" is not actually supported. I will fix this in the next
>> version by adding a /chosen/stdout-path to the dts. The compatible
>> string provided to OF_EARLYCON_DECLARE will also be changed from
>> "fsl,s32v234-linflexuart" to "fsl,s32-linflexuart" to match the one in
>> the device tree nodes. I missed this after importing a rename from our
>> codebase.
>>
>> Should I remove this addition from kernel-parameters.txt after that?
> 
> Yes, if you can use earlycon instead, then you can drop your custom option
> entirely and therefore there's no need to document it either.

Can you please clarify what you mean by "drop your custom option"? The
"linflex" option documented in the paragraph is the name of the
earlycon_id declared via "OF_EARLYCON_DECLARE(linflex, ...)". We have
not done anything particular to accept it in the parameter value.

We do use earlycon (e.g. "earlycon=linflex,0x40053000"), we just do not
support an empty value after "=", which needs to be fixed as I
understand, because it does not respect the comment[1] about ARM64.

Regards,
Stefan

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/kernel-parameters.txt?h=v5.3-rc3#n980

^ permalink raw reply

* [PATCH 19/19] ARM: dts: mmp3: Add MMP3 SoC dts file
From: Lubomir Rintel @ 2019-08-09  9:31 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, Kishon Vijay Abraham I, Russell King,
	Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
	linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>

Describes most of the hardware found on Marvell MMP3, aka PXA2128, aka
Armada 620. Missing bits are the LCD controller, HSIC controllers,
Audio and GPU. Will be completed once bindings and drivers settle.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
 arch/arm/boot/dts/mmp3.dtsi | 534 ++++++++++++++++++++++++++++++++++++
 1 file changed, 534 insertions(+)
 create mode 100644 arch/arm/boot/dts/mmp3.dtsi

diff --git a/arch/arm/boot/dts/mmp3.dtsi b/arch/arm/boot/dts/mmp3.dtsi
new file mode 100644
index 0000000000000..5a6275257ebdd
--- /dev/null
+++ b/arch/arm/boot/dts/mmp3.dtsi
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ *  Copyright (C) 2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <dt-bindings/clock/marvell,mmp2.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		serial3 = &uart4;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "marvell,mmp3-smp";
+
+		cpu@0 {
+			compatible = "marvell,pj4b";
+			device_type = "cpu";
+			next-level-cache = <&l2>;
+			reg = <0>;
+		};
+
+		cpu@1 {
+			compatible = "marvell,pj4b";
+			device_type = "cpu";
+			next-level-cache = <&l2>;
+			reg = <1>;
+		};
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		axi@d4200000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			interrupt-controller@d4282000 {
+				compatible = "marvell,mmp3-intc";
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0xd4282000 0x1000>,
+				      <0xd4284000 0x100>;
+				mrvl,intc-nr-irqs = <64>;
+			};
+
+			pmic_mux: interrupt-controller@d4282150 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x150 0x4>, <0x168 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <4>;
+			};
+
+			rtc_mux: interrupt-controller@d4282154 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x154 0x4>, <0x16c 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			hsi3_mux: interrupt-controller@d42821bc {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1bc 0x4>, <0x1a4 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <3>;
+			};
+
+			gpu_mux: interrupt-controller@d42821c0 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1c0 0x4>, <0x1a8 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <3>;
+			};
+
+			twsi_mux: interrupt-controller@d4282158 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x158 0x4>, <0x170 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <5>;
+			};
+
+			hsi2_mux: interrupt-controller@d42821c4 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1c4 0x4>, <0x1ac 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			dxo_mux: interrupt-controller@d42821c8 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1c8 0x4>, <0x1b0 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			misc1_mux: interrupt-controller@d428215c {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x15c 0x4>, <0x174 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <31>;
+			};
+
+			ci_mux: interrupt-controller@d42821cc {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1cc 0x4>, <0x1b4 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			ssp_mux: interrupt-controller@d4282160 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x160 0x4>, <0x178 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <2>;
+			};
+
+			hsi1_mux: interrupt-controller@d4282184 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x184 0x4>, <0x17c 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <4>;
+			};
+
+			misc2_mux: interrupt-controller@d4282188 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x188 0x4>, <0x180 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <20>;
+			};
+
+			hsi0_mux: interrupt-controller@d42821d0 {
+				compatible = "mrvl,mmp2-mux-intc";
+				interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				reg = <0x1d0 0x4>, <0x1b8 0x4>;
+				reg-names = "mux status", "mux mask";
+				mrvl,intc-nr-irqs = <5>;
+			};
+
+			usb_otg_phy0: usb-otg-phy@d4207000 {
+				compatible = "marvell,mmp3-usb-phy";
+				reg = <0xd4207000 0x40>;
+				#phy-cells = <0>;
+				status = "disabled";
+			};
+
+			usb_otg0: usb-otg@d4208000 {
+				compatible = "marvell,pxau2o-ehci";
+				reg = <0xd4208000 0x200>;
+				interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_USB>;
+				clock-names = "USBCLK";
+				phys = <&usb_otg_phy0>;
+				phy-names = "usb";
+				status = "disabled";
+			};
+
+			mmc1: mmc@d4280000 {
+				compatible = "mrvl,pxav3-mmc";
+				reg = <0xd4280000 0x120>;
+				clocks = <&soc_clocks MMP2_CLK_SDH0>;
+				clock-names = "io";
+				interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+				status = "disabled";
+			};
+
+			mmc2: mmc@d4280800 {
+				compatible = "mrvl,pxav3-mmc";
+				reg = <0xd4280800 0x120>;
+				clocks = <&soc_clocks MMP2_CLK_SDH1>;
+				clock-names = "io";
+				interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+				status = "disabled";
+			};
+
+			mmc3: mmc@d4281000 {
+				compatible = "mrvl,pxav3-mmc";
+				reg = <0xd4281000 0x120>;
+				clocks = <&soc_clocks MMP2_CLK_SDH2>;
+				clock-names = "io";
+				interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+				status = "disabled";
+			};
+
+			mmc4: mmc@d4281800 {
+				compatible = "mrvl,pxav3-mmc";
+				reg = <0xd4281800 0x120>;
+				clocks = <&soc_clocks MMP2_CLK_SDH3>;
+				clock-names = "io";
+				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+				status = "disabled";
+			};
+
+			camera0: camera@d420a000 {
+				compatible = "marvell,mmp2-ccic";
+				reg = <0xd420a000 0x800>;
+				interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_CCIC0>;
+				clock-names = "axi";
+				#clock-cells = <0>;
+				clock-output-names = "mclk";
+				status = "disabled";
+			};
+
+			camera1: camera@d420a800 {
+				compatible = "marvell,mmp2-ccic";
+				reg = <0xd420a800 0x800>;
+				interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_CCIC1>;
+				clock-names = "axi";
+				#clock-cells = <0>;
+				clock-output-names = "mclk";
+				status = "disabled";
+			};
+		};
+
+		apb@d4000000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			timer: timer@d4014000 {
+				compatible = "mrvl,mmp-timer";
+				reg = <0xd4014000 0x100>;
+				interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_TIMER>;
+			};
+
+			uart1: uart@d4030000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4030000 0x1000>;
+				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_UART0>;
+				resets = <&soc_clocks MMP2_CLK_UART0>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+
+			uart2: uart@d4017000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4017000 0x1000>;
+				interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_UART1>;
+				resets = <&soc_clocks MMP2_CLK_UART1>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+
+			uart3: uart@d4018000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4018000 0x1000>;
+				interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_UART2>;
+				resets = <&soc_clocks MMP2_CLK_UART2>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+
+			uart4: uart@d4016000 {
+				compatible = "mrvl,mmp-uart";
+				reg = <0xd4016000 0x1000>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_UART3>;
+				resets = <&soc_clocks MMP2_CLK_UART3>;
+				reg-shift = <2>;
+				status = "disabled";
+			};
+
+			gpio: gpio@d4019000 {
+				compatible = "marvell,mmp2-gpio";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4019000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "gpio_mux";
+				clocks = <&soc_clocks MMP2_CLK_GPIO>;
+				resets = <&soc_clocks MMP2_CLK_GPIO>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				ranges;
+
+				gcb0: gpio@d4019000 {
+					reg = <0xd4019000 0x4>;
+				};
+
+				gcb1: gpio@d4019004 {
+					reg = <0xd4019004 0x4>;
+				};
+
+				gcb2: gpio@d4019008 {
+					reg = <0xd4019008 0x4>;
+				};
+
+				gcb3: gpio@d4019100 {
+					reg = <0xd4019100 0x4>;
+				};
+
+				gcb4: gpio@d4019104 {
+					reg = <0xd4019104 0x4>;
+				};
+
+				gcb5: gpio@d4019108 {
+					reg = <0xd4019108 0x4>;
+				};
+			};
+
+			twsi1: i2c@d4011000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4011000 0x1000>;
+				interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI0>;
+				resets = <&soc_clocks MMP2_CLK_TWSI0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				mrvl,i2c-fast-mode;
+				status = "disabled";
+			};
+
+			twsi2: i2c@d4031000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4031000 0x1000>;
+				interrupt-parent = <&twsi_mux>;
+				interrupts = <0>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI1>;
+				resets = <&soc_clocks MMP2_CLK_TWSI1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			twsi3: i2c@d4032000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4032000 0x1000>;
+				interrupt-parent = <&twsi_mux>;
+				interrupts = <1>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI2>;
+				resets = <&soc_clocks MMP2_CLK_TWSI2>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			twsi4: i2c@d4033000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4033000 0x1000>;
+				interrupt-parent = <&twsi_mux>;
+				interrupts = <2>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI3>;
+				resets = <&soc_clocks MMP2_CLK_TWSI3>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+
+			twsi5: i2c@d4033800 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4033800 0x1000>;
+				interrupt-parent = <&twsi_mux>;
+				interrupts = <3>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI4>;
+				resets = <&soc_clocks MMP2_CLK_TWSI4>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			twsi6: i2c@d4034000 {
+				compatible = "mrvl,mmp-twsi";
+				reg = <0xd4034000 0x1000>;
+				interrupt-parent = <&twsi_mux>;
+				interrupts = <4>;
+				clocks = <&soc_clocks MMP2_CLK_TWSI5>;
+				resets = <&soc_clocks MMP2_CLK_TWSI5>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			rtc: rtc@d4010000 {
+				compatible = "mrvl,mmp-rtc";
+				reg = <0xd4010000 0x1000>;
+				interrupts = <1 0>;
+				interrupt-names = "rtc 1Hz", "rtc alarm";
+				interrupt-parent = <&rtc_mux>;
+				clocks = <&soc_clocks MMP2_CLK_RTC>;
+				resets = <&soc_clocks MMP2_CLK_RTC>;
+				status = "disabled";
+			};
+
+			ssp1: spi@d4035000 {
+				compatible = "marvell,mmp2-ssp";
+				reg = <0xd4035000 0x1000>;
+				clocks = <&soc_clocks MMP2_CLK_SSP0>;
+				interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			ssp2: spi@d4036000 {
+				compatible = "marvell,mmp2-ssp";
+				reg = <0xd4036000 0x1000>;
+				clocks = <&soc_clocks MMP2_CLK_SSP1>;
+				interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			ssp3: spi@d4037000 {
+				compatible = "marvell,mmp2-ssp";
+				reg = <0xd4037000 0x1000>;
+				clocks = <&soc_clocks MMP2_CLK_SSP2>;
+				interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			ssp4: spi@d4039000 {
+				compatible = "marvell,mmp2-ssp";
+				reg = <0xd4039000 0x1000>;
+				clocks = <&soc_clocks MMP2_CLK_SSP3>;
+				interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		l2: l2-cache-controller@d0020000 {
+			compatible = "marvell,tauros3-cache", "arm,pl310-cache";
+			reg = <0xd0020000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		soc_clocks: clocks {
+			compatible = "marvell,mmp2-clock";
+			reg = <0xd4050000 0x1000>,
+			      <0xd4282800 0x400>,
+			      <0xd4015000 0x1000>;
+			reg-names = "mpmu", "apmu", "apbc";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			#power-domain-cells = <1>;
+		};
+
+		snoop-control-unit@e0000000 {
+			compatible = "arm,arm11mp-scu";
+			reg = <0xe0000000 0x100>;
+		};
+
+		gic: interrupt-controller@e0001000 {
+			compatible = "arm,arm11mp-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0xe0001000 0x1000>,
+			      <0xe0000100 0x100>;
+		};
+
+		local-timer@e0000600 {
+			compatible = "arm,arm11mp-twd-timer";
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
+						  IRQ_TYPE_EDGE_RISING)>;
+			reg = <0xe0000600 0x20>;
+		};
+
+		watchdog@2c000620 {
+			compatible = "arm,arm11mp-twd-wdt";
+			reg = <0xe0000620 0x20>;
+			interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) |
+						  IRQ_TYPE_EDGE_RISING)>;
+		};
+	};
+};
-- 
2.21.0

^ permalink raw reply related

* Re: [PATCH v3 0/2] dt-bindings: net: meson-dwmac: convert to yaml
From: Neil Armstrong @ 2019-08-09  9:31 UTC (permalink / raw)
  To: David Miller
  Cc: robh+dt, martin.blumenstingl, devicetree, netdev, linux-amlogic,
	linux-arm-kernel, linux-kernel
In-Reply-To: <20190808.112033.180369877501058953.davem@davemloft.net>

Hi,

On 08/08/2019 20:20, David Miller wrote:
> From: Neil Armstrong <narmstrong@baylibre.com>
> Date: Thu,  8 Aug 2019 13:40:59 +0200
> 
>> This patchsets converts the Amlogic Meson DWMAC glue bindings over to
>> YAML schemas using the already converted dwmac bindings.
>>
>> The first patch is needed because the Amlogic glue needs a supplementary
>> reg cell to access the DWMAC glue registers.
>>
>> Changes since v2:
>> - Added review tags
>> - Updated allwinner,sun7i-a20-gmac.yaml reg maxItems
> 
> Where is this targetted to be merged, an ARM tree?  Or one of my
> networking trees?
> 

I assume you can take it in one of your net trees.

Thanks,
Neil

^ permalink raw reply

* [PATCH 18/19] phy: phy-mmp3-usb: add a new driver
From: Lubomir Rintel @ 2019-08-09  9:31 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Rob Herring, Mark Rutland, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, Kishon Vijay Abraham I, Russell King,
	Michael Turquette, Stephen Boyd, devicetree, linux-kernel,
	linux-arm-kernel, linux-clk, Lubomir Rintel
In-Reply-To: <20190809093158.7969-1-lkundrak@v3.sk>

This is the USB2 PHY as found on the Marvell MMP3 SoC. Based on Marvell GPL
release.

While at that, also add a MAINTAINERS entry including the other MMP PHY
driver.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
 MAINTAINERS                        |   7 +
 drivers/phy/marvell/Kconfig        |  11 ++
 drivers/phy/marvell/Makefile       |   1 +
 drivers/phy/marvell/phy-mmp3-usb.c | 291 +++++++++++++++++++++++++++++
 4 files changed, 310 insertions(+)
 create mode 100644 drivers/phy/marvell/phy-mmp3-usb.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fb2ceb265a8c3..fb7e8edfc3d66 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10790,6 +10790,13 @@ F:	arch/arm/boot/dts/mmp*
 F:	arch/arm/mach-mmp/
 F:	linux/soc/mmp/
 
+MMP USB PHY DRIVERS
+R:	Lubomir Rintel <lkundrak@v3.sk>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	drivers/phy/marvell/phy-mmp3-usb.c
+F:	drivers/phy/marvell/phy-pxa-usb.c
+
 MMU GATHER AND TLB INVALIDATION
 M:	Will Deacon <will@kernel.org>
 M:	"Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index 0e1642419c0bf..d33ef35b3e51b 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -102,3 +102,14 @@ config PHY_PXA_USB
 	  The PHY driver will be used by Marvell udc/ehci/otg driver.
 
 	  To compile this driver as a module, choose M here.
+
+config PHY_MMP3_USB
+	tristate "Marvell MMP3 USB PHY Driver"
+	depends on MACH_MMP3_DT || COMPILE_TEST
+	select GENERIC_PHY
+	help
+	  Enable this to support Marvell MMP3 USB PHY driver for Marvell
+	  SoC. This driver will do the PHY initialization and shutdown.
+	  The PHY driver will be used by Marvell udc/ehci/otg driver.
+
+	  To compile this driver as a module, choose M here.
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile
index 434eb9ca6cc3f..5a106b1549f41 100644
--- a/drivers/phy/marvell/Makefile
+++ b/drivers/phy/marvell/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
 obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
 obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
+obj-$(CONFIG_PHY_MMP3_USB)		+= phy-mmp3-usb.o
 obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY)	+= phy-mvebu-a3700-comphy.o
 obj-$(CONFIG_PHY_MVEBU_A3700_UTMI)	+= phy-mvebu-a3700-utmi.o
 obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY)	+= phy-armada38x-comphy.o
diff --git a/drivers/phy/marvell/phy-mmp3-usb.c b/drivers/phy/marvell/phy-mmp3-usb.c
new file mode 100644
index 0000000000000..499869595a582
--- /dev/null
+++ b/drivers/phy/marvell/phy-mmp3-usb.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mmp/cputype.h>
+
+#define USB2_PLL_REG0		0x4
+#define USB2_PLL_REG1		0x8
+#define USB2_TX_REG0		0x10
+#define USB2_TX_REG1		0x14
+#define USB2_TX_REG2		0x18
+#define USB2_RX_REG0		0x20
+#define USB2_RX_REG1		0x24
+#define USB2_RX_REG2		0x28
+#define USB2_ANA_REG0		0x30
+#define USB2_ANA_REG1		0x34
+#define USB2_ANA_REG2		0x38
+#define USB2_DIG_REG0		0x3C
+#define USB2_DIG_REG1		0x40
+#define USB2_DIG_REG2		0x44
+#define USB2_DIG_REG3		0x48
+#define USB2_TEST_REG0		0x4C
+#define USB2_TEST_REG1		0x50
+#define USB2_TEST_REG2		0x54
+#define USB2_CHARGER_REG0	0x58
+#define USB2_OTG_REG0		0x5C
+#define USB2_PHY_MON0		0x60
+#define USB2_RESETVE_REG0	0x64
+#define USB2_ICID_REG0		0x78
+#define USB2_ICID_REG1		0x7C
+
+/* USB2_PLL_REG0 */
+
+/* This is for Ax stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3		0
+#define USB2_PLL_FBDIV_MASK_MMP3		(0xFF << 0)
+
+#define USB2_PLL_REFDIV_SHIFT_MMP3		8
+#define USB2_PLL_REFDIV_MASK_MMP3		(0xF << 8)
+
+#define USB2_PLL_VDD12_SHIFT_MMP3		12
+#define USB2_PLL_VDD18_SHIFT_MMP3		14
+
+/* This is for B0 stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3_B0		0
+#define USB2_PLL_REFDIV_SHIFT_MMP3_B0		9
+#define USB2_PLL_VDD18_SHIFT_MMP3_B0		14
+#define USB2_PLL_FBDIV_MASK_MMP3_B0		0x01FF
+#define USB2_PLL_REFDIV_MASK_MMP3_B0		0x3E00
+
+#define USB2_PLL_CAL12_SHIFT_MMP3		0
+#define USB2_PLL_CALI12_MASK_MMP3		(0x3 << 0)
+
+#define USB2_PLL_VCOCAL_START_SHIFT_MMP3	2
+
+#define USB2_PLL_KVCO_SHIFT_MMP3		4
+#define USB2_PLL_KVCO_MASK_MMP3			(0x7<<4)
+
+#define USB2_PLL_ICP_SHIFT_MMP3			8
+#define USB2_PLL_ICP_MASK_MMP3			(0x7<<8)
+
+#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3		12
+
+#define USB2_PLL_PU_PLL_SHIFT_MMP3		13
+#define USB2_PLL_PU_PLL_MASK			(0x1 << 13)
+
+#define USB2_PLL_READY_MASK_MMP3		(0x1 << 15)
+
+/* USB2_TX_REG0 */
+#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3		8
+#define USB2_TX_IMPCAL_VTH_MASK_MMP3		(0x7 << 8)
+
+#define USB2_TX_RCAL_START_SHIFT_MMP3		13
+
+/* USB2_TX_REG1 */
+#define USB2_TX_CK60_PHSEL_SHIFT_MMP3		0
+#define USB2_TX_CK60_PHSEL_MASK_MMP3		(0xf << 0)
+
+#define USB2_TX_AMP_SHIFT_MMP3			4
+#define USB2_TX_AMP_MASK_MMP3			(0x7 << 4)
+
+#define USB2_TX_VDD12_SHIFT_MMP3		8
+#define USB2_TX_VDD12_MASK_MMP3			(0x3 << 8)
+
+/* USB2_TX_REG2 */
+#define USB2_TX_DRV_SLEWRATE_SHIFT		10
+
+/* USB2_RX_REG0 */
+#define USB2_RX_SQ_THRESH_SHIFT_MMP3		4
+#define USB2_RX_SQ_THRESH_MASK_MMP3		(0xf << 4)
+
+#define USB2_RX_SQ_LENGTH_SHIFT_MMP3		10
+#define USB2_RX_SQ_LENGTH_MASK_MMP3		(0x3 << 10)
+
+/* USB2_ANA_REG1*/
+#define USB2_ANA_PU_ANA_SHIFT_MMP3		14
+
+/* USB2_OTG_REG0 */
+#define USB2_OTG_PU_OTG_SHIFT_MMP3		3
+
+struct mmp3_usb_phy {
+	struct phy *phy;
+	void __iomem *base;
+};
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+	return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl_relaxed(base + offset);
+	reg |= value;
+	writel_relaxed(reg, base + offset);
+	readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl_relaxed(base + offset);
+	reg &= ~value;
+	writel_relaxed(reg, base + offset);
+	readl_relaxed(base + offset);
+}
+
+static int mmp3_usb_phy_init(struct phy *phy)
+{
+	struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+	void __iomem *base = mmp3_usb_phy->base;
+
+	if (cpu_is_mmp3_a0()) {
+		u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3
+			| USB2_PLL_REFDIV_MASK_MMP3));
+		u2o_set(base, USB2_PLL_REG0,
+			0xd << USB2_PLL_REFDIV_SHIFT_MMP3
+			| 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);
+	} else if (cpu_is_mmp3_b0()) {
+		u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0
+			| USB2_PLL_FBDIV_MASK_MMP3_B0);
+		u2o_set(base, USB2_PLL_REG0,
+			0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0
+			| 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);
+	} else {
+		dev_err(&phy->dev, "unsupported silicon revision\n");
+		return -ENODEV;
+	}
+
+	u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK
+		| USB2_PLL_ICP_MASK_MMP3
+		| USB2_PLL_KVCO_MASK_MMP3
+		| USB2_PLL_CALI12_MASK_MMP3);
+	u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3
+		| 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3
+		| 3 << USB2_PLL_ICP_SHIFT_MMP3
+		| 3 << USB2_PLL_KVCO_SHIFT_MMP3
+		| 3 << USB2_PLL_CAL12_SHIFT_MMP3);
+
+	u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);
+	u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);
+
+	u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3
+		| USB2_TX_AMP_MASK_MMP3
+		| USB2_TX_CK60_PHSEL_MASK_MMP3);
+	u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3
+		| 4 << USB2_TX_AMP_SHIFT_MMP3
+		| 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);
+
+	u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);
+	u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);
+
+	u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);
+	u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);
+
+	u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);
+
+	u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);
+
+	return 0;
+}
+
+static int mmp3_usb_phy_calibrate(struct phy *phy)
+{
+	struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
+	void __iomem *base = mmp3_usb_phy->base;
+	int loops;
+
+	/*
+	 * PLL VCO and TX Impedance Calibration Timing:
+	 *
+	 *                _____________________________________
+	 * PU  __________|
+	 *                        _____________________________
+	 * VCOCAL START _________|
+	 *                                 ___
+	 * REG_RCAL_START ________________|   |________|_______
+	 *               | 200us | 400us  | 40| 400us  | USB PHY READY
+	 */
+
+	udelay(200);
+	u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);
+	udelay(400);
+	u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+	udelay(40);
+	u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
+	udelay(400);
+
+	loops = 0;
+	while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {
+		mdelay(1);
+		loops++;
+		if (loops > 100) {
+			dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static const struct phy_ops mmp3_usb_phy_ops = {
+	.init		= mmp3_usb_phy_init,
+	.calibrate	= mmp3_usb_phy_calibrate,
+	.owner		= THIS_MODULE,
+};
+
+static const struct of_device_id mmp3_usb_phy_of_match[] = {
+	{ .compatible = "marvell,mmp3-usb-phy", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);
+
+static int mmp3_usb_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *resource;
+	struct mmp3_usb_phy *mmp3_usb_phy;
+	struct phy_provider *provider;
+
+	mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);
+	if (!mmp3_usb_phy)
+		return -ENOMEM;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mmp3_usb_phy->base = devm_ioremap_resource(dev, resource);
+	if (IS_ERR(mmp3_usb_phy->base)) {
+		dev_err(dev, "failed to remap PHY regs\n");
+		return PTR_ERR(mmp3_usb_phy->base);
+	}
+
+	mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);
+	if (IS_ERR(mmp3_usb_phy->phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(mmp3_usb_phy->phy);
+	}
+
+	phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);
+	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	if (IS_ERR(provider)) {
+		dev_err(dev, "failed to register PHY provider\n");
+		return PTR_ERR(provider);
+	}
+
+	return 0;
+}
+
+static struct platform_driver mmp3_usb_phy_driver = {
+	.probe		= mmp3_usb_phy_probe,
+	.driver		= {
+		.name	= "mmp3-usb-phy",
+		.of_match_table = mmp3_usb_phy_of_match,
+	},
+};
+module_platform_driver(mmp3_usb_phy_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.21.0

^ permalink raw reply related


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