Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 04/15] dt-bindings: display: sunxi-drm: Add TCON TOP description
From: Maxime Ripard @ 2018-05-21  8:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180519183127.2718-5-jernej.skrabec@siol.net>

Hi,

On Sat, May 19, 2018 at 08:31:16PM +0200, Jernej Skrabec wrote:
> TCON TOP main purpose is to configure whole display pipeline. It
> determines relationships between mixers and TCONs, selects source TCON
> for HDMI, muxes LCD and TV encoder GPIO output,

I'm not sure you mean GPIO here, but rather pin?

> selects TV encoder clock source and contains additional TV TCON and
> DSI gates.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  .../bindings/display/sunxi/sun4i-drm.txt      | 20 +++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> index 3346c1e2a7a0..a099957ab62a 100644
> --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -187,6 +187,26 @@ And on the A23, A31, A31s and A33, you need one more clock line:
>     - 'lvds-alt': An alternative clock source, separate from the TCON channel 0
>                   clock, that can be used to drive the LVDS clock
>  
> +TCON TOP
> +--------
> +
> +TCON TOPs main purpose is to configure whole display pipeline. It determines
> +relationships between mixers and TCONs, selects source TCON for HDMI, muxes
> +LCD and TV encoder GPIO output, selects TV encoder clock source and contains
> +additional TV TCON and DSI gates.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun8i-r40-tcon-top
> +  - reg: base address and size of the memory-mapped region.
> +  - clocks: phandle to the clocks feeding the TCON TOP
> +    * bus: TCON TOP interface clock
> +  - clock-names: clock name mentioned above
> +  - resets: phandle to the reset line driving the DRC
> +    * rst: TCON TOP reset line
> +  - reset-names: reset name mentioned above
> +  - #clock-cells : must contain 1
> +

I guess you should better describe the OF-graph endpoints, and the
clocks output. Just using the binding additions here doesn't allow to
get a clear idea of how the DT should look like.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/0904bec1/attachment.sig>

^ permalink raw reply

* [PATCH 05/15] drm/sun4i: Add TCON TOP driver
From: Maxime Ripard @ 2018-05-21  8:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180519183127.2718-6-jernej.skrabec@siol.net>

