Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/3] ARM: dts: imx6: Add Savageboard common file
From: Shawn Guo @ 2017-01-02  6:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161209010436.7994-2-woogyom.kim@gmail.com>

On Fri, Dec 09, 2016 at 10:04:34AM +0900, Milo Kim wrote:
> * Memory
>   memblock for DDR3 1GB
> 
> * Regulator
>   3.3V for panel and backlight.
> 
> * Display
>   Enable HDMI and LVDS panel. Savageboard supports AVIC TM097TDH02 panel
>   which is compatible with Hannstar HSD100PXN1, so reuse it.
> 
> * Clock
>   The commit d28be499c45e6 is applied to support LVDS and HDMI output
>   simultaneously.
> 
> * Pinmux
>   eMMC, ethernet, HDMI, I2C, power button, PWM, SD card and UART.
> 
> * Others
>   Enable ethernet, UART1 debug, USB host, USDHC3 for microSD card and
>   USDHC4 for built-in eMMC storage.
> 
> Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
> ---
>  arch/arm/boot/dts/imx6qdl-savageboard.dtsi | 262 +++++++++++++++++++++++++++++
>  1 file changed, 262 insertions(+)
>  create mode 100644 arch/arm/boot/dts/imx6qdl-savageboard.dtsi
> 
> diff --git a/arch/arm/boot/dts/imx6qdl-savageboard.dtsi b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
> new file mode 100644
> index 0000000..a7a7e1d
> --- /dev/null
> +++ b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
> @@ -0,0 +1,262 @@
> +/*
> + * Copyright (C) 2016 Milo Kim <woogyom.kim@gmail.com>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This file is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License
> + *     version 2 as published by the Free Software Foundation.
> + *
> + *     This file is distributed in the hope that it will be useful
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */

The copyright text needs to be corrected as below.

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

> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +
> +/ {
> +	chosen {
> +		stdout-path = &uart1;
> +	};
> +
> +	memory at 10000000 {
> +		device_type = "memory";
> +		reg = <0x10000000 0x40000000>;
> +	};
> +
> +	backlight: panel_bl {

The node name should be as generic as possible, while label name can be
specific.  That said, the following one should be better.

	panel_bl: backlight

> +		compatible = "pwm-backlight";
> +		brightness-levels = <0 4 8 16 32 64 128 255>;
> +		default-brightness-level = <4>;
> +		power-supply = <&reg_3p3v>;
> +		pwms = <&pwm1 0 10000>;
> +	};
> +
> +	gpio-keys {
> +		compatible = "gpio-keys";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_gpio_keys>;
> +
> +		power {
> +			gpios = <&gpio3 7 GPIO_ACTIVE_LOW>;
> +			label = "Power Button";
> +			linux,code = <KEY_POWER>;
> +			wakeup-source;
> +		};
> +	};
> +
> +	panel {
> +		compatible = "avic, tm097tdh02", "hannstar,hsd100pxn1";

"avic, tm097tdh02" is an undocumented compatible.

> +		backlight = <&backlight>;
> +		power-supply = <&reg_3p3v>;
> +
> +		port {
> +			panel_in: endpoint {
> +				remote-endpoint = <&lvds0_out>;
> +			};
> +		};
> +	};
> +
> +	reg_3p3v: regulator-3p3v {
> +		compatible = "regulator-fixed";
> +		regulator-name = "3P3V";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +		regulator-always-on;
> +	};
> +};
> +
> +&clks {
> +	assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
> +			  <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
> +	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
> +				 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
> +};
> +
> +&fec {
> +	phy-mode = "rgmii";
> +	phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_enet>;
> +	status = "okay";
> +};
> +
> +&hdmi {
> +	ddc-i2c-bus = <&i2c2>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_hdmi_tx_cec>;
> +	status = "okay";
> +};
> +
> +&i2c2 {
> +	clock-frequency = <100000>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_i2c2>;
> +	status = "okay";
> +};
> +
> +&ldb {
> +	status = "okay";
> +
> +	lvds-channel at 0 {
> +		reg = <0>;
> +		status = "okay";
> +
> +		port at 4 {
> +			reg = <4>;
> +
> +			lvds0_out: endpoint {
> +				remote-endpoint = <&panel_in>;
> +			};
> +		};
> +	};
> +};
> +
> +&pwm1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_pwm1>;
> +	status = "okay";
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_uart1>;
> +	status = "okay";
> +};
> +
> +&usbh1 {
> +	status = "okay";
> +};
> +
> +/* SD card */
> +&usdhc3 {
> +	bus-width = <4>;
> +	cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
> +	no-1-8-v;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_sd>;
> +	status = "okay";
> +};
> +
> +/* eMMC */
> +&usdhc4 {
> +	bus-width = <8>;
> +	keep-power-in-suspend;
> +	no-1-8-v;
> +	non-removable;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_emmc>;
> +	status = "okay";
> +};
> +
> +&iomuxc {
> +	pinctrl_emmc: emmcgrp {
> +		fsl,pins = <
> +			MX6QDL_PAD_SD4_CMD__SD4_CMD		0x17059
> +			MX6QDL_PAD_SD4_CLK__SD4_CLK		0x10059
> +			MX6QDL_PAD_SD4_DAT0__SD4_DATA0		0x17059
> +			MX6QDL_PAD_SD4_DAT1__SD4_DATA1		0x17059
> +			MX6QDL_PAD_SD4_DAT2__SD4_DATA2		0x17059
> +			MX6QDL_PAD_SD4_DAT3__SD4_DATA3		0x17059
> +			MX6QDL_PAD_SD4_DAT4__SD4_DATA4		0x17059
> +			MX6QDL_PAD_SD4_DAT5__SD4_DATA5		0x17059
> +			MX6QDL_PAD_SD4_DAT6__SD4_DATA6		0x17059
> +			MX6QDL_PAD_SD4_DAT7__SD4_DATA7		0x17059
> +		>;
> +	};
> +
> +	pinctrl_enet: enetgrp {
> +		fsl,pins = <
> +			MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x1b0b0
> +			MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
> +			MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x1b030
> +			MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b030
> +			MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b030
> +			MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b030
> +			MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b030
> +			MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b030
> +			MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x1b0b0
> +			MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b030
> +			MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b030
> +			MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b030
> +			MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b030
> +			MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b030
> +			MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b030
> +			/* PHY reset */
> +			MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25	0x1b0b0
> +		>;
> +	};
> +
> +	pinctrl_hdmi_tx_cec: hdmitxcecgrp {
> +		fsl,pins = <
> +			MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE	0x1f8b0
> +		>;
> +	};
> +
> +	pinctrl_i2c2: i2c2grp {
> +		fsl,pins = <
> +			MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
> +			MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
> +		>;
> +	};
> +
> +	pinctrl_gpio_keys: gpiokeysgrp {
> +		fsl,pins = <
> +			MX6QDL_PAD_EIM_DA7__GPIO3_IO07		0x1b0b1
> +		>;
> +	};

The pinctrl entries are well sorted alphabetically except this one.

Shawn

> +
> +	pinctrl_pwm1: pwm1grp {
> +		fsl,pins = <
> +			MX6QDL_PAD_SD1_DAT3__PWM1_OUT		0x1b0b1
> +		>;
> +	};
> +
> +	pinctrl_sd: sdgrp {
> +		fsl,pins = <
> +			MX6QDL_PAD_SD3_CMD__SD3_CMD		0x17059
> +			MX6QDL_PAD_SD3_CLK__SD3_CLK		0x10059
> +			MX6QDL_PAD_SD3_DAT0__SD3_DATA0		0x17059
> +			MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
> +			MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
> +			MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
> +			/* CD pin */
> +			MX6QDL_PAD_NANDF_D0__GPIO2_IO00		0x1b0b1
> +		>;
> +	};
> +
> +	pinctrl_uart1: uart1grp {
> +		fsl,pins = <
> +			MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA	0x1b0b1
> +			MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA	0x1b0b1
> +		>;
> +	};
> +};
> -- 
> 2.9.3
> 

^ permalink raw reply

* [PATCH v3 10/10] dts: arm64: hip06: Add Hisilicon SoC PMU support
From: Anurup M @ 2017-01-02  6:51 UTC (permalink / raw)
  To: linux-arm-kernel

1. Add nodes for hip06 L3 cache to support uncore events.
2. Add nodes for hip06 MN to support uncore events.

Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 arch/arm64/boot/dts/hisilicon/hip06.dtsi | 72 ++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index e861698..02ff95f 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -963,6 +963,78 @@
 			status = "disabled";
 		};
 
+		djtag0: djtag at 60010000 {
+			compatible = "hisilicon,hip06-djtag-v1";
+			reg = <0x0 0x60010000 0x0 0x10000>;
+			hisi-scl-id = <0x02>;
+
+			/* L3 cache bank 0 for socket0 CPU die scl#2 */
+			pmul3c0 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x02>;
+			};
+
+			/* L3 cache bank 1 for socket0 CPU die scl#2 */
+			pmul3c1 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x04>;
+			};
+
+			/* L3 cache bank 2 for socket0 CPU die scl#2 */
+			pmul3c2 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x01>;
+			};
+
+			/* L3 cache bank 3 for socket0 CPU die scl#2 */
+			pmul3c3 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x08>;
+			};
+
+			/* Miscellaneous node for socket0 CPU die scl#2 */
+			pmumn0 {
+				compatible = "hisilicon,hip06-pmu-mn-v1";
+				hisi-module-id = <0x0b>;
+			};
+		};
+
+		djtag1: djtag at 40010000 {
+			compatible = "hisilicon,hip06-djtag-v1";
+			reg = <0x0 0x40010000 0x0 0x10000>;
+			hisi-scl-id = <0x01>;
+
+			/* L3 cache bank 0 for socket0 CPU die scl#1 */
+			pmul3c0 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x02>;
+			};
+
+			/* L3 cache bank 1 for socket0 CPU die scl#1 */
+			pmul3c1 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x04>;
+			};
+
+			/* L3 cache bank 2 for socket0 CPU die scl#1 */
+			pmul3c2 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x01>;
+			};
+
+			/* L3 cache bank 3 for socket0 CPU die scl#1 */
+			pmul3c3 {
+				compatible = "hisilicon,hip06-pmu-l3c-v1";
+				hisi-module-id = <0x04 0x08>;
+			};
+
+			/* Miscellaneous node for socket0 CPU die scl#1 */
+			pmumn1 {
+				compatible = "hisilicon,hip06-pmu-mn-v1";
+				hisi-module-id = <0x0b>;
+			};
+		};
+
 		sas1: sas at a2000000 {
 			compatible = "hisilicon,hip06-sas-v2";
 			reg = <0 0xa2000000 0 0x10000>;
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 09/10] perf: hisi: Miscellanous node(MN) event counting in perf
From: Anurup M @ 2017-01-02  6:51 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shaokun Zhang <zhangshaokun@hisilicon.com>

1. Add support to count MN hardware events.
2. MN events are listed in sysfs at /sys/devices/hisi_mn_2/events/
   The events can be selected as shown in perf list
   e.g.: For MN_READ_REQUEST event for Super CPU cluster 2 the
   event format is -e "hisi_mn_2/read_req/"

Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 drivers/perf/hisilicon/Makefile         |   2 +-
 drivers/perf/hisilicon/hisi_uncore_mn.c | 501 ++++++++++++++++++++++++++++++++
 2 files changed, 502 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_mn.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 0887b56..26b2507 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_HISI_PMU) += djtag.o hisi_uncore_pmu.o hisi_uncore_l3c.o