On Sat, May 19, 2018 at 08:31:17PM +0200, Jernej Skrabec wrote:
> As already described in DT binding, TCON TOP is responsible for
> configuring display pipeline. In this initial driver focus is on HDMI
> pipeline, so TVE and LCD configuration is not implemented.
> 
> Implemented features:
> - HDMI source selection
> - clock driver (TCON and DSI gating)
> - connecting mixers and TCONS
> 
> Something similar also existed in previous SoCs, except that it was part
> of first TCON.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/gpu/drm/sun4i/Makefile             |   3 +-
>  drivers/gpu/drm/sun4i/sun8i_tcon_top.c     | 256 +++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun8i_tcon_top.h     |  20 ++
>  include/dt-bindings/clock/sun8i-tcon-top.h |  11 +
>  4 files changed, 289 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
>  create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h
> 
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 2589f4acd5ae..09fbfd6304ba 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -16,7 +16,8 @@ sun8i-drm-hdmi-y		+= sun8i_hdmi_phy_clk.o
>  
>  sun8i-mixer-y			+= sun8i_mixer.o sun8i_ui_layer.o \
>  				   sun8i_vi_layer.o sun8i_ui_scaler.o \
> -				   sun8i_vi_scaler.o sun8i_csc.o
> +				   sun8i_vi_scaler.o sun8i_csc.o \
> +				   sun8i_tcon_top.o
>  
>  sun4i-tcon-y			+= sun4i_crtc.o
>  sun4i-tcon-y			+= sun4i_dotclock.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> new file mode 100644
> index 000000000000..075a356a6dfa
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net> */
> +
> +#include <drm/drmP.h>
> +
> +#include <dt-bindings/clock/sun8i-tcon-top.h>
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/spinlock.h>
> +
> +#include "sun8i_tcon_top.h"
> +
> +#define TCON_TOP_PORT_SEL_REG		0x1C
> +#define TCON_TOP_PORT_DE0_MSK			GENMASK(1, 0)
> +#define TCON_TOP_PORT_DE1_MSK			GENMASK(5, 4)
> +#define TCON_TOP_PORT_TCON_LCD0			0
> +#define TCON_TOP_PORT_TCON_LCD1			1
> +#define TCON_TOP_PORT_TCON_TV0			2
> +#define TCON_TOP_PORT_TCON_TV1			3
> +
> +#define TCON_TOP_GATE_SRC_REG		0x20
> +#define TCON_TOP_HDMI_SRC_MSK			GENMASK(29, 28)
> +#define TCON_TOP_HDMI_SRC_NONE			0
> +#define TCON_TOP_HDMI_SRC_TCON_TV0		1
> +#define TCON_TOP_HDMI_SRC_TCON_TV1		2
> +#define TCON_TOP_TCON_TV1_GATE			24
> +#define TCON_TOP_TCON_TV0_GATE			20
> +#define TCON_TOP_TCON_DSI_GATE			16
> +
> +#define CLK_NUM					3
> +
> +struct sun8i_tcon_top {
> +	struct clk		*bus;
> +	void __iomem		*regs;
> +	struct reset_control	*rst;
> +
> +	/*
> +	 * spinlock is used for locking access to registers from different
> +	 * places - tcon driver and clk subsystem.
> +	 */
> +	spinlock_t		reg_lock;
> +};
> +
> +struct sun8i_tcon_top_gate {
> +	const char	*name;
> +	u8		bit;
> +	int		index;
> +};
> +
> +static const struct sun8i_tcon_top_gate gates[] = {
> +	{"bus-tcon-top-dsi", TCON_TOP_TCON_DSI_GATE, CLK_BUS_TCON_TOP_DSI},
> +	{"bus-tcon-top-tv0", TCON_TOP_TCON_TV0_GATE, CLK_BUS_TCON_TOP_TV0},
> +	{"bus-tcon-top-tv1", TCON_TOP_TCON_TV1_GATE, CLK_BUS_TCON_TOP_TV1},
> +};
> +
> +void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int tcon)
> +{
> +	unsigned long flags;
> +	u32 val;
> +
> +	if (tcon > 1) {
> +		DRM_ERROR("TCON index is too high!\n");
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> +	val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +	val &= ~TCON_TOP_HDMI_SRC_MSK;
> +	val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK,
> +			  TCON_TOP_HDMI_SRC_TCON_TV0 + tcon);
> +	writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> +	spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
> +			      int mixer, enum tcon_type tcon_type, int tcon)
> +{
> +	unsigned long flags;
> +	u32 val, reg;
> +
> +	if (mixer > 1) {
> +		DRM_ERROR("Mixer index is too high!\n");
> +		return;
> +	}
> +
> +	if (tcon > 1) {
> +		DRM_ERROR("TCON index is too high!\n");
> +		return;
> +	}
> +
> +	switch (tcon_type) {
> +	case tcon_type_lcd:
> +		val = TCON_TOP_PORT_TCON_LCD0 + tcon;
> +		break;
> +	case tcon_type_tv:
> +		val = TCON_TOP_PORT_TCON_TV0 + tcon;
> +		break;
> +	default:
> +		DRM_ERROR("Invalid TCON type!\n");
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> +	reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> +	if (mixer == 0) {
> +		reg &= ~TCON_TOP_PORT_DE0_MSK;
> +		reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, val);
> +	} else {
> +		reg &= ~TCON_TOP_PORT_DE1_MSK;
> +		reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, val);
> +	}
> +	writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> +
> +	spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +static int sun8i_tcon_top_probe(struct platform_device *pdev)
> +{
> +	struct clk_hw_onecell_data *clk_data;
> +	struct sun8i_tcon_top *tcon_top;
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	int ret, i;
> +
> +	tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
> +	if (!tcon_top)
> +		return -ENOMEM;
> +
> +	clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> +				sizeof(*clk_data->hws) * CLK_NUM,
> +				GFP_KERNEL);
> +	if (!clk_data)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&tcon_top->reg_lock);
> +
> +	tcon_top->rst = devm_reset_control_get(dev, "rst");
> +	if (IS_ERR(tcon_top->rst)) {
> +		dev_err(dev, "Couldn't get our reset line\n");
> +		return PTR_ERR(tcon_top->rst);
> +	}
> +
> +	tcon_top->bus = devm_clk_get(dev, "bus");
> +	if (IS_ERR(tcon_top->bus)) {
> +		dev_err(dev, "Couldn't get the bus clock\n");
> +		return PTR_ERR(tcon_top->bus);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	tcon_top->regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(tcon_top->regs))
> +		return PTR_ERR(tcon_top->regs);
> +
> +	ret = reset_control_deassert(tcon_top->rst);
> +	if (ret) {
> +		dev_err(dev, "Could not deassert ctrl reset control\n");
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(tcon_top->bus);
> +	if (ret) {
> +		dev_err(dev, "Could not enable bus clock\n");
> +		goto err_assert_reset;
> +	}
> +
> +	/*
> +	 * Default register values might have some reserved bits set, which
> +	 * prevents TCON TOP from working properly. Set them to 0 here.
> +	 */
> +	writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> +	writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> +	for (i = 0; i < CLK_NUM; i++) {
> +		const char *parent_name = "bus-tcon-top";

I guess retrieving the parent's clock name at runtime would be more
flexible.

> +		struct clk_init_data init;
> +		struct clk_gate *gate;
> +
> +		gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> +		if (!gate) {
> +			ret = -ENOMEM;
> +			goto err_disable_clock;
> +		}
> +
> +		init.name = gates[i].name;
> +		init.ops = &clk_gate_ops;
> +		init.flags = CLK_IS_BASIC;
> +		init.parent_names = &parent_name;
> +		init.num_parents = 1;
> +
> +		gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> +		gate->bit_idx = gates[i].bit;
> +		gate->lock = &tcon_top->reg_lock;
> +		gate->hw.init = &init;
> +
> +		ret = devm_clk_hw_register(dev, &gate->hw);
> +		if (ret)
> +			goto err_disable_clock;

Isn't it what clk_hw_register_gate is doing?

> +		clk_data->hws[gates[i].index] = &gate->hw;
> +	}
> +
> +	clk_data->num = CLK_NUM;
> +
> +	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
> +	if (ret)
> +		goto err_disable_clock;
> +
> +	platform_set_drvdata(pdev, tcon_top);
> +
> +	return 0;
> +
> +err_disable_clock:
> +	clk_disable_unprepare(tcon_top->bus);
> +err_assert_reset:
> +	reset_control_assert(tcon_top->rst);
> +
> +	return ret;
> +}
> +
> +static int sun8i_tcon_top_remove(struct platform_device *pdev)
> +{
> +	struct sun8i_tcon_top *tcon_top = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(tcon_top->bus);
> +	reset_control_assert(tcon_top->rst);
> +
> +	return 0;
> +}
> +
> +const struct of_device_id sun8i_tcon_top_of_table[] = {
> +	{ .compatible = "allwinner,sun8i-r40-tcon-top" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
> +
> +static struct platform_driver sun8i_tcon_top_platform_driver = {
> +	.probe		= sun8i_tcon_top_probe,
> +	.remove		= sun8i_tcon_top_remove,
> +	.driver		= {
> +		.name		= "sun8i-tcon-top",
> +		.of_match_table	= sun8i_tcon_top_of_table,
> +	},
> +};
> +module_platform_driver(sun8i_tcon_top_platform_driver);
> +
> +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
> +MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> new file mode 100644
> index 000000000000..19126e07d2a6
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net> */
> +
> +#ifndef _SUN8I_TCON_TOP_H_
> +#define _SUN8I_TCON_TOP_H_
> +
> +#include <linux/device.h>
> +
> +struct sun8i_tcon_top;
> +
> +enum tcon_type {
> +	tcon_type_lcd,
> +	tcon_type_tv,

The usual practice is to have the enum values upper-case.

Thanks!
Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/55182603/attachment.sig>

^ permalink raw reply

* [PATCH V3 0/8] net: ethernet: stmmac: add support for stm32mp1
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel

Patches to have Ethernet support on stm32mp1
Changelog:
Remark from Rob Herring
In Documentation/devicetree/bindings/arm/stm32.txt:
In arch/arm/boot/dts/stm32mp157c.dtsi:
Add "st,stm32mp157-syscfg" compatible

Christophe Roullier (8):
  net: ethernet: stmmac: add adaptation for stm32mp157c.
  dt-bindings: stm32-dwmac: add support of MPU families
  ARM: dts: stm32: add ethernet pins to stm32mp157c
  ARM: dts: stm32: Add syscfg on stm32mp1
  ARM: dts: stm32: Add ethernet dwmac on stm32mp1
  net: stmmac: add dwmac-4.20a compatible
  ARM: dts: stm32: add support of ethernet on stm32mp157c-ev1
  dt-bindings: stm32: add compatible for syscon

 Documentation/devicetree/bindings/arm/stm32.txt    |   5 +
 .../devicetree/bindings/net/stm32-dwmac.txt        |  18 +-
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi          |  46 ++++
 arch/arm/boot/dts/stm32mp157c-ev1.dts              |  20 ++
 arch/arm/boot/dts/stm32mp157c.dtsi                 |  35 +++
 drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c  | 270 +++++++++++++++++++--
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   3 +-
 7 files changed, 379 insertions(+), 18 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH V3 1/8] net: ethernet: stmmac: add adaptation for stm32mp157c.
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

Glue codes to support stm32mp157c device and stay
compatible with stm32 mcu family

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 270 ++++++++++++++++++++--
 1 file changed, 255 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 9e6db16..f51e327 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -16,49 +16,183 @@
 #include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/stmmac.h>
 
 #include "stmmac_platform.h"
 
-#define MII_PHY_SEL_MASK	BIT(23)
+#define SYSCFG_MCU_ETH_MASK		BIT(23)
+#define SYSCFG_MP1_ETH_MASK		GENMASK(23, 16)
+
+#define SYSCFG_PMCR_ETH_CLK_SEL		BIT(16)
+#define SYSCFG_PMCR_ETH_REF_CLK_SEL	BIT(17)
+#define SYSCFG_PMCR_ETH_SEL_MII		BIT(20)
+#define SYSCFG_PMCR_ETH_SEL_RGMII	BIT(21)
+#define SYSCFG_PMCR_ETH_SEL_RMII	BIT(23)
+#define SYSCFG_PMCR_ETH_SEL_GMII	0
+#define SYSCFG_MCU_ETH_SEL_MII		0
+#define SYSCFG_MCU_ETH_SEL_RMII		1
 
 struct stm32_dwmac {
 	struct clk *clk_tx;
 	struct clk *clk_rx;
+	struct clk *clk_eth_ck;
+	struct clk *clk_ethstp;
+	struct clk *syscfg_clk;
+	bool int_phyclk;	/* Clock from RCC to drive PHY */
 	u32 mode_reg;		/* MAC glue-logic mode register */
 	struct regmap *regmap;
 	u32 speed;
+	const struct stm32_ops *ops;
+	struct device *dev;
+};
+
+struct stm32_ops {
+	int (*set_mode)(struct plat_stmmacenet_data *plat_dat);
+	int (*clk_prepare)(struct stm32_dwmac *dwmac, bool prepare);
+	int (*suspend)(struct stm32_dwmac *dwmac);
+	void (*resume)(struct stm32_dwmac *dwmac);
+	int (*parse_data)(struct stm32_dwmac *dwmac,
+			  struct device *dev);
+	u32 syscfg_eth_mask;
 };
 
 static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat)
 {
 	struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
-	u32 reg = dwmac->mode_reg;
-	u32 val;
 	int ret;
 
-	val = (plat_dat->interface == PHY_INTERFACE_MODE_MII) ? 0 : 1;
-	ret = regmap_update_bits(dwmac->regmap, reg, MII_PHY_SEL_MASK, val);
-	if (ret)
-		return ret;
+	if (dwmac->ops->set_mode) {
+		ret = dwmac->ops->set_mode(plat_dat);
+		if (ret)
+			return ret;
+	}
 
 	ret = clk_prepare_enable(dwmac->clk_tx);
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(dwmac->clk_rx);
-	if (ret)
-		clk_disable_unprepare(dwmac->clk_tx);
+	if (!dwmac->dev->power.is_suspended) {
+		ret = clk_prepare_enable(dwmac->clk_rx);
+		if (ret) {
+			clk_disable_unprepare(dwmac->clk_tx);
+			return ret;
+		}
+	}
+
+	if (dwmac->ops->clk_prepare) {
+		ret = dwmac->ops->clk_prepare(dwmac, true);
+		if (ret) {
+			clk_disable_unprepare(dwmac->clk_rx);
+			clk_disable_unprepare(dwmac->clk_tx);
+		}
+	}
 
 	return ret;
 }
 
+static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare)
+{
+	int ret = 0;
+
+	if (prepare) {
+		ret = clk_prepare_enable(dwmac->syscfg_clk);
+		if (ret)
+			return ret;
+
+		if (dwmac->int_phyclk) {
+			ret = clk_prepare_enable(dwmac->clk_eth_ck);
+			if (ret) {
+				clk_disable_unprepare(dwmac->syscfg_clk);
+				return ret;
+			}
+		}
+	} else {
+		clk_disable_unprepare(dwmac->syscfg_clk);
+		if (dwmac->int_phyclk)
+			clk_disable_unprepare(dwmac->clk_eth_ck);
+	}
+	return ret;
+}
+
+static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+	struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
+	u32 reg = dwmac->mode_reg;
+	int val;
+
+	switch (plat_dat->interface) {
+	case PHY_INTERFACE_MODE_MII:
+		val = SYSCFG_PMCR_ETH_SEL_MII;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
+		break;
+	case PHY_INTERFACE_MODE_GMII:
+		val = SYSCFG_PMCR_ETH_SEL_GMII;
+		if (dwmac->int_phyclk)
+			val |= SYSCFG_PMCR_ETH_CLK_SEL;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		val = SYSCFG_PMCR_ETH_SEL_RMII;
+		if (dwmac->int_phyclk)
+			val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		val = SYSCFG_PMCR_ETH_SEL_RGMII;
+		if (dwmac->int_phyclk)
+			val |= SYSCFG_PMCR_ETH_CLK_SEL;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
+		break;
+	default:
+		pr_debug("SYSCFG init :  Do not manage %d interface\n",
+			 plat_dat->interface);
+		/* Do not manage others interfaces */
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(dwmac->regmap, reg,
+				 dwmac->ops->syscfg_eth_mask, val);
+}
+
+static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+	struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
+	u32 reg = dwmac->mode_reg;
+	int val;
+
+	switch (plat_dat->interface) {
+	case PHY_INTERFACE_MODE_MII:
+		val = SYSCFG_MCU_ETH_SEL_MII;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		val = SYSCFG_MCU_ETH_SEL_RMII;
+		pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
+		break;
+	default:
+		pr_debug("SYSCFG init :  Do not manage %d interface\n",
+			 plat_dat->interface);
+		/* Do not manage others interfaces */
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(dwmac->regmap, reg,
+				 dwmac->ops->syscfg_eth_mask, val);
+}
+
 static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac)
 {
 	clk_disable_unprepare(dwmac->clk_tx);
 	clk_disable_unprepare(dwmac->clk_rx);
+
+	if (dwmac->ops->clk_prepare)
+		dwmac->ops->clk_prepare(dwmac, false);
 }
 
 static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
@@ -70,15 +204,22 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
 	/*  Get TX/RX clocks */
 	dwmac->clk_tx = devm_clk_get(dev, "mac-clk-tx");
 	if (IS_ERR(dwmac->clk_tx)) {
-		dev_err(dev, "No tx clock provided...\n");
+		dev_err(dev, "No ETH Tx clock provided...\n");
 		return PTR_ERR(dwmac->clk_tx);
 	}
+
 	dwmac->clk_rx = devm_clk_get(dev, "mac-clk-rx");
 	if (IS_ERR(dwmac->clk_rx)) {
-		dev_err(dev, "No rx clock provided...\n");
+		dev_err(dev, "No ETH Rx clock provided...\n");
 		return PTR_ERR(dwmac->clk_rx);
 	}
 
+	if (dwmac->ops->parse_data) {
+		err = dwmac->ops->parse_data(dwmac, dev);
+		if (err)
+			return err;
+	}
+
 	/* Get mode register */
 	dwmac->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
 	if (IS_ERR(dwmac->regmap))
@@ -91,11 +232,46 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
 	return err;
 }
 
+static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
+			       struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+
+	dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk");
+
+	/* Check if internal clk from RCC selected */
+	if (dwmac->int_phyclk) {
+		/*  Get ETH_CLK clocks */
+		dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck");
+		if (IS_ERR(dwmac->clk_eth_ck)) {
+			dev_err(dev, "No ETH CK clock provided...\n");
+			return PTR_ERR(dwmac->clk_eth_ck);
+		}
+	}
+
+	/*  Clock used for low power mode */
+	dwmac->clk_ethstp = devm_clk_get(dev, "ethstp");
+	if (IS_ERR(dwmac->clk_ethstp)) {
+		dev_err(dev, "No ETH peripheral clock provided for CStop mode ...\n");
+		return PTR_ERR(dwmac->clk_ethstp);
+	}
+
+	/*  Clock for sysconfig */
+	dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk");
+	if (IS_ERR(dwmac->syscfg_clk)) {
+		dev_err(dev, "No syscfg clock provided...\n");
+		return PTR_ERR(dwmac->syscfg_clk);
+	}
+
+	return 0;
+}
+
 static int stm32_dwmac_probe(struct platform_device *pdev)
 {
 	struct plat_stmmacenet_data *plat_dat;
 	struct stmmac_resources stmmac_res;
 	struct stm32_dwmac *dwmac;
+	const struct stm32_ops *data;
 	int ret;
 
 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -112,6 +288,16 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
 		goto err_remove_config_dt;
 	}
 
+	data = of_device_get_match_data(&pdev->dev);
+	if (!data) {
+		dev_err(&pdev->dev, "no of match data provided\n");
+		ret = -EINVAL;
+		goto err_remove_config_dt;
+	}
+
+	dwmac->ops = data;
+	dwmac->dev = &pdev->dev;
+
 	ret = stm32_dwmac_parse_data(dwmac, &pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Unable to parse OF data\n");
@@ -149,15 +335,48 @@ static int stm32_dwmac_remove(struct platform_device *pdev)
 	return ret;
 }
 
+static int stm32mp1_suspend(struct stm32_dwmac *dwmac)
+{
+	int ret = 0;
+
+	ret = clk_prepare_enable(dwmac->clk_ethstp);
+	if (ret)
+		return ret;
+
+	clk_disable_unprepare(dwmac->clk_tx);
+	clk_disable_unprepare(dwmac->syscfg_clk);
+	if (dwmac->int_phyclk)
+		clk_disable_unprepare(dwmac->clk_eth_ck);
+
+	return ret;
+}
+
+static void stm32mp1_resume(struct stm32_dwmac *dwmac)
+{
+	clk_disable_unprepare(dwmac->clk_ethstp);
+}
+
+static int stm32mcu_suspend(struct stm32_dwmac *dwmac)
+{
+	clk_disable_unprepare(dwmac->clk_tx);
+	clk_disable_unprepare(dwmac->clk_rx);
+
+	return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int stm32_dwmac_suspend(struct device *dev)
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct stm32_dwmac *dwmac = priv->plat->bsp_priv;
+
 	int ret;
 
 	ret = stmmac_suspend(dev);
-	stm32_dwmac_clk_disable(priv->plat->bsp_priv);
+
+	if (dwmac->ops->suspend)
+		ret = dwmac->ops->suspend(dwmac);
 
 	return ret;
 }
@@ -166,8 +385,12 @@ static int stm32_dwmac_resume(struct device *dev)
 {
 	struct net_device *ndev = dev_get_drvdata(dev);
 	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct stm32_dwmac *dwmac = priv->plat->bsp_priv;
 	int ret;
 
+	if (dwmac->ops->resume)
+		dwmac->ops->resume(dwmac);
+
 	ret = stm32_dwmac_init(priv->plat);
 	if (ret)
 		return ret;
@@ -181,8 +404,24 @@ static int stm32_dwmac_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
 	stm32_dwmac_suspend, stm32_dwmac_resume);
 
+static struct stm32_ops stm32mcu_dwmac_data = {
+	.set_mode = stm32mcu_set_mode,
+	.suspend = stm32mcu_suspend,
+	.syscfg_eth_mask = SYSCFG_MCU_ETH_MASK
+};
+
+static struct stm32_ops stm32mp1_dwmac_data = {
+	.set_mode = stm32mp1_set_mode,
+	.clk_prepare = stm32mp1_clk_prepare,
+	.suspend = stm32mp1_suspend,
+	.resume = stm32mp1_resume,
+	.parse_data = stm32mp1_parse_data,
+	.syscfg_eth_mask = SYSCFG_MP1_ETH_MASK
+};
+
 static const struct of_device_id stm32_dwmac_match[] = {
-	{ .compatible = "st,stm32-dwmac"},
+	{ .compatible = "st,stm32-dwmac", .data = &stm32mcu_dwmac_data},
+	{ .compatible = "st,stm32mp1-dwmac", .data = &stm32mp1_dwmac_data},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, stm32_dwmac_match);
@@ -199,5 +438,6 @@ static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
 module_platform_driver(stm32_dwmac_driver);
 
 MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@gmail.com>");
-MODULE_DESCRIPTION("STMicroelectronics MCU DWMAC Specific Glue layer");
+MODULE_AUTHOR("Christophe Roullier <christophe.roullier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DWMAC Specific Glue layer");
 MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 2/8] dt-bindings: stm32-dwmac: add support of MPU families
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

Add description for Ethernet MPU families fields

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/net/stm32-dwmac.txt | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
index 489dbcb..1341012 100644
--- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
@@ -6,14 +6,28 @@ Please see stmmac.txt for the other unchanged properties.
 The device node has following properties.
 
 Required properties:
-- compatible:  Should be "st,stm32-dwmac" to select glue, and
+- compatible:  For MCU family should be "st,stm32-dwmac" to select glue, and
 	       "snps,dwmac-3.50a" to select IP version.
+	       For MPU family should be "st,stm32mp1-dwmac" to select
+	       glue, and "snps,dwmac-4.20a" to select IP version.
 - clocks: Must contain a phandle for each entry in clock-names.
 - clock-names: Should be "stmmaceth" for the host clock.
 	       Should be "mac-clk-tx" for the MAC TX clock.
 	       Should be "mac-clk-rx" for the MAC RX clock.
+	       For MPU family need to add also "ethstp" for power mode clock and,
+	                                       "syscfg-clk" for SYSCFG clock.
+- interrupt-names: Should contain a list of interrupt names corresponding to
+           the interrupts in the interrupts property, if available.
+		   Should be "macirq" for the main MAC IRQ
+		   Should be "eth_wake_irq" for the IT which wake up system
 - st,syscon : Should be phandle/offset pair. The phandle to the syscon node which
-	      encompases the glue register, and the offset of the control register.
+	       encompases the glue register, and the offset of the control register.
+
+Optional properties:
+- clock-names:     For MPU family "mac-clk-ck" for PHY without quartz
+- st,int-phyclk (boolean) :  valid only where PHY do not have quartz and need to be clock
+	           by RCC
+
 Example:
 
 	ethernet at 40028000 {
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 3/8] ARM: dts: stm32: add ethernet pins to stm32mp157c
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

Add ethernet pins on stm32mp157c.

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 46 +++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 6f044100..cf83eb244 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -158,6 +158,52 @@
 					bias-disable;
 				};
 			};
+
+			ethernet0_rgmii_pins_a: rgmii-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
+						 <STM32_PINMUX('G', 4, AF11)>, /* ETH_RGMII_GTX_CLK */
+						 <STM32_PINMUX('G', 13, AF11)>, /* ETH_RGMII_TXD0 */
+						 <STM32_PINMUX('G', 14, AF11)>, /* ETH_RGMII_TXD1 */
+						 <STM32_PINMUX('C', 2, AF11)>, /* ETH_RGMII_TXD2 */
+						 <STM32_PINMUX('E', 2, AF11)>, /* ETH_RGMII_TXD3 */
+						 <STM32_PINMUX('B', 11, AF11)>, /* ETH_RGMII_TX_CTL */
+						 <STM32_PINMUX('A', 2, AF11)>, /* ETH_MDIO */
+						 <STM32_PINMUX('C', 1, AF11)>; /* ETH_MDC */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <3>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('C', 4, AF11)>, /* ETH_RGMII_RXD0 */
+						 <STM32_PINMUX('C', 5, AF11)>, /* ETH_RGMII_RXD1 */
+						 <STM32_PINMUX('B', 0, AF11)>, /* ETH_RGMII_RXD2 */
+						 <STM32_PINMUX('B', 1, AF11)>, /* ETH_RGMII_RXD3 */
+						 <STM32_PINMUX('A', 1, AF11)>, /* ETH_RGMII_RX_CLK */
+						 <STM32_PINMUX('A', 7, AF11)>; /* ETH_RGMII_RX_CTL */
+					bias-disable;
+				};
+			};
+
+			ethernet0_rgmii_pins_sleep_a: rgmii-sleep-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('G', 5, ANALOG)>, /* ETH_RGMII_CLK125 */
+						 <STM32_PINMUX('G', 4, ANALOG)>, /* ETH_RGMII_GTX_CLK */
+						 <STM32_PINMUX('G', 13, ANALOG)>, /* ETH_RGMII_TXD0 */
+						 <STM32_PINMUX('G', 14, ANALOG)>, /* ETH_RGMII_TXD1 */
+						 <STM32_PINMUX('C', 2, ANALOG)>, /* ETH_RGMII_TXD2 */
+						 <STM32_PINMUX('E', 2, ANALOG)>, /* ETH_RGMII_TXD3 */
+						 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH_RGMII_TX_CTL */
+						 <STM32_PINMUX('A', 2, ANALOG)>, /* ETH_MDIO */
+						 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH_MDC */
+						 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH_RGMII_RXD0 */
+						 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH_RGMII_RXD1 */
+						 <STM32_PINMUX('B', 0, ANALOG)>, /* ETH_RGMII_RXD2 */
+						 <STM32_PINMUX('B', 1, ANALOG)>, /* ETH_RGMII_RXD3 */
+						 <STM32_PINMUX('A', 1, ANALOG)>, /* ETH_RGMII_RX_CLK */
+						 <STM32_PINMUX('A', 7, ANALOG)>; /* ETH_RGMII_RX_CTL */
+				};
+			};
 		};
 
 		pinctrl_z: pin-controller-z {
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 4/8] ARM: dts: stm32: Add syscfg on stm32mp1
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

System configuration controller is mainly used to manage
the compensation cell and other IOs and system related
settings.

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index bc3eddc..dbc0e707 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -167,6 +167,11 @@
 			#reset-cells = <1>;
 		};
 
+		syscfg: system-config at 50020000 {
+			compatible = "st,stm32mp157-syscfg", "syscon";
+			reg = <0x50020000 0x400>;
+		};
+
 		usart1: serial at 5c000000 {
 			compatible = "st,stm32h7-uart";
 			reg = <0x5c000000 0x400>;
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 5/8] ARM: dts: stm32: Add ethernet dwmac on stm32mp1
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

Add Ethernet support (Synopsys MAC IP 4.20a) on stm32mp1 SOC.
Enable feature supported by the stmmac driver, such as TSO.

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index dbc0e707..99cc94c 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -179,5 +179,35 @@
 			clocks = <&rcc USART1_K>;
 			status = "disabled";
 		};