+obj-$(CONFIG_HISI_PMU) += djtag.o hisi_uncore_pmu.o hisi_uncore_l3c.o hisi_uncore_mn.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_mn.c b/drivers/perf/hisilicon/hisi_uncore_mn.c
new file mode 100644
index 0000000..ad868d1
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_mn.c
@@ -0,0 +1,501 @@
+/*
+ * HiSilicon SoC MN Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
+ *
+ * This code is based on the uncore PMU's like arm-cci and
+ * arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include "hisi_uncore_pmu.h"
+
+/*
+ * ARMv8 HiSilicon MN event types.
+ */
+enum armv8_hisi_mn_event_types {
+	HISI_HWEVENT_MN_EO_BARR_REQ	= 0x0,
+	HISI_HWEVENT_MN_EC_BARR_REQ	= 0x01,
+	HISI_HWEVENT_MN_DVM_OP_REQ	= 0x02,
+	HISI_HWEVENT_MN_DVM_SYNC_REQ	= 0x03,
+	HISI_HWEVENT_MN_READ_REQ	= 0x04,
+	HISI_HWEVENT_MN_WRITE_REQ	= 0x05,
+	HISI_HWEVENT_MN_EVENT_MAX	= 0x08,
+};
+
+/*
+ * ARMv8 HiSilicon Hardware counter Index.
+ */
+enum armv8_hisi_mn_counters {
+	HISI_IDX_MN_COUNTER0	= 0x0,
+	HISI_IDX_MN_COUNTER_MAX	= 0x4,
+};
+
+#define HISI_MAX_CFG_MN_CNTR	0x04
+#define MN1_EVTYPE_REG_OFF 0x48
+#define MN1_EVCTRL_REG_OFF 0x40
+#define MN1_CNT0_REG_OFF 0x30
+#define MN1_EVENT_EN 0x01
+#define MN1_BANK_SELECT 0x01
+
+#define GET_MODULE_ID(hwmod_data) hwmod_data->mn_hwcfg.module_id
+
+struct hisi_mn_hwcfg {
+	u32 module_id;
+};
+
+struct hisi_mn_data {
+	struct hisi_djtag_client *client;
+	DECLARE_BITMAP(event_used_mask, HISI_MAX_CFG_MN_CNTR);
+	struct hisi_mn_hwcfg mn_hwcfg;
+};
+
+static inline int hisi_mn_counter_valid(int idx)
+{
+	return (idx >= HISI_IDX_MN_COUNTER0 &&
+			idx < HISI_IDX_MN_COUNTER_MAX);
+}
+
+/* Select the counter register offset from the index */
+static inline u32 get_counter_reg_off(int cntr_idx)
+{
+	return (MN1_CNT0_REG_OFF + (cntr_idx * 4));
+}
+
+static u32 hisi_mn_read_counter(struct hisi_mn_data *mn_data,
+							int cntr_idx)
+{
+	struct hisi_djtag_client *client = mn_data->client;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 reg_off, value;
+
+	reg_off = get_counter_reg_off(cntr_idx);
+
+	hisi_djtag_readreg(module_id, MN1_BANK_SELECT, reg_off,
+						client, &value);
+
+	return value;
+}
+
+static u64 hisi_mn_event_update(struct perf_event *event,
+			struct hw_perf_event *hwc, int idx)
+{
+	struct hisi_pmu *mn_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	u64 delta, prev_raw_count, new_raw_count = 0;
+
+	if (!hisi_mn_counter_valid(idx)) {
+		dev_err(mn_pmu->dev,
+				"Unsupported event index:%d!\n", idx);
+		return 0;
+	}
+
+	do {
+		/* Get count from the MN */
+		prev_raw_count = local64_read(&hwc->prev_count);
+		new_raw_count =	hisi_mn_read_counter(mn_data, idx);
+		delta = (new_raw_count - prev_raw_count) & HISI_MAX_PERIOD;
+
+		local64_add(delta, &event->count);
+	} while (local64_cmpxchg(
+			&hwc->prev_count, prev_raw_count, new_raw_count) !=
+							prev_raw_count);
+
+	return new_raw_count;
+}
+
+static void hisi_mn_set_evtype(struct hisi_pmu *mn_pmu, int idx, u32 val)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	struct hisi_djtag_client *client = mn_data->client;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 event_value, value = 0;
+
+	event_value = (val - HISI_HWEVENT_MN_EO_BARR_REQ);
+
+	/*
+	 * Value to write to event select register
+	 * Each byte in the 32 bit select register is used to
+	 * configure the event code. Each byte correspond to a
+	 * counter register to use.
+	 */
+	val = event_value << (8 * idx);
+
+	/*
+	 * Set the event in MN_EVENT_TYPE Register
+	 */
+	hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF,
+							client, &value);
+	value &= ~(0xff << (8 * idx));
+	value |= val;
+	hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF,
+							value, client);
+}
+
+static void hisi_mn_clear_evtype(struct hisi_pmu *mn_pmu, int idx)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	struct hisi_djtag_client *client = mn_data->client;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 value;
+
+	if (!hisi_mn_counter_valid(idx)) {
+		dev_err(mn_pmu->dev,
+				"Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	/*
+	 * Clear the event in MN_EVENT_TYPE Register
+	 */
+	hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF,
+							client, &value);
+	value &= ~(0xff << (8 * idx));
+	value |= (0xff << (8 * idx));
+	hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVTYPE_REG_OFF,
+							value, client);
+}
+
+static u32 hisi_mn_write_counter(struct hisi_pmu *mn_pmu,
+				struct hw_perf_event *hwc, u32 value)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	struct hisi_djtag_client *client = mn_data->client;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 reg_off;
+	int idx = GET_CNTR_IDX(hwc);
+	int ret;
+
+	if (!hisi_mn_counter_valid(idx)) {
+		dev_err(mn_pmu->dev, "Unsupported event index:%d!\n", idx);
+		return -EINVAL;
+	}
+
+	reg_off = get_counter_reg_off(idx);
+
+	ret = hisi_djtag_writereg(module_id, MN1_BANK_SELECT, reg_off,
+							value, client);
+	if (!ret)
+		ret = value;
+
+	return ret;
+}
+
+static void hisi_mn_start_counters(struct hisi_pmu *mn_pmu)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	struct hisi_djtag_client *client = mn_data->client;
+	unsigned long *used_mask = mn_data->event_used_mask;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 num_counters = mn_pmu->num_counters;
+	u32 value;
+
+	int enabled = bitmap_weight(used_mask, num_counters);
+
+	if (!enabled)
+		return;
+
+	/*
+	 * Set the event_bus_en bit in MN_EVENT_CTRL to start counting
+	 * for the L3C bank
+	 */
+	hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF,
+							client, &value);
+	value |= MN1_EVENT_EN;
+	hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF,
+							value, client);
+}
+
+static void hisi_mn_stop_counters(struct hisi_pmu *mn_pmu)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	struct hisi_djtag_client *client = mn_data->client;
+	u32 module_id = GET_MODULE_ID(mn_data);
+	u32 value;
+
+	/*
+	 * Clear the event_bus_en bit in MN_EVENT_CTRL
+	 */
+	hisi_djtag_readreg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF,
+						client, &value);
+	value &= ~(MN1_EVENT_EN);
+	hisi_djtag_writereg(module_id, MN1_BANK_SELECT, MN1_EVCTRL_REG_OFF,
+							value, client);
+}
+
+static void hisi_mn_clear_event_idx(struct hisi_pmu *mn_pmu, int idx)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	void *bitmap_addr;
+
+	if (!hisi_mn_counter_valid(idx)) {
+		dev_err(mn_pmu->dev, "Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	bitmap_addr = mn_data->event_used_mask;
+	clear_bit(idx, bitmap_addr);
+
+}
+
+static int hisi_mn_get_event_idx(struct hisi_pmu *mn_pmu)
+{
+	struct hisi_mn_data *mn_data = mn_pmu->hwmod_data;
+	const unsigned long *used_mask = mn_data->event_used_mask;
+	u32 num_counters = mn_pmu->num_counters;
+	int event_idx;
+
+	event_idx = find_first_zero_bit(used_mask, num_counters);
+
+	if (event_idx == num_counters)
+		return -EAGAIN;
+
+	set_bit(event_idx, mn_data->event_used_mask);
+
+	return event_idx;
+}
+
+static int init_hisi_mn_hwcfg_fdt(struct device *dev,
+				struct hisi_mn_data *mn_data)
+{
+	struct hisi_mn_hwcfg *mn_hwcfg = &mn_data->mn_hwcfg;
+	struct device_node *node = dev->of_node;
+	int ret;
+
+	ret = of_property_read_u32(node, "hisi-module-id",
+					&mn_hwcfg->module_id);
+	if (ret < 0) {
+		dev_err(dev, "DT: Couldnot read module-id!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int init_hisi_mn_data(struct hisi_pmu *mn_pmu,
+				struct hisi_djtag_client *client)
+{
+	struct hisi_mn_data *mn_data;
+	struct device *dev = &client->dev;
+	int ret;
+
+	mn_data = devm_kzalloc(dev, sizeof(*mn_data), GFP_KERNEL);
+	if (!mn_data)
+		return -ENOMEM;
+
+	/* Set the djtag Identifier */
+	mn_data->client = client;
+
+	mn_pmu->hw_events.events = devm_kcalloc(dev, mn_pmu->num_counters,
+					sizeof(*mn_pmu->hw_events.events),
+					GFP_KERNEL);
+	if (!mn_pmu->hw_events.events)
+		return -ENOMEM;
+
+	raw_spin_lock_init(&mn_pmu->hw_events.pmu_lock);
+
+	mn_pmu->hwmod_data = mn_data;
+
+	if (dev->of_node) {
+		ret = init_hisi_mn_hwcfg_fdt(dev, mn_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct attribute *hisi_mn_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-11"),
+	NULL,
+};
+
+static struct attribute_group hisi_mn_format_group = {
+	.name = "format",
+	.attrs = hisi_mn_format_attr,
+};
+
+static struct attribute *hisi_mn_events_attr[] = {
+	HISI_PMU_EVENT_ATTR_STR(eo_barrier_req, "event=0x0"),
+	HISI_PMU_EVENT_ATTR_STR(ec_barrier_req,	"event=0x01"),
+	HISI_PMU_EVENT_ATTR_STR(dvm_op_req, "event=0x02"),
+	HISI_PMU_EVENT_ATTR_STR(dvm_sync_req, "event=0x03"),
+	HISI_PMU_EVENT_ATTR_STR(read_req, "event=0x04"),
+	HISI_PMU_EVENT_ATTR_STR(write_req, "event=0x05"),
+	NULL,
+};
+
+static struct attribute_group hisi_mn_events_group = {
+	.name = "events",
+	.attrs = hisi_mn_events_attr,
+};
+
+static struct attribute *hisi_mn_attrs[] = {
+	NULL,
+};
+
+static struct attribute_group hisi_mn_attr_group = {
+	.attrs = hisi_mn_attrs,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_mn_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static const struct attribute_group hisi_mn_cpumask_attr_group = {
+	.attrs = hisi_mn_cpumask_attrs,
+};
+
+static const struct attribute_group *hisi_mn_pmu_attr_groups[] = {
+	&hisi_mn_attr_group,
+	&hisi_mn_format_group,
+	&hisi_mn_events_group,
+	&hisi_mn_cpumask_attr_group,
+	NULL,
+};
+
+static struct hisi_uncore_ops hisi_uncore_mn_ops = {
+	.set_evtype = hisi_mn_set_evtype,
+	.clear_evtype = hisi_mn_clear_evtype,
+	.set_event_period = hisi_pmu_set_event_period,
+	.get_event_idx = hisi_mn_get_event_idx,
+	.clear_event_idx = hisi_mn_clear_event_idx,
+	.event_update = hisi_mn_event_update,
+	.start_counters = hisi_mn_start_counters,
+	.stop_counters = hisi_mn_stop_counters,
+	.write_counter = hisi_mn_write_counter,
+};
+
+static int hisi_mn_pmu_init(struct hisi_pmu *mn_pmu,
+				struct hisi_djtag_client *client)
+{
+	struct device *dev = &client->dev;
+
+	mn_pmu->num_events = HISI_HWEVENT_MN_EVENT_MAX;
+	mn_pmu->num_counters = HISI_IDX_MN_COUNTER_MAX;
+	mn_pmu->scl_id = hisi_djtag_get_sclid(client);
+
+	mn_pmu->name = kasprintf(GFP_KERNEL, "hisi_mn_%d", mn_pmu->scl_id);
+	mn_pmu->ops = &hisi_uncore_mn_ops;
+	mn_pmu->dev = dev;
+
+	/* Pick one core to use for cpumask attributes */
+	cpumask_set_cpu(smp_processor_id(), &mn_pmu->cpu);
+
+	return 0;
+}
+
+static int hisi_pmu_mn_dev_probe(struct hisi_djtag_client *client)
+{
+	struct hisi_pmu *mn_pmu = NULL;
+	struct device *dev = &client->dev;
+	int ret;
+
+	mn_pmu = hisi_pmu_alloc(dev);
+	if (!mn_pmu)
+		return -ENOMEM;
+
+	ret = init_hisi_mn_data(mn_pmu, client);
+	if (ret)
+		return ret;
+
+	ret = hisi_mn_pmu_init(mn_pmu, client);
+	if (ret)
+		return ret;
+
+	mn_pmu->pmu = (struct pmu) {
+		.name = mn_pmu->name,
+		.task_ctx_nr = perf_invalid_context,
+		.event_init = hisi_uncore_pmu_event_init,
+		.pmu_enable = hisi_uncore_pmu_enable,
+		.pmu_disable = hisi_uncore_pmu_disable,
+		.add = hisi_uncore_pmu_add,
+		.del = hisi_uncore_pmu_del,
+		.start = hisi_uncore_pmu_start,
+		.stop = hisi_uncore_pmu_stop,
+		.read = hisi_uncore_pmu_read,
+		.attr_groups = hisi_mn_pmu_attr_groups,
+	};
+
+	ret = hisi_uncore_pmu_setup(mn_pmu, mn_pmu->name);
+	if (ret) {
+		dev_err(mn_pmu->dev, "hisi_uncore_pmu_init FAILED!!\n");
+		return ret;
+	}
+
+	/* Set the drv data to MN pmu */
+	dev_set_drvdata(dev, mn_pmu);
+
+	return 0;
+}
+
+static int hisi_pmu_mn_dev_remove(struct hisi_djtag_client *client)
+{
+	struct hisi_pmu *mn_pmu = NULL;
+	struct device *dev = &client->dev;
+
+	mn_pmu = dev_get_drvdata(dev);
+
+	perf_pmu_unregister(&mn_pmu->pmu);
+
+	return 0;
+}
+
+static const struct of_device_id mn_of_match[] = {
+	{ .compatible = "hisilicon,hip05-pmu-mn-v1", },
+	{ .compatible = "hisilicon,hip06-pmu-mn-v1", },
+	{ .compatible = "hisilicon,hip07-pmu-mn-v2", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mn_of_match);
+
+static struct hisi_djtag_driver hisi_pmu_mn_driver = {
+	.driver = {
+		.name = "hisi-pmu-mn",
+		.of_match_table = mn_of_match,
+	},
+	.probe = hisi_pmu_mn_dev_probe,
+	.remove = hisi_pmu_mn_dev_remove,
+};
+
+static int __init hisi_pmu_mn_init(void)
+{
+	int rc;
+
+	rc = hisi_djtag_register_driver(THIS_MODULE, &hisi_pmu_mn_driver);
+	if (rc < 0) {
+		pr_err("hisi pmu MN init failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+module_init(hisi_pmu_mn_init);
+
+static void __exit hisi_pmu_mn_exit(void)
+{
+	hisi_djtag_unregister_driver(&hisi_pmu_mn_driver);
+}
+module_exit(hisi_pmu_mn_exit);
+
+MODULE_DESCRIPTION("HiSilicon SoC HIP0x MN PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shaokun Zhang");
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 08/10] perf: hisi: Add sysfs attributes for L3 cache(L3C) PMU
From: Anurup M @ 2017-01-02  6:50 UTC (permalink / raw)
  To: linux-arm-kernel

1. Add L3 caches events to /sys/devices/hisi_l3c0_2/events/
   The events can be selected as shown in perf list
   e.g.: For L3C_READ_ALLOCATE event for Super CPU cluster 2 the
   event format is -e "hisi_l3c0_2/read_allocate/"
2. Add cpu_mask attribute group for showing the available CPU
   for counting.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_l3c.c | 53 ++++++++++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c | 39 +++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h | 21 +++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c.c b/drivers/perf/hisilicon/hisi_uncore_l3c.c
index 01b2264..b2063e8 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c.c
@@ -432,6 +432,58 @@ static int init_hisi_l3c_data(struct hisi_pmu *l3c_pmu,
 	return 0;
 }
 
+static struct attribute *hisi_l3c_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-11"),
+	NULL,
+};
+
+static struct attribute_group hisi_l3c_format_group = {
+	.name = "format",
+	.attrs = hisi_l3c_format_attr,
+};
+
+static struct attribute *hisi_l3c_events_attr[] = {
+	HISI_PMU_EVENT_ATTR_STR(read_allocate, "event=0x0"),
+	HISI_PMU_EVENT_ATTR_STR(write_allocate, "event=0x01"),
+	HISI_PMU_EVENT_ATTR_STR(read_noallocate, "event=0x02"),
+	HISI_PMU_EVENT_ATTR_STR(write_noallocate, "event=0x03"),
+	HISI_PMU_EVENT_ATTR_STR(read_hit, "event=0x04"),
+	HISI_PMU_EVENT_ATTR_STR(write_hit, "event=0x05"),
+	NULL,
+};
+
+static struct attribute_group hisi_l3c_events_group = {
+	.name = "events",
+	.attrs = hisi_l3c_events_attr,
+};
+
+static struct attribute *hisi_l3c_attrs[] = {
+	NULL,
+};
+
+static struct attribute_group hisi_l3c_attr_group = {
+	.attrs = hisi_l3c_attrs,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_l3c_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL,
+};
+
+static const struct attribute_group hisi_l3c_cpumask_attr_group = {
+	.attrs = hisi_l3c_cpumask_attrs,
+};
+
+static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = {
+	&hisi_l3c_attr_group,
+	&hisi_l3c_format_group,
+	&hisi_l3c_events_group,
+	&hisi_l3c_cpumask_attr_group,
+	NULL,
+};
+
 static struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.set_evtype = hisi_l3c_set_evtype,
 	.clear_evtype = hisi_l3c_clear_evtype,
@@ -495,6 +547,7 @@ static int hisi_pmu_l3c_dev_probe(struct hisi_djtag_client *client)
 		.start = hisi_uncore_pmu_start,
 		.stop = hisi_uncore_pmu_stop,
 		.read = hisi_uncore_pmu_read,
+		.attr_groups = hisi_l3c_pmu_attr_groups,
 	};
 
 	ret = hisi_uncore_pmu_setup(l3c_pmu, l3c_pmu->name);
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 0ba8cd5..c66c1c8 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -26,6 +26,45 @@
 #include <linux/perf_event.h>
 #include "hisi_uncore_pmu.h"
 
+/*
+ * PMU format attributes
+ */
+ssize_t hisi_format_sysfs_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr;
+
+	eattr = container_of(attr, struct dev_ext_attribute, attr);
+	return sprintf(buf, "%s\n", (char *) eattr->var);
+}
+
+/*
+ * PMU event attributes
+ */
+ssize_t hisi_event_sysfs_show(struct device *dev,
+				  struct device_attribute *attr, char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr =
+		container_of(attr, struct perf_pmu_events_attr, attr);
+
+	if (pmu_attr->event_str)
+		return sprintf(page, "%s", pmu_attr->event_str);
+
+	return 0;
+}
+
+/*
+ * sysfs cpumask attributes
+ */
+ssize_t hisi_cpumask_sysfs_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct pmu *pmu = dev_get_drvdata(dev);
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(pmu);
+
+	return cpumap_print_to_pagebuf(true, buf, &hisi_pmu->cpu);
+}
+
 /* djtag read interface - Call djtag driver to access SoC registers */
 int hisi_djtag_readreg(int module_id, int bank, u32 offset,
 				struct hisi_djtag_client *client, u32 *pvalue)
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 90c85e5..8eadf5a 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -47,6 +47,21 @@
 #define GET_CNTR_IDX(hwc) (hwc->idx)
 #define to_hisi_pmu(c)	(container_of(c, struct hisi_pmu, pmu))
 
+#define HISI_PMU_FORMAT_ATTR(_name, _config)		\
+	(&((struct dev_ext_attribute[]) {		\
+		{ .attr = __ATTR(_name, 0444,	\
+			hisi_format_sysfs_show, NULL),	\
+		  .var = (void *) _config,		\
+		}					\
+	})[0].attr.attr)
+
+#define HISI_PMU_EVENT_ATTR_STR(_name, _str)		\
+	(&((struct perf_pmu_events_attr[]) {		\
+		{ .attr = __ATTR(_name, 0444,	\
+			 hisi_event_sysfs_show, NULL),	\
+		  .event_str = _str,			\
+		}					\
+	  })[0].attr.attr)
 
 struct hisi_pmu;
 
@@ -103,4 +118,10 @@ int hisi_djtag_writereg(int module_id, int bank,
 				u32 offset, u32 value,
 				struct hisi_djtag_client *client);
 struct hisi_pmu *hisi_pmu_alloc(struct device *dev);
+ssize_t hisi_event_sysfs_show(struct device *dev,
+				  struct device_attribute *attr, char *buf);
+ssize_t hisi_format_sysfs_show(struct device *dev,
+				  struct device_attribute *attr, char *buf);
+ssize_t hisi_cpumask_sysfs_show(struct device *dev,
+				struct device_attribute *attr, char *buf);
 #endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 07/10] perf: hisi: Add support for Hisilicon SoC event counters
From: Anurup M @ 2017-01-02  6:50 UTC (permalink / raw)
  To: linux-arm-kernel

1. HiP05/06/07 uncore PMU to support different hardware event counters.
2. Hisilicon PMU shall use the DJTAG hardware interface to access
   hardware event counters and configuration register.
3. Routines to initialize and setup PMU.
4. Routines to enable/disable/add/del/start/stop hardware event counting.
5. Add support to count L3 cache hardware events.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile          |   2 +-
 drivers/perf/hisilicon/hisi_uncore_l3c.c | 556 +++++++++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c | 326 ++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h | 106 ++++++
 4 files changed, 989 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index be8f093..0887b56 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_HISI_PMU) += djtag.o
+obj-$(CONFIG_HISI_PMU) += djtag.o hisi_uncore_pmu.o hisi_uncore_l3c.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c.c b/drivers/perf/hisilicon/hisi_uncore_l3c.c
new file mode 100644
index 0000000..01b2264
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c.c
@@ -0,0 +1,556 @@
+/*
+ * HiSilicon SoC L3C Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's like arm-cci and
+ * arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/perf_event.h>
+#include "hisi_uncore_pmu.h"
+
+/*
+ * ARMv8 HiSilicon L3C event types.
+ */
+enum armv8_hisi_l3c_event_types {
+	HISI_HWEVENT_L3C_READ_ALLOCATE		= 0x0,
+	HISI_HWEVENT_L3C_WRITE_ALLOCATE		= 0x01,
+	HISI_HWEVENT_L3C_READ_NOALLOCATE	= 0x02,
+	HISI_HWEVENT_L3C_WRITE_NOALLOCATE	= 0x03,
+	HISI_HWEVENT_L3C_READ_HIT		= 0x04,
+	HISI_HWEVENT_L3C_WRITE_HIT		= 0x05,
+	HISI_HWEVENT_L3C_EVENT_MAX		= 0x15,
+};
+
+/*
+ * ARMv8 HiSilicon Hardware counter Index.
+ */
+enum armv8_hisi_l3c_counters {
+	HISI_IDX_L3C_COUNTER0		= 0x0,
+	HISI_IDX_L3C_COUNTER_MAX	= 0x8,
+};
+
+#define HISI_MAX_CFG_L3C_CNTR	0x08
+#define L3C_EVTYPE_REG_OFF 0x140
+#define L3C_EVCTRL_REG_OFF 0x04
+#define L3C_CNT0_REG_OFF 0x170
+#define L3C_EVENT_EN 0x1000000
+
+#define GET_MODULE_ID(hwmod_data) hwmod_data->l3c_hwcfg.module_id
+#define GET_BANK_SEL(hwmod_data) hwmod_data->l3c_hwcfg.module_id
+
+struct hisi_l3c_hwcfg {
+	u32 module_id;
+	u32 bank_select;
+	u32 bank_id;
+};
+
+struct hisi_l3c_data {
+	struct hisi_djtag_client *client;
+	DECLARE_BITMAP(event_used_mask, HISI_MAX_CFG_L3C_CNTR);
+	struct hisi_l3c_hwcfg l3c_hwcfg;
+};
+
+struct hisi_l3c_hw_diff {
+	u32 (*get_bank_id)(u32 module_id, u32 bank_select);
+};
+
+/* hip05/06 chips L3C bank identifier */
+static u32 l3c_bankid_map_v1[MAX_BANKS] = {
+	0x02, 0x01, 0x04, 0x08,
+};
+
+/* hip07 chip L3C bank identifier */
+static u32 l3c_bankid_map_v2[MAX_BANKS] = {
+	0x01, 0x02, 0x03, 0x04,
+};
+
+/* Return the L3C bank index to use in PMU name */
+static u32 get_l3c_bank_v1(u32 module_id, u32 bank_select)
+{
+	u32 i;
+
+	/*
+	 * For v1 chip (hip05/06) the index of bank_select
+	 * in the bankid_map gives the bank index.
+	 */
+	for (i = 0 ; i < MAX_BANKS; i++)
+		if (l3c_bankid_map_v1[i] == bank_select)
+			break;
+
+	return i;
+}
+
+/* Return the L3C bank index to use in PMU name */
+static u32 get_l3c_bank_v2(u32 module_id, u32 bank_select)
+{
+	u32 i;
+
+	/*
+	 * For v2 chip (hip07) each bank has different
+	 * module ID. So index of module ID in the
+	 * bankid_map gives the bank index.
+	 */
+	for (i = 0 ; i < MAX_BANKS; i++)
+		if (l3c_bankid_map_v2[i] == module_id)
+			break;
+
+	return i;
+}
+
+static inline int hisi_l3c_counter_valid(int idx)
+{
+	return (idx >= HISI_IDX_L3C_COUNTER0 &&
+			idx < HISI_IDX_L3C_COUNTER_MAX);
+}
+
+/* Select the counter register offset from the index */
+static inline u32 get_counter_reg_off(int cntr_idx)
+{
+	return (L3C_CNT0_REG_OFF + (cntr_idx * 4));
+}
+
+static u32 hisi_l3c_read_counter(struct hisi_l3c_data *l3c_data,
+							int cntr_idx)
+{
+	struct hisi_djtag_client *client = l3c_data->client;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 reg_off, value;
+
+	reg_off = get_counter_reg_off(cntr_idx);
+
+	hisi_djtag_readreg(module_id, bank_sel, reg_off, client, &value);
+
+	return value;
+}
+
+static u64 hisi_l3c_event_update(struct perf_event *event,
+				struct hw_perf_event *hwc, int idx)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	u64 delta, prev_raw_count, new_raw_count = 0;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
+		return 0;
+	}
+
+	do {
+		/* Get count from the L3C bank / submodule */
+		new_raw_count += hisi_l3c_read_counter(l3c_data, idx);
+		prev_raw_count = local64_read(&hwc->prev_count);
+
+		/*
+		 *  compute the delta
+		 */
+		delta = (new_raw_count - prev_raw_count) & HISI_MAX_PERIOD;
+
+		local64_add(delta, &event->count);
+	} while (local64_cmpxchg(
+			 &hwc->prev_count, prev_raw_count, new_raw_count) !=
+							 prev_raw_count);
+
+	return new_raw_count;
+}
+
+static void hisi_l3c_set_evtype(struct hisi_pmu *l3c_pmu, int idx, u32 val)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_djtag_client *client = l3c_data->client;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 reg_off = L3C_EVTYPE_REG_OFF;
+	u32 event_value, value = 0;
+
+	event_value = (val - HISI_HWEVENT_L3C_READ_ALLOCATE);
+
+	/*
+	 * Select the appropriate Event select register(L3C_EVENT_TYPEx).
+	 * There are 2 Event Select registers for the 8 hardware counters.
+	 * For the first 4 hardware counters, the L3C_EVTYPE_REG_OFF is chosen.
+	 * For the next 4 hardware counters, the second register is chosen.
+	 */
+	if (idx > 3)
+		reg_off += 4;
+
+	/*
+	 * Value to write to event select register
+	 * Each byte in the 32 bit select register is used to
+	 * configure the event code. Each byte correspond to a
+	 * counter register to use.
+	 */
+	val = event_value << (8 * idx);
+
+	/*
+	 * Set the event in L3C_EVENT_TYPEx Register
+	 * for all L3C banks
+	 */
+	hisi_djtag_readreg(module_id, bank_sel, reg_off, client, &value);
+	value &= ~(0xff << (8 * idx));
+	value |= val;
+	hisi_djtag_writereg(module_id, bank_sel, reg_off, value, client);
+}
+
+static void hisi_l3c_clear_evtype(struct hisi_pmu *l3c_pmu, int idx)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_djtag_client *client = l3c_data->client;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 reg_off = L3C_EVTYPE_REG_OFF;
+	u32 value;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		dev_err(l3c_pmu->dev,
+				"Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	/*
+	 * Clear Counting in L3C event config register.
+	 * Select the appropriate Event select register(L3C_EVENT_TYPEx).
+	 * There are 2 Event Select registers for the 8 hardware counters.
+	 * For the first 4 hardware counters, the L3C_EVTYPE_REG_OFF is chosen.
+	 * For the next 4 hardware counters, the second register is chosen.
+	 */
+	if (idx > 3)
+		reg_off += 4;
+
+	/*
+	 * Clear the event in L3C_EVENT_TYPEx Register
+	 */
+	hisi_djtag_readreg(module_id, bank_sel, reg_off, client, &value);
+	value &= ~(0xff << (8 * idx));
+	value |= (0xff << (8 * idx));
+	hisi_djtag_writereg(module_id, bank_sel, reg_off, value, client);
+}
+
+static u32 hisi_l3c_write_counter(struct hisi_pmu *l3c_pmu,
+				struct hw_perf_event *hwc, u32 value)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_djtag_client *client = l3c_data->client;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 reg_off;
+	int idx = GET_CNTR_IDX(hwc);
+	int ret;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		dev_err(l3c_pmu->dev,
+				"Unsupported event index:%d!\n", idx);
+		return -EINVAL;
+	}
+
+	reg_off = get_counter_reg_off(idx);
+
+	ret = hisi_djtag_writereg(module_id, bank_sel, reg_off, value, client);
+	if (!ret)
+		ret = value;
+
+	return ret;
+}
+
+static void hisi_l3c_start_counters(struct hisi_pmu *l3c_pmu)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_djtag_client *client = l3c_data->client;
+	unsigned long *used_mask = l3c_data->event_used_mask;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 num_counters = l3c_pmu->num_counters;
+	u32 value;
+
+	int enabled = bitmap_weight(used_mask, num_counters);
+
+	if (!enabled)
+		return;
+
+	/*
+	 * Set the event_bus_en bit in L3C AUCNTRL to start counting
+	 * for the L3C bank
+	 */
+	hisi_djtag_readreg(module_id, bank_sel, L3C_EVCTRL_REG_OFF,
+							client, &value);
+	value |= L3C_EVENT_EN;
+	hisi_djtag_writereg(module_id, bank_sel, L3C_EVCTRL_REG_OFF,
+							value, client);
+}
+
+static void hisi_l3c_stop_counters(struct hisi_pmu *l3c_pmu)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_djtag_client *client = l3c_data->client;
+	u32 module_id = GET_MODULE_ID(l3c_data);
+	u32 bank_sel = GET_BANK_SEL(l3c_data);
+	u32 value;
+
+	/*
+	 * Clear the event_bus_en bit in L3C AUCNTRL
+	 */
+	hisi_djtag_readreg(module_id, bank_sel, L3C_EVCTRL_REG_OFF,
+							client, &value);
+	value &= ~(L3C_EVENT_EN);
+	hisi_djtag_writereg(module_id, bank_sel, L3C_EVCTRL_REG_OFF,
+							value, client);
+}
+
+static void hisi_l3c_clear_event_idx(struct hisi_pmu *l3c_pmu, int idx)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	void *bitmap_addr;
+
+	if (!hisi_l3c_counter_valid(idx)) {
+		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
+		return;
+	}
+
+	bitmap_addr = l3c_data->event_used_mask;
+	clear_bit(idx, bitmap_addr);
+}
+
+static int hisi_l3c_get_event_idx(struct hisi_pmu *l3c_pmu)
+{
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	unsigned long *used_mask = l3c_data->event_used_mask;
+	u32 num_counters = l3c_pmu->num_counters;
+	int event_idx;
+
+	event_idx = find_first_zero_bit(used_mask, num_counters);
+
+	if (event_idx == num_counters)
+		return -EAGAIN;
+
+	set_bit(event_idx, used_mask);
+
+	return event_idx;
+}
+
+/* Handle differences in L3C hw in v1/v2 chips */
+static const struct hisi_l3c_hw_diff l3c_hw_v1 = {
+	.get_bank_id = get_l3c_bank_v1,
+};
+
+/* Handle differences in L3C hw in v1/v2 chips */
+static const struct hisi_l3c_hw_diff l3c_hw_v2 = {
+	.get_bank_id = get_l3c_bank_v2,
+};
+
+static const struct of_device_id l3c_of_match[] = {
+	{ .compatible = "hisilicon,hip05-pmu-l3c-v1", &l3c_hw_v1},
+	{ .compatible = "hisilicon,hip06-pmu-l3c-v1", &l3c_hw_v1},
+	{ .compatible = "hisilicon,hip07-pmu-l3c-v2", &l3c_hw_v2},
+	{},
+};
+MODULE_DEVICE_TABLE(of, l3c_of_match);
+
+static int init_hisi_l3c_hwcfg_fdt(struct device *dev,
+				struct hisi_l3c_data *l3c_data)
+{
+	struct hisi_l3c_hwcfg *l3c_hwcfg = &l3c_data->l3c_hwcfg;
+	struct device_node *node = dev->of_node;
+	const struct of_device_id *of_id;
+	u32 module_id[2];
+	int ret;
+
+	ret = of_property_read_u32_array(node, "hisi-module-id",
+							module_id, 2);
+	if (ret < 0) {
+		dev_err(dev, "DT: Couldnot read module-id!\n");
+		return -EINVAL;
+	}
+	l3c_hwcfg->module_id = module_id[0];
+	l3c_hwcfg->bank_select = module_id[1];
+
+	of_id = of_match_device(l3c_of_match, dev);
+	if (of_id) {
+		const struct hisi_l3c_hw_diff *l3c_hw = of_id->data;
+		u32 bank_id;
+
+		/* Get the L3C bank index to set the pmu name */
+		bank_id = l3c_hw->get_bank_id(l3c_hwcfg->module_id,
+							l3c_hwcfg->bank_select);
+		if (bank_id == MAX_BANKS) {
+			dev_err(dev, "DT: Invalid bank-select!\n");
+			return -EINVAL;
+		}
+		l3c_hwcfg->bank_id = bank_id;
+	}
+
+	return 0;
+}
+
+static int init_hisi_l3c_data(struct hisi_pmu *l3c_pmu,
+				struct hisi_djtag_client *client)
+{
+	struct hisi_l3c_data *l3c_data;
+	struct device *dev = &client->dev;
+	int ret;
+
+	l3c_data = devm_kzalloc(dev, sizeof(*l3c_data), GFP_KERNEL);
+	if (!l3c_data)
+		return -ENOMEM;
+
+	/* Set the djtag Identifier */
+	l3c_data->client = client;
+
+	l3c_pmu->hw_events.events = devm_kcalloc(dev, l3c_pmu->num_counters,
+					sizeof(*l3c_pmu->hw_events.events),
+					GFP_KERNEL);
+	if (!l3c_pmu->hw_events.events)
+		return -ENOMEM;
+
+	raw_spin_lock_init(&l3c_pmu->hw_events.pmu_lock);
+
+	l3c_pmu->hwmod_data = l3c_data;
+
+	if (dev->of_node) {
+		ret = init_hisi_l3c_hwcfg_fdt(dev, l3c_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct hisi_uncore_ops hisi_uncore_l3c_ops = {
+	.set_evtype = hisi_l3c_set_evtype,
+	.clear_evtype = hisi_l3c_clear_evtype,
+	.set_event_period = hisi_pmu_set_event_period,
+	.get_event_idx = hisi_l3c_get_event_idx,
+	.clear_event_idx = hisi_l3c_clear_event_idx,
+	.event_update = hisi_l3c_event_update,
+	.start_counters = hisi_l3c_start_counters,
+	.stop_counters = hisi_l3c_stop_counters,
+	.write_counter = hisi_l3c_write_counter,
+};
+
+static int hisi_l3c_pmu_init(struct hisi_pmu *l3c_pmu,
+				struct hisi_djtag_client *client)
+{
+	struct device *dev = &client->dev;
+	struct hisi_l3c_data *l3c_data = l3c_pmu->hwmod_data;
+	struct hisi_l3c_hwcfg *l3c_hwcfg = &l3c_data->l3c_hwcfg;
+
+	l3c_pmu->num_events = HISI_HWEVENT_L3C_EVENT_MAX;
+	l3c_pmu->num_counters = HISI_IDX_L3C_COUNTER_MAX;
+	l3c_pmu->scl_id = hisi_djtag_get_sclid(client);
+
+	l3c_pmu->name = kasprintf(GFP_KERNEL, "hisi_l3c%u_%u",
+				l3c_hwcfg->bank_id, l3c_pmu->scl_id);
+	l3c_pmu->ops = &hisi_uncore_l3c_ops;
+	l3c_pmu->dev = dev;
+
+	/* Pick one core to use for cpumask attributes */
+	cpumask_set_cpu(smp_processor_id(), &l3c_pmu->cpu);
+
+	return 0;
+}
+
+static int hisi_pmu_l3c_dev_probe(struct hisi_djtag_client *client)
+{
+	struct hisi_pmu *l3c_pmu;
+	struct device *dev = &client->dev;
+	int ret;
+
+	l3c_pmu = hisi_pmu_alloc(dev);
+	if (!l3c_pmu)
+		return -ENOMEM;
+
+	ret = init_hisi_l3c_data(l3c_pmu, client);
+	if (ret)
+		return ret;
+
+	ret = hisi_l3c_pmu_init(l3c_pmu, client);
+	if (ret)
+		return ret;
+
+	l3c_pmu->pmu = (struct pmu) {
+		.name = l3c_pmu->name,
+		.task_ctx_nr = perf_invalid_context,
+		.event_init = hisi_uncore_pmu_event_init,
+		.pmu_enable = hisi_uncore_pmu_enable,
+		.pmu_disable = hisi_uncore_pmu_disable,
+		.add = hisi_uncore_pmu_add,
+		.del = hisi_uncore_pmu_del,
+		.start = hisi_uncore_pmu_start,
+		.stop = hisi_uncore_pmu_stop,
+		.read = hisi_uncore_pmu_read,
+	};
+
+	ret = hisi_uncore_pmu_setup(l3c_pmu, l3c_pmu->name);
+	if (ret) {
+		dev_err(dev, "hisi_uncore_pmu_init FAILED!!\n");
+		return ret;
+	}
+
+	/* Set the drv data to L3C pmu */
+	dev_set_drvdata(dev, l3c_pmu);
+
+	return 0;
+}
+
+static int hisi_pmu_l3c_dev_remove(struct hisi_djtag_client *client)
+{
+	struct hisi_pmu *l3c_pmu;
+	struct device *dev = &client->dev;
+
+	l3c_pmu = dev_get_drvdata(dev);
+
+	perf_pmu_unregister(&l3c_pmu->pmu);
+
+	return 0;
+}
+
+static struct hisi_djtag_driver hisi_pmu_l3c_driver = {
+	.driver = {
+		.name = "hisi-pmu-l3c",
+		.of_match_table = l3c_of_match,
+	},
+	.probe = hisi_pmu_l3c_dev_probe,
+	.remove = hisi_pmu_l3c_dev_remove,
+};
+
+static int __init hisi_pmu_l3c_init(void)
+{
+	int rc;
+
+	rc = hisi_djtag_register_driver(THIS_MODULE, &hisi_pmu_l3c_driver);
+	if (rc < 0) {
+		pr_err("hisi pmu L3C init failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+module_init(hisi_pmu_l3c_init);
+
+static void __exit hisi_pmu_l3c_exit(void)
+{
+	hisi_djtag_unregister_driver(&hisi_pmu_l3c_driver);
+
+}
+module_exit(hisi_pmu_l3c_exit);
+
+MODULE_DESCRIPTION("HiSilicon SoC HIP0x L3C PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Anurup M");
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
new file mode 100644
index 0000000..0ba8cd5
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -0,0 +1,326 @@
+/*
+ * HiSilicon SoC Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's like arm-cci and
+ * arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitmap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include "hisi_uncore_pmu.h"
+
+/* djtag read interface - Call djtag driver to access SoC registers */
+int hisi_djtag_readreg(int module_id, int bank, u32 offset,
+				struct hisi_djtag_client *client, u32 *pvalue)
+{
+	int ret;
+	u32 chain_id = 0;
+
+	while (bank != 1) {
+		bank = (bank >> 0x1);
+		chain_id++;
+	}
+
+	ret = hisi_djtag_readl(client, offset, module_id, chain_id, pvalue);
+	if (ret)
+		dev_err(&client->dev, "read failed, ret=%d!\n", ret);
+
+	return ret;
+}
+
+/* djtag write interface - Call djtag driver  to access SoC registers */
+int hisi_djtag_writereg(int module_id, int bank,
+				u32 offset, u32 value,
+				struct hisi_djtag_client *client)
+{
+	int ret;
+
+	ret = hisi_djtag_writel(client, offset, module_id,
+						HISI_DJTAG_MOD_MASK, value);
+	if (ret)
+		dev_err(&client->dev, "write failed, ret=%d!\n", ret);
+
+	return ret;
+}
+
+static int pmu_map_event(struct perf_event *event)
+{
+	return (int)(event->attr.config & HISI_EVTYPE_EVENT);
+}
+
+static int hisi_hw_perf_event_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+	struct device *dev = hisi_pmu->dev;
+	struct perf_event *sibling;
+	int mapping;
+
+	mapping = pmu_map_event(event);
+	if (mapping < 0) {
+		dev_err(dev, "event %x:%llx not supported\n",
+				event->attr.type, event->attr.config);
+		return mapping;
+	}
+
+	/*
+	 * We don't assign an index until we actually place the event onto
+	 * hardware. Use -1 to signify that we haven't decided where to put it
+	 * yet.
+	 */
+	hwc->idx		= -1;
+	hwc->config		= 0;
+	hwc->event_base		= 0;
+
+	/* For HiSilicon SoC update config_base based on event encoding */
+	hwc->config_base = event->attr.config;
+
+	/*
+	 * We must NOT create groups containing mixed PMUs, although
+	 * software events are acceptable
+	 */
+	if (event->group_leader->pmu != event->pmu &&
+	    !is_software_event(event->group_leader))
+		return -EINVAL;
+
+	list_for_each_entry(sibling, &event->group_leader->sibling_list,
+							    group_entry)
+		if (sibling->pmu != event->pmu && !is_software_event(sibling))
+			return -EINVAL;
+
+	return 0;
+}
+
+int hisi_uncore_pmu_event_init(struct perf_event *event)
+{
+	int err;
+	struct hisi_pmu *hisi_pmu;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/*
+	 * We do not support sampling as the counters are all
+	 * shared by all CPU cores in a CPU die(SCCL). Also we
+	 * do not support attach to a task(per-process mode)
+	 */
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	/* counters do not have these bits */
+	if (event->attr.exclude_user	||
+	    event->attr.exclude_kernel	||
+	    event->attr.exclude_host	||
+	    event->attr.exclude_guest	||
+	    event->attr.exclude_hv	||
+	    event->attr.exclude_idle)
+		return -EINVAL;
+
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	hisi_pmu = to_hisi_pmu(event->pmu);
+	event->cpu = cpumask_first(&hisi_pmu->cpu);
+
+	err = hisi_hw_perf_event_init(event);
+
+	return err;
+}
+
+/*
+ * Enable counter and set the counter to count
+ * the event that we're interested in.
+ */
+static void hisi_uncore_pmu_enable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	/*
+	 * Set event in Event select registers.
+	 */
+	if (hisi_pmu->ops->set_evtype)
+		hisi_pmu->ops->set_evtype(hisi_pmu, GET_CNTR_IDX(hwc),
+							hwc->config_base);
+
+	/* Enable the hardware event counting */
+	if (hisi_pmu->ops->enable_counter)
+		hisi_pmu->ops->enable_counter(hisi_pmu, GET_CNTR_IDX(hwc));
+}
+
+/*
+ * Disable counting and clear the event.
+ */
+static void hisi_uncore_pmu_disable_event(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	/* Disable the hardware event counting */
+	if (hisi_pmu->ops->disable_counter)
+		hisi_pmu->ops->disable_counter(hisi_pmu, GET_CNTR_IDX(hwc));
+
+	/*
+	 * Clear event in Event select registers.
+	 */
+	if (hisi_pmu->ops->clear_evtype)
+		hisi_pmu->ops->clear_evtype(hisi_pmu, GET_CNTR_IDX(hwc));
+}
+
+void hisi_pmu_set_event_period(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	/*
+	 * The Hisilicon PMU counters have a period of 2^32. To account for the
+	 * possiblity of extreme interrupt latency we program for a period of
+	 * half that. Hopefully we can handle the interrupt before another 2^31
+	 * events occur and the counter overtakes its previous value.
+	 */
+	u64 val = 1ULL << 31;
+
+	local64_set(&hwc->prev_count, val);
+
+	/* Write to the hardware event counter */
+	hisi_pmu->ops->write_counter(hisi_pmu, hwc, val);
+}
+
+void hisi_uncore_pmu_start(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+	hwc->state = 0;
+
+	if (hisi_pmu->ops->set_event_period)
+		hisi_pmu->ops->set_event_period(event);
+
+	if (flags & PERF_EF_RELOAD) {
+		u64 prev_raw_count =  local64_read(&hwc->prev_count);
+
+		hisi_pmu->ops->write_counter(hisi_pmu, hwc,
+						(u32)prev_raw_count);
+	}
+
+	hisi_uncore_pmu_enable_event(event);
+	perf_event_update_userpage(event);
+}
+
+void hisi_uncore_pmu_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	hisi_uncore_pmu_disable_event(event);
+	WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+	hwc->state |= PERF_HES_STOPPED;
+
+	if (hwc->state & PERF_HES_UPTODATE)
+		return;
+
+	/* Read hardware counter and update the Perf counter statistics */
+	hisi_pmu->ops->event_update(event, hwc, GET_CNTR_IDX(hwc));
+	hwc->state |= PERF_HES_UPTODATE;
+}
+
+int hisi_uncore_pmu_add(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_pmu_hw_events *hw_events;
+	int idx;
+
+	hw_events = &hisi_pmu->hw_events;
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	/* Get an available counter index for counting. */
+	idx = hisi_pmu->ops->get_event_idx(hisi_pmu);
+	if (idx < 0)
+		return -EAGAIN;
+
+	event->hw.idx = idx;
+	hw_events->events[idx] = event;
+
+	if (flags & PERF_EF_START)
+		hisi_uncore_pmu_start(event, PERF_EF_RELOAD);
+
+	return 0;
+}
+
+void hisi_uncore_pmu_del(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+	struct hisi_pmu_hw_events *hw_events = &hisi_pmu->hw_events;
+
+	hisi_uncore_pmu_stop(event, PERF_EF_UPDATE);
+
+	hisi_pmu->ops->clear_event_idx(hisi_pmu, GET_CNTR_IDX(hwc));
+	perf_event_update_userpage(event);
+	hw_events->events[GET_CNTR_IDX(hwc)] = NULL;
+}
+
+struct hisi_pmu *hisi_pmu_alloc(struct device *dev)
+{
+	struct hisi_pmu *hisi_pmu;
+
+	hisi_pmu = devm_kzalloc(dev, sizeof(*hisi_pmu), GFP_KERNEL);
+	if (!hisi_pmu)
+		return ERR_PTR(-ENOMEM);
+
+	return hisi_pmu;
+}
+
+void hisi_uncore_pmu_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
+
+	/* Read hardware counter and update the Perf counter statistics */
+	hisi_pmu->ops->event_update(event, hwc, GET_CNTR_IDX(hwc));
+}
+
+void hisi_uncore_pmu_enable(struct pmu *pmu)
+{
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(pmu);
+
+	if (hisi_pmu->ops->start_counters)
+		hisi_pmu->ops->start_counters(hisi_pmu);
+}
+
+void hisi_uncore_pmu_disable(struct pmu *pmu)
+{
+	struct hisi_pmu *hisi_pmu = to_hisi_pmu(pmu);
+
+	if (hisi_pmu->ops->stop_counters)
+		hisi_pmu->ops->start_counters(hisi_pmu);
+}
+
+int hisi_uncore_pmu_setup(struct hisi_pmu *hisi_pmu, const char *pmu_name)
+{
+	/* Register the events with perf */
+	return perf_pmu_register(&hisi_pmu->pmu, pmu_name, -1);
+}
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
new file mode 100644
index 0000000..90c85e5
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -0,0 +1,106 @@
+/*
+ * HiSilicon SoC Hardware event counters support
+ *
+ * Copyright (C) 2016 Huawei Technologies Limited
+ * Author: Anurup M <anurup.m@huawei.com>
+ *
+ * This code is based on the uncore PMU's like arm-cci and
+ * arm-ccn.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __HISI_UNCORE_PMU_H__
+#define __HISI_UNCORE_PMU_H__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/local64.h>
+#include "djtag.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "hisi_pmu: " fmt
+
+#define HISI_DJTAG_MOD_MASK (0xFFFF)
+#define HISI_CNTR_SCCL_MASK    (0xF00)
+
+#define HISI_EVTYPE_EVENT	0xfff
+#define HISI_MAX_PERIOD ((1LLU << 32) - 1)
+
+#define MAX_BANKS 8
+#define MAX_COUNTERS 30
+#define MAX_UNITS 8
+
+#define GET_CNTR_IDX(hwc) (hwc->idx)
+#define to_hisi_pmu(c)	(container_of(c, struct hisi_pmu, pmu))
+
+
+struct hisi_pmu;
+
+struct hisi_uncore_ops {
+	void (*set_evtype)(struct hisi_pmu *, int, u32);
+	void (*clear_evtype)(struct hisi_pmu *, int);
+	void (*set_event_period)(struct perf_event *);
+	int (*get_event_idx)(struct hisi_pmu *);
+	void (*clear_event_idx)(struct hisi_pmu *, int);
+	u64 (*event_update)(struct perf_event *,
+			     struct hw_perf_event *, int);
+	u32 (*read_counter)(struct hisi_pmu *, int, int);
+	u32 (*write_counter)(struct hisi_pmu *,
+				struct hw_perf_event *, u32);
+	void (*enable_counter)(struct hisi_pmu *, int);
+	void (*disable_counter)(struct hisi_pmu *, int);
+	void (*start_counters)(struct hisi_pmu *);
+	void (*stop_counters)(struct hisi_pmu *);
+};
+
+struct hisi_pmu_hw_events {
+	struct perf_event **events;
+	raw_spinlock_t pmu_lock;
+};
+
+/* Generic pmu struct for different pmu types */
+struct hisi_pmu {
+	const char *name;
+	struct hisi_pmu_hw_events hw_events;
+	struct hisi_uncore_ops *ops;
+	struct device *dev;
+	void *hwmod_data; /* Hardware module specific data */
+	cpumask_t cpu;
+	struct pmu pmu;
+	u32 scl_id;
+	int num_counters;
+	int num_events;
+};
+
+void hisi_uncore_pmu_read(struct perf_event *event);
+void hisi_uncore_pmu_del(struct perf_event *event, int flags);
+int hisi_uncore_pmu_add(struct perf_event *event, int flags);
+void hisi_uncore_pmu_start(struct perf_event *event, int flags);
+void hisi_uncore_pmu_stop(struct perf_event *event, int flags);
+void hisi_pmu_set_event_period(struct perf_event *event);
+int hisi_uncore_pmu_setup(struct hisi_pmu *hisi_pmu, const char *pmu_name);
+void hisi_uncore_pmu_enable(struct pmu *pmu);
+void hisi_uncore_pmu_disable(struct pmu *pmu);
+int hisi_uncore_pmu_event_init(struct perf_event *event);
+int hisi_djtag_readreg(int module_id, int bank, u32 offset,
+				struct hisi_djtag_client *client,
+							u32 *value);
+int hisi_djtag_writereg(int module_id, int bank,
+				u32 offset, u32 value,
+				struct hisi_djtag_client *client);
+struct hisi_pmu *hisi_pmu_alloc(struct device *dev);
+#endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 06/10] drivers: perf: hisi: Add support for Hisilicon Djtag driver
From: Anurup M @ 2017-01-02  6:50 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tan Xiaojun <tanxiaojun@huawei.com>

The Hisilicon Djtag is an independent component which connects
with some other components in the SoC by Debug Bus. This driver
can be configured to access the registers of connecting components
(like L3 cache) during real time debugging.

Signed-off-by: Tan Xiaojun <tanxiaojun@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 drivers/perf/Makefile           |   1 +
 drivers/perf/hisilicon/Makefile |   1 +
 drivers/perf/hisilicon/djtag.c  | 731 ++++++++++++++++++++++++++++++++++++++++
 drivers/perf/hisilicon/djtag.h  |  39 +++
 4 files changed, 772 insertions(+)
 create mode 100644 drivers/perf/hisilicon/Makefile
 create mode 100644 drivers/perf/hisilicon/djtag.c
 create mode 100644 drivers/perf/hisilicon/djtag.h

diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index b116e98..061f229 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
 obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
+obj-$(CONFIG_HISI_PMU) += hisilicon/
diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
new file mode 100644
index 0000000..be8f093
--- /dev/null
+++ b/drivers/perf/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HISI_PMU) += djtag.o
diff --git a/drivers/perf/hisilicon/djtag.c b/drivers/perf/hisilicon/djtag.c
new file mode 100644
index 0000000..5aeba55
--- /dev/null
+++ b/drivers/perf/hisilicon/djtag.c
@@ -0,0 +1,731 @@
+/*
+ * Driver for Hisilicon Djtag r/w via System Controller.
+ *
+ * Copyright (C) 2016 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time64.h>
+
+#include "djtag.h"
+
+#define SC_DJTAG_TIMEOUT_US    (100 * USEC_PER_MSEC) /* 100ms */
+
+/* for djtag v1 */
+#define SC_DJTAG_MSTR_EN		0x6800
+#define DJTAG_NOR_CFG			BIT(1)	/* accelerate R,W */
+#define DJTAG_MSTR_EN			BIT(0)
+#define SC_DJTAG_MSTR_START_EN		0x6804
+#define DJTAG_MSTR_START_EN		0x1
+#define SC_DJTAG_DEBUG_MODULE_SEL	0x680c
+#define SC_DJTAG_MSTR_WR		0x6810
+#define DJTAG_MSTR_W			0x1
+#define DJTAG_MSTR_R			0x0
+#define SC_DJTAG_CHAIN_UNIT_CFG_EN	0x6814
+#define CHAIN_UNIT_CFG_EN		0xFFFF
+#define SC_DJTAG_MSTR_ADDR		0x6818
+#define SC_DJTAG_MSTR_DATA		0x681c
+#define SC_DJTAG_RD_DATA_BASE		0xe800
+
+/* for djtag v2 */
+#define SC_DJTAG_SEC_ACC_EN_EX		0xd800
+#define DJTAG_SEC_ACC_EN_EX		0x1
+#define SC_DJTAG_MSTR_CFG_EX		0xd818
+#define DJTAG_MSTR_RW_SHIFT_EX		29
+#define DJTAG_MSTR_RD_EX		(0x0 << DJTAG_MSTR_RW_SHIFT_EX)
+#define DJTAG_MSTR_WR_EX		(0x1 << DJTAG_MSTR_RW_SHIFT_EX)
+#define DEBUG_MODULE_SEL_SHIFT_EX	16
+#define CHAIN_UNIT_CFG_EN_EX		0xFFFF
+#define SC_DJTAG_MSTR_ADDR_EX		0xd810
+#define SC_DJTAG_MSTR_DATA_EX		0xd814
+#define SC_DJTAG_MSTR_START_EN_EX	0xd81c
+#define DJTAG_MSTR_START_EN_EX		0x1
+#define SC_DJTAG_RD_DATA_BASE_EX	0xe800
+#define SC_DJTAG_OP_ST_EX		0xe828
+#define DJTAG_OP_DONE_EX		BIT(8)
+
+#define DJTAG_PREFIX "hisi-djtag-dev-"
+
+static DEFINE_IDR(djtag_hosts_idr);
+
+struct hisi_djtag_ops {
+	int (*djtag_read)(void __iomem *regs_base, u32 offset,
+					u32 mod_sel, u32 mod_mask,
+					int chain_id, u32 *rval);
+	int (*djtag_write)(void __iomem *regs_base, u32 offset,
+					u32 mod_sel, u32 mod_mask,
+					u32 wval, int chain_id);
+};
+
+struct hisi_djtag_host {
+	spinlock_t lock;
+	int id;
+	u32 scl_id;
+	struct device dev;
+	struct list_head client_list;
+	void __iomem *sysctl_reg_map;
+	struct device_node *of_node;
+	const struct hisi_djtag_ops *djtag_ops;
+};
+
+#define to_hisi_djtag_client(d) container_of(d, struct hisi_djtag_client, dev)
+#define to_hisi_djtag_driver(d) container_of(d, struct hisi_djtag_driver, \
+								 driver)
+#define MODULE_PREFIX "hisi_djtag:"
+
+static void djtag_prepare_v1(void __iomem *regs_base, u32 offset,
+						u32 mod_sel, u32 mod_mask)
+{
+	/* djtag master enable & accelerate R,W */
+	writel(DJTAG_NOR_CFG | DJTAG_MSTR_EN, regs_base + SC_DJTAG_MSTR_EN);
+
+	/* select module */
+	writel(mod_sel, regs_base + SC_DJTAG_DEBUG_MODULE_SEL);
+	writel(mod_mask & CHAIN_UNIT_CFG_EN,
+			regs_base + SC_DJTAG_CHAIN_UNIT_CFG_EN);
+
+	/* address offset */
+	writel(offset, regs_base + SC_DJTAG_MSTR_ADDR);
+}
+
+static int djtag_do_operation_v1(void __iomem *regs_base)
+{
+	u32 rd;
+	int timeout = SC_DJTAG_TIMEOUT_US;
+
+	/* start to write to djtag register */
+	writel(DJTAG_MSTR_START_EN, regs_base + SC_DJTAG_MSTR_START_EN);
+
+	/* ensure the djtag operation is done */
+	do {
+		rd = readl(regs_base + SC_DJTAG_MSTR_START_EN);
+		if (!(rd & DJTAG_MSTR_EN))
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static void djtag_prepare_v2(void __iomem *regs_base, u32 offset,
+						u32 mod_sel, u32 mod_mask)
+{
+	/* djtag mster enable */
+	writel(DJTAG_SEC_ACC_EN_EX, regs_base + SC_DJTAG_SEC_ACC_EN_EX);
+
+	/* address offset */
+	writel(offset, regs_base + SC_DJTAG_MSTR_ADDR_EX);
+}
+
+static int djtag_do_operation_v2(void __iomem *regs_base)
+{
+	u32 rd;
+	int timeout = SC_DJTAG_TIMEOUT_US;
+
+	/* start to write to djtag register */
+	writel(DJTAG_MSTR_START_EN_EX, regs_base + SC_DJTAG_MSTR_START_EN_EX);
+
+	/* ensure the djtag operation is done */
+	do {
+		rd = readl(regs_base + SC_DJTAG_MSTR_START_EN_EX);
+
+		if (!(rd & DJTAG_MSTR_START_EN_EX))
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0)
+		goto timeout;
+
+	timeout = SC_DJTAG_TIMEOUT_US;
+	do {
+		rd = readl(regs_base + SC_DJTAG_OP_ST_EX);
+
+		if (rd & DJTAG_OP_DONE_EX)
+			break;
+
+		udelay(1);
+	} while (timeout--);
+
+	if (timeout < 0)
+		goto timeout;
+
+	return 0;
+
+timeout:
+	return -EBUSY;
+}
+
+/*
+ * djtag_read_v1/v2: djtag read interface
+ * @reg_base:	djtag register base address
+ * @offset:	register's offset
+ * @mod_sel:	module selection
+ * @mod_mask:	mask to select specific modules for write
+ * @chain_id:	which sub module for read
+ * @rval:	value in register for read
+ *
+ * Return non-zero if error, else return 0.
+ */
+static int djtag_read_v1(void __iomem *regs_base, u32 offset, u32 mod_sel,
+					u32 mod_mask, int chain_id, u32 *rval)
+{
+	int ret;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	djtag_prepare_v1(regs_base, offset, mod_sel, mod_mask);
+
+	writel(DJTAG_MSTR_R, regs_base + SC_DJTAG_MSTR_WR);
+
+	ret = djtag_do_operation_v1(regs_base);
+	if (ret) {
+		if (ret == EBUSY)
+			pr_err("djtag: %s timeout!\n", "read");
+		return ret;
+	}
+
+	*rval = readl(regs_base + SC_DJTAG_RD_DATA_BASE + chain_id * 0x4);
+
+	return 0;
+}
+
+static int djtag_read_v2(void __iomem *regs_base, u32 offset, u32 mod_sel,
+					u32 mod_mask, int chain_id, u32 *rval)
+{
+	int ret;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN_EX)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	djtag_prepare_v2(regs_base, offset, mod_sel, mod_mask);
+
+	writel(DJTAG_MSTR_RD_EX
+			| (mod_sel << DEBUG_MODULE_SEL_SHIFT_EX)
+			| (mod_mask & CHAIN_UNIT_CFG_EN_EX),
+				regs_base + SC_DJTAG_MSTR_CFG_EX);
+
+	ret = djtag_do_operation_v2(regs_base);
+	if (ret) {
+		if (ret == EBUSY)
+			pr_err("djtag: %s timeout!\n", "read");
+		return ret;
+	}
+
+	*rval = readl(regs_base + SC_DJTAG_RD_DATA_BASE_EX +
+					      chain_id * 0x4);
+
+	return 0;
+}
+
+/*
+ * djtag_write_v1/v2: djtag write interface
+ * @reg_base:	djtag register base address
+ * @offset:	register's offset
+ * @mod_sel:	module selection
+ * @mod_mask:	mask to select specific modules for write
+ * @wval:	value to register for write
+ * @chain_id:	which sub module for read
+ *
+ * Return non-zero if error, else return 0.
+ */
+static int djtag_write_v1(void __iomem *regs_base, u32 offset, u32 mod_sel,
+					u32 mod_mask, u32 wval, int chain_id)
+{
+	int ret;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	djtag_prepare_v1(regs_base, offset, mod_sel, mod_mask);
+
+	writel(DJTAG_MSTR_W, regs_base + SC_DJTAG_MSTR_WR);
+	writel(wval, regs_base + SC_DJTAG_MSTR_DATA);
+
+	ret = djtag_do_operation_v1(regs_base);
+	if (ret) {
+		if (ret == EBUSY)
+			pr_err("djtag: %s timeout!\n", "write");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int djtag_write_v2(void __iomem *regs_base, u32 offset, u32 mod_sel,
+					u32 mod_mask, u32 wval, int chain_id)
+{
+	int ret;
+
+	if (!(mod_mask & CHAIN_UNIT_CFG_EN_EX)) {
+		pr_warn("djtag: do nothing.\n");
+		return 0;
+	}
+
+	djtag_prepare_v2(regs_base, offset, mod_sel, mod_mask);
+
+	writel(DJTAG_MSTR_WR_EX
+			| (mod_sel << DEBUG_MODULE_SEL_SHIFT_EX)
+			| (mod_mask & CHAIN_UNIT_CFG_EN_EX),
+				regs_base + SC_DJTAG_MSTR_CFG_EX);
+	writel(wval, regs_base + SC_DJTAG_MSTR_DATA_EX);
+
+	ret = djtag_do_operation_v2(regs_base);
+	if (ret) {
+		if (ret == EBUSY)
+			pr_err("djtag: %s timeout!\n", "write");
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * djtag_writel - write registers via djtag
+ * @client: djtag client handle
+ * @offset:	register's offset
+ * @mod_sel:	module selection
+ * @mod_mask:	mask to select specific modules
+ * @val:	value to write to register
+ *
+ * If error return errno, otherwise return 0.
+ */
+int hisi_djtag_writel(struct hisi_djtag_client *client, u32 offset,
+				 u32 mod_sel, u32 mod_mask, u32 val)
+{
+	void __iomem *reg_map = client->host->sysctl_reg_map;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&client->host->lock, flags);
+	ret = client->host->djtag_ops->djtag_write(reg_map, offset, mod_sel,
+						mod_mask, val, 0);
+	if (ret)
+		pr_err("djtag_writel: error! ret=%d\n", ret);
+	spin_unlock_irqrestore(&client->host->lock, flags);
+
+	return ret;
+}
+
+/**
+ * djtag_readl - read registers via djtag
+ * @client: djtag client handle
+ * @offset:	register's offset
+ * @mod_sel:	module type selection
+ * @chain_id:	chain_id number, mostly is 0
+ * @val:	register's value
+ *
+ * If error return errno, otherwise return 0.
+ */
+int hisi_djtag_readl(struct hisi_djtag_client *client, u32 offset,
+				u32 mod_sel, int chain_id, u32 *val)
+{
+	void __iomem *reg_map = client->host->sysctl_reg_map;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&client->host->lock, flags);
+	ret = client->host->djtag_ops->djtag_read(reg_map, offset, mod_sel,
+					0xffff, chain_id, val);
+	if (ret)
+		pr_err("djtag_readl: error! ret=%d\n", ret);
+	spin_unlock_irqrestore(&client->host->lock, flags);
+
+	return ret;
+}
+
+u32 hisi_djtag_get_sclid(struct hisi_djtag_client *client)
+{
+	return client->host->scl_id;
+}
+
+static const struct hisi_djtag_ops djtag_v1_ops = {
+	.djtag_read  = djtag_read_v1,
+	.djtag_write  = djtag_write_v1,
+};
+
+static const struct hisi_djtag_ops djtag_v2_ops = {
+	.djtag_read  = djtag_read_v2,
+	.djtag_write  = djtag_write_v2,
+};
+
+static const struct of_device_id djtag_of_match[] = {
+	/* for hip05 CPU and IO die */
+	{ .compatible = "hisilicon,hip05-djtag-v1",
+		.data = &djtag_v1_ops },
+	/* for hip06 CPU die */
+	{ .compatible = "hisilicon,hip06-djtag-v1",
+		.data = &djtag_v1_ops },
+	/* for hip06 IO die */
+	{ .compatible = "hisilicon,hip06-djtag-v2",
+		.data = &djtag_v2_ops },
+	/* for hip07 CPU and IO die */
+	{ .compatible = "hisilicon,hip07-djtag-v2",
+		.data = &djtag_v2_ops },
+	{},
+};
+MODULE_DEVICE_TABLE(of, djtag_of_match);
+
+static ssize_t
+show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct hisi_djtag_client *client = to_hisi_djtag_client(dev);
+
+	return sprintf(buf, "%s%s\n", MODULE_PREFIX, client->name);
+}
+static DEVICE_ATTR(modalias, 0444, show_modalias, NULL);
+
+static struct attribute *hisi_djtag_dev_attrs[] = {
+	NULL,
+	/* modalias helps coldplug:  modprobe $(cat .../modalias) */
+	&dev_attr_modalias.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(hisi_djtag_dev);
+
+static struct device_type hisi_djtag_client_type = {
+	.groups		= hisi_djtag_dev_groups,
+};
+
+static struct hisi_djtag_client *hisi_djtag_verify_client(struct device *dev)
+{
+	return (dev->type == &hisi_djtag_client_type)
+			? to_hisi_djtag_client(dev)
+			: NULL;
+}
+
+static int hisi_djtag_device_probe(struct device *dev)
+{
+	struct hisi_djtag_driver *driver;
+	struct hisi_djtag_client *client;
+	int rc;
+
+	client = hisi_djtag_verify_client(dev);
+	if (!client) {
+		dev_err(dev, "could not find client\n");
+		return -ENODEV;
+	}
+
+	driver = to_hisi_djtag_driver(dev->driver);
+	if (!driver) {
+		dev_err(dev, "could not find driver\n");
+		return -ENODEV;
+	}
+
+	rc = driver->probe(client);
+	if (rc < 0) {
+		dev_err(dev, "client probe failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hisi_djtag_device_remove(struct device *dev)
+{
+	struct hisi_djtag_driver *driver;
+	struct hisi_djtag_client *client;
+	int rc;
+
+	client = hisi_djtag_verify_client(dev);
+	if (!client) {
+		dev_err(dev, "could not find client\n");
+		return -ENODEV;
+	}
+
+	driver = to_hisi_djtag_driver(dev->driver);
+	if (!driver) {
+		dev_err(dev, "could not find driver\n");
+		return -ENODEV;
+	}
+
+	rc = driver->remove(client);
+	if (rc < 0) {
+		dev_err(dev, "client probe failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hisi_djtag_device_match(struct device *dev,
+					struct device_driver *drv)
+{
+	struct hisi_djtag_client *client = hisi_djtag_verify_client(dev);
+
+	if (!client)
+		return false;
+
+	if (of_driver_match_device(dev, drv))
+		return true;
+
+	return false;
+}
+
+struct bus_type hisi_djtag_bus = {
+	.name		= "hisi-djtag",
+	.match		= hisi_djtag_device_match,
+	.probe		= hisi_djtag_device_probe,
+	.remove		= hisi_djtag_device_remove,
+};
+
+static struct hisi_djtag_client *
+		hisi_djtag_client_alloc(struct hisi_djtag_host *host)
+{
+	struct hisi_djtag_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+
+	client->host = host;
+
+	client->dev.parent = &client->host->dev;
+	client->dev.bus = &hisi_djtag_bus;
+	client->dev.type = &hisi_djtag_client_type;
+
+	return client;
+}
+
+static int hisi_djtag_new_of_device(struct hisi_djtag_host *host,
+						struct device_node *node)
+{
+	struct hisi_djtag_client *client;
+	int rc;
+
+	client = hisi_djtag_client_alloc(host);
+	if (!client)
+		return -ENOMEM;
+
+	client->dev.of_node = of_node_get(node);
+	snprintf(client->name, DJTAG_CLIENT_NAME_LEN, "%s%d_%s",
+				DJTAG_PREFIX, host->id, node->name);
+	dev_set_name(&client->dev, "%s", client->name);
+
+	rc = device_register(&client->dev);
+	if (rc < 0) {
+		pr_err("DT: error adding new device, rc=%d\n", rc);
+		of_node_put(node);
+		kfree(client);
+		return -EINVAL;
+	}
+
+	list_add(&client->next, &host->client_list);
+	return 0;
+}
+
+static void djtag_register_devices(struct hisi_djtag_host *host)
+{
+	struct device_node *node;
+
+	if (host->of_node) {
+		for_each_available_child_of_node(host->of_node, node) {
+			if (of_node_test_and_set_flag(node, OF_POPULATED))
+				continue;
+			hisi_djtag_new_of_device(host, node);
+		}
+	}
+}
+
+static int hisi_djtag_add_host(struct hisi_djtag_host *host)
+{
+	int rc;
+
+	host->dev.bus = &hisi_djtag_bus;
+
+	rc = idr_alloc(&djtag_hosts_idr, host, 0, 0, GFP_KERNEL);
+	if (rc < 0) {
+		dev_err(&host->dev, "No available djtag host ID'!s\n");
+		return rc;
+	}
+	host->id = rc;
+
+	/* Suffix the unique ID and set djtag hostname */
+	dev_set_name(&host->dev, "djtag-host-%d", host->id);
+	rc = device_register(&host->dev);
+	if (rc < 0) {
+		dev_err(&host->dev, "add_host dev register failed, rc=%d\n",
+									rc);
+		idr_remove(&djtag_hosts_idr, host->id);
+		return rc;
+	}
+
+	djtag_register_devices(host);
+
+	return 0;
+}
+
+static int djtag_host_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct hisi_djtag_host *host;
+	const struct of_device_id *of_id;
+	struct resource *res;
+	int rc;
+
+	host = kzalloc(sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	of_id = of_match_device(djtag_of_match, dev);
+	if (of_id) {
+		const struct hisi_djtag_ops *djtag_ops = of_id->data;
+
+		host->djtag_ops = djtag_ops;
+		host->of_node = of_node_get(dev->of_node);
+
+		/* Find the SCL ID */
+		if (of_property_read_u32(dev->of_node, "hisi-scl-id",
+					&host->scl_id)) {
+			dev_err(dev, "DT: Cant read scl-id!\n");
+			rc = -EINVAL;
+			goto fail;
+		}
+	} else {
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	spin_lock_init(&host->lock);
+
+	INIT_LIST_HEAD(&host->client_list);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "No reg resorces!\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	if (!resource_size(res)) {
+		dev_err(dev, "Zero reg entry!\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	host->sysctl_reg_map = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->sysctl_reg_map)) {
+		dev_warn(dev, "Unable to map sysctl registers.\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, host);
+
+	rc = hisi_djtag_add_host(host);
+	if (rc) {
+		dev_err(dev, "add host failed, rc=%d\n", rc);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	of_node_put(dev->of_node);
+	kfree(host);
+	return rc;
+}
+
+static int djtag_host_remove(struct platform_device *pdev)
+{
+	struct hisi_djtag_host *host;
+	struct hisi_djtag_client *client, *tmp;
+	struct list_head *client_list;
+
+	host = platform_get_drvdata(pdev);
+	client_list = &host->client_list;
+
+	list_for_each_entry_safe(client, tmp, client_list, next) {
+		list_del(&client->next);
+		device_unregister(&client->dev);
+		of_node_put(client->dev.of_node);
+		kfree(client);
+	}
+
+	device_unregister(&host->dev);
+	idr_remove(&djtag_hosts_idr, host->id);
+	of_node_put(host->of_node);
+	kfree(host);
+
+	return 0;
+}
+
+static struct platform_driver djtag_dev_driver = {
+	.driver = {
+		.name = "hisi-djtag",
+		.of_match_table = djtag_of_match,
+	},
+	.probe = djtag_host_probe,
+	.remove = djtag_host_remove,
+};
+module_platform_driver(djtag_dev_driver);
+
+int hisi_djtag_register_driver(struct module *owner,
+				struct hisi_djtag_driver *driver)
+{
+	int rc;
+
+	driver->driver.owner = owner;
+	driver->driver.bus = &hisi_djtag_bus;
+
+	rc = driver_register(&driver->driver);
+	if (rc < 0)
+		pr_err("%s register failed, rc=%d\n", __func__, rc);
+
+	return rc;
+}
+
+void hisi_djtag_unregister_driver(struct hisi_djtag_driver *driver)
+{
+	driver->driver.bus = &hisi_djtag_bus;
+	driver_unregister(&driver->driver);
+}
+
+static int __init hisi_djtag_init(void)
+{
+	int rc;
+
+	rc = bus_register(&hisi_djtag_bus);
+	if (rc) {
+		pr_err("hisi  djtag init failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+module_init(hisi_djtag_init);
+
+static void __exit hisi_djtag_exit(void)
+{
+	bus_unregister(&hisi_djtag_bus);
+}
+module_exit(hisi_djtag_exit);
+
+MODULE_DESCRIPTION("Hisilicon djtag driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
diff --git a/drivers/perf/hisilicon/djtag.h b/drivers/perf/hisilicon/djtag.h
new file mode 100644
index 0000000..53a5462
--- /dev/null
+++ b/drivers/perf/hisilicon/djtag.h
@@ -0,0 +1,39 @@
+/*
+ * Driver for Hisilicon djtag r/w via System Controller.
+ *
+ * Copyright (C) 2016-2017 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __HISI_DJTAG_H
+#define __HISI_DJTAG_H
+
+#define DJTAG_CLIENT_NAME_LEN 32
+
+struct hisi_djtag_client {
+	struct hisi_djtag_host *host;
+	struct list_head next;
+	char name[DJTAG_CLIENT_NAME_LEN];
+	struct device dev;
+};
+
+struct hisi_djtag_driver {
+	struct device_driver driver;
+	int (*probe)(struct hisi_djtag_client *);
+	int (*remove)(struct hisi_djtag_client *);
+};
+
+extern struct bus_type hisi_djtag_bus;
+
+int hisi_djtag_register_driver(struct module *owner,
+				struct hisi_djtag_driver *driver);
+void hisi_djtag_unregister_driver(struct hisi_djtag_driver *driver);
+int hisi_djtag_readl(struct hisi_djtag_client *client, u32 offset,
+					u32 mod_sel, int chain_id, u32 *val);
+int hisi_djtag_writel(struct hisi_djtag_client *client, u32 offset,
+					u32 mod_sel, u32 mod_mask, u32 val);
+u32 hisi_djtag_get_sclid(struct hisi_djtag_client *client);
+#endif /* __HISI_DJTAG_H */
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 05/10] perf: hisi: Update Kconfig for Hisilicon PMU support
From: Anurup M @ 2017-01-02  6:49 UTC (permalink / raw)
  To: linux-arm-kernel

Update Kconfig for HiP05/06/07 PMU support.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/perf/Kconfig | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 4d5c5f9..2a5435b 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -19,4 +19,12 @@ config XGENE_PMU
         help
           Say y if you want to use APM X-Gene SoC performance monitors.
 
+config HISI_PMU
+	bool "HiSilicon SoC PMU"
+	depends on HW_PERF_EVENTS && ARM64
+	help
+	  Enable hardware event counter support for hardware event counters
+	  in Hisilicon HiP05/06/07 SoC. The hardware modules like L3C and MN
+	  have hardware events and counters.
+
 endmenu
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 04/10] Documentation: perf: hisi: Documentation for HiP05/06/07 PMU event counting.
From: Anurup M @ 2017-01-02  6:49 UTC (permalink / raw)
  To: linux-arm-kernel

Documentation for perf usage and Hisilicon SoC PMU uncore events.
The Hisilicon SOC has event counters for hardware modules like
L3 cache, Miscellaneous node etc. These events are all uncore.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 Documentation/perf/hisi-pmu.txt | 75 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/perf/hisi-pmu.txt

diff --git a/Documentation/perf/hisi-pmu.txt b/Documentation/perf/hisi-pmu.txt
new file mode 100644
index 0000000..16f77ab
--- /dev/null
+++ b/Documentation/perf/hisi-pmu.txt
@@ -0,0 +1,75 @@
+Hisilicon SoC PMU (Performance Monitoring Unit)
+================================================
+The Hisilicon SoC HiP05/06/07 chips consist of various independent system
+device PMU's such as L3 cache(L3C) and Miscellaneous Nodes(MN).
+These PMU devices are independent and have hardware logic to gather
+statistics and performance information.
+
+HiP0x chips are encapsulated by multiple CPU and IO die's. The CPU die is
+called as Super CPU cluster (SCCL) which includes 16 cpu-cores. Every SCCL
+is further grouped as CPU clusters (CCL) which includes 4 cpu-cores each.
+Each SCCL has 1 L3 cache and 1 MN units.
+
+The L3 cache is shared by all CPU cores in a CPU die. The L3C has four banks
+(or instances). Each bank or instance of L3C has Eight 32-bit counter
+registers and also event control registers. The HiP05/06 chip L3 cache has
+22 statistics events. The HiP07 chip has 66 statistics events. These events
+are very useful for debugging.
+
+The MN module is also shared by all CPU cores in a CPU die. It receives
+barriers and DVM(Distributed Virtual Memory) messages from cpu or smmu, and
+perform the required actions and return response messages. These events are
+very useful for debugging. The MN has total 9 statistics events and support
+four 32-bit counter registers in hip05/06/07 chips.
+
+There is no memory mapping for L3 cache and MN registers. It can be accessed
+by using the Hisilicon djtag interface. The Djtag in a SCCL is an independent
+module which connects with some modules in the SoC by Debug Bus.
+
+Hisilicon SoC (HiP05/06/07) PMU driver
+--------------------------------------
+The HiP0x PMU driver shall register perf PMU drivers like L3 cache, MN, etc.
+The available events and configuration options shall be described in the sysfs.
+The "perf list" shall list the available events from sysfs.
+
+The L3 cache in a SCCL is divided as 4 banks. Each L3 cache bank have separate
+PMU registers for event counting and control. So each L3 cache bank is
+registered with perf as a separate PMU.
+The PMU name will appear in event listing as hisi_l3c<bank-id>_<scl-id>.
+where "bank-id" is the bank index (0 to 3) and "scl-id" is the SCCL identifier
+e.g. hisi_l3c0_2/read_hit is READ_HIT event of L3 cache bank #0 SCCL ID #2.
+
+The MN in a SCCL is registered as a separate PMU with perf.
+The PMU name will appear in event listing as hisi_mn_<scl-id>.
+e.g. hisi_mn_2/read_req. READ_REQUEST event of MN of Super CPU cluster #2.
+
+The event code is represented by 12 bits.
+	i) event 0-11
+		The event code will be represented using the LSB 12 bits.
+
+The driver also provides a "cpumask" sysfs attribute, which shows the CPU core
+ID used to count the uncore PMU event.
+
+Example usage of perf:
+$# perf list
+hisi_l3c0_2/read_hit/ [kernel PMU event]
+------------------------------------------
+hisi_l3c1_2/write_hit/ [kernel PMU event]
+------------------------------------------
+hisi_l3c0_1/read_hit/ [kernel PMU event]
+------------------------------------------
+hisi_l3c0_1/write_hit/ [kernel PMU event]
+------------------------------------------
+hisi_mn_2/read_req/ [kernel PMU event]
+hisi_mn_2/write_req/ [kernel PMU event]
+------------------------------------------
+
+$# perf stat -a -e "hisi_l3c0_2/read_allocate/" sleep 5
+
+$# perf stat -A -C 0 -e "hisi_l3c0_2/read_allocate/" sleep 5
+
+The current driver doesnot support sampling. so "perf record" is unsupported.
+Also attach to a task is unsupported as the events are all uncore.
+
+Note: Please contact the maintainer for a complete list of events supported for
+the PMU devices in the SoC and its information if needed.
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 03/10] dt-bindings: perf: hisi: Add Devicetree bindings for Hisilicon SoC PMU
From: Anurup M @ 2017-01-02  6:49 UTC (permalink / raw)
  To: linux-arm-kernel

1) Device tree bindings for Hisilicon SoC PMU.
2) Add example for Hisilicon L3 cache and MN PMU.
3) Add child nodes of L3C and MN in djtag bindings example.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 .../devicetree/bindings/arm/hisilicon/djtag.txt    |  25 ++++++
 .../devicetree/bindings/arm/hisilicon/pmu.txt      | 100 +++++++++++++++++++++
 2 files changed, 125 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
index bbe8b45..653fdb7 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
@@ -27,6 +27,31 @@ Example 1: Djtag for CPU die
 		hisi-scl-id = <0x02>;
 
 		/* All connecting components will appear as child nodes */
+
+		pmul3c0 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x02>;
+		};
+
+		pmul3c1 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x04>;
+		};
+
+		pmul3c2 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x01>;
+		};
+
+		pmul3c3 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x08>;
+		};
+
+		pmumn0 {
+			compatible = "hisilicon,hip05-pmu-mn-v1";
+			hisi-module-id = <0x0b>;
+		};
 	};
 
 Example 2: Djtag for IO die
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
new file mode 100644
index 0000000..fceef8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
@@ -0,0 +1,100 @@
+Hisilicon SoC HiP05/06/07 ARMv8 PMU
+===================================
+
+The Hisilicon SoC chips like HiP05/06/07 etc. consist of various independent
+system device PMUs such as L3 cache (L3C) and Miscellaneous Nodes(MN). These
+PMU devices are independent and have hardware logic to gather statistics and
+performance information.
+
+HiSilicon SoC chip is encapsulated by multiple CPU and IO dies. The CPU die
+is called as Super CPU cluster (SCCL) which includes 16 cpu-cores. Every SCCL
+in HiP05/06/07 chips are further grouped as CPU clusters (CCL) which includes
+4 cpu-cores each.
+e.g. In the case of HiP05/06/07, each SCCL has 1 L3 cache and 1 MN PMU device.
+The L3 cache is further grouped as 4 L3 cache banks in a SCCL.
+
+The Hisilicon SoC PMU DT node bindings for uncore PMU devices are as below.
+For PMU devices like L3 cache. MN etc. which are accessed using the djtag,
+the parent node will be the djtag node of the corresponding CPU die (SCCL).
+
+L3 cache
+---------
+The L3 cache is dedicated for each SCCL. Each SCCL in HiP05/06/07 chips have 4
+L3 cache banks. Each L3 cache bank have separate DT nodes.
+
+Required properties:
+
+	- compatible : This value should be as follows
+		(a) "hisilicon,hip05-pmu-l3c-v1" for v1 hw in HiP05 chipset
+		(b) "hisilicon,hip06-pmu-l3c-v1" for v1 hw in HiP06 chipset
+		(c) "hisilicon,hip07-pmu-l3c-v2" for v2 hw in HiP07 chipset
+
+	- hisi-module-id : This property is a combination of two values in the below order.
+		      a) Module ID: The module identifier for djtag.
+		      b) Instance or Bank ID: This will identify the L3 cache bank
+			 or instance.
+
+Optional properties:
+
+	- interrupt-parent : A phandle indicating which interrupt controller
+		this PMU signals interrupts to.
+
+	- interrupts : Interrupt line used by this L3 cache bank.
+
+	*The counter overflow IRQ is not supported in v1 hardware (HiP05/06).
+
+Miscellaneous Node
+------------------
+The MN is dedicated for each SCCL and hence there are separate DT nodes for MN
+for each SCCL.
+
+Required properties:
+
+	- compatible : This value should be as follows
+		(a) "hisilicon,hip05-pmu-mn-v1" for v1 hw in HiP05 chipset
+		(b) "hisilicon,hip06-pmu-mn-v1" for v1 hw in HiP06 chipset
+		(c) "hisilicon,hip07-pmu-mn-v2" for v2 hw in HiP07 chipset
+
+	- hisi-module-id : Module ID to input for djtag.
+
+Optional properties:
+
+	- interrupt-parent : A phandle indicating which interrupt controller
+		this PMU signals interrupts to.
+
+	- interrupts : Interrupt line used by this PMU.
+
+	*The counter overflow IRQ is not supported in v1 hardware (HiP05/06).
+
+Example:
+
+	djtag0: djtag at 80010000 {
+		compatible = "hisilicon,hip05-djtag-v1";
+		reg = <0x0 0x80010000 0x0 0x10000>;
+		scl-id = <0x02>;
+
+		pmul3c0 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x02>;
+		};
+
+		pmul3c1 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x04>;
+		};
+
+		pmul3c2 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x01>;
+		};
+
+		pmul3c3 {
+			compatible = "hisilicon,hip05-pmu-l3c-v1";
+			hisi-module-id = <0x04 0x08>;
+		};
+
+		pmumn0 {
+			compatible = "hisilicon,hip05-pmu-mn-v1";
+			hisi-module-id = <0x0b>;
+		};
+	};
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 02/10] dt-bindings: hisi: Add Hisilicon HiP05/06/07 Djtag dts bindings
From: Anurup M @ 2017-01-02  6:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tan Xiaojun <tanxiaojun@huawei.com>