+
+		stmmac_axi_config_0: stmmac-axi-config {
+			snps,wr_osr_lmt = <0x7>;
+			snps,rd_osr_lmt = <0x7>;
+			snps,blen = <0 0 0 0 16 8 4>;
+		};
+
+		ethernet0: ethernet at 5800a000 {
+			compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
+			reg = <0x5800a000 0x2000>;
+			reg-names = "stmmaceth";
+			interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_NONE>;
+			interrupt-names = "macirq";
+			clock-names = "stmmaceth",
+				      "mac-clk-tx",
+				      "mac-clk-rx",
+				      "ethstp",
+				      "syscfg-clk";
+			clocks = <&rcc ETHMAC>,
+				 <&rcc ETHTX>,
+				 <&rcc ETHRX>,
+				 <&rcc ETHSTP>,
+				 <&rcc SYSCFG>;
+			st,syscon = <&syscfg 0x4>;
+			snps,mixed-burst;
+			snps,pbl = <2>;
+			snps,axi-config = <&stmmac_axi_config_0>;
+			snps,tso;
+			status = "disabled";
+		};
 	};
 };
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 6/8] net: stmmac: add dwmac-4.20a compatible
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

Manage dwmac-4.20a version from synopsys

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index ebd3e5f..6d141f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -472,7 +472,8 @@ struct plat_stmmacenet_data *
 	}
 
 	if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
-	    of_device_is_compatible(np, "snps,dwmac-4.10a")) {
+	    of_device_is_compatible(np, "snps,dwmac-4.10a") ||
+	    of_device_is_compatible(np, "snps,dwmac-4.20a")) {
 		plat->has_gmac4 = 1;
 		plat->has_gmac = 0;
 		plat->pmt = 1;
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 7/8] ARM: dts: stm32: add support of ethernet on stm32mp157c-ev1
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

MAC is connected to a PHY in RGMII mode.

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 arch/arm/boot/dts/stm32mp157c-ev1.dts | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 57e6dbc..a7fee5c 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -17,5 +17,25 @@
 
 	aliases {
 		serial0 = &uart4;
+		ethernet0 = &ethernet0;
+	};
+};
+
+&ethernet0 {
+	status = "okay";
+	pinctrl-0 = <&ethernet0_rgmii_pins_a>;
+	pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
+	pinctrl-names = "default", "sleep";
+	phy-mode = "rgmii";
+	max-speed = <1000>;
+	phy-handle = <&phy0>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+		phy0: ethernet-phy at 0 {
+			reg = <0>;
+		};
 	};
 };
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 8/8] dt-bindings: stm32: add compatible for syscon
From: Christophe Roullier @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526890046-10565-1-git-send-email-christophe.roullier@st.com>

This patch describes syscon DT bindings.

Signed-off-by: Christophe Roullier <christophe.roullier@st.com>
---
 Documentation/devicetree/bindings/arm/stm32.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/stm32.txt b/Documentation/devicetree/bindings/arm/stm32.txt
index 6808ed9..e46ebad 100644
--- a/Documentation/devicetree/bindings/arm/stm32.txt
+++ b/Documentation/devicetree/bindings/arm/stm32.txt
@@ -8,3 +8,8 @@ using one of the following compatible strings:
   st,stm32f746
   st,stm32h743
   st,stm32mp157
+
+Required nodes:
+- syscon: the soc bus node must have a system controller node pointing to the
+  global control registers, with the compatible string
+  "st,stm32mp157-syscfg", "syscon";
-- 
1.9.1

^ permalink raw reply related

* [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top
From: Maxime Ripard @ 2018-05-21  8:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180519183127.2718-7-jernej.skrabec@siol.net>

On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> If SoC has TCON TOP unit, it has to be configured from TCON, since it
> has all information needed. Additionally, if it is TCON TV, it must also
> enable bus gate inside TCON TOP unit.

Why?

> Add support for such TCONs.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tcon.h |  8 ++++++++
>  2 files changed, 36 insertions(+)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 08747fc3ee71..e0c562ce1c22 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
>  		dev_err(dev, "Couldn't get the TCON bus clock\n");
>  		return PTR_ERR(tcon->clk);
>  	}
> +
> +	if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> +		tcon->top_clk = devm_clk_get(dev, "tcon-top");
> +		if (IS_ERR(tcon->top_clk)) {
> +			dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> +			return PTR_ERR(tcon->top_clk);
> +		}
> +		clk_prepare_enable(tcon->top_clk);
> +	}
> +
>  	clk_prepare_enable(tcon->clk);
>  
>  	if (tcon->quirks->has_channel_0) {
> @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
>  static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
>  {
>  	clk_disable_unprepare(tcon->clk);
> +	clk_disable_unprepare(tcon->top_clk);
>  }
>  
>  static int sun4i_tcon_init_irq(struct device *dev,
> @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
>  	tcon->id = engine->id;
>  	tcon->quirks = of_device_get_match_data(dev);
>  
> +	if (tcon->quirks->needs_tcon_top) {
> +		struct device_node *np;
> +
> +		np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> +		if (np) {
> +			struct platform_device *pdev;
> +
> +			pdev = of_find_device_by_node(np);
> +			if (pdev)
> +				tcon->tcon_top = platform_get_drvdata(pdev);
> +			of_node_put(np);
> +
> +			if (!tcon->tcon_top)
> +				return -EPROBE_DEFER;
> +		}
> +	}
> +

I might have missed it, but I've not seen the bindings additions for
that property. This shouldn't really be done that way anyway, instead
of using a direct phandle, you should be using the of-graph, with the
TCON-top sitting where it belongs in the flow of data.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/9e6fce45/attachment.sig>

^ permalink raw reply

* [PATCH 0/2] get rid of Kconfig symbol MACH_MESON8B
From: Jerome Brunet @ 2018-05-21  8:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180520172353.19256-1-martin.blumenstingl@googlemail.com>

On Sun, 2018-05-20 at 19:23 +0200, Martin Blumenstingl wrote:
> as noted by Kevin [0] there are two Kconfig symbols which only differ
> in their Kconfig help text and the list of .dtbs that are being built.
> the goal of this small series is to get rid of the unnecessary
> MACH_MESON8B Kconfig symbol by merging it into MACH_MESON8.
> 
> 
> [0] http://lists.infradead.org/pipermail/linux-amlogic/2018-May/007342.html
> 
> Martin Blumenstingl (2):
>   ARM: dts: meson: build the Meson8b .dtbs with MACH_MESON8
>   ARM: meson: merge Kconfig symbol MACH_MESON8B into MACH_MESON8
> 
>  arch/arm/boot/dts/Makefile  | 5 ++---
>  arch/arm/mach-meson/Kconfig | 9 +--------
>  2 files changed, 3 insertions(+), 11 deletions(-)
> 

For the series:

Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>

^ permalink raw reply

* [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver
From: Maxime Ripard @ 2018-05-21  8:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180519183127.2718-13-jernej.skrabec@siol.net>

On Sat, May 19, 2018 at 08:31:24PM +0200, Jernej Skrabec wrote:
> Expand HDMI PHY clock driver to support second clock parent.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h      |  6 +-
>  drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c     | 29 ++++++-
>  drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
>  3 files changed, 98 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> index 801a17222762..aadbe0a10b0c 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> @@ -98,7 +98,8 @@
>  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN		BIT(29)
>  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN		BIT(28)
>  #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33	BIT(27)
> -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL	BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK	BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT	26
>  #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN		BIT(25)
>  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x)	((x) << 22)
>  #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x)	((x) << 20)
> @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
>  void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
>  const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
>  
> -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
> +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
> +			 bool second_parent);
>  
>  #endif /* _SUN8I_DW_HDMI_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> index deba47ed69d8..7a911f0a3ae3 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
>  	regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
>  			   SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
>  
> -	regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
> +	/*
> +	 * NOTE: We have to be careful not to overwrite PHY parent
> +	 * clock selection bit and clock divider.
> +	 */
> +	regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> +			   ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
> +			   pll_cfg1_init);

It feels like it belongs in a separate patch.

>  	regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
>  			   (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
>  			   pll_cfg2_init);
> @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
>  			   SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
>  			   SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
>  
> +	/* reset PLL clock configuration */
> +	regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
> +	regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
> +

Ditto,

> +
> +		/*
> +		 * Even though HDMI PHY clock doesn't have enable/disable
> +		 * handlers, we have to enable it. Otherwise it could happen
> +		 * that parent PLL is not enabled by clock framework in a
> +		 * highly unlikely event when parent PLL is used solely for
> +		 * HDMI PHY clock.
> +		 */
> +		clk_prepare_enable(phy->clk_phy);

The implementation of the clock doesn't really matter in our API
usage. If we're using a clock, we have to call
clk_prepare_enable. That's documented everywhere, and mentionning how
the clock is implemented is an abstraction leakage and it's
irrelevant. I'd simply remove the comment here.

And it should be in a separate patch as well.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180521/d5f8520a/attachment.sig>

^ permalink raw reply

* [PATCH V2 2/3] clk: imx7d: correct enet clock CCGR registers
From: Stefan Agner @ 2018-05-21  8:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AM3PR04MB1315417C51882B554AEBC617F5950@AM3PR04MB1315.eurprd04.prod.outlook.com>

On 21.05.2018 04:35, Anson Huang wrote:
> Hi, Stefan
> 
> Anson Huang
> Best Regards!
> 
> 
>> -----Original Message-----
>> From: Stefan Agner [mailto:stefan at agner.ch]
>> Sent: Friday, May 18, 2018 9:02 PM
>> To: Anson Huang <anson.huang@nxp.com>
>> Cc: shawnguo at kernel.org; kernel at pengutronix.de; Fabio Estevam
>> <fabio.estevam@nxp.com>; robh+dt at kernel.org; mark.rutland at arm.com;
>> mturquette at baylibre.com; sboyd at kernel.org; Adriana Reus
>> <adriana.reus@nxp.com>; rui.silva at linaro.org; dl-linux-imx
>> <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
>> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org;
>> linux-clk at vger.kernel.org
>> Subject: Re: [PATCH V2 2/3] clk: imx7d: correct enet clock CCGR registers
>>
>> On 18.05.2018 03:01, Anson Huang wrote:
>> > Correct enet clock gates as below:
>> >
>> > CCGR6: IMX7D_ENET_AXI_ROOT_CLK (enet1 and enet2 bus clocks)
>> > CCGR112: IMX7D_ENET1_TIME_ROOT_CLK, IMX7D_ENET1_IPG_ROOT_CLK
>> > CCGR113: IMX7D_ENET2_TIME_ROOT_CLK, IMX7D_ENET2_IPG_ROOT_CLK
>> >
>> > Just rename unused IMX7D_ENETx_REF_ROOT_CLK for
>> > IMX7D_ENETx_IPG_ROOT_CLK instead of adding new clocks.
>>
>> Are you sure that IMX7D_ENETx_REF_ROOT_CLK are not used?
>>
>> I understand that the reference manual does not a gate at 0x44e0...
>>
>> But in a earlier revision of our Colibri iMX7 we actually used clock out, and
>> referenced this clock to enable the reference clock (see also:
>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatch
>> work.kernel.org%2Fpatch%2F9211371%2F&data=02%7C01%7CAnson.Huang%
>> 40nxp.com%7Cea0856a68d8e4b921ba608d5bcbf9c02%7C686ea1d3bc2b4c6fa
>> 92cd99c5c301635%7C0%7C1%7C636622453508888330&sdata=rEhwj0innLDc
>> AEgxJyqd5vtG3SNVS05r2hEFvSc%2BQQs%3D&reserved=0).
>>
>> I guess if the gate really does not exist, then we should/would have to set
>> IMX7D_ENET1_REF_ROOT_DIV to use the SoC provided ref clock.
>>
>> --
>> Stefan
>  
> I looked into the RTL and also checked with our design team, they confirm that
> there is no CCGR78(0x44e0) and CCGR80(0x4500) on i.MX7D, the register offset
> are there, but no hardware wire connection for them. That is why they did NOT
> list them in Reference Manual. So I think we can remove them. 
> 
> For your case of using them as clock input, maybe clock tree auto use its parent
> IMX7D_ENETx_REF_ROOT_DIV which is existing, so it works.