Add Hisilicon HiP05/06/07 Djtag dts bindings for CPU and IO Die

Signed-off-by: Tan Xiaojun <tanxiaojun@huawei.com>
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 .../devicetree/bindings/arm/hisilicon/djtag.txt    | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/djtag.txt

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
new file mode 100644
index 0000000..bbe8b45
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
@@ -0,0 +1,41 @@
+The Hisilicon Djtag is an independent component which connects with some other
+components in the SoC by Debug Bus. The djtag is available in CPU and IO dies
+in the chip. The djtag controls access to connecting modules of CPU and IO
+dies.
+The various connecting components in CPU die (like L3 cache, L3 cache PMU etc.)
+are accessed by djtag during real time debugging. In IO die there are connecting
+components like RSA. These components appear as devices attached to djtag bus.
+
+Hisilicon HiP05/06/07 djtag for CPU and IO die
+Required properties:
+  - compatible : The value should be as follows
+	(a) "hisilicon,hip05-djtag-v1" for CPU and IO die which use v1 hw in
+	    HiP05 chipset.
+	(b) "hisilicon,hip06-djtag-v1" for CPU die which use v1 hw in HiP06 chipset.
+	(c) "hisilicon,hip06-djtag-v2" for IO die which use v2 hw in HiP06 chipset.
+	(d) "hisilicon,hip07-djtag-v2" for CPU and IO die which use v2 hw in
+	    HiP07 chipset.
+  - reg : Register address and size
+  - hisi-scl-id : The Super Cluster ID for CPU or IO die
+
+Example 1: Djtag for CPU die
+
+	/* for Hisilicon HiP05 djtag for CPU Die */
+	djtag0: djtag at 80010000 {
+		compatible = "hisilicon,hip05-djtag-v1";
+		reg = <0x0 0x80010000 0x0 0x10000>;
+		hisi-scl-id = <0x02>;
+
+		/* All connecting components will appear as child nodes */
+	};
+
+Example 2: Djtag for IO die
+
+	/* for Hisilicon HiP05 djtag for IO Die */
+	djtag1: djtag at d0000000 {
+		compatible = "hisilicon,hip05-djtag-v1";
+		reg = <0x0 0xd0000000 0x0 0x10000>;
+		hisi-scl-id = <0x01>;
+
+		/* All connecting components will appear as child nodes */
+	};
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 01/10] arm64: MAINTAINERS: hisi: Add hisilicon SoC PMU support
From: Anurup M @ 2017-01-02  6:48 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for Hisilicon SoC hardware event counters
for HIP05/06/07 chip versions.

Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b224caa..fca339e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5725,6 +5725,15 @@ S:	Maintained
 F:	drivers/net/ethernet/hisilicon/
 F:	Documentation/devicetree/bindings/net/hisilicon*.txt
 