That make sense.

The change looks good to me.

Reviewed-by: Stefan Agner <stefan@agner.ch>

--
Stefan

> 
> Anson.
> 
>>
>> >
>> > Based on Andy Duan's patch from the NXP kernel tree.
>> >
>> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
>> > ---
>> >  drivers/clk/imx/clk-imx7d.c             | 10 ++++++----
>> >  include/dt-bindings/clock/imx7d-clock.h |  4 ++--
>> >  2 files changed, 8 insertions(+), 6 deletions(-)
>> >
>> > diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
>> > index 23d5090a..d4936b9 100644
>> > --- a/drivers/clk/imx/clk-imx7d.c
>> > +++ b/drivers/clk/imx/clk-imx7d.c
>> > @@ -26,6 +26,8 @@ static u32 share_count_sai1;  static u32
>> > share_count_sai2;  static u32 share_count_sai3;  static u32
>> > share_count_nand;
>> > +static u32 share_count_enet1;
>> > +static u32 share_count_enet2;
>> >
>> >  static const struct clk_div_table test_div_table[] = {
>> >  	{ .val = 3, .div = 1, },
>> > @@ -805,6 +807,10 @@ static void __init imx7d_clocks_init(struct
>> > device_node *ccm_node)
>> >  	clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk",
>> > "mipi_dsi_post_div", base + 0x4650, 0);
>> >  	clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk",
>> > "mipi_csi_post_div", base + 0x4640, 0);
>> >  	clks[IMX7D_MIPI_DPHY_ROOT_CLK] =
>> imx_clk_gate4("mipi_dphy_root_clk",
>> > "mipi_dphy_post_div", base + 0x4660, 0);
>> > +	clks[IMX7D_ENET1_IPG_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base
>> > + 0x4700, 0, &share_count_enet1);
>> > +	clks[IMX7D_ENET1_TIME_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div",
>> > base + 0x4700, 0, &share_count_enet1);
>> > +	clks[IMX7D_ENET2_IPG_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base
>> > + 0x4710, 0, &share_count_enet2);
>> > +	clks[IMX7D_ENET2_TIME_ROOT_CLK] =
>> > imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div",
>> > base + 0x4710, 0, &share_count_enet2);
>> >  	clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk",
>> > "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
>> >  	clks[IMX7D_SAI1_IPG_CLK]  = imx_clk_gate2_shared2("sai1_ipg_clk",
>> > "ipg_root_clk",  base + 0x48c0, 0, &share_count_sai1);
>> >  	clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk",
>> > "sai2_post_div", base + 0x48d0, 0, &share_count_sai2); @@ -812,10
>> > +818,6 @@ static void __init imx7d_clocks_init(struct device_node
>> > *ccm_node)
>> >  	clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk",
>> > "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
>> >  	clks[IMX7D_SAI3_IPG_CLK]  = imx_clk_gate2_shared2("sai3_ipg_clk",
>> > "ipg_root_clk",  base + 0x48e0, 0, &share_count_sai3);
>> >  	clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk",
>> > "spdif_post_div", base + 0x44d0, 0);
>> > -	clks[IMX7D_ENET1_REF_ROOT_CLK] =
>> imx_clk_gate4("enet1_ref_root_clk",
>> > "enet1_ref_post_div", base + 0x44e0, 0);
>> > -	clks[IMX7D_ENET1_TIME_ROOT_CLK] =
>> > imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base +
>> > 0x44f0, 0);
>> > -	clks[IMX7D_ENET2_REF_ROOT_CLK] =
>> imx_clk_gate4("enet2_ref_root_clk",
>> > "enet2_ref_post_div", base + 0x4500, 0);
>> > -	clks[IMX7D_ENET2_TIME_ROOT_CLK] =
>> > imx_clk_gate4("enet2_time_root_clk", "enet2_time_post_div", base +
>> > 0x4510, 0);
>> >  	clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk",
>> > "eim_post_div", base + 0x4160, 0);
>> >  	clks[IMX7D_NAND_RAWNAND_CLK] =
>> > imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base +
>> > 0x4140, 0, &share_count_nand);
>> >  	clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] =
>> > imx_clk_gate2_shared2("nand_usdhc_rawnand_clk",
>> "nand_usdhc_root_clk",
>> > base + 0x4140, 0, &share_count_nand); diff --git
>> > a/include/dt-bindings/clock/imx7d-clock.h
>> > b/include/dt-bindings/clock/imx7d-clock.h
>> > index b2325d3e2..0d67f53 100644
>> > --- a/include/dt-bindings/clock/imx7d-clock.h
>> > +++ b/include/dt-bindings/clock/imx7d-clock.h
>> > @@ -168,7 +168,7 @@
>> >  #define IMX7D_SPDIF_ROOT_SRC		155
>> >  #define IMX7D_SPDIF_ROOT_CG		156
>> >  #define IMX7D_SPDIF_ROOT_DIV		157
>> > -#define IMX7D_ENET1_REF_ROOT_CLK	158
>> > +#define IMX7D_ENET1_IPG_ROOT_CLK        158
>> >  #define IMX7D_ENET1_REF_ROOT_SRC	159
>> >  #define IMX7D_ENET1_REF_ROOT_CG		160
>> >  #define IMX7D_ENET1_REF_ROOT_DIV	161
>> > @@ -176,7 +176,7 @@
>> >  #define IMX7D_ENET1_TIME_ROOT_SRC	163
>> >  #define IMX7D_ENET1_TIME_ROOT_CG	164
>> >  #define IMX7D_ENET1_TIME_ROOT_DIV	165
>> > -#define IMX7D_ENET2_REF_ROOT_CLK	166
>> > +#define IMX7D_ENET2_IPG_ROOT_CLK        166
>> >  #define IMX7D_ENET2_REF_ROOT_SRC	167
>> >  #define IMX7D_ENET2_REF_ROOT_CG		168
>> >  #define IMX7D_ENET2_REF_ROOT_DIV	169

^ permalink raw reply

* [RFT v2 0/4] Perf script: Add python script for CoreSight trace disassembler
From: Leo Yan @ 2018-05-21  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series is to support for using 'perf script' for CoreSight
trace disassembler, for this purpose this patch series adds a new
python script to parse CoreSight tracing event and use command 'objdump'
for disassembled lines, finally this can generate readable program
execution flow for reviewing tracing data.

Patch 0001 is one fixing patch to generate samples for the start packet
and exception packets.

Patch 0002 is the prerequisite to add addr into sample dict, so this
value can be used by python script to analyze instruction range.

Patch 0003 is to add python script for trace disassembler.

Patch 0004 is to add doc to explain python script usage and give
example for it.

This patch series has been rebased on acme git tree [1] with the last
commit 19422a9f2a3b ("perf tools: Fix kernel_start for PTI on x86") and
tested on Hikey (ARM64 octa CA53 cores).

In this version the script has no dependency on ARM64 platform and is
expected to support ARM32 platform, but I am lacking ARM32 platform for
testing on it, so firstly upstream to support ARM64 platform.

This patch series is firstly to support 'per-thread' recording tracing
data, but we also need to verify the script can dump trace disassembler
CPU wide tracing and kernel panic kdump tracing data.  I also verified
this patch series which can work with kernel panic kdump tracing data,
because Mathieu is working on CPU wide tracing related work, so after
this we need to retest for CPU wide tracing and kdump tracing to ensure
the python script can handle well for all cases.

You are very welcome to test the script in this patch series, your
testing result and suggestion are very valuable to perfect this script
to cover more cases.

Changes from v1:
* According to Mike and Rob suggestion, add the fixing to generate samples
  for the start packet and exception packets.
* Simplify the python script to remove the exception prediction algorithm,
  we can rely on the sane exception packets for disassembler.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git


Leo Yan (4):
  perf cs-etm: Generate sample for missed packets
  perf script python: Add addr into perf sample dict
  perf script python: Add script for CoreSight trace disassembler
  coresight: Document for CoreSight trace disassembler

 Documentation/trace/coresight.txt                  |  52 +++++
 tools/perf/scripts/python/arm-cs-trace-disasm.py   | 234 +++++++++++++++++++++
 tools/perf/util/cs-etm.c                           |  35 ++-
 .../util/scripting-engines/trace-event-python.c    |   2 +
 4 files changed, 316 insertions(+), 7 deletions(-)
 create mode 100644 tools/perf/scripts/python/arm-cs-trace-disasm.py

-- 
2.7.4

^ permalink raw reply

* [RFT v2 1/4] perf cs-etm: Generate sample for missed packets
From: Leo Yan @ 2018-05-21  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526892748-326-1-git-send-email-leo.yan@linaro.org>