+HISILICON SOC PMU
+M:	Anurup M <anurup.m@huawei.com>
+W:	http://www.hisilicon.com
+S:	Supported
+F:	drivers/perf/hisilicon/
+F:	Documentation/perf/hisi-pmu.txt
+F:	Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
+F:	Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
+
 HISILICON ROCE DRIVER
 M:	Lijun Ou <oulijun@huawei.com>
 M:	Wei Hu(Xavier) <xavier.huwei@huawei.com>
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3 00/10] perf: arm64: Support for Hisilicon SoC Hardware event counters
From: Anurup M @ 2017-01-02  6:47 UTC (permalink / raw)
  To: linux-arm-kernel

Provide Support for Hisilicon SoC(HiP05/06/07) Hardware event counters.
The Hisilicon SoC HiP0x series has many uncore or non-CPU performance
events and counters units.

This patch series is implemented refering to arm-cci, Intel/AMD uncore and
also the cavium thunderX and xgene uncore pmu patches.
This v3 version has addressed the review comments of v1 and v2 versions.

Support for Hisilicon L3 cache(L3C) and Misclennaneous nodes(MN) hardware
events and counters are added in this implementation.

The Hisilicon uncore PMUs can be found under /sys/bus/event_source/devices.
The counters are exported via sysfs in the corresponding events files
under the PMU directory so the perf tool can list the event names.

ToDo:
1) The counter overflow handling is currently unsupported in this
   patch series.
2) ACPI support.

Version history
---------------
v3
--
- Fix review comments of v2 version.
- Handle event groups. Do not allow group of mixed PMUs.
- Use hip0x prefix in compatible names and hisi- prefix in
  added device properties.
- Fix all sparse and gcc W=1 warnings.

v2
--
- Fix review comments of v1 version.
- Move djtag driver to drivers/perf/hisilicon.
- Have separate PMU instance for each L3 cache banks.
- Modify device properties in DTS as per review comments.
- Handle hardware version difference.
- Change compatible names of djtag so use prefix hisi-
  and remove chip version as driver only depend on djtag
  hw version.
- use devm_kzalloc.
- Remove DDRC changes in this series. As the DDRC PMU doesnot
  depend on djtag it will be send separately.

v1
--
-Initial version with support for L3C, MN and DDRC event counters
-Djtag driver is used to access registers of L3 cache and MN.

Anurup M (7):
  arm64: MAINTAINERS: hisi: Add hisilicon SoC PMU support
  dt-bindings: perf: hisi: Add Devicetree bindings for Hisilicon SoC PMU
  Documentation: perf: hisi: Documentation for HiP05/06/07 PMU event
    counting.
  perf: hisi: Update Kconfig for Hisilicon PMU support
  perf: hisi: Add support for Hisilicon SoC event counters
  perf: hisi: Add sysfs attributes for L3 cache(L3C) PMU
  dts: arm64: hip06: Add Hisilicon SoC PMU support