Commit e573e978fb12 ("perf cs-etm: Inject capabilitity for CoreSight
traces") reworks the samples generation flow from CoreSight trace to
match the correct format so Perf report tool can display the samples
properly.  But the change has side effect for packet handling, it only
generate samples when 'prev_packet->last_instr_taken_branch' is true,
this results in the start tracing packet and exception packets are
dropped.

This patch checks extra two conditions for complete samples:

- If 'prev_packet->sample_type' is zero we can use this condition to
  get to know this is the start tracing packet; for this case, the start
  packet's end_addr is zero as well so we need to handle it in the
  function cs_etm__last_executed_instr();

- If 'prev_packet->exc' is true, we can know the previous packet is
  exception handling packet so need to generate sample for exception
  flow.

Fixes: e573e978fb12 ("perf cs-etm: Inject capabilitity for CoreSight traces")
Cc: Mike Leach <mike.leach@arm.com>
Cc: Robert Walker <robert.walker@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm.c | 35 ++++++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 822ba91..378953b 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -495,6 +495,13 @@ static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq)
 static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet)
 {
 	/*
+	 * The packet is the start tracing packet if the end_addr is zero,
+	 * returns 0 for this case.
+	 */
+	if (!packet->end_addr)
+		return 0;
+
+	/*
 	 * The packet records the execution range with an exclusive end address
 	 *
 	 * A64 instructions are constant size, so the last executed
@@ -897,13 +904,27 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
 		etmq->period_instructions = instrs_over;
 	}
 
-	if (etm->sample_branches &&
-	    etmq->prev_packet &&
-	    etmq->prev_packet->sample_type == CS_ETM_RANGE &&
-	    etmq->prev_packet->last_instr_taken_branch) {
-		ret = cs_etm__synth_branch_sample(etmq);
-		if (ret)
-			return ret;
+	if (etm->sample_branches && etmq->prev_packet) {
+		bool generate_sample = false;
+
+		/* Generate sample for start tracing packet */
+		if (etmq->prev_packet->sample_type == 0)
+			generate_sample = true;
+
+		/* Generate sample for exception packet */
+		if (etmq->prev_packet->exc == true)
+			generate_sample = true;
+
+		/* Generate sample for normal branch packet */
+		if (etmq->prev_packet->sample_type == CS_ETM_RANGE &&
+		    etmq->prev_packet->last_instr_taken_branch)
+			generate_sample = true;
+
+		if (generate_sample) {
+			ret = cs_etm__synth_branch_sample(etmq);
+			if (ret)
+				return ret;
+		}
 	}
 
 	if (etm->sample_branches || etm->synth_opts.last_branch) {
-- 
2.7.4

^ permalink raw reply related

* [RFT v2 2/4] perf script python: Add addr into perf sample dict
From: Leo Yan @ 2018-05-21  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526892748-326-1-git-send-email-leo.yan@linaro.org>

ARM CoreSight auxtrace uses 'sample->addr' to record the target address
for branch instructions, so the data of 'sample->addr' is required for
tracing data analysis.

This commit collects data of 'sample->addr' into perf sample dict,
finally can be used for python script for parsing event.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/scripting-engines/trace-event-python.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 10dd5fc..7f8afac 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -531,6 +531,8 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample,
 			PyLong_FromUnsignedLongLong(sample->period));
 	pydict_set_item_string_decref(dict_sample, "phys_addr",
 			PyLong_FromUnsignedLongLong(sample->phys_addr));
+	pydict_set_item_string_decref(dict_sample, "addr",
+			PyLong_FromUnsignedLongLong(sample->addr));
 	set_sample_read_in_dict(dict_sample, sample, evsel);
 	pydict_set_item_string_decref(dict, "sample", dict_sample);
 
-- 
2.7.4

^ permalink raw reply related

* [RFT v2 3/4] perf script python: Add script for CoreSight trace disassembler
From: Leo Yan @ 2018-05-21  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526892748-326-1-git-send-email-leo.yan@linaro.org>

This commit adds python script to parse CoreSight tracing event and
use command 'objdump' for disassembled lines, finally we can generate
readable program execution flow for reviewing tracing data.

The script receives CoreSight tracing packet with below format:

                +------------+------------+------------+
  packet(n):    |    addr    |    ip      |    cpu     |
                +------------+------------+------------+
  packet(n+1):  |    addr    |    ip      |    cpu     |
                +------------+------------+------------+

packet::ip is the last address of current branch instruction and
packet::addr presents the start address of the next coming branch
instruction.  So for one branch instruction which starts in packet(n),
its execution flow starts from packet(n)::addr and it stops at
packet(n+1)::ip.  As results we need to combine the two continuous
packets to generate the instruction range, this is the rationale for the
script implementation:

  [ sample(n)::addr .. sample(n+1)::ip ]

Credits to Tor Jeremiassen who have written the script skeleton and
provides the ideas for reading symbol file according to build-id,
creating memory map for dso and basic packet handling.  Mathieu Poirier
contributed fixes for build-id and memory map bugs.  The detailed
development history for this script you can find from [1].  Based on Tor
and Mathieu work, the script is updated samples handling for the
corrected sample format.  Another minor enhancement is to support for
without build-id case, the script can parse kernel symbols with option
'-k' for vmlinux file path.

[1] https://github.com/Linaro/perf-opencsd/commits/perf-opencsd-v4.15/tools/perf/scripts/python/cs-trace-disasm.py

Co-authored-by: Tor Jeremiassen <tor@ti.com>
Co-authored-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/scripts/python/arm-cs-trace-disasm.py | 234 +++++++++++++++++++++++
 1 file changed, 234 insertions(+)
 create mode 100644 tools/perf/scripts/python/arm-cs-trace-disasm.py

diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py
new file mode 100644
index 0000000..58de36f
--- /dev/null
+++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py
@@ -0,0 +1,234 @@
+# arm-cs-trace-disasm.py: ARM CoreSight Trace Dump With Disassember
+# SPDX-License-Identifier: GPL-2.0
+#
+# Tor Jeremiassen <tor@ti.com> is original author who wrote script
+# skeleton, Mathieu Poirier <mathieu.poirier@linaro.org> contributed
+# fixes for build-id and memory map; Leo Yan <leo.yan@linaro.org>
+# updated the packet parsing with new samples format.
+
+import os
+import sys
+import re
+from subprocess import *
+from optparse import OptionParser, make_option
+
+# Command line parsing
+
+option_list = [
+	# formatting options for the bottom entry of the stack
+	make_option("-k", "--vmlinux", dest="vmlinux_name",
+		    help="Set path to vmlinux file"),
+	make_option("-d", "--objdump", dest="objdump_name",
+		    help="Set path to objdump executable file"),
+	make_option("-v", "--verbose", dest="verbose",
+		    action="store_true", default=False,
+		    help="Enable debugging log")
+]
+
+parser = OptionParser(option_list=option_list)
+(options, args) = parser.parse_args()
+
+if (options.objdump_name == None):
+	sys.exit("No objdump executable file specified - use -d or --objdump option")
+
+# Initialize global dicts and regular expression
+
+build_ids = dict()
+mmaps = dict()
+disasm_cache = dict()
+cpu_data = dict()
+disasm_re = re.compile("^\s*([0-9a-fA-F]+):")
+disasm_func_re = re.compile("^\s*([0-9a-fA-F]+)\s\<.*\>:")
+cache_size = 32*1024
+prev_cpu = -1
+
+def parse_buildid():
+	global build_ids
+
+	buildid_regex = "([a-fA-f0-9]+)[ \t]([^ \n]+)"
+	buildid_re = re.compile(buildid_regex)
+
+	results = check_output(["perf", "buildid-list"]).split('\n');
+	for line in results:
+		m = buildid_re.search(line)
+		if (m == None):
+			continue;
+
+		id_name = m.group(2)
+		id_num  = m.group(1)
+
+		if (id_name == "[kernel.kallsyms]") :
+			append = "/kallsyms"
+		elif (id_name == "[vdso]") :
+			append = "/vdso"
+		else:
+			append = "/elf"
+
+		build_ids[id_name] = os.environ['PERF_BUILDID_DIR'] + \
+					"/" + id_name + "/" + id_num + append;
+		# Replace duplicate slash chars to single slash char
+		build_ids[id_name] = build_ids[id_name].replace('//', '/', 1)
+
+	if ((options.vmlinux_name == None) and ("[kernel.kallsyms]" in build_ids)):
+		print "kallsyms cannot be used to dump assembler"
+
+	# Set vmlinux path to replace kallsyms file, if without buildid we still
+	# can use vmlinux to prase kernel symbols
+	if ((options.vmlinux_name != None)):
+		build_ids['[kernel.kallsyms]'] = options.vmlinux_name;
+
+def parse_mmap():
+	global mmaps
+
+	# Check mmap for PERF_RECORD_MMAP and PERF_RECORD_MMAP2
+	mmap_regex = "PERF_RECORD_MMAP.* -?[0-9]+/[0-9]+: \[(0x[0-9a-fA-F]+)\((0x[0-9a-fA-F]+)\).*:\s.*\s(\S*)"
+	mmap_re = re.compile(mmap_regex)
+
+	results = check_output("perf script --show-mmap-events | fgrep PERF_RECORD_MMAP", shell=True).split('\n')
+	for line in results:
+		m = mmap_re.search(line)
+		if (m != None):
+			if (m.group(3) == '[kernel.kallsyms]_text'):
+				dso = '[kernel.kallsyms]'
+			else:
+				dso = m.group(3)
+
+			start = int(m.group(1),0)
+			end   = int(m.group(1),0) + int(m.group(2),0)
+			mmaps[dso] = [start, end]
+
+def find_dso_mmap(addr):
+	global mmaps
+
+	for key, value in mmaps.items():
+		if (addr >= value[0] and addr < value[1]):
+			return key
+
+	return None
+
+def read_disam(dso, start_addr, stop_addr):
+	global mmaps
+	global build_ids
+
+	addr_range = start_addr  + ":" + stop_addr;
+
+	# Don't let the cache get too big, clear it when it hits max size
+	if (len(disasm_cache) > cache_size):
+		disasm_cache.clear();
+
+	try:
+		disasm_output = disasm_cache[addr_range];
+	except:
+		try:
+			fname = build_ids[dso];
+		except KeyError:
+			sys.exit("cannot find symbol file for " + dso)
+
+		disasm = [ options.objdump_name, "-d", "-z",
+			   "--start-address="+start_addr,
+			   "--stop-address="+stop_addr, fname ]
+
+		disasm_output = check_output(disasm).split('\n')
+		disasm_cache[addr_range] = disasm_output;
+
+	return disasm_output
+
+def dump_disam(dso, start_addr, stop_addr, check_svc):
+	for line in read_disam(dso, start_addr, stop_addr):
+		m = disasm_func_re.search(line)
+		if (m != None):
+			print "\t",line
+			continue
+
+		m = disasm_re.search(line)
+		if (m == None):
+			continue;
+
+		print "\t",line
+
+		if ((check_svc == True) and "svc" in line):
+			return
+
+def dump_packet(sample):
+	print "Packet = { cpu: 0x%d addr: 0x%x phys_addr: 0x%x ip: 0x%x " \
+	      "pid: %d tid: %d period: %d time: %d }" % \
+	      (sample['cpu'], sample['addr'], sample['phys_addr'], \
+	       sample['ip'], sample['pid'], sample['tid'], \
+	       sample['period'], sample['time'])
+
+def trace_begin():
+	print 'ARM CoreSight Trace Data Assembler Dump'
+	parse_buildid()
+	parse_mmap()
+
+def trace_end():
+	print 'End'
+
+def trace_unhandled(event_name, context, event_fields_dict):
+	print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
+
+def process_event(param_dict):
+	global cache_size
+	global options
+	global prev_cpu
+
+	sample = param_dict["sample"]
+
+	if (options.verbose == True):
+		dump_packet(sample)
+
+	# If period doesn't equal to 1, this packet is for instruction sample
+	# packet, we need drop this synthetic packet.
+	if (sample['period'] != 1):
+		print "Skip synthetic instruction sample"
+		return
+
+	cpu = format(sample['cpu'], "d");
+
+	# Initialize CPU data if it's empty, and directly return back
+	# if this is the first tracing event for this CPU.
+	if (cpu_data.get(str(cpu) + 'addr') == None):
+		cpu_data[str(cpu) + 'addr'] = format(sample['addr'], "#x")
+		prev_cpu = cpu
+		return
+
+	# The format for packet is:
+	#
+	#                 +------------+------------+------------+
+	#  sample_prev:   |    addr    |    ip      |    cpu     |
+	#                 +------------+------------+------------+
+	#  sample_next:   |    addr    |    ip      |    cpu     |
+	#                 +------------+------------+------------+
+	#
+	# We need to combine the two continuous packets to get the instruction
+	# range for sample_prev::cpu:
+	#
+	#     [ sample_prev::addr .. sample_next::ip ]
+	#
+	# For this purose, sample_prev::addr is stored into cpu_data structure
+	# and read back for 'start_addr' when the new packet comes, and we need
+	# to use sample_next::ip to calculate 'stop_addr', plusing extra 4 for
+	# 'stop_addr' is for the sake of objdump so the final assembler dump can
+	# include last instruction for sample_next::ip.
+
+	start_addr = cpu_data[str(prev_cpu) + 'addr']
+	stop_addr  = format(sample['ip'] + 4, "#x")
+
+	# Sanity checking dso for start_addr and stop_addr
+	prev_dso = find_dso_mmap(int(start_addr, 0))
+	next_dso = find_dso_mmap(int(stop_addr, 0))
+
+	# If cannot find dso so cannot dump assembler, bail out
+	if (prev_dso == None or next_dso == None):
+		print "Address range [ %s .. %s ]: failed to find dso" % (start_addr, stop_addr)
+		prev_cpu = cpu
+		return
+	elif (prev_dso != next_dso):
+		print "Address range [ %s .. %s ]: isn't in same dso" % (start_addr, stop_addr)
+		prev_cpu = cpu
+		return
+
+	dump_disam(prev_dso, start_addr, stop_addr, False)
+
+	cpu_data[str(cpu) + 'addr'] = format(sample['addr'], "#x")
+	prev_cpu = cpu
-- 
2.7.4