Shaokun Zhang (1):
  perf: hisi: Miscellanous node(MN) event counting in perf

Tan Xiaojun (2):
  dt-bindings: hisi: Add Hisilicon HiP05/06/07 Djtag dts bindings
  drivers: perf: hisi: Add support for Hisilicon Djtag driver

 .../devicetree/bindings/arm/hisilicon/djtag.txt    |  66 ++
 .../devicetree/bindings/arm/hisilicon/pmu.txt      | 100 +++
 Documentation/perf/hisi-pmu.txt                    |  75 +++
 MAINTAINERS                                        |   9 +
 arch/arm64/boot/dts/hisilicon/hip06.dtsi           |  72 ++
 drivers/perf/Kconfig                               |   8 +
 drivers/perf/Makefile                              |   1 +
 drivers/perf/hisilicon/Makefile                    |   1 +
 drivers/perf/hisilicon/djtag.c                     | 731 +++++++++++++++++++++
 drivers/perf/hisilicon/djtag.h                     |  39 ++
 drivers/perf/hisilicon/hisi_uncore_l3c.c           | 609 +++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_mn.c            | 501 ++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c           | 365 ++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.h           | 127 ++++
 14 files changed, 2704 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
 create mode 100644 Documentation/perf/hisi-pmu.txt
 create mode 100644 drivers/perf/hisilicon/Makefile
 create mode 100644 drivers/perf/hisilicon/djtag.c
 create mode 100644 drivers/perf/hisilicon/djtag.h
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_mn.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h