^ permalink raw reply related

* [RFT v2 4/4] coresight: Document for CoreSight trace disassembler
From: Leo Yan @ 2018-05-21  8:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526892748-326-1-git-send-email-leo.yan@linaro.org>

This commit documents CoreSight trace disassembler usage and gives
example for it.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 Documentation/trace/coresight.txt | 52 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt
index 6f0120c..b8f2359 100644
--- a/Documentation/trace/coresight.txt
+++ b/Documentation/trace/coresight.txt
@@ -381,3 +381,55 @@ sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tuto
 	$ taskset -c 2 ./sort_autofdo
 	Bubble sorting array of 30000 elements
 	5806 ms
+
+
+Tracing data disassembler
+-------------------------
+
+'perf script' supports to use script to parse tracing packet and rely on
+'objdump' for disassembled lines, this can convert tracing data to readable
+program execution flow for easily reviewing tracing data.
+
+The CoreSight trace disassembler is located in the folder:
+tools/perf/scripts/python/arm-cs-trace-disasm.py.  This script support below
+options:
+
+	-d, --objdump: Set path to objdump executable, this option is
+		       mandatory.
+	-k, --vmlinux: Set path to vmlinux file.
+	-v, --verbose: Enable debugging log, after enable this option the
+		       script dumps every event data.
+
+Below is one example for using python script to dump CoreSight trace
+disassembler:
+
+	$ perf script -s arm-cs-trace-disasm.py -i perf.data \
+	    -F cpu,event,ip,addr,sym -- -d objdump -k ./vmlinux > cs-disasm.log
+
+Below is one example for the disassembler log:
+
+ARM CoreSight Trace Data Assembler Dump
+	ffff000008a5f2dc <etm4_enable_hw+0x344>:
+	ffff000008a5f2dc:	340000a0 	cbz	w0, ffff000008a5f2f0 <etm4_enable_hw+0x358>
+	ffff000008a5f2f0 <etm4_enable_hw+0x358>:
+	ffff000008a5f2f0:	f9400260 	ldr	x0, [x19]
+	ffff000008a5f2f4:	d5033f9f 	dsb	sy
+	ffff000008a5f2f8:	913ec000 	add	x0, x0, #0xfb0
+	ffff000008a5f2fc:	b900001f 	str	wzr, [x0]
+	ffff000008a5f300:	f9400bf3 	ldr	x19, [sp, #16]
+	ffff000008a5f304:	a8c27bfd 	ldp	x29, x30, [sp], #32
+	ffff000008a5f308:	d65f03c0 	ret
+	ffff000008a5fa18 <etm4_enable+0x1b0>:
+	ffff000008a5fa18:	14000025 	b	ffff000008a5faac <etm4_enable+0x244>
+	ffff000008a5faac <etm4_enable+0x244>:
+	ffff000008a5faac:	b9406261 	ldr	w1, [x19, #96]
+	ffff000008a5fab0:	52800015 	mov	w21, #0x0                   	// #0
+	ffff000008a5fab4:	f901ca61 	str	x1, [x19, #912]
+	ffff000008a5fab8:	2a1503e0 	mov	w0, w21
+	ffff000008a5fabc:	3940e261 	ldrb	w1, [x19, #56]
+	ffff000008a5fac0:	f901ce61 	str	x1, [x19, #920]
+	ffff000008a5fac4:	a94153f3 	ldp	x19, x20, [sp, #16]
+	ffff000008a5fac8:	a9425bf5 	ldp	x21, x22, [sp, #32]
+	ffff000008a5facc:	a94363f7 	ldp	x23, x24, [sp, #48]
+	ffff000008a5fad0:	a8c47bfd 	ldp	x29, x30, [sp], #64
+	ffff000008a5fad4:	d65f03c0 	ret
-- 
2.7.4

^ permalink raw reply related

* [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
From: ilialin at codeaurora.org @ 2018-05-21  9:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180521044938.bnr2sdkmvdorfxqm@vireshk-i7>

Final version (addressing Russel's comment as well):




// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 */

/*
 * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
 * the CPU frequency subset and voltage value of each OPP varies
 * based on the silicon variant in use. Qualcomm Process Voltage Scaling
Tables
 * defines the voltage and frequency value based on the msm-id in SMEM
 * and speedbin blown in the efuse combination.
 * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the
SoC
 * to provide the OPP framework with required information.
 * This is used to determine the voltage and frequency value for each OPP of
 * operating-points-v2 table when it is parsed by the OPP framework.
 */

#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>

#define MSM_ID_SMEM	137
#define SILVER_LEAD	0
#define GOLD_LEAD	2

enum _msm_id {
	MSM8996V3 = 0xF6ul,
	APQ8096V3 = 0x123ul,
	MSM8996SG = 0x131ul,
	APQ8096SG = 0x138ul,
};

enum _msm8996_version {
	MSM8996_V3,
	MSM8996_SG,
	NUM_OF_MSM8996_VERSIONS,
};

static enum _msm8996_version __init qcom_cpufreq_kryo_get_msm_id(void)
{
	size_t len;
	u32 *msm_id;
	enum _msm8996_version version;

	msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
	/* The first 4 bytes are format, next to them is the actual msm-id
*/
	msm_id++;

	switch ((enum _msm_id)*msm_id) {
	case MSM8996V3:
	case APQ8096V3:
		version = MSM8996_V3;
		break;
	case MSM8996SG:
	case APQ8096SG:
		version = MSM8996_SG;
		break;
	default:
		version = NUM_OF_MSM8996_VERSIONS;
	}

	return version;
}

static int __init qcom_cpufreq_kryo_driver_init(void)
{
	struct device *cpu_dev_silver, *cpu_dev_gold;
	struct opp_table *opp_silver, *opp_gold;
	enum _msm8996_version msm8996_version;
	struct nvmem_cell *speedbin_nvmem;
	struct platform_device *pdev;
	struct device_node *np;
	u8 *speedbin;
	u32 versions;
	size_t len;
	int ret;

	cpu_dev_silver = get_cpu_device(SILVER_LEAD);
	if (NULL == cpu_dev_silver)
		return -ENODEV;

	cpu_dev_gold = get_cpu_device(SILVER_LEAD);
	if (NULL == cpu_dev_gold)
		return -ENODEV;

	msm8996_version = qcom_cpufreq_kryo_get_msm_id();
	if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
		dev_err(cpu_dev_silver, "Not Snapdragon 820/821!");
		return -ENODEV;
	}

	np = dev_pm_opp_of_get_opp_desc_node(cpu_dev_silver);
	if (IS_ERR(np))
		return PTR_ERR(np);

	if (!of_device_is_compatible(np, "operating-points-v2-kryo-cpu")) {
		ret = -ENOENT;
		goto free_np;
	}

	speedbin_nvmem = of_nvmem_cell_get(np, NULL);
	if (IS_ERR(speedbin_nvmem)) {
		ret = PTR_ERR(speedbin_nvmem);
		dev_err(cpu_dev_silver, "Could not get nvmem cell: %d\n",
ret);
		goto free_np;
	}

	speedbin = nvmem_cell_read(speedbin_nvmem, &len);
	nvmem_cell_put(speedbin_nvmem);

	switch (msm8996_version) {
	case MSM8996_V3:
		versions = 1 << (unsigned int)(*speedbin);
		break;
	case MSM8996_SG:
		versions = 1 << ((unsigned int)(*speedbin) + 4);
		break;
	default:
		BUG();
		break;
	}

	opp_silver =
dev_pm_opp_set_supported_hw(cpu_dev_silver,&versions,1);
	if (IS_ERR(opp_silver)) {
		dev_err(cpu_dev_silver, "Failed to set supported
hardware\n");
		ret = PTR_ERR(opp_silver);
		goto free_np;
	}

	opp_gold = dev_pm_opp_set_supported_hw(cpu_dev_gold,&versions,1);
	if (IS_ERR(opp_gold)) {
		dev_err(cpu_dev_gold, "Failed to set supported hardware\n");
		ret = PTR_ERR(opp_gold);
		goto free_opp_silver;
	}

	pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
	if (!IS_ERR(pdev))
		return 0;

	ret = PTR_ERR(pdev);
	dev_err(cpu_dev_silver, "Failed to register platform device\n");
	dev_pm_opp_put_supported_hw(opp_gold);

free_opp_silver:
	dev_pm_opp_put_supported_hw(opp_silver);

free_np:
	of_node_put(np);

	return ret;
}
late_initcall(qcom_cpufreq_kryo_driver_init);

MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
MODULE_LICENSE("GPL v2");






> -----Original Message-----
> From: Viresh Kumar <viresh.kumar@linaro.org>
> Sent: Monday, May 21, 2018 07:50
> To: ilialin at codeaurora.org
> Cc: mturquette at baylibre.com; sboyd at kernel.org; robh at kernel.org;
> mark.rutland at arm.com; nm at ti.com; lgirdwood at gmail.com;
> broonie at kernel.org; andy.gross at linaro.org; david.brown at linaro.org;
> catalin.marinas at arm.com; will.deacon at arm.com; rjw at rjwysocki.net; linux-
> clk at vger.kernel.org; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-pm at vger.kernel.org; linux-arm-
> msm at vger.kernel.org; linux-soc at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org; rnayak at codeaurora.org;
> amit.kucheria at linaro.org; nicolas.dechesne at linaro.org;
> celster at codeaurora.org; tfinkel at codeaurora.org
> Subject: Re: [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
> 
> On 19-05-18, 14:45, ilialin at codeaurora.org wrote:
> > Hi Viresh,
> >
> > If I send patches in reply, it will produce new patches, instead of
> > answers in the thread. Please find below the file dump.
> 
> There is one email from you which appears to be just fine and appears to
be
> in reply to this thread only. Maybe its your email client that screwed it
up for
> you ? Things look good in mutt.
> 
> --
> viresh

^ permalink raw reply

* [PATCH v8 10/15] cpufreq: Add Kryo CPU scaling driver
From: Viresh Kumar @ 2018-05-21  9:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <000501d3f0e2$23500c00$69f02400$@codeaurora.org>

On 21-05-18, 12:00, ilialin at codeaurora.org wrote:
> Final version (addressing Russel's comment as well):

Sorry, can't review it like this. At least you should be posting your
diff here and you also need to do that from a sane email client like
mutt, which wouldn't auto-fix/update the code. Doing it from gmail or
thunderbird will ofcourse screw it.

Or a simple way is to send the patch again (alone) using in-reply-to
field.

-- 
viresh

^ permalink raw reply

* [PATCH v9 02/12] drivers: base: cacheinfo: setup DT cache properties early
From: Sudeep Holla @ 2018-05-21  9:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAHp75VfEYcPdECmDDOd8CLBBXGpcwSUGQRr0x8VTb1-7j51_0Q@mail.gmail.com>



On 18/05/18 22:50, Andy Shevchenko wrote:
> On Thu, May 17, 2018 at 6:47 PM, Sudeep Holla <sudeep.holla@arm.com> wrote:
> 
>> Is below patch does what you were looking for ?
> 
> Somewhat.
> See below for some minors.
> 

Thanks

>> of_property_read_u64 searches for a property in a device node and read
>> a 64-bit value from it. Instead of using of_get_property to get the
>> property and then read 64-bit value using of_read_number, we can make
>> use of of_property_read_u64.
> 
> Suggested-by?
>

Yes indeed, added it locally after I sent out this patch. Will send out
a proper patch soon.

>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> 
> 
>> -       cache_size = of_get_property(np, propname, NULL);
>> -       if (cache_size)
>> -               this_leaf->size = of_read_number(cache_size, 1);
>> +       if (!of_property_read_u64(np, propname, &cache_size))
>> +               this_leaf->size = cache_size;
> 
> I suppose it's something like this
> 
> ret = of_property_...(..., &this_leaf->VAR);
> if (ret)
>  warning / set default / etc

OK, I do prefer this but once I was told not to use structure elements
directly like that, but should be harmless in this particular case, will
do so.

-- 
Regards,
Sudeep

^ permalink raw reply

* [PATCH v9 06/11] arm64: kexec_file: allow for loading Image-format kernel
From: AKASHI Takahiro @ 2018-05-21  9:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4a8409dc-27b3-1ddc-0427-0ca55edcb893@arm.com>

James,

I haven't commented on this email.

On Tue, May 15, 2018 at 06:14:37PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 15/05/18 06:13, AKASHI Takahiro wrote:
> > On Fri, May 11, 2018 at 06:07:06PM +0100, James Morse wrote:
> >> On 07/05/18 08:21, AKASHI Takahiro wrote:
> >>> On Tue, May 01, 2018 at 06:46:11PM +0100, James Morse wrote:
> >>>> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>>>> This patch provides kexec_file_ops for "Image"-format kernel. In this
> >>>>> implementation, a binary is always loaded with a fixed offset identified
> >>>>> in text_offset field of its header.
> >>
> >>>>> diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
> >>>>> index e4de1223715f..3cba4161818a 100644
> >>>>> --- a/arch/arm64/include/asm/kexec.h
> >>>>> +++ b/arch/arm64/include/asm/kexec.h
> 
> >>>> Could we check branch_code is non-zero, and text-offset points within image-size?
> >>>
> >>> We could do it, but I don't think this check is very useful.
> >>>
> >>>>
> >>>> We could check that this platform supports the page-size/endian config that this
> >>>> Image was built with... We get a message from the EFI stub if the page-size
> >>>> can't be supported, it would be nice to do the same here (as we can).
> >>>
> >>> There is no restriction on page-size or endianness for kexec.
> >>
> >> No, but it won't boot if the hardware doesn't support it. The kernel will spin
> >> at a magic address that is, difficult, to debug without JTAG. The bug report
> >> will be "it didn't boot".
> > 
> > OK.
> > Added sanity checks for cpu features, endianness as well as page size.
> > 
> >>
> >>> What will be the purpose of this check?
> >>
> >> These values are in the header so that the bootloader can check them, then print
> >> a meaningful error. Here, kexec_file_load() is playing the part of the bootloader.
> 
> >> I'm assuming kexec_file_load() can only be used to kexec linux... unlike regular
> >> kexec. Is this where I'm going wrong?
> 
> Trying to work this out for myself: we can't support any UEFI application as we
> can't give it the boot-services environment, so I'm pretty sure
> kexec_file_load() must be linux-specific.
> 
> Can we state somewhere that we only expect arm64 linux to be booted with
> kexec_file_load()? Its not clear from the kconfig text, which refers to kexec,
> which explicitly states it can boot other OS. But for kexec_file_load() we're
> following the kernel's booting.txt.

While I don't know anything about requirements in booting other OS's nor
if we can boot them even with kexec, I agree that kexec_file_load is a more
limited form of booting mechanism. I will add some statement in Kconfig.

> >>>>> diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
> >>>>> new file mode 100644
> >>>>> index 000000000000..4dd524ad6611
> >>>>> --- /dev/null
> >>>>> +++ b/arch/arm64/kernel/kexec_image.c
> >>>>> @@ -0,0 +1,79 @@
> >>>>
> >>>>> +static void *image_load(struct kimage *image,
> >>>>> +				char *kernel, unsigned long kernel_len,
> >>>>> +				char *initrd, unsigned long initrd_len,
> >>>>> +				char *cmdline, unsigned long cmdline_len)
> >>>>> +{
> >>>>> +	struct kexec_buf kbuf;
> >>>>> +	struct arm64_image_header *h = (struct arm64_image_header *)kernel;
> >>>>> +	unsigned long text_offset;
> >>>>> +	int ret;
> >>>>> +
> >>>>> +	/* Load the kernel */
> >>>>> +	kbuf.image = image;
> >>>>> +	kbuf.buf_min = 0;
> >>>>> +	kbuf.buf_max = ULONG_MAX;
> >>>>> +	kbuf.top_down = false;
> >>>>> +
> >>>>> +	kbuf.buffer = kernel;
> >>>>> +	kbuf.bufsz = kernel_len;
> >>>>> +	kbuf.memsz = le64_to_cpu(h->image_size);
> >>>>> +	text_offset = le64_to_cpu(h->text_offset);
> >>>>> +	kbuf.buf_align = SZ_2M;
> >>>>
> >>>>> +	/* Adjust kernel segment with TEXT_OFFSET */
> >>>>> +	kbuf.memsz += text_offset;
> >>>>> +
> >>>>> +	ret = kexec_add_buffer(&kbuf);
> >>>>> +	if (ret)
> >>>>> +		goto out;
> >>>>> +
> >>>>> +	image->arch.kern_segment = image->nr_segments - 1;
> >>>>
> >>>> You only seem to use kern_segment here, and in load_other_segments() called
> >>>> below. Could it not be a local variable passed in? Instead of arch-specific data
> >>>> we keep forever?
> >>>
> >>> No, kern_segment is also used in load_other_segments() in machine_kexec_file.c.
> >>> To optimize memory hole allocation logic in locate_mem_hole_callback(),
> >>> we need to know the exact range of kernel image (start and end).
> >>
> >> That's the second user. My badly-made point is one calls the other, but passes
> >> the data via some until-kexec lifetime struct. (its not important, just an
> >> indicator this worked differently in the past and hasn't been cleaned up).
> >> I meant something like [0].
> > 
> > OK, but instead of adding kern_seg, I want to change the interface to:
> > 
> > | extern int load_other_segments(struct kimage *image,
> > |		unsigned long kernel_load_addr, unsigned long kernel_size,
> > |		char *initrd, unsigned long initrd_len,
> > |		char *cmdline, unsigned long cmdline_len);
> > 
> > This way, we will in future be able to address an issue I mentioned in
> > my previous e-mail. (If we support vmlinux, the kernel occupies two segments
> > for text and data, respectively.)
> 
> Aha, its not from old-stuff, its for future-stuff!

I have vmlinux patch, but it is very unlikely for me to submit it :)

Thanks,
-Takahiro AKASHI

> 
> James

^ permalink raw reply

* [PATCH v3 4/5] ARM: perf: Allow the use of the PMUv3 driver on 32bit ARM
From: Vladimir Murzin @ 2018-05-21  9:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180518143913.26306-5-marc.zyngier@arm.com>

On 18/05/18 15:39, Marc Zyngier wrote:
> +static inline int read_pmuver(void)
> +{
> +	/* PMUVers is not a signed field */
> +	u32 dfr0 = read_cpuid_ext(CPUID_EXT_DFR0);
> +	return (dfr0 >> 24) & 0xf;
> +}

Should we rule out versions prior v3 here or in __armv8pmu_probe_pmu()?

Thanks
Vladimir

^ permalink raw reply


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