-- 
2.1.4

^ permalink raw reply

* [PATCH 2/2] arm64:dt:ls1012a: Add TMU device tree support for LS1012A
From: Shawn Guo @ 2017-01-02  6:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481167706-44234-2-git-send-email-hongtao.jia@nxp.com>

On Thu, Dec 08, 2016 at 11:28:26AM +0800, Jia Hongtao wrote:
> Also add nodes and properties for thermal management support.
> 
> Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com>
> ---
> Depend on patch "[v3] arm64: Add DTS support for FSL's LS1012A SoC".
> https://patchwork.kernel.org/patch/9462399/

Please send me the patch only after the dependent one is already
accepted.

Shawn

^ permalink raw reply

* [PATCH 1/2] arm64:dt:ls1046a: Add TMU device tree support for LS1046A
From: Shawn Guo @ 2017-01-02  6:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481167706-44234-1-git-send-email-hongtao.jia@nxp.com>

On Thu, Dec 08, 2016 at 11:28:25AM +0800, Jia Hongtao wrote:
> Also add nodes and properties for thermal management support.
> 
> Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com>

"arm64: dts: ls1046a: ..." for subject prefix please.  Also, since we
have ls1046a in prefix, the 'for LS1046A' is not needed.

> ---
>  arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 79 ++++++++++++++++++++++++++
>  1 file changed, 79 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> index 38806ca..40604e9 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
> @@ -45,6 +45,8 @@
>   */
>  
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/thermal/thermal.h>
> +

Unneeded newline.

>  
>  / {
>  	compatible = "fsl,ls1046a";
> @@ -67,6 +69,7 @@
>  			clocks = <&clockgen 1 0>;
>  			next-level-cache = <&l2>;
>  			cpu-idle-states = <&CPU_PH20>;
> +			#cooling-cells = <2>;
>  		};
>  
>  		cpu1: cpu at 1 {
> @@ -279,6 +282,82 @@
>  			clocks = <&sysclk>;
>  		};
>  
> +		tmu: tmu at 1f00000 {
> +			compatible = "fsl,qoriq-tmu";
> +			reg = <0x0 0x1f00000 0x0 0x10000>;
> +			interrupts = <0 33 0x4>;
> +			fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>;
> +			fsl,tmu-calibration = <0x00000000 0x00000026
> +					       0x00000001 0x0000002d
> +					       0x00000002 0x00000032
> +					       0x00000003 0x00000039
> +					       0x00000004 0x0000003f
> +					       0x00000005 0x00000046
> +					       0x00000006 0x0000004d
> +					       0x00000007 0x00000054
> +					       0x00000008 0x0000005a
> +					       0x00000009 0x00000061
> +					       0x0000000a 0x0000006a
> +					       0x0000000b 0x00000071
> +

Instead of a newline, can we have a single line comment here to tell how
these calibration data is grouped?

> +					       0x00010000 0x00000025
> +					       0x00010001 0x0000002c
> +					       0x00010002 0x00000035
> +					       0x00010003 0x0000003d
> +					       0x00010004 0x00000045
> +					       0x00010005 0x0000004e
> +					       0x00010006 0x00000057
> +					       0x00010007 0x00000061
> +					       0x00010008 0x0000006b
> +					       0x00010009 0x00000076
> +
> +					       0x00020000 0x00000029
> +					       0x00020001 0x00000033
> +					       0x00020002 0x0000003d
> +					       0x00020003 0x00000049
> +					       0x00020004 0x00000056
> +					       0x00020005 0x00000061
> +					       0x00020006 0x0000006d
> +
> +					       0x00030000 0x00000021
> +					       0x00030001 0x0000002a
> +					       0x00030002 0x0000003c
> +					       0x00030003 0x0000004e>;
> +			big-endian;
> +			#thermal-sensor-cells = <1>;
> +		};
> +
> +		thermal-zones {
> +			cpu_thermal: cpu-thermal {
> +				polling-delay-passive = <1000>;
> +				polling-delay = <5000>;
> +

We usually do not have newline between properties but nodes, or between
property list and child node.

> +				thermal-sensors = <&tmu 3>;
> +
> +				trips {
> +					cpu_alert: cpu-alert {
> +						temperature = <85000>;
> +						hysteresis = <2000>;
> +						type = "passive";
> +					};

Have a newline here.

Shawn

> +					cpu_crit: cpu-crit {
> +						temperature = <95000>;
> +						hysteresis = <2000>;
> +						type = "critical";
> +					};
> +				};
> +
> +				cooling-maps {
> +					map0 {
> +						trip = <&cpu_alert>;
> +						cooling-device =
> +							<&cpu0 THERMAL_NO_LIMIT
> +							THERMAL_NO_LIMIT>;
> +					};
> +				};
> +			};
> +		};
> +
>  		dspi: dspi at 2100000 {
>  			compatible = "fsl,ls1021a-v1.0-dspi";
>  			#address-cells = <1>;
> -- 
> 2.1.0.27.g96db324
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH] ARM: dts: imx6sx-udoo-neo: Pass the 'phy-reset-duration' property
From: Shawn Guo @ 2017-01-02  6:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480966119-17350-1-git-send-email-festevam@gmail.com>

On Mon, Dec 05, 2016 at 05:28:39PM -0200, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
> 
> imx6sx-udoo-neo has a KSZ8091 Ethernet PHY, which requires the reset
> signal to be low for at least 10ms.
> 
> Pass the 'phy-reset-duration' property to reflect such requirement.
> 
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>

Applied, thanks.

^ permalink raw reply

* [PATCH 1/3] dma: zx: rename zx296702_dma.c to zx_dma.c
From: Vinod Koul @ 2017-01-02  5:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481810617-7650-1-git-send-email-shawnguo@kernel.org>

On Thu, Dec 15, 2016 at 10:03:35PM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
> 
> ZTE ZX dma driver is not ZX296702 specific.  It works for not only
> ZX296702 but also other ZTE ZX family platforms like ZX296718.  Let's
> rename the file to reflect that.

Applied all after fixing subsystem name

-- 
~Vinod

^ permalink raw reply

* [PATCH] dmaengine: ipu: Make sure the interrupt routine checks all interrupts.
From: Vinod Koul @ 2017-01-02  5:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482354838-22615-1-git-send-email-lilja.magnus@gmail.com>

On Wed, Dec 21, 2016 at 10:13:58PM +0100, Magnus Lilja wrote:
> Commit 3d8cc00073d6 ("dmaengine: ipu: Consolidate duplicated irq handlers")
> consolidated the two interrupts routines into one, but the remaining
> interrupt routine only checks the status of the error interrupts, not the
> normal interrupts.
> 
> This patch fixes that problem (tested on i.MX31 PDK board).

Applied thnx

-- 
~Vinod

^ permalink raw reply

* [PATCH 0/9] dmaengine: stm32-dma: Bug fixes and improvements series
From: Vinod Koul @ 2017-01-02  4:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481636451-27863-1-git-send-email-cedric.madianga@gmail.com>

On Tue, Dec 13, 2016 at 02:40:42PM +0100, M'boumba Cedric Madianga wrote:
> This patchset adds bug fixes reported by devices using STM32 DMA and some
> improvements mainly linked to dmaengine framework evolution.

So you should order fixes first and then new additions.

Fixes go in for current release whereas the rest for next one.

I have applied two to fixes and rest to updated, patch 5 didn't apply, please
resend that one.

-- 
~Vinod

^ permalink raw reply

* [PATCH 8/8] ARM: dts: kirkwood-rd88f6281: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts | 11 ++++++++
 arch/arm/boot/dts/kirkwood-rd88f6281.dtsi   | 44 +++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts b/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
index 1a797381d3d4..57cfcc2941cd 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
+++ b/arch/arm/boot/dts/kirkwood-rd88f6281-z0.dts
@@ -33,3 +33,14 @@
 &eth1 {
       status = "disabled";
 };
+
+&switch {
+	reg = <0>;
+
+	ports {
+		port at 4 {
+			reg = <4>;
+			label = "wan";
+		};
+	};	
+};
diff --git a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
index d5aacf137e40..91f5da5dae5f 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
+++ b/arch/arm/boot/dts/kirkwood-rd88f6281.dtsi
@@ -54,6 +54,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -115,6 +117,48 @@
 
 &mdio {
 	status = "okay";
+
+	switch: switch at 0 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan4";
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth0port>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+
+		};
+	};
 };
 
 &eth0 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH 7/8] ARM: dts: kirkwood-mv88f6281gtw-ge: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts | 49 ++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
index 172a38c0b8a9..5622115158ab 100644
--- a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
+++ b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
@@ -112,6 +112,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -159,6 +161,53 @@
 
 &mdio {
 	status = "okay";
+
+	switch at 0 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan4";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "wan";
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth0port>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};	
 };
 
 &eth0 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH 6/8] ARM: dts: kirkwood-linksys-viper: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/kirkwood-linksys-viper.dts | 49 ++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/kirkwood-linksys-viper.dts b/arch/arm/boot/dts/kirkwood-linksys-viper.dts
index 345fcac48dc7..df7851820507 100644
--- a/arch/arm/boot/dts/kirkwood-linksys-viper.dts
+++ b/arch/arm/boot/dts/kirkwood-linksys-viper.dts
@@ -70,6 +70,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -207,6 +209,53 @@
 
 &mdio {
 	status = "okay";
+
+	switch at 10 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <16>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "ethernet1";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "ethernet2";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "ethernet3";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "ethernet4";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "internet";
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth0port>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
 };
 
 &uart0 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH 5/8] ARM: dts: kirkwood-dir665: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/kirkwood-dir665.dts | 49 +++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/kirkwood-dir665.dts b/arch/arm/boot/dts/kirkwood-dir665.dts
index 41acbb6dd6ab..4d2b15d6244a 100644
--- a/arch/arm/boot/dts/kirkwood-dir665.dts
+++ b/arch/arm/boot/dts/kirkwood-dir665.dts
@@ -194,6 +194,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -241,6 +243,53 @@
 
 &mdio {
 	status = "okay";
+
+	switch at 0 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan4";
+			};
+
+			port at 1 {
+			       reg = <1>;
+			       label = "lan3";
+			};
+
+			port at 2 {
+			       reg = <2>;
+			       label = "lan2";
+			};
+
+			port at 3 {
+			       reg = <3>;
+			       label = "lan1";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "wan";
+			};
+
+			port at 6 {
+				reg = <6>;
+				label = "cpu";
+				ethernet = <&eth0port>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
 };
 
 /* eth0 is connected to a Marvell 88E6171 switch, without a PHY. So set
-- 
2.9.3

^ permalink raw reply related

* [PATCH 4/8] ARM: dts: armada-xp-linksys-mamba: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-xp-linksys-mamba.dts | 53 +++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 83ac884c0f8a..42ea8764814c 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -302,6 +302,8 @@
 	};
 
 	dsa {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -398,3 +400,54 @@
 		spi-max-frequency = <40000000>;
 	};
 };
+
+&mdio {
+	status = "okay";
+
+	switch at 0 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan4";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan3";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan2";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan1";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "internet";
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth0>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH 3/8] ARM: dts: armada-388-clearfog: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net:
dsa: Document new binding"). The legacy binding node is kept included, but is
marked disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-388-clearfog.dts | 65 +++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/arch/arm/boot/dts/armada-388-clearfog.dts b/arch/arm/boot/dts/armada-388-clearfog.dts
index 71ce201c903e..35207aa1f4ec 100644
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
@@ -351,6 +351,8 @@
 	};
 
 	dsa at 0 {
+		status = "okay";
+
 		compatible = "marvell,dsa";
 		dsa,ethernet = <&eth1>;
 		dsa,mii-bus = <&mdio>;
@@ -444,3 +446,66 @@
 		status = "disabled";
 	};
 };
+
+&mdio {
+	status = "okay";
+
+	switch at 4 {
+		compatible = "marvell,mv88e6085";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <4>;
+		pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>;
+		pinctrl-names = "default";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port at 0 {
+				reg = <0>;
+				label = "lan5";
+			};
+
+			port at 1 {
+				reg = <1>;
+				label = "lan4";
+			};
+
+			port at 2 {
+				reg = <2>;
+				label = "lan3";
+			};
+
+			port at 3 {
+				reg = <3>;
+				label = "lan2";
+			};
+
+			port at 4 {
+				reg = <4>;
+				label = "lan1";
+			};
+
+			port at 5 {
+				reg = <5>;
+				label = "cpu";
+				ethernet = <&eth1>;
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+
+			port at 6 {
+				/* 88E1512 external phy */
+				reg = <6>;
+				label = "lan6";
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH 2/8] ARM: dts: armada-38x: Utilize new DSA binding
From: Florian Fainelli @ 2017-01-02  2:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102022249.10657-1-f.fainelli@gmail.com>

Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net: dsa:
Document new binding"). The legacy binding node is kept included, but is marked
disabled.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/boot/dts/armada-385-linksys.dtsi | 52 ++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index 8f0e508f64ae..20d5e8b00f2d 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -103,8 +103,56 @@
 				};
 			};
 
-			mdio {
+			mdio at 72004 {
 				status = "okay";
+
+				switch at 0 {
+					compatible = "marvell,mv88e6095";
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port at 0 {
+							reg = <0>;
+							label = "lan4";
+						};
+
+						port at 1 {
+							reg = <1>;
+							label = "lan3";
+						};
+
+						port at 2 {
+							reg = <2>;
+							label = "lan2";
+						};
+
+						port at 3 {
+							reg = <3>;
+							label = "lan1";
+						};
+
+						port at 4 {
+							reg = <4>;
+							label = "wan";
+						};
+
+						port at 5 {
+							reg = <5>;
+							label = "cpu";
+							ethernet = <&eth2>;
+
+							fixed-link {
+								speed = <1000>;
+								full-duplex;
+							};
+						};
+					};
+				};
 			};
 
 			sata at a8000 {
@@ -261,6 +309,8 @@
 	};
 
 	dsa at 0 {
+		status = "disabled";
+
 		compatible = "marvell,dsa";
 		#address-cells = <2>;
 		#size-cells = <0>;
-- 
2.9.3

^ 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